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