2 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * Test rendering with two contexts into one window.
24 * Setup different rendering state for each context to check that
25 * context switching is handled properly.
39 #include <X11/keysym.h>
46 #define M_PI 3.14159265
50 /** Event handler results: */
55 static GLfloat view_rotx
= 0.0, view_roty
= 210.0, view_rotz
= 0.0;
56 static GLint gear1
, gear2
;
57 static GLfloat angle
= 0.0;
59 static GLboolean animate
= GL_TRUE
; /* Animation */
67 (void) gettimeofday(&tv
, NULL
);
70 (void) gettimeofday(&tv
, &tz
);
72 return (double) tv
.tv_sec
+ tv
.tv_usec
/ 1000000.0;
78 * Draw a gear wheel. You'll probably want to call this function when
79 * building a display list since we do a lot of trig here.
81 * Input: inner_radius - radius of hole at center
82 * outer_radius - radius at center of teeth
83 * width - width of gear
84 * teeth - number of teeth
85 * tooth_depth - depth of tooth
88 gear(GLfloat inner_radius
, GLfloat outer_radius
, GLfloat width
,
89 GLint teeth
, GLfloat tooth_depth
)
97 r1
= outer_radius
- tooth_depth
/ 2.0;
98 r2
= outer_radius
+ tooth_depth
/ 2.0;
100 da
= 2.0 * M_PI
/ teeth
/ 4.0;
102 glShadeModel(GL_FLAT
);
104 glNormal3f(0.0, 0.0, 1.0);
106 /* draw front face */
107 glBegin(GL_QUAD_STRIP
);
108 for (i
= 0; i
<= teeth
; i
++) {
109 angle
= i
* 2.0 * M_PI
/ teeth
;
110 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
111 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
113 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
114 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
120 /* draw front sides of teeth */
122 da
= 2.0 * M_PI
/ teeth
/ 4.0;
123 for (i
= 0; i
< teeth
; i
++) {
124 angle
= i
* 2.0 * M_PI
/ teeth
;
126 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
127 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
128 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
130 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
135 glNormal3f(0.0, 0.0, -1.0);
138 glBegin(GL_QUAD_STRIP
);
139 for (i
= 0; i
<= teeth
; i
++) {
140 angle
= i
* 2.0 * M_PI
/ teeth
;
141 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
142 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
144 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
146 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
151 /* draw back sides of teeth */
153 da
= 2.0 * M_PI
/ teeth
/ 4.0;
154 for (i
= 0; i
< teeth
; i
++) {
155 angle
= i
* 2.0 * M_PI
/ teeth
;
157 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
159 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
161 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
162 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
166 /* draw outward faces of teeth */
167 glBegin(GL_QUAD_STRIP
);
168 for (i
= 0; i
< teeth
; i
++) {
169 angle
= i
* 2.0 * M_PI
/ teeth
;
171 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), width
* 0.5);
172 glVertex3f(r1
* cos(angle
), r1
* sin(angle
), -width
* 0.5);
173 u
= r2
* cos(angle
+ da
) - r1
* cos(angle
);
174 v
= r2
* sin(angle
+ da
) - r1
* sin(angle
);
175 len
= sqrt(u
* u
+ v
* v
);
178 glNormal3f(v
, -u
, 0.0);
179 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), width
* 0.5);
180 glVertex3f(r2
* cos(angle
+ da
), r2
* sin(angle
+ da
), -width
* 0.5);
181 glNormal3f(cos(angle
), sin(angle
), 0.0);
182 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
184 glVertex3f(r2
* cos(angle
+ 2 * da
), r2
* sin(angle
+ 2 * da
),
186 u
= r1
* cos(angle
+ 3 * da
) - r2
* cos(angle
+ 2 * da
);
187 v
= r1
* sin(angle
+ 3 * da
) - r2
* sin(angle
+ 2 * da
);
188 glNormal3f(v
, -u
, 0.0);
189 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
191 glVertex3f(r1
* cos(angle
+ 3 * da
), r1
* sin(angle
+ 3 * da
),
193 glNormal3f(cos(angle
), sin(angle
), 0.0);
196 glVertex3f(r1
* cos(0), r1
* sin(0), width
* 0.5);
197 glVertex3f(r1
* cos(0), r1
* sin(0), -width
* 0.5);
201 glShadeModel(GL_SMOOTH
);
203 /* draw inside radius cylinder */
204 glBegin(GL_QUAD_STRIP
);
205 for (i
= 0; i
<= teeth
; i
++) {
206 angle
= i
* 2.0 * M_PI
/ teeth
;
207 glNormal3f(-cos(angle
), -sin(angle
), 0.0);
208 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), -width
* 0.5);
209 glVertex3f(r0
* cos(angle
), r0
* sin(angle
), width
* 0.5);
218 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
221 glRotatef(view_rotx
, 1.0, 0.0, 0.0);
222 glRotatef(view_roty
+ angle
, 0.0, 1.0, 0.0);
223 glRotatef(view_rotz
, 0.0, 0.0, 1.0);
226 glDisable(GL_CULL_FACE
);
228 glRotatef(angle
, 0.0, 0.0, 1.0);
231 /* This should not effect the other context's rendering */
232 glEnable(GL_CULL_FACE
);
233 glCullFace(GL_FRONT_AND_BACK
);
237 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
244 /* this flush is important since we'll be switching contexts next */
251 draw_frame(Display
*dpy
, Window win
, GLXContext ctx1
, GLXContext ctx2
)
253 static double tRot0
= -1.0;
254 double dt
, t
= current_time();
262 /* advance rotation for next frame */
263 angle
+= 70.0 * dt
; /* 70 degrees per second */
268 glXMakeCurrent(dpy
, (GLXDrawable
) win
, ctx1
);
271 glXMakeCurrent(dpy
, (GLXDrawable
) win
, ctx2
);
274 glXSwapBuffers(dpy
, win
);
278 /* new window size or exposure */
280 reshape(Display
*dpy
, Window win
,
281 GLXContext ctx1
, GLXContext ctx2
, int width
, int height
)
287 /* loop: left half of window, right half of window */
288 for (i
= 0; i
< 2; i
++) {
290 glXMakeCurrent(dpy
, win
, ctx1
);
292 glXMakeCurrent(dpy
, win
, ctx2
);
294 glViewport(width
* i
, 0, width
, height
);
295 glScissor(width
* i
, 0, width
, height
);
298 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
300 glMatrixMode(GL_PROJECTION
);
302 glFrustum(-1.0, 1.0, -h
, h
, 5.0, 60.0);
305 glMatrixMode(GL_MODELVIEW
);
307 glTranslatef(0.0, 0.0, -30.0);
314 init(Display
*dpy
, Window win
, GLXContext ctx1
, GLXContext ctx2
)
316 static GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
317 static GLfloat red
[4] = { 0.8, 0.1, 0.0, 1.0 };
318 static GLfloat green
[4] = { 0.0, 0.8, 0.2, 0.5 };
319 /*static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };*/
323 static GLuint stipple
[32] = {
324 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
325 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
327 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
328 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
330 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
331 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
333 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
334 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00
337 glXMakeCurrent(dpy
, win
, ctx1
);
339 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
340 glEnable(GL_LIGHTING
);
342 glEnable(GL_DEPTH_TEST
);
344 gear1
= glGenLists(1);
345 glNewList(gear1
, GL_COMPILE
);
346 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, red
);
347 gear(1.0, 4.0, 1.0, 20, 0.7);
350 glEnable(GL_NORMALIZE
);
351 glEnable(GL_SCISSOR_TEST
);
352 glClearColor(0.4, 0.4, 0.4, 1.0);
354 glPolygonStipple((GLubyte
*) stipple
);
355 glEnable(GL_POLYGON_STIPPLE
);
360 glXMakeCurrent(dpy
, win
, ctx2
);
362 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
363 glEnable(GL_LIGHTING
);
365 glEnable(GL_DEPTH_TEST
);
367 gear2
= glGenLists(1);
368 glNewList(gear2
, GL_COMPILE
);
369 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, green
);
370 gear(1.5, 3.0, 1.5, 16, 0.7);
373 glEnable(GL_NORMALIZE
);
374 glEnable(GL_SCISSOR_TEST
);
375 glClearColor(0.6, 0.6, 0.6, 1.0);
378 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
384 * Create an RGB, double-buffered window.
385 * Return the window and two context handles.
388 make_window_and_contexts( Display
*dpy
, const char *name
,
389 int x
, int y
, int width
, int height
,
394 int attribs
[] = { GLX_RGBA
,
402 XSetWindowAttributes attr
;
406 XVisualInfo
*visinfo
;
408 scrnum
= DefaultScreen( dpy
);
409 root
= RootWindow( dpy
, scrnum
);
411 visinfo
= glXChooseVisual( dpy
, scrnum
, attribs
);
413 printf("Error: couldn't get an RGB, Double-buffered visual\n");
417 /* window attributes */
418 attr
.background_pixel
= 0;
419 attr
.border_pixel
= 0;
420 attr
.colormap
= XCreateColormap( dpy
, root
, visinfo
->visual
, AllocNone
);
421 attr
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
422 mask
= CWBackPixel
| CWBorderPixel
| CWColormap
| CWEventMask
;
424 win
= XCreateWindow( dpy
, root
, x
, y
, width
, height
,
425 0, visinfo
->depth
, InputOutput
,
426 visinfo
->visual
, mask
, &attr
);
428 /* set hints and properties */
430 XSizeHints sizehints
;
433 sizehints
.width
= width
;
434 sizehints
.height
= height
;
435 sizehints
.flags
= USSize
| USPosition
;
436 XSetNormalHints(dpy
, win
, &sizehints
);
437 XSetStandardProperties(dpy
, win
, name
, name
,
438 None
, (char **)NULL
, 0, &sizehints
);
442 *ctxRet1
= glXCreateContext( dpy
, visinfo
, NULL
, True
);
443 *ctxRet2
= glXCreateContext( dpy
, visinfo
, NULL
, True
);
445 if (!*ctxRet1
|| !*ctxRet2
) {
446 printf("Error: glXCreateContext failed\n");
455 * Handle one X event.
456 * \return NOP, EXIT or DRAW
459 handle_event(Display
*dpy
, Window win
, GLXContext ctx1
, GLXContext ctx2
,
465 switch (event
->type
) {
468 case ConfigureNotify
:
469 reshape(dpy
, win
, ctx1
, ctx2
,
470 event
->xconfigure
.width
, event
->xconfigure
.height
);
476 code
= XLookupKeysym(&event
->xkey
, 0);
477 if (code
== XK_Left
) {
480 else if (code
== XK_Right
) {
483 else if (code
== XK_Up
) {
486 else if (code
== XK_Down
) {
490 r
= XLookupString(&event
->xkey
, buffer
, sizeof(buffer
),
492 if (buffer
[0] == 27) {
496 else if (buffer
[0] == 'a' || buffer
[0] == 'A') {
508 event_loop(Display
*dpy
, Window win
, GLXContext ctx1
, GLXContext ctx2
)
512 while (!animate
|| XPending(dpy
) > 0) {
514 XNextEvent(dpy
, &event
);
515 op
= handle_event(dpy
, win
, ctx1
, ctx2
, &event
);
522 draw_frame(dpy
, win
, ctx1
, ctx2
);
528 main(int argc
, char *argv
[])
530 unsigned int winWidth
= 800, winHeight
= 400;
534 GLXContext ctx1
, ctx2
;
535 char *dpyName
= NULL
;
536 GLboolean printInfo
= GL_FALSE
;
539 for (i
= 1; i
< argc
; i
++) {
540 if (strcmp(argv
[i
], "-display") == 0) {
549 dpy
= XOpenDisplay(dpyName
);
551 printf("Error: couldn't open display %s\n",
552 dpyName
? dpyName
: getenv("DISPLAY"));
556 make_window_and_contexts(dpy
, "multictx", x
, y
, winWidth
, winHeight
,
558 XMapWindow(dpy
, win
);
561 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
562 printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION
));
563 printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR
));
564 printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS
));
567 init(dpy
, win
, ctx1
, ctx2
);
569 /* Set initial projection/viewing transformation.
570 * We can't be sure we'll get a ConfigureNotify event when the window
573 reshape(dpy
, win
, ctx1
, ctx2
, winWidth
, winHeight
);
575 event_loop(dpy
, win
, ctx1
, ctx2
);
577 glDeleteLists(gear1
, 1);
578 glDeleteLists(gear2
, 1);
579 glXDestroyContext(dpy
, ctx1
);
580 glXDestroyContext(dpy
, ctx2
);
581 XDestroyWindow(dpy
, win
);