GeUserArea.DrawBitmap



  • 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



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



  • 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



  • 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



  • 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).



  • 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



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



  • 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  
    


  • 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.)



  • 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



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

    Hi Martin,

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


Log in to reply