Open Search
    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