Document copied for Picture viewer doesnt copy contents of child of a TagData
-
I am encountering a problem when rendering to picture viewer.
I have two plugins, a TagData and a NodeData as its child.
I also created a link from the TagData to the NodeData for easy access
However when the document is copied and sent to the picture viewer renderer there are two issues.- The link is not copied
- The contents of the NodeData basecontainer are not copied over
The copied TagData does have a child object with my type, so it does exist
Here is how I connect the two plugins
Bool MyTagData::Init(GeListNode* node, Bool isCloneInit) { BaseTag* tag = (BaseTag*)node; BaseContainer *data = tag->GetDataInstance(); BaseList2D* mynodedata= BaseList2D::Alloc(ID_MY_NODEDATA); // Creating my MyNodeData mynodedata->InsertUnderLast(node); //Add as mynodedata as a child to mytagdata data->SetLink(MYTAG_NODEDATA_INK, mynodedata); //Add link for easy access return true; }
This basically works in all situations, except when sending it to the picture viewer for rendering.
I feel like im missing something, but i cant find what in the documentation -
Hey you are not supposed to modify the scene graph during the init function.
Adding children to a tag while it may be possible is as far as I know not something done in Cinema 4D. so for optimization purpose I would not be surprised that they are never copied at all.With that's said I would recommend you to use a custom branch to store your BaseList2D as demonstrated in C++ SDK: Custom Branching Code Example .
In last case you should implement the CopyTo to properly copy your data when your node is copied. But again modifying the scene Graph during the Init is not the way to got.Cheers,
Maxime. -
Thanks for your reply m_adam
Thanks for providing the information that the init function should not modify the scene graph. Ill take this into account in the future.
I went through that example you linked, but Im a bit unclear why it is nessesary to manually create the handling of a custom and parallel nodegraph branch when plugin GeListNodes are already graphs themselves?
-
Hello @ECHekman,
Thanks for providing the information that the init function should not modify the scene graph. Ill take this into account in the future.
It is not only
NodeData::Init
but the majority ofNodeData
methods and the methods of derived classes that cannot modify the scene graph of a loaded document, as for example the scene graph they are attached to. The reason is that such methods, as for exampleNodeData::Init
,TagData:Execute
,ObjectData::GetVirtualObjects
, and many more, run in their own threads to parallelize scene execution. Modifying the scene graph of a loaded document from a non-main-thread (i.e., parallel) context can lead to race conditions and access violations and are therefore strictly forbidden. Forbidden are primarily allocations and deallocations, parameter get/set access is allowed (as long as it does not allocate or deallocate a pointed object) but also discouraged outside ofTagData::Execute
. For details, see Cinema 4D Threads Manual.I went through that example you linked, but I' m a bit unclear why it is necessary to manually create the handling of a custom and parallel nodegraph branch when plugin GeListNodes are already graphs themselves?
I am not quite sure how you mean 'parallel', but a
GeListNode
implements both hierarchal (i.e., tree) relations withInsertUnder, GetUp, GetDown, GetNext
etc. and arbitrary (i.e., graph) relations withGetBranchInfo
. The hierarchy of a node type, e.g.,Obase
- aBaseObject
orTmytag
- your tag class, are always meant to be of the same type and follow the conventions of their base class. Tags are not meant to have children. You must implement your own branch to declare your own non-hierarchical relation between your plugin tag and your basic node.The workaround Maxime suggested, just implementing
NodeData::CopyTo
is unfortunately not valid.First of all, you must always implement all three serialization functions
Read
,Write
, andCopyTo
, you can never only implement only one of them.But storing nodes irregularly in this manner can lead to access violations as Cinema 4D is then not aware that this quasi-branch exists and might try to execute multiple things at once (via
NodeData::GetAccessedObjects
), leading to read/write access violations. Moreover, I am fairly sure that this might lead to event or call starvation when Cinema finds there such a danglingBaseList2D
(NodeData
) instance under yourBaseTag
(TagData
). Or even worse, it will ignore completely it in some contexts, because tags are not supposed to have children.You must implement a branch in your case, I would recommend following the SDK example as it is slightly cleaner than the forum preview Maxime linked to.
Cheers,
Ferdinand