Jump to content
  • Advertisement
Sign in to follow this  
nraiyani

OpenGL Bitmap Font rendering problem

This topic is 5026 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 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);
}

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

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

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!