summaryrefslogtreecommitdiff
path: root/model.h
diff options
context:
space:
mode:
Diffstat (limited to 'model.h')
-rw-r--r--model.h246
1 files changed, 246 insertions, 0 deletions
diff --git a/model.h b/model.h
new file mode 100644
index 0000000..e7a2843
--- /dev/null
+++ b/model.h
@@ -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;
+}