Okay, we have all data. Now what? (tldr: I marshalled all the json data from gltf. I did not verified it. I did not tested it. I did not imported it. Nothing is done)

This commit is contained in:
Андреев Григорий 2026-02-08 02:41:07 +03:00
parent 2dd4ad0d7b
commit 24a8be3a75
6 changed files with 576 additions and 66 deletions

View File

@ -7,5 +7,13 @@ void generate_l1_gltf_headers() {
SpanU8 l = cstr("l1"), ns = cstr("");
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("GltfScene"), true, false);
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("GltfNode"), true, false);
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("Gltf"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("GltfBuffer"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("GltfBufferView"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("GltfAccessor"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("GltfMeshPrimitivePart"), true, false);
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("GltfMesh"), true, false);
generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("GltfMaterial"), true, false);
generate_eve_span_company_for_primitive(l, ns, cstr("GltfTexture"), true, false);
generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){
.T = cstr("GltfTextureInfo"), .t_primitive = true, });
}

View File

@ -16,11 +16,11 @@
typedef const char* CSTR;
typedef enum {
Option_Some, Option_None
Option_None = 0, Option_Some = 1
} Option_variant;
typedef enum {
Result_Ok, Result_Err
Result_Err = 0, Result_Ok = 1
} Result_variant;
NORETURN

View File

@ -238,7 +238,3 @@ GenericMeshTopology alice_expect_read_generic_mesh_from_obj_file(VecU8 file_path
OptionGenericMeshTopology option = alice_read_generic_mesh_from_obj_file(file_path);
return OptionGenericMeshTopology_expect(option);
}
/*
ret_error = VecU8_fmt("");
goto destroy_everything_return_error;
*/

View File

