http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / hacks / glx / glxfonts.c
1 /* glxfonts, Copyright (c) 2001-2004 Jamie Zawinski <jwz@jwz.org>
2  * Loads X11 fonts for use with OpenGL.
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13
14 #include "config.h"
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <ctype.h>
19 #include <GL/glx.h>
20 #include <GL/glu.h>
21 #include "resources.h"
22 #include "glxfonts.h"
23
24 /* These are in xlock-gl.c */
25 extern void clear_gl_error (void);
26 extern void check_gl_error (const char *type);
27
28 /* screenhack.h */
29 extern char *progname;
30
31
32 /* Loads the font named by the X resource "res".
33    Returns an XFontStruct.
34    Also converts the font to a set of GL lists and returns the first list.
35 */
36 void
37 load_font (Display *dpy, char *res, XFontStruct **font_ret, GLuint *dlist_ret)
38 {
39   const char *font = get_string_resource (res, "Font");
40   const char *def1 = "-*-times-bold-r-normal-*-180-*";
41   const char *def2 = "fixed";
42   XFontStruct *f;
43   Font id;
44   int first, last;
45
46   if (!res || !*res) abort();
47   if (!font_ret && !dlist_ret) abort();
48
49   if (!font) font = def1;
50
51   f = XLoadQueryFont(dpy, font);
52   if (!f && !!strcmp (font, def1))
53     {
54       fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
55                progname, font, def1);
56       font = def1;
57       f = XLoadQueryFont(dpy, font);
58     }
59
60   if (!f && !!strcmp (font, def2))
61     {
62       fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
63                progname, font, def2);
64       font = def2;
65       f = XLoadQueryFont(dpy, font);
66     }
67
68   if (!f)
69     {
70       fprintf (stderr, "%s: unable to load fallback font \"%s\" either!\n",
71                progname, font);
72       exit (1);
73     }
74
75   id = f->fid;
76   first = f->min_char_or_byte2;
77   last = f->max_char_or_byte2;
78   
79   if (dlist_ret)
80     {
81       clear_gl_error ();
82       *dlist_ret = glGenLists ((GLuint) last+1);
83       check_gl_error ("glGenLists");
84       glXUseXFont(id, first, last-first+1, *dlist_ret + first);
85       check_gl_error ("glXUseXFont");
86     }
87
88   if (font_ret)
89     *font_ret = f;
90 }
91
92
93 /* Width of the string in pixels.
94  */
95 int
96 string_width (XFontStruct *f, const char *c)
97 {
98   int w = 0;
99   while (*c)
100     {
101       int cc = *((unsigned char *) c);
102       w += (f->per_char
103             ? f->per_char[cc-f->min_char_or_byte2].rbearing
104             : f->min_bounds.rbearing);
105       c++;
106     }
107   return w;
108 }
109
110
111 /* Draws the string on the window at the given pixel position.
112    Newlines and tab stops are honored.
113    Any text inside [] will be rendered as a subscript.
114    Assumes the font has been loaded as with load_font().
115  */
116 void
117 print_gl_string (Display *dpy,
118                  XFontStruct *font,
119                  GLuint font_dlist,
120                  int window_width, int window_height,
121                  GLfloat x, GLfloat y,
122                  const char *string)
123 {
124   GLfloat line_height = font->ascent + font->descent;
125   GLfloat sub_shift = (line_height * 0.3);
126   int cw = string_width (font, "m");
127   int tabs = cw * 7;
128
129   y -= line_height;
130
131   glPushAttrib (GL_TRANSFORM_BIT |  /* for matrix contents */
132                 GL_ENABLE_BIT);     /* for various glDisable calls */
133   glDisable (GL_LIGHTING);
134   glDisable (GL_DEPTH_TEST);
135   glDisable (GL_TEXTURE_2D);
136   {
137     glMatrixMode(GL_PROJECTION);
138     glPushMatrix();
139     {
140       glLoadIdentity();
141
142       glMatrixMode(GL_MODELVIEW);
143       glPushMatrix();
144       {
145         unsigned int i;
146         int x2 = x;
147         Bool sub_p = False;
148         glLoadIdentity();
149
150         gluOrtho2D (0, window_width, 0, window_height);
151
152         glRasterPos2f (x, y);
153         for (i = 0; i < strlen(string); i++)
154           {
155             char c = string[i];
156             if (c == '\n')
157               {
158                 glRasterPos2f (x, (y -= line_height));
159                 x2 = x;
160               }
161             else if (c == '\t')
162               {
163                 x2 -= x;
164                 x2 = ((x2 + tabs) / tabs) * tabs;  /* tab to tab stop */
165                 x2 += x;
166                 glRasterPos2f (x2, y);
167               }
168             else if (c == '[' && (isdigit (string[i+1])))
169               {
170                 sub_p = True;
171                 glRasterPos2f (x2, (y -= sub_shift));
172               }
173             else if (c == ']' && sub_p)
174               {
175                 sub_p = False;
176                 glRasterPos2f (x2, (y += sub_shift));
177               }
178             else
179               {
180                 glCallList (font_dlist + (int)(c));
181                 x2 += (font->per_char
182                        ? font->per_char[c - font->min_char_or_byte2].width
183                        : font->min_bounds.width);
184               }
185           }
186       }
187       glPopMatrix();
188     }
189     glMatrixMode(GL_PROJECTION);
190     glPopMatrix();
191   }
192   glPopAttrib();
193
194   glMatrixMode(GL_MODELVIEW);
195 }