diff options
Diffstat (limited to 'model.h')
-rw-r--r-- | model.h | 246 |
1 files changed, 246 insertions, 0 deletions
@@ -0,0 +1,246 @@ +#define TINYOBJ_LOADER_C_IMPLEMENTATION +#include "tinyobj_loader_c.h" + +mat4 apply_transform(transform_t transform) +{ + mat4 result = mat4_make_scale(transform.scale); + result = mat4_rotate(result, transform.rotation); + result = mat4_transl(result, transform.position); + return result; +} + +void init_mesh_buffers(mesh_t *mesh) +{ + assert(mesh->vertices); + assert(mesh->nvertices > 0); + + u32 vertices_size = mesh->nvertices*sizeof(vertex_t); + u32 indices_size = mesh->nindices*sizeof(u32); + + glGenVertexArrays(1, &mesh->vao); + glBindVertexArray(mesh->vao); + + glGenBuffers(1, &mesh->vbo); + glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); + glBufferData(GL_ARRAY_BUFFER, vertices_size, mesh->vertices, GL_STATIC_DRAW); + + if (mesh->indices && (mesh->nindices > 0)) { + glGenBuffers(1, &mesh->ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_size, mesh->indices, GL_STATIC_DRAW); + } + + glEnableVertexAttribArray(SHADER_POSITION_LOCATION); + glVertexAttribPointer(SHADER_POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE, + sizeof(vertex_t), (void *)offsetof(vertex_t, position)); + + glEnableVertexAttribArray(SHADER_NORMAL_LOCATION); + glVertexAttribPointer(SHADER_NORMAL_LOCATION, 3, GL_FLOAT, GL_FALSE, + sizeof(vertex_t), (void *)offsetof(vertex_t, normal)); + + glEnableVertexAttribArray(SHADER_TEXCOORDS_LOCATION); + glVertexAttribPointer(SHADER_TEXCOORDS_LOCATION, 2, GL_FLOAT, GL_FALSE, + sizeof(vertex_t), (void *)offsetof(vertex_t, texcoords)); + + glBindVertexArray(0); +} + +mesh_t init_mesh(transform_t transform, i32 nvertices, vertex_t *vertices, i32 nindices, u32 *indices) +{ + mesh_t mesh = {0}; + mesh.transform = transform; + mesh.nvertices = nvertices; + mesh.vertices = vertices; + mesh.nindices = nindices; + mesh.indices = indices; + init_mesh_buffers(&mesh); + return mesh; +} + +void clear_mesh(mesh_t *mesh) +{ + glBindVertexArray(mesh->vao); + glDisableVertexAttribArray(SHADER_POSITION_LOCATION); + glDisableVertexAttribArray(SHADER_NORMAL_LOCATION); + glDisableVertexAttribArray(SHADER_TEXCOORDS_LOCATION); + + glBindVertexArray(0); + glDeleteVertexArrays(1, &mesh->vao); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &mesh->vbo); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &mesh->ebo); +} + +void add_mesh_texture(mesh_t *mesh, texture_t texture) +{ + if (!mesh) { + printf("error: can't add texture to a null mesh :|\n"); + return; + } + + if (mesh->ntextures+1 >= MAX_TEXTURE_PER_MESH) { + printf("warning: \"%s\" texture limit reached: %d\n", texture.name, MAX_TEXTURE_PER_MESH); + return; + } + + mesh->textures[mesh->ntextures++] = texture; +} + +mesh_t gen_quad_mesh(arena_t *arena, transform_t transform, f32 width, f32 height) +{ + assert(width > 0); + assert(height > 0); + + i32 nvertices = 4; + vertex_t *vertices = push_arena(arena, nvertices*sizeof(vertex_t)); + vertices[0] = (vertex_t){{-width/2.0f, -height/2.0f, 0.0f}, V3_ZERO, {0.0f, 0.0f}}; + vertices[1] = (vertex_t){{-width/2.0f, height/2.0f, 0.0f}, V3_ZERO, {0.0f, height}}; + vertices[2] = (vertex_t){{ width/2.0f, -height/2.0f, 0.0f}, V3_ZERO, {width, 0.0f}}; + vertices[3] = (vertex_t){{ width/2.0f, height/2.0f, 0.0f}, V3_ZERO, {width, height}}; + + i32 nindices = 6; + u32 *indices = push_arena(arena, nindices*sizeof(u32)); + indices[0] = 0; + indices[1] = 1; + indices[2] = 3; + indices[3] = 0; + indices[4] = 2; + indices[5] = 3; + + mesh_t mesh = init_mesh(transform, nvertices, vertices, nindices, indices); + + return mesh; +} + +mesh_t gen_circle_mesh(arena_t *arena, transform_t transform, f32 radius, i32 nvertices) +{ + if (nvertices < 3) + nvertices = 3; + + vertex_t *vertices = push_arena(arena, nvertices*sizeof(vertex_t)); + + f32 angle = 0.0f; + f32 dangle = 2.0f*F_PI/nvertices; + for (i32 i = 0; i < nvertices; ++i, angle += dangle) + vertices[i] = (vertex_t){{fcos(angle)*radius, fsin(angle)*radius, 0.0f}, V3_ZERO, V2_ZERO}; + + i32 nindices = nvertices*3; + u32 *indices = push_arena(arena, nindices*sizeof(u32)); + for (i32 i = 0, vi = 1; i < nindices; i += 3, vi++) { + indices[i] = 0; + indices[i+1] = vi; + indices[i+2] = ((vi+1 == nvertices) ? 1 : vi+1); + } + + mesh_t mesh = init_mesh(transform, nvertices, vertices, nindices, indices); + + return mesh; +} + +model_t init_model(transform_t transform, i32 nmeshes, mesh_t *meshes) +{ + model_t model = { + transform, + nmeshes, + meshes, + }; + return model; +} + +void read_file_tinyobj(void* ctx, const char* filename, const i32 is_mtl, const char* obj_filename, char** data, u64* len) +{ + if (is_mtl) + printf("info: is_mtl is set (don't use it right now)\n"); + if (obj_filename) + printf("info: obj_filename is \"%s\"\n", obj_filename); + if (!filename) { + printf("error: obj filename is zero\n"); + *data = 0; + *len = 0; + return; + } + + arena_t *arena = (arena_t *)ctx; + *len = sys_read_file(arena, data, filename); +} + +model_t load_model_obj(arena_t *arena, transform_t transform, const char *filename) +{ + tinyobj_attrib_t attrib; + u64 nshapes; + tinyobj_shape_t *shapes; + u64 nmaterials; + tinyobj_material_t *materials; + + u32 flags = TINYOBJ_FLAG_TRIANGULATE; + i32 status = tinyobj_parse_obj(&attrib, &shapes, &nshapes, &materials, &nmaterials, + filename, read_file_tinyobj, arena, flags); + + model_t model = {0}; + if (status != TINYOBJ_SUCCESS) { + printf("error: failed to parse \"%s\"\n", filename); + return model; + } + + u64 ntriangles = attrib.num_face_num_verts; + u64 face_offset = 0; + + u64 nvertices = ntriangles*3; + vertex_t *vertices = push_arena(arena, sizeof(vertex_t)*nvertices); + + u64 nindices = ntriangles*3; + u32 *indices = push_arena(arena, sizeof(u32)*nindices); + + i32 vertex_count = 0, index_count = 0, index_index = 0; + for (u32 i = 0; i < attrib.num_face_num_verts; ++i) { + assert(attrib.face_num_verts[i]%3 == 0); + assert(attrib.face_num_verts[i]/3 > 0); + assert(attrib.num_texcoords); + + tinyobj_vertex_index_t idx; + for (i32 j = 0; j < 3; ++j) { + idx = attrib.faces[face_offset+j]; + assert(idx.v_idx >= 0); + v3 position = { + attrib.vertices[3*idx.v_idx+0], + attrib.vertices[3*idx.v_idx+1], + attrib.vertices[3*idx.v_idx+2] + }; + + assert(idx.vn_idx < (i32)attrib.num_normals); + v3 normal = { + attrib.normals[3*idx.vn_idx+0], + attrib.normals[3*idx.vn_idx+1], + attrib.normals[3*idx.vn_idx+2] + }; + + assert(idx.vt_idx < (i32)attrib.num_texcoords); + v2 texcoords = { + attrib.texcoords[2*idx.vt_idx+0], + attrib.texcoords[2*idx.vt_idx+1] + }; + + vertices[vertex_count++] = (vertex_t){position, normal, texcoords}; + indices[index_index++] = index_count++; + } + + face_offset += 3; + } + + i32 nmeshes = 1; + mesh_t *meshes = push_arena(arena, sizeof(mesh_t)*nmeshes); + *meshes = init_mesh(DEFAULT_TRANSFORM, nvertices, vertices, nindices, indices); + + tinyobj_attrib_free(&attrib); + tinyobj_shapes_free(shapes, nshapes); + tinyobj_materials_free(materials, nmaterials); + + model = init_model(transform, nmeshes, meshes); + + printf("info: \"%s\" loaded successfully\n", filename); + + return model; +} |