Transforming Text

Last Updated: Aug 9th, 2012
Text as far as we're concerned is just a set of textured quads. If we treat a rendered string as one big quad, we can transform it just like any quad.From LFont.cpp
LFRect getStringArea( std::string text );
/*
Pre Condition:
-A loaded font
Post Condition:
-Returns area for given text
Side Effects:
-None
*/
The new LFont function getStringArea() gives us the rendering area for an entire string.
From LFont.cpp
LFRect LFont::getStringArea( std::string text )
{
//Initialize area
GLfloat subWidth = 0.f;
LFRect area = { 0.f, 0.f, subWidth, mLineHeight };
//Go through string
for( int i = 0; i < text.length(); ++i )
{
//Space
if( text[ i ] == ' ' )
{
subWidth += mSpace;
}
//Newline
else if( text[ i ] == '\n' )
{
//Add another line
area.h += mLineHeight;
//Check for max width
if( subWidth > area.w )
{
area.w = subWidth;
subWidth = 0.f;
}
}
//Character
else
{
//Get ASCII
GLuint ascii = (unsigned char)text[ i ];
subWidth += mClips[ ascii ].w;
}
}
//Check for max width
if( subWidth > area.w )
{
area.w = subWidth;
}
return area;
}
The way this function calculates area is simple. For every newline, it adds on a line height to the area height. To calculate how wide the text area is, we need to find the line
of text with the greatest width.
To do that, we go through the string adding the character/space width for each character to "subWidth". When we reach a newline or the end of the whole string, we check if this line of text has a greater width than the current text area width. If it is, it means we found the greatest line width for the string.
To do that, we go through the string adding the character/space width for each character to "subWidth". When we reach a newline or the end of the whole string, we check if this line of text has a greater width than the current text area width. If it is, it means we found the greatest line width for the string.
From LUtil.cpp
//Font
LFont gFont;
//Text areas
LFRect gScaledArea = { 0.f, 0.f, 0.f, 0.f };
LFRect gPivotArea = { 0.f, 0.f, 0.f, 0.f };
LFRect gCirclingArea = { 0.f, 0.f, 0.f, 0.f };
//Transformation variables
GLfloat gBigTextScale = 3.f;
GLfloat gPivotAngle = 0.f;
GLfloat gCirclingAngle = 0.f;
At the top of LUtil.cpp we declare the font, the text areas for the text we're going to render, and various transformation variables.
From LUtil.cpp
bool loadMedia()
{
//Load text
if( !gFont.loadFreeType( "25_transforming_text/lazy.ttf", 60 ) )
{
printf( "Unable to load ttf font!\n" );
return false;
}
//Calculate rendering areas
gScaledArea = gFont.getStringArea( "Big Text!" );
gPivotArea = gFont.getStringArea( "Pivot" );
gCirclingArea = gFont.getStringArea( "Wheee!" );
return true;
}
After we load the text, we precalculate the render areas for all of the strings so we don't calculate them every time we render.
From LUtil.cpp
void update()
{
//Update angles
gPivotAngle += -1.f;
gCirclingAngle += +2.f;
//Scale
gBigTextScale += 0.1f;
if( gBigTextScale >= 3.f )
{
gBigTextScale = 0.f;
}
}
In the update function() we update rotation angles and text scaling.
From LUtil.cpp
void render()
{
//Clear color buffer
glClear( GL_COLOR_BUFFER_BIT );
//Big upper middle text
glLoadIdentity();
glColor3f( 1.f, 0.f, 0.f );
//Move to render point
glTranslatef( ( SCREEN_WIDTH - gScaledArea.w * gBigTextScale ) / 2.f, ( SCREEN_HEIGHT - gScaledArea.h * gBigTextScale ) / 4.f, 0.f );
//Scale and render
glScalef( gBigTextScale, gBigTextScale, gBigTextScale );
gFont.renderText( 0.f, 0.f, "Big Text!" , &gScaledArea, LFONT_TEXT_ALIGN_CENTERED_H );
First we render some red text that pops out at the user. First we want to translate the text to the center of the top half of the screen. Since we're translating a scaled
quad (we're treating the text area like a single quad) in unscaled coordinates, we scale the text area in the call to glTranslate().
Then we call glScale() and render the scaled text.
Then we call glScale() and render the scaled text.
From LUtil.cpp
//Lower pivoting text
glLoadIdentity();
glColor3f( 0.f, 1.f, 0.f );
//Move to render point
glTranslatef( ( SCREEN_WIDTH - gPivotArea.w * 1.5f ) / 2.f, ( SCREEN_HEIGHT - gPivotArea.h * 1.5f ) * 3.f / 4.f, 0.f );
//Scale and move to pivot point
glScalef( 1.5f, 1.5f, 1.5f );
glTranslatef( gPivotArea.w / 2.f, gPivotArea.h / 2.f, 0.f );
//Rotate around pivot
glRotatef( gPivotAngle, 0.f, 0.f, 1.f );
//Move back to render point and render
glTranslatef( -gPivotArea.w / 2.f, -gPivotArea.h / 2.f, 0.f );
gFont.renderText( 0.f, 0.f, "Pivot", &gPivotArea, LFONT_TEXT_ALIGN_CENTERED_H );
Here we have rotating green text that rotates around it's center at the bottom half of the screen.
From LUtil.cpp
//Circling text
glLoadIdentity();
glColor3f( 0.f, 0.f, 1.f );
//Move to center of screen
glTranslatef( SCREEN_WIDTH / 2.f, SCREEN_HEIGHT / 2.f, 0.f );
//Rotate around center
glRotatef( gCirclingAngle, 0.f, 0.f, 1.f );
//Move to arm position
glTranslatef( 0.f, -SCREEN_HEIGHT / 2.f, 0.f );
//Center on arm
glTranslatef( -gCirclingArea.w / 2.f, 0.f, 0.f );
//Render
gFont.renderText( 0.f, 0.f, "Wheee!", &gCirclingArea, LFONT_TEXT_ALIGN_CENTERED_H );
//Update screen
glutSwapBuffers();
}
Finally we render text that circles around the screen. It works by rotating around the center of the screen.