dinodraw.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:12k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /* 
  2.  * Dinodraw.c
  3.  *
  4.  * Copyright (c) James Bowman 1998,
  5.  * parts (c) Mark J. Kilgard, 1994.
  6.  */
  7. /* This program is freely distributable without licensing fees 
  8.    and is provided without guarantee or warrantee expressed or 
  9.    implied. This program is -not- in the public domain. */
  10. /* Modified version of Mark J. Kilgard's dinospin that demontrates use of
  11.  * stencil buffer to interactively view overdraw.
  12.  */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <math.h>       /* for cos(), sin(), and sqrt() */
  17. #include <GL/glut.h>
  18. #include "trackball.h"
  19. typedef enum {
  20.   RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
  21.   LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
  22. } displayLists;
  23. GLfloat angle = -150;   /* in degrees */
  24. GLboolean doubleBuffer = GL_TRUE, iconic = GL_FALSE, keepAspect = GL_FALSE;
  25. int spinning = 0, moving = 0;
  26. int beginx, beginy;
  27. int W = 300, H = 300;
  28. float curquat[4];
  29. float lastquat[4];
  30. GLdouble bodyWidth = 2.0;
  31. int newModel = 1;
  32. int scaling;
  33. float scalefactor = 1.0;
  34. /* *INDENT-OFF* */
  35. GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
  36.   {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
  37.   {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
  38.   {1, 2} };
  39. GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
  40.   {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
  41.   {13, 9}, {11, 11}, {9, 11} };
  42. GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
  43.   {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
  44. GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
  45.   {9.6, 15.25}, {9, 15.25} };
  46. GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
  47. GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
  48. GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
  49. GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0}; /* red-tinted */
  50. GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
  51. /* *INDENT-ON* */
  52. void
  53. extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
  54.   GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
  55. {
  56.   static GLUtriangulatorObj *tobj = NULL;
  57.   GLdouble vertex[3], dx, dy, len;
  58.   int i;
  59.   int count = dataSize / (2 * sizeof(GLfloat));
  60.   if (tobj == NULL) {
  61.     tobj = gluNewTess();  /* create and initialize a GLU
  62.                              polygon * * tesselation object */
  63.     gluTessCallback(tobj, GLU_BEGIN, glBegin);
  64.     gluTessCallback(tobj, GLU_VERTEX, glVertex2fv);  /* semi-tricky 
  65.                                                       */
  66.     gluTessCallback(tobj, GLU_END, glEnd);
  67.   }
  68.   glNewList(side, GL_COMPILE);
  69.   glShadeModel(GL_SMOOTH);  /* smooth minimizes seeing
  70.                                tessellation */
  71.   gluBeginPolygon(tobj);
  72.   for (i = 0; i < count; i++) {
  73.     vertex[0] = data[i][0];
  74.     vertex[1] = data[i][1];
  75.     vertex[2] = 0;
  76.     gluTessVertex(tobj, vertex, data[i]);
  77.   }
  78.   gluEndPolygon(tobj);
  79.   glEndList();
  80.   glNewList(edge, GL_COMPILE);
  81.   glShadeModel(GL_FLAT);  /* flat shade keeps angular hands
  82.                              from being * * "smoothed" */
  83.   glBegin(GL_QUAD_STRIP);
  84.   for (i = 0; i <= count; i++) {
  85.     /* mod function handles closing the edge */
  86.     glVertex3f(data[i % count][0], data[i % count][1], 0.0);
  87.     glVertex3f(data[i % count][0], data[i % count][1], thickness);
  88.     /* Calculate a unit normal by dividing by Euclidean
  89.        distance. We * could be lazy and use
  90.        glEnable(GL_NORMALIZE) so we could pass in * arbitrary
  91.        normals for a very slight performance hit. */
  92.     dx = data[(i + 1) % count][1] - data[i % count][1];
  93.     dy = data[i % count][0] - data[(i + 1) % count][0];
  94.     len = sqrt(dx * dx + dy * dy);
  95.     glNormal3f(dx / len, dy / len, 0.0);
  96.   }
  97.   glEnd();
  98.   glEndList();
  99.   glNewList(whole, GL_COMPILE);
  100.   glFrontFace(GL_CW);
  101.   glCallList(edge);
  102.   glNormal3f(0.0, 0.0, -1.0);  /* constant normal for side */
  103.   glCallList(side);
  104.   glPushMatrix();
  105.   glTranslatef(0.0, 0.0, thickness);
  106.   glFrontFace(GL_CCW);
  107.   glNormal3f(0.0, 0.0, 1.0);  /* opposite normal for other side 
  108.                                */
  109.   glCallList(side);
  110.   glPopMatrix();
  111.   glEndList();
  112. }
  113. void
  114. makeDinosaur(void)
  115. {
  116.   GLfloat bodyWidth = 3.0;
  117.   extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
  118.     BODY_SIDE, BODY_EDGE, BODY_WHOLE);
  119.   extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
  120.     ARM_SIDE, ARM_EDGE, ARM_WHOLE);
  121.   extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
  122.     LEG_SIDE, LEG_EDGE, LEG_WHOLE);
  123.   extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
  124.     EYE_SIDE, EYE_EDGE, EYE_WHOLE);
  125.   glNewList(DINOSAUR, GL_COMPILE);
  126.   glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
  127.   glCallList(BODY_WHOLE);
  128.   glPushMatrix();
  129.   glTranslatef(0.0, 0.0, bodyWidth);
  130.   glCallList(ARM_WHOLE);
  131.   glCallList(LEG_WHOLE);
  132.   glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
  133.   glCallList(ARM_WHOLE);
  134.   glTranslatef(0.0, 0.0, -bodyWidth / 4);
  135.   glCallList(LEG_WHOLE);
  136.   glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
  137.   glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
  138.   glCallList(EYE_WHOLE);
  139.   glPopMatrix();
  140.   glEndList();
  141. }
  142. void
  143. recalcModelView(void)
  144. {
  145.   GLfloat m[4][4];
  146.   glPopMatrix();
  147.   glPushMatrix();
  148.   build_rotmatrix(m, curquat);
  149.   glMultMatrixf(&m[0][0]);
  150.   glScalef(scalefactor, scalefactor, scalefactor);
  151.   glTranslatef(-8, -8, -bodyWidth / 2);
  152.   newModel = 0;
  153. }
  154. void
  155. showMessage(GLfloat x, GLfloat y, GLfloat z, char *message)
  156. {
  157.   glPushMatrix();
  158.   glDisable(GL_LIGHTING);
  159.   glTranslatef(x, y, z);
  160.   glScalef(.02, .02, .02);
  161.   while (*message) {
  162.     glutStrokeCharacter(GLUT_STROKE_ROMAN, *message);
  163.     message++;
  164.   }
  165.   glEnable(GL_LIGHTING);
  166.   glPopMatrix();
  167. }
  168. void
  169. redraw(void)
  170. {
  171.   if (newModel)
  172.     recalcModelView();
  173.   glClear(GL_COLOR_BUFFER_BIT | 
  174.   GL_DEPTH_BUFFER_BIT | 
  175.   GL_STENCIL_BUFFER_BIT);
  176.   /* Draw the real scene in the left viewport... */
  177.   glViewport(0, 0, W / 2, H);
  178.   glDisable(GL_STENCIL_TEST);
  179.   glCallList(DINOSAUR);
  180.   showMessage(2, 7.1, 4.1, "Spin me.");
  181.   /* ...and the overdraw indicator in the right viewport */
  182.   glViewport(W / 2, 0, W / 2, H);
  183.   /* First draw the scene again, this time without color updates,
  184.    * just counting pixels drawn in the stencil buffer.
  185.    */
  186.   glEnable(GL_STENCIL_TEST);
  187.   glStencilFunc(GL_ALWAYS, 0, 0);
  188.   glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
  189.   glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  190.   glCallList(DINOSAUR);
  191.   showMessage(2, 7.1, 4.1, "Spin me.");
  192.   glMatrixMode(GL_MODELVIEW);
  193.   glPushMatrix();
  194.   glLoadIdentity();
  195.   glMatrixMode(GL_PROJECTION);
  196.   glPushMatrix();
  197.   glLoadIdentity();
  198.   glDisable(GL_LIGHTING);
  199.   glDisable(GL_DEPTH_TEST);
  200.   glColor3f(1.0f, 1.0f, 1.0f);
  201.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  202.   /* Copy bit 0 into the blue plane */
  203.   glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
  204.   glStencilFunc(GL_NOTEQUAL, 0, 0xf8 | 0x01);
  205.   glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
  206.   /* Copy bit 1 into the red plane */
  207.   glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
  208.   glStencilFunc(GL_NOTEQUAL, 0, 0xf8 | 0x02);
  209.   glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
  210.   /* Copy bit 2 into the green plane */
  211.   glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
  212.   glStencilFunc(GL_NOTEQUAL, 0, 0xf8 | 0x04);
  213.   glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
  214.   /* Note that anything greater than 7 will have one of  bits 3-7 set,
  215.    * hence will be drawn on all three planes by the mask with 0xf8 above.
  216.    * So anything overdrawn 7 or more times will be drawn in white.
  217.    */
  218.   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  219.   glEnable(GL_DEPTH_TEST);
  220.   glEnable(GL_LIGHTING);
  221.   glMatrixMode(GL_PROJECTION);
  222.   glPopMatrix();
  223.   glMatrixMode(GL_MODELVIEW);
  224.   glPopMatrix();
  225.   glutSwapBuffers();
  226. }
  227. void
  228. myReshape(int w, int h)
  229. {
  230.   glViewport(0, 0, w / 2, h);
  231.   W = w;
  232.   H = h;
  233. }
  234. void
  235. mouse(int button, int state, int x, int y)
  236. {
  237.   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  238.     spinning = 0;
  239.     glutIdleFunc(NULL);
  240.     moving = 1;
  241.     beginx = x;
  242.     beginy = y;
  243.     if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) {
  244.       scaling = 1;
  245.     } else {
  246.       scaling = 0;
  247.     }
  248.   }
  249.   if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
  250.     moving = 0;
  251.   }
  252. }
  253. void
  254. animate(void)
  255. {
  256.   add_quats(lastquat, curquat, curquat);
  257.   newModel = 1;
  258.   glutPostRedisplay();
  259. }
  260. void
  261. motion(int x, int y)
  262. {
  263.   if (scaling) {
  264.     scalefactor = scalefactor * (1.0 + (((float) (beginy - y)) / H));
  265.     beginx = x;
  266.     beginy = y;
  267.     newModel = 1;
  268.     glutPostRedisplay();
  269.     return;
  270.   }
  271.   if (moving) {
  272.     trackball(lastquat,
  273.       (2.0 * beginx - W) / W,
  274.       (H - 2.0 * beginy) / H,
  275.       (2.0 * x - W) / W,
  276.       (H - 2.0 * y) / H
  277.       );
  278.     beginx = x;
  279.     beginy = y;
  280.     spinning = 1;
  281.     glutIdleFunc(animate);
  282.   }
  283. }
  284. GLboolean lightZeroSwitch = GL_TRUE, lightOneSwitch = GL_TRUE;
  285. void
  286. controlLights(int value)
  287. {
  288.   switch (value) {
  289.   case 1:
  290.     lightZeroSwitch = !lightZeroSwitch;
  291.     if (lightZeroSwitch) {
  292.       glEnable(GL_LIGHT0);
  293.     } else {
  294.       glDisable(GL_LIGHT0);
  295.     }
  296.     break;
  297.   case 2:
  298.     lightOneSwitch = !lightOneSwitch;
  299.     if (lightOneSwitch) {
  300.       glEnable(GL_LIGHT1);
  301.     } else {
  302.       glDisable(GL_LIGHT1);
  303.     }
  304.     break;
  305. #ifdef GL_MULTISAMPLE_SGIS
  306.   case 3:
  307.     if (glIsEnabled(GL_MULTISAMPLE_SGIS)) {
  308.       glDisable(GL_MULTISAMPLE_SGIS);
  309.     } else {
  310.       glEnable(GL_MULTISAMPLE_SGIS);
  311.     }
  312.     break;
  313. #endif
  314.   case 4:
  315.     glutFullScreen();
  316.     break;
  317.   case 5:
  318.     exit(0);
  319.     break;
  320.   }
  321.   glutPostRedisplay();
  322. }
  323. void
  324. vis(int visible)
  325. {
  326.   if (visible == GLUT_VISIBLE) {
  327.     if (spinning)
  328.       glutIdleFunc(animate);
  329.   } else {
  330.     if (spinning)
  331.       glutIdleFunc(NULL);
  332.   }
  333. }
  334. int
  335. main(int argc, char **argv)
  336. {
  337.   glutInit(&argc, argv);
  338.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
  339.   trackball(curquat, 0.0, 0.0, 0.0, 0.0);
  340.   glutInitWindowSize(600, 300);
  341.   glutCreateWindow("dinodraw");
  342.   glutDisplayFunc(redraw);
  343.   glutReshapeFunc(myReshape);
  344.   glutVisibilityFunc(vis);
  345.   glutMouseFunc(mouse);
  346.   glutMotionFunc(motion);
  347.   glutCreateMenu(controlLights);
  348.   glutAddMenuEntry("Toggle right light", 1);
  349.   glutAddMenuEntry("Toggle left light", 2);
  350.   if (glutGet(GLUT_WINDOW_NUM_SAMPLES) > 0) {
  351.     glutAddMenuEntry("Toggle multisampling", 3);
  352.     glutSetWindowTitle("dinospin (multisample capable)");
  353.   }
  354.   glutAddMenuEntry("Full screen", 4);
  355.   glutAddMenuEntry("Quit", 5);
  356.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  357.   makeDinosaur();
  358.   glEnable(GL_CULL_FACE);
  359.   glEnable(GL_DEPTH_TEST);
  360.   glEnable(GL_LIGHTING);
  361.   glMatrixMode(GL_PROJECTION);
  362.   gluPerspective( /* field of view in degree */ 40.0,
  363.   /* aspect ratio */ 1.0,
  364.     /* Z near */ 1.0, /* Z far */ 40.0);
  365.   glMatrixMode(GL_MODELVIEW);
  366.   gluLookAt(0.0, 0.0, 30.0,  /* eye is at (0,0,30) */
  367.     0.0, 0.0, 0.0,      /* center is at (0,0,0) */
  368.     0.0, 1.0, 0.);      /* up is in positive Y direction */
  369.   glPushMatrix();       /* dummy push so we can pop on model
  370.                            recalc */
  371.   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
  372.   glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
  373.   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
  374.   glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
  375.   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
  376.   glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
  377.   glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
  378.   glEnable(GL_LIGHT0);
  379.   glEnable(GL_LIGHT1);
  380.   glLineWidth(2.0);
  381.   glutMainLoop();
  382.   return 0;             /* ANSI C requires main to return int. */
  383. }