Describes how to create a custom node space by implementing an interface and creating the required description with the Resource Editor. A node space defines what node types will be compatible with a node system.
Resource Editor
A custom node space requires description resources which must be loaded on the startup of Cinema 4D. In order to be able to create the required description files, Cinema 4D has to be launched with the following parameters:
- g_applicationRepositoryWritable=true
- g_developerNodeEditorFunctions=true
- g_descriptionEditorDeveloperMode=true
For successfully running a Cinema 4D instance to modify such a resource, one has to compile a work-in-progress state of a plugin which already does contain the database registration steps as described in Registering Node Databases. Then a Cinema 4D instance should be run with the required startup parameters and work-in-progress plugin registered. In such an instance the Resource Editor can be used to define and modify the resources related to a plugin. In order to create a custom node space with the Resource Editor, one has to take the following steps:
Switch the Resource Editor mode to "Developer Mode" in the menu. |
|
In "Database" select the custom database net.maxonexample.handbook.nodes.registereddatabase. The selected database should be the one registered for the plugin, as described in Registering Node Databases. |
|
Add a new data type by invoking "Data Type/Add Data Type" in the menu of the Resource Editor. |
|
In order to be distinguishable for Cinema 4D, all data types have to be identified with a unique identifier. "net.maxonexample.handbook.nodespace.node_renderer" will be the identifier used in this example. |
|
Once a data type has been defined, attributes can be defined for it by running the menu command "Attribute/Add Attribute/New". |
|
In a newly created attribute under the drop-down element "Command" the value "include" has to be selected. Where under the heading "Data", the value "Identifier" should then be set as "net.maxon.nodespace.base". This will include all the attributes that are defined in the data type net.maxon.nodespace.base; a predefined data type that is being shipped with Cinema 4D. |
|
Select "Data" and "String" as the attributes to be included for the newly defined data type. |
|
In the drop-down menu, "net.maxonexample.handbook.nodespace.node_renderer" has to be selected again in order to refresh the dialog and finalize including all attributes. The display name of a node space or its translations can be defined with the field "String" under the element-identifier "net.maxon.object.base.name". |
|
A database can be saved from the Resource Editor menu with "Database/Save All", writing the database that has been defined into JSON format. |
|
The node space can now be selected in the drop-down menu on the top left of the interface of Cinema 4D. |
|
Code
Now that a description for the node space has been defined, a NodeSystemClassInterface and NodeSpaceInterface can be implemented for it. Both need an unique identifier.
A NodeSystemClassInterface should be implemented and registered first:
class NodeRendererNodeSystemClassImpl :
public maxon::Component<NodeRendererNodeSystemClassImpl, maxon::nodes::NodeSystemClassInterface>
{
public:
{
if (idString.StartsWith("net.maxon"_s))
return true;
return super.SupportsImpl(templ);
}
{
return { };
}
};
Definition: objectbase.h:2651
static const Class< typename INTERFACE::Hxx1::ReferenceClass > & GetClass()
Definition: objectbase.h:2733
Definition: apibaseid.h:253
Definition: resultbase.h:766
Definition: string.h:1235
#define MAXON_COMPONENT(KIND,...)
Definition: objectbase.h:2212
#define MAXON_METHOD
Definition: interfacebase.h:1001
Followed by a node space implementation based on NodeSpaceInterface; which also has to be registered:
class NodeRendererNodeSpaceImpl :
public maxon::Component<NodeRendererNodeSpaceImpl, maxon::nodes::NodeSpaceInterface>
{
public:
private:
maxon::nodes::NodeSystemClass _class;
};
@ NORMAL
Samples the surface as the user moves over it the SculptObject and returns a new hit point and normal...
Now the node space has to be registered and unregistered. To do that, one can extend the previously created LoadResources() and FreeResources() functions. Make sure to register the NodeSpace after having registered the NodeSpace definition database. The node space identifier is defined in the description resource that has been defined earlier.
const maxon::Id spaceDescriptionId =
maxon::Id(
"net.maxonexample.handbook.nodespace.node_renderer");
maxon::nodes::NodeSpaceRef nodeRendererSpace = NodeRendererNodeSpaceImpl::CreateInit(nodeRendererData)
iferr_return;
g_exampleNodeSpace = maxon::nodes::MaterialNodeSpaces::Register(NodeRendererNodeSpaceImpl::GetDescriptor().GetId(), nodeRendererSpace)
iferr_return;
static MAXON_METHOD Result< DataDictionary > LoadDescription(const Id &spaceDescriptionId)
#define iferr_return
Definition: resultbase.h:1519
The global node space resource should be overwritten with a new maxon::GenericData instance when a node space is freed in the context of the macro MAXON_INITIALIZATION.
Definition: genericdata.h:20
Final Code
If all the steps have been followed, the code should look like this. The .h file
#ifndef _NODESPACE_H__
#define _NODESPACE_H__
static maxon::Id g_nodeRendererNodeSystemClass =
maxon::Id(
"net.maxonexample.handbook.class.noderenderernodesystemclass");
class NodeRendererNodeSystemClassImpl :
public maxon::Component<NodeRendererNodeSystemClassImpl, maxon::nodes::NodeSystemClassInterface>
{
public:
{
if (idString.StartsWith("net.maxon"_s))
return true;
return super.SupportsImpl(templ);
}
{
return { };
}
};
static maxon::Id g_nodeRendererNodespaceID =
maxon::Id(
"net.maxonexample.handbook.class.noderenderernodespace");
class NodeRendererNodeSpaceImpl :
public maxon::Component<NodeRendererNodeSpaceImpl, maxon::nodes::NodeSpaceInterface>
{
public:
private:
maxon::nodes::NodeSystemClass _class;
};
#endif
int32_t Int32
32 bit signed integer datatype.
Definition: apibase.h:176
#define MAXON_COMPONENT_CLASS_REGISTER(C,...)
Definition: objectbase.h:2409
#define MAXON_COMPONENT_OBJECT_REGISTER(C,...)
Definition: objectbase.h:2473
The .cpp file
static maxon::Result<void> ConfigurePreviewImageRequest(maxon::DataDictionaryObjectRef request)
{
request.Set(maxon::nodes::PREVIEWIMAGEREQUEST::PROVIDER, PreviewImageProviderExampleHandbook::GetClass())
iferr_return;
}
{
_class = NodeRendererNodeSystemClassImpl::GetClass().Create()
iferr_return;
spaceData.Set(maxon::nodes::NODESPACE::NODESYSTEMCLASS, _class)
iferr_return;
}
static maxon::Id g_nodeRendererDatabaseID =
maxon::Id(
"net.maxonexample.handbook.nodes.registereddatabase");
{
{
err.CritStop();
return err;
};
const maxon::Url& binaryUrl = maxon::g_maxon.GetUrl();
const maxon::Id spaceDescriptionId =
maxon::Id(
"net.maxonexample.handbook.nodespace.node_renderer");
maxon::nodes::NodeSpaceRef nodeRendererSpace = NodeRendererNodeSpaceImpl::CreateInit(nodeRendererData)
iferr_return;
g_exampleNodeSpace = maxon::nodes::MaterialNodeSpaces::Register(NodeRendererNodeSpaceImpl::GetDescriptor().GetId(), nodeRendererSpace)
iferr_return;
}
static void FreeResources()
{
{
err.CritStop();
return;
};
}
static MAXON_METHOD Result< void > RegisterDatabaseWithUrl(const Id &databaseId, const Url &url, const CString &version=CString::NullValue())
static MAXON_METHOD Result< void > UnregisterDatabase(const Id &databaseId)
return OK
Definition: apibase.h:2690
#define MAXON_INITIALIZATION(...)
Definition: module.h:795
#define iferr_scope_handler
Definition: resultbase.h:1402
#define iferr_scope
Definition: resultbase.h:1384