]>
Commit | Line | Data |
---|---|---|
b6b64776 | 1 | // The following implementation is based on TexFont API, |
2 | // implementation and accompanying programs by Mark J. Kilgard. | |
3 | // Original license: | |
4 | ||
5 | /* Copyright (c) Mark J. Kilgard, 1997. */ | |
6 | /* This program is freely distributable without licensing fees and is | |
7 | provided without guarantee or warrantee expressed or implied. This | |
8 | program is -not- in the public domain. */ | |
9 | ||
10 | #include "GLTextNS.h" | |
11 | ||
12 | #include <TMath.h> | |
13 | #include <TString.h> | |
14 | ||
15 | #include <GL/glu.h> | |
16 | ||
17 | #include <assert.h> | |
18 | #include <ctype.h> | |
19 | #include <stdlib.h> | |
20 | #include <stdio.h> | |
21 | ||
22 | #include <Reve/Reve.h> | |
23 | #include <Reve/GLTextNS.h> | |
24 | ||
25 | using Reve::Exc_t; | |
26 | ||
27 | namespace GLTextNS { | |
28 | ||
29 | TexFont* fgDefaultFont = 0; | |
30 | ||
31 | #if 0 | |
32 | /* Uncomment to debug various scenarios. */ | |
33 | #undef GL_VERSION_1_1 | |
34 | #undef GL_EXT_texture_object | |
35 | #undef GL_EXT_texture | |
36 | #endif | |
37 | ||
38 | int useLuminanceAlpha = 1; | |
39 | ||
40 | /* byte swap a 32-bit value */ | |
41 | #define SWAPL(x, n) { \ | |
42 | n = ((char *) (x))[0]; \ | |
43 | ((char *) (x))[0] = ((char *) (x))[3]; \ | |
44 | ((char *) (x))[3] = n; \ | |
45 | n = ((char *) (x))[1]; \ | |
46 | ((char *) (x))[1] = ((char *) (x))[2]; \ | |
47 | ((char *) (x))[2] = n; } | |
48 | ||
49 | /* byte swap a short */ | |
50 | #define SWAPS(x, n) { \ | |
51 | n = ((char *) (x))[0]; \ | |
52 | ((char *) (x))[0] = ((char *) (x))[1]; \ | |
53 | ((char *) (x))[1] = n; } | |
54 | ||
55 | /**************************************************************************/ | |
56 | ||
57 | static TexGlyphVertexInfo* getTCVI(TexFont * txf, int c) | |
58 | { | |
59 | TexGlyphVertexInfo *tgvi; | |
60 | ||
61 | /* Automatically substitute uppercase letters with lowercase if not | |
62 | uppercase available (and vice versa). */ | |
63 | if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { | |
64 | tgvi = txf->lut[c - txf->min_glyph]; | |
65 | if (tgvi) { | |
66 | return tgvi; | |
67 | } | |
68 | if (islower(c)) { | |
69 | c = toupper(c); | |
70 | if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { | |
71 | return txf->lut[c - txf->min_glyph]; | |
72 | } | |
73 | } | |
74 | if (isupper(c)) { | |
75 | c = tolower(c); | |
76 | if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { | |
77 | return txf->lut[c - txf->min_glyph]; | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | //fprintf(stderr, "texfont: tried to access unavailable font character \"%c\" (%d)\n", | |
83 | // isprint(c) ? c : ' ', c); | |
84 | ||
85 | tgvi = txf->lut[' ' - txf->min_glyph]; | |
86 | if (tgvi) return tgvi; | |
87 | tgvi = txf->lut['_' - txf->min_glyph]; | |
88 | if (tgvi) return tgvi; | |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
93 | /**************************************************************************/ | |
94 | ||
95 | static char *lastError; | |
96 | ||
97 | char* txfErrorString(void) | |
98 | { | |
99 | return lastError; | |
100 | } | |
101 | ||
102 | /**************************************************************************/ | |
103 | ||
104 | TexFont* txfLoadFont(const char *filename) | |
105 | { | |
106 | TexFont *txf; | |
107 | FILE *file; | |
108 | GLfloat w, h, xstep, ystep; | |
109 | char fileid[4], tmp; | |
110 | unsigned char *texbitmap; | |
111 | int min_glyph, max_glyph; | |
112 | int endianness, swap, format, stride, width, height; | |
113 | int i, j, got; | |
114 | ||
115 | txf = NULL; | |
116 | file = fopen(filename, "rb"); | |
117 | if (file == NULL) { | |
118 | lastError = "file open failed."; | |
119 | goto error; | |
120 | } | |
121 | txf = (TexFont *) malloc(sizeof(TexFont)); | |
122 | if (txf == NULL) { | |
123 | lastError = "out of memory."; | |
124 | goto error; | |
125 | } | |
126 | /* For easy cleanup in error case. */ | |
127 | txf->texobj = 0; // MT add | |
128 | txf->tgi = NULL; | |
129 | txf->tgvi = NULL; | |
130 | txf->lut = NULL; | |
131 | txf->teximage = NULL; | |
132 | ||
133 | got = fread(fileid, 1, 4, file); | |
134 | if (got != 4 || strncmp(fileid, "\377txf", 4)) { | |
135 | lastError = "not a texture font file."; | |
136 | goto error; | |
137 | } | |
138 | assert(sizeof(int) == 4); /* Ensure external file format size. */ | |
139 | got = fread(&endianness, sizeof(int), 1, file); | |
140 | if (got == 1 && endianness == 0x12345678) { | |
141 | swap = 0; | |
142 | } else if (got == 1 && endianness == 0x78563412) { | |
143 | swap = 1; | |
144 | } else { | |
145 | lastError = "not a texture font file."; | |
146 | goto error; | |
147 | } | |
148 | #define EXPECT(n) if (got != n) { lastError = "premature end of file."; goto error; } | |
149 | got = fread(&format, sizeof(int), 1, file); | |
150 | EXPECT(1); | |
151 | got = fread(&txf->tex_width, sizeof(int), 1, file); | |
152 | EXPECT(1); | |
153 | got = fread(&txf->tex_height, sizeof(int), 1, file); | |
154 | EXPECT(1); | |
155 | got = fread(&txf->max_ascent, sizeof(int), 1, file); | |
156 | EXPECT(1); | |
157 | got = fread(&txf->max_descent, sizeof(int), 1, file); | |
158 | EXPECT(1); | |
159 | got = fread(&txf->num_glyphs, sizeof(int), 1, file); | |
160 | EXPECT(1); | |
161 | ||
162 | if (swap) { | |
163 | SWAPL(&format, tmp); | |
164 | SWAPL(&txf->tex_width, tmp); | |
165 | SWAPL(&txf->tex_height, tmp); | |
166 | SWAPL(&txf->max_ascent, tmp); | |
167 | SWAPL(&txf->max_descent, tmp); | |
168 | SWAPL(&txf->num_glyphs, tmp); | |
169 | } | |
170 | txf->tgi = (TexGlyphInfo *) malloc(txf->num_glyphs * sizeof(TexGlyphInfo)); | |
171 | if (txf->tgi == NULL) { | |
172 | lastError = "out of memory."; | |
173 | goto error; | |
174 | } | |
175 | assert(sizeof(TexGlyphInfo) == 12); /* Ensure external file format size. */ | |
176 | got = fread(txf->tgi, sizeof(TexGlyphInfo), txf->num_glyphs, file); | |
177 | EXPECT(txf->num_glyphs); | |
178 | ||
179 | if (swap) { | |
180 | for (i = 0; i < txf->num_glyphs; i++) { | |
181 | SWAPS(&txf->tgi[i].c, tmp); | |
182 | SWAPS(&txf->tgi[i].x, tmp); | |
183 | SWAPS(&txf->tgi[i].y, tmp); | |
184 | } | |
185 | } | |
186 | txf->tgvi = (TexGlyphVertexInfo *) | |
187 | malloc(txf->num_glyphs * sizeof(TexGlyphVertexInfo)); | |
188 | if (txf->tgvi == NULL) { | |
189 | lastError = "out of memory."; | |
190 | goto error; | |
191 | } | |
192 | w = txf->tex_width; | |
193 | h = txf->tex_height; | |
194 | txf->max_width = 0; | |
195 | xstep = 0.5 / w; | |
196 | ystep = 0.5 / h; | |
197 | for (i = 0; i < txf->num_glyphs; i++) { | |
198 | TexGlyphInfo *tgi; | |
199 | ||
200 | tgi = &txf->tgi[i]; | |
201 | txf->tgvi[i].t0[0] = tgi->x / w - xstep; // MT - xstep | |
202 | txf->tgvi[i].t0[1] = tgi->y / h - ystep; // MT - ystep | |
203 | txf->tgvi[i].v0[0] = tgi->xoffset; | |
204 | txf->tgvi[i].v0[1] = tgi->yoffset; | |
205 | txf->tgvi[i].t1[0] = (tgi->x + tgi->width) / w + xstep; | |
206 | txf->tgvi[i].t1[1] = tgi->y / h - ystep; // MT - ystep | |
207 | txf->tgvi[i].v1[0] = tgi->xoffset + tgi->width; | |
208 | txf->tgvi[i].v1[1] = tgi->yoffset; | |
209 | txf->tgvi[i].t2[0] = (tgi->x + tgi->width) / w + xstep; | |
210 | txf->tgvi[i].t2[1] = (tgi->y + tgi->height) / h + ystep; | |
211 | txf->tgvi[i].v2[0] = tgi->xoffset + tgi->width; | |
212 | txf->tgvi[i].v2[1] = tgi->yoffset + tgi->height; | |
213 | txf->tgvi[i].t3[0] = tgi->x / w - xstep; // MT - xstep | |
214 | txf->tgvi[i].t3[1] = (tgi->y + tgi->height) / h + ystep; | |
215 | txf->tgvi[i].v3[0] = tgi->xoffset; | |
216 | txf->tgvi[i].v3[1] = tgi->yoffset + tgi->height; | |
217 | txf->tgvi[i].advance = tgi->advance; | |
218 | ||
219 | if(tgi->width > txf->max_width) txf->max_width = tgi->width; | |
220 | } | |
221 | ||
222 | min_glyph = txf->tgi[0].c; | |
223 | max_glyph = txf->tgi[0].c; | |
224 | for (i = 1; i < txf->num_glyphs; i++) { | |
225 | if (txf->tgi[i].c < min_glyph) { | |
226 | min_glyph = txf->tgi[i].c; | |
227 | } | |
228 | if (txf->tgi[i].c > max_glyph) { | |
229 | max_glyph = txf->tgi[i].c; | |
230 | } | |
231 | } | |
232 | txf->min_glyph = min_glyph; | |
233 | txf->range = max_glyph - min_glyph + 1; | |
234 | ||
235 | txf->lut = (TexGlyphVertexInfo **) | |
236 | calloc(txf->range, sizeof(TexGlyphVertexInfo *)); | |
237 | if (txf->lut == NULL) { | |
238 | lastError = "out of memory."; | |
239 | goto error; | |
240 | } | |
241 | for (i = 0; i < txf->num_glyphs; i++) { | |
242 | txf->lut[txf->tgi[i].c - txf->min_glyph] = &txf->tgvi[i]; | |
243 | } | |
244 | ||
245 | switch (format) { | |
246 | case TXF_FORMAT_BYTE: | |
247 | if (useLuminanceAlpha) { | |
248 | unsigned char *orig; | |
249 | ||
250 | orig = (unsigned char *) malloc(txf->tex_width * txf->tex_height); | |
251 | if (orig == NULL) { | |
252 | lastError = "out of memory."; | |
253 | goto error; | |
254 | } | |
255 | got = fread(orig, 1, txf->tex_width * txf->tex_height, file); | |
256 | EXPECT(txf->tex_width * txf->tex_height); | |
257 | txf->teximage = (unsigned char *) | |
258 | malloc(2 * txf->tex_width * txf->tex_height); | |
259 | if (txf->teximage == NULL) { | |
260 | lastError = "out of memory."; | |
261 | goto error; | |
262 | } | |
263 | for (i = 0; i < txf->tex_width * txf->tex_height; i++) { | |
264 | txf->teximage[i * 2] = orig[i]; | |
265 | txf->teximage[i * 2 + 1] = orig[i]; | |
266 | } | |
267 | free(orig); | |
268 | } else { | |
269 | txf->teximage = (unsigned char *) | |
270 | malloc(txf->tex_width * txf->tex_height); | |
271 | if (txf->teximage == NULL) { | |
272 | lastError = "out of memory."; | |
273 | goto error; | |
274 | } | |
275 | got = fread(txf->teximage, 1, txf->tex_width * txf->tex_height, file); | |
276 | EXPECT(txf->tex_width * txf->tex_height); | |
277 | } | |
278 | break; | |
279 | case TXF_FORMAT_BITMAP: | |
280 | width = txf->tex_width; | |
281 | height = txf->tex_height; | |
282 | stride = (width + 7) >> 3; | |
283 | texbitmap = (unsigned char *) malloc(stride * height); | |
284 | if (texbitmap == NULL) { | |
285 | lastError = "out of memory."; | |
286 | goto error; | |
287 | } | |
288 | got = fread(texbitmap, 1, stride * height, file); | |
289 | EXPECT(stride * height); | |
290 | if (useLuminanceAlpha) { | |
291 | txf->teximage = (unsigned char *) calloc(width * height * 2, 1); | |
292 | if (txf->teximage == NULL) { | |
293 | lastError = "out of memory."; | |
294 | goto error; | |
295 | } | |
296 | for (i = 0; i < height; i++) { | |
297 | for (j = 0; j < width; j++) { | |
298 | if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) { | |
299 | txf->teximage[(i * width + j) * 2] = 255; | |
300 | txf->teximage[(i * width + j) * 2 + 1] = 255; | |
301 | } | |
302 | } | |
303 | } | |
304 | } else { | |
305 | txf->teximage = (unsigned char *) calloc(width * height, 1); | |
306 | if (txf->teximage == NULL) { | |
307 | lastError = "out of memory."; | |
308 | goto error; | |
309 | } | |
310 | for (i = 0; i < height; i++) { | |
311 | for (j = 0; j < width; j++) { | |
312 | if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) { | |
313 | txf->teximage[i * width + j] = 255; | |
314 | } | |
315 | } | |
316 | } | |
317 | } | |
318 | free(texbitmap); | |
319 | break; | |
320 | } | |
321 | ||
322 | fclose(file); | |
323 | return txf; | |
324 | ||
325 | error: | |
326 | ||
327 | if (txf) { | |
328 | if (txf->tgi) | |
329 | free(txf->tgi); | |
330 | if (txf->tgvi) | |
331 | free(txf->tgvi); | |
332 | if (txf->lut) | |
333 | free(txf->lut); | |
334 | if (txf->teximage) | |
335 | free(txf->teximage); | |
336 | free(txf); | |
337 | } | |
338 | if (file) | |
339 | fclose(file); | |
340 | return NULL; | |
341 | } | |
342 | ||
343 | /**************************************************************************/ | |
344 | ||
345 | GLuint txfEstablishTexture(TexFont * txf, GLuint texobj, | |
346 | GLboolean setupMipmaps) | |
347 | { | |
348 | if (txf->texobj == 0) { | |
349 | if (texobj == 0) { | |
350 | glGenTextures(1, &txf->texobj); | |
351 | } else { | |
352 | txf->texobj = texobj; | |
353 | } | |
354 | } | |
355 | glBindTexture(GL_TEXTURE_2D, txf->texobj); | |
356 | ||
357 | if (useLuminanceAlpha) { | |
358 | if (setupMipmaps) { | |
359 | gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, | |
360 | txf->tex_width, txf->tex_height, | |
361 | GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, txf->teximage); | |
362 | } else { | |
363 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, | |
364 | txf->tex_width, txf->tex_height, 0, | |
365 | GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, txf->teximage); | |
366 | } | |
367 | } else { | |
368 | if (setupMipmaps) { | |
369 | gluBuild2DMipmaps(GL_TEXTURE_2D, GL_INTENSITY4, | |
370 | txf->tex_width, txf->tex_height, | |
371 | GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage); | |
372 | } else { | |
373 | glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4, | |
374 | txf->tex_width, txf->tex_height, 0, | |
375 | GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage); | |
376 | } | |
377 | } | |
378 | ||
379 | // MT: tried changing MIN/MAG filters ... bad idea. | |
380 | ||
381 | return txf->texobj; | |
382 | } | |
383 | ||
384 | /**************************************************************************/ | |
385 | ||
386 | void txfBindFontTexture(TexFont * txf) | |
387 | { | |
388 | glBindTexture(GL_TEXTURE_2D, txf->texobj); | |
389 | } | |
390 | ||
391 | /**************************************************************************/ | |
392 | ||
393 | void txfUnloadFont(TexFont * txf) | |
394 | { | |
395 | if (txf->texobj) { | |
396 | glDeleteTextures(1, &txf->texobj); | |
397 | } | |
398 | if (txf->teximage) { | |
399 | free(txf->teximage); | |
400 | } | |
401 | free(txf->tgi); | |
402 | free(txf->tgvi); | |
403 | free(txf->lut); | |
404 | free(txf); | |
405 | } | |
406 | ||
407 | /**************************************************************************/ | |
408 | ||
409 | void txfGetStringMetrics(TexFont * txf, const char *TString, int len, | |
410 | int &width, int &max_ascent, int &max_descent) | |
411 | { | |
412 | TexGlyphVertexInfo *tgvi; | |
413 | int w, i; | |
414 | int ma = 0, md = 0; | |
415 | ||
416 | w = 0; | |
417 | for (i = 0; i < len; i++) { | |
418 | if (TString[i] == 27) { | |
419 | switch (TString[i + 1]) { | |
420 | case 'M': | |
421 | i += 4; | |
422 | break; | |
423 | case 'T': | |
424 | i += 7; | |
425 | break; | |
426 | case 'L': | |
427 | i += 7; | |
428 | break; | |
429 | case 'F': | |
430 | i += 13; | |
431 | break; | |
432 | } | |
433 | } else { | |
434 | tgvi = getTCVI(txf, TString[i]); | |
435 | w += int(tgvi->advance); | |
436 | ma = TMath::Max(ma, (int)( tgvi->v3[1])); | |
437 | md = TMath::Max(md, (int)(-tgvi->v0[1])); | |
438 | } | |
439 | } | |
440 | width = w; | |
441 | max_ascent = ma; // txf->max_ascent; | |
442 | max_descent = md; // txf->max_descent; | |
443 | // printf("%d %d %d %d\n", txf->max_ascent, txf->max_descent, ma, md); | |
444 | } | |
445 | ||
446 | /**************************************************************************/ | |
447 | ||
448 | void txfRenderGlyph(TexFont * txf, int c) | |
449 | { | |
450 | TexGlyphVertexInfo *tgvi; | |
451 | ||
452 | tgvi = getTCVI(txf, c); | |
453 | glBegin(GL_QUADS); | |
454 | glTexCoord2fv(tgvi->t0); | |
455 | glVertex2sv(tgvi->v0); | |
456 | glTexCoord2fv(tgvi->t1); | |
457 | glVertex2sv(tgvi->v1); | |
458 | glTexCoord2fv(tgvi->t2); | |
459 | glVertex2sv(tgvi->v2); | |
460 | glTexCoord2fv(tgvi->t3); | |
461 | glVertex2sv(tgvi->v3); | |
462 | glEnd(); | |
463 | glTranslatef(tgvi->advance, 0.0, 0.0); | |
464 | } | |
465 | ||
466 | void txfRenderString(TexFont * txf, const char *TString, int len, | |
467 | bool keep_pos) | |
468 | { | |
469 | int i; | |
470 | if(keep_pos) glPushMatrix(); | |
471 | for (i = 0; i < len; i++) { | |
472 | txfRenderGlyph(txf, TString[i]); | |
473 | } | |
474 | if(keep_pos) glPopMatrix(); | |
475 | } | |
476 | ||
477 | void txfRenderString(TexFont * txf, const char *TString, int len, | |
478 | GLfloat maxx, GLfloat fadew, | |
479 | bool keep_pos) | |
480 | { | |
481 | GLfloat x = 0, xg0, xg1, yg0, yg1, f0, f1; | |
482 | fadew *= txf->max_width; | |
483 | GLfloat xfade = maxx - fadew; | |
484 | ||
485 | GLfloat col[4]; | |
486 | glGetFloatv(GL_CURRENT_COLOR, col); | |
487 | ||
488 | glBegin(GL_QUADS); | |
489 | for (int i = 0; i < len; i++) { | |
490 | ||
491 | TexGlyphVertexInfo *tgvi; | |
492 | ||
493 | tgvi = getTCVI(txf, TString[i]); | |
494 | ||
495 | xg0 = x + tgvi->v0[0]; | |
496 | xg1 = x + tgvi->v1[0]; | |
497 | yg0 = tgvi->v0[1]; | |
498 | yg1 = tgvi->v2[1]; | |
499 | ||
500 | if(xg1 > xfade) { | |
501 | f0 = 1; if(xg0 > xfade) f0 *= 1 - (xg0-xfade)/fadew; | |
502 | f1 = 1 - (xg1-xfade)/fadew; | |
503 | ||
504 | // printf("XX %s %c %f %f x(%f,%f) y(%f,%f)\n", | |
505 | // TString, TString[i], f0, f1, | |
506 | // xg0, xg1,yg0, yg1); | |
507 | ||
508 | glColor4f(f0*col[0], f0*col[1], f0*col[2], f0*col[3]); | |
509 | glTexCoord2fv(tgvi->t0); glVertex2f(xg0, yg0); | |
510 | glColor4f(f1*col[0], f1*col[1], f1*col[2], f1*col[3]); | |
511 | glTexCoord2fv(tgvi->t1); glVertex2f(xg1, yg0); | |
512 | glTexCoord2fv(tgvi->t2); glVertex2f(xg1, yg1); | |
513 | glColor4f(f0*col[0], f0*col[1], f0*col[2], f0*col[3]); | |
514 | glTexCoord2fv(tgvi->t3); glVertex2f(xg0, yg1); | |
515 | } else { | |
516 | glTexCoord2fv(tgvi->t0); glVertex2f(xg0, yg0); | |
517 | glTexCoord2fv(tgvi->t1); glVertex2f(xg1, yg0); | |
518 | glTexCoord2fv(tgvi->t2); glVertex2f(xg1, yg1); | |
519 | glTexCoord2fv(tgvi->t3); glVertex2f(xg0, yg1); | |
520 | } | |
521 | ||
522 | x += tgvi->advance; | |
523 | if(x > maxx) break; | |
524 | } | |
525 | glEnd(); | |
526 | ||
527 | if(!keep_pos) glTranslatef(x, 0.0, 0.0); | |
528 | } | |
529 | ||
530 | /**************************************************************************/ | |
531 | ||
532 | void txfRenderGlyphZW(TexFont * txf, int c, float z, float w) | |
533 | { | |
534 | TexGlyphVertexInfo *tgvi; | |
535 | ||
536 | tgvi = getTCVI(txf, c); | |
537 | glBegin(GL_QUADS); | |
538 | glTexCoord2fv(tgvi->t0); | |
539 | glVertex4f(tgvi->v0[0], tgvi->v0[1], z, w); | |
540 | glTexCoord2fv(tgvi->t1); | |
541 | glVertex4f(tgvi->v1[0], tgvi->v1[1], z, w); | |
542 | glTexCoord2fv(tgvi->t2); | |
543 | glVertex4f(tgvi->v2[0], tgvi->v2[1], z, w); | |
544 | glTexCoord2fv(tgvi->t3); | |
545 | glVertex4f(tgvi->v3[0], tgvi->v3[1], z, w); | |
546 | glEnd(); | |
547 | glTranslatef(tgvi->advance, 0.0, 0.0); | |
548 | } | |
549 | ||
550 | void txfRenderStringZW(TexFont * txf, const char *TString, int len, | |
551 | float z, float w, bool keep_pos) | |
552 | { | |
553 | int i; | |
554 | ||
555 | if(keep_pos) glPushMatrix(); | |
556 | for (i = 0; i < len; i++) { | |
557 | txfRenderGlyphZW(txf, TString[i], z, w); | |
558 | } | |
559 | if(keep_pos) glPopMatrix(); | |
560 | } | |
561 | ||
562 | /**************************************************************************/ | |
563 | ||
564 | enum { | |
565 | MONO, TOP_BOTTOM, LEFT_RIGHT, FOUR | |
566 | }; | |
567 | ||
568 | /**************************************************************************/ | |
569 | ||
570 | void txfRenderFancyString(TexFont * txf, char *TString, int len) | |
571 | { | |
572 | TexGlyphVertexInfo *tgvi; | |
573 | GLubyte c[4][3]; | |
574 | int mode = MONO; | |
575 | int i; | |
576 | ||
577 | for (i = 0; i < len; i++) { | |
578 | if (TString[i] == 27) { | |
579 | switch (TString[i + 1]) { | |
580 | case 'M': | |
581 | mode = MONO; | |
582 | glColor3ubv((GLubyte *) & TString[i + 2]); | |
583 | i += 4; | |
584 | break; | |
585 | case 'T': | |
586 | mode = TOP_BOTTOM; | |
587 | memcpy(c, &TString[i + 2], 6); | |
588 | i += 7; | |
589 | break; | |
590 | case 'L': | |
591 | mode = LEFT_RIGHT; | |
592 | memcpy(c, &TString[i + 2], 6); | |
593 | i += 7; | |
594 | break; | |
595 | case 'F': | |
596 | mode = FOUR; | |
597 | memcpy(c, &TString[i + 2], 12); | |
598 | i += 13; | |
599 | break; | |
600 | } | |
601 | } else { | |
602 | switch (mode) { | |
603 | case MONO: | |
604 | txfRenderGlyph(txf, TString[i]); | |
605 | break; | |
606 | case TOP_BOTTOM: | |
607 | tgvi = getTCVI(txf, TString[i]); | |
608 | glBegin(GL_QUADS); | |
609 | glColor3ubv(c[0]); | |
610 | glTexCoord2fv(tgvi->t0); | |
611 | glVertex2sv(tgvi->v0); | |
612 | glTexCoord2fv(tgvi->t1); | |
613 | glVertex2sv(tgvi->v1); | |
614 | glColor3ubv(c[1]); | |
615 | glTexCoord2fv(tgvi->t2); | |
616 | glVertex2sv(tgvi->v2); | |
617 | glTexCoord2fv(tgvi->t3); | |
618 | glVertex2sv(tgvi->v3); | |
619 | glEnd(); | |
620 | glTranslatef(tgvi->advance, 0.0, 0.0); | |
621 | break; | |
622 | case LEFT_RIGHT: | |
623 | tgvi = getTCVI(txf, TString[i]); | |
624 | glBegin(GL_QUADS); | |
625 | glColor3ubv(c[0]); | |
626 | glTexCoord2fv(tgvi->t0); | |
627 | glVertex2sv(tgvi->v0); | |
628 | glColor3ubv(c[1]); | |
629 | glTexCoord2fv(tgvi->t1); | |
630 | glVertex2sv(tgvi->v1); | |
631 | glColor3ubv(c[1]); | |
632 | glTexCoord2fv(tgvi->t2); | |
633 | glVertex2sv(tgvi->v2); | |
634 | glColor3ubv(c[0]); | |
635 | glTexCoord2fv(tgvi->t3); | |
636 | glVertex2sv(tgvi->v3); | |
637 | glEnd(); | |
638 | glTranslatef(tgvi->advance, 0.0, 0.0); | |
639 | break; | |
640 | case FOUR: | |
641 | tgvi = getTCVI(txf, TString[i]); | |
642 | glBegin(GL_QUADS); | |
643 | glColor3ubv(c[0]); | |
644 | glTexCoord2fv(tgvi->t0); | |
645 | glVertex2sv(tgvi->v0); | |
646 | glColor3ubv(c[1]); | |
647 | glTexCoord2fv(tgvi->t1); | |
648 | glVertex2sv(tgvi->v1); | |
649 | glColor3ubv(c[2]); | |
650 | glTexCoord2fv(tgvi->t2); | |
651 | glVertex2sv(tgvi->v2); | |
652 | glColor3ubv(c[3]); | |
653 | glTexCoord2fv(tgvi->t3); | |
654 | glVertex2sv(tgvi->v3); | |
655 | glEnd(); | |
656 | glTranslatef(tgvi->advance, 0.0, 0.0); | |
657 | break; | |
658 | } | |
659 | } | |
660 | } | |
661 | } | |
662 | ||
663 | /**************************************************************************/ | |
664 | ||
665 | int txfInFont(TexFont * txf, int c) | |
666 | { | |
667 | /* NOTE: No uppercase/lowercase substituion. */ | |
668 | if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) { | |
669 | if (txf->lut[c - txf->min_glyph]) { | |
670 | return 1; | |
671 | } | |
672 | } | |
673 | return 0; | |
674 | } | |
675 | ||
676 | /**************************************************************************/ | |
677 | ||
678 | bool LoadDefaultFont( TString file) | |
679 | { | |
680 | static const Exc_t _eh("GLTextNS::LoadFont "); | |
681 | ||
682 | if(fgDefaultFont) { | |
683 | txfUnloadFont(fgDefaultFont); | |
684 | fgDefaultFont = 0; | |
685 | } | |
686 | ||
687 | fgDefaultFont = GLTextNS::txfLoadFont(file.Data()); | |
688 | if(fgDefaultFont != 0) { | |
689 | txfEstablishTexture(fgDefaultFont, 0, GL_TRUE); | |
690 | return true; | |
691 | } | |
692 | else { | |
693 | throw(_eh + Form("Error loading font from file '%s': %s", | |
694 | file.Data(), txfErrorString())); | |
695 | } | |
696 | ||
697 | return false; | |
698 | } | |
699 | ||
700 | } // end GLTextNS |