X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fglx%2Fglxfonts.c;h=9197af975b2f69ecb4ab8e4e8fb7f0395ff615d1;hp=55ee7f515f3cfa0eb5277328f81da6919c39777b;hb=f0261d8acab611f3433160e4f07367b870439739;hpb=7b34ef992563d7bcbb64cc5597dc45fa24470b05 diff --git a/hacks/glx/glxfonts.c b/hacks/glx/glxfonts.c index 55ee7f51..9197af97 100644 --- a/hacks/glx/glxfonts.c +++ b/hacks/glx/glxfonts.c @@ -1,4 +1,4 @@ -/* glxfonts, Copyright (c) 2001-2008 Jamie Zawinski +/* glxfonts, Copyright (c) 2001-2009 Jamie Zawinski * Loads X11 fonts for use with OpenGL. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -46,6 +46,221 @@ extern char *progname; */ +/* Mostly lifted from the Mesa implementation of glXUseXFont(), since + Mac OS 10.6 no longer supports aglUseFont() which was their analog + of that. This code could be in libjwxyz instead, but we might as + well use the same text-drawing code on both X11 and Cocoa. + */ +static void +fill_bitmap (Display *dpy, Window win, GC gc, + unsigned int width, unsigned int height, + int x0, int y0, char c, GLubyte *bitmap) +{ + XImage *image; + int x, y; + Pixmap pixmap; + + pixmap = XCreatePixmap (dpy, win, 8*width, height, 1); + XSetForeground(dpy, gc, 0); + XFillRectangle (dpy, pixmap, gc, 0, 0, 8*width, height); + XSetForeground(dpy, gc, 1); + XDrawString (dpy, pixmap, gc, x0, y0, &c, 1); + + image = XGetImage (dpy, pixmap, 0, 0, 8*width, height, 1, XYPixmap); + + /* Fill the bitmap (X11 and OpenGL are upside down wrt each other). */ + for (y = 0; y < height; y++) + for (x = 0; x < 8*width; x++) + if (XGetPixel (image, x, y)) + bitmap[width*(height - y - 1) + x/8] |= (1 << (7 - (x % 8))); + + XFreePixmap (dpy, pixmap); + XDestroyImage (image); +} + + +#if 0 +static void +dump_bitmap (unsigned int width, unsigned int height, GLubyte *bitmap) +{ + int x, y; + + printf (" "); + for (x = 0; x < 8*width; x++) + printf ("%o", 7 - (x % 8)); + putchar ('\n'); + for (y = 0; y < height; y++) + { + printf ("%3o:", y); + for (x = 0; x < 8*width; x++) + putchar ((bitmap[width*(height - y - 1) + x/8] & (1 << (7 - (x % 8)))) + ? '#' : '.'); + printf (" "); + for (x = 0; x < width; x++) + printf ("0x%02x, ", bitmap[width*(height - y - 1) + x]); + putchar ('\n'); + } +} +#endif + + +void +xscreensaver_glXUseXFont (Display *dpy, Font font, + int first, int count, int listbase) +{ + Window win = RootWindowOfScreen (DefaultScreenOfDisplay (dpy)); + Pixmap pixmap; + GC gc; + XGCValues values; + unsigned long valuemask; + + XFontStruct *fs; + + GLint swapbytes, lsbfirst, rowlength; + GLint skiprows, skippixels, alignment; + + unsigned int max_width, max_height, max_bm_width, max_bm_height; + GLubyte *bm; + + int i; + + fs = XQueryFont (dpy, font); + if (!fs) + { + /*gl_error (CC->gl_ctx, GL_INVALID_VALUE, + "Couldn't get font structure information");*/ + abort(); + return; + } + + /* Allocate a bitmap that can fit all characters. */ + max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing; + max_height = fs->max_bounds.ascent + fs->max_bounds.descent; + max_bm_width = (max_width + 7) / 8; + max_bm_height = max_height; + + bm = (GLubyte *) malloc ((max_bm_width * max_bm_height) * sizeof (GLubyte)); + if (!bm) + { + /*gl_error (CC->gl_ctx, GL_OUT_OF_MEMORY, + "Couldn't allocate bitmap in glXUseXFont()");*/ + abort(); + return; + } + + /* Save the current packing mode for bitmaps. */ + glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes); + glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst); + glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength); + glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows); + glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels); + glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment); + + /* Enforce a standard packing mode which is compatible with + fill_bitmap() from above. This is actually the default mode, + except for the (non)alignment. */ + glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); + glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); + glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); + glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); + glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); + glPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + pixmap = XCreatePixmap (dpy, win, 10, 10, 1); + values.foreground = 0; + values.background = 1; + values.font = fs->fid; + valuemask = GCForeground | GCBackground | GCFont; + gc = XCreateGC (dpy, pixmap, valuemask, &values); + XFreePixmap (dpy, pixmap); + +# ifdef HAVE_COCOA + /* Anti-aliasing of fonts looks like crap with 1-bit bitmaps. + It would be nice if we were using full-depth bitmaps, so + that the text showed up anti-aliased on screen, but + glBitmap() doesn't work that way. */ + jwxyz_XSetAntiAliasing (dpy, gc, False); +# endif + + for (i = 0; i < count; i++) + { + unsigned int width, height, bm_width, bm_height; + GLfloat x0, y0, dx, dy; + XCharStruct *ch; + int x, y; + int c = first + i; + int list = listbase + i; + + if (fs->per_char + && (c >= fs->min_char_or_byte2) && (c <= fs->max_char_or_byte2)) + ch = &fs->per_char[c-fs->min_char_or_byte2]; + else + ch = &fs->max_bounds; + + /* I'm not entirely clear on why this is necessary on OSX, but + without it, the characters are clipped. And it does not hurt + under real X11. -- jwz. */ + ch->lbearing--; + ch->ascent++; + + /* glBitmap()'s parameters: + "Bitmap parameters xorig, yorig, width, and height are + computed from font metrics as descent-1, -lbearing, + rbearing-lbearing, and ascent+descent, respectively. + xmove is taken from the glyph's width metric, and + ymove is set to zero. Finally, the glyph's image is + converted to the appropriate format for glBitmap." + */ + width = ch->rbearing - ch->lbearing; + height = ch->ascent + ch->descent; + x0 = - ch->lbearing; + y0 = ch->descent - 1; + dx = ch->width; + dy = 0; + + /* X11's starting point. */ + x = - ch->lbearing; + y = ch->ascent; + + /* Round the width to a multiple of eight. We will use this also + for the pixmap for capturing the X11 font. This is slightly + inefficient, but it makes the OpenGL part real easy. */ + bm_width = (width + 7) / 8; + bm_height = height; + + glNewList (list, GL_COMPILE); + if ((c >= fs->min_char_or_byte2) && (c <= fs->max_char_or_byte2) + && (bm_width > 0) && (bm_height > 0)) + { + memset (bm, '\0', bm_width * bm_height); + fill_bitmap (dpy, win, gc, bm_width, bm_height, x, y, c, bm); + glBitmap (width, height, x0, y0, dx, dy, bm); +#if 0 + printf ("width/height = %d/%d\n", width, height); + printf ("bm_width/bm_height = %d/%d\n", bm_width, bm_height); + dump_bitmap (bm_width, bm_height, bm); +#endif + } + else + glBitmap (0, 0, 0.0, 0.0, dx, dy, NULL); + glEndList (); + } + + free (bm); + XFreeFontInfo( NULL, fs, 0 ); + XFreeGC (dpy, gc); + + /* Restore saved packing modes. */ + glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes); + glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst); + glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength); + glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels); + glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); +} + + + /* Loads the font named by the X resource "res". Returns an XFontStruct. Also converts the font to a set of GL lists and returns the first list. @@ -95,39 +310,15 @@ load_font (Display *dpy, char *res, XFontStruct **font_ret, GLuint *dlist_ret) last = f->max_char_or_byte2; -# ifndef HAVE_COCOA /* Xlib version */ - if (dlist_ret) { clear_gl_error (); *dlist_ret = glGenLists ((GLuint) last+1); check_gl_error ("glGenLists"); - glXUseXFont(id, first, last-first+1, *dlist_ret + first); - check_gl_error ("glXUseXFont"); - } - -# else /* HAVE_COCOA */ - - { - int afid, face, size; - afid = jwxyz_font_info (id, &size, &face); - - if (dlist_ret) - { - clear_gl_error (); - *dlist_ret = glGenLists ((GLuint) last+1); - check_gl_error ("glGenLists"); - - AGLContext ctx = aglGetCurrentContext(); - if (! aglUseFont (ctx, afid, face, size, - first, last-first+1, *dlist_ret + first)) { - check_gl_error ("aglUseFont"); - abort(); - } + xscreensaver_glXUseXFont(dpy, id, first, last-first+1, + *dlist_ret + first); + check_gl_error ("xscreensaver_glXUseXFont"); } - } - -# endif /* HAVE_COCOA */ if (font_ret) *font_ret = f;