#include "Model.h" Model::Model(const char* path) { Loadobj(path, Vertices, Normals, TextureCoords); CreateBuffers(Vertices, Normals, TextureCoords); } Model::Model(OBJ &obj) { OBJ::MaterialInfo* currentMaterial = nullptr; TextureGroup* currentTexGroup = nullptr; int index = 0; for (auto face : obj.Faces) { if (face.Material == nullptr) { LOG_ERROR("Missing material for .obj file \"%s\"", obj.Path().string().c_str()); return; } // New material if (face.Material != currentMaterial) { currentMaterial = face.Material; // Load texture std::shared_ptr texture = std::make_shared(currentMaterial->TextureFile); // TODO: Load material parameters // Create new texture group (start index of new group is upcoming index) TextureGroup texGroup = { texture, index, index }; TextureGroups.push_back(texGroup); currentTexGroup = &TextureGroups.back(); } // Face definitions for (auto faceDef : face.Definitions) { glm::vec3 vertex; std::tie(vertex.x, vertex.y, vertex.z) = obj.Vertices.at(faceDef.VertexIndex - 1); Vertices.push_back(vertex); if (faceDef.NormalIndex != 0) { glm::vec3 normal; std::tie(normal.x, normal.y, normal.z) = obj.Normals.at(faceDef.NormalIndex - 1); Normals.push_back(normal); } if (faceDef.TextureCoordIndex != 0) { glm::vec2 texCoord; // TODO: W-coord? std::tie(texCoord.x, texCoord.y, std::ignore) = obj.TextureCoords.at(faceDef.TextureCoordIndex - 1); TextureCoords.push_back(texCoord); } currentTexGroup->EndIndex = index; index++; } } if (Vertices.size() > 0) { CreateBuffers(Vertices, Normals, TextureCoords); } } bool Model::Loadobj(const char* path, std::vector & out_vertices, std::vector &out_normals, std::vector & out_TextureCoords) { std::vector< unsigned int > vertexIndices, TextureCoordIndices, normalIndices; std::vector< glm::vec3 > temp_vertices; std::vector< glm::vec2 > temp_TextureCoords; std::vector< glm::vec3 > temp_normals; FILE * file = fopen(path, "r"); LOG_INFO("Loading .obj file"); if( file == NULL ) { LOG_INFO("Load .obj file: failed"); return false; } char lineHeader[512]; while(true) { //read the first word of the line int res = fscanf(file, "%s", lineHeader); if( res == EOF ) // EOF - End Of File { for( unsigned int i = 0; i < vertexIndices.size(); i++ ) { unsigned int vertexIndex = vertexIndices[i]; glm::vec3 vertex = temp_vertices[ vertexIndex-1]; out_vertices.push_back(vertex); } for( unsigned int i = 0; i < TextureCoordIndices.size(); i++ ) { unsigned int TextureCoordIndex = TextureCoordIndices[i]; glm::vec2 TextureCoord = temp_TextureCoords[ TextureCoordIndex-1]; out_TextureCoords.push_back(TextureCoord); } for( unsigned int i = 0; i < normalIndices.size(); i++ ) { unsigned int normalIndex = normalIndices[i]; glm::vec3 normal = temp_normals[ normalIndex-1]; out_normals.push_back(normal); } LOG_INFO("Model Loaded\n"); break; } if( strcmp( lineHeader, "v" ) == 0 ) // vertex { glm::vec3 vertex; fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z); temp_vertices.push_back(vertex); } else if ( strcmp( lineHeader, "vt" ) == 0 ) // texture coordinate { glm::vec2 TextureCoord; fscanf(file, "%f %f\n", &TextureCoord.x, &TextureCoord.y ); temp_TextureCoords.push_back(TextureCoord); } else if( strcmp( lineHeader, "vn" ) == 0 ) // normal { glm::vec3 normal; fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z ); temp_normals.push_back(normal); } else if( strcmp( lineHeader, "f" ) == 0) { unsigned int vertexIndex[3], TextureCoordIndex[3], normalIndex[3]; int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &TextureCoordIndex[0], &normalIndex[0], &vertexIndex[1], &TextureCoordIndex[1], &normalIndex[1],&vertexIndex[2], &TextureCoordIndex[2], &normalIndex[2]); if(matches != 9) { printf("File can't be read, try exporting with other options\n"); return false; } vertexIndices.push_back(vertexIndex[0]); vertexIndices.push_back(vertexIndex[1]); vertexIndices.push_back(vertexIndex[2]); TextureCoordIndices.push_back(TextureCoordIndex[0]); TextureCoordIndices.push_back(TextureCoordIndex[1]); TextureCoordIndices.push_back(TextureCoordIndex[2]); normalIndices.push_back(normalIndex[0]); normalIndices.push_back(normalIndex[1]); normalIndices.push_back(normalIndex[2]); } else if ( strcmp( lineHeader, "mtllib" ) == 0 ) { char fileName[512]; fscanf(file, "%s\n", &fileName); FILE * mtlfile = fopen(fileName, "r"); LOG_INFO("Loading .mtl file"); if( mtlfile == NULL ) { LOG_INFO("Load .mtl file: failed"); return false; } char mtllineHeader[512]; //read the first word of the line while (true) { int mtlres = fscanf(mtlfile, "%s", mtllineHeader); if( mtlres == EOF ) // EOF - End Of File { break; } else if ( strcmp( mtllineHeader, "map_Kd" ) == 0 ) { char textureFileName[512]; fscanf(mtlfile, "%s", textureFileName); texture.push_back(std::make_shared(textureFileName)); LOG_INFO("Texture Loaded\n"); } } } } return true; } void Model::CreateBuffers( std::vector vertices, std::vector normals, std::vectortextureCoords) { LOG_INFO("Generating VertexBuffer"); glGenBuffers(1, &VertexBuffer); if (vertices.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW); GLERROR("GLEW: BufferFail, VertexBuffer"); } else { LOG_WARNING("Created empty vertex buffer!"); } LOG_INFO("Generating NormalBuffer"); glGenBuffers(1, &NormalBuffer); if (normals.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, NormalBuffer); glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW); GLERROR("GLEW: BufferFail, NormalBuffer"); } else { LOG_WARNING("Created empty normal buffer!"); } LOG_INFO("Generating textureCoordBuffer"); glGenBuffers(1, &TextureCoordBuffer); if (textureCoords.size() > 0) { glBindBuffer(GL_ARRAY_BUFFER, TextureCoordBuffer); glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), &textureCoords[0], GL_STATIC_DRAW); GLERROR("GLEW: BufferFail, TextureCoordBuffer"); } else { LOG_WARNING("Created empty texture coordinate buffer!"); } glGenVertexArrays(1, &VAO); glBindVertexArray(VAO); GLERROR("GLEW: BufferFail4"); glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); GLERROR("GLEW: BufferFail5"); glBindBuffer(GL_ARRAY_BUFFER, NormalBuffer); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); GLERROR("GLEW: BufferFail5"); glBindBuffer(GL_ARRAY_BUFFER, TextureCoordBuffer); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); GLERROR("GLEW: BufferFail5"); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); GLERROR("GLEW: BufferFail5"); }