title: OpenGL color issue
body: <p>I'm trying to find out a color issue.
  I have created a landscape, loaded from a heightmap, and an animation, loaded from a MD2 model. The MD2 model will get it's color from a bitmap texture. The color of the landscape has to be set by glColor3f.</p>
  
  <p>Now the problem is in my my Draw method:</p>
  
  <pre><code>void drawScene() {
  glClearColor(1, 1, 1, 0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  
  gluLookAt(cameraPositionX, cameraPositionY, cameraPositionZ, cameraAimX, cameraAimY, cameraAimZ, 0, 1, 0);
  
  GLfloat ambientColor[] = {0.4f, 0.4f, 0.4f, 1.0f};
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
  
  GLfloat lightColor0[] = {0.6f, 0.6f, 0.6f, 1.0f};
  GLfloat lightPos0[] = {-0.5f, 0.8f, 0.1f, 0.0f};
  glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
  glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
  
  if (_model != NULL) {
      glPushMatrix();
      glTranslatef(modelPositionX, modelPositionY, modelPositionZ);
      glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
      glRotatef(110.0f, 1.0f, 0.0f, 0.0f);
      glScalef(0.2f, 0.2f, 0.2f);
      _model-&gt;draw();
      glPopMatrix();
  }
  
  glTranslatef(-(float)(_terrain-&gt;width() - 1) / 2,
               0.0f,
               -(float)(_terrain-&gt;length() - 1) / 2);
  
  glColor3f(0.0f, 1.0f, 0.0f);
  for(int z = 0; z &lt; _terrain-&gt;length() - 1; z++) {
      glBegin(GL_TRIANGLE_STRIP);
      for(int x = 0; x &lt; _terrain-&gt;width(); x++) {
          Vec3f normal = _terrain-&gt;getNormal(x, z);
          glNormal3f(normal[0], normal[1], normal[2]);
          glVertex3f(x, _terrain-&gt;getHeight(x, z), z);
          normal = _terrain-&gt;getNormal(x, z + 1);
          glNormal3f(normal[0], normal[1], normal[2]);
          glVertex3f(x, _terrain-&gt;getHeight(x, z + 1), z + 1);
      }
      glEnd();
  }
  
  glutSwapBuffers();
  </code></pre>
  
  <p>}</p>
  
  <p>When I comment out the glColor3f(0.0f, 1.0f, 0.0f); statement, the landscape will get the same color as the animation gets from the bitmap texture. But when I include the glColor3f(0.0f, 1.0f, 0.0f); statement, the animation will get the  same color as the landscape does. I would like to have the animation and the landscape to have different colors.</p>
  
  <p>Here's the complete main.cpp class and the md2model.cpp class.</p>
  
  <p>Main.cpp</p>
  
  <pre><code>#include &lt;iostream&gt;
  #include &lt;stdlib.h&gt;
  
  #ifdef __APPLE__
  #include &lt;OpenGL/OpenGL.h&gt;
  #include &lt;GLUT/glut.h&gt;
  #else
  #include &lt;GL/glut.h&gt;
  #endif
  
  #include "imageloader.h"
  #include "imageloader.cpp"
  #include "vec3f.h"
  #include "vec3f.cpp"
  #include "md2model.h"
  #include "md2model.cpp"
  
  using namespace std;
  
  class Terrain {
  private:
      int w;
      int l;
      float** hs;
      Vec3f** normals;
      bool computedNormals;
  public:
      Terrain(int w2, int l2) {
          w = w2;
          l = l2;
  
          hs = new float*[l];
          for(int i = 0; i &lt; l; i++) {
              hs[i] = new float[w];
          }
  
          normals = new Vec3f*[l];
          for(int i = 0; i &lt; l; i++) {
              normals[i] = new Vec3f[w];
          }
  
          computedNormals = false;
      }
  
      ~Terrain() {
          for(int i = 0; i &lt; l; i++) {
              delete[] hs[i];
          }
          delete[] hs;
  
          for(int i = 0; i &lt; l; i++) {
              delete[] normals[i];
          }
          delete[] normals;
      }
  
      int width() {
          return w;
      }
  
      int length() {
          return l;
      }
  
      void setHeight(int x, int z, float y) {
          hs[z][x] = y;
          computedNormals = false;
      }
  
      float getHeight(int x, int z) {
          return hs[z][x];
      }
  
      void computeNormals() {
          if (computedNormals) {
              return;
          }
  
          Vec3f** normals2 = new Vec3f*[l];
          for(int i = 0; i &lt; l; i++) {
              normals2[i] = new Vec3f[w];
          }
  
          for(int z = 0; z &lt; l; z++) {
              for(int x = 0; x &lt; w; x++) {
                  Vec3f sum(0.0f, 0.0f, 0.0f);
  
                  Vec3f out;
                  if (z &gt; 0) {
                      out = Vec3f(0.0f, hs[z - 1][x] - hs[z][x], -1.0f);
                  }
                  Vec3f in;
                  if (z &lt; l - 1) {
                      in = Vec3f(0.0f, hs[z + 1][x] - hs[z][x], 1.0f);
                  }
                  Vec3f left;
                  if (x &gt; 0) {
                      left = Vec3f(-1.0f, hs[z][x - 1] - hs[z][x], 0.0f);
                  }
                  Vec3f right;
                  if (x &lt; w - 1) {
                      right = Vec3f(1.0f, hs[z][x + 1] - hs[z][x], 0.0f);
                  }
  
                  if (x &gt; 0 &amp;&amp; z &gt; 0) {
                      sum += out.cross(left).normalize();
                  }
                  if (x &gt; 0 &amp;&amp; z &lt; l - 1) {
                      sum += left.cross(in).normalize();
                  }
                  if (x &lt; w - 1 &amp;&amp; z &lt; l - 1) {
                      sum += in.cross(right).normalize();
                  }
                  if (x &lt; w - 1 &amp;&amp; z &gt; 0) {
                      sum += right.cross(out).normalize();
                  }
  
                  normals2[z][x] = sum;
              }
          }
  
          const float FALLOUT_RATIO = 0.5f;
          for(int z = 0; z &lt; l; z++) {
              for(int x = 0; x &lt; w; x++) {
                  Vec3f sum = normals2[z][x];
  
                  if (x &gt; 0) {
                      sum += normals2[z][x - 1] * FALLOUT_RATIO;
                  }
                  if (x &lt; w - 1) {
                      sum += normals2[z][x + 1] * FALLOUT_RATIO;
                  }
                  if (z &gt; 0) {
                      sum += normals2[z - 1][x] * FALLOUT_RATIO;
                  }
                  if (z &lt; l - 1) {
                      sum += normals2[z + 1][x] * FALLOUT_RATIO;
                  }
  
                  if (sum.magnitude() == 0) {
                      sum = Vec3f(0.0f, 1.0f, 0.0f);
                  }
                  normals[z][x] = sum;
              }
          }
  
          for(int i = 0; i &lt; l; i++) {
              delete[] normals2[i];
          }
          delete[] normals2;
  
          computedNormals = true;
      }
  
      Vec3f getNormal(int x, int z) {
          if (!computedNormals) {
              computeNormals();
          }
          return normals[z][x];
      }
  };
  
  Terrain* loadTerrain(const char* filename, float height) {
  Image* image = loadBMP(filename);
  Terrain* t = new Terrain(image-&gt;width, image-&gt;height);
  for(int y = 0; y &lt; image-&gt;height; y++) {
      for(int x = 0; x &lt; image-&gt;width; x++) {
          unsigned char color =
              (unsigned char)image-&gt;pixels[3 * (y * image-&gt;width + x)];
          float h = height * ((color / 255.0f) - 0.5f);
          t-&gt;setHeight(x, y, h);
      }
  }
  
  delete image;
  t-&gt;computeNormals();
  return t;
  }
  
  float cameraPositionX = 2;
  float cameraPositionY = 2;
  float cameraPositionZ = 1;
  
  float cameraAimX = 0;
  float cameraAimY = 0;
  float cameraAimZ = 0;
  
  float modelPositionX = 0;
  float modelPositionY = 1;
  float modelPositionZ = 0;
  
  Terrain* _terrain;
  
  MD2Model* _model;
  
  void cleanup() {
  delete _terrain;
  delete _model;
  }
  
  void handleKeypress(unsigned char key, int x, int y) {
  switch (key) {
      case 27:
          cleanup();
          exit(0);
  }
  }
  
  void handleSpecialKeypress(int key, int x, int y) {
  switch (key) {
      case GLUT_KEY_UP:
              cameraPositionX -= 0.5;
      cameraAimX -= 0.5;
      modelPositionX -= 0.5;
  
      if (_model != NULL) {
              _model-&gt;advance(0.025f);
          }
  
      glutPostRedisplay();
              break;
      case GLUT_KEY_DOWN:
              cameraPositionX += 0.5;
      cameraAimX += 0.5;
      modelPositionX += 0.5;
  
      if (_model != NULL) {
              _model-&gt;advance(0.025f);
          }
  
      glutPostRedisplay();
              break;
  case GLUT_KEY_LEFT:
              //Do something
              break;
      case GLUT_KEY_RIGHT:
              //Do something
              break;
    }
  }
  
  void initRendering() {
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_COLOR_MATERIAL);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_NORMALIZE);
  glShadeModel(GL_SMOOTH);
  
  _model = MD2Model::load("tallguy.md2");
  if (_model != NULL) {
      _model-&gt;setAnimation("run");
  }
  }
  
  void handleResize(int w, int h) {
  glViewport(0, 0, w, h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(105.0, (double)w / (double)h, 1.0, 500.0);
  }
  
  void drawScene() {
  glClearColor(1, 1, 1, 0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  
  gluLookAt(cameraPositionX, cameraPositionY, cameraPositionZ, cameraAimX, cameraAimY, cameraAimZ, 0, 1, 0);
  
  GLfloat ambientColor[] = {0.4f, 0.4f, 0.4f, 1.0f};
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientColor);
  
  GLfloat lightColor0[] = {0.6f, 0.6f, 0.6f, 1.0f};
  GLfloat lightPos0[] = {-0.5f, 0.8f, 0.1f, 0.0f};
  glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor0);
  glLightfv(GL_LIGHT0, GL_POSITION, lightPos0);
  
  if (_model != NULL) {
      glPushMatrix();
      glTranslatef(modelPositionX, modelPositionY, modelPositionZ);
      glRotatef(-90.0f, 0.0f, 0.0f, 1.0f);
      glRotatef(110.0f, 1.0f, 0.0f, 0.0f);
      glScalef(0.2f, 0.2f, 0.2f);
      _model-&gt;draw();
      glPopMatrix();
  }
  
  glTranslatef(-(float)(_terrain-&gt;width() - 1) / 2,
               0.0f,
               -(float)(_terrain-&gt;length() - 1) / 2);
  
  //glColor3f(0.0f, 1.0f, 0.0f);
  for(int z = 0; z &lt; _terrain-&gt;length() - 1; z++) {
      glBegin(GL_TRIANGLE_STRIP);
      for(int x = 0; x &lt; _terrain-&gt;width(); x++) {
          Vec3f normal = _terrain-&gt;getNormal(x, z);
          glNormal3f(normal[0], normal[1], normal[2]);
          glVertex3f(x, _terrain-&gt;getHeight(x, z), z);
          normal = _terrain-&gt;getNormal(x, z + 1);
          glNormal3f(normal[0], normal[1], normal[2]);
          glVertex3f(x, _terrain-&gt;getHeight(x, z + 1), z + 1);
      }
      glEnd();
  }
  
  glutSwapBuffers();
  }
  
  int main(int argc, char** argv) {
  glutInit(&amp;argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(400, 400);
  
  glutCreateWindow("Terrain");
  initRendering();
  
  _terrain = loadTerrain("heightmap.bmp", 50);
  
  glutDisplayFunc(drawScene);
  glutKeyboardFunc(handleKeypress);
  glutSpecialFunc(handleSpecialKeypress);
  glutReshapeFunc(handleResize);
  
  glutMainLoop();
  return 0;
  }
  </code></pre>
  
  <p>M2DModel.cpp</p>
  
  <pre><code>#include &lt;fstream&gt;
  #include "imageloader.h"
  #include "md2model.h"
  #include "string.h"
  
  using namespace std;
  
  namespace {
  //Normals used in the MD2 file format
  float NORMALS[486] =
      {-0.525731f,  0.000000f,  0.850651f,
       -0.442863f,  0.238856f,  0.864188f,
       -0.295242f,  0.000000f,  0.955423f,
       -0.309017f,  0.500000f,  0.809017f,
       -0.162460f,  0.262866f,  0.951056f,
        0.000000f,  0.000000f,  1.000000f,
        0.000000f,  0.850651f,  0.525731f,
       -0.147621f,  0.716567f,  0.681718f,
        0.147621f,  0.716567f,  0.681718f,
        0.000000f,  0.525731f,  0.850651f,
        0.309017f,  0.500000f,  0.809017f,
        0.525731f,  0.000000f,  0.850651f,
        0.295242f,  0.000000f,  0.955423f,
        0.442863f,  0.238856f,  0.864188f,
        0.162460f,  0.262866f,  0.951056f,
       -0.681718f,  0.147621f,  0.716567f,
       -0.809017f,  0.309017f,  0.500000f,
       -0.587785f,  0.425325f,  0.688191f,
       -0.850651f,  0.525731f,  0.000000f,
       -0.864188f,  0.442863f,  0.238856f,
       -0.716567f,  0.681718f,  0.147621f,
       -0.688191f,  0.587785f,  0.425325f,
       -0.500000f,  0.809017f,  0.309017f,
       -0.238856f,  0.864188f,  0.442863f,
       -0.425325f,  0.688191f,  0.587785f,
       -0.716567f,  0.681718f, -0.147621f,
       -0.500000f,  0.809017f, -0.309017f,
       -0.525731f,  0.850651f,  0.000000f,
        0.000000f,  0.850651f, -0.525731f,
       -0.238856f,  0.864188f, -0.442863f,
        0.000000f,  0.955423f, -0.295242f,
       -0.262866f,  0.951056f, -0.162460f,
        0.000000f,  1.000000f,  0.000000f,
        0.000000f,  0.955423f,  0.295242f,
       -0.262866f,  0.951056f,  0.162460f,
        0.238856f,  0.864188f,  0.442863f,
        0.262866f,  0.951056f,  0.162460f,
        0.500000f,  0.809017f,  0.309017f,
        0.238856f,  0.864188f, -0.442863f,
        0.262866f,  0.951056f, -0.162460f,
        0.500000f,  0.809017f, -0.309017f,
        0.850651f,  0.525731f,  0.000000f,
        0.716567f,  0.681718f,  0.147621f,
        0.716567f,  0.681718f, -0.147621f,
        0.525731f,  0.850651f,  0.000000f,
        0.425325f,  0.688191f,  0.587785f,
        0.864188f,  0.442863f,  0.238856f,
        0.688191f,  0.587785f,  0.425325f,
        0.809017f,  0.309017f,  0.500000f,
        0.681718f,  0.147621f,  0.716567f,
        0.587785f,  0.425325f,  0.688191f,
        0.955423f,  0.295242f,  0.000000f,
        1.000000f,  0.000000f,  0.000000f,
        0.951056f,  0.162460f,  0.262866f,
        0.850651f, -0.525731f,  0.000000f,
        0.955423f, -0.295242f,  0.000000f,
        0.864188f, -0.442863f,  0.238856f,
        0.951056f, -0.162460f,  0.262866f,
        0.809017f, -0.309017f,  0.500000f,
        0.681718f, -0.147621f,  0.716567f,
        0.850651f,  0.000000f,  0.525731f,
        0.864188f,  0.442863f, -0.238856f,
        0.809017f,  0.309017f, -0.500000f,
        0.951056f,  0.162460f, -0.262866f,
        0.525731f,  0.000000f, -0.850651f,
        0.681718f,  0.147621f, -0.716567f,
        0.681718f, -0.147621f, -0.716567f,
        0.850651f,  0.000000f, -0.525731f,
        0.809017f, -0.309017f, -0.500000f,
        0.864188f, -0.442863f, -0.238856f,
        0.951056f, -0.162460f, -0.262866f,
        0.147621f,  0.716567f, -0.681718f,
        0.309017f,  0.500000f, -0.809017f,
        0.425325f,  0.688191f, -0.587785f,
        0.442863f,  0.238856f, -0.864188f,
        0.587785f,  0.425325f, -0.688191f,
        0.688191f,  0.587785f, -0.425325f,
       -0.147621f,  0.716567f, -0.681718f,
       -0.309017f,  0.500000f, -0.809017f,
        0.000000f,  0.525731f, -0.850651f,
       -0.525731f,  0.000000f, -0.850651f,
       -0.442863f,  0.238856f, -0.864188f,
       -0.295242f,  0.000000f, -0.955423f,
       -0.162460f,  0.262866f, -0.951056f,
        0.000000f,  0.000000f, -1.000000f,
        0.295242f,  0.000000f, -0.955423f,
        0.162460f,  0.262866f, -0.951056f,
       -0.442863f, -0.238856f, -0.864188f,
       -0.309017f, -0.500000f, -0.809017f,
       -0.162460f, -0.262866f, -0.951056f,
        0.000000f, -0.850651f, -0.525731f,
       -0.147621f, -0.716567f, -0.681718f,
        0.147621f, -0.716567f, -0.681718f,
        0.000000f, -0.525731f, -0.850651f,
        0.309017f, -0.500000f, -0.809017f,
        0.442863f, -0.238856f, -0.864188f,
        0.162460f, -0.262866f, -0.951056f,
        0.238856f, -0.864188f, -0.442863f,
        0.500000f, -0.809017f, -0.309017f,
        0.425325f, -0.688191f, -0.587785f,
        0.716567f, -0.681718f, -0.147621f,
        0.688191f, -0.587785f, -0.425325f,
        0.587785f, -0.425325f, -0.688191f,
        0.000000f, -0.955423f, -0.295242f,
        0.000000f, -1.000000f,  0.000000f,
        0.262866f, -0.951056f, -0.162460f,
        0.000000f, -0.850651f,  0.525731f,
        0.000000f, -0.955423f,  0.295242f,
        0.238856f, -0.864188f,  0.442863f,
        0.262866f, -0.951056f,  0.162460f,
        0.500000f, -0.809017f,  0.309017f,
        0.716567f, -0.681718f,  0.147621f,
        0.525731f, -0.850651f,  0.000000f,
       -0.238856f, -0.864188f, -0.442863f,
       -0.500000f, -0.809017f, -0.309017f,
       -0.262866f, -0.951056f, -0.162460f,
       -0.850651f, -0.525731f,  0.000000f,
       -0.716567f, -0.681718f, -0.147621f,
       -0.716567f, -0.681718f,  0.147621f,
       -0.525731f, -0.850651f,  0.000000f,
       -0.500000f, -0.809017f,  0.309017f,
       -0.238856f, -0.864188f,  0.442863f,
       -0.262866f, -0.951056f,  0.162460f,
       -0.864188f, -0.442863f,  0.238856f,
       -0.809017f, -0.309017f,  0.500000f,
       -0.688191f, -0.587785f,  0.425325f,
       -0.681718f, -0.147621f,  0.716567f,
       -0.442863f, -0.238856f,  0.864188f,
       -0.587785f, -0.425325f,  0.688191f,
       -0.309017f, -0.500000f,  0.809017f,
       -0.147621f, -0.716567f,  0.681718f,
       -0.425325f, -0.688191f,  0.587785f,
       -0.162460f, -0.262866f,  0.951056f,
        0.442863f, -0.238856f,  0.864188f,
        0.162460f, -0.262866f,  0.951056f,
        0.309017f, -0.500000f,  0.809017f,
        0.147621f, -0.716567f,  0.681718f,
        0.000000f, -0.525731f,  0.850651f,
        0.425325f, -0.688191f,  0.587785f,
        0.587785f, -0.425325f,  0.688191f,
        0.688191f, -0.587785f,  0.425325f,
       -0.955423f,  0.295242f,  0.000000f,
       -0.951056f,  0.162460f,  0.262866f,
       -1.000000f,  0.000000f,  0.000000f,
       -0.850651f,  0.000000f,  0.525731f,
       -0.955423f, -0.295242f,  0.000000f,
       -0.951056f, -0.162460f,  0.262866f,
       -0.864188f,  0.442863f, -0.238856f,
       -0.951056f,  0.162460f, -0.262866f,
       -0.809017f,  0.309017f, -0.500000f,
       -0.864188f, -0.442863f, -0.238856f,
       -0.951056f, -0.162460f, -0.262866f,
       -0.809017f, -0.309017f, -0.500000f,
       -0.681718f,  0.147621f, -0.716567f,
       -0.681718f, -0.147621f, -0.716567f,
       -0.850651f,  0.000000f, -0.525731f,
       -0.688191f,  0.587785f, -0.425325f,
       -0.587785f,  0.425325f, -0.688191f,
       -0.425325f,  0.688191f, -0.587785f,
       -0.425325f, -0.688191f, -0.587785f,
       -0.587785f, -0.425325f, -0.688191f,
       -0.688191f, -0.587785f, -0.425325f};
  
  //Returns whether the system is little-endian
  bool littleEndian() {
      //The short value 1 has bytes (1, 0) in little-endian and (0, 1) in
      //big-endian
      short s = 1;
      return (((char*)&amp;s)[0]) == 1;
  }
  
  //Converts a two-character array to an unsigned short, using little-endian
  //form
  unsigned short toUShort(const char* bytes) {
      return (unsigned short)(((unsigned char)bytes[1] &lt;&lt; 8) |
                              (unsigned char)bytes[0]);
  }
  
  //Converts a four-character array to a float, using little-endian form
  float toFloat(const char* bytes) {
      float f;
      if (littleEndian()) {
          ((char*)&amp;f)[0] = bytes[0];
          ((char*)&amp;f)[1] = bytes[1];
          ((char*)&amp;f)[2] = bytes[2];
          ((char*)&amp;f)[3] = bytes[3];
      }
      else {
          ((char*)&amp;f)[0] = bytes[3];
          ((char*)&amp;f)[1] = bytes[2];
          ((char*)&amp;f)[2] = bytes[1];
          ((char*)&amp;f)[3] = bytes[0];
      }
      return f;
  }
  
  //Reads the next two bytes as an unsigned short, using little-endian form
  unsigned short readUShort(ifstream &amp;input) {
      char buffer[2];
      input.read(buffer, 2);
      return toUShort(buffer);
  }
  
  //Reads the next four bytes as a float, using little-endian form
  float readFloat(ifstream &amp;input) {
      char buffer[4];
      input.read(buffer, 4);
      return toFloat(buffer);
  }
  
  //Calls readFloat three times and returns the results as a Vec3f object
  Vec3f readVec3f(ifstream &amp;input) {
      float x = readFloat(input);
      float y = readFloat(input);
      float z = readFloat(input);
      return Vec3f(x, y, z);
  }
  
  //Makes the image into a texture, and returns the id of the texture
  GLuint loadTexture(Image *image) {
      GLuint textureId;
      glGenTextures(1, &amp;textureId);
      glBindTexture(GL_TEXTURE_2D, textureId);
      glTexImage2D(GL_TEXTURE_2D,
                   0,
                   GL_RGB,
                   image-&gt;width, image-&gt;height,
                   0,
                   GL_RGB,
                   GL_UNSIGNED_BYTE,
                   image-&gt;pixels);
      return textureId;
  }
  }
  
  MD2Model::~MD2Model() {
  if (frames != NULL) {
      for(int i = 0; i &lt; numFrames; i++) {
          delete[] frames[i].vertices;
      }
      delete[] frames;
  }
  
  if (texCoords != NULL) {
      delete[] texCoords;
  }
  if (triangles != NULL) {
      delete[] triangles;
  }
  }
  
  MD2Model::MD2Model() {
  frames = NULL;
  texCoords = NULL;
  triangles = NULL;
  time = 0;
  }
  
  
  //Loads the MD2 model
  
  MD2Model* MD2Model::load(const char* filename) {
  ifstream input;
  input.open(filename, istream::binary);
  
  char buffer[64];
  input.read(buffer, 4); //Should be "IPD2", if this is an MD2 file
  if (buffer[0] != 'I' || buffer[1] != 'D' ||
      buffer[2] != 'P' || buffer[3] != '2') {
      return NULL;
  }
  if (readInt(input) != 8) { //The version number
      return NULL;
  }
  
  int textureWidth = readInt(input);   //The width of the textures
  int textureHeight = readInt(input);  //The height of the textures
  readInt(input);                      //The number of bytes per frame
  int numTextures = readInt(input);    //The number of textures
  if (numTextures != 1) {
      return NULL;
  }
  int numVertices = readInt(input);    //The number of vertices
  int numTexCoords = readInt(input);   //The number of texture coordinates
  int numTriangles = readInt(input);   //The number of triangles
  readInt(input);                      //The number of OpenGL commands
  int numFrames = readInt(input);      //The number of frames
  
  //Offsets (number of bytes after the beginning of the file to the beginning
  //of where certain data appear)
  int textureOffset = readInt(input);  //The offset to the textures
  int texCoordOffset = readInt(input); //The offset to the texture coordinates
  int triangleOffset = readInt(input); //The offset to the triangles
  int frameOffset = readInt(input);    //The offset to the frames
  readInt(input);                      //The offset to the OpenGL commands
  readInt(input);                      //The offset to the end of the file
  
  //Load the texture
  input.seekg(textureOffset, ios_base::beg);
  input.read(buffer, 64);
  if (strlen(buffer) &lt; 5 ||
      strcmp(buffer + strlen(buffer) - 4, ".bmp") != 0) {
      return NULL;
  }
  Image* image = loadBMP(buffer);
  GLuint textureId = loadTexture(image);
  delete image;
  MD2Model* model = new MD2Model();
  model-&gt;textureId = textureId;
  
  //Load the texture coordinates
  input.seekg(texCoordOffset, ios_base::beg);
  model-&gt;texCoords = new MD2TexCoord[numTexCoords];
  for(int i = 0; i &lt; numTexCoords; i++) {
      MD2TexCoord* texCoord = model-&gt;texCoords + i;
      texCoord-&gt;texCoordX = (float)readShort(input) / textureWidth;
      texCoord-&gt;texCoordY = 1 - (float)readShort(input) / textureHeight;
  }
  
  //Load the triangles
  input.seekg(triangleOffset, ios_base::beg);
  model-&gt;triangles = new MD2Triangle[numTriangles];
  model-&gt;numTriangles = numTriangles;
  for(int i = 0; i &lt; numTriangles; i++) {
      MD2Triangle* triangle = model-&gt;triangles + i;
      for(int j = 0; j &lt; 3; j++) {
          triangle-&gt;vertices[j] = readUShort(input);
      }
      for(int j = 0; j &lt; 3; j++) {
          triangle-&gt;texCoords[j] = readUShort(input);
      }
  }
  
  //Load the frames
  input.seekg(frameOffset, ios_base::beg);
  model-&gt;frames = new MD2Frame[numFrames];
  model-&gt;numFrames = numFrames;
  for(int i = 0; i &lt; numFrames; i++) {
      MD2Frame* frame = model-&gt;frames + i;
      frame-&gt;vertices = new MD2Vertex[numVertices];
      Vec3f scale = readVec3f(input);
      Vec3f translation = readVec3f(input);
      input.read(frame-&gt;name, 16);
  
      for(int j = 0; j &lt; numVertices; j++) {
          MD2Vertex* vertex = frame-&gt;vertices + j;
          input.read(buffer, 3);
          Vec3f v((unsigned char)buffer[0],
                  (unsigned char)buffer[1],
                  (unsigned char)buffer[2]);
          vertex-&gt;pos = translation + Vec3f(scale[0] * v[0],
                                            scale[1] * v[1],
                                            scale[2] * v[2]);
          input.read(buffer, 1);
          int normalIndex = (int)((unsigned char)buffer[0]);
          vertex-&gt;normal = Vec3f(NORMALS[3 * normalIndex],
                                 NORMALS[3 * normalIndex + 1],
                                 NORMALS[3 * normalIndex + 2]);
      }
  }
  
  model-&gt;startFrame = 0;
  model-&gt;endFrame = numFrames - 1;
  return model;
  
  }
  
  
  void MD2Model::setAnimation(const char* name) {
  /* The names of frames normally begin with the name of the animation in
   * which they are, e.g. "run", and are followed by a non-alphabetical
   * character.  Normally, they indicate their frame number in the animation,
   * e.g. "run_1", "run_2", etc.
   */
  bool found = false;
  for(int i = 0; i &lt; numFrames; i++) {
      MD2Frame* frame = frames + i;
      if (strlen(frame-&gt;name) &gt; strlen(name) &amp;&amp;
          strncmp(frame-&gt;name, name, strlen(name)) == 0 &amp;&amp;
          !isalpha(frame-&gt;name[strlen(name)])) {
          if (!found) {
              found = true;
              startFrame = i;
          }
          else {
              endFrame = i;
          }
      }
      else if (found) {
          break;
      }
  }
  
  }
  
  
  void MD2Model::advance(float dt) {
  if (dt &lt; 0) {
      return;
  }
  
  time += dt;
  if (time &lt; 1000000000) {
      time -= (int)time;
  }
  else {
      time = 0;
  }
  }
  
  void MD2Model::draw() {
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureId);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  
  //Figure out the two frames between which we are interpolating
  int frameIndex1 = (int)(time * (endFrame - startFrame + 1)) + startFrame;
  if (frameIndex1 &gt; endFrame) {
      frameIndex1 = startFrame;
  }
  
  int frameIndex2;
  if (frameIndex1 &lt; endFrame) {
      frameIndex2 = frameIndex1 + 1;
  }
  else {
      frameIndex2 = startFrame;
  }
  
  MD2Frame* frame1 = frames + frameIndex1;
  MD2Frame* frame2 = frames + frameIndex2;
  
  //Figure out the fraction that we are between the two frames
  float frac =
      (time - (float)(frameIndex1 - startFrame) /
       (float)(endFrame - startFrame + 1)) * (endFrame - startFrame + 1);
  
  //Draw the model as an interpolation between the two frames
  glBegin(GL_TRIANGLES);
  for(int i = 0; i &lt; numTriangles; i++) {
      MD2Triangle* triangle = triangles + i;
      for(int j = 0; j &lt; 3; j++) {
          MD2Vertex* v1 = frame1-&gt;vertices + triangle-&gt;vertices[j];
          MD2Vertex* v2 = frame2-&gt;vertices + triangle-&gt;vertices[j];
          Vec3f pos = v1-&gt;pos * (1 - frac) + v2-&gt;pos * frac;
          Vec3f normal = v1-&gt;normal * (1 - frac) + v2-&gt;normal * frac;
          if (normal[0] == 0 &amp;&amp; normal[1] == 0 &amp;&amp; normal[2] == 0) {
              normal = Vec3f(0, 0, 1);
          }
          glNormal3f(normal[0], normal[1], normal[2]);
  
          MD2TexCoord* texCoord = texCoords + triangle-&gt;texCoords[j];
          glTexCoord2f(texCoord-&gt;texCoordX, texCoord-&gt;texCoordY);
          glVertex3f(pos[0], pos[1], pos[2]);
      }
  }
  glEnd();
  }
  </code></pre>