Archived

This topic is now archived and is closed to further replies.

Printing Text to the Screen

This topic is 5195 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Hi, I''ve been trying to adapt Ben Humphrey''s tutorial on displaying text in OpenGL from http://www.gametutorials.com into an Object Oriented framework. I basically threw all of his code into a class and modified the variables to work with it (well sort of).. Problem is, I''m not getting any text. I''ve basically created a simple OpenGL perspective window, created a global instance of my class (glText), and called glText.glDrawText(20,20,"Some text to display); in my rendering routine. I can''t figure out why it''s not working. When the window is being created, I pass the class the hDC, and the client height. Here''s the class code. If anyone can see what''s gumming it up I''d appreciate any help you have to offer.
// OGLText.h: interface for the OGLText class.

//

//	An Object-Oriented implementation of Ben Humphrey''s (DigiBen) tutorial

//	on text display.

//

//////////////////////////////////////////////////////////////////////

#if !defined(AFX_OGLTEXT_H__50FE5C91_4582_4ABF_826D_1FAB34C01A2C__INCLUDED_)
#define AFX_OGLTEXT_H__50FE5C91_4582_4ABF_826D_1FAB34C01A2C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include<windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <gl\gl.h>
#include <gl\glu.h>

class OGLText
{
public:
void SetScreenHeight(int);

OGLText();
void SetDC(HDC);
OGLText(unsigned int);
void glDrawText(int, int, const char *, ...);
void PositionText(int,int);
UINT CreateOpenGLFont(LPSTR, int);
void SetFontListID(UINT);
virtual ~OGLText();

protected:
int SCREEN_HEIGHT;
HDC m_hDC;
UINT FontListID;
HFONT hOldFont;
unsigned int MAX_CHARS;
unsigned int FONT_HEIGHT;
};

#endif // !defined(AFX_OGLTEXT_H__50FE5C91_4582_4ABF_826D_1FAB34C01A2C__INCLUDED_)

///////////////////////////////////////////////////////////////////

// OGLText.cpp: implementation of the OGLText class.

//

//////////////////////////////////////////////////////////////////////

#include "OGLText.h"

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

OGLText::OGLText()
{
MAX_CHARS = 256;
}

OGLText::OGLText(unsigned int h = 18)
{
FONT_HEIGHT = h;
MAX_CHARS = 256;
}

OGLText::~OGLText()
{
// Destroy''s the font freeing up memory

glDeleteLists(FontListID, MAX_CHARS);				// Free the display list

SelectObject(m_hDC, hOldFont);						// Select the old font back in so we don''t have memory leaks

}

UINT OGLText::CreateOpenGLFont(LPSTR strFontName, int height)
{

UINT	fontListID = 0;								// This will hold the base ID for our display list

HFONT	hFont;										// This will store the handle to our font

// Here we generate the lists for each character we want to use.

// This function then returns the base pointer, which will be 1 because

// we haven''t created any other lists.  If we generated another list after

// this, the base pointer would be at 257 since the last one used was 256 (which is MAX_CHARS)

fontListID = glGenLists(MAX_CHARS);					// Generate the list for the font

// Now we actually need to create the font.  We use a windows function called:

// CreateFont() that returns a handle to a font (HFONT).  Our CreateOpenGLFont()

// function allows us to pass in a name and height.  For simplistic reasons, I left

// other options out, but feel free to add them to your function (like bold, italic, width..)

hFont = CreateFont(	height,							// Our desired HEIGHT of the font

0,								// The WIDTH (If we leave this zero it will pick the best width depending on the height)

0,								// The angle of escapement

0,								// The angle of orientation

FW_BOLD,						// The font''s weight (We want it bold)

FALSE,							// Italic - We don''t want italic

FALSE,							// Underline - We don''t want it underlined

FALSE,							// Strikeout - We don''t want it strikethrough

ANSI_CHARSET,					// This is the type of character set

OUT_TT_PRECIS,					// The Output Precision

CLIP_DEFAULT_PRECIS,			// The Clipping Precision

ANTIALIASED_QUALITY,			// The quality of the font - We want anitaliased fonts

FF_DONTCARE|DEFAULT_PITCH,		// The family and pitch of the font.  We don''t care.

strFontName);					// The font name (Like "Arial", "Courier", etc...)

// Now that we have created a new font, we need to select that font into our global HDC.

// We store the old font so we can select it back in when we are done to avoid memory leaks.

hOldFont = (HFONT)SelectObject(m_hDC, hFont);

// This function does the magic.  It takes the current font selected in

// the hdc and makes bitmaps out of each character.  These are called glyphs.

// The first parameter is the HDC that holds the font to be used.

// The second parameters is the ASCII value to start from, which is zero in our case.

// The third parameters is the ASCII value to end on (255 is the last of the ASCII values so we minus 1 from MAX_CHARS)

// The last parameter is the base pointer for the display lists being used.  This should be 1.

wglUseFontBitmaps(m_hDC, 0, MAX_CHARS - 1, fontListID);	// Builds 255 bitmap characters

return fontListID;									// Return the ID to the display list to use later

}

