Core Nodes Implementation

About

A core node is a basic node of Cinema 4D's node material system. It represents a basic functionality that can be used in a node material.

The relevant interfaces needed to implement custom core nodes are found in the corenodes.framework.

Implementation

A simple custom core node is implemented as follows:

// This example shows
#include "maxon/micronodes.h"
// core node class
class MaximumComponentCoreNode
{
public:
// input port "colora"
MAXON_PORT_INPUT(maxon::ColorA, colora);
// input port "colorb"
MAXON_PORT_INPUT(maxon::ColorA, colorb);
// output port "result"
MAXON_PORT_OUTPUT(maxon::ColorA, result);
class Impl : public maxon::corenodes::BasicMicroNode
{
public:
MAXON_ATTRIBUTE_FORCE_INLINE maxon::Result<void> Process(const Ports<colora, colorb, result>& ports) const
{
// access input port color
const maxon::ColorA& inputColorA = ports.colora();
const maxon::ColorA& inputColorB = ports.colorb();
// invert color
maxon::ColorA resultColor;
resultColor.r = maxon::Max(inputColorA.r, inputColorB.r);
resultColor.g = maxon::Max(inputColorA.g, inputColorB.g);
resultColor.b = maxon::Max(inputColorA.b, inputColorB.b);
resultColor.a = maxon::Max(inputColorA.a, inputColorB.a);
// store in result port
ports.result.Update(resultColor);
return maxon::OK;
}
};
static maxon::Result<void> Init(const maxon::corenodes::MicroNodeGroupRef& group)
{
return group.AddChild<Impl>();
}
};
using namespace maxon::corenodes;
// we choose pure registration, because the node has no lazy evaluation (and is evaluated from left to right).
MAXON_CORENODE_REGISTER_PURE(MaximumComponentCoreNode, "net.maxonexample.corenodes.examplenode");

Description

The description of the core node must be created with the Resource Editor.The new data type must have the ID of the core node.

The data type properties are:

  • Classification: "node"
  • Description Processor: "CoreNodeDescriptionProcessor"
  • Processor Parameters: The core node ID.
  • Menu Category: Select a category for the node.

The core node needs a new attribute:

  • Command: "include"
  • Identifier: "net.maxon.node.base"
  • Include: "net.maxon.node.base"

The name of the node is set with net.maxon.node.base.

Port descriptions are created with new attributes:

  • Command: "attribute"
  • Identifier: the port ID
  • Datatype: The port data type
  • Classification: "input" or "output"
  • Gui Type Id: The proper UI for that data type
  • Group Id: The proper group, either "net.maxon.node.base.group.inputs" or "net.maxon.node.base.group.outputs"
  • String: The name displayed in the UI.

Description Handling

The description of the core node must be loaded and handled properly:

// This example loads and handles the description database containing the core node description.
static maxon::BaseArray<maxon::GenericData> g_coreNodeDescriptions;
// the ID of the database storing the core node's description
static maxon::Id g_corenodesDatabaseId = maxon::Id { "net.maxonexample.corenodes" };
// function to process the description
static maxon::Result<void> HandleCoreNodeDescriptions(const maxon::Id& databaseId)
{
const maxon::LanguageRef language = maxon::LanguageRef();
for (const maxon::IdAndVersion& id : ids)
{
maxon::DataDescription description = maxon::DataDescriptionDatabaseInterface::LoadDescription(maxon::DATADESCRIPTION_CATEGORY_DATA, maxon::LanguageRef(), id.first) iferr_return;
maxon::DataDictionary info = description.GetInfo();
maxon::Id builderId = info.Get(maxon::DESCRIPTION::DATA::INFO::PROCESSOR, maxon::Id());
if (builderId.IsPopulated())
{
const maxon::DescriptionProcessor& processor = maxon::DescriptionProcessors::Get(builderId);
if (processor)
{
maxon::GenericData d = processor.Process(id.first, description) iferr_return;
g_coreNodeDescriptions.Append(std::move(d)) iferr_return;
}
}
}
return maxon::OK;
}
// load description
static maxon::Result<void> HandleInitializeModule()
{
{
err.CritStop();
return err;
};
// get plugin "res" folder
// get "nodes" folder within the "res" folder
const maxon::Url coreNodesResourceUrl = pluginDir.Append("nodes"_s) iferr_return;
// register database
// handle the core node description
HandleCoreNodeDescriptions(g_corenodesDatabaseId) iferr_return;
return maxon::OK;
}
// free description
static void HandleFreeModule()
{
g_coreNodeDescriptions.Reset();
}
MAXON_INITIALIZATION(HandleInitializeModule, HandleFreeModule);

This is an extended version of the typical procedure to load MAXON API descriptions. See Loading Data Descriptions.

Further Reading