From 2dd4ad0d7b6b7c5da72866fa911bac43aa9a6b55 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Fri, 6 Feb 2026 17:44:36 +0300 Subject: [PATCH] Saving progress. Parsing of nodes and scenes arrays of glb object --- src/l1/anne/gltf_structures.h | 1 + src/l1/anne/util_temp_very_base.h | 15 +- src/l1/core/int_primitives.h | 2 + src/l2/alice/model_file.h | 33 +-- src/l2/core/glb_file.h | 340 ++++++++++++++++++++++++++++-- src/l2/core/json.h | 72 ++++++- src/l3/r4/r4.c | 21 +- 7 files changed, 433 insertions(+), 51 deletions(-) diff --git a/src/l1/anne/gltf_structures.h b/src/l1/anne/gltf_structures.h index ca9a4c3..62a47c1 100644 --- a/src/l1/anne/gltf_structures.h +++ b/src/l1/anne/gltf_structures.h @@ -7,4 +7,5 @@ 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); } diff --git a/src/l1/anne/util_temp_very_base.h b/src/l1/anne/util_temp_very_base.h index b6ee4b0..c873417 100644 --- a/src/l1/anne/util_temp_very_base.h +++ b/src/l1/anne/util_temp_very_base.h @@ -5,8 +5,12 @@ /* These headers are guarded */ void generate_util_temp_very_base_headers() { SpanU8 l = cstr("l1"), ns = cstr(""); - SpanU8 T_codegen_VecAndSpan[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64")}; - SpanU8 T_codegen_Option[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64")}; + SpanU8 T_codegen_VecAndSpan[] = { + cstr("U8"), cstr("U16"), cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64"), cstr("Flt32"), cstr("Flt64") + }; + SpanU8 T_codegen_Option[] = { + cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64"), cstr("S64"), cstr("Flt32"), cstr("Flt64") + }; SpanU8 T_codegen_VecAndSpan_of_Vec[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")}; SpanU8 T_codegen_VecAndSpan_of_Span[] = {cstr("U8"), cstr("U16"), cstr("U32"), cstr("U64")}; for (size_t i = 0; i < ARRAY_SIZE(T_codegen_VecAndSpan); i++) { @@ -47,6 +51,13 @@ void generate_util_temp_very_base_headers() { VecU8_drop(SpanT); VecU8_drop(dependency); } + + // todo: maybe make these for all other int types too + generate_Option_templ_inst_guarded_header(l, ns, cstr("#include \"VecAndSpan_U8.h\""), + (option_template_instantiation_op){.T = cstr("SpanU8"), .t_primitive = true}); + generate_Option_templ_inst_guarded_header(l, ns, cstr("#include \"VecAndSpan_U64.h\""), + (option_template_instantiation_op){.T = cstr("VecU64"), .t_primitive = false}); + generate_guarded_span_company_for_primitive(l, ns, cstr("CSTR"), cstr(""), true, false); generate_ResultType_templ_inst_guarded_header(l, ns, diff --git a/src/l1/core/int_primitives.h b/src/l1/core/int_primitives.h index 487a996..8ce457b 100644 --- a/src/l1/core/int_primitives.h +++ b/src/l1/core/int_primitives.h @@ -12,6 +12,8 @@ typedef int8_t S8; typedef int16_t S16; typedef int32_t S32; typedef int64_t S64; +typedef float Flt32; +typedef double Flt64; // todo: move these to util (l1) template instantiation too #define int_minmax_function_Definition(T) \ diff --git a/src/l2/alice/model_file.h b/src/l2/alice/model_file.h index da523e7..b4b8d44 100644 --- a/src/l2/alice/model_file.h +++ b/src/l2/alice/model_file.h @@ -238,32 +238,7 @@ 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); } - -/* Temporary function for some experiments. Will rewrite/delete later */ -GenericMeshTopology alice_expect_read_generic_mesh_from_glb_file(VecU8 file_path) { - GLBFileSegments segments; - int code = glb_file_get_segments(VecU8_to_span(&file_path), &segments); - if (code) { - abortf("Something went wrong when reading glb container\n"); - } - - /* default_scene "scene" : Option - * - * scenes "scenes" : Vec { - * if "scenes" field is not present, it counts as empty vector } - * - * nodes "nodes" : Vec { - * if "nodes" field is not present, it counts as empty vector } - */ - - OptionU32 default_scene = None_U32(); - - - - VecU8_print(VecU8_fmt("default_scene: %v\n", - default_scene.variant == Option_None ? vcstr("None") : U64_stringification(default_scene.some))); - - VecGenericMeshVertexInc vertices = VecGenericMeshVertexInc_new(); - VecU32 indexes = VecU32_new(); - return (GenericMeshTopology){.vertices = vertices, .indexes = indexes}; -} \ No newline at end of file +/* +ret_error = VecU8_fmt(""); +goto destroy_everything_return_error; + */ \ No newline at end of file diff --git a/src/l2/core/glb_file.h b/src/l2/core/glb_file.h index 0ae1cee..3920ac7 100644 --- a/src/l2/core/glb_file.h +++ b/src/l2/core/glb_file.h @@ -2,7 +2,7 @@ #include "json_encoded.h" #include "../../../gen/l1/VecAndSpan_U64.h" -#include "../../../gen/l1/OptionU32.h" +#include "../../../gen/l1/OptionU64.h" #include "../../l1_5/core/quaternion.h" /* todo: add big endian support */ @@ -11,7 +11,7 @@ typedef struct { U32 version; Json gltf; - /* If length is 0, BIN segment is absent */ + /* If length is 0, BIN segment is absent. Keeps pointing at original string */ SpanU8 bin_segment; } GLBFileSegments; @@ -19,42 +19,54 @@ void GLBFileSegments_drop(GLBFileSegments self){ Json_drop(self.gltf); } +/* Can point to some string (.ok can contain span). Be careful with lifetimes */ +typedef struct { + Result_variant variant; + union { + GLBFileSegments ok; + // this one has infinite lifetime + SpanU8 err; + }; +} ResultGLBFileSegmentsOrSpanU8; + /* Returns positive on error, 0 on ok */ -int glb_file_get_segments(SpanU8 file, GLBFileSegments* ret){ +ResultGLBFileSegmentsOrSpanU8 glb_file_get_segments(SpanU8 file){ if (file.len < 12) { - return 1; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, .err=cstr("too smol")}; } SpanU8 json_segment = {0, 0}; // length of 0 means segment is absent SpanU8 bin_segment = {0, 0}; // length of 0 means segment is absent if (*(const U32*)file.data != 0x46546C67) { - return 2; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, .err=cstr("magic number is incorrect")}; } U32 version = *(const U32*)(file.data + 4); /* Nobody cares about version */ if (*(const U32*)(file.data + 8) != file.len) { - return 3; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, .err=cstr("incorrect glb file length")};; } U64 cur = 12; while (cur < file.len) { if (cur + 8 > file.len) { - return 4; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, + .err=cstr("out-of-bounds when reading segment header")};; } U32 chunk_length = *(const U32*)(file.data + cur); U32 chunk_type = *(const U32*)(file.data + cur + 4); if (cur + 8 + chunk_length > file.len) { - return 5; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, + .err=cstr("out-of-bounds when reading segment data")};; } SpanU8 cur_segment = SpanU8_span(file, cur + 8, chunk_length); if (chunk_type == 0x4E4F534A) { if (json_segment.len > 0) { /* Illegal! Two json segments */ - return 6; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, .err=cstr("two json segments")};; } json_segment = cur_segment; } else if (chunk_type == 0x004E4942) { if (bin_segment.len > 0) { /* Illegal! Two bin segments */ - return 7; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, .err=cstr("two bin segments")};; } bin_segment = cur_segment; } @@ -62,17 +74,15 @@ int glb_file_get_segments(SpanU8 file, GLBFileSegments* ret){ } if (json_segment.len == 0) { /* Illegal, no json segment */ - return 8; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, .err=cstr("no json segment in glb file")};; } - SpanU8_print(json_segment); - printf("\n"); OptionJson parsed_json = json_decode(json_segment, 15); if (parsed_json.variant == Option_None) { - return 9; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Err, .err=cstr("syntax error in json segment")};; } /* Everything is correct */ - *ret = (GLBFileSegments){.version = version, .gltf = parsed_json.some, .bin_segment = bin_segment}; - return 0; + return (ResultGLBFileSegmentsOrSpanU8){.variant = Result_Ok, + .ok = (GLBFileSegments){.version = version, .gltf = parsed_json.some, .bin_segment = bin_segment}}; } typedef struct { @@ -87,10 +97,35 @@ void GltfScene_drop(GltfScene self) { #include "../../../gen/l1/eve/VecGltfScene.h" +typedef enum { + GltfNodeTransformation_none, + GltfNodeTransformation_trs, + GltfNodeTransformation_mat, +} GltfNodeTransformation_variant; + +typedef struct { + vec3 translation; + quaternion_t rotation; + vec3 scale; +} GltfNodeTransformationTRS; + +typedef struct { + GltfNodeTransformation_variant variant; + union { + GltfNodeTransformationTRS trs; + mat4 mat; + }; +} GltfNodeTransformation; + typedef struct { VecU8 name; VecU64 children; - OptionU32 mesh; + OptionU64 mesh; + GltfNodeTransformation trans; + + /* These are not specified in gltf file */ + bool has_parent; + U64 parent; /* Relevant only when self.has_parent = true */ } GltfNode; void GltfNode_drop(GltfNode self) { @@ -99,3 +134,274 @@ void GltfNode_drop(GltfNode self) { } #include "../../../gen/l1/eve/VecGltfNode.h" + +#include "../../../gen/l1/VecAndSpan_VecU8.h" + +typedef struct { + VecVecU8 external_files; + VecGltfNode nodes; + VecGltfScene scenes; + OptionU64 default_scene; +} GltfFileStructure; + +void GltfFileStructure_drop(GltfFileStructure self) { + VecVecU8_drop(self.external_files); + VecGltfNode_drop(self.nodes); + VecGltfScene_drop(self.scenes); +} + +typedef struct { + Result_variant variant; + union { + GltfFileStructure ok; + VecU8 err; + }; +} ResultGltfFileStructureOrVecU8; + +ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments) { + const Json* json = &segments->gltf; + // VecU8_print(json_encode(json)); + // printf("\n"); + + /* default_scene "scene" : Option + * + * scenes "scenes" : Vec { + * if "scenes" field is not present, it counts as empty vector } + * + * nodes "nodes" : Vec { + * if "nodes" field is not present, it counts as empty vector } + */ + + VecU8 ret_error = VecU8_new(); + OptionU64 default_scene = None_U64(); + VecGltfScene scenes = VecGltfScene_new(); + VecGltfNode nodes = VecGltfNode_new(); + VecVecU8 external_files = VecVecU8_new(); + + + const Json* json_default_scene = Json_dict_at(json, cstr("scene")); + if (json_default_scene) { + default_scene = Json_try_as_u64(json_default_scene); + if (default_scene.variant != Option_Some) { + ret_error = VecU8_fmt("$scene is not an positive integer"); + goto destroy_everything_return_error; + } + } + + const Json* json_scenes = Json_dict_at(json, cstr("scenes")); + if (json_scenes) { + if (json_scenes->variant != Json_arr){ + ret_error = VecU8_fmt("$scenes is not an array"); + goto destroy_everything_return_error; + } + const VecJson* arr_scenes = &json_scenes->arr; + scenes = VecGltfScene_new_reserved(arr_scenes->len); + 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); + } + + VecU64 cur_scene_nodes = VecU64_new(); + const Json* json_cur_scene_nodes = Json_dict_at(json_scene, cstr("nodes")); + if (json_cur_scene_nodes) { + OptionVecU64 opt_cs_nodes = Json_try_as_arr_of_u64(json_cur_scene_nodes); + if (opt_cs_nodes.variant != Option_Some) { + ret_error = VecU8_fmt("$scenes[%u].nodes is not an array of positive integers", i); + goto destroy_everything_return_error; + } + cur_scene_nodes = opt_cs_nodes.some; + } + VecGltfScene_append(&scenes, (GltfScene){.name = name, .nodes = cur_scene_nodes}); + } + } + + const Json* json_nodes = Json_dict_at(json, cstr("nodes")); + if (json_nodes) { + if (json_nodes->variant != Json_arr) { + ret_error = VecU8_fmt("$nodes is not an array"); + goto destroy_everything_return_error; + } + const VecJson* arr_nodes = &json_nodes->arr; + 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]; + + 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); + } + + 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; + } + 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; + } + } + + const Json* json_matrix = Json_dict_at(json_node, cstr("matrix")); + const Json* json_translation = Json_dict_at(json_node, cstr("translation")); + const Json* json_rotation = Json_dict_at(json_node, cstr("rotation")); + const Json* json_scale = Json_dict_at(json_node, cstr("scale")); + + 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; + } + + GltfNodeTransformation trans; + if (json_matrix) { + 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; + } + trans = (GltfNodeTransformation){.variant = GltfNodeTransformation_mat, .mat = { + .x = {md[0], md[1], md[2], md[3]}, .y = {md[4], md[5], md[6], md[7]}, + .z = {md[8], md[9], md[10], md[11]}, .w = {md[12], md[13], md[14], md[15]}}}; + } else if (has_trs) { + trans.variant = GltfNodeTransformation_trs; + if (json_translation) { + 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; + } + trans.trs.translation = (vec3){data[0], data[1], data[2]}; + } else { + trans.trs.translation = (vec3){0}; + } + if (json_rotation) { + 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; + } + trans.trs.rotation = (quaternion_t){data[3], data[0], data[1], data[2]}; + } else { + trans.trs.rotation = (quaternion_t){1, 0, 0, 0}; + } + if (json_scale) { + 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; + } + trans.trs.scale = (vec3){data[0], data[1], data[2]}; + } + } else { + trans.variant = GltfNodeTransformation_none; + } + + VecGltfNode_append(&nodes, (GltfNode){.name = name, .children = children, .mesh = mesh, + .trans = trans, .has_parent = false}); + } + } + + /* Now we are doing some checks and filling fields that were not directly specified */ + for (size_t 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]; + if (n2 >= nodes.len) { + ret_error = VecU8_fmt("Node %u has child %u that is out-of-bounds of nodes array", i, n2); + goto destroy_everything_return_error; + } + GltfNode* lower_node = &nodes.buf[n2]; + if (lower_node->has_parent) { + ret_error = VecU8_fmt("Node %u has two parents (%u and %u)", n2, lower_node->parent, i); + goto destroy_everything_return_error; + } + lower_node->has_parent = true; + lower_node->parent = i; + } + } + + for (size_t 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]; + if (n >= nodes.len) { + ret_error = VecU8_fmt("Scene $u has child %u that is out-of-bounds of nodes array", s, n); + goto destroy_everything_return_error; + } + const GltfNode* node = &nodes.buf[n]; + if (node->has_parent) { + ret_error = VecU8_fmt("Scene %u specifies a non-root node %u", s, n); + goto destroy_everything_return_error; + } + } + } + + if (default_scene.variant == Option_Some && default_scene.some >= scenes.len) { + ret_error = VecU8_fmt("Default scene %u is out-of-bounds of scenes array", default_scene.some); + goto destroy_everything_return_error; + } + + /* Printing stuff (for test) */ + 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) + VecU8_append_cstr(&children_txt, ", "); + U64_stringification_into_buf(node->children.buf[j], &children_txt); + } + VecU8_print(VecU8_fmt("Node #%u \"%r\": %v, children= [ %v ], %v\n", i, node->name, + node->has_parent ? VecU8_fmt("parent= %u", node->parent) : vcstr("root node"), + children_txt, + 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]; + VecU8 nodes_txt = VecU8_new(); + for (size_t j = 0; j < scene->nodes.len; j++) { + if (j) + VecU8_append_cstr(&nodes_txt, ", "); + U64_stringification_into_buf(scene->nodes.buf[j], &nodes_txt); + } + VecU8_print(VecU8_fmt("Scene #%u \"%r\": root nodes= [ %v ]\n", i, scene->name, nodes_txt)); + } + + 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}; +} diff --git a/src/l2/core/json.h b/src/l2/core/json.h index cc7f07d..2e85206 100644 --- a/src/l2/core/json.h +++ b/src/l2/core/json.h @@ -103,12 +103,80 @@ const Json* Json_dict_at(const Json* self, SpanU8 key) { while (cur != d->NIL) { RBTreeNode_KVPVecU8ToJson* n = (RBTreeNode_KVPVecU8ToJson*)cur; if (SpanU8_less_SpanU8(VecU8_to_span(&n->key), key)) { - cur = cur->left; - } else if (SpanU8_less_SpanU8(key, VecU8_to_span(&n->key))) { cur = cur->right; + } else if (SpanU8_less_SpanU8(key, VecU8_to_span(&n->key))) { + cur = cur->left; } else { return &n->value; } } return NULL; } + +/* Random quality of life json functions */ + +#include "../../../gen/l1/OptionS64.h" + +/* self must not be NULL */ +OptionS64 Json_try_as_int(const Json* self) { + return self->variant == Json_integer ? Some_S64(self->integer) : None_S64(); +} + +#include "../../../gen/l1/OptionU64.h" + +OptionU64 Json_try_as_u64(const Json* self) { + return (self->variant == Json_integer && self->integer >= 0) ? Some_U64((U64)self->integer) : None_U64(); +} + +#include "../../../gen/l1/OptionSpanU8.h" + +/* self must not be NULL, returns immutable string reference */ +OptionSpanU8 Json_try_as_str(const Json* self) { + return self->variant == Json_str ? Some_SpanU8(VecU8_to_span(&self->str)) : None_SpanU8(); +} + +#include "../../../gen/l1/OptionFlt32.h" + +OptionFlt32 Json_try_as_float(const Json* self) { + if (self->variant == Json_integer) + return Some_Flt32((float)self->integer); + if (self->variant == Json_float) + return Some_Flt32(self->float_num); + return None_Flt32(); +} + +#include "../../../gen/l1/OptionVecU64.h" + +OptionVecU64 Json_try_as_arr_of_u64(const Json* self) { + if (self->variant != Json_arr) + return None_VecU64(); + VecU64 res = VecU64_new_zeroinit(self->arr.len); + for (size_t i = 0; i < self->arr.len; i++) { + const Json* el = &self->arr.buf[i]; + if (el->variant != Json_integer || el->integer < 0) { + VecU64_drop(res); + return None_VecU64(); + } + res.buf[i] = (U64)el->integer; + } + return Some_VecU64(res); +} + +#include "../../../gen/l1/VecAndSpan_Flt32.h" + +/* true=ok, false=err */ +bool Json_try_as_MutSpanFlt32(const Json* self, MutSpanFlt32 ret) { + if (self->variant != Json_arr) + return false; + size_t n = ret.len; + if (self->arr.len != n) + return false; + for (size_t i = 0; i < n; i++) { + const Json* el = &self->arr.buf[i]; + OptionFlt32 opt = Json_try_as_float(el); + if (opt.variant != Option_Some) + return false; + ret.data[i] = opt.some; + } + return true; +} \ No newline at end of file diff --git a/src/l3/r4/r4.c b/src/l3/r4/r4.c index c803dda..3b34905 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -403,5 +403,24 @@ void run_app(){ } int main(){ - alice_expect_read_generic_mesh_from_glb_file(vcstr("./src/l3/models/skeleton.glb")); + VecU8 file = read_file_by_path(vcstr("./src/l3/models/skeleton.glb")); + ResultGLBFileSegmentsOrSpanU8 segments_r = glb_file_get_segments(VecU8_to_span(&file)); + if (segments_r.variant == Result_Err) { + printf("Something went wrong when reading glb container\n"); + SpanU8_print(segments_r.err); + printf("\n"); + VecU8_drop(file); + abort(); + } + ResultGltfFileStructureOrVecU8 structure_r = glb_file_get_structure(&segments_r.ok); + if (structure_r.variant == Result_Err) { + printf("Something when parsing gltf\n"); + VecU8_print(structure_r.err); + printf("\n"); + GLBFileSegments_drop(segments_r.ok); + VecU8_drop(file); + abort(); + } + GLBFileSegments_drop(segments_r.ok); + VecU8_drop(file); }