diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d005b2..85808a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,11 +17,9 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) -#add_compile_options("-I/nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/pipewire-0.3 -I/nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/spa-0.2") +message(INFO ${LIBPIPEWIRE_CFLAGS}) -#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \ -# -I /nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/pipewire-0.3 \ -# -I /nix/store/2hm4rjvywd00p417y43i9rzx8v793qi0-pipewire-1.4.5-dev/include/spa-0.2 ") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBPIPEWIRE_CFLAGS}") add_compile_definitions(_POSIX_C_SOURCE=200112L) add_compile_definitions(_GNU_SOURCE) @@ -43,8 +41,12 @@ add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) #add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c) #target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon) # -#add_executable(2a_render_test src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c) -#target_link_libraries(2a_render_test ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon) +add_executable(r2a src/l2/tests/r2/r2a.c gen/l_wl_protocols/xdg-shell-private.c) +target_link_libraries(r2a ${LIBPIPEWIRE_LIBS} -lwayland-client -lrt -lm -lxkbcommon) + +add_executable(r2c src/l2/tests/r2/r2c.c) +target_link_libraries(r2c -lm) + # #add_executable(3_render_test src/l2/tests/r3/r3.c gen/l_wl_protocols/xdg-shell-private.c) #target_link_libraries(3_render_test -lwayland-client -lm -lvulkan -lxkbcommon) diff --git a/src/l1/core/VecU8_as_str.h b/src/l1/core/VecU8_as_str.h index 2922b50..92678ae 100644 --- a/src/l1/core/VecU8_as_str.h +++ b/src/l1/core/VecU8_as_str.h @@ -209,7 +209,7 @@ NODISCARD VecU8 VecU8_fmt(const char* fmt, ...) { } // todo: generate a special span method to check equality of contents -bool strings_in_spans_equal(SpanU8 a, SpanU8 b) { +bool SpanU8_cont_equal(SpanU8 a, SpanU8 b) { if (a.len != b.len) return false; for (size_t i = 0; i < a.len; i++) { diff --git a/src/l1_4/tests/t2.c b/src/l1_4/tests/t2.c index 0016d01..1d36224 100644 --- a/src/l1_4/tests/t2.c +++ b/src/l1_4/tests/t2.c @@ -3,38 +3,38 @@ int main(){ { VecU8 res = VecU8_fmt("%i", 0); - check(strings_in_spans_equal(VecU8_to_span(&res), cstr("0"))); + check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("0"))); VecU8_drop(res); } { VecU8 res = VecU8_fmt("%i%i%i%i", -1LL, 0LL, 44LL, -231LL); - check(strings_in_spans_equal(VecU8_to_span(&res), cstr("-1044-231"))); + check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("-1044-231"))); VecU8_drop(res); } { VecU8 res = VecU8_fmt("%i", 44LL); - check(strings_in_spans_equal(VecU8_to_span(&res), cstr("44"))); + check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("44"))); VecU8_drop(res); } { VecU8 res = VecU8_fmt("%u", 44ULL); - check(strings_in_spans_equal(VecU8_to_span(&res), cstr("44"))); + check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("44"))); VecU8_drop(res); } { VecU8 res = VecU8_fmt("%u %i", 18446744073709551615ULL, -1LL); - check(strings_in_spans_equal(VecU8_to_span(&res), cstr("18446744073709551615 -1"))); + check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("18446744073709551615 -1"))); VecU8_drop(res); } { VecU8 res = VecU8_fmt("%i %i", 9223372036854775807LL, -9223372036854775807LL-1); - check(strings_in_spans_equal(VecU8_to_span(&res), cstr("9223372036854775807 -9223372036854775808"))); + check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("9223372036854775807 -9223372036854775808"))); VecU8_drop(res); } { VecU8 vec2 = vcstr("vec2"); VecU8 res = VecU8_fmt("%i %v %i", -1230LL, vec2, 1340LL); - check(strings_in_spans_equal(VecU8_to_span(&res), cstr("-1230 vec2 1340"))); + check(SpanU8_cont_equal(VecU8_to_span(&res), cstr("-1230 vec2 1340"))); VecU8_drop(res); } return 0; diff --git a/src/l1_5/anne/codegen.c b/src/l1_5/anne/codegen.c index a451285..9d21a5f 100644 --- a/src/l1_5/anne/codegen.c +++ b/src/l1_5/anne/codegen.c @@ -7,6 +7,7 @@ int main() { mkdir_nofail("l1_5"); + mkdir_nofail("l1_5/eve"); generate_l1_5_liza_headers(); generate_l1_5_template_instantiation_for_base_types(); generate_l1_5_template_instantiations_for_margaret(); diff --git a/src/l1_5/anne/liza.h b/src/l1_5/anne/liza.h index 68c82d4..0a41df6 100644 --- a/src/l1_5/anne/liza.h +++ b/src/l1_5/anne/liza.h @@ -4,8 +4,30 @@ #include "../codegen/trait_wrap_boil.h" void generate_l1_5_liza_headers() { - mkdir_nofail("l1_5/liza"); - // todo: use#include "../codegen/trait_wrap_boil.h" + mkdir_nofail("l1_5/eve/liza"); + SpanU8 l = cstr("l1_5"), ns = cstr("liza"); + generate_trait_wrapper_templ_inst_eve_header(l, ns, (trait_wrapper_boil_options){ + .trait = { + .name = cstr("LizaInstrument"), + .methods = (SpanNamedMethodSignatureRecordRef){ + // todo: request options for instrument + .data = (NamedMethodSignatureRecordRef[]){ + { + .takes_self = true, + .params = (SpanNamedVariableRecordRef){ + .data = (NamedVariableRecordRef[]){ + {.type = cstr("double"), .name = cstr("frequency") }, + { .type = cstr("double"), .name = cstr("time") }, + }, .len = 2 + }, + .return_type = cstr("BoxLizaSound"), + .name = cstr("ding"), + } + }, .len = 1 + } + }, + .box = true, .ref = true, .mut_ref = true + }); } #endif \ No newline at end of file diff --git a/src/l1_5/codegen/rbtree_set_map_template_inst.h b/src/l1_5/codegen/rbtree_set_map_template_inst.h index b28457f..68028db 100644 --- a/src/l1_5/codegen/rbtree_set_map_template_inst.h +++ b/src/l1_5/codegen/rbtree_set_map_template_inst.h @@ -414,7 +414,8 @@ NODISCARD VecU8 generate_rbtree_Map_template_instantiation(map_instantiation_op return res; } -void generate_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op, bool generate_node_struct) { +void generate_rbtree_Map_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, map_instantiation_op op, + bool generate_node_struct) { generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_rbtree_Map_template_instantiation(op, generate_node_struct), get_name_of_rbtree_map_structure(op)); } diff --git a/src/l1_5/codegen/trait_wrap_boil.h b/src/l1_5/codegen/trait_wrap_boil.h index 97b5332..7dd20fc 100644 --- a/src/l1_5/codegen/trait_wrap_boil.h +++ b/src/l1_5/codegen/trait_wrap_boil.h @@ -11,6 +11,8 @@ typedef struct { #include "../../../gen/l1/eve/embassy_l1_5/SpanNamedVariableRecordRef.h" typedef struct { + bool takes_self; + bool takes_mut_self; SpanNamedVariableRecordRef params; SpanU8 return_type; SpanU8 name; @@ -20,24 +22,30 @@ typedef struct { typedef struct { SpanNamedMethodSignatureRecordRef methods; + bool drop_primitive; SpanU8 name; } NamedTraitDefRecordRef; NODISCARD VecU8 generate_trait_table_structure(NamedTraitDefRecordRef trait){ - VecU8 res = VecU8_from_cstr("typedef struct {"); - // todo: add iteration macro + VecU8 res = VecU8_from_cstr("typedef struct {\n"); for (size_t i = 0; i < trait.methods.len; i++) { NamedMethodSignatureRecordRef method = *SpanNamedMethodSignatureRecordRef_at(trait.methods, i); VecU8_append_vec(&res, VecU8_fmt(SPACE "%s (*%s)(", method.return_type, method.name)); + if (method.takes_self) { + VecU8_append_span(&res, method.takes_mut_self ? cstr("void*") : cstr("const void*")); + } for (size_t p = 0; p < method.params.len; p++) { NamedVariableRecordRef param = *SpanNamedVariableRecordRef_at(method.params, p); - if (p) + if (p || method.takes_self) VecU8_append_span(&res, cstr(", ")); VecU8_append_span(&res, param.type); } VecU8_append_span(&res, cstr(");\n")); } - VecU8_append_vec(&res, VecU8_fmt("} %s;\n\n", trait.name)); + if (!trait.drop_primitive) { + VecU8_append_span(&res, cstr(SPACE "void (*drop)(void*);\n")); + } + VecU8_append_vec(&res, VecU8_fmt("} %s_Table;\n\n", trait.name)); return res; } @@ -48,10 +56,114 @@ typedef struct { bool mut_ref; } trait_wrapper_boil_options; +/* (refkind, self_as_ptr) in {(Ref, false), (MutRef, false), (Box, true)} */ +void codegen_append_trait_wrapper_some_method_some_refkind(VecU8* res, SpanU8 trait_name, + NamedMethodSignatureRecordRef method, SpanU8 refkind, bool self_as_ptr){ + VecU8_append_vec(res, VecU8_fmt( + "%s %s%s_%s(%s%s%s self", + /* return_type, refkind, trait.name, method.name, refkind, trait.name */ + method.return_type, refkind, trait_name, method.name, refkind, trait_name, self_as_ptr ? cstr("*") : cstr(""))); + for (size_t p = 0; p < method.params.len; p++) { + NamedVariableRecordRef param = method.params.data[p]; + VecU8_append_vec(res, VecU8_fmt(", %s %s", param.type, param.name)); + } + VecU8_append_span(res, cstr("){\n" SPACE)); + if (!SpanU8_cont_equal(method.return_type, cstr("void"))) + VecU8_append_span(res, cstr("return ")); + VecU8_append_vec(res, VecU8_fmt("self%s""t->%s(", + self_as_ptr ? cstr("->") : cstr("."), + method.name)); + if (method.takes_self) { + VecU8_append_vec(res, VecU8_fmt("self%s""r", self_as_ptr ? cstr("->") : cstr("."))); + } + for (size_t p = 0; p < method.params.len; p++) { + NamedVariableRecordRef param = method.params.data[p]; + if (p > 0 || method.takes_self) + VecU8_append_span(res, cstr(", ")); + VecU8_append_span(res, param.name); + } + VecU8_append_span(res, cstr(");\n}\n\n")); +} + NODISCARD VecU8 generate_trait_wrapper_boilerplate(trait_wrapper_boil_options op) { + /* Checking */ + for (size_t i = 0; i < op.trait.methods.len; i++) { + NamedMethodSignatureRecordRef method = op.trait.methods.data[i]; + assert(!method.takes_mut_self || method.takes_self); + } + VecU8 res = VecU8_new(); - // todo: write it + VecU8_append_vec(&res, generate_trait_table_structure(op.trait)); + if (op.ref) { + VecU8_append_vec(&res, VecU8_fmt( + "typedef struct {\n" + SPACE "const void* r;\n" + SPACE "const %s_Table* t;\n" /* op.trait.name */ + "} Ref%s;\n\n", /* op.trait.name */ + op.trait.name, op.trait.name)); + for (size_t i = 0; i < op.trait.methods.len; i++) { + NamedMethodSignatureRecordRef method = op.trait.methods.data[i]; + if (method.takes_mut_self) + continue; + codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("Ref"), false); + } + } + if (op.mut_ref) { + VecU8_append_vec(&res, VecU8_fmt( + "typedef struct {\n" + SPACE "void* r;\n" + SPACE "const %s_Table* t;\n" + "} MutRef%s;\n\n", + op.trait.name, op.trait.name)); + for (size_t i = 0; i < op.trait.methods.len; i++) { + NamedMethodSignatureRecordRef method = op.trait.methods.data[i]; + codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("MutRef"), false); + } + } + if (op.box) { + VecU8_append_vec(&res, VecU8_fmt( + "typedef struct {\n" + SPACE "void* r;\n" + SPACE "const %s_Table* t;\n" + "} Box%s;\n\n", + op.trait.name, op.trait.name)); + for (size_t i = 0; i < op.trait.methods.len; i++) { + NamedMethodSignatureRecordRef method = op.trait.methods.data[i]; + codegen_append_trait_wrapper_some_method_some_refkind(&res, op.trait.name, method, cstr("Box"), true); + } + VecU8_append_vec(&res, VecU8_fmt( + "void Box%s_drop(Box%s self){\n" /* trait.name, trait.name */ + "%s" /* epsilon / calling self.t->drop() */ + SPACE "free(self.r);\n" + "}\n\n", + op.trait.name, op.trait.name, + op.trait.drop_primitive ? cstr("") : cstr(SPACE "self.t->drop(self.r);\n"))); + if (op.ref) { + VecU8_append_vec(&res, VecU8_fmt( + "Ref%s Box%s_ref(Box%s *self) {\n" + SPACE "return (Ref%s){.r = self->r, .t = self->t};\n" + "}\n\n", op.trait.name, op.trait.name, op.trait.name, op.trait.name)); + } + if (op.mut_ref) { + VecU8_append_vec(&res, VecU8_fmt( + "MutRef%s Box%s_mut_ref(Box%s *self) {\n" + SPACE "return (MutRef%s){.r = self->r, .t = self->t};\n" + "}\n\n", op.trait.name, op.trait.name, op.trait.name, op.trait.name)); + } + } return res; } +void generate_trait_wrapper_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, trait_wrapper_boil_options op){ + generate_SOME_templ_inst_eve_header(layer, bonus_ns, generate_trait_wrapper_boilerplate(op), + VecU8_from_span(op.trait.name)); +} + +void generate_trait_wrapper_templ_inst_guarded_header(SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, + trait_wrapper_boil_options op){ + generate_SOME_templ_inst_guarded_header(layer, bonus_ns, + VecU8_fmt("#include \n%s", dependencies), + generate_trait_wrapper_boilerplate(op), VecU8_from_span(op.trait.name)); +} + #endif \ No newline at end of file diff --git a/src/l1_5/core/stringop.h b/src/l1_5/core/stringop.h index 616fee3..a40efda 100644 --- a/src/l1_5/core/stringop.h +++ b/src/l1_5/core/stringop.h @@ -29,7 +29,7 @@ bool string_contains_string_ignorecase(SpanU8 str1, SpanU8 str2) { bool is_string_in_string_vec(SpanU8 a, const VecVecU8* B) { for (size_t i = 0; i < B->len; i++) { - if (strings_in_spans_equal(a, VecU8_to_span(VecVecU8_at(B, i)))) + if (SpanU8_cont_equal(a, VecU8_to_span(VecVecU8_at(B, i)))) return true; } return false; diff --git a/src/l2/allie/allie.c b/src/l2/allie/allie.c index 9a9c79f..5be76a9 100644 --- a/src/l2/allie/allie.c +++ b/src/l2/allie/allie.c @@ -2032,15 +2032,6 @@ void Alice_set_point_light(Alice* alice, int index, Pipeline0PointLight data){ ubo->point_light_arr[index] = data; } - -void Alice_clear_screen_text(Alice* alice){ - LucyRenderer_clear(&alice->lucy_renderer); -} - -void Alice_add_screen_text(Alice* alice, RBTreeNodeLucyFaceFixedSize* ffs, vec4 color, SpanU8 text, ivec2 start_pos){ - LucyRenderer_add_text(&alice->lucy_renderer, ffs, color, 0, text, start_pos); -} - /* This function actually consumes alice handler. Alice must not be used after */ void Alice_mainloop(Alice* alice, const AliceCallbacks* callbacks) { alice->callbacks.on_wl_keyboard_key = callbacks->on_wl_keyboard_key; @@ -2132,7 +2123,7 @@ void allie_alice_clear_text(Alice* alice){ void allie_alice_add_text(Alice* alice, RBTreeNodeLucyFaceFixedSize* ffs, float color_x, float color_y, float color_z, float color_w, const U8* text_data, U64 text_len, S32 start_pos_x, S32 start_pos_y){ - LucyRenderer_add_text(&alice->lucy_renderer, ffs, (vec4){color_x, color_y, color_z, color_w}, 0, + LucyRenderer_add_simple_label(&alice->lucy_renderer, ffs, (vec4){color_x, color_y, color_z, color_w}, 0, (SpanU8){text_data, text_len}, (ivec2){start_pos_x, start_pos_y}); } diff --git a/src/l2/liza/instrument.h b/src/l2/liza/instrument.h index 618f0a8..5af7158 100644 --- a/src/l2/liza/instrument.h +++ b/src/l2/liza/instrument.h @@ -3,35 +3,7 @@ #include "playing_sound_loop.h" -// todo: rewrite with the help of l1_5 - -typedef struct { - /* self (takes ownership) */ - void (*drop)(void*); - /* self, frequency, time, returns: new sound box */ - BoxLizaSound (*ding)(const void*, double, double); - // todo: request options for instrument -} LizaInstrument_Table; - -typedef struct { - const void* r; - const LizaInstrument_Table* t; -} RefLizaInstrument; - -typedef struct { - void* r; - const LizaInstrument_Table* t; -} MutLizaInstrument; - -typedef struct { - void* m; - const LizaInstrument_Table* t; -} BoxLizaInstrument; - -void BoxLizaInstrument_drop(BoxLizaInstrument self) { - self.t->drop(self.m); -} - +#include "../../../gen/l1_5/eve/liza/LizaInstrument.h" #include "../../../gen/l1/eve/liza/VecBoxLizaInstrument.h" diff --git a/src/l2/liza/playing_sound_loop.h b/src/l2/liza/playing_sound_loop.h index 6008bd6..87db4a3 100644 --- a/src/l2/liza/playing_sound_loop.h +++ b/src/l2/liza/playing_sound_loop.h @@ -4,6 +4,7 @@ // todo: move loop here and rewrite with l1_5 help #include "../../l1/core/int_primitives.h" +#include typedef struct { /* self (takes ownership) */ diff --git a/src/l2/lucy/glyph_render.h b/src/l2/lucy/glyph_render.h index 11d05dc..9641a74 100644 --- a/src/l2/lucy/glyph_render.h +++ b/src/l2/lucy/glyph_render.h @@ -6,12 +6,12 @@ #include "../../../gen/l1/geom.h" // todo: rewrite this crrp crap using instances -typedef struct{ - vec4 color; - vec2 pos; - vec2 tex_cord; - U32 tex_ind; -} LucyVertex; +// typedef struct{ +// vec4 color; +// vec2 pos; +// vec2 tex_cord; +// U32 tex_ind; +// } LucyVertex; typedef struct { @@ -20,7 +20,8 @@ typedef struct { vec2 br_pos; vec2 lt_tex; vec2 br_tex; -} LucyGlyphInstance; + U32 tex_ind; +} LucyRenderInstance; typedef struct { MargaretEngineReference ve; @@ -60,17 +61,21 @@ LucyRenderer LucyRenderer_new( .fragment_shader_code = read_file_by_path(VecU8_fmt("%s/gen/l_adele/lucy/frag.spv", root_dir)), .vertexBindingDescriptionCount = 1, .pVertexBindingDescriptions = (VkVertexInputBindingDescription[]){ - { .binding = 0, .stride = sizeof(LucyVertex), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX } }, - .vertexAttributeDescriptionCount = 4, + { .binding = 0, .stride = sizeof(LucyRenderInstance), .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE } }, + .vertexAttributeDescriptionCount = 6, .pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]){ {.location = 0, .binding = 0, - .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(LucyVertex, color)}, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = offsetof(LucyRenderInstance, color)}, {.location = 1, .binding = 0, - .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyVertex, pos)}, + .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, lt_pos)}, {.location = 2, .binding = 0, - .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyVertex, tex_cord)}, + .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, br_pos)}, {.location = 3, .binding = 0, - .format = VK_FORMAT_R32_UINT, .offset = offsetof(LucyVertex, tex_ind)}, + .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, lt_tex)}, + {.location = 4, .binding = 0, + .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(LucyRenderInstance, br_tex)}, + {.location = 5, .binding = 0, + .format = VK_FORMAT_R32_UINT, .offset = offsetof(LucyRenderInstance, tex_ind)}, }, .depthTestEnable = false, .depthWriteEnable = false, .blendEnable = true, }); @@ -88,10 +93,44 @@ void LucyRenderer_clear(LucyRenderer* self){ self->glyphs_count = 0; } +void LucyRenderer_draw_char_glyph(LucyRenderer* self, vec4 color, ivec2 pos, LucyStoredGlyph* glyph){ + if (glyph->w > 0 && glyph->h > 0) { + OptionLucyImage* img_slot = VecOptionLucyImage_mat(&self->cache->image_slots, glyph->img_slot_id); + assert(img_slot->variant == Option_Some); + LucyImage* img = &img_slot->some; + float atlas_w = (float)img->img.width; + float atlas_h = (float)img->img.height; + ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing); + + U64 needed_vbo_length = (self->glyphs_count + 1) * sizeof(LucyRenderInstance); + if (self->staging_vbo.len < needed_vbo_length) { + printf("LucyRenderer Staging Buffer: Gotta replace %lu with %lu\n", + self->staging_vbo.len, needed_vbo_length); + MargaretBufAllocator_expand_or_move_old_host_visible( + self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length); + } + + LucyRenderInstance* vbo_data = (LucyRenderInstance*)MargaretSubbuf_get_mapped(&self->staging_vbo); + vbo_data[self->glyphs_count++] = (LucyRenderInstance){ + .color = color, + .lt_pos = (vec2){(float)positioned.x, (float)positioned.y}, + .br_pos = (vec2){(float)(positioned.x + glyph->w), (float)(positioned.y + glyph->h)}, + .lt_tex = (vec2){ + (float)(glyph->pos_on_atlas.x) / atlas_w, + (float)(glyph->pos_on_atlas.y) / atlas_h + }, + .br_tex = (vec2){ + (float)(glyph->pos_on_atlas.x + glyph->w) / atlas_w, + (float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h + }, .tex_ind = glyph->img_slot_id + }; + } +} + /* When another_frame starts, you are safe to call this function, but you also have to call it * before LucyRenderer_another_frame, because _another_frame method records transfer of data */ -void LucyRenderer_add_text( +void LucyRenderer_add_simple_label( LucyRenderer* self, RBTreeNodeLucyFaceFixedSize* ffs, vec4 color, U32 additional_y_advance, SpanU8 text, ivec2 start_pos ){ @@ -114,70 +153,14 @@ void LucyRenderer_add_text( } assert(map_it > 0 && map_it < glyphs->tree.len); LucyStoredGlyph* glyph = &glyphs->el.buf[map_it - 1].value; - if (glyph->w > 0 && glyph->h > 0) { - OptionLucyImage* img_slot = VecOptionLucyImage_mat(&self->cache->image_slots, glyph->img_slot_id); - assert(img_slot->variant == Option_Some); - LucyImage* img = &img_slot->some; - float atlas_w = (float)img->img.width; - float atlas_h = (float)img->img.height; - U32 desc_elem_id = glyph->img_slot_id; - ivec2 positioned = ivec2_add_ivec2(pos, glyph->bearing); - - U64 needed_vbo_length = (self->glyphs_count + 1) * 6 * sizeof(LucyVertex); - if (self->staging_vbo.len < needed_vbo_length) { - printf("LucyRenderer Staging Buffer: Gotta replace %lu with %lu\n", - self->staging_vbo.len, needed_vbo_length); - MargaretBufAllocator_expand_or_move_old_host_visible( - self->ve.staging_buffers, &self->staging_vbo, needed_vbo_length); - } - - LucyVertex* vbo_data = (LucyVertex*)MargaretSubbuf_get_mapped(&self->staging_vbo); - vbo_data += self->glyphs_count * 6; - - LucyVertex v0 = { - .color = color, .pos = (vec2){(float)positioned.x, (float)positioned.y}, - .tex_cord = (vec2){ - (float)(glyph->pos_on_atlas.x) / atlas_w, - (float)(glyph->pos_on_atlas.y) / atlas_h - }, .tex_ind = desc_elem_id - }; - LucyVertex v1 = { - .color = color, .pos = (vec2){(float)(positioned.x + glyph->w), (float)positioned.y}, - .tex_cord = (vec2){ - (float)(glyph->pos_on_atlas.x + glyph->w) / atlas_w, - (float)(glyph->pos_on_atlas.y) / atlas_h - }, .tex_ind = desc_elem_id - }; - LucyVertex v2 = { - .color = color, .pos = (vec2){(float)positioned.x, (float)(positioned.y + glyph->h)}, - .tex_cord = (vec2){ - (float)(glyph->pos_on_atlas.x) / atlas_w, - (float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h - }, .tex_ind = desc_elem_id - }; - LucyVertex v3 = { - .color = color, .pos = (vec2){(float)(positioned.x + glyph->w), (float)(positioned.y + glyph->h)}, - .tex_cord = (vec2){ - (float)(glyph->pos_on_atlas.x + glyph->w) / atlas_w, - (float)(glyph->pos_on_atlas.y + glyph->h) / atlas_h - }, .tex_ind = desc_elem_id - }; - *(vbo_data++) = v1; - *(vbo_data++) = v0; - *(vbo_data++) = v2; - *(vbo_data++) = v1; - *(vbo_data++) = v2; - *(vbo_data++) = v3; - - self->glyphs_count++; - } + LucyRenderer_draw_char_glyph(self, color, pos, glyph); pos.x += (S32)glyph->advance_x; } } /* It only records transfer commands (transfer command buffer is passed in MargaretEngineReference object) */ void LucyRenderer_another_frame(LucyRenderer* self){ - U64 needed_vbo_length = self->glyphs_count * 6 * sizeof(LucyVertex); + U64 needed_vbo_length = self->glyphs_count * sizeof(LucyRenderInstance); if (self->vbo.len < needed_vbo_length) { MargaretBufAllocator_expand_or_free_old(self->ve.dev_local_buffers, &self->vbo, needed_vbo_length); } @@ -201,7 +184,7 @@ void LucyRenderer_another_frame_rec_drawing( (VkBuffer[]){MargaretSubbuf_get_buffer(&self->vbo)}, (VkDeviceSize[]){self->vbo.start}); vkCmdBindDescriptorSets(drawing_cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, self->pipeline_layout, 0, 1, (VkDescriptorSet[]){self->cache->descriptor_set}, 0, NULL); - vkCmdDraw(drawing_cmd_buf, self->glyphs_count * 6, 1, 0, 0); + vkCmdDraw(drawing_cmd_buf, 6, self->glyphs_count, 0, 0); } #endif \ No newline at end of file diff --git a/src/l2/tests/r2/liza_collection.h b/src/l2/tests/r2/liza_collection.h index 62a2310..5bd2f1e 100644 --- a/src/l2/tests/r2/liza_collection.h +++ b/src/l2/tests/r2/liza_collection.h @@ -105,7 +105,7 @@ const LizaInstrument_Table LizaInstrument_Table_WeirdGuitar = { BoxLizaInstrument BoxLizaInstrument_from_WeirdGuitar(WeirdGuitar obj) { void* mem = safe_malloc(sizeof(WeirdGuitar)); memcpy(mem, &obj, sizeof(WeirdGuitar)); - return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_WeirdGuitar}; + return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_WeirdGuitar}; } /* ElectroBlaster which produces AmplitudeModulationSound */ @@ -192,7 +192,7 @@ const LizaInstrument_Table LizaInstrument_Table_AMKeys = { BoxLizaInstrument BoxLizaInstrument_from_AMKeys(AMKeys obj) { void* mem = safe_malloc(sizeof(AMKeys)); memcpy(mem, &obj, sizeof(AMKeys)); - return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_AMKeys}; + return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_AMKeys}; } /* FMKeys which produces FrequencyModulationSound */ @@ -278,7 +278,7 @@ const LizaInstrument_Table LizaInstrument_Table_FMKeys = { BoxLizaInstrument BoxLizaInstrument_from_FMKeys(FMKeys obj) { void* mem = safe_malloc(sizeof(FMKeys)); memcpy(mem, &obj, sizeof(FMKeys)); - return (BoxLizaInstrument){.m = mem, .t = &LizaInstrument_Table_FMKeys}; + return (BoxLizaInstrument){.r = mem, .t = &LizaInstrument_Table_FMKeys}; } diff --git a/src/l2/tests/r2/r2a.c b/src/l2/tests/r2/r2a.c index 3d288bf..604aa4d 100644 --- a/src/l2/tests/r2/r2a.c +++ b/src/l2/tests/r2/r2a.c @@ -100,7 +100,8 @@ static void r2a_app_h_pw_stream_process(void *ug){ return; } struct spa_buffer *buf = b->buffer; - uint32_t stride = sizeof(int16_t) * DEFAULT_CHANNELS; + assert(buf->n_datas >= 1); + const uint32_t stride = sizeof(int16_t) * DEFAULT_CHANNELS; uint32_t n_frames = buf->datas[0].maxsize / stride; if (b->requested) n_frames = SPA_MIN(b->requested, n_frames); @@ -515,12 +516,12 @@ static void r2a_app_h_wl_keyboard_key( }; if (state->selected_instrument < state->instruments.len) { // todo: add box to ref and box to mref methods - const BoxLizaInstrument* instrument = &VecMyInstrument_at(&state->instruments, state->selected_instrument)->liza; + BoxLizaInstrument* instrument = &VecMyInstrument_mat(&state->instruments, state->selected_instrument)->liza; for (int i = 0; i < ARRAY_SIZE(octave); i++) { if (keysym == octave[i] && key_action == WL_KEYBOARD_KEY_STATE_PRESSED) { safe_pthread_mutex_lock(&state->audio_thread_bridge->mut); VecBoxLizaSound_append(&state->audio_thread_bridge->cmd.new_sounds, - instrument->t->ding(instrument->m, 440 * pow(2, (double)i / 12), 0.9)); + BoxLizaInstrument_ding(instrument, 440 * pow(2, (double)i / 12), 0.9)); safe_pthread_mutex_unlock(&state->audio_thread_bridge->mut); break; } diff --git a/src/l2/tests/r2/r2b.c b/src/l2/tests/r2/r2b.c index de11835..40e5e58 100644 --- a/src/l2/tests/r2/r2b.c +++ b/src/l2/tests/r2/r2b.c @@ -101,7 +101,7 @@ void BoxLizaSound_drop(BoxLizaSound self) { free(self.m); } -#include "../../../../gen/l2/eve/r2/VecBoxLizaSound.h" +#include "../../../../gen/l1/eve/r2/VecBoxLizaSound.h" typedef struct { bool stop; diff --git a/src/l2/tests/r2/r2c.c b/src/l2/tests/r2/r2c.c new file mode 100644 index 0000000..1dfba51 --- /dev/null +++ b/src/l2/tests/r2/r2c.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DESIRED_SAMPLE_RATE 44100 +#define DESIRED_CHANNELS 2 // Prefer stereo, as mono often not supported on hardware +#define DESIRED_PERIOD_SIZE 1024 +#define DESIRED_PERIODS 4 +#define FORMAT SNDRV_PCM_FORMAT_S16_LE +#define DURATION 5 // seconds +#define BYTES_PER_SAMPLE 2 + +int main() { + int card = -1, device = -1; + FILE *proc = fopen("/proc/asound/pcm", "r"); + if (!proc) { + perror("Failed to open /proc/asound/pcm"); + return 1; + } + + printf("Opened /proc/asound/pcm\n"); + + char line[256]; + while (fgets(line, sizeof(line), proc)) { + if (strstr(line, "playback")) { + sscanf(line, "%02d-%02d", &card, &device); + break; + } + } + fclose(proc); + + if (card < 0 || device < 0) { + fprintf(stderr, "No playback devices found\n"); + return 1; + } + + char devname[64]; + snprintf(devname, sizeof(devname), "/dev/snd/pcmC%dD%dp", card, device); + + int fd = open(devname, O_WRONLY); + if (fd < 0) { + perror("Failed to open PCM device"); + return 1; + } + + printf("Opened device\n"); + + struct snd_pcm_hw_params params; + memset(¶ms, 0, sizeof(params)); + + // Initialize to full possible ranges for refinement + int i; + for (i = SNDRV_PCM_HW_PARAM_FIRST_MASK; i <= SNDRV_PCM_HW_PARAM_LAST_MASK; i++) { + struct snd_mask *mask = ¶ms.masks[i - SNDRV_PCM_HW_PARAM_FIRST_MASK]; + mask->bits[0] = ~0U; + mask->bits[1] = ~0U; + } + for (i = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; i <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; i++) { + struct snd_interval *interval = ¶ms.intervals[i - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; + interval->min = 0; + interval->max = ~0U; + interval->openmin = interval->openmax = 0; + interval->integer = 0; + } + params.rmask = ~0U; + params.cmask = 0; + params.info = ~0U; + + // Refine to hardware-supported ranges + if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, ¶ms) < 0) { + perror("Failed initial HW_REFINE"); + close(fd); + return 1; + } + + printf("Refined hw params\n"); + + // Set access to RW_INTERLEAVED if supported + struct snd_mask *access_mask = ¶ms.masks[SNDRV_PCM_HW_PARAM_ACCESS - SNDRV_PCM_HW_PARAM_FIRST_MASK]; + unsigned int access_bit = SNDRV_PCM_ACCESS_RW_INTERLEAVED; + if (!(access_mask->bits[access_bit / 32] & (1U << (access_bit % 32)))) { + fprintf(stderr, "RW_INTERLEAVED access not supported\n"); + close(fd); + return 1; + } + memset(access_mask, 0, sizeof(*access_mask)); + access_mask->bits[access_bit / 32] |= (1U << (access_bit % 32)); + params.rmask |= (1U << SNDRV_PCM_HW_PARAM_ACCESS); + + // Set format to S16_LE if supported + struct snd_mask *format_mask = ¶ms.masks[SNDRV_PCM_HW_PARAM_FORMAT - SNDRV_PCM_HW_PARAM_FIRST_MASK]; + unsigned int format_bit = FORMAT; + if (!(format_mask->bits[format_bit / 32] & (1U << (format_bit % 32)))) { + fprintf(stderr, "S16_LE format not supported\n"); + close(fd); + return 1; + } + memset(format_mask, 0, sizeof(*format_mask)); + format_mask->bits[format_bit / 32] |= (1U << (format_bit % 32)); + params.rmask |= (1U << SNDRV_PCM_HW_PARAM_FORMAT); + + // Set channels to nearest supported (prefer DESIRED_CHANNELS) + struct snd_interval *channels_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_CHANNELS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; + unsigned int channels = DESIRED_CHANNELS; + if (channels < channels_int->min) channels = channels_int->min; + if (channels > channels_int->max) channels = channels_int->max; + if (channels != DESIRED_CHANNELS) { + fprintf(stderr, "Adjusted channels to %u (hardware range: %u-%u)\n", channels, channels_int->min, channels_int->max); + } + channels_int->min = channels_int->max = channels; + channels_int->integer = 1; + params.rmask |= (1U << SNDRV_PCM_HW_PARAM_CHANNELS); + + // Set sample rate to nearest supported + struct snd_interval *rate_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; + unsigned int sample_rate = DESIRED_SAMPLE_RATE; + if (sample_rate < rate_int->min) sample_rate = rate_int->min; + if (sample_rate > rate_int->max) sample_rate = rate_int->max; + if (sample_rate != DESIRED_SAMPLE_RATE) { + fprintf(stderr, "Adjusted sample rate to %u Hz (hardware range: %u-%u)\n", sample_rate, rate_int->min, rate_int->max); + } + rate_int->min = rate_int->max = sample_rate; + rate_int->integer = 1; + params.rmask |= (1U << SNDRV_PCM_HW_PARAM_RATE); + + // Set period size to nearest supported + struct snd_interval *period_size_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_PERIOD_SIZE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; + unsigned int period_size = DESIRED_PERIOD_SIZE; + if (period_size < period_size_int->min) period_size = period_size_int->min; + if (period_size > period_size_int->max) period_size = period_size_int->max; + if (period_size != DESIRED_PERIOD_SIZE) { + fprintf(stderr, "Adjusted period size to %u frames (hardware range: %u-%u)\n", period_size, period_size_int->min, period_size_int->max); + } + period_size_int->min = period_size_int->max = period_size; + period_size_int->integer = 1; + params.rmask |= (1U << SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + + // Set periods (less strict, clamp to range) + struct snd_interval *periods_int = ¶ms.intervals[SNDRV_PCM_HW_PARAM_PERIODS - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; + unsigned int periods = DESIRED_PERIODS; + if (periods < periods_int->min) periods = periods_int->min; + if (periods > periods_int->max) periods = periods_int->max; + if (periods != DESIRED_PERIODS) { + fprintf(stderr, "Adjusted periods to %u (hardware range: %u-%u)\n", periods, periods_int->min, periods_int->max); + } + periods_int->min = periods_int->max = periods; + periods_int->integer = 1; + params.rmask |= (1U << SNDRV_PCM_HW_PARAM_PERIODS); + + // Refine again with desired values to confirm + if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, ¶ms) < 0) { + perror("Failed to refine desired HW params"); + close(fd); + return 1; + } + + printf("Refined hw params the last time\n"); + + // Now apply the parameters + if (ioctl(fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms) < 0) { + perror("Failed to set HW params"); + close(fd); + return 1; + } + + printf("HW params set\n"); + + if (ioctl(fd, SNDRV_PCM_IOCTL_PREPARE, 0) < 0) { + perror("Failed to prepare PCM"); + close(fd); + return 1; + } + + printf("Prepared\n"); + + // Generate and play sine wave + size_t frame_size = channels * BYTES_PER_SAMPLE; + short *buffer = malloc(period_size * frame_size); + if (!buffer) { + perror("Failed to allocate buffer"); + close(fd); + return 1; + } + + unsigned long total_frames = (unsigned long)sample_rate * DURATION; + unsigned long frames_written = 0; + double phase = 0.0; + const double freq = 440.0; // Hz + const double phase_inc = 2.0 * M_PI * freq / sample_rate; + + while (frames_written < total_frames) { + size_t frames_to_write = period_size; + if (frames_written + frames_to_write > total_frames) { + frames_to_write = total_frames - frames_written; + } + + for (size_t j = 0; j < frames_to_write; ++j) { + short sample = (short)(32767.0 * sin(phase)); + for (unsigned int ch = 0; ch < channels; ++ch) { + buffer[j * channels + ch] = sample; + } + phase += phase_inc; + if (phase >= 2.0 * M_PI) phase -= 2.0 * M_PI; + } + + ssize_t bytes_written = write(fd, buffer, frames_to_write * frame_size); + printf("bytes written = %lu\n", bytes_written); + if (bytes_written < 0) { + if (errno == EPIPE) { + // Underrun: recover + ioctl(fd, SNDRV_PCM_IOCTL_PREPARE, 0); + continue; + } + perror("Write failed"); + break; + } + + frames_written += bytes_written / frame_size; + } + + free(buffer); + // Drain remaining data + ioctl(fd, SNDRV_PCM_IOCTL_DRAIN, 0); + close(fd); + return 0; +} \ No newline at end of file diff --git a/src/l3/r4/R4.hs b/src/l3/r4/R4.hs index 28eb866..5b75279 100644 --- a/src/l3/r4/R4.hs +++ b/src/l3/r4/R4.hs @@ -33,6 +33,14 @@ puckLevitationHeight = 0.4 + 0.2 puckSpots :: [Vec2] puckSpots = [(Vec2 (-10) (-10)), (Vec2 (-15) (-15)) , (Vec2 (-18) (-18)), (Vec2 (-18) (-25)), (Vec2 (-18) (-30))] +introText :: String +introText = "Накануне новогодняя сессия 2025 года. Все были готовы провести экзамен по матану, но злой Гринч похитил 67 " ++ + "шайб с бергамотом Матвея и улетел. Вся надежда была потеряна, но в полёте Гринч выронил все, и те упали в Дубки. Тебе " ++ + "необходимо вернуть их Матвею.\n" ++ + "Естесственно, вернёшь ты их Гринчу, так как ты и сам не понимаешь преобразования Фурье и хочешь помочь сорвать" ++ + "экзамен.\n\n" ++ + "Итак, ты в Дубках..." + main :: IO() main = do alice <- newAlice diff --git a/src/l3/r4/r4.c b/src/l3/r4/r4.c index 8133923..6f592fb 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -64,7 +64,7 @@ int main(){ }); LucyGlyphCache_add_glyphs(lucy_requests); - LucyRenderer_add_text(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0, + LucyRenderer_add_simple_label(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0, cstr("Bebra budet\nотнюхана\n"), (ivec2){10, 10}); ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6)); diff --git a/src/l_adele/lucy/lucy.frag b/src/l_adele/lucy/lucy.frag index 24272f9..5725fa3 100644 --- a/src/l_adele/lucy/lucy.frag +++ b/src/l_adele/lucy/lucy.frag @@ -13,4 +13,5 @@ layout (binding=0) uniform sampler2D images[]; void main(){ float I = texture(images[nonuniformEXT(tex_ind)], tex_cord).r; fin_color = vec4(color.rgb, color.a * I); + //fin_color = vec4(0, 0, 0, 1); } diff --git a/src/l_adele/lucy/lucy.vert b/src/l_adele/lucy/lucy.vert index 5a9f3ce..b02e6a3 100644 --- a/src/l_adele/lucy/lucy.vert +++ b/src/l_adele/lucy/lucy.vert @@ -1,9 +1,11 @@ #version 450 layout(location = 0) in vec4 color; -layout(location = 1) in vec2 pos; -layout(location = 2) in vec2 tex_cord; -layout(location = 3) in uint tex_ind; +layout(location = 1) in vec2 lt_pos; +layout(location = 2) in vec2 br_pos; +layout(location = 3) in vec2 lt_tex; +layout(location = 4) in vec2 br_tex; +layout(location = 5) in uint tex_ind; layout(push_constant, std430) uniform pc { float width; @@ -23,8 +25,17 @@ float deng(float B1, float x){ } void main(){ + const vec2 all_v_pos[6] = vec2[]( + vec2(br_pos.x, lt_pos.y), lt_pos, vec2(lt_pos.x, br_pos.y), + vec2(br_pos.x, lt_pos.y), vec2(lt_pos.x, br_pos.y), br_pos + ); + const vec2 all_v_tex[6] = vec2[]( + vec2(br_tex.x, lt_tex.y), lt_tex, vec2(lt_tex.x, br_tex.y), + vec2(br_tex.x, lt_tex.y), vec2(lt_tex.x, br_tex.y), br_tex + ); vsout_color = color; - vsout_tex_cord = tex_cord; + vsout_tex_cord = all_v_tex[gl_VertexIndex % 6]; vsout_tex_ind = tex_ind; + vec2 pos = all_v_pos[gl_VertexIndex % 6]; gl_Position = vec4(deng(width, pos.x), deng(height, pos.y), 0, 1); }