1: 
     2: /* Copyright (c) Mark J. Kilgard, 1997. */
     3: 
     4: /* This program is freely distributable without licensing fees  and is
     5:    provided without guarantee or warrantee expressed or  implied. This
     6:    program is -not- in the public domain. */
     7: 
     8: #include <assert.h> 
     9: #include <ctype.h> 
    10: #include <stdlib.h> 
    11: #include <stdio.h> 
    12: #include <string.h> 
    13: #include <GL/glu.h> 
    14: #include "TexFont.h" 
    15: 
    16: #if 0 
    17: /* Uncomment to debug various scenarios. */
    18: #undef GL_VERSION_1_1 
    19: #undef GL_EXT_texture_object 
    20: #undef GL_EXT_texture 
    21: #endif 
    22: 
    23: #ifndef GL_VERSION_1_1 
    24: #if defined(GL_EXT_texture_object) && defined(GL_EXT_texture) 
    25: #define glGenTextures glGenTexturesEXT 
    26: #define glBindTexture glBindTextureEXT 
    27: #ifndef GL_INTENSITY4 
    28: #define GL_INTENSITY4 GL_INTENSITY4_EXT 
    29: #endif 
    30: int useLuminanceAlpha = 0;
    31: #else 
    32: #define USE_DISPLAY_LISTS 
    33: /* Intensity texture format not in OpenGL 1.0; added by the EXT_texture
    34:    extension and now part of OpenGL 1.1. */
    35: int useLuminanceAlpha = 1;
    36: #endif 
    37: #else 
    38: int useLuminanceAlpha = 0;
    39: #endif 
    40: 
    41: /* byte swap a 32-bit value */
    42: #define SWAPL(x, n) { \ 
    43:                  n = ((char *) (x))[0];\
    44:                  ((char *) (x))[0] = ((char *) (x))[3];\
    45:                  ((char *) (x))[3] = n;\
    46:                  n = ((char *) (x))[1];\
    47:                  ((char *) (x))[1] = ((char *) (x))[2];\
    48:                  ((char *) (x))[2] = n; }
    49: 
    50: /* byte swap a short */
    51: #define SWAPS(x, n) { \ 
    52:                  n = ((char *) (x))[0];\
    53:                  ((char *) (x))[0] = ((char *) (x))[1];\
    54:                  ((char *) (x))[1] = n; }
    55: 
    56: static TexGlyphVertexInfo *
    57: 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:   fprintf(stderr, "texfont: tried to access unavailable font character \"%c\" (%d)\n",
    82:     isprint(c) ? c : ' ', c);
    83:   abort();
    84:   /* NOTREACHED */
    85: }
    86: 
    87: static char *lastError;
    88: 
    89: char *
    90: txfErrorString(void)
    91: {
    92:   return lastError;
    93: }
    94: 
    95: TexFont *
    96: txfLoadFont(char *filename)
    97: {
    98:   TexFont *txf;
    99:   FILE *file;
   100:   GLfloat w, h, xstep, ystep;
   101:   char fileid[4], tmp;
   102:   unsigned char *texbitmap;
   103:   int min_glyph, max_glyph;
   104:   int endianness, swap, format, stride, width, height;
   105:   int i, j, got;
   106: 
   107:   txf = NULL;
   108:   file = fopen(filename, "rb");
   109:   if (file == NULL) {
   110:     lastError = "file open failed.";
   111:     goto error;
   112:   }
   113:   txf = (TexFont *) malloc(sizeof(TexFont));
   114:   if (txf == NULL) {
   115:     lastError = "out of memory.";
   116:     goto error;
   117:   }
   118:   /* For easy cleanup in error case. */
   119:   txf->tgi = NULL;
   120:   txf->tgvi = NULL;
   121:   txf->lut = NULL;
   122:   txf->teximage = NULL;
   123: 
   124:   got = fread(fileid, 1, 4, file);
   125:   if (got != 4 || strncmp(fileid, "\377txf", 4)) {
   126:     lastError = "not a texture font file.";
   127:     goto error;
   128:   }
   129:   assert(sizeof(int) == 4);  /* Ensure external file format size. */
   130:   got = fread(&endianness, sizeof(int), 1, file);
   131:   if (got == 1 && endianness == 0x12345678) {
   132:     swap = 0;
   133:   } else if (got == 1 && endianness == 0x78563412) {
   134:     swap = 1;
   135:   } else {
   136:     lastError = "not a texture font file.";
   137:     goto error;
   138:   }
   139: #define EXPECT(n) if (got != n) { lastError = "premature end of file."; goto error; } 
   140:   got = fread(&format, sizeof(int), 1, file);
   141:   EXPECT(1);
   142:   got = fread(&txf->tex_width, sizeof(int), 1, file);
   143:   EXPECT(1);
   144:   got = fread(&txf->tex_height, sizeof(int), 1, file);
   145:   EXPECT(1);
   146:   got = fread(&txf->max_ascent, sizeof(int), 1, file);
   147:   EXPECT(1);
   148:   got = fread(&txf->max_descent, sizeof(int), 1, file);
   149:   EXPECT(1);
   150:   got = fread(&txf->num_glyphs, sizeof(int), 1, file);
   151:   EXPECT(1);
   152: 
   153:   if (swap) {
   154:     SWAPL(&format, tmp);
   155:     SWAPL(&txf->tex_width, tmp);
   156:     SWAPL(&txf->tex_height, tmp);
   157:     SWAPL(&txf->max_ascent, tmp);
   158:     SWAPL(&txf->max_descent, tmp);
   159:     SWAPL(&txf->num_glyphs, tmp);
   160:   }
   161:   txf->tgi = (TexGlyphInfo *) malloc(txf->num_glyphs * sizeof(TexGlyphInfo));
   162:   if (txf->tgi == NULL) {
   163:     lastError = "out of memory.";
   164:     goto error;
   165:   }
   166:   assert(sizeof(TexGlyphInfo) == 12);  /* Ensure external file format size. */
   167:   got = fread(txf->tgi, sizeof(TexGlyphInfo), txf->num_glyphs, file);
   168:   EXPECT(txf->num_glyphs);
   169: 
   170:   if (swap) {
   171:     for (i = 0; i < txf->num_glyphs; i++) {
   172:       SWAPS(&txf->tgi[i].c, tmp);
   173:       SWAPS(&txf->tgi[i].x, tmp);
   174:       SWAPS(&txf->tgi[i].y, tmp);
   175:     }
   176:   }
   177:   txf->tgvi = (TexGlyphVertexInfo *)
   178:     malloc(txf->num_glyphs * sizeof(TexGlyphVertexInfo));
   179:   if (txf->tgvi == NULL) {
   180:     lastError = "out of memory.";
   181:     goto error;
   182:   }
   183:   w = txf->tex_width;
   184:   h = txf->tex_height;
   185:   xstep = 0.5 / w;
   186:   ystep = 0.5 / h;
   187:   for (i = 0; i < txf->num_glyphs; i++) {
   188:     TexGlyphInfo *tgi;
   189: 
   190:     tgi = &txf->tgi[i];
   191:     txf->tgvi[i].t0[0] = tgi->x / w + xstep;
   192:     txf->tgvi[i].t0[1] = tgi->y / h + ystep;
   193:     txf->tgvi[i].v0[0] = tgi->xoffset;
   194:     txf->tgvi[i].v0[1] = tgi->yoffset;
   195:     txf->tgvi[i].t1[0] = (tgi->x + tgi->width) / w + xstep;
   196:     txf->tgvi[i].t1[1] = tgi->y / h + ystep;
   197:     txf->tgvi[i].v1[0] = tgi->xoffset + tgi->width;
   198:     txf->tgvi[i].v1[1] = tgi->yoffset;
   199:     txf->tgvi[i].t2[0] = (tgi->x + tgi->width) / w + xstep;
   200:     txf->tgvi[i].t2[1] = (tgi->y + tgi->height) / h + ystep;
   201:     txf->tgvi[i].v2[0] = tgi->xoffset + tgi->width;
   202:     txf->tgvi[i].v2[1] = tgi->yoffset + tgi->height;
   203:     txf->tgvi[i].t3[0] = tgi->x / w + xstep;
   204:     txf->tgvi[i].t3[1] = (tgi->y + tgi->height) / h + ystep;
   205:     txf->tgvi[i].v3[0] = tgi->xoffset;
   206:     txf->tgvi[i].v3[1] = tgi->yoffset + tgi->height;
   207:     txf->tgvi[i].advance = tgi->advance;
   208:   }
   209: 
   210:   min_glyph = txf->tgi[0].c;
   211:   max_glyph = txf->tgi[0].c;
   212:   for (i = 1; i < txf->num_glyphs; i++) {
   213:     if (txf->tgi[i].c < min_glyph) {
   214:       min_glyph = txf->tgi[i].c;
   215:     }
   216:     if (txf->tgi[i].c > max_glyph) {
   217:       max_glyph = txf->tgi[i].c;
   218:     }
   219:   }
   220:   txf->min_glyph = min_glyph;
   221:   txf->range = max_glyph - min_glyph + 1;
   222: 
   223:   txf->lut = (TexGlyphVertexInfo **)
   224:     calloc(txf->range, sizeof(TexGlyphVertexInfo *));
   225:   if (txf->lut == NULL) {
   226:     lastError = "out of memory.";
   227:     goto error;
   228:   }
   229:   for (i = 0; i < txf->num_glyphs; i++) {
   230:     txf->lut[txf->tgi[i].c - txf->min_glyph] = &txf->tgvi[i];
   231:   }
   232: 
   233:   switch (format) {
   234:   case TXF_FORMAT_BYTE:
   235:     if (useLuminanceAlpha) {
   236:       unsigned char *orig;
   237: 
   238:       orig = (unsigned char *) malloc(txf->tex_width * txf->tex_height);
   239:       if (orig == NULL) {
   240:         lastError = "out of memory.";
   241:         goto error;
   242:       }
   243:       got = fread(orig, 1, txf->tex_width * txf->tex_height, file);
   244:       EXPECT(txf->tex_width * txf->tex_height);
   245:       txf->teximage = (unsigned char *)
   246:         malloc(2 * txf->tex_width * txf->tex_height);
   247:       if (txf->teximage == NULL) {
   248:         lastError = "out of memory.";
   249:         goto error;
   250:       }
   251:       for (i = 0; i < txf->tex_width * txf->tex_height; i++) {
   252:         txf->teximage[i * 2] = orig[i];
   253:         txf->teximage[i * 2 + 1] = orig[i];
   254:       }
   255:       free(orig);
   256:     } else {
   257:       txf->teximage = (unsigned char *)
   258:         malloc(txf->tex_width * txf->tex_height);
   259:       if (txf->teximage == NULL) {
   260:         lastError = "out of memory.";
   261:         goto error;
   262:       }
   263:       got = fread(txf->teximage, 1, txf->tex_width * txf->tex_height, file);
   264:       EXPECT(txf->tex_width * txf->tex_height);
   265:     }
   266:     break;
   267:   case TXF_FORMAT_BITMAP:
   268:     width = txf->tex_width;
   269:     height = txf->tex_height;
   270:     stride = (width + 7) >> 3;
   271:     texbitmap = (unsigned char *) malloc(stride * height);
   272:     if (texbitmap == NULL) {
   273:       lastError = "out of memory.";
   274:       goto error;
   275:     }
   276:     got = fread(texbitmap, 1, stride * height, file);
   277:     EXPECT(stride * height);
   278:     if (useLuminanceAlpha) {
   279:       txf->teximage = (unsigned char *) calloc(width * height * 2, 1);
   280:       if (txf->teximage == NULL) {
   281:         lastError = "out of memory.";
   282:         goto error;
   283:       }
   284:       for (i = 0; i < height; i++) {
   285:         for (j = 0; j < width; j++) {
   286:           if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) {
   287:             txf->teximage[(i * width + j) * 2] = 255;
   288:             txf->teximage[(i * width + j) * 2 + 1] = 255;
   289:           }
   290:         }
   291:       }
   292:     } else {
   293:       txf->teximage = (unsigned char *) calloc(width * height, 1);
   294:       if (txf->teximage == NULL) {
   295:         lastError = "out of memory.";
   296:         goto error;
   297:       }
   298:       for (i = 0; i < height; i++) {
   299:         for (j = 0; j < width; j++) {
   300:           if (texbitmap[i * stride + (j >> 3)] & (1 << (j & 7))) {
   301:             txf->teximage[i * width + j] = 255;
   302:           }
   303:         }
   304:       }
   305:     }
   306:     free(texbitmap);
   307:     break;
   308:   }
   309: 
   310:   fclose(file);
   311:   return txf;
   312: 
   313: error:
   314: 
   315:   if (txf) {
   316:     if (txf->tgi)
   317:       free(txf->tgi);
   318:     if (txf->tgvi)
   319:       free(txf->tgvi);
   320:     if (txf->lut)
   321:       free(txf->lut);
   322:     if (txf->teximage)
   323:       free(txf->teximage);
   324:     free(txf);
   325:   }
   326:   if (file)
   327:     fclose(file);
   328:   return NULL;
   329: }
   330: 
   331: GLuint
   332: txfEstablishTexture(
   333:   TexFont * txf,
   334:   GLuint texobj,
   335:   GLboolean setupMipmaps)
   336: {
   337:   if (txf->texobj == 0) {
   338:     if (texobj == 0) {
   339: #if !defined(USE_DISPLAY_LISTS) 
   340:       glGenTextures(1, &txf->texobj);
   341: #else 
   342:       txf->texobj = glGenLists(1);
   343: #endif 
   344:     } else {
   345:       txf->texobj = texobj;
   346:     }
   347:   }
   348: #if !defined(USE_DISPLAY_LISTS) 
   349:   glBindTexture(GL_TEXTURE_2D, txf->texobj);
   350: #else 
   351:   glNewList(txf->texobj, GL_COMPILE);
   352: #endif 
   353: 
   354: #if 1 
   355:   /* XXX Indigo2 IMPACT in IRIX 5.3 and 6.2 does not support the GL_INTENSITY
   356:      internal texture format. Sigh. Win32 non-GLX users should disable this
   357:      code. */
   358:   if (useLuminanceAlpha == 0) {
   359:     char *vendor, *renderer, *version;
   360: 
   361:     renderer = (char *) glGetString(GL_RENDERER);
   362:     vendor = (char *) glGetString(GL_VENDOR);
   363:     if (!strcmp(vendor, "SGI") && !strncmp(renderer, "IMPACT", 6)) {
   364:       version = (char *) glGetString(GL_VERSION);
   365:       if (!strcmp(version, "1.0 Irix 6.2") ||
   366:         !strcmp(version, "1.0 Irix 5.3")) {
   367:         unsigned char *latex;
   368:         int width = txf->tex_width;
   369:         int height = txf->tex_height;
   370:         int i;
   371: 
   372:         useLuminanceAlpha = 1;
   373:         latex = (unsigned char *) calloc(width * height * 2, 1);
   374:         /* XXX unprotected alloc. */
   375:         for (i = 0; i < height * width; i++) {
   376:           latex[i * 2] = txf->teximage[i];
   377:           latex[i * 2 + 1] = txf->teximage[i];
   378:         }
   379:         free(txf->teximage);
   380:         txf->teximage = latex;
   381:       }
   382:     }
   383:   }
   384: #endif 
   385: 
   386:   if (useLuminanceAlpha) {
   387:     if (setupMipmaps) {
   388:       gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE_ALPHA,
   389:         txf->tex_width, txf->tex_height,
   390:         GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, txf->teximage);
   391:     } else {
   392:       glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
   393:         txf->tex_width, txf->tex_height, 0,
   394:         GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, txf->teximage);
   395:     }
   396:   } else {
   397: #if defined(GL_VERSION_1_1) || defined(GL_EXT_texture) 
   398:     /* Use GL_INTENSITY4 as internal texture format since we want to use as
   399:        little texture memory as possible. */
   400:     if (setupMipmaps) {
   401:       gluBuild2DMipmaps(GL_TEXTURE_2D, GL_INTENSITY4,
   402:         txf->tex_width, txf->tex_height,
   403:         GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage);
   404:     } else {
   405:       glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY4,
   406:         txf->tex_width, txf->tex_height, 0,
   407:         GL_LUMINANCE, GL_UNSIGNED_BYTE, txf->teximage);
   408:     }
   409: #else 
   410:     abort();            /* Should not get here without EXT_texture or OpenGL
   411:                            1.1. */
   412: #endif 
   413:   }
   414: 
   415: #if defined(USE_DISPLAY_LISTS) 
   416:   glEndList();
   417:   glCallList(txf->texobj);
   418: #endif 
   419:   return txf->texobj;
   420: }
   421: 
   422: void
   423: txfBindFontTexture(
   424:   TexFont * txf)
   425: {
   426: #if !defined(USE_DISPLAY_LISTS) 
   427:   glBindTexture(GL_TEXTURE_2D, txf->texobj);
   428: #else 
   429:   glCallList(txf->texobj);
   430: #endif 
   431: }
   432: 
   433: void
   434: txfUnloadFont(
   435:   TexFont * txf)
   436: {
   437:   if (txf->teximage) {
   438:     free(txf->teximage);
   439:   }
   440:   free(txf->tgi);
   441:   free(txf->tgvi);
   442:   free(txf->lut);
   443:   free(txf);
   444: }
   445: 
   446: void
   447: txfGetStringMetrics(
   448:   TexFont * txf,
   449:   char *string,
   450:   int len,
   451:   int *width,
   452:   int *max_ascent,
   453:   int *max_descent)
   454: {
   455:   TexGlyphVertexInfo *tgvi;
   456:   int w, i;
   457: 
   458:   w = 0;
   459:   for (i = 0; i < len; i++) {
   460:     if (string[i] == 27) {
   461:       switch (string[i + 1]) {
   462:       case 'M':
   463:         i += 4;
   464:         break;
   465:       case 'T':
   466:         i += 7;
   467:         break;
   468:       case 'L':
   469:         i += 7;
   470:         break;
   471:       case 'F':
   472:         i += 13;
   473:         break;
   474:       }
   475:     } else {
   476:       tgvi = getTCVI(txf, string[i]);
   477:       /* HACK HACK HACK */;
   478:       if(tgvi == NULL) fprintf(stderr, "We're fucked dude!\n");
   479:       w += tgvi->advance;
   480:     }
   481:   }
   482:   *width = w;
   483:   *max_ascent = txf->max_ascent;
   484:   *max_descent = txf->max_descent;
   485: }
   486: 
   487: void
   488: txfRenderGlyph(TexFont * txf, int c)
   489: {
   490:   TexGlyphVertexInfo *tgvi;
   491: 
   492:   tgvi = getTCVI(txf, c);
   493:   glBegin(GL_QUADS);
   494:   glTexCoord2fv(tgvi->t0);
   495:   glVertex2sv(tgvi->v0);
   496:   glTexCoord2fv(tgvi->t1);
   497:   glVertex2sv(tgvi->v1);
   498:   glTexCoord2fv(tgvi->t2);
   499:   glVertex2sv(tgvi->v2);
   500:   glTexCoord2fv(tgvi->t3);
   501:   glVertex2sv(tgvi->v3);
   502:   glEnd();
   503:   glTranslatef(tgvi->advance, 0.0, 0.0);
   504: }
   505: 
   506: void
   507: txfRenderString(
   508:   TexFont * txf,
   509:   char *string,
   510:   int len)
   511: {
   512:   int i;
   513: 
   514:   for (i = 0; i < len; i++) {
   515:     txfRenderGlyph(txf, string[i]);
   516:   }
   517: }
   518: 
   519: enum {
   520:   MONO, TOP_BOTTOM, LEFT_RIGHT, FOUR
   521: };
   522: 
   523: void
   524: txfRenderFancyString(
   525:   TexFont * txf,
   526:   char *string,
   527:   int len)
   528: {
   529:   TexGlyphVertexInfo *tgvi;
   530:   GLubyte c[4][3];
   531:   int mode = MONO;
   532:   int i;
   533: 
   534:   for (i = 0; i < len; i++) {
   535:     if (string[i] == 27) {
   536:       switch (string[i + 1]) {
   537:       case 'M':
   538:         mode = MONO;
   539:         glColor3ubv((GLubyte *) & string[i + 2]);
   540:         i += 4;
   541:         break;
   542:       case 'T':
   543:         mode = TOP_BOTTOM;
   544:         memcpy(c, &string[i + 2], 6);
   545:         i += 7;
   546:         break;
   547:       case 'L':
   548:         mode = LEFT_RIGHT;
   549:         memcpy(c, &string[i + 2], 6);
   550:         i += 7;
   551:         break;
   552:       case 'F':
   553:         mode = FOUR;
   554:         memcpy(c, &string[i + 2], 12);
   555:         i += 13;
   556:         break;
   557:       }
   558:     } else {
   559:       switch (mode) {
   560:       case MONO:
   561:         txfRenderGlyph(txf, string[i]);
   562:         break;
   563:       case TOP_BOTTOM:
   564:         tgvi = getTCVI(txf, string[i]);
   565:         glBegin(GL_QUADS);
   566:         glColor3ubv(c[0]);
   567:         glTexCoord2fv(tgvi->t0);
   568:         glVertex2sv(tgvi->v0);
   569:         glTexCoord2fv(tgvi->t1);
   570:         glVertex2sv(tgvi->v1);
   571:         glColor3ubv(c[1]);
   572:         glTexCoord2fv(tgvi->t2);
   573:         glVertex2sv(tgvi->v2);
   574:         glTexCoord2fv(tgvi->t3);
   575:         glVertex2sv(tgvi->v3);
   576:         glEnd();
   577:         glTranslatef(tgvi->advance, 0.0, 0.0);
   578:         break;
   579:       case LEFT_RIGHT:
   580:         tgvi = getTCVI(txf, string[i]);
   581:         glBegin(GL_QUADS);
   582:         glColor3ubv(c[0]);
   583:         glTexCoord2fv(tgvi->t0);
   584:         glVertex2sv(tgvi->v0);
   585:         glColor3ubv(c[1]);
   586:         glTexCoord2fv(tgvi->t1);
   587:         glVertex2sv(tgvi->v1);
   588:         glColor3ubv(c[1]);
   589:         glTexCoord2fv(tgvi->t2);
   590:         glVertex2sv(tgvi->v2);
   591:         glColor3ubv(c[0]);
   592:         glTexCoord2fv(tgvi->t3);
   593:         glVertex2sv(tgvi->v3);
   594:         glEnd();
   595:         glTranslatef(tgvi->advance, 0.0, 0.0);
   596:         break;
   597:       case FOUR:
   598:         tgvi = getTCVI(txf, string[i]);
   599:         glBegin(GL_QUADS);
   600:         glColor3ubv(c[0]);
   601:         glTexCoord2fv(tgvi->t0);
   602:         glVertex2sv(tgvi->v0);
   603:         glColor3ubv(c[1]);
   604:         glTexCoord2fv(tgvi->t1);
   605:         glVertex2sv(tgvi->v1);
   606:         glColor3ubv(c[2]);
   607:         glTexCoord2fv(tgvi->t2);
   608:         glVertex2sv(tgvi->v2);
   609:         glColor3ubv(c[3]);
   610:         glTexCoord2fv(tgvi->t3);
   611:         glVertex2sv(tgvi->v3);
   612:         glEnd();
   613:         glTranslatef(tgvi->advance, 0.0, 0.0);
   614:         break;
   615:       }
   616:     }
   617:   }
   618: }
   619: 
   620: int
   621: txfInFont(TexFont * txf, int c)
   622: {
   623:   TexGlyphVertexInfo *tgvi;
   624: 
   625:   /* NOTE: No uppercase/lowercase substituion. */
   626:   if ((c >= txf->min_glyph) && (c < txf->min_glyph + txf->range)) {
   627:     if (txf->lut[c - txf->min_glyph]) {
   628:       return 1;
   629:     }
   630:   }
   631:   return 0;
   632: }
   633: