Proving Default Graph Setups

Table of Contents

Describes how to implement a default state for a node graph.

The default state of a node graph determines what nodes, with which values and connections, will be contained by default in a newly created graph. A custom node called net.maxonexample.handbook.noderenderer.usernode_shade is used in this example and must be created to provide expected functionality.

Code

To implement a default state, a function has to be created that will provide this default setup by creating the required nodes, setting the values and making the port connections. This function has to be registered in NodeRendererNodeSpaceImpl::Init().

static maxon::Result<void> CreateMaterialGraphDefaultSetup(const maxon::nodes::NodesGraphModelRef& graph)
{
// Instantiate a node that only has a description, but no process function.
maxon::nodes::NodeTemplate userNodeSystem = maxon::nodes::NodesLib::LoadTemplate(maxon::AssetInterface::GetBuiltinRepository(), maxon::Id("net.maxonexample.handbook.noderenderer.usernode")) iferr_return;
maxon::GraphNode userGraphNode = graph.AddChild(maxon::Id("user node instance"), userNodeSystem) iferr_return;
maxon::nodes::NodeTemplate shaderNodeSystem = maxon::nodes::NodesLib::LoadTemplate(maxon::AssetInterface::GetBuiltinRepository(), maxon::Id("net.maxonexample.handbook.noderenderer.usernode_shade")) iferr_return;
maxon::GraphNode shaderNode = graph.AddChild(maxon::Id("shader node instance"), shaderNodeSystem) iferr_return;
// Connect the two instances.
maxon::GraphNode outPort = userGraphNode.GetOutputs().FindChild(maxon::Id("net.maxonexample.handbook.node.usernode.out")) iferr_return;
maxon::GraphNode inPort = shaderNode.GetInputs().FindChild(maxon::Id("usernode_shade.colorA")) iferr_return;
outPort.Connect(inPort) iferr_return;
// Replace the default value for the first instance.
maxon::GraphNode valuePort = shaderNode.GetInputs().FindChild(maxon::Id("usernode_shade.colorB")) iferr_return;
valuePort.SetDefaultValue(maxon::Data(maxon::ColorA(1.0, 1.0, 0.0, 1.0))) iferr_return;
return maxon::OK;
}
static MAXON_METHOD const AssetRepositoryRef & GetBuiltinRepository()
Definition: apibaseid.h:253
static MAXON_METHOD Result< NodeTemplate > LoadTemplate(const AssetRepositoryRef &repo, const Id &assetId)
OK
Ok.
Definition: ge_prepass.h:0
Col4< Float, 1 > ColorA
Definition: vector4d.h:60
The maxon namespace contains all declarations of the MAXON API.
Definition: autoweight.h:14
Definition: animation_attributes.h:10
#define iferr_scope
Definition: resultbase.h:1384
#define iferr_return
Definition: resultbase.h:1519
Definition: node.h:10

This function then has to be written to the DataDictionary of the node space as a callback for providing a default setup.

// Defines the callback function that will create the default setup for the graph.
spaceData.Set(maxon::nodes::NODESPACE::CREATEMATERIALGRAPHFUNC, maxon::nodes::NODESPACE::CreateMaterialGraphFunc(CreateMaterialGraphDefaultSetup)) iferr_return;
Definition: delegate.h:240

Final Code

If all the steps have been followed, the code should look like the following:

