#include "model.h" #include "logger.h" bool load_model(Model *model, Render_Data *render_data, string model_filepath, string texture_filepath) { { bool success = load_texture(&model->texture, texture_filepath); if (!success) { log(1, "%s: failed to load texture\n", __FUNCTION__); return false; } } model->gltf_model = new tinygltf::Model(); tinygltf::TinyGLTF gltf_loader; string loader_errors; string loader_warnings; bool result = false; result = gltf_loader.LoadASCIIFromFile(model->gltf_model, &loader_errors, &loader_warnings, model_filepath); if (!loader_warnings.empty()) { log(1, "%s: warnings while loading glTF model:\n%s", __FUNCTION__, loader_warnings.c_str()); } if (!loader_errors.empty()) { log(1, "%s: errors while loading glTF model:\n%s", __FUNCTION__, loader_errors.c_str()); } if (!result) { log(1, "%s error: could not load file '%s'\n", __FUNCTION__, model_filepath.c_str()); return false; } glGenVertexArrays(1, &model->vao); glBindVertexArray(model->vao); create_model_vertex_buffers(model); create_model_index_buffer(model); glBindVertexArray(0); s32 root_node_id = model->gltf_model->scenes.at(0).nodes.at(0); create_root(model->root_node, root_node_id); render_data->triangle_count = get_model_triangle_count(model); return true; } void draw_model(Model *model) { const tinygltf::Primitive& primitives = model->gltf_model->meshes.at(0).primitives.at(0); const tinygltf::Accessor& index_accessor = model->gltf_model->accessors.at(primitives.indices); u32 draw_mode = GL_TRIANGLES; switch (primitives.mode) { case TINYGLTF_MODE_TRIANGLES: draw_mode = GL_TRIANGLES; break; default: log(1, "%s error: unknown draw mode %i\n", __FUNCTION__, draw_mode); break; } bind_texture(&model->texture); glBindVertexArray(model->vao); glDrawElements(draw_mode, index_accessor.count, index_accessor.componentType, nullptr); glBindVertexArray(0); unbind_texture(); } void cleanup_model(Model *model) { glDeleteBuffers(model->vertex_vbo.size(), model->vertex_vbo.data()); glDeleteBuffers(1, &model->vao); glDeleteBuffers(1, &model->index_vbo); cleanup_texture(&model->texture); delete model->gltf_model; } void create_model_vertex_buffers(Model *model) { const tinygltf::Primitive &primitives = model->gltf_model->meshes.at(0).primitives.at(0); model->vertex_vbo.resize(primitives.attributes.size()); for (const auto& attrib : primitives.attributes) { const string attrib_type = attrib.first; const s32 accessor_num = attrib.second; const tinygltf::Accessor &accessor = model->gltf_model->accessors.at(accessor_num); const tinygltf::BufferView &buffer_view = model->gltf_model->bufferViews[accessor.bufferView]; const tinygltf::Buffer &buffer = model->gltf_model->buffers[buffer_view.buffer]; if ((attrib_type.compare("POSITION") != 0) && (attrib_type.compare("NORMAL") != 0) && (attrib_type.compare("TEXCOORD_0") != 0)) { log(1, "%s: skipping attribute type %s\n", __FUNCTION__, attrib_type.c_str()); continue; } s32 data_size = 1; switch(accessor.type) { case TINYGLTF_TYPE_SCALAR: data_size = 1; break; case TINYGLTF_TYPE_VEC2: data_size = 2; break; case TINYGLTF_TYPE_VEC3: data_size = 3; break; case TINYGLTF_TYPE_VEC4: data_size = 4; break; default: log(1, "%s error: accessor %i uses data size %i\n", __FUNCTION__, accessor_num, data_size); break; } u32 data_type = GL_FLOAT; switch(accessor.componentType) { case TINYGLTF_COMPONENT_TYPE_FLOAT: data_type = GL_FLOAT; break; default: log(1, "%s error: accessor %i uses unknown data type %i\n", __FUNCTION__, accessor_num, data_type); break; } glGenBuffers(1, &model->vertex_vbo.at(model->attributes.at(attrib_type))); glBindBuffer(GL_ARRAY_BUFFER, model->vertex_vbo.at(model->attributes.at(attrib_type))); glVertexAttribPointer(model->attributes.at(attrib_type), data_size, data_type, GL_FALSE, 0, (void*) 0); glEnableVertexAttribArray(model->attributes.at(attrib_type)); glBindBuffer(GL_ARRAY_BUFFER, 0); } } void create_model_index_buffer(Model *model) { glGenBuffers(1, &model->index_vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->index_vbo); } void upload_model_vertex_buffers(Model *model) { for (s32 i = 0; i < 3; ++i) { const tinygltf::Accessor& accessor = model->gltf_model->accessors.at(i); const tinygltf::BufferView& buffer_view = model->gltf_model->bufferViews.at(accessor.bufferView); const tinygltf::Buffer& buffer = model->gltf_model->buffers.at(buffer_view.buffer); glBindBuffer(GL_ARRAY_BUFFER, model->vertex_vbo[i]); glBufferData(GL_ARRAY_BUFFER, buffer_view.byteLength, &buffer.data.at(0) + buffer_view.byteOffset, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } } void upload_model_index_buffer(Model *model) { const tinygltf::Primitive& primitives = model->gltf_model->meshes.at(0).primitives.at(0); const tinygltf::Accessor& index_accessor = model->gltf_model->accessors.at(primitives.indices); const tinygltf::BufferView& index_buffer_view = model->gltf_model->bufferViews.at(index_accessor.bufferView); const tinygltf::Buffer& index_buffer = model->gltf_model->buffers.at(index_buffer_view.buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->index_vbo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_buffer_view.byteLength, &index_buffer.data.at(0) + index_buffer_view.byteOffset, GL_STATIC_DRAW); } s32 get_model_triangle_count(Model *model) { const tinygltf::Primitive& primitives = model->gltf_model->meshes.at(0).primitives.at(0); const tinygltf::Accessor& index_accessor = model->gltf_model->accessors.at(primitives.indices); return index_accessor.count; }