324 lines
8.3 KiB
C
324 lines
8.3 KiB
C
/****************************************************************************
|
|
Copyright 1995 by Silicon Graphics Incorporated, Mountain View, California.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
provided that the above copyright notice appear in all copies and that
|
|
both that copyright notice and this permission notice appear in
|
|
supporting documentation, and that the name of Silicon Graphics not be
|
|
used in advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
|
|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
|
|
USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
****************************************************************************/
|
|
|
|
/*
|
|
* Derived from code written by Kurt Akeley, November 1992
|
|
*
|
|
* Uses PolygonOffset to draw hidden-line images. PolygonOffset
|
|
* shifts the z values of polygons an amount that is
|
|
* proportional to their slope in screen z. This keeps
|
|
* the lines, which are drawn without displacement, from
|
|
* interacting with their respective polygons, and
|
|
* thus eliminates line dropouts.
|
|
*
|
|
* The left image shows an ordinary antialiased wireframe image.
|
|
* The center image shows an antialiased hidden-line image without
|
|
* PolygonOffset.
|
|
* The right image shows an antialiased hidden-line image using
|
|
* PolygonOffset to reduce artifacts.
|
|
*
|
|
* Drag with a mouse button pressed to rotate the models.
|
|
* Press the escape key to exit.
|
|
*/
|
|
|
|
/*
|
|
* Modified for OpenGL 1.1 glPolygonOffset() conventions
|
|
*/
|
|
|
|
|
|
#include <GL/glx.h>
|
|
#include <GL/glu.h>
|
|
#include <X11/keysym.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#undef GL_EXT_polygon_offset /* use GL 1.1 version instead of extension */
|
|
|
|
|
|
#ifndef EXIT_FAILURE
|
|
# define EXIT_FAILURE 1
|
|
#endif
|
|
#ifndef EXIT_SUCCESS
|
|
# define EXIT_SUCCESS 0
|
|
#endif
|
|
|
|
#define MAXQUAD 6
|
|
|
|
typedef float Vertex[3];
|
|
|
|
typedef Vertex Quad[4];
|
|
|
|
/* data to define the six faces of a unit cube */
|
|
Quad quads[MAXQUAD] = {
|
|
{ {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0} },
|
|
{ {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1} },
|
|
{ {0,0,0}, {1,0,0}, {1,0,1}, {0,0,1} },
|
|
{ {0,1,0}, {1,1,0}, {1,1,1}, {0,1,1} },
|
|
{ {0,0,0}, {0,0,1}, {0,1,1}, {0,1,0} },
|
|
{ {1,0,0}, {1,0,1}, {1,1,1}, {1,1,0} }
|
|
};
|
|
|
|
#define WIREFRAME 0
|
|
#define HIDDEN_LINE 1
|
|
|
|
static void error(const char* prog, const char* msg);
|
|
static void cubes(int mx, int my, int mode);
|
|
static void fill(Quad quad);
|
|
static void outline(Quad quad);
|
|
static void draw_hidden(Quad quad, int mode);
|
|
static void process_input(Display *dpy, Window win);
|
|
static int query_extension(char* extName);
|
|
|
|
static int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
|
|
GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None };
|
|
|
|
static int dimension = 3;
|
|
|
|
int main(int argc, char** argv) {
|
|
Display *dpy;
|
|
XVisualInfo *vi;
|
|
XSetWindowAttributes swa;
|
|
Window win;
|
|
GLXContext cx;
|
|
|
|
dpy = XOpenDisplay(0);
|
|
if (!dpy) error(argv[0], "can't open display");
|
|
|
|
vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
|
|
if (!vi) error(argv[0], "no suitable visual");
|
|
|
|
cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
|
|
|
|
swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
|
|
vi->visual, AllocNone);
|
|
|
|
swa.border_pixel = 0;
|
|
swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
|
|
ButtonPressMask | ButtonMotionMask;
|
|
win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, 900, 300,
|
|
0, vi->depth, InputOutput, vi->visual,
|
|
CWBorderPixel|CWColormap|CWEventMask, &swa);
|
|
XStoreName(dpy, win, "hiddenline");
|
|
XMapWindow(dpy, win);
|
|
|
|
glXMakeCurrent(dpy, win, cx);
|
|
|
|
/* check for the polygon offset extension */
|
|
#ifndef GL_VERSION_1_1
|
|
if (!query_extension("GL_EXT_polygon_offset"))
|
|
error(argv[0], "polygon_offset extension is not available");
|
|
#else
|
|
(void) query_extension;
|
|
#endif
|
|
|
|
/* set up viewing parameters */
|
|
glMatrixMode(GL_PROJECTION);
|
|
gluPerspective(20, 1, 0.1, 20);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glTranslatef(0, 0, -15);
|
|
|
|
/* set other relevant state information */
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
#ifdef GL_EXT_polygon_offset
|
|
printf("using 1.0 offset extension\n");
|
|
glPolygonOffsetEXT( 1.0, 0.00001 );
|
|
#else
|
|
printf("using 1.1 offset\n");
|
|
glPolygonOffset( 1.0, 0.5 );
|
|
#endif
|
|
|
|
glShadeModel( GL_FLAT );
|
|
glDisable( GL_DITHER );
|
|
|
|
/* process events until the user presses ESC */
|
|
while (1) process_input(dpy, win);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
draw_scene(int mx, int my) {
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
glPushMatrix();
|
|
glTranslatef(-1.7, 0.0, 0.0);
|
|
cubes(mx, my, WIREFRAME);
|
|
glPopMatrix();
|
|
|
|
glPushMatrix();
|
|
cubes(mx, my, HIDDEN_LINE);
|
|
glPopMatrix();
|
|
|
|
glPushMatrix();
|
|
glTranslatef(1.7, 0.0, 0.0);
|
|
#ifdef GL_EXT_polygon_offset
|
|
glEnable(GL_POLYGON_OFFSET_EXT);
|
|
#else
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
#endif
|
|
cubes(mx, my, HIDDEN_LINE);
|
|
#ifdef GL_EXT_polygon_offset
|
|
glDisable(GL_POLYGON_OFFSET_EXT);
|
|
#else
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
#endif
|
|
glPopMatrix();
|
|
}
|
|
|
|
|
|
static void
|
|
cubes(int mx, int my, int mode) {
|
|
int x, y, z, i;
|
|
|
|
/* track the mouse */
|
|
glRotatef(mx / 2.0, 0, 1, 0);
|
|
glRotatef(my / 2.0, 1, 0, 0);
|
|
|
|
/* draw the lines as hidden polygons */
|
|
glTranslatef(-0.5, -0.5, -0.5);
|
|
glScalef(1.0/dimension, 1.0/dimension, 1.0/dimension);
|
|
for (z = 0; z < dimension; z++) {
|
|
for (y = 0; y < dimension; y++) {
|
|
for (x = 0; x < dimension; x++) {
|
|
glPushMatrix();
|
|
glTranslatef(x, y, z);
|
|
glScalef(0.8, 0.8, 0.8);
|
|
for (i = 0; i < MAXQUAD; i++)
|
|
draw_hidden(quads[i], mode);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
fill(Quad quad) {
|
|
/* draw a filled polygon */
|
|
glBegin(GL_QUADS);
|
|
glVertex3fv(quad[0]);
|
|
glVertex3fv(quad[1]);
|
|
glVertex3fv(quad[2]);
|
|
glVertex3fv(quad[3]);
|
|
glEnd();
|
|
}
|
|
|
|
static void
|
|
outline(Quad quad) {
|
|
/* draw an outlined polygon */
|
|
glBegin(GL_LINE_LOOP);
|
|
glVertex3fv(quad[0]);
|
|
glVertex3fv(quad[1]);
|
|
glVertex3fv(quad[2]);
|
|
glVertex3fv(quad[3]);
|
|
glEnd();
|
|
}
|
|
|
|
static void
|
|
draw_hidden(Quad quad, int mode) {
|
|
if (mode == HIDDEN_LINE) {
|
|
glColor3f(0, 0, 0);
|
|
fill(quad);
|
|
}
|
|
|
|
/* draw the outline using white, optionally fill the interior with black */
|
|
glColor3f(1, 1, 1);
|
|
outline(quad);
|
|
}
|
|
|
|
static void
|
|
process_input(Display *dpy, Window win) {
|
|
XEvent event;
|
|
static int prevx, prevy;
|
|
static int deltax = 90, deltay = 40;
|
|
|
|
do {
|
|
char buf[31];
|
|
KeySym keysym;
|
|
|
|
XNextEvent(dpy, &event);
|
|
switch(event.type) {
|
|
case Expose:
|
|
break;
|
|
case ConfigureNotify: {
|
|
/* this approach preserves a 1:1 viewport aspect ratio */
|
|
int vX, vY, vW, vH;
|
|
int eW = event.xconfigure.width, eH = event.xconfigure.height;
|
|
if (eW >= eH) {
|
|
vX = 0;
|
|
vY = (eH - eW) >> 1;
|
|
vW = vH = eW;
|
|
} else {
|
|
vX = (eW - eH) >> 1;
|
|
vY = 0;
|
|
vW = vH = eH;
|
|
}
|
|
glViewport(vX, vY, vW, vH);
|
|
}
|
|
break;
|
|
case KeyPress:
|
|
(void) XLookupString(&event.xkey, buf, sizeof(buf), &keysym, NULL);
|
|
switch (keysym) {
|
|
case XK_Escape:
|
|
exit(EXIT_SUCCESS);
|
|
default:
|
|
break;
|
|
}
|
|
case ButtonPress:
|
|
prevx = event.xbutton.x;
|
|
prevy = event.xbutton.y;
|
|
break;
|
|
case MotionNotify:
|
|
deltax += (event.xbutton.x - prevx); prevx = event.xbutton.x;
|
|
deltay += (event.xbutton.y - prevy); prevy = event.xbutton.y;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} while (XPending(dpy));
|
|
|
|
draw_scene(deltax, deltay);
|
|
glXSwapBuffers(dpy, win);
|
|
}
|
|
|
|
static void
|
|
error(const char *prog, const char *msg) {
|
|
fprintf(stderr, "%s: %s\n", prog, msg);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
static int
|
|
query_extension(char* extName) {
|
|
char *p = (char *) glGetString(GL_EXTENSIONS);
|
|
char *end = p + strlen(p);
|
|
while (p < end) {
|
|
int n = strcspn(p, " ");
|
|
if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0))
|
|
return GL_TRUE;
|
|
p += (n + 1);
|
|
}
|
|
return GL_FALSE;
|
|
}
|
|
|