DrawTexture(): Alpha problem

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 29/08/2012 at 10:39, xxxxxxxx wrote:

Here is the code for a tag plugin that will draw text onto the screen like a HUD display using the DrawTexture() function.
I've converted this to python from my C++ plugin. But the SDK uses an unsigned short int (UWORD) in the alpha section that I do not know how to convert to python.
So I'm hoping someone here will know how to convert that part from C++ to python.

import c4d,os  
from c4d import plugins, bitmaps, documents  
  
PLUGIN_ID = 1000003  #TESTING ID# Only!!!  
  
class DrawText(plugins.TagData) :  
  def Init(self, tag) :  
      return True  
  
  def Draw(self, tag, op, bd, bh) :  
    
  doc = documents.GetActiveDocument()  
  obj = tag.GetObject()                                       #The object the python tag is on  
  if obj.GetType() == 5100:  
      points = obj.GetAllPoints()              
      globalpnts = obj.GetMg() * points[4]   
  
##### There is an OpenGL bug that makes the text hide behind objects    #####  
##### This is a dummy 2D object with zero length which works around that bug #####  
  bd.SetPen(c4d.Vector(1.0, 1.0, 1.0))  
  bd.SetMatrix_Screen()                                       #Use the screen's matrix to draw on  
  bd.DrawLine2D(c4d.Vector(0, 0, 0), c4d.Vector(0, 0, 0))     #Draw a line with a zero length<---This is our dummy object  
  bd.SetDepth(True)                                           #This fixes drawing problems when using 2D functions  
###############################################################  
  
  text = "My Text"                            #The text that will display on the screen  
  
  cm = c4d.bitmaps.GeClipMap()  
  cm.Init(0, 0, 32)  
  cm.BeginDraw()                              #Start drawing the object. This must be used before drawing the text  
  width = cm.TextWidth(text)                  #Gets the width of the text  
  height = cm.TextHeight()                    #Gets the height of the text  
  cm.EndDraw()                                #Tell C4D we're done drawing the text  
  cm.Destroy()                                #Release any memory used by the GeClipMap class  
  
  cm.Init(width, height, 32)                  #Dynamically sets the size of the virtual plane the text is on  
  cm.BeginDraw()  
  cm.SetColor(255, 255, 255, 255)             #Sets the color of the text to white  
  cm.TextAt(0,0,text)  
  cm.EndDraw()          
  bd.SetMatrix_Screen()                       #We always need a matrix to draw things...In this case we'll use the screen's matrix  
  bd.SetLightList(c4d.BDRAW_SETLIGHTLIST_NOLIGHTS)#Use other options for different results if desired      
    
  xpos=255                                     #The X screen location of the left upper corner of the plane object the text bitmap is on  
  ypos=255                                     #The Y screen location of the left upper corner of the plane object the text bitmap is on  
  
  
  #Now we set the actual vector postions for the four point plane object that holds the text bitmap  
  padr = [  
  (c4d.Vector(xpos,ypos,0)),                          #upper left corner  
  (c4d.Vector(xpos+width,ypos,0)),                    #upper right corner  
  (c4d.Vector(xpos+width,ypos+height,0)),             #lower right corner  
  (c4d.Vector(xpos,ypos+height,0))                    #lower left corner  
  ]      
  
  #Now we set the color vector values for the plane object   
  cadr = [  
  (c4d.Vector(1,1,1)),                            
  (c4d.Vector(1,1,1)),                   
  (c4d.Vector(1,1,1)),            
  (c4d.Vector(1,1,1))                
  ]  
  
  
  #Now we set up the normals directions for the four point plane object that holds the text bitmap  
  vnadr = [  
  (c4d.Vector(0,0,1)),                            
  (c4d.Vector(0,0,1)),                   
  (c4d.Vector(0,0,1)),            
  (c4d.Vector(0,0,1))                
  ]      
  
  #Now we set up the UV's for the four point plane object that holds the text bitmap  
  uvadr = [  
  (c4d.Vector(0,0,0)),                            
  (c4d.Vector(1,0,0)),                   
  (c4d.Vector(1,1,0)),            
  (c4d.Vector(0,1,0))                
  ]          
  
  cmbmp = bitmaps.BaseBitmap()  
  cmbmp = cm.GetBitmap()  
        
  bmp = bitmaps.BaseBitmap()  
  bmp = cm.GetBitmap()  
    
  alpha = bmp.GetInternalChannel()               #Get at the RGBA channels of the bitmap copy  
  alpha = bmp.AddChannel(True, False)  
    
    
        
  ################## This is the C++ looop that needs to be converted to python########  
  ######## GetPixel() stores color data r,g,b in a UWORD variable that doesn't exist in python #######       
  
  #Apply the alpha bitmap to the solution so only the text is visible on the screen  
  #The alpha acts like a matte object. So if you find that your text is getting cut off..Your alpha might be too small  
  #You can increase the width and height of the alpha to fix that problem  
  
  # LONG x,y;  
      # for(y=0; y<height; y++)  
      # {  
        # for(x=0; x<width; x++)  
        # {  
           # UWORD r;                                //An unsigned short int variable...Can hold absolute values between 0->65,535  
           # bmp->GetPixel(x,y,&r,&r,&r);            //Get each pixel's X.Y coords and assign them to pointers (r,g,b) (0 <= r/g/b <= 255)   
           # bmp->SetAlphaPixel(alpha, x, y, r);     //r is the opacity  
        # }  
      # }  
  ########################################################################################################  
    
    
  bd.DrawTexture(bmp,padr,cadr,vnadr,uvadr,4,c4d.DRAW_ALPHA_NORMAL,c4d.DRAW_TEXTUREFLAGS_0)  
  bd.SetDepth(True)      
    
        
  return True  
  
