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


SUBMITTED BY: Guest

DATE: Nov. 12, 2013, 2:51 a.m.

FORMAT: Text only

SIZE: 7.0 kB

HITS: 1165

  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. struct coordinate{
  20. float x,y,z;
  21. coordinate(float a,float b,float c) : x(a),y(b),z(c) {};
  22. };
  23. //for faces, it can contain triangles and quads as well, the four variable contain which is that
  24. struct face{
  25. int facenum;
  26. bool four;
  27. int faces[4];
  28. face(int facen,int f1,int f2,int f3) : facenum(facen){ //constructor for triangle
  29. faces[0]=f1;
  30. faces[1]=f2;
  31. faces[2]=f3;
  32. four=false;
  33. }
  34. face(int facen,int f1,int f2,int f3,int f4) : facenum(facen){ //overloaded constructor for quad
  35. faces[0]=f1;
  36. faces[1]=f2;
  37. faces[2]=f3;
  38. faces[3]=f4;
  39. four=true;
  40. }
  41. };
  42. float angle=0.0; //we rotate or object with angle degrees
  43. int loadObject(const char* filename)
  44. {
  45. std::vector<std::string*> coord; //read every single line of the obj file as a string
  46. std::vector<coordinate*> vertex;
  47. std::vector<face*> faces;
  48. std::vector<coordinate*> normals; //normal vectors for every face
  49. std::ifstream in(filename); //open the .obj file
  50. if(!in.is_open()) //if not opened, exit with -1
  51. {
  52. std::cout << "Nor oepened" << std::endl;
  53. return -1;
  54. }
  55. char buf[256];
  56. //read in every line to coord
  57. while(!in.eof())
  58. {
  59. in.getline(buf,256);
  60. coord.push_back(new std::string(buf));
  61. }
  62. //go through all of the elements of coord, and decide what kind of element is that
  63. for(int i=0;i<coord.size();i++)
  64. {
  65. if(coord[i]->c_str()[0]=='#') //if it is a comment (the first character is #)
  66. continue; //we don't care about that
  67. else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]==' ') //if vector
  68. {
  69. float tmpx,tmpy,tmpz;
  70. sscanf(coord[i]->c_str(),"v %f %f %f",&tmpx,&tmpy,&tmpz); //read in the 3 float coordinate to tmpx,tmpy,tmpz
  71. vertex.push_back(new coordinate(tmpx,tmpy,tmpz)); //and then add it to the end of our vertex list
  72. }else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]=='n') //if normal vector
  73. {
  74. float tmpx,tmpy,tmpz; //do the same thing
  75. sscanf(coord[i]->c_str(),"vn %f %f %f",&tmpx,&tmpy,&tmpz);
  76. normals.push_back(new coordinate(tmpx,tmpy,tmpz));
  77. }else if(coord[i]->c_str()[0]=='f') //if face
  78. {
  79. int a,b,c,d,e;
  80. if(count(coord[i]->begin(),coord[i]->end(),' ')==3) //if it is a triangle (it has 3 space in it)
  81. {
  82. sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b);
  83. faces.push_back(new face(b,a,c,d)); //read in, and add to the end of the face list
  84. }else{
  85. sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b,&e,&b);
  86. faces.push_back(new face(b,a,c,d,e)); //do the same, except we call another constructor, and we use different pattern
  87. }
  88. }
  89. }
  90. //raw
  91. int num; //the id for the list
  92. num=glGenLists(1); //generate a uniqe
  93. glNewList(num,GL_COMPILE); //and create it
  94. for(int i=0;i<faces.size();i++)
  95. {
  96. if(faces[i]->four) //if it's a quad draw a quad
  97. {
  98. glBegin(GL_QUADS);
  99. //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
  100. //I subtract 1 because the index start from 0 in C++
  101. glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
  102. //draw the faces
  103. glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
  104. glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
  105. glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
  106. glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z);
  107. glEnd();
  108. }else{
  109. glBegin(GL_TRIANGLES);
  110. glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
  111. glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
  112. glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
  113. glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
  114. glEnd();
  115. }
  116. }
  117. glEndList();
  118. //delete everything to avoid memory leaks
  119. for(int i=0;i<coord.size();i++)
  120. delete coord[i];
  121. for(int i=0;i<faces.size();i++)
  122. delete faces[i];
  123. for(int i=0;i<normals.size();i++)
  124. delete normals[i];
  125. for(int i=0;i<vertex.size();i++)
  126. delete vertex[i];
  127. return num; //return with the id
  128. }
  129. int cube;
  130. void init()
  131. {
  132. glClearColor(0.0,0.0,0.0,1.0);
  133. glMatrixMode(GL_PROJECTION);
  134. glLoadIdentity();
  135. gluPerspective(45,640.0/480.0,1.0,500.0);
  136. glMatrixMode(GL_MODELVIEW);
  137. glEnable(GL_DEPTH_TEST);
  138. cube=loadObject("test.obj"); //load the test.obj file
  139. glEnable(GL_LIGHTING); //we enable lighting, to make the 3D object to 3D
  140. glEnable(GL_LIGHT0);
  141. float col[]={1.0,1.0,1.0,1.0}; //light color is white
  142. glLightfv(GL_LIGHT0,GL_DIFFUSE,col);
  143. }
  144. void display()
  145. {
  146. glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  147. glLoadIdentity();
  148. float pos[]={-1.0,1.0,-2.0,1.0}; //set the position
  149. glLightfv(GL_LIGHT0,GL_POSITION,pos);
  150. glTranslatef(0.0,0.0,-5.0);
  151. glRotatef(angle,0.0,0.0,1.0);
  152. glCallList(cube); //draw the 3D mesh
  153. }
  154. int main(int argc,char** argv)
  155. {
  156. SDL_Init(SDL_INIT_EVERYTHING);
  157. SDL_Surface* screen=SDL_SetVideoMode(640,480,32,SDL_SWSURFACE|SDL_OPENGL);
  158. bool running=true;
  159. Uint32 start;
  160. SDL_Event event;
  161. init();
  162. while(running)
  163. {
  164. start=SDL_GetTicks();
  165. while(SDL_PollEvent(&event))
  166. {
  167. switch(event.type)
  168. {
  169. case SDL_QUIT:
  170. running=false;
  171. break;
  172. }
  173. }
  174. display();
  175. SDL_GL_SwapBuffers();
  176. angle+=0.5;
  177. if(angle>360)
  178. angle-=360;
  179. if(1000/30>(SDL_GetTicks()-start))
  180. SDL_Delay(1000/30-(SDL_GetTicks()-start));
  181. }
  182. SDL_Quit();
  183. return 0;
  184. }

comments powered by Disqus