Legay curiosities and font rendering

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 :slight_smile:

#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(&gm,0,sizeof(GLYPHMETRICS));

	// identity matrix 

	memset(&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, &gm, 0, NULL, &mat2);
		if(size == GDI_ERROR) { glEndList(); continue; }

		if(size) {

			data = new UCHAR[size];

			GetGlyphOutline(hdc,first+i,GGO_GRAY8_BITMAP,&gm,size,data,&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;
}