From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / hacks / glx / glxfonts.c
1 /* glxfonts, Copyright (c) 2001-2014 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  *
11  * Draws 2D text over the GL scene, e.g., the FPS displays.
12  * Also billboarding.
13  * The lower-level character rendering code is in texfont.c.
14  */
15
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <ctype.h>
24
25 #ifdef HAVE_COCOA
26 # include "jwxyz.h"
27 /*# include <AGL/agl.h>*/
28 #else
29 # include <GL/glx.h>
30 # include <GL/glu.h>
31 #endif
32
33 #ifdef HAVE_JWZGLES
34 # include "jwzgles.h"
35 #endif /* HAVE_JWZGLES */
36
37 #include "resources.h"
38 #include "glxfonts.h"
39 #include "texfont.h"
40 #include "fps.h"
41
42
43 /* These are in xlock-gl.c */
44 extern void clear_gl_error (void);
45 extern void check_gl_error (const char *type);
46
47 /* screenhack.h */
48 extern char *progname;
49
50
51 #undef DEBUG  /* Defining this causes check_gl_error() to be called inside
52                  time-critical sections, which could slow things down (since
53                  it might result in a round-trip, and stall of the pipeline.)
54                */
55
56 #undef countof
57 #define countof(x) (sizeof((x))/sizeof((*x)))
58
59
60 /* Draws the string on the window at the given pixel position.
61    Newlines and tab stops are honored.
62    Any numbers inside [] will be rendered as a subscript.
63    Assumes the font has been loaded as with load_texture_font().
64
65    If width and height are 0, then instead the text is placed
66    into the 3D scene at the origin, billboarded to face the
67    viewer.
68  */
69 void
70 print_gl_string (Display *dpy,
71                  texture_font_data *data,
72                  int window_width, int window_height,
73                  GLfloat x, GLfloat y,
74                  const char *string,
75                  Bool clear_background_p)
76 {
77   Bool in_scene_p = (window_width == 0);
78
79   int line_height = 0;
80   int lines = 0;
81   const char *c;
82   GLfloat color[4];
83
84   Bool tex_p   = glIsEnabled (GL_TEXTURE_2D);
85   Bool texs_p  = glIsEnabled (GL_TEXTURE_GEN_S);
86   Bool text_p  = glIsEnabled (GL_TEXTURE_GEN_T);
87   Bool light_p = glIsEnabled (GL_LIGHTING);
88   Bool blend_p = glIsEnabled (GL_BLEND);
89   Bool depth_p = glIsEnabled (GL_DEPTH_TEST);
90   Bool cull_p  = glIsEnabled (GL_CULL_FACE);
91   Bool fog_p   = glIsEnabled (GL_FOG);
92   GLint oblend;
93   GLint ovp[4];
94
95 #  ifndef HAVE_JWZGLES
96   GLint opoly[2];
97   glGetIntegerv (GL_POLYGON_MODE, opoly);
98 #  endif
99
100   if (!in_scene_p)
101     glGetIntegerv (GL_VIEWPORT, ovp);
102
103   glGetIntegerv (GL_BLEND_DST, &oblend);
104   glGetFloatv (GL_CURRENT_COLOR, color);
105
106   for (c = string; *c; c++)
107     if (*c == '\n') lines++;
108
109   texture_string_width (data, "m", &line_height);
110   y -= line_height;
111
112
113   glEnable (GL_TEXTURE_2D);
114   glEnable (GL_BLEND);
115   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
116   glPolygonMode (GL_FRONT, GL_FILL);
117
118   glDisable (GL_TEXTURE_GEN_S);
119   glDisable (GL_TEXTURE_GEN_T);
120   glDisable (GL_LIGHTING);
121   glDisable (GL_CULL_FACE);
122   glDisable (GL_FOG);
123
124   if (!in_scene_p)
125     glDisable (GL_DEPTH_TEST);
126
127   /* Each matrix mode has its own stack, so we need to push/pop
128      them separately.
129    */
130   glMatrixMode(GL_PROJECTION);
131   glPushMatrix();
132   {
133 # ifdef DEBUG
134     check_gl_error ("glPushMatrix");
135 # endif
136     if (!in_scene_p)
137       glLoadIdentity();
138
139     glMatrixMode(GL_MODELVIEW);
140     glPushMatrix();
141     {
142 # ifdef DEBUG
143       check_gl_error ("glPushMatrix");
144 # endif
145
146       if (!in_scene_p)
147         {
148           int rot = (int) current_device_rotation();
149           while (rot <= -180) rot += 360;
150           while (rot >   180) rot -= 360;
151
152           glLoadIdentity();
153           glViewport (0, 0, window_width, window_height);
154           glOrtho (0, window_width, 0, window_height, -1, 1);
155
156           if (rot > 135 || rot < -135)          /* 180 */
157             {
158               glTranslatef (window_width, window_height, 0);
159               glRotatef (180, 0, 0, 1);
160             }
161           else if (rot > 45)                    /* 90 */
162             {
163               glTranslatef (window_width, 0, 0);
164               glRotatef (90, 0, 0, 1);
165             }
166           else if (rot < -45)                   /* 270 */
167             {
168               glTranslatef(0, window_height, 0);
169               glRotatef (-90, 0, 0, 1);
170             }
171         }
172
173 # ifdef DEBUG
174       check_gl_error ("glOrtho");
175 # endif
176
177       /* Let's always dropshadow the FPS and Title text. */
178       if (! in_scene_p)
179         clear_background_p = True;
180
181
182       /* draw the text */
183
184       glTranslatef (x, y, 0);
185
186       {
187         const XPoint offsets[] = {{ -1, -1 },
188                                   { -1,  1 },
189                                   {  1,  1 },
190                                   {  1, -1 },
191                                   {  0,  0 }};
192         int i;
193
194         glColor3f (0, 0, 0);
195         for (i = 0; i < countof(offsets); i++)
196           {
197             if (! clear_background_p)
198               i = countof(offsets)-1;
199             if (offsets[i].x == 0)
200               glColor4fv (color);
201
202             glPushMatrix();
203             glTranslatef (offsets[i].x, offsets[i].y, 0);
204             print_texture_string (data, string);
205             glPopMatrix();
206           }
207       }
208
209 # ifdef DEBUG
210       check_gl_error ("print_texture_string");
211 # endif
212     }
213     glPopMatrix();
214   }
215   glMatrixMode(GL_PROJECTION);
216   glPopMatrix();
217
218   if (tex_p)   glEnable (GL_TEXTURE_2D); else glDisable (GL_TEXTURE_2D);
219   if (texs_p)  glEnable (GL_TEXTURE_GEN_S);/*else glDisable(GL_TEXTURE_GEN_S);*/
220   if (text_p)  glEnable (GL_TEXTURE_GEN_T);/*else glDisable(GL_TEXTURE_GEN_T);*/
221   if (blend_p) glEnable (GL_BLEND); else glDisable (GL_BLEND);
222   if (light_p) glEnable (GL_LIGHTING); /*else glDisable (GL_LIGHTING);*/
223   if (depth_p) glEnable (GL_DEPTH_TEST); else glDisable (GL_DEPTH_TEST);
224   if (cull_p)  glEnable (GL_CULL_FACE); /*else glDisable (GL_CULL_FACE);*/
225   if (fog_p)   glEnable (GL_FOG); /*else glDisable (GL_FOG);*/
226
227   if (!in_scene_p)
228     glViewport (ovp[0], ovp[1], ovp[2], ovp[3]);
229
230   glBlendFunc (GL_SRC_ALPHA, oblend);
231
232 # ifndef HAVE_JWZGLES
233   glPolygonMode (GL_FRONT, opoly[0]);
234 # endif
235
236   glMatrixMode(GL_MODELVIEW);
237 }