Textured Text & Billboard text
by Peter Simard · 02/23/2006 (10:51 am) · 25 comments
Download Code File
This resource is based on the textured font resource. You can create the font images you need using www.lmnopc.com/bitmapfontbuilder/. Simply add the 2 attached files to your project and compile. Below is sample code you can place at the end of your player.cc's RenderImage method to have true names above players heads.
Examples:
Name from far away
Name close up
Name partially hidden
player.cc
player.h
This resource is based on the textured font resource. You can create the font images you need using www.lmnopc.com/bitmapfontbuilder/. Simply add the 2 attached files to your project and compile. Below is sample code you can place at the end of your player.cc's RenderImage method to have true names above players heads.
Examples:
Name from far away
Name close up
Name partially hidden// Render Name
if(!nameBitmap && getShapeName() != NULL)
{
generateNameBitmap();
}
if(nameBitmap)
{
MatrixF ModelView;
Point4F Position;
const Point4F XRotation(1,0,0,0);
const Point4F YRotation(0,1,0,0);
const Point4F ZRotation(0,0,1,0);
F32 LeftTexPos;
F32 RightTexPos;
glEnable ( GL_TEXTURE_2D );
glBindTexture ( GL_TEXTURE_2D, nameTexture.getGLName() );
glEnable ( GL_BLEND );
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA );
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
ColorF nameColor;
nameColor.set(0, 1, 0, 0.2f);
glColor4f(nameColor.red, nameColor.green, nameColor.blue, nameColor.alpha);
glEnable ( GL_ALPHA_TEST );
glEnable ( GL_CULL_FACE );
glAlphaFunc ( GL_GREATER, 0.1f );
glPushMatrix();
// Perform Spherical Billboarding.
MatrixF posMatrix = getRenderTransform();
Point3F pos = posMatrix.getPosition();
pos.z += 2.5;
posMatrix.setPosition(pos);
dglMultMatrix(&posMatrix);
dglGetModelview(&ModelView);
ModelView.setColumn(0, XRotation);
ModelView.setColumn(1, YRotation);
ModelView.setColumn(2, ZRotation);
dglLoadMatrix(&ModelView);
// Change the number it divides by to change the font size
F32 Width = nameTexture.getWidth() / 140.0f;
F32 Height = nameTexture.getHeight() / 70.0f;
LeftTexPos = 0.0f;
RightTexPos = 1.0f - LeftTexPos;
// Draw Billboard.
glBegin(GL_QUADS);
// Draw Top part of billboard.
glTexCoord2f (LeftTexPos,0);
glVertex3f (-Width,0,Height);
glTexCoord2f (RightTexPos,0);
glVertex3f (+Width,0,Height);
glTexCoord2f (RightTexPos,1);
glVertex3f (+Width,0,0);
glTexCoord2f (LeftTexPos,1);
glVertex3f (-Width,0,0);
glEnd();
// Restore our Modelview.
glPopMatrix();
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
glDisable ( GL_CULL_FACE );
glDisable ( GL_ALPHA_TEST );
glDisable ( GL_BLEND );
glDisable ( GL_TEXTURE_2D );
}player.cc
void Player::generateNameBitmap()
{
nameBitmap = new BitmapText();
nameBitmap->setText(getShapeName());
nameTexture = TextureHandle(NULL, nameBitmap, BitmapKeepTexture);
}
Player::Player()
{
nameBitmap = 0;
nameTexture = 0;
....
}player.h
#ifndef _GBITMAPTEXT_H_
#include "dgl/bitmapText.h"
#endif
BitmapText* nameBitmap;
TextureHandle nameTexture;
void generateNameBitmap();
#2
other notes:
player.h needs at the beginning:
#ifndef _GBITMAPTEXT_H_
#include "dgl/bitmapText.h"
#endif
bitmapText.h and bitmapText.cc go in the /engine/dgl directory, and ariel3.png goes in example/common/ui/cache.
For some reason, it only worked the 1st time - subsequent missions and after restarting, the names seem to have disappeared.
02/20/2006 (12:55 am)
Hm - 1.4 TLK doesn't have a Render Object in player.cc. I tossed it on the end of Player::renderImage.other notes:
player.h needs at the beginning:
#ifndef _GBITMAPTEXT_H_
#include "dgl/bitmapText.h"
#endif
bitmapText.h and bitmapText.cc go in the /engine/dgl directory, and ariel3.png goes in example/common/ui/cache.
For some reason, it only worked the 1st time - subsequent missions and after restarting, the names seem to have disappeared.
#3
02/20/2006 (12:00 pm)
Thanks for the report. I updated the resource to include those changes.
#4
If we change
if(!nameBitmap && getShapeName() != NULL)
{
generateNameBitmap();
}
if(nameBitmap)
{
...
to
if(getShapeName() != NULL)
{
generateNameBitmap();
...
it works, but I suspect that this isn't an optimal solution.
Also changing
MatrixF posMatrix = getTransform();
to
MatrixF posMatrix = getRenderTransform();
results in a much smoother appearance when the avatar is running around.
02/21/2006 (11:19 pm)
The above code still doesn't work properly on a stock installation of TLK 1.4 - Its going haywire when Kork is running around.If we change
if(!nameBitmap && getShapeName() != NULL)
{
generateNameBitmap();
}
if(nameBitmap)
{
...
to
if(getShapeName() != NULL)
{
generateNameBitmap();
...
it works, but I suspect that this isn't an optimal solution.
Also changing
MatrixF posMatrix = getTransform();
to
MatrixF posMatrix = getRenderTransform();
results in a much smoother appearance when the avatar is running around.
#5
02/23/2006 (11:10 am)
Thanks for the getRenderTransform fix. It was actually in my current code but I forgot to update the resource. I'm not sure why you are having to generate the bitmap for each frame. The texture should be kept in memory. Doing it that way will work but it will cause slowdowns especially if there is a lot of units on screen. Make sure you are setting the textures to null inside the player constructor, as that could be why.
#6
I found that I actually didn't want the names to scale realistically with distance - if anyone feels the same:
F32 Width = nameTexture.getWidth() / 140.0f * sqrt(dist);
F32 Height = nameTexture.getHeight() / 140.0f * sqrt(dist);
Where 140.0f is just a scaling factor - the names will still scale, but not as quickly.
Also slipping in a distance filter
if(nameBitmap && dist < 100.0)
..
Since no one really sees the model at that range, much less a name attached to it.
Yay - now that the name works right, time to work on a damage bar & other billboard stuff :D
02/23/2006 (11:26 pm)
Ah yes, that would do it.I found that I actually didn't want the names to scale realistically with distance - if anyone feels the same:
F32 Width = nameTexture.getWidth() / 140.0f * sqrt(dist);
F32 Height = nameTexture.getHeight() / 140.0f * sqrt(dist);
Where 140.0f is just a scaling factor - the names will still scale, but not as quickly.
Also slipping in a distance filter
if(nameBitmap && dist < 100.0)
..
Since no one really sees the model at that range, much less a name attached to it.
Yay - now that the name works right, time to work on a damage bar & other billboard stuff :D
#7
02/24/2006 (9:39 pm)
I hate rar formats. But it looks good and I'm going to try it.
#8
(1) I did not want my own vehicles name to be in my face all the time so I only display the names of the other player/vehicles. To do that add the following bold code
(2) I found that when facing one direction the text was brighter than when facing the opposite. It turns our that the glLighting was affecting the billboard and needed to be turned off. I added the bold bits
At the end that section add if (wasLit)
glEnable(GL_LIGHTING);
I also added Pauls dist changes as it is better suited to vehicles.
One problem is that by using the font bitmap you limit your game to that character set and thus have no Unicode support for other countries were you might get sales. I'm no Unicode expert but I know the guiMlTextcontrol allows drop shadows etc and perhaps as an Unicode alternative the guishapenamehud can be modified/enhanced by adding those text feature from guiMlTextcontrol
02/25/2006 (1:14 pm)
OK, I added it to the wheeledvehicle class and made a few minor changes.(1) I did not want my own vehicles name to be in my face all the time so I only display the names of the other player/vehicles. To do that add the following bold code
[b]if(isControlObject())
return;[/b]
// Render Name
if(!nameBitmap && getShapeName() != NULL)
{
generateNameBitmap();
}(2) I found that when facing one direction the text was brighter than when facing the opposite. It turns our that the glLighting was affecting the billboard and needed to be turned off. I added the bold bits
[b]bool wasLit = glIsEnabled(GL_LIGHTING); glDisable(GL_LIGHTING);[/b] glEnable ( GL_TEXTURE_2D ); glBindTexture ( GL_TEXTURE_2D, nameTexture.getGLName() ); glEnable ( GL_BLEND ); glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ); glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
At the end that section add if (wasLit)
glEnable(GL_LIGHTING);
I also added Pauls dist changes as it is better suited to vehicles.
One problem is that by using the font bitmap you limit your game to that character set and thus have no Unicode support for other countries were you might get sales. I'm no Unicode expert but I know the guiMlTextcontrol allows drop shadows etc and perhaps as an Unicode alternative the guishapenamehud can be modified/enhanced by adding those text feature from guiMlTextcontrol
#9
1. How would you set this up to orient the text relative to the object's facing instead of always towards you?
2. Can this be abstracted to also do images (in example, adding a 'team' animated image which appears over their head)?
04/04/2006 (8:07 am)
Pretty cool! A few questions on this:1. How would you set this up to orient the text relative to the object's facing instead of always towards you?
2. Can this be abstracted to also do images (in example, adding a 'team' animated image which appears over their head)?
#10
05/24/2006 (8:20 pm)
When you alt-enter to change to fullscreen the engine crashes with the above code. (assuming there is a billboarded text displayed as you do so). If anybody has found a fix for it that'd be appreciated!
#11
Any ideas as to why this may be happening? I have to confess I don't really understand this code. Am I right in saying that the bitmapText.cc file creates a bitmap (a texture) that is then wrapped around a Matrix (a billboard?) in player.cc?
A great resource btw Peter!
Gords
07/12/2006 (11:06 am)
I'm looking to expand this resource do that more text can be added on the fly in-game. I have managed to get the thing to word-wrap as required, but for some reason the text area seems to fly off more to the left hand side all the time, getting worse the more text that is added.Any ideas as to why this may be happening? I have to confess I don't really understand this code. Am I right in saying that the bitmapText.cc file creates a bitmap (a texture) that is then wrapped around a Matrix (a billboard?) in player.cc?
A great resource btw Peter!
Gords
#12
07/23/2006 (10:53 am)
I would also like to know how to use this for images (little icons) above the head
#13
You can use this to place a bitmap above a players head by using Peter's player.cc code above. But instead of using BitmapText.cc to generate your image and load that to the TextureHandle, you simply need to load in your bitmap directly.
Unfortunately, this does not get rendered to other players, which is a problem I am trying to deal with at the moment.
Gordon
07/23/2006 (2:15 pm)
Vincent,You can use this to place a bitmap above a players head by using Peter's player.cc code above. But instead of using BitmapText.cc to generate your image and load that to the TextureHandle, you simply need to load in your bitmap directly.
Unfortunately, this does not get rendered to other players, which is a problem I am trying to deal with at the moment.
Gordon
#14
07/27/2006 (1:53 am)
Gordon, did you manage to get the images to work in multiplayer?
#15
The path I *think* needs to be followed is to set some sort of variable into shapebase.cc and get it to replicate to other clients to signify what should be displayed above that players head. You could then render each players bitmap accordingly on each client.
i.e. the code above works because it can call shape->getShapeName(), if you could add a function to shapebase (that replicates) called getCurrentIcon() you can get that players current icon status and render accordingly.
Hope this makes sense.
Gordon
07/27/2006 (5:24 am)
Vincent, I'm still battling with this, although have been working on something else recently.The path I *think* needs to be followed is to set some sort of variable into shapebase.cc and get it to replicate to other clients to signify what should be displayed above that players head. You could then render each players bitmap accordingly on each client.
i.e. the code above works because it can call shape->getShapeName(), if you could add a function to shapebase (that replicates) called getCurrentIcon() you can get that players current icon status and render accordingly.
Hope this makes sense.
Gordon
#16
08/09/2006 (6:46 am)
Has anyone gotten past the copyrect problem in 1.3? If so could you upload the code?
#17
I need to change the bitmap text rather frequently. I tried modifying generateBitmap() (see below) to instantiate only one BitmapText object and repeatedly call setText on it. However, it crashes in GBitmap::deleteImage() on the 3rd setText.
Can we improve on this or we just have to instantiate a new BitmapText object to change text?
08/27/2006 (1:29 am)
Nice resource. Much thanks.I need to change the bitmap text rather frequently. I tried modifying generateBitmap() (see below) to instantiate only one BitmapText object and repeatedly call setText on it. However, it crashes in GBitmap::deleteImage() on the 3rd setText.
generateNameBitmap()
{
if (!nameBitmap)
nameBitmap = new BitmapText();
nameBitmap->setText(mBitmapText);
nameTexture = TextureHandle(NULL, nameBitmap, BitmapKeepTexture);
}Can we improve on this or we just have to instantiate a new BitmapText object to change text?
#18
Anyway, looking at my code, the way I got around this was to destroy and then renew the BitmapText object on each generateNameBitmap. A hack? Yes. But effective, and I haven't noticed any observable performance hit.
08/28/2006 (2:44 pm)
Ron, I also used this resource to rapidly change the text. I also remember hitting a problem with an error on the 3rd change. I have no idea why this occurs!Anyway, looking at my code, the way I got around this was to destroy and then renew the BitmapText object on each generateNameBitmap. A hack? Yes. But effective, and I haven't noticed any observable performance hit.
#19
08/28/2006 (6:54 pm)
Gordon, thanks. Do you mind posting that part of your code concerning the destroy and new? My code (below) still crashes on the 3rd text change. Without the delete statement, it continues but the previous bitmap is not freed.if (nameBitmap)
delete nameBitmap;
nameBitmap = new BitmapText();
nameBitmap->setText(mBitmapText);
nameTexture = TextureHandle(NULL, nameBitmap, BitmapKeepTexture);
#20
Lucky you mentioned this, as it appears that some of my conditionals were not correct and I wasn't deleting the BitmapText either!!
I'm having major problems with another area at the moment, so can't look at this at the mo. However, a quick look at the code reveals that it is only NameTexture used after the initial generation. I assume there is a problem with the bitmap being used by both objects when it is destroyed in the "delete nameBitmap".
If you solve it please let me know. Otherwise, I'll post here when I get around to fixing it!
Sorry I can't be of more help!
Thanks, Gordon
08/30/2006 (5:43 am)
Ron,Lucky you mentioned this, as it appears that some of my conditionals were not correct and I wasn't deleting the BitmapText either!!
I'm having major problems with another area at the moment, so can't look at this at the mo. However, a quick look at the code reveals that it is only NameTexture used after the initial generation. I assume there is a problem with the bitmap being used by both objects when it is destroyed in the "delete nameBitmap".
If you solve it please let me know. Otherwise, I'll post here when I get around to fixing it!
Sorry I can't be of more help!
Thanks, Gordon

Torque 3D Owner Rubes
Thanks for posting this.