blob: a0286bdbcb5ba8d65711b71a4cb5f9497ce83991 [file] [log] [blame]
Brian Paul0852d0b2000-06-13 19:41:30 +00001/*
2 * Create N GLX windows/contexts and render to them in round-robin
3 * order.
4 *
5 * Copyright (C) 2000 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26#include <GL/gl.h>
27#include <GL/glx.h>
28#include <stdio.h>
29#include <stdlib.h>
Brian Paul1b2976f2001-11-26 17:21:46 +000030#include <string.h>
Brian Paul0852d0b2000-06-13 19:41:30 +000031#include <unistd.h>
32
33
34/*
35 * Each display/window/context:
36 */
37struct head {
38 char DisplayName[1000];
39 Display *Dpy;
40 Window Win;
41 GLXContext Context;
42 float Angle;
43 char Renderer[1000];
44 char Vendor[1000];
45 char Version[1000];
46};
47
48
49#define MAX_HEADS 200
50static struct head Heads[MAX_HEADS];
51static int NumHeads = 0;
Brian Paulfac5fd22000-12-02 20:33:05 +000052static GLboolean SwapSeparate = GL_TRUE;
53
Brian Paul0852d0b2000-06-13 19:41:30 +000054
55
56static void
57Error(const char *display, const char *msg)
58{
59 fprintf(stderr, "Error on display %s - %s\n", display, msg);
60 exit(1);
61}
62
63
64static struct head *
65AddHead(const char *displayName, const char *name)
66{
67 Display *dpy;
68 Window win;
69 GLXContext ctx;
70 int attrib[] = { GLX_RGBA,
71 GLX_RED_SIZE, 1,
72 GLX_GREEN_SIZE, 1,
73 GLX_BLUE_SIZE, 1,
74 GLX_DOUBLEBUFFER,
75 None };
76 int scrnum;
77 XSetWindowAttributes attr;
78 unsigned long mask;
79 Window root;
80 XVisualInfo *visinfo;
81 int width = 90, height = 90;
82 int xpos = 0, ypos = 0;
83
84 if (NumHeads >= MAX_HEADS)
85 return NULL;
86
87 dpy = XOpenDisplay(displayName);
88 if (!dpy) {
89 Error(displayName, "Unable to open display");
90 return NULL;
91 }
92
93 scrnum = DefaultScreen(dpy);
94 root = RootWindow(dpy, scrnum);
95
96 visinfo = glXChooseVisual(dpy, scrnum, attrib);
97 if (!visinfo) {
98 Error(displayName, "Unable to find RGB, double-buffered visual");
99 return NULL;
100 }
101
102 /* window attributes */
103 xpos = (NumHeads % 10) * 100;
104 ypos = (NumHeads / 10) * 100;
105 printf("%d, %d\n", xpos, ypos);
106 attr.background_pixel = 0;
107 attr.border_pixel = 0;
108 attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
109 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
110 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
111
112 win = XCreateWindow(dpy, root, xpos, ypos, width, height,
113 0, visinfo->depth, InputOutput,
114 visinfo->visual, mask, &attr);
115 if (!win) {
116 Error(displayName, "Couldn't create window");
117 return NULL;
118 }
119
120 {
121 XSizeHints sizehints;
122 sizehints.x = xpos;
123 sizehints.y = ypos;
124 sizehints.width = width;
125 sizehints.height = height;
126 sizehints.flags = USSize | USPosition;
127 XSetNormalHints(dpy, win, &sizehints);
128 XSetStandardProperties(dpy, win, name, name,
129 None, (char **)NULL, 0, &sizehints);
130 }
131
132
133 ctx = glXCreateContext(dpy, visinfo, NULL, True);
134 if (!ctx) {
135 Error(displayName, "Couldn't create GLX context");
136 return NULL;
137 }
138
139 XMapWindow(dpy, win);
140
141 if (!glXMakeCurrent(dpy, win, ctx)) {
142 Error(displayName, "glXMakeCurrent failed");
143 printf("glXMakeCurrent failed in Redraw()\n");
Brian Paul27b07582001-04-27 21:19:13 +0000144 return NULL;
Brian Paul0852d0b2000-06-13 19:41:30 +0000145 }
146
147 /* save the info for this head */
148 {
149 struct head *h = &Heads[NumHeads];
150 strcpy(h->DisplayName, name);
151 h->Dpy = dpy;
152 h->Win = win;
153 h->Context = ctx;
154 h->Angle = 0.0;
155 strcpy(h->Version, (char *) glGetString(GL_VERSION));
156 strcpy(h->Vendor, (char *) glGetString(GL_VENDOR));
157 strcpy(h->Renderer, (char *) glGetString(GL_RENDERER));
158 NumHeads++;
159 return &Heads[NumHeads-1];
160 }
161
162}
163
164
165static void
Brian Paul125fddc2001-01-23 23:45:05 +0000166DestroyHeads(void)
167{
168 int i;
169 for (i = 0; i < NumHeads; i++) {
170 XDestroyWindow(Heads[i].Dpy, Heads[i].Win);
171 glXDestroyContext(Heads[i].Dpy, Heads[i].Context);
172 XCloseDisplay(Heads[i].Dpy);
173 }
174}
175
176
177static void
Brian Paul0852d0b2000-06-13 19:41:30 +0000178Redraw(struct head *h)
179{
180 if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
181 Error(h->DisplayName, "glXMakeCurrent failed");
182 printf("glXMakeCurrent failed in Redraw()\n");
183 return;
184 }
185
186 h->Angle += 1.0;
187
188 glShadeModel(GL_FLAT);
189 glClearColor(0.5, 0.5, 0.5, 1.0);
190 glClear(GL_COLOR_BUFFER_BIT);
191
192 /* draw green triangle */
193 glColor3f(0.0, 1.0, 0.0);
194 glPushMatrix();
195 glRotatef(h->Angle, 0, 0, 1);
196 glBegin(GL_TRIANGLES);
197 glVertex2f(0, 0.8);
198 glVertex2f(-0.8, -0.7);
199 glVertex2f(0.8, -0.7);
200 glEnd();
201 glPopMatrix();
202
Brian Paulfac5fd22000-12-02 20:33:05 +0000203 if (!SwapSeparate)
204 glXSwapBuffers(h->Dpy, h->Win);
Brian Paul0852d0b2000-06-13 19:41:30 +0000205}
206
207
Brian Paulfac5fd22000-12-02 20:33:05 +0000208static void
209Swap(struct head *h)
210{
211 glXSwapBuffers(h->Dpy, h->Win);
212}
213
Brian Paul0852d0b2000-06-13 19:41:30 +0000214
215static void
216Resize(const struct head *h, unsigned int width, unsigned int height)
217{
218 if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
219 Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
220 return;
221 }
222 glFlush();
223 glViewport(0, 0, width, height);
224 glMatrixMode(GL_PROJECTION);
225 glLoadIdentity();
226 glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
227}
228
229
230
231static void
232EventLoop(void)
233{
234 while (1) {
235 int i;
236 for (i = 0; i < NumHeads; i++) {
237 struct head *h = &Heads[i];
238 while (XPending(h->Dpy) > 0) {
239 XEvent event;
240 XNextEvent(h->Dpy, &event);
241 if (event.xany.window == h->Win) {
242 switch (event.type) {
243 case Expose:
244 Redraw(h);
Brian Paulfac5fd22000-12-02 20:33:05 +0000245 if (SwapSeparate)
246 Swap(h);
Brian Paul0852d0b2000-06-13 19:41:30 +0000247 break;
248 case ConfigureNotify:
249 Resize(h, event.xconfigure.width, event.xconfigure.height);
250 break;
251 case KeyPress:
252 return;
253 default:
254 /*no-op*/ ;
255 }
256 }
257 else {
258 printf("window mismatch\n");
259 }
260 }
Brian Paulfac5fd22000-12-02 20:33:05 +0000261 }
262
263 /* redraw all windows */
264 for (i = 0; i < NumHeads; i++) {
265 Redraw(&Heads[i]);
266 }
267 /* swapbuffers on all windows, if not already done */
268 if (SwapSeparate) {
269 for (i = 0; i < NumHeads; i++) {
270 Swap(&Heads[i]);
271 }
Brian Paul0852d0b2000-06-13 19:41:30 +0000272 }
273 usleep(1);
274 }
275}
276
277
278
279static void
280PrintInfo(const struct head *h)
281{
282 printf("Name: %s\n", h->DisplayName);
Brian Paul1b2976f2001-11-26 17:21:46 +0000283 printf(" Display: %p\n", (void *) h->Dpy);
Brian Paul27b07582001-04-27 21:19:13 +0000284 printf(" Window: 0x%x\n", (int) h->Win);
Brian Pauld93b68f2003-04-21 14:51:16 +0000285 printf(" Context: 0x%lx\n", (long) h->Context);
Brian Paul0852d0b2000-06-13 19:41:30 +0000286 printf(" GL_VERSION: %s\n", h->Version);
287 printf(" GL_VENDOR: %s\n", h->Vendor);
288 printf(" GL_RENDERER: %s\n", h->Renderer);
289}
290
291
292int
293main(int argc, char *argv[])
294{
Brian Paul27b07582001-04-27 21:19:13 +0000295 char *dpyName = NULL;
Brian Paul0852d0b2000-06-13 19:41:30 +0000296 int i;
Brian Paul27b07582001-04-27 21:19:13 +0000297
Brian Paul0852d0b2000-06-13 19:41:30 +0000298 if (argc == 1) {
Brian Paul0852d0b2000-06-13 19:41:30 +0000299 printf("manywin: open N simultaneous glx windows\n");
300 printf("Usage:\n");
Brian Paulfac5fd22000-12-02 20:33:05 +0000301 printf(" manywin [-s] numWindows\n");
302 printf("Options:\n");
303 printf(" -s = swap immediately after drawing (see src code)\n");
Brian Paul0852d0b2000-06-13 19:41:30 +0000304 printf("Example:\n");
305 printf(" manywin 10\n");
306 return 0;
307 }
308 else {
Brian Paulfac5fd22000-12-02 20:33:05 +0000309 int n = 3;
310 for (i = 1; i < argc; i++) {
311 if (strcmp(argv[i], "-s") == 0) {
312 SwapSeparate = GL_FALSE;
313 }
Brian Paul27b07582001-04-27 21:19:13 +0000314 else if (strcmp(argv[i], "-display") == 0 && i < argc) {
315 dpyName = argv[i+1];
316 i++;
317 }
Brian Paulfac5fd22000-12-02 20:33:05 +0000318 else {
319 n = atoi(argv[i]);
320 }
321 }
322 if (n < 1)
323 n = 1;
324
Brian Paul0852d0b2000-06-13 19:41:30 +0000325 printf("%d windows\n", n);
326 for (i = 0; i < n; i++) {
327 char name[100];
328 struct head *h;
329 sprintf(name, "%d", i);
Brian Paul27b07582001-04-27 21:19:13 +0000330 h = AddHead(dpyName, name);
Brian Paul0852d0b2000-06-13 19:41:30 +0000331 if (h) {
332 PrintInfo(h);
333 }
334 }
335 }
336
337 EventLoop();
Brian Paul125fddc2001-01-23 23:45:05 +0000338 DestroyHeads();
Brian Paul0852d0b2000-06-13 19:41:30 +0000339 return 0;
340}