1 /* texfonts, Copyright (c) 2005 Jamie Zawinski <jwz@jwz.org>
2 * Loads X11 fonts into textures for use with OpenGL.
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
21 #include "resources.h"
24 /* These are in xlock-gl.c */
25 extern void clear_gl_error (void);
26 extern void check_gl_error (const char *type);
29 extern char *progname;
31 struct texture_font_data {
35 int cell_width, cell_height;
36 int tex_width, tex_height;
40 /* return the next larger power of 2. */
44 static unsigned int pow2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
45 2048, 4096, 8192, 16384, 32768, 65536 };
47 for (j = 0; j < sizeof(pow2)/sizeof(*pow2); j++)
48 if (pow2[j] >= i) return pow2[j];
49 abort(); /* too big! */
53 /* Given a Pixmap of depth 1, converts it to an OpenGL luminance mipmap.
54 The 1 bits are drawn, the 0 bits are alpha.
55 Pass in the size of the pixmap; the size of the texture is returned
56 (it may be larger, since GL like powers of 2.)
59 bitmap_to_texture (Display *dpy, Pixmap p, int *wP, int *hP)
64 int w2 = to_pow2 (ow);
65 int h2 = to_pow2 (oh);
67 XImage *image = XGetImage (dpy, p, 0, 0, ow, oh, ~0L, XYPixmap);
68 unsigned char *data = (unsigned char *) calloc (w2, (h2 + 1));
69 unsigned char *out = data;
70 GLuint iformat = GL_INTENSITY;
71 GLuint format = GL_LUMINANCE;
72 GLuint type = GL_UNSIGNED_BYTE;
74 for (y = 0; y < h2; y++)
75 for (x = 0; x < w2; x++)
76 *out++ = (x >= ow || y >= oh ? 0 :
77 XGetPixel (image, x, y) ? 255 : 0);
78 XDestroyImage (image);
82 gluBuild2DMipmaps (GL_TEXTURE_2D, iformat, w2, h2, format, type, data);
84 glTexImage2D (GL_TEXTURE_2D, 0, iformat, w2, h2, 0, format, type, data);
88 sprintf (msg, "%s (%d x %d)",
89 mipmap_p ? "gluBuild2DMipmaps" : "glTexImage2D",
95 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
96 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
97 mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
99 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
100 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
109 /* Loads the font named by the X resource "res" and returns
110 a texture-font object.
113 load_texture_font (Display *dpy, char *res)
115 texture_font_data *data = 0;
116 const char *font = get_string_resource (res, "Font");
117 const char *def1 = "-*-times-bold-r-normal-*-240-*";
118 const char *def2 = "-*-times-bold-r-normal-*-180-*";
119 const char *def3 = "fixed";
122 if (!res || !*res) abort();
123 if (!font) font = def1;
125 f = XLoadQueryFont(dpy, font);
126 if (!f && !!strcmp (font, def1))
128 fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
129 progname, font, def1);
131 f = XLoadQueryFont(dpy, font);
134 if (!f && !!strcmp (font, def2))
136 fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
137 progname, font, def2);
139 f = XLoadQueryFont(dpy, font);
142 if (!f && !!strcmp (font, def3))
144 fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
145 progname, font, def3);
147 f = XLoadQueryFont(dpy, font);
152 fprintf (stderr, "%s: unable to load fallback font \"%s\" either!\n",
157 data = (texture_font_data *) calloc (1, sizeof(*data));
161 /* Create a pixmap big enough to fit every character in the font.
162 Make it square-ish, since GL likes dimensions to be powers of 2.
165 Screen *screen = DefaultScreenOfDisplay (dpy);
166 Window root = RootWindowOfScreen (screen);
170 int cw = f->max_bounds.rbearing - f->min_bounds.lbearing;
171 int ch = f->max_bounds.ascent + f->max_bounds.descent;
176 data->cell_width = cw;
177 data->cell_height = ch;
179 p = XCreatePixmap (dpy, root, w, h, 1);
183 gc = XCreateGC (dpy, p, (GCFont|GCForeground|GCBackground), &gcv);
184 XFillRectangle (dpy, p, gc, 0, 0, w, h);
185 XSetForeground (dpy, gc, 1);
186 for (i = 0; i < 256; i++)
189 int x = (i % 16) * cw;
190 int y = (i / 16) * ch;
192 /* See comment in print_texture_string for bit layout explanation. */
194 int lbearing = (f->per_char
195 ? f->per_char[i - f->min_char_or_byte2].lbearing
196 : f->min_bounds.lbearing);
197 int ascent = (f->per_char
198 ? f->per_char[i - f->min_char_or_byte2].ascent
199 : f->max_bounds.ascent);
200 int width = (f->per_char
201 ? f->per_char[i - f->min_char_or_byte2].width
202 : f->max_bounds.width);
204 if (width == 0) continue;
205 XDrawString (dpy, p, gc, x - lbearing, y + ascent, &c, 1);
209 glGenTextures (1, &data->texid);
210 glBindTexture (GL_TEXTURE_2D, data->texid);
212 data->tex_height = h;
214 #if 0 /* debugging: splat the bitmap onto the desktop root window */
216 Window win = RootWindow (dpy, 0);
217 GC gc2 = XCreateGC (dpy, win, 0, &gcv);
218 XSetForeground (dpy, gc2, BlackPixel (dpy, 0));
219 XSetBackground (dpy, gc2, WhitePixel (dpy, 0));
220 XCopyPlane (dpy, p, win, gc2, 0, 0, w, h, 0, 0, 1);
226 bitmap_to_texture (dpy, p, &data->tex_width, &data->tex_height);
227 XFreePixmap (dpy, p);
234 /* Width of the string in pixels.
237 texture_string_width (texture_font_data *data, const char *c,
238 int *line_height_ret)
241 XFontStruct *f = data->font;
244 int cc = *((unsigned char *) c);
246 ? f->per_char[cc-f->min_char_or_byte2].width
247 : f->max_bounds.width);
251 *line_height_ret = f->ascent + f->descent;
256 /* Draws the string in the scene at the origin.
257 Newlines and tab stops are honored.
260 print_texture_string (texture_font_data *data, const char *string)
262 XFontStruct *f = data->font;
263 GLfloat line_height = f->ascent + f->descent;
264 # ifdef DO_SUBSCRIPTS
265 GLfloat sub_shift = (line_height * 0.3);
267 # endif /* DO_SUBSCRIPTS */
268 int cw = texture_string_width (data, "m", 0);
275 glBindTexture (GL_TEXTURE_2D, data->texid);
276 glNormal3f (0, 0, 1);
280 for (i = 0; i < strlen(string); i++)
290 x = ((x + tabs) / tabs) * tabs; /* tab to tab stop */
292 # ifdef DO_SUBSCRIPTS
293 else if (c == '[' && (isdigit (string[i+1])))
298 else if (c == ']' && sub_p)
303 # endif /* DO_SUBSCRIPTS */
306 /* The texture is divided into 16x16 rectangles whose size are
307 the max_bounds charcell of the font. Within each rectangle,
308 the individual characters' charcells sit in the upper left.
310 [A]----------------------------
321 |----[B]----------|---| |
325 |--------------------[C] |
328 ------------------------------ cell_height
330 We want to make a quad from point A to point C.
331 We want to position that quad so that point B lies at x,y.
333 int lbearing = (f->per_char
334 ? f->per_char[c - f->min_char_or_byte2].lbearing
335 : f->min_bounds.lbearing);
336 int rbearing = (f->per_char
337 ? f->per_char[c - f->min_char_or_byte2].rbearing
338 : f->max_bounds.rbearing);
339 int ascent = (f->per_char
340 ? f->per_char[c - f->min_char_or_byte2].ascent
341 : f->max_bounds.ascent);
342 int descent = (f->per_char
343 ? f->per_char[c - f->min_char_or_byte2].descent
344 : f->max_bounds.descent);
345 int cwidth = (f->per_char
346 ? f->per_char[c - f->min_char_or_byte2].width
347 : f->max_bounds.width);
349 int ax = ((int) c % 16) * data->cell_width; /* point A */
350 int ay = ((int) c / 16) * data->cell_height;
352 int bx = ax - lbearing; /* point B */
353 int by = ay + ascent;
355 int cx = bx + rbearing; /* point C */
356 int cy = by + descent;
358 GLfloat tax = (GLfloat) ax / data->tex_width; /* tex coords of A */
359 GLfloat tay = (GLfloat) ay / data->tex_height;
361 GLfloat tcx = (GLfloat) cx / data->tex_width; /* tex coords of C */
362 GLfloat tcy = (GLfloat) cy / data->tex_height;
364 GLfloat qx0 = x + lbearing; /* quad top left */
365 GLfloat qy0 = y + ascent;
366 GLfloat qx1 = qx0 + rbearing - lbearing; /* quad bot right */
367 GLfloat qy1 = qy0 - (ascent + descent);
369 if (cwidth > 0 && c != ' ')
372 glTexCoord2f (tax, tay); glVertex3f (qx0, qy0, 0);
373 glTexCoord2f (tcx, tay); glVertex3f (qx1, qy0, 0);
374 glTexCoord2f (tcx, tcy); glVertex3f (qx1, qy1, 0);
375 glTexCoord2f (tax, tcy); glVertex3f (qx0, qy1, 0);
378 glDisable(GL_TEXTURE_2D);
379 glBegin (GL_LINE_LOOP);
380 glTexCoord2f (tax, tay); glVertex3f (qx0, qy0, 0);
381 glTexCoord2f (tcx, tay); glVertex3f (qx1, qy0, 0);
382 glTexCoord2f (tcx, tcy); glVertex3f (qx1, qy1, 0);
383 glTexCoord2f (tax, tcy); glVertex3f (qx0, qy1, 0);
385 glEnable(GL_TEXTURE_2D);
395 /* Releases the font and texture.
398 free_texture_font (texture_font_data *data)
401 XFreeFont (data->dpy, data->font);
403 glDeleteTextures (1, &data->texid);