167 lines
5.8 KiB
C++

#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;
}