3 * Example of using the X "shape" extension with OpenGL: render a spinning
4 * cube inside of a non-rectangular window.
6 * Press ESC to exit. Press up/down to change window shape.
8 * To compile add "shape" to the PROGS list in Makefile.
13 * This program is in the public domain.
24 #include <X11/Xutil.h>
25 #include <X11/keysym.h>
26 #include <X11/extensions/shape.h>
34 static int Width
=500, Height
=500;
36 static float Xangle
= 0.0, Yangle
= 0.0;
38 static int MinSides
= 3;
39 static int MaxSides
= 20;
42 /* return current time (in seconds) */
48 (void) gettimeofday(&tv
, NULL
);
51 (void) gettimeofday(&tv
, &tz
);
53 return (double) tv
.tv_sec
+ tv
.tv_usec
/ 1000000.0;
58 * Draw the OpenGL stuff and do a SwapBuffers.
60 static void display(Display
*dpy
, Window win
)
64 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
68 glScalef(scale
, scale
, scale
);
69 glRotatef(Xangle
, 1.0, 0.0, 0.0);
70 glRotatef(Yangle
, 0.0, 1.0, 0.0);
75 glColor3f(1.0, 1.0, 1.0);
76 glBegin(GL_LINE_LOOP
);
77 glVertex3f(-1.0, -1.0, -1.0);
78 glVertex3f( 1.0, -1.0, -1.0);
79 glVertex3f( 1.0, 1.0, -1.0);
80 glVertex3f(-1.0, 1.0, -1.0);
83 glBegin(GL_LINE_LOOP
);
84 glVertex3f(-1.0, -1.0, 1.0);
85 glVertex3f( 1.0, -1.0, 1.0);
86 glVertex3f( 1.0, 1.0, 1.0);
87 glVertex3f(-1.0, 1.0, 1.0);
91 glVertex3f(-1.0, -1.0, -1.0); glVertex3f(-1.0, -1.0, 1.0);
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);
101 glScalef(0.75, 0.75, 0.75);
105 glVertex3f(1, -1, -1);
106 glVertex3f(1, 1, -1);
108 glVertex3f(1, -1, 1);
113 glVertex3f(-1, -1, -1);
114 glVertex3f(-1, 1, -1);
115 glVertex3f(-1, 1, 1);
116 glVertex3f(-1, -1, 1);
121 glVertex3f(-1, 1, -1);
122 glVertex3f( 1, 1, -1);
123 glVertex3f( 1, 1, 1);
124 glVertex3f(-1, 1, 1);
129 glVertex3f(-1, -1, -1);
130 glVertex3f( 1, -1, -1);
131 glVertex3f( 1, -1, 1);
132 glVertex3f(-1, -1, 1);
137 glVertex3f(-1, -1, 1);
138 glVertex3f( 1, -1, 1);
139 glVertex3f( 1, 1, 1);
140 glVertex3f(-1, 1, 1);
145 glVertex3f(-1, -1, -1);
146 glVertex3f( 1, -1, -1);
147 glVertex3f( 1, 1, -1);
148 glVertex3f(-1, 1, -1);
155 glXSwapBuffers(dpy
, win
);
160 * This is called when we have to recompute the window shape bitmask.
161 * We just generate an n-sided regular polygon here but any other shape
164 static void make_shape_mask(Display
*dpy
, Window win
, int width
, int height
,
171 /* allocate 1-bit deep pixmap and a GC */
172 shapeMask
= XCreatePixmap(dpy
, win
, width
, height
, 1);
173 gc
= XCreateGC(dpy
, shapeMask
, 0, &xgcv
);
175 /* clear shapeMask to zeros */
176 XSetForeground(dpy
, gc
, 0);
177 XFillRectangle(dpy
, shapeMask
, gc
, 0, 0, width
, height
);
180 XSetForeground(dpy
, gc
, 1);
185 float step
= 2.0 * PI
/ sides
;
186 float radius
= width
/ 2;
189 for (i
=0;i
<sides
;i
++) {
190 int x
= cx
+ radius
* sin(angle
);
191 int y
= cy
- radius
* cos(angle
);
196 XFillPolygon(dpy
, shapeMask
, gc
, points
, sides
, Convex
, CoordModeOrigin
);
199 /* This is the only SHAPE extension call- simple! */
200 XShapeCombineMask(dpy
, win
, ShapeBounding
, 0, 0, shapeMask
, ShapeSet
);
203 XFreePixmap(dpy
, shapeMask
);
208 * Called when window is resized. Do OpenGL viewport and projection stuff.
210 static void reshape(int width
, int height
)
212 glViewport(0, 0, width
, height
);
213 glMatrixMode(GL_PROJECTION
);
215 glFrustum(-1.0, 1.0, -1.0, 1.0, 3.0, 20.0);
216 glMatrixMode(GL_MODELVIEW
);
218 glTranslatef(0.0, 0.0, -10.0);
220 glEnable(GL_DEPTH_TEST
);
227 static void event_loop(Display
*dpy
, Window win
)
232 XNextEvent(dpy
, &event
);
233 switch (event
.type
) {
235 display(dpy
, event
.xexpose
.window
);
237 case ConfigureNotify
:
238 Width
= event
.xconfigure
.width
;
239 Height
= event
.xconfigure
.height
,
240 make_shape_mask(dpy
, win
, Width
, Height
, Sides
);
241 reshape(Width
, Height
);
248 XLookupString(&event
.xkey
, buf
, sizeof(buf
), &keySym
, &stat
);
255 if (Sides
>MaxSides
) Sides
= MaxSides
;
256 make_shape_mask(dpy
, win
, Width
, Height
, Sides
);
260 if (Sides
<MinSides
) Sides
= MinSides
;
261 make_shape_mask(dpy
, win
, Width
, Height
, Sides
);
271 static double t0
= -1.0;
272 double dt
, t
= current_time();
276 Xangle
+= 90.0 * dt
; /* 90 degrees per second */
286 * Allocate a "nice" colormap. This could be better (HP-CR support, etc).
288 static Colormap
alloc_colormap(Display
*dpy
, Window parent
, Visual
*vis
)
290 Screen
*scr
= DefaultScreenOfDisplay(dpy
);
291 int scrnum
= DefaultScreen(dpy
);
293 if (MaxCmapsOfScreen(scr
)==1 && vis
==DefaultVisual(dpy
, scrnum
)) {
294 /* The window and root are of the same visual type so */
295 /* share the root colormap. */
296 return DefaultColormap(dpy
, scrnum
);
299 return XCreateColormap(dpy
, parent
, vis
, AllocNone
);
304 int main(int argc
, char *argv
[])
306 static int glAttribs
[] = {
313 XVisualInfo
*visInfo
;
318 XSetWindowAttributes winAttribs
;
319 unsigned long winAttribsMask
;
322 const char *name
= "OpenGL in a Shaped Window";
324 dpy
= XOpenDisplay(NULL
);
326 fprintf(stderr
, "Couldn't open default display\n");
330 /* check that we can use the shape extension */
331 if (!XQueryExtension(dpy
, "SHAPE", &ignore
, &ignore
, &ignore
)) {
332 fprintf(stderr
, "Display doesn't support shape extension\n");
336 scrn
= DefaultScreen(dpy
);
338 root
= RootWindow(dpy
, scrn
);
340 visInfo
= glXChooseVisual(dpy
, scrn
, glAttribs
);
342 fprintf(stderr
, "Couldn't get RGB, DB, Z visual\n");
346 glCtx
= glXCreateContext(dpy
, visInfo
, 0, True
);
348 fprintf(stderr
, "Couldn't create GL context\n");
352 cmap
= alloc_colormap(dpy
, root
, visInfo
->visual
);
354 fprintf(stderr
, "Couln't create colormap\n");
358 winAttribs
.border_pixel
= 0;
359 winAttribs
.colormap
= cmap
;
360 winAttribs
.event_mask
= StructureNotifyMask
| ExposureMask
| KeyPressMask
;
361 winAttribsMask
= CWBorderPixel
| CWColormap
| CWEventMask
;
362 win
= XCreateWindow(dpy
, root
, 0, 0, Width
, Height
, 0,
363 visInfo
->depth
, InputOutput
,
365 winAttribsMask
, &winAttribs
);
368 XSizeHints sizehints
;
372 sizehints.width = width;
373 sizehints.height = height;
376 XSetNormalHints(dpy
, win
, &sizehints
);
377 XSetStandardProperties(dpy
, win
, name
, name
,
378 None
, (char **)NULL
, 0, &sizehints
);
382 XMapWindow(dpy
, win
);
384 glXMakeCurrent(dpy
, win
, glCtx
);
386 printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER
));
387 printf("Press ESC to exit.\n");
388 printf("Press up/down to change window shape.\n");
390 event_loop(dpy
, win
);