]> git.uio.no Git - u/mrichter/AliRoot.git/blob - EVE/Reve/GLTextNS.cxx
First big commit of the mchview program and its accompanying library,
[u/mrichter/AliRoot.git] / EVE / Reve / GLTextNS.cxx
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