Skip to main content
gamedev.net
🔒 Locked

Bitmap Font rendering problem

Started by nraiyani Jan 16, 2005 at 2:49 PM 0 replies 1.7k views
Original Post
nraiyani
nraiyani
Hi, i've been playing with idea of creating a Bitmap Font in run time. To that end i manage to hack some thing up, but currently i am having issue trying to get it to display. 1st basic explaination of how i am doing things (code is Win32 specific) step 1: Get a Font, and render it to a Bitmap, using HFont, and HBitmap. step 2: use that bitmap image to generate a display list of fonts to be used by OpenGL. Simple enough concept. Problem i am having is, well i am not sure. i did manage to get the font to render. i know this becuase it produced an output in raw image format. But i can't seem to be able to display it in opengl. Code Follows. (Forgive me for the sloppyness, but i wanted to get it working 1st before i beautified it). Functions, that i think problem might exist in, are MakeBitmap() : which creates the Bitmap using HBitmap and HFont MakeFntDspList() : which make the Display List to be used by OpenGL If you could help me point out my stupid, i would be happy. Thanks in advance.

#define NUMCELLS 16;

CBaseFont::CBaseFont(char *FontName, int iSize)
{
	m_pFontName = new char [20];
	strcpy(m_pFontName, FontName);

	m_iFontWidth = m_iFontHeight = NUMCELLS * nextPOW2(iSize);
	m_iCellWidth = m_iFontWidth / NUMCELLS;
	m_iCellHeight = m_iFontHeight / NUMCELLS;

	MakeBitmap();
	MakeFntDspList();
}

CBaseFont::~CBaseFont()
{
	DeleteFntDspList();
	delete [] m_pFontName;
	delete [] m_pBitmap;
}

int CBaseFont::nextPOW2(int iVal)
{
	int i = 1;
	while (i < iVal)
		i = i << 1;
	return i;
}

bool CBaseFont::CreateHDC()
{
	m_hDC = CreateCompatibleDC(NULL);
	if (m_hDC == NULL)
		return false;
	return true;
}

bool CBaseFont::CreateHBMP()
{
	memset(&m_BitmapInfo, 0, sizeof(BITMAPINFO));
	m_BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	m_BitmapInfo.bmiHeader.biWidth = m_iFontWidth;
	m_BitmapInfo.bmiHeader.biHeight = m_iFontHeight;
	m_BitmapInfo.bmiHeader.biBitCount = 24;
	m_BitmapInfo.bmiHeader.biPlanes = 1;

	m_hBitmap = CreateDIBSection(m_hDC, &m_BitmapInfo, 
							DIB_RGB_COLORS, 
							(void **)&m_pBitmap, NULL, 0);
	if (m_hBitmap == NULL)
		return false;
	return true;
}

bool CBaseFont::CreateHFONT()
{
	m_hFont = CreateFont(m_iCellHeight, 0, 0, 0, 
						FW_NORMAL, FALSE, FALSE, FALSE, 
						ANSI_CHARSET, OUT_DEFAULT_PRECIS, 
						CLIP_DEFAULT_PRECIS, 
						ANTIALIASED_QUALITY, 
						DEFAULT_PITCH, 
						m_pFontName);
	if (m_hFont == NULL)
		return false;
	return true;
}

bool CBaseFont::SetTextMetrics()
{
	GetCharABCWidths(m_hDC, 0, 255, m_abc);
	return true;
}

bool CBaseFont::MakeBitmap()
{
	CreateHDC();
	CreateHBMP();
	CreateHFONT();

	SelectObject(m_hDC, m_hBitmap);
	SelectObject(m_hDC, m_hFont);

	SetBkColor(m_hDC, RGB(0, 0, 0));
	SetTextColor(m_hDC, RGB(255, 255, 255));

	for(int i=0, y=0; y < NUMCELLS; y++)
	{
		for(int x=0; x < NUMCELLS; x++)
		{
			unsigned short text[1]={ i++ };

			m_Rect.left = m_iCellWidth * x;
			m_Rect.top = m_iCellHeight * y;
			m_Rect.right = m_Rect.left + m_iCellWidth;
			m_Rect.bottom = m_Rect.top + m_iCellHeight;

			DrawTextW(m_hDC, text, 1, &m_Rect, DT_LEFT|DT_TOP);
		}
	}
	SetTextMetrics();
	DeleteWinStuff();

	return true;
}

