1 /* font-ximage.c --- renders text to an XImage for use with OpenGL.
2 * xscreensaver, Copyright (c) 2001, 2003 Jamie Zawinski <jwz@jwz.org>
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
23 # include <OpenGL/gl.h>
24 #else /* !HAVE_COCOA */
25 # include <X11/Xlib.h>
26 # include <X11/Xutil.h>
27 # include <GL/gl.h> /* only for GLfloat */
28 #endif /* !HAVE_COCOA */
30 extern char *progname;
32 #include "font-ximage.h"
35 #define MAX(a,b) ((a)>(b)?(a):(b))
38 #define countof(x) (sizeof((x))/sizeof((*x)))
44 union { int i; char c[sizeof(int)]; } u;
50 /* return the next larger power of 2. */
54 static const unsigned int pow2[] = {
55 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
56 2048, 4096, 8192, 16384, 32768, 65536 };
58 for (j = 0; j < countof(pow2); j++)
59 if (pow2[j] >= i) return pow2[j];
60 abort(); /* too big! */
64 /* Returns an XImage structure containing the string rendered in the font.
65 This XImage will be 32 bits per pixel, 8 each per R, G, and B, with the
66 extra byte set to 0xFF.
68 Foregroune and background are GL-style color specifiers: 4 floats from
72 text_to_ximage (Screen *screen, Visual *visual,
74 const char *text_lines,
78 Display *dpy = DisplayOfScreen (screen);
83 f = XLoadQueryFont(dpy, font);
86 f = XLoadQueryFont(dpy, "fixed");
88 fprintf (stderr, "%s: unable to load font \"%s\"; using \"fixed\".\n",
92 fprintf (stderr, "%s: unable to load fonts \"%s\" or \"fixed\"!\n",
98 /* Parse the text, and render it to `bitmap'
101 char *text, *text2, *line, *token;
112 text = strdup (text_lines);
114 (text[strlen(text)-1] == '\r' ||
115 text[strlen(text)-1] == '\n'))
116 text[strlen(text)-1] = 0;
118 text2 = strdup (text);
120 memset(&overall, 0, sizeof(overall));
123 while ((line = strtok (token, "\r\n")))
126 int ascent, descent, direction;
128 XTextExtents (f, line, strlen(line),
129 &direction, &ascent, &descent, &o2);
130 overall.lbearing = MAX(overall.lbearing, o2.lbearing);
131 overall.rbearing = MAX(overall.rbearing, o2.rbearing);
135 width = overall.lbearing + overall.rbearing + margin + margin + 1;
136 height = ((f->ascent + f->descent) * lines) + margin + margin;
138 /* GL texture sizes must be powers of two. */
140 int w2 = to_pow2(width);
141 int h2 = to_pow2(height);
142 xoff = (w2 - width) / 2;
143 yoff = (h2 - height) / 2;
148 bitmap = XCreatePixmap(dpy, RootWindowOfScreen (screen), width, height, 1);
152 gc = XCreateGC (dpy, bitmap, (GCFont | GCForeground), &gcv);
153 XFillRectangle(dpy, bitmap, gc, 0, 0, width, height);
154 XSetForeground(dpy, gc, fg);
158 while ((line = strtok(token, "\r\n")))
161 int ascent, descent, direction, xoff2;
164 XTextExtents(f, line, strlen(line),
165 &direction, &ascent, &descent, &o2);
167 ((overall.lbearing + overall.rbearing) -
168 (o2.lbearing + o2.rbearing)) / 2);
170 XDrawString(dpy, bitmap, gc,
171 overall.lbearing + margin + xoff,
172 ((f->ascent * (lines + 1)) +
173 (f->descent * lines) +
181 XUnloadFont(dpy, f->fid);
186 /* Convert the server-side Pixmap to a client-side GL-ordered XImage.
189 XImage *ximage1, *ximage2;
190 unsigned long fg, bg;
193 ximage1 = XGetImage (dpy, bitmap, 0, 0, width, height, ~0L, ZPixmap);
194 XFreePixmap(dpy, bitmap);
195 ximage2 = XCreateImage (dpy, visual, 32, ZPixmap, 0, 0,
196 width, height, 32, 0);
198 ximage2->data = (char *) malloc (height * ximage2->bytes_per_line);
200 /* Translate the 1-bit image to a deep image:
201 first figure out what the colors are.
204 int rpos, gpos, bpos, apos; /* bitfield positions */
206 /* Note that unlike X, which is endianness-agnostic (since any XImage
207 can have its own specific bit ordering, with the server reversing
208 things as necessary) OpenGL pretends everything is client-side, so
209 we need to pack things in the right order for the client machine.
212 /* #### Cherub says that the little-endian case must be taken on MacOSX,
213 or else the colors/alpha are the wrong way around. How can
217 rpos = 24, gpos = 16, bpos = 8, apos = 0;
220 rpos = 0, gpos = 8, bpos = 16, apos = 24;
222 fg = (((unsigned long) (texture_fg[0] * 255.0) << rpos) |
223 ((unsigned long) (texture_fg[1] * 255.0) << gpos) |
224 ((unsigned long) (texture_fg[2] * 255.0) << bpos) |
225 ((unsigned long) (texture_fg[3] * 255.0) << apos));
226 bg = (((unsigned long) (texture_bg[0] * 255.0) << rpos) |
227 ((unsigned long) (texture_bg[1] * 255.0) << gpos) |
228 ((unsigned long) (texture_bg[2] * 255.0) << bpos) |
229 ((unsigned long) (texture_bg[3] * 255.0) << apos));
232 for (y = 0; y < height; y++)
234 int y2 = (height-1-y); /* Texture maps are upside down. */
235 for (x = 0; x < width; x++)
236 XPutPixel (ximage2, x, y,
237 XGetPixel (ximage1, x, y2) ? fg : bg);
240 XDestroyImage (ximage1);
243 for (y = 0; y < height; y++)
245 int y2 = (height-1-y); /* Texture maps are upside down. */
246 for (x = 0; x < width; x++)
247 fputc ((XGetPixel (ximage2, x, y2) == fg ? '#' : ' '), stdout);
248 fputc ('\n', stdout);
250 fputc ('\n', stdout);