Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > PYTHON Development
  New Posts New Posts
  FAQ FAQ  Forum Search

GeUserArea.DrawBitmap

Author
Message
  Topic Search Topic Search
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Topic: GeUserArea.DrawBitmap
    Posted: 2017 Dec 07 at 12:06pm

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
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1878
Direct Link To This Post Posted: 2017 Dec 08 at 8:09am
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.
Cheers,
Andreas
SDK Support Engineer
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2017 Dec 08 at 11:39am
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
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2017 Dec 11 at 1:08am
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
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1878
Direct Link To This Post Posted: 2017 Dec 11 at 9:52am
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).

Cheers,
Andreas
SDK Support Engineer
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2017 Dec 12 at 4:33am
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
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
Andreas Block View Drop Down
Forum Moderator
Forum Moderator
Avatar

Joined: 2014 Oct 01
Location: Hannover
Online Status: Offline
Posts: 1878
Direct Link To This Post Posted: 2017 Dec 13 at 10:16am
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?

Cheers,
Andreas
SDK Support Engineer
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2017 Dec 13 at 12:42pm
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 

"The higher that the monkey can climb, the more he shows his tail"
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Dec 15 at 2:53am
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.)





Edited by Yannick Puech - 2017 Dec 15 at 2:54am
MAXON
Developer Support
Back to Top
monkeytack View Drop Down
Member
Member


Joined: 2014 Apr 14
Location: Germany
Online Status: Offline
Posts: 283
Direct Link To This Post Posted: 2017 Dec 19 at 1:06am
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
"The higher that the monkey can climb, the more he shows his tail"
Back to Top
Yannick Puech View Drop Down
Forum Moderator
Forum Moderator


Joined: 2011 Apr 13
Location: Spain
Online Status: Offline
Posts: 1143
Direct Link To This Post Posted: 2017 Dec 22 at 6:41am
Hi Martin,

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



MAXON
Developer Support
Back to Top

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.172 seconds.