if __name__ == "__main__":  
  path, file = os.path.split(__file__)  
  bmp = bitmaps.BaseBitmap()  
  bmp.InitWith(os.path.join(path, "res", "icon.tif"))  
  plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "DrawText", g = DrawText, description = "drawtext", icon = bmp, info = c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE)

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 30/08/2012 at 07:04, xxxxxxxx wrote:

Hi,

C++ uses more 'precise' types but don't worry about that in Python. You can use a Python int to hold the pixel color (returned by GetPixel()) without problem.

This code is pretty interesting and not difficult to understand.

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 30/08/2012 at 07:39, xxxxxxxx wrote:

Originally posted by xxxxxxxx

 
#The alpha acts like a matte object. So if you find that your text is getting cut off..Your alpha might be too small  
#You can increase the width and height of the alpha to fix that problem  

What do you mean by increasing the width and height of the alpha?

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 30/08/2012 at 08:10, xxxxxxxx wrote:

Hi Yannick,

I'm having trouble with that loop. Because the C++ version is using pointers to insert three color values(I'm assuming vectors) into it. And I don't know how to create a python variable that is the right type to do that. I tried c4d.Vector but it didn't work.
The sdk has a page listing color as a struct. I'm not sure if this is what I need to do. Or how to do it.

    for y in xrange(height) :  
      for x in xrange(width) :  
          r  <----------------------#How do I define this as a three value color variable?    
          bmp.GetPixel(x,y,r,r,r)  
          bmp.SetAlphaPixel(alpha, x, y, r)

-Per your question about about the width and height of the alpha.
If you scale the virtual plane by placing their vectors father apart(padr). I've found that the alpha will not always scale up enough. So the text can sometimes get chopped off.
So adding something like width+5 and height+5 in the alpha loop will fix that problem by making the alpha bigger so it doesn't cut off the text.
This also seems to stretch the text and make it blurrier the more it's scaled up. So I'm not sure if this is the proper way to scale the text. But it's the only way I've found to do it (But it's probably wrong).
I probably should have written better notes about that one.

*Edit- It just dawned on me that to scale the text. We might need to use the Font function to do that. But I haven't been able to figure out how to use it.
The Blit() function is another very cool function that could be all kinds of fun to use for drawing animated things to the screen. But the SDK gives me no clue who how to use it.

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 30/08/2012 at 10:22, xxxxxxxx wrote:

One other additional note about FontData in the python docs.
It was added to the SDK. But what is there is very vague on how to use it.

In C++ this is an example how we do it:

    BaseContainer *data=((BaseList2D* )node)->GetDataInstance(); //Create a new Base Container and assign to a variable  
  if (!data) return FALSE;  
  
  GeData d2(FONTCHOOSER_DATA, DEFAULTVALUE);                       //Create a parameter container variable with font flags  
  FontData* fd = (FontData* )d2.GetCustomDataType(FONTCHOOSER_DATA); //Get the font data from above and assign it to a variable  
  if (!fd) return FALSE;  
  
  BaseContainer bc;                                      //Create a new Base Container and assign to a variable  
  GeClipMap::EnumerateFonts(&bc, GE_CM_FONTSORT_FLAT);   //Grab all the fonts and fill the BaseContainer(bc) with that list  
  
  LONG i=0;  
  while (TRUE)  
  {  
      LONG id = bc.GetIndexId(i++); //Loop through the BaseContainer to get each individual element that currently holds font data   
      if (id==NOTOK) break;         //Exit the while loop if there are no more container elements found  
  
      BaseContainer *fbc = bc.GetContainerInstance(id); //Creates a new temporary Base Container holding the indexes of BaseContainer bc  
      if (fbc)          //If there is an index found   
      {  
       String name;     //Create an empty string variable    
       if (!GeClipMap::GetFontName(fbc, GE_FONT_NAME_DISPLAY, &name)) return FALSE;  //If no font names are found in the index. Exit the while loop  
  
       if (name.Compare("Arial") == 0) //Compares the String object with another string   
        {  
         fd->SetFont(fbc);   //Set the font to the value of the variable fbc  
         if (!data->SetData(MY_FONT,d2)->GetType()) return FALSE; //Error handling  
  
         return TRUE;  
        }  
      }  
  }  
  
  //This code block sets the font to the default if the Arial font is not found  
  BaseContainer bc2;  
  if (!GeClipMap::GetDefaultFont(GE_FONT_DEFAULT_SYSTEM, &bc2)) return FALSE;  
  fd->SetFont(&bc2);  
  if (!data->SetData(MY_FONT,d2)->GetType()) return FALSE;

In the python docs there is no information on how to do the same thing.
-No information how to create a variable with FONTCHOOSER_DATA in it.
-No information on how to iterate all the fonts and then store them in a container
-No information on how to then use those stored fonts and set them as needed

Without that information. I can't use any of the various font functions in the python SDK.

-ScottA

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 31/08/2012 at 01:05, xxxxxxxx wrote:

Originally posted by xxxxxxxx

I'm having trouble with that loop. Because the C++ version is using pointers to insert three color values(I'm assuming vectors) into it. And I don't know how to create a python variable that is the right type to do that. I tried c4d.Vector but it didn't work.
The sdk has a page listing color as a struct. I'm not sure if this is what I need to do. Or how to do it.

    for y in xrange(height) :  
      for x in xrange(width) :  
          r  <----------------------#How do I define this as a three value color variable?    
          bmp.GetPixel(x,y,r,r,r)  
          bmp.SetAlphaPixel(alpha, x, y, r)

