I explored the idea of storing the runtime data as a field in the DNA of the node. So in DNA_node_types.h
, I add:
typedef struct NodeGeometryPizza {
// [...]
NodeGeometryPizzaRuntimeHandle *runtime;
} NodeGeometryPizza;
In order to define NodeGeometryPizzaRuntimeHandle
, I use the same workaround than for NodeDeclarationHandle
, at the beginning of the file (but I guess I could have simply set the type to void*):
/** Same workaround than for NodeDeclarationHandle. */
#ifdef __cplusplus
namespace blender::nodes::node_geo_pizza_cc{
class RuntimeData;
} // namespace blender::nodes::node_geo_pizza_cc
using NodeGeometryOpenMfxRuntimeHandle = blender::nodes::node_geo_pizza_cc::RuntimeData;
#else
typedef struct NodeGeometryOpenMfxRuntimeHandle NodeGeometryOpenMfxRuntimeHandle;
#endif
Then, in my node_geo_pizza.cc
file I can define the runtime data:
namespace blender::nodes::node_geo_pizza_cc {
class RuntimeData { /* [...] */ };
}
And regarding memory allocation, this requires me to change 3 callbacks, namely (i) init, (ii) free and (iii) copy:
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeGeometryPizza *data = MEM_cnew<NodeGeometryPizza>(__func__);
data->olive_count = 5;
data->runtime = MEM_new<RuntimeData>(__func__); // Alloc runtime data
node->storage = data;
}
static void node_free_storage(struct bNode *node)
{
NodeGeometryPizza &storage = node_storage(*node);
// If there is some runtime data, delete it
if (storage.runtime != nullptr) {
MEM_delete<RuntimeData>(storage.runtime);
storage.runtime = nullptr;
}
// Then call the regular free callback
node_free_standard_storage(node);
}
static void node_copy_storage(struct bNodeTree *dest_ntree,
struct bNode *dest_node,
const struct bNode *src_node)
{
// First copy the storage data using the standard callback
node_copy_standard_storage(dest_ntree, dest_node, src_node);
// Then duplicate runtime memory and call RuntimeData::operator=()
NodeGeometryOpenMfx &dest_storage = node_storage(*dest_node);
const NodeGeometryOpenMfx &src_storage = node_storage(*src_node);
dest_storage.runtime = MEM_new<RuntimeData>(__func__);
*dest_storage.runtime = *src_storage.runtime;
}
and in register_node_type_geo_pizza()
:
node_type_storage(&ntype,
"NodeGeometryPizza",
file_ns::node_free_storage,
file_ns::node_copy_storage);
PS The pizza-related naming assumes that this tutorial was used as a base.