diff options
author | 2025-02-07 11:27:18 -0500 | |
---|---|---|
committer | 2025-02-07 11:27:18 -0500 | |
commit | 4da7be39827ea5888ef9c97b1aadf61b0d76347c (patch) | |
tree | 15d0ff8f8bcb0e871efb1b2e65c2bc8d07b17565 /mons_gltf/src |
initial commit (lol)
Diffstat (limited to 'mons_gltf/src')
-rw-r--r-- | mons_gltf/src/gltf.c | 549 |
1 files changed, 549 insertions, 0 deletions
diff --git a/mons_gltf/src/gltf.c b/mons_gltf/src/gltf.c new file mode 100644 index 0000000..10f177c --- /dev/null +++ b/mons_gltf/src/gltf.c @@ -0,0 +1,549 @@ +#include "gltf.h" +#include <stdlib.h> +#include <stdio.h> +#include <libgen.h> +#include <string.h> +#include "json.h" +#include "transform.h" +#include "mons_math/vec3.h" +#include "mons_math/quat.h" +#include "vertex.h" +#include "mesh.h" +#include "texture.h" +#include "image.h" +#include "qoi.h" +#include "model.h" +#include "shader.h" + +// TODO: Morph Targets +// TODO: Skins + +typedef enum mons_gltf_buffer_view_target { + MONS_GLTF_BUFFER_VIEW_ARRAY_BUFFER = 34962, + MONS_GLTF_BUFFER_VIEW_ELEMENT_ARRAY_BUFFER = 34963, +} mons_gltf_buffer_view_target; + +typedef struct mons_gltf_buffer_view { + int buffer_index; + int byte_length; + int byte_offset; + int byte_stride; + mons_gltf_buffer_view_target target; +} mons_gltf_buffer_view; + +typedef enum mons_gltf_accessor_component_type { + MONS_GLTF_ACCESSOR_BYTE = 5120, + MONS_GLTF_ACCESSOR_UNSIGNED_BYTE = 5121, + MONS_GLTF_ACCESSOR_SHORT = 5122, + MONS_GLTF_ACCESSOR_UNSIGNED_SHORT = 5123, + MONS_GLTF_ACCESSOR_UNSIGNED_INT = 5125, + MONS_GLTF_ACCESSOR_FLOAT = 5126, +} mons_gltf_accessor_component_type; + +typedef enum mons_gltf_accessor_type { + MONS_GLTF_ACCESSOR_SCALAR = 1, + MONS_GLTF_ACCESSOR_VEC2 = 2, + MONS_GLTF_ACCESSOR_VEC3 = 3, + MONS_GLTF_ACCESSOR_VEC4 = 4, + MONS_GLTF_ACCESSOR_MAT2 = 4, + MONS_GLTF_ACCESSOR_MAT3 = 9, + MONS_GLTF_ACCESSOR_MAT4 = 16, +} mons_gltf_accessor_type; + +typedef struct mons_gltf_accessor { + int buffer_view_index; + int byte_offset; + mons_gltf_accessor_component_type component_type; + int count; + float *min; + float *max; + mons_gltf_accessor_type type; +} mons_gltf_accessor; + +typedef enum mons_gltf_primitive_mode { + MONS_GLTF_MODE_POINTS, + MONS_GLTF_MODE_LINES, + MONS_GLTF_MODE_LINE_LOOP, + MONS_GLTF_MODE_LINE_STRIP, + MONS_GLTF_MODE_TRIANGLES, + MONS_GLTF_MODE_TRIANGLE_STRIP, + MONS_GLTF_MODE_TRIANGLE_FAN, +} mons_gltf_primitive_mode; + +typedef struct mons_gltf_primitive { + mons_hashmap attributes; + int indices_accessor; + int material; + mons_gltf_primitive_mode mode; +} mons_gltf_primitive; + +typedef struct mons_gltf_mesh { + mons_gltf_primitive *primitives; +} mons_gltf_mesh; + +typedef struct mons_gltf_texture { + int sampler_index; + int source_index; +} mons_gltf_texture; + +typedef enum mons_gltf_sampler_filter { + MONS_SAMPLER_NEAREST = 9728, + MONS_SAMPLER_LINEAR = 9729, + MONS_SAMPLER_NEAREST_MIPMAP_NEAREST = 9984, + MONS_SAMPLER_LINEAR_MIPMAP_NEAREST = 9985, + MONS_SAMPLER_NEAREST_MIPMAP_LINEAR = 9986, + MONS_SAMPLER_LINEAR_MIPMAP_LINEAR = 9987, +} mons_gltf_sampler_filter; + +typedef enum mons_gltf_sampler_wrapmode { + MONS_SAMPLER_CLAMP_TO_EDGE = 33071, + MONS_SAMPLER_MIRRORED_REPEAT = 33648, + MONS_SAMPLER_REPEAT = 10497, +} mons_gltf_sampler_wrapmode; + +typedef struct mons_gltf_sampler { + mons_gltf_sampler_filter mag_filter; + mons_gltf_sampler_filter min_filter; + mons_gltf_sampler_wrapmode wrap_s; + mons_gltf_sampler_wrapmode wrap_t; +} mons_gltf_sampler; + +typedef struct mons_gltf_material { + int base_color_texture_index; + int normal_texture_index; + int metallic_roughness_texture_index; +} mons_gltf_material; + +int mons_load_gltf(char *path, mons_program shader, mons_model **out, int *count) { + + FILE *stream = fopen(path, "r"); + // Read JSON into memory + fseek(stream, 0L, SEEK_END); + unsigned long len = ftell(stream); + char *json_buffer = malloc(len); + rewind(stream); + fread(json_buffer, 1, len, stream); + fclose(stream); + mons_json_value json; + if (mons_json_parse(json_buffer, &json) == EXIT_FAILURE) { + printf("Failed to parse JSON\n"); + return EXIT_FAILURE; + } + + mons_json_value asset_info; + mons_json_get_value(json, "asset", &asset_info); + char *asset_info_str = mons_json_to_string(asset_info); + printf("Loading GLTF Asset: %s\n", asset_info_str); + free(asset_info_str); + + mons_json_array gltf_nodes_array; + mons_json_get_array(json, "nodes", &gltf_nodes_array); + printf("GLTF Node Count: %d\n", gltf_nodes_array.len); + for (int i = 0; i < gltf_nodes_array.len; i++) { + mons_json_value node_info = gltf_nodes_array.values[i]; + char *name; + mons_json_get_string(node_info, "name", &name); + printf("\t%d: %s\n", i, name); + mons_transform transform = MONS_TRANSFORM_IDENTITY; + mons_json_array node_transform_matrix_json; + if (mons_json_get_array(node_info, "matrix", + &node_transform_matrix_json) == EXIT_SUCCESS) { + for (int j = 0; j < node_transform_matrix_json.len; j++) { + *(((float *)&transform) + j) = + node_transform_matrix_json.values[j].data.number; + } + } else { + + mons_vec3 translation = MONS_VEC3_ZERO; + mons_vec3 scale = MONS_VEC3_ONE; + mons_quat rotation = MONS_QUAT_IDENTITY; + mons_json_array node_translation_json; + mons_json_array node_rotation_json; + mons_json_array node_scale_json; + int has_translation = + (mons_json_get_array(node_info, "translation", + &node_translation_json) == EXIT_SUCCESS); + int has_rotation = + (mons_json_get_array(node_info, "rotation", + &node_rotation_json) == EXIT_SUCCESS); + int has_scale = + (mons_json_get_array(node_info, "scale", + &node_translation_json) == EXIT_SUCCESS); + + if (has_translation) { + for (int j = 0; j < node_translation_json.len; j++) { + *(((float *)&translation) + j) = + node_translation_json.values[j].data.number; + } + printf("TRANSLATION: %f, %f, %f\n", translation.x, + translation.y, translation.z); + } + if (has_rotation) { + printf("ROTATION\n"); + for (int j = 0; j < node_rotation_json.len; j++) { + *(((float *)&rotation) + j) = + node_rotation_json.values[j].data.number; + } + } + if (has_scale) { + printf("SCALE\n"); + for (int j = 0; j < node_scale_json.len; j++) { + *(((float *)&scale) + j) = + node_scale_json.values[j].data.number; + } + } + if (has_scale || has_rotation || has_translation) { + transform = (mons_transform) { + translation, + scale, + rotation, + }; + } + } + } + + mons_json_array gltf_scenes_array; + mons_json_get_array(json, "scenes", &gltf_scenes_array); + printf("GLTF Scene Count: %d\n", gltf_scenes_array.len); + for (int i = 0; i < gltf_scenes_array.len; i++) { + mons_json_value scene_info = gltf_scenes_array.values[i]; + char *name; + mons_json_get_string(scene_info, "name", &name); + printf("\t%d: %s\n", i, name); + mons_json_array scene_nodes_array; + mons_json_get_array(scene_info, "nodes", &scene_nodes_array); + printf("\t%d Nodes:\n", scene_nodes_array.len); + for (int j = 0; j < scene_nodes_array.len; j++) { + int node_index = scene_nodes_array.values[j].data.number; + printf("\t\t%d\n", node_index); + } + } + + mons_json_array gltf_buffers_array; + mons_json_get_array(json, "buffers", &gltf_buffers_array); + printf("GLTF Buffer Count: %d\n", gltf_buffers_array.len); + FILE **buffers = calloc(gltf_buffers_array.len, sizeof(FILE *)); + for (int i = 0; i < gltf_buffers_array.len; i++) { + mons_json_value buffer_info = gltf_buffers_array.values[i]; + char *buffer_uri; + mons_json_get_string(buffer_info, "uri", &buffer_uri); + char *path_copy = strdup(path); + char *base_path = dirname(path_copy); + char *full_buffer_path = + calloc(strlen(base_path) + strlen(buffer_uri) + 2, 1); + snprintf(full_buffer_path, strlen(base_path) + strlen(buffer_uri) + 2, + "%s/%s", base_path, buffer_uri); + printf("\t%d: %s\n", i, full_buffer_path); + buffers[i] = fopen(full_buffer_path, "rb"); + if (buffers[i] == NULL) { + printf("Failed to open buffer for reading\n"); + } + free(path_copy); + } + + mons_json_array gltf_buffer_views_array; + mons_json_get_array(json, "bufferViews", &gltf_buffer_views_array); + printf("GLTF Buffer View Count: %d\n", gltf_buffer_views_array.len); + mons_gltf_buffer_view *buffer_views = + calloc(gltf_buffer_views_array.len, sizeof(mons_gltf_buffer_view)); + for (int i = 0; i < gltf_buffer_views_array.len; i++) { + mons_json_value buffer_view_info = gltf_buffer_views_array.values[i]; + mons_json_get_int(buffer_view_info, "buffer", + &buffer_views[i].buffer_index); + mons_json_get_int(buffer_view_info, "byteLength", + &buffer_views[i].byte_length); + mons_json_get_int(buffer_view_info, "byteOffset", + &buffer_views[i].byte_offset); + mons_json_get_int(buffer_view_info, "byteStride", + &buffer_views[i].byte_stride); + mons_json_get_int(buffer_view_info, "target", + (int *)(&buffer_views[i].target)); + printf("%d: %d bytes @ %d+%d, type %d, stride %d\n", i, + buffer_views[i].byte_length, buffer_views[i].buffer_index, + buffer_views[i].byte_offset, buffer_views[i].target, + buffer_views[i].byte_stride); + } + + mons_json_array gltf_accessors_array; + mons_json_get_array(json, "accessors", &gltf_accessors_array); + printf("GLTF Accessor Count: %d\n", gltf_accessors_array.len); + mons_gltf_accessor *accessors = + calloc(gltf_accessors_array.len, sizeof(mons_gltf_accessor)); + for (int i = 0; i < gltf_accessors_array.len; i++) { + mons_json_value accessor_info = gltf_accessors_array.values[i]; + mons_json_get_int(accessor_info, "bufferView", + &accessors[i].buffer_view_index); + mons_json_get_int(accessor_info, "byteOffset", + &accessors[i].byte_offset); + mons_json_get_int(accessor_info, "componentType", + (int *)(&accessors[i].component_type)); + mons_json_get_int(accessor_info, "count", &accessors[i].count); + char *accessor_type; + mons_json_get_string(accessor_info, "type", &accessor_type); + if (strcmp(accessor_type, "SCALAR") == 0) { + accessors[i].type = MONS_GLTF_ACCESSOR_SCALAR; + } else if (strcmp(accessor_type, "VEC2") == 0) { + accessors[i].type = MONS_GLTF_ACCESSOR_VEC2; + } else if (strcmp(accessor_type, "VEC3") == 0) { + accessors[i].type = MONS_GLTF_ACCESSOR_VEC3; + } else if (strcmp(accessor_type, "VEC4") == 0) { + accessors[i].type = MONS_GLTF_ACCESSOR_VEC4; + } else if (strcmp(accessor_type, "MAT2") == 0) { + accessors[i].type = MONS_GLTF_ACCESSOR_MAT2; + } else if (strcmp(accessor_type, "MAT3") == 0) { + accessors[i].type = MONS_GLTF_ACCESSOR_MAT3; + } else if (strcmp(accessor_type, "MAT4") == 0) { + accessors[i].type = MONS_GLTF_ACCESSOR_MAT4; + } + mons_json_array min_array; + if (mons_json_get_array(accessor_info, "min", &min_array) == + EXIT_SUCCESS) { + accessors[i].min = calloc(accessors[i].type, sizeof(float)); + for (int j = 0; j < accessors[i].type; j++) { + accessors[i].min[j] = min_array.values[j].data.number; + } + } + mons_json_array max_array; + if (mons_json_get_array(accessor_info, "max", &max_array) == + EXIT_SUCCESS) { + accessors[i].max = calloc(accessors[i].type, sizeof(float)); + for (int j = 0; j < accessors[i].type; j++) { + accessors[i].max[j] = max_array.values[j].data.number; + } + } + printf("%d: %d %d-component elements @ %d+%d\n", i, accessors[i].count, + accessors[i].type, accessors[i].buffer_view_index, + accessors[i].byte_offset); + if (accessors[i].min != NULL) { + printf("\tMin: ["); + for (int j = 0; j < accessors[i].type; j++) { + printf("%f", accessors[i].min[j]); + if (j + 1 < accessors[i].type) { + printf(", "); + } else { + printf("]\n"); + } + } + } + if (accessors[i].max != NULL) { + printf("\tMax: ["); + for (int j = 0; j < accessors[i].type; j++) { + printf("%f", accessors[i].max[j]); + if (j + 1 < accessors[i].type) { + printf(", "); + } else { + printf("]\n"); + } + } + } + } + + mons_json_array gltf_images_array; + mons_json_get_array(json, "images", &gltf_images_array); + printf("GLTF Image Count: %d\n", gltf_images_array.len); + mons_image *images = calloc(gltf_images_array.len, sizeof(mons_image)); + for (int i = 0; i < gltf_images_array.len; i++) { + mons_json_value image_info = gltf_images_array.values[i]; + char *mimetype = NULL; + mons_json_get_string(image_info, "mimeType", &mimetype); + int buffer_view_index; + FILE *image_buffer = NULL; + if (mons_json_get_int(image_info, "bufferView", &buffer_view_index) == + EXIT_SUCCESS) { + if (mimetype == NULL) { + printf( + "Cannot load image from buffer view, missing mimetype\n"); + continue; + } + mons_gltf_buffer_view image_buffer_view = + buffer_views[buffer_view_index]; + image_buffer = buffers[image_buffer_view.buffer_index]; + } + char *uri = NULL; + if(mons_json_get_string(image_info, "uri", &uri) == EXIT_SUCCESS) { + char *path_copy = strdup(path); + char *base_path = dirname(path_copy); + char *full_buffer_path = + calloc(strlen(base_path) + strlen(uri) + 2, 1); + snprintf(full_buffer_path, strlen(base_path) + strlen(uri) + 2, + "%s/%s", base_path, uri); + printf("%d: %s\n", i, full_buffer_path); + image_buffer = fopen(full_buffer_path, "rb"); + } + + if(image_buffer == NULL) { + printf("Failed to open image buffer for reading\n"); + continue; + } + if (strcmp(mimetype, "image/qoi") == 0 || + (uri != NULL && strcmp(strrchr(uri, '.'), "qoi") == 0)) { + images[i] = mons_load_qoi(image_buffer); + } + } + + mons_json_array gltf_samplers_array; + mons_json_get_array(json, "samplers", &gltf_samplers_array); + printf("GLTF Sampler Count: %d\n", gltf_samplers_array.len); + mons_gltf_sampler *samplers = calloc(gltf_samplers_array.len, sizeof(mons_gltf_sampler)); + for(int i = 0; i < gltf_samplers_array.len; i++) { + mons_json_value sampler_info = gltf_samplers_array.values[i]; + mons_json_get_int(sampler_info, "magFilter", (int*)&samplers[i].mag_filter); + mons_json_get_int(sampler_info, "minFilter", (int*)&samplers[i].min_filter); + mons_json_get_int(sampler_info, "wrapS", (int*)&samplers[i].wrap_s); + mons_json_get_int(sampler_info, "wrapT", (int*)&samplers[i].wrap_t); + printf("%d: min %d, mag %d, wrap %d, %d\n", i, samplers[i].min_filter, samplers[i].mag_filter, samplers[i].wrap_s, samplers[i].wrap_t); + } + + mons_json_array gltf_textures_array; + mons_json_get_array(json, "textures", &gltf_textures_array); + printf("GLTF Texture Count: %d\n", gltf_textures_array.len); + mons_gltf_texture *textures = + calloc(gltf_textures_array.len, sizeof(mons_gltf_texture)); + for (int i = 0; i < gltf_textures_array.len; i++) { + mons_json_value texture_info = gltf_textures_array.values[i]; + textures[i].sampler_index = -1; + textures[i].source_index = -1; + mons_json_get_int(texture_info, "sampler", &textures[i].sampler_index); + mons_json_get_int(texture_info, "source", &textures[i].source_index); + printf("%d: sampler %d, source %d\n", i, textures[i].sampler_index, + textures[i].source_index); + } + + mons_json_array gltf_materials_array; + mons_json_get_array(json, "materials", &gltf_materials_array); + mons_gltf_material *materials = calloc(gltf_materials_array.len, sizeof(mons_gltf_material)); + printf("GLTF Material Count: %d\n", gltf_materials_array.len); + for (int i = 0; i < gltf_materials_array.len; i++) { + mons_json_value material_info = gltf_materials_array.values[i]; + mons_json_get_int(material_info, "pbrMetallicRoughness.baseColorTexture.index", &materials[i].base_color_texture_index); + mons_json_get_int(material_info, "normalTexture.index", &materials[i].normal_texture_index); + mons_json_get_int(material_info, "pbrMetallicRoughness.metallicRoughnessTexture.index", &materials[i].metallic_roughness_texture_index); + } + + mons_json_array gltf_mesh_array; + mons_json_get_array(json, "meshes", &gltf_mesh_array); + printf("GLTF Mesh Count: %d\n", gltf_mesh_array.len); + mons_model *models = calloc(gltf_mesh_array.len, sizeof(mons_model)); + for (int i = 0; i < gltf_mesh_array.len; i++) { + mons_json_value mesh_info = gltf_mesh_array.values[i]; + mons_json_array primitives_array; + mons_json_get_array(mesh_info, "primitives", &primitives_array); + printf("%d: %d Primitives\n", i, primitives_array.len); + for (int j = 0; j < primitives_array.len; j++) { + mons_json_value primitive_info = primitives_array.values[j]; + mons_vertex *vertices; + int vertex_count; + int position_accessor_index; + if (mons_json_get_int(primitive_info, "attributes.POSITION", + &position_accessor_index) == EXIT_SUCCESS) { + mons_gltf_accessor position_accessor = + accessors[position_accessor_index]; + vertices = calloc(position_accessor.count, sizeof(mons_vertex)); + mons_gltf_buffer_view position_buffer_view = + buffer_views[position_accessor.buffer_view_index]; + FILE *position_buffer = + buffers[position_buffer_view.buffer_index]; + mons_vec3 *positions = + calloc(position_accessor.count, sizeof(mons_vec3)); + fseek(position_buffer, position_buffer_view.byte_offset, + SEEK_SET); + fread(positions, sizeof(mons_vec3), position_accessor.count, + position_buffer); + for (int k = 0; k < position_accessor.count; k++) { + vertices[k].position = positions[k]; + } + vertex_count = position_accessor.count; + } + int texcoord_accessor_index; + if (mons_json_get_int(primitive_info, "attributes.TEXCOORD_0", + &texcoord_accessor_index) == EXIT_SUCCESS) { + mons_gltf_accessor texcoord_accessor = + accessors[texcoord_accessor_index]; + mons_gltf_buffer_view texcoord_buffer_view = + buffer_views[texcoord_accessor.buffer_view_index]; + FILE *texcoord_buffer = + buffers[texcoord_buffer_view.buffer_index]; + mons_vec2 *texcoords = + calloc(texcoord_accessor.count, sizeof(mons_vec2)); + fseek(texcoord_buffer, texcoord_buffer_view.byte_offset, + SEEK_SET); + fread(texcoords, sizeof(mons_vec2), texcoord_accessor.count, + texcoord_buffer); + for (int k = 0; k < texcoord_accessor.count; k++) { + vertices[k].texture_coords = texcoords[k]; + } + } + int index_accessor_index; + int *indices; + int index_count; + if (mons_json_get_int(primitive_info, "indices", + &index_accessor_index) == EXIT_SUCCESS) { + mons_gltf_accessor index_accessor = + accessors[index_accessor_index]; + mons_gltf_buffer_view index_buffer_view = + buffer_views[index_accessor.buffer_view_index]; + FILE *index_buffer = buffers[index_buffer_view.buffer_index]; + indices = calloc(index_accessor.count, sizeof(int)); + unsigned short *index_shorts = + calloc(index_accessor.count, sizeof(unsigned short)); + fseek(index_buffer, index_buffer_view.byte_offset, SEEK_SET); + fread(index_shorts, sizeof(unsigned short), + index_accessor.count, index_buffer); + for (int k = 0; k < index_accessor.count; k++) { + indices[k] = index_shorts[k]; + } + index_count = index_accessor.count; + } + int normal_accessor_index; + if (mons_json_get_int(primitive_info, "attributes.NORMAL", + &normal_accessor_index) == EXIT_SUCCESS) { + mons_gltf_accessor normal_accessor = + accessors[normal_accessor_index]; + mons_gltf_buffer_view normal_buffer_view = + buffer_views[normal_accessor.buffer_view_index]; + FILE *normal_buffer = + buffers[normal_buffer_view.buffer_index]; + mons_vec3 *normals = + calloc(normal_accessor.count, sizeof(mons_vec3)); + fseek(normal_buffer, normal_buffer_view.byte_offset, + SEEK_SET); + fread(normals, sizeof(mons_vec3), normal_accessor.count, + normal_buffer); + for (int k = 0; k < normal_accessor.count; k++) { + vertices[k].normal = normals[k]; + } + } + + int material_index; + mons_json_get_int(primitive_info, "material", &material_index); + + mons_gltf_material material = materials[material_index]; + + mons_texture *textures = calloc(3, sizeof(mons_texture)); + textures[0] = mons_texture_from_image(images[material.base_color_texture_index]); + textures[1] = mons_texture_from_image(images[material.normal_texture_index]); + textures[2] = mons_texture_from_image(images[material.metallic_roughness_texture_index]); + + models[i] = (mons_model) { + .mesh = mons_create_mesh(vertices, vertex_count, indices, index_count), + .textures = textures, + .textures_len = 3, + .shader = shader, + .transform = MONS_TRANSFORM_IDENTITY, + }; + } + } + + *out = models; + *count = gltf_mesh_array.len; + + for (int i = 0; i < gltf_accessors_array.len; i++) { + free(accessors[i].min); + free(accessors[i].max); + } + free(accessors); + free(buffer_views); + free(buffers); + mons_json_free(json); + return EXIT_SUCCESS; +} |