X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fglx%2Ftexfont.c;h=8f39ea86bddfb08778255a089e518eb9dd412759;hb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e;hp=906f3e22a5a6af8f21ae61dacefc9eb2aa13dd06;hpb=5f1f12f2a37da634000f96d18d59cc73a8814ef7;p=xscreensaver diff --git a/hacks/glx/texfont.c b/hacks/glx/texfont.c index 906f3e22..8f39ea86 100644 --- a/hacks/glx/texfont.c +++ b/hacks/glx/texfont.c @@ -1,5 +1,4 @@ -/* texfonts, Copyright (c) 2005-2010 Jamie Zawinski - * Loads X11 fonts into textures for use with OpenGL. +/* texfonts, Copyright (c) 2005-2014 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -8,9 +7,11 @@ * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. + * + * Renders X11 fonts into textures for use with OpenGL. + * A higher level API is in glxfonts.c. */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -21,15 +22,26 @@ #include #ifdef HAVE_COCOA -# include +# ifdef USE_IPHONE +# include "jwzgles.h" +# else +# include +# endif #else # include # include #endif +#ifdef HAVE_JWZGLES +# include "jwzgles.h" +#endif /* HAVE_JWZGLES */ + #include "resources.h" #include "texfont.h" +#define DO_SUBSCRIPTS + + /* These are in xlock-gl.c */ extern void clear_gl_error (void); extern void check_gl_error (const char *type); @@ -82,11 +94,30 @@ bitmap_to_texture (Display *dpy, Pixmap p, Visual *visual, int *wP, int *hP) int h2 = to_pow2 (oh); int x, y; XImage *image = XGetImage (dpy, p, 0, 0, ow, oh, ~0L, ZPixmap); - unsigned char *data = (unsigned char *) calloc (w2, (h2 + 1)); + unsigned char *data = (unsigned char *) calloc (w2 * 2, (h2 + 1)); unsigned char *out = data; + + /* OpenGLES doesn't support GL_INTENSITY, so instead of using a + texture with 1 byte per pixel, the intensity value, we have + to use 2 bytes per pixel: solid white, and an alpha value. + */ +# ifdef HAVE_JWZGLES +# undef GL_INTENSITY +# endif + +# ifdef GL_INTENSITY GLuint iformat = GL_INTENSITY; - GLuint format = GL_LUMINANCE; - GLuint type = GL_UNSIGNED_BYTE; + GLuint format = GL_LUMINANCE; +# else + GLuint iformat = GL_LUMINANCE_ALPHA; + GLuint format = GL_LUMINANCE_ALPHA; +# endif + GLuint type = GL_UNSIGNED_BYTE; + +# ifdef HAVE_JWZGLES + /* This would work, but it's wasteful for no benefit. */ + mipmap_p = False; +# endif for (y = 0; y < h2; y++) for (x = 0; x < w2; x++) { @@ -94,7 +125,11 @@ bitmap_to_texture (Display *dpy, Pixmap p, Visual *visual, int *wP, int *hP) /* instead of averaging all three channels, let's just use red, and assume it was already grayscale. */ unsigned long r = pixel & visual->red_mask; + /* This goofy trick is to make any of RGBA/ABGR/ARGB work. */ pixel = ((r >> 24) | (r >> 16) | (r >> 8) | r) & 0xFF; +# ifndef GL_INTENSITY + *out++ = 0xFF; /* 2 bytes per pixel */ +# endif *out++ = pixel; } XDestroyImage (image); @@ -118,6 +153,20 @@ bitmap_to_texture (Display *dpy, Pixmap p, Visual *visual, int *wP, int *hP) glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, mipmap_p ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); + + /* This makes scaled font pixmaps tolerable to look at. + LOD bias is part of OpenGL 1.4. + GL_EXT_texture_lod_bias has been present since the original iPhone. + */ +# if !defined(GL_TEXTURE_LOD_BIAS) && defined(GL_TEXTURE_LOD_BIAS_EXT) +# define GL_TEXTURE_LOD_BIAS GL_TEXTURE_LOD_BIAS_EXT +# endif +# ifdef GL_TEXTURE_LOD_BIAS + if (mipmap_p) + glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.25); +# endif + clear_gl_error(); /* invalid enum on iPad 3 */ + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -128,69 +177,20 @@ bitmap_to_texture (Display *dpy, Pixmap p, Visual *visual, int *wP, int *hP) } -/* Loads the font named by the X resource "res" and returns - a texture-font object. -*/ -texture_font_data * -load_texture_font (Display *dpy, char *res) +static texture_font_data * +load_texture_xfont (Display *dpy, XFontStruct *f) { Screen *screen = DefaultScreenOfDisplay (dpy); Window root = RootWindowOfScreen (screen); XWindowAttributes xgwa; - - texture_font_data *data = 0; - char *font = get_string_resource (dpy, res, "Font"); - const char *def1 = "-*-helvetica-medium-r-normal-*-240-*"; - const char *def2 = "-*-helvetica-medium-r-normal-*-180-*"; - const char *def3 = "fixed"; - XFontStruct *f; int which; + GLint old_texture = 0; + texture_font_data *data = 0; - check_gl_error ("stale texture font"); + glGetIntegerv (GL_TEXTURE_BINDING_2D, &old_texture); XGetWindowAttributes (dpy, root, &xgwa); - if (!res || !*res) abort(); - if (!font) font = strdup(def1); - - f = XLoadQueryFont(dpy, font); - if (!f && !!strcmp (font, def1)) - { - fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", - progname, font, def1); - free (font); - font = strdup (def1); - f = XLoadQueryFont(dpy, font); - } - - if (!f && !!strcmp (font, def2)) - { - fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", - progname, font, def2); - free (font); - font = strdup (def2); - f = XLoadQueryFont(dpy, font); - } - - if (!f && !!strcmp (font, def3)) - { - fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", - progname, font, def3); - free (font); - font = strdup (def3); - f = XLoadQueryFont(dpy, font); - } - - if (!f) - { - fprintf (stderr, "%s: unable to load fallback font \"%s\" either!\n", - progname, font); - exit (1); - } - - free (font); - font = 0; - data = (texture_font_data *) calloc (1, sizeof(*data)); data->dpy = dpy; data->font = f; @@ -278,75 +278,138 @@ load_texture_font (Display *dpy, char *res) data->tex_width = w; data->tex_height = h; -#if 0 /* debugging: splat the bitmap onto the desktop root window */ - { - Window win = RootWindow (dpy, 0); - GC gc2 = XCreateGC (dpy, win, 0, &gcv); - XSetForeground (dpy, gc2, BlackPixel (dpy, 0)); - XSetBackground (dpy, gc2, WhitePixel (dpy, 0)); - XCopyArea (dpy, p, win, gc2, 0, 0, w, h, 0, 0); - XFreeGC (dpy, gc2); - XSync(dpy, False); - usleep (100000); - } -#endif - #if 0 /* debugging: write the bitmap to a pgm file */ { char file[255]; XImage *image; int x, y; - FILE *f; + FILE *ff; sprintf (file, "/tmp/%02d.pgm", which); image = XGetImage (dpy, p, 0, 0, w, h, ~0L, ZPixmap); - f = fopen (file, "w"); - fprintf (f, "P5\n%d %d\n255\n", w, h); + ff = fopen (file, "w"); + fprintf (ff, "P5\n%d %d\n255\n", w, h); for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned long pix = XGetPixel (image, x, y); unsigned long r = (pix & xgwa.visual->red_mask); r = ((r >> 24) | (r >> 16) | (r >> 8) | r); - fprintf (f, "%c", (char) r); + fprintf (ff, "%c", (char) r); } - fclose (f); + fclose (ff); XDestroyImage (image); - fprintf (stderr, "%s: wrote %s\n", progname, file); + fprintf (stderr, "%s: wrote %s (%d x %d)\n", progname, file, + f->max_bounds.rbearing - f->min_bounds.lbearing, + f->max_bounds.ascent + f->max_bounds.descent); } -#endif +#endif /* 0 */ bitmap_to_texture (dpy, p, xgwa.visual, &data->tex_width, &data->tex_height); XFreePixmap (dpy, p); } + /* Reset to the caller's default */ + glBindTexture (GL_TEXTURE_2D, old_texture); + return data; } -/* Width of the string in pixels. +/* Loads the font named by the X resource "res" and returns + a texture-font object. +*/ +texture_font_data * +load_texture_font (Display *dpy, char *res) +{ + char *font = get_string_resource (dpy, res, "Font"); + const char *def1 = "-*-helvetica-medium-r-normal-*-240-*"; + const char *def2 = "-*-helvetica-medium-r-normal-*-180-*"; + const char *def3 = "fixed"; + XFontStruct *f; + + if (!strcmp (res, "fpsFont")) + def1 = "-*-courier-bold-r-normal-*-180-*"; /* Kludge. Sue me. */ + + if (!res || !*res) abort(); + if (!font) font = strdup(def1); + + f = XLoadQueryFont(dpy, font); + if (!f && !!strcmp (font, def1)) + { + fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", + progname, font, def1); + free (font); + font = strdup (def1); + f = XLoadQueryFont(dpy, font); + } + + if (!f && !!strcmp (font, def2)) + { + fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", + progname, font, def2); + free (font); + font = strdup (def2); + f = XLoadQueryFont(dpy, font); + } + + if (!f && !!strcmp (font, def3)) + { + fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", + progname, font, def3); + free (font); + font = strdup (def3); + f = XLoadQueryFont(dpy, font); + } + + if (!f) + { + fprintf (stderr, "%s: unable to load fallback font \"%s\" either!\n", + progname, font); + exit (1); + } + + free (font); + font = 0; + + return load_texture_xfont (dpy, f); +} + + +/* Bounding box of the multi-line string, in pixels. */ int -texture_string_width (texture_font_data *data, const char *c, - int *line_height_ret) +texture_string_width (texture_font_data *data, const char *c, int *height_ret) { - int w = 0; XFontStruct *f = data->font; + int x = 0; + int max_w = 0; + int lh = f->ascent + f->descent; + int h = lh; while (*c) { int cc = *((unsigned char *) c); - w += (f->per_char && cc >= f->min_char_or_byte2 - ? f->per_char[cc-f->min_char_or_byte2].width - : f->max_bounds.width); + if (*c == '\n') + { + if (x > max_w) max_w = x; + x = 0; + h += lh; + } + else + x += (f->per_char + ? f->per_char[cc-f->min_char_or_byte2].width + : f->min_bounds.rbearing); c++; } - if (line_height_ret) - *line_height_ret = f->ascent + f->descent; - return w; + if (x > max_w) max_w = x; + if (height_ret) *height_ret = h; + return max_w; } /* Draws the string in the scene at the origin. Newlines and tab stops are honored. + Any numbers inside [] will be rendered as a subscript. + Assumes the font has been loaded as with load_texture_font(). */ void print_texture_string (texture_font_data *data, const char *string) @@ -361,12 +424,24 @@ print_texture_string (texture_font_data *data, const char *string) int tabs = cw * 7; int x, y; unsigned int i; + GLint old_texture = 0; + GLfloat omatrix[16]; + int ofront; + + glGetIntegerv (GL_TEXTURE_BINDING_2D, &old_texture); + glGetIntegerv (GL_FRONT_FACE, &ofront); + glGetFloatv (GL_TEXTURE_MATRIX, omatrix); clear_gl_error (); glPushMatrix(); glNormal3f (0, 0, 1); + glFrontFace (GL_CW); + + glMatrixMode (GL_TEXTURE); + glLoadIdentity (); + glMatrixMode (GL_MODELVIEW); x = 0; y = 0; @@ -380,7 +455,8 @@ print_texture_string (texture_font_data *data, const char *string) } else if (c == '\t') { - x = ((x + tabs) / tabs) * tabs; /* tab to tab stop */ + if (tabs) + x = ((x + tabs) / tabs) * tabs; /* tab to tab stop */ } # ifdef DO_SUBSCRIPTS else if (c == '[' && (isdigit (string[i+1]))) @@ -456,8 +532,8 @@ print_texture_string (texture_font_data *data, const char *string) int bx = ax - lbearing; /* point B */ int by = ay + ascent; - int cx = bx + rbearing; /* point C */ - int cy = by + descent; + int cx = bx + rbearing + 1; /* point C */ + int cy = by + descent + 1; GLfloat tax = (GLfloat) ax / data->tex_width; /* tex coords of A */ GLfloat tay = (GLfloat) ay / data->tex_height; @@ -499,6 +575,14 @@ print_texture_string (texture_font_data *data, const char *string) } glPopMatrix(); + /* Reset to the caller's default */ + glBindTexture (GL_TEXTURE_2D, old_texture); + glFrontFace (ofront); + + glMatrixMode (GL_TEXTURE); + glMultMatrixf (omatrix); + glMatrixMode (GL_MODELVIEW); + check_gl_error ("texture font print"); } @@ -508,10 +592,13 @@ void free_texture_font (texture_font_data *data) { int i; - if (data->font) - XFreeFont (data->dpy, data->font); + for (i = 0; i < data->ntextures; i++) if (data->texid[i]) glDeleteTextures (1, &data->texid[i]); + + if (data->font) + XFreeFont (data->dpy, data->font); + free (data); }