+static texture_font_data *
+load_texture_xfont (Display *dpy, XFontStruct *f)
+{
+ Screen *screen = DefaultScreenOfDisplay (dpy);
+ Window root = RootWindowOfScreen (screen);
+ XWindowAttributes xgwa;
+ int which;
+ GLint old_texture = 0;
+ texture_font_data *data = 0;
+
+ glGetIntegerv (GL_TEXTURE_BINDING_2D, &old_texture);
+
+ XGetWindowAttributes (dpy, root, &xgwa);
+
+ data = (texture_font_data *) calloc (1, sizeof(*data));
+ data->dpy = dpy;
+ data->font = f;
+
+ /* Figure out how many textures to use.
+ E.g., if we need 1024x1024 bits, use four 512x512 textures,
+ to be gentle to machines with low texture size limits.
+ */
+ {
+ int w = to_pow2 (16 * (f->max_bounds.rbearing - f->min_bounds.lbearing));
+ int h = to_pow2 (16 * (f->max_bounds.ascent + f->max_bounds.descent));
+ int i = (w > h ? w : h);
+
+ if (i <= 512) data->grid_mag = 1; /* 1 tex of 16x16 chars */
+ else if (i <= 1024) data->grid_mag = 2; /* 4 tex of 8x8 chars */
+ else if (i <= 2048) data->grid_mag = 4; /* 16 tex of 4x4 chars */
+ else data->grid_mag = 8; /* 32 tex of 2x2 chars */
+
+ data->ntextures = data->grid_mag * data->grid_mag;
+
+# if 0
+ fprintf (stderr,
+ "%s: %dx%d grid of %d textures of %dx%d chars (%dx%d bits)\n",
+ progname,
+ data->grid_mag, data->grid_mag,
+ data->ntextures,
+ 16 / data->grid_mag, 16 / data->grid_mag,
+ i, i);
+# endif
+ }
+
+ for (which = 0; which < data->ntextures; which++)
+ {
+ /* Create a pixmap big enough to fit every character in the font.
+ (modulo the "ntextures" scaling.)
+ Make it square-ish, since GL likes dimensions to be powers of 2.
+ */
+ XGCValues gcv;
+ GC gc;
+ Pixmap p;
+ int cw = f->max_bounds.rbearing - f->min_bounds.lbearing;
+ int ch = f->max_bounds.ascent + f->max_bounds.descent;
+ int grid_size = (16 / data->grid_mag);
+ int w = cw * grid_size;
+ int h = ch * grid_size;
+ int i;
+
+ data->cell_width = cw;
+ data->cell_height = ch;
+
+ p = XCreatePixmap (dpy, root, w, h, xgwa.depth);
+ gcv.font = f->fid;
+ gcv.foreground = BlackPixelOfScreen (xgwa.screen);
+ gcv.background = BlackPixelOfScreen (xgwa.screen);
+ gc = XCreateGC (dpy, p, (GCFont|GCForeground|GCBackground), &gcv);
+ XFillRectangle (dpy, p, gc, 0, 0, w, h);
+ XSetForeground (dpy, gc, WhitePixelOfScreen (xgwa.screen));
+ for (i = 0; i < 256 / data->ntextures; i++)
+ {
+ int ii = (i + (which * 256 / data->ntextures));
+ char c = (char) ii;
+ int x = (i % grid_size) * cw;
+ int y = (i / grid_size) * ch;
+
+ /* See comment in print_texture_string for bit layout explanation.
+ */
+ int lbearing = (f->per_char && ii >= f->min_char_or_byte2
+ ? f->per_char[ii - f->min_char_or_byte2].lbearing
+ : f->min_bounds.lbearing);
+ int ascent = (f->per_char && ii >= f->min_char_or_byte2
+ ? f->per_char[ii - f->min_char_or_byte2].ascent
+ : f->max_bounds.ascent);
+ int width = (f->per_char && ii >= f->min_char_or_byte2
+ ? f->per_char[ii - f->min_char_or_byte2].width
+ : f->max_bounds.width);
+
+ if (width == 0) continue;
+ XDrawString (dpy, p, gc, x - lbearing, y + ascent, &c, 1);
+ }
+ XFreeGC (dpy, gc);
+
+ glGenTextures (1, &data->texid[which]);
+ glBindTexture (GL_TEXTURE_2D, data->texid[which]);
+ check_gl_error ("texture font load");
+ data->tex_width = w;
+ data->tex_height = h;
+
+#if 0 /* debugging: write the bitmap to a pgm file */
+ {
+ char file[255];
+ XImage *image;
+ int x, y;
+ FILE *ff;
+ sprintf (file, "/tmp/%02d.pgm", which);
+ image = XGetImage (dpy, p, 0, 0, w, h, ~0L, ZPixmap);
+ ff = fopen (file, "w");
+ fprintf (ff, "P5\n%d %d\n255\n", w, h);
+ for (y = 0; y < h; y++)
+ for (x = 0; x < w; x++) {
+ unsigned long pix = XGetPixel (image, x, y);
+ unsigned long r = (pix & xgwa.visual->red_mask);
+ r = ((r >> 24) | (r >> 16) | (r >> 8) | r);
+ fprintf (ff, "%c", (char) r);
+ }
+ fclose (ff);
+ XDestroyImage (image);
+ fprintf (stderr, "%s: wrote %s (%d x %d)\n", progname, file,
+ f->max_bounds.rbearing - f->min_bounds.lbearing,
+ f->max_bounds.ascent + f->max_bounds.descent);
+ }
+#endif /* 0 */
+
+ bitmap_to_texture (dpy, p, xgwa.visual,
+ &data->tex_width, &data->tex_height);
+ XFreePixmap (dpy, p);
+ }
+
+ /* Reset to the caller's default */
+ glBindTexture (GL_TEXTURE_2D, old_texture);
+
+ return data;
+}
+
+