Font rendering problem

Discuss programming topics that involve the OpenGL API.
Post Reply
Zylyx_
Posts: 111
Joined: Wed Dec 05, 2007 6:52 pm
Location: scotland, uk

Font rendering problem

Post by Zylyx_ »

As expected, I ran into a problem with my new code implementation built on top of my last one.

Basicaly, I'm assigning the new font handle to my global font handle, g_hFont.

Then I create a new font using the windows CreateFont() function.

Then I use wglUseFontBitmaps() to trace the font glyphs and convert them into bitmaps. i then return all of this as a new list element/counter, to my global g_FontList variable.

Now, it's my DrawTextGL() function that might be the problem. The original function I based it on (th eone from Game Tutorials LLC), used a variable argument list to pass additional string information into the function. But I ripped that out because I didnt see any need for it (well, not at this point, anyways).

So what happens in this function is that I create a temp 256 char array. Then I position the text, then I push all of the current list elements in my glList using glPushAttrib(GL_LIST_BIT).
Then I set the list base element to the font list base counter (the global g_FontList variable).

Then I use the glCallLists() function. Note that I'm using strlen to get the size of the characters in my temp 256 char array, and i treat them as GL_UNSIGNED_BYTE, which is a character. Finaly I pop the attribute list using glPopAttrib().

However, all i'm getting is a blank screen....
No font what so ever!!

Maybe it's a simple glitch I overlooked for the moment, but I would really appreciate it if you guys here could give it your expert glance.

Perhaps it's my wrong understanding of GL Lists, because I treat them as STL vectors (in my mind), which I'm hoping is the correct understanding.

Anyways, here is the all mighty code (sorry fo rthe big chunks, lol).




gl_win32_core.h

Code: Select all

//This file contains all of the core Win32/OpenGL function prototypes, system includes and global variables required for setting up a basic
//windowed rendering environment for OpenGL application using Win32. 

#ifndef _GL_WIN32_CORE_H_
#define _GL_WIN32_CORE_H_

//Library includes (preferably set this in the project->properties/option tab if available)
//#pragma comment(lib, "opengl32.lib")
//#pragma comment(lib, "glu32.lib")

//System includes
#include <windows.h>		// Must have for Windows platform builds
#include <tchar.h>			// Requires to convert each character in each string argument into a 2 byte character. Win32 treats all string characters as UNICODE.
#include <gl\gl.h>			// Microsoft OpenGL headers (version 1.1 by themselves)
#include <gl\glu.h>			// OpenGL Utilities

//OpenGL hRC specific 
static GLfloat windowWidth;
static GLfloat windowHeight;						

//Win32 specific global variables
static LPCTSTR lpszAppName = L"Swogle";
static HWND  g_hWnd;		//Window handle	
static RECT  g_rRect;		//Window rendering dimensions					
static HDC   g_hDC;			//GDI hardware device context				
static HGLRC g_hRC;			//Hardware renedeing contect for OpenGL	
static HINSTANCE g_hInstance; //App instance (id)

///////////////////////////////////
//Core Win32 function prototypes
///////////////////////////////////

//WinMain
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

//WindowProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam);

//Prog main loop
WPARAM MainLoop();

//Resiter and create new window
HWND CreateMyWindow(LPCTSTR strWindowName, int nWidth, int nHeight);

/////////////////////////////////////
//Core OpenGL function prototypes
////////////////////////////////////

//Set display format
void SetDCPixelFormat();

//Change window size
void ChangeSize(GLsizei w, GLsizei h);

//Add Init function for GL specific stuff

//This draws everything to the screen
void RenderScene();

//Free all memeory associated with the program
void DeInit();

#endif

gl_win32_core.cpp

Code: Select all

//This file contains all of the core Win32/OpenGL function implementations required for setting up a basic
//windowed rendering environment for OpenGL application using Win32. 

#include "gl_win32_core.h"
#include "gl_win32_core_add.h"

//=======================================================================================================================================================
//=======================================================================================================================================================
//Core Win32 function implementations
//=======================================================================================================================================================
//=======================================================================================================================================================

/////////////////////////////////////
//WinMain function implementation
////////////////////////////////////
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	//HWND hWnd; //Local window handle

	//Create new window
	g_hWnd = CreateMyWindow(lpszAppName, 800, 600);

	//If window handle is invalid, quit the program
	if(g_hWnd == NULL)
	{
		return TRUE;
	}

	g_hInstance = hInstance;

	//Initialize the program here
														
	//Run message loop and return the result
	return MainLoop();						
}

