http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.31.tar.gz
[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 extern void clear_gl_error (void);
25 extern void check_gl_error (const char *type);
26
27 static int fps_text_x = 10;
28 static int fps_text_y = 10;
29 static int fps_ascent, fps_descent;
30 static int fps_sample_frames = 10;
31 static GLuint font_dlist;
32 static Bool fps_clear_p = False;
33
34 static void
35 fps_init (ModeInfo *mi)
36 {
37   const char *font = get_string_resource ("fpsFont", "Font");
38   XFontStruct *f;
39   Font id;
40   int first, last;
41
42   fps_clear_p = get_boolean_resource ("fpsSolid", "FPSSolid");
43
44   if (!font) font = "-*-courier-bold-r-normal-*-180-*";
45   f = XLoadQueryFont(mi->dpy, font);
46   if (!f) f = XLoadQueryFont(mi->dpy, "fixed");
47
48   id = f->fid;
49   first = f->min_char_or_byte2;
50   last = f->max_char_or_byte2;
51   
52   clear_gl_error ();
53   font_dlist = glGenLists ((GLuint) last+1);
54   check_gl_error ("glGenLists");
55
56   fps_ascent = f->ascent;
57   fps_descent = f->descent;
58
59   if (get_boolean_resource ("fpsTop", "FPSTop"))
60     fps_text_y = - (f->ascent + 10);
61
62   glXUseXFont(id, first, last-first+1, font_dlist + first);
63   check_gl_error ("glXUseXFont");
64 }
65
66
67 static void
68 fps_print_string (ModeInfo *mi, GLfloat x, GLfloat y, const char *string)
69 {
70   int i;
71   /* save the current state */
72   /* note: could be expensive! */
73
74   if (y < 0)
75     y = mi->xgwa.height + y;
76
77   clear_gl_error ();
78   glPushAttrib(GL_ALL_ATTRIB_BITS);
79   {
80     check_gl_error ("glPushAttrib");
81
82     /* disable lighting and texturing when drawing bitmaps!
83        (glPopAttrib() restores these, I believe.)
84      */
85     glDisable(GL_TEXTURE_2D);
86     glDisable(GL_LIGHTING);
87     glDisable(GL_BLEND);
88     glDisable(GL_DEPTH_TEST);
89
90     /* glPopAttrib() does not restore matrix changes, so we must
91        push/pop the matrix stacks to be non-intrusive there.
92      */
93     glMatrixMode(GL_PROJECTION);
94     glPushMatrix();
95     {
96       check_gl_error ("glPushMatrix");
97       glLoadIdentity();
98
99       /* Each matrix mode has its own stack, so we need to push/pop
100          them separately. */
101       glMatrixMode(GL_MODELVIEW);
102       glPushMatrix();
103       {
104         check_gl_error ("glPushMatrix");
105         glLoadIdentity();
106
107         gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
108         check_gl_error ("gluOrtho2D");
109
110         /* clear the background */
111         if (fps_clear_p)
112           {
113             glColor3f (0, 0, 0);
114             glRecti (x, y - fps_descent,
115                      mi->xgwa.width - x,
116                      y + fps_ascent + fps_descent);
117           }
118
119         /* draw the text */
120         glColor3f (1, 1, 1);
121         glRasterPos2f (x, y);
122         for (i = 0; i < strlen(string); i++)
123           glCallList (font_dlist + (int)string[i]);
124
125         check_gl_error ("fps_print_string");
126       }
127       glPopMatrix();
128     }
129     glMatrixMode(GL_PROJECTION);
130     glPopMatrix();
131
132   }
133   /* clean up after our state changes */
134   glPopAttrib();
135   check_gl_error ("glPopAttrib");
136 }
137
138
139 void
140 do_fps (ModeInfo *mi)
141 {
142   /* every N frames, get the time and use it to get the frames per second */
143   static int frame_counter = -1;
144   static double oldtime = 0; /* time in usecs, as a double */
145   static double newtime = 0;
146
147   static char msg [1024] = { 0, };
148
149   if (frame_counter == -1)
150     {
151       fps_init (mi);
152       frame_counter = fps_sample_frames;
153     }
154
155   if (frame_counter++ == fps_sample_frames)
156     {
157       double fps;
158       struct timeval now;
159 # ifdef GETTIMEOFDAY_TWO_ARGS
160       struct timezone tzp;
161       gettimeofday(&now, &tzp);
162 # else
163       gettimeofday(&now);
164 # endif
165
166       oldtime = newtime;
167       newtime = now.tv_sec + ((double) now.tv_usec * 0.000001);
168
169       fps = fps_sample_frames / (newtime - oldtime);
170
171       if (fps < 0.0001)
172         {
173           strcpy(msg, "FPS: (accumulating...)");
174         }
175       else
176         {
177           sprintf(msg, "FPS: %.02f", fps);
178
179           if (mi->pause != 0)
180             {
181               char buf[40];
182               sprintf(buf, "%f", mi->pause / 1000000.0); /* FTSO C */
183               while(*buf && buf[strlen(buf)-1] == '0')
184                 buf[strlen(buf)-1] = 0;
185               if (buf[strlen(buf)-1] == '.')
186                 buf[strlen(buf)-1] = 0;
187               sprintf(msg + strlen(msg), " (including %s sec/frame delay)",
188                       buf);
189             }
190         }
191
192       frame_counter = 0;
193     }
194
195   fps_print_string (mi, fps_text_x, fps_text_y, msg);
196 }