Usually Cinema4D store settings for nodes and tools in a BaseContainer.
BaseContainer is very useful class that allow you to store different data type in easy way.
But you will notice there are some cases where Cinema don’t store parameter in BaseContainer, for example some of light and camera parameters are not reachable by Get/Set BaseContainer Methods.
So why? In most of cases this happen because the data is dependent from another node proprieties (for example object matrix) or the value have to be computed each time and is not useful to store it as value.
Anyhow the simplest way to Get/Set value for nodes or tools is to use GetParameter() or SetParameter() that will ensure the fact that BaseContainer based value will be stored in correct way and other non BaseContainer parameter will be properly handled.
Here a typical Get/Set call to BaseContainer:
BaseDocument* doc = GetActiveDocument(); if (doc) { BaseObject* op = doc->GetFirstObject(); if (op) { BaseContainer* bc = op->GetDataInstance(); if (!bc) { Real axisLen = bc->GetReal(ID_AXISLEN); // do some with axislen // set back the value to BaseContainer bc->SetReal(ID_AXISLEN, axisLen); //..... } } }
and here you can find the same call with Get/SetParameter:
BaseDocument* doc = GetActiveDocument(); if (doc) { BaseObject* op = doc->GetFirstObject(); if (op) { GeData d; // this is Cinema4D generic data container op->GetParameter(DescID(ID_AXISLEN), d, DESCFLAGS_GET_0); Real axisLen = d.GetReal(); // do some with axislen // set back the value to op op->SetParameter(DescID(ID_AXISLEN), GeData(axisLen), DESCFLAGS_SET_0); //..... } }
in the example you can see three main difference:
– Get/SetParameter use GeData that is the generic data container in cinema, it can hold all types including CustomDataType so you have to extract the correct data from it after retrieved;
– Get/SetParameter is called to the node so is not needed to get container from it
– Get/SetParameter use Descriptions
Also for your plugins is possible to handle parameters in this way if is needed, to achieve the result you have to use NodeData::GetDParameter() and NodeData::SetDParameter() during your plugin implementation.
The concept is to implement in GetDparameter() how the parameter have to be retrieved/calculated and in SetDParameter how the parameter should affect all the “linked values” when the user modify it.
Here a simple example where ID_AXISLEN parameter is the object’s z scale:
class MyObject : public ObjectData { INSTANCEOF(MyObject,ObjectData) public: virtual Bool Init(GeListNode *node) { return TRUE; } virtual Bool GetDParameter(GeListNode* node, const DescID& id, GeData& t_data, DESCFLAGS_GET& flags) { switch (id[0].id) { case ID_AXISLEN: { BaseObject* op = (BaseObject*)node; if (op) break; // get Object scale Vector opScale = op->GetAbsScale(); // pass z component to t_data t_data = GeData(opScale.z); // don't forget to set flags flags |= DESCFLAGS_GET_PARAM_GET; break; } } return SUPER::GetDParameter(node, id, t_data, flags); } virtual Bool SetDParameter(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_SET& flags) { switch (id[0].id) { case ID_AXISLEN: { BaseObject* op = (BaseObject*)node; if (op) break; // get Object scale Vector opScale = op->GetAbsScale(); // pass z component form t_data opScale = Vector(opScale.x, opScale.y, t_data.GetReal()); // set back the new scale to op op->SetAbsScale(opScale); // don't forget to set flags flags |= DESCFLAGS_SET_PARAM_SET; break; } } return SUPER::SetDParameter(node, id, t_data, flags); } static NodeData *Alloc(void) { return gNew MyObject; } };