//////////////////////////////////////////////
//CreateMyWindow() function implementation
//////////////////////////////////////////////
HWND CreateMyWindow(LPCTSTR strWindowName, int nWidth, int nHeight)
{
	HWND hWnd; //Local window handle
	WNDCLASS wc; //Window class that will be registered

	//clear the memory first
    memset(&wc, 0, sizeof(wc));
    
    //Set all of the attributes up for the window class & register it
    wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC; //CS_OWNDC: Tells Windows to create a device context just for this window
    wc.lpfnWndProc = WndProc;
	wc.cbClsExtra		= 0;
	wc.cbWndExtra		= 0;
    wc.hInstance = g_hInstance;
    wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = NULL; //No need for background brush when using OpenGL
	wc.lpszMenuName = NULL; //No menus either
    wc.lpszClassName = lpszAppName;
	
	//Now, register the windows class with Windows
    RegisterClass(&wc);							

	//Create the main application window
	hWnd = CreateWindow(
							lpszAppName, 
							strWindowName, 
							WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, //WS_CLIPCHILDREN & WS_CLIPSIBLINGS are used to prevent 
							CW_USEDEFAULT,											 //the OpenGL rendering context from rendering into other  
							CW_USEDEFAULT,											 //windows. An OpenGL rendering context must be associated
							nWidth,													 //with only one active window at a time. 
							nHeight, 
							NULL, 
							NULL, 
							g_hInstance, 
							NULL
						);

	//If there is no window handle...
	if(!hWnd)
	{
		return NULL;
	}

	// Show the window
	ShowWindow(hWnd, SW_SHOWNORMAL);	

	// Draw the window
	UpdateWindow(hWnd);									

	//Sets Keyboard Focus To The Window
	SetFocus(hWnd);											

	return hWnd;
}

/////////////////////////////////////////
//WindowProc() function implementation
////////////////////////////////////////
LRESULT CALLBACK WndProc(HWND hWnd,UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	switch(nMsg)
	{
		//Setup the window for OpenGL here
	case WM_CREATE:
		{
			//Store device context
			g_hDC = GetDC(hWnd);

			//Select the pixel format
			SetDCPixelFormat();

			//Create the rendering context and make it current
			g_hRC = wglCreateContext(g_hDC);
			wglMakeCurrent(g_hDC, g_hRC);

			//Create a timer that calls specific functions 30 times a second
			SetTimer(hWnd, 30, 1, NULL);

			//Creat the font
			g_FontList = MakeGLFont((LPCTSTR)"Arial", FONT_HEIGHT);

			return 0;
		}
		//When the window is destroyed, clean up after OpenGL
	case WM_DESTROY:
		{
			//Kill timer
			KillTimer(hWnd, 101);

			//Delete any OpenGL-allocated memory here
			DestroyFont();	

			//Deselect current rendering context and delete it
			wglMakeCurrent(g_hDC, NULL);
			wglDeleteContext(g_hRC);

			//Terminate program after window is destroyed
			PostQuitMessage(0);

			return 0;
		}
		//Change window size appropriately (keeping all clipping bounds for the viewport and rendering volume in order)
	case WM_SIZE:
		{
			ChangeSize(LOWORD(lParam), HIWORD(lParam));
			return 0;
		}
		//Call the timer function here. The MoveSquare() function goes here, and after it is called, the window is
		//invalidated so that it will be drawn again. This happens 30 times a second.
	case WM_TIMER:
		{
			//Anim code goes here

			//Invalidate the rect
			InvalidateRect(hWnd, NULL, FALSE);

			return 0;
		}
		//The WM_PAINT message is sent by Windows everytime the screen needs to be updated. And that's what we do here
	case WM_PAINT:
		{
			//Render current scene
			RenderScene();

			//Swap buffers
			SwapBuffers(g_hDC);

			//Validate the newly painted client area
			ValidateRect(hWnd, NULL);

			return 0;
		}
	default:
		{
			return DefWindowProc(hWnd, nMsg, wParam, lParam);
		}
	}
	return 0;
}

///////////////////////////////////////
//MainLoop() function implementation
//////////////////////////////////////
WPARAM MainLoop()
{
	MSG msg;
	
	while(1)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) //Peek to see if there are any messages in the que...
		{
			if (!GetMessage(&msg, NULL, 0, 0)) //Same as above, except the message get's removed from the message queue
			{
				return msg.wParam; //If there is no message to get, return wParam, which returns a 0 upon normal program termination
			}

			//do the rest
			TranslateMessage(&msg); 
			DispatchMessage(&msg);
		}
		//else
		//{
			//call game logic code here
		//}
	}
	
	//Window cleanup code goes here...
	DeInit();
    
	//Return the exit code for the application.
	return msg.wParam;
}

