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

    SpecialEventAdd unpredictable timing to GUI::Command

    Cinema 4D SDK
    c++ r21
    4
    11
    1.2k
    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.
    • P
      PluginStudent
      last edited by

      Shouldn't you catch core messages by implementing GeDialog::CoreMessage()?

      SpecialEventAdd() adds a message to an event queue, which is processed at some point. So I don't think you can force that to process the message synchronously.

      If you somehow want to update the UI, there is GeUpdateUI(). But I don't know if that is synchronous or not.

      1 Reply Last reply Reply Quote 0
      • J
        JuicyJuggles
        last edited by

        Your totally right!

        I actually do catch it in Bool GUI::CoreMessage(Int32 id, const BaseContainer &bc).
        Basically yes i want to force it synchronously =(

        If i wanted to try GeUpdateUI() i think i would have the same issue because inside where I catch the message then I call SetString(DLG_DYNAMIC_RENDER_TEXT, "text"_s); so the message needs to still come before GeUpdateUI() i think.

        Should I update the UI with a different function then call GeUpdateUI() .

        ApplicationOutput(); has the same issue. Its like the way to get synchronous output is writing to a file but then I cant see it in realtime.

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

          Hi,

          I think it would be best if you would provide some (dummy) code to illustrate what you are doing, because there multiple things that remain unclear (at least to me).

          1. Normally you should not have to worry about updating a GeDialog at all, unless it contains a custom gadget that has not been implemented properly. Modifying the values / objects of your gadgets should update the dialog automatically.
          2. The phrasing "in my main thread" is somewhat ambiguous. Are you referring to the main thread of Cinema 4D with that or the thread of your application in which you perform the more expensive computations? If the latter is the case, all GUI calls from this thread will be ignored by Cinema 4D.
          3. Although this has not been revealed by Maxon officiallly, it seems very likely that also Cinema 4D is executing a main event loop. You marking something to be redrawn will never be executed immediately, but only when you are back in the redraw state of that loop. Everything else would be wildly inefficient - think of hundreds of elements all invoking their own redraw. If your app makes this processes sluggish, you have to execute the computationally expensive parts of your code in a thread other than Cinema's main thread, i.e. make it non-blocking for the main-loop.
          4. The way you (and @PluginStudent) are using the word "synchronously" confuses me a bit. Messages in Cinema 4D are being processed synchronously to the context they are being called in (which is usually the main thread). Synchronously means "in a blocking manner" or "with non-overlapping bars" for a process diagram. So I assume you both actually mean asynchronously, but invoking a message asynchronously to the context you are currently in won't change much, because GUI operations will still be executed synchronously with the main thread of Cinema 4D. Which in turn will come full circle when the original context/thread you spawned the message from was the main thread of Cinema 4D.

          Cheers,
          zipit

          MAXON SDK Specialist
          developers.maxon.net

          1 Reply Last reply Reply Quote 0
          • J
            JuicyJuggles
            last edited by JuicyJuggles

            Hi Zipit - sorry it took time to get back to this. Here is some sample code that I hope shows what i am trying to do. in the ZoomInOut function i want the SpecialEventAdd(); message to be caught by GUI::CoreMessage before the second for loop in in ZoomInOut starts.

            In GUI::CoreMessage I catch the SpecialEventAdd(); message and call SetString(DLG_DYNAMIC_RENDER_TEXT, "test changed text"_s); which does change the AddStaticText dialog on my panel, but it doesnt update until after the second for loop.

            1. Do you see something I have implemented wrong? When I am not doing lots of draw calls its does update without having to do anything.
            2. I mean the main application thread. I cant implement a second thread because as I understand only the main application thread can make draw calls.
            3. I agree about your theory of a main a loop running and the draw call is executed at intervals. All the draw calls do make the app sluggish. My intent is to time how long the draw calls take so sluggish may be expected and have to draw in the main loop so it will be blocking but that is okay for my use.
            4. I think we were expecting that when you call SpecialEventAdd(); that would be caught by GUI::CoreMessage which calls AddStaticText() and then would continue after SpecialEventAdd(); where more draw calls are. But since I think your right about a loop in C4D itself the GUI::CoreMessage part of the loop isnt called when there are draw calls in the "queue". Maybe looking for a way to force it synchronously
            /////main.cpp///// 
            Bool GUI::CoreMessage(Int32 id, const BaseContainer &bc)
            {
                
            	switch (id)
            	{
            	case CUSTOMEVENT::UPDATE_UI_DIALOG:
            	{
            
            		SetString(DLG_DYNAMIC_RENDER_TEXT, "test changed text"_s);
            	}
            	}
            }
            
            bool GUI::CreateLayout()
            {
            	
            	AddStaticText(DLG_DYNAMIC_RENDER_TEXT, BFH_LEFT, 250, 12, "initial text "_s, BORDER_NONE);
            
            
            	
            	return true;
            }
            
            
            ////testclass.cpp////
            void TestClass::ZoomInOut(int steps)
            {
            	for (int i = 0; i < steps; i++)
            	{
            		CallCommand(14063);
            		DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW | DRAWFLAGS::NO_THREAD | DRAWFLAGS::NO_REDUCTION | DRAWFLAGS::STATICBREAK);
            	}
            	
                   //this message isnt caught until the for loop below it is completed, need it to be synchronous 
            	SpecialEventAdd(CUSTOMEVENT::UPDATE_UI_DIALOG);
            
            	for (int i = 0; i < steps; i++)
            	{
            		CallCommand(14064);
            		DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW | DRAWFLAGS::NO_THREAD | DRAWFLAGS::NO_REDUCTION | DRAWFLAGS::STATICBREAK);
            	}
            }
            

            Thank you for your help!

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

              Hi,

              due to the flag DRAWFLAGS::NO_THREAD, your multiple viewport redraws are executed synchronously and make the execution of TestClass::ZoomInOut rather lengthy. This in turn blocks the redraw of your dialog, because that will only happen once the program left the scope of ZoomInOut (or more precisely the scope of the GeDialog method that called ZoomInOut).

              Despite that:

              • I would not use CallCommand in a plugin. At least not in such a brute force manner. Modifying the camera attached to the active viewport seems more elegant.
              • Depending on the value of steps: The execution of possibly hundreds or thousands of viewport redraws seems a bit excessive for a single command.

              Cheers,
              zipit

              MAXON SDK Specialist
              developers.maxon.net

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

                hi,

                Sorry, i don't understand what's the goal of your code ? Maybe it's just a design issu. That could surely help us to understand what you are trying to do.

                Your function Bool GUI::CoreMessage(Int32 id, const BaseContainer &bc) in main.cpp ?

                More important, who is calling ZoomInOut and from where ?

                This question need some lights.

                For example, if ZoomInOut is called in your tread, you can make it loop until the special event have done its job. If it's called in the main thread it's not a good way to go.

                Cheers,
                Manuel

                MAXON SDK Specialist

                MAXON Registered Developer

                J 1 Reply Last reply Reply Quote 0
                • J
                  JuicyJuggles @ferdinand
                  last edited by

                  @zipit

                  Hi Zipit - I do want the DRAWFLAGS::NO_THREAD because when I time the draw calls having other threads would give me inconsistent timing over multiple tests. It sounds like the way C4D works this is all expected and because i am forcing so many draw calls the GeDialog doesnt get updated till after.

                  Your right about CallCommand - just being lazy to zoom in and out instead of changing the editor camera position.
                  My use case dictates lots of draw calls, it is in the hundreds to thousands.

                  Thank you!

                  1 Reply Last reply Reply Quote 0
                  • J
                    JuicyJuggles @Manuel
                    last edited by

                    @m_magalhaes

                    Hi m_magalhaes - The goal is to time how long it takes to do all the draw calls inside ZoomInOut.
                    Yes Bool GUI::CoreMessage(Int32 id, const BaseContainer &bc) in in main.cpp

                    I added to the code to show there is a button in GUI::CreateLayout() that calls GUI::Command(Int32 id, const BaseContainer &msg) which then calls ZoomInOut

                    I have to call ZoomInOut from the main C4D thread because DrawViews can only be called by the main thread. I think that is how i understand the documentation.

                    /////main.cpp///// 
                    
                    TestClass testClassInstance = TestClass();
                    
                    Bool GUI::CoreMessage(Int32 id, const BaseContainer &bc)
                    {
                        
                    	switch (id)
                    	{
                    	case CUSTOMEVENT::UPDATE_UI_DIALOG:
                    	{
                    
                    		SetString(DLG_DYNAMIC_RENDER_TEXT, "test changed text"_s);
                    	}
                    	}
                    }
                    
                    bool GUI::CreateLayout()
                    {
                    	
                    	AddStaticText(DLG_DYNAMIC_RENDER_TEXT, BFH_LEFT, 250, 12, "initial text "_s, BORDER_NONE);
                    	AddButton(RUN_TESTS, BFH_LEFT, 0, 0, "Run Test"_s);
                    
                    	
                    	return true;
                    }
                    
                    bool GUI::Command(Int32 id, const BaseContainer &msg)
                    {
                    	switch (id)
                    	{
                    	case RUN_TESTS:
                    	{
                    		testClassInstance.ZoomInOut();
                    	}
                    	}
                    
                    }
                    
                    
                    ////testclass.cpp////
                    void TestClass::ZoomInOut(int steps)
                    {
                    	for (int i = 0; i < steps; i++)
                    	{
                    		CallCommand(14063);
                    		DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW | DRAWFLAGS::NO_THREAD | DRAWFLAGS::NO_REDUCTION | DRAWFLAGS::STATICBREAK);
                    	}
                    	
                           //this message isnt caught until the for loop below it is completed, need it to be synchronous 
                    	SpecialEventAdd(CUSTOMEVENT::UPDATE_UI_DIALOG);
                    
                    	for (int i = 0; i < steps; i++)
                    	{
                    		CallCommand(14064);
                    		DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW | DRAWFLAGS::NO_THREAD | DRAWFLAGS::NO_REDUCTION | DRAWFLAGS::STATICBREAK);
                    	}
                    }
                    
                    1 Reply Last reply Reply Quote 0
                    • ManuelM
                      Manuel
                      last edited by

                      hi,

                      I would expect the gui to be with your class, the main only registering your CommandData but as long as you find yourself confortable, that's the same.

                      What i could suggest is once you hit the button "start" you can use SetTimer using 1 as parameter.

                      You can override the function Timer or catch the message BFM_TIMER_MESSAGE inside your Message function.

                      you can call

                      DrawViews(DRAWFLAGS::ONLY_ACTIVE_VIEW|DRAWFLAGS::NO_REDUCTION|DRAWFLAGS::NO_THREAD|DRAWFLAGS::NO_ANIMATION|DRAWFLAGS::PRIVATE_NO_WAIT_GL_FINISHED|DRAWFLAGS::NO_HIGHLIGHT_PLANE);
                      

                      Cheers,
                      Manuel

                      MAXON SDK Specialist

                      MAXON Registered Developer

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

                        hi,

                        without feedback, i'll set this thread to solved tomorrow.

                        Cheers,
                        Manuel

                        MAXON SDK Specialist

                        MAXON Registered Developer

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