title: Opengl obj object loader with textures
body: <p>I am using an object loader to load an obj model that I exported from blender. I can load the model but none of the textures are loaded and I don't know why. Should they be loaded when I render the model in the main class or do I need to load the textures as well as rendering the model?</p>
  
  <p>objloader.cpp</p>
  
  <pre><code>/************************************************************
  *Loads obj file - limited to vertices, faces, normals, texture maps
  *loads to object structure as defined in .h file
  ************************************************************/
  
  #include &lt;stdio.h&gt;
  #include &lt;iostream&gt;
  #include &lt;io.h&gt;
  #include &lt;stdlib.h&gt;
  #include "glut.h"
  
  #include "objloader.h"
  
  using namespace std;
  
  void object_type::render()
  {
      glBegin(GL_TRIANGLES); // glBegin and glEnd delimit the vertices that define a primitive (in our case triangles)
  
      for (int j=0;j&lt;polygons_qty;j++)
      {
          //----------------- FIRST VERTEX -----------------
          //Normal coordinates of the first vertex
          glNormal3f( normcoord[ polygon[j].n[0] - 1 ].i,
                  normcoord[ polygon[j].n[0] - 1 ].j,
                  normcoord[ polygon[j].n[0] - 1 ].k);
          // Texture coordinates of the first vertex
              glTexCoord2f( mapcoord[ polygon[j].t[0] - 1 ].u,
                    mapcoord[ polygon[j].t[0] - 1 ].v);
          // Coordinates of the first vertex
          glVertex3f( vertex[ polygon[j].v[0] - 1].x,
                  vertex[ polygon[j].v[0] - 1].y,
                  vertex[ polygon[j].v[0] - 1].z);
  
          //----------------- SECOND VERTEX -----------------
          //Normal coordinates of the first vertex
          glNormal3f( normcoord[ polygon[j].n[1] - 1 ].i,
                  normcoord[ polygon[j].n[1] - 1 ].j,
                  normcoord[ polygon[j].n[1] - 1 ].k);
          // Texture coordinates of the first vertex
          glTexCoord2f( mapcoord[ polygon[j].t[1] - 1 ].u,
                    mapcoord[ polygon[j].t[1] - 1 ].v);
          // Coordinates of the first vertex
          glVertex3f( vertex[ polygon[j].v[1] - 1].x,
                  vertex[ polygon[j].v[1] - 1].y,
                  vertex[ polygon[j].v[1] - 1].z);
  
          //----------------- THIRD VERTEX -----------------
          //Normal coordinates of the first vertex
          glNormal3f( normcoord[ polygon[j].n[2] - 1 ].i,
                  normcoord[ polygon[j].n[2] - 1 ].j,
                  normcoord[ polygon[j].n[2] - 1 ].k);
          // Texture coordinates of the first vertex
          glTexCoord2f( mapcoord[ polygon[j].t[2] - 1 ].u,
                    mapcoord[ polygon[j].t[2] - 1 ].v);
          // Coordinates of the first vertex
          glVertex3f( vertex[ polygon[j].v[2] - 1].x,
                  vertex[ polygon[j].v[2] - 1].y,
                  vertex[ polygon[j].v[2] - 1].z);
      }
      glEnd();
  }
  
  
  /*
  vertex_type vertex[MAX_VERTICES]; 
  mapcoord_type mapcoord[MAX_VERTICES];
  normcoord_type normcoord[MAX_NORMALS];
  polygon_type polygon[MAX_POLYGONS];
  int id_texture
  */
  
  
  int object_type::objdatadisplay()
  {
     int i;
     printf("VERTICES: %d\n",vertices_qty); 
  for (i =0;i&lt;vertices_qty;i++)
   {
       printf("%f %f %f\n",vertex[i].x,vertex[i].y,vertex[i].z);
   }
  
     printf("NORMALS: %d\n",normcoord_qty); 
  for (i =0;i&lt;normcoord_qty;i++)
  {
       printf("%f %f %f\n",normcoord[i].i,normcoord[i].j,normcoord[i].k);
  }
     printf("MAP COORDS: %d\n",mapcoord_qty);
  for (i =0;i&lt;mapcoord_qty;i++)
  {
       printf("%f %f\n",mapcoord[i].u,mapcoord[i].v);
  }
     printf("POLYGONS: %d\n",polygons_qty); 
  for (i=0;i&lt;polygons_qty;i++) //for each vertex of polygon (triangle)
  {
      for (int j = 0;j&lt;3;j++)
      {   
               printf("%d::%d/%d/%d\n",i,polygon[i].v[j],polygon[i].t[j],polygon[i].n[j]);
      }
  }
  return 1;
  }
  
  
  int object_type::objloader(char *p_filename)
  {
      int ivertex=0; //Index variable
      int inormal =0;
      int ipolygon=0;
      int imap=0;
      char string[256];
  FILE *l_file; //File pointer
  
  char l_char; //Char variable
  
  unsigned short l_face_flags; //Flag that stores some face information
  
  if ((l_file=fopen (p_filename, "rt"))== NULL) return 0; //Open the file
  
  
  while (!feof(l_file)) //Loop to scan the whole file 
  {
      fscanf(l_file,"%c",&amp;l_char);
      if(l_char=='\n')//read char if'/n' -skip to next and read   
          fscanf(l_file,"%c",&amp;l_char);
      switch (l_char) //parse
      {   
      default: fgets(string,256,l_file);
          break;
      case 'v':   //a vertex or a normal or a text co-ord
          fscanf(l_file,"%c",&amp;l_char);
          switch (l_char)  
          {
          case ' ':   //a vertex -expect and so read 3 floats next
                fscanf(l_file,"%f %f %f",&amp;vertex[ivertex].x, &amp;vertex[ivertex].y,&amp;vertex[ivertex].z);
  
  
                ivertex++;
                break;
          case 'n': //a normal -expect and so read 3 floats next
                fscanf(l_file,"%f %f %f",&amp;normcoord[inormal].i, &amp;normcoord[inormal].j,&amp;normcoord[inormal].k);
                inormal++;
                break;
          case 't': //a texture map coord-expect and so read 2 floats next
                fscanf(l_file,"%f %f",&amp;mapcoord[imap].u, &amp;mapcoord[imap].v);
                imap++;
                break;
          }  //end switch
          break;
      case 'f': //a face read next assume format is -&gt; f 1/1/1 2/2/2 3/3/3
          for (int i=0;i&lt;3;i++) //for each vertex of polygon (triangle)
          {
               fscanf(l_file,"%c",&amp;l_char); //read space char - ignore this
               fscanf(l_file,"%d",&amp;polygon[ipolygon].v[i]); //read vertex.
               fscanf(l_file,"%c",&amp;l_char); //read space char - ignore this
               fscanf(l_file,"%d",&amp;polygon[ipolygon].t[i]); //read text coord.
               fscanf(l_file,"%c",&amp;l_char); //read space char - ignore this
               fscanf(l_file,"%d",&amp;polygon[ipolygon].n[i]); //read normal.
          }
          ipolygon++;
          break;
  
      } //end switch
  }
  
  fclose (l_file); // Closes the file stream
  vertices_qty = ivertex;
  polygons_qty = ipolygon;
  mapcoord_qty = imap;
  normcoord_qty = inormal;
  
  return 1;  //if successful    
  }
  </code></pre>
  
  <p>objloader.h</p>
  
  <pre><code>#ifndef OBJLOAD
  #define OBJLOAD
  
  /************************************************
  *Loads obj file - limited to vertices, faces, normals, texture maps
  *loads to object structure as defined in .h file
  ****************************************************/
  
  
  #define MAX_VERTICES 8000 // Max number of vertices (for each object)
  #define MAX_POLYGONS 8000 // Max number of polygons (for each object)
  #define MAX_NORMALS 8000 // Max number of polygons (for each object)
  
  // Our vertex type
  typedef struct{
  float x,y,z;
  }vertex_type;
  
  // Our normal type
  typedef struct{
  float i,j,k;
  }normcoord_type;
  
  // The polygon (triangle), 3 numbers that aim 3 vertices
  typedef struct{
  int v[3],t[3],n[3];
  }polygon_type;
  
  // The mapcoord type, 2 texture coordinates for each vertex
  typedef struct{
  float u,v;
  }mapcoord_type;
  
  // The object type
  class object_type{
  public:
  int id_texture; 
  object_type(){}
  ~object_type(){}
  int objloader(char *p_filename); 
  int objdatadisplay();
  void render();
  
  private:
  char name[20];
  int vertices_qty;
  int polygons_qty;
  int mapcoord_qty;
  int normcoord_qty;
  
  vertex_type vertex[MAX_VERTICES]; 
  mapcoord_type mapcoord[MAX_VERTICES];
  normcoord_type normcoord[MAX_NORMALS];
  polygon_type polygon[MAX_POLYGONS];
  
  };
  #endif
  </code></pre>
  
  <p>main.cpp</p>
  
  <pre><code>#include "objloader.h"
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;math.h&gt;
  #include &lt;GL/glew.h&gt;
  
  #ifdef __WIN32__
  #include &lt;windows.h&gt;
  #endif
  
  #include "glut.h"  //glut has all ogl relevant .h files included 
  
  int screen_width=800;
  int screen_height=600;
  
  //angle of rotation
  float xpos = 0, ypos = 0, zpos = 0, xrot = 0, yrot = 0, angle=0.0;
  
  float cRadius = 10.0f; // our radius distance from our character
  
  float lastx, lasty;
  
  object_type *objarray[2];  //objects container for our world. Used throughout so global
  
  //Lights settings
  GLfloat light_ambient[]= { 0.1f, 0.1f, 0.1f, 0.1f };
  GLfloat light_diffuse[]= { 1.0f, 1.0f, 1.0f, 0.0f };
  GLfloat light_specular[]= { 1.0f, 1.0f, 1.0f, 0.0f };
  GLfloat light_position[]= { 100.0f, 0.0f, -10.0f, 1.0f };
  
  //Materials settings
  GLfloat mat_ambient[]= { 0.5f, 0.5f, 0.0f, 0.0f };
  GLfloat mat_diffuse[]= { 0.5f, 0.5f, 0.0f, 0.0f };
  GLfloat mat_specular[]= { 1.0f, 1.0f, 1.0f, 0.0f };
  GLfloat mat_shininess[]= { 1.0f };
  
  
  /************************************
   *
   * SUBROUTINE init(void)
   *
   * Used to initialize OpenGL and to setup our world
   *
  ************************************/
  
  void init(void)
  {
      glClearColor(0.0, 0.0, 0.0, 0.0); // Clear background color to black
  
      // Viewport transformation
      glViewport(0,0,screen_width,screen_height);  
  
      // Projection transformation
      glMatrixMode(GL_PROJECTION); // Specifies which matrix stack is the target for matrix operations 
      glLoadIdentity(); // We initialize the projection matrix as identity
      gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,5.0f,10000.0f);     
  
  
  //Lights initialization and activation
      glLightfv (GL_LIGHT1, GL_AMBIENT, light_ambient);
      glLightfv (GL_LIGHT1, GL_DIFFUSE, light_diffuse);
      glLightfv (GL_LIGHT1, GL_DIFFUSE, light_specular);
      glLightfv (GL_LIGHT1, GL_POSITION, light_position);    
      glEnable (GL_LIGHT1);
      glEnable (GL_LIGHTING);
  
      //Materials initialization and activation
  glMaterialfv (GL_FRONT, GL_AMBIENT, mat_ambient);
      glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_diffuse);
      glMaterialfv (GL_FRONT, GL_DIFFUSE, mat_specular);
      glMaterialfv (GL_FRONT, GL_POSITION, mat_shininess);    
  
  //Other initializations
      glShadeModel(GL_SMOOTH); // Type of shading for the polygons
  glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Texture mapping perspective correction
      glEnable(GL_TEXTURE_2D); // Texture mapping ON
      glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); // Polygon rasterization mode (polygon filled)
  glEnable(GL_CULL_FACE); // Enable the back face culling
      glEnable(GL_DEPTH_TEST); // Enable the depth test 
  
  glTranslatef(0.0f, 0.0f, -cRadius);
      glRotatef(xrot,1.0,0.0,0.0);
  
  angle++; //increase the angle
  
  for (int i=0;i&lt;2;i++)
  {
  printf("*************\n");
      objarray[i] = new (object_type);
      objarray[i]-&gt;objloader("C:/3dModels/Museum.obj");
      objarray[i]-&gt;objdatadisplay();      
  }
  
  }
  
  
  /**********************************************************
   *
   * SUBROUTINE resize(int p_width, int p_height)
   *
   * This routine must be called everytime we resize our window.
   *
   * Input parameters: p_width = width in pixels of our viewport
   *                   p_height = height in pixels of our viewport
   * 
   *********************************************************/
  
  void resize (int p_width, int p_height)
  {
  if (screen_width==0 &amp;&amp; screen_height==0) exit(0);
      screen_width=p_width; // We obtain the new screen width values and store it
      screen_height=p_height; // Height value
  
      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // We clear both the color and the depth buffer so to draw the next frame
      glViewport(0,0,screen_width,screen_height); // Viewport transformation
  
      glMatrixMode(GL_PROJECTION); // Projection transformation
      glLoadIdentity(); // We initialize the projection matrix as identity
      gluPerspective(45.0f,(GLfloat)screen_width/(GLfloat)screen_height,5.0f,10000.0f);
  
      glutPostRedisplay (); // This command redraw the scene (it calls the same routine of glutDisplayFunc)
  }
  
  /**********************************************************
   *
   * SUBROUTINE keyboard(void)
   *
   * Subroutine to handle keyboard input
   * 
   *********************************************************/
  
  
  void keyboard (unsigned char key, int x, int y) {
      if (key=='q')
      {
      xrot += 1;
      if (xrot &gt;360) xrot -= 360;
      }
  
      if (key=='z')
      {
      xrot -= 1;
  
  if (xrot &lt; -360) xrot += 360;
      }
  
      if (key=='w')
      {
      float xrotrad, yrotrad;
      yrotrad = (yrot / 180 * 3.141592654f);
      xrotrad = (xrot / 180 * 3.141592654f); 
      xpos += float(sin(yrotrad));
      zpos -= float(cos(yrotrad));
      ypos -= float(sin(xrotrad));
      }
  
      if (key=='s')
      {
      float xrotrad, yrotrad;
      yrotrad = (yrot / 180 * 3.141592654f);
      xrotrad = (xrot / 180 * 3.141592654f); 
      xpos -= float(sin(yrotrad));
      zpos += float(cos(yrotrad));
      ypos += float(sin(xrotrad));
      }
  
      if (key=='d')
      {
      float yrotrad;
      yrotrad = (yrot / 180 * 3.141592654f);
      xpos += float(cos(yrotrad)) * 0.2;
      zpos += float(sin(yrotrad)) * 0.2;
      }
  
      if (key=='a')
      {
      float yrotrad;
      yrotrad = (yrot / 180 * 3.141592654f);
      xpos -= float(cos(yrotrad)) * 0.2;
      zpos -= float(sin(yrotrad)) * 0.2;
      }
  
      if (key==27)
      {
      exit(0);
      }
  }
  
  /**********************************************************
   *
   * SUBROUTINE mouseMovement(void)
   *
   * Subroutine to handle mouse input
   * 
   *********************************************************/
  
  void mouseMovement(int x, int y) {
  int diffx=x-lastx; //check the difference between the current x and the last x position
  int diffy=y-lasty; //check the difference between the current y and the last y position
  lastx=x; //set lastx to the current x position
  lasty=y; //set lasty to the current y position
  xrot += (float) diffy; //set the xrot to xrot with the addition of the difference in the y position
  yrot += (float) diffx;    //set the xrot to yrot with the addition of the difference in the x position
  }
  
  
  /**********************************************************
   *
   * SUBROUTINE display(void)
   *
   * This is our main rendering subroutine, called each frame
   * 
   *********************************************************/
  
  void display(void)
  {
  
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // This clear the background color to dark blue
      glMatrixMode(GL_MODELVIEW); // Modeling transformation
      glPushMatrix();
  glLoadIdentity(); // Initialize the model matrix as identity
  
      glTranslatef(0.0f, 0.0f, -cRadius); // We move the object forward (the model matrix is multiplied by the translation matrix)
      glRotatef(xrot,1.0,0.0,0.0); // Rotations of the object (the model matrix is multiplied by the rotation matrices)
  
      glRotatef(yrot,0.0,1.0,0.0);
  
  glTranslated(-xpos,0.0f,-zpos); //translate the screen to the position of our camera
  
  
  if (objarray[0]-&gt;id_texture!=-1) 
  {
      glBindTexture(GL_TEXTURE_2D, objarray[0]-&gt;id_texture); // We set the active texture 
      glEnable(GL_TEXTURE_2D); // Texture mapping ON
      printf("Txt map ON");
  }
  else
      glDisable(GL_TEXTURE_2D); // Texture mapping OFF
  
  
  objarray[0]-&gt;render();
  glPopMatrix();
  glPushMatrix();
  glTranslatef(5.0,0.0,-20.0);
  glFlush(); // This force the execution of OpenGL commands
  glutSwapBuffers(); // In double buffered mode we invert the positions of the visible buffer and the writing buffer
  }
  
  
  
  /**********************************************************
   *
   * The main routine
   * 
   *********************************************************/
  
  
  int main(int argc, char **argv)
  {
      // We use the GLUT utility to initialize the window, to handle the input and to interact with the windows system
      glutInit(&amp;argc, argv);    
      glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
      glutInitWindowSize(screen_width,screen_height);
      glutInitWindowPosition(0,0);
      glutCreateWindow("Demo 1: To exit press ESC");    
      glutDisplayFunc(display);
      glutIdleFunc(display);
      glutReshapeFunc (resize);
  
  glutPassiveMotionFunc(mouseMovement); //check for mouse movement
  glutKeyboardFunc (keyboard); 
  
  init();
      glutMainLoop();
  
      return(0);    
  }
  </code></pre>
  
  <p>Example obj from blender, cube.obj:</p>
  
  <pre><code># Blender v2.66 (sub 1) OBJ File: 'cube.blend'
  # www.blender.org
  mtllib cube.mtl
  g Cube
  v 1.000000 0.665869 -1.000000
  v 1.000000 0.665869 1.000000
  v -1.000000 0.665869 1.000000
  v -1.000000 0.665869 -1.000000
  v 1.000000 2.665869 -0.999999
  v 0.999999 2.665869 1.000001
  v -1.000000 2.665869 1.000000
  v -1.000000 2.665869 -1.000000
  vt 0.000000 0.334353
  vt 0.332314 0.333333
  vt 0.333333 0.665647
  vt 1.000000 0.001019
  vt 0.998981 0.333333
  vt 0.666667 0.332314
  vt 1.000000 0.665647
  vt 0.667686 0.666667
  vt 0.334353 0.666667
  vt 0.333333 0.334353
  vt 0.666667 0.665647
  vt 0.333333 0.332314
  vt 0.001020 0.333333
  vt 0.332314 0.000000
  vt 0.333333 0.001019
  vt 0.665647 0.000000
  vt 0.001019 0.666667
  vt 0.667686 0.000000
  vt 0.666667 0.334353
  vt 0.665647 0.333333
  vt 0.000000 0.001020
  vt 0.334353 0.333333
  vn 0.000000 -1.000000 0.000000
  vn -0.000000 1.000000 0.000000
  vn 1.000000 -0.000000 0.000001
  vn -0.000000 -0.000000 1.000000
  vn -1.000000 -0.000000 -0.000000
  vn 0.000000 0.000000 -1.000000
  vn 1.000000 0.000000 -0.000000
  usemtl Material
  s off
  f 1/1/1 2/2/1 3/3/1
  f 5/4/2 8/5/2 7/6/2
  f 1/5/3 5/7/3 6/8/3
  f 2/9/4 6/10/4 3/11/4
  f 3/12/5 7/13/5 4/14/5
  f 5/15/6 1/16/6 4/6/6
  f 4/17/1 1/1/1 3/3/1
  f 6/18/2 5/4/2 7/6/2
  f 2/19/7 1/5/7 6/8/7
  f 6/10/4 7/20/4 3/11/4
  f 7/13/5 8/21/5 4/14/5
  f 8/22/6 5/15/6 4/6/6
  </code></pre>