Advertisement
thecplusplusguy

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

Aug 26th, 2011
13,735
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.88 KB | None | 0 0
  1. //This example program is created by thecplusplusuy for demonstration purposes. It's a simple 3D model loader (wavefront (.obj)), which is capable to load materials and UV textures:
  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. //this file is the objloader.cpp
  6. #include "objloader.h"
  7.     //nothing to explain here
  8.     coordinate::coordinate(float a,float b,float c)
  9.     {
  10.         x=a;
  11.         y=b;
  12.         z=c;
  13.     }
  14.     //nothing to explain here
  15.     face::face(int facen,int f1,int f2,int f3,int t1,int t2,int t3,int m){
  16.         facenum=facen;
  17.         faces[0]=f1;
  18.         faces[1]=f2;
  19.         faces[2]=f3;
  20.         texcoord[0]=t1;
  21.         texcoord[1]=t2;
  22.         texcoord[2]=t3;
  23.         mat=m;
  24.         four=false;
  25.     }
  26.     //nothing to explain here
  27.     face::face(int facen,int f1,int f2,int f3,int f4,int t1,int t2,int t3,int t4,int m){
  28.         facenum=facen;
  29.         faces[0]=f1;
  30.         faces[1]=f2;
  31.         faces[2]=f3;
  32.         faces[3]=f4;
  33.         texcoord[0]=t1;
  34.         texcoord[1]=t2;
  35.         texcoord[2]=t3;
  36.         texcoord[3]=t4;
  37.         mat=m;
  38.         four=true;
  39.     }
  40.    
  41.     //nothing to explain here
  42.     material::material(const char* na,float al,float n,float ni2,float* d,float* a,float* s,int i,int t)
  43.     {
  44.         name=na;
  45.         alpha=al;
  46.         ni=ni2;
  47.         ns=n;
  48.         dif[0]=d[0];
  49.         dif[1]=d[1];
  50.         dif[2]=d[2];
  51.        
  52.         amb[0]=a[0];
  53.         amb[1]=a[1];
  54.         amb[2]=a[2];
  55.        
  56.         spec[0]=s[0];
  57.         spec[1]=s[1];
  58.         spec[2]=s[2];
  59.        
  60.         illum=i;
  61.         texture=t;
  62.     }
  63.    
  64.     //nothing to explain here
  65.     texcoord::texcoord(float a,float b)
  66.     {
  67.         u=a;
  68.         v=b;
  69.     }
  70.  
  71. int objloader::load(const char* filename)
  72. {
  73.     std::ifstream in(filename); //open the model file
  74.     if(!in.is_open())
  75.     {
  76.         std::cout << "Nor oepened" << std::endl; //if it's not opened then error message, and return with -1
  77.         return -1;
  78.     }
  79.     char buf[256];  //temp buffer
  80.     int curmat=0;   //the current (default) material is 0, it's used, when we read the faces
  81.     while(!in.eof())
  82.     {
  83.         in.getline(buf,256);    //while we are not in the end of the file, read everything as a string to the coord vector
  84.         coord.push_back(new std::string(buf));
  85.     }
  86.     for(int i=0;i<coord.size();i++) //and then go through all line and decide what kind of line it is
  87.     {
  88.         if((*coord[i])[0]=='#') //if it's a comment
  89.             continue;   //we don't have to do anything with it
  90.         else if((*coord[i])[0]=='v' && (*coord[i])[1]==' ') //if a vertex
  91.         {
  92.             float tmpx,tmpy,tmpz;
  93.             sscanf(coord[i]->c_str(),"v %f %f %f",&tmpx,&tmpy,&tmpz);   //read the 3 floats, which makes up the vertex
  94.             vertex.push_back(new coordinate(tmpx,tmpy,tmpz));   //and put it in the vertex vector
  95.         }else if((*coord[i])[0]=='v' && (*coord[i])[1]=='n')    //if it's a normal vector
  96.         {
  97.             float tmpx,tmpy,tmpz;
  98.             sscanf(coord[i]->c_str(),"vn %f %f %f",&tmpx,&tmpy,&tmpz);
  99.             normals.push_back(new coordinate(tmpx,tmpy,tmpz));  //basically do the same
  100.             isnormals=true;
  101.         }else if((*coord[i])[0]=='f')   //if it's a face
  102.         {
  103.             int a,b,c,d,e;
  104.             if(count(coord[i]->begin(),coord[i]->end(),' ')==4) //if this is a quad
  105.             {
  106.                 if(coord[i]->find("//")!=std::string::npos) //if it's contain a normal vector, but not contain texture coorinate
  107.                 {
  108.                     sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b,&e,&b);  //read in this form
  109.                     faces.push_back(new face(b,a,c,d,e,0,0,0,0,curmat));    //and put to the faces, we don't care about the texture coorinate in this case
  110.                                                                                                                                 //and if there is no material, it doesn't matter, what is curmat
  111.                 }else if(coord[i]->find("/")!=std::string::npos)    //if we have texture coorinate and normal vectors
  112.                 {
  113.                     int t[4];   //texture coorinates
  114.                     //read in this form, and put to the end of the vector
  115.                     sscanf(coord[i]->c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d",&a,&t[0],&b,&c,&t[1],&b,&d,&t[2],&b,&e,&t[3],&b);
  116.                     faces.push_back(new face(b,a,c,d,e,t[0],t[1],t[2],t[3],curmat));
  117.                 }else{
  118.                     //else we don't have normal vectors nor texture coorinate
  119.                     sscanf(coord[i]->c_str(),"f %d %d %d %d",&a,&b,&c,&d);
  120.                     faces.push_back(new face(-1,a,b,c,d,0,0,0,0,curmat));      
  121.                 }
  122.             }else{  //if it's a triangle
  123.                             //do the same, except we use one less vertex/texture coorinate/face number
  124.                     if(coord[i]->find("//")!=std::string::npos)
  125.                     {
  126.                         sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b);
  127.                         faces.push_back(new face(b,a,c,d,0,0,0,curmat));
  128.                     }else if(coord[i]->find("/")!=std::string::npos)
  129.                     {
  130.                         int t[3];
  131.                         sscanf(coord[i]->c_str(),"f %d/%d/%d %d/%d/%d %d/%d/%d",&a,&t[0],&b,&c,&t[1],&b,&d,&t[2],&b);
  132.                         faces.push_back(new face(b,a,c,d,t[0],t[1],t[2],curmat));
  133.                     }else{
  134.                         sscanf(coord[i]->c_str(),"f %d %d %d",&a,&b,&c);
  135.                         faces.push_back(new face(-1,a,b,c,0,0,0,curmat));                  
  136.                     }
  137.             }
  138.     }else if((*coord[i])[0]=='u' && (*coord[i])[1]=='s' && (*coord[i])[2]=='e') //use material material_name
  139.     {
  140.         char tmp[200];
  141.         sscanf(coord[i]->c_str(),"usemtl %s",tmp);  //read the name of the material to tmp
  142.         for(int i=0;i<materials.size();i++) //go through all of the materials
  143.         {
  144.             if(strcmp(materials[i]->name.c_str(),tmp)==0)   //and compare the tmp with the name of the material
  145.             {
  146.                 curmat=i;   //if it's equal then set the current material to that
  147.                 break;
  148.             }
  149.         }
  150.     }else if((*coord[i])[0]=='m' && (*coord[i])[1]=='t' && (*coord[i])[2]=='l' && (*coord[i])[3]=='l')  //material library, a file, which contain
  151.                                                                                                                                                                                                             //all of the materials
  152.     {
  153.         char filen[200];
  154.         sscanf(coord[i]->c_str(),"mtllib %s",filen);    //read the filename
  155.         std::ifstream mtlin(filen); //open the file
  156.         if(!mtlin.is_open())    //if not opened error message, clean all memory, return with -1
  157.         {
  158.             std::cout << "connot open the material file" << std::endl;
  159.             clean();
  160.             return -1;
  161.         }
  162.         ismaterial=true;    //we use materials
  163.         std::vector<std::string> tmp;//contain all of the line of the file
  164.         char c[200];
  165.         while(!mtlin.eof())
  166.         {
  167.             mtlin.getline(c,200);   //read all lines to tmp
  168.             tmp.push_back(c);
  169.         }
  170.         char name[200]; //name of the material
  171.         char filename[200]; //filename of the texture
  172.         float amb[3],dif[3],spec[3],alpha,ns,ni;    //colors, shininess, and something else
  173.         int illum;
  174.         unsigned int texture;
  175.         bool ismat=false;   //do we already have a material read in to these variables?
  176.         strcpy(filename,"\0");  //set filename to nullbyte character
  177.         for(int i=0;i<tmp.size();i++) //go through all lines of the mtllib file
  178.         {
  179.             if(tmp[i][0]=='#')  //we don't care about comments
  180.                 continue;
  181.             if(tmp[i][0]=='n' && tmp[i][1]=='e' && tmp[i][2]=='w')  //new material
  182.             {
  183.                 if(ismat)   //if we have a material
  184.                 {
  185.                     if(strcmp(filename,"\0")!=0)    //if we have a texture
  186.                     {
  187.                         materials.push_back(new material(name,alpha,ns,ni,dif,amb,spec,illum,texture)); //push back
  188.                         strcpy(filename,"\0");
  189.                     }else{
  190.                             materials.push_back(new material(name,alpha,ns,ni,dif,amb,spec,illum,-1));      //push back, but use -1 to texture     
  191.                     }
  192.                 }
  193.                 ismat=false;    //we start from a fresh material
  194.                 sscanf(tmp[i].c_str(),"newmtl %s",name);    //read in the name
  195.             }else if(tmp[i][0]=='N' && tmp[i][1]=='s')  //the shininess
  196.             {
  197.                 sscanf(tmp[i].c_str(),"Ns %f",&ns);
  198.                 ismat=true;
  199.             }else if(tmp[i][0]=='K' && tmp[i][1]=='a')  //the ambient
  200.             {
  201.                 sscanf(tmp[i].c_str(),"Ka %f %f %f",&amb[0],&amb[1],&amb[2]);
  202.                 ismat=true;
  203.             }else if(tmp[i][0]=='K' && tmp[i][1]=='d')  //the diffuse
  204.             {
  205.                 sscanf(tmp[i].c_str(),"Kd %f %f %f",&dif[0],&dif[1],&dif[2]);
  206.                 ismat=true;
  207.             }else if(tmp[i][0]=='K' && tmp[i][1]=='s')  //the specular
  208.             {
  209.                 sscanf(tmp[i].c_str(),"Ks %f %f %f",&spec[0],&spec[1],&spec[2]);
  210.                 ismat=true;
  211.             }else if(tmp[i][0]=='N' && tmp[i][1]=='i')  //the I don't know what is this
  212.             {
  213.                 sscanf(tmp[i].c_str(),"Ni %f",&ni);
  214.                 ismat=true;
  215.             }else if(tmp[i][0]=='d' && tmp[i][1]==' ')  //the alpha
  216.             {
  217.                 sscanf(tmp[i].c_str(),"d %f",&alpha);
  218.                 ismat=true;
  219.             }else if(tmp[i][0]=='i' && tmp[i][1]=='l')  //the illum (don't ask)
  220.             {
  221.                 sscanf(tmp[i].c_str(),"illum %d",&illum);
  222.                 ismat=true;
  223.             }else if(tmp[i][0]=='m' && tmp[i][1]=='a')  //and the texture
  224.             {
  225.                 sscanf(tmp[i].c_str(),"map_Kd %s",filename);
  226.                 texture=loadTexture(filename);  //read the filename, and use the loadTexture function to load it, and get the id.
  227.                 ismat=true;
  228.             }
  229.         }
  230.         if(ismat)   //there is no newmat after the last newmat, so we have to put the last material 'manually'
  231.         {
  232.             if(strcmp(filename,"\0")!=0)
  233.             {
  234.                 materials.push_back(new material(name,alpha,ns,ni,dif,amb,spec,illum,texture));
  235.             }else{
  236.                     materials.push_back(new material(name,alpha,ns,ni,dif,amb,spec,illum,-1));             
  237.             }
  238.         }
  239.     }else if((*coord[i])[0]=='v' && (*coord[i])[1]=='t')    //back to the obj file, texture coorinate
  240.     {
  241.         float u,v;
  242.         sscanf(coord[i]->c_str(),"vt %f %f",&u,&v); //read the uv coordinate
  243.         texturecoordinate.push_back(new texcoord(u,1-v));   //I push back 1-v instead of normal v, because obj file use the upper left corner as 0,0 coorinate
  244.         //but OpenGL use bottom left corner as 0,0, so I convert it
  245.         istexture=true;
  246.     }
  247. }
  248.     if(materials.size()==0) //if some reason the material file doesn't contain any material, we don't have material
  249.         ismaterial=false;
  250.     else    //else we have
  251.         ismaterial=true;
  252.     std::cout << vertex.size() << " " << normals.size() << " " << faces.size() << " " << materials.size() << std::endl;     //test purposes
  253.     //draw
  254.     int num;
  255.     num=glGenLists(1);  //I generate a unique identifier for the list
  256.     glNewList(num,GL_COMPILE);
  257.     int last=-1;    //the last material (default -1, which doesn't exist, so we use the first material)
  258.     for(int i=0;i<faces.size();i++) //go throught all faces
  259.     {
  260.         if(last!=faces[i]->mat && ismaterial)   //if we have a meterial AND the last material is not the same
  261.         {
  262.             //set all of the material property
  263.             float diffuse[]={materials[faces[i]->mat]->dif[0],materials[faces[i]->mat]->dif[1],materials[faces[i]->mat]->dif[2],1.0};
  264.             float ambient[]={materials[faces[i]->mat]->amb[0],materials[faces[i]->mat]->amb[1],materials[faces[i]->mat]->amb[2],1.0};
  265.             float specular[]={materials[faces[i]->mat]->spec[0],materials[faces[i]->mat]->spec[1],materials[faces[i]->mat]->spec[2],1.0};
  266.             glMaterialfv(GL_FRONT,GL_DIFFUSE,diffuse);
  267.             glMaterialfv(GL_FRONT,GL_AMBIENT,ambient);
  268.             glMaterialfv(GL_FRONT,GL_SPECULAR,specular);
  269.             glMaterialf(GL_FRONT,GL_SHININESS,materials[faces[i]->mat]->ns);
  270.             last=faces[i]->mat; //set the current to last
  271.             if(materials[faces[i]->mat]->texture==-1)   //if we don't have texture, disable it, else enable it
  272.                 glDisable(GL_TEXTURE_2D);
  273.             else{
  274.                 glEnable(GL_TEXTURE_2D);
  275.                 glBindTexture(GL_TEXTURE_2D,materials[faces[i]->mat]->texture); //and use it
  276.             }
  277.         }
  278.         if(faces[i]->four)  //if quad
  279.         {
  280.             glBegin(GL_QUADS);
  281.                 if(isnormals)   //if there are normals
  282.                     glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);    //use them
  283.                    
  284.                 if(istexture && materials[faces[i]->mat]->texture!=-1)  //if there are textures
  285.                     glTexCoord2f(texturecoordinate[faces[i]->texcoord[0]-1]->u,texturecoordinate[faces[i]->texcoord[0]-1]->v);  //set the texture coorinate
  286.                
  287.                 glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
  288.                
  289.                 if(istexture && materials[faces[i]->mat]->texture!=-1)
  290.                     glTexCoord2f(texturecoordinate[faces[i]->texcoord[1]-1]->u,texturecoordinate[faces[i]->texcoord[1]-1]->v);
  291.                
  292.                 glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
  293.                
  294.                 if(istexture && materials[faces[i]->mat]->texture!=-1)
  295.                     glTexCoord2f(texturecoordinate[faces[i]->texcoord[2]-1]->u,texturecoordinate[faces[i]->texcoord[2]-1]->v);
  296.                
  297.                 glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
  298.                
  299.                 if(istexture && materials[faces[i]->mat]->texture!=-1)
  300.                     glTexCoord2f(texturecoordinate[faces[i]->texcoord[3]-1]->u,texturecoordinate[faces[i]->texcoord[3]-1]->v);
  301.                
  302.                 glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z);
  303.             glEnd();
  304.         }else{
  305.             glBegin(GL_TRIANGLES);
  306.                 if(isnormals)   //if there are normals
  307.                     glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
  308.  
  309.                 if(istexture && materials[faces[i]->mat]->texture!=-1)
  310.                     glTexCoord2f(texturecoordinate[faces[i]->texcoord[0]-1]->u,texturecoordinate[faces[i]->texcoord[0]-1]->v);
  311.  
  312.  
  313.                 glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
  314.                
  315.                 if(istexture && materials[faces[i]->mat]->texture!=-1)
  316.                     glTexCoord2f(texturecoordinate[faces[i]->texcoord[1]-1]->u,texturecoordinate[faces[i]->texcoord[1]-1]->v);
  317.                
  318.                 glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
  319.                
  320.                
  321.                 if(istexture && materials[faces[i]->mat]->texture!=-1)
  322.                     glTexCoord2f(texturecoordinate[faces[i]->texcoord[2]-1]->u,texturecoordinate[faces[i]->texcoord[2]-1]->v);
  323.                
  324.                 glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
  325.             glEnd();
  326.         }
  327.     }
  328.     glEndList();
  329.     clean();
  330.     lists.push_back(num);
  331.     return num;
  332. }
  333.  
  334. void objloader::clean()
  335. {
  336.     //delete all the dynamically allocated memory
  337.     for(int i=0;i<coord.size();i++)
  338.         delete coord[i];
  339.     for(int i=0;i<faces.size();i++)
  340.         delete faces[i];
  341.     for(int i=0;i<normals.size();i++)
  342.         delete normals[i];
  343.     for(int i=0;i<vertex.size();i++)
  344.         delete vertex[i];
  345.     for(int i=0;i<materials.size();i++)
  346.         delete materials[i];
  347.     for(int i=0;i<texturecoordinate.size();i++)
  348.         delete texturecoordinate[i];
  349.     //and all elements from the vector
  350.     coord.clear();
  351.     faces.clear();
  352.     normals.clear();
  353.     vertex.clear();
  354.     materials.clear();
  355.     texturecoordinate.clear();
  356. }
  357.  
  358. objloader::~objloader()
  359. {
  360.     //delete lists and textures
  361.     for(std::vector<unsigned int>::const_iterator it=texture.begin();it!=texture.end();it++)
  362.     {
  363.         glDeleteTextures(1,&(*it));
  364.     }
  365.     for(std::vector<unsigned int>::const_iterator it=lists.begin();it!=lists.end();it++)
  366.     {
  367.         glDeleteLists(*it,1);
  368.     }
  369. }
  370.  
  371. //load the filename textures (only BMP, R5G6B5 format)
  372. unsigned int objloader::loadTexture(const char* filename)
  373. {
  374.     //nothing new in here
  375.     unsigned int num;
  376.     glGenTextures(1,&num);
  377.     SDL_Surface* img=SDL_LoadBMP(filename);
  378.     glBindTexture(GL_TEXTURE_2D,num);
  379.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  380.     glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  381.     glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,img->w,img->h,0,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,img->pixels);
  382.     glTexEnvi(GL_TEXTURE_2D,GL_TEXTURE_ENV_MODE,GL_MODULATE);   //maybe just this
  383.     SDL_FreeSurface(img);
  384.     texture.push_back(num);
  385.     return num;
  386. }
  387.  
  388. objloader::objloader()
  389. {
  390.     //at default we set all booleans to false, so we don't use anything
  391.     ismaterial=false;
  392.     isnormals=false;
  393.     istexture=false;
  394. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement