Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    Animating the Status Spin with Render Progress

    Cinema 4D SDK
    python windows r23
    2
    3
    450
    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.
    • ?
      A Former User
      last edited by A Former User

      Hello!
      I'm rendering an image in my plugin with documents.RenderDocument() and using StatusSetSpin().

      With the code below, I'm using RenderDocument()'s prog parameter function to update the Status progress bar. Currently this code shows the spinner, but the render progress isn't given until after the rendering has completed which is unexpected. With the progress_type RENDERPROGRESSTYPE_DURINGRENDERING, I'd expect the function to execute during rendering rather than afterwards. Perhaps it is, but the UI gets frozen during rendering. With longer renders (like with the Zombie - Toon Rig scene from the Content Browser), the StatusBar doesn't get cleared with the code I have below. Here are my questions:

      • If this is working as intended, is there a way to animate the progress bar while the document is rendering?
      • How do I guarantee that c4d.StatusClear() is going to get called after the progress updates?
      import c4d
      from c4d import documents
      
      def updateProgressBar(p, progress_type):
          if progress_type == c4d.RENDERPROGRESSTYPE_BEFORERENDERING:
              print("Before Rendering")
              c4d.StatusSetText('Initializing render...') 
              c4d.StatusSetSpin()
          elif progress_type == c4d.RENDERPROGRESSTYPE_DURINGRENDERING:
              print(p)
              c4d.StatusSetText('Rendering...') 
              c4d.StatusSetSpin()
          elif progress_type == c4d.RENDERPROGRESSTYPE_AFTERRENDERING:
              print("After Rendering")
              c4d.StatusClear()
              c4d.EventAdd()
              
      def main(doc):
          rd = doc.GetActiveRenderData().GetData()
          bmp = c4d.bitmaps.BaseBitmap()
          bmp.Init(int(rd[c4d.RDATA_XRES]), int(rd[c4d.RDATA_YRES]), 24)
          documents.RenderDocument(doc, rd, bmp, c4d.RENDERFLAGS_EXTERNAL, prog=updateProgressBar)
          c4d.StatusClear()
          c4d.StatusSetText('Render complete.')
          c4d.EventAdd()
      
      if __name__=='__main__':
          main(doc)
      

      Thank you!

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

        Hi @blastframe,

        thank you for reaching out to us. What you are trying to do is unfortunately not supported by us.

        Inside your callback function updateProgressBar you are inside the render thread or in other words not in the main thread. Which makes all gui operations of limits. I actually just recently asked @m_magalhaes what Maxon's stance is on the status bar functionalities being considered GUI operations or not, because I always wondered myself. Other than other GUI operations the status bar methods do not test if they are on the main thread. So you can bend the rules a bit with them. So it's kinda nice to have here an example which proves that they are subject to the same limitations although they do not enforce them.

        To solve your problem you have two options:

        1. Use the c4d.documents.BatchRender type as it has the status bar functionality built in.
        2. Try to wiggle your way around RenderDocument and make it work anyways. This is not supported by us (at least In Python).

        You have here two problems at play for option two. The threading scope and its GUI limitations of the callback function and the blocking nature of RenderDocument. RenderDocument accepts a th argument with which you can pass in a BaseThread to be used as the render thread. Unfortunately it actually only accepts a BaseThread and not a C4DThread, which makes a customly designed thread type solution impossible for us here. So the only way I see which COULD work (with the emphasis it being a possibility and not a guarantee):

        You need three threads:

        • the main thread,
        • an execution thread (which basically just encapsulates a RenderDocument call),
        • and a render thread created internally by RenderDocument (you won't need to populate th).

        You also will need a cross-thread communication object, I will call signal object. More on that later.

        Then you do the following on the main thread:

        1. Instantiate a signal object S.
        2. Instantiate and start an execution thread E.
        3. While E is running run a loop:
          a.Check the signal object and operate with it the status bar.

        In parallel runs the execution thread which internally runs the render thread:

        1. Your callback is being called in the render thread.
        2. You write some render information into the signal object S.

        Which COULD work. There is however the problem that the Cinema 4D SDK does not expose its cross-thread communication objects to Python and the one's provided by CPython like semaphore and lock are not supported. So you would have to write one yourself. Which is not really possible (at least in a safe way, due to the fact that Cinema's threading internals are not public knowledge). So there is not really a solution here for you from an official Maxon point of view (besides form using BatchRender). But since only a one-way communication is here necessary, you might be able to do it anyways 😉 I hope you understand that this option clearly falls out of the scope of support.

        Cheers,
        Ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        ? 1 Reply Last reply Reply Quote 0
        • ?
          A Former User @ferdinand
          last edited by

          @ferdinand Thank you, Ferdinand for the thorough answer and ideas for workarounds. I don't quite have my head around how to use threading in Cinema 4D yet but you've inspired me to look into it. Thank you!

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