#include #include "glbase.h" #include "glfont.h" #include "Input.h" Uint8 prescale2[4] = { 0, 85, 170, 255 }, prescale3[8] = { 0, 36, 72, 109, 145, 182, 218, 255 }; #define DEBUG 1 #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; ffont->read(&nbentries, 2); ffont->read(&flags, 1); ffont->read(&maxX, 1); ffont->read(&maxY, 1); ffont->read(&base, 1); ffont->read(&inter, 1); nbcU = 256 / maxX; nbcV = 256 / maxY; nbcT = nbcU * nbcV; nbT = nbentries / nbcT; if (nbentries % nbcT) { nbT++; } #ifdef DEBUG 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); #endif 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++) { ffont->read(&sizes[i], 1); for (int v = 0; v < maxY; v++) { for (int u = 0; u < maxX; u++) { Uint8 f; ffont->read(&f, 1); 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, Color 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, Color c) { drawentry(entry, cx, cy, c); cx += sizes[entry]; } void mogltk::font::putchar(char ch, Color c) { Uint16 * p; int i; for (i = 0, p = corresp; i < nbentries; i++, p++) { if (*(p++) == ch) { putentry(*p, c); return; } } } void mogltk::font::newline(void) { cx = ox; cy += inter; } int mogltk::font::printf(const String & m, ...) { static char buffer[STRBUFSIZ + 1]; va_list ap; char * p; int r; va_start(ap, m); r = vsnprintf(buffer, STRBUFSIZ, m.to_charp(), ap); va_end(ap); for (p = buffer; *p; p++) { if (*p == '\n') { newline(); } else { putchar(*p, textcolor); } } return r; } void mogltk::font::setcolor(Color c) { textcolor = c; } void mogltk::font::setshadow(int s) { shadow = s; }