Jump to content
  • Advertisement


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.

If you intended to correct an error in the post then please contact us.

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 <stdio.h>
#include <stdlib.h>
#include <gl\gl.h>
#include <gl\glu.h>									

class OGLText  
	void SetScreenHeight(int);
	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();

	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


	MAX_CHARS = 256;

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

	// 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.


	// 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)


Share this post

Link to post
Share on other sites

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!