1 /* xlock-gl.c --- xscreensaver compatibility layer for xlockmore GL modules.
2 * xscreensaver, Copyright (c) 1997, 1998, 1999 Jamie Zawinski <jwz@jwz.org>
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
12 * This file, along with xlockmore.h, make it possible to compile an xlockmore
13 * GL module into a standalone program, and thus use it with xscreensaver.
14 * By Jamie Zawinski <jwz@jwz.org> on 31-May-97.
18 #include "screenhack.h"
19 #include "xlockmoreI.h"
25 /* Gag -- we use this to turn X errors from glXCreateContext() into
26 something that will actually make sense to the user.
28 static XErrorHandler orig_ehandler = 0;
29 static Bool got_error = 0;
32 BadValue_ehandler (Display *dpy, XErrorEvent *error)
34 if (error->error_code == BadValue)
40 return orig_ehandler (dpy, error);
45 init_GL(ModeInfo * mi)
47 Display *dpy = mi->dpy;
48 Window window = mi->window;
49 Screen *screen = mi->xgwa.screen;
50 Visual *visual = mi->xgwa.visual;
51 GLXContext glx_context = 0;
52 XVisualInfo vi_in, *vi_out;
55 vi_in.screen = screen_number (screen);
56 vi_in.visualid = XVisualIDFromVisual (visual);
57 vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
59 if (! vi_out) abort ();
63 orig_ehandler = XSetErrorHandler (BadValue_ehandler);
64 glx_context = glXCreateContext (dpy, vi_out, 0, GL_TRUE);
66 XSetErrorHandler (orig_ehandler);
71 XFree((char *) vi_out);
75 fprintf(stderr, "%s: couldn't create GL context for visual 0x%x.\n",
76 progname, (unsigned int) XVisualIDFromVisual (visual));
80 glXMakeCurrent (dpy, window, glx_context);
83 GLboolean rgba_mode = 0;
84 glGetBooleanv(GL_RGBA_MODE, &rgba_mode);
87 glIndexi (WhitePixelOfScreen (screen));
88 glClearIndex (BlackPixelOfScreen (screen));
92 /* GLXContext is already a pointer type.
93 Why this function returns a pointer to a pointer, I have no idea...
96 GLXContext *ptr = (GLXContext *) malloc(sizeof(GLXContext));
105 /* clear away any lingering error codes */
107 clear_gl_error (void)
109 while (glGetError() != GL_NO_ERROR)
113 /* report a GL error. */
115 check_gl_error (const char *type)
120 switch ((i = glGetError())) {
121 case GL_NO_ERROR: return;
122 case GL_INVALID_ENUM: e = "invalid enum"; break;
123 case GL_INVALID_VALUE: e = "invalid value"; break;
124 case GL_INVALID_OPERATION: e = "invalid operation"; break;
125 case GL_STACK_OVERFLOW: e = "stack overflow"; break;
126 case GL_STACK_UNDERFLOW: e = "stack underflow"; break;
127 case GL_OUT_OF_MEMORY: e = "out of memory"; break;
128 #ifdef GL_TABLE_TOO_LARGE_EXT
129 case GL_TABLE_TOO_LARGE_EXT: e = "table too large"; break;
131 #ifdef GL_TEXTURE_TOO_LARGE_EXT
132 case GL_TEXTURE_TOO_LARGE_EXT: e = "texture too large"; break;
135 e = buf; sprintf (buf, "unknown error %d", (int) i); break;
137 fprintf (stderr, "%s: %s error: %s\n", progname, type, e);
144 /* Frames-per-second statistics */
146 static int fps_text_x = 10;
147 static int fps_text_y = 10;
148 static int fps_sample_frames = 10;
149 static GLuint font_dlist;
152 fps_init (ModeInfo *mi)
154 const char *font = get_string_resource ("fpsFont", "Font");
159 if (!font) font = "-*-courier-bold-r-normal-*-180-*";
160 f = XLoadQueryFont(mi->dpy, font);
161 if (!f) f = XLoadQueryFont(mi->dpy, "fixed");
164 first = f->min_char_or_byte2;
165 last = f->max_char_or_byte2;
168 font_dlist = glGenLists ((GLuint) last+1);
169 check_gl_error ("glGenLists");
171 if (get_boolean_resource ("fpsTop", "FPSTop"))
172 fps_text_y = - (f->ascent + 10);
174 glXUseXFont(id, first, last-first+1, font_dlist + first);
175 check_gl_error ("glXUseXFont");
180 fps_print_string (ModeInfo *mi, GLfloat x, GLfloat y, const char *string)
183 /* save the current state */
184 /* note: could be expensive! */
187 y = mi->xgwa.height + y;
190 glPushAttrib(GL_ALL_ATTRIB_BITS);
192 check_gl_error ("glPushAttrib");
194 /* disable lighting and texturing when drawing bitmaps!
195 (glPopAttrib() restores these, I believe.)
197 glDisable(GL_TEXTURE_2D);
198 glDisable(GL_LIGHTING);
201 /* glPopAttrib() does not restore matrix changes, so we must
202 push/pop the matrix stacks to be non-intrusive there.
204 glMatrixMode(GL_PROJECTION);
207 check_gl_error ("glPushMatrix");
210 /* Each matrix mode has its own stack, so we need to push/pop
212 glMatrixMode(GL_MODELVIEW);
215 check_gl_error ("glPushMatrix");
218 gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
219 check_gl_error ("gluOrtho2D");
223 glRasterPos2f (x, y);
224 for (i = 0; i < strlen(string); i++)
225 glCallList (font_dlist + (int)string[i]);
227 check_gl_error ("fps_print_string");
231 glMatrixMode(GL_PROJECTION);
235 /* clean up after our state changes */
237 check_gl_error ("glPopAttrib");
242 do_fps (ModeInfo *mi)
244 /* every N frames, get the time and use it to get the frames per second */
245 static int frame_counter = -1;
246 static double oldtime = 0; /* time in usecs, as a double */
247 static double newtime = 0;
249 static char msg [1024] = { 0, };
251 if (frame_counter == -1)
254 frame_counter = fps_sample_frames;
257 if (frame_counter++ == fps_sample_frames)
261 # ifdef GETTIMEOFDAY_TWO_ARGS
263 gettimeofday(&now, &tzp);
269 newtime = now.tv_sec + ((double) now.tv_usec * 0.000001);
271 fps = fps_sample_frames / (newtime - oldtime);
275 strcpy(msg, "FPS: (accumulating...)");
279 sprintf(msg, "FPS: %.02f", fps);
284 sprintf(buf, "%f", mi->pause / 1000000.0); /* FTSO C */
285 while(*buf && buf[strlen(buf)-1] == '0')
286 buf[strlen(buf)-1] = 0;
287 if (buf[strlen(buf)-1] == '.')
288 buf[strlen(buf)-1] = 0;
289 sprintf(msg + strlen(msg), " (including %s sec/frame delay)",
297 fps_print_string (mi, fps_text_x, fps_text_y, msg);