]> git.cworth.org Git - vogl/blob - src/glxspheres/glxspheres.c
Initial vogl checkin
[vogl] / src / glxspheres / glxspheres.c
1 /* Copyright (C)2007 Sun Microsystems, Inc.
2  * Copyright (C)2011, 2013 D. R. Commander
3  *
4  * This library is free software and may be redistributed and/or modified under
5  * the terms of the wxWindows Library License, Version 3.1 or (at your option)
6  * any later version.  The full license is in the LICENSE.txt file included
7  * with this distribution.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * wxWindows Library License for more details.
13  */
14
15 /* This program's goal is to reproduce, as closely as possible, the image
16    output of the nVidia SphereMark demo by R. Stephen Glanville using the
17    simplest available rendering method.  GLXSpheres is meant primarily to
18    serve as an image pipeline benchmark for VirtualGL. */
19
20 #include <GL/glx.h>
21 #ifdef MESAGLU
22 #include <mesa/glu.h>
23 #else
24 #include <GL/glu.h>
25 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <limits.h>
30 #include <math.h>
31 #include <memory.h>
32 #include <sys/time.h>
33
34 //#include "rrtimer.h"
35 //#include "rrutil.h"
36
37 #define min(a, b) (((a) < (b)) ? (a) : (b))
38
39 static double rrtime()
40 {
41     struct timeval cur_time;
42     gettimeofday(&cur_time, NULL);
43     return ((unsigned long long)(cur_time.tv_sec) * 1000000ULL + (unsigned long long)(cur_time.tv_usec)) / 1000000.0;
44 }
45
46 #define _throw(m)                                         \
47     {                                                     \
48         fprintf(stderr, "ERROR (%d): %s\n", __LINE__, m); \
49         goto bailout;                                     \
50     }
51 #define np2(i) ((i) > 0 ? (1 << (int)(log((double)(i)) / log(2.))) : 0)
52 #define _catch(f)         \
53     {                     \
54         if ((f) == -1)    \
55             goto bailout; \
56     }
57
58 #define spherered(f) fabs(MAXI *(2. * f - 1.))
59 #define spheregreen(f) fabs(MAXI *(2. * fmod(f + 2. / 3., 1.) - 1.))
60 #define sphereblue(f) fabs(MAXI *(2. * fmod(f + 1. / 3., 1.) - 1.))
61
62 #define DEF_WIDTH 1240
63 #define DEF_HEIGHT 900
64
65 #define DEF_SLICES 32
66 #define DEF_STACKS 32
67
68 #define NSPHERES 20
69
70 #define _2PI 6.283185307180
71 #define MAXI (220. / 255.)
72
73 #define NSCHEMES 7
74 enum
75 {
76     GREY = 0,
77     RED,
78     GREEN,
79     BLUE,
80     YELLOW,
81     MAGENTA,
82     CYAN
83 };
84
85 #define DEFBENCHTIME 2.0
86
87 Display *dpy = NULL;
88 Window win = 0, olwin = 0;
89 int usestereo = 0, useoverlay = 0, useci = 0, useimm = 0, interactive = 0, oldb = 1,
90     locolor = 0, maxframes = 0, totalframes = 0, directctx = True;
91 double benchtime = DEFBENCHTIME;
92 int ncolors = 0, nolcolors, colorscheme = GREY;
93 Colormap colormap = 0, olcolormap = 0;
94 GLXContext ctx = 0, olctx = 0;
95
96 int spherelist = 0, fontlistbase = 0;
97 GLUquadricObj *spherequad = NULL;
98 int slices = DEF_SLICES, stacks = DEF_STACKS;
99 float x = 0., y = 0., z = -3.;
100 float outer_angle = 0., middle_angle = 0., inner_angle = 0.;
101 float lonesphere_color = 0.;
102 unsigned int transpixel = 0;
103
104 int width = DEF_WIDTH, height = DEF_HEIGHT;
105
106 int setcolorscheme(Colormap c, int nc, int scheme)
107 {
108     XColor xc[256];
109     int i;
110     if (!nc || !c)
111         _throw("Color map not allocated");
112     if (scheme < 0 || scheme > NSCHEMES - 1 || !c)
113         _throw("Invalid argument");
114
115     for (i = 0; i < nc; i++)
116     {
117         xc[i].flags = DoRed | DoGreen | DoBlue;
118         xc[i].pixel = i;
119         xc[i].red = xc[i].green = xc[i].blue = 0;
120         if (scheme == GREY || scheme == RED || scheme == YELLOW || scheme == MAGENTA)
121             xc[i].red = (i * (256 / nc)) << 8;
122         if (scheme == GREY || scheme == GREEN || scheme == YELLOW || scheme == CYAN)
123             xc[i].green = (i * (256 / nc)) << 8;
124         if (scheme == GREY || scheme == BLUE || scheme == MAGENTA || scheme == CYAN)
125             xc[i].blue = (i * (256 / nc)) << 8;
126     }
127     XStoreColors(dpy, c, xc, nc);
128     return 0;
129
130 bailout:
131     return -1;
132 }
133
134 void reshape(int w, int h)
135 {
136     XWindowChanges changes;
137     if (w <= 0)
138         w = 1;
139     if (h <= 0)
140         h = 1;
141     width = w;
142     height = h;
143     if (useoverlay && olwin)
144     {
145         changes.width = width;
146         changes.height = height;
147         XConfigureWindow(dpy, olwin, CWWidth | CWHeight, &changes);
148     }
149 }
150
151 void setspherecolor(float c)
152 {
153     if (useci)
154     {
155         GLfloat ndx = c * (float)(ncolors - 1);
156         GLfloat mat_ndxs[] = { ndx * 0.3, ndx * 0.8, ndx };
157         glIndexf(ndx);
158         glMaterialfv(GL_FRONT, GL_COLOR_INDEXES, mat_ndxs);
159     }
160     else
161     {
162         float mat[4] = { spherered(c), spheregreen(c), sphereblue(c), 0.25 };
163         glColor3f(spherered(c), spheregreen(c), sphereblue(c));
164         glMaterialfv(GL_FRONT, GL_AMBIENT, mat);
165         glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
166     }
167 }
168
169 void renderspheres(int buf)
170 {
171     int i;
172     GLfloat xaspect, yaspect;
173     GLfloat stereocameraoffset = 0.;
174     GLfloat neardist = 1.5, fardist = 40., zeroparallaxdist = 17.;
175     glDrawBuffer(buf);
176
177     xaspect = (GLfloat)width / (GLfloat)(min(width, height));
178     yaspect = (GLfloat)height / (GLfloat)(min(width, height));
179
180     if (buf == GL_BACK_LEFT)
181         stereocameraoffset = -xaspect * zeroparallaxdist / neardist * 0.035;
182     else if (buf == GL_BACK_RIGHT)
183         stereocameraoffset = xaspect * zeroparallaxdist / neardist * 0.035;
184
185     glMatrixMode(GL_PROJECTION);
186     glLoadIdentity();
187     glFrustum(-xaspect, xaspect, -yaspect, yaspect, neardist, fardist);
188     glTranslatef(-stereocameraoffset, 0., 0.);
189     glMatrixMode(GL_MODELVIEW);
190     glViewport(0, 0, width, height);
191
192     // Begin rendering
193     glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
194     glClearDepth(20.0f);
195     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
196
197     // Lone sphere
198     glPushMatrix();
199     glTranslatef(0., 0., z);
200     setspherecolor(lonesphere_color);
201     if (useimm)
202         gluSphere(spherequad, 1.3, slices, stacks);
203     else
204         glCallList(spherelist);
205     glPopMatrix();
206
207     // Outer ring
208     glPushMatrix();
209     glRotatef(outer_angle, 0., 0., 1.);
210     for (i = 0; i < NSPHERES; i++)
211     {
212         double f = (double)i / (double)NSPHERES;
213         glPushMatrix();
214         glTranslatef(sin(_2PI * f) * 5., cos(_2PI * f) * 5., -10.);
215         setspherecolor(f);
216         if (useimm)
217             gluSphere(spherequad, 1.3, slices, stacks);
218         else
219             glCallList(spherelist);
220         glPopMatrix();
221     }
222     glPopMatrix();
223
224     // Middle ring
225     glPushMatrix();
226     glRotatef(middle_angle, 0., 0., 1.);
227     for (i = 0; i < NSPHERES; i++)
228     {
229         double f = (double)i / (double)NSPHERES;
230         glPushMatrix();
231         glTranslatef(sin(_2PI * f) * 5., cos(_2PI * f) * 5., -17.);
232         setspherecolor(f);
233         if (useimm)
234             gluSphere(spherequad, 1.3, slices, stacks);
235         else
236             glCallList(spherelist);
237         glPopMatrix();
238     }
239     glPopMatrix();
240
241     // Inner ring
242     glPushMatrix();
243     glRotatef(inner_angle, 0., 0., 1.);
244     for (i = 0; i < NSPHERES; i++)
245     {
246         double f = (double)i / (double)NSPHERES;
247         glPushMatrix();
248         glTranslatef(sin(_2PI * f) * 5., cos(_2PI * f) * 5., -29.);
249         setspherecolor(f);
250         if (useimm)
251             gluSphere(spherequad, 1.3, slices, stacks);
252         else
253             glCallList(spherelist);
254         glPopMatrix();
255     }
256     glPopMatrix();
257
258     // Move the eye back to the middle
259     glMatrixMode(GL_PROJECTION);
260     glTranslatef(stereocameraoffset, 0., 0.);
261 }
262
263 void renderoverlay(void)
264 {
265     int i, j, w = width / 8, h = height / 8;
266     unsigned char *buf = NULL;
267     int ndx = (int)(lonesphere_color * (float)(nolcolors - 1));
268     glShadeModel(GL_FLAT);
269     glDisable(GL_DEPTH_TEST);
270     glDisable(GL_LIGHTING);
271     glMatrixMode(GL_PROJECTION);
272     glLoadIdentity();
273     glMatrixMode(GL_MODELVIEW);
274     glViewport(0, 0, width, height);
275     glRasterPos3f(-0.5, 0.5, 0.0);
276     glClearIndex((float)transpixel);
277     glClear(GL_COLOR_BUFFER_BIT);
278     glIndexf(lonesphere_color * (float)(nolcolors - 1));
279     glBegin(GL_LINES);
280     glVertex2f(-1. + lonesphere_color * 2., -1.);
281     glVertex2f(-1. + lonesphere_color * 2., 1.);
282     glVertex2f(-1., -1. + lonesphere_color * 2.);
283     glVertex2f(1., -1. + lonesphere_color * 2.);
284     glEnd();
285     if (w && h)
286     {
287         if ((buf = (unsigned char *)malloc(w * h)) == NULL)
288             _throw("Could not allocate memory");
289         for (i = 0; i < h; i++)
290             for (j = 0; j < w; j++)
291             {
292                 if (((i / 4) % 2) != ((j / 4) % 2))
293                     buf[i * w + j] = 0;
294                 else
295                     buf[i * w + j] = ndx;
296             }
297         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
298         glDrawPixels(w, h, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, buf);
299     }
300     glRasterPos3f(0., 0., 0.);
301     glListBase(fontlistbase);
302     glCallLists(24, GL_UNSIGNED_BYTE, "GLX Spheres Overlay Test");
303 bailout:
304     if (buf)
305         free(buf);
306 }
307
308 int display(int advance)
309 {
310     static int first = 1;
311     static double start = 0., elapsed = 0., mpixels = 0.;
312     static unsigned long frames = 0;
313     static char temps[256];
314     XFontStruct *fontinfo = NULL;
315     int minchar, maxchar;
316     GLfloat xaspect, yaspect;
317
318     if (first)
319     {
320         GLfloat id4[] = { 1., 1., 1., 1. };
321         GLfloat light0_amb[] = { 0.3, 0.3, 0.3, 1. };
322         GLfloat light0_dif[] = { 0.8, 0.8, 0.8, 1. };
323         GLfloat light0_pos[] = { 1., 1., 1., 0. };
324
325         spherelist = glGenLists(1);
326         if (!(spherequad = gluNewQuadric()))
327             _throw("Could not allocate GLU quadric object");
328         glNewList(spherelist, GL_COMPILE);
329         gluSphere(spherequad, 1.3, slices, stacks);
330         glEndList();
331
332         if (!locolor)
333         {
334             if (useci)
335             {
336                 glMaterialf(GL_FRONT, GL_SHININESS, 50.);
337             }
338             else
339             {
340                 glMaterialfv(GL_FRONT, GL_AMBIENT, id4);
341                 glMaterialfv(GL_FRONT, GL_DIFFUSE, id4);
342                 glMaterialfv(GL_FRONT, GL_SPECULAR, id4);
343                 glMaterialf(GL_FRONT, GL_SHININESS, 50.);
344
345                 glLightfv(GL_LIGHT0, GL_AMBIENT, light0_amb);
346                 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_dif);
347                 glLightfv(GL_LIGHT0, GL_SPECULAR, id4);
348             }
349             glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
350             glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 180.);
351             glEnable(GL_LIGHTING);
352             glEnable(GL_LIGHT0);
353         }
354
355         if (locolor)
356             glShadeModel(GL_FLAT);
357         else
358             glShadeModel(GL_SMOOTH);
359         glEnable(GL_DEPTH_TEST);
360         glDepthFunc(GL_LESS);
361
362         if (useoverlay)
363         {
364             glXMakeCurrent(dpy, olwin, olctx);
365         }
366         if (!(fontinfo = XLoadQueryFont(dpy, "fixed")))
367             _throw("Could not load X font");
368         minchar = fontinfo->min_char_or_byte2;
369         maxchar = fontinfo->max_char_or_byte2;
370         fontlistbase = glGenLists(maxchar + 1);
371         glXUseXFont(fontinfo->fid, minchar, maxchar - minchar + 1, fontlistbase + minchar);
372         XFreeFont(dpy, fontinfo);
373         fontinfo = NULL;
374         snprintf(temps, 255, "Measuring performance ...");
375         if (useoverlay)
376             glXMakeCurrent(dpy, win, ctx);
377
378         first = 0;
379     }
380
381     if (advance)
382     {
383         z -= 0.5;
384         if (z < -29.)
385         {
386             if (useci || useoverlay)
387                 colorscheme = (colorscheme + 1) % NSCHEMES;
388             if (useci)
389                 _catch(setcolorscheme(colormap, ncolors, colorscheme));
390             if (useoverlay)
391                 _catch(setcolorscheme(olcolormap, nolcolors, colorscheme));
392             z = -3.5;
393         }
394         outer_angle += 0.1;
395         if (outer_angle > 360.)
396             outer_angle -= 360.;
397         middle_angle -= 0.37;
398         if (middle_angle < -360.)
399             middle_angle += 360.;
400         inner_angle += 0.63;
401         if (inner_angle > 360.)
402             inner_angle -= 360.;
403         lonesphere_color += 0.005;
404         if (lonesphere_color > 1.)
405             lonesphere_color -= 1.;
406     }
407
408     if (usestereo)
409     {
410         renderspheres(GL_BACK_LEFT);
411         renderspheres(GL_BACK_RIGHT);
412     }
413     else
414         renderspheres(GL_BACK);
415
416     glDrawBuffer(GL_BACK);
417     if (useoverlay)
418     {
419         glXMakeCurrent(dpy, olwin, olctx);
420         renderoverlay();
421     }
422     else
423         glPushAttrib(GL_CURRENT_BIT);
424     glPushAttrib(GL_LIST_BIT);
425     glPushAttrib(GL_ENABLE_BIT);
426     glDisable(GL_LIGHTING);
427     if (useoverlay || useci)
428         glIndexf(254.);
429     else
430         glColor3f(1., 1., 1.);
431     if (useoverlay)
432         glRasterPos3f(-0.95, -0.95, 0.);
433     else
434     {
435         xaspect = (GLfloat)width / (GLfloat)(min(width, height));
436         yaspect = (GLfloat)height / (GLfloat)(min(width, height));
437         glRasterPos3f(-0.95 * xaspect, -0.95 * yaspect, -1.5);
438     }
439     glListBase(fontlistbase);
440     glCallLists(strlen(temps), GL_UNSIGNED_BYTE, temps);
441     glPopAttrib();
442     glPopAttrib();
443     glPopAttrib();
444     if (useoverlay)
445     {
446         if (oldb)
447             glXSwapBuffers(dpy, olwin);
448         glXMakeCurrent(dpy, win, ctx);
449     }
450     glXSwapBuffers(dpy, win);
451
452     if (start > 0.)
453     {
454
455         elapsed += rrtime() - start;
456         frames++;
457         totalframes++;
458         mpixels += (double)width * (double)height / 1000000.;
459         if (elapsed > benchtime || (maxframes && totalframes > maxframes))
460         {
461             snprintf(temps, 255, "%f frames/sec - %f Mpixels/sec",
462                      (double)frames / elapsed, mpixels / elapsed);
463             printf("%s\n", temps);
464             elapsed = mpixels = 0.;
465             frames = 0;
466         }
467     }
468     if (maxframes && totalframes > maxframes)
469         goto bailout;
470
471     start = rrtime();
472
473     return 0;
474
475 bailout:
476     if (spherequad)
477     {
478         gluDeleteQuadric(spherequad);
479         spherequad = NULL;
480     }
481     if (fontinfo)
482     {
483         XFreeFont(dpy, fontinfo);
484         fontinfo = NULL;
485     }
486     return -1;
487 }
488
489 Atom protoatom = 0, deleteatom = 0;
490
491 int event_loop(Display *dpy)
492 {
493     while (1)
494     {
495         int advance = 0, dodisplay = 0;
496
497         while (1)
498         {
499             XEvent event;
500             if (interactive)
501                 XNextEvent(dpy, &event);
502             else
503             {
504                 if (XPending(dpy) > 0)
505                     XNextEvent(dpy, &event);
506                 else
507                     break;
508             }
509             switch (event.type)
510             {
511                 case Expose:
512                     dodisplay = 1;
513                     break;
514                 case ConfigureNotify:
515                     reshape(event.xconfigure.width, event.xconfigure.height);
516                     break;
517                 case KeyPress:
518                 {
519                     char buf[10];
520                     int key;
521                     (void)key;
522                     key = XLookupString(&event.xkey, buf, sizeof(buf), NULL, NULL);
523                     switch (buf[0])
524                     {
525                         case 27:
526                         case 'q':
527                         case 'Q':
528                             return 0;
529                     }
530                     break;
531                 }
532                 case MotionNotify:
533                     if (event.xmotion.state & Button1Mask)
534                         dodisplay = advance = 1;
535                     break;
536                 case ClientMessage:
537                 {
538                     XClientMessageEvent *cme = (XClientMessageEvent *)&event;
539                     if (cme->message_type == protoatom && cme->data.l[0] == (long)deleteatom)
540                         return 0;
541                 }
542             }
543             if (interactive)
544             {
545                 if (XPending(dpy) <= 0)
546                     break;
547             }
548         }
549         if (!interactive)
550         {
551             _catch(display(1));
552         }
553         else
554         {
555             if (dodisplay)
556             {
557                 _catch(display(advance));
558             }
559         }
560     }
561
562 bailout:
563     return -1;
564 }
565
566 void usage(char **argv)
567 {
568     printf("\nUSAGE: %s [options]\n\n", argv[0]);
569     printf("Options:\n");
570     printf("-c = Use color index rendering (default is RGB)\n");
571     printf("-fs = Full-screen mode\n");
572     printf("-i = Interactive mode.  Frames advance in response to mouse movement\n");
573     printf("-l = Use fewer than 24 colors (to force non-JPEG encoding in TurboVNC)\n");
574     printf("-m = Use immediate mode rendering (default is display list)\n");
575     printf("-o = Test 8-bit transparent overlays\n");
576     printf("-p <p> = Use (approximately) <p> polygons to render scene\n");
577     printf("-s = Use stereographic rendering initially\n");
578     printf("     (this can be switched on and off in the application)\n");
579     printf("-32 = Use 32-bit visual (default is 24-bit)\n");
580     printf("-f <n> = max frames to render\n");
581     printf("-bt <t> = print benchmark results every <t> seconds (default=%.1f)\n",
582            DEFBENCHTIME);
583     printf("-w <wxh> = specify window width and height\n");
584     printf("-ic = Use indirect rendering context\n");
585     printf("-sc <s> = Create window on X screen # <s>\n");
586     printf("\n");
587     exit(0);
588 }
589
590 int main(int argc, char **argv)
591 {
592     int i, usealpha = 0;
593     XVisualInfo *v = NULL;
594     int rgbattribs[] = { GLX_RGBA, GLX_RED_SIZE, 8, GLX_GREEN_SIZE, 8,
595                          GLX_BLUE_SIZE, 8, GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, None, None, None,
596                          None };
597     int ciattribs[] = { GLX_BUFFER_SIZE, 8, GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER,
598                         None };
599     int olattribs[] = { GLX_BUFFER_SIZE, 8, GLX_LEVEL, 1, GLX_TRANSPARENT_TYPE,
600                         GLX_TRANSPARENT_INDEX, GLX_DOUBLEBUFFER, None };
601     XSetWindowAttributes swa;
602     Window root;
603     int fullscreen = 0;
604     unsigned long mask = 0;
605     int screen = -1;
606
607     for (i = 0; i < argc; i++)
608     {
609         if (!strncasecmp(argv[i], "-h", 2))
610             usage(argv);
611         if (!strncasecmp(argv[i], "-?", 2))
612             usage(argv);
613         if (!strncasecmp(argv[i], "-c", 2))
614             useci = 1;
615         if (!strncasecmp(argv[i], "-ic", 3))
616             directctx = False;
617         else if (!strncasecmp(argv[i], "-i", 2))
618             interactive = 1;
619         if (!strncasecmp(argv[i], "-l", 2))
620             locolor = 1;
621         if (!strncasecmp(argv[i], "-m", 2))
622             useimm = 1;
623         if (!strncasecmp(argv[i], "-o", 2))
624             useoverlay = 1;
625         if (!strncasecmp(argv[i], "-w", 2) && i < argc - 1)
626         {
627             int w = 0, h = 0;
628             if (sscanf(argv[++i], "%dx%d", &w, &h) == 2 && w > 0 && h > 0)
629             {
630                 width = w;
631                 height = h;
632                 printf("Window dimensions: %d x %d\n", width, height);
633             }
634         }
635         if (!strncasecmp(argv[i], "-p", 2) && i < argc - 1)
636         {
637             int npolys = atoi(argv[++i]);
638             if (npolys > 0)
639             {
640                 slices = stacks = (int)(sqrt((double)npolys / ((double)(3 * NSPHERES + 1))));
641                 if (slices < 1)
642                     slices = stacks = 1;
643             }
644         }
645         if (!strncasecmp(argv[i], "-fs", 3))
646             fullscreen = 1;
647         else if (!strncasecmp(argv[i], "-f", 2) && i < argc - 1)
648         {
649             int mf = atoi(argv[++i]);
650             if (mf > 0)
651             {
652                 maxframes = mf;
653                 printf("Number of frames to render: %d\n", maxframes);
654             }
655         }
656         if (!strncasecmp(argv[i], "-bt", 3) && i < argc - 1)
657         {
658             double temp = atof(argv[++i]);
659             if (temp > 0.0)
660                 benchtime = temp;
661         }
662         if (!strncasecmp(argv[i], "-sc", 3) && i < argc - 1)
663         {
664             int sc = atoi(argv[++i]);
665             if (sc > 0)
666             {
667                 screen = sc;
668                 printf("Rendering to screen %d\n", screen);
669             }
670         }
671         else if (!strncasecmp(argv[i], "-s", 2))
672         {
673             rgbattribs[10] = GLX_STEREO;
674             usestereo = 1;
675         }
676         if (!strncasecmp(argv[i], "-32", 3))
677             usealpha = 1;
678     }
679
680     if (usealpha)
681     {
682         if (rgbattribs[10] == None)
683         {
684             rgbattribs[10] = GLX_ALPHA_SIZE;
685             rgbattribs[11] = 8;
686         }
687         else
688         {
689             rgbattribs[11] = GLX_ALPHA_SIZE;
690             rgbattribs[12] = 8;
691         }
692     }
693
694     fprintf(stderr, "Polygons in scene: %d\n", (NSPHERES * 3 + 1) * slices * stacks);
695
696     if ((dpy = XOpenDisplay(0)) == NULL)
697         _throw("Could not open display");
698     if (screen < 0)
699         screen = DefaultScreen(dpy);
700
701     if (useci)
702     {
703         if ((v = glXChooseVisual(dpy, screen, ciattribs)) == NULL)
704             _throw("Could not obtain index visual");
705     }
706     else
707     {
708         if ((v = glXChooseVisual(dpy, screen, rgbattribs)) == NULL)
709             _throw("Could not obtain RGB visual with requested properties");
710     }
711     fprintf(stderr, "Visual ID of %s: 0x%.2x\n", useoverlay ? "underlay" : "window",
712             (int)v->visualid);
713
714     root = RootWindow(dpy, screen);
715     swa.border_pixel = 0;
716     swa.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
717     swa.override_redirect = fullscreen ? True : False;
718     if (useci)
719     {
720         swa.colormap = colormap = XCreateColormap(dpy, root, v->visual, AllocAll);
721         ncolors = np2(v->colormap_size);
722         if (ncolors < 32)
723             _throw("Color map is not large enough");
724         _catch(setcolorscheme(colormap, ncolors, colorscheme));
725     }
726     else
727         swa.colormap = XCreateColormap(dpy, root, v->visual, AllocNone);
728
729     if (interactive)
730         swa.event_mask |= PointerMotionMask | ButtonPressMask;
731
732     mask = CWBorderPixel | CWColormap | CWEventMask;
733     if (fullscreen)
734     {
735         mask |= CWOverrideRedirect;
736         width = DisplayWidth(dpy, screen);
737         height = DisplayHeight(dpy, screen);
738     }
739     if (!(protoatom = XInternAtom(dpy, "WM_PROTOCOLS", False)))
740         _throw("Cannot obtain WM_PROTOCOLS atom");
741     if (!(deleteatom = XInternAtom(dpy, "WM_DELETE_WINDOW", False)))
742         _throw("Cannot obtain WM_DELETE_WINDOW atom");
743     if ((win = XCreateWindow(dpy, root, 0, 0, width, height, 0, v->depth,
744                              InputOutput, v->visual, mask, &swa)) == 0)
745         _throw("Could not create window");
746     XSetWMProtocols(dpy, win, &deleteatom, 1);
747     XStoreName(dpy, win, "GLX Spheres");
748     XMapWindow(dpy, win);
749     if (fullscreen)
750         XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
751     XSync(dpy, False);
752
753     if ((ctx = glXCreateContext(dpy, v, NULL, directctx)) == 0)
754         _throw("Could not create rendering context");
755     fprintf(stderr, "Context is %s\n",
756             glXIsDirect(dpy, ctx) ? "Direct" : "Indirect");
757     XFree(v);
758     v = NULL;
759
760     if (useoverlay)
761     {
762         if ((v = glXChooseVisual(dpy, screen, olattribs)) == NULL)
763         {
764             olattribs[6] = None;
765             oldb = 0;
766             if ((v = glXChooseVisual(dpy, screen, olattribs)) == NULL)
767                 _throw("Could not obtain overlay visual");
768         }
769         fprintf(stderr, "Visual ID of overlay: 0x%.2x\n", (int)v->visualid);
770
771         swa.colormap = olcolormap = XCreateColormap(dpy, root, v->visual, AllocAll);
772         nolcolors = np2(v->colormap_size);
773         if (nolcolors < 32)
774             _throw("Color map is not large enough");
775
776         _catch(setcolorscheme(olcolormap, nolcolors, colorscheme));
777
778         if ((olwin = XCreateWindow(dpy, win, 0, 0, width, height, 0, v->depth,
779                                    InputOutput, v->visual, CWBorderPixel | CWColormap | CWEventMask, &swa)) == 0)
780             _throw("Could not create overlay window");
781         XMapWindow(dpy, olwin);
782         XSync(dpy, False);
783
784         if ((olctx = glXCreateContext(dpy, v, NULL, directctx)) == 0)
785             _throw("Could not create overlay rendering context");
786         fprintf(stderr, "Overlay context is %s\n",
787                 glXIsDirect(dpy, olctx) ? "Direct" : "Indirect");
788
789         XFree(v);
790         v = NULL;
791     }
792
793     if (!glXMakeCurrent(dpy, win, ctx))
794         _throw("Could not bind rendering context");
795
796     fprintf(stderr, "OpenGL Renderer: %s\n", glGetString(GL_RENDERER));
797
798     _catch(event_loop(dpy));
799
800     if (dpy && olctx)
801     {
802         glXDestroyContext(dpy, olctx);
803         olctx = 0;
804     }
805     if (dpy && olwin)
806     {
807         XDestroyWindow(dpy, olwin);
808         olwin = 0;
809     }
810     if (dpy && ctx)
811     {
812         glXDestroyContext(dpy, ctx);
813         ctx = 0;
814     }
815     if (dpy && win)
816     {
817         XDestroyWindow(dpy, win);
818         win = 0;
819     }
820     if (dpy)
821         XCloseDisplay(dpy);
822     return 0;
823
824 bailout:
825     if (v)
826         XFree(v);
827     if (dpy && olctx)
828     {
829         glXDestroyContext(dpy, olctx);
830         olctx = 0;
831     }
832     if (dpy && olwin)
833     {
834         XDestroyWindow(dpy, olwin);
835         olwin = 0;
836     }
837     if (dpy && ctx)
838     {
839         glXDestroyContext(dpy, ctx);
840         ctx = 0;
841     }
842     if (dpy && win)
843     {
844         XDestroyWindow(dpy, win);
845         win = 0;
846     }
847     if (dpy)
848         XCloseDisplay(dpy);
849     return -1;
850 }