Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login

    Animatable control not working (DESC_ANIMATE_ON)

    Cinema 4D SDK
    c++ 2023
    2
    3
    518
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • WTools3DW
      WTools3D
      last edited by

      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);
      
      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        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

        1 Reply Last reply Reply Quote 1
        • WTools3DW
          WTools3D
          last edited by

          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

          1 Reply Last reply Reply Quote 0
          • First post
            Last post