Common Plugin Concepts

About

Custom plugin classes are added to Cinema 4D using plugin hooks. A plugin class is derived from a base class and implements its virtual functions.

Warning
MAXON API plugin classes are based on interfaces. See Interface Basics.

Plugin Classes

This is how a typical plugin class looks like:

// A simple example generator object plugin class.
class ExampleGenerator : public ObjectData
{
INSTANCEOF(ExampleGenerator, ObjectData)
public:
static NodeData* Alloc(void) { return NewObjClear(ExampleGenerator); }
{
return true;
}
{
}
virtual Bool Message(GeListNode* node, Int32 type, void* data)
{
return SUPER::Message(node, type, data);
}
};
#define INSTANCEOF(X, Y)
Definition: c4d_baselist.h:38
Definition: c4d_baseobject.h:248
static BaseObject * Alloc(Int32 type)
Represents a C4DAtom that resides in a 4D list.
Definition: c4d_baselist.h:1976
Definition: c4d_baseobject.h:203
Definition: c4d_nodedata.h:40
virtual Bool Init(GeListNode *node, Bool isCloneInit)
virtual Bool Message(GeListNode *node, Int32 type, void *data)
Definition: c4d_objectdata.h:166
virtual BaseObject * GetVirtualObjects(BaseObject *op, const HierarchyHelp *hh)
maxon::Bool Bool
Definition: ge_sys_math.h:51
maxon::Int32 Int32
Definition: ge_sys_math.h:56
#define Onull
Null.
Definition: ge_prepass.h:1078
PyObject ** type
Definition: pycore_pyerrors.h:34
PyObject * op
Definition: object.h:520
Definition: node.h:10
  • The class is derived from a base class, in this case ObjectData which in return is derived from NodeData.
  • The INSTANCEOF macro defines a connection between the plugin class and the base class. Using this macro one can use the SUPER macro to call functions of the base class.
  • Specific plugin functionality is defined by implementing virtual functions.
  • A static "Alloc" function creates and returns a new instance of the plugin class. See also NodeData::Init() / Alloc and Free Manual.

Registration

Cinema 4D has to be informed about the new plugin class. This is typically done using a "Register" function. Examples are:

Such "Register" functions are typically used in a plugin's PluginStart() function. See PluginStart.

RegisterObjectPlugin(123456, "Example Generator", OBJECT_GENERATOR, ExampleGenerator::Alloc, "Oexamplegenerator", nullptr, 0);
Bool RegisterObjectPlugin(Int32 id, const maxon::String &str, Int32 info, DataAllocator *g, const maxon::String &description, BaseBitmap *icon, Int32 disklevel)
#define OBJECT_GENERATOR
Generator object. Produces a polygonal or spline representation on its own. (e.g. primitive cube)
Definition: ge_prepass.h:947

The arguments of a "Register" function vary from type to type but usually are:

  • Plugin ID: This ID must be unique and be obtained from www.plugincafe.com. For test purposes the ID range of 1000001 to 1000010 is available.
  • Plugin name: To avoid hardcoded strings it is advised to load a string from a resource file using GeLoadString().
  • Plugin flags: In this case OBJECT_GENERATOR which means that the registered class is a generator object.
  • Function pointer: A pointer to the function that allocates a new instance of the class.
  • Plugin symbol: This is used to identify the associated resource files.
  • Plugin icon: In this case a nullptr is handed over for no icon. A BaseBitmap for the icon can easily be loaded with AutoBitmap.
  • Plugin level: Defines a version of this plugin (handled in NodeData::Read() and NodeData::Write()).

These flags can be used in the "Register" function of all NodeData based plugin classes:

ShaderData plugins can be placed in the "Effects" or "Surfaces" submenu, MaterialData plugins can be placed in the "Shaders" menu. To place them there the category name has to be added to the plugin name that is used with the "Register" function.

Basic Classes and Plugin Classes

Many plugin classes are based on NodeData. But typical Cinema 4D classes are based on C4DAtom, GeListNode and BaseList2D. The NodeData based plugin class is used as the "core" of such C4DAtom based class and implements its functionality.

The NodeData "core" can be obtained from objects and within a NodeData based plugin class it is possible to get the corresponding GeListNode.

For convenience the corresponding GeListNode is also handed over in the virtual functions of NodeData.

The corresponding functions are:

NodeDataC4DAtom / GeListNode / BaseList2D
NodeData::Message()C4DAtom::Message()
NodeData::GetDEnabling()C4DAtom::GetEnabling()
NodeData::GetDDescription()C4DAtom::GetDescription()
NodeData::SetDParameter()C4DAtom::SetParameter()
NodeData::GetDParameter()C4DAtom::GetParameter()
NodeData::Read()C4DAtom::Read()
NodeData::Write()C4DAtom::Write()
NodeData::CopyTo()C4DAtom::CopyTo()
NodeData::IsInstanceOf()C4DAtom::IsInstanceOf()
NodeData::TranslateDescID()C4DAtom::TranslateDescID()
NodeData::GetDocument()GeListNode::GetDocument()
NodeData::GetBranchInfo()GeListNode::GetBranchInfo()
NodeData::IsDocumentRelated()GeListNode::IsDocumentRelated()
NodeData::GetBubbleHelp()BaseList2D::GetBubbleHelp()
Note
While most elements of the classic Cinema 4D API are build with the API and return a NodeData based class, some elements are not based on NodeData (like GUI elements).

Further Reading