~ubuntu-branches/ubuntu/precise/rss-glx/precise

« back to all changes in this revision

Viewing changes to src/driver.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2009-06-03 18:41:32 UTC
  • mfrom: (1.1.5 upstream) (2.2.1 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090603184132-znjy66pq9xom7hac
Tags: 0.9.0-2ubuntu1
* Merge from debian unstable, remaining changes:
  - Drop dependency on openal. It is not enabled by default anyway, and
    allows openal to migrate to universe.
  - src/skyrocket.{cpp,xml}: Disable sound by default.
  - Add --disable-sound configure flag to debian/rules, as we don't keep 
    the dependencies on openal nor freeglut (both universe packages).
* Dropped changes, merged upstream:
  - other_src/Makefile.am: fix the upstream build rules to actually use
    the ImageMagick CFLAGS returned by pkg-config.
  - Move the unconditional ImageMagick check up in configure.in so that
    our first PKG_CHECK_MODULES() call isn't hidden behind a shell
    conditional.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2002 Tugrul Galatali <tugrul@galatali.com>
 
3
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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
 
16
 */
 
17
 
 
18
#include <signal.h>
 
19
#include <stdio.h>
 
20
#include <string.h>
 
21
#include <stdlib.h>
 
22
#include <time.h>
 
23
#include <unistd.h>
 
24
#include <sys/time.h>
 
25
#include <sys/param.h>
 
26
 
 
27
#include <X11/X.h>
 
28
#include <X11/Xlib.h>
 
29
#include <X11/keysym.h>
 
30
 
 
31
#include "config.h"
 
32
 
 
33
#ifdef HAVE_GLEW
 
34
#include <GL/glew.h>
 
35
#include <GL/glxew.h>
 
36
#endif
 
37
 
 
38
#include <GL/gl.h>
 
39
 
 
40
#ifndef HAVE_GLEW
 
41
#include <GL/glx.h>
 
42
#endif
 
43
 
 
44
#ifdef HAVE_DPMS_EXT
 
45
#include <X11/extensions/dpms.h>
 
46
#endif
 
47
 
 
48
#include "driver.h"
 
49
 
 
50
#include "vroot.h"
 
51
 
 
52
xstuff_t *XStuff;
 
53
 
 
54
extern const char *hack_name;
 
55
 
 
56
/*
 
57
 * display parameters
 
58
 */
 
59
int rootWindow = False;
 
60
int glewInitialized = False;
 
61
#ifdef HAVE_GLEW
 
62
int frameTime = 10000;
 
63
int vsync = 1;
 
64
#else
 
65
int frameTime = 33333;
 
66
int vsync = 0;
 
67
#endif
 
68
int idleOnDPMS = 1;
 
69
int signalled = 0;
 
70
 
 
71
void createWindow (int argc, char **argv)
 
72
{
 
73
        XVisualInfo *visualInfo;
 
74
        GLXContext context;
 
75
 
 
76
        XStuff->screen_num = DefaultScreen (XStuff->display);
 
77
        XStuff->rootWindow = RootWindow (XStuff->display, XStuff->screen_num);
 
78
 
 
79
        if (rootWindow || XStuff->existingWindow) {
 
80
                XWindowAttributes gwa;
 
81
                Visual *visual;
 
82
                XVisualInfo templ;
 
83
                int outCount;
 
84
 
 
85
                XStuff->window = XStuff->existingWindow ? XStuff->existingWindow : XStuff->rootWindow;
 
86
 
 
87
                XGetWindowAttributes (XStuff->display, XStuff->window, &gwa);
 
88
                visual = gwa.visual;
 
89
                XStuff->windowWidth = gwa.width;
 
90
                XStuff->windowHeight = gwa.height;
 
91
 
 
92
                templ.screen = XStuff->screen_num;
 
93
                templ.visualid = XVisualIDFromVisual (visual);
 
94
 
 
95
                visualInfo = XGetVisualInfo (XStuff->display, VisualScreenMask | VisualIDMask, &templ, &outCount);
 
96
 
 
97
                if (!visualInfo) {
 
98
                        fprintf (stderr, "%s: can't get GL visual for window 0x%lx.\n", XStuff->commandLineName, (unsigned long)XStuff->window);
 
99
                        exit (1);
 
100
                }
 
101
        } else {
 
102
                int attributeList[] = {
 
103
                        GLX_RGBA,
 
104
                        GLX_RED_SIZE, 1,
 
105
                        GLX_GREEN_SIZE, 1,
 
106
                        GLX_BLUE_SIZE, 1,
 
107
                        GLX_DEPTH_SIZE, 1,
 
108
                        GLX_DOUBLEBUFFER,
 
109
                        0
 
110
                };
 
111
                XSetWindowAttributes swa;
 
112
                XSizeHints hints;
 
113
                XWMHints wmHints;
 
114
 
 
115
                visualInfo = NULL;
 
116
 
 
117
                if (!(visualInfo = glXChooseVisual (XStuff->display, XStuff->screen_num, attributeList))) {
 
118
                        fprintf (stderr, "%s: can't open GL visual.\n", XStuff->commandLineName);
 
119
                        exit (1);
 
120
                }
 
121
 
 
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;
 
125
 
 
126
                XStuff->windowWidth = DisplayWidth (XStuff->display, XStuff->screen_num) / 3;
 
127
                XStuff->windowHeight = DisplayHeight (XStuff->display, XStuff->screen_num) / 3;
 
128
 
 
129
                XStuff->window =
 
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);
 
132
 
 
133
                hints.flags = USSize;
 
134
                hints.width = XStuff->windowWidth;
 
135
                hints.height = XStuff->windowHeight;
 
136
 
 
137
                wmHints.flags = InputHint;
 
138
                wmHints.input = True;
 
139
 
 
140
                XmbSetWMProperties (XStuff->display, XStuff->window, hack_name, hack_name, argv, argc, &hints, &wmHints, NULL);
 
141
        }
 
142
 
 
143
        context = glXCreateContext (XStuff->display, visualInfo, 0, GL_TRUE);
 
144
        if (!context) {
 
145
                fprintf (stderr, "%s: can't open GLX context.\n", XStuff->commandLineName);
 
146
                exit (1);
 
147
        }
 
148
 
 
149
        if (!glXMakeCurrent (XStuff->display, XStuff->window, context)) {
 
150
                fprintf (stderr, "%s: can't set GL context.\n", XStuff->commandLineName);
 
151
                exit (1);
 
152
        }
 
153
 
 
154
        XFree (visualInfo);
 
155
        XMapWindow (XStuff->display, XStuff->window);
 
156
}
 
