#ifdef __VMS
#include <GL/vms_x_fix.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <GL/gl.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define MAX_GLYPHS_PER_GRAB 512
static void
outputChar(int num, int width, int height,
int xoff, int yoff, int advance, int data)
{
if (width == 0 || height == 0) {
printf("#ifdef _WIN32\n");
printf("/* XXX Work around Microsoft OpenGL 1.1 bug where glBitmap with\n");
printf(" a height or width of zero does not advance the raster position\n");
printf(" as specified by OpenGL. (Cosmo OpenGL does not have this bug.) */\n");
printf("static const GLubyte ch%ddata[] = { 0x0 };\n", num);
printf("static const BitmapCharRec ch%d = {", num);
printf("%d,", 0);
printf("%d,", 0);
printf("%d,", xoff);
printf("%d,", yoff);
printf("%d,", advance);
printf("ch%ddata", num);
printf("};\n");
printf("#else\n");
}
printf("static const BitmapCharRec ch%d = {", num);
printf("%d,", width);
printf("%d,", height);
printf("%d,", xoff);
printf("%d,", yoff);
printf("%d,", advance);
if (data) {
printf("ch%ddata", num);
} else {
printf("0");
}
printf("};\n");
if (width == 0 || height == 0) {
printf("#endif\n");
}
printf("\n");
}
#define PRINTABLE(ch) (isascii(ch) ? isprint(ch) : 0)
void
captureXFont(Display * dpy, Font font, char *xfont, char *name)
{
int first, last, count;
int cnt, len;
Pixmap offscreen;
Window drawable;
XFontStruct *fontinfo;
XImage *image;
GC xgc;
XGCValues values;
int width, height;
int i, j, k;
XCharStruct *charinfo;
XChar2b character;
GLubyte *bitmapData;
int x, y;
int spanLength;
int charWidth, charHeight, maxSpanLength, pixwidth;
int grabList[MAX_GLYPHS_PER_GRAB];
int glyphsPerGrab = MAX_GLYPHS_PER_GRAB;
int numToGrab;
int rows, pages, byte1, byte2, index;
int nullBitmap;
drawable = RootWindow(dpy, DefaultScreen(dpy));
fontinfo = XQueryFont(dpy, font);
pages = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1;
first = (fontinfo->min_byte1 << 8) + fontinfo->min_char_or_byte2;
last = (fontinfo->max_byte1 << 8) + fontinfo->max_char_or_byte2;
count = last - first + 1;
width = fontinfo->max_bounds.rbearing -
fontinfo->min_bounds.lbearing;
height = fontinfo->max_bounds.ascent +
fontinfo->max_bounds.descent;
rows = fontinfo->max_byte1 - fontinfo->min_byte1 + 1;
maxSpanLength = (width + 7) / 8;
bitmapData = malloc(height * maxSpanLength);
if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) {
glyphsPerGrab = (1 << 15) / (8 * maxSpanLength);
}
pixwidth = glyphsPerGrab * 8 * maxSpanLength;
offscreen = XCreatePixmap(dpy, drawable, pixwidth, height, 1);
values.font = font;
values.background = 0;
values.foreground = 0;
xgc = XCreateGC(dpy, offscreen,
GCFont | GCBackground | GCForeground, &values);
XFillRectangle(dpy, offscreen, xgc, 0, 0,
8 * maxSpanLength * glyphsPerGrab, height);
XSetForeground(dpy, xgc, 1);
numToGrab = 0;
if (fontinfo->per_char == NULL) {
charinfo = &(fontinfo->min_bounds);
charWidth = charinfo->rbearing - charinfo->lbearing;
charHeight = charinfo->ascent + charinfo->descent;
spanLength = (charWidth + 7) / 8;
}
printf("\n/* GENERATED FILE -- DO NOT MODIFY */\n\n");
printf("#include \"glutbitmap.h\"\n\n");
for (i = first; count; i++, count--) {
int undefined;
if (rows == 1) {
undefined = (fontinfo->min_char_or_byte2 > i ||
fontinfo->max_char_or_byte2 < i);
} else {
byte2 = i & 0xff;
byte1 = i >> 8;
undefined = (fontinfo->min_char_or_byte2 > byte2 ||
fontinfo->max_char_or_byte2 < byte2 ||
fontinfo->min_byte1 > byte1 ||
fontinfo->max_byte1 < byte1);
}
if (undefined) {
goto PossiblyDoGrab;
}
if (fontinfo->per_char != NULL) {
if (rows == 1) {
index = i - fontinfo->min_char_or_byte2;
} else {
byte2 = i & 0xff;
byte1 = i >> 8;
index =
(byte1 - fontinfo->min_byte1) * pages +
(byte2 - fontinfo->min_char_or_byte2);
}
charinfo = &(fontinfo->per_char[index]);
charWidth = charinfo->rbearing - charinfo->lbearing;
charHeight = charinfo->ascent + charinfo->descent;
if (charWidth == 0 || charHeight == 0) {
if (charinfo->width != 0) {
outputChar(i, 0, 0, 0, 0, charinfo->width, 0);
}
goto PossiblyDoGrab;
}
}
grabList[numToGrab] = i;
character.byte2 = i & 255;
character.byte1 = i >> 8;
XDrawString16(dpy, offscreen, xgc,
-charinfo->lbearing + 8 * maxSpanLength * numToGrab,
charinfo->ascent, &character, 1);
numToGrab++;
PossiblyDoGrab:
if (numToGrab >= glyphsPerGrab || count == 1) {
image = XGetImage(dpy, offscreen,
0, 0, pixwidth, height, 1, XYPixmap);
for (j = numToGrab - 1; j >= 0; j--) {
if (fontinfo->per_char != NULL) {
byte2 = grabList[j] & 0xff;
byte1 = grabList[j] >> 8;
index =
(byte1 - fontinfo->min_byte1) * pages +
(byte2 - fontinfo->min_char_or_byte2);
charinfo = &(fontinfo->per_char[index]);
charWidth = charinfo->rbearing - charinfo->lbearing;
charHeight = charinfo->ascent + charinfo->descent;
spanLength = (charWidth + 7) / 8;
}
memset(bitmapData, 0, height * spanLength);
for (y = 0; y < charHeight; y++) {
for (x = 0; x < charWidth; x++) {
if (XGetPixel(image, j * maxSpanLength * 8 + x,
charHeight - 1 - y)) {
bitmapData[y * spanLength + x / 8] |=
(1 << (7 - (x & 7)));
}
}
}
if (PRINTABLE(grabList[j])) {
printf("/* char: 0x%x '%c' */\n\n",
grabList[j], grabList[j]);
} else {
printf("/* char: 0x%x */\n\n", grabList[j]);
}
nullBitmap = 1;
len = (charinfo->ascent + charinfo->descent) *
((charinfo->rbearing - charinfo->lbearing + 7) / 8);
cnt = 0;
while (cnt < len) {
for (k = 0; k < 16 && cnt < len; k++, cnt++) {
if (bitmapData[cnt] != 0) {
nullBitmap = 0;
}
}
}
if (!nullBitmap) {
printf("static const GLubyte ch%ddata[] = {\n", grabList[j]);
len = (charinfo->ascent + charinfo->descent) *
((charinfo->rbearing - charinfo->lbearing + 7) / 8);
cnt = 0;
while (cnt < len) {
for (k = 0; k < 16 && cnt < len; k++, cnt++) {
printf("0x%x,", bitmapData[cnt]);
}
printf("\n");
}
printf("};\n\n");
} else {
charWidth = 0;
charHeight = 0;
}
outputChar(grabList[j], charWidth, charHeight,
-charinfo->lbearing, charinfo->descent,
charinfo->width, !nullBitmap);
}
XDestroyImage(image);
numToGrab = 0;
if (count > 0) {
XSetForeground(dpy, xgc, 0);
XFillRectangle(dpy, offscreen, xgc, 0, 0,
8 * maxSpanLength * glyphsPerGrab, height);
XSetForeground(dpy, xgc, 1);
}
}
}
XFreeGC(dpy, xgc);
XFreePixmap(dpy, offscreen);
free(bitmapData);
printf("static const BitmapCharRec * const chars[] = {\n");
for (i = first; i <= last; i++) {
int undefined;
byte2 = i & 0xff;
byte1 = i >> 8;
undefined = (fontinfo->min_char_or_byte2 > byte2 ||
fontinfo->max_char_or_byte2 < byte2 ||
fontinfo->min_byte1 > byte1 ||
fontinfo->max_byte1 < byte1);
if (undefined) {
printf("0,\n");
} else {
if (fontinfo->per_char != NULL) {
if (rows == 1) {
index = i - fontinfo->min_char_or_byte2;
} else {
byte2 = i & 0xff;
byte1 = i >> 8;
index =
(byte1 - fontinfo->min_byte1) * pages +
(byte2 - fontinfo->min_char_or_byte2);
}
charinfo = &(fontinfo->per_char[index]);
charWidth = charinfo->rbearing - charinfo->lbearing;
charHeight = charinfo->ascent + charinfo->descent;
if (charWidth == 0 || charHeight == 0) {
if (charinfo->width == 0) {
printf("0,\n");
continue;
}
}
}
printf("&ch%d,\n", i);
}
}
printf("};\n\n");
printf("const BitmapFontRec %s = {\n", name);
printf("\"%s\",\n", xfont);
printf("%d,\n", last - first + 1);
printf("%d,\n", first);
printf("chars\n");
printf("};\n\n");
XFreeFont(dpy, fontinfo);
}
int
main(int argc, char **argv)
{
Display *dpy;
Font font;
if (argc != 3) {
fprintf(stderr, "usage: capturexfont XFONT NAME\n");
exit(1);
}
dpy = XOpenDisplay(NULL);
if (dpy == NULL) {
fprintf(stderr, "capturexfont: could not open X display\n");
exit(1);
}
font = XLoadFont(dpy, argv[1]);
if (font == None) {
fprintf(stderr, "capturexfont: bad font\n");
exit(1);
}
captureXFont(dpy, font, argv[1], argv[2]);
XCloseDisplay(dpy);
return 0;
}