#include #include "glbase.h" #include "glfont.h" #include "Input.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif Uint8 prescale2[4] = { 0, 85, 170, 255 }, prescale3[8] = { 0, 36, 72, 109, 145, 182, 218, 255 }; #define STRBUFSIZ 512 /* font file format ================ off|siz|description ---+---+------------------------------- 0 | 2 | Number of entries = nbentries 2 | 1 | Flags 3 | 1 | maxX (maximum width) 4 | 1 | maxY (maximum height) 5 | 1 | base (bottom line from top) 6 | 1 | inter (size of the interline) 7 | X | char entries 7+X| Y | char map X = (maxX * maxY + 1) * nbentries Y = nbentries * 4 Flags: ===== 0000000R R = RGBA (=1) or Alpha (=0) RGBA in 1232 format: ABBGGGRR Each entries: ============ off|siz|description ---+---+------------------------------- 0 | 1 | True size of the entry 1 | Z | Datas Z = maxX * maxY Datas are stored in order X first, then Y. Char map: ======== nbentries entries, each entry = 4 bytes = 2 uint16 off|siz|description ---+---+------------------------------- 0 | 2 | Unicode (?) 2 | 2 | Corresponding char entry I'm not sure about my word 'Unicode'. I write this only to say it's an attempt to make the fonts "internationals". If the "unicode" is < 255, then it should match only one byte in the string. Otherwise, it should match two bytes. Variables comments ================== nbcU = number of chars on X by texture nbcV = number of chars on Y by texture nbcT = number of char by texture nbT = number of textures */ mogltk::font::font(Handle * ffont) : textcolor(255, 255, 255, 255) { int i; nbentries = ffont->readU16(); flags = ffont->readU8(); maxX = ffont->readU8(); maxY = ffont->readU8(); base = ffont->readU8(); inter = ffont->readU8(); nbcU = 256 / maxX; nbcV = 256 / maxY; nbcT = nbcU * nbcV; nbT = nbentries / nbcT; if (nbentries % nbcT) { nbT++; } printm(M_INFO, "Creating font texture: %i entries, flags = 0x%02x, maxX = %i, maxY = %i\n", nbentries, flags, maxX, maxY); printm(M_INFO, "Which makes %i texture(s), with %i char by texture, %i on X, and %i on Y\n", nbT, nbcT, nbcU, nbcV); fonttex = (texture **) malloc(nbT * sizeof(texture *)); for (i = 0; i < nbT; i++) { fonttex[i] = new texture(256, 256, true); } sizes = (Uint8 *) malloc(nbentries * sizeof(Uint8)); Uint8 * curtex = (Uint8 *) fonttex[0]->GetSurface()->pixels; Uint32 curU = 0, curV = 0, curT = 0; for (int i = 0; i < nbentries; i++) { sizes[i] = ffont->readU8(); for (int v = 0; v < maxY; v++) { for (int u = 0; u < maxX; u++) { Uint8 f; f = ffont->readU8(); if (flags & 1) { Uint8 r, g, b, a; r = f & 3; g = (f >> 2) & 7; b = (f >> 5) & 3; a = (f >> 7) & 1; curtex[(curU + u + (curV + v) * 256) * 4 + 0] = prescale2[r]; curtex[(curU + u + (curV + v) * 256) * 4 + 1] = prescale3[g]; curtex[(curU + u + (curV + v) * 256) * 4 + 2] = prescale2[b]; curtex[(curU + u + (curV + v) * 256) * 4 + 3] = a ? 255 : 0; } else { curtex[(curU + u + (curV + v) * 256) * 4 + 0] = 255; curtex[(curU + u + (curV + v) * 256) * 4 + 1] = 255; curtex[(curU + u + (curV + v) * 256) * 4 + 2] = 255; curtex[(curU + u + (curV + v) * 256) * 4 + 3] = f; } } } if (((curU += maxX) + maxX) > 256) { curU = 0; if (((curV += maxY) + maxY) > 256) { curV = 0; if ((curT + 1) != nbT) curtex = (Uint8 *) fonttex[++curT]->GetSurface()->pixels; } } } corresp = (Uint16 *) malloc(nbentries * 2 * sizeof(Uint16)); ffont->read(corresp, 2 * sizeof(Uint16) * nbentries); } mogltk::font::~font() { int i; for (i = 0; i < nbT; i++) { delete fonttex[i]; } free((void *&) fonttex); free(sizes); } void mogltk::font::drawentry(Uint16 entry, int x, int y, ColorP c) { bool was2D; int trueentry, cx, cy, px, py; was2D = mogltk::glbase::is2D(); if (!was2D) mogltk::glbase::Enter2DMode(); if (shadow) { int os = shadow; shadow = 0; drawentry(entry, x + os, y + os, BLACK); shadow = os; } y -= base; Bind(entry / nbcT); c.Bind(); trueentry = entry % nbcT; cx = trueentry % nbcU; cy = trueentry / nbcU; px = cx * maxX; py = cy * maxY; glBegin(GL_TRIANGLE_STRIP); glTexCoord2i(px , py ); glVertex2i(x , y ); glTexCoord2i(px + maxX - 1, py ); glVertex2i(x + maxX - 1, y ); glTexCoord2i(px , py + maxY - 1); glVertex2i(x , y + maxY - 1); glTexCoord2i(px + maxX - 1, py + maxY - 1); glVertex2i(x + maxX - 1, y + maxY - 1); glEnd(); if (!was2D) mogltk::glbase::Leave2DMode(); } void mogltk::font::Bind(int index) { fonttex[index]->Bind(); } void mogltk::font::putcursor(int x, int y) { cx = ox = x; cy = y; } void mogltk::font::putentry(Uint16 entry, ColorP c) { drawentry(entry, cx, cy, c); cx += sizes[entry]; } void mogltk::font::putchar(char ch, ColorP c) { Uint16 * p; int i; for (i = 0, p = corresp; i < nbentries; i++, p++) { if (*(p++) == ch) { putentry(*p, c); return; } } } int mogltk::font::getchar(char ch) const { Uint16 * p; int i; for (i = 0, p = corresp; i < nbentries; i++, p++) { if (*(p++) == ch) { return *p; } } return -1; } void mogltk::font::newline(void) { cx = ox; cy += inter; } int mogltk::font::printf(const ugly_string & m, va_list ap) { char * p; static char buffer[STRBUFSIZ + 1]; int r; #ifdef HAVE_VSNPRINTF r = vsnprintf(buffer, STRBUFSIZ, m.p, ap); #else r = vsprintf(buffer, m.p, ap); #endif for (p = buffer; *p; p++) { if (*p == '\n') { newline(); } else { putchar(*p, textcolor); } } return r; } int mogltk::font::printf(const ugly_string & m, ...) { va_list ap; int r; va_start(ap, m); r = printf(m, ap); va_end(ap); return r; } int mogltk::font::printf(const char * p, ...) { ugly_string m; va_list ap; int r; m.p = p; va_start(ap, p); r = printf(m, ap); va_end(ap); return r; } void mogltk::font::setcolor(ColorP c) { textcolor = c; } void mogltk::font::setshadow(int s) { shadow = s; } int mogltk::font::singletextsize(const String & s) const { unsigned int i; int r = 0; for (i = 0; i < s.strlen(); i++) { r += sizes[getchar(s[i])]; } return r; } mogltk::font * mogltk::SystemFont;