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. 👍
    -ScottA


Log in to reply