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