Merge branch '7.8' into master
[mesa.git] / progs / xdemos / multictx.c
1 /*
2 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
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.
20 */
21
22 /*
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.
26 *
27 * Brian Paul
28 * 6 Aug 2009
29 */
30
31
32 #include <math.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <unistd.h>
38 #include <X11/Xlib.h>
39 #include <X11/keysym.h>
40 #include <GL/gl.h>
41 #include <GL/glx.h>
42
43
44
45 #ifndef M_PI
46 #define M_PI 3.14159265
47 #endif
48
49
50 /** Event handler results: */
51 #define NOP 0
52 #define EXIT 1
53 #define DRAW 2
54
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;
58
59 static GLboolean animate = GL_TRUE; /* Animation */
60
61
62 static double
63 current_time(void)
64 {
65 struct timeval tv;
66 #ifdef __VMS
67 (void) gettimeofday(&tv, NULL );
68 #else
69 struct timezone tz;
70 (void) gettimeofday(&tv, &tz);
71 #endif
72 return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
73 }
74
75
76 /*
77 *
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.
80 *
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
86 */
87 static void
88 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
89 GLint teeth, GLfloat tooth_depth)
90 {
91 GLint i;
92 GLfloat r0, r1, r2;
93 GLfloat angle, da;
94 GLfloat u, v, len;
95
96 r0 = inner_radius;
97 r1 = outer_radius - tooth_depth / 2.0;
98 r2 = outer_radius + tooth_depth / 2.0;
99
100 da = 2.0 * M_PI / teeth / 4.0;
101
102 glShadeModel(GL_FLAT);
103
104 glNormal3f(0.0, 0.0, 1.0);
105
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);
112 if (i < teeth) {
113 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
114 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
115 width * 0.5);
116 }
117 }
118 glEnd();
119
120 /* draw front sides of teeth */
121 glBegin(GL_QUADS);
122 da = 2.0 * M_PI / teeth / 4.0;
123 for (i = 0; i < teeth; i++) {
124 angle = i * 2.0 * M_PI / teeth;
125
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),
129 width * 0.5);
130 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
131 width * 0.5);
132 }
133 glEnd();
134
135 glNormal3f(0.0, 0.0, -1.0);
136
137 /* draw back face */
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);
143 if (i < teeth) {
144 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
145 -width * 0.5);
146 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
147 }
148 }
149 glEnd();
150
151 /* draw back sides of teeth */
152 glBegin(GL_QUADS);
153 da = 2.0 * M_PI / teeth / 4.0;
154 for (i = 0; i < teeth; i++) {
155 angle = i * 2.0 * M_PI / teeth;
156
157 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
158 -width * 0.5);
159 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
160 -width * 0.5);
161 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
162 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
163 }
164 glEnd();
165
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;
170
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);
176 u /= len;
177 v /= len;
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),
183 width * 0.5);
184 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
185 -width * 0.5);
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),
190 width * 0.5);
191 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
192 -width * 0.5);
193 glNormal3f(cos(angle), sin(angle), 0.0);
194 }
195
196 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
197 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
198
199 glEnd();
200
201 glShadeModel(GL_SMOOTH);
202
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);
210 }
211 glEnd();
212 }
213
214
215 static void
216 draw(int ctx)
217 {
218 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
219
220 glPushMatrix();
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);
224
225 if (ctx == 0) {
226 glDisable(GL_CULL_FACE);
227 glPushMatrix();
228 glRotatef(angle, 0.0, 0.0, 1.0);
229 glCallList(gear1);
230 glPopMatrix();
231 /* This should not effect the other context's rendering */
232 glEnable(GL_CULL_FACE);
233 glCullFace(GL_FRONT_AND_BACK);
234 }
235 else {
236 glPushMatrix();
237 glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
238 glCallList(gear2);
239 glPopMatrix();
240 }
241
242 glPopMatrix();
243
244 /* this flush is important since we'll be switching contexts next */
245 glFlush();
246 }
247
248
249
250 static void
251 draw_frame(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
252 {
253 static double tRot0 = -1.0;
254 double dt, t = current_time();
255
256 if (tRot0 < 0.0)
257 tRot0 = t;
258 dt = t - tRot0;
259 tRot0 = t;
260
261 if (animate) {
262 /* advance rotation for next frame */
263 angle += 70.0 * dt; /* 70 degrees per second */
264 if (angle > 3600.0)
265 angle -= 3600.0;
266 }
267
268 glXMakeCurrent(dpy, (GLXDrawable) win, ctx1);
269 draw(0);
270
271 glXMakeCurrent(dpy, (GLXDrawable) win, ctx2);
272 draw(1);
273
274 glXSwapBuffers(dpy, win);
275 }
276
277
278 /* new window size or exposure */
279 static void
280 reshape(Display *dpy, Window win,
281 GLXContext ctx1, GLXContext ctx2, int width, int height)
282 {
283 int i;
284
285 width /= 2;
286
287 /* loop: left half of window, right half of window */
288 for (i = 0; i < 2; i++) {
289 if (i == 0)
290 glXMakeCurrent(dpy, win, ctx1);
291 else
292 glXMakeCurrent(dpy, win, ctx2);
293
294 glViewport(width * i, 0, width, height);
295 glScissor(width * i, 0, width, height);
296
297 {
298 GLfloat h = (GLfloat) height / (GLfloat) width;
299
300 glMatrixMode(GL_PROJECTION);
301 glLoadIdentity();
302 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
303 }
304
305 glMatrixMode(GL_MODELVIEW);
306 glLoadIdentity();
307 glTranslatef(0.0, 0.0, -30.0);
308 }
309 }
310
311
312
313 static void
314 init(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
315 {
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 };*/
320
321 /* first ctx */
322 {
323 static GLuint stipple[32] = {
324 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
325 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
326
327 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
328 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
329
330 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
331 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
332
333 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
334 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00
335 };
336
337 glXMakeCurrent(dpy, win, ctx1);
338
339 glLightfv(GL_LIGHT0, GL_POSITION, pos);
340 glEnable(GL_LIGHTING);
341 glEnable(GL_LIGHT0);
342 glEnable(GL_DEPTH_TEST);
343
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);
348 glEndList();
349
350 glEnable(GL_NORMALIZE);
351 glEnable(GL_SCISSOR_TEST);
352 glClearColor(0.4, 0.4, 0.4, 1.0);
353
354 glPolygonStipple((GLubyte *) stipple);
355 glEnable(GL_POLYGON_STIPPLE);
356 }
357
358 /* second ctx */
359 {
360 glXMakeCurrent(dpy, win, ctx2);
361
362 glLightfv(GL_LIGHT0, GL_POSITION, pos);
363 glEnable(GL_LIGHTING);
364 glEnable(GL_LIGHT0);
365 glEnable(GL_DEPTH_TEST);
366
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);
371 glEndList();
372
373 glEnable(GL_NORMALIZE);
374 glEnable(GL_SCISSOR_TEST);
375 glClearColor(0.6, 0.6, 0.6, 1.0);
376
377 glEnable(GL_BLEND);
378 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
379 }
380 }
381
382
383 /**
384 * Create an RGB, double-buffered window.
385 * Return the window and two context handles.
386 */
387 static void
388 make_window_and_contexts( Display *dpy, const char *name,
389 int x, int y, int width, int height,
390 Window *winRet,
391 GLXContext *ctxRet1,
392 GLXContext *ctxRet2)
393 {
394 int attribs[] = { GLX_RGBA,
395 GLX_RED_SIZE, 1,
396 GLX_GREEN_SIZE, 1,
397 GLX_BLUE_SIZE, 1,
398 GLX_DOUBLEBUFFER,
399 GLX_DEPTH_SIZE, 1,
400 None };
401 int scrnum;
402 XSetWindowAttributes attr;
403 unsigned long mask;
404 Window root;
405 Window win;
406 XVisualInfo *visinfo;
407
408 scrnum = DefaultScreen( dpy );
409 root = RootWindow( dpy, scrnum );
410
411 visinfo = glXChooseVisual( dpy, scrnum, attribs );
412 if (!visinfo) {
413 printf("Error: couldn't get an RGB, Double-buffered visual\n");
414 exit(1);
415 }
416
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;
423
424 win = XCreateWindow( dpy, root, x, y, width, height,
425 0, visinfo->depth, InputOutput,
426 visinfo->visual, mask, &attr );
427
428 /* set hints and properties */
429 {
430 XSizeHints sizehints;
431 sizehints.x = x;
432 sizehints.y = y;
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);
439 }
440
441 *winRet = win;
442 *ctxRet1 = glXCreateContext( dpy, visinfo, NULL, True );
443 *ctxRet2 = glXCreateContext( dpy, visinfo, NULL, True );
444
445 if (!*ctxRet1 || !*ctxRet2) {
446 printf("Error: glXCreateContext failed\n");
447 exit(1);
448 }
449
450 XFree(visinfo);
451 }
452
453
454 /**
455 * Handle one X event.
456 * \return NOP, EXIT or DRAW
457 */
458 static int
459 handle_event(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2,
460 XEvent *event)
461 {
462 (void) dpy;
463 (void) win;
464
465 switch (event->type) {
466 case Expose:
467 return DRAW;
468 case ConfigureNotify:
469 reshape(dpy, win, ctx1, ctx2,
470 event->xconfigure.width, event->xconfigure.height);
471 break;
472 case KeyPress:
473 {
474 char buffer[10];
475 int r, code;
476 code = XLookupKeysym(&event->xkey, 0);
477 if (code == XK_Left) {
478 view_roty += 5.0;
479 }
480 else if (code == XK_Right) {
481 view_roty -= 5.0;
482 }
483 else if (code == XK_Up) {
484 view_rotx += 5.0;
485 }
486 else if (code == XK_Down) {
487 view_rotx -= 5.0;
488 }
489 else {
490 r = XLookupString(&event->xkey, buffer, sizeof(buffer),
491 NULL, NULL);
492 if (buffer[0] == 27) {
493 /* escape */
494 return EXIT;
495 }
496 else if (buffer[0] == 'a' || buffer[0] == 'A') {
497 animate = !animate;
498 }
499 }
500 return DRAW;
501 }
502 }
503 return NOP;
504 }
505
506
507 static void
508 event_loop(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
509 {
510 while (1) {
511 int op;
512 while (!animate || XPending(dpy) > 0) {
513 XEvent event;
514 XNextEvent(dpy, &event);
515 op = handle_event(dpy, win, ctx1, ctx2, &event);
516 if (op == EXIT)
517 return;
518 else if (op == DRAW)
519 break;
520 }
521
522 draw_frame(dpy, win, ctx1, ctx2);
523 }
524 }
525
526
527 int
528 main(int argc, char *argv[])
529 {
530 unsigned int winWidth = 800, winHeight = 400;
531 int x = 0, y = 0;
532 Display *dpy;
533 Window win;
534 GLXContext ctx1, ctx2;
535 char *dpyName = NULL;
536 GLboolean printInfo = GL_FALSE;
537 int i;
538
539 for (i = 1; i < argc; i++) {
540 if (strcmp(argv[i], "-display") == 0) {
541 dpyName = argv[i+1];
542 i++;
543 }
544 else {
545 return 1;
546 }
547 }
548
549 dpy = XOpenDisplay(dpyName);
550 if (!dpy) {
551 printf("Error: couldn't open display %s\n",
552 dpyName ? dpyName : getenv("DISPLAY"));
553 return -1;
554 }
555
556 make_window_and_contexts(dpy, "multictx", x, y, winWidth, winHeight,
557 &win, &ctx1, &ctx2);
558 XMapWindow(dpy, win);
559
560 if (printInfo) {
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));
565 }
566
567 init(dpy, win, ctx1, ctx2);
568
569 /* Set initial projection/viewing transformation.
570 * We can't be sure we'll get a ConfigureNotify event when the window
571 * first appears.
572 */
573 reshape(dpy, win, ctx1, ctx2, winWidth, winHeight);
574
575 event_loop(dpy, win, ctx1, ctx2);
576
577 glDeleteLists(gear1, 1);
578 glDeleteLists(gear2, 1);
579 glXDestroyContext(dpy, ctx1);
580 glXDestroyContext(dpy, ctx2);
581 XDestroyWindow(dpy, win);
582 XCloseDisplay(dpy);
583
584 return 0;
585 }