Merge branch '7.8'
[mesa.git] / progs / xdemos / manywin.c
1 /*
2 * Create N GLX windows/contexts and render to them in round-robin order.
3 * Also, have the contexts share all texture objects.
4 * Press 'd' to delete a texture, 'u' to unbind it.
5 *
6 * Copyright (C) 2000 Brian Paul All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 #include <GL/gl.h>
28 #include <GL/glx.h>
29 #include <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <X11/keysym.h>
35
36
37 /*
38 * Each display/window/context:
39 */
40 struct head {
41 char DisplayName[1000];
42 Display *Dpy;
43 Window Win;
44 GLXContext Context;
45 float Angle;
46 char Renderer[1000];
47 char Vendor[1000];
48 char Version[1000];
49 };
50
51
52 #define MAX_HEADS 200
53 static struct head Heads[MAX_HEADS];
54 static int NumHeads = 0;
55 static GLboolean SwapSeparate = GL_TRUE;
56 static GLuint TexObj = 0;
57
58
59 static void
60 Error(const char *display, const char *msg)
61 {
62 fprintf(stderr, "Error on display %s - %s\n", XDisplayName(display), msg);
63 exit(1);
64 }
65
66
67 static struct head *
68 AddHead(const char *displayName, const char *name)
69 {
70 Display *dpy;
71 Window win;
72 GLXContext ctx;
73 int attrib[] = { GLX_RGBA,
74 GLX_RED_SIZE, 1,
75 GLX_GREEN_SIZE, 1,
76 GLX_BLUE_SIZE, 1,
77 GLX_DOUBLEBUFFER,
78 None };
79 int scrnum;
80 XSetWindowAttributes attr;
81 unsigned long mask;
82 Window root;
83 XVisualInfo *visinfo;
84 int width = 90, height = 90;
85 int xpos = 0, ypos = 0;
86
87 if (NumHeads >= MAX_HEADS)
88 return NULL;
89
90 dpy = XOpenDisplay(displayName);
91 if (!dpy) {
92 Error(displayName, "Unable to open display");
93 return NULL;
94 }
95
96 scrnum = DefaultScreen(dpy);
97 root = RootWindow(dpy, scrnum);
98
99 visinfo = glXChooseVisual(dpy, scrnum, attrib);
100 if (!visinfo) {
101 Error(displayName, "Unable to find RGB, double-buffered visual");
102 return NULL;
103 }
104
105 /* window attributes */
106 xpos = (NumHeads % 10) * 100;
107 ypos = (NumHeads / 10) * 100;
108 printf("%d, %d\n", xpos, ypos);
109 attr.background_pixel = 0;
110 attr.border_pixel = 0;
111 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
112 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
113 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
114
115 win = XCreateWindow(dpy, root, xpos, ypos, width, height,
116 0, visinfo->depth, InputOutput,
117 visinfo->visual, mask, &attr);
118 if (!win) {
119 Error(displayName, "Couldn't create window");
120 return NULL;
121 }
122
123 {
124 XSizeHints sizehints;
125 sizehints.x = xpos;
126 sizehints.y = ypos;
127 sizehints.width = width;
128 sizehints.height = height;
129 sizehints.flags = USSize | USPosition;
130 XSetNormalHints(dpy, win, &sizehints);
131 XSetStandardProperties(dpy, win, name, name,
132 None, (char **)NULL, 0, &sizehints);
133 }
134
135 if (NumHeads == 0) {
136 ctx = glXCreateContext(dpy, visinfo, NULL, True);
137 }
138 else {
139 /* share textures & dlists with 0th context */
140 printf("sharing\n");
141 ctx = glXCreateContext(dpy, visinfo, Heads[0].Context, True);
142 }
143 if (!ctx) {
144 Error(displayName, "Couldn't create GLX context");
145 return NULL;
146 }
147
148 XMapWindow(dpy, win);
149
150 if (!glXMakeCurrent(dpy, win, ctx)) {
151 Error(displayName, "glXMakeCurrent failed");
152 printf("glXMakeCurrent failed in Redraw()\n");
153 return NULL;
154 }
155
156 if (NumHeads == 0) {
157 /* create texture object now */
158 static const GLubyte checker[2][2][4] = {
159 { {255, 255, 255, 255}, { 0, 0, 0, 255} },
160 { { 0, 0, 0, 0}, {255, 255, 255, 255} }
161 };
162 glGenTextures(1, &TexObj);
163 assert(TexObj);
164 glBindTexture(GL_TEXTURE_2D, TexObj);
165 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGB,
166 GL_UNSIGNED_BYTE, checker);
167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
169 }
170 else {
171 /* bind 0th context's texture in this context too */
172 assert(TexObj);
173 glBindTexture(GL_TEXTURE_2D, TexObj);
174 }
175 glEnable(GL_TEXTURE_2D);
176
177 /* save the info for this head */
178 {
179 struct head *h = &Heads[NumHeads];
180 const char * tmp;
181
182 if (strlen(name) + 1 > sizeof(h->DisplayName)) {
183 Error(displayName, "name string overflow");
184 return NULL;
185 }
186 strcpy(h->DisplayName, name);
187
188 h->Dpy = dpy;
189 h->Win = win;
190 h->Context = ctx;
191 h->Angle = 0.0;
192
193 tmp = (char *) glGetString(GL_VERSION);
194 if (strlen(tmp) + 1 > sizeof(h->Version)) {
195 Error(displayName, "GL_VERSION string overflow");
196 return NULL;
197 }
198 strcpy(h->Version, tmp);
199
200 tmp = (char *) glGetString(GL_VENDOR);
201 if (strlen(tmp) + 1 > sizeof(h->Vendor)) {
202 Error(displayName, "GL_VENDOR string overflow");
203 return NULL;
204 }
205 strcpy(h->Vendor, tmp);
206
207 tmp = (char *) glGetString(GL_RENDERER);
208 if (strlen(tmp) + 1 > sizeof(h->Renderer)) {
209 Error(displayName, "GL_RENDERER string overflow");
210 return NULL;
211 }
212 strcpy(h->Renderer, tmp);
213
214 NumHeads++;
215 return &Heads[NumHeads-1];
216 }
217
218 }
219
220
221 static void
222 DestroyHeads(void)
223 {
224 int i;
225 for (i = 0; i < NumHeads; i++) {
226 XDestroyWindow(Heads[i].Dpy, Heads[i].Win);
227 glXDestroyContext(Heads[i].Dpy, Heads[i].Context);
228 XCloseDisplay(Heads[i].Dpy);
229 }
230 }
231
232
233 static void
234 Redraw(struct head *h)
235 {
236 if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
237 Error(h->DisplayName, "glXMakeCurrent failed");
238 printf("glXMakeCurrent failed in Redraw()\n");
239 return;
240 }
241
242 h->Angle += 1.0;
243
244 glShadeModel(GL_FLAT);
245 glClearColor(0.5, 0.5, 0.5, 1.0);
246 glClear(GL_COLOR_BUFFER_BIT);
247
248 /* draw green triangle */
249 glColor3f(0.0, 1.0, 0.0);
250 glPushMatrix();
251 glRotatef(h->Angle, 0, 0, 1);
252 glBegin(GL_TRIANGLES);
253 glTexCoord2f(0.5, 1.0); glVertex2f(0, 0.8);
254 glTexCoord2f(0.0, 0.0); glVertex2f(-0.8, -0.7);
255 glTexCoord2f(1.0, 0.0); glVertex2f(0.8, -0.7);
256 glEnd();
257 glPopMatrix();
258
259 if (!SwapSeparate)
260 glXSwapBuffers(h->Dpy, h->Win);
261 }
262
263
264 static void
265 Swap(struct head *h)
266 {
267 glXSwapBuffers(h->Dpy, h->Win);
268 }
269
270
271 static void
272 Resize(const struct head *h, unsigned int width, unsigned int height)
273 {
274 if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
275 Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
276 return;
277 }
278 glFlush();
279 glViewport(0, 0, width, height);
280 glMatrixMode(GL_PROJECTION);
281 glLoadIdentity();
282 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
283 }
284
285
286
287 static void
288 EventLoop(void)
289 {
290 while (1) {
291 int i;
292 for (i = 0; i < NumHeads; i++) {
293 struct head *h = &Heads[i];
294 while (XPending(h->Dpy) > 0) {
295 XEvent event;
296 XNextEvent(h->Dpy, &event);
297 if (event.xany.window == h->Win) {
298 switch (event.type) {
299 case Expose:
300 Redraw(h);
301 if (SwapSeparate)
302 Swap(h);
303 break;
304 case ConfigureNotify:
305 Resize(h, event.xconfigure.width, event.xconfigure.height);
306 break;
307 case KeyPress:
308 {
309 char buf[100];
310 KeySym keySym;
311 XComposeStatus stat;
312 XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
313 switch (keySym) {
314 case XK_Escape:
315 return;
316 break;
317 case XK_d:
318 case XK_D:
319 printf("Delete Texture in window %d\n", i);
320 glXMakeCurrent(h->Dpy, h->Win, h->Context);
321 glDeleteTextures(1, &TexObj);
322 break;
323 case XK_u:
324 case XK_U:
325 printf("Unbind Texture in window %d\n", i);
326 glXMakeCurrent(h->Dpy, h->Win, h->Context);
327 glBindTexture(GL_TEXTURE_2D, 0);
328 break;
329 }
330 }
331 break;
332 default:
333 /*no-op*/ ;
334 }
335 }
336 else {
337 printf("window mismatch\n");
338 }
339 }
340 }
341
342 /* redraw all windows */
343 for (i = 0; i < NumHeads; i++) {
344 Redraw(&Heads[i]);
345 }
346 /* swapbuffers on all windows, if not already done */
347 if (SwapSeparate) {
348 for (i = 0; i < NumHeads; i++) {
349 Swap(&Heads[i]);
350 }
351 }
352 usleep(1);
353 }
354 }
355
356
357
358 static void
359 PrintInfo(const struct head *h)
360 {
361 printf("Name: %s\n", h->DisplayName);
362 printf(" Display: %p\n", (void *) h->Dpy);
363 printf(" Window: 0x%x\n", (int) h->Win);
364 printf(" Context: 0x%lx\n", (long) h->Context);
365 printf(" GL_VERSION: %s\n", h->Version);
366 printf(" GL_VENDOR: %s\n", h->Vendor);
367 printf(" GL_RENDERER: %s\n", h->Renderer);
368 }
369
370
371 int
372 main(int argc, char *argv[])
373 {
374 char *dpyName = NULL;
375 int i;
376
377 if (argc == 1) {
378 printf("manywin: open N simultaneous glx windows\n");
379 printf("Usage:\n");
380 printf(" manywin [-s] numWindows\n");
381 printf("Options:\n");
382 printf(" -s = swap immediately after drawing (see src code)\n");
383 printf("Example:\n");
384 printf(" manywin 10\n");
385 return 0;
386 }
387 else {
388 int n = 3;
389 for (i = 1; i < argc; i++) {
390 if (strcmp(argv[i], "-s") == 0) {
391 SwapSeparate = GL_FALSE;
392 }
393 else if (strcmp(argv[i], "-display") == 0 && i < argc) {
394 dpyName = argv[i+1];
395 i++;
396 }
397 else {
398 n = atoi(argv[i]);
399 }
400 }
401 if (n < 1)
402 n = 1;
403 if (n > MAX_HEADS)
404 n = MAX_HEADS;
405
406 printf("%d windows\n", n);
407 for (i = 0; i < n; i++) {
408 char name[100];
409 struct head *h;
410 sprintf(name, "%d", i);
411 h = AddHead(dpyName, name);
412 if (h) {
413 PrintInfo(h);
414 }
415 }
416 }
417
418 EventLoop();
419 DestroyHeads();
420 return 0;
421 }