157
 
 
158
void clearBuffers() {
 
159
        int i;
 
160
        XEvent event;
 
161
 
 
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);
 
165
 
 
166
                while (XPending (XStuff->display)) {
 
167
                        XNextEvent (XStuff->display, &event);
 
168
                }
 
169
        }
 
170
}
 
171
 
 
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;
 
174
}
 
175
 
 
176
void mainLoop (void)
 
177
{
 
178
        int bFPS = False;
 
179
        XEvent event;
 
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;
 
183
        int fps = 0;
 
184
        int drawEnabled = 1;
 
185
 
 
186
        if (!rootWindow) {
 
187
                XSetWMProtocols (XStuff->display, XStuff->window, &XA_WM_DELETE_WINDOW, 1);
 
188
        }
 
189
 
 
190
        clearBuffers ();
 
191
 
 
192
#ifdef HAVE_GLEW
 
193
        if (glewInitialized) {
 
194
                if ((vsync > 0) && GLXEW_SGI_swap_control) {
 
195
                        glXSwapIntervalSGI (vsync);
 
196
                }
 
197
        }
 
198
#endif
 
199
 
 
200
#ifdef HAVE_DPMS_EXT
 
201
        int dpmsAvailable = 0;
 
202
        {
 
203
                int event_number, error_number;
 
204
                if (DPMSQueryExtension(XStuff->display, &event_number, &error_number)) {
 
205
                        if (DPMSCapable(XStuff->display)) {
 
206
                                dpmsAvailable = 1;
 
207
                        }
 
208
                }
 
209
        }
 
210
#endif
 
211
 
 
212
        gettimeofday (&cycleStart, NULL);
 
213
        now = fps_time = cycleStart;
 
214
        int frameTimeSoFar = 0;
 
215
#ifdef HAVE_DPMS_EXT
 
216
        int sinceLastDPMSPoll = 0;
 
217
#endif
 
218
        while (!signalled) {
 
219
#ifdef HAVE_DPMS_EXT
 
220
                sinceLastDPMSPoll = sinceLastDPMSPoll + frameTimeSoFar;
 
221
                if (idleOnDPMS && dpmsAvailable && (sinceLastDPMSPoll > 1000000)) {
 
222
                        CARD16 state;
 
223
                        BOOL onoff;
 
224
 
 
225
                        sinceLastDPMSPoll = 0;
 
226
                        drawEnabled = 1;
 
227
 
 
228
                        if (DPMSInfo(XStuff->display, &state, &onoff)) {
 
229
                                if (onoff && (state != DPMSModeOn)) drawEnabled = 0;
 
230
                        }
 
231
 
 
232
                        // If the display isn't on, kick back and poll DPMS every second
 
233
                        if (!drawEnabled) {
 
234
                                sleep(1);
 
235
                        }
 
236
                }
 
237
#endif
 
238
 
 
239
                if (drawEnabled) {
 
240
                        hack_draw (XStuff, (double)now.tv_sec + now.tv_usec / 1000000.0f, frameTimeSoFar / 1000000.0f);
 
241
 
 
242
                        glXSwapBuffers (XStuff->display, XStuff->window);
 
243
                }
 
244
 
 
245
                if (bFPS) {
 
246
                        if (fps != -1)
 
247
                                fps++;
 
248
 
 
249
                        if (now.tv_sec > fps_time.tv_sec) {
 
250
                                if (fps != -1) {
 
251
                                        printf ("%.4f fps\n", fps / (deltaus(now, fps_time) / 1000000.0));
 
252
                                }
 
253
 
 
254
                                fps = 0;
 
255
                                fps_time.tv_sec = now.tv_sec;
 
256
                                fps_time.tv_usec = now.tv_usec;
 
257
                        }
 
258
                }
 
259
 
 
260
                while (XPending (XStuff->display)) {
 
261
                        KeySym keysym;
 
262
                        char c = 0;
 
263
 
 
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;
 
270
 
 
271
                                        clearBuffers ();
 
272
 
 
273
                                        hack_reshape (XStuff);
 
274
                                }
 
275
 
 
276
                                break;
 
277
                        case KeyPress:
 
278
                                XLookupString (&event.xkey, &c, 1, &keysym, 0);
 
279
 
 
280
                                if (c == 'f') {
 
281
                                        bFPS = !bFPS;
 
282
 
 
283
                                        if (bFPS) {
 
284
                                                fps = -1;
 
285
                                                gettimeofday (&fps_time, NULL);
 
286
                                        }
 
287
                                }
 
288
 
 
289
                                if (c == 'q' || c == 'Q' || c == 3 || c == 27)
 
290
                                        return;
 
291
 
 
292
                                break;
 
293
                        case ClientMessage:
 
294
                                if (event.xclient.message_type == XA_WM_PROTOCOLS) {
 
295
                                        if (event.xclient.data.l[0] == (int)XA_WM_DELETE_WINDOW) {
 
296
                                                return;
 
297
                                        }
 
298
                                }
 
299
                                break;
 
300
                        case DestroyNotify:
 
301
                                return;
 
302
                        }
 
303
                }
 
