1 /* texfonts, Copyright (c) 2005-2015 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Renders X11 fonts into textures for use with OpenGL.
12 * A higher level API is in glxfonts.c.
28 # include <OpenGL/glu.h>
30 #elif defined(HAVE_ANDROID)
40 #endif /* HAVE_JWZGLES */
42 #ifdef HAVE_XSHM_EXTENSION
44 #endif /* HAVE_XSHM_EXTENSION */
47 #include "resources.h"
49 #include "fps.h" /* for current_device_rotation() */
51 #undef HAVE_XSHM_EXTENSION /* doesn't actually do any good here */
54 /* These are in xlock-gl.c */
55 extern void clear_gl_error (void);
56 extern void check_gl_error (const char *type);
59 extern char *progname;
61 /* LRU cache of textures, to optimize the case where we're drawing the
62 same strings repeatedly.
64 typedef struct texfont_cache texfont_cache;
65 struct texfont_cache {
69 int tex_width, tex_height;
73 struct texture_font_data {
82 #define countof(x) (sizeof((x))/sizeof((*x)))
85 /* return the next larger power of 2. */
89 static const unsigned int pow2[] = {
90 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
91 2048, 4096, 8192, 16384, 32768, 65536 };
93 for (j = 0; j < sizeof(pow2)/sizeof(*pow2); j++)
94 if (pow2[j] >= i) return pow2[j];
95 abort(); /* too big! */
99 /* Given a Pixmap (of screen depth), converts it to an OpenGL luminance mipmap.
100 RGB are averaged to grayscale, and the resulting value is treated as alpha.
101 Pass in the size of the pixmap; the size of the texture is returned
102 (it may be larger, since GL like powers of 2.)
104 We use a screen-depth pixmap instead of a 1bpp bitmap so that if the fonts
105 were drawn with antialiasing, that is preserved.
108 bitmap_to_texture (Display *dpy, Pixmap p, Visual *visual, int depth,
111 Bool mipmap_p = True;
114 int w2 = to_pow2 (ow);
115 int h2 = to_pow2 (oh);
116 int x, y, max, scale;
118 unsigned char *data = (unsigned char *) calloc (w2 * 2, (h2 + 1));
119 unsigned char *out = data;
121 /* If either dimension is larger than the supported size, reduce.
122 We still return the old size to keep the caller's math working,
123 but the texture itself will have fewer pixels in it.
125 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max);
127 while (w2 > max || h2 > max)
134 /* OpenGLES doesn't support GL_INTENSITY, so instead of using a
135 texture with 1 byte per pixel, the intensity value, we have
136 to use 2 bytes per pixel: solid white, and an alpha value.
143 GLuint iformat = GL_INTENSITY;
144 GLuint format = GL_LUMINANCE;
146 GLuint iformat = GL_LUMINANCE_ALPHA;
147 GLuint format = GL_LUMINANCE_ALPHA;
149 GLuint type = GL_UNSIGNED_BYTE;
151 # ifdef HAVE_XSHM_EXTENSION
152 Bool use_shm = get_boolean_resource (dpy, "useSHM", "Boolean");
153 XShmSegmentInfo shm_info;
154 # endif /* HAVE_XSHM_EXTENSION */
156 # ifdef HAVE_XSHM_EXTENSION
159 image = create_xshm_image (dpy, visual, depth, ZPixmap, 0, &shm_info,
162 XShmGetImage (dpy, p, image, 0, 0, ~0L);
166 # endif /* HAVE_XSHM_EXTENSION */
169 image = XGetImage (dpy, p, 0, 0, ow, oh, ~0L, ZPixmap);
172 /* This would work, but it's wasteful for no benefit. */
177 fprintf (stderr, "\n");
179 for (y = 0; y < h2; y++) {
180 for (x = 0; x < w2; x++) {
181 /* Might be better to average a scale x scale square of source pixels,
182 but at the resolutions we're dealing with, this is probably good
186 unsigned long pixel = (sx >= ow || sy >= oh ? 0 :
187 XGetPixel (image, sx, sy));
188 /* instead of averaging all three channels, let's just use red,
189 and assume it was already grayscale. */
190 unsigned long r = pixel & visual->red_mask;
191 /* This goofy trick is to make any of RGBA/ABGR/ARGB work. */
192 pixel = ((r >> 24) | (r >> 16) | (r >> 8) | r) & 0xFF;
195 if (sx < ow && sy < oh)
197 fprintf (stderr, "%c",
198 r >= 0xFF000000 ? '#' :
199 r >= 0x88000000 ? '%' :
202 fprintf (stderr, "%c",
203 r >= 0xFF0000 ? '#' :
204 r >= 0x880000 ? '%' :
209 # if 0 /* Debugging checkerboard */
210 if (sx < ow && sy < oh && (((sx / 4) & 1) ^ ((sy / 4) & 1)))
214 # ifndef GL_INTENSITY
215 *out++ = 0xFF; /* 2 bytes per pixel (luminance, alpha) */
220 fprintf (stderr, "\n");
224 # ifdef HAVE_XSHM_EXTENSION
226 destroy_xshm_image (dpy, image, &shm_info);
228 # endif /* HAVE_XSHM_EXTENSION */
229 XDestroyImage (image);
234 gluBuild2DMipmaps (GL_TEXTURE_2D, iformat, w2, h2, format, type, data);
236 glTexImage2D (GL_TEXTURE_2D, 0, iformat, w2, h2, 0, format, type, data);
240 sprintf (msg, "texture font %s (%d x %d)",
241 mipmap_p ? "gluBuild2DMipmaps" : "glTexImage2D",
243 check_gl_error (msg);
253 /* Loads the font named by the X resource "res" and returns
254 a texture-font object.
257 load_texture_font (Display *dpy, char *res)
259 int screen = DefaultScreen (dpy);
260 char *font = get_string_resource (dpy, res, "Font");
261 const char *def1 = "-*-helvetica-medium-r-normal-*-*-180-*-*-*-*-*-*";
262 const char *def2 = "-*-helvetica-medium-r-normal-*-*-140-*-*-*-*-*-*";
263 const char *def3 = "fixed";
265 texture_font_data *data;
266 int cache_size = get_integer_resource (dpy, "texFontCacheSize", "Integer");
268 /* Hacks that draw a lot of different strings on the screen simultaneously,
269 like Star Wars, should set this to a larger value for performance. */
273 if (!res || !*res) abort();
275 if (!strcmp (res, "fpsFont")) { /* Kludge. */
276 def1 = "-*-courier-bold-r-normal-*-*-140-*-*-*-*-*-*";
277 cache_size = 0; /* No need for a cache on FPS: already throttled. */
280 if (!font) font = strdup(def1);
282 f = XftFontOpenXlfd (dpy, screen, font);
283 if (!f && !!strcmp (font, def1))
285 fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
286 progname, font, def1);
288 font = strdup (def1);
289 f = XftFontOpenXlfd (dpy, screen, font);
292 if (!f && !!strcmp (font, def2))
294 fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
295 progname, font, def2);
297 font = strdup (def2);
298 f = XftFontOpenXlfd (dpy, screen, font);
301 if (!f && !!strcmp (font, def3))
303 fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
304 progname, font, def3);
306 font = strdup (def3);
307 f = XftFontOpenXlfd (dpy, screen, font);
312 fprintf (stderr, "%s: unable to load fallback font \"%s\" either!\n",
320 data = (texture_font_data *) calloc (1, sizeof(*data));
323 data->cache_size = cache_size;
329 /* Measure the string, returning the overall metrics.
330 Newlines and tab stops are honored.
331 Any numbers inside [] will be rendered as a subscript.
333 The origin is at the origin of the first character, so subsequent
334 lines of a multi-line string look like descenders (below baseline).
336 If an XftDraw is supplied, render the string as well, at X,Y.
337 Positive Y is down (X11 style, not OpenGL style).
340 iterate_texture_string (texture_font_data *data,
342 int draw_x, int draw_y,
343 XftDraw *xftdraw, XftColor *xftcolor,
344 XCharStruct *metrics_ret)
346 int line_height = data->xftfont->ascent + data->xftfont->descent;
347 int subscript_offset = line_height * 0.3;
349 Bool sub_p = False, osub_p = False;
350 int cw = 0, tabs = 0;
351 XCharStruct overall = { 0, };
360 (*s == '[' && isdigit(s[1])) ||
361 (*s == ']' && sub_p))
368 if (sub_p) y2 += subscript_offset;
370 XftTextExtentsUtf8 (data->dpy, data->xftfont,
371 (FcChar8 *) os, (int) (s - os),
373 c.lbearing = -e.x; /* XGlyphInfo to XCharStruct */
374 c.rbearing = e.width - e.x;
376 c.descent = e.height - e.y;
381 # define MAX(A,B) ((A)>(B)?(A):(B))
382 # define MIN(A,B) ((A)<(B)?(A):(B))
383 overall.ascent = MAX (overall.ascent, -y2 + c.ascent);
384 overall.descent = MAX (overall.descent, y2 + c.descent);
385 overall.lbearing = MIN (overall.lbearing, (x + c.lbearing));
386 overall.rbearing = MAX (overall.rbearing, x + c.rbearing);
387 overall.width = MAX (overall.width, x + c.width);
403 /* Measure "m" to determine tab width. */
405 XftTextExtentsUtf8 (data->dpy, data->xftfont,
406 (FcChar8 *) "m", 1, &e);
411 x = ((x + tabs) / tabs) * tabs;
413 else if (*s == '[' && isdigit(s[1]))
415 else if (*s == ']' && sub_p)
418 if (xftdraw && s != os)
419 XftDrawStringUtf8 (xftdraw, xftcolor, data->xftfont,
422 oy + (osub_p ? subscript_offset : 0),
423 (FcChar8 *) os, (int) (s - os));
434 *metrics_ret = overall;
438 /* Bounding box of the multi-line string, in pixels,
439 and overall ascent/descent of the font.
442 texture_string_metrics (texture_font_data *data, const char *s,
443 XCharStruct *metrics_ret,
444 int *ascent_ret, int *descent_ret)
447 iterate_texture_string (data, s, 0, 0, 0, 0, metrics_ret);
448 if (ascent_ret) *ascent_ret = data->xftfont->ascent;
449 if (descent_ret) *descent_ret = data->xftfont->descent;
453 /* Returns a cache entry for this string, with a valid texid.
454 If the returned entry has a string in it, the texture is valid.
455 Otherwise it is an empty entry waiting to be rendered.
457 static struct texfont_cache *
458 get_cache (texture_font_data *data, const char *string)
461 texfont_cache *prev = 0, *prev2 = 0, *curr = 0, *next = 0;
464 for (prev2 = 0, prev = 0, curr = data->cache, next = curr->next;
466 prev2 = prev, prev = curr, curr = next,
467 next = (curr ? curr->next : 0), count++)
469 if (!strcmp (string, curr->string))
472 prev->next = next; /* Unlink from list */
473 if (curr != data->cache)
475 curr->next = data->cache; /* Move to front */
482 /* Made it to the end of the list without a hit.
483 If the cache is full, empty out the last one on the list,
484 and move it to the front. Keep the texid.
486 if (count > data->cache_size)
491 prev->tex_height = 0;
492 memset (&prev->extents, 0, sizeof(prev->extents));
495 if (prev != data->cache)
496 prev->next = data->cache;
501 /* Not cached, and cache not full. Add a new entry at the front,
502 and allocate a new texture for it.
504 curr = (struct texfont_cache *) calloc (1, sizeof(*prev));
505 glGenTextures (1, &curr->texid);
507 curr->next = data->cache;
514 /* Renders the given string into the prevailing texture.
515 Returns the metrics of the text, and size of the texture.
518 string_to_texture (texture_font_data *data, const char *string,
519 XCharStruct *extents_ret,
520 int *tex_width_ret, int *tex_height_ret)
522 Window window = RootWindow (data->dpy, 0);
526 XWindowAttributes xgwa;
533 /* Measure the string and create a Pixmap of the proper size.
535 XGetWindowAttributes (data->dpy, window, &xgwa);
536 iterate_texture_string (data, string, 0, 0, 0, 0, &overall);
537 width = overall.rbearing - overall.lbearing;
538 height = overall.ascent + overall.descent;
539 if (width <= 0) width = 1;
540 if (height <= 0) height = 1;
541 p = XCreatePixmap (data->dpy, window, width, height, xgwa.depth);
543 gcv.foreground = BlackPixelOfScreen (xgwa.screen);
544 gc = XCreateGC (data->dpy, p, GCForeground, &gcv);
545 XFillRectangle (data->dpy, p, gc, 0, 0, width, height);
546 XFreeGC (data->dpy, gc);
548 /* Render the string into the pixmap.
550 rcolor.red = rcolor.green = rcolor.blue = rcolor.alpha = 0xFFFF;
551 XftColorAllocValue (data->dpy, xgwa.visual, xgwa.colormap,
553 xftdraw = XftDrawCreate (data->dpy, p, xgwa.visual, xgwa.colormap);
554 iterate_texture_string (data, string,
555 -overall.lbearing, overall.ascent,
556 xftdraw, &xftcolor, 0);
557 XftDrawDestroy (xftdraw);
558 XftColorFree (data->dpy, xgwa.visual, xgwa.colormap, &xftcolor);
560 /* Copy the bits from the Pixmap into a texture, unless it's cached.
562 bitmap_to_texture (data->dpy, p, xgwa.visual, xgwa.depth,
564 XFreePixmap (data->dpy, p);
566 if (extents_ret) *extents_ret = overall;
567 if (tex_width_ret) *tex_width_ret = width;
568 if (tex_height_ret) *tex_height_ret = height;
572 /* Set the various OpenGL parameters for properly rendering things
573 with a texture generated by string_to_texture().
576 enable_texture_string_parameters (void)
578 glEnable (GL_TEXTURE_2D);
580 /* Texture-rendering parameters to make font pixmaps tolerable to look at.
582 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
583 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
584 GL_LINEAR_MIPMAP_LINEAR);
586 /* LOD bias is part of OpenGL 1.4.
587 GL_EXT_texture_lod_bias has been present since the original iPhone.
589 # if !defined(GL_TEXTURE_LOD_BIAS) && defined(GL_TEXTURE_LOD_BIAS_EXT)
590 # define GL_TEXTURE_LOD_BIAS GL_TEXTURE_LOD_BIAS_EXT
592 # ifdef GL_TEXTURE_LOD_BIAS
593 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.25);
595 clear_gl_error(); /* invalid enum on iPad 3 */
597 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
598 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
600 /* Don't write the transparent parts of the quad into the depth buffer. */
601 glAlphaFunc (GL_GREATER, 0.01);
602 glEnable (GL_ALPHA_TEST);
604 glDisable (GL_LIGHTING);
605 glDisable (GL_TEXTURE_GEN_S);
606 glDisable (GL_TEXTURE_GEN_T);
607 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
611 /* Draws the string in the scene at the origin.
612 Newlines and tab stops are honored.
613 Any numbers inside [] will be rendered as a subscript.
614 Assumes the font has been loaded as with load_texture_font().
616 The origin is at the origin of the first character, so subsequent
617 lines of a multi-line string are below that.
620 print_texture_string (texture_font_data *data, const char *string)
623 int tex_width, tex_height;
624 texfont_cache *cache;
627 if (!*string) return;
631 /* Save the prevailing texture ID, and bind ours. Restored at the end. */
632 glGetIntegerv (GL_TEXTURE_BINDING_2D, &old_texture);
634 cache = get_cache (data, string);
636 glBindTexture (GL_TEXTURE_2D, cache->texid);
637 check_gl_error ("texture font binding");
639 /* Measure the string and make a pixmap that will fit it,
644 overall = data->cache->extents;
645 tex_width = data->cache->tex_width;
646 tex_height = data->cache->tex_height;
649 string_to_texture (data, string, &overall, &tex_width, &tex_height);
653 Bool alpha_p, blend_p, light_p, gen_s_p, gen_t_p;
655 GLfloat qx0, qy0, qx1, qy1;
656 GLfloat tx0, ty0, tx1, ty1;
658 /* If face culling is not enabled, draw front and back. */
659 Bool draw_back_face_p = !glIsEnabled (GL_CULL_FACE);
661 /* Save the prevailing texture environment, and set up ours.
663 glGetIntegerv (GL_FRONT_FACE, &ofront);
664 glGetIntegerv (GL_BLEND_DST, &oblend);
665 glGetFloatv (GL_TEXTURE_MATRIX, omatrix);
666 blend_p = glIsEnabled (GL_BLEND);
667 alpha_p = glIsEnabled (GL_ALPHA_TEST);
668 light_p = glIsEnabled (GL_LIGHTING);
669 gen_s_p = glIsEnabled (GL_TEXTURE_GEN_S);
670 gen_t_p = glIsEnabled (GL_TEXTURE_GEN_T);
674 glNormal3f (0, 0, 1);
677 glMatrixMode (GL_TEXTURE);
679 glMatrixMode (GL_MODELVIEW);
681 enable_texture_string_parameters();
683 /* Draw a quad with that texture on it, possibly using a cached texture.
684 Position the XCharStruct origin at 0,0 in the scene.
686 qx0 = overall.lbearing;
687 qy0 = -overall.descent;
688 qx1 = overall.rbearing;
689 qy1 = overall.ascent;
693 tx1 = (overall.rbearing - overall.lbearing) / (GLfloat) tex_width;
694 ty0 = (overall.ascent + overall.descent) / (GLfloat) tex_height;
696 glEnable (GL_CULL_FACE);
697 glFrontFace (GL_CCW);
699 glTexCoord2f (tx0, ty0); glVertex3f (qx0, qy0, 0);
700 glTexCoord2f (tx1, ty0); glVertex3f (qx1, qy0, 0);
701 glTexCoord2f (tx1, ty1); glVertex3f (qx1, qy1, 0);
702 glTexCoord2f (tx0, ty1); glVertex3f (qx0, qy1, 0);
705 if (draw_back_face_p)
709 glTexCoord2f (tx0, ty0); glVertex3f (qx0, qy0, 0);
710 glTexCoord2f (tx1, ty0); glVertex3f (qx1, qy0, 0);
711 glTexCoord2f (tx1, ty1); glVertex3f (qx1, qy1, 0);
712 glTexCoord2f (tx0, ty1); glVertex3f (qx0, qy1, 0);
714 glDisable (GL_CULL_FACE);
719 /* Reset to the caller's texture environment.
721 glBindTexture (GL_TEXTURE_2D, old_texture);
722 glFrontFace (ofront);
723 if (!alpha_p) glDisable (GL_ALPHA_TEST);
724 if (!blend_p) glDisable (GL_BLEND);
725 if (light_p) glEnable (GL_LIGHTING);
726 if (gen_s_p) glEnable (GL_TEXTURE_GEN_S);
727 if (gen_t_p) glEnable (GL_TEXTURE_GEN_T);
729 glBlendFunc (GL_SRC_ALPHA, oblend);
731 glMatrixMode (GL_TEXTURE);
732 glMultMatrixf (omatrix);
733 glMatrixMode (GL_MODELVIEW);
735 check_gl_error ("texture font print");
737 /* Store this string into the cache, unless that's where it came from.
741 cache->string = strdup (string);
742 cache->extents = overall;
743 cache->tex_width = tex_width;
744 cache->tex_height = tex_height;
750 /* Draws the string on the window at the given pixel position.
751 Newlines and tab stops are honored.
752 Any numbers inside [] will be rendered as a subscript.
753 Assumes the font has been loaded as with load_texture_font().
755 Position is 0 for center, 1 for top left, 2 for bottom left.
758 print_texture_label (Display *dpy,
759 texture_font_data *data,
760 int window_width, int window_height,
766 Bool tex_p = glIsEnabled (GL_TEXTURE_2D);
767 Bool texs_p = glIsEnabled (GL_TEXTURE_GEN_S);
768 Bool text_p = glIsEnabled (GL_TEXTURE_GEN_T);
769 Bool depth_p = glIsEnabled (GL_DEPTH_TEST);
770 Bool cull_p = glIsEnabled (GL_CULL_FACE);
771 Bool fog_p = glIsEnabled (GL_FOG);
774 # ifndef HAVE_JWZGLES
776 glGetIntegerv (GL_POLYGON_MODE, opoly);
779 glGetIntegerv (GL_VIEWPORT, ovp);
781 glGetFloatv (GL_CURRENT_COLOR, color);
783 glEnable (GL_TEXTURE_2D);
784 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
785 glPolygonMode (GL_FRONT, GL_FILL);
787 glDisable (GL_TEXTURE_GEN_S);
788 glDisable (GL_TEXTURE_GEN_T);
789 glDisable (GL_CULL_FACE);
792 glDisable (GL_DEPTH_TEST);
794 /* Each matrix mode has its own stack, so we need to push/pop
797 glMatrixMode(GL_PROJECTION);
802 glMatrixMode(GL_MODELVIEW);
807 int x, y, w, h, swap;
808 int rot = (int) current_device_rotation();
811 glViewport (0, 0, window_width, window_height);
812 glOrtho (0, window_width, 0, window_height, -1, 1);
814 while (rot <= -180) rot += 360;
815 while (rot > 180) rot -= 360;
817 texture_string_metrics (data, string, &cs, &ascent, &descent);
818 h = cs.ascent + cs.descent;
823 /* Size of the font is in points, so scale iOS pixels to points. */
824 GLfloat scale = window_width / 768.0;
825 if (scale < 1) scale = 1;
827 /* jwxyz-XLoadFont has already doubled the font size, to compensate
828 for physically smaller screens. Undo that, since OpenGL hacks
829 use full-resolution framebuffers, unlike X11 hacks. */
832 window_width /= scale;
833 window_height /= scale;
834 glScalef (scale, scale, scale);
836 # endif /* USE_IPHONE */
838 if (rot > 135 || rot < -135) /* 180 */
840 glTranslatef (window_width, window_height, 0);
841 glRotatef (180, 0, 0, 1);
843 else if (rot > 45) /* 90 */
845 glTranslatef (window_width, 0, 0);
846 glRotatef (90, 0, 0, 1);
848 window_width = window_height;
849 window_height = swap;
851 else if (rot < -45) /* 270 */
853 glTranslatef(0, window_height, 0);
854 glRotatef (-90, 0, 0, 1);
856 window_width = window_height;
857 window_height = swap;
862 x = (window_width - w) / 2;
863 y = (window_height + h) / 2 - ascent;
867 y = window_height - ascent*2;
877 glTranslatef (x, y, 0);
879 /* draw the text five times, to give it a border. */
881 const XPoint offsets[] = {{ -1, -1 },
889 for (i = 0; i < countof(offsets); i++)
891 if (offsets[i].x == 0)
894 glTranslatef (offsets[i].x, offsets[i].y, 0);
895 print_texture_string (data, string);
902 glMatrixMode(GL_PROJECTION);
905 if (tex_p) glEnable (GL_TEXTURE_2D); else glDisable (GL_TEXTURE_2D);
906 if (texs_p) glEnable (GL_TEXTURE_GEN_S);/*else glDisable(GL_TEXTURE_GEN_S);*/
907 if (text_p) glEnable (GL_TEXTURE_GEN_T);/*else glDisable(GL_TEXTURE_GEN_T);*/
908 if (depth_p) glEnable (GL_DEPTH_TEST); else glDisable (GL_DEPTH_TEST);
909 if (cull_p) glEnable (GL_CULL_FACE); /*else glDisable (GL_CULL_FACE);*/
910 if (fog_p) glEnable (GL_FOG); /*else glDisable (GL_FOG);*/
912 glViewport (ovp[0], ovp[1], ovp[2], ovp[3]);
914 # ifndef HAVE_JWZGLES
915 glPolygonMode (GL_FRONT, opoly[0]);
918 glMatrixMode(GL_MODELVIEW);
922 /* Releases the font and texture.
925 free_texture_font (texture_font_data *data)
929 texfont_cache *next = data->cache->next;
930 glDeleteTextures (1, &data->cache->texid);
935 XftFontClose (data->dpy, data->xftfont);