Noise() function is very slowwwww
-
On 17/05/2013 at 07:56, xxxxxxxx wrote:
I've always used the c4d_debug.txt file to do my debugging. But I would like to try using the command line approach to see if I like it better.
But the problem is I've never done this before. And I don't know how to do it.After searching around for a bit. I found some examples for plain C++
`int main(int argc, char** argv)
But C4D plugins don't have an int main() function. So I don't know how to set it up.
And then I'm not sure how to use it.
In the C++ examples I'm finding. They are peppered with commands throughout the code.
Is there a way to have the entire plugin be checked for memory leaks with one -debug instance like the c4d_debug.txt works?-ScottA
` -
On 17/05/2013 at 08:14, xxxxxxxx wrote:
Call Cinema 4D from the command-line just like you would call any other program from the command-line.
-
On 17/05/2013 at 08:35, xxxxxxxx wrote:
Ah. Ok.
I was confusing "command args" with "command line". !LOL
[URL-REMOVED]Thanks,
-ScottA
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 17/05/2013 at 09:49, xxxxxxxx wrote:
Since there are no examples in the SDK for how to use the Noise() function.
I'm posting a simple example. Just in case anyone needs it://This is an example of using the Noise() function in a shader plugin #include "c4d.h" #include "c4d_symbols.h" #include "myshader.h" #include "lib_noise.h" #define PLUGIN_ID 1000000 //temp ID only!!! class MyShader : public ShaderData { private: C4DNoise *mynoise; public: virtual Bool Init(GeListNode *node); virtual Vector Output(BaseShader *chn, ChannelData *cd); virtual INITRENDERRESULT InitRender(BaseShader *sh, const InitRenderStruct &irs); virtual void FreeRender(BaseShader *sh); static NodeData *Alloc(void) { return gNew MyShader; } }; Bool MyShader::Init(GeListNode *node) { BaseContainer *data = ((BaseShader* )node)->GetDataInstance(); mynoise = NULL; return TRUE; } INITRENDERRESULT MyShader::InitRender(BaseShader *sh, const InitRenderStruct &irs) { BaseContainer *data = sh->GetDataInstance(); LONG seed = 555; mynoise = C4DNoise::Alloc(seed); return INITRENDERRESULT_OK; } Vector MyShader::Output(BaseShader *chn, ChannelData *cd) { Vector p = cd->p; p *= 10; //The number of repeats Real n = mynoise->Noise(NOISE_CRANAL, FALSE, p, 0.0, 1.0, FALSE, 0.25, 0.25, 0); return Vector(n); } void MyShader::FreeRender(BaseShader *sh) { mynoise->Free(mynoise); } Bool RegisterShaderPlugin(void) { return RegisterShaderPlugin(PLUGIN_ID,GeLoadString(IDS_MY_SHADER),0, MyShader::Alloc,"myshader",0); }
-ScottA
-
On 17/05/2013 at 10:07, xxxxxxxx wrote:
Scott, I'm so confused when you say "function" everytime, because this word relates to a global
function in the usual terms. The Noise() "function" is a method in this case, a method of the
C4DThread class. -
On 17/05/2013 at 10:16, xxxxxxxx wrote:
Dangerous, Scott
You should definitely check 'mynoise' for NULL after allocating it in InitRender(), and then return INITRENDERRESULT_OUTOFMEMORY if it's NULL. If I think about it, you should always check all pointers for NULL:
INITRENDERRESULT MyShader::InitRender(BaseShader *sh, const InitRenderStruct &irs;) { if (!sh) return INITRENDERRESULT_OUTOFMEMORY; BaseContainer *data = sh->GetDataInstance(); LONG seed = 555; mynoise = C4DNoise::Alloc(seed); if (!mynoise) return INITRENDERRESULT_OUTOFMEMORY; return INITRENDERRESULT_OK; }
The line in FreeRender() will probably not work. Since Free() is a static function of the BaseShader class, it has to be as follows (also add a NULL check here, just in case).
void MyShader::FreeRender(BaseShader *sh) { if (mynoise) BaseShader::Free(mynoise); }
And as a last tip: I would not set the mynoise pointer to NULL in the Init() function. To have a defined state of the MyShader class after allocation, you must initialize all members in the class constructor. Also use the INSTANCEOF() macro to indicate that your shader class is an instance of BaseShader. That enables you to use SUPER to call the parent class' functions (shown further down in Init()).
class MyShader : public ShaderData { INSTANCEOF(MyShader, BaseShader) private: C4DNoise *mynoise; public: virtual Bool Init(GeListNode *node); virtual Vector Output(BaseShader *chn, ChannelData *cd); virtual INITRENDERRESULT InitRender(BaseShader *sh, const InitRenderStruct &irs;); virtual void FreeRender(BaseShader *sh); static NodeData *Alloc(void) { return gNew MyShader; } MyShader() : mynoise(NULL) { } };
Use Init() only to initialize (= set default values for) the parameters in your shader's BaseContainer. And again, an additional NULL pointer check for 'data'.
Bool MyShader::Init(GeListNode *node) { BaseContainer *data = ((BaseShader* )node)->GetDataInstance(); if (! // Set default parameters in 'data' here data->SetReal(MYSHADER_PARAMETER_BLAH, 1.0); data->SetLong(MYSHADER_PARAMETER_FOOBAR, 123); return SUPER::Init(node); }
-
On 17/05/2013 at 10:30, xxxxxxxx wrote:
I'm just curious: Why does the C4D API use the INSTANCEOF() macro? In my humble opinion, it
is doing some "hidden magic" (which is what macros always do) and this one is making even darker
magic. From the name itself it is almost not possible to conclude it typedefs the parent class as
SUPER.> typedef ShaderData SUPER;
So clear, and even a bit shorter.
-Nik
-
On 17/05/2013 at 10:49, xxxxxxxx wrote:
Thanks Frank.
The code I posted works works fine for me with no memory leaks. But I do admit that it's very lean, and not using of defensive code.I didn't now that about the INSTANCEOF() macro.
That code has always been a bit of a mystery to me about what it's really used for.I do usually use the style: type::Free(instance) to free allocated memory.
And I only do it that way because that's how other people use it. Not knowing why I'm using it that way. Rather than using the style: mynoise- >Free(mynoise);
Most of the time I can't use the style: mynoise->Free(mynoise); because it doesn't free the memory.
But in this case it worked. So that's what I used.
But I really don't have a good grasp of why one style works. And one style doesn't.
I'm self taught. And C++ memory management is something I've never really understood properly.-ScottA
-
On 17/05/2013 at 10:58, xxxxxxxx wrote:
Originally posted by xxxxxxxx
I didn't now that about the INSTANCEOF() macro.
That code has always been a bit of a mystery to me about what it's really used for.And here's my proof, thanks Scott. The INSTANCEOF() macro is one of the most confusing things
I have seen in the C4D API. -
On 17/05/2013 at 12:42, xxxxxxxx wrote:
Nah, it's not confusing. It just enables you to use SUPER::blah() instead of ShaderData::Blah(). You don't have to use it, but it saves you some typing work, especially if you override more functions than just one. No voodoo going on here.
If you ever wonder what stuff does, just look up how it's defined.
-
On 17/05/2013 at 12:48, xxxxxxxx wrote:
class MyShader : public ShaderData { typedef ShaderData SUPER; INSTANCEOF(MyShader, ShaderData); };
Shorter! And those lines are equal. Of course if you know very well what the macro does, this
line won't interfere you while analyzing code. But for someone just getting started in C++, this
is very confusing because1. he doesn't know what the macro does, and it's name is not really implying that it typedefs the
base class to SUPER. Yes, this is in the documentation, but having to look up what a macro
actually does is IMHO a bad design. Though, this is really just my subjective opinion.
2. he wonders why the compiler complains that SUPER is not defined when he is creating is first
subclass (he obviously forgot about the INSTANCEOF() part).That's at least what I remember from back then. Until I actually saw the definition line in the C4D
header files, I assumed it to be some black magic.Best,
-Niklas -
On 18/05/2013 at 04:38, xxxxxxxx wrote:
Originally posted by xxxxxxxx
but having to look up what a macro actually does is IMHO a bad design
If you don't look it up, how would you ever know what it does (except if it's indicated by the macro's name)? That is not bad design, it just normal to look things up. There are functions and macros and structures and lots of other stuff... if you don't know what they are for, look it up. It's just one click.
If you only assume what stuff is good for, without verifying your assumptions, and then considering stuff black magic based on your assumption, you should rethink your strategy. Remember that old saying: "Every catastrophe's beginning is a s**tty assumption."