304
 
 
305
                gettimeofday (&now, NULL);
 
306
                frameTimeSoFar = deltaus(now, cycleStart);
 
307
 
 
308
                if (frameTime) {
 
309
                        while (frameTimeSoFar < frameTime) {
 
310
#ifdef HAVE_NANOSLEEP
 
311
                                struct timespec hundreth;
 
312
 
 
313
                                hundreth.tv_sec = 0;
 
314
                                hundreth.tv_nsec = (frameTime - frameTimeSoFar) * 1000;
 
315
 
 
316
                                nanosleep (&hundreth, NULL);
 
317
#else
 
318
                                usleep (frameTime - frameTimeSoFar);
 
319
#endif
 
320
 
 
321
                                gettimeofday (&now, NULL);
 
322
                                frameTimeSoFar = deltaus(now, cycleStart);
 
323
                        }
 
324
 
 
325
                        int delta = 0;
 
326
                        do {
 
327
                                cycleStart.tv_usec += frameTime;
 
328
                                if (cycleStart.tv_usec > 1000000) {
 
329
                                        cycleStart.tv_sec++;
 
330
                                        cycleStart.tv_usec -= 1000000;
 
331
                                }
 
332
                                delta = deltaus(now, cycleStart);
 
333
                        } while (delta > frameTime);
 
334
                } else {
 
335
                        cycleStart = now;
 
336
                }
 
