So, been sort of working on this win32 font issue for a while now. I know there are a tonne of other librarys out there for font rendering, but I like the wglUseFontBitmaps for simplicity, Unicode support, ability to use the Win32 text functions for calculating the dimensions of text, to centre text etc ..

But the bitmap fonts have one major limitation, the bitmaps are binary images and thus can not do transparency, and thus can not be anti-aliased.

Thus I set about trying to write a direct plug in replacement for this. The first thing that made me really wonder was the
glbitmap function. Not talked about in the API is the fact the bitmap function takes images that are inverted (Win32 layout) instead of the standard OGL layout that gldrawpixels takes. I find this most strange. Even more strange, the glbitmap function can put the raster position outside the viewport for rendering, so that you can render text that will overlap into the viewport, while you can't do this with the glrasterpos functions. This makes me think that maybe microsoft simply wrote this function for their text function. I can't see any other reason for glbitmap existing.

Heres a screeny of my text rendering in my media centre software.


And here is the code, should just be a drop in replacement for the standard Win32 text functions, and should look the same, only better. Enjoy

Code :
#include <windows.h>
#include <gl\gl.h>
#include <stdio.h>
#include <math.h>
 
void remapColourRange(UCHAR *data, int numberOfItems) {
 
	for(int i=0; i<numberOfItems; i++) {
		data[i] = (data[i] * 255) / 64;
	}
}
 
void copyLine(UCHAR *in, UCHAR *out, int width) {
 
	for(int i=0; i<width; i++) {
		out[i] = in[i];
	}
}
 
void flipImage(UCHAR *data, int width, int height) {
 
	//===========
	UCHAR *temp;
	DWORD offset;
	DWORD offset2;
	//===========
 
	offset	= 0;
	offset2	= 0;
	temp	= new UCHAR[width];
 
	for(int i=0; i<height/2; i++) {
 
		offset = ((width+3) & ~3) * i;
		copyLine(data+offset,temp,width);			// copy bottom line
 
		offset2 = ((width+3) & ~3) * (height-i-1);
		copyLine(data+offset2,data+offset,width);	// copy top line to bottom
 
		copyLine(temp,data+offset2,width);			// temp line to top
	}
 
	delete []temp;
}
 
void convertLine(UCHAR *in, UCHAR *out, int width) {
 
	for(int i=0; i<width*4; i+=4) {
		out[i+0] = 255;
		out[i+1] = 255;
		out[i+2] = 255;
		out[i+3] = in[i/4];
	}
}
 
void convertToRGB(UCHAR *in, UCHAR *out, int width, int height) {
 
	//==========
	int offset;
	int offset2;
	//==========
 
	offset	= (width+3) & ~3;
	offset2	= (((width*4)+3) & ~3);
 
	for(int i=0; i<height; i++) {
		convertLine(in+(offset*i),out+(offset2*i),width);
	}
}
 
BOOL createFont(HDC hdc, DWORD first, DWORD count, DWORD listBase) {
 
	//===========================
	GLYPHMETRICS	gm;
	MAT2			mat2;
	DWORD			size;
	UCHAR			*data;
	UCHAR			*RGBData;
	//===========================
 
	// safety checks
 
	if(!count)	return FALSE;
	if(!hdc)	return FALSE;
 
	// initiate variables
 
	size	= 0;
	data	= NULL;
	RGBData = NULL;
	memset(&amp;gm,0,sizeof(GLYPHMETRICS));
 
	// identity matrix 
 
	memset(&amp;mat2, 0, sizeof(mat2));
	mat2.eM11.value = 1;	mat2.eM21.value = 0;
	mat2.eM12.value = 0;	mat2.eM22.value = 1;
 
	glPixelStorei(GL_UNPACK_ALIGNMENT,4);
 
	for(DWORD i = 0 ; i< count; i++) {
 
		glNewList(listBase+i,GL_COMPILE);
 
		// get size of the structure first
 
		size = GetGlyphOutline(hdc,first+i,GGO_GRAY8_BITMAP, &amp;gm, 0, NULL, &amp;mat2);
		if(size == GDI_ERROR) { glEndList(); continue; }
 
		if(size) {
 
			data = new UCHAR[size];
 
			GetGlyphOutline(hdc,first+i,GGO_GRAY8_BITMAP,&amp;gm,size,data,&amp;mat2);
 
			remapColourRange(data,size);
			flipImage	(data,gm.gmBlackBoxX,gm.gmBlackBoxY);
 
			RGBData = new UCHAR[(((gm.gmBlackBoxX*4)+3) & ~3) * gm.gmBlackBoxY ];
 
			convertToRGB(data,RGBData,gm.gmBlackBoxX,gm.gmBlackBoxY);
		}
 
		glEnable	(GL_BLEND);
		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
		glBitmap	(0,0,0,0,(GLfloat)gm.gmptGlyphOrigin.x,(GLfloat)gm.gmptGlyphOrigin.y-(GLfloat)gm.gmBlackBoxY,NULL);	//incriment raster position
		if(size)	glDrawPixels(gm.gmBlackBoxX,gm.gmBlackBoxY, GL_RGBA, GL_UNSIGNED_BYTE, RGBData);
		glBitmap	(0,0,0,0,(GLfloat)-gm.gmptGlyphOrigin.x,-((GLfloat)gm.gmptGlyphOrigin.y-(GLfloat)gm.gmBlackBoxY),NULL);	//incriment raster position
		glBitmap	(0,0,0,0,(GLfloat)gm.gmCellIncX,(GLfloat)gm.gmCellIncY,NULL);	//incriment raster position
 
		glDisable	(GL_BLEND);
 
		glEndList();
 
		delete []data;
		delete []RGBData;
	}
 
	glPixelStorei	(GL_UNPACK_ALIGNMENT,1);
 
	return TRUE;
}