Merge branch 'mesa_7_7_branch'
[mesa.git] / progs / xdemos / offset.c
1 /****************************************************************************
2 Copyright 1995 by Silicon Graphics Incorporated, Mountain View, California.
3
4 All Rights Reserved
5
6 Permission to use, copy, modify, and distribute this software and its
7 documentation for any purpose and without fee is hereby granted,
8 provided that the above copyright notice appear in all copies and that
9 both that copyright notice and this permission notice appear in
10 supporting documentation, and that the name of Silicon Graphics not be
11 used in advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13
14 SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 PERFORMANCE OF THIS SOFTWARE.
21
22 ****************************************************************************/
23
24 /*
25 * Derived from code written by Kurt Akeley, November 1992
26 *
27 * Uses PolygonOffset to draw hidden-line images. PolygonOffset
28 * shifts the z values of polygons an amount that is
29 * proportional to their slope in screen z. This keeps
30 * the lines, which are drawn without displacement, from
31 * interacting with their respective polygons, and
32 * thus eliminates line dropouts.
33 *
34 * The left image shows an ordinary antialiased wireframe image.
35 * The center image shows an antialiased hidden-line image without
36 * PolygonOffset.
37 * The right image shows an antialiased hidden-line image using
38 * PolygonOffset to reduce artifacts.
39 *
40 * Drag with a mouse button pressed to rotate the models.
41 * Press the escape key to exit.
42 */
43
44 /*
45 * Modified for OpenGL 1.1 glPolygonOffset() conventions
46 */
47
48
49 #include <GL/glx.h>
50 #include <X11/keysym.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54
55 #undef GL_EXT_polygon_offset /* use GL 1.1 version instead of extension */
56
57
58 #ifndef EXIT_FAILURE
59 # define EXIT_FAILURE 1
60 #endif
61 #ifndef EXIT_SUCCESS
62 # define EXIT_SUCCESS 0
63 #endif
64
65 #define MAXQUAD 6
66
67 typedef float Vertex[3];
68
69 typedef Vertex Quad[4];
70
71 /* data to define the six faces of a unit cube */
72 Quad quads[MAXQUAD] = {
73 { {0,0,0}, {0,0,1}, {0,1,1}, {0,1,0} }, /* x = 0 */
74 { {0,0,0}, {1,0,0}, {1,0,1}, {0,0,1} }, /* y = 0 */
75 { {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0} }, /* z = 0 */
76 { {1,0,0}, {1,0,1}, {1,1,1}, {1,1,0} }, /* x = 1 */
77 { {0,1,0}, {1,1,0}, {1,1,1}, {0,1,1} }, /* y = 1 */
78 { {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1} } /* z = 1 */
79 };
80
81 #define WIREFRAME 0
82 #define HIDDEN_LINE 1
83
84 static void error(const char* prog, const char* msg);
85 static void cubes(int mx, int my, int mode);
86 static void fill(Quad quad);
87 static void outline(Quad quad);
88 static void draw_hidden(Quad quad, int mode, int face);
89 static void process_input(Display *dpy, Window win);
90 static int query_extension(char* extName);
91
92 static int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
93 GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None };
94
95 static int dimension = 3;
96
97 static float Scale = 1.0;
98
99
100 int main(int argc, char** argv) {
101 Display *dpy;
102 XVisualInfo *vi;
103 XSetWindowAttributes swa;
104 Window win;
105 GLXContext cx;
106 GLint z;
107
108 dpy = XOpenDisplay(0);
109 if (!dpy) error(argv[0], "can't open display");
110
111 vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
112 if (!vi) error(argv[0], "no suitable visual");
113
114 cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
115
116 swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
117 vi->visual, AllocNone);
118
119 swa.border_pixel = 0;
120 swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
121 ButtonPressMask | ButtonMotionMask;
122 win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, 900, 300,
123 0, vi->depth, InputOutput, vi->visual,
124 CWBorderPixel|CWColormap|CWEventMask, &swa);
125 XStoreName(dpy, win, "hiddenline");
126 XMapWindow(dpy, win);
127
128 glXMakeCurrent(dpy, win, cx);
129
130 /* check for the polygon offset extension */
131 #ifndef GL_VERSION_1_1
132 if (!query_extension("GL_EXT_polygon_offset"))
133 error(argv[0], "polygon_offset extension is not available");
134 #else
135 (void) query_extension;
136 #endif
137
138 /* set up viewing parameters */
139 glMatrixMode(GL_PROJECTION);
140 glFrustum(-1, 1, -1, 1, 6, 20);
141 glMatrixMode(GL_MODELVIEW);
142 glTranslatef(0, 0, -15);
143
144 /* set other relevant state information */
145 glEnable(GL_DEPTH_TEST);
146
147 glGetIntegerv(GL_DEPTH_BITS, &z);
148 printf("GL_DEPTH_BITS = %d\n", z);
149
150 #ifdef GL_EXT_polygon_offset
151 printf("using 1.0 offset extension\n");
152 glPolygonOffsetEXT( 1.0, 0.00001 );
153 #else
154 printf("using 1.1 offset\n");
155 glPolygonOffset( 1.0, 0.5 );
156 #endif
157
158 glShadeModel( GL_FLAT );
159 glDisable( GL_DITHER );
160
161 /* process events until the user presses ESC */
162 while (1) process_input(dpy, win);
163
164 return 0;
165 }
166
167 static void
168 draw_scene(int mx, int my) {
169 glClearColor(0.25, 0.25, 0.25, 0);
170 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
171
172 glPushMatrix();
173 glTranslatef(-1.7, 0.0, 0.0);
174 cubes(mx, my, WIREFRAME);
175 glPopMatrix();
176
177 glPushMatrix();
178 cubes(mx, my, HIDDEN_LINE);
179 glPopMatrix();
180
181 glPushMatrix();
182 glTranslatef(1.7, 0.0, 0.0);
183 #ifdef GL_EXT_polygon_offset
184 glEnable(GL_POLYGON_OFFSET_EXT);
185 #else
186 glEnable(GL_POLYGON_OFFSET_FILL);
187 #endif
188 glScalef(Scale, Scale, Scale);
189 cubes(mx, my, HIDDEN_LINE);
190 #ifdef GL_EXT_polygon_offset
191 glDisable(GL_POLYGON_OFFSET_EXT);
192 #else
193 glDisable(GL_POLYGON_OFFSET_FILL);
194 #endif
195 glPopMatrix();
196 }
197
198
199 static void
200 cubes(int mx, int my, int mode) {
201 int x, y, z, i;
202
203 /* track the mouse */
204 glRotatef(mx / 2.0, 0, 1, 0);
205 glRotatef(my / 2.0, 1, 0, 0);
206
207 /* draw the lines as hidden polygons */
208 glTranslatef(-0.5, -0.5, -0.5);
209 glScalef(1.0/dimension, 1.0/dimension, 1.0/dimension);
210 for (z = 0; z < dimension; z++) {
211 for (y = 0; y < dimension; y++) {
212 for (x = 0; x < dimension; x++) {
213 glPushMatrix();
214 glTranslatef(x, y, z);
215 glScalef(0.8, 0.8, 0.8);
216 for (i = 0; i < MAXQUAD; i++)
217 draw_hidden(quads[i], mode, i);
218 glPopMatrix();
219 }
220 }
221 }
222 }
223
224 static void
225 fill(Quad quad) {
226 /* draw a filled polygon */
227 glBegin(GL_QUADS);
228 glVertex3fv(quad[0]);
229 glVertex3fv(quad[1]);
230 glVertex3fv(quad[2]);
231 glVertex3fv(quad[3]);
232 glEnd();
233 }
234
235 static void
236 outline(Quad quad) {
237 /* draw an outlined polygon */
238 glBegin(GL_LINE_LOOP);
239 glVertex3fv(quad[0]);
240 glVertex3fv(quad[1]);
241 glVertex3fv(quad[2]);
242 glVertex3fv(quad[3]);
243 glEnd();
244 }
245
246 static void
247 draw_hidden(Quad quad, int mode, int face) {
248 static const GLfloat colors[3][3] = {
249 {0.5, 0.5, 0.0},
250 {0.8, 0.5, 0.0},
251 {0.0, 0.5, 0.8}
252 };
253 if (mode == HIDDEN_LINE) {
254 glColor3fv(colors[face % 3]);
255 fill(quad);
256 }
257
258 /* draw the outline using white */
259 glColor3f(1, 1, 1);
260 outline(quad);
261 }
262
263 static void
264 process_input(Display *dpy, Window win) {
265 XEvent event;
266 static int prevx, prevy;
267 static int deltax = 90, deltay = 40;
268
269 do {
270 char buf[31];
271 KeySym keysym;
272
273 XNextEvent(dpy, &event);
274 switch(event.type) {
275 case Expose:
276 break;
277 case ConfigureNotify: {
278 /* this approach preserves a 1:1 viewport aspect ratio */
279 int vX, vY, vW, vH;
280 int eW = event.xconfigure.width, eH = event.xconfigure.height;
281 if (eW >= eH) {
282 vX = 0;
283 vY = (eH - eW) >> 1;
284 vW = vH = eW;
285 } else {
286 vX = (eW - eH) >> 1;
287 vY = 0;
288 vW = vH = eH;
289 }
290 glViewport(vX, vY, vW, vH);
291 }
292 break;
293 case KeyPress:
294 (void) XLookupString(&event.xkey, buf, sizeof(buf), &keysym, NULL);
295 switch (keysym) {
296 case 'Z':
297 Scale *= 1.1;
298 break;
299 case 'z':
300 Scale *= 0.9;
301 break;
302 case XK_Escape:
303 exit(EXIT_SUCCESS);
304 default:
305 break;
306 }
307 break;
308 case ButtonPress:
309 prevx = event.xbutton.x;
310 prevy = event.xbutton.y;
311 break;
312 case MotionNotify:
313 deltax += (event.xbutton.x - prevx); prevx = event.xbutton.x;
314 deltay += (event.xbutton.y - prevy); prevy = event.xbutton.y;
315 break;
316 default:
317 break;
318 }
319 } while (XPending(dpy));
320
321 draw_scene(deltax, deltay);
322 glXSwapBuffers(dpy, win);
323 }
324
325 static void
326 error(const char *prog, const char *msg) {
327 fprintf(stderr, "%s: %s\n", prog, msg);
328 exit(EXIT_FAILURE);
329 }
330
331 static int
332 query_extension(char* extName) {
333 char *p = (char *) glGetString(GL_EXTENSIONS);
334 char *end = p + strlen(p);
335 while (p < end) {
336 int n = strcspn(p, " ");
337 if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0))
338 return GL_TRUE;
339 p += (n + 1);
340 }
341 return GL_FALSE;
342 }
343