I wrote trait wrapper boilerpalte codegen

This commit is contained in:
Андреев Григорий 2026-01-07 16:17:28 +03:00
parent 9a9a5b1b0f
commit 8cb684d82e
20 changed files with 485 additions and 147 deletions

View File

@ -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)

View File

@ -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++) {

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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));
}

View File

@ -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 <stdlib.h>\n%s", dependencies),
generate_trait_wrapper_boilerplate(op), VecU8_from_span(op.trait.name));
}
#endif

View File

@ -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;

View File

@ -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});
}

View File

@ -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"

View File

@ -4,6 +4,7 @@
// todo: move loop here and rewrite with l1_5 help
#include "../../l1/core/int_primitives.h"
#include <stdlib.h>
typedef struct {
/* self (takes ownership) */

View File

@ -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

View File

@ -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};
}

View File

@ -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;
}

View File

@ -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;

232
src/l2/tests/r2/r2c.c Normal file
View File

@ -0,0 +1,232 @@
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sound/asound.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#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(&params, 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 = &params.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 = &params.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, &params) < 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 = &params.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 = &params.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 = &params.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 = &params.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 = &params.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 = &params.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, &params) < 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, &params) < 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;
}

View File

@ -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

View File

@ -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));

View File

@ -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);
}

View File

@ -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);
}