The current documentation of BaseBitmap.GetPixel() is confusing but you see that it says that it returns the pixel color as a list of integer values, so you can do this:

r, g, b = bmp.GetPixel(x,y)

And in C++, r isn't a three color variable but it works because r, g and b holds the same value in the bitmap (greyscale) so it assigns three times the same value to r.

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 31/08/2012 at 01:29, xxxxxxxx wrote:

Originally posted by xxxxxxxx

-Per your question about about the width and height of the alpha.
If you scale the virtual plane by placing their vectors father apart(padr). I've found that the alpha will not always scale up enough. So the text can sometimes get chopped off.
So adding something like width+5 and height+5 in the alpha loop will fix that problem by making the alpha bigger so it doesn't cut off the text.
This also seems to stretch the text and make it blurrier the more it's scaled up. So I'm not sure if this is the proper way to scale the text. But it's the only way I've found to do it (But it's probably wrong).
I probably should have written better notes about that one.

What I've done is to have a minimum alpha so the text isn't chopped off:

r,g,b = bmp.GetPixel(x, y)
if r < 150:
    r = 150
bmp.SetAlphaPixel(alpha, x, y, r)

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 31/08/2012 at 01:51, xxxxxxxx wrote:

Originally posted by xxxxxxxx

-No information how to create a variable with FONTCHOOSER_DATA in it.

In Python you can get the default font container for FONTCHOOSER_DATA calling

ft = c4d.GetCustomDataTypeDefault(c4d.FONTCHOOSER_DATA)

Or you can also create a default FontData with

fd = c4d.FontData()

Originally posted by xxxxxxxx

-No information on how to iterate all the fonts and then store them in a container

It's currently not possible to enumerate all the fonts and get information on them because EnumerateFonts(), GetFontName(), GetFontDescription(), GetDefaultFont(), GetFontSize(), SetFontSize() are missing in the Python SDK.

Originally posted by xxxxxxxx

-No information on how to then use those stored fonts and set them as needed

FontData has SetFont()/GetFont() methods in Python too.

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 31/08/2012 at 08:34, xxxxxxxx wrote:

Thanks a lot Yannick. That's got it working now.
I'm so bad at interpreting those little (semi-hidden) things in the SDKs.

I found another error in the code I posted. So here's the entire code again that should work properly:

import c4d,os  
from c4d import plugins, bitmaps, documents  
  
PLUGIN_ID = 1000003  #TESTING ID# Only!!!  
  
class DrawText(plugins.TagData) :  
  def Init(self, tag) :  
      return True  
  
  def Draw(self, tag, op, bd, bh) :  
    
  doc = documents.GetActiveDocument()  
  obj = tag.GetObject()                                       #The object the python tag is on  
  if obj.GetType() == 5100:  
      points = obj.GetAllPoints()              
      globalpnts = obj.GetMg() * points[4]   
  
  bd.SetPen(c4d.Vector(1.0, 1.0, 1.0))  
  bd.SetMatrix_Screen()                                       #Use the screen's matrix to draw on  
  bd.DrawLine2D(c4d.Vector(0, 0, 0), c4d.Vector(0, 0, 0))     #Draw a line with a zero length<---This is our dummy object  
  bd.SetDepth(True)                                           #This fixes drawing problems when using 2D functions  
  
  text = "My Text"                            #The text that will display on the screen  
  
  cm = c4d.bitmaps.GeClipMap()  
  cm.Init(0, 0, 32)  
  cm.BeginDraw()                              #Start drawing the object. This must be used before drawing the text  
  width = cm.TextWidth(text)                  #Gets the width of the text  
  height = cm.TextHeight()                    #Gets the height of the text  
  cm.EndDraw()                                #Tell C4D we're done drawing the text  
  cm.Destroy()                                #Release any memory used by the GeClipMap class  
  
  cm.Init(width, height, 32)                  #Dynamically sets the size of the virtual plane the text is on  
  cm.BeginDraw()  
  cm.SetColor(255, 255, 255, 255)             #Sets the color of the text to white  
  cm.TextAt(0,0,text)  
  cm.EndDraw()          
  bd.SetMatrix_Screen()                       #We always need a matrix to draw things...In this case we'll use the screen's matrix  
  bd.SetLightList(c4d.BDRAW_SETLIGHTLIST_NOLIGHTS)#Use other options for different results if desired      
    
  xpos=255                                     #The X screen location of the left upper corner of the plane object the text bitmap is on  
  ypos=255                                     #The Y screen location of the left upper corner of the plane object the text bitmap is on  
  
  
  #Now we set the actual vector postions for the four point plane object that holds the text bitmap  
  padr = [  
  (c4d.Vector(xpos,ypos,0)),                          #upper left corner  
  (c4d.Vector(xpos+width,ypos,0)),                    #upper right corner  
  (c4d.Vector(xpos+width,ypos+height,0)),             #lower right corner  
  (c4d.Vector(xpos,ypos+height,0))                    #lower left corner  
  ]      
  
  #Now we set the color vector values for the plane object   
  cadr = [  
  (c4d.Vector(1,1,1)),                            
  (c4d.Vector(1,1,1)),                   
  (c4d.Vector(1,1,1)),            
  (c4d.Vector(1,1,1))                
  ]  
  
  
  #Now we set up the normals directions for the four point plane object that holds the text bitmap  
  vnadr = [  
  (c4d.Vector(0,0,1)),                            
  (c4d.Vector(0,0,1)),                   
  (c4d.Vector(0,0,1)),            
  (c4d.Vector(0,0,1))                
  ]      
  
  #Now we set up the UV's for the four point plane object that holds the text bitmap  
  uvadr = [  
  (c4d.Vector(0,0,0)),                            
  (c4d.Vector(1,0,0)),                   
  (c4d.Vector(1,1,0)),            
  (c4d.Vector(0,1,0))                
  ]          
  
  cmbmp = bitmaps.BaseBitmap()                 #Get the bitmap image(the text) being displayed on the virtual plane  
  cmbmp = cm.GetBitmap()  
        
  bmp = bitmaps.BaseBitmap()                   #Get a copy of that image(we'll use this to create an alpha background channel)   
  bmp = cmbmp.GetClone()  
    
  alpha = bmp.GetInternalChannel()             #Get at the RGBA channels of the bitmap copy  
  alpha = bmp.AddChannel(True, False)          #Add a channel and assign it to a variable so we can use it later on  
    
        
  #Apply the alpha bitmap to the solution so only the text is visible on the screen  
  #The alpha acts like a matte object. So if you find that your text is getting cut off..Your alpha might be too small  
  #You can increase the width and height of the alpha to fix that problem by adding numbers to height+ and width+      
    
  for y in xrange(height) :  
      for x in xrange(width) :  
          r,g,b = bmp.GetPixel(x, y)   
          bmp.SetAlphaPixel(alpha, x, y, r)  
            
  
  #Optionally....You can also hard code an alpha size to control the size of the alpha  
  #r,g,b = bmp.GetPixel(x, y)  
  #if r < 150:  
  #    r = 150  
  #bmp.SetAlphaPixel(alpha, x, y, r)              
  
    
  bd.DrawTexture(bmp,padr,cadr,vnadr,uvadr,4,c4d.DRAW_ALPHA_NORMAL,c4d.DRAW_TEXTUREFLAGS_0)  
  bd.SetDepth(True)      
    
        
  return True  
  
if __name__ == "__main__":  
  path, file = os.path.split(__file__)  
  bmp = bitmaps.BaseBitmap()  
  bmp.InitWith(os.path.join(path, "res", "icon.tif"))  
  plugins.RegisterTagPlugin(id = PLUGIN_ID, str = "DrawText", g = DrawText, description = "drawtext", icon = bmp, info = c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE)

As always...Thanks a ton for your help Yannick. :thumbsup:
-ScottA