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;
37 static int Redraw
= 0;
39 static int MinSides
= 3;
40 static int MaxSides
= 20;
43 /* return current time (in seconds) */
49 (void) gettimeofday(&tv
, NULL
);
52 (void) gettimeofday(&tv
, &tz
);
54 return (double) tv
.tv_sec
+ tv
.tv_usec
/ 1000000.0;
59 * Draw the OpenGL stuff and do a SwapBuffers.
61 static void display(Display
*dpy
, Window win
)
65 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
69 glScalef(scale
, scale
, scale
);
70 glRotatef(Xangle
, 1.0, 0.0, 0.0);
71 glRotatef(Yangle
, 0.0, 1.0, 0.0);
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);
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);
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);
102 glScalef(0.75, 0.75, 0.75);
106 glVertex3f(1, -1, -1);
107 glVertex3f(1, 1, -1);
109 glVertex3f(1, -1, 1);
114 glVertex3f(-1, -1, -1);
115 glVertex3f(-1, 1, -1);
116 glVertex3f(-1, 1, 1);
117 glVertex3f(-1, -1, 1);
122 glVertex3f(-1, 1, -1);
123 glVertex3f( 1, 1, -1);
124 glVertex3f( 1, 1, 1);
125 glVertex3f(-1, 1, 1);
130 glVertex3f(-1, -1, -1);
131 glVertex3f( 1, -1, -1);
132 glVertex3f( 1, -1, 1);
133 glVertex3f(-1, -1, 1);
138 glVertex3f(-1, -1, 1);
139 glVertex3f( 1, -1, 1);
140 glVertex3f( 1, 1, 1);
141 glVertex3f(-1, 1, 1);
146 glVertex3f(-1, -1, -1);
147 glVertex3f( 1, -1, -1);
148 glVertex3f( 1, 1, -1);
149 glVertex3f(-1, 1, -1);
156 glXSwapBuffers(dpy
, win
);
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
165 static void make_shape_mask(Display
*dpy
, Window win
, int width
, int height
,
172 /* allocate 1-bit deep pixmap and a GC */
173 shapeMask
= XCreatePixmap(dpy
, win
, width
, height
, 1);
174 gc
= XCreateGC(dpy
, shapeMask
, 0, &xgcv
);
176 /* clear shapeMask to zeros */
177 XSetForeground(dpy
, gc
, 0);
178 XFillRectangle(dpy
, shapeMask
, gc
, 0, 0, width
, height
);
181 XSetForeground(dpy
, gc
, 1);
186 float step
= 2.0 * PI
/ sides
;
187 float radius
= width
/ 2;
190 for (i
=0;i
<sides
;i
++) {
191 int x
= cx
+ radius
* sin(angle
);
192 int y
= cy
- radius
* cos(angle
);
197 XFillPolygon(dpy
, shapeMask
, gc
, points
, sides
, Convex
, CoordModeOrigin
);
200 /* This is the only SHAPE extension call- simple! */
201 XShapeCombineMask(dpy
, win
, ShapeBounding
, 0, 0, shapeMask
, ShapeSet
);
204 XFreePixmap(dpy
, shapeMask
);
209 * Called when window is resized. Do OpenGL viewport and projection stuff.
211 static void reshape(int width
, int height
)
213 glViewport(0, 0, width
, height
);
214 glMatrixMode(GL_PROJECTION
);
216 glFrustum(-1.0, 1.0, -1.0, 1.0, 3.0, 20.0);
217 glMatrixMode(GL_MODELVIEW
);
219 glTranslatef(0.0, 0.0, -10.0);
221 glEnable(GL_DEPTH_TEST
);
228 static void event_loop(Display
*dpy
, Window win
)
233 XNextEvent(dpy
, &event
);
234 switch (event
.type
) {
236 display(dpy
, event
.xexpose
.window
);
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
);
249 XLookupString(&event
.xkey
, buf
, sizeof(buf
), &keySym
, &stat
);
256 if (Sides
>MaxSides
) Sides
= MaxSides
;
257 make_shape_mask(dpy
, win
, Width
, Height
, Sides
);
261 if (Sides
<MinSides
) Sides
= MinSides
;
262 make_shape_mask(dpy
, win
, Width
, Height
, Sides
);
272 static double t0
= -1.0;
273 double dt
, t
= current_time();
277 Xangle
+= 90.0 * dt
; /* 90 degrees per second */
287 * Allocate a "nice" colormap. This could be better (HP-CR support, etc).
289 static Colormap
alloc_colormap(Display
*dpy
, Window parent
, Visual
*vis
)
291 Screen
*scr
= DefaultScreenOfDisplay(dpy
);
292 int scrnum
= DefaultScreen(dpy
);
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
);
300 return XCreateColormap(dpy
, parent
, vis
, AllocNone
);
305 int main(int argc
, char *argv
[])
307 static int glAttribs
[] = {
314 XVisualInfo
*visInfo
;
319 XSetWindowAttributes winAttribs
;
320 unsigned long winAttribsMask
;
323 const char *name
= "OpenGL in a Shaped Window";
325 dpy
= XOpenDisplay(NULL
);
327 fprintf(stderr
, "Couldn't open default display\n");
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");
337 scrn
= DefaultScreen(dpy
);
339 root
= RootWindow(dpy
, scrn
);
341 visInfo
= glXChooseVisual(dpy
, scrn
, glAttribs
);
343 fprintf(stderr
, "Couldn't get RGB, DB, Z visual\n");
347 glCtx
= glXCreateContext(dpy
, visInfo
, 0, True
);
349 fprintf(stderr
, "Couldn't create GL context\n");
353 cmap
= alloc_colormap(dpy
, root
, visInfo
->visual
);
355 fprintf(stderr
, "Couln't create colormap\n");
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
,
366 winAttribsMask
, &winAttribs
);
369 XSizeHints sizehints
;
373 sizehints.width = width;
374 sizehints.height = height;
377 XSetNormalHints(dpy
, win
, &sizehints
);
378 XSetStandardProperties(dpy
, win
, name
, name
,
379 None
, (char **)NULL
, 0, &sizehints
);
383 XMapWindow(dpy
, win
);
385 glXMakeCurrent(dpy
, win
, glCtx
);
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");
391 event_loop(dpy
, win
);