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

GIS编程

开发平台:

Visual C++

  1. /* envmap.c - David Blythe, SGI */
  2. /* Texture environment mapping demo. */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <math.h>
  6. #ifndef _WIN32
  7. #include <unistd.h>
  8. #else
  9. #define drand48() (((float) rand())/((float) RAND_MAX))
  10. #endif
  11. #include <string.h>
  12. #include <GL/glut.h>
  13. #include "texture.h"
  14. #if defined(GL_VERSION_1_1)
  15. /* Routines called directly. */
  16. #elif defined(GL_EXT_texture_object) && defined(GL_EXT_copy_texture) && defined(GL_EXT_subtexture)
  17. #define glBindTexture(A,B)     glBindTextureEXT(A,B)
  18. #define glGenTextures(A,B)     glGenTexturesEXT(A,B)
  19. #define glDeleteTextures(A,B)  glDeleteTexturesEXT(A,B)
  20. #define glCopyTexSubImage2D(A,B,C,D,E,F,G,H) glCopyTexSubImage2DEXT(A,B,C,D,E,F,G,H)
  21. #else
  22. #define glBindTexture(A,B)
  23. #define glGenTextures(A,B)
  24. #define glDeleteTextures(A,B)
  25. #define glCopyTexSubImage2D(A,B,C,D,E,F,G,H)
  26. #endif
  27. /* Some <math.h> files do not define M_PI... */
  28. #ifndef M_PI
  29. #define M_PI 3.14159265358979323846
  30. #endif
  31. #define OB_CUBE    0
  32. #define OB_SPHERE  1
  33. #define OB_SQUARE  2
  34. #define OB_CYL     3
  35. #define OB_TORUS   4
  36. #define OB_HSPHERE 5
  37. #define NOBJS 5
  38. #define TDRAW 10
  39. #define LIST_BASE 100
  40. #define TOBJ_BASE 200
  41. #define TEXSIZE   256   /* default texture-size */
  42. typedef struct _vector {
  43.   float x, y, z;
  44. } vector_t;
  45. typedef struct _face {
  46.   char *filename;
  47.   unsigned *buf;
  48.   int width;
  49.   int height;
  50.   int components;
  51.   vector_t u, v, n, o;  /* plane equation */
  52.   float angle1;
  53.   vector_t axis1;       /* for rotation */
  54.   float angle2;
  55.   vector_t axis2;
  56. } face_t;
  57. typedef struct _color {
  58.   float r, g, b;
  59. } color_t;
  60. struct {                /* command-line options */
  61.   int use_spheremap;
  62.   char *spheremap_file;
  63.   int hw;
  64.   int size;
  65.   int samples;
  66.   int object;
  67.   char *outfile;
  68.   int tessellation;
  69. } opts = {
  70.   0, 0, 0, TEXSIZE, 4, OB_TORUS, 0, 30
  71. };                      /* default settings */
  72. void display(void);
  73. void init(void);
  74. void build_lists(void);
  75. unsigned *render_spheremap(int *width, int *height,
  76.   int *components, int doalloc);
  77. /* strdup is actually not a standard ANSI C or POSIX routine
  78.    so implement a private one.  OpenVMS does not have a strdup; Linux's
  79.    standard libc doesn't declare strdup by default (unless BSD or SVID
  80.    interfaces are requested). */
  81. static char *
  82. stralloc(const char *string)
  83. {
  84.   char *copy;
  85.   copy = malloc(strlen(string) + 1);
  86.   if (copy == NULL)
  87.     return NULL;
  88.   strcpy(copy, string);
  89.   return copy;
  90. }
  91. void
  92. vadd(vector_t * a, vector_t * b, vector_t * sum)
  93. {
  94.   sum->x = a->x + b->x;
  95.   sum->y = a->y + b->y;
  96.   sum->z = a->z + b->z;
  97. }
  98. void
  99. vsub(vector_t * a, vector_t * b, vector_t * diff)
  100. {
  101.   diff->x = a->x - b->x;
  102.   diff->y = a->y - b->y;
  103.   diff->z = a->z - b->z;
  104. }
  105. void
  106. vscale(vector_t * v, float scale)
  107. {
  108.   v->x *= scale;
  109.   v->y *= scale;
  110.   v->z *= scale;
  111. }
  112. float
  113. vdot(vector_t * u, vector_t * v)
  114. {
  115.   return (u->x * v->x + u->y * v->y + u->z * v->z);
  116. }
  117. void
  118. vreflect(vector_t * axis, vector_t * v, vector_t * r)
  119. {
  120.   vector_t t = *axis;
  121.   vscale(&t, 2 * vdot(axis, v));
  122.   vsub(&t, v, r);
  123. }
  124. int
  125. intersect(vector_t * v)
  126. {
  127.   int f;
  128.   float x, y, z;
  129.   x = fabs(v->x);
  130.   y = fabs(v->y);
  131.   z = fabs(v->z);
  132.   if (x >= y && x >= z)
  133.     f = (v->x > 0) ? 2 : 0;
  134.   else if (y >= x && y >= z)
  135.     f = (v->y > 0) ? 4 : 5;
  136.   else
  137.     f = (v->z > 0) ? 3 : 1;
  138.   return f;
  139. }
  140. face_t face[6] =
  141. {
  142.   {"../data/00.rgb", 0, 0, 0, 0,
  143.     {0, 0, -1},
  144.     {0, 1, 0},
  145.     {-1, 0, 0},
  146.     {-0.5, -0.5, 0.5}, 90.0,
  147.     {0, 1, 0}, 0,
  148.     {0, 0, 0}},
  149.   {"../data/01.rgb", 0, 0, 0, 0,
  150.     {1, 0, 0},
  151.     {0, 1, 0},
  152.     {0, 0, -1},
  153.     {-0.5, -0.5, -0.5}, 180.0,
  154.     {0, 1, 0}, 0,
  155.     {0, 0, 0}},
  156.   {"../data/02.rgb", 0, 0, 0, 0,
  157.     {0, 0, 1},
  158.     {0, 1, 0},
  159.     {1, 0, 0},
  160.     {0.5, -0.5, -0.5}, 270.0,
  161.     {0, 1, 0}, 0,
  162.     {0, 0, 0}},
  163.   {"../data/03.rgb", 0, 0, 0, 0,
  164.     {-1, 0, 0},
  165.     {0, 1, 0},
  166.     {0, 0, 1},
  167.     {0.5, -0.5, 0.5}, 0.0,
  168.     {0, 1, 0}, 0,
  169.     {0, 0, 0}},
  170.   {"../data/04.rgb", 0, 0, 0, 0,
  171.     {1, 0, 0},
  172.     {0, 0, 1},
  173.     {0, 1, 0},
  174.     {-0.5, 0.5, -0.5}, 90.0,
  175.     {1, 0, 0}, 180.0,
  176.     {0, 1, 0}},
  177.   {"../data/05.rgb", 0, 0, 0, 0,
  178.     {1, 0, 0},
  179.     {0, 0, -1},
  180.     {0, -1, 0},
  181.     {-0.5, -0.5, 0.5}, -90.0,
  182.     {1, 0, 0}, 180.0,
  183.     {0, 1, 0}}
  184. };
  185. void
  186. sample(int facenum, float s, float t, color_t * c)
  187. {
  188.   face_t *f = &face[facenum];
  189.   int xpos, ypos;
  190.   unsigned char *p;
  191.   xpos = s * f->width;
  192.   ypos = t * f->height;
  193.   p = (unsigned char *) &f->buf[ypos * f->width + xpos];
  194.   c->r = p[0] / 255.0;
  195.   c->g = p[1] / 255.0;
  196.   c->b = p[2] / 255.0;
  197. }
  198. unsigned *
  199. construct_spheremap(int *width, int *height,
  200.   int *components)
  201. {
  202.   int i, j, x, y, f;
  203.   unsigned *spheremap;
  204.   unsigned char *lptr;
  205.   int size = opts.size;
  206.   color_t c, texel;
  207.   vector_t v, r, p;
  208.   float s, t, temp, k;
  209.   int samples;
  210.   /* Read in the 6 faces of the environment */
  211.   for (i = 0; i < 6; i++) {
  212.     face[i].buf = read_texture(face[i].filename, &face[i].width,
  213.       &face[i].height, &face[i].components);
  214.     if (!face[i].buf) {
  215.       fprintf(stderr, "Error: cannot load image %sn", face[i].filename);
  216.       exit(1);
  217.     }
  218.   }
  219.   *components = face[0].components;
  220.   *width = *height = size;
  221.   samples = opts.samples;
  222.   spheremap = (unsigned *) malloc(size * size * sizeof(unsigned));
  223.   if (!spheremap) {
  224.     perror("malloc");
  225.     exit(1);
  226.   }
  227.   lptr = (unsigned char *) spheremap;
  228.   /* Calculate sphere-map by rendering a perfectly reflective solid sphere. */
  229.   for (y = 0; y < size; y++)
  230.     for (x = 0; x < size; x++) {
  231.       texel.r = texel.g = texel.b = 0.0;
  232.       for (j = 0; j < samples; j++) {
  233.         s = (x + (float) drand48()) / size - 0.5;
  234.         t = (y + (float) drand48()) / size - 0.5;
  235.         temp = s * s + t * t;
  236.         if (temp >= 0.25) {  /* point not on sphere */
  237.           c.r = c.g = c.b = 0;
  238.           continue;
  239.         }
  240.         /* get point on sphere */
  241.         p.x = s;
  242.         p.y = t;
  243.         p.z = sqrt(0.25 - temp);
  244.         vscale(&p, 2.0);
  245.         /* ray from infinity (eyepoint) to surface */
  246.         v.x = 0.0;
  247.         v.y = 0.0;
  248.         v.z = 1.0;
  249.         /* get reflected ray */
  250.         vreflect(&p, &v, &r);
  251.         /* Intersect reflected ray with cube */
  252.         f = intersect(&r);
  253.         k = vdot(&face[f].o, &face[f].n) / vdot(&r, &face[f].n);
  254.         vscale(&r, k);
  255.         vsub(&r, &face[f].o, &v);
  256.         /* Get texture map-indices */
  257.         s = vdot(&v, &face[f].u);
  258.         t = vdot(&v, &face[f].v);
  259.         /* Sample to get color */
  260.         sample(f, s, t, &c);
  261.         texel.r += c.r;
  262.         texel.g += c.g;
  263.         texel.b += c.b;
  264.       }
  265.       lptr[0] = 255 * texel.r / samples;
  266.       lptr[1] = 255 * texel.g / samples;
  267.       lptr[2] = 255 * texel.b / samples;
  268.       lptr[3] = 0xff;
  269.       lptr += 4;
  270.     }
  271.   return (unsigned *) spheremap;
  272. }
  273. void
  274. texture_init(void)
  275. {
  276.   unsigned *buf;
  277.   int width, height, components;
  278.   char filename[80];
  279.   if (opts.use_spheremap) {
  280.     strcpy(filename, opts.spheremap_file);
  281.     buf = read_texture(filename, &width, &height, &components);
  282.     if (components == 3)
  283.       components++;
  284.     if (!buf) {
  285.       fprintf(stderr, "Error: cannot load image %sn", filename);
  286.       exit(1);
  287.     }
  288.   } else {
  289.     buf = (opts.hw) ?
  290.       render_spheremap(&width, &height, &components, 1) :
  291.       construct_spheremap(&width, &height, &components);
  292.     if (!buf) {
  293.       fprintf(stderr, "Error: Cannot construct spheremapn");
  294.       exit(1);
  295.     }
  296.   }
  297.   glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + TDRAW);
  298.   glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  299.   glEnable(GL_TEXTURE_2D);
  300.   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
  301.   gluBuild2DMipmaps(GL_TEXTURE_2D, components, width, height,
  302.     GL_RGBA, GL_UNSIGNED_BYTE, buf);
  303.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  304.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  305.     GL_LINEAR_MIPMAP_LINEAR);
  306.   glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  307.   glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  308.   glEnable(GL_TEXTURE_GEN_S);
  309.   glEnable(GL_TEXTURE_GEN_T);
  310.   free(buf);
  311. }
  312. void
  313. texture_init_from_spheremap(void)
  314. {
  315.   int w, h, components;
  316.   render_spheremap(&w, &h, &components, 0);
  317.   glReadBuffer(GL_BACK);
  318.   glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + TDRAW);
  319.   glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
  320.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  321.   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  322.   glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  323.   glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  324.   glEnable(GL_TEXTURE_GEN_S);
  325.   glEnable(GL_TEXTURE_GEN_T);
  326. }
  327. void
  328. parse(int argc, char *argv[])
  329. {
  330.   int i = 1;
  331.   char *usage =
  332.   "Usage: map [-size n] [-samples n] [-help] n
  333. t[-sphere filename | -cubemap [0-5].rgb]n
  334. n
  335. t-size n : specify size of sphere-map (when generated from cubemap)n
  336. t-samples n : #samples to use per pixel of the spheremapn
  337. t-sphere file.rgb  : specify spheremap-imagen
  338. t-cubemap [0-5].rgb: specify 6 cubemap filesn
  339. t-out file.rgb: save generated spheremap to filen
  340. t-hw   : Use hardware texture mapping to create sphere-mapn
  341. t-help : print this messagen";
  342. #define check_arg(i, n, str) 
  343.   if (argc < i+n) {       
  344.     fprintf(stderr, "%s needs an argumentn", str);  
  345.     fprintf(stderr, usage); 
  346.     exit(1); 
  347.   }
  348.   while (i < argc) {
  349.     if (!strcmp(argv[i], "-size")) {
  350.       check_arg(i, 1, "-size");
  351.       opts.size = atoi(argv[++i]);
  352.     } else if (!strcmp(argv[i], "-samples")) {
  353.       check_arg(i, 1, "-samples");
  354.       opts.samples = atoi(argv[++i]);
  355.     } else if (!strcmp(argv[i], "-out")) {
  356.       check_arg(i, 1, "-out");
  357.       opts.outfile = stralloc(argv[++i]);
  358.     } else if (!strcmp(argv[i], "-sphere")) {
  359.       opts.use_spheremap = 1;
  360.     } else if (!strcmp(argv[i], "-cubemap")) {
  361.       int j;
  362.       check_arg(i, 6, "-cubemap");
  363.       for (j = 0; j < 6; j++)
  364.         face[j].filename = stralloc(argv[++i]);
  365.     } else if (!strcmp(argv[i], "-help")) {
  366.       fprintf(stderr, usage);
  367.       exit(0);
  368.     } else if (!strcmp(argv[i], "-hw")) {
  369.       opts.hw = 1;
  370.     } else {
  371.       if (opts.use_spheremap && !opts.spheremap_file)
  372.         opts.spheremap_file = stralloc(argv[i]);
  373.       else {
  374.         fprintf(stderr, "Error: unrecognized option %sn", argv[i]);
  375.         fprintf(stderr, usage);
  376.         exit(1);
  377.       }
  378.     }
  379.     i++;
  380.   }                     /* end-while */
  381. }
  382. #ifdef use_copytex
  383. static int currwidth = TEXSIZE;
  384. static int currheight = TEXSIZE;
  385. #else
  386. static int currwidth = 400;
  387. static int currheight = 400;
  388. #endif
  389. static int do_spheremap = 0, do_alloc = 0;
  390. static GLfloat rotv[] =
  391. {0., 0., 0.};
  392. static GLfloat rots[] =
  393. {0., 0., 0.};
  394. static GLfloat plane[4][3] =
  395. {
  396.   {1.0, -1.0, 0.0},
  397.   {1.0, 1.0, 0.0},
  398.   {-1.0, 1.0, 0.0},
  399.   {-1.0, -1.0, 0.0}
  400. };
  401. static GLfloat cube[6][4][3] =
  402. {
  403.   {
  404.     {1.0, -1.0, -1.0},  /* counter-clockwise faces */
  405.     {-1.0, -1.0, -1.0},
  406.     {-1.0, 1.0, -1.0},
  407.     {1.0, 1.0, -1.0}
  408.   },
  409.   {
  410.     {1.0, -1.0, 1.0},
  411.     {1.0, -1.0, -1.0},
  412.     {1.0, 1.0, -1.0},
  413.     {1.0, 1.0, 1.0}
  414.   },
  415.   {
  416.     {-1.0, -1.0, 1.0},
  417.     {1.0, -1.0, 1.0},
  418.     {1.0, 1.0, 1.0},
  419.     {-1.0, 1.0, 1.0}
  420.   },
  421.   {
  422.     {-1.0, -1.0, -1.0},
  423.     {-1.0, -1.0, 1.0},
  424.     {-1.0, 1.0, 1.0},
  425.     {-1.0, 1.0, -1.0}
  426.   },
  427.   {
  428.     {1.0, 1.0, 1.0},
  429.     {1.0, 1.0, -1.0},
  430.     {-1.0, 1.0, -1.0},
  431.     {-1.0, 1.0, 1.0}
  432.   },
  433.   {
  434.     {1.0, -1.0, -1.0},
  435.     {1.0, -1.0, 1.0},
  436.     {-1.0, -1.0, 1.0},
  437.     {-1.0, -1.0, -1.0}
  438.   }
  439. };
  440. static float norm[6][3] =
  441. {
  442.   {0.0, 0.0, -1.0},
  443.   {1.0, 0.0, 0.0},
  444.   {0.0, 0.0, 1.0},
  445.   {-1.0, 0.0, 0.0},
  446.   {0.0, 1.0, 0.0},
  447.   {0.0, -1.0, 0.0}
  448. };
  449. void
  450. reshape(int w, int h)
  451. {
  452.   currwidth = w;
  453.   currheight = h;
  454.   glViewport(0, 0, w, h);
  455.   glMatrixMode(GL_PROJECTION);
  456.   glLoadIdentity();
  457.   gluPerspective(40.0, (GLfloat) w / (GLfloat) h, 1.0, 20.0);
  458.   glMatrixMode(GL_MODELVIEW);
  459.   glLoadIdentity();
  460.   gluLookAt(0, 0, 6,
  461.     0, 0, 0,
  462.     0, 1, 0);
  463. }
  464. /* ARGSUSED1 */
  465. void
  466. keys(unsigned char key, int x, int y)
  467. {
  468.   switch (key) {
  469.   case 'o':            /* switch between objects */
  470.     opts.object = (opts.object + 1) % NOBJS;
  471.     glutPostRedisplay();
  472.     break;
  473.   case '+':            /* change tessellation */
  474.     opts.tessellation += 2;
  475.     build_lists();
  476.     glutPostRedisplay();
  477.     break;
  478.   case '-':
  479.     opts.tessellation -= 2;
  480.     if (opts.tessellation < 4)
  481.       opts.tessellation = 4;
  482.     build_lists();
  483.     glutPostRedisplay();
  484.     break;
  485.   case 's':            /* toggle between spheremap generation */
  486.     /* mode and display mode */
  487.     do_spheremap ^= 1;
  488.     if (!do_spheremap)  /* switch back to normal mode */
  489.       do_alloc = 1;
  490.     glutPostRedisplay();
  491.     break;
  492.   case 'h':
  493.   case 'H':
  494.     printf("nKey functionsn");
  495.     printf("to: switch objectsn");
  496.     printf("ts: switch to spheremap generation moden");
  497.     printf("t+: increase tessellationn");
  498.     printf("t-: decrease tessellationn");
  499.     printf("th: helpn");
  500.     printf("tESC: quitn");
  501.     printf("tleft/right arrow-keys: Rotate around X axisn");
  502.     printf("tup/down arrow-keys: Rotate around Y axisn");
  503.     printf("tpage-up/pgdown arrow-keys: Rotate around Z axisn");
  504.     break;
  505.   case 27:
  506.     exit(0);
  507.   }
  508. }
  509. /* ARGSUSED1 */
  510. void
  511. special_keys(int key, int x, int y)
  512. {
  513.   GLfloat *vect;
  514.   if (do_spheremap)
  515.     vect = rots;
  516.   else
  517.     vect = rotv;
  518.   switch (key) {
  519.   case GLUT_KEY_LEFT:
  520.     vect[1] -= 0.5;
  521.     glutPostRedisplay();
  522.     break;
  523.   case GLUT_KEY_RIGHT:
  524.     vect[1] += 0.5;
  525.     glutPostRedisplay();
  526.     break;
  527.   case GLUT_KEY_UP:
  528.     vect[0] -= 0.5;
  529.     glutPostRedisplay();
  530.     break;
  531.   case GLUT_KEY_DOWN:
  532.     vect[0] += 0.5;
  533.     glutPostRedisplay();
  534.     break;
  535.   case GLUT_KEY_PAGE_UP:
  536.     vect[2] -= 0.5;
  537.     glutPostRedisplay();
  538.     break;
  539.   case GLUT_KEY_PAGE_DOWN:
  540.     vect[2] += 0.5;
  541.     glutPostRedisplay();
  542.     break;
  543.   }
  544. }
  545. /* Use mouse buttons to generate spheremap on the fly while the objects are
  546.    being displayed.  */
  547. static void
  548. motion(int x, int y)
  549. {
  550.   rots[1] = 180.0 * x / currwidth - 90.0;
  551.   rots[0] = 180.0 * y / currheight - 90.0;
  552. #ifdef use_copytex
  553.   if (!do_spheremap)
  554.     texture_init_from_spheremap();
  555. #endif
  556.   glutPostRedisplay();
  557. }
  558. void
  559. menu(int value)
  560. {
  561.   keys((unsigned char) value, 0, 0);
  562. }
  563. #if defined(GL_VERSION_1_1)
  564. static int
  565. supportsOneDotOne(void)
  566. {
  567.   const char *version;
  568.   int major, minor;
  569.   version = (char *) glGetString(GL_VERSION);
  570.   if (sscanf(version, "%d.%d", &major, &minor) == 2)
  571.     return major >= 1 && minor >= 1;
  572.   return 0;            /* OpenGL version string malformed! */
  573. }
  574. #endif
  575. int
  576. main(int argc, char *argv[])
  577. {
  578.   int hasExtendedTextures;
  579.   parse(argc, argv);
  580.   glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
  581.   glutInitWindowSize(currwidth, currheight);
  582.   glutCreateWindow("Environment map");
  583. #if defined(GL_VERSION_1_1)
  584.   hasExtendedTextures = supportsOneDotOne();
  585.   if(!hasExtendedTextures) {
  586.     fprintf(stderr,
  587.       "envmap: This example requires OpenGL 1.1.n");
  588.     exit(1);
  589.   }
  590. #elif defined(GL_EXT_texture_object) && defined(GL_EXT_copy_texture) && defined(GL_EXT_subtexture)
  591.   hasExtendedTextures = glutExtensionSupported("GL_EXT_subtexture")
  592.     && glutExtensionSupported("GL_EXT_texture_object")
  593.     && glutExtensionSupported("GL_EXT_copy_texture");
  594.   if(!hasExtendedTextures) {
  595.     fprintf(stderr,
  596.       "envmap: This example requires the OpenGL EXT_subtexture, EXT_texture_object, and EXT_copy_texture extensions.n");
  597.     exit(1);
  598.   }
  599. #else
  600.   hasExtendedTextures = 0;
  601.   if(!hasExtendedTextures) {
  602.     fprintf(stderr,
  603.       "envmap: This example must be compiled with either OpenGL 1.1 or the OpenGL EXT_subtexture, EXT_texture_object, and EXT_copy_texture extensions.n");
  604.     exit(1);
  605.   }
  606. #endif
  607.   init();
  608.   glutReshapeFunc(reshape);
  609.   glutKeyboardFunc(keys);
  610.   glutSpecialFunc(special_keys);
  611.   if (opts.hw)
  612.     glutMotionFunc(motion);
  613.   glutDisplayFunc(display);
  614.   glutCreateMenu(menu);
  615.   glutAddMenuEntry("Switch object", 'o');
  616.   glutAddMenuEntry("Up tessellation", '+');
  617.   glutAddMenuEntry("Lower tessellation", '-');
  618.   glutAddMenuEntry("Quit", 27);
  619.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  620.   glutMainLoop();
  621.   return 0;             /* ANSI C requires main to return int. */
  622. }
  623. void
  624. build_cube(void)
  625. {
  626.   int i;
  627.   glNewList(LIST_BASE + OB_CUBE, GL_COMPILE);
  628.   for (i = 0; i < 6; i++) {
  629.     glBegin(GL_QUADS);
  630.     glNormal3fv(norm[i]);
  631.     glVertex3fv(cube[i][0]);
  632.     glVertex3fv(cube[i][1]);
  633.     glVertex3fv(cube[i][2]);
  634.     glVertex3fv(cube[i][3]);
  635.     glEnd();
  636.   }
  637.   glEndList();
  638. }
  639. void
  640. build_sphere(int tess)
  641. {
  642.   float r = 1.0, r1, r2, z1, z2;
  643.   float theta, phi;
  644.   int nlon = tess, nlat = tess;
  645.   int i, j;
  646.   glNewList(LIST_BASE + OB_SPHERE, GL_COMPILE);
  647.   glBegin(GL_TRIANGLE_FAN);
  648.   theta = M_PI * 1.0 / nlat;
  649.   r2 = r * sin(theta);
  650.   z2 = r * cos(theta);
  651.   glNormal3f(0.0, 0.0, 1.0);
  652.   glVertex3f(0.0, 0.0, r);
  653.   for (j = 0, phi = 0.0; j <= nlon; j++, phi = 2 * M_PI * j / nlon) {
  654.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  655.     glVertex3f(r2 * cos(phi), r2 * sin(phi), z2);  /* top */
  656.   }
  657.   glEnd();
  658.   for (i = 2; i < nlat; i++) {
  659.     theta = M_PI * i / nlat;
  660.     r1 = r * sin(M_PI * (i - 1) / nlat);
  661.     z1 = r * cos(M_PI * (i - 1) / nlat);
  662.     r2 = r * sin(theta);
  663.     z2 = r * cos(theta);
  664.     glBegin(GL_QUAD_STRIP);
  665.     for (j = 0, phi = 0; j <= nlat; j++, phi = 2 * M_PI * j / nlon) {
  666.       glNormal3f(r1 * cos(phi), r1 * sin(phi), z1);
  667.       glVertex3f(r1 * cos(phi), r1 * sin(phi), z1);
  668.       glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  669.       glVertex3f(r2 * cos(phi), r2 * sin(phi), z2);
  670.     }
  671.     glEnd();
  672.   }
  673.   glBegin(GL_TRIANGLE_FAN);
  674.   theta = M_PI * (nlat - 1) / nlat;
  675.   r2 = r * sin(theta);
  676.   z2 = r * cos(theta);
  677.   glNormal3f(0.0, 0.0, -1.0);
  678.   glVertex3f(0.0, 0.0, -r);
  679.   for (j = nlon, phi = 0.0; j >= 0; j--, phi = 2 * M_PI * j / nlon) {
  680.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  681.     glVertex3f(r2 * cos(phi), r2 * sin(phi), z2);  /* bottom */
  682.   }
  683.   glEnd();
  684.   glEndList();
  685. }
  686. /* Same as above routine except that we use homogeneous co-ordinates. Each
  687.    component (including w) is multiplied by z */
  688. void
  689. build_special_sphere(int tess)
  690. {
  691.   float r = 1.0, r1, r2, z1, z2;
  692.   float theta, phi;
  693.   int nlon = tess, nlat = tess;
  694.   int i, j;
  695.   glNewList(LIST_BASE + OB_HSPHERE, GL_COMPILE);
  696.   glBegin(GL_TRIANGLE_FAN);
  697.   theta = M_PI * 1.0 / nlat;
  698.   r2 = r * sin(theta);
  699.   z2 = r * cos(theta);
  700.   glNormal3f(0.0, 0.0, 1.0);
  701.   glVertex4f(0.0, 0.0, r * r, r);
  702.   for (j = 0, phi = 0.0; j <= nlon; j++, phi = 2 * M_PI * j / nlon) {
  703.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  704.     glVertex4f(r2 * cos(phi) * z2, r2 * sin(phi) * z2, z2 * z2, z2);  /* top */
  705.   }
  706.   glEnd();
  707.   for (i = 2; i < nlat; i++) {
  708.     theta = M_PI * i / nlat;
  709.     r1 = r * sin(M_PI * (i - 1) / nlat);
  710.     z1 = r * cos(M_PI * (i - 1) / nlat);
  711.     r2 = r * sin(theta);
  712.     z2 = r * cos(theta);
  713.     if (fabs(z1) < 0.01 || fabs(z2) < 0.01)
  714.       break;
  715.     glBegin(GL_QUAD_STRIP);
  716.     for (j = 0, phi = 0; j <= nlat; j++, phi = 2 * M_PI * j / nlon) {
  717.       glNormal3f(r1 * cos(phi), r1 * sin(phi), z1);
  718.       glVertex4f(r1 * cos(phi) * z1, r1 * sin(phi) * z1, z1 * z1, z1);
  719.       glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  720.       glVertex4f(r2 * cos(phi) * z2, r2 * sin(phi) * z2, z2 * z2, z2);
  721.     }
  722.     glEnd();
  723.   }
  724.   glBegin(GL_TRIANGLE_FAN);
  725.   theta = M_PI * (nlat - 1) / nlat;
  726.   r2 = r * sin(theta);
  727.   z2 = r * cos(theta);
  728.   glNormal3f(0.0, 0.0, -1.0);
  729.   glVertex4f(0.0, 0.0, -r * -r, -r);
  730.   for (j = nlon, phi = 0.0; j >= 0; j--, phi = 2 * M_PI * j / nlon) {
  731.     glNormal3f(r2 * cos(phi), r2 * sin(phi), z2);
  732.     glVertex4f(r2 * cos(phi) * z2, r2 * sin(phi) * z2, z2 * z2, z2);  /* bottom 
  733.                                                                        */
  734.   }
  735.   glEnd();
  736.   glEndList();
  737. }
  738. void
  739. build_square(void)
  740. {
  741.   glNewList(LIST_BASE + OB_SQUARE, GL_COMPILE);
  742.   glBegin(GL_POLYGON);
  743.   glNormal3f(0.0, 0.0, 1.0);
  744.   glVertex3fv(plane[0]);
  745.   glVertex3fv(plane[1]);
  746.   glVertex3fv(plane[2]);
  747.   glVertex3fv(plane[3]);
  748.   glEnd();
  749.   glEndList();
  750. }
  751. void
  752. build_cylinder(int tess)
  753. {
  754.   int slices = tess, stacks = tess;
  755.   int i, j;
  756.   GLfloat phi, z1, r, z2;
  757.   glNewList(LIST_BASE + OB_CYL, GL_COMPILE);
  758.   z1 = 2.0;
  759.   r = 1.0;
  760.   glBegin(GL_TRIANGLE_FAN);
  761.   glNormal3f(0.0, 0.0, 1.0);
  762.   glVertex3f(0.0, 0.0, z1);
  763.   for (i = 0; i <= slices; i++) {
  764.     phi = M_PI * 2.0 * i / slices;
  765.     glVertex3f(r * cos(phi), r * sin(phi), z1);
  766.   }
  767.   glEnd();
  768.   for (i = 0, z2 = 0.0, z1 = 2.0 / stacks; i < stacks; i++) {
  769.     glBegin(GL_QUAD_STRIP);
  770.     for (j = 0, phi = 0; j <= slices; j++, phi = M_PI * 2.0 * j / slices) {
  771.       glNormal3f(r * cos(phi), r * sin(phi), 0);
  772.       glVertex3f(r * cos(phi), r * sin(phi), z1);
  773.       glVertex3f(r * cos(phi), r * sin(phi), z2);
  774.     }
  775.     glEnd();
  776.     z1 += 2.0 / stacks;
  777.     z2 += 2.0 / stacks;
  778.   }
  779.   z2 = 0.0;
  780.   glBegin(GL_TRIANGLE_FAN);
  781.   glNormal3f(0.0, 0.0, -1.0);
  782.   glVertex3f(0.0, 0.0, z2);
  783.   for (i = slices; i >= 0; i--) {
  784.     phi = M_PI * 2.0 * i / slices;
  785.     glVertex3f(r * cos(phi), r * sin(phi), z2);
  786.   }
  787.   glEnd();
  788.   glEndList();
  789. }
  790. void
  791. build_torus(int tess)
  792. {
  793.   int i, j, k, l;
  794.   int numg = 1.2 * tess;
  795.   int nums = tess;
  796.   GLfloat x, y, z;
  797.   GLfloat theta, phi;
  798.   const GLfloat twopi = 2.0 * M_PI;
  799.   const GLfloat rg = 2.0, rs = 1.0;
  800.   glNewList(LIST_BASE + OB_TORUS, GL_COMPILE);
  801.   for (i = 0; i < numg; i++) {
  802.     glBegin(GL_QUAD_STRIP);
  803.     for (j = 0; j <= nums; j++) {
  804.       phi = twopi * j / nums;
  805.       for (k = 0; k <= 1; k++) {
  806.         l = (i + k) % numg;
  807.         theta = twopi * l / numg;
  808.         glNormal3f(rs * cos(phi) * cos(theta),
  809.           rs * cos(phi) * sin(theta),
  810.           rs * sin(phi));
  811.         x = (rg + rs * cos(phi)) * cos(theta);
  812.         y = (rg + rs * cos(phi)) * sin(theta);
  813.         z = rs * sin(phi);
  814.         glVertex3f(x, y, z);
  815.       }
  816.     }
  817.     glEnd();
  818.   }
  819.   glEndList();
  820. }
  821. void
  822. display(void)
  823. {
  824.   static int once = 0;
  825.   if (!once && opts.hw) {
  826.     texture_init();
  827.     once = 1;
  828.   }
  829.   if (do_spheremap || do_alloc) {
  830.     int w, h, comp;
  831.     if (do_alloc) {
  832.       texture_init();
  833.       do_alloc = 0;
  834.     } else
  835.       render_spheremap(&w, &h, &comp, 0);
  836.   } else {
  837.     glPushMatrix();
  838.     glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + TDRAW);
  839.     glEnable(GL_DEPTH_TEST);
  840.     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  841.     glRotatef(rotv[0], 1, 0, 0);
  842.     glRotatef(rotv[1], 0, 1, 0);
  843.     glRotatef(rotv[2], 0, 0, 1);
  844.     switch (opts.object) {
  845.     case OB_SQUARE:
  846.     case OB_CUBE:
  847.     case OB_SPHERE:
  848.       glCallList(LIST_BASE + opts.object);
  849.       break;
  850.     case OB_CYL:
  851.       glTranslatef(0.0, 0.0, -1.0);
  852.       glCallList(LIST_BASE + OB_CYL);
  853.       break;
  854.     case OB_TORUS:
  855.       glScalef(0.6, 0.6, 0.6);
  856.       glEnable(GL_NORMALIZE);
  857.       glCallList(LIST_BASE + OB_TORUS);
  858.       glDisable(GL_NORMALIZE);
  859.       break;
  860.     default:
  861.       printf("Eh?n");
  862.     }
  863.     glLineWidth(2.0);
  864.     glDisable(GL_DEPTH_TEST);
  865.     glDisable(GL_TEXTURE_2D);
  866.     glBegin(GL_LINES);
  867.     glColor3f(1.0, 0.0, 0.0);
  868.     glVertex3f(0.0, 0.0, 0.0);
  869.     glVertex3f(4.0, 0.0, 0.0);
  870.     glColor3f(0.0, 1.0, 0.0);
  871.     glVertex3f(0.0, 0.0, 0.0);
  872.     glVertex3f(0.0, 4.0, 0.0);
  873.     glColor3f(1.0, 1.0, 1.0);
  874.     glVertex3f(0.0, 0.0, 0.0);
  875.     glVertex3f(0.0, 0.0, 4.0);
  876.     glEnd();
  877.     glEnable(GL_TEXTURE_2D);
  878.     glEnable(GL_DEPTH_TEST);
  879.     glPopMatrix();
  880.   }
  881.   glutSwapBuffers();
  882. }
  883. void
  884. build_lists(void)
  885. {
  886.   build_square();
  887.   build_cube();
  888.   build_sphere(opts.tessellation);
  889.   build_cylinder(opts.tessellation);
  890.   build_torus(opts.tessellation);
  891.   build_special_sphere(opts.tessellation + 10);
  892. }
  893. void
  894. init(void)
  895. {
  896.   glEnable(GL_DEPTH_TEST);
  897.   glEnable(GL_CULL_FACE);
  898.   glClearColor(0.0, 0.0, 0.0, 1.0);
  899.   build_lists();
  900.   texture_init();
  901. }
  902. void
  903. err(void)
  904. {
  905.   printf("error=%#xn", glGetError());
  906. }
  907. /* Use projective textures to generate sphere-map */
  908. unsigned *
  909. render_spheremap(int *width, int *height,
  910.   int *components, int doalloc)
  911. {
  912.   int i, j, k;
  913.   GLfloat p[4];
  914.   static unsigned *spheremap = NULL;
  915.   static int texread_done = 0;
  916.   if (!opts.hw)         /* shouldn't come here */
  917.     return NULL;
  918.   for (i = 0; i < 6; i++) {
  919.     if (!texread_done) {
  920.       face[i].buf = read_texture(face[i].filename, &face[i].width,
  921.         &face[i].height, &face[i].components);
  922.       if (!face[i].buf) {
  923.         fprintf(stderr, "Error: cannot load image %sn", face[i].filename);
  924.         exit(1);
  925.       }
  926.       for (j = 0; j < face[i].height; j++)  /* texture border hack!! */
  927.         for (k = 0; k < face[i].width; k++)
  928.           if (j < 1 || k < 1 ||
  929.             j > face[i].height - 2 || k > face[i].width - 2) {
  930.             unsigned char *p = (unsigned char *) &face[i].buf[face[i].width * j + k];
  931.             p[3] = 0;   /* zero out alpha */
  932.           }
  933.     }
  934.     glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + i);
  935.     glEnable(GL_TEXTURE_2D);
  936.     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  937.     glTexImage2D(GL_TEXTURE_2D, 0, 4,
  938.       face[i].width, face[i].height, 0,
  939.       GL_RGBA, GL_UNSIGNED_BYTE, face[i].buf);
  940.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  941.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  942.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  943.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  944.     glTexGenf(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  945.     p[0] = 2.0;
  946.     p[1] = p[2] = p[3] = 0.0;  /* 2zx */
  947.     glTexGenfv(GL_S, GL_OBJECT_PLANE, p);
  948.     glTexGenf(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  949.     p[0] = 0.0;
  950.     p[1] = 2.0;
  951.     p[2] = p[3] = 0.0;  /* 2zy */
  952.     glTexGenfv(GL_T, GL_OBJECT_PLANE, p);
  953.     glTexGenf(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  954.     p[0] = p[1] = 0.0;
  955.     p[2] = 0.0;
  956.     p[3] = 2.0;         /* 2z */
  957.     glTexGenfv(GL_R, GL_OBJECT_PLANE, p);
  958.     glEnable(GL_TEXTURE_GEN_S);
  959.     glEnable(GL_TEXTURE_GEN_T);
  960.     glEnable(GL_TEXTURE_GEN_R);
  961.   }
  962.   texread_done = 1;
  963.   glMatrixMode(GL_PROJECTION);
  964.   glPushMatrix();
  965.   glMatrixMode(GL_MODELVIEW);
  966.   glPushMatrix();
  967.   glMatrixMode(GL_TEXTURE);
  968.   glPushMatrix();
  969.   glColor4f(1.0, 1.0, 1.0, 1.0);
  970.   /* Initialize sphere-map colors, and viewing transformations */
  971.   glMatrixMode(GL_PROJECTION);
  972.   glLoadIdentity();
  973.   glOrtho(-1, 1, -1, 1, 1.0, 100);
  974.   glMatrixMode(GL_MODELVIEW);
  975.   glLoadIdentity();
  976.   gluLookAt(0, 0, 6,
  977.     0, 0, 0,
  978.     0, 1, 0);
  979.   glEnable(GL_DEPTH_TEST);
  980.   glEnable(GL_CULL_FACE);
  981.   glEnable(GL_BLEND);
  982.   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  983.   glClearColor(0.0, 0.0, 0.0, 1.0);
  984.   glClearDepth(1.0);
  985.   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  986.   /* Look at the sphere from the chosen viewing direction and render the
  987.      sphere at origin.  */
  988.   for (i = 0; i < 6; i++) {  /* for all faces */
  989.     glBindTexture(GL_TEXTURE_2D, TOBJ_BASE + i);
  990.     glMatrixMode(GL_TEXTURE);
  991.     glLoadIdentity();
  992.     glScalef(0.5, 0.5, 1.0);
  993.     glTranslatef(1.0, 1.0, 0.0);
  994.     glFrustum(-1.01, 1.01, -1.01, 1.01, 1.0, 100.0);
  995.     if (face[i].angle2 != 0.) {
  996.       glRotatef(face[i].angle2,
  997.         face[i].axis2.x, face[i].axis2.y, face[i].axis2.z);
  998.     }
  999.     glRotatef(face[i].angle1,
  1000.       face[i].axis1.x, face[i].axis1.y, face[i].axis1.z);
  1001.     glRotatef(rots[0], 1, 0, 0);
  1002.     glRotatef(rots[1], 0, 1, 0);
  1003.     glRotatef(rots[2], 0, 0, 1);
  1004.     glTranslatef(0.0, 0.0, -1.00);
  1005.     glMatrixMode(GL_MODELVIEW);
  1006.     glClear(GL_DEPTH_BUFFER_BIT);
  1007.     glCallList(LIST_BASE + OB_HSPHERE);
  1008.   }
  1009.   glDisable(GL_BLEND);
  1010.   glMatrixMode(GL_PROJECTION);
  1011.   glPopMatrix();
  1012.   glMatrixMode(GL_MODELVIEW);
  1013.   glPopMatrix();
  1014.   glMatrixMode(GL_TEXTURE);
  1015.   glPopMatrix();
  1016.   glMatrixMode(GL_MODELVIEW);
  1017.   if (doalloc) {
  1018.     /* read in current image and return it to be used as the spheremap */
  1019.     unsigned *temp;
  1020.     temp = (unsigned *)
  1021.       malloc(currwidth * currheight * sizeof(unsigned));
  1022.     spheremap = (unsigned *)
  1023.       malloc(opts.size * opts.size * sizeof(unsigned));
  1024.     glReadBuffer(GL_BACK);
  1025.     glReadPixels(0, 0, currwidth, currheight, GL_RGBA,
  1026.       GL_UNSIGNED_BYTE, temp);
  1027.     gluScaleImage(GL_RGBA,
  1028.       currwidth, currheight, GL_UNSIGNED_BYTE, temp,
  1029.       opts.size, opts.size, GL_UNSIGNED_BYTE, spheremap);
  1030.     free(temp);
  1031.   }
  1032.   *width = *height = opts.size;
  1033.   *components = 4;
  1034.   return (unsigned *) spheremap;
  1035. }