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
    • Login

    Setting node dirty does not trigger an update.

    Cinema 4D SDK
    r21 c++
    3
    18
    2.3k
    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.
    • ManuelM
      Manuel
      last edited by

      Hi,

      GetDDescription is called by cinema 4D if the UI need any update. Setting the nodeData dirty could not be enough in certain cases.
      How do you determine if GetDDescription have been called or not?
      Sharing some code would help us to reproduce the issue.

      Cheers,
      Manuel

      MAXON SDK Specialist

      MAXON Registered Developer

      1 Reply Last reply Reply Quote 0
      • O
        Ogers
        last edited by Ogers

        This post is deleted!
        1 Reply Last reply Reply Quote 0
        • O
          Ogers
          last edited by

          Hello, here is a part of the code I am using.
          Note that my RenderSettings class is inherited from VideoPostData

          static const Int32 DLRenderFinished = 10000;
          
          
          Bool RenderSettings::Init(GeListNode* i_node)
          {
          	render_started = false;
          	return TRUE;
          }
          
          
          Bool RenderSettings::GetDDescription(GeListNode* i_node, Description* i_description, DESCFLAGS_DESC& i_flags)
          {
          	i_description->LoadDescription(ID_RENDERSETTINGS);
          
          	const DescID* singleid = i_description->GetSingleDescID();
          	const Int32 ID = DL_RENDER_BUTTON;
          	const DescID cid = DescLevel(ID, DTYPE_BUTTON, 0);
          
          	if (!singleid || cid.IsPartOf(*singleid, nullptr))
          	{
          		BaseContainer bc = GetCustomDataTypeDefault(DTYPE_BUTTON);
          
          		bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON);
          		if (render_started)
          			bc.SetString(DESC_NAME, "Stop Render"_s);
          		else
          			bc.SetString(DESC_NAME, "Start Render"_s);
          
          		i_description->SetParameter(cid, bc, DescLevel(ID_OBJECTPROPERTIES));
          	}
          	i_flags |= DESCFLAGS_DESC::LOADED;
          	return SUPER::GetDDescription(i_node, i_description, i_flags);
          }
          
          
          Bool RenderSettings::Message(GeListNode* i_node, Int32 i_type, void* i_data)
          {
          	switch (i_type) 
          	{
          	case MSG_DESCRIPTION_COMMAND: 
          	{
          		DescriptionCommand* dc = (DescriptionCommand*) i_data;
          		const Int32 id = dc->_descId[0].id;
          
          		if (id == DL_RENDER_BUTTON)
          		{
          			//Start rendering and show stop render button
          			render_started = true;
          			SpecialEventAdd(DL_START_RENDER);
          			i_node->SetDirty(DIRTYFLAGS::DESCRIPTION);
          		}
          		break;
          	}
          	
          	case DLRenderFinished:
                         //DLRenderFinished is executed successfully when rendering is finished, but this does not trigger an update on the UI.
          		render_started= false;
          		i_node->SetDirty(DIRTYFLAGS::DESCRIPTION);
          		break;
          	}
          	return SUPER::Message(i_node, i_type, i_data);
          }
          

          Thank you.

          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by Manuel

            Hi,

            when you register your videopostdata, you need to define a description resource file see [RegisterVideoPostPlugin.] (https://developers.maxon.net/docs/cpp/2023_2/c4d__videopostdata_8h.html#a331d072052d737de4730f4a6ea9020cb) Otherwise, the function GetDDescription will never be called.

            In GetDDescription, you can than load the dummy resource file and add your button defining the parent to "ID_VIDEOPOSTPROPERTIES" and not ID_OBJECTPROPERTIES.

            Bool PC13401::GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags)
            {
            	if (!description->LoadDescription(node->GetType()))
            		return false;
            
            
            	const DescID* singleid = description->GetSingleDescID();
            	const DescID cid = DescLevel(g_LaunchButtonID, DTYPE_BUTTON, 0);
            
            	if (!singleid || cid.IsPartOf(*singleid, nullptr))
            	{
            		BaseContainer bc = GetCustomDataTypeDefault(DTYPE_BUTTON);
            
            		bc.SetInt32(DESC_CUSTOMGUI, CUSTOMGUI_BUTTON);
            		if (_render_started)
            			bc.SetString(DESC_NAME, "Stop Render"_s);
            		else
            			bc.SetString(DESC_NAME, "Start Render"_s);
            
            		description->SetParameter(cid, bc, DescLevel(ID_VIDEOPOSTPROPERTIES));
            	}
            
            	flags |= DESCFLAGS_DESC::LOADED;
            	return NodeData::GetDDescription(node, description, flags);
            }
            // .....
            
            // in my message function:
            	i_node->SetDirty(DIRTYFLAGS::DESCRIPTION);
            	_render_started = !_render_started;
            
            

            Cheers,
            Manuel

            MAXON SDK Specialist

            MAXON Registered Developer

            O 1 Reply Last reply Reply Quote 0
            • O
              Ogers @Manuel
              last edited by

              Hello,
              Yes, I am aware of that part, I had already registered my VideoPost Plugin and ID_RENDERSETTINGS is the plugin ID I am using for that (Loading it on GetDDescription which loads fine), but I had not included register function on my sample code.

              Also, GetDDescription is being called when I click the 'render' button on my Render Settings (VideoPost) but the problem is that it does not get called when the rendering has finished (for this to happen I don't interact with the UI at all), but only set my node dirty, thinking it would automatically trigger GetDDescription function to be called.

              Defined the parent to 'ID_VIDEOPOSTPROPERTIES' as suggested but this did not help too.

              Thank you.

              1 Reply Last reply Reply Quote 0
              • ManuelM
                Manuel
                last edited by

                Hi,

                Sorry i'm not able to reproduce that issue, it's working fine here.
                Could you provide the RegisterVideoPostPlugin function and how you send the message to the VP?

                Cheers,
                Manuel

                MAXON SDK Specialist

                MAXON Registered Developer

                O 1 Reply Last reply Reply Quote 0
                • O
                  Ogers @Manuel
                  last edited by Ogers

                  Hello, here is the code.

                  Bool Register3DelightPlugin(void)
                  {
                  	return RegisterVideoPostPlugin(ID_RENDERSETTINGS, "3Delight"_s, PLUGINFLAG_VIDEOPOST_ISRENDERER, RenderSettings::Alloc, "dlrendersettings"_s,  0, 0);
                  }
                  

                  The message is sent through RenderManager which is inherited from Message Data.

                  Bool RenderManager::CoreMessage(Int32 id, const BaseContainer& bc)
                  {
                  //This is executed when rendering has finished.
                  	if (id == DL_FRAME_COMPLETED) 
                  	{
                  		ApplicationOutput("Frame has completed Rendering");
                  		BaseDocument* doc = GetActiveDocument();
                  	
                  		RenderData* rd = doc->GetActiveRenderData();
                  		bool has_vp = false;
                  		BaseVideoPost* vp = rd->GetFirstVideoPost();
                  		
                  		while (vp != NULL && !has_vp) 
                  		{
                  			has_vp = (vp->GetType() == ID_RENDERSETTINGS); // Look for rendersettings
                  
                  			if (!has_vp) 
                  			{
                  				vp = vp->GetNext();
                  			}
                  		}
                  
                  		if (has_vp) 
                  		{
                  //Message to VP is sent correctly. This triggers the RenderSettings::Message function for case DLRenderFinished.
                  			vp->Message(DLRenderFinished);
                  		}
                  		StatusSetText(String(""));
                  		parser = 0x0;
                  		RenderNextFrame();
                  	} 
                         return TRUE;
                  }
                  
                  1 Reply Last reply Reply Quote 0
                  • ManuelM
                    Manuel
                    last edited by

                    Hi,
                    Sorry I'm probably missing something.

                    I'm using R21.023, what's your version?
                    What if you drag and drop the VP into the python console and add .Message(DLRenderFinished) ? (of course, the number itself must be used and not DLRenderFinished)

                    I'm wondering if there's not a thread issue now.

                    Cheers,
                    Manuel

                    MAXON SDK Specialist

                    MAXON Registered Developer

                    1 Reply Last reply Reply Quote 0
                    • O
                      Ogers
                      last edited by

                      Hello,
                      I am using R21.027.
                      From python console, it worked fine. After setting the node dirty, getDDescription function got executed. But I wonder what is different as the same event is being executed when the rendering finishes and the node is set Dirty except that getDDescription does not get executed after.

                      1 Reply Last reply Reply Quote 0
                      • ManuelM
                        Manuel
                        last edited by

                        Hi,
                        Cool we are progressing 😄
                        Can you try something like that? This will execute the call to message directly in the MainThread.

                        if (has_vp)
                        {
                           maxon::ExecuteOnMainThread([]()
                             {
                               vp->Message(DLRenderFinished);
                             }
                           );
                        }
                        

                        Cheers,
                        Manuel

                        MAXON SDK Specialist

                        MAXON Registered Developer

                        1 Reply Last reply Reply Quote 0
                        • O
                          Ogers
                          last edited by

                          Hello,
                          Tried that by still the same :/.

                          Thanks,
                          Ogers.

                          1 Reply Last reply Reply Quote 0
                          • ferdinandF
                            ferdinand
                            last edited by

                            Hello @everyone,

                            don't mind me, this is just a slightly bored myself surfing on private time and did not read the thread in its entirety. But what stands out to me is that you do this in your RenderManger::CoreMessage:

                            BaseDocument* doc = GetActiveDocument();
                            

                            Is there actually a guarantee that your render manager will only render the active document? And when you use the rendering logic provided by Cinema, the active document and rendering document will be two different documents, even when the rendering was spawned for the active document, because for rendering, a document is being cloned. So, unless this is intentional, you might be operating on the wrong document there, because as I do understand, this message of yours is coming in from a node/something in the rendered document.

                            Just pointing this out because it is a common pitfall in the Cinema 4D SDK.

                            Cheers,
                            Ferdinand

                            MAXON SDK Specialist
                            developers.maxon.net

                            1 Reply Last reply Reply Quote 0
                            • O
                              Ogers
                              last edited by Ogers

                              Hello,

                              BaseDocument* doc = GetActiveDocument();
                              BaseDocument* renderdoc = (BaseDocument*) doc->GetClone(COPYFLAGS::DOCUMENT, nullptr);
                              
                              RenderData* rd = renderdoc->GetActiveRenderData();
                              

                              If this is what you mean for getting the rendering document, I am using this way on my original code. I am not sure if the issue is related to this.

                              Cheers,
                              Ogers

                              1 Reply Last reply Reply Quote 0
                              • ManuelM
                                Manuel
                                last edited by

                                Hi,

                                as the VideoPostData is inside the current document, it's right to retrieve the current document. But as Ferdinand said, that's a common pitfall.

                                I was able to reproduce the issue. Using the Console automatically add an EventAdd(). That's why it was working using the console. If you send the message with the script manager, it will not work.

                                So, you have to "force" the UI update with an EventAdd(). SetDirty only set the VideoPostData dirty but doesn't trigger a UI update.
                                As it's the end of the render, the scene should not have changed too much and the redraw shouldn't take too much time.

                                	case DLRenderFinished:
                                		{
                                			//DLRenderFinished is executed successfully when rendering is finished, but this does not trigger an update on the UI.
                                			_render_started = false;
                                			i_node->SetDirty(DIRTYFLAGS::DESCRIPTION);
                                			EventAdd();
                                			break;
                                		}
                                

                                Just one question, that's strange to launch the render from the render preferences. Is that the final workflow?

                                Cheers,
                                Manuel

                                MAXON SDK Specialist

                                MAXON Registered Developer

                                O 1 Reply Last reply Reply Quote 0
                                • O
                                  Ogers @Manuel
                                  last edited by Ogers

                                  Hello,
                                  Trying to "force" the UI update using EventAdd() after setting the node dirty still does not trigger GetDDescription function. I thought this was what I was missing but seems there is something else.

                                  I am not 100% sure if it will be the final workflow, but for now, that's our intention. We are trying to keep a uniform UI on all DCCs (as in the image below) and this way has proven to be efficient.
                                  Of course, this will not be the only way to launch a render, but if we see it to be efficient in Cinema4D too then yes this will also be a way we will keep.
                                  Unfortunately, our C4D plugin is too far away from other plugins that we support on other DCCs, and there's still a lot to do.

                                  As for the buttons' workflow, it would be:
                                  Clicking Render will set the button to Abort Render and make the other two buttons insensitive until rendering finishes (that is why I want to update the UI after rendering is finished), or abort render is clicked which this updates the UI fine.

                                  The same goes for the other two buttons (Start IPR -> Abort IPR and make the other two buttons insensitive until you abort it).

                                  a6afe6b4-f6e3-481e-bb85-cdcfa0bb9049-image.png

                                  Cheers,
                                  Ogers

                                  1 Reply Last reply Reply Quote 0
                                  • ManuelM
                                    Manuel
                                    last edited by

                                    Hi,

                                    I tried again to reproduce this issue but i can't. Would be interesting to send us some of your code using our mailbox [email protected]

                                    Cheers,
                                    Manuel

                                    MAXON SDK Specialist

                                    MAXON Registered Developer

                                    1 Reply Last reply Reply Quote 0
                                    • ferdinandF
                                      ferdinand
                                      last edited by

                                      Hello @Ogers,

                                      without any further questions, we will consider this topic as solved by Monday, the 25th and flag it accordingly.

                                      Thank you for your understanding,
                                      Ferdinand

                                      MAXON SDK Specialist
                                      developers.maxon.net

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