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 */
14 #include <GL/vms_x_fix.h>
23 #include <X11/Xutil.h>
25 #define MAX_GLYPHS_PER_GRAB 512 /* This is big enough for 2^9
26 glyph character sets */
29 outputChar(int num
, int width
, int height
,
30 int xoff
, int yoff
, int advance
, int data
)
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
);
43 printf("%d,", advance
);
44 printf("ch%ddata", num
);
48 printf("static const BitmapCharRec ch%d = {", num
);
50 printf("%d,", height
);
53 printf("%d,", advance
);
55 printf("ch%ddata", num
);
60 if (width
== 0 || height
== 0) {
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)
72 captureXFont(Display
* dpy
, Font font
, char *xfont
, char *name
)
74 int first
, last
, count
;
78 XFontStruct
*fontinfo
;
84 XCharStruct
*charinfo
;
89 int charWidth
, charHeight
, maxSpanLength
, pixwidth
;
90 int grabList
[MAX_GLYPHS_PER_GRAB
];
91 int glyphsPerGrab
= MAX_GLYPHS_PER_GRAB
;
93 int rows
, pages
, byte1
, byte2
, index
;
96 drawable
= RootWindow(dpy
, DefaultScreen(dpy
));
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;
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;
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
);
124 pixwidth
= glyphsPerGrab
* 8 * maxSpanLength
;
125 offscreen
= XCreatePixmap(dpy
, drawable
, pixwidth
, height
, 1);
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);
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;
143 printf("\n/* GENERATED FILE -- DO NOT MODIFY */\n\n");
144 printf("#include \"glutbitmap.h\"\n\n");
145 for (i
= first
; count
; i
++, count
--) {
148 undefined
= (fontinfo
->min_char_or_byte2
> i
||
149 fontinfo
->max_char_or_byte2
< i
);
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
);
162 if (fontinfo
->per_char
!= NULL
) {
164 index
= i
- fontinfo
->min_char_or_byte2
;
169 (byte1
- fontinfo
->min_byte1
) * pages
+
170 (byte2
- fontinfo
->min_char_or_byte2
);
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
180 outputChar(i
, 0, 0, 0, 0, charinfo
->width
, 0);
185 grabList
[numToGrab
] = i
;
186 character
.byte2
= i
& 255;
187 character
.byte1
= i
>> 8;
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);
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;
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;
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)));
231 if (PRINTABLE(grabList
[j
])) {
232 printf("/* char: 0x%x '%c' */\n\n",
233 grabList
[j
], grabList
[j
]);
235 printf("/* char: 0x%x */\n\n", grabList
[j
]);
238 /* Determine if the bitmap is null. */
240 len
= (charinfo
->ascent
+ charinfo
->descent
) *
241 ((charinfo
->rbearing
- charinfo
->lbearing
+ 7) / 8);
244 for (k
= 0; k
< 16 && cnt
< len
; k
++, cnt
++) {
245 if (bitmapData
[cnt
] != 0) {
252 printf("static const GLubyte ch%ddata[] = {\n", grabList
[j
]);
253 len
= (charinfo
->ascent
+ charinfo
->descent
) *
254 ((charinfo
->rbearing
- charinfo
->lbearing
+ 7) / 8);
257 for (k
= 0; k
< 16 && cnt
< len
; k
++, cnt
++) {
258 printf("0x%x,", bitmapData
[cnt
]);
268 outputChar(grabList
[j
], charWidth
, charHeight
,
269 -charinfo
->lbearing
, charinfo
->descent
,
270 charinfo
->width
, !nullBitmap
);
272 XDestroyImage(image
);
275 XSetForeground(dpy
, xgc
, 0);
276 XFillRectangle(dpy
, offscreen
, xgc
, 0, 0,
277 8 * maxSpanLength
* glyphsPerGrab
, height
);
278 XSetForeground(dpy
, xgc
, 1);
283 XFreePixmap(dpy
, offscreen
);
284 /* For portability reasons we don't use alloca for
285 bitmapData, but we could. */
288 printf("static const BitmapCharRec * const chars[] = {\n");
289 for (i
= first
; i
<= last
; i
++) {
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
);
300 if (fontinfo
->per_char
!= NULL
) {
302 index
= i
- fontinfo
->min_char_or_byte2
;
307 (byte1
- fontinfo
->min_byte1
) * pages
+
308 (byte2
- fontinfo
->min_char_or_byte2
);
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) {
320 printf("&ch%d,\n", i
);
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
);
331 XFreeFont(dpy
, fontinfo
);
335 main(int argc
, char **argv
)
341 fprintf(stderr
, "usage: capturexfont XFONT NAME\n");
344 dpy
= XOpenDisplay(NULL
);
346 fprintf(stderr
, "capturexfont: could not open X display\n");
349 font
= XLoadFont(dpy
, argv
[1]);
351 fprintf(stderr
, "capturexfont: bad font\n");
354 captureXFont(dpy
, font
, argv
[1], argv
[2]);