132001f49Smrg/*
232001f49Smrg * Copyright (C) 2009  VMware, Inc.   All Rights Reserved.
332001f49Smrg *
432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
532001f49Smrg * copy of this software and associated documentation files (the "Software"),
632001f49Smrg * to deal in the Software without restriction, including without limitation
732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
932001f49Smrg * Software is furnished to do so, subject to the following conditions:
1032001f49Smrg *
1132001f49Smrg * The above copyright notice and this permission notice shall be included
1232001f49Smrg * in all copies or substantial portions of the Software.
1332001f49Smrg *
1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1532001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1732001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1832001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1932001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2032001f49Smrg */
2132001f49Smrg
2232001f49Smrg/*
2332001f49Smrg * Test rendering with two contexts into one window.
2432001f49Smrg * Setup different rendering state for each context to check that
2532001f49Smrg * context switching is handled properly.
2632001f49Smrg *
2732001f49Smrg * Brian Paul
2832001f49Smrg * 6 Aug 2009
2932001f49Smrg */
3032001f49Smrg
3132001f49Smrg
3232001f49Smrg#include <math.h>
3332001f49Smrg#include <stdlib.h>
3432001f49Smrg#include <stdio.h>
3532001f49Smrg#include <string.h>
3632001f49Smrg#include <sys/time.h>
3732001f49Smrg#include <unistd.h>
3832001f49Smrg#include <X11/Xlib.h>
3932001f49Smrg#include <X11/keysym.h>
4032001f49Smrg#include <GL/gl.h>
4132001f49Smrg#include <GL/glx.h>
4232001f49Smrg
4332001f49Smrg
4432001f49Smrg
4532001f49Smrg#ifndef M_PI
4632001f49Smrg#define M_PI 3.14159265
4732001f49Smrg#endif
4832001f49Smrg
4932001f49Smrg
5032001f49Smrg/** Event handler results: */
5132001f49Smrg#define NOP 0
5232001f49Smrg#define EXIT 1
5332001f49Smrg#define DRAW 2
5432001f49Smrg
5532001f49Smrgstatic GLfloat view_rotx = 0.0, view_roty = 210.0, view_rotz = 0.0;
5632001f49Smrgstatic GLint gear1, gear2;
5732001f49Smrgstatic GLfloat angle = 0.0;
5832001f49Smrg
5932001f49Smrgstatic GLboolean animate = GL_TRUE;	/* Animation */
6032001f49Smrg
6132001f49Smrg
6232001f49Smrgstatic double
6332001f49Smrgcurrent_time(void)
6432001f49Smrg{
6532001f49Smrg   struct timeval tv;
6632001f49Smrg#ifdef __VMS
6732001f49Smrg   (void) gettimeofday(&tv, NULL );
6832001f49Smrg#else
6932001f49Smrg   struct timezone tz;
7032001f49Smrg   (void) gettimeofday(&tv, &tz);
7132001f49Smrg#endif
7232001f49Smrg   return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
7332001f49Smrg}
7432001f49Smrg
7532001f49Smrg
7632001f49Smrg/*
7732001f49Smrg *
7832001f49Smrg *  Draw a gear wheel.  You'll probably want to call this function when
7932001f49Smrg *  building a display list since we do a lot of trig here.
8032001f49Smrg *
8132001f49Smrg *  Input:  inner_radius - radius of hole at center
8232001f49Smrg *          outer_radius - radius at center of teeth
8332001f49Smrg *          width - width of gear
8432001f49Smrg *          teeth - number of teeth
8532001f49Smrg *          tooth_depth - depth of tooth
8632001f49Smrg */
8732001f49Smrgstatic void
8832001f49Smrggear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
8932001f49Smrg     GLint teeth, GLfloat tooth_depth)
9032001f49Smrg{
9132001f49Smrg   GLint i;
9232001f49Smrg   GLfloat r0, r1, r2;
9332001f49Smrg   GLfloat angle, da;
9432001f49Smrg   GLfloat u, v, len;
9532001f49Smrg
9632001f49Smrg   r0 = inner_radius;
9732001f49Smrg   r1 = outer_radius - tooth_depth / 2.0;
9832001f49Smrg   r2 = outer_radius + tooth_depth / 2.0;
9932001f49Smrg
10032001f49Smrg   da = 2.0 * M_PI / teeth / 4.0;
10132001f49Smrg
10232001f49Smrg   glShadeModel(GL_FLAT);
10332001f49Smrg
10432001f49Smrg   glNormal3f(0.0, 0.0, 1.0);
10532001f49Smrg
10632001f49Smrg   /* draw front face */
10732001f49Smrg   glBegin(GL_QUAD_STRIP);
10832001f49Smrg   for (i = 0; i <= teeth; i++) {
10932001f49Smrg      angle = i * 2.0 * M_PI / teeth;
11032001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
11132001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
11232001f49Smrg      if (i < teeth) {
11332001f49Smrg	 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
11432001f49Smrg	 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
11532001f49Smrg		    width * 0.5);
11632001f49Smrg      }
11732001f49Smrg   }
11832001f49Smrg   glEnd();
11932001f49Smrg
12032001f49Smrg   /* draw front sides of teeth */
12132001f49Smrg   glBegin(GL_QUADS);
12232001f49Smrg   da = 2.0 * M_PI / teeth / 4.0;
12332001f49Smrg   for (i = 0; i < teeth; i++) {
12432001f49Smrg      angle = i * 2.0 * M_PI / teeth;
12532001f49Smrg
12632001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
12732001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
12832001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
12932001f49Smrg		 width * 0.5);
13032001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
13132001f49Smrg		 width * 0.5);
13232001f49Smrg   }
13332001f49Smrg   glEnd();
13432001f49Smrg
13532001f49Smrg   glNormal3f(0.0, 0.0, -1.0);
13632001f49Smrg
13732001f49Smrg   /* draw back face */
13832001f49Smrg   glBegin(GL_QUAD_STRIP);
13932001f49Smrg   for (i = 0; i <= teeth; i++) {
14032001f49Smrg      angle = i * 2.0 * M_PI / teeth;
14132001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
14232001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
14332001f49Smrg      if (i < teeth) {
14432001f49Smrg	 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
14532001f49Smrg		    -width * 0.5);
14632001f49Smrg	 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
14732001f49Smrg      }
14832001f49Smrg   }
14932001f49Smrg   glEnd();
15032001f49Smrg
15132001f49Smrg   /* draw back sides of teeth */
15232001f49Smrg   glBegin(GL_QUADS);
15332001f49Smrg   da = 2.0 * M_PI / teeth / 4.0;
15432001f49Smrg   for (i = 0; i < teeth; i++) {
15532001f49Smrg      angle = i * 2.0 * M_PI / teeth;
15632001f49Smrg
15732001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
15832001f49Smrg		 -width * 0.5);
15932001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
16032001f49Smrg		 -width * 0.5);
16132001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
16232001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
16332001f49Smrg   }
16432001f49Smrg   glEnd();
16532001f49Smrg
16632001f49Smrg   /* draw outward faces of teeth */
16732001f49Smrg   glBegin(GL_QUAD_STRIP);
16832001f49Smrg   for (i = 0; i < teeth; i++) {
16932001f49Smrg      angle = i * 2.0 * M_PI / teeth;
17032001f49Smrg
17132001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
17232001f49Smrg      glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
17332001f49Smrg      u = r2 * cos(angle + da) - r1 * cos(angle);
17432001f49Smrg      v = r2 * sin(angle + da) - r1 * sin(angle);
17532001f49Smrg      len = sqrt(u * u + v * v);
17632001f49Smrg      u /= len;
17732001f49Smrg      v /= len;
17832001f49Smrg      glNormal3f(v, -u, 0.0);
17932001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
18032001f49Smrg      glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
18132001f49Smrg      glNormal3f(cos(angle), sin(angle), 0.0);
18232001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
18332001f49Smrg		 width * 0.5);
18432001f49Smrg      glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
18532001f49Smrg		 -width * 0.5);
18632001f49Smrg      u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
18732001f49Smrg      v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
18832001f49Smrg      glNormal3f(v, -u, 0.0);
18932001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
19032001f49Smrg		 width * 0.5);
19132001f49Smrg      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
19232001f49Smrg		 -width * 0.5);
19332001f49Smrg      glNormal3f(cos(angle), sin(angle), 0.0);
19432001f49Smrg   }
19532001f49Smrg
19632001f49Smrg   glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
19732001f49Smrg   glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
19832001f49Smrg
19932001f49Smrg   glEnd();
20032001f49Smrg
20132001f49Smrg   glShadeModel(GL_SMOOTH);
20232001f49Smrg
20332001f49Smrg   /* draw inside radius cylinder */
20432001f49Smrg   glBegin(GL_QUAD_STRIP);
20532001f49Smrg   for (i = 0; i <= teeth; i++) {
20632001f49Smrg      angle = i * 2.0 * M_PI / teeth;
20732001f49Smrg      glNormal3f(-cos(angle), -sin(angle), 0.0);
20832001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
20932001f49Smrg      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
21032001f49Smrg   }
21132001f49Smrg   glEnd();
21232001f49Smrg}
21332001f49Smrg
21432001f49Smrg
21532001f49Smrgstatic void
21632001f49Smrgdraw(int ctx)
21732001f49Smrg{
21832001f49Smrg   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
21932001f49Smrg
22032001f49Smrg   glPushMatrix();
22132001f49Smrg   glRotatef(view_rotx, 1.0, 0.0, 0.0);
22232001f49Smrg   glRotatef(view_roty + angle, 0.0, 1.0, 0.0);
22332001f49Smrg   glRotatef(view_rotz, 0.0, 0.0, 1.0);
22432001f49Smrg
22532001f49Smrg   if (ctx == 0) {
22632001f49Smrg      glDisable(GL_CULL_FACE);
22732001f49Smrg      glPushMatrix();
22832001f49Smrg      glRotatef(angle, 0.0, 0.0, 1.0);
22932001f49Smrg      glCallList(gear1);
23032001f49Smrg      glPopMatrix();
23132001f49Smrg      /* This should not effect the other context's rendering */
23232001f49Smrg      glEnable(GL_CULL_FACE);
23332001f49Smrg      glCullFace(GL_FRONT_AND_BACK);
23432001f49Smrg   }
23532001f49Smrg   else {
23632001f49Smrg      glPushMatrix();
23732001f49Smrg      glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
23832001f49Smrg      glCallList(gear2);
23932001f49Smrg      glPopMatrix();
24032001f49Smrg   }
24132001f49Smrg
24232001f49Smrg   glPopMatrix();
24332001f49Smrg
24432001f49Smrg   /* this flush is important since we'll be switching contexts next */
24532001f49Smrg   glFlush();
24632001f49Smrg}
24732001f49Smrg
24832001f49Smrg
24932001f49Smrg
25032001f49Smrgstatic void
25132001f49Smrgdraw_frame(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
25232001f49Smrg{
25332001f49Smrg   static double tRot0 = -1.0;
25432001f49Smrg   double dt, t = current_time();
25532001f49Smrg
25632001f49Smrg   if (tRot0 < 0.0)
25732001f49Smrg      tRot0 = t;
25832001f49Smrg   dt = t - tRot0;
25932001f49Smrg   tRot0 = t;
26032001f49Smrg
26132001f49Smrg   if (animate) {
26232001f49Smrg      /* advance rotation for next frame */
26332001f49Smrg      angle += 70.0 * dt;  /* 70 degrees per second */
26432001f49Smrg      if (angle > 3600.0)
26532001f49Smrg         angle -= 3600.0;
26632001f49Smrg   }
26732001f49Smrg
26832001f49Smrg   glXMakeCurrent(dpy, (GLXDrawable) win, ctx1);
26932001f49Smrg   draw(0);
27032001f49Smrg
27132001f49Smrg   glXMakeCurrent(dpy, (GLXDrawable) win, ctx2);
27232001f49Smrg   draw(1);
27332001f49Smrg
27432001f49Smrg   glXSwapBuffers(dpy, win);
27532001f49Smrg}
27632001f49Smrg
27732001f49Smrg
27832001f49Smrg/* new window size or exposure */
27932001f49Smrgstatic void
28032001f49Smrgreshape(Display *dpy, Window win,
28132001f49Smrg        GLXContext ctx1, GLXContext ctx2, int width, int height)
28232001f49Smrg{
28332001f49Smrg   int i;
28432001f49Smrg
28532001f49Smrg   width /= 2;
28632001f49Smrg
28732001f49Smrg   /* loop: left half of window, right half of window */
28832001f49Smrg   for (i = 0; i < 2; i++) {
28932001f49Smrg      if (i == 0)
29032001f49Smrg         glXMakeCurrent(dpy, win, ctx1);
29132001f49Smrg      else
29232001f49Smrg         glXMakeCurrent(dpy, win, ctx2);
29332001f49Smrg
29432001f49Smrg      glViewport(width * i, 0, width, height);
29532001f49Smrg      glScissor(width * i, 0, width, height);
29632001f49Smrg
29732001f49Smrg      {
29832001f49Smrg         GLfloat h = (GLfloat) height / (GLfloat) width;
29932001f49Smrg
30032001f49Smrg         glMatrixMode(GL_PROJECTION);
30132001f49Smrg         glLoadIdentity();
30232001f49Smrg         glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
30332001f49Smrg      }
30432001f49Smrg
30532001f49Smrg      glMatrixMode(GL_MODELVIEW);
30632001f49Smrg      glLoadIdentity();
30732001f49Smrg      glTranslatef(0.0, 0.0, -30.0);
30832001f49Smrg   }
30932001f49Smrg}
31032001f49Smrg
31132001f49Smrg
31232001f49Smrg
31332001f49Smrgstatic void
31432001f49Smrginit(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
31532001f49Smrg{
31632001f49Smrg   static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
31732001f49Smrg   static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
31832001f49Smrg   static GLfloat green[4] = { 0.0, 0.8, 0.2, 0.5 };
31932001f49Smrg   /*static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };*/
32032001f49Smrg
32132001f49Smrg   /* first ctx */
32232001f49Smrg   {
32332001f49Smrg      static GLuint stipple[32] = {
32432001f49Smrg         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
32532001f49Smrg         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
32632001f49Smrg
32732001f49Smrg         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
32832001f49Smrg         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
32932001f49Smrg
33032001f49Smrg         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
33132001f49Smrg         0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
33232001f49Smrg
33332001f49Smrg         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
33432001f49Smrg         0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00
33532001f49Smrg      };
33632001f49Smrg
33732001f49Smrg      glXMakeCurrent(dpy, win, ctx1);
33832001f49Smrg
33932001f49Smrg      glLightfv(GL_LIGHT0, GL_POSITION, pos);
34032001f49Smrg      glEnable(GL_LIGHTING);
34132001f49Smrg      glEnable(GL_LIGHT0);
34232001f49Smrg      glEnable(GL_DEPTH_TEST);
34332001f49Smrg
34432001f49Smrg      gear1 = glGenLists(1);
34532001f49Smrg      glNewList(gear1, GL_COMPILE);
34632001f49Smrg      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
34732001f49Smrg      gear(1.0, 4.0, 1.0, 20, 0.7);
34832001f49Smrg      glEndList();
34932001f49Smrg
35032001f49Smrg      glEnable(GL_NORMALIZE);
35132001f49Smrg      glEnable(GL_SCISSOR_TEST);
35232001f49Smrg      glClearColor(0.4, 0.4, 0.4, 1.0);
35332001f49Smrg
35432001f49Smrg      glPolygonStipple((GLubyte *) stipple);
35532001f49Smrg      glEnable(GL_POLYGON_STIPPLE);
35632001f49Smrg   }
35732001f49Smrg
35832001f49Smrg   /* second ctx */
35932001f49Smrg   {
36032001f49Smrg      glXMakeCurrent(dpy, win, ctx2);
36132001f49Smrg
36232001f49Smrg      glLightfv(GL_LIGHT0, GL_POSITION, pos);
36332001f49Smrg      glEnable(GL_LIGHTING);
36432001f49Smrg      glEnable(GL_LIGHT0);
36532001f49Smrg      glEnable(GL_DEPTH_TEST);
36632001f49Smrg
36732001f49Smrg      gear2 = glGenLists(1);
36832001f49Smrg      glNewList(gear2, GL_COMPILE);
36932001f49Smrg      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
37032001f49Smrg      gear(1.5, 3.0, 1.5, 16, 0.7);
37132001f49Smrg      glEndList();
37232001f49Smrg
37332001f49Smrg      glEnable(GL_NORMALIZE);
37432001f49Smrg      glEnable(GL_SCISSOR_TEST);
37532001f49Smrg      glClearColor(0.6, 0.6, 0.6, 1.0);
37632001f49Smrg
37732001f49Smrg      glEnable(GL_BLEND);
37832001f49Smrg      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
37932001f49Smrg   }
38032001f49Smrg}
38132001f49Smrg
38232001f49Smrg
38332001f49Smrg/**
38432001f49Smrg * Create an RGB, double-buffered window.
38532001f49Smrg * Return the window and two context handles.
38632001f49Smrg */
38732001f49Smrgstatic void
38832001f49Smrgmake_window_and_contexts( Display *dpy, const char *name,
38932001f49Smrg                          int x, int y, int width, int height,
39032001f49Smrg                          Window *winRet,
39132001f49Smrg                          GLXContext *ctxRet1,
39232001f49Smrg                          GLXContext *ctxRet2)
39332001f49Smrg{
39432001f49Smrg   int attribs[] = { GLX_RGBA,
39532001f49Smrg                     GLX_RED_SIZE, 1,
39632001f49Smrg                     GLX_GREEN_SIZE, 1,
39732001f49Smrg                     GLX_BLUE_SIZE, 1,
39832001f49Smrg                     GLX_DOUBLEBUFFER,
39932001f49Smrg                     GLX_DEPTH_SIZE, 1,
40032001f49Smrg                     None };
40132001f49Smrg   int scrnum;
40232001f49Smrg   XSetWindowAttributes attr;
40332001f49Smrg   unsigned long mask;
40432001f49Smrg   Window root;
40532001f49Smrg   Window win;
40632001f49Smrg   XVisualInfo *visinfo;
40732001f49Smrg
40832001f49Smrg   scrnum = DefaultScreen( dpy );
40932001f49Smrg   root = RootWindow( dpy, scrnum );
41032001f49Smrg
41132001f49Smrg   visinfo = glXChooseVisual( dpy, scrnum, attribs );
41232001f49Smrg   if (!visinfo) {
41332001f49Smrg      printf("Error: couldn't get an RGB, Double-buffered visual\n");
41432001f49Smrg      exit(1);
41532001f49Smrg   }
41632001f49Smrg
41732001f49Smrg   /* window attributes */
41832001f49Smrg   attr.background_pixel = 0;
41932001f49Smrg   attr.border_pixel = 0;
42032001f49Smrg   attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
42132001f49Smrg   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
42232001f49Smrg   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
42332001f49Smrg
42432001f49Smrg   win = XCreateWindow( dpy, root, x, y, width, height,
42532001f49Smrg		        0, visinfo->depth, InputOutput,
42632001f49Smrg		        visinfo->visual, mask, &attr );
42732001f49Smrg
42832001f49Smrg   /* set hints and properties */
42932001f49Smrg   {
43032001f49Smrg      XSizeHints sizehints;
43132001f49Smrg      sizehints.x = x;
43232001f49Smrg      sizehints.y = y;
43332001f49Smrg      sizehints.width  = width;
43432001f49Smrg      sizehints.height = height;
43532001f49Smrg      sizehints.flags = USSize | USPosition;
43632001f49Smrg      XSetNormalHints(dpy, win, &sizehints);
43732001f49Smrg      XSetStandardProperties(dpy, win, name, name,
43832001f49Smrg                              None, (char **)NULL, 0, &sizehints);
43932001f49Smrg   }
44032001f49Smrg
44132001f49Smrg   *winRet = win;
44232001f49Smrg   *ctxRet1 = glXCreateContext( dpy, visinfo, NULL, True );
44332001f49Smrg   *ctxRet2 = glXCreateContext( dpy, visinfo, NULL, True );
44432001f49Smrg
44532001f49Smrg   if (!*ctxRet1 || !*ctxRet2) {
44632001f49Smrg      printf("Error: glXCreateContext failed\n");
44732001f49Smrg      exit(1);
44832001f49Smrg   }
44932001f49Smrg
45032001f49Smrg   XFree(visinfo);
45132001f49Smrg}
45232001f49Smrg
45332001f49Smrg
45432001f49Smrg/**
45532001f49Smrg * Handle one X event.
45632001f49Smrg * \return NOP, EXIT or DRAW
45732001f49Smrg */
45832001f49Smrgstatic int
45932001f49Smrghandle_event(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2,
46032001f49Smrg             XEvent *event)
46132001f49Smrg{
46232001f49Smrg   (void) dpy;
46332001f49Smrg   (void) win;
46432001f49Smrg
46532001f49Smrg   switch (event->type) {
46632001f49Smrg   case Expose:
46732001f49Smrg      return DRAW;
46832001f49Smrg   case ConfigureNotify:
46932001f49Smrg      reshape(dpy, win, ctx1, ctx2,
47032001f49Smrg              event->xconfigure.width, event->xconfigure.height);
47132001f49Smrg      break;
47232001f49Smrg   case KeyPress:
47332001f49Smrg      {
47432001f49Smrg         char buffer[10];
47532001f49Smrg         int code;
47632001f49Smrg         code = XLookupKeysym(&event->xkey, 0);
47732001f49Smrg         if (code == XK_Left) {
47832001f49Smrg            view_roty += 5.0;
47932001f49Smrg         }
48032001f49Smrg         else if (code == XK_Right) {
48132001f49Smrg            view_roty -= 5.0;
48232001f49Smrg         }
48332001f49Smrg         else if (code == XK_Up) {
48432001f49Smrg            view_rotx += 5.0;
48532001f49Smrg         }
48632001f49Smrg         else if (code == XK_Down) {
48732001f49Smrg            view_rotx -= 5.0;
48832001f49Smrg         }
48932001f49Smrg         else {
49032001f49Smrg            XLookupString(&event->xkey, buffer, sizeof(buffer),
49132001f49Smrg                          NULL, NULL);
49232001f49Smrg            if (buffer[0] == 27) {
49332001f49Smrg               /* escape */
49432001f49Smrg               return EXIT;
49532001f49Smrg            }
49632001f49Smrg            else if (buffer[0] == 'a' || buffer[0] == 'A') {
49732001f49Smrg               animate = !animate;
49832001f49Smrg            }
49932001f49Smrg         }
50032001f49Smrg         return DRAW;
50132001f49Smrg      }
50232001f49Smrg   }
50332001f49Smrg   return NOP;
50432001f49Smrg}
50532001f49Smrg
50632001f49Smrg
50732001f49Smrgstatic void
50832001f49Smrgevent_loop(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
50932001f49Smrg{
51032001f49Smrg   while (1) {
51132001f49Smrg      int op;
51232001f49Smrg      while (!animate || XPending(dpy) > 0) {
51332001f49Smrg         XEvent event;
51432001f49Smrg         XNextEvent(dpy, &event);
51532001f49Smrg         op = handle_event(dpy, win, ctx1, ctx2, &event);
51632001f49Smrg         if (op == EXIT)
51732001f49Smrg            return;
51832001f49Smrg         else if (op == DRAW)
51932001f49Smrg            break;
52032001f49Smrg      }
52132001f49Smrg
52232001f49Smrg      draw_frame(dpy, win, ctx1, ctx2);
52332001f49Smrg   }
52432001f49Smrg}
52532001f49Smrg
52632001f49Smrg
52732001f49Smrgint
52832001f49Smrgmain(int argc, char *argv[])
52932001f49Smrg{
53032001f49Smrg   unsigned int winWidth = 800, winHeight = 400;
53132001f49Smrg   int x = 0, y = 0;
53232001f49Smrg   Display *dpy;
53332001f49Smrg   Window win;
53432001f49Smrg   GLXContext ctx1, ctx2;
53532001f49Smrg   char *dpyName = NULL;
53632001f49Smrg   GLboolean printInfo = GL_FALSE;
53732001f49Smrg   int i;
53832001f49Smrg
53932001f49Smrg   for (i = 1; i < argc; i++) {
54032001f49Smrg      if (strcmp(argv[i], "-display") == 0) {
54132001f49Smrg         dpyName = argv[i+1];
54232001f49Smrg         i++;
54332001f49Smrg      }
54432001f49Smrg      else {
54532001f49Smrg         return 1;
54632001f49Smrg      }
54732001f49Smrg   }
54832001f49Smrg
54932001f49Smrg   dpy = XOpenDisplay(dpyName);
55032001f49Smrg   if (!dpy) {
55132001f49Smrg      printf("Error: couldn't open display %s\n",
55232001f49Smrg	     dpyName ? dpyName : getenv("DISPLAY"));
55332001f49Smrg      return -1;
55432001f49Smrg   }
55532001f49Smrg
55632001f49Smrg   make_window_and_contexts(dpy, "multictx", x, y, winWidth, winHeight,
55732001f49Smrg                            &win, &ctx1, &ctx2);
55832001f49Smrg   XMapWindow(dpy, win);
55932001f49Smrg
56032001f49Smrg   if (printInfo) {
56132001f49Smrg      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
56232001f49Smrg      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
56332001f49Smrg      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
56432001f49Smrg      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
56532001f49Smrg   }
56632001f49Smrg
56732001f49Smrg   init(dpy, win, ctx1, ctx2);
56832001f49Smrg
56932001f49Smrg   /* Set initial projection/viewing transformation.
57032001f49Smrg    * We can't be sure we'll get a ConfigureNotify event when the window
57132001f49Smrg    * first appears.
57232001f49Smrg    */
57332001f49Smrg   reshape(dpy, win, ctx1, ctx2, winWidth, winHeight);
57432001f49Smrg
57532001f49Smrg   event_loop(dpy, win, ctx1, ctx2);
57632001f49Smrg
57732001f49Smrg   glDeleteLists(gear1, 1);
57832001f49Smrg   glDeleteLists(gear2, 1);
57932001f49Smrg   glXDestroyContext(dpy, ctx1);
58032001f49Smrg   glXDestroyContext(dpy, ctx2);
58132001f49Smrg   XDestroyWindow(dpy, win);
58232001f49Smrg   XCloseDisplay(dpy);
58332001f49Smrg
58432001f49Smrg   return 0;
58532001f49Smrg}
586