topical media & game development

talk show tell print

basic-visual-05-spheresubdivision.c

? / basic-visual-05-spheresubdivision.c


  // ------------------------------------------------------------------------
  // This program is complementary material for the book:
  //
  // Frank Nielsen
  //
  // Visual Computing: Geometry, Graphics, and Vision
  //
  // ISBN: 1-58450-427-7
  //
  // Charles River Media, Inc.
  //
  //
  // All programs are available at www.charlesriver.com/visualcomputing/
  //
  // You may use this program for ACADEMIC and PERSONAL purposes ONLY. 
  //
  //
  // The use of this program in a commercial product requires EXPLICITLY
  // written permission from the author. The author is NOT responsible or 
  // liable for damage or loss that may be caused by the use of this program. 
  //
  // Copyright (c) 2005. Frank Nielsen. All rights reserved.
  // ------------------------------------------------------------------------
   
  // ------------------------------------------------------------------------
  // File: spheresubdivision.cpp
  // 
  // Description: subdivision refinement of the icosahedron for approximating
  // the unit sphere
  // ------------------------------------------------------------------------
  
  include <stdafx.h>
  
  include <stdlib.h>
  include <math.h>
  include <GL/glut.h>
  
  using namespace std;
  
  // coordinates of one of the icosahedron vertex
  define X 0.525731112119133696
  define Z 0.850650808352039932
  
  // icosahedron  vertices
  static GLfloat icosahedronvertex[12][3] = {
    {-X, 0.0, Z}, {X, 0.0, Z}, {-X, 0.0, -Z}, {X, 0.0, -Z},
    {0.0, Z, X}, {0.0, Z, -X}, {0.0, -Z, X}, {0.0, -Z, -X},
    {Z, X, 0.0}, {-Z, X, 0.0}, {Z, -X, 0.0}, {-Z, -X, 0.0}
  };
  
  // icosehedron faces
  static int icosahedrontriangle[20][3] = {
    {1,4,0}, {4,9,0}, {4,5,9}, {8,5,4}, {1,8,4},
    {1,10,8}, {10,3,8}, {8,3,5}, {3,2,5}, {3,7,2},
    {3,10,7}, {10,6,7}, {6,11,7}, {6,0,11}, {6,1,0},
    {10,1,6}, {11,0,9}, {2,11,9}, {5,2,9}, {11,2,7}
  };
  
  GLfloat angle=0.0;
  
  int subdiv = 0;        
  bool animation=true;
  
  // Vertices should belong to the unit sphere.
  // so we perform normalization
  void Normalize(GLfloat v[3])
  {
    GLfloat d = sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
    if (d!=0.0)
    {
            v[0]/=d; 
            v[1]/=d; 
            v[2]/=d;
    }
  }
  
  // Recursively subdivide the sphere
  void OneToFourTriangle(GLfloat v1[3], GLfloat v2[3], GLfloat v3[3], int depth)
  {
    GLfloat v12[3], v23[3], v31[3];
    int i;
  
    if (depth == 0) {
                  Normalize(v1);
                  Normalize(v2);
                  Normalize(v3);
  
                  glColor3f(0.5,0.5,0.5);
                  glBegin(GL_TRIANGLES);
                  glVertex3fv(v1);
                  glVertex3fv(v2);
                  glVertex3fv(v3);
                  glEnd();
  
                  glColor3f(0,0,0);
                  glLineWidth(3);
                  glBegin(GL_LINE_LOOP);
                  glVertex3fv(v1);
                  glVertex3fv(v2);
                  glVertex3fv(v3);
                  glEnd();
    }
    else
    {
    // midpoint
    for (i = 0; i < 3; i++) 
    {
      v12[i] = (v1[i]+v2[i])/2.0;
      v23[i] = (v2[i]+v3[i])/2.0;
      v31[i] = (v3[i]+v1[i])/2.0;
    }
    
  
    // lift midpoints on the sphere
    Normalize(v12);
    Normalize(v23);
    Normalize(v31);
  
    // subdivide new one-to-four triangles 
    OneToFourTriangle(v1, v12, v31, depth-1);
    OneToFourTriangle(v2, v23, v12, depth-1);
    OneToFourTriangle(v3, v31, v23, depth-1);
    OneToFourTriangle(v12, v23, v31, depth-1);
    }
  }
  
  void display(void)
  {
    int i;
  
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.5, 0.5, -1.5,
              0.0, 0.0, 0.0,  
                  0.0, 1.0, 0.0); 
  
   
  if (animation) angle+=0.3;
  if (angle>360) angle-=360.0;
  
  glPushMatrix();
  glRotatef(angle,1,0,1);
  
    // subdivide each face of the triangle
    for (i = 0; i < 20; i++)
    {
      OneToFourTriangle(&icosahedronvertex[icosahedrontriangle[i][0]][0],
                &icosahedronvertex[icosahedrontriangle[i][1]][0],
                    &icosahedronvertex[icosahedrontriangle[i][2]][0],
                    subdiv);
    }
  
    glPopMatrix();
  
    glFlush();
    glutSwapBuffers();
  }
  
  void reshape(int w, int h)
  {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.25, 1.25, -1.25 , 1.25 , -2.0, 2.0);
    glMatrixMode(GL_MODELVIEW);
    glutPostRedisplay();
  }
  
  void keyboard(unsigned char key, int x, int y)
  {
    if (key=='q') exit(0);
  
     if (key==' ') 
     {
          animation=!animation;
     }
  
    if (key=='+') subdiv++;
    if (key=='-') 
          {
            subdiv--;
            if (subdiv<0) subdiv = 0;
          }
  
    glutPostRedisplay();
  }
  
  void idle()
  {
  if (animation) subdiv=(int)(angle/70);
  
   glutPostRedisplay();
  }
  
  int main(int argc, char **argv)
  {
   
  cout<<"Visual Computing: Geometry, Graphics, and Vision (ISBN:1-58450-427-7)"<<endl;
  cout<<"Demo program\n\n"<<endl;
  
  cout<<"Recursive subdivision of the icosahedron for approximating the sphere."<<endl;
  cout<<"' ' SPACE: toggle on/off animation."<<endl;
  cout<<"+/- increase/decrease subdivision level."<<endl;
  
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); 
    glutInitWindowSize(1024,1024);
    glutCreateWindow("Icosahedron subdivision for approximating the sphere");
  
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    glutKeyboardFunc(keyboard);
    glutIdleFunc(idle);
  
    glClearColor(1.0, 1.0, 1.0, 0.0);        
    glEnable(GL_DEPTH_TEST);
  
    glutMainLoop();
    return(0);
  }
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.