@ -4,6 +4,7 @@
#include "../../../gen/l1/VecAndSpan_U64.h"
#include "../../../gen/l1/OptionU64.h"
#include "../../l1_5/core/quaternion.h"
#include "../../l1/core/VecU8_as_str.h"
/* todo: add big endian support */
@ -135,6 +136,125 @@ void GltfNode_drop(GltfNode self) {
#include "../../../gen/l1/eve/VecGltfNode.h"
typedef struct {
U64 length;
bool is_external;
U64 external_file_id;
/* name is overlooked */
} GltfBuffer;
#include "../../../gen/l1/eve/VecGltfBuffer.h"
typedef struct {
U64 buffer;
U64 length;
U64 offset;
U64 stride; // Set to 0 when not specified. May replace with Option later
/* name is overlooked */
} GltfBufferView;
#include "../../../gen/l1/eve/VecGltfBufferView.h"
typedef enum {
GltfAccessorComponentType_byte, /* 5120 */
GltfAccessorComponentType_unsigned_byte, /* 5121 */
GltfAccessorComponentType_short, /* 5122 */
GltfAccessorComponentType_unsigned_short, /* 5123 */
GltfAccessorComponentType_unsigned_int, /* 5125 */
GltfAccessorComponentType_float, /* 5126 */
} GltfAccessorComponentType;
typedef enum {
GltfAccessorMatrixType_scalar,
GltfAccessorMatrixType_vec2,
GltfAccessorMatrixType_vec3,
GltfAccessorMatrixType_vec4,
GltfAccessorMatrixType_mat2,
GltfAccessorMatrixType_mat3,
GltfAccessorMatrixType_mat4,
} GltfAccessorMatrixType;
typedef struct {
U64 buffer_view;
U64 offset;
U64 count;
GltfAccessorComponentType component_type;
GltfAccessorMatrixType matrix_type;
/* name is overlooked */
} GltfAccessor;
#include "../../../gen/l1/eve/VecGltfAccessor.h"
typedef enum {
GltfPrimitiveMode_triangles, /* 4, this is default btw */
GltfPrimitiveMode_something_else, /* I honestly could not care less */
} GltfPrimitiveMode;
typedef struct {
OptionU64 position; /* index in accessors array */
OptionU64 texcoord_0; /* index in accessors array */
OptionU64 color_0; /* index in accessors array */
OptionU64 indices; /* index in accessors array */
OptionU64 material;
GltfPrimitiveMode mode;
/* morph targets are overlooked */
} GltfMeshPrimitivePart;
#include "../../../gen/l1/eve/VecGltfMeshPrimitivePart.h"
typedef struct {
VecGltfMeshPrimitivePart primitives;
VecU8 name;
} GltfMesh;
void GltfMesh_drop(GltfMesh self) {
VecGltfMeshPrimitivePart_drop(self.primitives);
VecU8_drop(self.name);
}
#include "../../../gen/l1/eve/VecGltfMesh.h"
typedef struct {
U64 index;
U64 tex_coord_set_index; // If you are a white person, this should not exceed 0
} GltfTextureInfo;
#include "../../../gen/l1/eve/OptionGltfTextureInfo.h"
typedef struct {
VecU8 name;
OptionGltfTextureInfo base_color_tex;
OptionGltfTextureInfo normal_map_tex;
float metallic_factor;
float roughness_factor;
/* base_color_factor is overlooked */
} GltfMaterial;
void GltfMaterial_drop(GltfMaterial self) {
VecU8_drop(self.name);
}
#include "../../../gen/l1/eve/VecGltfMaterial.h"
typedef enum {
GltfImageMimeType_png, /* image/png */
/* The only other mime-type that is allowed is image/jpeg, too bad I don't support it either */
GltfImageMimeType_jpeg, /* image/jpeg */
GltfImageMimeType_something_else,
} GltfImageMimeType;
typedef struct {
/* For simplicity, GltfTexture embeds both GltfImage and GltfSampler */
/* embeds sampler info. Will add later */
GltfImageMimeType source_mime_type;
bool is_in_buffer_view;
U64 source_buffer_view; // Relevant only if is_in_buffer_view is true
U64 external_file_id; // Relevant only if is_in_buffer_view is false
/* name is overlooked */
} GltfTexture;
#include "../../../gen/l1/eve/VecGltfTexture.h"
#include "../../../gen/l1/VecAndSpan_VecU8.h"
typedef struct {
@ -142,6 +262,12 @@ typedef struct {
VecGltfNode nodes;
VecGltfScene scenes;
OptionU64 default_scene;
VecGltfBuffer buffers;
VecGltfBufferView buffer_views;
VecGltfAccessor accessors;
VecGltfMesh meshes;
VecGltfMaterial materials;
VecGltfTexture textures;
} GltfFileStructure;
void GltfFileStructure_drop(GltfFileStructure self) {
@ -158,10 +284,43 @@ typedef struct {
};
} ResultGltfFileStructureOrVecU8;
/* Helper function for glb_file_get_structure. Returns NULL on error.
* json is the toplevel object. Tries to get $samplers[id] $*/
const Json* glb_file_structure_parsing__get_sampler(const Json* json, U64 id) {
const Json* js = Json_dict_at(json, cstr("samplers"));
if (!js || js->variant != Json_arr)
return NULL;
const VecJson* arr = &js->arr;
if (id >= arr->len)
return NULL;
return &arr->buf[id];
}
const Json* glb_file_structure_parsing__get_image(const Json* json, U64 id) {
const Json* js = Json_dict_at(json, cstr("images"));
if (!js || js->variant != Json_arr)
return NULL;
const VecJson* arr = &js->arr;
if (id >= arr->len)
return NULL;
return &arr->buf[id];
}
OptionGltfTextureInfo glb_file_json_dict_field_try_as_tex_info(const Json* dict, SpanU8 key) {
const Json* el = Json_dict_at(dict, key);
if (!el)
return None_GltfTextureInfo();
OptionU64 opt_index = Json_dict_field_try_as_u64(el, cstr("index"));
if (opt_index.variant != Option_Some)
return None_GltfTextureInfo();
OptionU64 opt_tex_coord = Json_dict_field_try_as_u64(el, cstr("texCoord"));
return Some_GltfTextureInfo((GltfTextureInfo){ .index = opt_index.some,
opt_tex_coord.variant == Option_Some ? opt_tex_coord.some : 0});
}
ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments) {
const Json* json = &segments->gltf;
// VecU8_print(json_encode(json));
// printf("\n");
/* default_scene "scene" : Option<index into scenes>
*
@ -172,12 +331,17 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
* if "nodes" field is not present, it counts as empty vector }
*/
VecVecU8 external_files = VecVecU8_new();
VecU8 ret_error = VecU8_new();
OptionU64 default_scene = None_U64();
VecGltfScene scenes = VecGltfScene_new();
VecGltfNode nodes = VecGltfNode_new();
VecVecU8 external_files = VecVecU8_new();
VecGltfBuffer buffers = VecGltfBuffer_new();
VecGltfBufferView buffer_views = VecGltfBufferView_new();
VecGltfAccessor accessors = VecGltfAccessor_new();
VecGltfMesh meshes = VecGltfMesh_new();
VecGltfMaterial materials = VecGltfMaterial_new();
VecGltfTexture textures = VecGltfTexture_new();
const Json* json_default_scene = Json_dict_at(json, cstr("scene"));
if (json_default_scene) {
@ -199,15 +363,8 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
for (size_t i = 0; i < arr_scenes->len; i++) {
const Json* json_scene = &arr_scenes->buf[i];
VecU8 name = VecU8_new(); // free
const Json* json_name = Json_dict_at(json_scene, cstr("name"));
if (json_name) {
if (json_name->variant != Json_str) {
ret_error = VecU8_fmt("$scenes[%u].name is not a string", i);
goto destroy_everything_return_error;
}
name = VecU8_clone(&json_name->str);
}
OptionSpanU8 opt_name = Json_dict_field_try_as_str(json_scene, cstr("name"));
SpanU8 name = opt_name.variant == Option_Some ? opt_name.some : cstr("");
VecU64 cur_scene_nodes = VecU64_new();
const Json* json_cur_scene_nodes = Json_dict_at(json_scene, cstr("nodes"));
@ -219,7 +376,7 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
}
cur_scene_nodes = opt_cs_nodes.some;
}
VecGltfScene_append(&scenes, (GltfScene){.name = name, .nodes = cur_scene_nodes});
VecGltfScene_append(&scenes, (GltfScene){.name = VecU8_from_span(name), .nodes = cur_scene_nodes});
}
}
@ -233,37 +390,22 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
nodes = VecGltfNode_new_reserved(arr_nodes->len);
for (size_t i = 0; i < arr_nodes->len; i++) {
const Json* json_node = &arr_nodes->buf[i];
VecU64 children = VecU64_new(); // free
VecU8 name = VecU8_new(); // free
const Json* json_name = Json_dict_at(json_node, cstr("name"));
if (json_name) {
if (json_name->variant != Json_str) {
ret_error = VecU8_fmt("nodes[%u].name is not a string", i);
goto destroy_everything_return_error;
}
name = VecU8_clone(&json_name->str);
}
OptionSpanU8 opt_name = Json_dict_field_try_as_str(json_node, cstr("name"));
SpanU8 name = opt_name.variant == Option_Some ? opt_name.some : cstr("");
VecU64 children = VecU64_new();
const Json* json_children = Json_dict_at(json_node, cstr("children"));
if (json_children) {
OptionVecU64 opt_children = Json_try_as_arr_of_u64(json_children);
if (opt_children.variant != Option_Some) {
ret_error = VecU8_fmt("$nodes[%u].children is not an array of positive integers", i);
goto destroy_everything_return_error;
goto destroy_node_info_return_error;
}
children = opt_children.some;
}
OptionU64 mesh = None_U64();
const Json* json_mesh = Json_dict_at(json_node, cstr("mesh"));
if (json_mesh) {
mesh = Json_try_as_u64(json_mesh);
if (mesh.variant != Option_Some) {
ret_error = VecU8_fmt("$nodes[%u].mesh is not an positive integer", i);
goto destroy_everything_return_error;
}
}
OptionU64 mesh = Json_dict_field_try_as_u64(json_node, cstr("mesh"));
const Json* json_matrix = Json_dict_at(json_node, cstr("matrix"));
const Json* json_translation = Json_dict_at(json_node, cstr("translation"));
@ -273,7 +415,7 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
bool has_trs = json_translation != NULL || json_rotation != NULL || json_scale != NULL;
if (json_matrix && has_trs) {
ret_error = VecU8_fmt("$nodes[%u] has both matrix and TRS present", i);
goto destroy_everything_return_error;
goto destroy_node_info_return_error;
}
GltfNodeTransformation trans;
@ -281,7 +423,7 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
float md[16];
if (!Json_try_as_MutSpanFlt32(json_matrix, (MutSpanFlt32){md, 16})) {
ret_error = VecU8_fmt("nodes[%u].matrix is not an array of 16 floats", i);
goto destroy_everything_return_error;
goto destroy_node_info_return_error;
}
trans = (GltfNodeTransformation){.variant = GltfNodeTransformation_mat, .mat = {
.x = {md[0], md[1], md[2], md[3]}, .y = {md[4], md[5], md[6], md[7]},
@ -292,7 +434,7 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
float data[3];
if (!Json_try_as_MutSpanFlt32(json_translation, (MutSpanFlt32){data, 3})) {
ret_error = VecU8_fmt("nodes[%u].translation is not an array of 3 floats", i);
goto destroy_everything_return_error;
goto destroy_node_info_return_error;
}
trans.trs.translation = (vec3){data[0], data[1], data[2]};
} else {
@ -302,7 +444,7 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
float data[4];
if (!Json_try_as_MutSpanFlt32(json_rotation, (MutSpanFlt32){data, 4})) {
ret_error = VecU8_fmt("nodes[%u].rotation is not an array of 4 floats", i);
goto destroy_everything_return_error;
goto destroy_node_info_return_error;
}
trans.trs.rotation = (quaternion_t){data[3], data[0], data[1], data[2]};
} else {
@ -312,7 +454,7 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
float data[3];
if (!Json_try_as_MutSpanFlt32(json_scale, (MutSpanFlt32){data, 3})) {
ret_error = VecU8_fmt("nodes[%u].scale is not an array of 3 floats", i);
goto destroy_everything_return_error;
goto destroy_node_info_return_error;
}
trans.trs.scale = (vec3){data[0], data[1], data[2]};
}
@ -320,13 +462,331 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
trans.variant = GltfNodeTransformation_none;
}
VecGltfNode_append(&nodes, (GltfNode){.name = name, .children = children, .mesh = mesh,
VecGltfNode_append(&nodes, (GltfNode){.name = VecU8_from_span(name), .children = children, .mesh = mesh,
.trans = trans, .has_parent = false});
continue; /* When OK */
destroy_node_info_return_error:
VecU64_drop(children);
goto destroy_everything_return_error;
}
}
const Json* json_buffers = Json_dict_at(json, cstr("buffers"));
if (json_buffers) {
if (json_buffers->variant != Json_arr) {
ret_error = VecU8_fmt("$buffers is not an array");
goto destroy_everything_return_error;
}
const VecJson* arr_buffers = &json_buffers->arr;
buffers = VecGltfBuffer_new_reserved(arr_buffers->len);
for (U64 i = 0; i < arr_buffers->len; i++) {
const Json* json_buffer = &arr_buffers->buf[i];
GltfBuffer buffer;
OptionU64 opt_byte_length = Json_dict_field_try_as_u64(json_buffer, cstr("byteLength"));
if (opt_byte_length.variant != Option_Some) {
ret_error = VecU8_fmt("$buffers[%u].byteLength is not a positive integer", i);
goto destroy_everything_return_error;
}
buffer.length = opt_byte_length.some;
const Json* json_uri = Json_dict_at(json_buffer, cstr("uri"));
if (json_uri) {
OptionSpanU8 uri = Json_try_as_str(json_uri);
if (uri.variant != Option_Some) {
ret_error = VecU8_fmt("$buffers[%u].uri is not a string", i);
goto destroy_everything_return_error;
}
buffer.is_external = true;
buffer.external_file_id = external_files.len;
VecVecU8_append(&external_files, VecU8_from_span(uri.some));
} else {
buffer.is_external = false;
}
VecGltfBuffer_append(&buffers, buffer);
}
}
const Json* json_buffer_views = Json_dict_at(json, cstr("bufferViews"));
if (json_buffer_views) {
if (json_buffer_views->variant != Json_arr) {
ret_error = VecU8_fmt("$bufferViews is not an array");
goto destroy_everything_return_error;
}
const VecJson* arr_buffer_views = &json_buffer_views->arr;
buffer_views = VecGltfBufferView_new_reserved(arr_buffer_views->len);
for (U64 i = 0; i < arr_buffer_views->len; i++) {
const Json* json_buffer_view = &arr_buffer_views->buf[i];
OptionU64 opt_buffer_id = Json_dict_field_try_as_u64(json_buffer_view, cstr("buffer"));
if (opt_buffer_id.variant != Option_Some) {
ret_error = VecU8_fmt("$bufferViews[%u].buffer is not a positive integer", i);
goto destroy_everything_return_error;
}
/* At this point I gave up spotting all file errors */
OptionU64 opt_byte_offset = Json_dict_field_try_as_u64(json_buffer_view, cstr("byteOffset"));
U64 byte_offset = opt_byte_offset.variant == Option_Some ? opt_byte_offset.some : 0;
OptionU64 opt_byte_length = Json_dict_field_try_as_u64(json_buffer_view, cstr("byteLength"));
if (opt_byte_length.variant != Option_Some) {
ret_error = VecU8_fmt("$bufferViews[%u].byteLength is not a positive integer", i);
goto destroy_everything_return_error;
}
OptionU64 opt_byte_stride = Json_dict_field_try_as_u64(json_buffer_view, cstr("byteStride"));
U64 byte_stride = opt_byte_stride.variant == Option_Some ? opt_byte_stride.some : 0;
/* Ignoring an error */
VecGltfBufferView_append(&buffer_views, (GltfBufferView){.buffer = opt_buffer_id.some,
.offset = byte_offset, .length = opt_byte_length.some, .stride = byte_stride});
}
}
const Json* json_accessors = Json_dict_at(json, cstr("accessors"));
if (json_accessors && json_accessors->variant == Json_arr) {
const VecJson* arr_accessors = &json_accessors->arr;
accessors = VecGltfAccessor_new_reserved(arr_accessors->len);
for (size_t i = 0; i < arr_accessors->len; i++) {
const Json* json_accessor = &arr_accessors->buf[i];
OptionU64 opt_buffer_view_id = Json_dict_field_try_as_u64(json_accessor, cstr("bufferView"));
if (opt_buffer_view_id.variant != Option_Some) {
ret_error = VecU8_fmt("Oh, I am really sorry, but accessors without bufferView are not supported", i);
goto destroy_everything_return_error;
}
OptionU64 opt_byte_offset = Json_dict_field_try_as_u64(json_accessor, cstr("byteOffset"));
U64 byte_offset = opt_byte_offset.variant == Option_Some ? opt_byte_offset.some : 0;
OptionU64 opt_count = Json_dict_field_try_as_u64(json_accessor, cstr("count"));
if (opt_count.variant != Option_Some) {
ret_error = VecU8_fmt("$accessors[%u].count is not a positive integer", i);
goto destroy_everything_return_error;
}
GltfAccessorComponentType component_type;
OptionU64 opt_component_type = Json_dict_field_try_as_u64(json_accessor, cstr("componentType"));
if (opt_component_type.variant != Option_Some) {
ret_error = VecU8_fmt("$accessors[%u].componentType is not a positive integer", i);
goto destroy_everything_return_error;
}
U64 int_component_type = opt_component_type.some;
if (int_component_type == 5120) {
component_type = GltfAccessorComponentType_byte;
} else if (int_component_type == 5121) {
component_type = GltfAccessorComponentType_unsigned_byte;
} else if (int_component_type == 5122) {
component_type = GltfAccessorComponentType_short;
} else if (int_component_type == 5123) {
component_type = GltfAccessorComponentType_unsigned_short;
} else if (int_component_type == 5125) {
component_type = GltfAccessorComponentType_unsigned_int;
} else if (int_component_type == 5126) {
component_type = GltfAccessorComponentType_float;
} else {
ret_error = VecU8_fmt("$accessors[%u].componentType %s is incorrect", i, int_component_type);
goto destroy_everything_return_error;
}
GltfAccessorMatrixType matrix_type;
OptionSpanU8 opt_matrix_type = Json_dict_field_try_as_str(json_accessor, cstr("type"));
if (opt_matrix_type.variant != Option_Some) {
ret_error = VecU8_fmt("$accessors[%u].type is not a string", i);
goto destroy_everything_return_error;
}
if (SpanU8_cont_equal(opt_matrix_type.some, cstr("SCALAR"))) {
matrix_type = GltfAccessorMatrixType_scalar;
} else if (SpanU8_cont_equal(opt_matrix_type.some, cstr("VEC2"))) {
matrix_type = GltfAccessorMatrixType_vec2;
} else if (SpanU8_cont_equal(opt_matrix_type.some, cstr("VEC3"))) {
matrix_type = GltfAccessorMatrixType_vec3;
} else if (SpanU8_cont_equal(opt_matrix_type.some, cstr("VEC4"))) {
matrix_type = GltfAccessorMatrixType_vec4;
} else if (SpanU8_cont_equal(opt_matrix_type.some, cstr("MAT2"))) {
matrix_type = GltfAccessorMatrixType_mat2;
} else if (SpanU8_cont_equal(opt_matrix_type.some, cstr("MAT3"))) {
matrix_type = GltfAccessorMatrixType_mat3;
} else if (SpanU8_cont_equal(opt_matrix_type.some, cstr("MAT4"))) {
matrix_type = GltfAccessorMatrixType_mat4;
} else {
ret_error = VecU8_fmt("$accessors[%u].type is incorrect", i);
goto destroy_everything_return_error;
}
VecGltfAccessor_append(&accessors, (GltfAccessor){
.buffer_view = opt_buffer_view_id.some, .offset = byte_offset, .count = opt_count.some,
.component_type = component_type, .matrix_type = matrix_type});
}
}
const Json* json_meshes = Json_dict_at(json, cstr("meshes"));
if (json_meshes && json_meshes->variant == Json_arr) {
const VecJson* arr_meshes = &json_meshes->arr;
meshes = VecGltfMesh_new_reserved(arr_meshes->len);
for (size_t i = 0; i < arr_meshes->len; i++) {
const Json* json_mesh = &arr_meshes->buf[i];
OptionSpanU8 opt_name = Json_dict_field_try_as_str(json_mesh, cstr("name"));
SpanU8 name = opt_name.variant == Option_Some ? opt_name.some : cstr("");
const Json* json_primitives = Json_dict_at(json_mesh, cstr("primitives"));
if (!json_primitives || json_primitives->variant != Json_arr) {
ret_error = VecU8_fmt("meshes[%u].primitives is not a non-empty array", i);
goto destroy_everything_return_error;
}
const VecJson* arr_primitives = &json_primitives->arr;
VecGltfMeshPrimitivePart primitives = VecGltfMeshPrimitivePart_new_reserved(arr_primitives->len);
for (U64 p = 0; p < arr_primitives->len; p++) {
const Json* json_primitive = &arr_primitives->buf[p];
OptionU64 indices_accsr = Json_dict_field_try_as_u64(json_primitive, cstr("indices"));
const Json* json_attributes = Json_dict_at(json_primitive, cstr("attributes"));
if (!json_attributes) {
VecGltfMeshPrimitivePart_drop(primitives);
ret_error = VecU8_fmt("meshes[%u].primitives[%u] does not exist", i, p);
}
OptionU64 position_accsr = Json_dict_field_try_as_u64(json_attributes, cstr("POSITION"));
OptionU64 texcoord_0_accsr = Json_dict_field_try_as_u64(json_attributes, cstr("TEXCOORD_0"));
OptionU64 color_0_accsr = Json_dict_field_try_as_u64(json_attributes, cstr("COLOR_0"));
OptionU64 material = Json_dict_field_try_as_u64(json_primitive, cstr("material"));
GltfPrimitiveMode mode = GltfPrimitiveMode_triangles;
OptionU64 opt_mode = Json_dict_field_try_as_u64(json_primitive, cstr("mode"));
if (opt_mode.variant == Option_Some) {
mode = opt_mode.some == 4 ? GltfPrimitiveMode_triangles : GltfPrimitiveMode_something_else;
}
VecGltfMeshPrimitivePart_append(&primitives, (GltfMeshPrimitivePart){.position = position_accsr,
.texcoord_0 = texcoord_0_accsr, .color_0 = color_0_accsr, .indices = indices_accsr,
.material = material, .mode = mode});
}
VecGltfMesh_append(&meshes, (GltfMesh){.primitives = primitives, .name = VecU8_from_span(name)});
}
}
const Json* json_materials = Json_dict_at(json, cstr("materials"));
if (json_materials && json_materials->variant == Json_arr) {
const VecJson* arr_materials = &json_materials->arr;
materials = VecGltfMaterial_new_reserved(arr_materials->len);
for (U64 i = 0; i < arr_materials->len; i++) {
const Json* json_material = &arr_materials->buf[i];
OptionSpanU8 opt_name = Json_dict_field_try_as_str(json_material, cstr("name"));
SpanU8 name = opt_name.variant == Option_Some ? opt_name.some : cstr("");
OptionGltfTextureInfo normal_map_tex;
normal_map_tex = glb_file_json_dict_field_try_as_tex_info(json_material, cstr("normalTexture"));
OptionGltfTextureInfo base_color_tex = None_GltfTextureInfo();
float metallic_factor = 1.f;
float roughness_factor = 1.f;
const Json* pbr_mr = Json_dict_at(json_material, cstr("pbrMetallicRoughness"));
if (pbr_mr) {
base_color_tex = glb_file_json_dict_field_try_as_tex_info(pbr_mr, cstr("baseColorTexture"));
OptionFlt32 opt_metallic_factor = Json_dict_field_try_as_float(pbr_mr, cstr("metallicFactor"));
if (opt_metallic_factor.some != Option_Some)
metallic_factor = opt_metallic_factor.some;
OptionFlt32 opt_roughness_factor = Json_dict_field_try_as_float(pbr_mr, cstr("roughnessFactor"));
if (opt_roughness_factor.some != Option_Some)
roughness_factor = opt_roughness_factor.some;
}
VecGltfMaterial_append(&materials, (GltfMaterial){.name = VecU8_from_span(name),
.base_color_tex = base_color_tex, .normal_map_tex = normal_map_tex,
.metallic_factor = metallic_factor, .roughness_factor = roughness_factor });
}
}
const Json* json_textures = Json_dict_at(json, cstr("textures"));
if (json_textures && json_textures->variant == Json_arr) {
const VecJson* arr_textures = &json_textures->arr;
textures = VecGltfTexture_new_reserved(arr_textures->len);
for (U64 i = 0; i < arr_textures->len; i++) {
const Json* json_texture = &arr_textures->buf[i];
GltfTexture texture;
OptionU64 opt_sampler_id = Json_dict_field_try_as_u64(json_texture, cstr("sampler"));
if (opt_sampler_id.variant == Option_Some) {
const Json* json_sampler = glb_file_structure_parsing__get_sampler(json, opt_sampler_id.some);
if (!json_sampler) {
ret_error = VecU8_fmt("$textures[%u].sampler points to out-of-bounds sampler", i);
goto destroy_everything_return_error;
}
}
OptionU64 opt_source_image_id = Json_dict_field_try_as_u64(json_texture, cstr("source"));
if (opt_source_image_id.variant != Option_Some) {
ret_error = VecU8_fmt("Ahh I am so sorry, but textures without images are not supported", i);
goto destroy_everything_return_error;
}
U64 image_id = opt_source_image_id.some;
const Json* json_image = glb_file_structure_parsing__get_image(json, image_id);
if (!json_image) {
ret_error = VecU8_fmt("$textures[%u].source points to out-of-bounds image", i);
goto destroy_everything_return_error;
}
OptionSpanU8 opt_uri = Json_dict_field_try_as_str(json_image, cstr("uri"));
OptionSpanU8 opt_mime_type = Json_dict_field_try_as_str(json_image, cstr("mimeType"));
OptionU64 opt_buffer_view = Json_dict_field_try_as_u64(json_image, cstr("bufferView"));
if (opt_buffer_view.variant == Option_Some && opt_uri.variant == Option_Some) {
ret_error = VecU8_fmt("$images[%u] has both uri and bufferView defined", image_id);
goto destroy_everything_return_error;
}
if (opt_buffer_view.variant == Option_Some && opt_mime_type.variant != Option_Some) {
ret_error = VecU8_fmt("$images[%u].bufferView is defined, but mimeType isn't specified", image_id);
goto destroy_everything_return_error;
}
if (opt_buffer_view.variant != Option_Some && opt_uri.variant != Option_Some) {
ret_error = VecU8_fmt("images[%u] has neither uri nor bufferView defined", image_id);
goto destroy_everything_return_error;
}
texture.source_mime_type = GltfImageMimeType_something_else;
if (opt_mime_type.variant != Option_Some) {
if (SpanU8_cont_equal(opt_mime_type.some, cstr("image/png"))) {
texture.source_mime_type = GltfImageMimeType_png;
} else if (SpanU8_cont_equal(opt_mime_type.some, cstr("image/jpeg"))) {
texture.source_mime_type = GltfImageMimeType_jpeg;
}
}
if (opt_uri.variant == Option_Some) {
SpanU8 uri = opt_uri.some;
if (opt_mime_type.variant != Option_Some) {
assert(texture.source_mime_type == GltfImageMimeType_something_else);
if (SpanU8_is_postfix(cstr(".png"), uri)) {
texture.source_mime_type = GltfImageMimeType_png;
} else if (SpanU8_is_postfix(cstr(".png"), uri)) {
texture.source_mime_type = GltfImageMimeType_jpeg;
}
}
U64 new_external_file_id = external_files.len;
VecVecU8_append(&external_files, VecU8_from_span(uri));
texture.is_in_buffer_view = false;
texture.external_file_id = new_external_file_id;
} else {
assert(opt_buffer_view.variant == Option_Some);
texture.is_in_buffer_view = true;
texture.source_buffer_view = opt_buffer_view.some;
}
VecGltfTexture_append(&textures, texture);
}
}
/* Now we are doing some checks and filling fields that were not directly specified */
for (size_t i = 0; i < nodes.len; i++) {
for (U64 i = 0; i < nodes.len; i++) {
const GltfNode* node = &nodes.buf[i];
for (size_t jjj = 0; jjj < node->children.len; jjj++) {
U64 n2 = node->children.buf[jjj];
@ -344,7 +804,7 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
}
}
for (size_t s = 0; s < scenes.len; s++) {
for (U64 s = 0; s < scenes.len; s++) {
const GltfScene* scene = &scenes.buf[s];
for (size_t jjj = 0; jjj < scene->nodes.len; jjj++) {
U64 n = scene->nodes.buf[jjj];
@ -365,9 +825,37 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
goto destroy_everything_return_error;
}
/* Printing stuff (for test) */
for (U64 i = 0; i < nodes.len; i++) {
const GltfNode* node = &nodes.buf[i];
/* ret_error stores nothing, nothing to free */
return (ResultGltfFileStructureOrVecU8){.variant = Result_Ok, .ok = (GltfFileStructure){
.nodes = nodes, .scenes = scenes, .default_scene = default_scene, .external_files = external_files}};
destroy_everything_return_error:
VecVecU8_drop(external_files);
VecGltfNode_drop(nodes);
VecGltfScene_drop(scenes);
VecGltfBuffer_drop(buffers);
VecGltfBufferView_drop(buffer_views);
VecGltfAccessor_drop(accessors);
VecGltfMesh_drop(meshes);
VecGltfMaterial_drop(materials);
VecGltfTexture_drop(textures);
return (ResultGltfFileStructureOrVecU8){.variant = Result_Err, .err = ret_error};
}
void GltfFileStructure_debug_print(const GltfFileStructure* self) {
const VecVecU8* external_files = &self->external_files;
const VecGltfNode* nodes = &self->nodes;
const VecGltfScene* scenes = &self->scenes;
OptionU64 default_scene = self->default_scene;
const VecGltfBuffer* buffers = &self->buffers;
const VecGltfBufferView* buffer_views = &self->buffer_views;
const VecGltfAccessor* accessors = &self->accessors;
const VecGltfMesh* meshes = &self->meshes;
const VecGltfMaterial* materials = &self->materials;
const VecGltfTexture* textures = &self->textures;
for (U64 i = 0; i < nodes->len; i++) {
const GltfNode* node = &nodes->buf[i];
VecU8 children_txt = VecU8_new();
for (size_t j = 0; j < node->children.len; j++) {
if (j)
@ -380,8 +868,8 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
node->mesh.variant == Option_Some ? VecU8_fmt("mesh= %u", node->mesh.some) : vcstr("no mesh")));
}
for (U64 i = 0; i < scenes.len; i++) {
const GltfScene* scene = &scenes.buf[i];
for (U64 i = 0; i < scenes->len; i++) {
const GltfScene* scene = &scenes->buf[i];
VecU8 nodes_txt = VecU8_new();
for (size_t j = 0; j < scene->nodes.len; j++) {
if (j)
@ -393,15 +881,4 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments)
VecU8_print(VecU8_fmt("default_scene: %v\n",
default_scene.variant == Option_None ? vcstr("None") : U64_stringification(default_scene.some)));
/* End of debug print */
/* ret_error stores nothing, nothing to free */
return (ResultGltfFileStructureOrVecU8){.variant = Result_Ok, .ok = (GltfFileStructure){
.nodes = nodes, .scenes = scenes, .default_scene = default_scene, .external_files = external_files}};
destroy_everything_return_error:
VecGltfNode_drop(nodes);
VecGltfScene_drop(scenes);
VecVecU8_drop(external_files);
return (ResultGltfFileStructureOrVecU8){.variant = Result_Err, .err = ret_error};
}

View File

@ -179,4 +179,29 @@ bool Json_try_as_MutSpanFlt32(const Json* self, MutSpanFlt32 ret) {
ret.data[i] = opt.some;
}
return true;
}
}
OptionU64 Json_dict_field_try_as_u64(const Json* self, SpanU8 key) {
const Json* el = Json_dict_at(self, key);
if (!el)
return None_U64();
return Json_try_as_u64(el);
}
OptionSpanU8 Json_dict_field_try_as_str(const Json* self, SpanU8 key) {
const Json* el = Json_dict_at(self, key);
if (!el || el->variant != Json_str)
return None_SpanU8();
return Some_SpanU8(VecU8_to_span(&el->str));
}
OptionFlt32 Json_dict_field_try_as_float(const Json* self, SpanU8 key) {
const Json* el = Json_dict_at(self, key);
if (!el)
return None_Flt32();
if (el->variant == Json_integer)
return Some_Flt32((float)el->integer);
if (el->variant == Json_float)
return Some_Flt32((float)el->float_num);
return None_Flt32();
}

View File

@ -412,6 +412,8 @@ int main(){
VecU8_drop(file);
abort();
}
VecU8_print(json_encode(&segments_r.ok.gltf));
printf("\n");
ResultGltfFileStructureOrVecU8 structure_r = glb_file_get_structure(&segments_r.ok);
if (structure_r.variant == Result_Err) {
printf("Something when parsing gltf\n");
@ -421,6 +423,8 @@ int main(){
VecU8_drop(file);
abort();
}
GltfFileStructure_debug_print(&structure_r.ok);
GltfFileStructure_drop(structure_r.ok);
GLBFileSegments_drop(segments_r.ok);
VecU8_drop(file);
}