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