Animatable control not working (DESC_ANIMATE_ON)

Hi.
I am struggling to update existing plugins to be animatable.
Plugins are geometry generator derived from ObjectData.
Panel is generated with GetDDescription() callback.
And internal data are handled via GetDParameter() and SetDParameter() callbacks.

Below is simplified example.
I need to animate the internal parameter (Float m_value).
It doesn't work when set to DESC_ANIMATE_ON.
Animation of Value parameter appears in panel with the animate diamond icon, but it doesn't switch to red state when clicking on it.

1d6b4d01-6e6a-4d0a-b220-b7d0ab2ec025-image.png

#define CTL_VAL_ID	1001
//===========================================================================================================
// class
//===========================================================================================================
class TestData : public ObjectData
{
	INSTANCEOF(TestData, ObjectData);		// Cinema4D hierarchy	
public:
	// create
	static NodeData* Create() { return NewObjClear(TestData); }

	//----------------------------------------------------------
	// DATA
	//----------------------------------------------------------
	Float	m_value = 15;

	//----------------------------------------------------------	
	// panel
	//----------------------------------------------------------
	Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags)
	{
		// validation
		if (node == nullptr || description == nullptr)			return false;
		// load the description for Obase
		if (description->LoadDescription(Obase) == false)		return false;

		// load all parameters
		if (description->GetSingleDescID() == nullptr)
		{
			//
			const DescID cid = DescLevel(CTL_VAL_ID, DTYPE_REAL, 0);
			//---------------------------------------------------------------------
			BaseContainer bc = GetCustomDataTypeDefault(DTYPE_REAL);
			//---------------------------------------------
			bc.SetInt32(DESC_UNIT, e_CtlUnitType::flt);
			bc.SetString(DESC_NAME, String("Value: "));
			bc.SetInt32(DESC_SCALEH, 1);
			//---------------------------------------------		
			// animate ON
			bc.SetInt32(DESC_ANIMATE, DESC_ANIMATE_ON);
			//---------------------------------------------
			// set parameter
			description->SetParameter(cid, bc, DescLevel(ID_OBJECTPROPERTIES));
		}

		// controls loaded into tool description
		flags |= DESCFLAGS_DESC::LOADED;


		// base	class
		return SUPER::GetDDescription(node, description, flags);
	}
	//----------------------------------------------------------
	Bool GetDParameter(GeListNode* node, const DescID& id, GeData& t_data, DESCFLAGS_GET& flags) override
	{
		// shortcuts		
		BaseContainer* bc = static_cast<BaseObject*>(node)->GetDataInstance();

		//-----------------------------------------
		// parameter value to bc (get from bc)		
		if (CTL_VAL_ID == id[0].id)
		{
			bc->SetFloat(CTL_VAL_ID, m_value);
			return true;
		}
		//---------------------
		// base
		return SUPER::GetDParameter(node, id, t_data, flags);
	}
	//----------------------------------------------------------
	Bool SetDParameter(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_SET& flags) override
	{
		//-----------------------------------------
		// parameter value from bc (set in bc)
		C4dControls controls(t_data);
		if (CTL_VAL_ID == id[0].id)
		{
			m_value	= t_data.GetFloat();
			return true;
		}
		//-----------------------------------------
		// base
		return SUPER::SetDParameter(node, id, t_data, flags);
	}
};

RegisterObjectPlugin(1060016, String("#$44 Test Nurbs"), OBJECT_GENERATOR | OBJECT_USECACHECOLOR, TestData::Create, maxon::String(""), nullptr, 0);

hi,
thanks for your question. GetDDescription can be called for a single parameter. In your code, you are simply not checking if the single parameter is your "value" parameter. I cannot dig into the code to really understand why this is blocking the creation of the track, but this is the issue.

@wtools3d said in Animatable control not working (DESC_ANIMATE_ON):

if (description->GetSingleDescID() == nullptr)

This part should be replaced by a better check

const DescID* singleid = description->GetSingleDescID();
const DescID cid = DescLevel(CTL_VAL_ID, DTYPE_REAL, 0);
if (!singleid || cid.IsPartOf(*singleid, nullptr))
{
    BaseContainer bc = GetCustomDataTypeDefault(DTYPE_REAL);
    // etc ......

One more remark, as m_value is a class parameter, be aware that you might need to implement Read/Write/CopyTo functions so the parameter is correctly loaded, saved, or copied. In your case, i do not understand why you are copying the value to this parameter but i got the feeling that if you save your document and load it back the values stored in the base container will be override by the default one (15).

Cheers,
Manuel

MAXON SDK Specialist

MAXON Registered Developer

Yes, this condition was the issue!
It was a copy-paste part from some C4D example without deeper thinking.
Now it works as expected also with animations!

Regarding the value as a class parameter, it is of course handled for read-write copy.
Our plugins are ported into more applications not just for C4D. Using its own data management so that's why the Get-Set callback are used.

Thank you for your quick and useful help, as usual 🙂

Regards,
Viktor