X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fglx%2Fglxfonts.c;h=1519006d4edb7c1726684dd94cda16e46d959261;hb=6afd6db0ae9396cd7ff897ade597cd5483f49b0e;hp=55ee7f515f3cfa0eb5277328f81da6919c39777b;hpb=c1b9b55ad8d59dc05ef55e316aebf5863e7dfa56;p=xscreensaver diff --git a/hacks/glx/glxfonts.c b/hacks/glx/glxfonts.c index 55ee7f51..1519006d 100644 --- a/hacks/glx/glxfonts.c +++ b/hacks/glx/glxfonts.c @@ -1,5 +1,4 @@ -/* glxfonts, Copyright (c) 2001-2008 Jamie Zawinski - * Loads X11 fonts for use with OpenGL. +/* glxfonts, Copyright (c) 2001-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,6 +7,10 @@ * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. + * + * Draws 2D text over the GL scene, e.g., the FPS displays. + * Also billboarding. + * The lower-level character rendering code is in texfont.c. */ #ifdef HAVE_CONFIG_H @@ -21,16 +24,21 @@ #ifdef HAVE_COCOA # include "jwxyz.h" -# include -# include -# include +/*# include */ #else # include # include #endif +#ifdef HAVE_JWZGLES +# include "jwzgles.h" +#endif /* HAVE_JWZGLES */ + #include "resources.h" #include "glxfonts.h" +#include "texfont.h" +#include "fps.h" + /* These are in xlock-gl.c */ extern void clear_gl_error (void); @@ -45,262 +53,184 @@ extern char *progname; it might result in a round-trip, and stall of the pipeline.) */ - -/* 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. -*/ -void -load_font (Display *dpy, char *res, XFontStruct **font_ret, GLuint *dlist_ret) -{ - XFontStruct *f; - - const char *font = get_string_resource (dpy, res, "Font"); - const char *def1 = "-*-helvetica-medium-r-normal-*-180-*"; - const char *def2 = "fixed"; - Font id; - int first, last; - - if (!res || !*res) abort(); - if (!font_ret && !dlist_ret) abort(); - - if (!font) font = def1; - - f = XLoadQueryFont(dpy, font); - if (!f && !!strcmp (font, def1)) - { - fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", - progname, font, def1); - font = def1; - f = XLoadQueryFont(dpy, font); - } - - if (!f && !!strcmp (font, def2)) - { - fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n", - progname, font, def2); - font = def2; - f = XLoadQueryFont(dpy, font); - } - - if (!f) - { - fprintf (stderr, "%s: unable to load fallback font \"%s\" either!\n", - progname, font); - exit (1); - } - - id = f->fid; - first = f->min_char_or_byte2; - 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(); - } - } - } - -# endif /* HAVE_COCOA */ - - if (font_ret) - *font_ret = f; -} - - -/* Width (and optionally height) of the string in pixels. - */ -int -string_width (XFontStruct *f, const char *c, int *height_ret) -{ - int x = 0; - int max_w = 0; - int h = f->ascent + f->descent; - while (*c) - { - int cc = *((unsigned char *) c); - if (*c == '\n') - { - if (x > max_w) max_w = x; - x = 0; - h += f->ascent + f->descent; - } - else - x += (f->per_char - ? f->per_char[cc-f->min_char_or_byte2].width - : f->min_bounds.rbearing); - c++; - } - if (x > max_w) max_w = x; - if (height_ret) *height_ret = h; - - return max_w; -} +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) /* Draws the string on the window at the given pixel position. Newlines and tab stops are honored. - Any text inside [] will be rendered as a subscript. - Assumes the font has been loaded as with load_font(). + Any numbers inside [] will be rendered as a subscript. + Assumes the font has been loaded as with load_texture_font(). + + If width and height are 0, then instead the text is placed + into the 3D scene at the origin, billboarded to face the + viewer. */ void print_gl_string (Display *dpy, - XFontStruct *font, - GLuint font_dlist, + texture_font_data *data, int window_width, int window_height, GLfloat x, GLfloat y, const char *string, Bool clear_background_p) { - GLfloat line_height = font->ascent + font->descent; - GLfloat sub_shift = (line_height * 0.3); - int cw = string_width (font, "m", 0); - int tabs = cw * 7; - + Bool in_scene_p = (window_width == 0); + + int line_height = 0; + int lines = 0; + const char *c; + GLfloat color[4]; + + Bool tex_p = glIsEnabled (GL_TEXTURE_2D); + Bool texs_p = glIsEnabled (GL_TEXTURE_GEN_S); + Bool text_p = glIsEnabled (GL_TEXTURE_GEN_T); + Bool light_p = glIsEnabled (GL_LIGHTING); + Bool blend_p = glIsEnabled (GL_BLEND); + Bool depth_p = glIsEnabled (GL_DEPTH_TEST); + Bool cull_p = glIsEnabled (GL_CULL_FACE); + Bool fog_p = glIsEnabled (GL_FOG); + GLint oblend; + GLint ovp[4]; + +# ifndef HAVE_JWZGLES + GLint opoly[2]; + glGetIntegerv (GL_POLYGON_MODE, opoly); +# endif + + if (!in_scene_p) + glGetIntegerv (GL_VIEWPORT, ovp); + + glGetIntegerv (GL_BLEND_DST, &oblend); + glGetFloatv (GL_CURRENT_COLOR, color); + + for (c = string; *c; c++) + if (*c == '\n') lines++; + + texture_string_width (data, "m", &line_height); y -= line_height; - /* Sadly, this causes a stall of the graphics pipeline (as would the - equivalent calls to glGet*.) But there's no way around this, short - of having each caller set up the specific display matrix we need - here, which would kind of defeat the purpose of centralizing this - code in one file. + + glEnable (GL_TEXTURE_2D); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPolygonMode (GL_FRONT, GL_FILL); + + glDisable (GL_TEXTURE_GEN_S); + glDisable (GL_TEXTURE_GEN_T); + glDisable (GL_LIGHTING); + glDisable (GL_CULL_FACE); + glDisable (GL_FOG); + + if (!in_scene_p) + glDisable (GL_DEPTH_TEST); + + /* Each matrix mode has its own stack, so we need to push/pop + them separately. */ - glPushAttrib (GL_TRANSFORM_BIT | /* for matrix contents */ - GL_ENABLE_BIT | /* for various glDisable calls */ - GL_CURRENT_BIT | /* for glColor3f() */ - GL_LIST_BIT); /* for glListBase() */ + glMatrixMode(GL_PROJECTION); + glPushMatrix(); { # ifdef DEBUG - check_gl_error ("glPushAttrib"); + check_gl_error ("glPushMatrix"); # endif + if (!in_scene_p) + glLoadIdentity(); - /* disable lighting and texturing when drawing bitmaps! - (glPopAttrib() restores these.) - */ - glDisable (GL_TEXTURE_2D); - glDisable (GL_LIGHTING); - glDisable (GL_BLEND); - glDisable (GL_DEPTH_TEST); - glDisable (GL_CULL_FACE); - - /* glPopAttrib() does not restore matrix changes, so we must - push/pop the matrix stacks to be non-intrusive there. - */ - glMatrixMode(GL_PROJECTION); + glMatrixMode(GL_MODELVIEW); glPushMatrix(); { # ifdef DEBUG check_gl_error ("glPushMatrix"); # endif - glLoadIdentity(); - /* Each matrix mode has its own stack, so we need to push/pop - them separately. */ - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - { - unsigned int i; - int x2 = x; - Bool sub_p = False; + if (!in_scene_p) + { + int rot = (int) current_device_rotation(); + while (rot <= -180) rot += 360; + while (rot > 180) rot -= 360; + + glLoadIdentity(); + glViewport (0, 0, window_width, window_height); + glOrtho (0, window_width, 0, window_height, -1, 1); + + if (rot > 135 || rot < -135) /* 180 */ + { + glTranslatef (window_width, window_height, 0); + glRotatef (180, 0, 0, 1); + } + else if (rot > 45) /* 90 */ + { + glTranslatef (window_width, 0, 0); + glRotatef (90, 0, 0, 1); + } + else if (rot < -45) /* 270 */ + { + glTranslatef(0, window_height, 0); + glRotatef (-90, 0, 0, 1); + } + } # ifdef DEBUG - check_gl_error ("glPushMatrix"); + check_gl_error ("glOrtho"); # endif - glLoadIdentity(); - gluOrtho2D (0, window_width, 0, window_height); -# ifdef DEBUG - check_gl_error ("gluOrtho2D"); -# endif + /* Let's always dropshadow the FPS and Title text. */ + if (! in_scene_p) + clear_background_p = True; - if (clear_background_p) - { - int w, h; - int lh = font->ascent + font->descent; - w = string_width (font, string, &h); - glColor3f (0, 0, 0); - glRecti (x - font->descent, - y + lh, - x + w + 2*font->descent, - y + lh - h - font->descent); - glColor3f (1, 1, 1); - } - /* draw the text */ - glRasterPos2f (x, y); -/* glListBase (font_dlist);*/ - for (i = 0; i < strlen(string); i++) + /* draw the text */ + + glTranslatef (x, y, 0); + + { + const XPoint offsets[] = {{ -1, -1 }, + { -1, 1 }, + { 1, 1 }, + { 1, -1 }, + { 0, 0 }}; + int i; + + glColor3f (0, 0, 0); + for (i = 0; i < countof(offsets); i++) { - unsigned char c = (unsigned char) string[i]; - if (c == '\n') - { - glRasterPos2f (x, (y -= line_height)); - x2 = x; - } - else if (c == '\t') - { - x2 -= x; - x2 = ((x2 + tabs) / tabs) * tabs; /* tab to tab stop */ - x2 += x; - glRasterPos2f (x2, y); - } - else if (c == '[' && (isdigit (string[i+1]))) - { - sub_p = True; - glRasterPos2f (x2, (y -= sub_shift)); - } - else if (c == ']' && sub_p) - { - sub_p = False; - glRasterPos2f (x2, (y += sub_shift)); - } - else - { -/* glCallLists (s - string, GL_UNSIGNED_BYTE, string);*/ - glCallList (font_dlist + (int)(c)); - x2 += (font->per_char - ? font->per_char[c - font->min_char_or_byte2].width - : font->min_bounds.width); - } + if (! clear_background_p) + i = countof(offsets)-1; + if (offsets[i].x == 0) + glColor4fv (color); + + glPushMatrix(); + glTranslatef (offsets[i].x, offsets[i].y, 0); + print_texture_string (data, string); + glPopMatrix(); } + } + # ifdef DEBUG - check_gl_error ("print_gl_string"); + check_gl_error ("print_texture_string"); # endif - } - glPopMatrix(); } - glMatrixMode(GL_PROJECTION); glPopMatrix(); } - glPopAttrib(); -# ifdef DEBUG - check_gl_error ("glPopAttrib"); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + + if (tex_p) glEnable (GL_TEXTURE_2D); else glDisable (GL_TEXTURE_2D); + if (texs_p) glEnable (GL_TEXTURE_GEN_S);/*else glDisable(GL_TEXTURE_GEN_S);*/ + if (text_p) glEnable (GL_TEXTURE_GEN_T);/*else glDisable(GL_TEXTURE_GEN_T);*/ + if (blend_p) glEnable (GL_BLEND); else glDisable (GL_BLEND); + if (light_p) glEnable (GL_LIGHTING); /*else glDisable (GL_LIGHTING);*/ + if (depth_p) glEnable (GL_DEPTH_TEST); else glDisable (GL_DEPTH_TEST); + if (cull_p) glEnable (GL_CULL_FACE); /*else glDisable (GL_CULL_FACE);*/ + if (fog_p) glEnable (GL_FOG); /*else glDisable (GL_FOG);*/ + + if (!in_scene_p) + glViewport (ovp[0], ovp[1], ovp[2], ovp[3]); + + glBlendFunc (GL_SRC_ALPHA, oblend); + +# ifndef HAVE_JWZGLES + glPolygonMode (GL_FRONT, opoly[0]); # endif glMatrixMode(GL_MODELVIEW);