void CBaseFont::DeleteWinStuff()
{
	int bmpSize;
	if (m_hFont != NULL)
		DeleteObject(m_hFont);

	if (m_hBitmap != NULL)
	{
		bmpSize = (m_BitmapInfo.bmiHeader.biWidth * 
						m_BitmapInfo.bmiHeader.biHeight) * 
						(m_BitmapInfo.bmiHeader.biBitCount / 8);

		unsigned char *tempBMP = new unsigned char [bmpSize];
		memcpy(tempBMP, m_pBitmap, bmpSize);

		DeleteObject(m_hBitmap);

		m_pBitmap = new unsigned char [bmpSize];
		memcpy(m_pBitmap, tempBMP, bmpSize);
		delete [] tempBMP;
	}

	if (m_hDC != NULL)
		DeleteObject(m_hDC);


	FILE *stream;
	stream = fopen("font.raw", "wb");
	fwrite(m_pBitmap, bmpSize, 1, stream);
	fclose(stream);
}

bool CBaseFont::MakeGLFntTexture()
{
	glGenTextures(1, &m_FontID);
	glBindTexture(GL_TEXTURE_2D, m_FontID);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY16, 
				m_iFontWidth, m_iFontHeight, 0, GL_RGB, GL_BYTE, m_pBitmap);


	return true;
}

bool CBaseFont::MakeFntDspList()
{
	int ch = 0;
	float cellW = 1.0f / (float)NUMCELLS;
	float s, t, chrW, chrT, chrSpc;
	float fntSize = (float)m_iFontHeight / NUMCELLS;

	MakeGLFntTexture();
	m_ListBase = glGenLists(256);

	for (int i = 1; i < NUMCELLS + 1; i++)
	{
		for (int j = 0; j < NUMCELLS; j++)
		{
			chrT = (float)(m_abc[ch].abcB + m_abc[ch].abcC);
			chrW = chrT / (float)m_iFontWidth;
			chrSpc = (float)m_abc[ch].abcA;

			s = 1.0f - (float)j * cellW;
			t = (float)j * cellW;

			glNewList(m_ListBase + ch, GL_COMPILE);
			{
				glTranslatef(chrSpc, 0.0f, 0.0f);
				glBegin(GL_QUADS);
				{
					glTexCoord2f(s, t);
						glVertex3f(0, 0, 0);
					glTexCoord2f(s, t + cellW);
						glVertex3f(0, fntSize, 0);
					glTexCoord2f(s + chrW, t + cellW);
						glVertex3f(chrT, fntSize, 0);
					glTexCoord2f(s + chrW, t);
						glVertex3f(chrT, 0, 0);
				}glEnd();
				glTranslatef(chrT, 0.0f, 0.0f);
			}glEndList();
			ch++;
		}
	}

	return true;
}

bool CBaseFont::DeleteFntDspList()
{
	if (m_ListBase)
		glDeleteLists(m_ListBase, 256);

	glDeleteTextures(1, &m_FontID);
	return true;
}

void CBaseFont::print(char *text)
{
	glPushAttrib(GL_ALL_ATTRIB_BITS);
	{
		glDisable(GL_LIGHTING);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

		glBindTexture(GL_TEXTURE_2D, m_FontID);
		glListBase(m_ListBase);
		glCallLists(strlen((const char *)text), GL_UNSIGNED_BYTE, text);
	}glPopAttrib();
	glBindTexture(GL_TEXTURE_2D, 0);
}
42

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.