summaryrefslogtreecommitdiff
path: root/genfontfile.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2000-10-03 10:34:48 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2000-10-03 10:34:48 +0200
commit6a50f37f25b43112d4a1fad8a5057089548dfc3c (patch)
treec3a28722d1c7b04c12174fe748aead391e7c0ed8 /genfontfile.c
parentb4faf3787a24c43b0a22b3ee695374012c992eb2 (diff)
downloadvdr-6a50f37f25b43112d4a1fad8a5057089548dfc3c.tar.gz
vdr-6a50f37f25b43112d4a1fad8a5057089548dfc3c.tar.bz2
Faster OSD by using bitmap
Diffstat (limited to 'genfontfile.c')
-rw-r--r--genfontfile.c378
1 files changed, 378 insertions, 0 deletions
diff --git a/genfontfile.c b/genfontfile.c
new file mode 100644
index 00000000..a98f8012
--- /dev/null
+++ b/genfontfile.c
@@ -0,0 +1,378 @@
+/* Copyright (c) Mark J. Kilgard, 1997. */
+
+/* This program is freely distributable without licensing fees and is
+ provided without guarantee or warrantee expressed or implied. This
+ program is -not- in the public domain. */
+
+/* X compile line: cc -o gentexfont gentexfont.c -lX11 */
+
+/* 2000-10-01: Stripped down the original code to get a simple bitmap C-code generator */
+/* for use with the VDR project (see http://www.cadsoft.de/people/kls/vdr) */
+/* Renamed the file 'genfontfile.c' since it no longer generates 'tex' data */
+/* Klaus Schmidinger (kls@cadsoft.de) */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <math.h>
+
+typedef struct {
+ unsigned short c; /* Potentially support 16-bit glyphs. */
+ unsigned char width;
+ unsigned char height;
+ signed char xoffset;
+ signed char yoffset;
+ signed char advance;
+ char dummy; /* Space holder for alignment reasons. */
+ short x;
+ short y;
+} TexGlyphInfo;
+
+typedef struct {
+ short width;
+ short height;
+ short xoffset;
+ short yoffset;
+ short advance;
+ unsigned char *bitmap;
+} PerGlyphInfo, *PerGlyphInfoPtr;
+
+typedef struct {
+ int min_char;
+ int max_char;
+ int max_ascent;
+ int max_descent;
+ PerGlyphInfo glyph[1];
+} FontInfo, *FontInfoPtr;
+
+Display *dpy;
+FontInfoPtr fontinfo;
+
+/* #define REPORT_GLYPHS */
+#ifdef REPORT_GLYPHS
+#define DEBUG_GLYPH4(msg,a,b,c,d) printf(msg,a,b,c,d)
+#define DEBUG_GLYPH(msg) printf(msg)
+#else
+#define DEBUG_GLYPH4(msg,a,b,c,d) { /* nothing */ }
+#define DEBUG_GLYPH(msg) { /* nothing */ }
+#endif
+
+#define MAX_GLYPHS_PER_GRAB 512 /* this is big enough for 2^9 glyph
+ character sets */
+
+FontInfoPtr
+SuckGlyphsFromServer(Display * dpy, Font font)
+{
+ Pixmap offscreen;
+ XFontStruct *fontinfo;
+ XImage *image;
+ GC xgc;
+ XGCValues values;
+ int numchars;
+ int width, height, pixwidth;
+ int i, j;
+ XCharStruct *charinfo;
+ XChar2b character;
+ unsigned char *bitmapData;
+ int x, y;
+ int spanLength;
+ int charWidth, charHeight, maxSpanLength;
+ int grabList[MAX_GLYPHS_PER_GRAB];
+ int glyphsPerGrab = MAX_GLYPHS_PER_GRAB;
+ int numToGrab, thisglyph;
+ FontInfoPtr myfontinfo;
+
+ fontinfo = XQueryFont(dpy, font);
+ if (!fontinfo)
+ return NULL;
+
+ numchars = fontinfo->max_char_or_byte2 - fontinfo->min_char_or_byte2 + 1;
+ if (numchars < 1)
+ return NULL;
+
+ myfontinfo = (FontInfoPtr) malloc(sizeof(FontInfo) + (numchars - 1) * sizeof(PerGlyphInfo));
+ if (!myfontinfo)
+ return NULL;
+
+ myfontinfo->min_char = fontinfo->min_char_or_byte2;
+ myfontinfo->max_char = fontinfo->max_char_or_byte2;
+ myfontinfo->max_ascent = fontinfo->max_bounds.ascent;
+ myfontinfo->max_descent = fontinfo->max_bounds.descent;
+
+ width = fontinfo->max_bounds.rbearing - fontinfo->min_bounds.lbearing;
+ height = fontinfo->max_bounds.ascent + fontinfo->max_bounds.descent;
+
+ maxSpanLength = (width + 7) / 8;
+ /* Be careful determining the width of the pixmap; the X protocol allows
+ pixmaps of width 2^16-1 (unsigned short size) but drawing coordinates
+ max out at 2^15-1 (signed short size). If the width is too large, we
+ need to limit the glyphs per grab. */
+ if ((glyphsPerGrab * 8 * maxSpanLength) >= (1 << 15)) {
+ glyphsPerGrab = (1 << 15) / (8 * maxSpanLength);
+ }
+ pixwidth = glyphsPerGrab * 8 * maxSpanLength;
+ offscreen = XCreatePixmap(dpy, RootWindow(dpy, DefaultScreen(dpy)),
+ 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;
+ }
+ for (i = 0; i < numchars; i++) {
+ if (fontinfo->per_char != NULL) {
+ charinfo = &(fontinfo->per_char[i]);
+ charWidth = charinfo->rbearing - charinfo->lbearing;
+ charHeight = charinfo->ascent + charinfo->descent;
+ if (charWidth == 0 || charHeight == 0) {
+ /* Still must move raster pos even if empty character */
+ myfontinfo->glyph[i].width = 0;
+ myfontinfo->glyph[i].height = 0;
+ myfontinfo->glyph[i].xoffset = 0;
+ myfontinfo->glyph[i].yoffset = 0;
+ myfontinfo->glyph[i].advance = charinfo->width;
+ myfontinfo->glyph[i].bitmap = NULL;
+ goto PossiblyDoGrab;
+ }
+ }
+ grabList[numToGrab] = i;
+
+ /* XXX is this right for large fonts? */
+ character.byte2 = (i + fontinfo->min_char_or_byte2) & 255;
+ character.byte1 = (i + fontinfo->min_char_or_byte2) >> 8;
+
+ /* XXX we could use XDrawImageString16 which would also paint the backing
+
+ rectangle but X server bugs in some scalable font rasterizers makes it
+
+ more effective to do XFillRectangles to clear the pixmap and
+ XDrawImage16 for the text. */
+ XDrawString16(dpy, offscreen, xgc,
+ -charinfo->lbearing + 8 * maxSpanLength * numToGrab,
+ charinfo->ascent, &character, 1);
+
+ numToGrab++;
+
+ PossiblyDoGrab:
+
+ if (numToGrab >= glyphsPerGrab || i == numchars - 1) {
+ image = XGetImage(dpy, offscreen,
+ 0, 0, pixwidth, height, 1, XYPixmap);
+ for (j = 0; j < numToGrab; j++) {
+ thisglyph = grabList[j];
+ if (fontinfo->per_char != NULL) {
+ charinfo = &(fontinfo->per_char[thisglyph]);
+ charWidth = charinfo->rbearing - charinfo->lbearing;
+ charHeight = charinfo->ascent + charinfo->descent;
+ spanLength = (charWidth + 7) / 8;
+ }
+ bitmapData = calloc(height * spanLength, sizeof(char));
+ if (!bitmapData)
+ goto FreeFontAndReturn;
+ DEBUG_GLYPH4("index %d, glyph %d (%d by %d)\n",
+ j, thisglyph + fontinfo->min_char_or_byte2, charWidth, charHeight);
+ for (y = 0; y < charHeight; y++) {
+ for (x = 0; x < charWidth; x++) {
+ /* XXX The algorithm used to suck across the font ensures that
+ each glyph begins on a byte boundary. In theory this would
+ make it convienent to copy the glyph into a byte oriented
+ bitmap. We actually use the XGetPixel function to extract
+ each pixel from the image which is not that efficient. We
+ could either do tighter packing in the pixmap or more
+ efficient extraction from the image. Oh well. */
+ if (XGetPixel(image, j * maxSpanLength * 8 + x, charHeight - 1 - y)) {
+ DEBUG_GLYPH("x");
+ bitmapData[y * spanLength + x / 8] |= (1 << (x & 7));
+ } else {
+ DEBUG_GLYPH(" ");
+ }
+ }
+ DEBUG_GLYPH("\n");
+ }
+ myfontinfo->glyph[thisglyph].width = charWidth;
+ myfontinfo->glyph[thisglyph].height = charHeight;
+ myfontinfo->glyph[thisglyph].xoffset = charinfo->lbearing;
+ myfontinfo->glyph[thisglyph].yoffset = -charinfo->descent;
+ myfontinfo->glyph[thisglyph].advance = charinfo->width;
+ myfontinfo->glyph[thisglyph].bitmap = bitmapData;
+ }
+ XDestroyImage(image);
+ numToGrab = 0;
+ /* do we need to clear the offscreen pixmap to get more? */
+ if (i < numchars - 1) {
+ XSetForeground(dpy, xgc, 0);
+ XFillRectangle(dpy, offscreen, xgc, 0, 0, 8 * maxSpanLength * glyphsPerGrab, height);
+ XSetForeground(dpy, xgc, 1);
+ }
+ }
+ }
+ XFreeGC(dpy, xgc);
+ XFreePixmap(dpy, offscreen);
+ return myfontinfo;
+
+FreeFontAndReturn:
+ XDestroyImage(image);
+ XFreeGC(dpy, xgc);
+ XFreePixmap(dpy, offscreen);
+ for (j = i - 1; j >= 0; j--) {
+ if (myfontinfo->glyph[j].bitmap)
+ free(myfontinfo->glyph[j].bitmap);
+ }
+ free(myfontinfo);
+ return NULL;
+}
+
+void
+printGlyph(FontInfoPtr font, int c)
+{
+ PerGlyphInfoPtr glyph;
+ unsigned char *bitmapData;
+ int width, height, spanLength;
+ int x, y, l;
+ char buf[1000], *b;
+
+ if (c < font->min_char || c > font->max_char) {
+ fprintf(stderr, "out of range glyph\n");
+ exit(1);
+ }
+ glyph = &font->glyph[c - font->min_char];
+ bitmapData = glyph->bitmap;
+ width = glyph->width;
+ spanLength = (width + 7) / 8;
+ height = glyph->height;
+
+ printf(" { // %d\n", c);
+ printf(" %d, %d,\n", glyph->advance, font->max_ascent + font->max_descent);
+ for (y = 0; y < font->max_ascent - glyph->yoffset - height; y++) {
+ printf(" 0x%08X, // ", 0);
+ for (x = 0; x < glyph->xoffset + width || x < glyph->advance; x++)
+ putchar('.');
+ putchar('\n');
+ }
+ for (y = height; y-- > 0;) {
+ l = 0;
+ b = buf;
+ for (x = 0; x < glyph->xoffset; x++)
+ *b++ = '.';
+ if (bitmapData) {
+ for (x = 0; x < width; x++) {
+ if (bitmapData[y * spanLength + x / 8] & (1 << (x & 7))) {
+ *b++ = '*';
+ l |= 1;
+ }
+ else
+ *b++ = '.';
+ l <<= 1;
+ }
+ for (x = 0; x < glyph->advance - width - glyph->xoffset; x++) {
+ *b++ = '.';
+ l <<= 1;
+ }
+ }
+ *b = 0;
+ printf(" 0x%08X, // %s\n", l, buf);
+ }
+ for (y = 0; y < font->max_descent + glyph->yoffset; y++) {
+ printf(" 0x%08X, // ", 0);
+ for (x = 0; x < glyph->xoffset + width || x < glyph->advance; x++)
+ putchar('.');
+ putchar('\n');
+ }
+ printf(" },\n");
+}
+
+void
+getMetric(FontInfoPtr font, int c, TexGlyphInfo * tgi)
+{
+ PerGlyphInfoPtr glyph;
+ unsigned char *bitmapData;
+
+ tgi->c = c;
+ if (c < font->min_char || c > font->max_char) {
+ tgi->width = 0;
+ tgi->height = 0;
+ tgi->xoffset = 0;
+ tgi->yoffset = 0;
+ tgi->dummy = 0;
+ tgi->advance = 0;
+ return;
+ }
+ glyph = &font->glyph[c - font->min_char];
+ bitmapData = glyph->bitmap;
+ if (bitmapData) {
+ tgi->width = glyph->width;
+ tgi->height = glyph->height;
+ tgi->xoffset = glyph->xoffset;
+ tgi->yoffset = glyph->yoffset;
+ } else {
+ tgi->width = 0;
+ tgi->height = 0;
+ tgi->xoffset = 0;
+ tgi->yoffset = 0;
+ }
+ tgi->dummy = 0;
+ tgi->advance = glyph->advance;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ TexGlyphInfo tgi;
+ int usageError = 0;
+ char *varname, *fontname;
+ XFontStruct *xfont;
+ int i;
+
+ if (argc == 3) {
+ varname = argv[1];
+ fontname = argv[2];
+ }
+ else
+ usageError = 1;
+
+ if (usageError) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "usage: genfontfile variable_name X_font_name\n");
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+
+ dpy = XOpenDisplay(NULL);
+ if (!dpy) {
+ fprintf(stderr, "could not open display\n");
+ exit(1);
+ }
+ /* find an OpenGL-capable RGB visual with depth buffer */
+ xfont = XLoadQueryFont(dpy, fontname);
+ if (!xfont) {
+ fprintf(stderr, "could not get load X font: %s\n", fontname);
+ exit(1);
+ }
+ fontinfo = SuckGlyphsFromServer(dpy, xfont->fid);
+ if (!fontinfo) {
+ fprintf(stderr, "could not get font glyphs\n");
+ exit(1);
+ }
+
+ printf("%s[][%d] = {\n", varname, fontinfo->max_ascent + fontinfo->max_descent + 2);
+ for (c = 32; c < 256; c++) {
+ getMetric(fontinfo, c, &tgi);
+ printGlyph(fontinfo, c);
+ }
+ printf(" };\n");
+ return 0;
+}