00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <math.h>
00015
00016
00017 #include <GL/gl.h>
00018 #include <GL/glx.h>
00019 #include <GL/glu.h>
00020
00021
00022 #include <X11/Xlib.h>
00023 #include <X11/Xatom.h>
00024 #include <X11/Xmu/StdCmap.h>
00025 #include <X11/keysym.h>
00026
00027 Display *dpy;
00028 Window win;
00029 GLfloat angle = -150;
00030 Bool doubleBuffer = True, iconic = False, keepAspect = False;
00031 int W = 300, H = 300;
00032 XSizeHints sizeHints = {0};
00033 GLdouble bodyWidth = 2.0;
00034 int configuration[] = {GLX_DOUBLEBUFFER, GLX_RGBA, GLX_DEPTH_SIZE, 12,
00035 GLX_RED_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_GREEN_SIZE, 1, None};
00036
00037 typedef enum {
00038 RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
00039 LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
00040 } displayLists;
00041
00042 void extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
00043 GLdouble thickness, GLuint side, GLuint edge, GLuint whole);
00044 void redraw(void);
00045 void makeDinosaur(void);
00046 void contextInit(void);
00047
00048 void
00049 fatalError(char *message)
00050 {
00051 fprintf(stderr, "glxdino: %s\n", message);
00052 exit(1);
00053 }
00054
00055 Colormap
00056 getShareableColormap(XVisualInfo * vi)
00057 {
00058 Status status;
00059 XStandardColormap *standardCmaps;
00060 Colormap cmap;
00061 int i, numCmaps;
00062
00063
00064 if (vi->class != TrueColor)
00065 fatalError("No support for non-TrueColor visual.");
00066
00067
00068 status = XmuLookupStandardColormap(dpy, vi->screen, vi->visualid,
00069 vi->depth, XA_RGB_DEFAULT_MAP, False, True);
00070 if (status == 1) {
00071 status = XGetRGBColormaps(dpy, RootWindow(dpy, vi->screen),
00072 &standardCmaps, &numCmaps, XA_RGB_DEFAULT_MAP);
00073 if (status == 1)
00074 for (i = 0; i < numCmaps; i++)
00075 if (standardCmaps[i].visualid == vi->visualid) {
00076 cmap = standardCmaps[i].colormap;
00077 XFree(standardCmaps);
00078 return cmap;
00079 }
00080 }
00081 cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
00082 vi->visual, AllocNone);
00083 return cmap;
00084 }
00085
00086 void extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
00087 GLdouble thickness, GLuint side, GLuint edge, GLuint whole);
00088 GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
00089 {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
00090 {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
00091 {1, 2} };
00092 GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
00093 {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
00094 {13, 9}, {11, 11}, {9, 11} };
00095 GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
00096 {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
00097 GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
00098 {9.6, 15.25}, {9, 15.25} };
00099 GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0};
00100 GLfloat eyeColor[] = {1.0, 0.2, 0.2, 1.0};
00101
00102 void
00103 makeDinosaur(void)
00104 {
00105 GLfloat bodyWidth = 3.0;
00106
00107 extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
00108 BODY_SIDE, BODY_EDGE, BODY_WHOLE);
00109 extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
00110 ARM_SIDE, ARM_EDGE, ARM_WHOLE);
00111 extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
00112 LEG_SIDE, LEG_EDGE, LEG_WHOLE);
00113 extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
00114 EYE_SIDE, EYE_EDGE, EYE_WHOLE);
00115 glNewList(DINOSAUR, GL_COMPILE);
00116 glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
00117 glCallList(BODY_WHOLE);
00118 glPushMatrix();
00119 glTranslatef(0.0, 0.0, bodyWidth);
00120 glCallList(ARM_WHOLE);
00121 glCallList(LEG_WHOLE);
00122 glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
00123 glCallList(ARM_WHOLE);
00124 glTranslatef(0.0, 0.0, -bodyWidth / 4);
00125 glCallList(LEG_WHOLE);
00126 glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
00127 glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
00128 glCallList(EYE_WHOLE);
00129 glPopMatrix();
00130 glEndList();
00131 }
00132
00133
00134
00135 #ifdef LINUX2
00136 #define CAST_GLU_FUNCPTR (_GLUfuncptr)
00137 #else
00138 #define CAST_GLU_FUNCPTR
00139 #endif
00140
00141 void
00142 extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
00143 GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
00144 {
00145 static GLUtriangulatorObj *tobj = NULL;
00146 GLdouble vertex[3], dx, dy, len;
00147 int i;
00148 int count = dataSize / (2 * sizeof(GLfloat));
00149
00150 if (tobj == NULL) {
00151 tobj = gluNewTess();
00152
00153
00154 gluTessCallback(tobj, GLU_BEGIN, CAST_GLU_FUNCPTR glBegin);
00155 gluTessCallback(tobj, GLU_VERTEX, CAST_GLU_FUNCPTR glVertex2fv);
00156 gluTessCallback(tobj, GLU_END, CAST_GLU_FUNCPTR glEnd);
00157 }
00158 glNewList(side, GL_COMPILE);
00159 glShadeModel(GL_SMOOTH);
00160
00161 gluBeginPolygon(tobj);
00162 for (i = 0; i < count; i++) {
00163 vertex[0] = data[i][0];
00164 vertex[1] = data[i][1];
00165 vertex[2] = 0;
00166 gluTessVertex(tobj, vertex, &data[i]);
00167 }
00168 gluEndPolygon(tobj);
00169 glEndList();
00170 glNewList(edge, GL_COMPILE);
00171 glShadeModel(GL_FLAT);
00172
00173 glBegin(GL_QUAD_STRIP);
00174 for (i = 0; i <= count; i++) {
00175
00176 glVertex3f(data[i % count][0], data[i % count][1], 0.0);
00177 glVertex3f(data[i % count][0], data[i % count][1], thickness);
00178
00179
00180
00181
00182 dx = data[(i + 1) % count][1] - data[i % count][1];
00183 dy = data[i % count][0] - data[(i + 1) % count][0];
00184 len = sqrt(dx * dx + dy * dy);
00185 glNormal3f(dx / len, dy / len, 0.0);
00186 }
00187 glEnd();
00188 glEndList();
00189 glNewList(whole, GL_COMPILE);
00190 glFrontFace(GL_CW);
00191 glCallList(edge);
00192 glNormal3f(0.0, 0.0, -1.0);
00193 glCallList(side);
00194 glPushMatrix();
00195 glTranslatef(0.0, 0.0, thickness);
00196 glFrontFace(GL_CCW);
00197 glNormal3f(0.0, 0.0, 1.0);
00198 glCallList(side);
00199 glPopMatrix();
00200 glEndList();
00201 }
00202
00203 GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
00204 GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0};
00205 GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
00206 GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0};
00207
00208 void
00209 contextInit(void)
00210 {
00211 glEnable(GL_CULL_FACE);
00212
00213 glEnable(GL_DEPTH_TEST);
00214
00215 glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
00216 glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
00217 glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
00218 glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
00219 glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
00220 glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
00221 glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
00222
00223
00224 glEnable(GL_LIGHT0);
00225 glEnable(GL_LIGHT1);
00226 glEnable(GL_LIGHTING);
00227
00228
00229 glMatrixMode(GL_PROJECTION);
00230 gluPerspective(
00231 40.0,
00232 1.0,
00233 1.0,
00234 40.0);
00235
00236
00237 glMatrixMode(GL_MODELVIEW);
00238 gluLookAt(
00239 0.0, 0.0, 30.0,
00240 0.0, 0.0, 0.0,
00241 0.0, 1.0, 0.);
00242 glPushMatrix();
00243
00244 }
00245
00246 int
00247 main(int argc, char **argv)
00248 {
00249 XVisualInfo *vi;
00250 Colormap cmap;
00251 XSetWindowAttributes swa;
00252 XWMHints *wmHints;
00253 Atom wmDeleteWindow;
00254 GLXContext cx;
00255 XEvent event;
00256 KeySym ks;
00257 Bool needRedraw = False, recalcModelView = True;
00258 char *display = NULL, *geometry = NULL;
00259 int flags, x, y, width, height, lastX = 0, i;
00260
00261 for (i = 1; i < argc; i++) {
00262 if (!strcmp(argv[i], "-geometry")) {
00263 if (++i >= argc)
00264 fatalError("follow -geometry option with geometry parameter");
00265 geometry = argv[i];
00266 } else if (!strcmp(argv[i], "-display")) {
00267 if (++i >= argc)
00268 fatalError("follow -display option with display parameter");
00269 display = argv[i];
00270 } else if (!strcmp(argv[i], "-iconic"))
00271 iconic = True;
00272 else if (!strcmp(argv[i], "-keepaspect"))
00273 keepAspect = True;
00274 else if (!strcmp(argv[i], "-single"))
00275 doubleBuffer = False;
00276 else
00277 fatalError("bad option");
00278 }
00279
00280 dpy = XOpenDisplay(display);
00281 if (dpy == NULL)
00282 fatalError("could not open display");
00283
00284 if (!glXQueryExtension(dpy, NULL, NULL))
00285 fatalError("X server has no OpenGL GLX extension");
00286
00287
00288 if (!doubleBuffer)
00289 goto SingleBufferOverride;
00290 vi = glXChooseVisual(dpy, DefaultScreen(dpy), configuration);
00291 if (vi == NULL) {
00292 SingleBufferOverride:
00293 vi = glXChooseVisual(dpy, DefaultScreen(dpy), &configuration[1]);
00294 if (vi == NULL)
00295 fatalError("no appropriate RGB visual with depth buffer");
00296 doubleBuffer = False;
00297 }
00298 cmap = getShareableColormap(vi);
00299
00300
00301 cx = glXCreateContext(dpy, vi,
00302 NULL,
00303 True);
00304 if (cx == NULL)
00305 fatalError("could not create rendering context");
00306
00307 flags = XParseGeometry(geometry, &x, &y,
00308 (unsigned int *) &width, (unsigned int *) &height);
00309 if (WidthValue & flags) {
00310 sizeHints.flags |= USSize;
00311 sizeHints.width = width;
00312 W = width;
00313 }
00314 if (HeightValue & flags) {
00315 sizeHints.flags |= USSize;
00316 sizeHints.height = height;
00317 H = height;
00318 }
00319 if (XValue & flags) {
00320 if (XNegative & flags)
00321 x = DisplayWidth(dpy, DefaultScreen(dpy)) + x - sizeHints.width;
00322 sizeHints.flags |= USPosition;
00323 sizeHints.x = x;
00324 }
00325 if (YValue & flags) {
00326 if (YNegative & flags)
00327 y = DisplayHeight(dpy, DefaultScreen(dpy)) + y - sizeHints.height;
00328 sizeHints.flags |= USPosition;
00329 sizeHints.y = y;
00330 }
00331 if (keepAspect) {
00332 sizeHints.flags |= PAspect;
00333 sizeHints.min_aspect.x = sizeHints.max_aspect.x = W;
00334 sizeHints.min_aspect.y = sizeHints.max_aspect.y = H;
00335 }
00336 swa.colormap = cmap;
00337 swa.border_pixel = 0;
00338 swa.event_mask = ExposureMask | StructureNotifyMask |
00339 ButtonPressMask | Button1MotionMask | KeyPressMask;
00340 win = XCreateWindow(dpy, RootWindow(dpy, vi->screen),
00341 sizeHints.x, sizeHints.y, W, H,
00342 0, vi->depth, InputOutput, vi->visual,
00343 CWBorderPixel | CWColormap | CWEventMask, &swa);
00344 XSetStandardProperties(dpy, win, "OpenGLosaurus", "glxdino",
00345 None, argv, argc, &sizeHints);
00346 wmHints = XAllocWMHints();
00347 wmHints->initial_state = iconic ? IconicState : NormalState;
00348 wmHints->flags = StateHint;
00349 XSetWMHints(dpy, win, wmHints);
00350 wmDeleteWindow = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
00351 XSetWMProtocols(dpy, win, &wmDeleteWindow, 1);
00352 glXMakeCurrent(dpy, win, cx);
00353 makeDinosaur();
00354 contextInit();
00355 XMapWindow(dpy, win);
00356 for (;;) {
00357 do {
00358 XNextEvent(dpy, &event);
00359 switch (event.type) {
00360 case ConfigureNotify:
00361 glViewport(0, 0,
00362 event.xconfigure.width, event.xconfigure.height);
00363
00364 case Expose:
00365 needRedraw = True;
00366 break;
00367 case MotionNotify:
00368 recalcModelView = True;
00369 angle -= (lastX - event.xmotion.x);
00370 case ButtonPress:
00371 lastX = event.xbutton.x;
00372 break;
00373 case KeyPress:
00374 ks = XLookupKeysym((XKeyEvent *) & event, 0);
00375 if (ks == XK_Escape)
00376 exit(0);
00377 break;
00378 case ClientMessage:
00379 if (event.xclient.data.l[0] == wmDeleteWindow)
00380 exit(0);
00381 break;
00382 }
00383 } while (XPending(dpy));
00384 if (recalcModelView) {
00385 glPopMatrix();
00386
00387 glPushMatrix();
00388 glRotatef(angle, 0.0, 1.0, 0.0);
00389 glTranslatef(-8, -8, -bodyWidth / 2);
00390 recalcModelView = False;
00391 needRedraw = True;
00392 }
00393 if (needRedraw) {
00394 redraw();
00395 needRedraw = False;
00396 }
00397 }
00398 }
00399
00400 void
00401 redraw(void)
00402 {
00403 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00404 glCallList(DINOSAUR);
00405 if (doubleBuffer)
00406 glXSwapBuffers(dpy, win);
00407 else
00408 glFlush();
00409 }