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("const BitmapFontRec %s = {\n", name);
325
printf("\"%s\",\n", xfont);
326
printf("%d,\n", last - first + 1);
327
printf("%d,\n", first);
330
XFreeFont(dpy, fontinfo);
334
main(int argc, char **argv)
340
fprintf(stderr, "usage: capturexfont XFONT NAME\n");
343
dpy = XOpenDisplay(NULL);
345
fprintf(stderr, "capturexfont: could not open X display\n");
348
font = XLoadFont(dpy, argv[1]);
350
fprintf(stderr, "capturexfont: bad font\n");
353
captureXFont(dpy, font, argv[1], argv[2]);