icosahedron.c
contents ::
  Makefile
  icosahedron.c

/*****************************************************************************
 *                                                                           *
 *                                                                           *
 *     OPENGL                                                                *
 *     ~ Building an Icosahedron                                             *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           *
 *                                                                           * 
 *****************************************************************************/

#define X .525731112119133606
#define Z .850650808352039932

#include <stdlib.h>
#include <GL/glut.h>


void init(void){
  GLfloat mat_specular[] = { 1.0, 0.0, 0.0, 0.0 };
  GLfloat mat_shininess[] = { 39.0 };
  GLfloat light_position[] = { 1, 1, 1, 1 };
  GLfloat white_light[] = { 0.0, 1.0, 1.0, 1.0 };

  glClearColor(0.0, 0., 0.0, 0.0);
  //glShadeModel(GL_SMOOTH);
   glShadeModel(GL_FLAT);
  
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
  glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
  glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
  
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHT0);
   // glEnable(GL_DEPTH_TEST);
}

void drawtriangle(float *v1, float *v2, float *v3){
  glBegin(GL_TRIANGLES);
    glNormal3fv(v1);
    glVertex3fv(v1);
    glNormal3fv(v2);
    glVertex3fv(v2);
    glNormal3fv(v3);
    glVertex3fv(v3);
    glFrontFace(GL_CW);
  glEnd();
}

void normalize(float v[3]){
  GLfloat d = sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]);
  if(d == 0.0){
    error("zero length vector");
    return;
  }
  v[0] /= d;
  v[1] /= d;
  v[2] /= d;
}

void subdivide(float *v1, float *v2, float *v3, long depth){
  GLfloat v12[3], v23[3], v31[3];
  GLint i;

  if(depth <= 0){
    drawtriangle(v1, v2, v3);
    return;
  }

  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;
  }
  
  normalize(v12);
  normalize(v23);
  normalize(v31);

  subdivide(v1, v12, v31, depth-1);
  subdivide(v2, v23, v12, depth-1);
  subdivide(v3, v31, v23, depth-1);
  subdivide(v12, v23, v31, depth-1);
}

void normcrossprod(float v1[3], float v2[3], float out[3]){
  out[0] = v1[1]*v2[2] - v1[2]*v2[1];
  out[1] = v1[2]*v2[0] - v1[0]*v2[2];
  out[2] = v1[0]*v2[1] - v1[1]*v2[0];
  normalize(out);
}

void display(void){
  static GLfloat vdata[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}  
  };
  
  static GLuint tindices[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},   
  };
  
  int i;
  int j;
  GLfloat d1[3], d2[3], norm[3];

  glClear(GL_COLOR_BUFFER_BIT);
  glPushMatrix();
  glColor3f(1.0, 1.0, 1.0);
  /* viewing transformation */
  gluLookAt(1,0,1,0,0,0,0,1,0);
  glBegin(GL_TRIANGLES);
  i=0;
  for(i=0; i</*20 */20/* seems to cover most of circle?*/; i++){
/* some random code from page 88 
   to replace color info goes here */
    for(j=0; j<3; j++){
      d1[j] = vdata[tindices[i][0]][j] - vdata[tindices[i][1]][j];
      d2[j] = vdata[tindices[i][1]][j] - vdata[tindices[i][2]][j];
    }
    normcrossprod(d1, d2, norm);
    glNormal3fv(norm);
    
    subdivide(&vdata[tindices[i][0]][0],
               &vdata[tindices[i][1]][0],
               &vdata[tindices[i][2]][0],
               2
               );
  }
  glEnd();
  glPopMatrix();
  glutSwapBuffers();
}


/*
 * Request double buffer display mode.
 * Register mouse input callback functions
 */
int main(int argc, char **argv){
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
  glutInitWindowSize(350, 350);
  glutInitWindowPosition(100, 100);
  glutCreateWindow("by James Little");
  init();
  glutDisplayFunc(display);

  // glutReshapeFunc(reshape);
  // glutMouseFunc(mouse);
  printf("Have a good day old chap!\n");
  glutMainLoop();
  return 0;
}

James Little