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

    Frequent crash when running plugin multiple times

    Scheduled Pinned Locked Moved PYTHON Development
    12 Posts 0 Posters 1.1k Views
    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.
    • H Offline
      Helper
      last edited by

      On 02/02/2016 at 08:56, xxxxxxxx wrote:

      I have a plugin that is, fundamentally, working. However, when I run it several times, sometimes it hangs (and creates a bugreport warning).

      I don't know if I'm leaving something behind that is not freed correctly or what else could be causing this.

      My plugin is as follows (and includes) :

      - A modal dialog. Yes, I want it to be modal. I have to make sure that, when it is running, absolutely no changes can occur in the document.

      - The model dialog includes a User Area.

      - The User Area is refreshed by a Timer from the dialog.

      - A button in the dialog triggers a User Thread that performs a cycle. Inside that cycle, I render several frames, using c4d.documents.RenderDocument

      - Another button allows the abortion of the render. This is done through a global variable that is set to True if the Abort is pressed. And the rende(c4d.documents.RenderDocument) only occurs if the global variable is False.

      Is there any type of garbage collection that can/should be performed?
      I know it should occur automatically when my plugin finishes (closes).
      But, sometimes, I perform several calculations and abort those calculations before closing the window, and it hangs.

      Sometimes, I close the plugin and, when I open it again, it hangs when I start the calculation.

      What could possibly be wrong for it to hang sometimes and others don't?

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        On 03/02/2016 at 03:02, xxxxxxxx wrote:

        Hi Rui,

        Without any code it's difficult to tell what's wrong.
        But it looks like this is related to how the thread is managed.
        How is it started/stopped?
        Are you sure nothing forbidden is done inside it?

        Please post some code for these parts.

        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          On 04/02/2016 at 04:25, xxxxxxxx wrote:

          Thank you, Yannick.
          I will prepare a listing of the snippets of relevant code, stripping out the junk and commenting as much as I can.

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            On 04/02/2016 at 04:48, xxxxxxxx wrote:

              
            """   
            Diffence Render   
            Written for Cinema 4D R15 and up   
            """   
              
            import c4d   
            from c4d import gui, plugins, utils, bitmaps, storage   
            from c4d.threading import C4DThread   
            from datetime import datetime   
            import time   
              
            import os   
              
            v_start_frame=2000   
            v_end_frame=2001   
            b_close=2010   
            b_calculate=2011   
            b_copy_rs=2012   
            quality=2020   
            the_filename=2030   
            b_filename=2040   
            b_abort=2050   
            t_info=2060   
            t_info2=2070   
              
            #be sure to use a unique ID obtained from www.plugincafe.com   
            PLUGIN_ID = 1036575   
              
            rImage1 = bitmaps.BaseBitmap()   
            rImage2 = bitmaps.BaseBitmap()   
            mImage = bitmaps.BaseBitmap()   
            start_frame=0   
            end_frame=99   
            current_frame=99   
            abort = False   
            calculating = False   
              
            document_time = c4d.BaseTime()   
            start_time = time.time()   
            last_estimate = 0   
            last_estimate_string = ""   
              
            frames_dir = ""   
            masks_dir = ""   
            main_dir = ""   
              
            average_change = 0   
              
            # *******************************************************************************   
              
            class RenderDisplay(gui.GeUserArea) :   
                    
                 highlight_line = c4d.Vector(0, 0.6, 0)   
                 black = c4d.Vector(0)   
                 white = c4d.Vector(1)   
                 shadow_line = c4d.Vector(0.15)   
              
                 success = False   
                    
                 def __init__(self,bmp) :   
                      super(RenderDisplay, self).__init__()   
                      self.bmp = rImage1   
                    
                 def DrawMsg(self, x1, y1, x2, y2, msg_ref) :   
              
                      global start_frame   
                      global end_frame   
                      global current_frame   
                      global abort   
                      global calculating   
              
                      #init draw region   
                      self.OffScreenOn()   
                      self.SetClippingRegion(x1, y1, x2, y2)   
                         
                      the_color=self.GetColorRGB(c4d.COLOR_BG)   
                      back_color=c4d.Vector(the_color['r']/255.0,the_color['g']/255.0,the_color['b']/255.0)   
                      dimmed=c4d.Vector(c4d.utils.Clamp(0.0,1.0,back_color.x*1.1),c4d.utils.Clamp(0.0,1.0,back_color.y*1.1),c4d.utils.Clamp(0.0,1.0,back_color.z*1.1))   
              
                      self.DrawSetPen(back_color)   
                      self.DrawRectangle(x1, y1, x2, y2)   
                         
                      self.DrawBorder(c4d.BORDER_THIN_IN,0,0,256,256)   
                      self.DrawBorder(c4d.BORDER_THIN_IN,272,0,528,256)   
              
                      if self.bmp:   
                           ww=self.bmp.GetBw()   
                           hh=self.bmp.GetBh()   
              
                           if ww>0 and hh>0:   
                                sc=254.0/float(ww)   
                                if hh*sc>254: sc=254.0/float(hh)   
              
                                nw=int(ww*sc)   
                                nh=int(hh*sc)   
                                nx=128-int(nw/2)   
                                ny=128-int(nh/2)   
              
                                self.DrawBitmap(self.bmp,nx,ny,nw,nh,0,0,ww,hh,c4d.BMP_NORMAL)   
              
                                if mImage:   
                                     self.DrawBitmap(mImage,270+nx,ny,nw,nh,0,0,ww,hh,c4d.BMP_NORMAL)   
              
                      # progress bar   
              
                      self.DrawBorder(c4d.BORDER_THIN_IN,100,268,528,278)   
                      self.DrawSetPen(self.white if calculating else dimmed)   
              
                      percent=0.0   
                      progress="Frame --/--"   
              
                      if float(end_frame-start_frame)>0.0: percent=float(current_frame-start_frame+1)/float(end_frame-start_frame+1)   
              
                      self.DrawRectangle(102, 270, int(102+424*percent), 276)   
                    
                      #self.DrawSetTextCol(self.white, back_color)   
                      self.DrawSetTextCol(self.white if calculating else dimmed, back_color)   
                      progress="Frame "+str(int(current_frame-start_frame+1))+"/"+str(int(end_frame-start_frame)+1)   
                         
                      self.DrawText(progress if calculating else "Frame --/--", 2, 266)   
              
            # *******************************************************************************   
              
            class MyThread(c4d.threading.C4DThread) :   
              
                 thumbnail = RenderDisplay(None)   
                 v_quality=0   
              
                 def Main(self) :   
              
                      global start_frame   
                      global end_frame   
                      global current_frame   
                      global abort   
                      global calculating   
                      global frames_dir   
                      global masks_dir   
                      global start_time   
                      global main_dir   
                      global average_change   
              
                      # not calculating at the moment...   
                      if calculating==False: return   
              
                      # get the render data   
                      doc=c4d.documents.GetActiveDocument()   
                      rd=doc.GetActiveRenderData()   
              
                      # bitmap size   
                      o_ww=rd[c4d.RDATA_XRES]   
                      o_hh=rd[c4d.RDATA_YRES]   
                      ww=int(o_ww*self.v_quality)   
                      hh=int(o_hh*self.v_quality)   
              
                      # get the content of the render data container   
                      new_rd=doc.GetActiveRenderData().GetData()   
              
                      new_rd[c4d.RDATA_MULTIPASS_ENABLE] = False   
                      new_rd[c4d.RDATA_PROJECTFILE] = False   
                      new_rd[c4d.RDATA_FRAMESEQUENCE] = 1   
                      new_rd[c4d.RDATA_SAVEIMAGE] = False   
                      new_rd[c4d.RDATA_MULTIPASS_SAVEIMAGE] = False   
                      new_rd[c4d.RDATA_XRES]=ww   
                      new_rd[c4d.RDATA_YRES]=hh   
                      new_rd[c4d.RDATA_ANTIALIASING] = 0 # no antialiasing   
              
                      rImage1.Init(ww,hh,24)   
                      rImage2.Init(ww,hh,24)   
                      mImage.Init(ww,hh,24)   
              
                      # perform the renders while not aborting and before the end of all frames   
                      while current_frame<=end_frame and abort==False and calculating==True:   
              
                           new_rd[c4d.RDATA_FRAMEFROM]=c4d.BaseTime(current_frame,doc.GetFps())   
                           new_rd[c4d.RDATA_FRAMETO]=c4d.BaseTime(current_frame,doc.GetFps())   
                           doc.SetTime(c4d.BaseTime(current_frame,doc.GetFps()))   
              
                           res2=c4d.documents.RenderDocument(doc,new_rd,rImage1,c4d.RENDERFLAGS_EXTERNAL|c4d.RENDERFLAGS_NODOCUMENTCLONE)   
              
                           # prepare the mask   
                           if current_frame==start_frame:   
                                # first frame   
                                for yy in xrange(hh) :   
                                     for xx in xrange(ww) :   
                                          mImage.SetPixel(xx,yy,255,255,255)   
                           else:   
                                for yy in xrange(hh) :   
                                     for xx in xrange(ww) :   
                                          diff= 0 if rImage1.GetPixel(xx,yy)==rImage2.GetPixel(xx,yy) else 255   
                                          mImage.SetPixel(xx,yy,diff,diff,diff)   
                         
                           # save the frame and the mask   
                           frame_name=os.path.join(frames_dir,"frame_%05d.png" % (current_frame,))   
                           result=rImage1.Save(frame_name,c4d.FILTER_PNG)   
              
                           masks_name=os.path.join(masks_dir,"mask_%05d.png" % (current_frame,))   
                           result=mImage.Save(masks_name,c4d.FILTER_PNG)   
              
                           rImage1.CopyTo(rImage2)   
              
                           current_frame=current_frame+1   
              
                      # RENDER FINISHED!!!   
              
                      # create a report file   
                      if os.path.exists(main_dir) :   
              
                           report_path=os.path.join(main_dir,"Report.txt")   
              
                           hf=open(report_path,'w')   
              
                           if hf:   
                                hf.write("Report for file < "+doc.GetDocumentName()+" >\n\n")   
              
                                hf.write("Date: "+time.strftime("%d/%m/%Y")+"\n\n")   
              
                                hf.write("Original frame size: %d x %d\n" % (o_ww,o_hh))   
                                hf.write("Final masks frame size: %d x %d\n\n" % (ww,hh))   
              
                                hf.write("Frame Range: frame %d to frame %d (%d in total)\n\n" % (start_frame,end_frame,end_frame-start_frame+1))   
              
                                if abort:   
                                     hf.write("ABORTED BEFORE COMPLETION AT FRAME "+str(current_frame)+"!\n\n")   
              
                                spent=time.time()-start_time   
                                d=divmod(spent,86400)   
                                h=divmod(d[1],3600)   
                                m=divmod(h[1],60)   
                                s=m[1]   
              
                                hf.write("Total render calculation time: %02d:%02d:%02d\n\n" % (h[0],m[0],s))   
              
                                total_pixels=(end_frame-start_frame+1)*(ww*hh)   
                                aver=float(total_pixels-average_change)/float(total_pixels)   
              
                                hf.write("Average change: %d%% (less change is better)" % (100*(1.0-aver),))   
              
                                hf.close()   
              
                      # clean the house   
                      rImage1.FlushAll()   
                      rImage2.FlushAll()   
                      mImage.FlushAll()   
              
                      abort=True   
                      calculating=False   
              
            # *******************************************************************************   
              
            class DiffRender(gui.GeDialog) :   
                    
                 thumbnail = RenderDisplay(None)   
                 thread = MyThread()   
              
                 counter=0   
                    
                 def CreateLayout(self) :   
                      self.SetTitle("Render Differences")   
                         
                      self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, title="", rows=1, cols=1, groupflags=c4d.BORDER_GROUP_IN)   
                      self.GroupBorderSpace(5, 5, 5, 5)   
                         
                      #give really unique ID to userarea, otherwise the update process will fail!   
                      area = self.AddUserArea(id=1001, flags=c4d.BFH_SCALEFIT|c4d.BFV_TOP,initw=528, inith=204)   
                      self.AttachUserArea(self.thumbnail, area)   
              
                      self.AddStaticText(id=t_info2,flags=c4d.BFH_SCALEFIT|c4d.BFV_TOP,inith=0, name="Info: ---", borderstyle=c4d.BORDER_THIN_IN)   
              
                      self.AddButton(id=b_abort, flags=c4d.BFH_CENTER,initw=64, inith=16, name="Abort")   
              
                      self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT)   
              
                      # Filename   
                      self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT|c4d.BFV_TOP, title="", rows=1, cols=3,)   
                      self.AddStaticText(0,flags=c4d.BFH_LEFT|c4d.BFV_TOP,initw=90, inith=12, name="Masks Path")   
                      self.AddEditText(id=the_filename,flags=c4d.BFH_SCALEFIT|c4d.BFV_TOP,initw=0, inith=12)   
                      self.AddButton(id=b_filename, flags=c4d.BFH_FIT|c4d.BFV_TOP,initw=50, inith=12, name="...")   
                      self.GroupEnd()   
              
                      # quality   
                      self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT|c4d.BFV_TOP, title="", rows=1, cols=3,)   
                      self.AddStaticText(0,flags=c4d.BFH_FIT|c4d.BFV_TOP,initw=90, inith=12,name="Quality")   
                      self.AddEditSlider(id=quality, flags=c4d.BFH_SCALEFIT|c4d.BFV_TOP,initw=50, inith=12)   
                      self.AddStaticText(id=t_info,flags=c4d.BFH_FIT|c4d.BFV_TOP,initw=120, inith=12, name="--- x ---")   
                      self.GroupEnd()   
              
                      self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT)   
              
                      # frames   
                      self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT|c4d.BFV_TOP, title="", rows=1, cols=6,)   
                      self.AddStaticText(0,flags=c4d.BFH_FIT|c4d.BFV_TOP,initw=90, inith=12,name="From frame")   
                      self.AddEditNumberArrows(id=v_start_frame, flags=c4d.BFH_FIT|c4d.BFV_TOP,initw=80, inith=12)   
                      self.AddStaticText(0,flags=c4d.BFH_FIT|c4d.BFV_TOP,initw=74, inith=12,name="To frame")   
                      self.AddEditNumberArrows(id=v_end_frame, flags=c4d.BFH_FIT|c4d.BFV_TOP,initw=80, inith=12)   
                      self.AddButton(id=b_copy_rs, flags=c4d.BFH_SCALEFIT,initw=0, inith=12, name="Copy from Render Settings")   
                      self.GroupEnd()   
              
                      self.AddSeparatorH(inith=0, flags=c4d.BFH_FIT)   
                         
                      self.GroupBegin(id=0, flags=c4d.BFH_RIGHT, title="", rows=1, cols=2,)   
                      self.AddButton(id=b_close, flags=c4d.BFH_RIGHT,initw=60, inith=16, name="Close")   
                      self.AddButton(id=b_calculate, flags=c4d.BFH_RIGHT,initw=80, inith=16, name="Calculate")   
                      self.GroupEnd()   
                      self.GroupEnd()   
                      return True   
              
            # *******************************************************************************   
              
                 def InitValues(self) :   
                      self.SetInt32(id=quality,value=75,min=10,max=100)   
                      self.SetInt32(id=v_start_frame,value=0)   
                      self.SetInt32(id=v_end_frame,value=99)   
              
                      doc=c4d.documents.GetActiveDocument()   
                      rd=doc.GetActiveRenderData()   
                      ww=rd[c4d.RDATA_XRES_VIRTUAL]   
                      hh=rd[c4d.RDATA_YRES_VIRTUAL]   
                      qual=float(self.GetInt32(quality))/100.0   
                      self.SetString(id=t_info,value="( "+str(int(ww*qual))+" x "+str(int(hh*qual))+" )")   
              
                      calculating=False   
              
                      success=False   
              
                      self.Enable(b_abort,False)   
              
                      self.SetTimer(700)   
              
                      return True   
              
            # *******************************************************************************   
              
                 def Command(self,id,msg) :   
              
                      global start_frame   
                      global end_frame   
                      global current_frame   
                      global abort   
                      global calculating   
                      global document_time   
                      global start_time   
                      global last_estimate   
                      global last_estimate_string   
                      global frames_dir   
                      global masks_dir   
                      global main_dir   
                      global average_change   
              
                      doc=c4d.documents.GetActiveDocument()   
              
                      if id==quality:   
                           rd=doc.GetActiveRenderData()   
                           ww=rd[c4d.RDATA_XRES_VIRTUAL]   
                           hh=rd[c4d.RDATA_YRES_VIRTUAL]   
                           qual=float(self.GetInt32(quality))/100.0   
                           self.SetString(id=t_info,value="( "+str(int(ww*qual))+" x "+str(int(hh*qual))+" )")   
              
                      if id==b_close:   
                           self.Close()   
              
                      if id==b_copy_rs:   
                           doc=c4d.documents.GetActiveDocument()   
                           rd=doc.GetActiveRenderData()   
                           start=rd[c4d.RDATA_FRAMEFROM].GetFrame(doc.GetFps())   
                           end=rd[c4d.RDATA_FRAMETO].GetFrame(doc.GetFps())   
                           self.SetInt32(id=v_start_frame,value=start)   
                           self.SetInt32(id=v_end_frame,value=end)   
              
                      if id==b_filename:   
                           new_filename=c4d.storage.LoadDialog(title="Select the destination folder",flags=c4d.FILESELECT_DIRECTORY)   
                           if new_filename!=None:   
                                self.SetFilename(id=the_filename,fn=new_filename)   
              
                      if id==b_calculate:   
                           # check the path   
                           new_filename=self.GetFilename(id=the_filename)   
                           if new_filename=="":   
                                c4d.gui.MessageDialog("A valid path needs to be set, in order to save the difference masks.")   
                                return True   
              
                           if not os.path.exists(new_filename) :   
                                c4d.gui.MessageDialog("A valid path needs to be set, in order to save the difference masks.")   
                                return True                       
              
                           main_dir=new_filename   
              
                           # check start and end frames   
                           start_frame=self.GetInt32(id=v_start_frame)   
                           end_frame=self.GetInt32(id=v_end_frame)   
                           if start_frame>=end_frame:   
                                c4d.gui.MessageDialog("There is a problem with the start and/or end frames.")   
                                return True   
              
                           # check if the required folders exist. If not, create them   
                           frames_dir=os.path.join(new_filename,"frames")   
                           if not os.path.exists(frames_dir) :   
                                os.mkdir(frames_dir)   
              
                           masks_dir=os.path.join(new_filename,"masks")   
                           if not os.path.exists(masks_dir) :   
                                os.mkdir(masks_dir)   
              
                           # clip the end_frame, if necessary   
                           max_frames=doc.GetMaxTime().GetFrame(doc.GetFps())   
                           if end_frame>max_frames:   
                                end_frame=max_frames   
              
                           # disable/enable GUI for calculations   
                           self.Enable(b_abort,True)   
                           self.Enable(b_calculate,False)   
                           self.Enable(b_close,False)   
                           self.Enable(b_filename,False)   
                           self.Enable(the_filename,False)   
                           self.Enable(quality,False)   
                           self.Enable(t_info,False)   
                           self.Enable(v_start_frame,False)   
                           self.Enable(v_end_frame,False)   
                           self.Enable(b_copy_rs,False)   
              
                           # adjust all the required variables   
                           abort=False   
                           calculating=True   
                           current_frame=start_frame   
                           start_time=time.time()   
                           last_estimate=time.strptime("23:59:59","%H:%M:%S")   
                           last_estimate_string=""   
                           average_change=0   
                           self.counter=1   
                           document_time=doc.GetTime()   
                           self.thread.v_quality=float(self.GetInt32(quality))/100.0   
              
                           # start the calculation   
                           self.thread.Start()   
              
              
                      if id==b_abort:   
                           abort=True   
              
                           self.SetString(id=t_info2,value="Aborting...")   
                              
                           self.Enable(b_abort,False)   
                           self.Enable(b_calculate,True)   
                           self.Enable(b_close,True)   
                           self.Enable(b_filename,True)   
                           self.Enable(the_filename,True)   
                           self.Enable(quality,True)   
                           self.Enable(t_info,True)   
                           self.Enable(v_start_frame,True)   
                           self.Enable(v_end_frame,True)   
                           self.Enable(b_copy_rs,True)   
              
                           doc.SetTime(document_time)   
              
                      #c4d.EventAdd()   
                      return True   
              
            # *******************************************************************************   
              
                 def Timer(self, msg) :   
              
                      global start_frame   
                      global end_frame   
                      global current_frame   
                      global abort   
                      global calculating   
                      global document_time   
                      global start_time   
                      global last_estimate   
                      global last_estimate_string   
              
                      if self.counter==0:   
                           if calculating and not abort:   
                                spent=time.time()-start_time   
                                d=divmod(spent,86400)   
                                h=divmod(d[1],3600)   
                                m=divmod(h[1],60)   
                                s=m[1]   
              
                                time_string="Elapsed: %02d:%02d:%02d" % (h[0],m[0],s)   
              
                                if current_frame>start_frame:   
                                     each_frame=spent/float(current_frame-start_frame-.1)   
                                     estimated=(end_frame-current_frame)*each_frame   
                                        
                                     d=divmod(estimated,86400)   
                                     h=divmod(d[1],3600)   
                                     m=divmod(h[1],60)   
                                     s=m[1]   
                                     last_estimate_string=" ( Estimated time to finish: %02d:%02d:%02d )" % (h[0],m[0],s)   
                                     last_estimate=estimated   
              
                                time_string=time_string+last_estimate_string   
                                self.SetString(id=t_info2,value=time_string)   
              
                      self.counter=(self.counter+1) % 3   
              
                      if abort==True:   
                           self.thread.End(True)   
                           calculating=False   
                           self.Enable(b_abort,False)   
                           self.Enable(b_calculate,True)   
                           self.Enable(b_close,True)   
                           self.Enable(b_filename,True)   
                           self.Enable(the_filename,True)   
                           self.Enable(quality,True)   
                           self.Enable(t_info,True)   
                           self.Enable(v_start_frame,True)   
                           self.Enable(v_end_frame,True)   
                           self.Enable(b_copy_rs,True)   
                           doc=c4d.documents.GetActiveDocument()   
                           doc.SetTime(document_time)   
                           c4d.StopAllThreads()   
                                   
                      #Since we can't update the USER_AREA manually while rendering   
                      #We must ReDraw it constantly before we start rendering   
                      #Only do this ReDrawing when we are actually rendering!!!   
                      if self.thread.IsRunning() :   
                           self.thumbnail.Redraw()   
                              
              
            # *******************************************************************************   
              
            class BitmapManagerCommandData(c4d.plugins.CommandData) :   
                 dialog = None   
              
                 def Execute(self, doc) :   
                      """Just create the dialog when the user clicked on the entry   
                      in the plugins menu to open it."""   
                      if self.dialog is None:   
                         self.dialog = DiffRender()   
              
                      return self.dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL, pluginid=PLUGIN_ID, defaulth=300, defaultw=550)   
              
                 def RestoreLayout(self, sec_ref) :   
                      """Same for this method. Just allocate it when the dialog   
                      is needed"""   
                      if self.dialog is None:   
                         self.dialog = DiffRender()   
              
                      return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)   
              
            # *******************************************************************************   
              
            if __name__ == "__main__":   
                  bmp = bitmaps.BaseBitmap()   
                  dir, f = os.path.split(__file__)   
                  fn = os.path.join(dir, "res", "icon.tif")   
                  bmp.InitWith(fn)   
                  c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="Differences Render",   
                                                          help="Renders set of bitmaps with differences between animation frames.",info=0,   
                                                              dat=BitmapManagerCommandData(), icon=bmp)   
            
            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              On 04/02/2016 at 08:48, xxxxxxxx wrote:

              Hi Rui,

              That's quite a long piece of code 🙂.

              First, you're doing forbidden operations in the custom thread:
              - Modification of the active document (doc.SetTime())
              - File operation (open(), write() etc.)

              RenderDocument() is called without passing the thread... So it doesn't know it runs from a custom thread.
              The last (optional) parameter th should be passed self.Get()).

              The Main() function of your thread should be used to call RenderDocument() mainly. Modifying the rendered bitmap there should be fine too.
              All other operations have to be done from the dialog. Modify the document there and run the thread for each frame to render.
              Then do also the file operation in your dialog after the render and thread have finished each frame.

              Also I'm not sure the behavior between globals and a C4DThread is safe. You'd better use members of the custom threads.
              When the render operation has to be aborted you shouldn't rely on a global bool but immediately end the thread.

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                On 04/02/2016 at 09:21, xxxxxxxx wrote:

                Thank you for the pointers. I will change my code, then.
                Just one thing... how can I know that a render operation finished for each frame, in order to advance with the bitmap operations?

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  On 04/02/2016 at 09:24, xxxxxxxx wrote:

                  Oh, another thing.
                  If I don't set the time of the document inside the thread with doc.SetTime(), simply setting the start/end frame of the render with

                  new_rd[c4d.RDATA_FRAMEFROM]=c4d.BaseTime(current_frame,doc.GetFps())
                  new_rd[c4d.RDATA_FRAMETO]=c4d.BaseTime(current_frame,doc.GetFps())

                  will be enough? I mean, will it calculate the animation correctly? Even files with particles and dynamics?

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    On 05/02/2016 at 01:23, xxxxxxxx wrote:

                    Hi Rui,

                    Originally posted by xxxxxxxx

                    How can I know that a render operation finished for each frame, in order to advance with the bitmap operations?

                    Use your dialog's Timer() function to keep track of the running thread. When finished do the bitmap and file operations.
                    Then start another thread for the next render if cycle hasn't finished.

                    Originally posted by xxxxxxxx

                    If I don't set the time of the document inside the thread with doc.SetTime(), simply setting the start/end frame of the render with

                    new_rd[c4d.RDATA_FRAMEFROM]=c4d.BaseTime(current_frame,doc.GetFps()) 
                    new_rd[c4d.RDATA_FRAMETO]=c4d.BaseTime(current_frame,doc.GetFps())

                    will be enough? I mean, will it calculate the animation correctly? Even files with particles and dynamics?

                    To make sure the document to render is updated for a given frame call ExecutePasses() after SetTime().

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      Helper
                      last edited by

                      On 05/02/2016 at 07:07, xxxxxxxx wrote:

                      Thank you, Yannick.
                      That sounds logical.
                      My only problem is that my cycle is now in the main thread and it happens in the Command method, while the cycle is running, I have no events for the clicking on the Abort button.
                      How can I create a cycle, when the user clicks "Calculate" and still have a way to cancel the render, by clicking "Abort"?

                      1 Reply Last reply Reply Quote 0
                      • H Offline
                        Helper
                        last edited by

                        On 08/02/2016 at 03:47, xxxxxxxx wrote:

                        Originally posted by xxxxxxxx

                        My only problem is that my cycle is now in the main thread and it happens in the Command method, while the cycle is running, I have no events for the clicking on the Abort button.
                        How can I create a cycle, when the user clicks "Calculate" and still have a way to cancel the render, by clicking "Abort"?

                        What do you mean by 'cycle'?
                        You shouldn't use a while loop for the render cycle. Use Timer() to check if the thread for the render has finished. If yes do your bitmap and file operations then starts the next render thread.

                        1 Reply Last reply Reply Quote 0
                        • H Offline
                          Helper
                          last edited by

                          On 08/02/2016 at 13:22, xxxxxxxx wrote:

                          Oh, ok. Requires a little more "thinking of" but I will give it a try
                          Another thing... instead of using global variables should I make them all childs of the user thread process?
                          Thank you, Yannick.

                          1 Reply Last reply Reply Quote 0
                          • H Offline
                            Helper
                            last edited by

                            On 09/02/2016 at 00:15, xxxxxxxx wrote:

                            Originally posted by xxxxxxxx

                            Another thing... instead of using global variables should I make them all childs of the user thread process?

                            It's always better to use member variable in classes. This forces to write cleaner and safer code.
                            Avoid as much as possible using global variables.

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