void OGLText::PositionText( int x, int y )
{
// If you are to use this font code for your applications,

// you must be aware that you cannot position the font in 3D,

// which means you can''t rotate and scale it.  That will be covered in

// the next font tutorial.  BUT, though that might be a drag, this code

// is useful because when you display the text, it will always be on top

// of everything else.  This is good if the camera is moving around, and you

// don''t want the text to move.  If the text was positioned in 3D you would have

// to come up with a tricky way of making it always render in front of the camera.

// To do this, we need to set the Raster Position.  That is the position that OpenGL

// starts drawing at.  Since it''s in floating point, it''s not very intuitive, so what

// we do is create a new view port, and then always draw the text at (0, 0, 0) in that

// view port.  The weird part is that the Y is flipped, so (0, 0) is the bottom left corner.

// Below we do some simple math to flip it back to normal.

// Before we create a new view port, we need to save the current one we have.

// This saves our transform (matrix) information and our current viewport information.

// At the end of this function we POP it back.

glPushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT );

// Here we use a new projection and modelview matrix to work with.

glMatrixMode( GL_PROJECTION );						// Set our matrix to our projection matrix

glPushMatrix();										// Push on a new matrix to work with

glLoadIdentity();									// reset the matrix

glMatrixMode( GL_MODELVIEW );						// Set our matrix to our model view matrix

glPushMatrix();										// Push on a new matrix to work with

glLoadIdentity();									// Reset that matrix

// Because the Y is flipped, we want 0 to be at the top, not bottom.

// If we subtract the font height from the screen height, that should display the

// font at the top of the screen (if they passed in 0 for Y), but then we subtract

// the Y from that to get the desired position.  Since the font''s drawing point is

// at the base line of the font, we needed to subtract the font height to make sure

// if they passed in (0, 0) it wouldn''t be off screen.  If you view this in window mode,

// the top of the window will cut off part of the font, but in full screen it works fine.

// You just need to add about 25 to the Y to fix that for window mode.

y = SCREEN_HEIGHT - FONT_HEIGHT - y;				// Calculate the weird screen position

// Now we create another view port (that is why we saved the old one above).

// Since glViewPort takes the lower LEFT corner, we needed to change the Y

// to make it more intuitive when using PositionText().  We minus 1 from the X and Y

// because 0 is taken into account with the position.  The next 2 parameters are set

// to 0 for the width and height so it will always draw in the middle of that position.

// glRasterPos4f() takes (0, 0, 0) as the middle of the viewport, so if we give it a small

// width/height it will draw at the X and Y given.  Sounds strange, to test this, try

// using glRasterPos4f(0, 0, 0, 1) instead of PositionText() and you will see, everything

// will be drawn from the middle.

glViewport( x - 1, y - 1, 0, 0 );					// Create a new viewport to draw into

// This is the most important function in here.  This actually positions the text.

// The parameters are (x, y, z, w).  w should always be 1 , it''s a clip coordinate.

// don''t worry about that though.  Because we set the projection and modelview matrix

// back to the beginning (through LoadIdentity()), the view port is looking at (0, 0, 0).

// This is the middle, so if we set the drawing position to the middle, it will draw at our

// X and Y because the width/height of the viewport is 0, starting at X and Y.

// You can actually call this function (or glRasterPos2f(0, 0)) instead of PositionText(),

// but it is in floating point and doesn''t work as nicely.  You will see why if you try.

glRasterPos4f( 0, 0, 0, 1 );						// Set the drawing position

// Now that we positioned the raster position, any text we draw afterwards will start

// from that position.  Now we just have to put everything else back to normal.

glPopMatrix();										// Pop the current modelview matrix off the stack

glMatrixMode( GL_PROJECTION );						// Go back into projection mode

glPopMatrix();										// Pop the projection matrix off the stack

glPopAttrib();										// This restores our TRANSFORM and VIEWPORT attributes

}

void OGLText::glDrawText(int x, int y, const char *strString, ...)
{
char		strText[256];							// This will hold our text to display

va_list		argumentPtr;							// This will hold the pointer to the argument list

// If you have never used a va_list, listen up.  Remember printf()?

// or sprintf()?  Well, you can add unlimited arguments into the text like:

// printf("My name is %s and I am %d years old!", strName, age);

// Well, that is what va_list''s do.

// First we need to check if there was even a string given

if (strString == NULL)								// Check if a string was given

return;											// Don''t render anything then

// First we need to parse the string for arguments given

// To do this we pass in a va_list variable that is a pointer to the list of arguments.

// Then we pass in the string that holds all of those arguments.

va_start(argumentPtr, strString);					// Parse the arguments out of the string

// Then we use a special version of sprintf() that takes a pointer to the argument list.

// This then does the normal sprintf() functionality.

vsprintf(strText, strString, argumentPtr);			// Now add the arguments into the full string

va_end(argumentPtr);								// This resets and frees the pointer to the argument list.

// Before we draw the text, we need to position it with our own function.

PositionText(x, y);									// Call our own function to position the text on screen

// Now, before we set the list base, we need to save off the current one.

glPushAttrib(GL_LIST_BIT);							// This saves the list base information

// Then we want to set the list base to the font''s list base, which should be 1 in our case.

// That way when we call our display list it will start from the font''s lists''.

glListBase(FontListID);							// This sets the lists base

// Now comes the actually rendering.  We pass in the length of the string,

// then the data types (which are characters so its a UINT), then the actually char array.

// This will then take the ASCII value of each character and associate it with a bitmap.

glCallLists(strlen(strText), GL_UNSIGNED_BYTE, strText);

glPopAttrib();										// Return the display list back to it''s previous state

}

void OGLText::SetDC(HDC dc)
{
m_hDC = dc;
}

void OGLText::SetFontListID(UINT i)
{
FontListID = i;
}

void OGLText::SetScreenHeight(int h)
{
SCREEN_HEIGHT = h;
}


Thanks!

Share on other sites
Looks to me like your drawing outside the window (20,20).

• 10
• 17
• 9
• 13
• 41