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

    GeUserArea.DrawBitmap

    PYTHON Development
    0
    11
    1.9k
    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
      Helper
      last edited by

      On 07/12/2017 at 12:06, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   R19 
      Platform:      Mac OSX  ; 
      Language(s) :       PYTHON  ;

      ---------
      Hi,

      there seems to be an issue with GeUserArea.DrawBitmap().

      Not only that  BMP_DiMIMAGE is listed twice in the docs, but also the attribute of the function "mode" ,except BMP_NORMAL, can´t be assigned.
      Especially BMP_ALLOWALPHA is really needed.

      cheers
      Martin

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

        On 08/12/2017 at 08:09, xxxxxxxx wrote:

        Hi Martin,

        instead of drawing into the GeUserArea directly, we recommend to do all drawing (especially with alpha channels) into a GeClipMap. And then in the end only use DrawBitmap() with BMP_NORMAL and BMP_ALLOWALPHA to draw the GeClipMap (or rather the BaseBitrmap retrieved from the GeClipMap) into the GeUserArea. In this way BMP_ALLOWALPHA works for me as expected.

        I borrowed some of Niklas' code from this thread:

        import c4d
        import c4d.gui     as gui
        import c4d.bitmaps as bitmaps
          
        class Area(gui.GeUserArea) :
            
            def __init__(self, w = 20, h = 20, r = 1, g = 1, b = 1) :
                self.bmp = bitmaps.GeClipMap()
                self.bmp.Init(w, h)
                self.bmp.BeginDraw()
                self.w   = w
                self.h   = h
                
                r = int(r * 255)
                g = int(g * 255)
                b = int(b * 255)
          
                for x in xrange(w) :
                    for y in xrange(h) :
                        a = (x * 4 / float(w))**(y / float(h))
                        try:
                            a = 1 / (x**2 / float(w)**2) * a
                        except:
                            a = 0
                        a = int(a * 255)
                        self.bmp.SetPixelRGBA(x, y, r, g, b, a)
                        
                self.bmp.EndDraw()
                        
            def DrawMsg(self, x1, y1, x2, y2, msg) :
                #self.DrawSetPen(c4d.Vector(0, 0, 0))  # changes bg color seen through alpha
          
                w, h = self.w, self.h
                self.DrawBitmap(self.bmp.GetBitmap(),
                    0, 0, w, h, 0, 0, w, h, c4d.BMP_NORMAL | c4d.BMP_ALLOWALPHA)
                    
            def GetMinSize(self) :
                return self.w, self.h
                
        class Dialog(gui.GeDialog) :
            
            def __init__(self, area) :
                self.area = area
            
            def CreateLayout(self) :
                self.AddUserArea(1000, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT)
                self.AttachUserArea(self.area, 1000)
                return True
            
        def main() :
            area = Area(200, 200, 1.0, 0.66, 0.24)
            dlg  = Dialog(area)
            dlg.Open(c4d.DLG_TYPE_MODAL)
            
        if __name__ == "__main__":
            main()
        

        The double entry in the Python documentation will be fixed.

        For now, I have moved this thread into the Python sub-forum. If you still feel BMP_ALLOWALPHA is buggy, please provide us with some more detail.

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

          On 08/12/2017 at 11:39, xxxxxxxx wrote:

          Hi Andreas,

          I used GeClipMap() before, but no luck.
          Confident through Niklas example I investigated further and the error occurred because a negative value was set to ww and wh attribute of the function.
          In this special case BMP_NORMAL is valid, while the other modes are not, confusing...
          An abs() function or an exception raise would be nice in GeUserArea.DrawBitmap().

          thanks,
          Martin

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

            On 11/12/2017 at 01:08, xxxxxxxx wrote:

            Hi Andreas,

            thanks for your help,
            some additional notes and a working example:
            - drawing everything into one clipmap and at the end draw this clipmap to the userarea,
             seems to be the only working way of layering several alpha bitmaps on top of each other.

            - it is important to set to c4d.GE_CM_DRAWMODE_BLEND in GeClipMap.SetDrawMode(),
             otherwise the alpha channel is not being used.

            - it is important to overwrite GeUserArea.Sized() ,
             otherwise the clipmap won't show up

            If you feel like it´s ok, you can mark this thread as solved.

            import c4d  
            from c4d import bitmaps  
              
            OK = 1003  
            SHOW = 1005  
            USERAREA = 1004  
              
            class Canvas(c4d.gui.GeUserArea) :  
              
              def __init__(self) :  
                  self.w = self.GetWidth()  
                  self.h = self.GetHeight()  
                  self.rectangle=[-1,-1,-1,-1]  
                  self.drawMap = bitmaps.GeClipMap()  
                    
              ###########################          
              #UserArea Functions          
              def DrawMsg(self, x1, y1, x2, y2, msg) :    
                    
                  self.OffScreenOn()  
              
                  #draw everything in one clip map  
                  self.drawMap.BeginDraw()  
                  #draw background  
                  self.drawMap.SetColor(51, 51, 51)  
                  self.drawMap.FillRect(x1, y1, x2, y2)  
                    
                  #ensure that there is an object to draw the icon from  
                  obj=doc.GetFirstObject()  
                  if not obj:  
                      print "no item"  
                      self.drawMap.SetColor(255,170, 24)    
                      self.drawMap.TextAt(3,3,"Please, insert an object into the scene for testing!")  
                      self.drawMap.EndDraw()  
                      self.DrawBitmap(self.drawMap.GetBitmap(), 0, 0, self.GetWidth(), self.GetHeight(),  
                                      0, 0, self.GetWidth(), self.GetHeight(),  
                                      c4d.BMP_NORMAL)  
                      return  
                     
                  #draw text   
                  self.drawMap.SetColor(255,170, 24)    
                  self.drawMap.TextAt(3,3,str(50000000))  
                  #draw a rectangle  
                  self.drawMap.SetColor(100, 100, 100, 255)  
                  self.drawMap.FillRect(150, 0, 250, 50)  
                    
                  #needs to be set to draw alpha maps--------------------#  
                  self.drawMap.SetDrawMode(c4d.GE_CM_DRAWMODE_BLEND, 255)  
                  #------------------------------------------------------#  
                    
                  #draw icon with alpha  
                  objicon = obj.GetIcon()  
                  bmp = objicon['bmp']  
                  wbmp = objicon['w']  
                  hbmp = objicon['h']  
                  xbmp = objicon['x']  
                  ybmp = objicon['y']  
                  icon = bitmaps.BaseBitmap()  
                  icon.Init(wbmp,hbmp,depth=24)  
                  bmp.CopyPartTo(icon, xbmp, ybmp, wbmp, hbmp)  
                  alphaicon =icon.GetInternalChannel()  
              
                  iconclip = bitmaps.GeClipMap()  
                  iconclip.InitWithBitmap(icon,alphaicon)  
                    
                  self.drawMap.Blit( 50,50, iconclip, 0, 0,  wbmp, hbmp, rop = c4d.GE_CM_BLIT_COL)    
                    
                  #draw drag    
                  self.drawMap.SetColor(200, 200, 255, 100)    
                  xdr,ydr,x2dr,y2dr = self.toolDragSortEx()  
                  self.drawMap.FillRect(xdr,ydr,x2dr,y2dr)   
                    
                  self.drawMap.SetColor(255, 255, 255, 255)   
                  self.drawMap.Rect(xdr,ydr,x2dr,y2dr)  
                                                  
                  self.drawMap.EndDraw()  
                  self.DrawBitmap(self.drawMap.GetBitmap(), 0, 0, self.GetWidth(), self.GetHeight(),  
                                      0, 0, self.GetWidth(), self.GetHeight(),  
                                      c4d.BMP_NORMAL)  
                  return      
              
              def Sized(self, w, h) :  
                  self.w=w  
                  self.h=h  
                  #needs to be set---------------------------------------#   
                  self.drawMap.Destroy()  
                  self.drawMap.Init(self.w, self.h)  
                  #------------------------------------------------------#  
                  return  
                
              def GetMinSize(self) :  
                  return self.w, self.h  
              
              def InputEvent(self, msg) :  
                  dev = msg.GetLong(c4d.BFM_INPUT_DEVICE)  
                  if dev == c4d.BFM_INPUT_MOUSE:  
                      return self.HandleMouseEvents(msg)  
                  return False   
                        
              def HandleMouseEvents(self, msg) :  
                  #init values  
                  mousex = msg.GetLong(c4d.BFM_INPUT_X)  
                  mousey = msg.GetLong(c4d.BFM_INPUT_Y)   
                  start_x = mx = mousex - self.Local2Global()['x']  
                  start_y = my = mousey - self.Local2Global()['y']  
               
                  #drag interaction    
                  state = c4d.BaseContainer()  
                  self.MouseDragStart(c4d.KEY_MLEFT,start_x, start_y, c4d.MOUSEDRAGFLAGS_DONTHIDEMOUSE| c4d.MOUSEDRAGFLAGS_NOMOVE )  
                  while True:  
                      result, dx, dy, channels = self.MouseDrag()  
                        
                      #end of Drag  
                      if result == c4d.MOUSEDRAGRESULT_ESCAPE:  
                          break  
                      if not self.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, state) :  
                          print "mouse right etc"  
                          break  
                      if state[c4d.BFM_INPUT_VALUE] == 0:  
                          #mouse release  
                          self.rectangle = [-1,-1,-1,-1]  
                          self.Redraw()  
                          break  
              
                      #not moving, continue  
                      if dx == 0 and dy == 0:  
                          continue  
              
                      #draging  
                      mx -= dx  
                      my -= dy  
              
                      #start drag with rectangle  
                      self.rectangle = [start_x,start_y,mx,my]  
                      self.Redraw()       
                  return True  
                
              def toolDragSortEx(self) :    
                  if self.rectangle[0]<self.rectangle[2]:  
                      x1,x2 = self.rectangle[0],self.rectangle[2]  
                  else:  
                      x1,x2 = self.rectangle[2],self.rectangle[0]  
                  if self.rectangle[1]<self.rectangle[3]:  
                      y1,y2 = self.rectangle[1],self.rectangle[3]  
                  else:  
                      y1,y2 = self.rectangle[3],self.rectangle[1]  
                  return x1,y1,x2,y2  
              
            class AreaDialog(c4d.gui.GeDialog) :  
              
              def __init__(self,userarea) :  
                  self.userarea = userarea  
              
              def CreateLayout(self) :  
                  self.SetTitle("USERAREATEST")  
                  self.AddUserArea(USERAREA, c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT)  
                  self.AttachUserArea(self.userarea, USERAREA)                      
                  self.AddButton(OK, c4d.BFH_LEFT, name="OK")  
                  self.AddButton(SHOW, c4d.BFH_LEFT, name="Show bitmap")  
                  return True  
              
              def Command(self, id, msg) :  
                  if id==OK:  
                      self.Close()  
                      return True  
                    
                  if id==SHOW:  
                      bitmaps.ShowBitmap(self.userarea.drawMap.GetBitmap())  
                  return True  
              
            def main() :   
              userarea = Canvas()  
              dialog = None  
              dialog = AreaDialog(userarea)  
              dialog.Open(dlgtype=c4d.DLG_TYPE_MODAL_RESIZEABLE, xpos=100, ypos=100, defaultw=350, defaulth=500)  
              
            if __name__=='__main__':  
              main()  
            

            cheers,
            Martin

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

              On 11/12/2017 at 09:52, xxxxxxxx wrote:

              Hi Martin,

              thanks for your detailed final conclusion.

              Just a note on GeUserArea.Sized() : This function should actually always be implemented for a GeUserArea to properly react to resizing requests (well, if you have elements that need adaption like your bitmap for example).

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

                On 12/12/2017 at 04:33, xxxxxxxx wrote:

                Hi Andreas,

                thanks for the advice.
                A last aesthetical kind of question on this subject.
                How should this clipmap draw solution draw sharp alphas and typo into the userarea?
                The clipmap is always blown up to screen pixels after DrawBitmap .
                Is there any solution?

                cheers,
                Martin

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

                  On 13/12/2017 at 10:16, xxxxxxxx wrote:

                  Hi Martin,

                  I'm not sure I understand. Are you saying the GeClipmap gets modified/scaled by DrawBitmap()?
                  Looking at your DrawBitmap() call in the code above, you are passing the same GeUserArea width and height into "both" parameters of DrawBitmap(), while actually the second width and height should be the size of your bitmap. Could that be part of the problem?

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

                    On 13/12/2017 at 12:42, xxxxxxxx wrote:

                    Hi Andreas,

                    the clipmap was initialized with the width and height of the userarea. That´s why it makes no difference if  I use .Getwidth() from the userarea or .GetBw() from the clipmap.
                    The example code shows the loss of quality/sharpness comparing drawing text with GeUserArea.DrawText and drawing text on the clipmap and afterwards draw the bitmap from the clipmap.

                    You can simply replace the following DrawMsg function in my code above, to give it a try.

                    Thanks in advance!
                    Martin

                        def DrawMsg(self, x1, y1, x2, y2, msg) :  
                      
                          self.OffScreenOn()  
                      
                          #draw everything in one clip map  
                          self.drawMap.BeginDraw()  
                          #draw background  
                          self.drawMap.SetColor(51, 51, 51)  
                          self.drawMap.FillRect(x1, y1, x2, y2)  
                            
                          #draw text   
                          self.drawMap.SetColor(255,170, 24)    
                          self.drawMap.TextAt(3,10,"Motion-Tracker-Tracks können jetzt auch runde Suchmuster verwenden. ")  
                            
                          self.drawMap.EndDraw()  
                          self.DrawBitmap(self.drawMap.GetBitmap(), 0, 0, self.w, self.h,  
                                              0, 0, self.drawMap.GetBw(),self.drawMap.GetBh(),  
                                              c4d.BMP_NORMAL)  
                                                        
                          #draw with usual textdraw    
                          self.DrawSetTextCol(c4d.COLOR_TEXT_SELECTED_DARK,  
                                                      c4d.COLOR_TRANS)   
                          self.DrawText("Motion-Tracker-Tracks können jetzt auch runde Suchmuster verwenden.", 3, 30)  
                          return  
                    
                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 15/12/2017 at 02:53, xxxxxxxx wrote:

                      Hi Martin,

                      GeClipmap.TextAt() and GeUserArea.DrawText() doesn't give the same result because they use different means to draw text from different contexts.
                      GeClipmap.TextAt() draws into a bitmap whereas GeUserArea.DrawText() directly draws into the GUI.

                      (I answered as Andreas left for vacation.)

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

                        On 19/12/2017 at 01:06, xxxxxxxx wrote:

                        Hi Yannick,

                        I see, could you please confirm than that there is either a sup-pixel sampling in drawBitmap or a working alpha draw method missing while drawing several alphas over elements in the user area draw function?
                        I can´t reach the quality/result  I´m aiming for…

                        cheers martin

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

                          On 22/12/2017 at 06:41, xxxxxxxx wrote:

                          Hi Martin,

                          I'm afraid I can't disclose internal implementation details.

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