Original Post
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);
}