337
        }
 
338
}
 
339
 
 
340
void handle_global_opts (int c)
 
341
{
 
342
        switch (c) {
 
343
        case 'r':
 
344
                rootWindow = 1;
 
345
 
 
346
                break;
 
347
        case 'x':
 
348
                c = strtol_minmaxdef (optarg, 10, 0, 10000, 1, 100, "--maxfps: ");
 
349
 
 
350
                frameTime = (c > 0) ? 1000000 / c : 0;
 
351
 
 
352
                break;
 
353
        case 'y':
 
354
                vsync = strtol_minmaxdef (optarg, 10, 0, 100, 1, 2, "--vsync: ");
 
355
 
 
356
#ifndef HAVE_GLEW
 
357
                if (vsync)
 
358
                        fprintf (stderr, "Not compiled with GLEW, vsync not supported.\n");
 
359
#endif
 
360
 
 
361
                break;
 
362
        case 'M':
 
363
                idleOnDPMS = strtol_minmaxdef (optarg, 10, 0, 1, 0, 1, "--dpms: ");
 
364
 
 
365
#ifndef HAVE_DPMS_EXT
 
366
                if (idleOnDPMS)
 
367
                        fprintf (stderr, "Not compiled with DPMS, idling on DPMS not supported.\n");
 
368
#endif
 
369
 
 
370
                break;
 
371
        }
 
372
}
 
373
 
 
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)
 
375
{
 
376
        const int result = strtol (optarg, (char **)NULL, base);
 
377
 
 
378
        if (result < min) {
 
379
                if (errmsg) {
 
380
                        fprintf (stderr, "%s %d < %d, using %d instead.\n", errmsg, result, min, type ? min : def);
 
381
                }
 
382
 
 
383
                return type ? min : def;
 
384
        }
 
385
 
 
386
        if (result > max) {
 
387
                if (errmsg) {
 
388
                        fprintf (stderr, "%s %d > %d, using %d instead.\n", errmsg, result, max, type ? max : def);
 
389
                }
 
390
 
 
391
                return type ? max : def;
 
392
        }
 
393
 
 
394
        return result;
 
395
}
 
396
 
 
397
void signalHandler (int sig)
 
398
{
 
399
        signalled = 1;
 
400
}
 
401
 
 
402
int main (int argc, char *argv[])
 
403
{
 
404
        struct sigaction sa;
 
405
        char *display_name = NULL;      /* Server to connect to */
 
406
        int i, j;
 
407
 
 
408
        XStuff = (xstuff_t *) malloc (sizeof (xstuff_t));
 
409
        XStuff->commandLineName = argv[0];
 
410
 
 
411
        srandom ((unsigned)time (NULL));
 
412
 
 
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);
 
418
                        } else {
 
419
                                XStuff->existingWindow = strtol ((char *)(argv[i + 1]), (char **)NULL, 10);
 
420
                        }
 
421
 
 
422
                        for (j = i + 2; j < argc; j++) {
 
423
                                argv[j - 2] = argv[j];
 
424
                        }
 
425
 
 
426
                        argc -= 2;
 
427
 
 
428
                        break;
 
429
                }
 
430
        }
 
431
 
 
432
        hack_handle_opts (argc, argv);
 
433
 
 
434
        XStuff->display = NULL;
 
435
        XStuff->window = 0;
 
436
 
 
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);
 
443
 
 
444
        /*
 
445
         * Connect to the X server.
 
446
         */
 
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));
 
449
                exit (1);
 
450
        }
 
451
 
 
452
        createWindow (argc, argv);
 
453
 
 
454
#ifdef HAVE_GLEW
 
455
        if (glewInit () == GLEW_OK) {
 
456
                glewInitialized = True;
 
457
        }
 
458
#endif
 
459
 
 
460
        hack_init (XStuff);
 
461
 
 
462
        mainLoop ();
 
463
 
 
464
        /*
 
465
         * Clean up.
 
466
         */
 
467
        if (XStuff->display) {
 
468
                if (XStuff->window) {
 
469
                        hack_cleanup (XStuff);
 
470
 
 
471
                        if (!((rootWindow) || (XStuff->existingWindow)))
 
472
                                XDestroyWindow (XStuff->display, XStuff->window);
 
473
                }
 
474
 
 
475
                XCloseDisplay (XStuff->display);
 
476
        }
 
477
 
 
478
        return 0;
 
479
}