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

GIS编程

开发平台:

Visual C++

  1. /* smapmesh.c - construct a cube map from sphere map via warp
  2.    mesh */
  3. #include <assert.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include <GL/glut.h>
  8. #if defined(GL_EXT_texture_object) && !defined(GL_VERSION_1_1)
  9. #define glBindTexture(A,B)     glBindTextureEXT(A,B)
  10. #endif
  11. static int emphasize = 0;
  12. static int clearToWhite = 0;
  13. /* (x,y,z) reflection vector --> (s,t) sphere map coordinates */
  14. void
  15. rvec2st(float v[3], float st[2])
  16. {
  17.   double m;
  18.   /** In Section 2.10.4 ("Generating texture coordinates") of
  19.       the OpenGL 1.1 specification, you will find the
  20.       GL_SPHERE_MAP equations:
  21.       n' = normal after transformation to eye coordinates
  22.       u  = unit vector from origin to vertex in eye coordinates
  23.       (rx, ry, rz) = u - 2 * n' * transpose(n') * u
  24.       m  = 2 * sqrt(rx^2 + ry^2 + (rz + 1)^2))
  25.       s = rx/m + 0.5 t = ry/m + 0.5
  26.       The equation for calculating (rx, ry, rz) is the equation
  27.       for calculating the reflection vector for a surface and
  28.       observer.  The explanation and derivation for this
  29.       equation is found in Roger's "Procedural Elements for
  30.       Computer Graphics" 2nd ed. in Section 5-5 ("Determining
  31.       the Reflection Vector"). Note that Roger's convention has
  32.       the Z axis in the opposite direction from the OpenGL
  33.       convention. */
  34.   m = 2 * sqrt(v[0] * v[0] + v[1] * v[1] + (v[2] + 1) * (v[2] + 1));
  35.   st[0] = v[0] / m + 0.5;
  36.   st[1] = v[1] / m + 0.5;
  37. }
  38. /* (s,t) sphere map coordinate --> reflection verctor (x,y,z) */
  39. void
  40. st2rvec(float s, float t, float *xp, float *yp, float *zp)
  41. {
  42.   double rx, ry, rz;
  43.   double tmp1, tmp2;
  44.   /** Using algebra to invert the sphere mapping equations shown 
  45.       above in rvec2st, you get:
  46.       rx = 2*sqrt(-4*s^2 + 4*s - 4*t^2 + 4*t - 1)*(2*s-1)
  47.       ry = 2*sqrt(-4*s^2 + 4*s - 4*t^2 + 4*t - 1)*(2*t-1)
  48.       rz = -8*s^2 + 8*s - 8*t^2 + 8*t - 3
  49.       The C code below eliminates common subexpressions. */
  50.   tmp1 = s * (1 - s) + t * (1 - t);
  51.   tmp2 = 2 * sqrt(4 * tmp1 - 1);
  52.   rx = tmp2 * (2 * s - 1);
  53.   ry = tmp2 * (2 * t - 1);
  54.   rz = 8 * tmp1 - 3;
  55.   *xp = (float) rx;
  56.   *yp = (float) ry;
  57.   *zp = (float) rz;
  58. }
  59. /* For best results (ie, to avoid cracks in the sphere map
  60.    construction, XSTEPS, YSTEPS, and SPOKES should all be
  61.    equal. */
  62. /* Increasing the nSTEPS and RINGS constants below will give
  63.    you a better approximation to the sphere map image warp at
  64.    the cost of more polygons to render the image warp.  My bet
  65.    is that no will be able to the improved quality of a higher
  66.    level of tessellation. */
  67. #define XSTEPS  8
  68. #define YSTEPS  8
  69. #define SPOKES  8
  70. #define RINGS   3
  71. typedef struct _STXY {
  72.   GLfloat s, t;
  73.   GLfloat x, y;
  74. } STXY;
  75. STXY face[5][YSTEPS][XSTEPS];
  76. STXY back[4][RINGS][SPOKES];
  77. static struct {
  78.   int xl;
  79.   int yl;
  80.   int zl;
  81.   float dir;
  82. } faceInfo[5] = {
  83.   { 0, 1, 2, 1.0 } ,                     /* front */
  84.   { 0, 2, 1, 1.0 } ,                     /* top */
  85.   { 0, 2, 1, -1.0 } ,                     /* bottom */
  86.   { 1, 2, 0, -1.0 } ,                     /* left */
  87.   { 1, 2, 0, 1.0 } ,                     /* right */
  88. };
  89. static struct {
  90.   int xl;
  91.   int yl;
  92.   float dir;
  93. } edgeInfo[4] = {
  94.   { 0, 1, -1.0 } ,
  95.   { 0, 1, 1.0 } ,
  96.   { 1, 0, -1.0 } ,
  97.   { 1, 0, 1.0 }
  98. };
  99. void
  100. makeSpheremapMapping(void)
  101. {
  102.   float st[2];          /* (s,t) coordinate  */
  103.                         /* range=[0..1,0..1] */
  104.   float v[3];           /* (x,y,z) location on cube map */
  105.                         /* range=[-1..1,-1..1,-1..1] */
  106.   float rv[3];          /* reflection vector, ie. cube map */
  107.                         /* location normalized onto unit sphere */
  108.   float len;            /* distance from v[3] to origin */
  109.                         /* for converting to rv[3] */
  110.   int side;             /* which of 5 faces (all but back face) */
  111.   int i, j;
  112.   int xl, yl, zl;       /* renamed X, Y, Z index */
  113.   int edge;             /* which edge of back face */
  114.   float sc, tc;
  115.   /* for the front and four side faces */
  116.   for (side = 0; side < 5; side++) {
  117.     /* use faceInfo to parameterize face construction */
  118.     xl = faceInfo[side].xl;
  119.     yl = faceInfo[side].yl;
  120.     zl = faceInfo[side].zl;
  121.     /* cube map "Z" coordinate */
  122.     v[zl] = faceInfo[side].dir;
  123.     for (i = 0; i < YSTEPS; i++) {
  124.       /* cube map "Y" coordinate */
  125.       v[yl] = 2.0 / (YSTEPS - 1) * i - 1.0;
  126.       for (j = 0; j < XSTEPS; j++) {
  127.         /* cube map "X" coordinate */
  128.         v[xl] = 2.0 / (XSTEPS - 1) * j - 1.0;
  129.         /* normalize cube map location to construct */
  130.         /* reflection vector */
  131.         len = sqrt(1.0 + v[xl] * v[xl] + v[yl] * v[yl]);
  132.         rv[0] = v[0] / len;
  133.         rv[1] = v[1] / len;
  134.         rv[2] = v[2] / len;
  135.         /* map reflection vector to sphere map (s,t) */
  136.         /* NOTE: face[side][i][j] (x,y) gets updated */
  137.         rvec2st(rv, &face[side][i][j].x);
  138.         /* update texture coordinate, */
  139.         /* normalize [-1..1,-1..1] to [0..1,0..1] */
  140.         face[side][i][j].s = (v[xl] + 1.0) / 2.0;
  141.         face[side][i][j].t = (v[yl] + 1.0) / 2.0;
  142.       }
  143.     }
  144.   }
  145.   /* The back face must be specially handled.  The center point 
  146.      in the back face of a cube map becomes a a singularity
  147.      around the circular edge of a sphere map. */
  148.   /* Carefully work from each edge of the back face to center
  149.      of back face mapped to the outside of the sphere map. */
  150.   /* cube map "Z" coordinate, always -1 since backface */
  151.   v[2] = -1;
  152.   /* for each edge */
  153.   /* [x=-1, y=-1..1, z=-1] */
  154.   /* [x= 1, y=-1..1, z=-1] */
  155.   /* [x=-1..1, y=-1, z=-1] */
  156.   /* [x=-1..1, y= 1, z=-1] */
  157.   for (edge = 0; edge < 4; edge++) {
  158.     /* cube map "X" coordinate */
  159.     v[edgeInfo[edge].xl] = edgeInfo[edge].dir;
  160.     for (j = 0; j < SPOKES; j++) {
  161.       /* cube map "Y" coordinate */
  162.       v[edgeInfo[edge].yl] = 2.0 / (SPOKES - 1) * j - 1.0;
  163.       /* normalize cube map location to construct */
  164.       /* reflection vector */
  165.       len = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
  166.       rv[0] = v[0] / len;
  167.       rv[1] = v[1] / len;
  168.       rv[2] = v[2] / len;
  169.       /* Map reflection vector to sphere map (s,t). */
  170.       rvec2st(rv, st);
  171.       /* determine distinance from the center of sphere */
  172.       /* map (0.5,0.5) to (s,t) */
  173.       len = sqrt((st[0] - 0.5) * (st[0] - 0.5) + (st[1] - 0.5) * (st[1] - 0.5));
  174.       /* calculate (s,t) location extended to the singularity */
  175.       /* at the center of the back face (ie, extend to */
  176.       /* circle edge of the sphere map) */
  177.       sc = (st[0] - 0.5) / len * 0.5 + 0.5;
  178.       tc = (st[1] - 0.5) / len * 0.5 + 0.5;
  179.       /* (s,t) at back face edge */
  180.       back[edge][0][j].s = (v[0] + 1.0) / 2.0;
  181.       back[edge][0][j].t = (v[1] + 1.0) / 2.0;
  182.       back[edge][0][j].x = st[0];
  183.       back[edge][0][j].y = st[1];
  184.       /* If just two rings, we just generate a back face edge
  185.          vertex and a center vertex (2 rings), but if there are 
  186.          more rings, we carefully interpolate between the edge
  187.          and center vertices.  Notice how st2rvec is used to
  188.          map the interpolated (s,t) into a reflection vector
  189.          that must then be extended to the back cube face (it
  190.          is not correct to just interpolate the texture
  191.          coordinates!). */
  192.       if (RINGS > 2) {
  193.         float s, t;     /* interpolated (s,t) */
  194.         float ds, dt;   /* delta s and delta t */
  195.         float x, y, z;
  196.         /* Start interpolating from the edge. */
  197.         s = st[0];
  198.         t = st[1];
  199.         /* Calculate delta s and delta t for interpolation. */
  200.         ds = (sc - s) / (RINGS - 1);
  201.         dt = (tc - t) / (RINGS - 1);
  202.         for (i = 1; i < RINGS - 1; i++) {
  203.           /* Incremental interpolation of (s,t). */
  204.           s = s + ds;
  205.           t = t + dt;
  206.           /* Calculate reflection vector from interpolated */
  207.           /* (s,t). */
  208.           st2rvec(s, t, &x, &y, &z);
  209.           /* Assert that z must be on the back cube face. */
  210.           assert(z <= -sqrt(1.0 / 3.0));
  211.           /* Extend reflection vector out of back cube face. */
  212.           /* Note: z is negative value so negate z to avoid */
  213.           /* inverting x and y! */
  214.           x = x / -z;
  215.           y = y / -z;
  216.           back[edge][i][j].s = (x + 1.0) / 2.0;
  217.           back[edge][i][j].t = (y + 1.0) / 2.0;
  218.           back[edge][i][j].x = s;
  219.           back[edge][i][j].y = t;
  220.         }
  221.       }
  222.       /* (s,t) at circle edge of the sphere map is ALWAYS */
  223.       /* at center of back cube map face */
  224.       back[edge][RINGS - 1][j].s = 0.5;
  225.       back[edge][RINGS - 1][j].t = 0.5;
  226.       /* location of singularity at the edge of the sphere map */
  227.       back[edge][RINGS - 1][j].x = sc;
  228.       back[edge][RINGS - 1][j].y = tc;
  229.     }
  230.   }
  231. }
  232. void
  233. drawSphereMapping(GLuint texobj[6])
  234. {
  235.   int side, i, j;
  236.   /* five front and side faces */
  237.   for (side = 0; side < 5; side++) {
  238.     if (emphasize == side + 1) {
  239.       glLineWidth(3.0);
  240.     }
  241.     /* bind to texture for given face of cube map */
  242.     glBindTexture(GL_TEXTURE_2D, texobj[side]);
  243.     for (i = 0; i < YSTEPS - 1; i++) {
  244.       glBegin(GL_QUAD_STRIP);
  245.       for (j = 0; j < XSTEPS; j++) {
  246.         glTexCoord2fv(&face[side][i][j].s);
  247.         glVertex2fv(&face[side][i][j].x);
  248.         glTexCoord2fv(&face[side][i + 1][j].s);
  249.         glVertex2fv(&face[side][i + 1][j].x);
  250.       }
  251.       glEnd();
  252.     }
  253.     if (emphasize == side + 1) {
  254.       glLineWidth(1.0);
  255.     }
  256.   }
  257.   /* Back face specially rendered for its singularity! */
  258.   if (emphasize == 6) {
  259.     glLineWidth(3.0);
  260.   }
  261.   /* Bind to texture for back face of cube map. */
  262.   glBindTexture(GL_TEXTURE_2D, texobj[side]);
  263.   for (side = 0; side < 4; side++) {
  264.     for (j = 0; j < RINGS - 1; j++) {
  265.       glBegin(GL_QUAD_STRIP);
  266.       for (i = 0; i < SPOKES; i++) {
  267.         glTexCoord2fv(&back[side][j][i].s);
  268.         glVertex2fv(&back[side][j][i].x);
  269.         glTexCoord2fv(&back[side][j + 1][i].s);
  270.         glVertex2fv(&back[side][j + 1][i].x);
  271.       }
  272.       glEnd();
  273.     }
  274.   }
  275.   if (emphasize == 6) {
  276.     glLineWidth(1.0);
  277.   }
  278. }
  279. static void
  280. textureInit(void)
  281. {
  282.   static int width = 8, height = 8;
  283.   static GLubyte tex1[] = {
  284.     0, 0, 0, 0, 0, 0, 0, 0,
  285.     0, 0, 0, 0, 1, 0, 0, 0,
  286.     0, 0, 0, 1, 1, 0, 0, 0,
  287.     0, 0, 0, 0, 1, 0, 0, 0,
  288.     0, 0, 0, 0, 1, 0, 0, 0,
  289.     0, 0, 0, 0, 1, 0, 0, 0,
  290.     0, 0, 0, 1, 1, 1, 0, 0,
  291.     0, 0, 0, 0, 0, 0, 0, 0};
  292.   GLubyte tex[64][3];
  293.   GLint i, j;
  294.   /* setup first texture object */
  295.   glBindTexture(GL_TEXTURE_2D, 1);
  296.   /* red on white */
  297.   for (i = 0; i < height; i++) {
  298.     for (j = 0; j < width; j++) {
  299.       int p = i * width + j;
  300.       if (tex1[(height - i - 1) * width + j]) {
  301.         tex[p][0] = 255;
  302.         tex[p][1] = 0;
  303.         tex[p][2] = 0;
  304.       } else {
  305.         tex[p][0] = 255;
  306.         tex[p][1] = 255;
  307.         tex[p][2] = 255;
  308.       }
  309.     }
  310.   }
  311.   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  312.   gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,
  313.     GL_RGB, GL_UNSIGNED_BYTE, tex);
  314.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  315.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  316.     GL_LINEAR_MIPMAP_LINEAR);
  317. }
  318. static void
  319. display(void)
  320. {
  321.   /* All faces get the same texture! */
  322.   GLuint texobjs[6] = {1, 1, 1, 1, 1, 1};
  323.   /* Clear to gray. */
  324.   if (clearToWhite) {
  325.     glClearColor(1.0, 1.0, 1.0, 1.0);
  326.     glColor3f(0.0, 0.0, 0.0);
  327.     emphasize = 0;
  328.     glLineWidth(3.0);
  329.   } else {
  330.     glClearColor(0.5, 0.5, 0.5, 1.0);
  331.     glColor3f(1.0, 1.0, 1.0);
  332.     glLineWidth(1.0);
  333.   }
  334.   glClear(GL_COLOR_BUFFER_BIT);
  335.   glMatrixMode(GL_PROJECTION);
  336.   glLoadIdentity();
  337.   gluOrtho2D(0, 1, 0, 1);
  338.   glMatrixMode(GL_MODELVIEW);
  339.   glLoadIdentity();
  340.   drawSphereMapping(texobjs);
  341.   glutSwapBuffers();
  342. }
  343. static void
  344. menu(int value)
  345. {
  346.   switch (value) {
  347.   case 1:
  348.     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  349.     break;
  350.   case 2:
  351.     glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  352.     break;
  353.   case 3:
  354.     glEnable(GL_TEXTURE_2D);
  355.     break;
  356.   case 4:
  357.     glDisable(GL_TEXTURE_2D);
  358.     break;
  359.   case 5:
  360.     glEnable(GL_LINE_SMOOTH);
  361.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  362.     glEnable(GL_BLEND);
  363.     break;
  364.   case 6:
  365.     glDisable(GL_LINE_SMOOTH);
  366.     glDisable(GL_BLEND);
  367.     break;
  368.   case 7:
  369.     emphasize++;
  370.     emphasize %= 7;
  371.     break;
  372.   case 8:
  373.     clearToWhite = 1;
  374.     break;
  375.   case 9:
  376.     clearToWhite = 0;
  377.     break;
  378.   }
  379.   glutPostRedisplay();
  380. }
  381. void
  382. keyboard(unsigned char c, int x, int y)
  383. {
  384.   switch (c) {
  385.   case 27:
  386.     exit(0);
  387.     break;
  388.   case ' ':
  389.     menu(7);
  390.     break;
  391.   case 'a':
  392.     menu(5);
  393.     break;
  394.   case 'w':
  395.     menu(2);
  396.     break;
  397.   case 'f':
  398.     menu(1);
  399.     break;
  400.   case 't':
  401.     menu(3);
  402.     break;
  403.   case 'n':
  404.     menu(4);
  405.     break;
  406.   }
  407. }
  408. int
  409. main(int argc, char **argv)
  410. {
  411.   makeSpheremapMapping();
  412.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  413.   glutCreateWindow("smapmesh");
  414.   textureInit();
  415.   glEnable(GL_TEXTURE_2D);
  416.   glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  417.   glutDisplayFunc(display);
  418.   glutKeyboardFunc(keyboard);
  419.   glutCreateMenu(menu);
  420.   glutAddMenuEntry("fill", 1);
  421.   glutAddMenuEntry("wireframe", 2);
  422.   glutAddMenuEntry("texture", 3);
  423.   glutAddMenuEntry("no texture", 4);
  424.   glutAddMenuEntry("antialias lines", 5);
  425.   glutAddMenuEntry("aliased lines", 6);
  426.   glutAddMenuEntry("switch emphasis", 7);
  427.   glutAddMenuEntry("clear to white", 8);
  428.   glutAddMenuEntry("clear to gray", 9);
  429.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  430.   glutMainLoop();
  431.   return 0;
  432. }