Custom user nodes are containers of data created with the resource editor in Cinema 4D and provide a functionality similar to resource descriptions in the Classic API. A custom user node does not provide any logic, but is only a container for data. The logic for a node is being provided by a core node which can be connected to a custom user node. But that is not mandatory since a custom user node can also exist on its own. Such a node will then act like a dummy node, representing a set of data. For example, a texture node will hold some information - the texture path, the first frame, the last frame, and the result - but will just output that data without processing it.
Code
The following code is needed register the Description Processors that will be able to create and register the templates or our core nodes:
static maxon::nodes::NodeSystemClass g_nodeSystemClass;
{
{
{
}, g_nodeSystemClass);
});
}
Definition: apibaseid.h:253
Definition: resultbase.h:766
static MAXON_METHOD Result< NodeTemplate > CreateLazyTemplate(const Id &nodeId, Delegate< Result< NodeTemplate >()> &&creator, Delegate< Result< Bool >(const NodeSystemClass &cls)> &&support={})
static MAXON_METHOD Result< DescriptionProcessor > CreateNodeDescriptionProcessor(Delegate< Result< NodeTemplate >(const Id &descriptionId, const DataDescription &dataDescription)> &&delegate)
static MAXON_METHOD Result< NodeSystemBasedNodeTemplate > BuildNodeFromDescription(const Id &id, const NodeSystemClass &nodeClass, Bool addDependencies=true, const Delegate< Result< void >(const MutableRoot &root, const TemplateArguments &args)> &finalizer={})
#define MAXON_DECLARATION_REGISTER(...)
Definition: module.h:933
Resource Editor
The string identifiers defined in the resource editor can be exported to symbol definitions in the form of header files.
This has the advantage that the identifiers themselves can change over the development of a plugin, while their references in code, the symbols, do not have to. There are two options for generating such header files.
- Writing header files: When running Cinema 4D with the startup argument g_autoExportHeaderPaths="{name_of_the_file}.h", modifications to a node database with the Resource Editor can be reflected in the header file defined in the startup argument. This write operation still has to be manually invoked and will write the identifiers of the database that are not being ignored into a header file.
- Comparison tools: When running Cinema 4D with the startup argument g_externalCompareTool="{absolute_path_to}\{application}", modifications to a node database with the Resource Editor can be reflected with a comparison tool. Instead of writing the non-ignored identifiers to a specified file, a temporary file will be created that will the be opened alongside the original file in the comparison tool.
To use this feature, compile the plugin, start Cinema 4D and open the Resource Editor.
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.net.maxonexample.handbook.nodes.registereddatabase |
|
Add a new data type by invoking "Data Type/Add Data Type" in the menu of the Resource Editor. |
|
Set the data type identifier to "net.maxonexample.handbook.noderenderer.usernode" |
|
Once a data type has been defined, attributes can be defined for it by running the menu command "Attribute/Add Attribute/New". |
|
In the new attribute, select "Command/Include" and set the field "Identifier" as "net.maxon.node.base". Check "Data", "UI" and "String". Select "net.maxonexample.handbook.noderenderer.usernode" again, in order to update the Resource Editor. This will include different attributes:
- "net.maxon.object.base.name" defines the name of the node.
- "net.maxon.object.base.tags" defines the tags which describe the node in the Asset Browser.
- "net.maxon.object.base.annotations" defines the annotation of the node in the Asset Browser.
|
|
To export the header for this node, the attribute we just included has to be ignored. We have to do this because the identifier, "net.maxon.object.base", is one provided by Cinema 4D and therefore already has a symbol; which can be found as maxon::NODE::BASE in nodes_corenodes_base.h. An attribute can be ignored by checking the field "Ignore on Header Export" in the "Development" tab of the attribute. |
|
Now the settings for exporting identifiers have to be defined. Clear the selection of the tree view by clicking into an empty area of the gadget and then in the view on the right:
- Select "node" in "Classification",
- set "Description Processor" to "net.maxonexample.handbook.nodespace.noderendererprocessor",
- set "Menu Category" to "Uncategorized",
- and select the header file to which the identifiers should be exported to with "Include file".
|
|
Now a new attribute can be defined which will be exported:
- Set "Command" to "attribute",
- set "Identifier" to "net.maxonexample.handbook.node.usernode.out",
- select "Yes", when an "Invalid Identifier" warning message box opens,
- set "Datatype" to maxon::ColorA,
- set "Classification" to "output",
- set "Default Value" to some color,
- set "String" to "Result".
|
|
Once a file has been generated, the following information has to be added:
- A header guard,
- some includes, at least "maxon/fid.h", so that Maxon macros and data types can be used,
- at the end of the file, but before the header guard #endif, add an include-statement to include the files generated by the source processor for the node-project.
#include "<name_of_the_file>1.hxx"
#include "<name_of_the_file>2.hxx"
|
Final Code
If all steps have been followed, the code should look like the following:
static maxon::nodes::NodeSystemClass g_nodeSystemClass;
{
{
{
}, g_nodeSystemClass);
});
}
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;
};
g_nodeSystemClass = nullptr;
}
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)
Definition: genericdata.h:20
static MAXON_METHOD Result< DataDictionary > LoadDescription(const Id &spaceDescriptionId)
return OK
Definition: apibase.h:2690
#define MAXON_INITIALIZATION(...)
Definition: module.h:795
#define MAXON_METHOD
Definition: interfacebase.h:1001
#define iferr_scope_handler
Definition: resultbase.h:1402
#define iferr_scope
Definition: resultbase.h:1384
#define iferr_return
Definition: resultbase.h:1519