![]() |
smgl 0.11.0
Structured Metadata Engine and Graph Objects Library
|
Implementing a custom smgl::Node requires a few simple steps. In the following steps, we'll implement a custom node from scratch which calculates the sum of two inputs.
First, our custom node type should inherit from smgl::Node:
Nodes in a graph communicate with each other via ports. When a node has been updated, all of its output ports signal their downstream connections that new data is available. When an input port receives new data, the node is queued for updates. To ensure proper serialization, all ports should be registered with the Node metadata system in the class constructor:
Every smgl::Node has a std::function member object named compute which is executed whenever the node is updated by the graph scheduler. To define your node's computation behavior, assign a lambda function or function reference to smgl::Node::compute, generally in the class constructor:
To enable serialization and deserialization for your node, override the virtual member functions smgl::Node::serialize_ and smgl::Node::deserialize_:
Overriding these methods enables a node's state to be (de)serialized, but the node type must also be registered with the global factory so that smgl::Graph::Load can reconstruct it. Register types with the SMGL_NODE macro, which captures the type's source spelling as its serialization key. Always fully-qualify the type: the key is part of the node's serialization identity and must be spelled identically everywhere the type is registered.
Upgrading a project from the older RegisterNode<T>() auto-naming API? See Migrating Node registration to source-token naming.
The smgl::Metadata class is a dict-like type which provides easy serialization of many built-in types to the JSON format used by smgl. For data which is not easily serialized to JSON, every smgl::Node can request that smgl create a cache directory where arbitrary data can be saved and loaded during (de)serialization.
There are two methods for indicating that your custom node will need a cache directory. If your class will always write to the cache directory during serialization, call the smgl::Node::Node(bool) constructor when defining your constructor implementation:
This sets smgl::Node::usesCacheDir to return the value passed to the Node constructor. If your class conditionally uses the cache directory based on program state, assign an appropriate test function to smgl::Node::usesCacheDir:
If smgl::Node::usesCacheDir returns true, the cacheDir directory passed to smgl::Node::serialize_ is guaranteed to exist. Add custom serialization code to your serialization functions to write/read data to/from this location:
Below is a full implementation of a templated SumNode: