/-------------------------------------------------
class Font
{
private:
static const int minGlyph = ' ';
static const int maxGlyph = 126;
static int initCounter;
typedef struct
{
int minx, maxx;
int miny, maxy;
int advance;
SDL_Surface *pic;
GLuint tex;
GLfloat texMinX, texMinY;
GLfloat texMaxX, texMaxY;
} glyph;
int height;
int ascent;
int descent;
int lineSkip;
glyph glyphs[maxGlyph + 1];
unsigned char *address;
int length;
int pointSize;
int style;
float fgRed, fgGreen, fgBlue;
float bgRed, bgGreen, bgBlue;
TTF_Font *ttfFont;
SDL_Color foreground;
SDL_Color background;
void loadChar(char c)
{
GLfloat texcoord[4];
char letter[2] = {0, 0};
if ((minGlyph <= c) &&
(c <= maxGlyph) &&
(NULL == glyphs[c].pic))
{
SDL_Surface *g0 = NULL;
SDL_Surface *g1 = NULL;
letter[0] = c;
TTF_GlyphMetrics(ttfFont,
(Uint16)c,
&glyphs[c].minx,
&glyphs[c].maxx,
&glyphs[c].miny,
&glyphs[c].maxy,
&glyphs[c].advance);
g0 = TTF_RenderText_Shaded(ttfFont,
letter,
foreground,
background);
if (NULL != g0)
{
g1 = SDL_DisplayFormat(g0);
SDL_FreeSurface(g0);
}
if (NULL != g1)
{
glyphs[c].pic = g1;
glyphs[c].tex = loadTextureColorKey(g1, texcoord, 0, 0, 0);
glyphs[c].texMinX = texcoord[0];
glyphs[c].texMinY = texcoord[1];
glyphs[c].texMaxX = texcoord[2];
glyphs[c].texMaxY = texcoord[3];
}
}
}
public:
Font(unsigned char *address,
int length,
int pointSize,
int style,
float fgRed, float fgGreen, float fgBlue,
float bgRed, float bgGreen, float bgBlue):
address(address), length(length),
pointSize(pointSize),
style(style),
fgRed(fgRed), fgGreen(fgGreen), fgBlue(fgBlue),
bgRed(bgRed), bgGreen(bgGreen), bgBlue(bgBlue),
ttfFont(NULL)
{
if (0 == initCounter)
{
if (TTF_Init() < 0)
{
errorExit("cannot init SDL_ttf");
}
}
initCounter++;
initFont();
}
~Font()
{
initCounter--;
if (0 == initCounter)
{
TTF_Quit();
}
}
void initFont()
{
SDL_RWops *src = NULL;
int i;
src = SDL_RWFromMem(address, length);
ttfFont = TTF_OpenFontRW(src, 1, pointSize);
if (NULL == ttfFont)
{
errorExit("cannot open font file");
}
TTF_SetFontStyle(ttfFont, style);
foreground.r = (Uint8)(255 * fgRed);
foreground.g = (Uint8)(255 * fgGreen);
foreground.b = (Uint8)(255 * fgBlue);
background.r = (Uint8)(255 * bgRed);
background.g = (Uint8)(255 * bgGreen);
background.b = (Uint8)(255 * bgBlue);
height = TTF_FontHeight(ttfFont);
ascent = TTF_FontAscent(ttfFont);
descent = TTF_FontDescent(ttfFont);
lineSkip = TTF_FontLineSkip(ttfFont);
for (i = minGlyph; i <= maxGlyph; i++)
{
glyphs[i].pic = NULL;
glyphs[i].tex = 0;
}
}
int getLineSkip()
{
return lineSkip;
}
int getHeight()
{
return height;
}
void textSize(char *text,
SDL_Rect *r)
{
int maxx = 0;
int advance = 0;
r->x = 0;
r->y = 0;
r->w = 0;
r->h = height;
while (0 != *text)
{
if ((minGlyph <= *text) && (*text <= maxGlyph))
{
loadChar(*text);
maxx = glyphs[*text].maxx;
advance = glyphs[*text].advance;
r->w += advance;
}
text++;
}
r->w = r->w - advance + maxx;
}
void Font::drawText(char *text, int x, int y)
{
GLfloat left, right;
GLfloat top, bottom;
GLfloat texMinX, texMinY;
GLfloat texMaxX, texMaxY;
GLfloat minx;
glPushAttrib(GL_ALL_ATTRIB_BITS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
while (0 != *text)
{
if ((minGlyph <= *text) && (*text <= maxGlyph))
{
loadChar(*text);
texMinX = glyphs[((int)*text)].texMinX;
texMinY = glyphs[((int)*text)].texMinY;
texMaxX = glyphs[((int)*text)].texMaxX;
texMaxY = glyphs[((int)*text)].texMaxY;
minx = glyphs[((int)*text)].minx;
left = x + minx;
right = x + glyphs[((int)*text)].pic->w + minx;
top = y;
bottom = y + glyphs[((int)*text)].pic->h;
glBindTexture(GL_TEXTURE_2D, glyphs[((int)*text)].tex);
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(texMinX, texMinY); glVertex2f( left, top);
glTexCoord2f(texMaxX, texMinY); glVertex2f(right, top);
glTexCoord2f(texMinX, texMaxY); glVertex2f( left, bottom);
glTexCoord2f(texMaxX, texMaxY); glVertex2f(right, bottom);
glEnd();
x += glyphs[((int)*text)].advance;
}
text++;
}
glPopAttrib();
}