1 /* texfonts, Copyright (c) 2005-2016 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)
492 prev->tex_height = 0;
493 memset (&prev->extents, 0, sizeof(prev->extents));
496 if (prev != data->cache)
497 prev->next = data->cache;
502 /* Not cached, and cache not full. Add a new entry at the front,
503 and allocate a new texture for it.
505 curr = (struct texfont_cache *) calloc (1, sizeof(*prev));
506 glGenTextures (1, &curr->texid);
508 curr->next = data->cache;
515 /* Renders the given string into the prevailing texture.
516 Returns the metrics of the text, and size of the texture.
519 string_to_texture (texture_font_data *data, const char *string,
520 XCharStruct *extents_ret,
521 int *tex_width_ret, int *tex_height_ret)
523 Window window = RootWindow (data->dpy, 0);
527 XWindowAttributes xgwa;
534 /* Measure the string and create a Pixmap of the proper size.
536 XGetWindowAttributes (data->dpy, window, &xgwa);
537 iterate_texture_string (data, string, 0, 0, 0, 0, &overall);
538 width = overall.rbearing - overall.lbearing;
539 height = overall.ascent + overall.descent;
540 if (width <= 0) width = 1;
541 if (height <= 0) height = 1;
542 p = XCreatePixmap (data->dpy, window, width, height, xgwa.depth);
544 gcv.foreground = BlackPixelOfScreen (xgwa.screen);
545 gc = XCreateGC (data->dpy, p, GCForeground, &gcv);
546 XFillRectangle (data->dpy, p, gc, 0, 0, width, height);
547 XFreeGC (data->dpy, gc);
549 /* Render the string into the pixmap.
551 rcolor.red = rcolor.green = rcolor.blue = rcolor.alpha = 0xFFFF;
552 XftColorAllocValue (data->dpy, xgwa.visual, xgwa.colormap,
554 xftdraw = XftDrawCreate (data->dpy, p, xgwa.visual, xgwa.colormap);
555 iterate_texture_string (data, string,
556 -overall.lbearing, overall.ascent,
557 xftdraw, &xftcolor, 0);
558 XftDrawDestroy (xftdraw);
559 XftColorFree (data->dpy, xgwa.visual, xgwa.colormap, &xftcolor);
561 /* Copy the bits from the Pixmap into a texture, unless it's cached.
563 bitmap_to_texture (data->dpy, p, xgwa.visual, xgwa.depth,
565 XFreePixmap (data->dpy, p);
567 if (extents_ret) *extents_ret = overall;
568 if (tex_width_ret) *tex_width_ret = width;
569 if (tex_height_ret) *tex_height_ret = height;
573 /* Set the various OpenGL parameters for properly rendering things
574 with a texture generated by string_to_texture().
577 enable_texture_string_parameters (void)
579 glEnable (GL_TEXTURE_2D);
581 /* Texture-rendering parameters to make font pixmaps tolerable to look at.
583 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
584 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
585 GL_LINEAR_MIPMAP_LINEAR);
587 /* LOD bias is part of OpenGL 1.4.
588 GL_EXT_texture_lod_bias has been present since the original iPhone.
590 # if !defined(GL_TEXTURE_LOD_BIAS) && defined(GL_TEXTURE_LOD_BIAS_EXT)
591 # define GL_TEXTURE_LOD_BIAS GL_TEXTURE_LOD_BIAS_EXT
593 # ifdef GL_TEXTURE_LOD_BIAS
594 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.25);
596 clear_gl_error(); /* invalid enum on iPad 3 */
598 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
599 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
601 /* Don't write the transparent parts of the quad into the depth buffer. */
602 glAlphaFunc (GL_GREATER, 0.01);
603 glEnable (GL_ALPHA_TEST);
605 glDisable (GL_LIGHTING);
606 glDisable (GL_TEXTURE_GEN_S);
607 glDisable (GL_TEXTURE_GEN_T);
608 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
612 /* Draws the string in the scene at the origin.
613 Newlines and tab stops are honored.
614 Any numbers inside [] will be rendered as a subscript.
615 Assumes the font has been loaded as with load_texture_font().
617 The origin is at the origin of the first character, so subsequent
618 lines of a multi-line string are below that.
621 print_texture_string (texture_font_data *data, const char *string)
624 int tex_width, tex_height;
625 texfont_cache *cache;
628 if (!*string) return;
632 /* Save the prevailing texture ID, and bind ours. Restored at the end. */
633 glGetIntegerv (GL_TEXTURE_BINDING_2D, &old_texture);
635 cache = get_cache (data, string);
637 glBindTexture (GL_TEXTURE_2D, cache->texid);
638 check_gl_error ("texture font binding");
640 /* Measure the string and make a pixmap that will fit it,
645 overall = data->cache->extents;
646 tex_width = data->cache->tex_width;
647 tex_height = data->cache->tex_height;
650 string_to_texture (data, string, &overall, &tex_width, &tex_height);
654 Bool alpha_p, blend_p, light_p, gen_s_p, gen_t_p;
656 GLfloat qx0, qy0, qx1, qy1;
657 GLfloat tx0, ty0, tx1, ty1;
659 /* If face culling is not enabled, draw front and back. */
660 Bool draw_back_face_p = !glIsEnabled (GL_CULL_FACE);
662 /* Save the prevailing texture environment, and set up ours.
664 glGetIntegerv (GL_FRONT_FACE, &ofront);
665 glGetIntegerv (GL_BLEND_DST, &oblend);
666 glGetFloatv (GL_TEXTURE_MATRIX, omatrix);
667 blend_p = glIsEnabled (GL_BLEND);
668 alpha_p = glIsEnabled (GL_ALPHA_TEST);
669 light_p = glIsEnabled (GL_LIGHTING);
670 gen_s_p = glIsEnabled (GL_TEXTURE_GEN_S);
671 gen_t_p = glIsEnabled (GL_TEXTURE_GEN_T);
675 glNormal3f (0, 0, 1);
678 glMatrixMode (GL_TEXTURE);
680 glMatrixMode (GL_MODELVIEW);
682 enable_texture_string_parameters();
684 /* Draw a quad with that texture on it, possibly using a cached texture.
685 Position the XCharStruct origin at 0,0 in the scene.
687 qx0 = overall.lbearing;
688 qy0 = -overall.descent;
689 qx1 = overall.rbearing;
690 qy1 = overall.ascent;
694 tx1 = (overall.rbearing - overall.lbearing) / (GLfloat) tex_width;
695 ty0 = (overall.ascent + overall.descent) / (GLfloat) tex_height;
697 glEnable (GL_CULL_FACE);
698 glFrontFace (GL_CCW);
700 glTexCoord2f (tx0, ty0); glVertex3f (qx0, qy0, 0);
701 glTexCoord2f (tx1, ty0); glVertex3f (qx1, qy0, 0);
702 glTexCoord2f (tx1, ty1); glVertex3f (qx1, qy1, 0);
703 glTexCoord2f (tx0, ty1); glVertex3f (qx0, qy1, 0);
706 if (draw_back_face_p)
710 glTexCoord2f (tx0, ty0); glVertex3f (qx0, qy0, 0);
711 glTexCoord2f (tx1, ty0); glVertex3f (qx1, qy0, 0);
712 glTexCoord2f (tx1, ty1); glVertex3f (qx1, qy1, 0);
713 glTexCoord2f (tx0, ty1); glVertex3f (qx0, qy1, 0);
715 glDisable (GL_CULL_FACE);
720 /* Reset to the caller's texture environment.
722 glBindTexture (GL_TEXTURE_2D, old_texture);
723 glFrontFace (ofront);
724 if (!alpha_p) glDisable (GL_ALPHA_TEST);
725 if (!blend_p) glDisable (GL_BLEND);
726 if (light_p) glEnable (GL_LIGHTING);
727 if (gen_s_p) glEnable (GL_TEXTURE_GEN_S);
728 if (gen_t_p) glEnable (GL_TEXTURE_GEN_T);
730 glBlendFunc (GL_SRC_ALPHA, oblend);
732 glMatrixMode (GL_TEXTURE);
733 glMultMatrixf (omatrix);
734 glMatrixMode (GL_MODELVIEW);
736 check_gl_error ("texture font print");
738 /* Store this string into the cache, unless that's where it came from.
742 cache->string = strdup (string);
743 cache->extents = overall;
744 cache->tex_width = tex_width;
745 cache->tex_height = tex_height;
751 /* Draws the string on the window at the given pixel position.
752 Newlines and tab stops are honored.
753 Any numbers inside [] will be rendered as a subscript.
754 Assumes the font has been loaded as with load_texture_font().
756 Position is 0 for center, 1 for top left, 2 for bottom left.
759 print_texture_label (Display *dpy,
760 texture_font_data *data,
761 int window_width, int window_height,
767 Bool tex_p = glIsEnabled (GL_TEXTURE_2D);
768 Bool texs_p = glIsEnabled (GL_TEXTURE_GEN_S);
769 Bool text_p = glIsEnabled (GL_TEXTURE_GEN_T);
770 Bool depth_p = glIsEnabled (GL_DEPTH_TEST);
771 Bool cull_p = glIsEnabled (GL_CULL_FACE);
772 Bool fog_p = glIsEnabled (GL_FOG);
775 # ifndef HAVE_JWZGLES
777 glGetIntegerv (GL_POLYGON_MODE, opoly);
780 glGetIntegerv (GL_VIEWPORT, ovp);
782 glGetFloatv (GL_CURRENT_COLOR, color);
784 glEnable (GL_TEXTURE_2D);
785 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
786 glPolygonMode (GL_FRONT, GL_FILL);
788 glDisable (GL_TEXTURE_GEN_S);
789 glDisable (GL_TEXTURE_GEN_T);
790 glDisable (GL_CULL_FACE);
793 glDisable (GL_DEPTH_TEST);
795 /* Each matrix mode has its own stack, so we need to push/pop
798 glMatrixMode(GL_PROJECTION);
803 glMatrixMode(GL_MODELVIEW);
808 int x, y, w, h, swap;
809 /* int rot = (int) current_device_rotation(); */
810 int rot = 0; /* Since GL hacks rotate now */
813 glViewport (0, 0, window_width, window_height);
814 glOrtho (0, window_width, 0, window_height, -1, 1);
816 while (rot <= -180) rot += 360;
817 while (rot > 180) rot -= 360;
819 texture_string_metrics (data, string, &cs, &ascent, &descent);
820 h = cs.ascent + cs.descent;
825 /* Size of the font is in points, so scale iOS pixels to points. */
826 GLfloat scale = ((window_width > window_height
827 ? window_width : window_height)
829 if (scale < 1) scale = 1;
831 /* jwxyz-XLoadFont has already doubled the font size, to compensate
832 for physically smaller screens. Undo that, since OpenGL hacks
833 use full-resolution framebuffers, unlike X11 hacks. */
836 window_width /= scale;
837 window_height /= scale;
838 glScalef (scale, scale, scale);
840 # endif /* USE_IPHONE */
842 if (rot > 135 || rot < -135) /* 180 */
844 glTranslatef (window_width, window_height, 0);
845 glRotatef (180, 0, 0, 1);
847 else if (rot > 45) /* 90 */
849 glTranslatef (window_width, 0, 0);
850 glRotatef (90, 0, 0, 1);
852 window_width = window_height;
853 window_height = swap;
855 else if (rot < -45) /* 270 */
857 glTranslatef(0, window_height, 0);
858 glRotatef (-90, 0, 0, 1);
860 window_width = window_height;
861 window_height = swap;
866 x = (window_width - w) / 2;
867 y = (window_height + h) / 2 - ascent;
871 y = window_height - ascent*2;
881 glTranslatef (x, y, 0);
883 /* draw the text five times, to give it a border. */
885 const XPoint offsets[] = {{ -1, -1 },
893 for (i = 0; i < countof(offsets); i++)
895 if (offsets[i].x == 0)
898 glTranslatef (offsets[i].x, offsets[i].y, 0);
899 print_texture_string (data, string);
906 glMatrixMode(GL_PROJECTION);
909 if (tex_p) glEnable (GL_TEXTURE_2D); else glDisable (GL_TEXTURE_2D);
910 if (texs_p) glEnable (GL_TEXTURE_GEN_S);/*else glDisable(GL_TEXTURE_GEN_S);*/
911 if (text_p) glEnable (GL_TEXTURE_GEN_T);/*else glDisable(GL_TEXTURE_GEN_T);*/
912 if (depth_p) glEnable (GL_DEPTH_TEST); else glDisable (GL_DEPTH_TEST);
913 if (cull_p) glEnable (GL_CULL_FACE); /*else glDisable (GL_CULL_FACE);*/
914 if (fog_p) glEnable (GL_FOG); /*else glDisable (GL_FOG);*/
916 glViewport (ovp[0], ovp[1], ovp[2], ovp[3]);
918 # ifndef HAVE_JWZGLES
919 glPolygonMode (GL_FRONT, opoly[0]);
922 glMatrixMode(GL_MODELVIEW);
928 texfont_unicode_character_name (texture_font_data *data, unsigned long uc)
930 Font fid = data->xftfont->xfont->fid;
931 return jwxyz_unicode_character_name (data->dpy, fid, uc);
933 #endif /* HAVE_JWXYZ */
937 /* Releases the font and texture.
940 free_texture_font (texture_font_data *data)
944 texfont_cache *next = data->cache->next;
945 glDeleteTextures (1, &data->cache->texid);
950 XftFontClose (data->dpy, data->xftfont);