Pastebin launched a little side project called VERYVIRAL.com, check it out ;-) Want more features on Pastebin? Sign Up, it's FREE!

Simple obj loader (OpenGL,SDL,C++) - objloader.cpp

By: thecplusplusguy on Aug 9th, 2011  |  syntax: C++  |  size: 6.44 KB  |  views: 10,222  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. //This example program is created by thecplusplusuy for demonstration purposes. It's a simple Wavefront (.obj) loader:
  2. //http://www.youtube.com/user/thecplusplusguy
  3. //Free source, modify if you want, LGPL licence (I guess), I would be happy, if you would not delete the link
  4. //so other people can see the tutorial
  5. //compile under Linux:
  6. //g++ objloader.cpp -lSDL -lGL -lGLU
  7. //under Windows, set the libraries as I showed you in the tutorial 0
  8. #include <windows.h>
  9. #include <SDL/SDL.h> //check your include folder, it may be just SDL.h
  10. #include <GL/gl.h>
  11. #include <GL/glu.h>
  12. #include <cstdlib>
  13. #include <vector>
  14. #include <string>
  15. #include <algorithm>
  16. #include <fstream>
  17. #include <cstdio>
  18. #include <iostream>
  19.  
  20.  
  21. struct coordinate{
  22.         float x,y,z;
  23.         coordinate(float a,float b,float c) : x(a),y(b),z(c) {};
  24. };
  25.  
  26. //for faces, it can contain triangles and quads as well, the four variable contain which is that
  27. struct face{
  28.         int facenum;
  29.         bool four;
  30.         int faces[4];
  31.         face(int facen,int f1,int f2,int f3) : facenum(facen){  //constructor for triangle
  32.                 faces[0]=f1;
  33.                 faces[1]=f2;
  34.                 faces[2]=f3;
  35.                 four=false;
  36.         }
  37.         face(int facen,int f1,int f2,int f3,int f4) : facenum(facen){ //overloaded constructor for quad
  38.                 faces[0]=f1;
  39.                 faces[1]=f2;
  40.                 faces[2]=f3;
  41.                 faces[3]=f4;
  42.                 four=true;
  43.         }
  44. };
  45.  
  46. float angle=0.0;        //we rotate or object with angle degrees
  47.  
  48. int loadObject(const char* filename)
  49. {
  50.         std::vector<std::string*> coord;        //read every single line of the obj file as a string
  51.         std::vector<coordinate*> vertex;
  52.         std::vector<face*> faces;
  53.         std::vector<coordinate*> normals;       //normal vectors for every face
  54.         std::ifstream in(filename);     //open the .obj file
  55.         if(!in.is_open())       //if not opened, exit with -1
  56.         {
  57.                 std::cout << "Nor oepened" << std::endl;
  58.                 return -1;
  59.         }
  60.         char buf[256];
  61.         //read in every line to coord
  62.         while(!in.eof())
  63.         {
  64.                 in.getline(buf,256);
  65.                 coord.push_back(new std::string(buf));
  66.         }
  67.         //go through all of the elements of coord, and decide what kind of element is that
  68.         for(int i=0;i<coord.size();i++)
  69.         {
  70.                 if(coord[i]->c_str()[0]=='#')   //if it is a comment (the first character is #)
  71.                         continue;       //we don't care about that
  72.                 else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]==' ') //if vector
  73.                 {
  74.                         float tmpx,tmpy,tmpz;
  75.                         sscanf(coord[i]->c_str(),"v %f %f %f",&tmpx,&tmpy,&tmpz);       //read in the 3 float coordinate to tmpx,tmpy,tmpz
  76.                         vertex.push_back(new coordinate(tmpx,tmpy,tmpz));       //and then add it to the end of our vertex list
  77.                 }else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]=='n')        //if normal vector
  78.                 {
  79.                         float tmpx,tmpy,tmpz;   //do the same thing
  80.                         sscanf(coord[i]->c_str(),"vn %f %f %f",&tmpx,&tmpy,&tmpz);
  81.                         normals.push_back(new coordinate(tmpx,tmpy,tmpz));     
  82.                 }else if(coord[i]->c_str()[0]=='f')     //if face
  83.                 {
  84.                         int a,b,c,d,e;
  85.                         if(count(coord[i]->begin(),coord[i]->end(),' ')==3)     //if it is a triangle (it has 3 space in it)
  86.                         {
  87.                   sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b);
  88.                                 faces.push_back(new face(b,a,c,d));     //read in, and add to the end of the face list
  89.                         }else{
  90.                                 sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b,&e,&b);
  91.                                 faces.push_back(new face(b,a,c,d,e));   //do the same, except we call another constructor, and we use different pattern
  92.                         }
  93.                 }
  94.         }
  95. //raw
  96.         int num;        //the id for the list
  97.         num=glGenLists(1);      //generate a uniqe
  98.         glNewList(num,GL_COMPILE);      //and create it
  99.         for(int i=0;i<faces.size();i++)
  100.         {
  101.                 if(faces[i]->four)      //if it's a quad draw a quad
  102.                 {
  103.                         glBegin(GL_QUADS);
  104.                                 //basically all I do here, is use the facenum (so the number of the face) as an index for the normal, so the 1st normal owe to the first face
  105.                                 //I subtract 1 because the index start from 0 in C++
  106.                                 glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
  107.                                 //draw the faces
  108.                                 glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
  109.                                 glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
  110.                                 glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
  111.                                 glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z);
  112.                         glEnd();
  113.                 }else{
  114.                         glBegin(GL_TRIANGLES);
  115.                                 glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
  116.                                 glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
  117.                                 glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
  118.                                 glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
  119.                         glEnd();
  120.                 }
  121.         }
  122.         glEndList();
  123.         //delete everything to avoid memory leaks
  124.         for(int i=0;i<coord.size();i++)
  125.                 delete coord[i];
  126.         for(int i=0;i<faces.size();i++)
  127.                 delete faces[i];
  128.         for(int i=0;i<normals.size();i++)
  129.                 delete normals[i];
  130.         for(int i=0;i<vertex.size();i++)
  131.                 delete vertex[i];
  132.         return num;     //return with the id
  133. }
  134.  
  135. int cube;
  136. void init()
  137. {
  138.         glClearColor(0.0,0.0,0.0,1.0);
  139.         glMatrixMode(GL_PROJECTION);
  140.         glLoadIdentity();
  141.         gluPerspective(45,640.0/480.0,1.0,500.0);
  142.         glMatrixMode(GL_MODELVIEW);
  143.         glEnable(GL_DEPTH_TEST);
  144.         cube=loadObject("test.obj");    //load the test.obj file
  145.         glEnable(GL_LIGHTING);  //we enable lighting, to make the 3D object to 3D
  146.         glEnable(GL_LIGHT0);
  147.         float col[]={1.0,1.0,1.0,1.0};  //light color is white
  148.         glLightfv(GL_LIGHT0,GL_DIFFUSE,col);
  149. }
  150.  
  151. void display()
  152. {
  153.         glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  154.         glLoadIdentity();
  155.         float pos[]={-1.0,1.0,-2.0,1.0};        //set the position
  156.         glLightfv(GL_LIGHT0,GL_POSITION,pos);
  157.         glTranslatef(0.0,0.0,-5.0);
  158.         glRotatef(angle,0.0,0.0,1.0);
  159.         glCallList(cube);       //draw the 3D mesh
  160. }
  161.  
  162.  
  163. int main(int argc,char** argv)
  164. {
  165.         SDL_Init(SDL_INIT_EVERYTHING);
  166.         SDL_Surface* screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE|SDL_OPENGL);
  167.         bool running=true;
  168.         Uint32 start;
  169.         SDL_Event event;
  170.         init();
  171.         while(running)
  172.         {
  173.                 start=SDL_GetTicks();
  174.                 while(SDL_PollEvent(&event))
  175.                 {
  176.                         switch(event.type)
  177.                         {
  178.                                 case SDL_QUIT:
  179.                                         running=false;
  180.                                         break;
  181.                         }
  182.                 }
  183.                 display();
  184.                 SDL_GL_SwapBuffers();
  185.                 angle+=0.5;
  186.                 if(angle>360)
  187.                         angle-=360;
  188.                 if(1000/30>(SDL_GetTicks()-start))
  189.                         SDL_Delay(1000/30-(SDL_GetTicks()-start));
  190.         }
  191.         SDL_Quit();
  192.         return 0;      
  193. }