ARB prog parser: fix parameter binding type
[mesa.git] / progs / xdemos / corender.c
1 /**
2 * Example of cooperative rendering into one window by two processes.
3 * The first instance of the program creates the GLX window.
4 * The second instance of the program gets the window ID from the first
5 * and draws into it.
6 * Socket IPC is used for synchronization.
7 *
8 * Usage:
9 * 1. run 'corender &'
10 * 2. run 'corender 2' (any arg will do)
11 *
12 * Brian Paul
13 * 11 Oct 2007
14 */
15
16
17 #include <GL/gl.h>
18 #include <GL/glx.h>
19 #include <assert.h>
20 #include <math.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <X11/keysym.h>
25 #include <unistd.h>
26 #include "ipc.h"
27
28
29 #ifndef M_PI
30 #define M_PI 3.14159265358979323846
31 #endif
32
33 static int MyID = 0; /* 0 or 1 */
34 static int WindowID = 0;
35 static GLXContext Context = 0;
36 static int Width = 700, Height = 350;
37 static int Rot = 0;
38 static int Sock = 0;
39
40 static GLfloat Red[4] = {1.0, 0.2, 0.2, 1.0};
41 static GLfloat Blue[4] = {0.2, 0.2, 1.0, 1.0};
42
43 static int Sync = 1; /** synchronized rendering? */
44
45
46 static void
47 setup_ipc(void)
48 {
49 int k, port = 10001;
50
51 if (MyID == 0) {
52 /* I'm the first one, wait for connection from second */
53 k = CreatePort(&port);
54 assert(k != -1);
55
56 printf("Waiting for connection from another 'corender'\n");
57 Sock = AcceptConnection(k);
58 assert(Sock != -1);
59
60 printf("Got connection, sending windowID\n");
61
62 /* send windowID */
63 SendData(Sock, &WindowID, sizeof(WindowID));
64 }
65 else {
66 /* I'm the second one, connect to first */
67 char hostname[1000];
68
69 MyHostName(hostname, 1000);
70 Sock = Connect(hostname, port);
71 assert(Sock != -1);
72
73 /* get windowID */
74 ReceiveData(Sock, &WindowID, sizeof(WindowID));
75 printf("Contacted first 'corender', getting WindowID\n");
76 }
77 }
78
79
80
81 /** from GLUT */
82 static void
83 doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
84 {
85 int i, j;
86 GLfloat theta, phi, theta1;
87 GLfloat cosTheta, sinTheta;
88 GLfloat cosTheta1, sinTheta1;
89 GLfloat ringDelta, sideDelta;
90
91 ringDelta = 2.0 * M_PI / rings;
92 sideDelta = 2.0 * M_PI / nsides;
93
94 theta = 0.0;
95 cosTheta = 1.0;
96 sinTheta = 0.0;
97 for (i = rings - 1; i >= 0; i--) {
98 theta1 = theta + ringDelta;
99 cosTheta1 = cos(theta1);
100 sinTheta1 = sin(theta1);
101 glBegin(GL_QUAD_STRIP);
102 phi = 0.0;
103 for (j = nsides; j >= 0; j--) {
104 GLfloat cosPhi, sinPhi, dist;
105
106 phi += sideDelta;
107 cosPhi = cos(phi);
108 sinPhi = sin(phi);
109 dist = R + r * cosPhi;
110
111 glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
112 glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
113 glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
114 glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi);
115 }
116 glEnd();
117 theta = theta1;
118 cosTheta = cosTheta1;
119 sinTheta = sinTheta1;
120 }
121 }
122
123
124 static void
125 redraw(Display *dpy)
126 {
127 int dbg = 0;
128
129 glXMakeCurrent(dpy, WindowID, Context);
130 glEnable(GL_LIGHTING);
131 glEnable(GL_LIGHT0);
132 glEnable(GL_DEPTH_TEST);
133 glClearColor(0.5, 0.5, 0.5, 0.0);
134
135 if (MyID == 0) {
136 /* First process */
137
138 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
139
140 glPushMatrix();
141 glTranslatef(-1, 0, 0);
142 glRotatef(Rot, 1, 0, 0);
143 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
144 doughnut(0.5, 2.0, 20, 30);
145 glPopMatrix();
146
147 glFinish();
148 if (!Sync) {
149 usleep(1000*10);
150 }
151
152 /* signal second process to render */
153 if (Sync) {
154 int code = 1;
155 if (dbg) printf("0: send signal\n");
156 SendData(Sock, &code, sizeof(code));
157 SendData(Sock, &Rot, sizeof(Rot));
158 }
159
160 /* wait for second process to finish rendering */
161 if (Sync) {
162 int code = 0;
163 if (dbg) printf("0: wait signal\n");
164 ReceiveData(Sock, &code, sizeof(code));
165 if (dbg) printf("0: got signal\n");
166 assert(code == 2);
167 }
168
169 }
170 else {
171 /* Second process */
172
173 /* wait for first process's signal for me to render */
174 if (Sync) {
175 int code = 0;
176 if (dbg) printf("1: wait signal\n");
177 ReceiveData(Sock, &code, sizeof(code));
178 ReceiveData(Sock, &Rot, sizeof(Rot));
179
180 if (dbg) printf("1: got signal\n");
181 assert(code == 1);
182 }
183
184 /* XXX this clear should not be here, but for some reason, it
185 * makes things _mostly_ work correctly w/ NVIDIA's driver.
186 * There's only occasional glitches.
187 * Without this glClear(), depth buffer for the second process
188 * is pretty much broken.
189 */
190 /* glClear(GL_DEPTH_BUFFER_BIT); */
191
192 glPushMatrix();
193 glTranslatef(1, 0, 0);
194 glRotatef(Rot + 90 , 1, 0, 0);
195 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
196 doughnut(0.5, 2.0, 20, 30);
197 glPopMatrix();
198 glFinish();
199
200 glXSwapBuffers(dpy, WindowID);
201 usleep(1000*10);
202
203 /* signal first process that I'm done rendering */
204 if (Sync) {
205 int code = 2;
206 if (dbg) printf("1: send signal\n");
207 SendData(Sock, &code, sizeof(code));
208 }
209 }
210 }
211
212
213 static void
214 resize(Display *dpy, int width, int height)
215 {
216 float ar = (float) width / height;
217
218 glXMakeCurrent(dpy, WindowID, Context);
219
220 glViewport(0, 0, width, height);
221 glMatrixMode(GL_PROJECTION);
222 glLoadIdentity();
223 glFrustum(-ar, ar, 1.0, -1.0, 5.0, 200.0);
224 glMatrixMode(GL_MODELVIEW);
225 glLoadIdentity();
226 glTranslatef(0, 0, -15);
227
228 Width = width;
229 Height = height;
230 }
231
232
233
234 static void
235 set_window_title(Display *dpy, Window win, const char *title)
236 {
237 XSizeHints sizehints;
238 sizehints.flags = 0;
239 XSetStandardProperties(dpy, win, title, title,
240 None, (char **)NULL, 0, &sizehints);
241 }
242
243
244 static Window
245 make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
246 {
247 int scrnum;
248 XSetWindowAttributes attr;
249 unsigned long mask;
250 Window root;
251 Window win;
252 int x = 0, y = 0;
253 char *name = NULL;
254
255 scrnum = DefaultScreen( dpy );
256 root = RootWindow( dpy, scrnum );
257
258 /* window attributes */
259 attr.background_pixel = 0;
260 attr.border_pixel = 0;
261 attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
262 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
263 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
264
265 win = XCreateWindow( dpy, root, x, y, width, height,
266 0, visinfo->depth, InputOutput,
267 visinfo->visual, mask, &attr );
268
269 /* set hints and properties */
270 {
271 XSizeHints sizehints;
272 sizehints.x = x;
273 sizehints.y = y;
274 sizehints.width = width;
275 sizehints.height = height;
276 sizehints.flags = USSize | USPosition;
277 XSetNormalHints(dpy, win, &sizehints);
278 XSetStandardProperties(dpy, win, name, name,
279 None, (char **)NULL, 0, &sizehints);
280 }
281
282 return win;
283 }
284
285
286 static void
287 set_event_mask(Display *dpy, Window win)
288 {
289 XSetWindowAttributes attr;
290 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
291 XChangeWindowAttributes(dpy, win, CWEventMask, &attr);
292 }
293
294
295 static void
296 event_loop(Display *dpy)
297 {
298 while (1) {
299 while (XPending(dpy) > 0) {
300 XEvent event;
301 XNextEvent(dpy, &event);
302
303 switch (event.type) {
304 case Expose:
305 redraw(dpy);
306 break;
307 case ConfigureNotify:
308 resize(dpy, event.xconfigure.width, event.xconfigure.height);
309 break;
310 case KeyPress:
311 {
312 char buffer[10];
313 int r, code;
314 code = XLookupKeysym(&event.xkey, 0);
315 if (code == XK_Left) {
316 }
317 else {
318 r = XLookupString(&event.xkey, buffer, sizeof(buffer),
319 NULL, NULL);
320 if (buffer[0] == 27) {
321 exit(0);
322 }
323 }
324 }
325 default:
326 /* nothing */
327 ;
328 }
329 }
330
331 if (MyID == 0 || !Sync)
332 Rot += 1;
333 redraw(dpy);
334 }
335 }
336
337
338 static XVisualInfo *
339 choose_visual(Display *dpy)
340 {
341 int attribs[] = { GLX_RGBA,
342 GLX_RED_SIZE, 1,
343 GLX_GREEN_SIZE, 1,
344 GLX_BLUE_SIZE, 1,
345 GLX_DOUBLEBUFFER,
346 GLX_DEPTH_SIZE, 1,
347 None };
348 int scrnum = DefaultScreen( dpy );
349 return glXChooseVisual(dpy, scrnum, attribs);
350 }
351
352
353 static void
354 parse_opts(int argc, char *argv[])
355 {
356 if (argc > 1) {
357 MyID = 1;
358 }
359 }
360
361
362 int
363 main( int argc, char *argv[] )
364 {
365 Display *dpy;
366 XVisualInfo *visinfo;
367
368 parse_opts(argc, argv);
369
370 dpy = XOpenDisplay(NULL);
371
372 visinfo = choose_visual(dpy);
373
374 Context = glXCreateContext( dpy, visinfo, NULL, True );
375 if (!Context) {
376 printf("Error: glXCreateContext failed\n");
377 exit(1);
378 }
379
380 if (MyID == 0) {
381 WindowID = make_gl_window(dpy, visinfo, Width, Height);
382 set_window_title(dpy, WindowID, "corender");
383 XMapWindow(dpy, WindowID);
384 /*printf("WindowID 0x%x\n", (int) WindowID);*/
385 }
386
387 /* do ipc hand-shake here */
388 setup_ipc();
389 assert(Sock);
390 assert(WindowID);
391
392 if (MyID == 1) {
393 set_event_mask(dpy, WindowID);
394 }
395
396 resize(dpy, Width, Height);
397
398 event_loop(dpy);
399
400 return 0;
401 }