#include "gltf.h" #include #include #include #include #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; }