d38941e6a15dc83edd61fccea7fdaba0fdea65ac
[xscreensaver] / hacks / glx / glxfonts.c
1 /* glxfonts, Copyright (c) 2001-2006 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 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <ctype.h>
21
22 #ifdef HAVE_COCOA
23 # include "jwxyz.h"
24 # include <OpenGL/gl.h>
25 # include <OpenGL/glu.h>
26 # include <AGL/agl.h>
27 #else
28 # include <GL/glx.h>
29 # include <GL/glu.h>
30 #endif
31
32 #include "resources.h"
33 #include "glxfonts.h"
34
35 /* These are in xlock-gl.c */
36 extern void clear_gl_error (void);
37 extern void check_gl_error (const char *type);
38
39 /* screenhack.h */
40 extern char *progname;
41
42
43 /* Loads the font named by the X resource "res".
44    Returns an XFontStruct.
45    Also converts the font to a set of GL lists and returns the first list.
46 */
47 void
48 load_font (Display *dpy, char *res, XFontStruct **font_ret, GLuint *dlist_ret)
49 {
50   XFontStruct *f;
51
52   const char *font = get_string_resource (dpy, res, "Font");
53   const char *def1 = "-*-times-bold-r-normal-*-180-*";
54   const char *def2 = "fixed";
55   Font id;
56   int first, last;
57
58   if (!res || !*res) abort();
59   if (!font_ret && !dlist_ret) abort();
60
61   if (!font) font = def1;
62
63   f = XLoadQueryFont(dpy, font);
64   if (!f && !!strcmp (font, def1))
65     {
66       fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
67                progname, font, def1);
68       font = def1;
69       f = XLoadQueryFont(dpy, font);
70     }
71
72   if (!f && !!strcmp (font, def2))
73     {
74       fprintf (stderr, "%s: unable to load font \"%s\", using \"%s\"\n",
75                progname, font, def2);
76       font = def2;
77       f = XLoadQueryFont(dpy, font);
78     }
79
80   if (!f)
81     {
82       fprintf (stderr, "%s: unable to load fallback font \"%s\" either!\n",
83                progname, font);
84       exit (1);
85     }
86
87   id = f->fid;
88   first = f->min_char_or_byte2;
89   last = f->max_char_or_byte2;
90   
91
92 # ifndef HAVE_COCOA /* Xlib version */
93
94   if (dlist_ret)
95     {
96       clear_gl_error ();
97       *dlist_ret = glGenLists ((GLuint) last+1);
98       check_gl_error ("glGenLists");
99       glXUseXFont(id, first, last-first+1, *dlist_ret + first);
100       check_gl_error ("glXUseXFont");
101     }
102
103 # else  /* HAVE_COCOA */
104
105   {
106     int afid, face, size;
107     afid = jwxyz_font_info (id, &size, &face);
108
109     if (dlist_ret)
110       {
111         clear_gl_error ();
112         *dlist_ret = glGenLists ((GLuint) last+1);
113         check_gl_error ("glGenLists");
114
115         AGLContext ctx = aglGetCurrentContext();
116         if (! aglUseFont (ctx, afid, face, size, 
117                           first, last-first+1, *dlist_ret + first)) {
118           check_gl_error ("aglUseFont");
119           abort();
120       }
121     }
122   }
123
124 # endif  /* HAVE_COCOA */
125
126   if (font_ret)
127     *font_ret = f;
128 }
129
130
131 /* Width of the string in pixels.
132  */
133 int
134 string_width (XFontStruct *f, const char *c)
135 {
136   int w = 0;
137   while (*c)
138     {
139       int cc = *((unsigned char *) c);
140       w += (f->per_char
141             ? f->per_char[cc-f->min_char_or_byte2].rbearing
142             : f->min_bounds.rbearing);
143       c++;
144     }
145   return w;
146 }
147
148
149 /* Draws the string on the window at the given pixel position.
150    Newlines and tab stops are honored.
151    Any text inside [] will be rendered as a subscript.
152    Assumes the font has been loaded as with load_font().
153  */
154 void
155 print_gl_string (Display *dpy,
156                  XFontStruct *font,
157                  GLuint font_dlist,
158                  int window_width, int window_height,
159                  GLfloat x, GLfloat y,
160                  const char *string)
161 {
162   GLfloat line_height = font->ascent + font->descent;
163   GLfloat sub_shift = (line_height * 0.3);
164   int cw = string_width (font, "m");
165   int tabs = cw * 7;
166
167   y -= line_height;
168
169   glPushAttrib (GL_TRANSFORM_BIT |  /* for matrix contents */
170                 GL_ENABLE_BIT);     /* for various glDisable calls */
171   glDisable (GL_LIGHTING);
172   glDisable (GL_DEPTH_TEST);
173   glDisable (GL_TEXTURE_2D);
174   {
175     glMatrixMode(GL_PROJECTION);
176     glPushMatrix();
177     {
178       glLoadIdentity();
179
180       glMatrixMode(GL_MODELVIEW);
181       glPushMatrix();
182       {
183         unsigned int i;
184         int x2 = x;
185         Bool sub_p = False;
186         glLoadIdentity();
187
188         gluOrtho2D (0, window_width, 0, window_height);
189
190         glRasterPos2f (x, y);
191         for (i = 0; i < strlen(string); i++)
192           {
193             char c = string[i];
194             if (c == '\n')
195               {
196                 glRasterPos2f (x, (y -= line_height));
197                 x2 = x;
198               }
199             else if (c == '\t')
200               {
201                 x2 -= x;
202                 x2 = ((x2 + tabs) / tabs) * tabs;  /* tab to tab stop */
203                 x2 += x;
204                 glRasterPos2f (x2, y);
205               }
206             else if (c == '[' && (isdigit (string[i+1])))
207               {
208                 sub_p = True;
209                 glRasterPos2f (x2, (y -= sub_shift));
210               }
211             else if (c == ']' && sub_p)
212               {
213                 sub_p = False;
214                 glRasterPos2f (x2, (y += sub_shift));
215               }
216             else
217               {
218                 glCallList (font_dlist + (int)(c));
219                 x2 += (font->per_char
220                        ? font->per_char[c - font->min_char_or_byte2].width
221                        : font->min_bounds.width);
222               }
223           }
224       }
225       glPopMatrix();
226     }
227     glMatrixMode(GL_PROJECTION);
228     glPopMatrix();
229   }
230   glPopAttrib();
231
232   glMatrixMode(GL_MODELVIEW);
233 }