DrawText : Need a full working example
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 20/07/2012 at 09:05, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 12
Platform: Windows ;
Language(s) : C++ ;---------
I found a few posts where people said they figured out how to draw text. But they did not post enough of the code for me to build my own working example.I did find an older R11.5 version posted by Matthias that sort of works. But it has problems.
It inverts the front facing polygons of the object the tag is on. And makes them invisible.
Plus the text is always behind the object. !Cry
[URL-REMOVED]I'm posting the complete version that Matthias posted long ago(I hope that's ok?) in the hopes that someone out there knows why it's doing these unwanted things. Or has a better working version that they will be kind enough to post here.
#include "c4d.h" #include "c4d_symbols.h" #include "tsimpletag.h" #include "customgui_priority.h" //needed for the priority stuff to work #include "..\..\..\..\resource\_api\c4d_libs\lib_clipmap.h" #define PLUGIN_ID 1000007 // be sure to use a unique ID obtained from www.plugincafe.com class SimpleTag : public TagData { INSTANCEOF(SimpleTag,TagData) public: virtual Bool Message(GeListNode *node, LONG type, void *t_data); virtual Bool Init(GeListNode *node); virtual Bool GetDDescription(GeListNode *node, Description *description,DESCFLAGS_DESC &flags); virtual Bool GetDParameter(GeListNode *node, const DescID &id,GeData &t_data,DESCFLAGS_GET &flags); virtual Bool SetDParameter(GeListNode *node, const DescID &id,const GeData &t_data,DESCFLAGS_SET &flags); virtual Bool Draw(BaseTag* tag, BaseObject* op, BaseDraw* bd, BaseDrawHelp* bh); virtual EXECUTIONRESULT Execute(BaseTag *tag, BaseDocument *doc, BaseObject *op, BaseThread *bt, LONG priority, EXECUTIONFLAGS flags); static NodeData *Alloc(void) { return gNew SimpleTag; } }; Bool SimpleTag::GetDParameter(GeListNode *node, const DescID &id, GeData &t_data, DESCFLAGS_GET &flags) //Used to get the decriptions data { return SUPER::GetDParameter(node, id, t_data, flags); } Bool SimpleTag::SetDParameter(GeListNode *node, const DescID &id, const GeData &t_data, DESCFLAGS_SET &flags) //Used to change the decriptions data { return SUPER::SetDParameter(node, id, t_data, flags); } Bool SimpleTag::GetDDescription(GeListNode *node, Description *description,DESCFLAGS_DESC &flags) { //flags |= DESCFLAGS_DESC_LOADED; return TRUE; } Bool SimpleTag::Message(GeListNode *node, LONG type, void *data) { BaseTag *tag = (BaseTag* )node; //Get the tag and assign it to a variable //Do something tag->SetDirty(DIRTYFLAGS_DATA); //Used to update a Tag's AM GUI items return TRUE; } Bool SimpleTag::Init(GeListNode *node) { // intitial values for the tag when it's created are set in this section BaseTag *tag = (BaseTag* )node; //Assigns a variable to the tag's node BaseContainer *data = tag->GetDataInstance(); //Assigns a variable to that node's container data->SetBool(MYBOX,FALSE); //Sets the checkbox to disabled by default when tag is created-->looks in the description->tbasictag.h file for matching name return TRUE; } static Bool DrawText(String text, LONG xpos, LONG ypos, BaseDraw *bd) //Custom method to draw some text(static methods don't get declared in the class) { AutoAlloc<GeClipMap> cm; if(!cm) return FALSE; cm->Init(0, 0, 32); cm->BeginDraw(); LONG width = cm->TextWidth(text); //Sets the width value based on the length of the string being held in this variable LONG height = cm->TextHeight(); //Automatically calculates the maximum height of a string in the current font cm->EndDraw(); cm->Destroy(); //Resets the clip map to its initial state and frees allocated memory. //Requires a new call to Init*() before the clip map can be used again. cm->Init(width, height, 32); //Re-init the clipmap because it was previously destroyed GePrint(LongToString(width) + " " + LongToString(height)); cm->BeginDraw(); //Start editing the clipmap cm->SetColor(255, 255, 255, 255); //Sets the color of the text to white cm->TextAt(0,0,text); cm->EndDraw(); bd->SetMatrix_Screen(); //Sets the transformation matrix to screen coordinates, i.e. from (0, 0) to (width, height) bd->SetLightList(BDRAW_SETLIGHTLIST_NOLIGHTS); //Sets the lighting used by the draw functions Vector *padr = bNew Vector[4]; Vector *cadr = bNew Vector[4]; Vector *vnadr = bNew Vector[4]; //Create vectors with four values Vector *uvadr = bNew Vector[4]; padr[0] = Vector(xpos,ypos,0); padr[1] = Vector(xpos+width,ypos,0); padr[2] = Vector(xpos+width,ypos+height,0); padr[3] = Vector(xpos,ypos+height,0); cadr[0] = Vector(1,1,1); cadr[1] = Vector(1,1,1); cadr[2] = Vector(1,1,1); cadr[3] = Vector(1,1,1); vnadr[0] = Vector(0,0,1); vnadr[1] = Vector(0,0,1); vnadr[2] = Vector(0,0,1); vnadr[3] = Vector(0,0,1); uvadr[0] = Vector(0,0,0); uvadr[1] = Vector(1,0,0); uvadr[2] = Vector(1,1,0); uvadr[3] = Vector(0,1,0); BaseBitmap *cmbmp = cm->GetBitmap(); //Create a BaseBitmap instance to use in the DrawTexture function if(!cmbmp) return FALSE; BaseBitmap *bmp = cmbmp->GetClone(); //Create a clone of the above bitmap instance if(!bmp) return FALSE; BaseBitmap *alpha = bmp->GetInternalChannel(); //Create a third Bitmap instance to hold the alpha data alpha = bmp->AddChannel(TRUE, FALSE); if(!alpha) { BaseBitmap::Free(bmp); //Error handling: frees memory of the alpha bitmap instance if there was an error creating it return FALSE; } LONG x,y; for(y=0; y<height; y++) { for(x=0; x<width; x++) { UWORD r; bmp->GetPixel(x,y,&r,&r,&r); bmp->SetAlphaPixel(alpha, x, y, r); //r is the opacity } } bd->DrawTexture(bmp,padr,cadr,vnadr,uvadr,4,DRAW_ALPHA_NORMAL,DRAW_TEXTUREFLAGS_0); BaseBitmap::Free(bmp); //Free the memory being used by this bitmap instance bDelete(padr); bDelete(cadr); bDelete(vnadr); //Free the memory being used by these pointers bDelete(uvadr); return TRUE; } Bool SimpleTag::Draw(BaseTag *tag, BaseObject *op, BaseDraw *bd, BaseDrawHelp *bh) { if(tag->GetData().GetBool(MYBOX)) //If the 'MYBOX' checkbox attribute is enabled { DrawText("Hello World", 256, 256, bd); //Draw text on the screen at x,y position 256,256 } return TRUE; } EXECUTIONRESULT SimpleTag::Execute(BaseTag *tag, BaseDocument *doc, BaseObject *op, BaseThread *bt, LONG priority, EXECUTIONFLAGS flags) { return EXECUTIONRESULT_OK; } Bool RegisterSimpleTag(void) { String path=GeLoadString(IDS_SIMPLETAG); if (!path.Content()) return TRUE; // points to the res->c4d_symbols file which conatins the enum "IDS_SIMPLETAG" entry return RegisterTagPlugin(PLUGIN_ID,path,TAG_EXPRESSION|TAG_VISIBLE,SimpleTag::Alloc,"tsimpletag",AutoBitmap("myicon.tif"),0); }
If you know why this example doesn't work properly(clipping the object faces). Or if have a working version of drawing text that works better than this. Please post it.
It would very helpful.Thanks,
-ScottA
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/07/2012 at 11:54, xxxxxxxx wrote:
This is apparently an issue in the way a Tag's "Draw()" routine is called vs other plugin types (Generator, Tool, etc). If a Tag's Draw() routine alters the BaseDraw Matrix (ie. bd->SetMatrix_Screen()), then it needs to set it back (example code from all other plugin types don't do this)...
... DrawText("Hello World", 256, 256, bd); //Draw text on the screen at x,y position 256,256 //--------------------------------------------------------------------------------------- // There appears to be a difference (bug?) in the behavior of a (expression) Tag that // alters the BaseDraw Matrix (ie. bd->SetMatrix_Screen()) vs. how other objects // (Generators, Tools, etc.) that alter it when drawing into the viewport... // // If a (expression) Tag alters the matrix, it needs to set it back to what it was before // returning (examples of other object/plugin types don't do this). //--------------------------------------------------------------------------------------- bd->SetMatrix_Matrix(op, bh->GetMg()); ...
...I'm not sure if the above is exactly the correct matrix to use, but it seems to work.
Note that this is only an issue when OpenGL is enabled - this seems to be the same issue that Rui is having with his plugin.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/07/2012 at 12:16, xxxxxxxx wrote:
Thank you.
That fixed the invisible faces problem.Any ideas on how to make the text show in front of the object?
I'm thinking maybe: bd->SetMatrix_Screen(); is not the correct thing to use?I also vaguely remember reading something Matthias posted about using BaseDraw inside of the handles method to get a different result. Possibly related to visibility. But I can't remember the specifics.
Not sure if that has anything to do with this problem.
This whole drawing subject needs to be much better documented. I hope Yannick is working on it.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/07/2012 at 12:24, xxxxxxxx wrote:
I hadn't looked into the depth issue yet (except to note that it does display in front of the object it's attached to - if that's the selected object).
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/07/2012 at 12:59, xxxxxxxx wrote:
That's strange.
In the example I posted + your addition. The text is always a background type object and gets hidden by any object in the scene. No matter what's selected.I'm using R12 to test this. Not sure if that makes any difference.
I still need to convert it to R13. Because R13 does not have a TextHeight() function anymore.
Not sure if anything else has been changed between R12 & R13 for BD.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 21/07/2012 at 13:25, xxxxxxxx wrote:
Yeah, may be a difference in versions. BTW, look for GetTextHeight(), instead.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 08:22, xxxxxxxx wrote:
This seems to be rather a question about BaseDraw::DrawTexture. My old DrawText routine was just one (and probably the easiest) way to draw text through the GeClipMap class.
I'll have to check how this works in the current release. Sorry, can't check for older versions than R13.
cheers,
Matthias -
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 26/07/2012 at 08:33, xxxxxxxx wrote:
R13 is fine Matthias.
I will be forcing myself to dump R12 entirely when R14 comes out. Even if I hate working in it.Your old code works pretty darn well for me(with Giblet's addition). With the small problem that the text is always a background object instead of a foreground object.
That's really the only problem that I would like to see solved.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 27/08/2012 at 11:26, xxxxxxxx wrote:
Hurray!!
I figured out a way to make this darned thing work!!
It turns out that the bitmap text object getting covered by objects in the scene is an OpenGL bug(or limitation). And it only works properly on a very few select video cards.
But I found a way to force it to work with all video cards.The trick:
There needs to be a dummy 2D object(with no length) listed in the code first.
Then the you can add GeClipMap() objects like the bitmap text object. And they no longer get covered up by that OpenGL error.Here's an example from a tag based plugin with a switch to turn GeClipMap() text objects on/off:
Bool SimpleTag::Draw(BaseTag *tag, BaseObject *op, BaseDraw *bd, BaseDrawHelp *bh ) { //bd = doc->GetActiveBaseDraw(); //This is not needed because BaseDraw is already created in the parenths //if(bd) return FALSE; if(tag->GetData().GetBool(MYBOX)) //If the 'MYBOX' checkbox attribute is enabled { //There is an OpenGL problem with most video cards that makes the drawn object get covered up by objects in the scene //This is a work around to deal with that problem //We need to draw a dummy 2D object first...Then draw the actual object we want to see as a 2D HUD object bd->SetMatrix_Screen(); //Use the screen's matrix to draw on bd->DrawLine2D(Vector(0, 0, 0), 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 //Now we can create the text HUD object that we want to see in the view AutoAlloc<GeClipMap> cm; //Create an instance of the GeClipMap class if(!cm) return FALSE; String text = "Hello World"; //The text that we will see in the HUD cm->Init(0, 0, 32); //Initializes the GeClipMap class to use this variable(cm) as 32 bit cm->BeginDraw(); //Start drawing the object. This must be used before drawing the text LONG width = cm->GetTextWidth(text); //Gets the width of the text LONG height = cm->GetTextHeight(); //Gets the width 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); 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(BDRAW_SETLIGHTLIST_NOLIGHTS); //Use other options for different results if desired //Now we create the four vector variables that will determine the Size&Shape of the text we're drawing //NOTE: We're creating a four point plane that has a text image on it...Not text created with a bunch of vectors Vector *padr = bNew Vector[4]; Vector *cadr = bNew Vector[4]; Vector *vnadr = bNew Vector[4]; Vector *uvadr = bNew Vector[4]; LONG xpos=255; //The X screen location of the left upper corner of the plane object the text bitmap is on LONG 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[0] = Vector(xpos,ypos,0); padr[1] = Vector(xpos+width,ypos,0); padr[2] = Vector(xpos+width,ypos+height,0); padr[3] = Vector(xpos,ypos+height,0); //Now we set the color vector values for the plane object //We set it to white because we'll be using an alpha on it later on cadr[0] = Vector(1,1,1); cadr[1] = Vector(1,1,1); cadr[2] = Vector(1,1,1); cadr[3] = Vector(1,1,1); //Now we set up the normals directions for the four point plane object that holds the text bitmap vnadr[0] = Vector(0,0,1); vnadr[1] = Vector(0,0,1); vnadr[2] = Vector(0,0,1); vnadr[3] = Vector(0,0,1); //Now we set up the UV's for the four point plane object that holds the text bitmap uvadr[0] = Vector(0,0,0); uvadr[1] = Vector(1,0,0); uvadr[2] = Vector(1,1,0); uvadr[3] = Vector(0,1,0); BaseBitmap *cmbmp = NULL; cmbmp = cm->GetBitmap(); //Get the bitmap we're using and assign it to a variable(cmbmp) if(!cmbmp) return FALSE; BaseBitmap *bmp = NULL; bmp = cmbmp->GetClone(); //Get a copy of that bitmap variable so we can create an alpha version of it if(!bmp) return FALSE; BaseBitmap *alpha = NULL; alpha = bmp->GetInternalChannel(); //Get at the RGBA channels of the bitmap copy if(!alpha) alpha = bmp->AddChannel(TRUE, FALSE); //Makes the copy an alpha type of bitmap if(!alpha) { BaseBitmap::Free(bmp); return FALSE; } //Apply the alpha bitmap to the solution so only the text is visible on the screen LONG x,y; for(y=0; y<height; y++) { for(x=0; x<width; x++) { UWORD r; bmp->GetPixel(x,y,&r,&r,&r); bmp->SetAlphaPixel(alpha, x, y, r); //r is the opacity } } bd->DrawTexture(bmp,padr,cadr,vnadr,uvadr,4,DRAW_ALPHA_NORMAL,DRAW_TEXTUREFLAGS_0); //Does that actual drawing of the bitmap to the screen BaseBitmap::Free(bmp); //Free any memory used by BaseBitmap bDelete(padr); bDelete(cadr); //Delete all the empty pointers bDelete(vnadr); bDelete(uvadr); //2D drawing functions disable the Z buffer making object's in the scene half invisible //There are two ways to fix this: bd->SetDepth(TRUE); //This fixes the OpenGL problem //bd->SetMatrix_Matrix(op, bh->GetMg(),5); //This also fixes the OpenGL problem } return TRUE; }
@Matthias,
I would like to post a working example plugin of this on my website.
Do you mind if I post an example that uses some of your code you've posted here?
I'll give you credit in the source files.-ScottA
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 20/11/2012 at 01:06, xxxxxxxx wrote:
I know this thread is old, but I wanted to add that you may also use a SceneHook for drawing your 2D stuff.
The problem does not occur then.I wrote an article on the C4Dprogramming blog about that:
http://c4dprogramming.wordpress.com/2012/11/15/2d-drawing-using-a-scenehook/The example plugin in the article keeps it simple by just drawing 2D circles, but all I wrote there also applies to drawing text.
-
THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED
On 20/11/2012 at 08:37, xxxxxxxx wrote:
Thanks for posting this.
Most of the time when I draw something on the screen I want it to always show up regardless of what's selected in the scene. So I will probably continue to use my Dummy2D object rather than create a whole new scene hook. It's much quicker and simpler.
But it's nice to know that a scene hook will give use more control over it.I still think this is a bug. And we should be able to set the Z-depth values in our code to force 2D objects to the front of the screen without it causing other drawing problems.
-ScottA