Reading and Modifying Node Graphs

Provides an overview of modifying a graph. The graph stores selection, connection, and muting information for which both read and write access is being provided.

Transaction

The graph access relies on a database access model. To modify a graph, a transaction has to be started, bundling a set of operations. The modification operations are not being carried out until the transaction has been finalized. This finalization operation is called a commit. Transactions can be validated and rolled back, reversing all changes made within a transaction. The transaction logic also ensures a well-formed graph, as when an operation error occurs, the transaction will not be committed and therefore the previously made operations are not going to be applied. Important functions for modifying a graph under this model are:

A change list in this database model is a collection of operations carried out under a transaction. Change lists can be stored to apply changes again to same graph or to a completely different graph.

Access Selections

Information about selection states in a graph is being stored in a DataDictionary. The information can be stored on the root or group level.

Get the Selected Elements

// Return all the selected node in the graph
nodeGraph.GetSelectedTrueNodes([](const maxon::GraphNode& node) -> maxon::Result<Bool>
{
ApplicationOutput("this node @ is selected", node);
return true;
// Return all the selected ports in the graph
nodeGraph.GetSelectedPorts([](const maxon::GraphNode& port) -> maxon::Result<Bool>
{
ApplicationOutput("this port @ is selected", port);
return true;
// Get the selected wire from the graph.
nodeGraph.GetSelectedWires([](const maxon::GraphNode& source, const maxon::GraphNode& dest, const maxon::Wires& wire) -> maxon::Result<Bool>
{
ApplicationOutput("this wire @ is selected, it connects port @ and port @", wire, source, dest);
return true;

Set the Selected Elements

// Select an element.
// As the Graph is going to be modified, we need to encapsulate our modification inside a transaction.
graphNodeTransaction = nodeGraph.BeginTransaction() iferr_return;
// Select a True Node
nodeGraph.SelectTrueNode(colorGraphNode) iferr_return;
// Select a Port
nodeGraph.SelectPort(colorOutPort) iferr_return;
// Select a Wire
nodeGraph.SelectWire(colorOutPort, colorBlendIn1) iferr_return;
// Commit the transaction and make all modification permanent
graphNodeTransaction.Commit() iferr_return;

Handling a Connection

Two ports can be connected with different wire types, representing a connection. These wires convey information between ports. For more information on wires see maxon::Wires.

Adding a Connection

Add a connection between two ports.

// Connect ports is as easy as defining the first and the second port.
colorOutPort.Connect(colorBlendIn1) iferr_return;

Removing a Connection

// Disconnect some ports
// Remove all connections
colorOutPort.RemoveAllConnections() iferr_return;
// Remove all connections in one direction
color2OutPort.RemoveConnections(maxon::PORT_DIR::OUTPUT, maxon::Wires::All()) iferr_return;

Bypassing and Muting

Information can disabled or hidden without completely removing it with bypassing and muting.

Bypassing a Node

A node can be bypassed.

// Find the port that will contain the Boolean to bypass a node.
const maxon::GraphNode port = colorBlendOut.GetInputs().FindChild(maxon::NODE::BYPASSABLE::BYPASS) iferr_return;
if (port.IsValid())
{
maxon::GraphTransaction transaction = port.GetGraph().BeginTransaction() iferr_return;
transaction.Commit() iferr_return;
}

Muting a Connection

A connection can be muted.

// Mute All connections for the color node
// As we are changing the node itself, we need to begin a transaction
maxon::GraphTransaction transaction = nodeGraph.BeginTransaction() iferr_return;
// MuteConnectionWith can be used with one node or a port.
colorGraphNode.MuteConnectionWith(port) iferr_return;
transaction.Commit() iferr_return;

Muting a Port

To mute a port, it's required to mute all the connection of this port.

// Mute all connection for all port on a node.
colorGraphNode.MuteAllConnections(maxon::PORT_DIR::OUTPUT) iferr_return;
colorGraphNode.MuteAllConnections(maxon::PORT_DIR::INPUT) iferr_return;
// Mute all connection for one port.
colorBlendOut.MuteAllConnections(maxon::PORT_DIR::OUTPUT) iferr_return;

Animation Data

Animation data for a graph is not stored in the graph itself, but with the CTrack objects attached to a BaseList2D object associated with the graph. That BaseList2D can be obtained from the NodeMaterial class.

Reading Animation Data

To read animation data, first the special BaseList2D object has to be retrieved which contains the animation tracks. To access those tracks, it's required to know their DescID. See DescID Manual for more information about DescID.

static maxon::Result<void> ReadAnimationData(BaseDocument* doc)
{
// Retrieve the first material
BaseMaterial* material = doc->GetFirstMaterial();
if (!material->IsNodeBased())
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
NodeMaterial* myMaterial = static_cast<NodeMaterial*>(material);
const maxon::Id currentNodeSpaceID = GetActiveNodeSpaceId();
const maxon::NimbusBaseRef nimbusRef = myMaterial->GetNimbusRef(currentNodeSpaceID);
if (nimbusRef == nullptr)
return maxon::NullptrError(MAXON_SOURCE_LOCATION);
const maxon::nodes::NodesGraphModelRef& nodeGraph = nimbusRef.GetGraph();
// Retrieve the end node of this material
const maxon::NodePath endNodePath = nimbusRef.GetPath(maxon::NIMBUS_PATH::MATERIALENDNODE);
if (endNodePath.IsEmpty())
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
const maxon::GraphNode endNode = nodeGraph.GetNode(endNodePath);
if (!endNode.IsValid())
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
const maxon::NodePath transparencyRelativePath = maxon::NodePath::FromCString("transparency") iferr_return ;
maxon::NodePath transparencyPortPath = (endNodePath + transparencyRelativePath) iferr_return;
const maxon::GraphNode transparencyPort = nodeGraph.GetNode(transparencyPortPath);
if (!transparencyPort.IsValid())
return maxon::UnknownError(MAXON_SOURCE_LOCATION);
// Transparency.
// Get base DescID
DescID portDescID;
nimbusRef.GetDescID(transparencyPort, portDescID) iferr_return;
// Get BaseList2D object storing the animation tracks
const BaseList2D* const listElement = myMaterial->GetBaseListForNode(currentNodeSpaceID, transparencyPortPath) iferr_return;
BaseList2D* const listElementNonConst = const_cast<BaseList2D*>(listElement);
if (listElementNonConst != nullptr)
{
// Get track type
const maxon::Int32 type = portDescID[-1].dtype;
// If COLORA, access sub-tracks
if (type == DTYPE_COLORA)
{
// Add the sub-track Desc Level.
CTrack* const track = listElementNonConst->FindCTrack(portDescID + DescLevel(COLORA_B, DTYPE_REAL, 0));
if (track != nullptr)
{
// Get current time
const BaseTime now = doc->GetTime();
// Get track name and current value
const maxon::String name = track->GetName();
const maxon::Float value = track->GetValue(doc, now);
DiagnosticOutput(" Track: @, Value: @", name, value);
}
}
}
return maxon::OK;
}

Writing Animation Data

Writing animation data follows the same principle as reading animation data from a node system. Once it has been retrieved the Baselist2D object and its tracks, keyframes can be modified or added as with tracks for any other Baselist2D. See CTrack Manual for more information.

Getting and Setting Values

For each attribute, a GraphNode stores two values: one for the default values and another to store the modified values. For ports, the values of that data are being stored in the default parameter. This is why the value of data stored inside a port has to be accessed with the function maxon::GraphNodeFunctions::SetDefaultValue or maxon::GraphNodeFunctions::GetDefaultValue.

Next example reads the values of all attributes of a node.

Note
This will not read any default values for attributes, but only values that have been actively set.

Next example sets the name of a GraphNode. To retrieve the value of an attribute, use maxon::GraphNodeFunctions::GetValue.

Note
GetValue can return an empty value if the parameter has not been set.
// Access different attributes values.
const maxon::String name = endNode.GetValue<decltype(maxon::NODE::BASE::NAME)>().GetValueOrNull() iferr_return;
const maxon::IdAndVersion assetId = endNode.GetValue<decltype(maxon::NODE::ATTRIBUTE::ASSETID)>().GetValueOrNull() iferr_return;
const maxon::Id repositoryID = endNode.GetValue<decltype(maxon::NODE::ATTRIBUTE::REPOSITORYID)>().GetValueOrNull() iferr_return;
const maxon::Id assetVersion = endNode.GetValue<decltype(maxon::NODE::BASE::ASSETVERSION)>().GetValueOrNull() iferr_return;
const maxon::String comment = endNode.GetValue<decltype(maxon::NODE::BASE::COMMENT)>().GetValueOrNull() iferr_return;
const maxon::InternedId category = endNode.GetValue<decltype(maxon::NODE::BASE::CATEGORY)>().GetValueOrNull() iferr_return;
ApplicationOutput(" name: @", name);
// Start a transaction to be able to modify a node attributes.
maxon::GraphTransaction graphNodeTransaction = nodeGraph.BeginTransaction() iferr_return;
endNode.SetValue<decltype(maxon::NODE::BASE::NAME)>("My name is !!"_s) iferr_return;
graphNodeTransaction.Commit() iferr_return;

Next example defines the data value stored inside a port, using maxon::GraphNodeFunctions::SetDefaultValue

// Begin a transaction to change the data value of a port.
graphNodeTransaction = nodeGraph.BeginTransaction() iferr_return;
// Find the ports.
maxon::GraphNode enableTransparency = endNode.GetInputs().FindChild(maxon::RENDER::NODE::MATERIAL::ENABLETRANSPARENCY) iferr_return;
// Set the value of the data.
enableTransparency.SetDefaultValue(true) iferr_return;
transparency.SetDefaultValue(maxon::Color(1, 0, 0)) iferr_return;
graphNodeTransaction.Commit() iferr_return;
// Retrieve the data value of the port.
const Bool transparencyIsEnable = enableTransparency.GetDefaultValue(false) iferr_return;
ApplicationOutput("The transparency parameter enable is set to @", transparencyIsEnable);
maxon::GraphNodeFunctions::SetDefaultValue
Result< Bool > SetDefaultValue(T &&value) const
Definition: graph.h:1801
maxon::GraphNode::GetGraph
const GraphModelRef & GetGraph() const
Definition: graph.h:2239
maxon::Wires
Definition: graph.h:102
maxon::GraphNodeFunctions::GetValues
Result< void > GetValues(GraphAttributeInterface::FLAGS mask, GraphAttributeMap &map) const
Definition: graph.h:1625
BaseList2D
Definition: c4d_baselist.h:2174
maxon::GraphNodeFunctions::SetValue
Result< Bool > SetValue(const InternedId &attr, ForwardingDataPtr &&value, Bool checkAndInvalidate=true) const
Definition: graph.h:1738
BaseTime
Definition: c4d_basetime.h:24
maxon::GraphAttributeInterface::FLAGS::MESSAGE_MASK
@ MESSAGE_MASK
Use this mask to test for WARNING or ERROR.
maxon::GraphAttributeInterface::FLAGS::USER_STATE
@ USER_STATE
maxon::GraphTransaction::Commit
Result< void > Commit(const DataDictionary &userData=GetPtrSizedZeroRef< DataDictionary >(), Bool validate=true)
COLORA_B
@ COLORA_B
B component.
Definition: lib_description.h:230
maxon::GraphNodeFunctions::GetChildren
Result< Bool > GetChildren(const ValueReceiver< const GraphNode & > &callback, NODE_KIND mask=NODE_KIND::ALL_MASK) const
Definition: graph.h:1265
maxon::GraphNode::IsValid
Bool IsValid() const
Definition: graph.h:2210
DTYPE_COLORA
@ DTYPE_COLORA
Color with Alpha.
Definition: lib_description.h:77
maxon
The maxon namespace contains all declarations of the MAXON API.
Definition: c4d_basedocument.h:15
DescID
Definition: lib_description.h:327
maxon::Tuple< Id, Id >
maxon::PORT_DIR::INPUT
@ INPUT
Input direction, i.e., an input port or an incoming connection.
BaseList2D::IsNodeBased
Bool IsNodeBased() const
maxon::GraphAttributeInterface::FLAGS::META
@ META
maxon::Wires::All
static constexpr Wires All(WIRE_MODE mode=WIRE_MODE::ALL)
Definition: graph.h:184
BaseDocument::GetFirstMaterial
BaseMaterial * GetFirstMaterial(void)
maxon::String
Definition: string.h:1206
maxon::OK
return OK
Definition: apibase.h:2547
GetActiveNodeSpaceId
maxon::Id GetActiveNodeSpaceId()
maxon::Id
Definition: apibaseid.h:250
iferr_return
#define iferr_return
Definition: resultbase.h:1434
MAXON_SOURCE_LOCATION
#define MAXON_SOURCE_LOCATION
Definition: memoryallocationbase.h:66
maxon::Float
Float64 Float
Definition: apibase.h:198
BaseList2D::FindCTrack
CTrack * FindCTrack(const DescID &id)
maxon::NIMBUS_PATH::MATERIALENDNODE
@ MATERIALENDNODE
Path of the material end node.
DiagnosticOutput
#define DiagnosticOutput(formatString,...)
Definition: debugdiagnostics.h:166
CTrack
Definition: c4d_canimation.h:659
CTrack::GetValue
Float GetValue(BaseDocument *doc, const BaseTime &time)
Definition: c4d_canimation.h:844
maxon::GraphNodeFunctions::GetValue
Result< ConstDataPtr > GetValue(const InternedId &attr, const DataType &expectedType) const
Definition: graph.h:1661
maxon::Result
Definition: apibase.h:319
BaseDocument::GetTime
BaseTime GetTime(void) const
maxon::Int32
int32_t Int32
32 bit signed integer datatype.
Definition: apibase.h:177
DescLevel
Represents a level within a DescID.
Definition: lib_description.h:286
iferr_scope
#define iferr_scope
Definition: resultbase.h:1343
maxon::GraphAttributeInterface::FLAGS
FLAGS
Definition: graphattribs.h:89
maxon::GraphAttributeInterface::FLAGS::TRANSIENT
@ TRANSIENT
The attribute is transient (non-persistent, i.e., not stored by serialization).
TRANSPARENCY
TRANSPARENCY
Transparencies/alphas for in-between objects will be evaluated.
Definition: ge_prepass.h:3346
GetNode
GvNode * GetNode(GeListNode *bn)
Definition: c4d_graphview.h:2795
maxon::PORT_DIR::OUTPUT
@ OUTPUT
Output direction, i.e., an output port or an outgoing connection.
maxon::GraphAttributeInterface::FLAGS::TYPE_MASK
@ TYPE_MASK
Use this mask to test for the type (one of DIRECT, DERIVED, USER_STATE or DERIVED|USER_STATE).
maxon::HashMap
Definition: hashmap.h:1114
ApplicationOutput
#define ApplicationOutput(formatString,...)
Definition: debugdiagnostics.h:207
maxon::Col3< Float, 1 >
maxon::InternedId
Definition: datatypelib.h:26
NodeMaterial
Definition: c4d_basematerial.h:390
maxon::GraphNodeFunctions::GetInputs
Result< typename SFINAEHelper< GraphNode, BASE >::type > GetInputs() const
Definition: graph.h:1298
BaseList2D::GetNimbusRef
maxon::NimbusForwardRef GetNimbusRef(const maxon::Id &spaceId) const
maxon::GraphAttributeInterface::FLAGS::ROOT
@ ROOT
Bool
maxon::Bool Bool
Definition: ge_sys_math.h:55
maxon::GraphAttributeInterface::FLAGS::IMMUTABLE
@ IMMUTABLE
The attribute value can only be set once on creation of the node or port.
BaseList2D::GetName
String GetName() const
Definition: c4d_baselist.h:2348
maxon::GraphTransaction
Definition: graph.h:1083
DTYPE_REAL
@ DTYPE_REAL
Float
Definition: lib_description.h:68
maxon::GraphNodeFunctions::GetDefaultValue
Result< const T & > GetDefaultValue(const T &def=maxon::NullValue< const T & >()) const
Definition: graph.h:1817
BaseMaterial
Definition: c4d_basematerial.h:27
BaseDocument
Definition: c4d_basedocument.h:490
maxon::GraphNode
Definition: graph.h:2196