2 /* Copyright (c) Mark J. Kilgard, 1994. */
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. */
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 */
19 #include <X11/Xutil.h>
21 #define MAX_GLYPHS_PER_GRAB 512 /* This is big enough for 2^9
22 glyph character sets */
25 outputChar(int num
, int width
, int height
,
26 int xoff
, int yoff
, int advance
, int data
)
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
);
39 printf("%d,", advance
);
40 printf("ch%ddata", num
);
44 printf("static const BitmapCharRec ch%d = {", num
);
46 printf("%d,", height
);
49 printf("%d,", advance
);
51 printf("ch%ddata", num
);
56 if (width
== 0 || height
== 0) {
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)
68 captureXFont(Display
* dpy
, Font font
, char *xfont
, char *name
)
70 int first
, last
, count
;
74 XFontStruct
*fontinfo
;
80 XCharStruct
*charinfo
;
85 int charWidth
, charHeight
, maxSpanLength
, pixwidth
;
86 int grabList
[MAX_GLYPHS_PER_GRAB
];
87 int glyphsPerGrab
= MAX_GLYPHS_PER_GRAB
;
89 int rows
, pages
, byte1
, byte2
, index
;
92 drawable
= RootWindow(dpy
, DefaultScreen(dpy
));
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;
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;
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
);
120 pixwidth
= glyphsPerGrab
* 8 * maxSpanLength
;
121 offscreen
= XCreatePixmap(dpy
, drawable
, pixwidth
, height
, 1);
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);
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;
139 printf("\n/* GENERATED FILE -- DO NOT MODIFY */\n\n");
140 printf("#include \"glutbitmap.h\"\n\n");
141 for (i
= first
; count
; i
++, count
--) {
144 undefined
= (fontinfo
->min_char_or_byte2
> i
||
145 fontinfo
->max_char_or_byte2
< i
);
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
);
158 if (fontinfo
->per_char
!= NULL
) {
160 index
= i
- fontinfo
->min_char_or_byte2
;
165 (byte1
- fontinfo
->min_byte1
) * pages
+
166 (byte2
- fontinfo
->min_char_or_byte2
);
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
176 outputChar(i
, 0, 0, 0, 0, charinfo
->width
, 0);
181 grabList
[numToGrab
] = i
;
182 character
.byte2
= i
& 255;
183 character
.byte1
= i
>> 8;
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);
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;
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;
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)));
227 if (PRINTABLE(grabList
[j
])) {
228 printf("/* char: 0x%x '%c' */\n\n",
229 grabList
[j
], grabList
[j
]);
231 printf("/* char: 0x%x */\n\n", grabList
[j
]);
234 /* Determine if the bitmap is null. */
236 len
= (charinfo
->ascent
+ charinfo
->descent
) *
237 ((charinfo
->rbearing
- charinfo
->lbearing
+ 7) / 8);
240 for (k
= 0; k
< 16 && cnt
< len
; k
++, cnt
++) {
241 if (bitmapData
[cnt
] != 0) {
248 printf("static const GLubyte ch%ddata[] = {\n", grabList
[j
]);
249 len
= (charinfo
->ascent
+ charinfo
->descent
) *
250 ((charinfo
->rbearing
- charinfo
->lbearing
+ 7) / 8);
253 for (k
= 0; k
< 16 && cnt
< len
; k
++, cnt
++) {
254 printf("0x%x,", bitmapData
[cnt
]);
264 outputChar(grabList
[j
], charWidth
, charHeight
,
265 -charinfo
->lbearing
, charinfo
->descent
,
266 charinfo
->width
, !nullBitmap
);
268 XDestroyImage(image
);
271 XSetForeground(dpy
, xgc
, 0);
272 XFillRectangle(dpy
, offscreen
, xgc
, 0, 0,
273 8 * maxSpanLength
* glyphsPerGrab
, height
);
274 XSetForeground(dpy
, xgc
, 1);
279 XFreePixmap(dpy
, offscreen
);
280 /* For portability reasons we don't use alloca for
281 bitmapData, but we could. */
284 printf("static const BitmapCharRec * const chars[] = {\n");
285 for (i
= first
; i
<= last
; i
++) {
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
);
296 if (fontinfo
->per_char
!= NULL
) {
298 index
= i
- fontinfo
->min_char_or_byte2
;
303 (byte1
- fontinfo
->min_byte1
) * pages
+
304 (byte2
- fontinfo
->min_char_or_byte2
);
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) {
316 printf("&ch%d,\n", i
);
320 printf("const BitmapFontRec %s = {\n", name
);
321 printf("\"%s\",\n", xfont
);
322 printf("%d,\n", last
- first
+ 1);
323 printf("%d,\n", first
);
326 XFreeFont(dpy
, fontinfo
);
330 main(int argc
, char **argv
)
336 fprintf(stderr
, "usage: capturexfont XFONT NAME\n");
339 dpy
= XOpenDisplay(NULL
);
341 fprintf(stderr
, "capturexfont: could not open X display\n");
344 font
= XLoadFont(dpy
, argv
[1]);
346 fprintf(stderr
, "capturexfont: bad font\n");
349 captureXFont(dpy
, font
, argv
[1], argv
[2]);