dbbc0b4ff72720a585e04845650a4e5c84e2b7b2
[mesa.git] / progs / xdemos / shape.c
1
2 /*
3 * Example of using the X "shape" extension with OpenGL: render a spinning
4 * cube inside of a non-rectangular window.
5 *
6 * Press ESC to exit. Press up/down to change window shape.
7 *
8 * To compile add "shape" to the PROGS list in Makefile.
9 *
10 * Brian Paul
11 * June 16, 1997
12 *
13 * This program is in the public domain.
14 */
15
16
17 #include <math.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/time.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/keysym.h>
26 #include <X11/extensions/shape.h>
27 #include <GL/glx.h>
28
29 #ifndef PI
30 #define PI 3.1415926
31 #endif
32
33
34 static int Width=500, Height=500;
35
36 static float Xangle = 0.0, Yangle = 0.0;
37 static int Redraw = 0;
38 static int Sides = 5;
39 static int MinSides = 3;
40 static int MaxSides = 20;
41
42
43 /* return current time (in seconds) */
44 static double
45 current_time(void)
46 {
47 struct timeval tv;
48 #ifdef __VMS
49 (void) gettimeofday(&tv, NULL );
50 #else
51 struct timezone tz;
52 (void) gettimeofday(&tv, &tz);
53 #endif
54 return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
55 }
56
57
58 /*
59 * Draw the OpenGL stuff and do a SwapBuffers.
60 */
61 static void display(Display *dpy, Window win)
62 {
63 float scale = 1.7;
64
65 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
66
67 glPushMatrix();
68
69 glScalef(scale, scale, scale);
70 glRotatef(Xangle, 1.0, 0.0, 0.0);
71 glRotatef(Yangle, 0.0, 1.0, 0.0);
72
73 /*
74 * wireframe box
75 */
76 glColor3f(1.0, 1.0, 1.0);
77 glBegin(GL_LINE_LOOP);
78 glVertex3f(-1.0, -1.0, -1.0);
79 glVertex3f( 1.0, -1.0, -1.0);
80 glVertex3f( 1.0, 1.0, -1.0);
81 glVertex3f(-1.0, 1.0, -1.0);
82 glEnd();
83
84 glBegin(GL_LINE_LOOP);
85 glVertex3f(-1.0, -1.0, 1.0);
86 glVertex3f( 1.0, -1.0, 1.0);
87 glVertex3f( 1.0, 1.0, 1.0);
88 glVertex3f(-1.0, 1.0, 1.0);
89 glEnd();
90
91 glBegin(GL_LINES);
92 glVertex3f(-1.0, -1.0, -1.0); glVertex3f(-1.0, -1.0, 1.0);
93 glVertex3f( 1.0, -1.0, -1.0); glVertex3f( 1.0, -1.0, 1.0);
94 glVertex3f( 1.0, 1.0, -1.0); glVertex3f( 1.0, 1.0, 1.0);
95 glVertex3f(-1.0, 1.0, -1.0); glVertex3f(-1.0, 1.0, 1.0);
96 glEnd();
97
98 /*
99 * Solid box
100 */
101 glPushMatrix();
102 glScalef(0.75, 0.75, 0.75);
103
104 glColor3f(1, 0, 0);
105 glBegin(GL_POLYGON);
106 glVertex3f(1, -1, -1);
107 glVertex3f(1, 1, -1);
108 glVertex3f(1, 1, 1);
109 glVertex3f(1, -1, 1);
110 glEnd();
111
112 glColor3f(0, 1, 1);
113 glBegin(GL_POLYGON);
114 glVertex3f(-1, -1, -1);
115 glVertex3f(-1, 1, -1);
116 glVertex3f(-1, 1, 1);
117 glVertex3f(-1, -1, 1);
118 glEnd();
119
120 glColor3f(0, 1, 0);
121 glBegin(GL_POLYGON);
122 glVertex3f(-1, 1, -1);
123 glVertex3f( 1, 1, -1);
124 glVertex3f( 1, 1, 1);
125 glVertex3f(-1, 1, 1);
126 glEnd();
127
128 glColor3f(1, 0, 1);
129 glBegin(GL_POLYGON);
130 glVertex3f(-1, -1, -1);
131 glVertex3f( 1, -1, -1);
132 glVertex3f( 1, -1, 1);
133 glVertex3f(-1, -1, 1);
134 glEnd();
135
136 glColor3f(0, 0, 1);
137 glBegin(GL_POLYGON);
138 glVertex3f(-1, -1, 1);
139 glVertex3f( 1, -1, 1);
140 glVertex3f( 1, 1, 1);
141 glVertex3f(-1, 1, 1);
142 glEnd();
143
144 glColor3f(1, 1, 0);
145 glBegin(GL_POLYGON);
146 glVertex3f(-1, -1, -1);
147 glVertex3f( 1, -1, -1);
148 glVertex3f( 1, 1, -1);
149 glVertex3f(-1, 1, -1);
150 glEnd();
151 glPopMatrix();
152
153
154 glPopMatrix();
155
156 glXSwapBuffers(dpy, win);
157 }
158
159
160 /*
161 * This is called when we have to recompute the window shape bitmask.
162 * We just generate an n-sided regular polygon here but any other shape
163 * would be possible.
164 */
165 static void make_shape_mask(Display *dpy, Window win, int width, int height,
166 int sides)
167 {
168 Pixmap shapeMask;
169 XGCValues xgcv;
170 GC gc;
171
172 /* allocate 1-bit deep pixmap and a GC */
173 shapeMask = XCreatePixmap(dpy, win, width, height, 1);
174 gc = XCreateGC(dpy, shapeMask, 0, &xgcv);
175
176 /* clear shapeMask to zeros */
177 XSetForeground(dpy, gc, 0);
178 XFillRectangle(dpy, shapeMask, gc, 0, 0, width, height);
179
180 /* draw mask */
181 XSetForeground(dpy, gc, 1);
182 {
183 int cx = width / 2;
184 int cy = height / 2;
185 float angle = 0.0;
186 float step = 2.0 * PI / sides;
187 float radius = width / 2;
188 int i;
189 XPoint points[100];
190 for (i=0;i<sides;i++) {
191 int x = cx + radius * sin(angle);
192 int y = cy - radius * cos(angle);
193 points[i].x = x;
194 points[i].y = y;
195 angle += step;
196 }
197 XFillPolygon(dpy, shapeMask, gc, points, sides, Convex, CoordModeOrigin);
198 }
199
200 /* This is the only SHAPE extension call- simple! */
201 XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, shapeMask, ShapeSet);
202
203 XFreeGC(dpy, gc);
204 XFreePixmap(dpy, shapeMask);
205 }
206
207
208 /*
209 * Called when window is resized. Do OpenGL viewport and projection stuff.
210 */
211 static void reshape(int width, int height)
212 {
213 glViewport(0, 0, width, height);
214 glMatrixMode(GL_PROJECTION);
215 glLoadIdentity();
216 glFrustum(-1.0, 1.0, -1.0, 1.0, 3.0, 20.0);
217 glMatrixMode(GL_MODELVIEW);
218 glLoadIdentity();
219 glTranslatef(0.0, 0.0, -10.0);
220
221 glEnable(GL_DEPTH_TEST);
222 }
223
224
225 /*
226 * Process X events.
227 */
228 static void event_loop(Display *dpy, Window win)
229 {
230 while (1) {
231 XEvent event;
232 if (XPending(dpy)) {
233 XNextEvent(dpy, &event);
234 switch (event.type) {
235 case Expose:
236 display(dpy, event.xexpose.window);
237 break;
238 case ConfigureNotify:
239 Width = event.xconfigure.width;
240 Height = event.xconfigure.height,
241 make_shape_mask(dpy, win, Width, Height, Sides);
242 reshape(Width, Height);
243 break;
244 case KeyPress:
245 {
246 char buf[100];
247 KeySym keySym;
248 XComposeStatus stat;
249 XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
250 switch (keySym) {
251 case XK_Escape:
252 exit(0);
253 break;
254 case XK_Up:
255 Sides++;
256 if (Sides>MaxSides) Sides = MaxSides;
257 make_shape_mask(dpy, win, Width, Height, Sides);
258 break;
259 case XK_Down:
260 Sides--;
261 if (Sides<MinSides) Sides = MinSides;
262 make_shape_mask(dpy, win, Width, Height, Sides);
263 break;
264 }
265 }
266 break;
267 default:
268 ;;
269 }
270 }
271 else {
272 static double t0 = -1.0;
273 double dt, t = current_time();
274 if (t0 < 0.0)
275 t0 = t;
276 dt = t - t0;
277 Xangle += 90.0 * dt; /* 90 degrees per second */
278 Yangle += 70.0 * dt;
279 t0 = t;
280 display(dpy, win);
281 }
282 }
283 }
284
285
286 /*
287 * Allocate a "nice" colormap. This could be better (HP-CR support, etc).
288 */
289 static Colormap alloc_colormap(Display *dpy, Window parent, Visual *vis)
290 {
291 Screen *scr = DefaultScreenOfDisplay(dpy);
292 int scrnum = DefaultScreen(dpy);
293
294 if (MaxCmapsOfScreen(scr)==1 && vis==DefaultVisual(dpy, scrnum)) {
295 /* The window and root are of the same visual type so */
296 /* share the root colormap. */
297 return DefaultColormap(dpy, scrnum);
298 }
299 else {
300 return XCreateColormap(dpy, parent, vis, AllocNone);
301 }
302 }
303
304
305 int main(int argc, char *argv[])
306 {
307 static int glAttribs[] = {
308 GLX_DOUBLEBUFFER,
309 GLX_RGBA,
310 GLX_DEPTH_SIZE, 1,
311 None
312 };
313 Display *dpy;
314 XVisualInfo *visInfo;
315 int scrn;
316 Window root;
317 Colormap cmap;
318 Window win;
319 XSetWindowAttributes winAttribs;
320 unsigned long winAttribsMask;
321 GLXContext glCtx;
322 int ignore;
323 const char *name = "OpenGL in a Shaped Window";
324
325 dpy = XOpenDisplay(NULL);
326 if (!dpy) {
327 fprintf(stderr, "Couldn't open default display\n");
328 return 1;
329 }
330
331 /* check that we can use the shape extension */
332 if (!XQueryExtension(dpy, "SHAPE", &ignore, &ignore, &ignore )) {
333 fprintf(stderr, "Display doesn't support shape extension\n");
334 return 1;
335 }
336
337 scrn = DefaultScreen(dpy);
338
339 root = RootWindow(dpy, scrn);
340
341 visInfo = glXChooseVisual(dpy, scrn, glAttribs);
342 if (!visInfo) {
343 fprintf(stderr, "Couldn't get RGB, DB, Z visual\n");
344 return 1;
345 }
346
347 glCtx = glXCreateContext(dpy, visInfo, 0, True);
348 if (!glCtx) {
349 fprintf(stderr, "Couldn't create GL context\n");
350 return 1;
351 }
352
353 cmap = alloc_colormap(dpy, root, visInfo->visual);
354 if (!cmap) {
355 fprintf(stderr, "Couln't create colormap\n");
356 return 1;
357 }
358
359 winAttribs.border_pixel = 0;
360 winAttribs.colormap = cmap;
361 winAttribs.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
362 winAttribsMask = CWBorderPixel | CWColormap | CWEventMask;
363 win = XCreateWindow(dpy, root, 0, 0, Width, Height, 0,
364 visInfo->depth, InputOutput,
365 visInfo->visual,
366 winAttribsMask, &winAttribs);
367
368 {
369 XSizeHints sizehints;
370 /*
371 sizehints.x = xpos;
372 sizehints.y = ypos;
373 sizehints.width = width;
374 sizehints.height = height;
375 */
376 sizehints.flags = 0;
377 XSetNormalHints(dpy, win, &sizehints);
378 XSetStandardProperties(dpy, win, name, name,
379 None, (char **)NULL, 0, &sizehints);
380 }
381
382
383 XMapWindow(dpy, win);
384
385 glXMakeCurrent(dpy, win, glCtx);
386
387 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
388 printf("Press ESC to exit.\n");
389 printf("Press up/down to change window shape.\n");
390
391 event_loop(dpy, win);
392
393 return 0;
394 }