2
* Copyright (C) 2002 Tugrul Galatali <tugrul@galatali.com>
4
* driver.c is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 2 as
6
* published by the Free Software Foundation.
8
* driver.c is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program; if not, write to the Free Software
15
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
#include <sys/param.h>
29
#include <X11/keysym.h>
45
#include <X11/extensions/dpms.h>
54
extern const char *hack_name;
59
int rootWindow = False;
60
int glewInitialized = False;
62
int frameTime = 10000;
65
int frameTime = 33333;
71
void createWindow (int argc, char **argv)
73
XVisualInfo *visualInfo;
76
XStuff->screen_num = DefaultScreen (XStuff->display);
77
XStuff->rootWindow = RootWindow (XStuff->display, XStuff->screen_num);
79
if (rootWindow || XStuff->existingWindow) {
80
XWindowAttributes gwa;
85
XStuff->window = XStuff->existingWindow ? XStuff->existingWindow : XStuff->rootWindow;
87
XGetWindowAttributes (XStuff->display, XStuff->window, &gwa);
89
XStuff->windowWidth = gwa.width;
90
XStuff->windowHeight = gwa.height;
92
templ.screen = XStuff->screen_num;
93
templ.visualid = XVisualIDFromVisual (visual);
95
visualInfo = XGetVisualInfo (XStuff->display, VisualScreenMask | VisualIDMask, &templ, &outCount);
98
fprintf (stderr, "%s: can't get GL visual for window 0x%lx.\n", XStuff->commandLineName, (unsigned long)XStuff->window);
102
int attributeList[] = {
111
XSetWindowAttributes swa;
117
if (!(visualInfo = glXChooseVisual (XStuff->display, XStuff->screen_num, attributeList))) {
118
fprintf (stderr, "%s: can't open GL visual.\n", XStuff->commandLineName);
122
swa.colormap = XCreateColormap (XStuff->display, XStuff->rootWindow, visualInfo->visual, AllocNone);
123
swa.border_pixel = swa.background_pixel = swa.backing_pixel = BlackPixel (XStuff->display, XStuff->screen_num);
124
swa.event_mask = KeyPressMask | StructureNotifyMask;
126
XStuff->windowWidth = DisplayWidth (XStuff->display, XStuff->screen_num) / 3;
127
XStuff->windowHeight = DisplayHeight (XStuff->display, XStuff->screen_num) / 3;
130
XCreateWindow (XStuff->display, XStuff->rootWindow, 0, 0, XStuff->windowWidth, XStuff->windowHeight, 0, visualInfo->depth, InputOutput, visualInfo->visual,
131
CWBorderPixel | CWBackPixel | CWBackingPixel | CWColormap | CWEventMask, &swa);
133
hints.flags = USSize;
134
hints.width = XStuff->windowWidth;
135
hints.height = XStuff->windowHeight;
137
wmHints.flags = InputHint;
138
wmHints.input = True;
140
XmbSetWMProperties (XStuff->display, XStuff->window, hack_name, hack_name, argv, argc, &hints, &wmHints, NULL);
143
context = glXCreateContext (XStuff->display, visualInfo, 0, GL_TRUE);
145
fprintf (stderr, "%s: can't open GLX context.\n", XStuff->commandLineName);
149
if (!glXMakeCurrent (XStuff->display, XStuff->window, context)) {
150
fprintf (stderr, "%s: can't set GL context.\n", XStuff->commandLineName);
155
XMapWindow (XStuff->display, XStuff->window);
158
void clearBuffers() {
162
for (i = 0; i < 4; i++) {
163
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
164
glXSwapBuffers (XStuff->display, XStuff->window);
166
while (XPending (XStuff->display)) {
167
XNextEvent (XStuff->display, &event);
172
int deltaus(const struct timeval now, const struct timeval then) {
173
return (now.tv_sec - then.tv_sec) * 1000000 + now.tv_usec - then.tv_usec;
180
Atom XA_WM_PROTOCOLS = XInternAtom (XStuff->display, "WM_PROTOCOLS", False);
181
Atom XA_WM_DELETE_WINDOW = XInternAtom (XStuff->display, "WM_DELETE_WINDOW", False);
182
struct timeval cycleStart, now, fps_time;
187
XSetWMProtocols (XStuff->display, XStuff->window, &XA_WM_DELETE_WINDOW, 1);
193
if (glewInitialized) {
194
if ((vsync > 0) && GLXEW_SGI_swap_control) {
195
glXSwapIntervalSGI (vsync);
201
int dpmsAvailable = 0;
203
int event_number, error_number;
204
if (DPMSQueryExtension(XStuff->display, &event_number, &error_number)) {
205
if (DPMSCapable(XStuff->display)) {
212
gettimeofday (&cycleStart, NULL);
213
now = fps_time = cycleStart;
214
int frameTimeSoFar = 0;
216
int sinceLastDPMSPoll = 0;
220
sinceLastDPMSPoll = sinceLastDPMSPoll + frameTimeSoFar;
221
if (idleOnDPMS && dpmsAvailable && (sinceLastDPMSPoll > 1000000)) {
225
sinceLastDPMSPoll = 0;
228
if (DPMSInfo(XStuff->display, &state, &onoff)) {
229
if (onoff && (state != DPMSModeOn)) drawEnabled = 0;
232
// If the display isn't on, kick back and poll DPMS every second
240
hack_draw (XStuff, (double)now.tv_sec + now.tv_usec / 1000000.0f, frameTimeSoFar / 1000000.0f);
242
glXSwapBuffers (XStuff->display, XStuff->window);
249
if (now.tv_sec > fps_time.tv_sec) {
251
printf ("%.4f fps\n", fps / (deltaus(now, fps_time) / 1000000.0));
255
fps_time.tv_sec = now.tv_sec;
256
fps_time.tv_usec = now.tv_usec;
260
while (XPending (XStuff->display)) {
264
XNextEvent (XStuff->display, &event);
265
switch (event.type) {
266
case ConfigureNotify:
267
if ((int)XStuff->windowWidth != event.xconfigure.width || (int)XStuff->windowHeight != event.xconfigure.height) {
268
XStuff->windowWidth = event.xconfigure.width;
269
XStuff->windowHeight = event.xconfigure.height;
273
hack_reshape (XStuff);
278
XLookupString (&event.xkey, &c, 1, &keysym, 0);
285
gettimeofday (&fps_time, NULL);
289
if (c == 'q' || c == 'Q' || c == 3 || c == 27)
294
if (event.xclient.message_type == XA_WM_PROTOCOLS) {
295
if (event.xclient.data.l[0] == (int)XA_WM_DELETE_WINDOW) {
305
gettimeofday (&now, NULL);
306
frameTimeSoFar = deltaus(now, cycleStart);
309
while (frameTimeSoFar < frameTime) {
310
#ifdef HAVE_NANOSLEEP
311
struct timespec hundreth;
314
hundreth.tv_nsec = (frameTime - frameTimeSoFar) * 1000;
316
nanosleep (&hundreth, NULL);
318
usleep (frameTime - frameTimeSoFar);
321
gettimeofday (&now, NULL);
322
frameTimeSoFar = deltaus(now, cycleStart);
327
cycleStart.tv_usec += frameTime;
328
if (cycleStart.tv_usec > 1000000) {
330
cycleStart.tv_usec -= 1000000;
332
delta = deltaus(now, cycleStart);
333
} while (delta > frameTime);
340
void handle_global_opts (int c)
348
c = strtol_minmaxdef (optarg, 10, 0, 10000, 1, 100, "--maxfps: ");
350
frameTime = (c > 0) ? 1000000 / c : 0;
354
vsync = strtol_minmaxdef (optarg, 10, 0, 100, 1, 2, "--vsync: ");
358
fprintf (stderr, "Not compiled with GLEW, vsync not supported.\n");
363
idleOnDPMS = strtol_minmaxdef (optarg, 10, 0, 1, 0, 1, "--dpms: ");
365
#ifndef HAVE_DPMS_EXT
367
fprintf (stderr, "Not compiled with DPMS, idling on DPMS not supported.\n");
374
int strtol_minmaxdef (const char *optarg, const int base, const int min, const int max, const int type, const int def, const char *errmsg)
376
const int result = strtol (optarg, (char **)NULL, base);
380
fprintf (stderr, "%s %d < %d, using %d instead.\n", errmsg, result, min, type ? min : def);
383
return type ? min : def;
388
fprintf (stderr, "%s %d > %d, using %d instead.\n", errmsg, result, max, type ? max : def);
391
return type ? max : def;
397
void signalHandler (int sig)
402
int main (int argc, char *argv[])
405
char *display_name = NULL; /* Server to connect to */
408
XStuff = (xstuff_t *) malloc (sizeof (xstuff_t));
409
XStuff->commandLineName = argv[0];
411
srandom ((unsigned)time (NULL));
413
XStuff->existingWindow = 0;
414
for (i = 0; i < argc; i++) {
415
if (!strcmp (argv[i], "-window-id")) {
416
if ((argv[i + 1][0] == '0') && ((argv[i + 1][1] == 'x') || (argv[i + 1][1] == 'X'))) {
417
XStuff->existingWindow = strtol ((char *)(argv[i + 1] + 2), (char **)NULL, 16);
419
XStuff->existingWindow = strtol ((char *)(argv[i + 1]), (char **)NULL, 10);
422
for (j = i + 2; j < argc; j++) {
423
argv[j - 2] = argv[j];
432
hack_handle_opts (argc, argv);
434
XStuff->display = NULL;
437
memset ((void *)&sa, 0, sizeof (struct sigaction));
438
sa.sa_handler = signalHandler;
439
sigaction (SIGINT, &sa, 0);
440
sigaction (SIGPIPE, &sa, 0);
441
sigaction (SIGQUIT, &sa, 0);
442
sigaction (SIGTERM, &sa, 0);
445
* Connect to the X server.
447
if (NULL == (XStuff->display = XOpenDisplay (display_name))) {
448
fprintf (stderr, "%s: can't connect to X server %s\n", XStuff->commandLineName, XDisplayName (display_name));
452
createWindow (argc, argv);
455
if (glewInit () == GLEW_OK) {
456
glewInitialized = True;
467
if (XStuff->display) {
468
if (XStuff->window) {
469
hack_cleanup (XStuff);
471
if (!((rootWindow) || (XStuff->existingWindow)))
472
XDestroyWindow (XStuff->display, XStuff->window);
475
XCloseDisplay (XStuff->display);