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