#include #include #include "util.hpp" #include "body.hpp" #include "shaders.hpp" enum class ParserState { PREFIX, VERTEX, FACE, FACE_SKIP, }; bool load_body(Body* out_body, const char* obj_filepath) { Array source; if (!read_file(&source, obj_filepath)) { return false; } size_t num_verts = 0; size_t num_faces = 0; for (int i = 1; i < source.len; i++) { if (source[i] == ' ' && source[i - 1] == 'v') { num_verts++; } else if (source[i] == ' ' && source[i - 1] == 'f') { num_faces++; } } Array verts = { (float*)malloc(sizeof(float) * num_verts * 3), num_verts * 3 }; Array faces = { (int*)malloc(sizeof(int) * num_faces * 3), num_faces*3 }; // Get ready for the parsing loop ParserState state = ParserState::PREFIX; int vert_i = 0; int face_i = 0; int start = 0; for (int i = 1; i < source.len; i++) { switch (state) { case ParserState::PREFIX: if (source[i - 1] == 'v' && source[i] == ' ') { state = ParserState::VERTEX; start = i + 1; } else if (i > 0 && source[i - 1] == 'f' && source[i] == ' ') { state = ParserState::FACE; start = i + 1; } break; case ParserState::VERTEX: if (iswspace(source[i])) { verts[vert_i] = atof(&source[start]); vert_i++; start = i + 1; } break; case ParserState::FACE: if (source[i] == '/') { state = ParserState::FACE_SKIP; faces[face_i] = atoi(&source[start]) - 1; face_i++; } break; case ParserState::FACE_SKIP: if (iswspace(source[i])) { state = ParserState::FACE; start = i + 1; } } if (source[i] == '\n' || source[i] == '\r') { state = ParserState::PREFIX; continue; } } // Need a good validation check here. This is a stand in. if (verts.len == 0 || faces.len == 0) { printf( "Obj file appears incomplete or corrupted. Num verts %zu. Num Faces %zu.\n", verts.len, faces.len); return false; } uint vao, vbo, ebo; vao = 0; vbo = 0; ebo = 0; glGenVertexArrays(1, &vao); glGenBuffers(1, &vbo); glGenBuffers(1, &ebo); glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, verts.len * sizeof(float), verts.data, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, faces.len * sizeof(int), faces.data, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); *out_body = { .pose = glm::mat4(1), .scale = 1.0f, .ebo = ebo, .vao = vao, .vbo = vbo, .shader = 0, .verts = verts, .faces = faces, .color = glm::vec4(0.5, 0.5, 0.5, 1) }; return true; } void draw_body(const Body& b) { use_shader(b.shader); set_uniform(b.shader, "global_t", b.scale*b.pose); set_uniform(b.shader, "color", b.color); glBindVertexArray(b.vao); glDrawElements(GL_TRIANGLES, b.faces.len, GL_UNSIGNED_INT, 0); //glDisableVertexAttribArray(0); } void create_new_sphere(Body* b, float scale) { assert(load_body(b, "Icosphere.obj")); b->shader = shader; b->scale = scale; b->pose = glm::translate(b->pose, glm::vec3(0, 0, 0)); }