//=======================================================================================================================================================
//=======================================================================================================================================================
//Core OpenGL function implementations
//=======================================================================================================================================================
//=======================================================================================================================================================

//////////////////////////////////////////////////////////////////////////
//Hardware device context pixel format setting function implementation
/////////////////////////////////////////////////////////////////////////
void SetDCPixelFormat()
{
	int nPixelFormat;

	static PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(PIXELFORMATDESCRIPTOR),
		1,
		PFD_DRAW_TO_WINDOW | 
		PFD_SUPPORT_OPENGL |
		PFD_DOUBLEBUFFER,
		PFD_TYPE_RGBA,
		32,
		0,0,0,0,0,0,
		0,0,
		0,0,0,0,0,
		24,
		0,
		0,
		0,
		0,
		0,0,0
	};

	//Choose a best matched pixel format fitting the above description
	nPixelFormat = ChoosePixelFormat(g_hDC, &pfd);

	//Set the pixel format for the HDC
	SetPixelFormat(g_hDC, nPixelFormat, &pfd);
}

///////////////////////////////////////////
//RenderScene() function implementation  
//////////////////////////////////////////
void RenderScene()
{
	//Set the background clearing color to gray
	glClearColor(0.25f, 0.25f, 0.25f, 1.0f);

	//Clear the screen (with the current clearing color and the depth buffer
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	

	//Reset the identity matrix
	glLoadIdentity();	

	//Text color to draw
	glColor3f(1, 0, 0);	

	//Draw the text
	DrawTextGL(50, 25, (LPCTSTR)"TTF Test");
}

///////////////////////////////////////
//ChangeSize function implementation 
//////////////////////////////////////
void ChangeSize(GLsizei w, GLsizei h)
{
	GLfloat aspectRatio; //Aspect artio for drawing the window

	//Avoid dividing by zero
	if(h == 0)
	{ 
		h = 1;
	}

	//Set viewport to window dimenstions (0, 0 is the clipping region; w, h are the width and height of the viewport in pixels
	glViewport(0, 0, w, h);

	//Reset coordinate system
	glMatrixMode(GL_PROJECTION);//Define projection matrix
	glLoadIdentity();//Load identity matrix for GL_PROJECTION (reset matrix)

	aspectRatio = (GLfloat)w / (GLfloat)h;

	if(w <= h)
	{
		windowWidth = 100;
		windowHeight = 100 / aspectRatio;
		glOrtho(-100.0, 100.0, -windowHeight, windowHeight, 1.0, -1.0);
	}
	else
	{
		windowWidth = 100 * aspectRatio;
		windowHeight = 100;
		glOrtho(-windowWidth, windowWidth, -100.0, 100.0, 1.0, -1.0);
	}

	glMatrixMode(GL_MODELVIEW);//Set the matrix mode to effect all of the current geometry that is drawn
	glLoadIdentity();//Reset the matrix
}

/////////////////////////////////////////////////
//Free all memeory associated with the program
////////////////////////////////////////////////
void DeInit()
{
	//Add all cleanup code associated with the window here

	//Unregister the window class
	UnregisterClass(lpszAppName, g_hInstance);
}
gl_win32_core_add.h

Code: Select all

//This header file includes additional function prototypes for the gl_win32_core template. 
//This includes font rendering, input and sound. 

#ifndef _GL_WIN32_CORE_ADD_H_
#define _GL_WIN32_CORE_ADD_H_

#include "gl_win32_core.h"

//////////////////////////////////////////////////////////////////////
//Font rendering function prototypes, defines and global variables
/////////////////////////////////////////////////////////////////////

static UINT g_FontList = 0; //Counter for the font lists (257 in total).
static HFONT g_hOldFont; //Font handle for old font that gets saved when a new font is selected.

#define MAX_CHARS 256
#define FONT_HEIGHT 32

//Create a native windows font and return the display list counter
UINT MakeGLFont(LPCWSTR strFontName, GLsizei height);

//Set drawing position for the text
void PosText(GLsizei x, GLsizei y);

//Draw the text
void DrawTextGL(GLsizei x, GLsizei y, LPCTSTR strString);

