ftp://updates.redhat.com/enterprise/2.1AS/en/os/SRPMS/xscreensaver-3.33-4.rhel21...
[xscreensaver] / hacks / glx / fps.c
1 /* tube, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
2  * Utility function to draw a frames-per-second display.
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 #include "config.h"
14 #include <stdlib.h>
15 #include <stdio.h>
16
17 #include "screenhack.h"
18 #include "xlockmoreI.h"
19
20 #include <GL/gl.h>
21 #include <GL/glu.h>
22 #include <GL/glx.h>
23
24 #undef DEBUG  /* Defining this causes check_gl_error() to be called inside
25                  time-critical sections, which could slow things down (since
26                  it might result in a round-trip, and stall of the pipeline.)
27                */
28
29 extern void clear_gl_error (void);
30 extern void check_gl_error (const char *type);
31
32 static int fps_text_x = 10;
33 static int fps_text_y = 10;
34 static int fps_ascent, fps_descent;
35 static int fps_sample_frames = 10;
36 static GLuint font_dlist;
37 static Bool fps_clear_p = False;
38
39 static void
40 fps_init (ModeInfo *mi)
41 {
42   const char *font = get_string_resource ("fpsFont", "Font");
43   XFontStruct *f;
44   Font id;
45   int first, last;
46
47   fps_clear_p = get_boolean_resource ("fpsSolid", "FPSSolid");
48
49   if (!font) font = "-*-courier-bold-r-normal-*-180-*";
50   f = XLoadQueryFont(mi->dpy, font);
51   if (!f) f = XLoadQueryFont(mi->dpy, "fixed");
52
53   id = f->fid;
54   first = f->min_char_or_byte2;
55   last = f->max_char_or_byte2;
56   
57   clear_gl_error ();
58   font_dlist = glGenLists ((GLuint) last+1);
59   check_gl_error ("glGenLists");
60
61   fps_ascent = f->ascent;
62   fps_descent = f->descent;
63
64   if (get_boolean_resource ("fpsTop", "FPSTop"))
65     fps_text_y = - (f->ascent + 10);
66
67   glXUseXFont(id, first, last-first+1, font_dlist + first);
68   check_gl_error ("glXUseXFont");
69 }
70
71
72 static void
73 fps_print_string (ModeInfo *mi, GLfloat x, GLfloat y, const char *string)
74 {
75   int i;
76   /* save the current state */
77   /* note: could be expensive! */
78
79   if (y < 0)
80     y = mi->xgwa.height + y;
81
82   clear_gl_error ();
83
84   /* Sadly, this causes a stall of the graphics pipeline (as would the
85      equivalent calls to glGet*.)  But there's no way around this, short
86      of having each caller set up the specific display matrix we need
87      here, which would kind of defeat the purpose of centralizing this
88      code in one file.
89    */
90   glPushAttrib(GL_TRANSFORM_BIT |  /* for matrix contents */
91                GL_ENABLE_BIT |     /* for various glDisable calls */
92                GL_CURRENT_BIT |    /* for glColor3f() */
93                GL_LIST_BIT);       /* for glListBase() */
94   {
95 # ifdef DEBUG
96     check_gl_error ("glPushAttrib");
97 # endif
98
99     /* disable lighting and texturing when drawing bitmaps!
100        (glPopAttrib() restores these, I believe.)
101      */
102     glDisable(GL_TEXTURE_2D);
103     glDisable(GL_LIGHTING);
104     glDisable(GL_BLEND);
105     glDisable(GL_DEPTH_TEST);
106
107     /* glPopAttrib() does not restore matrix changes, so we must
108        push/pop the matrix stacks to be non-intrusive there.
109      */
110     glMatrixMode(GL_PROJECTION);
111     glPushMatrix();
112     {
113 # ifdef DEBUG
114       check_gl_error ("glPushMatrix");
115 # endif
116       glLoadIdentity();
117
118       /* Each matrix mode has its own stack, so we need to push/pop
119          them separately. */
120       glMatrixMode(GL_MODELVIEW);
121       glPushMatrix();
122       {
123 # ifdef DEBUG
124         check_gl_error ("glPushMatrix");
125 # endif
126         glLoadIdentity();
127
128         gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
129 # ifdef DEBUG
130         check_gl_error ("gluOrtho2D");
131 # endif
132
133         /* clear the background */
134         if (fps_clear_p)
135           {
136             glColor3f (0, 0, 0);
137             glRecti (x, y - fps_descent,
138                      mi->xgwa.width - x,
139                      y + fps_ascent + fps_descent);
140           }
141
142         /* draw the text */
143         glColor3f (1, 1, 1);
144         glRasterPos2f (x, y);
145         glListBase (font_dlist);
146         glCallLists (strlen(string), GL_UNSIGNED_BYTE, string);
147
148 # ifdef DEBUG
149         check_gl_error ("fps_print_string");
150 # endif
151       }
152       glPopMatrix();
153     }
154     glMatrixMode(GL_PROJECTION);
155     glPopMatrix();
156
157   }
158   /* clean up after our state changes */
159   glPopAttrib();
160 # ifdef DEBUG
161   check_gl_error ("glPopAttrib");
162 # endif
163 }
164
165
166 void
167 do_fps (ModeInfo *mi)
168 {
169   /* every N frames, get the time and use it to get the frames per second */
170   static int frame_counter = -1;
171   static double oldtime = 0; /* time in usecs, as a double */
172   static double newtime = 0;
173
174   static char msg [1024] = { 0, };
175
176   if (frame_counter == -1)
177     {
178       fps_init (mi);
179       frame_counter = fps_sample_frames;
180     }
181
182   if (frame_counter++ == fps_sample_frames)
183     {
184       double fps;
185       struct timeval now;
186 # ifdef GETTIMEOFDAY_TWO_ARGS
187       struct timezone tzp;
188       gettimeofday(&now, &tzp);
189 # else
190       gettimeofday(&now);
191 # endif
192
193       oldtime = newtime;
194       newtime = now.tv_sec + ((double) now.tv_usec * 0.000001);
195
196       fps = fps_sample_frames / (newtime - oldtime);
197
198       if (fps < 0.0001)
199         {
200           strcpy(msg, "FPS: (accumulating...)");
201         }
202       else
203         {
204           sprintf(msg, "FPS: %.02f", fps);
205
206           if (mi->pause != 0)
207             {
208               char buf[40];
209               sprintf(buf, "%f", mi->pause / 1000000.0); /* FTSO C */
210               while(*buf && buf[strlen(buf)-1] == '0')
211                 buf[strlen(buf)-1] = 0;
212               if (buf[strlen(buf)-1] == '.')
213                 buf[strlen(buf)-1] = 0;
214               sprintf(msg + strlen(msg), " (including %s sec/frame delay)",
215                       buf);
216             }
217         }
218
219       frame_counter = 0;
220     }
221
222   fps_print_string (mi, fps_text_x, fps_text_y, msg);
223 }