167 lines
5.8 KiB
C++
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;
|
|
}
|