//Free the display list associated with the font
void DestroyFont();

#endif
gl_win32_core_add.cpp

Code: Select all

//This file includes the implementations of the additional gl_win32_core template, gl_win32_core_add.h
//All the implementations of functions ofr font rendering, input and sound playback go here.

#include "gl_win32_core_add.h"

//=======================================================================================================================================================
//=======================================================================================================================================================
//Font rendering function implementations
//=======================================================================================================================================================
//=======================================================================================================================================================

/////////////////////////////////
//Font function implementation
/////////////////////////////////
UINT MakeGLFont(LPCWSTR strFontName, GLsizei height)
{
	UINT tempFontList = 0; //Temp font list counter.
	HFONT hFont; //Local font handle.

	//Generate a list to hold all of the font characters
	tempFontList = glGenLists(MAX_CHARS);

	//Create the font, using the Windows CreateFont() function.
	//Read MSDN's artilce on CreateFont() for parameter info.
	hFont = CreateFont(	FONT_HEIGHT,
						0,
						0,
						0,
						FW_NORMAL,
						FALSE,
						FALSE,
						FALSE,
						ANSI_CHARSET,
						OUT_TT_PRECIS,
						CLIP_DEFAULT_PRECIS,
						ANTIALIASED_QUALITY,
						FF_DONTCARE|DEFAULT_PITCH,
						strFontName);

	//Select the new font into the global hdc.
	//Store old font to select it back inorder to avoid memory leaks.
	//Thsi just catches and keeps the font until it is destroyed.
	g_hOldFont = (HFONT)SelectObject(g_hDC, hFont);

	//The next wgl specific function does the actual conversion of the font glyphs into bitmap characters.
	//This builds 255 bitmapped font characters.
	//Parameters: 
	// g_hDC - The hdc that holds the font
	// 0 - First ASCII glyph to be bitmapped
	// MAX_CHARS - 1 - Last ASCII glyph to be bitmapped
	// tempFontList - The starting display list
	wglUseFontBitmaps(g_hDC, 0, MAX_CHARS - 1, tempFontList);

	//Return the display list counter to use later on
	return tempFontList;
}

/////////////////////////////////////////////
//Font positioning function implementation
/////////////////////////////////////////////
void PosText(GLsizei x, GLsizei y)
{
	//Save the current view port. This saves the transformation matirx and the current viewport settings.
	glPushAttrib(GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);

	//Create a new projection and modelview matrix for the font to use
	glMatrixMode(GL_PROJECTION);						
	glPushMatrix();										
	glLoadIdentity();									
	glMatrixMode(GL_MODELVIEW);						
	glPushMatrix();										
	glLoadIdentity();	

	//Flip the 0 y coord position to the top of the screen.
	//Add 25 to the y coord in windowed mode to make sure the font doesnt go off screen
	y = (GLsizei)windowHeight - FONT_HEIGHT - y;

	//Create a new viewport for the font to be drawn into
	glViewport(x - 1, y - 1, 0, 0);

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

	//After text has been positioned, put everything back to normal
	glPopMatrix();										
	glMatrixMode(GL_PROJECTION);						
	glPopMatrix();										
	
	//Restores the TRANSFORM and VIEWPORT attributes
	glPopAttrib();										
}

/////////////////////////////////////////////
//Font drawing function implementation
/////////////////////////////////////////////
void DrawTextGL(GLsizei x, GLsizei y, LPCTSTR strString)
{
	char tmp_strText[256]; //Holds 256 unicode friendly characters

	//Check if a string was given
	if(strString == NULL)
	{
		return;
	}

	//First, position the text using the above function
	PosText(x, y);

	//Save the current list base
	glPushAttrib(GL_LIST_BIT);

	//Set the list base to the font list base counter
	glListBase(g_FontList);

	//Render the font.
	//Pass in the length of the string, character data types (unsigned int's) and the character array.
	//Note: Check if OpenGL is friendly with LPCTSTR type character strings....
	glCallLists(strlen(tmp_strText), GL_UNSIGNED_BYTE, tmp_strText);

	glPopAttrib();	
}

/////////////////////////////////////////
//Destroy font function implementation
////////////////////////////////////////
void DestroyFont()										
{
	// Free the display list
	glDeleteLists(g_FontList, MAX_CHARS);		

	// Select the old font back to avoid memory leaks
	SelectObject(g_hDC, g_hOldFont);						
}

						

Thank you in advance!!! :)
....noodle...
Post Reply