initial check-in (post crash)
[mesa.git] / src / glut / glx / capturexfont.c
1
2 /* Copyright (c) Mark J. Kilgard, 1994. */
3
4 /* This program is freely distributable without licensing fees
5 and is provided without guarantee or warrantee expressed or
6 implied. This program is -not- in the public domain. */
7
8 /* capturexfont.c connects to an X server and downloads a
9 bitmap font from which a C source file is generated,
10 encoding the font for GLUT's use. Example usage:
11 capturexfont.c 9x15 glutBitmap9By15 > glut_9x15.c */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <GL/gl.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xutil.h>
20
21 #define MAX_GLYPHS_PER_GRAB 512 /* This is big enough for 2^9
22 glyph character sets */
23
24 static void
25 outputChar(int num, int width, int height,
26 int xoff, int yoff, int advance, int data)
27 {
28 if (width == 0 || height == 0) {
29 printf("#ifdef _WIN32\n");
30 printf("/* XXX Work around Microsoft OpenGL 1.1 bug where glBitmap with\n");
31 printf(" a height or width of zero does not advance the raster position\n");
32 printf(" as specified by OpenGL. (Cosmo OpenGL does not have this bug.) */\n");
33 printf("static const GLubyte ch%ddata[] = { 0x0 };\n", num);
34 printf("static const BitmapCharRec ch%d = {", num);
35 printf("%d,", 0);
36 printf("%d,", 0);
37 printf("%d,", xoff);
38 printf("%d,", yoff);
39 printf("%d,", advance);
40 printf("ch%ddata", num);
41 printf("};\n");
42 printf("#else\n");
43 }
44 printf("static const BitmapCharRec ch%d = {", num);
45 printf("%d,", width);
46 printf("%d,", height);
47 printf("%d,", xoff);
48 printf("%d,", yoff);
49 printf("%d,", advance);
50 if (data) {
51 printf("ch%ddata", num);
52 } else {
53 printf("0");
54 }
55 printf("};\n");
56 if (width == 0 || height == 0) {
57 printf("#endif\n");
58 }
59 printf("\n");
60 }
61
62 /* Can't just use isprint because it only works for the range
63 of ASCII characters (ie, TRUE for isascii) and capturexfont
64 might be run on 16-bit fonts. */
65 #define PRINTABLE(ch) (isascii(ch) ? isprint(ch) : 0)
66
67 void
68 captureXFont(Display * dpy, Font font, char *xfont, char *name)
69 {
70 int first, last, count;
71 int cnt, len;
72 Pixmap offscreen;
73 Window drawable;
74 XFontStruct *fontinfo;
75 XImage *image;
76 GC xgc;
77 XGCValues values;
78 int width, height;
79 int i, j, k;
80 XCharStruct *charinfo;
81 XChar2b character;
82 GLubyte *bitmapData;
83 int x, y;
84 int spanLength;
85 int charWidth, charHeight, maxSpanLength, pixwidth;
86 int grabList[MAX_GLYPHS_PER_GRAB];
87 int glyphsPerGrab = MAX_GLYPHS_PER_GRAB;
88 int numToGrab;
89 int rows, pages, byte1, byte2, index;
90 int nullBitmap;
91
92 drawable = RootWindow(dpy, DefaultScreen(dpy));
93
94 fontinfo = XQueryFont(dpy, font);
95 pages = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1;
96 first = (fontinfo->min_byte1 << 8) + fontinfo->min_char_or_byte2;
97 last = (fontinfo->max_byte1 << 8) + fontinfo->max_char_or_byte2;
98 count = last - first + 1;
99
100 width = fontinfo->max_bounds.rbearing -
101 fontinfo->min_bounds.lbearing;
102 height = fontinfo->max_bounds.ascent +
103 fontinfo->max_bounds.descent;
104 /* 16-bit fonts have more than one row; indexing into
105 per_char is trickier. */
106 rows = fontinfo->max_byte1 - fontinfo->min_byte1 + 1;
107
108 maxSpanLength = (width + 7) / 8;
109 /* For portability reasons we don't use alloca for
110 bitmapData, but we could. */
111 bitmapData = malloc(height * maxSpanLength);
112 /* Be careful determining the width of the pixmap; the X
113 protocol allows pixmaps of width 2^16-1 (unsigned short
114 size) but drawing coordinates max out at 2^15-1 (signed
115 short size). If the width is too large, we need to limit
116 the glyphs per grab. */
117 if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) {
118 glyphsPerGrab = (1 << 15) / (8 * maxSpanLength);
119 }
120 pixwidth = glyphsPerGrab * 8 * maxSpanLength;
121 offscreen = XCreatePixmap(dpy, drawable, pixwidth, height, 1);
122
123 values.font = font;
124 values.background = 0;
125 values.foreground = 0;
126 xgc = XCreateGC(dpy, offscreen,
127 GCFont | GCBackground | GCForeground, &values);
128 XFillRectangle(dpy, offscreen, xgc, 0, 0,
129 8 * maxSpanLength * glyphsPerGrab, height);
130 XSetForeground(dpy, xgc, 1);
131
132 numToGrab = 0;
133 if (fontinfo->per_char == NULL) {
134 charinfo = &(fontinfo->min_bounds);
135 charWidth = charinfo->rbearing - charinfo->lbearing;
136 charHeight = charinfo->ascent + charinfo->descent;
137 spanLength = (charWidth + 7) / 8;
138 }
139 printf("\n/* GENERATED FILE -- DO NOT MODIFY */\n\n");
140 printf("#include \"glutbitmap.h\"\n\n");
141 for (i = first; count; i++, count--) {
142 int undefined;
143 if (rows == 1) {
144 undefined = (fontinfo->min_char_or_byte2 > i ||
145 fontinfo->max_char_or_byte2 < i);
146 } else {
147 byte2 = i & 0xff;
148 byte1 = i >> 8;
149 undefined = (fontinfo->min_char_or_byte2 > byte2 ||
150 fontinfo->max_char_or_byte2 < byte2 ||
151 fontinfo->min_byte1 > byte1 ||
152 fontinfo->max_byte1 < byte1);
153
154 }
155 if (undefined) {
156 goto PossiblyDoGrab;
157 }
158 if (fontinfo->per_char != NULL) {
159 if (rows == 1) {
160 index = i - fontinfo->min_char_or_byte2;
161 } else {
162 byte2 = i & 0xff;
163 byte1 = i >> 8;
164 index =
165 (byte1 - fontinfo->min_byte1) * pages +
166 (byte2 - fontinfo->min_char_or_byte2);
167 }
168 charinfo = &(fontinfo->per_char[index]);
169 charWidth = charinfo->rbearing - charinfo->lbearing;
170 charHeight = charinfo->ascent + charinfo->descent;
171 if (charWidth == 0 || charHeight == 0) {
172 if (charinfo->width != 0) {
173 /* Still must move raster pos even if empty character
174
175 */
176 outputChar(i, 0, 0, 0, 0, charinfo->width, 0);
177 }
178 goto PossiblyDoGrab;
179 }
180 }
181 grabList[numToGrab] = i;
182 character.byte2 = i & 255;
183 character.byte1 = i >> 8;
184
185 /* XXX We could use XDrawImageString16 which would also
186 paint the backing rectangle but X server bugs in some
187 scalable font rasterizers makes it more effective to do
188 XFillRectangles to clear the pixmap and then
189 XDrawImage16 for the text. */
190 XDrawString16(dpy, offscreen, xgc,
191 -charinfo->lbearing + 8 * maxSpanLength * numToGrab,
192 charinfo->ascent, &character, 1);
193
194 numToGrab++;
195
196 PossiblyDoGrab:
197
198 if (numToGrab >= glyphsPerGrab || count == 1) {
199 image = XGetImage(dpy, offscreen,
200 0, 0, pixwidth, height, 1, XYPixmap);
201 for (j = numToGrab - 1; j >= 0; j--) {
202 if (fontinfo->per_char != NULL) {
203 byte2 = grabList[j] & 0xff;
204 byte1 = grabList[j] >> 8;
205 index =
206 (byte1 - fontinfo->min_byte1) * pages +
207 (byte2 - fontinfo->min_char_or_byte2);
208 charinfo = &(fontinfo->per_char[index]);
209 charWidth = charinfo->rbearing - charinfo->lbearing;
210 charHeight = charinfo->ascent + charinfo->descent;
211 spanLength = (charWidth + 7) / 8;
212 }
213 memset(bitmapData, 0, height * spanLength);
214 for (y = 0; y < charHeight; y++) {
215 for (x = 0; x < charWidth; x++) {
216 if (XGetPixel(image, j * maxSpanLength * 8 + x,
217 charHeight - 1 - y)) {
218 /* Little endian machines (such as DEC Alpha)
219 could benefit from reversing the bit order
220 here and changing the GL_UNPACK_LSB_FIRST
221 parameter in glutBitmapCharacter to GL_TRUE. */
222 bitmapData[y * spanLength + x / 8] |=
223 (1 << (7 - (x & 7)));
224 }
225 }
226 }
227 if (PRINTABLE(grabList[j])) {
228 printf("/* char: 0x%x '%c' */\n\n",
229 grabList[j], grabList[j]);
230 } else {
231 printf("/* char: 0x%x */\n\n", grabList[j]);
232 }
233
234 /* Determine if the bitmap is null. */
235 nullBitmap = 1;
236 len = (charinfo->ascent + charinfo->descent) *
237 ((charinfo->rbearing - charinfo->lbearing + 7) / 8);
238 cnt = 0;
239 while (cnt < len) {
240 for (k = 0; k < 16 && cnt < len; k++, cnt++) {
241 if (bitmapData[cnt] != 0) {
242 nullBitmap = 0;
243 }
244 }
245 }
246
247 if (!nullBitmap) {
248 printf("static const GLubyte ch%ddata[] = {\n", grabList[j]);
249 len = (charinfo->ascent + charinfo->descent) *
250 ((charinfo->rbearing - charinfo->lbearing + 7) / 8);
251 cnt = 0;
252 while (cnt < len) {
253 for (k = 0; k < 16 && cnt < len; k++, cnt++) {
254 printf("0x%x,", bitmapData[cnt]);
255 }
256 printf("\n");
257 }
258 printf("};\n\n");
259 } else {
260 charWidth = 0;
261 charHeight = 0;
262 }
263
264 outputChar(grabList[j], charWidth, charHeight,
265 -charinfo->lbearing, charinfo->descent,
266 charinfo->width, !nullBitmap);
267 }
268 XDestroyImage(image);
269 numToGrab = 0;
270 if (count > 0) {
271 XSetForeground(dpy, xgc, 0);
272 XFillRectangle(dpy, offscreen, xgc, 0, 0,
273 8 * maxSpanLength * glyphsPerGrab, height);
274 XSetForeground(dpy, xgc, 1);
275 }
276 }
277 }
278 XFreeGC(dpy, xgc);
279 XFreePixmap(dpy, offscreen);
280 /* For portability reasons we don't use alloca for
281 bitmapData, but we could. */
282 free(bitmapData);
283
284 printf("static const BitmapCharRec * const chars[] = {\n");
285 for (i = first; i <= last; i++) {
286 int undefined;
287 byte2 = i & 0xff;
288 byte1 = i >> 8;
289 undefined = (fontinfo->min_char_or_byte2 > byte2 ||
290 fontinfo->max_char_or_byte2 < byte2 ||
291 fontinfo->min_byte1 > byte1 ||
292 fontinfo->max_byte1 < byte1);
293 if (undefined) {
294 printf("0,\n");
295 } else {
296 if (fontinfo->per_char != NULL) {
297 if (rows == 1) {
298 index = i - fontinfo->min_char_or_byte2;
299 } else {
300 byte2 = i & 0xff;
301 byte1 = i >> 8;
302 index =
303 (byte1 - fontinfo->min_byte1) * pages +
304 (byte2 - fontinfo->min_char_or_byte2);
305 }
306 charinfo = &(fontinfo->per_char[index]);
307 charWidth = charinfo->rbearing - charinfo->lbearing;
308 charHeight = charinfo->ascent + charinfo->descent;
309 if (charWidth == 0 || charHeight == 0) {
310 if (charinfo->width == 0) {
311 printf("0,\n");
312 continue;
313 }
314 }
315 }
316 printf("&ch%d,\n", i);
317 }
318 }
319 printf("};\n\n");
320 printf("const BitmapFontRec %s = {\n", name);
321 printf("\"%s\",\n", xfont);
322 printf("%d,\n", last - first + 1);
323 printf("%d,\n", first);
324 printf("chars\n");
325 printf("};\n\n");
326 XFreeFont(dpy, fontinfo);
327 }
328
329 int
330 main(int argc, char **argv)
331 {
332 Display *dpy;
333 Font font;
334
335 if (argc != 3) {
336 fprintf(stderr, "usage: capturexfont XFONT NAME\n");
337 exit(1);
338 }
339 dpy = XOpenDisplay(NULL);
340 if (dpy == NULL) {
341 fprintf(stderr, "capturexfont: could not open X display\n");
342 exit(1);
343 }
344 font = XLoadFont(dpy, argv[1]);
345 if (font == None) {
346 fprintf(stderr, "capturexfont: bad font\n");
347 exit(1);
348 }
349 captureXFont(dpy, font, argv[1], argv[2]);
350 XCloseDisplay(dpy);
351 return 0;
352 }