Hi,
2 months ago, I would like to display text on my OpenGL program but now, It’s always impossible to display anything on the screen.
Someone can send me a exemple for displaying text without Glut and under Windows ???
Thanks a lot.
Hi,
2 months ago, I would like to display text on my OpenGL program but now, It’s always impossible to display anything on the screen.
Someone can send me a exemple for displaying text without Glut and under Windows ???
Thanks a lot.
I hope this code isn’t too complicated, but I use this for my program to generate text under Windows NT/2000. There seems to be a slight problem with Win98, something to do with the space character not reporting the right width.
// Example: how to use this class
//
// DjOpenGlFont font;
// font.CreateFont(10, false, false, “Arial”, false);
// font.MakeCurrent();
// font.RenderString(“This is a test”, 10.0f, 10.0f);
class COpenglGlyphInfo
{
public:
unsigned short m_glyph; /* Potentially support 16-bit glyphs. /
unsigned char m_width;
unsigned char m_height;
char m_xoffset;
char m_yoffset;
char m_advance;
char m_dummy; / Space holder for alignment reasons. */
short m_x;
short m_y;
};
class COpenglGlyphVertexInfo
{
public:
GLfloat t0[2];
GLfloat v0[2];
GLfloat t1[2];
GLfloat v1[2];
GLfloat t2[2];
GLfloat v2[2];
GLfloat t3[2];
GLfloat v3[2];
GLfloat advance;
};
class COpenGlFont
{
public:
COpenGlFont();
virtual ~COpenGlFont();
int GetFontHeight();
int GetTextWidth(const char* pString, int len=-1);
int GetWidth(unsigned int key);
void RenderString(const string& string, float x, float y);
bool CreateFont();
void MakeCurrent();
protected:
void CreateVertexInfo();
int m_textureObject;
int m_textureWidth;
int m_textureHeight;
int m_maxHeight;
int m_glyphCount;
int m_minGlyph;
unsigned char* m_pTextureData;
COpenglGlyphInfo* m_pGlyphInfo;
COpenglGlyphVertexInfo* m_pGlyphVertexInfo;
bool m_bAntiAliased;
};
bool COpenGlFont::CreateFont(int pointSize, bool bBold, bool bItalic, LPCTSTR pszFontName, bool bAntiAliased)
{
HFONT hFont=NULL;
HDC hdc=NULL;
HDC hScreenDC=NULL;
HBITMAP hBitmap=NULL;
int i;
int size;
int saveDC;
GLYPHMETRICS gm;
MAT2 matrix={{0, 1}, {0, 0}, {0, 0}, {0, -1}};
BYTE* pBuffer=NULL;
bool result=false;
unsigned int uFormat;
m_bAntiAliased=bAntiAliased;
hScreenDC=CreateDC("DISPLAY", NULL, NULL, NULL);
if (hScreenDC)
hdc=CreateCompatibleDC(hScreenDC);
if (hdc)
{
saveDC=SaveDC(hdc);
hBitmap=CreateCompatibleBitmap(hScreenDC, 100, 100);
}
if (hBitmap)
{
SelectObject(hdc, (HGDIOBJ)hBitmap);
hFont=::CreateFont(-(int)(pointSize*10.0f)*GetDeviceCaps(hdc, LOGPIXELSY)/720, 0, 0, 0, (bBold?700:400), (bItalic?1:0), 0, 0, ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, pszFontName);
}
if (hFont)
{
int maxCharHeight=0;
int charX=0, charY=0;
bool done=false;
int textureSize=0;
result=true;
SelectObject(hdc, (HGDIOBJ)hFont);
m_textureWidth=16;
m_textureHeight=16;
m_glyphCount=91;
m_minGlyph=32;
while (!done)
{
m_textureWidth*=2;
m_textureHeight*=2;
maxCharHeight=0;
charX=0;
charY=0;
if (m_pTextureData)
{
delete[] m_pTextureData;
m_pTextureData=NULL;
}
if (!m_pGlyphVertexInfo)
m_pGlyphVertexInfo=new DjOpenglGlyphVertexInfo[m_glyphCount];
if (!m_pGlyphInfo)
m_pGlyphInfo=new COpenglGlyphInfo[m_glyphCount];
if (m_bAntiAliased)
{
m_pTextureData=new unsigned char[m_textureWidth*m_textureHeight*2];
textureSize=m_textureWidth*m_textureHeight*2;
memset(m_pTextureData, 0, textureSize*sizeof(unsigned char));
uFormat=GGO_GRAY8_BITMAP;
}
else
{
m_pTextureData=new unsigned char[m_textureWidth*m_textureHeight];
textureSize=m_textureWidth*m_textureHeight;
memset(m_pTextureData, 0, textureSize*sizeof(unsigned char));
uFormat=GGO_BITMAP;
}
for (i=m_minGlyph; i<m_minGlyph+m_glyphCount; i++)
{
size=GetGlyphOutline(hdc, (UINT)i, uFormat, &gm, 0, NULL, &matrix);
if (size>0)
{
if (pBuffer)
delete[] pBuffer;
pBuffer=new BYTE[size];
if (GetGlyphOutline(hdc, (UINT)i, uFormat, &gm, size, pBuffer, &matrix)==GDI_ERROR)
{
string msg;
LPVOID lpMsgBuf;
msg="Error: ";
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
msg+=(LPCTSTR)lpMsgBuf;
MessageBox(NULL, msg.c_str(), "Error", MB_OK|MB_ICONEXCLAMATION);
LocalFree(lpMsgBuf);
}
}
if (GetGlyphOutline(hdc, (UINT)i, GGO_METRICS, &gm, 0, NULL, &matrix)!=GDI_ERROR)
{
ABC abc;
GetCharABCWidths(hdc, i, i, &abc);
if (gm.gmBlackBoxX>0 && gm.gmBlackBoxY>0)
{
int width,height;
int h, w;
width=gm.gmBlackBoxX;
//Align DWORD
if (uFormat==GGO_GRAY8_BITMAP)
{
width=size/gm.gmBlackBoxY;
}
else if (uFormat==GGO_BITMAP)
{
width=gm.gmBlackBoxX/32;
if (gm.gmBlackBoxX%32)
width+=1;
}
height=gm.gmBlackBoxY;
if (size==0)
{
size=width*height;
if (uFormat==GGO_BITMAP)
size*=4;
if (pBuffer)
delete[] pBuffer;
pBuffer=new BYTE[size];
memset(pBuffer,0,size*sizeof(BYTE));
}
m_pGlyphInfo[i-m_minGlyph].m_glyph=i;
if (uFormat==GGO_GRAY8_BITMAP)
m_pGlyphInfo[i-m_minGlyph].m_width=width;
else if (uFormat==GGO_BITMAP)
m_pGlyphInfo[i-m_minGlyph].m_width=gm.gmBlackBoxX;
m_pGlyphInfo[i-m_minGlyph].m_height=gm.gmBlackBoxY;
m_pGlyphInfo[i-m_minGlyph].m_xoffset=(char)abc.abcA;
m_pGlyphInfo[i-m_minGlyph].m_yoffset=(char)-gm.gmptGlyphOrigin.y;
m_pGlyphInfo[i-m_minGlyph].m_advance=(char)(abc.abcA+abc.abcB+abc.abcC);
m_pGlyphInfo[i-m_minGlyph].m_dummy=0;
if (charX+m_pGlyphInfo[i-m_minGlyph].m_width>=m_textureWidth)
{
charY+=maxCharHeight;
charX=0;
maxCharHeight=0;
}
if (charY+m_pGlyphInfo[i-m_minGlyph].m_height>=m_textureHeight)
{
break;
}
m_pGlyphInfo[i-m_minGlyph].m_x=charX;
m_pGlyphInfo[i-m_minGlyph].m_y=charY;
charX+=m_pGlyphInfo[i-m_minGlyph].m_width;
maxCharHeight=max(maxCharHeight, m_pGlyphInfo[i-m_minGlyph].m_height);
for (h=0;h<(int)m_pGlyphInfo[i-m_minGlyph].m_height;h++)
{
for (w=0;w<(int)m_pGlyphInfo[i-m_minGlyph].m_width;w++)
{
if (m_bAntiAliased)
{
int index=(m_pGlyphInfo[i-m_minGlyph].m_y+h)*m_textureWidth+m_pGlyphInfo[i-m_minGlyph].m_x+w;
if (pBuffer[h*width+w])
{
ASSERT(index>=0 && index*2+1<textureSize);
m_pTextureData[index*2]=255;
m_pTextureData[index*2+1]=pBuffer[h*width+w]*255/64;
}
}
else
{
int index=h*width*4+w/8;
char mask=(1<<(7-(w%8)));
if (pBuffer[index] & mask)
{
index=(m_pGlyphInfo[i-m_minGlyph].m_y+h)*m_textureWidth+m_pGlyphInfo[i-m_minGlyph].m_x+w;
ASSERT(index>=0 && index<textureSize);
m_pTextureData[index]=255;
}
}
}
}
m_maxHeight=max(m_maxHeight,(int)gm.gmBlackBoxY);
}
}
}
if (i==m_minGlyph+m_glyphCount)
done=true;
}
if (pBuffer)
{
delete[] pBuffer;
pBuffer=NULL;
}
CreateVertexInfo();
}
if (hScreenDC)
ReleaseDC(NULL, hScreenDC);
if (hdc)
{
RestoreDC(hdc, saveDC);
DeleteDC(hdc);
}
if (hBitmap)
DeleteObject((HGDIOBJ)hBitmap);
if (hFont)
DeleteObject((HGDIOBJ)hFont);
return result;
}
void COpenGlFont::MakeCurrent()
{
if (m_textureObject)
{
DjGetDesktop().SetCurrentTexture(m_textureObject);
}
else
{
glGenTextures(1, &m_textureObject);
glBindTexture(GL_TEXTURE_2D, m_textureObject);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (m_bAntiAliased)
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, m_textureWidth, m_textureHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, m_pTextureData);
else
glTexImage2D(GL_TEXTURE_2D, 0, 3, m_textureWidth, m_textureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, m_pTextureData);
}
}
void COpenGlFont::CreateVertexInfo()
{
GLfloat w=(GLfloat)m_textureWidth;
GLfloat h=(GLfloat)m_textureHeight;
GLfloat xStep=0.0f;
GLfloat yStep=0.0f;
int i;
if (m_pGlyphVertexInfo)
delete[] m_pGlyphVertexInfo;
m_pGlyphVertexInfo=new DjOpenglGlyphVertexInfo[m_glyphCount];
for (i=0;i<m_glyphCount;i++)
{
COpenglGlyphInfo* pGlyphInfo=&m_pGlyphInfo[i];
m_pGlyphVertexInfo[i].t0[0]=pGlyphInfo->m_x/w+xStep;
m_pGlyphVertexInfo[i].t0[1]=pGlyphInfo->m_y/h+yStep;
m_pGlyphVertexInfo[i].v0[0]=pGlyphInfo->m_xoffset;
m_pGlyphVertexInfo[i].v0[1]=pGlyphInfo->m_yoffset;
m_pGlyphVertexInfo[i].t1[0]=(pGlyphInfo->m_x+pGlyphInfo->m_width)/w + xStep;
m_pGlyphVertexInfo[i].t1[1]=pGlyphInfo->m_y/h + yStep;
m_pGlyphVertexInfo[i].v1[0]=pGlyphInfo->m_xoffset + pGlyphInfo->m_width;
m_pGlyphVertexInfo[i].v1[1]=pGlyphInfo->m_yoffset;
m_pGlyphVertexInfo[i].t2[0]=(pGlyphInfo->m_x + pGlyphInfo->m_width)/w + xStep;
m_pGlyphVertexInfo[i].t2[1]=(pGlyphInfo->m_y + pGlyphInfo->m_height)/h + yStep;
m_pGlyphVertexInfo[i].v2[0]=pGlyphInfo->m_xoffset + pGlyphInfo->m_width;
m_pGlyphVertexInfo[i].v2[1]=pGlyphInfo->m_yoffset + pGlyphInfo->m_height;
m_pGlyphVertexInfo[i].t3[0]=pGlyphInfo->m_x/w + xStep;
m_pGlyphVertexInfo[i].t3[1]=(pGlyphInfo->m_y + pGlyphInfo->m_height)/h + yStep;
m_pGlyphVertexInfo[i].v3[0]=pGlyphInfo->m_xoffset;
m_pGlyphVertexInfo[i].v3[1]=pGlyphInfo->m_yoffset + pGlyphInfo->m_height;
m_pGlyphVertexInfo[i].advance=pGlyphInfo->m_advance;
}
}
int COpenGlFont::GetFontHeight()
{
return m_maxHeight+2;
}
int COpenGlFont::GetTextWidth(const char* pString, int len/=-1/)
{
int i, width=0;
if (pString)
{
if (len<0)
len=strlen(pString);
for (i=0; i<len; i++)
width+=(int)m_pGlyphVertexInfo[pString[i]-m_minGlyph].advance;
}
return width;
}
int COpenGlFont::GetWidth(unsigned int key)
{
return (int)m_pGlyphVertexInfo[key-m_minGlyph].advance;
}
void COpenGlFont::RenderString(LPCTSTR pString, float x, float y)
{
COpenglGlyphVertexInfo* tgvi;
int i;
int len=strlen(pString);
for (i=0;i<len;i++)
{
tgvi=&m_pGlyphVertexInfo[pString[i]-m_minGlyph];
glTexCoord2fv(tgvi->t0);
glVertex2f(tgvi->v0[0]+x,tgvi->v0[1]+y);
glTexCoord2fv(tgvi->t1);
glVertex2f(tgvi->v1[0]+x,tgvi->v1[1]+y);
glTexCoord2fv(tgvi->t2);
glVertex2f(tgvi->v2[0]+x,tgvi->v2[1]+y);
glTexCoord2fv(tgvi->t3);
glVertex2f(tgvi->v3[0]+x,tgvi->v3[1]+y);
x+=tgvi->advance;
}
}