diff --git a/Driver.cpp b/Driver.cpp index b4e6a9d..7096fd7 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3,6 +3,7 @@ #endif #include #include +#include #include "Model.h" #include "Obj.h" @@ -11,26 +12,63 @@ void usage(){ } void draw(Model::Model* model){ - glEnable(GL_TEXTURE_2D); + //glEnable(GL_TEXTURE_2D); // glBindTexture(GL_TEXTURE_2D, texturen[0]); +// glutSolidTeapot(1); glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + //glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, 0, model->normals); +// glNormalPointer(GL_FLOAT, 0, model->normals); - glTexCoordPointer(2,GL_FLOAT,0, model->textures ); +// glTexCoordPointer(2,GL_FLOAT,0, model->textureCoordinates ); glVertexPointer(3,GL_FLOAT, 0,model->triangles); glDrawArrays(GL_TRIANGLES, 0, model->totalConnectedTriangles); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); +// glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisable(GL_TEXTURE_2D); + //glDisable(GL_TEXTURE_2D); +} + +void reshape(GLint width, GLint height) { + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(65.0, (float)width / height, 1, 100); + glMatrixMode(GL_MODELVIEW); +} + +void keyboard(unsigned char key, int x, int y){ + +} +Model::Obj m = Model::Obj(); +void display(void) { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + glTranslatef(0, 0, -6); + glColor3f(1,1,1); + draw(&m); + glutSwapBuffers(); + int i; + if(i = glGetError()) + std::cerr << "OpenGL Error" << std::endl; } void main(int argc, char** argv){ + glutInit (&argc, argv); + glutInitWindowSize (800, 600); + glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); + glutCreateWindow ("Model Loader Example"); + glutReshapeFunc (reshape); + glutKeyboardFunc (keyboard); + glutDisplayFunc (display); + glShadeModel(GL_SMOOTH); // Enable Smooth Shading + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Black Background + glClearDepth(1.0f); // Depth Buffer Setup + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do /* //TODO, parse argv if(argc < 1){ @@ -38,8 +76,6 @@ void main(int argc, char** argv){ return; } */ - - Model::Model* m = new Model::Obj(); - m->load("cube.obj"); - + m.load("cube.obj"); + glutMainLoop (); } \ No newline at end of file diff --git a/Model.cpp b/Model.cpp index 92f1ba7..6a49063 100644 --- a/Model.cpp +++ b/Model.cpp @@ -3,6 +3,11 @@ namespace Model { Model::Model(){ totalConnectedTriangles = 0; totalConnectedPoints = 0; + + vertices = new std::vector(); + triangles = new std::vector(); + normals = new std::vector(); + textureCoordinates = new std::vector(); } float* Model::calculateNormal(float* coord1, float* coord2, float* coord3){ diff --git a/Model.h b/Model.h index 3edc7d9..478ddf5 100644 --- a/Model.h +++ b/Model.h @@ -12,6 +12,7 @@ #include #include #include +#include namespace Model { #define POINTS_PER_VERTEX 3 #define TOTAL_FLOATS_IN_TRIANGLE 9 @@ -23,13 +24,21 @@ namespace Model { virtual bool Model::load(char *filename) = 0; virtual void Model::release() = 0; - float* normals; - float* triangles; - float* vertices; - float* textures; + std::vector* normals; + std::vector* triangles; + std::vector* vertices; + std::vector* textureCoordinates; long totalConnectedPoints; long totalConnectedTriangles; }; + template + bool from_string(T& t, + const std::string& s, + std::ios_base& (*f)(std::ios_base&)) + { + std::istringstream iss(s); + return !(iss >> f >> t).fail(); + } } #endif // Model_h__ diff --git a/Obj.cpp b/Obj.cpp index 8e87eaf..89b9692 100644 --- a/Obj.cpp +++ b/Obj.cpp @@ -1,93 +1,75 @@ #include "Obj.h" +#include "Tokenizer.h" namespace Model { bool Obj::load(char* filename) { std::string line; - std::ifstream objFile (filename); - if (objFile.is_open() == false) // we could not open the file + std::ifstream objFile(filename); + if (objFile.is_open() == false) return false; - objFile.seekg (0, std::ios::end); // Go to end of the file, - long fileSize = objFile.tellg(); // get file size - objFile.seekg (0, std::ios::beg); // we'll use this to register memory for our 3d model - - vertices = new float[fileSize]; // Allocate memory for the vertices - triangles = new float[fileSize]; // Allocate memory for the triangles - normals = new float[fileSize]; // Allocate memory for the normals - - int triangle_index = 0; // Set triangle index to zero - int normal_index = 0; // Set normal index to zero - - while (! objFile.eof() ) // Start reading file data - { - getline (objFile,line); // Get line from file - - if (line.c_str()[0] == 'v') // The first character is a v: on this line is a vertex stored. - { - line[0] = ' '; // Set first character to 0. This will allow us to use sscanf - - sscanf(line.c_str(),"%f %f %f ", // Read floats from the line: v X Y Z - &vertices[totalConnectedPoints], - &vertices[totalConnectedPoints+1], - &vertices[totalConnectedPoints+2]); + objFile.seekg (0, std::ios::end); + long fileSize = objFile.tellg(); + objFile.seekg (0, std::ios::beg); + + // TODO make a better guess + vertices->reserve(fileSize); + normals->reserve(fileSize); + triangles->reserve(fileSize); + + int triangle_index = 0; + int normal_index = 0; + + while (! objFile.eof() ) { + getline (objFile,line); + Tokenizer tokenizer(line," "); + while(tokenizer.NextToken()){ + std::string lineType = tokenizer.GetToken(); + if(lineType == "v"){ + parseVertex(tokenizer); + } else if (lineType == "f"){ + parseFace(tokenizer); + totalConnectedTriangles++; + } else if (lineType == "#") { + // Line is a comment + } else { + std::cout << "Unhandled line: " << line << std::endl; + } - totalConnectedPoints += POINTS_PER_VERTEX; // Add 3 to the total connected points + break; } - else if (line.c_str()[0] == 'f') // The first character is an 'f': on this line is a point stored - { - line[0] = ' '; // Set first character to 0. This will allow us to use sscanf - - int vertexNumber[4] = { 0, 0, 0 }; - sscanf(line.c_str(),"%i%i%i", // Read integers from the line: f 1 2 3 - &vertexNumber[0], // First point of our triangle. This is an - &vertexNumber[1], // pointer to our vertices list - &vertexNumber[2] ); // each point represents an X,Y,Z. - - vertexNumber[0] -= 1; // OBJ file starts counting from 1 - vertexNumber[1] -= 1; // OBJ file starts counting from 1 - vertexNumber[2] -= 1; // OBJ file starts counting from 1 - - - /******************************************************************** - * Create triangles (f 1 2 3) from points: (v X Y Z) (v X Y Z) (v X Y Z). - * The vertices contains all verteces - * The triangles will be created using the verteces we read previously - */ - int tCounter = 0; - for (int i = 0; i < POINTS_PER_VERTEX; i++) { - triangles[triangle_index + tCounter ] = vertices[3*vertexNumber[i] ]; - triangles[triangle_index + tCounter +1 ] = vertices[3*vertexNumber[i]+1 ]; - triangles[triangle_index + tCounter +2 ] = vertices[3*vertexNumber[i]+2 ]; - tCounter += POINTS_PER_VERTEX; - } + } + objFile.close(); + triangles->resize(triangles->size()); + normals->resize(normals->size()); + textureCoordinates->resize(textureCoordinates->size()); - /********************************************************************* - * Calculate all normals, used for lighting - */ - float coord1[3] = { triangles[triangle_index], triangles[triangle_index+1],triangles[triangle_index+2]}; - float coord2[3] = {triangles[triangle_index+3],triangles[triangle_index+4],triangles[triangle_index+5]}; - float coord3[3] = {triangles[triangle_index+6],triangles[triangle_index+7],triangles[triangle_index+8]}; - float *norm = calculateNormal( coord1, coord2, coord3 ); + return true; + } - tCounter = 0; - for (int i = 0; i < POINTS_PER_VERTEX; i++) { - normals[normal_index + tCounter ] = norm[0]; - normals[normal_index + tCounter +1] = norm[1]; - normals[normal_index + tCounter +2] = norm[2]; - tCounter += POINTS_PER_VERTEX; - } + void Obj::parseVertex(Tokenizer& tokenizer){ + float f; + while(tokenizer.NextToken()){ + if(from_string(f,tokenizer.GetToken(),std::dec)) + vertices->push_back(f); + else + std::cerr << "Error parsing token into vertex component: " << tokenizer.GetToken() << std::endl; + } + totalConnectedPoints += POINTS_PER_VERTEX; + } - triangle_index += TOTAL_FLOATS_IN_TRIANGLE; - normal_index += TOTAL_FLOATS_IN_TRIANGLE; - totalConnectedTriangles += TOTAL_FLOATS_IN_TRIANGLE; - } else { - std::cout << "Unhandled line: " << line << std::endl; + void Obj::parseFace(Tokenizer& tokenizer){ + int vertexNumber[3] = { 0, 0, 0 }; + + for(int i = 0; i < 3; ++i){ + tokenizer.NextToken(); + if(from_string(vertexNumber[i],tokenizer.GetToken(),std::dec)){ + triangles->push_back(vertices->at( vertexNumber[i]- 1)); } + else + std::cerr << "Error parsing token into face component: " << tokenizer.GetToken() << std::endl; } - objFile.close(); // Close OBJ file - - return true; } void Obj::release() { diff --git a/Obj.h b/Obj.h index 1540e53..a765435 100644 --- a/Obj.h +++ b/Obj.h @@ -10,12 +10,17 @@ */ #include "Model.h" +#include "Tokenizer.h" namespace Model { class Obj : public Model { public: bool Obj::load(char *filename); // Loads the model void Obj::release(); // Release the model + + private: + void parseVertex(Tokenizer& tokenizer); + void parseFace(Tokenizer& tokenizer); }; } diff --git a/Ply.cpp b/Ply.cpp index ab02f1f..0105143 100644 --- a/Ply.cpp +++ b/Ply.cpp @@ -31,7 +31,7 @@ namespace Model { long fileSize = ftell(file); try { - vertices = (float*) malloc (ftell(file)); + // vertices = (float*) malloc (ftell(file)); } catch (char* ) { return false; @@ -39,8 +39,8 @@ namespace Model { if (vertices == NULL) return -1; fseek(file,0,SEEK_SET); - triangles = (float*) malloc(fileSize*sizeof(float)); - normals = (float*) malloc(fileSize*sizeof(float)); +// triangles = (float*) malloc(fileSize*sizeof(float)); +// normals = (float*) malloc(fileSize*sizeof(float)); int i = 0; int temp = 0; @@ -124,7 +124,7 @@ namespace Model { triangles[triangle_index+6] = vertices[3*vertex3]; triangles[triangle_index+7] = vertices[3*vertex3+1]; triangles[triangle_index+8] = vertices[3*vertex3+2]; - + /* float coord1[3] = { triangles[triangle_index], triangles[triangle_index+1],triangles[triangle_index+2]}; float coord2[3] = {triangles[triangle_index+3],triangles[triangle_index+4],triangles[triangle_index+5]}; float coord3[3] = {triangles[triangle_index+6],triangles[triangle_index+7],triangles[triangle_index+8]}; @@ -139,7 +139,7 @@ namespace Model { normals[normal_index+6] = norm[0]; normals[normal_index+7] = norm[1]; normals[normal_index+8] = norm[2]; - +*/ normal_index += 9; triangle_index += 9; diff --git a/Tokenizer.cpp b/Tokenizer.cpp new file mode 100644 index 0000000..855278d --- /dev/null +++ b/Tokenizer.cpp @@ -0,0 +1,47 @@ +#include "Tokenizer.h" +// From user vzczc +// post http://stackoverflow.com/questions/53849/how-do-i-tokenize-a-string-in-c + + +const std::string Tokenizer::DELIMITERS(" \t\n\r"); + +Tokenizer::Tokenizer(const std::string& s) : + m_string(s), + m_offset(0), + m_delimiters(DELIMITERS) {} + +Tokenizer::Tokenizer(const std::string& s, const std::string& delimiters) : +m_string(s), + m_offset(0), + m_delimiters(delimiters) {} + +bool Tokenizer::NextToken() +{ + return NextToken(m_delimiters); +} + +const std::string Tokenizer::GetToken() const{ + return m_token; +} + +bool Tokenizer::NextToken(const std::string& delimiters) +{ + size_t i = m_string.find_first_not_of(delimiters, m_offset); + if (std::string::npos == i) + { + m_offset = m_string.length(); + return false; + } + + size_t j = m_string.find_first_of(delimiters, i); + if (std::string::npos == j) + { + m_token = m_string.substr(i); + m_offset = m_string.length(); + return true; + } + + m_token = m_string.substr(i, j - i); + m_offset = j; + return true; +} \ No newline at end of file diff --git a/Tokenizer.h b/Tokenizer.h new file mode 100644 index 0000000..5978557 --- /dev/null +++ b/Tokenizer.h @@ -0,0 +1,22 @@ +#ifndef Tokenizer_h__ +#define Tokenizer_h__ + +#include +// From user vzczc +// post http://stackoverflow.com/questions/53849/how-do-i-tokenize-a-string-in-c +class Tokenizer { +public: + static const std::string DELIMITERS; + Tokenizer(const std::string& s); + Tokenizer(const std::string& s, const std::string& delimiters); + bool NextToken(); + bool NextToken(const std::string& delimiters); + const std::string GetToken() const; + // void Reset(); +protected: + size_t m_offset; + const std::string m_string; + std::string m_token; + std::string m_delimiters; +}; +#endif // Tokenizer_h__ \ No newline at end of file