offset.c revision 32001f49
1/****************************************************************************
2Copyright 1995 by Silicon Graphics Incorporated, Mountain View, California.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Silicon Graphics not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
18USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
19OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20PERFORMANCE 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
67typedef float Vertex[3];
68
69typedef Vertex Quad[4];
70
71/* data to define the six faces of a unit cube */
72Quad 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
84static void error(const char* prog, const char* msg);
85static void cubes(int mx, int my, int mode);
86static void fill(Quad quad);
87static void outline(Quad quad);
88static void draw_hidden(Quad quad, int mode, int face);
89static void process_input(Display *dpy, Window win);
90static int query_extension(char* extName);
91
92static 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
95static int dimension = 3;
96
97static float Scale = 1.0;
98
99
100int 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
167static void
168draw_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
199static void
200cubes(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
224static void
225fill(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
235static void
236outline(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
246static void
247draw_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
263static void
264process_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
325static void
326error(const char *prog, const char *msg) {
327    fprintf(stderr, "%s: %s\n", prog, msg);
328    exit(EXIT_FAILURE);
329}
330
331static int
332query_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
344