diff --git a/src/l1_5/marie/graphics_geom.h b/src/l1_5/marie/graphics_geom.h index b08815f..6dde418 100644 --- a/src/l1_5/marie/graphics_geom.h +++ b/src/l1_5/marie/graphics_geom.h @@ -97,6 +97,13 @@ mat4 marie_3d_scal_mat4(float scale){ 0, 0, 0, 1); } +mat4 marie_3d_scale_mat4(vec3 scale){ + return mat4_new(scale.x, 0, 0, 0, + 0, scale.y, 0, 0, + 0, 0, scale.z, 0, + 0, 0, 0, 1); +} + vec2 ivec2_to_vec2(ivec2 v){ return (vec2){(float)v.x, (float)v.y}; } diff --git a/src/l2/core/glb_file.h b/src/l2/core/glb_file.h index 9c8a34e..e4a1e7d 100644 --- a/src/l2/core/glb_file.h +++ b/src/l2/core/glb_file.h @@ -841,10 +841,10 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments) for (U64 bv = 0; bv < buffer_views.len; bv++) { const GltfBufferView* buffer_view = &buffer_views.buf[bv]; - if (buffer_view->usage_in_accessors >= 2 && buffer_view->stride == 0) { - ret_error = VecU8_fmt("BufferView %u is used by several accessors, but stride isn't specified", bv); - goto destroy_everything_return_error; - } + // if (buffer_view->usage_in_accessors >= 2 && buffer_view->stride == 0) { + // ret_error = VecU8_fmt("BufferView %u is used by several accessors, but stride isn't specified", bv); + // goto destroy_everything_return_error; + // } U64 buf_id = buffer_view->buffer; if (buf_id >= buffers.len) { ret_error = VecU8_fmt("BufferView %u has buffer %u, that is out-of-bounds of buffers array", bv, buf_id); @@ -927,10 +927,10 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments) ret_error = VecU8_fmt("Material's %u normal map texture is out-of-bounds of textures array", i); goto destroy_everything_return_error; } - if (material->normal_map_tex.some.tex_coord_set_index > 0) { - ret_error = VecU8_fmt("Mmmmm NOPE"); - goto destroy_everything_return_error; - } + // if (material->normal_map_tex.some.tex_coord_set_index > 0) { + // ret_error = VecU8_fmt("Mmmmm NOPE"); + // goto destroy_everything_return_error; + // } } } @@ -1001,7 +1001,11 @@ ResultGltfFileStructureOrVecU8 glb_file_get_structure(GLBFileSegments* segments) /* 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}}; + .external_files = external_files, + .nodes = nodes, .scenes = scenes, .default_scene = default_scene, + .buffers = buffers, .buffer_views = buffer_views, .accessors = accessors, + .meshes = meshes, .materials = materials, .textures = textures + }}; destroy_everything_return_error: VecVecU8_drop(external_files); VecGltfNode_drop(nodes); diff --git a/src/l3/models/skeleton_2.glb b/src/l3/models/skeleton_2.glb new file mode 100644 index 0000000..434b5f9 Binary files /dev/null and b/src/l3/models/skeleton_2.glb differ diff --git a/src/l3/r4/r4.c b/src/l3/r4/r4.c index 5abddd4..c3e2c44 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -18,7 +18,9 @@ float quad_form3_mul_vec(quad_form3_t Q, vec3 M) { typedef struct{ vec3 pos; vec3 color; - float magnitude; + vec3 color_2; + float phase; + float progress; } LightSourceState; #include "../../../gen/l1/eve/r4/VecLightSourceState.h" @@ -79,7 +81,7 @@ vec3 project_dir_onto_plane_xz(vec3 v){ return (vec3){xz.x, 0, xz.y}; } -typedef struct{ +typedef struct { Alice* alice; LucyFace* font_face; RBTreeNodeLucyFaceFixedSize* font_face_of_size_40; @@ -96,6 +98,8 @@ typedef struct{ U64 misses_count; U64 hits_count; Vecvec3 bullets_stuck_on_ROA; + + VecRefListNodeAliceGenericMeshHand skeleton_meshes; } R4BetaState; /* We are surrounded by a giant cubic mesh of light sources */ @@ -116,6 +120,21 @@ void physics_update(R4BetaState* st, float t){ roa_st->rot = mat3_mul_mat3(rot_gain, roa_st->rot); } +void flickering_lights_update(R4BetaState* st, float t) { + VecLightSourceState* ls = &st->LS_state; + for (size_t i = 0; i < ls->len; i++) { + LightSourceState* light = &ls->buf[i]; + light->phase += t; + check(fabsf(light->progress) < 10); + light->progress += t / 2; + while (light->progress > 1) { + light->progress -= 1; + light->color = light->color_2; + light->color_2 = sample_rainbow_color(); + } + } +} + /* Changs linear and rotational speed of RigidBody based on the impact with bullet. * It does not update mass, moment of intertia, center of mass of rigid body. It is as if the bullet was * very light compared to rigid body. @@ -249,6 +268,7 @@ void main_h_on_another_frame(void* data, float fl){ alice->cam_info.cam.pos = st->hero_pos; physics_update(st, fl); + flickering_lights_update(st, fl); AliceGenericMeshHand_set_inst(&st->ROA_mesh->el, 0, (GenericMeshInstanceInc){ .model_t = RigidBodyState_get_tran_mat_of_mesh(&st->ROA_state), @@ -259,12 +279,16 @@ void main_h_on_another_frame(void* data, float fl){ for (size_t i = 0; i < st->LS_state.len; i++) { LightSourceState* ls = &st->LS_state.buf[i]; + float magnitude = 1.3f + 1 * sinf(ls->phase); + vec3 color = vec3_mul_scal(vec3_add_vec3( + vec3_mul_scal(ls->color, 1 - ls->progress), vec3_mul_scal(ls->color_2, ls->progress)), + magnitude); AliceShinyMeshHand_set_inst(&st->LS_mesh->el, i, (ShinyMeshInstanceInc){ - .color_on = ls->color, + .color_on = color, .model_t = marie_translation_mat4(ls->pos), }); ubo->point_light_arr[i] = (Pipeline0PointLight){ - .pos = ls->pos, .color = vec3_mul_scal(ls->color, 21)}; + .pos = ls->pos, .color = vec3_mul_scal(color, 21)}; } if (st->LS_state.len + st->bullets_stuck_on_ROA.len > st->LS_mesh->el.instance_attr.count) { AliceShinyMeshHand_resize_instance_arr(alice, &st->LS_mesh->el, st->LS_state.len + st->bullets_stuck_on_ROA.len); @@ -299,6 +323,169 @@ void main_h_on_another_frame(void* data, float fl){ VecU8_drop(text); } +void gltf_file_structure_get_accessor_iter_range(const GLBFileSegments* segments, const GltfFileStructure* gltf, + const GltfAccessor* accsr, SpanU8* ret_span, U64* ret_stride) { + U64 bv_id = accsr->buffer_view; + const GltfBufferView* buffer_view = &gltf->buffer_views.buf[bv_id]; + const GltfBuffer* buffer = &gltf->buffers.buf[buffer_view->buffer]; + check(!buffer->is_external); // Not supported yet + SpanU8 s2 = SpanU8_span(segments->bin_segment, buffer_view->offset, buffer_view->length); + *ret_span = SpanU8_span(s2, accsr->offset, s2.len - accsr->offset); + U64 stride = buffer_view->stride; + if (stride == 0) + stride = GltfAccessor_get_type_size(accsr); + *ret_stride = stride; +} + +mat4 trs_mat4(vec3 translation, quaternion_t rotation, vec3 scale) { + return mat4_mul_mat4(mat4_mul_mat4( + marie_translation_mat4(translation), + marie_mat3_to_mat4(unit_quaternion_fl_to_rot3d_mat3(rotation))), + marie_3d_scale_mat4(scale)); +} + +/* This function assumes that we are in little-endian */ +void add_meshes_for_gltf_structure__h_rec(Alice* alice, const GLBFileSegments* segments, const GltfFileStructure* gltf, + VecGenericMeshVertexInc* res, mat4 parent_transform, U64 node_id, int rem_depth, int depth) { + check(rem_depth > 0); + check(node_id < gltf->nodes.len); + const GltfNode* node = &gltf->nodes.buf[node_id]; + + mat4 transform; + if (node->trans.variant == GltfNodeTransformation_mat) { + transform = node->trans.mat; + } else if (node->trans.variant == GltfNodeTransformation_trs) { + transform = trs_mat4(node->trans.trs.translation, node->trans.trs.rotation, node->trans.trs.scale); + } else { + transform = mat4_E; + } + mat4 my_transform = mat4_mul_mat4(parent_transform, transform); + + for (int i = 0; i < depth; i++) + printf("===="); + VecU8_print(VecU8_fmt("> Node %u \"%r\" %v\n", node_id, node->name, + node->mesh.variant ? + VecU8_fmt("mesh \"%r\"", gltf->meshes.buf[node->mesh.some].name) : + vcstr("no mesh"))); + + if (node->mesh.variant == Option_Some) { + check(node->mesh.some < gltf->meshes.len); + const GltfMesh* mesh = &gltf->meshes.buf[node->mesh.some]; + check(mesh->primitives.len == 1); // Don't you ever dare + const GltfMeshPrimitivePart* prim = &mesh->primitives.buf[0]; + check(prim->position.variant == Option_Some); + check(prim->mode == GltfPrimitiveMode_triangles); + + const GltfAccessor* position_accsr = &gltf->accessors.buf[prim->position.some]; + check(position_accsr->matrix_type == GltfAccessorMatrixType_vec3); + check(position_accsr->component_type == GltfAccessorComponentType_float); + + U64 VN = position_accsr->count; + VecGenericMeshVertexInc vert_stuck = VecGenericMeshVertexInc_new_zeroinit(VN); + SpanU8 POSITION; + U64 POSITION_stride; + gltf_file_structure_get_accessor_iter_range(segments, gltf, position_accsr, &POSITION, &POSITION_stride); + + for (size_t i = 0; i < VN; i++) { + vec3 pos_here; + memcpy(&pos_here, POSITION.data + POSITION_stride * i, sizeof(vec3)); + vec4 pos_over_there = mat4_mul_vec4(my_transform, vec3_and_one(pos_here)); + vert_stuck.buf[i].pos = (vec3){pos_over_there.x, pos_over_there.y, pos_over_there.z}; + } + + if (prim->texcoord_0.variant) { + const GltfAccessor* texcoord_0_accsr = &gltf->accessors.buf[prim->texcoord_0.some]; + check(texcoord_0_accsr->matrix_type == GltfAccessorMatrixType_vec2); + check(texcoord_0_accsr->component_type == GltfAccessorComponentType_float); + check(texcoord_0_accsr->count == VN); + SpanU8 TEXCOORD; + U64 TEXCOORD_stride; + gltf_file_structure_get_accessor_iter_range(segments, gltf, texcoord_0_accsr, &TEXCOORD, &TEXCOORD_stride); + for (size_t i = 0; i < VN; i++) { + memcpy(&vert_stuck.buf[i].tex, TEXCOORD.data + TEXCOORD_stride * i, sizeof(vec2)); + } + } + + if (prim->indices.variant) { + const GltfAccessor* indices_accsr = &gltf->accessors.buf[prim->indices.some]; + check(indices_accsr->matrix_type == GltfAccessorMatrixType_scalar); + + U64 UN = indices_accsr->count; + check(UN % 3 == 0); + VecU32 indices_stuck = VecU32_new_zeroinit(UN); + SpanU8 INDICES; + U64 INDICES_stride; + gltf_file_structure_get_accessor_iter_range(segments, gltf, indices_accsr, &INDICES, &INDICES_stride); + if (indices_accsr->component_type == GltfAccessorComponentType_unsigned_int) { + check(INDICES_stride == 4); + for (size_t i = 0; i < UN; i++) { + U32 ind; + memcpy(&ind, INDICES.data + INDICES_stride * i, sizeof(U32)); + check(ind < VN); + indices_stuck.buf[i] = ind; + } + } else if (indices_accsr->component_type == GltfAccessorComponentType_unsigned_short) { + check(INDICES_stride == 2); + for (size_t i = 0; i < UN; i++) { + U16 ind; + memcpy(&ind, INDICES.data + INDICES_stride * i, sizeof(U16)); + check(ind < VN); + indices_stuck.buf[i] = ind; + } + } else { + check(false); + } + + VecGenericMeshVertexInc vertexes = VecGenericMeshVertexInc_new_zeroinit(UN); + for (U64 i = 0; i < UN; i++) { + vertexes.buf[i] = vert_stuck.buf[indices_stuck.buf[i]]; + } + + VecGenericMeshVertexInc_append_vec(res, vertexes); + VecGenericMeshVertexInc_drop(vert_stuck); + VecU32_drop(indices_stuck); + } else { + printf("Primitive without indices\n"); + VecGenericMeshVertexInc_append_vec(res, vert_stuck); + } + } + for (size_t chi = 0; chi < node->children.len; chi++) { + U64 child_node = node->children.buf[chi]; + add_meshes_for_gltf_structure__h_rec(alice, segments, gltf, res, my_transform, child_node, rem_depth - 1, depth + 1); + } +} + +void add_meshes_for_gltf_structure(Alice* alice, + const GLBFileSegments* segments, const GltfFileStructure* gltf, VecRefListNodeAliceGenericMeshHand* res) { + OptionU64 root_node = None_U64(); + for (size_t nid = 0; nid < gltf->nodes.len; nid++) { + const GltfNode* node = &gltf->nodes.buf[nid]; + if (!node->has_parent) { + root_node = Some_U64(nid); + break; + } + } + /* Right now, it might be not true */ + check(root_node.variant == Option_Some); + VecGenericMeshVertexInc vertexes = VecGenericMeshVertexInc_new(); + add_meshes_for_gltf_structure__h_rec(alice, segments, gltf, &vertexes, mat4_E, root_node.some, 20, 0); + VecU32 indices_12345 = VecU32_new_zeroinit(vertexes.len); + for (size_t i = 0; i < vertexes.len; i++) { + indices_12345.buf[i] = i; + } + + GenericMeshTopology tt = {vertexes, indices_12345}; + RefListNodeAliceGenericMeshHand hand = Alice_add_generic_mesh(alice, &tt, (AliceGenericMeshTexturePaths){ + .diffuse_texture_path = vcstr("./src/l3/models/bone.png"), + .normal_texture_path = vcstr("./gen/l2/textures/flat_NORMAL.png"), + .specular_texture_path = vcstr("./gen/l2/textures/flat_NORMAL.png"), + }); + AliceGenericMeshHand_resize_instance_arr(alice, &hand->el, 1); + AliceGenericMeshHand_set_inst(&hand->el, 0, (GenericMeshInstanceInc){ + .model_t = marie_translation_mat4((vec3){10, -25, 10})}); + VecRefListNodeAliceGenericMeshHand_append(res, hand); +} + void run_app(){ R4BetaState st; st.hero_pos = (vec3){0, 0.81f, 0}; @@ -373,12 +560,12 @@ void run_app(){ for (U64 i = 0; i < lighting_system_dim; i++) { for (U64 j = 0; j < lighting_system_dim; j++) { vec3 clr = sample_rainbow_color(); + vec3 clr2 = sample_rainbow_color(); VecLightSourceState_append(&st.LS_state, (LightSourceState){ .pos = vec3_add_vec3(dir, vec3_add_vec3( vec3_mul_scal(u, -light_cage_rad + light_case_edge_offset + light_case_gap * (float)i), vec3_mul_scal(v, -light_cage_rad + light_case_edge_offset + light_case_gap * (float)j))), - .color = clr, - .magnitude = 1 + .color = clr, .color_2 = clr2, .progress = 0, .phase = frand01() * 1.6f, }); } } @@ -395,6 +582,38 @@ void run_app(){ st.hits_count = 0; st.bullets_stuck_on_ROA = Vecvec3_new(); + st.skeleton_meshes = VecRefListNodeAliceGenericMeshHand_new(); + { + 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(); + } + GLBFileSegments segments = segments_r.ok; + VecU8_print(json_encode(&segments.gltf)); + printf("\n"); + ResultGltfFileStructureOrVecU8 structure_r = glb_file_get_structure(&segments); + if (structure_r.variant == Result_Err) { + printf("Something when parsing gltf\n"); + VecU8_print(structure_r.err); + printf("\n"); + GLBFileSegments_drop(segments); + VecU8_drop(file); + abort(); + } + GltfFileStructure gltf = structure_r.ok; + add_meshes_for_gltf_structure(alice, &segments, &gltf, &st.skeleton_meshes); + + // GltfFileStructure_debug_print(&gltf); + GltfFileStructure_drop(gltf); + GLBFileSegments_drop(segments_r.ok); + VecU8_drop(file); + } + Alice_mainloop(st.alice, &(AliceCallbacks){ .on_wl_pointer_button = main_h_on_wl_pointer_button, .on_wl_keyboard_key = main_h_on_wl_keyboard_key, @@ -403,28 +622,5 @@ void run_app(){ } int main(){ - 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(); - } - 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"); - VecU8_print(structure_r.err); - printf("\n"); - GLBFileSegments_drop(segments_r.ok); - VecU8_drop(file); - abort(); - } - GltfFileStructure_debug_print(&structure_r.ok); - GltfFileStructure_drop(structure_r.ok); - GLBFileSegments_drop(segments_r.ok); - VecU8_drop(file); + run_app(); }