C++ Missing Information

On 03/07/2013 at 05:56, xxxxxxxx wrote:

User Information:
Cinema 4D Version:    
Language(s) :

Hei folks,

I find myself annoyed about missing information in the SDK documentation very often recently,
because I had to invest a lot of time figuring out these tings myself. I want to post things here
that I couldn't find in the documentation and was able to figure out myself or from information
collected from other threads. You are welcome to join!

I'll try to update the Table of Contents regularly. If you post, please make it one post for each
topic. If you have to add information or update the post, just do it. I'd also like to ask you to
not respond to this thread, but if any questions occure, create a new thread with a link to the
topic in this post. This way the thread stays focues on the actual topic: collecting information
missing from the SDK docs in one place. Thanks

Table of Contents:


On 03/07/2013 at 05:59, xxxxxxxx wrote:

EffectorData - Drawing of C4D_Falloff does not follow the Effector object

Description : The EffectorData class has a C4D_Falloff member. Necessary calls are automatically
forwarded to it (eg. C4D_Falloff::Draw() from EffectorData::Draw()). Though, there's one
problem one might experience while developing an effector: When the effector object is not
attached to any object (eg. effector list in a cloner, serving as a deformer), the visuals of the falloff
in the viewport stay at the position the effector was last invoked from.

Solution : Register the EffectorData plugin with the OBJECT_CALL_ADDEXECUTION flag. The
implementation of EffecorData::Execute() will automatically update the internal C4D_Falloff object
causing it to be drawn at the correct location.

Example :


Source : cinema4dsdk/source/object/dropeffector.cpp

On 03/07/2013 at 06:52, xxxxxxxx wrote:

GvOperatorData - Simple graph-view calculation example

While I tried to figure this out, an example would have been more than I could have ever dreamt
of. Remo was so kind to hand one over to me, which helped me figuring out a few things. Here is
an example of mine:

class MyOperatorData : public GvOperatorData {

typedef GvOperatorData super;


//| GvOperatorData Overrides

virtual Bool InitCalculation(GvNode* node, GvCalc* calc, GvRun* run) {
            if (!node || !calc || !run) return FALSE;
            if (!GvBuildValuesTable(node, m_values, calc, run, GV_EXISTING_PORTS)) {
                return FALSE;
            return super::InitCalculation(node, calc, run);

virtual void FreeCalculation(GvNode* node, GvCalc* calc) {
            GvFreeValuesTable(node, m_values);
            super::FreeCalculation(node, calc);

virtual Bool Calculate(GvNode* node, GvPort* outPort, GvRun* run, GvCalc* calc) {
            if (!node || !run || !calc) return FALSE;
            if (!GvCalculateInValuesTable(node, run, calc, m_values)) {
                return FALSE;

Bool index = 0;
            GvPort* indexPort = node->GetInPortFirstMainID(ID_MYPORT_INDEX);
            if (indexPort && indexPort->GetInteger(&index, run)) ;
            else {
                // Either work with index = 0 or stop calculation. Returning FALSE
                // will make the XPresso Node turn yellow!

// Limit the index.
            LONG count = GetFooBarArrayCountFromSomewhere();
            if (index < 0) index = 0;
            else if (index >= count) index = count - 1;

if (!outPort) {
                // If your node is an initiator, handle this step here. Eg. when
                // your input-ports should be directed to values on an object or
                // similar, you can retrieve the values here and fill in the object.
                // Example (imagine an array of objects that can be addressed via
                // via the index retrieved above) :

Real value = 0.0;
                GvPort* valuePort = node->GetInPortFirstMainID(ID_MYPORT_VALUE);
                if (valuePort && valuePort->GetReal(&value, run)) ;
                else {
                    // The port does either not exist or is not connected. If
                    // the port is described as an INPORT in the operator
                    // description resource, the value can even be retrieved when
                    // the port is not connected (since the value is defined in
                    // the Attributes Manager).
                    return FALSE;

Real* data = GetFooBarArrayFromSomewhere();
                data[index] = value;
                return TRUE;
            else {
                // Set the data for an output port.
                switch (outPort->GetMainID()) {
                    case ID_MYPORT_COUNT:
                        return outPort->SetInteger(count, run);

// If we reached this statement, something went wrong.
            return FALSE;


GvValuesInfo m_values;


On 03/07/2013 at 06:57, xxxxxxxx wrote:

GeDialog - Be careful with modal dialogs (platform differences)

Especially interesting for developers working on Windows only and giving the code away for
compilation or developers of Python plugins.

On OSX, a modal dialog does not have a close button in the title bar, unlike the windows modal
dialog! If you open a modal dialog on OSX without a hand-made close-button (simply add a Button
widget), you have to force quit Cinema since there is no way to close the window.

On 03/07/2013 at 09:10, xxxxxxxx wrote:

For modal dialogs, use the AddDlgGroup() with any of the following options OR'd together: DLG_OK and DLG_CANCEL.  And then handle them in the Command() method.  I know that this isn't the best solution, but it makes it easier to handle that bad situation in OSX.

On 14/07/2013 at 12:58, xxxxxxxx wrote:

MSVC vs. Clang : Differences

I thought I'd put things here that I came across while compiling plugins for Mac, written on Windows.
Though most of them might not be related to the C4D SDK at all, I think it is useful if you have at least
heard about them.

Context Macros :

The macros __FUNCTION__ and __PRETTY_FUNCTION__ are treated like string literals in MSVC and
GCC 3.3 (and earlier), but as of GCC 3.4, they are treated like variables. In MSVC and GCC 3.3, this
was possible:

GePrint(__FUNCTION__": something went wrong!");

This is not valid in GCC 3.4 any longer. (Clang is based on GCC)