ObjectData Modify Description[SOLVED]

On 02/06/2015 at 14:07, xxxxxxxx wrote:

User Information:
Cinema 4D Version:   R16 
Platform:   Windows  ;   Mac OSX  ; 
Language(s) :     C++  ;

Hello Forum,

I'm working on an ObjectData plugin that generates geometry based on child splines.  Some attributes in the Attributes Manager need to be enabled/disabled and min/max values need to be set based on the number of child splines.

For example:
The generator object has a count of 5 child splines.
I have a LONG attribute named "Special Splines."
"Special Splines" should always have a max value of (child splines count - 2);
The user changes "Special Splines" from 0 to 3.
I catch this in ObjectData::GetDDescription() and set min/max accordingly. 
"Special Splines" now has a max value of 3 and it's value is 3.
All good.
Now the user deletes one of the child splines.
"Special Splines" should now have a max value of 2 and be reset to a value of 2.

The only virtual functions i can find that are called when the user adds/deletes the child splines are ObjectData::GetVirtualObjects() and ObjectData::Message().  The type for Message(GeListNode *node, Int32 type, void *data) is MSG_GETCUSTOMICON or MSG_GETREALCAMERADATA.

The SDK states that no scene modifications can take place in GetVirtualObjects().  Is changing op's container or parameters considered a scene modification?

MSG_GETCUSTOMICON and MSG_GETREALCAMERADATA do not seem like the appropriate places to modify op's container or parameters.

Where can I safely update the op's container or parameters when the number of child splines change.

Thank you,

Joe Buck

On 02/06/2015 at 14:43, xxxxxxxx wrote:

in your ObjectData subclass, create a data member, update it in ObjectData::GetVirtualObjects() as needed.
use this data member to update description inside ::GetDDescription()

check LookAtCamera.cpp SDK example

On 02/06/2015 at 16:21, xxxxxxxx wrote:

Thanks for checking this out for me, but I don't think GetDDescription() is called when children are deleted.  Perhaps I do not understand your solution or I did not make my question clear(I have now edited original question to help).

I'm looking for some virtual function that is called when child objects are added or removed and where it is safe to modify op's container or parameters.


Joe Buck

On 02/06/2015 at 23:46, xxxxxxxx wrote:

I believe I have partially solved this issue by using a tag.

As an exception, modifications are allowed that change the object's parameters like position, or anything set through NodeData::SetDParameter(). However this should only be done by tags (expressions) and not by generator objects.

When child objects are added or removed from op, the tag can execute before GVO and modify op's parameters as needed.  However, I'm using C4DAtom::SetParameter() not NodeData::SetDParameter.  Is this still safe?  I have tested without crashes.

Is it possible to modify an object's description from a tag?  I would still like to modify the description's min/max values when the child count changes.  Is this totally hacky?

This is another rookie question: after re-reading the above quote from the SDK, how do you call a virtual function like NodeData::SetDParameter() from a tag on its object?

Thank you,

Joe Buck

On 03/06/2015 at 05:19, xxxxxxxx wrote:

tag got 2 functions that get called, ::SetDParameter() "here you can modify tag parameters"
and ::Execute() "here you can modify object parameters"

On 03/06/2015 at 11:57, xxxxxxxx wrote:

Thanks Mohamed.

ObjectData::Execute() was not getting called because I did not have OBJECT_CALL_ADDEXECUTION set in RegisterObjectPlugin().  This is a cleaner solution and now I get the virtual function calls I was looking for in this order:

  1. ObjectData::AddToExecution() EXECUTIONPRIORITY_INITIAL
  2. ObjectData::Execute()
  3. ObjectData::GetVirtualObjects()

Now I think I understand your initial suggestion better.  I'm trying to make the modifying children and changing a parameter the same experience for the user.  So now I will try to:

  1. React to user changes in Execute() by changing parameters and store data for min/max values in class members.
  2. Build object with new parameters in GetVirtualObjects().
  3. Modify Description min/max in GetDDescription() based on data members and present to user the next time they access the ObjectPlugin.

Sound right?  I'll try it out this afternoon.

Now back to the SDK docs...  What is the difference between modifying parameters in ObjectData::Execute() and TagData::Execute()?  The docs state that this should only happen with TagData.


Joe Buck

On 04/06/2015 at 05:59, xxxxxxxx wrote:

Hi Joe,

you are progressing a bit too fast for me :blush:
On your question how to call a virtual function like NodeData::SetDParameter() :
All nodes derived from NodeData (ObjectData,...) internally consist of two classes. One derived from BaseData represents basically the parameter side of the node, the other derived from BaseList2D (or rather C4DAtom) is used to handle the node within the scene.
In your tag you have a BaseObject pointer. In order to use SetDParameter() you need to get the "data representation" of the object. This is done via GetNodeData() and then you can call SetDParameter(), like so:

NodeData* nd = op->GetNodeData();
nd->SetDParameter(op, descId, GeData(whatever), flag);

I was wondering, why you would want to to do so. But I guess, by now you don't care anymore, either.

I am still looking for a good explanation, why SetParameter() should be used in Execute() of tags, only.
But as I believe, that the restriction wasn't written there for fun, I recommend to have a look into the "Core Messages" section of the threading article. You can use the given example pretty much directly to transfer your parameter setting from Execute() into the main thread.

On 04/06/2015 at 09:40, xxxxxxxx wrote:

Mr Block,

Originally posted by xxxxxxxx

by now you don't care anymore

I care. I care. I really do!!:joy:

Thanks for the great explanation.  I did not really want to do this.  I wanted to know if there was a difference between calling C4DAtom::SetParameter() and NodeData::SetDParameter().  The docs stated you should only use SetDParameter() and I was using SetParameter().

I wasn't trying to waste your time.  After the SetDParameter() question was answered, I planned on asking more rookie questions:

Is it possible to call NodeData::GetDDescription?  How would you get a pointer to the Description?  It appears that C4DAtom::GetDescription() only gets a copy of the description.

I will try the "Core Messages" route this afternoon.

Thanks for your help.

Joe Buck

On 08/06/2015 at 17:18, xxxxxxxx wrote:

Let's consider this closed.  My latest question was answered by Robert in a previous this post:

I'll take his word for it since he always seems to know what he is talking about.


Joe Buck

On 09/06/2015 at 05:53, xxxxxxxx wrote:

Hi Joe,

glad you found your answers. Just for completeness sake:
You asked:

What is the difference between modifying parameters in ObjectData::Execute() and TagData::Execute()?  The docs state that this should only happen with TagData.

You can use SetParameter() in ObjectData::Execute() as well. But you should make sure to do this on EXECUTIONPRIORITY_EXPRESSION. Later (e.g. EXECUTIONPRIORITY_GENERATOR, this is when the generator objects are build) you should not use SetParameter() anymore, as it could lead to constant rebuilding of caches or mismatching values in Attribute Manager.
Also note, this is the only exception to the rule, where you may change the scene from within a generator object plugin.

I'll change it in the docs accordingly.

On 09/06/2015 at 09:14, xxxxxxxx wrote:

Updated last post, after reconnecting with our development.

On 09/06/2015 at 09:39, xxxxxxxx wrote:

Thanks for figuring this out.  Any official information given about the pipeline sequence and cache is invaluable.

Joe Buck