#include "maxon/module.h"
#include "maxon/nodeslib.h"
static maxon::nodes::NodeSystemClass g_nodeSystemClass;
// This description processor has to be used for all nodes of the example namespace unless they register themselves at the BuiltinNodes registry (such as DynamicNode).
MAXON_DECLARATION_REGISTER(maxon::DescriptionProcessors, "net.maxonexample.handbook.nodespace.noderendererprocessor")
{
return maxon::nodes::NodesLib::CreateNodeDescriptionProcessor([] (const maxon::Id& descriptionId, const maxon::DataDescription& dataDescription) -> maxon::Result<maxon::nodes::NodeTemplate>
{
{
return maxon::nodes::NodesLib::BuildNodeFromDescription(descriptionId, g_nodeSystemClass);
}, g_nodeSystemClass);
});
}
static maxon::Result<void> CreateMaterialGraphDefaultSetup(const maxon::nodes::NodesGraphModelRef& graph)
{
// Instantiate a node that only has a description, but no process function.
maxon::nodes::NodeTemplate userNodeSystem = maxon::nodes::NodesLib::LoadTemplate(maxon::AssetInterface::GetBuiltinRepository(), maxon::Id("net.maxonexample.handbook.noderenderer.usernode")) iferr_return;
maxon::GraphNode userGraphNode = graph.AddChild(maxon::Id("user node instance"), userNodeSystem) iferr_return;
maxon::nodes::NodeTemplate shaderNodeSystem = maxon::nodes::NodesLib::LoadTemplate(maxon::AssetInterface::GetBuiltinRepository(), maxon::Id("net.maxonexample.handbook.noderenderer.usernode_shade")) iferr_return;
maxon::GraphNode shaderNode = graph.AddChild(maxon::Id("shader node instance"), shaderNodeSystem) iferr_return;
// Connect the two instances.
maxon::GraphNode outPort = userGraphNode.GetOutputs().FindChild(maxon::Id("net.maxonexample.handbook.node.usernode.out")) iferr_return;
maxon::GraphNode inPort = shaderNode.GetInputs().FindChild(maxon::Id("usernode_shade.colorA")) iferr_return;
outPort.Connect(inPort) iferr_return;
// Replace the default value for the first instance.
maxon::GraphNode valuePort = shaderNode.GetInputs().FindChild(maxon::Id("usernode_shade.colorB")) iferr_return;
valuePort.SetDefaultValue(maxon::Data(maxon::ColorA(1.0, 1.0, 0.0, 1.0))) iferr_return;
return maxon::OK;
}
static maxon::Result<void> ConfigurePreviewImageRequest(maxon::DataDictionaryObjectRef request)
{
request.Set(maxon::nodes::PREVIEWIMAGEREQUEST::PROVIDER, PreviewImageProviderExampleHandbook::GetClass()) iferr_return;
return maxon::OK;
}
MAXON_METHOD maxon::Result<void> NodeRendererNodeSpaceImpl::Init(maxon::DataDictionary spaceData)
{
_class = NodeRendererNodeSystemClassImpl::GetClass().Create() iferr_return;
spaceData.Set(maxon::nodes::NODESPACE::NODESYSTEMCLASS, _class) iferr_return;
// Defines the End Node for this node systems
maxon::BaseArray<maxon::Id> materialEndNodeIds;
// Define the node we want to be defined as the end node.
materialEndNodeIds.Append(maxon::Id("net.maxonexample.handbook.noderenderer.usernode_shade")) iferr_return;
// Define the information in the DataDictionnary.
spaceData.Set(maxon::nodes::NODESPACE::MATERIALENDNODEIDS, std::move(materialEndNodeIds)) iferr_return;
// Defines the supported render
// Create a BaseArray that store the supporter's engine ID.
maxon::BaseArray<maxon::Int> supportedRenderers;
// Here, g_nodeRendererId is the ID of a render engine.
supportedRenderers.Append(g_nodeRendererId) iferr_return;
supportedRenderers.Append(1023342) iferr_return;
supportedRenderers.Append(0) iferr_return;
// Add the array in the DataDictionnary.
spaceData.Set(maxon::nodes::NODESPACE::RENDERERS, std::move(supportedRenderers)) iferr_return;
// Defines the callback function that will create the default setup for the graph.
spaceData.Set(maxon::nodes::NODESPACE::CREATEMATERIALGRAPHFUNC, maxon::nodes::NODESPACE::CreateMaterialGraphFunc(CreateMaterialGraphDefaultSetup)) iferr_return;
super.Init(spaceData) iferr_return;
return maxon::OK;
}
static maxon::Id g_nodeRendererDatabaseID = maxon::Id("net.maxonexample.handbook.nodes.registereddatabase");
static maxon::GenericData g_exampleNodeSpace;
static maxon::Result<void> LoadResources()
{
{
err.CritStop();
return err;
};
// Get plugin location
const maxon::Url& binaryUrl = maxon::g_maxon.GetUrl();
// Get plugin folder
maxon::Url pluginDir = binaryUrl.GetDirectory();
// Get resource folder (this folder must exist)
const maxon::Url resourceUrl = pluginDir.Append("res"_s).Append("nodes"_s) iferr_return;
// Register database
// Register the node space
// Use the same ID as in the resource files
const maxon::Id spaceDescriptionId = maxon::Id("net.maxonexample.handbook.nodespace.node_renderer");
// Load the description
maxon::DataDictionary nodeRendererData = maxon::nodes::NodeSpaceHelpersInterface::LoadDescription(spaceDescriptionId) iferr_return;
maxon::nodes::NodeSpaceRef nodeRendererSpace = NodeRendererNodeSpaceImpl::CreateInit(nodeRendererData) iferr_return;
// Register the node space implementation
g_exampleNodeSpace = maxon::nodes::MaterialNodeSpaces::Register(NodeRendererNodeSpaceImpl::GetDescriptor().GetId(), nodeRendererSpace) iferr_return;
return maxon::OK;
}
static void FreeResources()
{
{
err.CritStop();
return;
};
// Unregister a database
g_exampleNodeSpace = maxon::GenericData();
g_nodeSystemClass = nullptr;
}
MAXON_INITIALIZATION(LoadResources, FreeResources);
MAXON_ATTRIBUTE_FORCE_INLINE ResultRef< T > Append(ARG &&x)
Definition: basearray.h:677
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
Definition: url.h:952
static MAXON_METHOD Result< DataDictionary > LoadDescription(const Id &spaceDescriptionId)
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={})
return OK
Definition: apibase.h:2690
#define MAXON_DECLARATION_REGISTER(...)
Definition: module.h:933
#define MAXON_INITIALIZATION(...)
Definition: module.h:795
#define MAXON_METHOD
Definition: interfacebase.h:1001
#define iferr_scope_handler
Definition: resultbase.h:1402