#include "Mesh.hpp" #include // fscanf #include // strcmp #include // atof Mesh::Mesh() { vbo = vao = tex = 0; flags = 0; mode = GL_STATIC_DRAW; } Mesh::Mesh(Vec3 *in_vertices, int v_count, Vec2 *in_uvs, int uv_count, Vec3 *in_normals, int n_count) { loadArrays(in_vertices, v_count, in_uvs, uv_count, in_normals, n_count); } Mesh::~Mesh() { if (flags & MESH_BUILT) destroyMesh(); } int Mesh::loadObj(const char *filename) { std::vector temp_vertices; std::vector temp_uvs; std::vector temp_normals; std::vector vertex_indices; std::vector uv_indices; std::vector normal_indices; int ret; #ifdef _WIN32 FILE *file; fopen_s(&file, filename, "r"); #else FILE *file = fopen(filename, "r"); #endif if (file == NULL) { // TODO: error report return 1; } char word[32]; #ifdef _WIN32 while ((ret = fscanf_s(file, "%s ", word)) != EOF) { #else while ((ret = fscanf(file, "%s ", word)) != EOF) { #endif if (strcmp(word, "v") == 0) { // vertices // "x y z w" as floats, with "w" being optional Vec3 vec; // our vertex char word[32]; char ch; int pos = 0, w_i = 0; while ((ch = fgetc(file)) != EOF) { if (ch == ' ' || ch == '\n') { if (pos == 0) { // x word[w_i] = '\0'; vec.x = (float)atof(word); } else if (pos == 1) { // y word[w_i] = '\0'; vec.y = (float)atof(word); } else if (pos == 2) { // z word[w_i] = '\0'; vec.z = (float)atof(word); /*} else if (pos == 3) { // w word[w_i] = '\0'; vec.w = atof(word);*/ } pos++; w_i = 0; } if (ch == '\n') break; word[w_i++] = ch; } temp_vertices.push_back(vec); } else if (strcmp(word, "vt") == 0) { // texture coordinates // "u v [w]" as floats, with "w" being optional Vec2 vec; // our texture coord char word[32]; char ch; int pos = 0, w_i = 0; while ((ch = fgetc(file)) != EOF) { if (ch == ' ' || ch == '\n') { if (pos == 0) { // x word[w_i] = '\0'; vec.x = (float)atof(word); } else if (pos == 1) { // y word[w_i] = '\0'; vec.y = (float)atof(word); /*} else if (pos == 3) { // w word[w_i] = '\0'; vec.w = atof(word);*/ } pos++; w_i = 0; } if (ch == '\n') break; word[w_i++] = ch; } temp_uvs.push_back(vec); } else if (strcmp(word, "vn") == 0) { // normals // "x y z" as floats Vec3 vec; // our normal char word[32]; char ch; int pos = 0, w_i = 0; while ((ch = fgetc(file)) != EOF) { if (ch == ' ' || ch == '\n') { if (pos == 0) { // x word[w_i] = '\0'; vec.x = (float)atof(word); } else if (pos == 1) { // y word[w_i] = '\0'; vec.y = (float)atof(word); } else if (pos == 2) { // z word[w_i] = '\0'; vec.z = (float)atof(word); /*} else if (pos == 3) { // w word[w_i] = '\0'; vec.w = atof(word);*/ } pos++; w_i = 0; } if (ch == '\n') break; word[w_i++] = ch; } temp_normals.push_back(vec); /*} else if (strcmp(word, "vp") == 0) { // parameter space vertices // "u v w", with 'v' and 'w' being optional*/ } else if (strcmp(word, "f") == 0) { // face definitions // "v1 v2 v3" for plain vertex indices // "v1/vt1 v2/vt2 v3/vt3" for vertex/texture-coordinate indices // "v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3" for vertex/texture-coordinate/normal indices // "v1//vn1 v2//vn2 v3//vn3" for vertex/normal indices char word[32]; char ch; int w_i = 0, mode = 0; // read in our faces into our index vectors while ((ch = fgetc(file)) != EOF) { if (ch == ' ' || ch == '\n') { word[w_i] = '\0'; if (mode == 0) { // was in vertex, now in texture-coords vertex_indices.push_back(atoi(word)); } else if (mode == 1) { // was in texture-coords, now in normal uv_indices.push_back(atoi(word)); } else if (mode == 2) { // was in normal, write it out normal_indices.push_back(atoi(word)); } w_i = 0; mode = 0; // reset our mode } else if (ch == '/') { word[w_i] = '\0'; if (mode == 0) { // was in vertex, now in texture-coords vertex_indices.push_back(atoi(word)); } else if (mode == 1) { // was in texture-coords, now in normal if (w_i > 0) uv_indices.push_back(atoi(word)); } mode++; w_i = 0; } else { word[w_i++] = ch; } if (ch == '\n') break; } //} else if (strcmp(word, "#") == 0) { // comment //} else if (strcmp(word, "o") == 0) { // object name //} else if (strcmp(word, "g") == 0) { // group name //} else if (Strmcpmp(word, "s") == 0) { // smooth // "s 1" or "s off" } else { // ergo, newline noms char ch; while ((ch = fgetc(file)) != EOF) { if (ch == '\n') break; } } } fclose(file); // we're done, let's convert our face-derived indices to our actual mesh int i; int indices = vertex_indices.size(); // TODO: vertex index access should be checked for validity (>= 0 < temp_vertices.size()) for (i = 0; i < indices; i++) { Vec3 vertex = temp_vertices[vertex_indices[i]-1]; vertices.push_back(vertex); } indices = uv_indices.size(); for (i = 0; i < indices; i++) { printf("%d/%d\n", i, indices); printf("%d\n", uv_indices[i]); Vec2 uv = temp_uvs[uv_indices[i]-1]; uvs.push_back(uv); } indices = normal_indices.size(); for (i = 0; i < indices; i++) { Vec3 normal = temp_normals[normal_indices[i]-1]; normals.push_back(normal); } flags |= MESH_LOADED; return 0; } int Mesh::loadArrays(Vec3 *in_vertices, int v_count, Vec2 *in_uvs, int uv_count, Vec3 *in_normals, int n_count) { if (v_count > 0) { vertices.assign(in_vertices, in_vertices + v_count); flags |= MESH_LOADED; } if (uv_count > 0) { uvs.assign(in_uvs, in_uvs + uv_count); } if (n_count > 0) { normals.assign(in_normals, in_normals + n_count); } return 0; } int Mesh::buildMesh() { if (!(flags & MESH_LOADED)) return 1; if (flags & MESH_BUILT) destroyMesh(); // generate our vertex buffer object from our given points glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(Vec3), &vertices[0], mode); flags |= MESH_BUILT; return 0; } int Mesh::destroyMesh() { glDeleteBuffers(1, &vbo); //glDeleteVertexArrays(1, &vao); flags &= ~MESH_BUILT; return 0; }