From 7b29269ac55b3c6d9422cfc44e889358f919edc8 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Fri, 12 Sep 2025 17:43:46 +0300 Subject: [PATCH 1/8] Saving uncomplete changes. Have to generate png methods for all the png types --- src/l1/anne/codegen.c | 7 +- .../{vulkan_utils.h => margaret_misc.h} | 5 +- src/l1/anne/margaret/png_pixel_masses.h | 74 +++ src/l1/anne/pixel_masses.h | 16 +- src/l1/anne/some_tests.h | 3 + src/l1/anne/util_temp_very_base.h | 4 + src/l1/codegen/util_template_inst.h | 94 ++++ src/l1/marie/geom_alg_utils.h | 15 + src/l1_5/core/stringop.h | 1 + src/l2/margaret/png_pixel_masses.h | 12 +- src/l2/marie/rasterization.h | 30 +- src/l2/marie/texture_processing.h | 41 ++ src/l2/tests/r0/r0.c | 458 ++++++++++-------- src/l2/tests/r0/r0_assets.h | 131 ++++- src/l2/tests/r0/r0_scene.h | 3 + src/l2/tests/r0/r0_tex_init_prep.c | 41 +- src/l2/tests/tv0/tv0.c | 0 17 files changed, 641 insertions(+), 294 deletions(-) rename src/l1/anne/margaret/{vulkan_utils.h => margaret_misc.h} (91%) create mode 100644 src/l1/anne/margaret/png_pixel_masses.h create mode 100644 src/l2/tests/tv0/tv0.c diff --git a/src/l1/anne/codegen.c b/src/l1/anne/codegen.c index 11b77de..88e241c 100644 --- a/src/l1/anne/codegen.c +++ b/src/l1/anne/codegen.c @@ -7,10 +7,11 @@ #include "some_tests.h" #include "util_temp_vulkan.h" -#include "margaret/vulkan_utils.h" +#include "margaret/margaret_misc.h" #include "marie/graphics_geom.h" #include "liza.h" #include "codegen_from_l1_5.h" +#include "margaret/png_pixel_masses.h" int main() { mkdir_nofail("l1"); @@ -21,10 +22,12 @@ int main() { generate_pixel_masses_header(); generate_headers_for_r0_r1_r2_r3(); generate_util_templ_inst_for_vulkan_headers(); - generate_margaret_eve_for_vulkan_utils(); generate_marie_headers_for_graphics_geom(); generate_liza_l1_headers(); generate_l1_headers_for_l1_5(); + mkdir_nofail("l1/margaret"); + generate_margaret_eve_for_vulkan_utils(); + generate_margaret_png_pixel_masses_header(); finish_layer(cstr("l1")); return 0; } diff --git a/src/l1/anne/margaret/vulkan_utils.h b/src/l1/anne/margaret/margaret_misc.h similarity index 91% rename from src/l1/anne/margaret/vulkan_utils.h rename to src/l1/anne/margaret/margaret_misc.h index 393523f..7c8d7c1 100644 --- a/src/l1/anne/margaret/vulkan_utils.h +++ b/src/l1/anne/margaret/margaret_misc.h @@ -1,5 +1,5 @@ -#ifndef PROTOTYPE1_SRC_L1_ANNE_MARGARET_VULKAN_H -#define PROTOTYPE1_SRC_L1_ANNE_MARGARET_VULKAN_H +#ifndef PROTOTYPE1_SRC_L1_ANNE_MARGARET_MARGARET_MISC_H +#define PROTOTYPE1_SRC_L1_ANNE_MARGARET_MARGARET_MISC_H #include "../../codegen/util_template_inst.h" @@ -21,4 +21,5 @@ void generate_margaret_eve_for_vulkan_utils() { .collab_vec_span = true}); } + #endif \ No newline at end of file diff --git a/src/l1/anne/margaret/png_pixel_masses.h b/src/l1/anne/margaret/png_pixel_masses.h new file mode 100644 index 0000000..ea00bed --- /dev/null +++ b/src/l1/anne/margaret/png_pixel_masses.h @@ -0,0 +1,74 @@ +#ifndef PROTOTYPE1_SRC_L1_ANNE_MARGARET_PNG_PIXEL_MASSES_H +#define PROTOTYPE1_SRC_L1_ANNE_MARGARET_PNG_PIXEL_MASSES_H + +#include "../../codegen/util_template_inst.h" + +typedef struct { + int channel_count; + SpanU8 name; +} color_type_name_in_png; + +color_type_name_in_png color_types_names_in_png[3] = { + {1, cstr("PNG_COLOR_TYPE_GRAY")}, + {3, cstr("PNG_COLOR_TYPE_RGB")}, + {4, cstr("PNG_COLOR_TYPE_RGBA")}, +}; + +NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signature, int depth, int channel_count) { + if (depth != 8) + abortf("Please no"); + for (size_t i = 0; i < ARRAY_SIZE(color_types_names_in_png); i++) { + if (channel_count == color_types_names_in_png[i].channel_count) { + SpanU8 color_type = color_types_names_in_png[i].name; + VecU8 res = VecU8_new(); + + VecU8 g_promise = VecU8_fmt("MargaretPromisedPng%s", format_signature); + SpanU8 promise = VecU8_to_span(&g_promise); + VecU8 g_tex = VecU8_fmt("TextureData%s", format_signature); + SpanU8 tex = VecU8_to_span(&g_tex); + + /* Non clonable structure */ + VecU8_append_vec(&res, VecU8_fmt( + "typedef struct {\n" + SPACE4 "FILE* fp;\n" + SPACE4 "png_structp pngshka;\n" + SPACE4 "png_infop info;\n" + SPACE4 "png_infop end_info;\n" + "} %s;\n\n" + "void %s_drop(%s self) {\n" + SPACE4 "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n" + SPACE4 "fclose(self.fp);\n" + "}\n\n", promise, promise, promise)); + + VecU8_append_vec(&res, generate_result_template_inst(promise, cstr("VecU8"), false, false)); + + VecU8_drop(g_promise); + VecU8_drop(g_tex); + return res; + } + } + abortf("Please don't"); +} + +void generate_margaret_png_pixel_masses_header() { + GeneratedHeader header = begin_header(cstr("l1/margaret/png_pixel_masses.h")); + + VecU8_append_span(&header.result, cstr( + "#include \"../pixel_masses.h\"" + "#include \"../ResultVoidOrVecU8\"" + "#include \n\n")); + + VecU8_append_span(&header.result, cstr( + "void margaret_libpng_h_error_cb(png_structp pngshka, png_const_charp err) {\n" + "printf(\"[!] %s\\n\", err);\n" + "}\n\n" + "void margaret_libpng_h_warning_cb(png_structp pngshka, png_const_charp warning) {\n" + "printf(\"[.] %s\\n\", warning);\n" + "}")); + + VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("TextureDataR8G8B8A8"), 8, 4)); + + finish_header(header); +} + +#endif \ No newline at end of file diff --git a/src/l1/anne/pixel_masses.h b/src/l1/anne/pixel_masses.h index 8a7868d..8e14f6d 100644 --- a/src/l1/anne/pixel_masses.h +++ b/src/l1/anne/pixel_masses.h @@ -2,6 +2,7 @@ #define PROTOTYPE_SRC_L1_CODEGEN_PIXEL_MASSES_H #include "../codegen/codegen.h" +#include "../codegen/util_template_inst.h" /* Used to generate both _at() and _cat() methods */ NODISCARD VecU8 generate_texture_data_method_at(SpanU8 tex, SpanU8 pixvec, SpanU8 memb, bool const_access) { @@ -76,17 +77,12 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 SPACE4 "write_whole_file_or_abort(path, VecU8_to_span(&data));\n" SPACE4 "VecU8_drop(data);\n" "}\n\n", tex, tex, tex)); - /* Result structure */ - VecU8 g_resoftex = VecU8_fmt("Result%sOrSpanU8", tex); + /* Result structure */ + VecU8 g_resoftex = get_ResultType_inst_name(tex, cstr("SpanU8")); SpanU8 resoftex = VecU8_to_span(&g_resoftex); - VecU8_append_vec(&res, VecU8_fmt( - "typedef struct {\n" - SPACE4 "Result_variant variant;\n" - SPACE4 "union {\n" - SPACE4 SPACE4 "%s ok;\n" - SPACE4 SPACE4 "SpanU8 err;\n" - SPACE4 "};\n" - "} %s;\n\n", tex, resoftex)); + VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("SpanU8"), false, true)); + /* I also add this, because why not?? Maye I will use it in the future... */ + VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("VecU8"), false, false)); /* Method _from_bitmap_text() * We assume that bytes are tightly packed in member type */ VecU8_append_vec(&res, VecU8_fmt( diff --git a/src/l1/anne/some_tests.h b/src/l1/anne/some_tests.h index ca058c4..1182fbe 100644 --- a/src/l1/anne/some_tests.h +++ b/src/l1/anne/some_tests.h @@ -21,6 +21,9 @@ void generate_headers_for_r0_r1_r2_r3() { /* r0_scene.h */ generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("UsedGenericModelOnScene"), true, false); generate_eve_span_company_for_non_primitive_non_clonable(l, ns, cstr("UsedShinyModelOnScene"), true, false); + /* r0 */ + generate_eve_span_company_for_primitive(l, ns, cstr("GenericModelTopAndTexInMemoryInfo"), true, false); + generate_eve_span_company_for_primitive(l, ns, cstr("ShinyModelTopInMemoryInfo"), true, false); } mkdir_nofail("l1/eve/r2"); { /* r2 */ diff --git a/src/l1/anne/util_temp_very_base.h b/src/l1/anne/util_temp_very_base.h index c4ea880..34de7ba 100644 --- a/src/l1/anne/util_temp_very_base.h +++ b/src/l1/anne/util_temp_very_base.h @@ -55,6 +55,10 @@ void generate_util_temp_very_base_headers() { } generate_guarded_span_company_for_primitive(cstr("l1"), cstr(""), cstr("CSTR"), cstr(""), true, false); + generate_guarded_header_of_result_type_instantiation(cstr("l1"), cstr(""), + cstr(""), cstr("VecU8"), cstr("#include \"VecAndSpan_int_primitives.h\""), true, false); + generate_guarded_header_of_result_type_instantiation(cstr("l1"), cstr(""), + cstr(""), cstr("SpanU8"), cstr("#include \"VecAndSpan_int_primitives.h\""), true, true); } #endif \ No newline at end of file diff --git a/src/l1/codegen/util_template_inst.h b/src/l1/codegen/util_template_inst.h index 99c08fb..4398c8b 100644 --- a/src/l1/codegen/util_template_inst.h +++ b/src/l1/codegen/util_template_inst.h @@ -3,6 +3,7 @@ #include "codegen.h" + // todo: add macro that iterates over vector /* if !primitive, requires methods T_drop, and, if also clonable, requires method T_clone */ @@ -614,4 +615,97 @@ void generate_guarded_span_company_for_non_primitive_non_clonable( }); } +NODISCARD VecU8 get_ResultType_inst_name(SpanU8 OkT, SpanU8 ErrT){ + bool ok_t_void = OkT.len == 0; + bool err_t_void = ErrT.len == 0; + assert(!ok_t_void || !err_t_void); + return VecU8_fmt("Result%s%s%s", !ok_t_void ? OkT : cstr("Void"), + !err_t_void ? cstr("Or") : cstr(""), !err_t_void ? ErrT : cstr("")); +} + +/* We are talking about Result template instantiation */ +NODISCARD VecU8 generate_result_template_inst(SpanU8 OkT, SpanU8 ErrT, bool ok_t_primitive, bool err_t_primitive) { + bool ok_t_void = OkT.len == 0; + bool err_t_void = ErrT.len == 0; + assert(!ok_t_void || !err_t_void); + assert(!ok_t_void || ok_t_primitive); + assert(!err_t_void || err_t_primitive); + + VecU8 g_ResultT = get_ResultType_inst_name(OkT, ErrT); + SpanU8 ResultT = VecU8_to_span(&g_ResultT); + + VecU8 res = VecU8_new(); + + VecU8_append_span(&res, cstr( + "typedef struct {\n" + SPACE4 "Result_variant variant;\n")); + if (ok_t_void && !err_t_void) { + VecU8_append_vec(&res, VecU8_fmt(SPACE4 "%s err;\n", ErrT)); + } else if (!ok_t_void && err_t_void) { + VecU8_append_vec(&res, VecU8_fmt(SPACE4 "%s ok;\n", OkT)); + } else { + VecU8_append_vec(&res, VecU8_fmt( + SPACE4 "union {\n" + SPACE4 SPACE4 "%s ok;\n" + SPACE4 SPACE4 "%s err;\n" + SPACE4 "};\n", OkT, ErrT)); + } + VecU8_append_vec(&res, VecU8_fmt("} %s;\n\n", ResultT)); + + if (!ok_t_primitive || !err_t_primitive) { + VecU8_append_vec(&res, VecU8_fmt( + "void %s_drop(%s self) {\n", ResultT, ResultT)); + if (ok_t_primitive && !err_t_primitive) { + VecU8_append_vec(&res, VecU8_fmt( + SPACE4 "if (self.variant == Result_Err)\n" + SPACE4 SPACE4 "%s_drop(self.err);\n", ErrT)); + } else if (!ok_t_primitive && err_t_primitive) { + VecU8_append_vec(&res, VecU8_fmt( + SPACE4 "if (self.variant == Result_Ok)\n" + SPACE4 SPACE4 "%s_drop(self.ok);\n", OkT)); + } else { + VecU8_append_vec(&res, VecU8_fmt( + SPACE4 "if (self.variant == Result_Ok)\n" + SPACE4 SPACE4 "%s_drop(self.ok);\n" + SPACE4 "else\n" + SPACE4 SPACE4 "%s_drop(self.err);\n", OkT, ErrT)); + } + VecU8_append_span(&res, cstr("}\n\n")); + } + VecU8_drop(g_ResultT); /* ResultT variable invalidated */ + return res; +} + +void generate_eve_header_of_result_type_instantiation( + SpanU8 l, SpanU8 ns, SpanU8 OkT, SpanU8 ErrT, bool ok_t_primitive, bool err_t_primitive + ) { + VecU8 ResultT = get_ResultType_inst_name(OkT, ErrT); + VecU8 nt_filepath = VecU8_fmt("%s/eve/%s/%s.h%c", l, ns, VecU8_to_span(&ResultT), 0); + VecU8 text = generate_result_template_inst(OkT, ErrT, ok_t_primitive, err_t_primitive); + write_whole_file_or_abort((CSTR)text.buf, VecU8_to_span(&text)); + VecU8_drop(text); + VecU8_drop(nt_filepath); + VecU8_drop(ResultT); +} + +void generate_guarded_header_of_result_type_instantiation( + SpanU8 layer, SpanU8 bonus_ns, SpanU8 OkT, SpanU8 ErrT, SpanU8 dependencies, bool ok_t_primitive, bool err_t_primitive + ) { + assert(layer.len > 1); + VecU8 filename = get_ResultType_inst_name(OkT, ErrT); + VecU8 path = VecU8_fmt("%s/%s%s%s", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), VecU8_to_span(&filename)); + GeneratedHeader head = begin_header(VecU8_to_span(&path)); + VecU8_drop(path); + VecU8_drop(filename); + VecU8_append_span(&head.result, cstr("#include \"../../")); + int to_my_layer = get_number_of_parts_in_header_namespace(bonus_ns); + for (int i = 0; i < to_my_layer; i++) + VecU8_append_span(&head.result, cstr("../")); + VecU8_append_span(&head.result, cstr("src/l1/core/util.h\"\n")); + VecU8_append_span(&head.result, dependencies); + VecU8_append_span(&head.result, cstr("\n\n")); + VecU8_append_vec(&head.result, generate_result_template_inst(OkT, ErrT, ok_t_primitive, err_t_primitive)); + finish_header(head); +} + #endif diff --git a/src/l1/marie/geom_alg_utils.h b/src/l1/marie/geom_alg_utils.h index 2cb162b..dd26bd2 100644 --- a/src/l1/marie/geom_alg_utils.h +++ b/src/l1/marie/geom_alg_utils.h @@ -54,6 +54,13 @@ typedef struct { vec2 v2; } MarieTriangle; +MarieTriangle MarieTriangle_mat3x2_mul_pos(MarieTriangle self, mat3x2 trop) { + return (MarieTriangle){ + .v0 = mat3x2_mul_vec3(trop, vec2_and_one(self.v0)), + .v1 = mat3x2_mul_vec3(trop, vec2_and_one(self.v1)), + .v2 = mat3x2_mul_vec3(trop, vec2_and_one(self.v2))}; +} + #include "../../../gen/l1/eve/marie/VecMarieTriangle.h" typedef struct { @@ -62,6 +69,14 @@ typedef struct { MariePlaneVertAttr v2; } MarieTriangleAttr; +MarieTriangleAttr MarieTriangle_goto_nat_cords_pres_par(MarieTriangle self, mat3x2 trop) { + return (MarieTriangleAttr){ + {mat3x2_mul_vec3(trop, vec2_and_one(self.v0)), {self.v0.x, self.v0.y, 0, 0}}, + {mat3x2_mul_vec3(trop, vec2_and_one(self.v1)), {self.v1.x, self.v1.y, 0, 0}}, + {mat3x2_mul_vec3(trop, vec2_and_one(self.v2)), {self.v2.x, self.v2.y, 0, 0}}, + }; +} + #include "../../../gen/l1/eve/marie/VecMarieTriangleAttr.h" vec2 marie_intersect_lines(vec2 A1, vec2 B1, vec2 A2, vec2 B2) { diff --git a/src/l1_5/core/stringop.h b/src/l1_5/core/stringop.h index e59cd43..ef85baf 100644 --- a/src/l1_5/core/stringop.h +++ b/src/l1_5/core/stringop.h @@ -27,6 +27,7 @@ bool string_contains_string_ignorecase(SpanU8 str1, SpanU8 str2) { return false; } +// todo: create a method "span_contents_equal" in span template bool strings_in_spans_equal(SpanU8 a, SpanU8 b) { if (a.len != b.len) return false; diff --git a/src/l2/margaret/png_pixel_masses.h b/src/l2/margaret/png_pixel_masses.h index 9fbc9c2..e3f1819 100644 --- a/src/l2/margaret/png_pixel_masses.h +++ b/src/l2/margaret/png_pixel_masses.h @@ -4,6 +4,7 @@ #include "../../../gen/l1/pixel_masses.h" #include "../../l1/core/util.h" #include "../../l1/core/VecU8_as_str.h" +#include "../../../gen/l1/ResultVoidOrVecU8" #include // todo: generate all of this automaticcally @@ -16,16 +17,6 @@ void margaret_libpng_h_warning_cb(png_structp pngshka, png_const_charp warning) printf("[.] %s\n", warning); } -typedef struct { - Result_variant variant; - VecU8 err; -} ResultVoidOrVecU8; - -void ResultVoidOrVecU8_drop(ResultVoidOrVecU8 self) { - if (self.variant == Result_Err) - VecU8_drop(self.err); -} - ResultVoidOrVecU8 TextureDataR8G8B8A8_write_to_png(const TextureDataR8G8B8A8* self, SpanU8 filename) { VecU8 nt_filename = VecU8_fmt("%s%c", filename, 0); FILE *fp = fopen((CSTR)nt_filename.buf, "wb"); @@ -79,7 +70,6 @@ void TextureDataR8G8B8A8_write_to_png_nofail(const TextureDataR8G8B8A8* self, Sp } } -/* This structure will be pinned */ typedef struct { FILE* fp; png_structp pngshka; diff --git a/src/l2/marie/rasterization.h b/src/l2/marie/rasterization.h index ca433c6..78bb141 100644 --- a/src/l2/marie/rasterization.h +++ b/src/l2/marie/rasterization.h @@ -24,7 +24,7 @@ MarieLinearFun marie_gen_scanline_borderline(vec2 a, vec2 b) { /* Utility function, that is used by rasterization function. * Don't use in your code*/ -void marie_rasterize_line_in_triangle_with_attr_sorted( +void marie_h_rasterize_only_one_line_of_triangle( vec2 v0pos, vec2 v1pos, vec2 v2pos, S32 L, S32 R, MarieVertAttr P0, MarieVertAttr P1, MarieVertAttr P2, float S, S32 my, FnMarieRasterizerCallback cb ) { @@ -44,7 +44,7 @@ void marie_rasterize_line_in_triangle_with_attr_sorted( /* Utility function, that is used by rasterization function. * Don't use in your code*/ -void marie_scan_rast_line_in_triangle_with_attr_sorted( +void marie_h_rasterize_half_of_triangle( vec2 v0pos, vec2 v1pos, vec2 v2pos, S32 below, S32 above, MarieVertAttr P0, MarieVertAttr P1, MarieVertAttr P2, MarieLinearFun left_border, MarieLinearFun right_border, FnMarieRasterizerCallback cb ) { @@ -66,7 +66,9 @@ void marie_scan_rast_line_in_triangle_with_attr_sorted( } } -void marie_rasterize_triangle_with_attr_sorted( +/* Utility function, that is used by rasterization function. + * Don't use in your code*/ +void marie_h_rasterize_triangle_with_attr_sorted( MariePlaneVertAttr v0, MariePlaneVertAttr v1, MariePlaneVertAttr v2, FnMarieRasterizerCallback cb ) { float S = marie_surface(v0.pos, v1.pos, v2.pos); @@ -89,22 +91,22 @@ void marie_rasterize_triangle_with_attr_sorted( MarieLinearFun line_12 = marie_gen_scanline_borderline(v1.pos, v2.pos); MarieLinearFun line_20 = marie_gen_scanline_borderline(v2.pos, v0.pos); - marie_rasterize_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy0, cb); + marie_h_rasterize_only_one_line_of_triangle(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy0, cb); if (sy0 + 1 < sy1) { MarieLinearFun left_border = S > 0 ? line_20 : line_01; MarieLinearFun right_border = S > 0 ? line_01 : line_20; - marie_scan_rast_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, sy0, sy1, P0, P1, P2, left_border, right_border, cb); + marie_h_rasterize_half_of_triangle(v0.pos, v1.pos, v2.pos, sy0, sy1, P0, P1, P2, left_border, right_border, cb); } if (sy1 > sy0) { - marie_rasterize_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy1, cb); + marie_h_rasterize_only_one_line_of_triangle(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy1, cb); } if (sy1 + 1 < sy2) { MarieLinearFun left_border = S > 0 ? line_20 : line_12; MarieLinearFun right_border = S > 0 ? line_12 : line_20; - marie_scan_rast_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, sy1, sy2, P0, P1, P2, left_border, right_border, cb); + marie_h_rasterize_half_of_triangle(v0.pos, v1.pos, v2.pos, sy1, sy2, P0, P1, P2, left_border, right_border, cb); } if (sy2 > sy1) { - marie_rasterize_line_in_triangle_with_attr_sorted(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy2, cb); + marie_h_rasterize_only_one_line_of_triangle(v0.pos, v1.pos, v2.pos, L, R, P0, P1, P2, S, sy2, cb); } } void marie_rasterize_triangle_with_attr( @@ -112,22 +114,22 @@ void marie_rasterize_triangle_with_attr( ) { if (a.pos.y < b.pos.y) { if (b.pos.y < c.pos.y) { - marie_rasterize_triangle_with_attr_sorted(a, b, c, cb); + marie_h_rasterize_triangle_with_attr_sorted(a, b, c, cb); } else { if (a.pos.y < c.pos.y) { - marie_rasterize_triangle_with_attr_sorted(a, c, b, cb); + marie_h_rasterize_triangle_with_attr_sorted(a, c, b, cb); } else { - marie_rasterize_triangle_with_attr_sorted(c, a, b, cb); + marie_h_rasterize_triangle_with_attr_sorted(c, a, b, cb); } } } else { if (a.pos.y < c.pos.y) { - marie_rasterize_triangle_with_attr_sorted(b, a, c, cb); + marie_h_rasterize_triangle_with_attr_sorted(b, a, c, cb); } else { if (b.pos.y < c.pos.y) { - marie_rasterize_triangle_with_attr_sorted(b, c, a, cb); + marie_h_rasterize_triangle_with_attr_sorted(b, c, a, cb); } else { - marie_rasterize_triangle_with_attr_sorted(c, b, a, cb); + marie_h_rasterize_triangle_with_attr_sorted(c, b, a, cb); } } } diff --git a/src/l2/marie/texture_processing.h b/src/l2/marie/texture_processing.h index 26b177d..7406564 100644 --- a/src/l2/marie/texture_processing.h +++ b/src/l2/marie/texture_processing.h @@ -2,6 +2,7 @@ #define PROTOTYPE1_SRC_L2_MARIE_TEXTURE_PROCESSING_H #include "../../../gen/l1/pixel_masses.h" +#include "rasterization.h" void TextureDataR8G8B8A8_print(const TextureDataR8G8B8A8* self) { U64 width = self->width; @@ -62,4 +63,44 @@ NODISCARD TextureDataR8G8B8A8 TextureDataR8G8B8A8_expand_nontransparent_1px(cons return res; } +vec4 marie_color_cvec4_to_vec4(cvec4 clr) { + return (vec4){(float)clr.x / 255, (float)clr.y / 255, (float)clr.z / 255, (float)clr.w / 255}; +} + +cvec4 marie_color_vec4_to_cvec4(vec4 clr) { + return (cvec4){(U8)roundf(clr.x * 255), (U8)roundf(clr.y * 255), (U8)roundf(clr.z * 255), (U8)roundf(clr.w * 255)}; +} + +vec3 marie_color_cvec3_to_vec3(cvec3 clr) { + return (vec3){(float)clr.x / 255, (float)clr.y / 255, (float)clr.z / 255}; +} + +cvec3 marie_color_vec3_to_cvec3(vec3 clr) { + return (cvec3){(U8)roundf(clr.x * 255), (U8)roundf(clr.y * 255), (U8)roundf(clr.z * 255)}; +} + +typedef struct { + TextureDataR8G8B8A8* self; + cvec4 pixel; +} TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest; + +void TextureDataR8G8B8A8_draw_triangle_of_one_color_h_draw_guest(void* ug, S32 x, S32 y, vec4 attr) { + TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest *g = ug; + if (TextureDataR8G8B8A8_is_inside(g->self, x, y)) + *TextureDataR8G8B8A8_mat(g->self, x, y) = g->pixel; +} + +/* Given triangle is not natural : it is from parameter space */ +void TextureDataR8G8B8A8_draw_triangle_of_one_color( + TextureDataR8G8B8A8* self, vec3 color, MarieTriangle param_triang, mat3x2 trop + ) { + TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest aboba = + { self, marie_color_vec4_to_cvec4(vec3_and_one(color)) }; + MarieTriangle natural = MarieTriangle_mat3x2_mul_pos(param_triang, trop); + marie_rasterize_triangle_with_attr( + (MariePlaneVertAttr){natural.v0, {}}, (MariePlaneVertAttr){natural.v1, {}}, (MariePlaneVertAttr){natural.v2, {}}, + (FnMarieRasterizerCallback){.fn = TextureDataR8G8B8A8_draw_triangle_of_one_color_h_draw_guest, + .guest = &aboba}); +} + #endif \ No newline at end of file diff --git a/src/l2/tests/r0/r0.c b/src/l2/tests/r0/r0.c index e47d1cc..671d82b 100644 --- a/src/l2/tests/r0/r0.c +++ b/src/l2/tests/r0/r0.c @@ -1019,6 +1019,32 @@ typedef struct { VkQueue presentation_queue; } UsedVulkanQueues; +typedef struct { + MargaretBufferInMemoryInfo vbo; + MargaretBufferInMemoryInfo ebo; + /* We store image in yet another meaningless buffer (will change it later) */ + TextureDataR8G8B8A8 reading_diffuse; + TextureDataR8G8B8A8 reading_normal; + TextureDataR8 reading_specular; + /* Filled during first (and the only) memory init */ + MargaretImageInMemoryInfo diffuse; + MargaretImageInMemoryInfo normal; + MargaretImageInMemoryInfo specular; + /* will be filled in later */ + VkImageView diffuse_view; + VkImageView normal_view; + VkImageView specular_view; +} GenericModelTopAndTexInMemoryInfo; + +#include "../../../../gen/l1/eve/r0/VecGenericModelTopAndTexInMemoryInfo.h" + +typedef struct { + MargaretBufferInMemoryInfo vbo; + MargaretBufferInMemoryInfo ebo; +} ShinyModelTopInMemoryInfo; + +#include "../../../../gen/l1/eve/r0/VecShinyModelTopInMemoryInfo.h" + typedef struct { MargaretInstanceAndItsDebug instance_and_debug; VkSurfaceKHR surface; @@ -1037,20 +1063,15 @@ typedef struct { MargaretSwapchainBundle swfb; SceneTemplate scene_template; - TextureDataR8G8B8A8 cyl_1_diffuse_tex; - TextureDataR8G8B8A8 cyl_1_normal_tex; + + VecGenericModelTopAndTexInMemoryInfo device_generic_models_top_and_tex; + VecShinyModelTopInMemoryInfo device_shiny_models_top; MargaretBufferInMemoryInfo host_mem_buffer; VkDeviceMemory host_mem; - VecMargaretBufferInMemoryInfo device_ebo_buffers_for_generic_meshes; - VecMargaretBufferInMemoryInfo device_vbo_buffers_for_generic_meshes; - VecMargaretBufferInMemoryInfo device_ebo_buffers_for_shiny_meshes; - VecMargaretBufferInMemoryInfo device_vbo_buffers_for_shiny_meshes; MargaretBufferInMemoryInfo device_lighting_ubo; MargaretBufferInMemoryInfo device_instance_attrs_for_models; MargaretImageInMemoryInfo device_IT1_image; MargaretImageInMemoryInfo device_zbuffer_image; - MargaretImageInMemoryInfo device_cyl_1_diffuse_texture; - MargaretImageInMemoryInfo device_cyl_1_normal_texture; VkDeviceMemory device_mem; VkCommandPool command_pool; @@ -1664,6 +1685,7 @@ int main() { state_r0 state = {0}; state.sane_image_extent_limit = (VkExtent2D){1000, 700}; + vulkan_ctx_r0 *vk_ctx = &state.vk_ctx; state.wl_display = wl_display_connect(NULL); if (!state.wl_display) @@ -1701,181 +1723,192 @@ int main() { abortf("wl_surface_frame\n"); wl_callback_add_listener(state.wl_callback, &main_h_wl_surface_frame_listener, &state); - state.vk_ctx.instance_and_debug = MargaretInstanceAndItsDebug_new(ENABLE_VALIDATION_LAYERS); - VkInstance instance = state.vk_ctx.instance_and_debug.instance; + vk_ctx->instance_and_debug = MargaretInstanceAndItsDebug_new(ENABLE_VALIDATION_LAYERS); + VkInstance instance = vk_ctx->instance_and_debug.instance; // print_instance_available_extensions(instance); // print_instance_available_layers(instance); - state.vk_ctx.surface = margaret_create_surface(instance, state.wl_display, state.wl_surface); + vk_ctx->surface = margaret_create_surface(instance, state.wl_display, state.wl_surface); - state.vk_ctx.physical_device = margaret_select_one_physical_device( - instance, state.vk_ctx.surface, GPU, bugged_GPU, sane_image_extent_limit); + vk_ctx->physical_device = margaret_select_one_physical_device( + instance, vk_ctx->surface, GPU, bugged_GPU, sane_image_extent_limit); // print_physical_device_available_extensions(physical_device); ResultMargaretChosenQueueFamiliesOrSpanU8 queue_fam_res = margaret_choose_good_queue_families( - state.vk_ctx.physical_device, state.vk_ctx.surface); + vk_ctx->physical_device, vk_ctx->surface); if (queue_fam_res.variant != Result_Ok) abortf("queue_fam_res.variant != Result_Ok"); - state.vk_ctx.queue_fam = queue_fam_res.ok; + vk_ctx->queue_fam = queue_fam_res.ok; - state.vk_ctx.device = margaret_create_logical_device(state.vk_ctx.physical_device, state.vk_ctx.queue_fam); + vk_ctx->device = margaret_create_logical_device(vk_ctx->physical_device, vk_ctx->queue_fam); - vkGetDeviceQueue(state.vk_ctx.device, state.vk_ctx.queue_fam.for_graphics, 0, &state.vk_ctx.queues.graphics_queue); - vkGetDeviceQueue(state.vk_ctx.device, state.vk_ctx.queue_fam.for_presentation, 0, &state.vk_ctx.queues.presentation_queue); + vkGetDeviceQueue(vk_ctx->device, vk_ctx->queue_fam.for_graphics, 0, &vk_ctx->queues.graphics_queue); + vkGetDeviceQueue(vk_ctx->device, vk_ctx->queue_fam.for_presentation, 0, &vk_ctx->queues.presentation_queue); ResultMargaretChosenSwapchainDetailsOrSpanU8 swapchain_details_res = margaret_choose_swapchain_details( - state.vk_ctx.physical_device, state.vk_ctx.surface, sane_image_extent_limit); + vk_ctx->physical_device, vk_ctx->surface, sane_image_extent_limit); if (swapchain_details_res.variant != Result_Ok) abortf("swapchain_details_res.variant != Result_Ok"); - OptionVkFormat zbuffer_format = margaret_find_supported_zbuffer_format(state.vk_ctx.physical_device); + OptionVkFormat zbuffer_format = margaret_find_supported_zbuffer_format(vk_ctx->physical_device); if (zbuffer_format.variant != Option_Some) abortf("Could not find supported zbuffer format\n"); - state.vk_ctx.zbuffer_format = zbuffer_format.some; - OptionVkFormat IT1_format = margaret_find_supported_hdr_buffer_format(state.vk_ctx.physical_device); + vk_ctx->zbuffer_format = zbuffer_format.some; + OptionVkFormat IT1_format = margaret_find_supported_hdr_buffer_format(vk_ctx->physical_device); if (IT1_format.variant != Option_Some) abortf("Could not find supported hdr buffer format\n"); - state.vk_ctx.IT1_format = IT1_format.some; + vk_ctx->IT1_format = IT1_format.some; - state.vk_ctx.render_pass_0 = create_render_pass_0(state.vk_ctx.device, IT1_format.some, zbuffer_format.some); - state.vk_ctx.pipeline_hands_0a = create_graphics_pipeline_0(state.vk_ctx.device, state.vk_ctx.render_pass_0, 0); - state.vk_ctx.pipeline_hands_0b = create_graphics_pipeline_0_b(state.vk_ctx.device, state.vk_ctx.render_pass_0, 0); + vk_ctx->render_pass_0 = create_render_pass_0(vk_ctx->device, IT1_format.some, zbuffer_format.some); + vk_ctx->pipeline_hands_0a = create_graphics_pipeline_0(vk_ctx->device, vk_ctx->render_pass_0, 0); + vk_ctx->pipeline_hands_0b = create_graphics_pipeline_0_b(vk_ctx->device, vk_ctx->render_pass_0, 0); - state.vk_ctx.render_pass_1 = create_render_pass_1(state.vk_ctx.device, swapchain_details_res.ok.surface_format.format); - state.vk_ctx.pipeline_hands_1 = create_graphics_pipeline_1(state.vk_ctx.device, state.vk_ctx.render_pass_1, 0); + vk_ctx->render_pass_1 = create_render_pass_1(vk_ctx->device, swapchain_details_res.ok.surface_format.format); + vk_ctx->pipeline_hands_1 = create_graphics_pipeline_1(vk_ctx->device, vk_ctx->render_pass_1, 0); - state.vk_ctx.swfb = MargaretSwapchainBundle_new( - state.vk_ctx.device, state.vk_ctx.queue_fam, swapchain_details_res.ok, - state.vk_ctx.surface, state.vk_ctx.render_pass_1, NULL); + vk_ctx->swfb = MargaretSwapchainBundle_new( + vk_ctx->device, vk_ctx->queue_fam, swapchain_details_res.ok, + vk_ctx->surface, vk_ctx->render_pass_1, NULL); - state.vk_ctx.scene_template = (SceneTemplate){ + vk_ctx->scene_template = (SceneTemplate){ .generic_models = VecGenericMeshInSceneTemplate_new(), .shiny_models = VecShinyMeshInSceneTemplate_new(), .point_lights_max_count = pipeline_0_ubo_point_light_max_count, .spotlights_max_count = pipeline_0_ubo_spotlight_max_count}; - VecGenericMeshInSceneTemplate_append(&state.vk_ctx.scene_template.generic_models, - (GenericMeshInSceneTemplate){.topology = generate_one_fourth_of_a_cylinder(10, 2, 6), .max_instance_count = 100}); - VecGenericMeshInSceneTemplate_append(&state.vk_ctx.scene_template.generic_models, - (GenericMeshInSceneTemplate){.topology = generate_one_fourth_of_a_cylinder(5, 5, 10), .max_instance_count = 1}); - VecShinyMeshInSceneTemplate_append(&state.vk_ctx.scene_template.shiny_models, (ShinyMeshInSceneTemplate){ + VecGenericMeshInSceneTemplate_append(&vk_ctx->scene_template.generic_models, + GenericMeshInSceneTemplate_for_log(10, 2, 6, 100)); + VecGenericMeshInSceneTemplate_append(&vk_ctx->scene_template.generic_models, + GenericMeshInSceneTemplate_for_log(5, 5, 10, 1)); + VecGenericMeshInSceneTemplate_append(&vk_ctx->scene_template.generic_models, + GenericMeshInSceneTemplate_for_log(1, 10, 4, 2)); + VecGenericMeshInSceneTemplate_append(&vk_ctx->scene_template.generic_models, + GenericMeshInSceneTemplate_for_log(2, 1, 6, 2)); + VecShinyMeshInSceneTemplate_append(&vk_ctx->scene_template.shiny_models, (ShinyMeshInSceneTemplate){ .topology = generate_shiny_rhombicuboctahedron(0.5f), .max_instance_count = 5 }); - VecShinyMeshInSceneTemplate_append(&state.vk_ctx.scene_template.shiny_models, (ShinyMeshInSceneTemplate){ + VecShinyMeshInSceneTemplate_append(&vk_ctx->scene_template.shiny_models, (ShinyMeshInSceneTemplate){ .topology = generate_shiny_cube(0.5f), .max_instance_count = 5 }); - // todo: generate more cool shiny models - // todo: learn how to use libpng - state.vk_ctx.cyl_1_diffuse_tex = TextureDataR8G8B8A8_read_from_png_nofail(cstr("textures/log_10_2_6.png")); - // todo: learn how to write texture immediately from file to mapped host memory buffer - // todo: and at the same time I need to add methods to convert between these formats - state.vk_ctx.cyl_1_normal_tex = TextureDataR8G8B8A8_read_from_png_nofail(cstr("textures/log_10_2_6_NORMAL.png")); + vk_ctx->device_generic_models_top_and_tex = VecGenericModelTopAndTexInMemoryInfo_new_reserved(vk_ctx->scene_template.generic_models.len); + for (size_t i = 0; i < vk_ctx->scene_template.generic_models.len; i++) { + const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&vk_ctx->scene_template.generic_models, i); + VecGenericModelTopAndTexInMemoryInfo_append(&vk_ctx->device_generic_models_top_and_tex, + (GenericModelTopAndTexInMemoryInfo){ + .vbo = GenericMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len), + .ebo = margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len), + .reading_diffuse = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)), + .reading_normal = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)), + // todo: continue from here. But first - create TextureDataR8 reading function + .reading_specular = TextureDataR8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)), + }); + } + // todo: kill myself (update: still WiP (update: it's became growing technical debt point now) - // todo: kill myself (update: still WiP) // We have only one staging buffer in host memory (because we don't really need more) - state.vk_ctx.host_mem_buffer = (MargaretBufferInMemoryInfo){ .sz = - MAX_U64(SceneTemplate_get_space_for_initial_model_topology_transfer(&state.vk_ctx.scene_template), - MAX_U64(SceneTemplate_get_space_needed_for_widest_state_transfer(&state.vk_ctx.scene_template), - MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&state.vk_ctx.cyl_1_diffuse_tex), - MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&state.vk_ctx.cyl_1_normal_tex), 0)))) + vk_ctx->host_mem_buffer = (MargaretBufferInMemoryInfo){ .sz = + MAX_U64(SceneTemplate_get_space_for_initial_model_topology_transfer(&vk_ctx->scene_template), + MAX_U64(SceneTemplate_get_space_needed_for_widest_state_transfer(&vk_ctx->scene_template), + MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_diffuse_tex), + MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_normal_tex), 0)))) , .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT }; - PtrMargaretBufferInMemoryInfo host_mem_buffer_SPAN[1] = {&state.vk_ctx.host_mem_buffer}; - state.vk_ctx.host_mem = margaret_initialize_buffers_and_images(state.vk_ctx.physical_device, state.vk_ctx.device, + PtrMargaretBufferInMemoryInfo host_mem_buffer_SPAN[1] = {&vk_ctx->host_mem_buffer}; + vk_ctx->host_mem = margaret_initialize_buffers_and_images(vk_ctx->physical_device, vk_ctx->device, (MutSpanPtrMargaretBufferInMemoryInfo){.data = host_mem_buffer_SPAN, .len = 1}, (MutSpanPtrMargaretImageInMemoryInfo){ 0 }, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); // todo: split this in two (or maybe even better: merge it all into one/two buffer and use offsets - state.vk_ctx.device_ebo_buffers_for_generic_meshes = VecMargaretBufferInMemoryInfo_new(); - state.vk_ctx.device_vbo_buffers_for_generic_meshes = VecMargaretBufferInMemoryInfo_new(); - for (size_t mi = 0; mi < state.vk_ctx.scene_template.generic_models.len; mi++) { - const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&state.vk_ctx.scene_template.generic_models, mi); - VecMargaretBufferInMemoryInfo_append(&state.vk_ctx.device_vbo_buffers_for_generic_meshes, + vk_ctx->device_ebo_buffers_for_generic_meshes = VecMargaretBufferInMemoryInfo_new(); + vk_ctx->device_vbo_buffers_for_generic_meshes = VecMargaretBufferInMemoryInfo_new(); + for (size_t mi = 0; mi < vk_ctx->scene_template.generic_models.len; mi++) { + const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&vk_ctx->scene_template.generic_models, mi); + VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_vbo_buffers_for_generic_meshes, GenericMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len)); - VecMargaretBufferInMemoryInfo_append(&state.vk_ctx.device_ebo_buffers_for_generic_meshes, + VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_ebo_buffers_for_generic_meshes, margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len)); } - state.vk_ctx.device_ebo_buffers_for_shiny_meshes = VecMargaretBufferInMemoryInfo_new(); - state.vk_ctx.device_vbo_buffers_for_shiny_meshes = VecMargaretBufferInMemoryInfo_new(); - for (size_t mi = 0; mi < state.vk_ctx.scene_template.shiny_models.len; mi++) { - const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&state.vk_ctx.scene_template.shiny_models, mi); - VecMargaretBufferInMemoryInfo_append(&state.vk_ctx.device_vbo_buffers_for_shiny_meshes, + vk_ctx->device_ebo_buffers_for_shiny_meshes = VecMargaretBufferInMemoryInfo_new(); + vk_ctx->device_vbo_buffers_for_shiny_meshes = VecMargaretBufferInMemoryInfo_new(); + for (size_t mi = 0; mi < vk_ctx->scene_template.shiny_models.len; mi++) { + const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&vk_ctx->scene_template.shiny_models, mi); + VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_vbo_buffers_for_shiny_meshes, ShinyMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len)); - VecMargaretBufferInMemoryInfo_append(&state.vk_ctx.device_ebo_buffers_for_shiny_meshes, + VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_ebo_buffers_for_shiny_meshes, margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len)); } - state.vk_ctx.device_lighting_ubo = margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(Pipeline0UBO)); - state.vk_ctx.device_instance_attrs_for_models = (MargaretBufferInMemoryInfo){ - .sz = SceneTemplate_get_space_needed_for_all_instance_attributes(&state.vk_ctx.scene_template), + vk_ctx->device_lighting_ubo = margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(Pipeline0UBO)); + vk_ctx->device_instance_attrs_for_models = (MargaretBufferInMemoryInfo){ + .sz = SceneTemplate_get_space_needed_for_all_instance_attributes(&vk_ctx->scene_template), .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT }; VecPtrMargaretBufferInMemoryInfo device_mem_buffers_SPAN = VecPtrMargaretBufferInMemoryInfo_new(); // todo: add iteration macro generation - for (size_t i = 0; i < state.vk_ctx.device_ebo_buffers_for_generic_meshes.len; i++) { + for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_generic_meshes.len; i++) { VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&state.vk_ctx.device_ebo_buffers_for_generic_meshes, i)); + VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_ebo_buffers_for_generic_meshes, i)); } - for (size_t i = 0; i < state.vk_ctx.device_vbo_buffers_for_generic_meshes.len; i++) { + for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_generic_meshes.len; i++) { VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&state.vk_ctx.device_vbo_buffers_for_generic_meshes, i)); + VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_vbo_buffers_for_generic_meshes, i)); } - for (size_t i = 0; i < state.vk_ctx.device_ebo_buffers_for_shiny_meshes.len; i++) { + for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_shiny_meshes.len; i++) { VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&state.vk_ctx.device_ebo_buffers_for_shiny_meshes, i)); + VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_ebo_buffers_for_shiny_meshes, i)); } - for (size_t i = 0; i < state.vk_ctx.device_vbo_buffers_for_shiny_meshes.len; i++) { + for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_shiny_meshes.len; i++) { VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&state.vk_ctx.device_vbo_buffers_for_shiny_meshes, i)); + VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_vbo_buffers_for_shiny_meshes, i)); } - VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &state.vk_ctx.device_lighting_ubo); - VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &state.vk_ctx.device_instance_attrs_for_models); + VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &vk_ctx->device_lighting_ubo); + VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &vk_ctx->device_instance_attrs_for_models); - state.vk_ctx.device_IT1_image = margaret_prep_image_mem_info_of_colorbuffer( + vk_ctx->device_IT1_image = margaret_prep_image_mem_info_of_colorbuffer( MAX_WIN_WIDTH, MAX_WIN_HEIGHT, IT1_format.some); - state.vk_ctx.device_zbuffer_image = margaret_prep_image_mem_info_of_zbuffer( + vk_ctx->device_zbuffer_image = margaret_prep_image_mem_info_of_zbuffer( MAX_WIN_WIDTH, MAX_WIN_HEIGHT, zbuffer_format.some); - state.vk_ctx.device_cyl_1_diffuse_texture = margaret_prep_image_mem_info_of_gpu_texture_srgba( - state.vk_ctx.cyl_1_diffuse_tex.width, TextureDataR8G8B8A8_get_height(&state.vk_ctx.cyl_1_diffuse_tex)); - state.vk_ctx.device_cyl_1_normal_texture = margaret_prep_image_mem_info_of_gpu_texture_unorm_32( - state.vk_ctx.cyl_1_normal_tex.width, TextureDataR8G8B8A8_get_height(&state.vk_ctx.cyl_1_normal_tex)); + vk_ctx->device_cyl_1_diffuse_texture = margaret_prep_image_mem_info_of_gpu_texture_srgba( + vk_ctx->cyl_1_diffuse_tex.width, TextureDataR8G8B8A8_get_height(&vk_ctx->cyl_1_diffuse_tex)); + vk_ctx->device_cyl_1_normal_texture = margaret_prep_image_mem_info_of_gpu_texture_unorm_32( + vk_ctx->cyl_1_normal_tex.width, TextureDataR8G8B8A8_get_height(&vk_ctx->cyl_1_normal_tex)); PtrMargaretImageInMemoryInfo device_mem_images_SPAN[] = { - &state.vk_ctx.device_IT1_image, &state.vk_ctx.device_zbuffer_image, &state.vk_ctx.device_cyl_1_diffuse_texture, - &state.vk_ctx.device_cyl_1_normal_texture + &vk_ctx->device_IT1_image, &vk_ctx->device_zbuffer_image, &vk_ctx->device_cyl_1_diffuse_texture, + &vk_ctx->device_cyl_1_normal_texture }; - state.vk_ctx.device_mem = margaret_initialize_buffers_and_images(state.vk_ctx.physical_device, state.vk_ctx.device, + vk_ctx->device_mem = margaret_initialize_buffers_and_images(vk_ctx->physical_device, vk_ctx->device, VecPtrMargaretBufferInMemoryInfo_to_mspan(&device_mem_buffers_SPAN), (MutSpanPtrMargaretImageInMemoryInfo){ .data = device_mem_images_SPAN, .len = ARRAY_SIZE(device_mem_images_SPAN) }, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); /* device_mem_buffers_SPAN invalidated */ VecPtrMargaretBufferInMemoryInfo_drop(device_mem_buffers_SPAN); - state.vk_ctx.command_pool = margaret_create_resettable_command_pool(state.vk_ctx.device, state.vk_ctx.queue_fam.for_graphics); - state.vk_ctx.rendering_command_buffer_0 = margaret_allocate_command_buffer(state.vk_ctx.device, state.vk_ctx.command_pool); - state.vk_ctx.rendering_command_buffer_1 = margaret_allocate_command_buffer(state.vk_ctx.device, state.vk_ctx.command_pool); - state.vk_ctx.transfer_command_buffer = margaret_allocate_command_buffer(state.vk_ctx.device, state.vk_ctx.command_pool); + vk_ctx->command_pool = margaret_create_resettable_command_pool(vk_ctx->device, vk_ctx->queue_fam.for_graphics); + vk_ctx->rendering_command_buffer_0 = margaret_allocate_command_buffer(vk_ctx->device, vk_ctx->command_pool); + vk_ctx->rendering_command_buffer_1 = margaret_allocate_command_buffer(vk_ctx->device, vk_ctx->command_pool); + vk_ctx->transfer_command_buffer = margaret_allocate_command_buffer(vk_ctx->device, vk_ctx->command_pool); - state.vk_ctx.my_cam_control_info = CamControlInfo_new(); - state.vk_ctx.Buba_control_info = (vec3){0}; + vk_ctx->my_cam_control_info = CamControlInfo_new(); + vk_ctx->Buba_control_info = (vec3){0}; - state.vk_ctx.scene = Scene_new(); + vk_ctx->scene = Scene_new(); { size_t offset_in_attr_buffer = 0; - for (size_t mi = 0; mi < state.vk_ctx.scene_template.generic_models.len; mi++) { - const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&state.vk_ctx.scene_template.generic_models, mi); - VecUsedGenericModelOnScene_append(&state.vk_ctx.scene.generic_models, (UsedGenericModelOnScene){ + for (size_t mi = 0; mi < vk_ctx->scene_template.generic_models.len; mi++) { + const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&vk_ctx->scene_template.generic_models, mi); + VecUsedGenericModelOnScene_append(&vk_ctx->scene.generic_models, (UsedGenericModelOnScene){ .model = (ModelOnSceneMem){ .vbo = VecMargaretBufferInMemoryInfo_at( - &state.vk_ctx.device_vbo_buffers_for_generic_meshes, mi)->buffer, + &vk_ctx->device_vbo_buffers_for_generic_meshes, mi)->buffer, .ebo = VecMargaretBufferInMemoryInfo_at( - &state.vk_ctx.device_ebo_buffers_for_generic_meshes, mi)->buffer, + &vk_ctx->device_ebo_buffers_for_generic_meshes, mi)->buffer, .indexes = M->topology.indexes.len, - .instance_attr_buf = state.vk_ctx.device_instance_attrs_for_models.buffer, + .instance_attr_buf = vk_ctx->device_instance_attrs_for_models.buffer, .instance_attr_buf_offset = offset_in_attr_buffer, .limit_max_instance_count = M->max_instance_count }, @@ -1883,16 +1916,16 @@ int main() { }); offset_in_attr_buffer += M->max_instance_count * sizeof(GenericMeshInstance); } - for (size_t mi = 0; mi < state.vk_ctx.scene_template.shiny_models.len; mi++) { - const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&state.vk_ctx.scene_template.shiny_models, mi); - VecUsedShinyModelOnScene_append(&state.vk_ctx.scene.shiny_models, (UsedShinyModelOnScene){ + for (size_t mi = 0; mi < vk_ctx->scene_template.shiny_models.len; mi++) { + const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&vk_ctx->scene_template.shiny_models, mi); + VecUsedShinyModelOnScene_append(&vk_ctx->scene.shiny_models, (UsedShinyModelOnScene){ .model = (ModelOnSceneMem){ .vbo = VecMargaretBufferInMemoryInfo_at( - &state.vk_ctx.device_vbo_buffers_for_shiny_meshes, mi)->buffer, + &vk_ctx->device_vbo_buffers_for_shiny_meshes, mi)->buffer, .ebo = VecMargaretBufferInMemoryInfo_at( - &state.vk_ctx.device_ebo_buffers_for_shiny_meshes, mi)->buffer, + &vk_ctx->device_ebo_buffers_for_shiny_meshes, mi)->buffer, .indexes = M->topology.indexes.len, - .instance_attr_buf = state.vk_ctx.device_instance_attrs_for_models.buffer, + .instance_attr_buf = vk_ctx->device_instance_attrs_for_models.buffer, .instance_attr_buf_offset = offset_in_attr_buffer, .limit_max_instance_count = M->max_instance_count }, @@ -1904,121 +1937,121 @@ int main() { for (int X = 0; X < 10; X++) { for (int Z = 0; Z < 10; Z++) { - VecGenericMeshInstance_append(&VecUsedGenericModelOnScene_mat(&state.vk_ctx.scene.generic_models, 0)->instances, + VecGenericMeshInstance_append(&VecUsedGenericModelOnScene_mat(&vk_ctx->scene.generic_models, 0)->instances, (GenericMeshInstance){ .model_t = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}) }); } } - VecGenericMeshInstance_append(&VecUsedGenericModelOnScene_mat(&state.vk_ctx.scene.generic_models, 1)->instances, - (GenericMeshInstance){ .model_t = marie_translation_mat4(state.vk_ctx.Buba_control_info) + VecGenericMeshInstance_append(&VecUsedGenericModelOnScene_mat(&vk_ctx->scene.generic_models, 1)->instances, + (GenericMeshInstance){ .model_t = marie_translation_mat4(vk_ctx->Buba_control_info) }); for (U64 i = 0; i < 5; i++) { - VecShinyMeshInstance_append(&VecUsedShinyModelOnScene_mat(&state.vk_ctx.scene.shiny_models, 0)->instances, + VecShinyMeshInstance_append(&VecUsedShinyModelOnScene_mat(&vk_ctx->scene.shiny_models, 0)->instances, (ShinyMeshInstance){ .model_t = marie_translation_mat4((vec3){ (float)((i * i * 10 + i * 4 + 1) % 13) + 2, (float)((i * i * 11 + i * 2 + 2) % 13), (float)((i * i * 9 + i * 1 + 4) % 13) + 3}), .color_off = (vec3){0.6f, 0.2f, 0.2f}}); } - VecShinyMeshInstance_append(&VecUsedShinyModelOnScene_mat(&state.vk_ctx.scene.shiny_models, 1)->instances, + VecShinyMeshInstance_append(&VecUsedShinyModelOnScene_mat(&vk_ctx->scene.shiny_models, 1)->instances, (ShinyMeshInstance){ .model_t = marie_translation_mat4((vec3){-5, 0, 3}), .color_off = (vec3){0.3f, 0.5f, 0.5f}}); // todo: synchronize them with my cool light sources) - if (vkMapMemory(state.vk_ctx.device, state.vk_ctx.host_mem, 0, VK_WHOLE_SIZE, 0, &state.vk_ctx.host_mem_buffer_mem) != VK_SUCCESS) + if (vkMapMemory(vk_ctx->device, vk_ctx->host_mem, 0, VK_WHOLE_SIZE, 0, &vk_ctx->host_mem_buffer_mem) != VK_SUCCESS) abortf("vkMapMemory"); SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd( - &state.vk_ctx.scene_template, &state.vk_ctx.scene, state.vk_ctx.host_mem_buffer_mem, - state.vk_ctx.transfer_command_buffer, state.vk_ctx.host_mem_buffer.buffer); + &vk_ctx->scene_template, &vk_ctx->scene, vk_ctx->host_mem_buffer_mem, + vk_ctx->transfer_command_buffer, vk_ctx->host_mem_buffer.buffer); { - VkCommandBuffer command_buffers[1] = { state.vk_ctx.transfer_command_buffer }; + VkCommandBuffer command_buffers[1] = { vk_ctx->transfer_command_buffer }; VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, .commandBufferCount = ARRAY_SIZE(command_buffers), .pCommandBuffers = command_buffers, }; - if (vkQueueSubmit(state.vk_ctx.queues.graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) + if (vkQueueSubmit(vk_ctx->queues.graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) abortf("vkQueueSubmit\n"); } - vkDeviceWaitIdle(state.vk_ctx.device); + vkDeviceWaitIdle(vk_ctx->device); { - memcpy(state.vk_ctx.host_mem_buffer_mem, state.vk_ctx.cyl_1_diffuse_tex.pixels.buf, - TextureDataR8G8B8A8_get_size_in_bytes(&state.vk_ctx.cyl_1_diffuse_tex)); + memcpy(vk_ctx->host_mem_buffer_mem, vk_ctx->cyl_1_diffuse_tex.pixels.buf, + TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_diffuse_tex)); margaret_copy_buffer_to_texture_for_frag_shader_imm( - state.vk_ctx.device, state.vk_ctx.command_pool, state.vk_ctx.queues.graphics_queue, - &state.vk_ctx.device_cyl_1_diffuse_texture, state.vk_ctx.host_mem_buffer.buffer); + vk_ctx->device, vk_ctx->command_pool, vk_ctx->queues.graphics_queue, + &vk_ctx->device_cyl_1_diffuse_texture, vk_ctx->host_mem_buffer.buffer); } - vkDeviceWaitIdle(state.vk_ctx.device); + vkDeviceWaitIdle(vk_ctx->device); { - memcpy(state.vk_ctx.host_mem_buffer_mem, state.vk_ctx.cyl_1_normal_tex.pixels.buf, - TextureDataR8G8B8A8_get_size_in_bytes(&state.vk_ctx.cyl_1_normal_tex)); + memcpy(vk_ctx->host_mem_buffer_mem, vk_ctx->cyl_1_normal_tex.pixels.buf, + TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_normal_tex)); margaret_copy_buffer_to_texture_for_frag_shader_imm( - state.vk_ctx.device, state.vk_ctx.command_pool, state.vk_ctx.queues.graphics_queue, - &state.vk_ctx.device_cyl_1_normal_texture, state.vk_ctx.host_mem_buffer.buffer); + vk_ctx->device, vk_ctx->command_pool, vk_ctx->queues.graphics_queue, + &vk_ctx->device_cyl_1_normal_texture, vk_ctx->host_mem_buffer.buffer); } - vkDeviceWaitIdle(state.vk_ctx.device); + vkDeviceWaitIdle(vk_ctx->device); // We sent everything we needed. but host_mem_buffer_mem may be used later // My zbuffer also needs a view - state.vk_ctx.zbuffer_view = margaret_create_view_for_image(state.vk_ctx.device, - &state.vk_ctx.device_zbuffer_image, VK_IMAGE_ASPECT_DEPTH_BIT); + vk_ctx->zbuffer_view = margaret_create_view_for_image(vk_ctx->device, + &vk_ctx->device_zbuffer_image, VK_IMAGE_ASPECT_DEPTH_BIT); /* Here we create an image view into a temporary IT1 texture and a framebuffer for scene rendering */ - state.vk_ctx.IT1_view = margaret_create_view_for_image(state.vk_ctx.device, - &state.vk_ctx.device_IT1_image, VK_IMAGE_ASPECT_COLOR_BIT); - state.vk_ctx.IT1_framebuffer = create_IT1_framebuffer(state.vk_ctx.device, - state.vk_ctx.IT1_view, state.vk_ctx.zbuffer_view, state.vk_ctx.render_pass_0, MAX_WIN_WIDTH, MAX_WIN_HEIGHT); + vk_ctx->IT1_view = margaret_create_view_for_image(vk_ctx->device, + &vk_ctx->device_IT1_image, VK_IMAGE_ASPECT_COLOR_BIT); + vk_ctx->IT1_framebuffer = create_IT1_framebuffer(vk_ctx->device, + vk_ctx->IT1_view, vk_ctx->zbuffer_view, vk_ctx->render_pass_0, MAX_WIN_WIDTH, MAX_WIN_HEIGHT); // My cylinder 1 texture needs VkImageView - state.vk_ctx.cyl_1_diffuse_texture_view = margaret_create_view_for_image( - state.vk_ctx.device, &state.vk_ctx.device_cyl_1_diffuse_texture, VK_IMAGE_ASPECT_COLOR_BIT); + vk_ctx->cyl_1_diffuse_texture_view = margaret_create_view_for_image( + vk_ctx->device, &vk_ctx->device_cyl_1_diffuse_texture, VK_IMAGE_ASPECT_COLOR_BIT); // My cylinder 1 normal texture also needs NkImageView - state.vk_ctx.cyl_1_normal_texture_view = margaret_create_view_for_image( - state.vk_ctx.device, &state.vk_ctx.device_cyl_1_normal_texture, VK_IMAGE_ASPECT_COLOR_BIT); + vk_ctx->cyl_1_normal_texture_view = margaret_create_view_for_image( + vk_ctx->device, &vk_ctx->device_cyl_1_normal_texture, VK_IMAGE_ASPECT_COLOR_BIT); // Right now I only have one light source - VecPipeline0PointLight_append(&state.vk_ctx.scene.point_lights, (Pipeline0PointLight){.pos = {0}, .color = {100, 100, 100}}); + VecPipeline0PointLight_append(&vk_ctx->scene.point_lights, (Pipeline0PointLight){.pos = {0}, .color = {100, 100, 100}}); // These samplers are global for a lot of my future textures - state.vk_ctx.linear_sampler = margaret_create_sampler(state.vk_ctx.physical_device, state.vk_ctx.device, true); - state.vk_ctx.nearest_sampler = margaret_create_sampler(state.vk_ctx.physical_device, state.vk_ctx.device, false); + vk_ctx->linear_sampler = margaret_create_sampler(vk_ctx->physical_device, vk_ctx->device, true); + vk_ctx->nearest_sampler = margaret_create_sampler(vk_ctx->physical_device, vk_ctx->device, false); - state.vk_ctx.descriptor_pool = margaret_create_descriptor_set_pool(state.vk_ctx.device, 2, 3, 3); - state.vk_ctx.descriptor_set_for_pipeline_0a = margaret_allocate_descriptor_set( - state.vk_ctx.device, state.vk_ctx.descriptor_pool, state.vk_ctx.pipeline_hands_0a.descriptor_set_layout); - state.vk_ctx.descriptor_set_for_pipeline_0b = margaret_allocate_descriptor_set( - state.vk_ctx.device, state.vk_ctx.descriptor_pool, state.vk_ctx.pipeline_hands_0b.descriptor_set_layout); - state.vk_ctx.descriptor_set_for_pipeline_1 = margaret_allocate_descriptor_set( - state.vk_ctx.device, state.vk_ctx.descriptor_pool, state.vk_ctx.pipeline_hands_1.descriptor_set_layout); + vk_ctx->descriptor_pool = margaret_create_descriptor_set_pool(vk_ctx->device, 2, 3, 3); + vk_ctx->descriptor_set_for_pipeline_0a = margaret_allocate_descriptor_set( + vk_ctx->device, vk_ctx->descriptor_pool, vk_ctx->pipeline_hands_0a.descriptor_set_layout); + vk_ctx->descriptor_set_for_pipeline_0b = margaret_allocate_descriptor_set( + vk_ctx->device, vk_ctx->descriptor_pool, vk_ctx->pipeline_hands_0b.descriptor_set_layout); + vk_ctx->descriptor_set_for_pipeline_1 = margaret_allocate_descriptor_set( + vk_ctx->device, vk_ctx->descriptor_pool, vk_ctx->pipeline_hands_1.descriptor_set_layout); // Configuring my descriptor sets, that I just allocated VkDescriptorBufferInfo buffer_info_for_descriptor_0_in_set_0a = { - .buffer = state.vk_ctx.device_lighting_ubo.buffer, + .buffer = vk_ctx->device_lighting_ubo.buffer, .offset = 0, .range = sizeof(Pipeline0UBO), }; VkDescriptorImageInfo image_info_for_descriptor_1_in_set_0a = { - .sampler = state.vk_ctx.linear_sampler, - .imageView = state.vk_ctx.cyl_1_diffuse_texture_view, + .sampler = vk_ctx->linear_sampler, + .imageView = vk_ctx->cyl_1_diffuse_texture_view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkDescriptorImageInfo image_info_for_descriptor_2_in_set_0a = { - .sampler = state.vk_ctx.nearest_sampler, - .imageView = state.vk_ctx.cyl_1_normal_texture_view, + .sampler = vk_ctx->nearest_sampler, + .imageView = vk_ctx->cyl_1_normal_texture_view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkDescriptorBufferInfo buffer_info_for_descriptor_0_in_set_0b = { - .buffer = state.vk_ctx.device_lighting_ubo.buffer, + .buffer = vk_ctx->device_lighting_ubo.buffer, .offset = 0, .range = sizeof(Pipeline0UBO), }; VkDescriptorImageInfo image_info_for_descriptor_0_in_set_1 = { - .sampler = state.vk_ctx.nearest_sampler, - .imageView = state.vk_ctx.IT1_view, + .sampler = vk_ctx->nearest_sampler, + .imageView = vk_ctx->IT1_view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkWriteDescriptorSet writes_in_descriptor_sets[] = { { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = state.vk_ctx.descriptor_set_for_pipeline_0a, + .dstSet = vk_ctx->descriptor_set_for_pipeline_0a, .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, @@ -2027,7 +2060,7 @@ int main() { }, { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = state.vk_ctx.descriptor_set_for_pipeline_0a, + .dstSet = vk_ctx->descriptor_set_for_pipeline_0a, .dstBinding = 1, .dstArrayElement = 0, .descriptorCount = 1, @@ -2036,7 +2069,7 @@ int main() { }, { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = state.vk_ctx.descriptor_set_for_pipeline_0a, + .dstSet = vk_ctx->descriptor_set_for_pipeline_0a, .dstBinding = 2, .dstArrayElement = 0, .descriptorCount = 1, @@ -2046,7 +2079,7 @@ int main() { { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = state.vk_ctx.descriptor_set_for_pipeline_0b, + .dstSet = vk_ctx->descriptor_set_for_pipeline_0b, .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, @@ -2056,7 +2089,7 @@ int main() { { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = state.vk_ctx.descriptor_set_for_pipeline_1, + .dstSet = vk_ctx->descriptor_set_for_pipeline_1, .dstBinding = 0, .dstArrayElement = 0, .descriptorCount = 1, @@ -2064,90 +2097,91 @@ int main() { .pImageInfo = &image_info_for_descriptor_0_in_set_1, }, }; - vkUpdateDescriptorSets(state.vk_ctx.device, ARRAY_SIZE(writes_in_descriptor_sets), writes_in_descriptor_sets, 0, NULL); + vkUpdateDescriptorSets(vk_ctx->device, ARRAY_SIZE(writes_in_descriptor_sets), writes_in_descriptor_sets, 0, NULL); - state.vk_ctx.jane = Jane_r0_create(state.vk_ctx.device); + vk_ctx->jane = Jane_r0_create(vk_ctx->device); state.prev_key_frame_time = margaret_clock_gettime_monotonic_raw(); state.frame_count_since_key = 0; /* Will happen mid-frame */ - state.vk_ctx.dt_transfer_required = true; + vk_ctx->dt_transfer_required = true; while (wl_display_dispatch(state.wl_display) >= 0) { if (state.closed) break; } - vkDeviceWaitIdle(state.vk_ctx.device); + vkDeviceWaitIdle(vk_ctx->device); // The End - vkDestroyDescriptorPool(state.vk_ctx.device, state.vk_ctx.descriptor_pool, NULL); - vkDestroySampler(state.vk_ctx.device, state.vk_ctx.linear_sampler, NULL); - vkDestroySampler(state.vk_ctx.device, state.vk_ctx.nearest_sampler, NULL); + vkDestroyDescriptorPool(vk_ctx->device, vk_ctx->descriptor_pool, NULL); + vkDestroySampler(vk_ctx->device, vk_ctx->linear_sampler, NULL); + vkDestroySampler(vk_ctx->device, vk_ctx->nearest_sampler, NULL); - vkDestroyImageView(state.vk_ctx.device, state.vk_ctx.cyl_1_normal_texture_view, NULL); - vkDestroyImageView(state.vk_ctx.device, state.vk_ctx.cyl_1_diffuse_texture_view, NULL); - vkDestroyFramebuffer(state.vk_ctx.device, state.vk_ctx.IT1_framebuffer, NULL); - vkDestroyImageView(state.vk_ctx.device, state.vk_ctx.IT1_view, NULL); - vkDestroyImageView(state.vk_ctx.device, state.vk_ctx.zbuffer_view, NULL); + vkDestroyImageView(vk_ctx->device, vk_ctx->cyl_1_normal_texture_view, NULL); + vkDestroyImageView(vk_ctx->device, vk_ctx->cyl_1_diffuse_texture_view, NULL); + vkDestroyFramebuffer(vk_ctx->device, vk_ctx->IT1_framebuffer, NULL); + vkDestroyImageView(vk_ctx->device, vk_ctx->IT1_view, NULL); + vkDestroyImageView(vk_ctx->device, vk_ctx->zbuffer_view, NULL); - Scene_drop(state.vk_ctx.scene); + Scene_drop(vk_ctx->scene); - vkDestroyCommandPool(state.vk_ctx.device, state.vk_ctx.command_pool, NULL); + vkDestroyCommandPool(vk_ctx->device, vk_ctx->command_pool, NULL); - vkUnmapMemory(state.vk_ctx.device, state.vk_ctx.host_mem); - vkFreeMemory(state.vk_ctx.device, state.vk_ctx.host_mem, NULL); - vkFreeMemory(state.vk_ctx.device, state.vk_ctx.device_mem, NULL); + vkUnmapMemory(vk_ctx->device, vk_ctx->host_mem); + vkFreeMemory(vk_ctx->device, vk_ctx->host_mem, NULL); + vkFreeMemory(vk_ctx->device, vk_ctx->device_mem, NULL); - vkDestroyImage(state.vk_ctx.device, state.vk_ctx.device_cyl_1_diffuse_texture.image, NULL); - vkDestroyImage(state.vk_ctx.device, state.vk_ctx.device_cyl_1_normal_texture.image, NULL); - vkDestroyImage(state.vk_ctx.device, state.vk_ctx.device_IT1_image.image, NULL); - vkDestroyImage(state.vk_ctx.device, state.vk_ctx.device_zbuffer_image.image, NULL); - vkDestroyBuffer(state.vk_ctx.device, state.vk_ctx.device_lighting_ubo.buffer, NULL); + // todo: delete all the crap + vkDestroyImage(vk_ctx->device, vk_ctx->device_cyl_1_diffuse_texture.image, NULL); + vkDestroyImage(vk_ctx->device, vk_ctx->device_cyl_1_normal_texture.image, NULL); + vkDestroyImage(vk_ctx->device, vk_ctx->device_IT1_image.image, NULL); + vkDestroyImage(vk_ctx->device, vk_ctx->device_zbuffer_image.image, NULL); + vkDestroyBuffer(vk_ctx->device, vk_ctx->device_lighting_ubo.buffer, NULL); - vkDestroyBuffer(state.vk_ctx.device, state.vk_ctx.device_instance_attrs_for_models.buffer, NULL); + vkDestroyBuffer(vk_ctx->device, vk_ctx->device_instance_attrs_for_models.buffer, NULL); - for (size_t i = 0; i < state.vk_ctx.device_ebo_buffers_for_generic_meshes.len; i++) - vkDestroyBuffer(state.vk_ctx.device, - VecMargaretBufferInMemoryInfo_at(&state.vk_ctx.device_ebo_buffers_for_generic_meshes, i)->buffer, + for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_generic_meshes.len; i++) + vkDestroyBuffer(vk_ctx->device, + VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_ebo_buffers_for_generic_meshes, i)->buffer, NULL); - VecMargaretBufferInMemoryInfo_drop(state.vk_ctx.device_ebo_buffers_for_generic_meshes); + VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_ebo_buffers_for_generic_meshes); - for (size_t i = 0; i < state.vk_ctx.device_vbo_buffers_for_generic_meshes.len; i++) - vkDestroyBuffer(state.vk_ctx.device, - VecMargaretBufferInMemoryInfo_at(&state.vk_ctx.device_vbo_buffers_for_generic_meshes, i)->buffer, + for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_generic_meshes.len; i++) + vkDestroyBuffer(vk_ctx->device, + VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_vbo_buffers_for_generic_meshes, i)->buffer, NULL); - VecMargaretBufferInMemoryInfo_drop(state.vk_ctx.device_vbo_buffers_for_generic_meshes); + VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_vbo_buffers_for_generic_meshes); - for (size_t i = 0; i < state.vk_ctx.device_ebo_buffers_for_shiny_meshes.len; i++) - vkDestroyBuffer(state.vk_ctx.device, - VecMargaretBufferInMemoryInfo_at(&state.vk_ctx.device_ebo_buffers_for_shiny_meshes, i)->buffer, + for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_shiny_meshes.len; i++) + vkDestroyBuffer(vk_ctx->device, + VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_ebo_buffers_for_shiny_meshes, i)->buffer, NULL); - VecMargaretBufferInMemoryInfo_drop(state.vk_ctx.device_ebo_buffers_for_shiny_meshes); + VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_ebo_buffers_for_shiny_meshes); - for (size_t i = 0; i < state.vk_ctx.device_vbo_buffers_for_shiny_meshes.len; i++) - vkDestroyBuffer(state.vk_ctx.device, - VecMargaretBufferInMemoryInfo_at(&state.vk_ctx.device_vbo_buffers_for_shiny_meshes, i)->buffer, + for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_shiny_meshes.len; i++) + vkDestroyBuffer(vk_ctx->device, + VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_vbo_buffers_for_shiny_meshes, i)->buffer, NULL); - VecMargaretBufferInMemoryInfo_drop(state.vk_ctx.device_vbo_buffers_for_shiny_meshes); + VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_vbo_buffers_for_shiny_meshes); - vkDestroyBuffer(state.vk_ctx.device, state.vk_ctx.host_mem_buffer.buffer, NULL); + vkDestroyBuffer(vk_ctx->device, vk_ctx->host_mem_buffer.buffer, NULL); - TextureDataR8G8B8A8_drop(state.vk_ctx.cyl_1_normal_tex); - TextureDataR8G8B8A8_drop(state.vk_ctx.cyl_1_diffuse_tex); - SceneTemplate_drop(state.vk_ctx.scene_template); + TextureDataR8G8B8A8_drop(vk_ctx->cyl_1_normal_tex); + TextureDataR8G8B8A8_drop(vk_ctx->cyl_1_diffuse_tex); + SceneTemplate_drop(vk_ctx->scene_template); - MargaretSwapchainBundle_drop_with_device(state.vk_ctx.device, state.vk_ctx.swfb); - Jane_r0_destroy(state.vk_ctx.device, state.vk_ctx.jane); - destroy_graphics_pipeline_hands(state.vk_ctx.device, state.vk_ctx.pipeline_hands_1); - vkDestroyRenderPass(state.vk_ctx.device, state.vk_ctx.render_pass_1, NULL); - destroy_graphics_pipeline_hands(state.vk_ctx.device, state.vk_ctx.pipeline_hands_0b); - destroy_graphics_pipeline_hands(state.vk_ctx.device, state.vk_ctx.pipeline_hands_0a); - vkDestroyRenderPass(state.vk_ctx.device, state.vk_ctx.render_pass_0, NULL); - vkDestroyDevice(state.vk_ctx.device, NULL); - vkDestroySurfaceKHR(instance, state.vk_ctx.surface, NULL); - MargaretInstanceAndItsDebug_drop(state.vk_ctx.instance_and_debug); + MargaretSwapchainBundle_drop_with_device(vk_ctx->device, vk_ctx->swfb); + Jane_r0_destroy(vk_ctx->device, vk_ctx->jane); + destroy_graphics_pipeline_hands(vk_ctx->device, vk_ctx->pipeline_hands_1); + vkDestroyRenderPass(vk_ctx->device, vk_ctx->render_pass_1, NULL); + destroy_graphics_pipeline_hands(vk_ctx->device, vk_ctx->pipeline_hands_0b); + destroy_graphics_pipeline_hands(vk_ctx->device, vk_ctx->pipeline_hands_0a); + vkDestroyRenderPass(vk_ctx->device, vk_ctx->render_pass_0, NULL); + vkDestroyDevice(vk_ctx->device, NULL); + vkDestroySurfaceKHR(instance, vk_ctx->surface, NULL); + MargaretInstanceAndItsDebug_drop(vk_ctx->instance_and_debug); if (state.wl_callback) wl_callback_destroy(state.wl_callback); diff --git a/src/l2/tests/r0/r0_assets.h b/src/l2/tests/r0/r0_assets.h index 1460d7a..2e177ef 100644 --- a/src/l2/tests/r0/r0_assets.h +++ b/src/l2/tests/r0/r0_assets.h @@ -8,6 +8,7 @@ #include "../../../../gen/l1/VecAndSpan_vec.h" #include "../../../../gen/l1/pixel_masses.h" #include "../../marie/rasterization.h" +#include "../../marie/texture_processing.h" typedef struct { vec3 pos; @@ -32,10 +33,16 @@ GenericMeshTopology GenericMeshTopology_clone(const GenericMeshTopology* self) { typedef struct { GenericMeshTopology topology; U32 max_instance_count; + VecU8 diffuse_texture_path; + VecU8 normal_texture_path; + VecU8 specular_texture_path; } GenericMeshInSceneTemplate; void GenericMeshInSceneTemplate_drop(GenericMeshInSceneTemplate self) { GenericMeshTopology_drop(self.topology); + VecU8_drop(self.diffuse_texture_path); + VecU8_drop(self.normal_texture_path); + VecU8_drop(self.specular_texture_path); } GenericMeshInSceneTemplate GenericMeshInSceneTemplate_clone(const GenericMeshInSceneTemplate* self) { @@ -454,6 +461,41 @@ vec2 Bublazhuzhka_get_derivative(const Bublazhuzhka* self, vec2 v) { return sum; } +cvec3 Bublazhuzhka_get_color(const Bublazhuzhka* self, vec2 v) { + float flats = 0; + for (size_t i = 0; i < self->wimbzles.len; i++) { + Wimbzle rect = *VecWimbzle_at(&self->wimbzles, i); + vec2 B = {rect.tr.x + rect.brd, rect.tr.y + rect.brd}; + vec2 C = {rect.bl.x - rect.brd, rect.bl.y - rect.brd}; + vec2 A = {C.x, B.y}; + vec2 D = {B.x, C.y}; + vec2 F = rect.tr; + vec2 G = rect.bl; + vec2 E = {G.x, F.y}; + vec2 H = {F.x, G.y}; + float slp = rect.height / rect.brd; + if (A.x < v.x && v.x < E.x && marie_surface(E, A, v) > 0 && marie_surface(C, G, v) > 0) { + return (cvec3){100, 30, 40}; + } else if (F.x < v.x && v.x < B.x && marie_surface(B, F, v) > 0 && marie_surface(H, D, v) > 0) { + return (cvec3){70, 60, 45}; + } else if (C.y < v.y && v.y < G.y && marie_surface(G, C, v) > 0 && marie_surface(D, H, v) > 0) { + return (cvec3){10, 100, 70}; + } else if (F.y < v.y && v.y < B.y && marie_surface(A, E, v) > 0 && marie_surface(F, B, v) > 0) { + return (cvec3){25, 50, 110}; + } else if (E.x <= v.x && v.x <= F.x && G.y <= v.y && v.y <= F.y) { + flats += rect.height; + } + } + for (size_t i = 0; i < self->nibzles.len; i++) { + Nibzle sphere = *VecNibzle_at(&self->nibzles, i); + float sq_h = pow2f(sphere.rad) - pow2f(v.x - sphere.center.x) - pow2f(v.y - sphere.center.y); + if (sq_h >= 0) + return (cvec3){120, 120, 120}; + } + U8 p = (U8)roundf((1.f - expf(flats)) * 60); + return (cvec3){121 - p * 2, 30 + p, 65 - p}; +} + cvec3 compress_normal_vec_into_norm_texel(vec3 n) { return (cvec3){(U32)roundf(255 * (n.x + 1) / 2), (U32)roundf(255 * (n.y + 1) / 2), (U32)roundf(255 * (n.z + 1) / 2)}; } @@ -575,10 +617,36 @@ void draw_polygon_on_normal_texture_flat_param_surf(TextureDataR8G8B8A8* tex, ve } +typedef struct { + TextureDataR8G8B8A8* self; + const Bublazhuzhka* bublazhuzhka; +} TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_H_DrawGuest; + +void TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_h_draw_guest(void* ug, S32 x, S32 y, vec4 attr) { + TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_H_DrawGuest *g = ug; + cvec3 clr = Bublazhuzhka_get_color(g->bublazhuzhka, (vec2){attr.x, attr.y}); + if (TextureDataR8G8B8A8_is_inside(g->self, x, y)) + *TextureDataR8G8B8A8_mat(g->self, x, y) = (cvec4){clr.x, clr.y, clr.z, 255}; +} + +/* Not natural coordinates. Needs translation operator to convert + * from parameter space*/ +void TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka( + TextureDataR8G8B8A8* self, const Bublazhuzhka* bublazhuzhka, MarieTriangle param_triangle, mat3x2 trop + ) { + TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_H_DrawGuest aboba = + {self, bublazhuzhka}; + MarieTriangleAttr natural = MarieTriangle_goto_nat_cords_pres_par(param_triangle, trop); + // todo: continue from here + marie_rasterize_triangle_with_attr( + natural.v0, natural.v1, natural.v2, + (FnMarieRasterizerCallback){.fn = TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka_h_draw_guest, .guest = &aboba}); +} -TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) { + +TextureDataR8G8B8A8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) { assert(k >= 1); const float a = M_PI_2f / (float)k; const float l = 2 * r * sinf(M_PI_4f / (float)k); @@ -589,36 +657,42 @@ TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, const vec2 v1tex = {r + w, r}; const vec2 v2tex = {r, 2 * r}; const vec2 v3tex = {r + w, 2 * r}; - TextureDataR8 res = TextureDataR8_new(width_pix, height_pix); - Vecvec2 P = Vecvec2_new_reserved(6 + k * 4); - Vecvec2_append(&P, v0tex); - Vecvec2_append(&P, (vec2){r, 0}); // 4 - Vecvec2_append(&P, (vec2){r + w, 0}); // 5 - Vecvec2_append(&P, v1tex); - for (size_t i = k; i > 0; i--) { - Vecvec2_append(&P, (vec2){r + w + r * sinf(a * (float)i), r + r * cosf(a * (float)i)}); - } - Vecvec2_append(&P, v3tex); + const vec2 v4tex = {r, 0}; + const vec2 v5tex = {r + w, 0}; + TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width_pix, height_pix); + mat3x2 cord_resol_trop = (mat3x2){.x.x = cord_resol.x, .y.y = cord_resol.y}; + + vec3 color_1 = (vec3){0.3f, 0.5f, 0.1f}; + TextureDataR8G8B8A8_draw_triangle_of_one_color(&res, color_1, (MarieTriangle){v0tex, v4tex, v5tex}, cord_resol_trop); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&res, color_1, (MarieTriangle){v0tex, v5tex, v1tex}, cord_resol_trop); + vec3 color_2 = (vec3){0.1f, 0.2f, 0.8f}; + vec3 color_3 = (vec3){0.2f, 0.3f, 0.9f}; + vec3 color_4 = (vec3){0.1f, 0.5f, 0.7f}; + vec3 color_5 = (vec3){0.7f, 0.05f, 0.2f}; for (size_t i = 1; i <= k; i++) { - Vecvec2_append(&P, (vec2){r + w, 2 * r + (float)i * l}); + vec2 A = (vec2){r - r * sinf(a * (float)i), r + r * cosf(a * (float)i)}; + vec2 B = (vec2){r - r * sinf(a * (float)(i-1)), r + r * cosf(a * (float)(i-1))}; + TextureDataR8G8B8A8_draw_triangle_of_one_color(&res, color_2, (MarieTriangle){v0tex, B, A}, cord_resol_trop); } - for (size_t i = k; i > 0; i--) { - Vecvec2_append(&P, (vec2){r, 2 * r + (float)i * l}); - } - Vecvec2_append(&P, v2tex); for (size_t i = 1; i <= k; i++) { - Vecvec2_append(&P, (vec2){r - r * sinf(a * (float)i), r + r * cosf(a * (float)i)}); + vec2 A = (vec2){r + w + r * sinf(a * (float)i), r + r * cosf(a * (float)i)}; + vec2 B = (vec2){r + w + r * sinf(a * (float)(i-1)), r + r * cosf(a * (float)(i-1))}; + TextureDataR8G8B8A8_draw_triangle_of_one_color(&res, color_3, (MarieTriangle){v1tex, A, B}, cord_resol_trop); } - for (size_t i = 0; i < P.len; i++) { - *Vecvec2_mat(&P, i) = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol); + for (size_t i = 1; i <= k; i++) { + vec2 A = (vec2){r, 2 * r + (float)(i) * l}; + vec2 B = (vec2){r, 2 * r + (float)(i-1) * l}; + vec2 C = (vec2){r + w, 2 * r + (float)(i-1) * l}; + vec2 D = (vec2){r + w, 2 * r + (float)(i) * l}; + vec3 c = i % 2 ? color_4 : color_5; + TextureDataR8G8B8A8_draw_triangle_of_one_color(&res, c, (MarieTriangle){A, B, C}, cord_resol_trop); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&res, c, (MarieTriangle){A, C, D}, cord_resol_trop); } - TextureDataR8_draw_perimeter_maxing(&res, Vecvec2_to_span(&P)); - Vecvec2_drop(P); Bublazhuzhka crap_on_back_side = fill_rectangle_with_crap(w, r); - // todo: draw bublazhuzhka pixel-by-pixel myself - Bublazhuzhka_TextureDataR8_draw_maxing(&crap_on_back_side, &res, - (mat3x2){.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)}); + mat3x2 back_side_trop = (mat3x2){.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)}; + TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka(&res, &crap_on_back_side, (MarieTriangle){{0, r}, {0, 0}, {w, 0}}, back_side_trop); + TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka(&res, &crap_on_back_side, (MarieTriangle){{0, r}, {w, 0}, {w, r}}, back_side_trop); Bublazhuzhka_drop(crap_on_back_side); return res; } @@ -792,4 +866,13 @@ ShinyMeshTopology generate_shiny_rhombicuboctahedron(float r) { return res; } +GenericMeshInSceneTemplate GenericMeshInSceneTemplate_for_log(U32 w, U32 r, U32 k, U32 max_instance_count) { + return (GenericMeshInSceneTemplate){.topology = generate_one_fourth_of_a_cylinder((float)w, (float)r, k), + .max_instance_count = max_instance_count, + .diffuse_texture_path = VecU8_format("log_%u_%u_%u_diffuse.png", w, r, k), + .normal_texture_path = VecU8_format("log_%u_%u_%u_NORMAL.png", w, r, k), + .specular_texture_path = VecU8_format("log_%u_%u_%u_specular.png", w, r, k), + }; +} + #endif diff --git a/src/l2/tests/r0/r0_scene.h b/src/l2/tests/r0/r0_scene.h index 4eca086..455dead 100644 --- a/src/l2/tests/r0/r0_scene.h +++ b/src/l2/tests/r0/r0_scene.h @@ -12,6 +12,9 @@ typedef struct { VkBuffer instance_attr_buf; VkDeviceSize instance_attr_buf_offset; U32 limit_max_instance_count; + VkImage diffuse_texture; + VkImage normal_texture; + VkImage specular_texture; } ModelOnSceneMem; /* Contains both data for model instances attributes and buffer (+offset) where it is stored */ diff --git a/src/l2/tests/r0/r0_tex_init_prep.c b/src/l2/tests/r0/r0_tex_init_prep.c index d96de16..0e1137d 100644 --- a/src/l2/tests/r0/r0_tex_init_prep.c +++ b/src/l2/tests/r0/r0_tex_init_prep.c @@ -3,28 +3,31 @@ #include "../../margaret/png_pixel_masses.h" #include "../../marie/texture_processing.h" -void model_1_template() { - TextureDataR8 tex = generate_tex_template_for_one_fourth_of_a_cylinder(120, 10, 2, 6); - TextureDataR8G8B8A8 tex_1_big = TextureDataR8G8B8A8_new(tex.width, TextureDataR8_get_height(&tex)); - for (size_t i = 0; i < tex.pixels.len; i++) { - U8 g = *VecU8_at(&tex.pixels, i); - *Veccvec4_mat(&tex_1_big.pixels, i) = (cvec4){g, g, g, 255}; +void for_log(U32 w, U32 r, U32 k) { + { + TextureDataR8G8B8A8 tex = generate_tex_template_for_one_fourth_of_a_cylinder(120, (float)w, (float)r, k); + TextureDataR8G8B8A8 fixed_tex = TextureDataR8G8B8A8_expand_nontransparent_1px(&tex); + VecU8 name = VecU8_format("textures/log_%u_%u_%u_TEMPLATE.png", w, r, k); + TextureDataR8G8B8A8_write_to_png_nofail(&fixed_tex, VecU8_to_span(&name)); + VecU8_drop(name); + TextureDataR8G8B8A8_drop(fixed_tex); + TextureDataR8G8B8A8_drop(tex); + } + { + TextureDataR8G8B8A8 tex = generate_normal_tex_for_one_fourth_of_a_cylinder(120, (float)w, (float)r, k); + TextureDataR8G8B8A8 fixed_tex = TextureDataR8G8B8A8_expand_nontransparent_1px(&tex); + VecU8 name = VecU8_format("textures/log_%u_%u_%u_NORMAL.png", w, r, k); + TextureDataR8G8B8A8_write_to_png_nofail(&fixed_tex, VecU8_to_span(&name)); + VecU8_drop(name); + TextureDataR8G8B8A8_drop(fixed_tex); + TextureDataR8G8B8A8_drop(tex); } - TextureDataR8G8B8A8_write_to_png_nofail(&tex_1_big, cstr("textures/log_10_2_6_TEMPLATE.png")); - TextureDataR8G8B8A8_drop(tex_1_big); - TextureDataR8_drop(tex); -} - -void model_1_normal() { - TextureDataR8G8B8A8 tex = generate_normal_tex_for_one_fourth_of_a_cylinder(120, 10, 2, 6); - TextureDataR8G8B8A8 fixed_tex = TextureDataR8G8B8A8_expand_nontransparent_1px(&tex); - TextureDataR8G8B8A8_write_to_png_nofail(&fixed_tex, cstr("textures/log_10_2_6_NORMAL.png")); - TextureDataR8G8B8A8_drop(fixed_tex); - TextureDataR8G8B8A8_drop(tex); } int main() { - model_1_template(); - model_1_normal(); + for_log(10, 2, 6); + for_log(5, 5, 10); + for_log(1, 10, 4); + for_log(2, 1, 6); return 0; } diff --git a/src/l2/tests/tv0/tv0.c b/src/l2/tests/tv0/tv0.c new file mode 100644 index 0000000..e69de29 From bbe997103574d1844be8e0f36df28b7f025ed41e Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Wed, 24 Sep 2025 15:01:47 +0300 Subject: [PATCH 2/8] Whooops. Merging errors --- src/l1/anne/margaret/png_pixel_masses.h | 12 ++++----- src/l1/anne/pixel_masses.h | 2 +- src/l1/codegen/util_template_inst.h | 35 ++++++++++++------------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/l1/anne/margaret/png_pixel_masses.h b/src/l1/anne/margaret/png_pixel_masses.h index ea00bed..1e779d5 100644 --- a/src/l1/anne/margaret/png_pixel_masses.h +++ b/src/l1/anne/margaret/png_pixel_masses.h @@ -30,14 +30,14 @@ NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signatu /* Non clonable structure */ VecU8_append_vec(&res, VecU8_fmt( "typedef struct {\n" - SPACE4 "FILE* fp;\n" - SPACE4 "png_structp pngshka;\n" - SPACE4 "png_infop info;\n" - SPACE4 "png_infop end_info;\n" + SPACE "FILE* fp;\n" + SPACE "png_structp pngshka;\n" + SPACE "png_infop info;\n" + SPACE "png_infop end_info;\n" "} %s;\n\n" "void %s_drop(%s self) {\n" - SPACE4 "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n" - SPACE4 "fclose(self.fp);\n" + SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n" + SPACE "fclose(self.fp);\n" "}\n\n", promise, promise, promise)); VecU8_append_vec(&res, generate_result_template_inst(promise, cstr("VecU8"), false, false)); diff --git a/src/l1/anne/pixel_masses.h b/src/l1/anne/pixel_masses.h index 7fc7a9c..62c36df 100644 --- a/src/l1/anne/pixel_masses.h +++ b/src/l1/anne/pixel_masses.h @@ -82,7 +82,7 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 SpanU8 resoftex = VecU8_to_span(&g_resoftex); VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("SpanU8"), false, true)); /* I also add this, because why not?? Maye I will use it in the future... */ - VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("VecU8"), false, false));1 + VecU8_append_vec(&res, generate_result_template_inst(tex, cstr("VecU8"), false, false)); /* Method _from_bitmap_text() * We assume that bytes are tightly packed in member type */ VecU8_append_vec(&res, VecU8_fmt( diff --git a/src/l1/codegen/util_template_inst.h b/src/l1/codegen/util_template_inst.h index 36eedd1..5923d72 100644 --- a/src/l1/codegen/util_template_inst.h +++ b/src/l1/codegen/util_template_inst.h @@ -3,7 +3,6 @@ #include "codegen.h" - // todo: add macro that iterates over vector /* if !primitive, requires methods T_drop, and, if also clonable, requires method T_clone */ @@ -575,17 +574,17 @@ NODISCARD VecU8 generate_result_template_inst(SpanU8 OkT, SpanU8 ErrT, bool ok_t VecU8_append_span(&res, cstr( "typedef struct {\n" - SPACE4 "Result_variant variant;\n")); + SPACE "Result_variant variant;\n")); if (ok_t_void && !err_t_void) { - VecU8_append_vec(&res, VecU8_fmt(SPACE4 "%s err;\n", ErrT)); + VecU8_append_vec(&res, VecU8_fmt(SPACE "%s err;\n", ErrT)); } else if (!ok_t_void && err_t_void) { - VecU8_append_vec(&res, VecU8_fmt(SPACE4 "%s ok;\n", OkT)); + VecU8_append_vec(&res, VecU8_fmt(SPACE "%s ok;\n", OkT)); } else { VecU8_append_vec(&res, VecU8_fmt( - SPACE4 "union {\n" - SPACE4 SPACE4 "%s ok;\n" - SPACE4 SPACE4 "%s err;\n" - SPACE4 "};\n", OkT, ErrT)); + SPACE "union {\n" + SPACE SPACE "%s ok;\n" + SPACE SPACE "%s err;\n" + SPACE "};\n", OkT, ErrT)); } VecU8_append_vec(&res, VecU8_fmt("} %s;\n\n", ResultT)); @@ -594,18 +593,18 @@ NODISCARD VecU8 generate_result_template_inst(SpanU8 OkT, SpanU8 ErrT, bool ok_t "void %s_drop(%s self) {\n", ResultT, ResultT)); if (ok_t_primitive && !err_t_primitive) { VecU8_append_vec(&res, VecU8_fmt( - SPACE4 "if (self.variant == Result_Err)\n" - SPACE4 SPACE4 "%s_drop(self.err);\n", ErrT)); + SPACE "if (self.variant == Result_Err)\n" + SPACE SPACE "%s_drop(self.err);\n", ErrT)); } else if (!ok_t_primitive && err_t_primitive) { VecU8_append_vec(&res, VecU8_fmt( - SPACE4 "if (self.variant == Result_Ok)\n" - SPACE4 SPACE4 "%s_drop(self.ok);\n", OkT)); + SPACE "if (self.variant == Result_Ok)\n" + SPACE SPACE "%s_drop(self.ok);\n", OkT)); } else { VecU8_append_vec(&res, VecU8_fmt( - SPACE4 "if (self.variant == Result_Ok)\n" - SPACE4 SPACE4 "%s_drop(self.ok);\n" - SPACE4 "else\n" - SPACE4 SPACE4 "%s_drop(self.err);\n", OkT, ErrT)); + SPACE "if (self.variant == Result_Ok)\n" + SPACE SPACE "%s_drop(self.ok);\n" + SPACE "else\n" + SPACE SPACE "%s_drop(self.err);\n", OkT, ErrT)); } VecU8_append_span(&res, cstr("}\n\n")); } @@ -627,14 +626,14 @@ void generate_eve_header_of_result_type_instantiation( void generate_guarded_header_of_result_type_instantiation( SpanU8 layer, SpanU8 bonus_ns, SpanU8 OkT, SpanU8 ErrT, SpanU8 dependencies, bool ok_t_primitive, bool err_t_primitive - ) { + ){ assert(layer.len > 1); VecU8 filename = get_ResultType_inst_name(OkT, ErrT); VecU8 path = VecU8_fmt("%s/%s%s%s", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), VecU8_to_span(&filename)); GeneratedHeader head = begin_header(VecU8_to_span(&path)); VecU8_drop(path); VecU8_drop(filename); - +} typedef struct{ SpanU8 T; From c8ae4ab0174c0632c289aec40052231c63474255 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Wed, 24 Sep 2025 16:37:53 +0300 Subject: [PATCH 3/8] NOW. We can actually do something real --- CMakeLists.txt | 10 +++++----- src/l1/anne/codegen.c | 2 +- src/l1/anne/margaret/png_pixel_masses.h | 10 +++++----- src/l1/codegen/util_template_inst.h | 6 +++++- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dda56d4..b9bd997 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,16 +27,16 @@ add_compile_definitions(_POSIX_C_SOURCE=200112L) add_compile_definitions(_GNU_SOURCE) add_compile_options(-fno-trapping-math) -#add_executable(codegen_l1 src/l1/anne/codegen.c) -#target_compile_definitions(codegen_l1 -# PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8) +add_executable(codegen_l1 src/l1/anne/codegen.c) +target_compile_definitions(codegen_l1 + PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8) #add_executable(0_test src/l1_4/tests/t0.c) #add_executable(1_test src/l1_4/tests/t1.c) # -add_executable(l1_4_t2 src/l1_4/tests/t2.c) +#add_executable(l1_4_t2 src/l1_4/tests/t2.c) -add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) +#add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) # #add_executable(0_render_test src/l2/tests/r0/r0.c gen/l_wl_protocols/xdg-shell-private.c # src/l1/core/rb_tree_node.h) diff --git a/src/l1/anne/codegen.c b/src/l1/anne/codegen.c index 88e241c..d4a4c06 100644 --- a/src/l1/anne/codegen.c +++ b/src/l1/anne/codegen.c @@ -26,7 +26,7 @@ int main() { generate_liza_l1_headers(); generate_l1_headers_for_l1_5(); mkdir_nofail("l1/margaret"); - generate_margaret_eve_for_vulkan_utils(); + generate_margaret_eve_for_vulkan_utils(); /* margaret misc */ generate_margaret_png_pixel_masses_header(); finish_layer(cstr("l1")); return 0; diff --git a/src/l1/anne/margaret/png_pixel_masses.h b/src/l1/anne/margaret/png_pixel_masses.h index 1e779d5..adc0a9e 100644 --- a/src/l1/anne/margaret/png_pixel_masses.h +++ b/src/l1/anne/margaret/png_pixel_masses.h @@ -54,17 +54,17 @@ void generate_margaret_png_pixel_masses_header() { GeneratedHeader header = begin_header(cstr("l1/margaret/png_pixel_masses.h")); VecU8_append_span(&header.result, cstr( - "#include \"../pixel_masses.h\"" - "#include \"../ResultVoidOrVecU8\"" + "#include \"../pixel_masses.h\"\n" + "#include \"../ResultVoidOrVecU8.h\"\n" "#include \n\n")); VecU8_append_span(&header.result, cstr( "void margaret_libpng_h_error_cb(png_structp pngshka, png_const_charp err) {\n" - "printf(\"[!] %s\\n\", err);\n" + SPACE "printf(\"[!] %s\\n\", err);\n" "}\n\n" "void margaret_libpng_h_warning_cb(png_structp pngshka, png_const_charp warning) {\n" - "printf(\"[.] %s\\n\", warning);\n" - "}")); + SPACE "printf(\"[.] %s\\n\", warning);\n" + "}\n\n")); VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("TextureDataR8G8B8A8"), 8, 4)); diff --git a/src/l1/codegen/util_template_inst.h b/src/l1/codegen/util_template_inst.h index 5923d72..4be35be 100644 --- a/src/l1/codegen/util_template_inst.h +++ b/src/l1/codegen/util_template_inst.h @@ -629,8 +629,12 @@ void generate_guarded_header_of_result_type_instantiation( ){ assert(layer.len > 1); VecU8 filename = get_ResultType_inst_name(OkT, ErrT); - VecU8 path = VecU8_fmt("%s/%s%s%s", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), VecU8_to_span(&filename)); + VecU8 path = VecU8_fmt("%s/%s%s%s.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), VecU8_to_span(&filename)); GeneratedHeader head = begin_header(VecU8_to_span(&path)); + VecU8_append_span(&head.result, dependencies); + VecU8_append_span(&head.result, cstr("\n\n")); + VecU8_append_vec(&head.result, generate_result_template_inst(OkT, ErrT, ok_t_primitive, err_t_primitive)); + finish_header(head); VecU8_drop(path); VecU8_drop(filename); } From ad5b3c58d6e08b3c812213ce6bea62fb9c7545b7 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Wed, 24 Sep 2025 17:49:59 +0300 Subject: [PATCH 4/8] Now we store height in TextureDataS. + wrote codegen for writing texture to png file --- src/l1/anne/margaret/png_pixel_masses.h | 53 ++++++++++++++++++++++++- src/l1/anne/pixel_masses.h | 6 +-- src/l1_5/codegen/trait_wrap_boil.h | 3 +- src/l2/margaret/png_pixel_masses.h | 4 +- src/l2/marie/texture_processing.h | 4 +- src/l2/tests/r0/r0.c | 4 +- 6 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/l1/anne/margaret/png_pixel_masses.h b/src/l1/anne/margaret/png_pixel_masses.h index adc0a9e..ee5e889 100644 --- a/src/l1/anne/margaret/png_pixel_masses.h +++ b/src/l1/anne/margaret/png_pixel_masses.h @@ -14,7 +14,7 @@ color_type_name_in_png color_types_names_in_png[3] = { {4, cstr("PNG_COLOR_TYPE_RGBA")}, }; -NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signature, int depth, int channel_count) { +NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signature, S64 depth, int channel_count) { if (depth != 8) abortf("Please no"); for (size_t i = 0; i < ARRAY_SIZE(color_types_names_in_png); i++) { @@ -27,6 +27,55 @@ NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signatu VecU8 g_tex = VecU8_fmt("TextureData%s", format_signature); SpanU8 tex = VecU8_to_span(&g_tex); + VecU8_append_vec(&res, VecU8_fmt( + "ResultVoidOrVecU8 %s_write_to_png(const %s* self, SpanU8 filename) {\n" /* tex, tex */ + SPACE "VecU8 nt_filename = VecU8_fmt(\"%%s%%c\", filename, 0);\n" + SPACE "FILE *fp = fopen((CSTR)nt_filename.buf, \"wb\");\n" + SPACE "VecU8_drop(nt_filename);\n" + SPACE "if (!fp) {\n" + SPACE SPACE "return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_fmt(\"Unable to open file %%s\", filename)};\n" + SPACE "}\n" + SPACE "png_structp pngshka = png_create_write_struct(PNG_LIBPNG_VER_STRING,\n" + SPACE SPACE "NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb);\n" + SPACE "if (!pngshka)\n" + SPACE SPACE "abortf(\"png_create_write_struct\");\n" + SPACE "png_infop info = png_create_info_struct(pngshka);\n" + SPACE "if (!info)\n" + SPACE SPACE"abortf(\"png_create_info_struct\");\n" + SPACE "png_bytep* row_pointers = NULL;\n" + SPACE "if (setjmp(png_jmpbuf(pngshka))){\n" + SPACE SPACE "png_destroy_write_struct(&pngshka, &info);\n" + SPACE SPACE "fclose(fp);\n" + SPACE SPACE "free(row_pointers);\n" + SPACE SPACE "return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr(\"Some png error happened\")};\n" + SPACE "}\n" + SPACE "png_init_io(pngshka, fp);\n" + SPACE "U32 width = self->width;\n" + SPACE "U32 height = self->height;\n" + SPACE "png_set_IHDR(pngshka, info, width, height, %i, %s,\n" /* depth, color_type */ + SPACE SPACE "PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);\n" + SPACE "row_pointers = calloc(height, sizeof(row_pointers));\n" + SPACE "for (U32 y = 0; y < height; y++) {\n" + SPACE SPACE "row_pointers[height - 1 - y] = (png_bytep)((%s_at(self, 0, y)));\n" /* tex */ + SPACE "}\n" + SPACE "png_set_rows(pngshka, info, row_pointers);\n" + SPACE "png_write_png(pngshka, info, 0, NULL);\n" + SPACE "/* No more errors */\n" + SPACE "free(row_pointers);\n" + SPACE "png_destroy_write_struct(&pngshka, &info);\n" + SPACE "fclose(fp);\n" + SPACE "return (ResultVoidOrVecU8){.variant = Result_Ok};\n" + "}\n\n" + "/* Aborts on error */\n" + "void %s_write_to_png_nofail(const %s* self, SpanU8 filename) {\n" /* tex, tex*/ + SPACE "ResultVoidOrVecU8 res = %s_write_to_png(self, filename);\n" /* tex */ + SPACE "if (res.variant == Result_Err) {\n" + SPACE SPACE "SpanU8_fprint(VecU8_to_span(&res.err), stderr);\n" + SPACE SPACE "abortf(\" %s_write_to_png\\n\");\n" /* tex */ + SPACE "}\n" + "}\n", + tex, tex, depth, color_type, tex, tex, tex, tex, tex)); + /* Non clonable structure */ VecU8_append_vec(&res, VecU8_fmt( "typedef struct {\n" @@ -66,7 +115,7 @@ void generate_margaret_png_pixel_masses_header() { SPACE "printf(\"[.] %s\\n\", warning);\n" "}\n\n")); - VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("TextureDataR8G8B8A8"), 8, 4)); + VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("R8G8B8A8"), 8, 4)); finish_header(header); } diff --git a/src/l1/anne/pixel_masses.h b/src/l1/anne/pixel_masses.h index 62c36df..1cbad50 100644 --- a/src/l1/anne/pixel_masses.h +++ b/src/l1/anne/pixel_masses.h @@ -25,6 +25,7 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 "typedef struct {\n" SPACE "%s pixels;\n" SPACE "size_t width;\n" + SPACE "size_t height;\n" "} %s;\n\n", pixvec, tex); /* Method _new() */ VecU8_append_vec(&res, VecU8_fmt( @@ -37,11 +38,6 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 "void %s_drop(%s self) {\n" SPACE "%s_drop(self.pixels);\n" "}\n\n", tex, tex, pixvec)); - /* Method _get_height() */ - VecU8_append_vec(&res, VecU8_fmt( - "size_t %s_get_height(const %s* self) {\n" - SPACE "return self->pixels.len / self->width;\n" - "}\n\n", tex, tex)); /* Methods _at and _cat */ VecU8_append_vec(&res, generate_texture_data_method_at(tex, pixvec, memb, false)); VecU8_append_vec(&res, generate_texture_data_method_at(tex, pixvec, memb, true)); diff --git a/src/l1_5/codegen/trait_wrap_boil.h b/src/l1_5/codegen/trait_wrap_boil.h index 0c9dded..97b5332 100644 --- a/src/l1_5/codegen/trait_wrap_boil.h +++ b/src/l1_5/codegen/trait_wrap_boil.h @@ -42,12 +42,13 @@ NODISCARD VecU8 generate_trait_table_structure(NamedTraitDefRecordRef trait){ } typedef struct { + NamedTraitDefRecordRef trait; bool box; bool ref; bool mut_ref; } trait_wrapper_boil_options; -NODISCARD VecU8 generate_trait_wrapper_boilerplate(NamedTraitDefRecordRef trait, trait_wrapper_boil_options op) { +NODISCARD VecU8 generate_trait_wrapper_boilerplate(trait_wrapper_boil_options op) { VecU8 res = VecU8_new(); // todo: write it return res; diff --git a/src/l2/margaret/png_pixel_masses.h b/src/l2/margaret/png_pixel_masses.h index e3f1819..bd73fbd 100644 --- a/src/l2/margaret/png_pixel_masses.h +++ b/src/l2/margaret/png_pixel_masses.h @@ -4,7 +4,7 @@ #include "../../../gen/l1/pixel_masses.h" #include "../../l1/core/util.h" #include "../../l1/core/VecU8_as_str.h" -#include "../../../gen/l1/ResultVoidOrVecU8" +#include "../../../gen/l1/ResultVoidOrVecU8.h" #include // todo: generate all of this automaticcally @@ -43,7 +43,7 @@ ResultVoidOrVecU8 TextureDataR8G8B8A8_write_to_png(const TextureDataR8G8B8A8* se png_init_io(pngshka, fp); U32 width = self->width; - U32 height = TextureDataR8G8B8A8_get_height(self); + U32 height = self->height; png_set_IHDR(pngshka, info, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); diff --git a/src/l2/marie/texture_processing.h b/src/l2/marie/texture_processing.h index 7406564..7f98b51 100644 --- a/src/l2/marie/texture_processing.h +++ b/src/l2/marie/texture_processing.h @@ -6,7 +6,7 @@ void TextureDataR8G8B8A8_print(const TextureDataR8G8B8A8* self) { U64 width = self->width; - U64 height = TextureDataR8G8B8A8_get_height(self); + // U64 height = ; U64 cell_width = MAX_U64(1, width / 350); U64 cell_height = MAX_U64(1, cell_width * 14 / 8); for (U64 CY = 0; CY < height; CY += cell_height) { @@ -34,7 +34,7 @@ void TextureDataR8G8B8A8_print(const TextureDataR8G8B8A8* self) { /* Fixes several of my generated textures */ NODISCARD TextureDataR8G8B8A8 TextureDataR8G8B8A8_expand_nontransparent_1px(const TextureDataR8G8B8A8* self) { S32 width = (S32)self->width; - S32 height = (S32)TextureDataR8G8B8A8_get_height(self); + S32 height = (S32)self->height; TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width, height); // S32 chain[9][2] = {{0, 0}, {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {1, 1}, {0, 1}, {-1, 1}}; for (S32 y = 0; y < height; y++) { diff --git a/src/l2/tests/r0/r0.c b/src/l2/tests/r0/r0.c index 60e5168..e338762 100644 --- a/src/l2/tests/r0/r0.c +++ b/src/l2/tests/r0/r0.c @@ -1862,9 +1862,9 @@ int main() { vk_ctx->device_zbuffer_image = margaret_prep_image_mem_info_of_zbuffer( MAX_WIN_WIDTH, MAX_WIN_HEIGHT, zbuffer_format.some); vk_ctx->device_cyl_1_diffuse_texture = margaret_prep_image_mem_info_of_gpu_texture_srgba( - vk_ctx->cyl_1_diffuse_tex.width, TextureDataR8G8B8A8_get_height(&vk_ctx->cyl_1_diffuse_tex)); + vk_ctx->cyl_1_diffuse_tex.width, &vk_ctx->cyl_1_diffuse_tex.height); vk_ctx->device_cyl_1_normal_texture = margaret_prep_image_mem_info_of_gpu_texture_unorm_32( - vk_ctx->cyl_1_normal_tex.width, TextureDataR8G8B8A8_get_height(&vk_ctx->cyl_1_normal_tex)); + vk_ctx->cyl_1_normal_tex.width, &vk_ctx->cyl_1_normal_tex.height); PtrMargaretImageInMemoryInfo device_mem_images_SPAN[] = { &vk_ctx->device_IT1_image, &vk_ctx->device_zbuffer_image, &vk_ctx->device_cyl_1_diffuse_texture, From aed4035806bb4de48b2722349e5916b16aa8ee23 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Thu, 25 Sep 2025 15:33:30 +0300 Subject: [PATCH 5/8] Moved textureDataS_print method to pixel_masses codegenerator. Wrote image reading in margaret_png_pixed_masses. Fixed some dumb bugs --- CMakeLists.txt | 8 +- src/l1/anne/margaret/png_pixel_masses.h | 243 +++++++++++++++++++---- src/l1/anne/pixel_masses.h | 44 ++++- src/l2/margaret/png_pixel_masses.h | 244 ------------------------ src/l2/marie/texture_processing.h | 27 --- src/l2/tests/r0/r0_tex_init_prep.c | 15 +- 6 files changed, 266 insertions(+), 315 deletions(-) delete mode 100644 src/l2/margaret/png_pixel_masses.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b9bd997..8dcee14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,10 +41,10 @@ target_compile_definitions(codegen_l1 #add_executable(0_render_test src/l2/tests/r0/r0.c gen/l_wl_protocols/xdg-shell-private.c # src/l1/core/rb_tree_node.h) #target_link_libraries(0_render_test -lvulkan -lwayland-client -lm -lxkbcommon -lpng) -# -#add_executable(0r_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c) -#target_link_libraries(0r_tex_init_prep -lm -lpng) -# + +add_executable(0r_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c) +target_link_libraries(0r_tex_init_prep -lm -lpng) + #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) # diff --git a/src/l1/anne/margaret/png_pixel_masses.h b/src/l1/anne/margaret/png_pixel_masses.h index ee5e889..74f0b5f 100644 --- a/src/l1/anne/margaret/png_pixel_masses.h +++ b/src/l1/anne/margaret/png_pixel_masses.h @@ -4,31 +4,38 @@ #include "../../codegen/util_template_inst.h" typedef struct { - int channel_count; + S64 channel_count; SpanU8 name; } color_type_name_in_png; -color_type_name_in_png color_types_names_in_png[3] = { +color_type_name_in_png color_types_names_in_png[] = { {1, cstr("PNG_COLOR_TYPE_GRAY")}, + {2, cstr("PNG_COLOR_TYPE_GRAY_ALPHA")}, {3, cstr("PNG_COLOR_TYPE_RGB")}, {4, cstr("PNG_COLOR_TYPE_RGBA")}, }; -NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signature, S64 depth, int channel_count) { +NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signature, S64 depth, S64 channel_count) { if (depth != 8) - abortf("Please no"); + abortf("Please no\n"); + SpanU8 color_type = cstr(""); for (size_t i = 0; i < ARRAY_SIZE(color_types_names_in_png); i++) { - if (channel_count == color_types_names_in_png[i].channel_count) { - SpanU8 color_type = color_types_names_in_png[i].name; - VecU8 res = VecU8_new(); + if (color_types_names_in_png[i].channel_count == channel_count) + color_type = color_types_names_in_png[i].name; + } + if (color_type.len == 0) + abortf("Please don't\n"); - VecU8 g_promise = VecU8_fmt("MargaretPromisedPng%s", format_signature); - SpanU8 promise = VecU8_to_span(&g_promise); - VecU8 g_tex = VecU8_fmt("TextureData%s", format_signature); - SpanU8 tex = VecU8_to_span(&g_tex); + U64 sizeof_pixel = (U64)depth / 8 * (U64)channel_count; + VecU8 res = VecU8_new(); - VecU8_append_vec(&res, VecU8_fmt( - "ResultVoidOrVecU8 %s_write_to_png(const %s* self, SpanU8 filename) {\n" /* tex, tex */ + VecU8 g_promise = VecU8_fmt("MargaretPromisedPng%s", format_signature); + SpanU8 promise = VecU8_to_span(&g_promise); + VecU8 g_tex = VecU8_fmt("TextureData%s", format_signature); + SpanU8 tex = VecU8_to_span(&g_tex); + + VecU8_append_vec(&res, VecU8_fmt( + "NODISCARD ResultVoidOrVecU8 %s_write_to_png(const %s* self, SpanU8 filename) {\n" /* tex, tex */ SPACE "VecU8 nt_filename = VecU8_fmt(\"%%s%%c\", filename, 0);\n" SPACE "FILE *fp = fopen((CSTR)nt_filename.buf, \"wb\");\n" SPACE "VecU8_drop(nt_filename);\n" @@ -76,27 +83,197 @@ NODISCARD VecU8 generate_margaret_png_texture_data_methods(SpanU8 format_signatu "}\n", tex, tex, depth, color_type, tex, tex, tex, tex, tex)); - /* Non clonable structure */ - VecU8_append_vec(&res, VecU8_fmt( - "typedef struct {\n" - SPACE "FILE* fp;\n" - SPACE "png_structp pngshka;\n" - SPACE "png_infop info;\n" - SPACE "png_infop end_info;\n" - "} %s;\n\n" - "void %s_drop(%s self) {\n" - SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n" - SPACE "fclose(self.fp);\n" - "}\n\n", promise, promise, promise)); + /* Non clonable structure */ + VecU8_append_vec(&res, VecU8_fmt( + "typedef struct {\n" + SPACE "FILE* fp;\n" + SPACE "png_structp pngshka;\n" + SPACE "png_infop info;\n" + SPACE "png_infop end_info;\n" + "} %s;\n\n" + "void %s_drop(%s self) {\n" + SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n" + SPACE "fclose(self.fp);\n" + "}\n\n", + promise, promise, promise)); - VecU8_append_vec(&res, generate_result_template_inst(promise, cstr("VecU8"), false, false)); + VecU8_append_vec(&res, generate_result_template_inst(promise, cstr("VecU8"), false, false)); - VecU8_drop(g_promise); - VecU8_drop(g_tex); - return res; - } - } - abortf("Please don't"); + VecU8_append_vec(&res, VecU8_fmt( + "NODISCARD Result%sOrVecU8 %s_begin(SpanU8 filename) {\n" /* promise, promise */ + SPACE "VecU8 nt_filename = VecU8_fmt(\"%%s%%c\", filename, 0);\n" + SPACE "FILE* fp = fopen((CSTR)nt_filename.buf, \"rb\");\n" + SPACE "VecU8_drop(nt_filename);\n" + SPACE "if (!fp) {\n" + SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err,\n" /* promise */ + SPACE SPACE SPACE ".err = VecU8_fmt(\"Unable to open file %%s\", filename)};\n" + SPACE "}\n" + SPACE "png_structp pngshka = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb);\n" + SPACE "if (!pngshka)\n" + SPACE SPACE "abortf(\"png_create_read_struct\");\n" + SPACE "png_infop info = png_create_info_struct(pngshka);\n" + SPACE "if (!info)\n" + SPACE SPACE "abortf(\"png_create_info_struct\");\n" + SPACE "png_infop end_info = png_create_info_struct(pngshka);\n" + SPACE "if (!end_info)\n" + SPACE SPACE "abortf(\"png_create_info_struct\");\n" + SPACE "if (setjmp(png_jmpbuf(pngshka))) {\n" + SPACE SPACE "png_destroy_read_struct(&pngshka, &info, &end_info);\n" + SPACE SPACE "fclose(fp);\n" + SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err,\n" /* promise */ + SPACE SPACE SPACE ".err = VecU8_from_cstr(\"Some png error happened\")};\n" + SPACE "}\n" + SPACE "png_init_io(pngshka, fp);\n" + SPACE "png_read_info(pngshka, info);\n" + SPACE "U32 width, height;\n" + SPACE "int bit_depth, color_type;\n" + SPACE "check(png_get_IHDR(pngshka, info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL));\n", + promise, promise, promise, promise)); + + /* We are still in PROMISE_begin method, now we need to do the conversion */ + if (depth == 8) { + VecU8_append_span(&res, cstr( + SPACE "if (bit_depth == 16)\n" + SPACE SPACE "png_set_strip_16(pngshka);\n" + SPACE "else if (color_type == PNG_COLOR_TYPE_GRAY && (bit_depth == 1 || bit_depth == 2 || bit_depth == 4))\n" + SPACE SPACE "png_set_expand_gray_1_2_4_to_8(pngshka);\n" + )); + } else + assert(false); + if (channel_count == 3 || channel_count == 4) { + VecU8_append_span(&res, cstr( + SPACE "if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)\n" + SPACE SPACE "png_set_gray_to_rgb(pngshka);\n" + SPACE "else if (color_type == PNG_COLOR_TYPE_PALETTE)" + SPACE SPACE "png_set_palette_to_rgb(pngshka);\n" + )); + } else if (channel_count == 1 || channel_count == 2) { + VecU8_append_span(&res, cstr( + SPACE "if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGBA) {\n" + SPACE SPACE "png_set_rgb_to_gray_fixed(pngshka, 1, 21268, 71514);\n" + SPACE "} else if (color_type == PNG_COLOR_TYPE_PALETTE) {\n" + SPACE SPACE "png_set_palette_to_rgb(pngshka);\n" + SPACE SPACE "png_set_rgb_to_gray_fixed(pngshka, 1, 21268, 71514);\n" + SPACE "}\n" + )); + } else + assert(false); + if (channel_count == 4 || channel_count == 2) { + VecU8_append_span(&res, cstr( + SPACE "if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_PALETTE) {\n" + SPACE SPACE "if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) \n" + SPACE SPACE SPACE "png_set_tRNS_to_alpha(pngshka);\n" + SPACE SPACE "else\n" + SPACE SPACE SPACE "png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER);\n" + SPACE "}\n" + )); + } else if (channel_count == 1 || channel_count == 3) { + VecU8_append_span(&res, cstr( + SPACE "if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGBA)\n" + SPACE SPACE "png_set_strip_alpha(pngshka);\n" + )); + } else + assert(false); + /* At this point we have a converted image png structure */ + + VecU8_append_vec(&res, VecU8_fmt( + SPACE "png_read_update_info(pngshka, info);\n" + SPACE "{\n" + SPACE SPACE "U32 new_width, new_height;\n" + SPACE SPACE "int new_bit_depth, new_color_type;\n" + SPACE SPACE "check(png_get_IHDR(pngshka, info, &new_width, &new_height, &new_bit_depth, &new_color_type, NULL, NULL, NULL));\n" + SPACE SPACE "assert(new_width == width && new_height == height && new_bit_depth == %i && new_color_type == %s);\n" /* depth, color_type */ + SPACE "}\n" + SPACE "return (Result%sOrVecU8){.variant = Result_Ok,\n" /* promise */ + SPACE SPACE ".ok = (%s){.fp = fp, .pngshka = pngshka, .info = info, .end_info = end_info}};\n" /* promise */ + "}\n\n", + (S64)depth, color_type, + promise, promise)); + + VecU8_append_vec(&res, VecU8_fmt( + "SizeOfRectangleU32 %s_get_extent(const %s* self) {\n" /* promise, promise */ + SPACE "U32 width, height;\n" + SPACE "int bit_depth, color_type;\n" + SPACE "check(png_get_IHDR(self->pngshka, self->info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL));\n" + SPACE "return (SizeOfRectangleU32){width, height};\n" + "}\n\n", + promise, promise)); + + assert(depth == 8 || depth == 16); + assert(channel_count == 1 || channel_count == 2 || channel_count == 4 || channel_count == 3); + + VecU8_append_vec(&res, VecU8_fmt( + "size_t %s_get_needed_buffer_size(const %s* self) {\n" /* promise, promise */ + SPACE "SizeOfRectangleU32 dim = %s_get_extent(self);\n" /* promise */ + SPACE "return %u * dim.width * dim.height;\n" /* sizeof_pixel */ + "}\n\n", + promise, promise, promise, sizeof_pixel)); + + VecU8_append_vec(&res, VecU8_fmt( + "NODISCARD ResultVoidOrVecU8 %s_finish(%s self, void* buffer) {\n" /* promise, promise */ + SPACE "SizeOfRectangleU32 dim = %s_get_extent(&self);\n" /* promise */ + SPACE "png_bytep* row_pointers = NULL;\n" + SPACE "if (setjmp(png_jmpbuf(self.pngshka))) {\n" + SPACE SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n" + SPACE SPACE "fclose(self.fp);\n" + SPACE SPACE "free(row_pointers);\n" + SPACE SPACE "return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr(\"Some png error happened\")};\n" + SPACE "}\n" + SPACE "row_pointers = calloc(dim.height, sizeof(row_pointers));\n" + SPACE "for (U32 y = 0; y < dim.height; y++) {\n" + SPACE SPACE "row_pointers[dim.height - 1 - y] = ((png_bytep)buffer) + %u * dim.width * y;\n" /* sizeof_pixel */ + SPACE "}\n" + SPACE "png_read_image(self.pngshka, row_pointers);\n" + SPACE "png_read_end(self.pngshka, self.end_info);\n" + SPACE "/* No more errors */\n" + SPACE "png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info);\n" + SPACE "fclose(self.fp);\n" + SPACE "free(row_pointers);\n" + SPACE "return (ResultVoidOrVecU8){.variant = Result_Ok};\n" + "}\n\n", + promise, promise, promise, sizeof_pixel + )); + + VecU8_append_vec(&res, VecU8_fmt( + "NODISCARD Result%sOrVecU8 %s_finish_into_%s(%s self) {\n" /* tex, promise, tex, promise */ + SPACE "SizeOfRectangleU32 dim = %s_get_extent(&self);\n" /* promise */ + SPACE "if (dim.width >= UINT32_MAX / 10 || dim.height >= UINT32_MAX / 10) {\n" + SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err, .err = vcstr(\"Input image is too big\")};\n" /* tex */ + SPACE "}\n" + SPACE "%s tex = %s_new(dim.width, dim.height);\n" /* tex, tex */ + SPACE "ResultVoidOrVecU8 res = %s_finish(self, tex.pixels.buf);\n" /* promise */ + SPACE "if (res.variant == Result_Err) {\n" + SPACE SPACE "%s_drop(tex);\n" /* tex */ + SPACE SPACE "return (Result%sOrVecU8){.variant = Result_Err, .err = res.err};\n" /* tex */ + SPACE "}\n" + SPACE "return (Result%sOrVecU8){.variant = Result_Ok, .ok = tex};\n" /* tex */ + "}\n\n", + tex, promise, tex, promise, promise, tex, tex, tex, promise, tex, tex, tex + )); + + VecU8_append_vec(&res, VecU8_fmt( + + "/* aborts on error */\n" + "NODISCARD %s %s_read_from_png_nofail(SpanU8 name) {\n" /* tex, tex */ + SPACE "Result%sOrVecU8 res_1 = %s_begin(name);\n" /* promise, promise */ + SPACE "if (res_1.variant == Result_Err) {\n" + SPACE SPACE "SpanU8_fprint(VecU8_to_span(&res_1.err), stderr);\n" + SPACE SPACE "abortf(\" MargaretPromisedPng_begin\\n\");\n" + SPACE "}\n" + SPACE "/* res_1 invalidated, we moved ownership to _finish methos */\n" + SPACE "Result%sOrVecU8 res_2 = %s_finish_into_%s(res_1.ok);\n" /* tex, promise, tex */ + SPACE "if (res_2.variant == Result_Err) {\n" + SPACE SPACE "SpanU8_fprint(VecU8_to_span(&res_2.err), stderr);\n" + SPACE SPACE "abortf(\" MargaretPromisedPng_finish (into TextureData)\\n\");\n" + SPACE "}\n" + SPACE "return res_2.ok;\n" + "}\n\n", + tex, tex, promise, promise, tex, promise, tex + )); + + VecU8_drop(g_promise); + VecU8_drop(g_tex); + return res; } void generate_margaret_png_pixel_masses_header() { @@ -115,6 +292,8 @@ void generate_margaret_png_pixel_masses_header() { SPACE "printf(\"[.] %s\\n\", warning);\n" "}\n\n")); + VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("R8"), 8, 1)); + VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("R8G8B8"), 8, 3)); VecU8_append_vec(&header.result, generate_margaret_png_texture_data_methods(cstr("R8G8B8A8"), 8, 4)); finish_header(header); diff --git a/src/l1/anne/pixel_masses.h b/src/l1/anne/pixel_masses.h index 1cbad50..4e751ed 100644 --- a/src/l1/anne/pixel_masses.h +++ b/src/l1/anne/pixel_masses.h @@ -17,11 +17,10 @@ NODISCARD VecU8 generate_texture_data_method_at(SpanU8 tex, SpanU8 pixvec, SpanU /* `tex` is the type name of texture data type * `memb` is the type name of pixel data type */ -NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 memb) { +NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 memb, SpanU8 luminosity_formula) { VecU8 g_pixvec = VecU8_fmt("Vec%s", memb); SpanU8 pixvec = VecU8_to_span(&g_pixvec); - - VecU8 res = VecU8_fmt( + VecU8 res = VecU8_fmt( "typedef struct {\n" SPACE "%s pixels;\n" SPACE "size_t width;\n" @@ -31,7 +30,7 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 VecU8_append_vec(&res, VecU8_fmt( "%s %s_new(U32 width, U32 height) {\n" SPACE "assert(!(SIZE_MAX / width / height < 100 || UINT32_MAX / width < 10 || UINT32_MAX / height < 10));\n" - SPACE "return (%s){.pixels = %s_new_zeroinit((size_t)width * height), .width = width};\n" + SPACE "return (%s){.pixels = %s_new_zeroinit((size_t)width * height), .width = width, .height = height};\n" "}\n\n", tex, tex, tex, pixvec)); /* Method _drop() */ VecU8_append_vec(&res, VecU8_fmt( @@ -117,6 +116,34 @@ NODISCARD VecU8 generate_texture_data_struct_and_necc_methods(SpanU8 tex, SpanU8 "bool %s_is_inside(const %s* self, S32 x, S32 y) {\n" SPACE "return x >= 0 && y >= 0 && x < (S32)self->width && self->width * y + x < self->pixels.len;\n" "}\n\n", tex, tex)); + /* Method _print() */ + VecU8_append_vec(&res, VecU8_fmt( + "void %s_print(const %s* self) {\n" /* tex, tex */ + SPACE "U64 width = self->width;\n" + SPACE "U64 height = self->height;\n" + SPACE "U64 cell_width = MAX_U64(1, width / 190);\n" + SPACE "U64 cell_height = MAX_U64(1, cell_width * 14 / 8);\n" + SPACE "for (U64 CY = 0; CY < height; CY += cell_height) {\n" + SPACE SPACE "for (U64 CX = 0; CX < width; CX += cell_width) {\n" + SPACE SPACE SPACE "float lum = 0;\n" + SPACE SPACE SPACE "for (U64 j = 0; j < cell_height; j++) {\n" + SPACE SPACE SPACE SPACE "U64 y = CY + j;\n" + SPACE SPACE SPACE SPACE "if (y >= height)\n" + SPACE SPACE SPACE SPACE SPACE "continue;\n" + SPACE SPACE SPACE SPACE "for (U64 i = 0; i < cell_width; i++) {\n" + SPACE SPACE SPACE SPACE SPACE "U64 x = CX + i;\n" + SPACE SPACE SPACE SPACE SPACE "if (x >= width)\n" + SPACE SPACE SPACE SPACE SPACE SPACE "continue;\n" + SPACE SPACE SPACE SPACE SPACE "%s pix = *%s_at(self, x, y);\n" /* memb, tex */ + SPACE SPACE SPACE SPACE SPACE "lum += %s;\n" /* luminosity_formula */ + SPACE SPACE SPACE SPACE "}\n" + SPACE SPACE SPACE "}\n" + SPACE SPACE SPACE "lum /= (float)cell_width * (float)cell_height;\n" + SPACE SPACE SPACE "putc(lum > 0.95 ? '@' : (lum > 0.8 ? '#' : (lum > 0.65 ? '*' : (lum > 0.4 ? '_' : (lum > 0.2 ? '.' : ' ')))), stdout);\n" + SPACE SPACE "}\n" + SPACE SPACE "putc('\\n', stdout);\n" + SPACE "}\n" + "}\n\n", tex, tex, memb, tex, luminosity_formula)); VecU8_drop(g_resoftex); VecU8_drop(g_pixvec); @@ -128,9 +155,12 @@ void generate_pixel_masses_header() { VecU8_append_span(&res.result, cstr("#include \"VecAndSpan_int_primitives.h\"\n")); VecU8_append_span(&res.result, cstr("#include \"../../src/l1/system/fileio.h\"\n")); VecU8_append_span(&res.result, cstr("#include \"VecAndSpan_cvec.h\"\n\n")); - VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8"), cstr("U8"))); - VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8"), cstr("cvec3"))); - VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8A8"), cstr("cvec4"))); + VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8"), cstr("U8"), + cstr("(float)pix / 255"))); + VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8"), cstr("cvec3"), + cstr("(float)pix.x / 255 * 0.21f + (float)pix.y / 255 * 0.71f + (float)pix.z / 255 * 0.08f"))); + VecU8_append_vec(&res.result, generate_texture_data_struct_and_necc_methods(cstr("TextureDataR8G8B8A8"), cstr("cvec4"), + cstr("(float)pix.x / 255 * 0.21f + (float)pix.y / 255 * 0.71f + (float)pix.z / 255 * 0.08f"))); finish_header(res); } diff --git a/src/l2/margaret/png_pixel_masses.h b/src/l2/margaret/png_pixel_masses.h deleted file mode 100644 index bd73fbd..0000000 --- a/src/l2/margaret/png_pixel_masses.h +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef PROTOTYPE1_SRC_L2_MARGARET_PNG_PIXEL_MASSES_H -#define PROTOTYPE1_SRC_L2_MARGARET_PNG_PIXEL_MASSES_H - -#include "../../../gen/l1/pixel_masses.h" -#include "../../l1/core/util.h" -#include "../../l1/core/VecU8_as_str.h" -#include "../../../gen/l1/ResultVoidOrVecU8.h" -#include - -// todo: generate all of this automaticcally - -void margaret_libpng_h_error_cb(png_structp pngshka, png_const_charp err) { - printf("[!] %s\n", err); -} - -void margaret_libpng_h_warning_cb(png_structp pngshka, png_const_charp warning) { - printf("[.] %s\n", warning); -} - -ResultVoidOrVecU8 TextureDataR8G8B8A8_write_to_png(const TextureDataR8G8B8A8* self, SpanU8 filename) { - VecU8 nt_filename = VecU8_fmt("%s%c", filename, 0); - FILE *fp = fopen((CSTR)nt_filename.buf, "wb"); - VecU8_drop(nt_filename); - if (!fp) { - return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_fmt("Unable to open file %s", filename)}; - } - png_structp pngshka = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb); - if (!pngshka) - abortf("png_create_write_struct"); - png_infop info = png_create_info_struct(pngshka); - if (!info) - abortf("png_create_info_struct"); - - png_bytep* row_pointers = NULL; - - if (setjmp(png_jmpbuf(pngshka))){ - png_destroy_write_struct(&pngshka, &info); - fclose(fp); - free(row_pointers); - return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr("Some png error happened")}; - } - png_init_io(pngshka, fp); - - U32 width = self->width; - U32 height = self->height; - - png_set_IHDR(pngshka, info, width, height, 8, PNG_COLOR_TYPE_RGBA, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - - row_pointers = calloc(height, sizeof(row_pointers)); - for (U32 y = 0; y < height; y++) { - row_pointers[height - 1 - y] = (png_bytep)((TextureDataR8G8B8A8_at(self, 0, y))); - } - png_set_rows(pngshka, info, row_pointers); - png_write_png(pngshka, info, 0, NULL); - /* No more errors */ - free(row_pointers); - png_destroy_write_struct(&pngshka, &info); - fclose(fp); - return (ResultVoidOrVecU8){.variant = Result_Ok}; -} - -/* Aborts on error */ -void TextureDataR8G8B8A8_write_to_png_nofail(const TextureDataR8G8B8A8* self, SpanU8 filename) { - ResultVoidOrVecU8 res = TextureDataR8G8B8A8_write_to_png(self, filename); - if (res.variant == Result_Err) { - SpanU8_fprint(VecU8_to_span(&res.err), stderr); - abortf(" TextureDataR8G8B8A8_write_to_png\n"); - } -} - -typedef struct { - FILE* fp; - png_structp pngshka; - png_infop info; - png_infop end_info; -} MargaretPromisedPngR8G8B8A8; - -void MargaretPromisedPngR8G8B8A8_drop(MargaretPromisedPngR8G8B8A8 self) { - png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info); - fclose(self.fp); -} - -typedef struct { - Result_variant variant; - union { - MargaretPromisedPngR8G8B8A8 ok; - VecU8 err; - }; -} ResultMargaretPromisedPngR8G8B8A8OrVecU8; - -void ResultMargaretPromisedPngR8G8B8A8OrVecU8_drop(ResultMargaretPromisedPngR8G8B8A8OrVecU8 self) { - if (self.variant == Result_Ok) - MargaretPromisedPngR8G8B8A8_drop(self.ok); - else - VecU8_drop(self.err); -} - -ResultMargaretPromisedPngR8G8B8A8OrVecU8 MargaretPromisedPngR8G8B8A8_begin(SpanU8 filename) { - VecU8 nt_filename = VecU8_fmt("%s%c", filename, 0); - FILE* fp = fopen((CSTR)nt_filename.buf, "rb"); - VecU8_drop(nt_filename); - if (!fp) { - return (ResultMargaretPromisedPngR8G8B8A8OrVecU8){.variant = Result_Err, - .err = VecU8_fmt("Unable to open file %s", filename)}; - } - png_structp pngshka = png_create_read_struct(PNG_LIBPNG_VER_STRING, - NULL, margaret_libpng_h_error_cb, margaret_libpng_h_warning_cb); - if (!pngshka) - abortf("png_create_read_struct"); - png_infop info = png_create_info_struct(pngshka); - if (!info) - abortf("png_create_info_struct"); - png_infop end_info = png_create_info_struct(pngshka); - if (!end_info) - abortf("png_create_info_struct"); - if (setjmp(png_jmpbuf(pngshka))) { - png_destroy_read_struct(&pngshka, &info, &end_info); - fclose(fp); - return (ResultMargaretPromisedPngR8G8B8A8OrVecU8){.variant = Result_Err, - .err = VecU8_from_cstr("Some png error happened")}; - } - png_init_io(pngshka, fp); - png_read_info(pngshka, info); - U32 width, height; - int bit_depth, color_type; - assert(png_get_IHDR(pngshka, info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL)); - - if (bit_depth == 16) { - png_set_strip_16(pngshka); - } - if (color_type == PNG_COLOR_TYPE_GRAY) { - if (bit_depth == 1 || bit_depth == 2 || bit_depth == 4) { - png_set_expand_gray_1_2_4_to_8(pngshka); - } - png_set_gray_to_rgb(pngshka); - if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(pngshka); - } else { - png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER); - } - } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - png_set_gray_to_rgb(pngshka); - } else if (color_type == PNG_COLOR_TYPE_RGB) { - if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(pngshka); - } else { - png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER); - } - } else if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(pngshka); - - if (png_get_valid(pngshka, info, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(pngshka); - } else { - png_set_add_alpha(pngshka, 0xFF, PNG_FILLER_AFTER); - } - } - png_read_update_info(pngshka, info); - - return (ResultMargaretPromisedPngR8G8B8A8OrVecU8){.variant = Result_Ok, - .ok = (MargaretPromisedPngR8G8B8A8){.fp = fp, .pngshka = pngshka, .info = info, .end_info = end_info}}; -} - -SizeOfRectangleU32 MargaretPromisedPngR8G8B8A8_get_extent(const MargaretPromisedPngR8G8B8A8* self) { - U32 width, height; - int bit_depth, color_type; - assert(png_get_IHDR(self->pngshka, self->info, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL)); - return (SizeOfRectangleU32){width, height}; -} - - -size_t MargaretPromisedPngR8G8B8A8_get_needed_buffer_size(const MargaretPromisedPngR8G8B8A8* self) { - SizeOfRectangleU32 dim = MargaretPromisedPngR8G8B8A8_get_extent(self); - return 4 * dim.width * dim.height; -} - -ResultVoidOrVecU8 MargaretPromisedPngR8G8B8A8_finish(MargaretPromisedPngR8G8B8A8 self, void* buffer) { - SizeOfRectangleU32 dim = MargaretPromisedPngR8G8B8A8_get_extent(&self); - - png_bytep* row_pointers = NULL; - if (setjmp(png_jmpbuf(self.pngshka))) { - png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info); - fclose(self.fp); - free(row_pointers); - return (ResultVoidOrVecU8){.variant = Result_Err, .err = VecU8_from_cstr("Some png error happened")}; - } - - row_pointers = calloc(dim.height, sizeof(row_pointers)); - for (U32 y = 0; y < dim.height; y++) { - row_pointers[dim.height - 1 - y] = ((png_bytep)buffer) + 4 * dim.width * y; - } - png_read_image(self.pngshka, row_pointers); - png_read_end(self.pngshka, self.end_info); - /* No more errors */ - png_destroy_read_struct(&self.pngshka, &self.info, &self.end_info); - fclose(self.fp); - free(row_pointers); - return (ResultVoidOrVecU8){.variant = Result_Ok}; -} - -// todo: move it to pixel_masses.h (and also generate result types automatically -typedef struct { - Result_variant variant; - union { - TextureDataR8G8B8A8 ok; - VecU8 err; - }; -} ResultTextureDataR8G8B8A8OrVecU8; - -void ResultTextureDataR8G8B8A8OrVecU8_drop(ResultTextureDataR8G8B8A8OrVecU8 self) { - if (self.variant == Result_Ok) - TextureDataR8G8B8A8_drop(self.ok); - else - VecU8_drop(self.err); -} - -ResultTextureDataR8G8B8A8OrVecU8 MargaretPromisedPngR8G8B8A8_finish_into_TextureDataR8G8B8A8(MargaretPromisedPngR8G8B8A8 self) { - SizeOfRectangleU32 dim = MargaretPromisedPngR8G8B8A8_get_extent(&self); - TextureDataR8G8B8A8 tex = TextureDataR8G8B8A8_new(dim.width, dim.height); - ResultVoidOrVecU8 res = MargaretPromisedPngR8G8B8A8_finish(self, tex.pixels.buf); - if (res.variant == Result_Err) - return (ResultTextureDataR8G8B8A8OrVecU8){.variant = Result_Err, .err = res.err}; - return (ResultTextureDataR8G8B8A8OrVecU8){.variant = Result_Ok, .ok = tex}; -} - -/* aborts on error */ -TextureDataR8G8B8A8 TextureDataR8G8B8A8_read_from_png_nofail(SpanU8 name) { - ResultMargaretPromisedPngR8G8B8A8OrVecU8 res_1 = MargaretPromisedPngR8G8B8A8_begin(name); - if (res_1.variant == Result_Err) { - SpanU8_fprint(VecU8_to_span(&res_1.err), stderr); - abortf(" MargaretPromisedPngR8G8B8A8_begin\n"); - } - /* res_1 invalidated, we moved ownership to _finish methos */ - ResultTextureDataR8G8B8A8OrVecU8 res_2 = MargaretPromisedPngR8G8B8A8_finish_into_TextureDataR8G8B8A8(res_1.ok); - if (res_2.variant == Result_Err) { - SpanU8_fprint(VecU8_to_span(&res_2.err), stderr); - abortf(" MargaretPromisedPngR8G8B8A8_finish (into TextureData)\n"); - } - return res_2.ok; -} - -#endif \ No newline at end of file diff --git a/src/l2/marie/texture_processing.h b/src/l2/marie/texture_processing.h index 7f98b51..c7db612 100644 --- a/src/l2/marie/texture_processing.h +++ b/src/l2/marie/texture_processing.h @@ -4,33 +4,6 @@ #include "../../../gen/l1/pixel_masses.h" #include "rasterization.h" -void TextureDataR8G8B8A8_print(const TextureDataR8G8B8A8* self) { - U64 width = self->width; - // U64 height = ; - U64 cell_width = MAX_U64(1, width / 350); - U64 cell_height = MAX_U64(1, cell_width * 14 / 8); - for (U64 CY = 0; CY < height; CY += cell_height) { - for (U64 CX = 0; CX < width; CX += cell_width) { - float lum = 0; - for (U64 j = 0; j < cell_height; j++) { - U64 y = cell_height * CY + j; - if (y >= height) - continue; - for (U64 i = 0; i < cell_width; i++) { - U64 x = cell_width * CX + i; - if (x >= width) - continue; - cvec4 pix = *TextureDataR8G8B8A8_at(self, x, y); - lum += (float)pix.x / 255 * 0.21f + (float)pix.y / 255 * 0.71f + (float)pix.z / 255 * 0.08f; - } - } - lum /= (float)cell_width * (float)cell_height; - printf("%s", lum > 0.95 ? "@" : (lum > 0.8 ? "#" : (lum > 0.65 ? "*" : (lum > 0.4 ? "_" : (lum > 0.2 ? "." : " "))))); - } - printf("\n"); - } -} - /* Fixes several of my generated textures */ NODISCARD TextureDataR8G8B8A8 TextureDataR8G8B8A8_expand_nontransparent_1px(const TextureDataR8G8B8A8* self) { S32 width = (S32)self->width; diff --git a/src/l2/tests/r0/r0_tex_init_prep.c b/src/l2/tests/r0/r0_tex_init_prep.c index 0e1137d..37bd066 100644 --- a/src/l2/tests/r0/r0_tex_init_prep.c +++ b/src/l2/tests/r0/r0_tex_init_prep.c @@ -1,6 +1,7 @@ #include "r0_assets.h" #include "../../marie/rasterization.h" -#include "../../margaret/png_pixel_masses.h" +// #include "../../margaret/png_pixel_masses.h" // todo: delete this file +#include "../../../../gen/l1/margaret/png_pixel_masses.h" #include "../../marie/texture_processing.h" void for_log(U32 w, U32 r, U32 k) { @@ -25,6 +26,18 @@ void for_log(U32 w, U32 r, U32 k) { } int main() { + // TextureDataR8G8B8A8 tex = TextureDataR8G8B8A8_read_from_png_nofail(cstr("/home/gregory/test/basn3p04.png")); + // TextureDataR8G8B8A8_print(&tex); + // TextureDataR8G8B8A8_drop(tex); + // + // TextureDataR8G8B8 TEX = TextureDataR8G8B8_read_from_png_nofail(cstr("/home/gregory/test/basn3p04.png")); + // TextureDataR8G8B8_print(&TEX); + // TextureDataR8G8B8_drop(TEX); + + // TextureDataR8 tex = TextureDataR8_read_from_png_nofail(cstr("textures/log_5_5_10_TEMPLATE.png")); + // TextureDataR8_print(&tex); + // TextureDataR8_drop(tex); + for_log(10, 2, 6); for_log(5, 5, 10); for_log(1, 10, 4); From f2f5ef5340c14f3934ac8a58926f89e09cf4afd8 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Sat, 27 Sep 2025 02:05:54 +0300 Subject: [PATCH 6/8] Wrote r0 (now it uses texture set per generic model) --- CMakeLists.txt | 15 +- src/l1/anne/margaret/margaret_misc.h | 1 + src/l1/anne/util_temp_vulkan.h | 1 + src/l2/margaret/vulkan_utils.h | 192 ++++--- src/l2/tests/r0/r0.c | 521 ++++++++++-------- src/l2/tests/r0/r0_assets.h | 6 +- src/l2/tests/r0/r0_scene.h | 19 +- ...{log_10_2_6.png => log_10_2_6_diffuse.png} | Bin .../tests/r0/textures/log_10_2_6_specular.png | Bin 0 -> 108698 bytes .../tests/r0/textures/log_1_10_4_diffuse.png | Bin 0 -> 57154 bytes .../tests/r0/textures/log_1_10_4_specular.png | Bin 0 -> 57154 bytes .../tests/r0/textures/log_2_1_6_diffuse.png | Bin 0 -> 2894 bytes .../tests/r0/textures/log_2_1_6_specular.png | Bin 0 -> 2894 bytes .../tests/r0/textures/log_5_5_10_diffuse.png | Bin 0 -> 23803 bytes .../tests/r0/textures/log_5_5_10_specular.png | Bin 0 -> 23803 bytes 15 files changed, 421 insertions(+), 334 deletions(-) rename src/l2/tests/r0/textures/{log_10_2_6.png => log_10_2_6_diffuse.png} (100%) create mode 100644 src/l2/tests/r0/textures/log_10_2_6_specular.png create mode 100644 src/l2/tests/r0/textures/log_1_10_4_diffuse.png create mode 100644 src/l2/tests/r0/textures/log_1_10_4_specular.png create mode 100644 src/l2/tests/r0/textures/log_2_1_6_diffuse.png create mode 100644 src/l2/tests/r0/textures/log_2_1_6_specular.png create mode 100644 src/l2/tests/r0/textures/log_5_5_10_diffuse.png create mode 100644 src/l2/tests/r0/textures/log_5_5_10_specular.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 8dcee14..0bbbc84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,9 +27,9 @@ add_compile_definitions(_POSIX_C_SOURCE=200112L) add_compile_definitions(_GNU_SOURCE) add_compile_options(-fno-trapping-math) -add_executable(codegen_l1 src/l1/anne/codegen.c) -target_compile_definitions(codegen_l1 - PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8) +#add_executable(codegen_l1 src/l1/anne/codegen.c)1 +#target_compile_definitions(codegen_l1 +# PRIVATE PROTOTYPE1_L1_CODEGEN_BOOTSTRAP_USE_CHICKEN_VECU8) #add_executable(0_test src/l1_4/tests/t0.c) #add_executable(1_test src/l1_4/tests/t1.c) @@ -37,10 +37,9 @@ target_compile_definitions(codegen_l1 #add_executable(l1_4_t2 src/l1_4/tests/t2.c) #add_executable(codegen_l1_5 src/l1_5/anne/codegen.c) -# -#add_executable(0_render_test src/l2/tests/r0/r0.c gen/l_wl_protocols/xdg-shell-private.c -# src/l1/core/rb_tree_node.h) -#target_link_libraries(0_render_test -lvulkan -lwayland-client -lm -lxkbcommon -lpng) + +add_executable(0_render_test src/l2/tests/r0/r0.c gen/l_wl_protocols/xdg-shell-private.c) +target_link_libraries(0_render_test -lvulkan -lwayland-client -lm -lxkbcommon -lpng) add_executable(0r_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c) target_link_libraries(0r_tex_init_prep -lm -lpng) @@ -58,4 +57,4 @@ target_link_libraries(0r_tex_init_prep -lm -lpng) #target_link_libraries(0_play_test -lncurses) # -add_executable(l2t0 src/l2/tests/data_structures/t0.c) +#add_executable(l2t0 src/l2/tests/data_structures/t0.c) diff --git a/src/l1/anne/margaret/margaret_misc.h b/src/l1/anne/margaret/margaret_misc.h index 511f0a3..b4bb8a2 100644 --- a/src/l1/anne/margaret/margaret_misc.h +++ b/src/l1/anne/margaret/margaret_misc.h @@ -21,6 +21,7 @@ void generate_margaret_eve_for_vulkan_utils() { .T = cstr("PtrMargaretImageInMemoryInfo"), .t_primitive = true, .vec = true, .span = true, .mut_span = true, .collab_vec_span = true }); + generate_eve_span_company_for_primitive(l, ns, cstr("MargaretCommandForImageCopying"), true, true); } diff --git a/src/l1/anne/util_temp_vulkan.h b/src/l1/anne/util_temp_vulkan.h index 1201086..b17e6f6 100644 --- a/src/l1/anne/util_temp_vulkan.h +++ b/src/l1/anne/util_temp_vulkan.h @@ -41,6 +41,7 @@ void generate_util_templ_inst_for_vulkan_headers() { generate_guarded_span_company_for_primitive(l, ns, cstr("VkSemaphore"), vulkan_dep, true, false); generate_guarded_span_company_for_primitive(l, ns, cstr("VkDescriptorPoolSize"), vulkan_dep, true, false); generate_guarded_span_company_for_primitive(l, ns, cstr("VkBufferCopy"), vulkan_dep, true, false); + generate_guarded_span_company_for_primitive(l, ns, cstr("VkImageMemoryBarrier"), vulkan_dep, true, false); } #endif \ No newline at end of file diff --git a/src/l2/margaret/vulkan_utils.h b/src/l2/margaret/vulkan_utils.h index 8afcf30..97849e8 100644 --- a/src/l2/margaret/vulkan_utils.h +++ b/src/l2/margaret/vulkan_utils.h @@ -1027,6 +1027,11 @@ MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_srgba(uint .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT }; } +MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_unorm_8(uint32_t w, uint32_t h){ + return (MargaretImageInMemoryInfo){ .width = w, .height = h, .format = VK_FORMAT_R8_UNORM, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT }; +} + MargaretImageInMemoryInfo margaret_prep_image_mem_info_of_gpu_texture_unorm_32(uint32_t w, uint32_t h) { return (MargaretImageInMemoryInfo){ .width = w, .height = h, .format = VK_FORMAT_R8G8B8A8_UNORM, .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT }; @@ -1103,98 +1108,107 @@ void margaret_copy_buffer_imm ( margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer); } -// todo: get rid of this crap. I can do better -// For application initialization purposes only -void transition_image_layout ( - VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue, - VkImage image, VkImageLayout old_layout, VkImageLayout new_layout, - VkPipelineStageFlags src_stage_mask, VkAccessFlags src_access_mask, - VkPipelineStageFlags dst_stage_mask, VkAccessFlags dst_access_mask - ) { - VkCommandBuffer cmd_buffer = margaret_alloc_and_begin_single_use_command_buffer(device, command_pool); - VkImageMemoryBarrier barrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .srcAccessMask = src_access_mask, - .dstAccessMask = dst_access_mask, - .oldLayout = old_layout, - .newLayout = new_layout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = image, - .subresourceRange = (VkImageSubresourceRange){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, - }; - vkCmdPipelineBarrier(cmd_buffer, src_stage_mask, dst_stage_mask, - // Flags - 0, - 0, NULL, - 0, NULL, - 1, &barrier +typedef struct { + size_t host_mem_buff_offset; + const MargaretImageInMemoryInfo* dst_image; +} MargaretCommandForImageCopying; + +#include "../../../gen/l1/eve/margaret/VecAndSpan_MargaretCommandForImageCopying.h" + +#include "../../../gen/l1/vulkan/VecVkImageMemoryBarrier.h" + +/* (destination_stage_mask, destination_access_mask) are probably + * (VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT) */ +void margaret_rerecord_cmd_buff_for_texture_init ( + VkCommandBuffer command_buffer, VkBuffer host_mem_buffer, + SpanMargaretCommandForImageCopying commands, + VkPipelineStageFlags destination_stage_mask, VkAccessFlags destination_access_mask + ){ + if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS) + abortf("vkResetCommandBuffer\n"); + VkCommandBufferBeginInfo begin_info = {.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,}; + if (vkBeginCommandBuffer(command_buffer, &begin_info) != VK_SUCCESS) + abortf("vkBeginCommandBuffer\n"); + VecVkImageMemoryBarrier barriers = VecVkImageMemoryBarrier_new_reserved(commands.len); + for (size_t i = 0; i < commands.len; i++) { + MargaretCommandForImageCopying img = commands.data[i]; + VecVkImageMemoryBarrier_append(&barriers, (VkImageMemoryBarrier){ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = 0, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = img.dst_image->image, + .subresourceRange = (VkImageSubresourceRange){ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }); + } + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, /* Flags */ + 0, NULL, 0, NULL, + barriers.len, barriers.buf); + barriers.len = 0; /* It's ok, VkImageMemoryBarrier is primitive */ + for (size_t i = 0; i < commands.len; i++) { + MargaretCommandForImageCopying img = commands.data[i]; + VkBufferImageCopy region = { + .bufferOffset = img.host_mem_buff_offset, + .bufferRowLength = 0, + .bufferImageHeight = 0, + .imageSubresource = (VkImageSubresourceLayers){ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = {0, 0, 0}, + .imageExtent = { + .width = img.dst_image->width, + .height = img.dst_image->height, + .depth = 1 + }, + }; + vkCmdCopyBufferToImage(command_buffer, host_mem_buffer, img.dst_image->image, + // We assume that image was already transitioned to optimal layout transition_image_layout + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + } + /* filling buffers Vec again */ + for (size_t i = 0; i < commands.len; i++) { + MargaretCommandForImageCopying img = commands.data[i]; + VecVkImageMemoryBarrier_append(&barriers, (VkImageMemoryBarrier){ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = destination_access_mask, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = img.dst_image->image, + .subresourceRange = (VkImageSubresourceRange){ + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }); + } + vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, destination_stage_mask, + 0, /* Flags */ + 0, NULL, 0, NULL, + barriers.len, barriers.buf ); - margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer); + VecVkImageMemoryBarrier_drop(barriers); + if (vkEndCommandBuffer(command_buffer) != VK_SUCCESS) + abortf("vkEndCommandBuffer"); } -// For application initialization purposes only -void margaret_copy_buffer_to_trans_dst_optimal_image ( - VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue, - const MargaretImageInMemoryInfo* dst_image, VkBuffer src_buffer - ) { - VkCommandBuffer cmd_buffer = margaret_alloc_and_begin_single_use_command_buffer(device, command_pool); - VkBufferImageCopy region = { - .bufferOffset = 0, - .bufferRowLength = 0, - .bufferImageHeight = 0, - .imageSubresource = (VkImageSubresourceLayers){ - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .imageOffset = {0, 0, 0}, - .imageExtent = { - .width = dst_image->width, - .height = dst_image->height, - .depth = 1 - }, - }; - vkCmdCopyBufferToImage(cmd_buffer, src_buffer, dst_image->image, - // We assume that image was already transitioned to optimal layout transition_image_layout - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - margaret_end_and_submit_and_free_command_buffer(device, command_pool, graphics_queue, cmd_buffer); -} - -// todo: AHFHDF EW WHAT IS THAT??? -// For application initialization purposes only -void margaret_copy_buffer_to_texture_for_frag_shader_imm( - VkDevice device, VkCommandPool command_pool, VkQueue graphics_queue, - const MargaretImageInMemoryInfo* dst_image, VkBuffer src_buffer - ) { - transition_image_layout(device, command_pool, graphics_queue, dst_image->image, - // previous and new layouts - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - // src stage and access - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, - // destination stage and access - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT - ); - margaret_copy_buffer_to_trans_dst_optimal_image(device, command_pool, graphics_queue, dst_image, src_buffer); - transition_image_layout(device, command_pool, graphics_queue, dst_image->image, - // previous and new layouts - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, - // src stage and access - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, - // destination stage and access - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT - ); -} - -// todo: cjafhs WHAT IS THIS?? I need to remove this. I can do better than this // For texture VkImageView margaret_create_view_for_image ( VkDevice device, const MargaretImageInMemoryInfo* image, VkImageAspectFlags aspect_flags diff --git a/src/l2/tests/r0/r0.c b/src/l2/tests/r0/r0.c index e338762..48f1bcf 100644 --- a/src/l2/tests/r0/r0.c +++ b/src/l2/tests/r0/r0.c @@ -10,7 +10,7 @@ #include "../../../../gen/l_wl_protocols/xdg-shell-client.h" #include #include "../../../l1/system/creating_child_proc.h" -#include "../../margaret/png_pixel_masses.h" +#include "../../../../gen/l1/margaret/png_pixel_masses.h" // todo: generate this structure in l2 typedef struct { @@ -787,12 +787,73 @@ void record_cmd_set_viewport_and_scissors(VkCommandBuffer command_buffer, VkExte vkCmdSetScissor(command_buffer, 0, 1, &scissor); } +typedef struct { + VkSemaphore in_frame_transfer_complete; + VkSemaphore image_available_semaphore; + VkSemaphore rendered_to_IT1_semaphore; + VkFence in_flight_fence; +} Jane_r0; + +NODISCARD Jane_r0 Jane_r0_create(VkDevice device) { + return (Jane_r0){ + .in_frame_transfer_complete = margaret_create_semaphore(device), + .image_available_semaphore = margaret_create_semaphore(device), + .rendered_to_IT1_semaphore = margaret_create_semaphore(device), + .in_flight_fence = margaret_create_fence(device, true) + }; +} + +void Jane_r0_destroy(VkDevice device, Jane_r0 jane) { + vkDestroyFence(device, jane.in_flight_fence, NULL); + vkDestroySemaphore(device, jane.rendered_to_IT1_semaphore, NULL); + vkDestroySemaphore(device, jane.image_available_semaphore, NULL); + vkDestroySemaphore(device, jane.in_frame_transfer_complete, NULL); +} + +// todo: handle case where presentation and graphics are from the same family +typedef struct { + VkQueue graphics_queue; + VkQueue presentation_queue; +} UsedVulkanQueues; + +typedef struct { + MargaretBufferInMemoryInfo vbo; + MargaretBufferInMemoryInfo ebo; + /* We store image in yet another meaningless buffer (will change it later) */ + TextureDataR8G8B8A8 reading_diffuse; + TextureDataR8G8B8A8 reading_normal; + TextureDataR8 reading_specular; + /* Filled during first (and the only) memory init */ + MargaretImageInMemoryInfo diffuse; + MargaretImageInMemoryInfo normal; + MargaretImageInMemoryInfo specular; + /* will be filled in later */ + VkImageView diffuse_view; + VkImageView normal_view; + VkImageView specular_view; + /* Each generic model has ti's own descriptor set + * It's because it has it's own textures. But it also has copies of references to light UBO + * Because I am to lazy to create two set layouts for generic model pipeline */ + VkDescriptorSet p_0a_set_0; +} GenericModelTopAndTexInMemoryInfo; + +#include "../../../../gen/l1/eve/r0/VecGenericModelTopAndTexInMemoryInfo.h" + +typedef struct { + MargaretBufferInMemoryInfo vbo; + MargaretBufferInMemoryInfo ebo; +} ShinyModelTopInMemoryInfo; + +#include "../../../../gen/l1/eve/r0/VecShinyModelTopInMemoryInfo.h" + + + void reset_and_record_command_buffer_0( VkCommandBuffer command_buffer, VkRenderPass render_pass_0, const PipelineHands* pipeline_and_layout_0a, const PipelineHands* pipeline_and_layout_0b, VkFramebuffer result_framebuffer, VkExtent2D image_extent, - const Scene* scene, - VkDescriptorSet descriptor_set_for_pipeline_0a, VkDescriptorSet descriptor_set_for_pipeline_0b, + const Scene* scene, const VecGenericModelTopAndTexInMemoryInfo* generic_models, + VkDescriptorSet descriptor_set_for_pipeline_0b, mat4 proj_cam_t, vec3 camera_pos ) { if (vkResetCommandBuffer(command_buffer, 0) != VK_SUCCESS) @@ -813,6 +874,7 @@ void reset_and_record_command_buffer_0( }; vkCmdBeginRenderPass(command_buffer, &renderpass_begin, VK_SUBPASS_CONTENTS_INLINE); + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout_0a->pipeline); // We forgot that viewport is not built into our pipeline // We forgot that scissors are not built into out pipeline @@ -831,7 +893,7 @@ void reset_and_record_command_buffer_0( vkCmdBindIndexBuffer(command_buffer, model->model.ebo, 0, VK_INDEX_TYPE_UINT32); vkCmdBindDescriptorSets( command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout_0a->pipeline_layout, 0, - 1, &descriptor_set_for_pipeline_0a, 0, NULL); + 1, &VecGenericModelTopAndTexInMemoryInfo_at(generic_models, i)->p_0a_set_0, 0, NULL); vkCmdDrawIndexed(command_buffer, model->model.indexes, model->instances.len, 0, 0, 0); } @@ -841,6 +903,9 @@ void reset_and_record_command_buffer_0( 0, sizeof(mat4), &proj_cam_t); vkCmdPushConstants(command_buffer, pipeline_and_layout_0b->pipeline_layout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(mat4), sizeof(vec3), &camera_pos); + vkCmdBindDescriptorSets( + command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout_0b->pipeline_layout, 0, + 1, &descriptor_set_for_pipeline_0b, 0, NULL); for (size_t i = 0; i < scene->shiny_models.len; i++) { const UsedShinyModelOnScene* model = VecUsedShinyModelOnScene_at(&scene->shiny_models, i); VkBuffer attached_buffers[2] = { model->model.vbo, model->model.instance_attr_buf }; @@ -849,9 +914,6 @@ void reset_and_record_command_buffer_0( assert(ARRAY_SIZE(attached_buffers) == 2 && ARRAY_SIZE(offsets_in_buffers) == 2); vkCmdBindVertexBuffers(command_buffer, 0, 2, attached_buffers, offsets_in_buffers); vkCmdBindIndexBuffer(command_buffer, model->model.ebo, 0, VK_INDEX_TYPE_UINT32); - vkCmdBindDescriptorSets( - command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_and_layout_0b->pipeline_layout, 0, - 1, &descriptor_set_for_pipeline_0b, 0, NULL); vkCmdDrawIndexed(command_buffer, model->model.indexes, model->instances.len, 0, 0, 0); } @@ -990,60 +1052,7 @@ void copy_scene_info_to_buffer_and_rerecord_full_copy_command_buffer( abortf("vkEndCommandBuffer"); } -typedef struct { - VkSemaphore in_frame_transfer_complete; - VkSemaphore image_available_semaphore; - VkSemaphore rendered_to_IT1_semaphore; - VkFence in_flight_fence; -} Jane_r0; -NODISCARD Jane_r0 Jane_r0_create(VkDevice device) { - return (Jane_r0){ - .in_frame_transfer_complete = margaret_create_semaphore(device), - .image_available_semaphore = margaret_create_semaphore(device), - .rendered_to_IT1_semaphore = margaret_create_semaphore(device), - .in_flight_fence = margaret_create_fence(device, true) - }; -} - -void Jane_r0_destroy(VkDevice device, Jane_r0 jane) { - vkDestroyFence(device, jane.in_flight_fence, NULL); - vkDestroySemaphore(device, jane.rendered_to_IT1_semaphore, NULL); - vkDestroySemaphore(device, jane.image_available_semaphore, NULL); - vkDestroySemaphore(device, jane.in_frame_transfer_complete, NULL); -} - -// todo: handle case where presentation and graphics are from the same family -typedef struct { - VkQueue graphics_queue; - VkQueue presentation_queue; -} UsedVulkanQueues; - -typedef struct { - MargaretBufferInMemoryInfo vbo; - MargaretBufferInMemoryInfo ebo; - /* We store image in yet another meaningless buffer (will change it later) */ - TextureDataR8G8B8A8 reading_diffuse; - TextureDataR8G8B8A8 reading_normal; - TextureDataR8 reading_specular; - /* Filled during first (and the only) memory init */ - MargaretImageInMemoryInfo diffuse; - MargaretImageInMemoryInfo normal; - MargaretImageInMemoryInfo specular; - /* will be filled in later */ - VkImageView diffuse_view; - VkImageView normal_view; - VkImageView specular_view; -} GenericModelTopAndTexInMemoryInfo; - -#include "../../../../gen/l1/eve/r0/VecGenericModelTopAndTexInMemoryInfo.h" - -typedef struct { - MargaretBufferInMemoryInfo vbo; - MargaretBufferInMemoryInfo ebo; -} ShinyModelTopInMemoryInfo; - -#include "../../../../gen/l1/eve/r0/VecShinyModelTopInMemoryInfo.h" typedef struct { MargaretInstanceAndItsDebug instance_and_debug; @@ -1086,12 +1095,12 @@ typedef struct { VkImageView zbuffer_view; VkImageView IT1_view; VkFramebuffer IT1_framebuffer; - VkImageView cyl_1_diffuse_texture_view; - VkImageView cyl_1_normal_texture_view; VkSampler linear_sampler; VkSampler nearest_sampler; VkDescriptorPool descriptor_pool; - VkDescriptorSet descriptor_set_for_pipeline_0a; + + /* Descriptor sets */ + // Descriptor sets for pipeline_0a are stored in device_generic_models_top_and_tex VkDescriptorSet descriptor_set_for_pipeline_0b; VkDescriptorSet descriptor_set_for_pipeline_1; @@ -1258,7 +1267,8 @@ void vulkano_frame_drawing(state_r0* state) { &state->vk_ctx.pipeline_hands_0a, &state->vk_ctx.pipeline_hands_0b, state->vk_ctx.IT1_framebuffer, state->vk_ctx.swfb.extent, &state->vk_ctx.scene, - state->vk_ctx.descriptor_set_for_pipeline_0a, state->vk_ctx.descriptor_set_for_pipeline_0b, + &state->vk_ctx.device_generic_models_top_and_tex, /* Needed just to get descriptor sets for generic models */ + state->vk_ctx.descriptor_set_for_pipeline_0b, t_mat, state->vk_ctx.my_cam_control_info.pos); reset_and_record_command_buffer_1(state->vk_ctx.rendering_command_buffer_1, state->vk_ctx.render_pass_1, @@ -1784,25 +1794,56 @@ int main() { vk_ctx->device_generic_models_top_and_tex = VecGenericModelTopAndTexInMemoryInfo_new_reserved(vk_ctx->scene_template.generic_models.len); for (size_t i = 0; i < vk_ctx->scene_template.generic_models.len; i++) { const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&vk_ctx->scene_template.generic_models, i); + TextureDataR8G8B8A8 reading_diffuse = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)); + TextureDataR8G8B8A8 reading_normal = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->normal_texture_path)); + TextureDataR8 reading_specular = TextureDataR8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)); VecGenericModelTopAndTexInMemoryInfo_append(&vk_ctx->device_generic_models_top_and_tex, (GenericModelTopAndTexInMemoryInfo){ .vbo = GenericMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len), .ebo = margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len), - .reading_diffuse = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)), - .reading_normal = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)), - // todo: continue from here. But first - create TextureDataR8 reading function - .reading_specular = TextureDataR8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)), + .reading_diffuse = reading_diffuse, .reading_normal = reading_normal, .reading_specular = reading_specular, + .diffuse = margaret_prep_image_mem_info_of_gpu_texture_srgba(reading_diffuse.width, reading_diffuse.height), + .normal = margaret_prep_image_mem_info_of_gpu_texture_unorm_32(reading_normal.width, reading_normal.height), + .specular = margaret_prep_image_mem_info_of_gpu_texture_unorm_8(reading_specular.width, reading_specular.height), + /* image views will be created after the images are allocated */ + /* descriptor set for each model will be allocated later */ }); } - // todo: kill myself (update: still WiP (update: it's became growing technical debt point now) + + VecU64 offset_of_image_in_host_mem_buff_during_init = VecU64_new_zeroinit(vk_ctx->device_generic_models_top_and_tex.len * 3); + U64 grand_total_texture_size_in_host_mem = 0; + { + U64 offset = 0; + for (size_t i = 0; i < vk_ctx->device_generic_models_top_and_tex.len; i++) { + offset_of_image_in_host_mem_buff_during_init.buf[3 * i + 0] = offset; + offset += TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->device_generic_models_top_and_tex.buf[i].reading_diffuse); + offset_of_image_in_host_mem_buff_during_init.buf[3 * i + 1] = offset; + offset += TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->device_generic_models_top_and_tex.buf[i].reading_normal); + offset_of_image_in_host_mem_buff_during_init.buf[3 * i + 2] = offset; + offset += TextureDataR8_get_size_in_bytes(&vk_ctx->device_generic_models_top_and_tex.buf[i].reading_specular); + } + grand_total_texture_size_in_host_mem = offset; + } + + vk_ctx->device_shiny_models_top = VecShinyModelTopInMemoryInfo_new_reserved(vk_ctx->scene_template.shiny_models.len); + for (size_t i = 0; i < vk_ctx->scene_template.shiny_models.len; i++) { + const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&vk_ctx->scene_template.shiny_models, i); + VecShinyModelTopInMemoryInfo_append(&vk_ctx->device_shiny_models_top, + (ShinyModelTopInMemoryInfo){ + .vbo = ShinyMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len), + .ebo = margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len), + }); + } + + // todo: kill myself (update: still WiP (update: it became a growing technical debt now)) + // todo: commit suicide // We have only one staging buffer in host memory (because we don't really need more) vk_ctx->host_mem_buffer = (MargaretBufferInMemoryInfo){ .sz = MAX_U64(SceneTemplate_get_space_for_initial_model_topology_transfer(&vk_ctx->scene_template), MAX_U64(SceneTemplate_get_space_needed_for_widest_state_transfer(&vk_ctx->scene_template), - MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_diffuse_tex), - MAX_U64(TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_normal_tex), 0)))) + MAX_U64(grand_total_texture_size_in_host_mem, 0))) , .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT }; PtrMargaretBufferInMemoryInfo host_mem_buffer_SPAN[1] = {&vk_ctx->host_mem_buffer}; vk_ctx->host_mem = margaret_initialize_buffers_and_images(vk_ctx->physical_device, vk_ctx->device, @@ -1810,50 +1851,15 @@ int main() { (MutSpanPtrMargaretImageInMemoryInfo){ 0 }, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - // todo: split this in two (or maybe even better: merge it all into one/two buffer and use offsets - vk_ctx->device_ebo_buffers_for_generic_meshes = VecMargaretBufferInMemoryInfo_new(); - vk_ctx->device_vbo_buffers_for_generic_meshes = VecMargaretBufferInMemoryInfo_new(); - for (size_t mi = 0; mi < vk_ctx->scene_template.generic_models.len; mi++) { - const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&vk_ctx->scene_template.generic_models, mi); - VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_vbo_buffers_for_generic_meshes, - GenericMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len)); - VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_ebo_buffers_for_generic_meshes, - margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len)); - } - vk_ctx->device_ebo_buffers_for_shiny_meshes = VecMargaretBufferInMemoryInfo_new(); - vk_ctx->device_vbo_buffers_for_shiny_meshes = VecMargaretBufferInMemoryInfo_new(); - for (size_t mi = 0; mi < vk_ctx->scene_template.shiny_models.len; mi++) { - const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&vk_ctx->scene_template.shiny_models, mi); - VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_vbo_buffers_for_shiny_meshes, - ShinyMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len)); - VecMargaretBufferInMemoryInfo_append(&vk_ctx->device_ebo_buffers_for_shiny_meshes, - margaret_prep_buffer_mem_info_of_gpu_ebo(M->topology.indexes.len)); - } - vk_ctx->device_lighting_ubo = margaret_prep_buffer_mem_info_of_gpu_ubo(sizeof(Pipeline0UBO)); vk_ctx->device_instance_attrs_for_models = (MargaretBufferInMemoryInfo){ .sz = SceneTemplate_get_space_needed_for_all_instance_attributes(&vk_ctx->scene_template), .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT }; - VecPtrMargaretBufferInMemoryInfo device_mem_buffers_SPAN = VecPtrMargaretBufferInMemoryInfo_new(); - // todo: add iteration macro generation - for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_generic_meshes.len; i++) { - VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_ebo_buffers_for_generic_meshes, i)); - } - for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_generic_meshes.len; i++) { - VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_vbo_buffers_for_generic_meshes, i)); - } - for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_shiny_meshes.len; i++) { - VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_ebo_buffers_for_shiny_meshes, i)); - } - for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_shiny_meshes.len; i++) { - VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, - VecMargaretBufferInMemoryInfo_mat(&vk_ctx->device_vbo_buffers_for_shiny_meshes, i)); - } + VecPtrMargaretBufferInMemoryInfo device_mem_buffers_SPAN = VecPtrMargaretBufferInMemoryInfo_new_reserved( + vk_ctx->device_generic_models_top_and_tex.len + vk_ctx->device_shiny_models_top.len); + VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &vk_ctx->device_lighting_ubo); VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &vk_ctx->device_instance_attrs_for_models); @@ -1861,21 +1867,35 @@ int main() { MAX_WIN_WIDTH, MAX_WIN_HEIGHT, IT1_format.some); vk_ctx->device_zbuffer_image = margaret_prep_image_mem_info_of_zbuffer( MAX_WIN_WIDTH, MAX_WIN_HEIGHT, zbuffer_format.some); - vk_ctx->device_cyl_1_diffuse_texture = margaret_prep_image_mem_info_of_gpu_texture_srgba( - vk_ctx->cyl_1_diffuse_tex.width, &vk_ctx->cyl_1_diffuse_tex.height); - vk_ctx->device_cyl_1_normal_texture = margaret_prep_image_mem_info_of_gpu_texture_unorm_32( - vk_ctx->cyl_1_normal_tex.width, &vk_ctx->cyl_1_normal_tex.height); - PtrMargaretImageInMemoryInfo device_mem_images_SPAN[] = { - &vk_ctx->device_IT1_image, &vk_ctx->device_zbuffer_image, &vk_ctx->device_cyl_1_diffuse_texture, - &vk_ctx->device_cyl_1_normal_texture - }; + VecPtrMargaretImageInMemoryInfo device_mem_images_SPAN = + VecPtrMargaretImageInMemoryInfo_new_reserved(2 + 3 * vk_ctx->scene_template.generic_models.len); + VecPtrMargaretImageInMemoryInfo_append(&device_mem_images_SPAN, &vk_ctx->device_IT1_image); + VecPtrMargaretImageInMemoryInfo_append(&device_mem_images_SPAN, &vk_ctx->device_zbuffer_image); + + for (size_t i = 0; i < vk_ctx->device_generic_models_top_and_tex.len; i++) { + GenericModelTopAndTexInMemoryInfo* M = &vk_ctx->device_generic_models_top_and_tex.buf[i]; + VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &M->vbo); + VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &M->ebo); + VecPtrMargaretImageInMemoryInfo_append(&device_mem_images_SPAN, &M->diffuse); + VecPtrMargaretImageInMemoryInfo_append(&device_mem_images_SPAN, &M->normal); + VecPtrMargaretImageInMemoryInfo_append(&device_mem_images_SPAN, &M->specular); + } + + for (size_t i = 0; i < vk_ctx->device_shiny_models_top.len; i++) { + ShinyModelTopInMemoryInfo* M = &vk_ctx->device_shiny_models_top.buf[i]; + VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &M->vbo); + VecPtrMargaretBufferInMemoryInfo_append(&device_mem_buffers_SPAN, &M->ebo); + } + vk_ctx->device_mem = margaret_initialize_buffers_and_images(vk_ctx->physical_device, vk_ctx->device, VecPtrMargaretBufferInMemoryInfo_to_mspan(&device_mem_buffers_SPAN), - (MutSpanPtrMargaretImageInMemoryInfo){ .data = device_mem_images_SPAN, .len = ARRAY_SIZE(device_mem_images_SPAN) }, + VecPtrMargaretImageInMemoryInfo_to_mspan(&device_mem_images_SPAN), VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - /* device_mem_buffers_SPAN invalidated */ + + /* device_mem_buffers_SPAN, device_mem_images_SPAN invalidated */ VecPtrMargaretBufferInMemoryInfo_drop(device_mem_buffers_SPAN); + VecPtrMargaretImageInMemoryInfo_drop(device_mem_images_SPAN); vk_ctx->command_pool = margaret_create_resettable_command_pool(vk_ctx->device, vk_ctx->queue_fam.for_graphics); vk_ctx->rendering_command_buffer_0 = margaret_allocate_command_buffer(vk_ctx->device, vk_ctx->command_pool); @@ -1890,16 +1910,17 @@ int main() { size_t offset_in_attr_buffer = 0; for (size_t mi = 0; mi < vk_ctx->scene_template.generic_models.len; mi++) { const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&vk_ctx->scene_template.generic_models, mi); + const GenericModelTopAndTexInMemoryInfo* MM = VecGenericModelTopAndTexInMemoryInfo_at(&vk_ctx->device_generic_models_top_and_tex, mi); VecUsedGenericModelOnScene_append(&vk_ctx->scene.generic_models, (UsedGenericModelOnScene){ - .model = (ModelOnSceneMem){ - .vbo = VecMargaretBufferInMemoryInfo_at( - &vk_ctx->device_vbo_buffers_for_generic_meshes, mi)->buffer, - .ebo = VecMargaretBufferInMemoryInfo_at( - &vk_ctx->device_ebo_buffers_for_generic_meshes, mi)->buffer, + .model = (GenericModelOnSceneMem){ + .vbo = MM->vbo.buffer, + .ebo = MM->ebo.buffer, .indexes = M->topology.indexes.len, .instance_attr_buf = vk_ctx->device_instance_attrs_for_models.buffer, .instance_attr_buf_offset = offset_in_attr_buffer, .limit_max_instance_count = M->max_instance_count + // todo: remove vbo, ebo from here (we don't need it here). + // as you may see, I didn't specifid images (that's becasuse I fpn need to) }, .instances = VecGenericMeshInstance_new(), }); @@ -1907,12 +1928,11 @@ int main() { } for (size_t mi = 0; mi < vk_ctx->scene_template.shiny_models.len; mi++) { const ShinyMeshInSceneTemplate* M = VecShinyMeshInSceneTemplate_at(&vk_ctx->scene_template.shiny_models, mi); + const ShinyModelTopInMemoryInfo* MM = VecShinyModelTopInMemoryInfo_at(&vk_ctx->device_shiny_models_top, mi); VecUsedShinyModelOnScene_append(&vk_ctx->scene.shiny_models, (UsedShinyModelOnScene){ - .model = (ModelOnSceneMem){ - .vbo = VecMargaretBufferInMemoryInfo_at( - &vk_ctx->device_vbo_buffers_for_shiny_meshes, mi)->buffer, - .ebo = VecMargaretBufferInMemoryInfo_at( - &vk_ctx->device_ebo_buffers_for_shiny_meshes, mi)->buffer, + .model = (ShinyModelOnSceneMem){ + .vbo = MM->vbo.buffer, + .ebo = MM->ebo.buffer, .indexes = M->topology.indexes.len, .instance_attr_buf = vk_ctx->device_instance_attrs_for_models.buffer, .instance_attr_buf_offset = offset_in_attr_buffer, @@ -1933,6 +1953,13 @@ int main() { VecGenericMeshInstance_append(&VecUsedGenericModelOnScene_mat(&vk_ctx->scene.generic_models, 1)->instances, (GenericMeshInstance){ .model_t = marie_translation_mat4(vk_ctx->Buba_control_info) }); + + VecGenericMeshInstance_append(&VecUsedGenericModelOnScene_mat(&vk_ctx->scene.generic_models, 2)->instances, + (GenericMeshInstance){ .model_t = marie_translation_mat4((vec3){5, -7, 6})}); + VecGenericMeshInstance_append(&VecUsedGenericModelOnScene_mat(&vk_ctx->scene.generic_models, 3)->instances, + (GenericMeshInstance){ .model_t = marie_translation_mat4((vec3){5, -7, -6})}); + + for (U64 i = 0; i < 5; i++) { VecShinyMeshInstance_append(&VecUsedShinyModelOnScene_mat(&vk_ctx->scene.shiny_models, 0)->instances, (ShinyMeshInstance){ .model_t = marie_translation_mat4((vec3){ @@ -1947,34 +1974,53 @@ int main() { if (vkMapMemory(vk_ctx->device, vk_ctx->host_mem, 0, VK_WHOLE_SIZE, 0, &vk_ctx->host_mem_buffer_mem) != VK_SUCCESS) abortf("vkMapMemory"); - SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd( + { + SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd( &vk_ctx->scene_template, &vk_ctx->scene, vk_ctx->host_mem_buffer_mem, vk_ctx->transfer_command_buffer, vk_ctx->host_mem_buffer.buffer); - { - VkCommandBuffer command_buffers[1] = { vk_ctx->transfer_command_buffer }; + VkSubmitInfo submit_info = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .commandBufferCount = ARRAY_SIZE(command_buffers), - .pCommandBuffers = command_buffers, + .commandBufferCount = 1, .pCommandBuffers = &vk_ctx->transfer_command_buffer, }; if (vkQueueSubmit(vk_ctx->queues.graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) abortf("vkQueueSubmit\n"); } vkDeviceWaitIdle(vk_ctx->device); + { - memcpy(vk_ctx->host_mem_buffer_mem, vk_ctx->cyl_1_diffuse_tex.pixels.buf, - TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_diffuse_tex)); - margaret_copy_buffer_to_texture_for_frag_shader_imm( - vk_ctx->device, vk_ctx->command_pool, vk_ctx->queues.graphics_queue, - &vk_ctx->device_cyl_1_diffuse_texture, vk_ctx->host_mem_buffer.buffer); - } - vkDeviceWaitIdle(vk_ctx->device); - { - memcpy(vk_ctx->host_mem_buffer_mem, vk_ctx->cyl_1_normal_tex.pixels.buf, - TextureDataR8G8B8A8_get_size_in_bytes(&vk_ctx->cyl_1_normal_tex)); - margaret_copy_buffer_to_texture_for_frag_shader_imm( - vk_ctx->device, vk_ctx->command_pool, vk_ctx->queues.graphics_queue, - &vk_ctx->device_cyl_1_normal_texture, vk_ctx->host_mem_buffer.buffer); + VecMargaretCommandForImageCopying commands = + VecMargaretCommandForImageCopying_new_reserved(vk_ctx->device_generic_models_top_and_tex.len); + for (size_t i = 0; i < vk_ctx->device_generic_models_top_and_tex.len; i++) { + const GenericModelTopAndTexInMemoryInfo* M = + VecGenericModelTopAndTexInMemoryInfo_at(&vk_ctx->device_generic_models_top_and_tex, i); + U64 diffuse_offset = *VecU64_at(&offset_of_image_in_host_mem_buff_during_init, 3 * i + 0); + U64 normal_offset = *VecU64_at(&offset_of_image_in_host_mem_buff_during_init, 3 * i + 1); + U64 specular_offset = *VecU64_at(&offset_of_image_in_host_mem_buff_during_init, 3 * i + 2); + memcpy(vk_ctx->host_mem_buffer_mem + diffuse_offset, + M->reading_diffuse.pixels.buf, TextureDataR8G8B8A8_get_size_in_bytes(&M->reading_diffuse)); + memcpy(vk_ctx->host_mem_buffer_mem + normal_offset, + M->reading_normal.pixels.buf, TextureDataR8G8B8A8_get_size_in_bytes(&M->reading_normal)); + memcpy(vk_ctx->host_mem_buffer_mem + specular_offset, + M->reading_specular.pixels.buf, TextureDataR8_get_size_in_bytes(&M->reading_specular)); + VecMargaretCommandForImageCopying_append(&commands, (MargaretCommandForImageCopying){ + .dst_image = &M->diffuse, .host_mem_buff_offset = diffuse_offset}); + VecMargaretCommandForImageCopying_append(&commands, (MargaretCommandForImageCopying){ + .dst_image = &M->normal, .host_mem_buff_offset = normal_offset}); + VecMargaretCommandForImageCopying_append(&commands, (MargaretCommandForImageCopying){ + .dst_image = &M->specular, .host_mem_buff_offset = specular_offset}); + } + margaret_rerecord_cmd_buff_for_texture_init(vk_ctx->transfer_command_buffer, vk_ctx->host_mem_buffer.buffer, + VecMargaretCommandForImageCopying_to_span(&commands), + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_SHADER_READ_BIT); + VecMargaretCommandForImageCopying_drop(commands); + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .commandBufferCount = 1, .pCommandBuffers = &vk_ctx->transfer_command_buffer, + }; + if (vkQueueSubmit(vk_ctx->queues.graphics_queue, 1, &submit_info, NULL) != VK_SUCCESS) + abortf("vkQueueSubmit\n"); } vkDeviceWaitIdle(vk_ctx->device); // We sent everything we needed. but host_mem_buffer_mem may be used later @@ -1985,16 +2031,18 @@ int main() { /* Here we create an image view into a temporary IT1 texture and a framebuffer for scene rendering */ vk_ctx->IT1_view = margaret_create_view_for_image(vk_ctx->device, &vk_ctx->device_IT1_image, VK_IMAGE_ASPECT_COLOR_BIT); + /* Busy creating views for all my textures */ + for (size_t i = 0; i < vk_ctx->device_generic_models_top_and_tex.len; i++) { + GenericModelTopAndTexInMemoryInfo* M = VecGenericModelTopAndTexInMemoryInfo_mat(&vk_ctx->device_generic_models_top_and_tex, i); + M->diffuse_view = margaret_create_view_for_image(vk_ctx->device, &M->diffuse, VK_IMAGE_ASPECT_COLOR_BIT); + M->normal_view = margaret_create_view_for_image(vk_ctx->device, &M->normal, VK_IMAGE_ASPECT_COLOR_BIT); + M->specular_view = margaret_create_view_for_image(vk_ctx->device, &M->specular, VK_IMAGE_ASPECT_COLOR_BIT); + } + + vk_ctx->IT1_framebuffer = create_IT1_framebuffer(vk_ctx->device, vk_ctx->IT1_view, vk_ctx->zbuffer_view, vk_ctx->render_pass_0, MAX_WIN_WIDTH, MAX_WIN_HEIGHT); - // My cylinder 1 texture needs VkImageView - vk_ctx->cyl_1_diffuse_texture_view = margaret_create_view_for_image( - vk_ctx->device, &vk_ctx->device_cyl_1_diffuse_texture, VK_IMAGE_ASPECT_COLOR_BIT); - // My cylinder 1 normal texture also needs NkImageView - vk_ctx->cyl_1_normal_texture_view = margaret_create_view_for_image( - vk_ctx->device, &vk_ctx->device_cyl_1_normal_texture, VK_IMAGE_ASPECT_COLOR_BIT); - // Right now I only have one light source VecPipeline0PointLight_append(&vk_ctx->scene.point_lights, (Pipeline0PointLight){.pos = {0}, .color = {100, 100, 100}}); @@ -2003,30 +2051,73 @@ int main() { vk_ctx->linear_sampler = margaret_create_sampler(vk_ctx->physical_device, vk_ctx->device, true); vk_ctx->nearest_sampler = margaret_create_sampler(vk_ctx->physical_device, vk_ctx->device, false); - vk_ctx->descriptor_pool = margaret_create_descriptor_set_pool(vk_ctx->device, 2, 3, 3); - vk_ctx->descriptor_set_for_pipeline_0a = margaret_allocate_descriptor_set( - vk_ctx->device, vk_ctx->descriptor_pool, vk_ctx->pipeline_hands_0a.descriptor_set_layout); + vk_ctx->descriptor_pool = margaret_create_descriptor_set_pool(vk_ctx->device, + 1 + 1 * vk_ctx->device_generic_models_top_and_tex.len, + 1 + 3 * vk_ctx->device_generic_models_top_and_tex.len, + 2 + 1 * vk_ctx->device_generic_models_top_and_tex.len); + for (size_t i = 0; i < vk_ctx->device_generic_models_top_and_tex.len; i++) { + GenericModelTopAndTexInMemoryInfo* M = &vk_ctx->device_generic_models_top_and_tex.buf[i]; + M->p_0a_set_0 = margaret_allocate_descriptor_set( + vk_ctx->device, vk_ctx->descriptor_pool, vk_ctx->pipeline_hands_0a.descriptor_set_layout); + } vk_ctx->descriptor_set_for_pipeline_0b = margaret_allocate_descriptor_set( vk_ctx->device, vk_ctx->descriptor_pool, vk_ctx->pipeline_hands_0b.descriptor_set_layout); vk_ctx->descriptor_set_for_pipeline_1 = margaret_allocate_descriptor_set( vk_ctx->device, vk_ctx->descriptor_pool, vk_ctx->pipeline_hands_1.descriptor_set_layout); // Configuring my descriptor sets, that I just allocated - VkDescriptorBufferInfo buffer_info_for_descriptor_0_in_set_0a = { - .buffer = vk_ctx->device_lighting_ubo.buffer, - .offset = 0, - .range = sizeof(Pipeline0UBO), - }; - VkDescriptorImageInfo image_info_for_descriptor_1_in_set_0a = { - .sampler = vk_ctx->linear_sampler, - .imageView = vk_ctx->cyl_1_diffuse_texture_view, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - }; - VkDescriptorImageInfo image_info_for_descriptor_2_in_set_0a = { - .sampler = vk_ctx->nearest_sampler, - .imageView = vk_ctx->cyl_1_normal_texture_view, - .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - }; + + for (size_t i = 0; i < vk_ctx->device_generic_models_top_and_tex.len; i++) { + GenericModelTopAndTexInMemoryInfo* M = &vk_ctx->device_generic_models_top_and_tex.buf[i]; + VkDescriptorBufferInfo buffer_info_for_descriptor_0_in_set_0a = { + .buffer = vk_ctx->device_lighting_ubo.buffer, + .offset = 0, + .range = sizeof(Pipeline0UBO), + }; + VkDescriptorImageInfo image_info_for_descriptor_1_in_set_0a = { + .sampler = vk_ctx->linear_sampler, + .imageView = M->diffuse_view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + VkDescriptorImageInfo image_info_for_descriptor_2_in_set_0a = { + .sampler = vk_ctx->nearest_sampler, + .imageView = M->normal_view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + // todo: add a third binding (for specular shading) + VkWriteDescriptorSet writes_in_descriptor_set[] = { + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = M->p_0a_set_0, + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &buffer_info_for_descriptor_0_in_set_0a, + }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = M->p_0a_set_0, + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &image_info_for_descriptor_1_in_set_0a, + }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = M->p_0a_set_0, + .dstBinding = 2, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &image_info_for_descriptor_2_in_set_0a, + }, + }; + vkUpdateDescriptorSets(vk_ctx->device, ARRAY_SIZE(writes_in_descriptor_set), writes_in_descriptor_set, 0, NULL); + } + + VkDescriptorBufferInfo buffer_info_for_descriptor_0_in_set_0b = { .buffer = vk_ctx->device_lighting_ubo.buffer, .offset = 0, @@ -2038,34 +2129,6 @@ int main() { .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; VkWriteDescriptorSet writes_in_descriptor_sets[] = { - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = vk_ctx->descriptor_set_for_pipeline_0a, - .dstBinding = 0, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .pBufferInfo = &buffer_info_for_descriptor_0_in_set_0a, - }, - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = vk_ctx->descriptor_set_for_pipeline_0a, - .dstBinding = 1, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = &image_info_for_descriptor_1_in_set_0a, - }, - { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .dstSet = vk_ctx->descriptor_set_for_pipeline_0a, - .dstBinding = 2, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = &image_info_for_descriptor_2_in_set_0a, - }, - { .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, .dstSet = vk_ctx->descriptor_set_for_pipeline_0b, @@ -2106,8 +2169,8 @@ int main() { vkDestroySampler(vk_ctx->device, vk_ctx->linear_sampler, NULL); vkDestroySampler(vk_ctx->device, vk_ctx->nearest_sampler, NULL); - vkDestroyImageView(vk_ctx->device, vk_ctx->cyl_1_normal_texture_view, NULL); - vkDestroyImageView(vk_ctx->device, vk_ctx->cyl_1_diffuse_texture_view, NULL); + // vkDestroyImageView(vk_ctx->device, vk_ctx->cyl_1_normal_texture_view, NULL); + // vkDestroyImageView(vk_ctx->device, vk_ctx->cyl_1_diffuse_texture_view, NULL); vkDestroyFramebuffer(vk_ctx->device, vk_ctx->IT1_framebuffer, NULL); vkDestroyImageView(vk_ctx->device, vk_ctx->IT1_view, NULL); vkDestroyImageView(vk_ctx->device, vk_ctx->zbuffer_view, NULL); @@ -2121,44 +2184,44 @@ int main() { vkFreeMemory(vk_ctx->device, vk_ctx->device_mem, NULL); // todo: delete all the crap - vkDestroyImage(vk_ctx->device, vk_ctx->device_cyl_1_diffuse_texture.image, NULL); - vkDestroyImage(vk_ctx->device, vk_ctx->device_cyl_1_normal_texture.image, NULL); + // vkDestroyImage(vk_ctx->device, vk_ctx->device_cyl_1_diffuse_texture.image, NULL); + // vkDestroyImage(vk_ctx->device, vk_ctx->device_cyl_1_normal_texture.image, NULL); vkDestroyImage(vk_ctx->device, vk_ctx->device_IT1_image.image, NULL); vkDestroyImage(vk_ctx->device, vk_ctx->device_zbuffer_image.image, NULL); vkDestroyBuffer(vk_ctx->device, vk_ctx->device_lighting_ubo.buffer, NULL); vkDestroyBuffer(vk_ctx->device, vk_ctx->device_instance_attrs_for_models.buffer, NULL); - for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_generic_meshes.len; i++) - vkDestroyBuffer(vk_ctx->device, - VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_ebo_buffers_for_generic_meshes, i)->buffer, - NULL); - VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_ebo_buffers_for_generic_meshes); - - for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_generic_meshes.len; i++) - vkDestroyBuffer(vk_ctx->device, - VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_vbo_buffers_for_generic_meshes, i)->buffer, - NULL); - VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_vbo_buffers_for_generic_meshes); - - for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_shiny_meshes.len; i++) - vkDestroyBuffer(vk_ctx->device, - VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_ebo_buffers_for_shiny_meshes, i)->buffer, - NULL); - VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_ebo_buffers_for_shiny_meshes); - - for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_shiny_meshes.len; i++) - vkDestroyBuffer(vk_ctx->device, - VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_vbo_buffers_for_shiny_meshes, i)->buffer, - NULL); - VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_vbo_buffers_for_shiny_meshes); + // for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_generic_meshes.len; i++) + // vkDestroyBuffer(vk_ctx->device, + // VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_ebo_buffers_for_generic_meshes, i)->buffer, + // NULL); + // VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_ebo_buffers_for_generic_meshes); + // + // for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_generic_meshes.len; i++) + // vkDestroyBuffer(vk_ctx->device, + // VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_vbo_buffers_for_generic_meshes, i)->buffer, + // NULL); + // VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_vbo_buffers_for_generic_meshes); + // + // for (size_t i = 0; i < vk_ctx->device_ebo_buffers_for_shiny_meshes.len; i++) + // vkDestroyBuffer(vk_ctx->device, + // VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_ebo_buffers_for_shiny_meshes, i)->buffer, + // NULL); + // VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_ebo_buffers_for_shiny_meshes); + // + // for (size_t i = 0; i < vk_ctx->device_vbo_buffers_for_shiny_meshes.len; i++) + // vkDestroyBuffer(vk_ctx->device, + // VecMargaretBufferInMemoryInfo_at(&vk_ctx->device_vbo_buffers_for_shiny_meshes, i)->buffer, + // NULL); + // VecMargaretBufferInMemoryInfo_drop(vk_ctx->device_vbo_buffers_for_shiny_meshes); vkDestroyBuffer(vk_ctx->device, vk_ctx->host_mem_buffer.buffer, NULL); - TextureDataR8G8B8A8_drop(vk_ctx->cyl_1_normal_tex); - TextureDataR8G8B8A8_drop(vk_ctx->cyl_1_diffuse_tex); + // TextureDataR8G8B8A8_drop(vk_ctx->cyl_1_normal_tex); + // TextureDataR8G8B8A8_drop(vk_ctx->cyl_1_diffuse_tex); SceneTemplate_drop(vk_ctx->scene_template); MargaretSwapchainBundle_drop_with_device(vk_ctx->device, vk_ctx->swfb); diff --git a/src/l2/tests/r0/r0_assets.h b/src/l2/tests/r0/r0_assets.h index 2e177ef..eb1b12c 100644 --- a/src/l2/tests/r0/r0_assets.h +++ b/src/l2/tests/r0/r0_assets.h @@ -869,9 +869,9 @@ ShinyMeshTopology generate_shiny_rhombicuboctahedron(float r) { GenericMeshInSceneTemplate GenericMeshInSceneTemplate_for_log(U32 w, U32 r, U32 k, U32 max_instance_count) { return (GenericMeshInSceneTemplate){.topology = generate_one_fourth_of_a_cylinder((float)w, (float)r, k), .max_instance_count = max_instance_count, - .diffuse_texture_path = VecU8_format("log_%u_%u_%u_diffuse.png", w, r, k), - .normal_texture_path = VecU8_format("log_%u_%u_%u_NORMAL.png", w, r, k), - .specular_texture_path = VecU8_format("log_%u_%u_%u_specular.png", w, r, k), + .diffuse_texture_path = VecU8_format("textures/log_%u_%u_%u_diffuse.png", w, r, k), + .normal_texture_path = VecU8_format("textures/log_%u_%u_%u_NORMAL.png", w, r, k), + .specular_texture_path = VecU8_format("textures/log_%u_%u_%u_specular.png", w, r, k), }; } diff --git a/src/l2/tests/r0/r0_scene.h b/src/l2/tests/r0/r0_scene.h index 455dead..b8e077e 100644 --- a/src/l2/tests/r0/r0_scene.h +++ b/src/l2/tests/r0/r0_scene.h @@ -15,12 +15,12 @@ typedef struct { VkImage diffuse_texture; VkImage normal_texture; VkImage specular_texture; -} ModelOnSceneMem; +} GenericModelOnSceneMem; /* Contains both data for model instances attributes and buffer (+offset) where it is stored */ /* Also, I made it non-clonable. Thus */ typedef struct { - ModelOnSceneMem model; + GenericModelOnSceneMem model; VecGenericMeshInstance instances; } UsedGenericModelOnScene; @@ -31,7 +31,16 @@ void UsedGenericModelOnScene_drop(UsedGenericModelOnScene self) { #include "../../../../gen/l1/eve/r0/VecUsedGenericModelOnScene.h" typedef struct { - ModelOnSceneMem model; + VkBuffer vbo; + VkBuffer ebo; + size_t indexes; + VkBuffer instance_attr_buf; + VkDeviceSize instance_attr_buf_offset; + U32 limit_max_instance_count; +} ShinyModelOnSceneMem; + +typedef struct { + ShinyModelOnSceneMem model; VecShinyMeshInstance instances; } UsedShinyModelOnScene; @@ -137,7 +146,7 @@ void SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd( // todo: ot use one buffer per all the data for (size_t mi = 0; mi < scene_template->generic_models.len; mi++) { const GenericMeshInSceneTemplate* mt = VecGenericMeshInSceneTemplate_at(&scene_template->generic_models, mi); - const ModelOnSceneMem *m_buf = &VecUsedGenericModelOnScene_at(&scene->generic_models, mi)->model; + const GenericModelOnSceneMem *m_buf = &VecUsedGenericModelOnScene_at(&scene->generic_models, mi)->model; size_t vbo_len = mt->topology.vertices.len * sizeof(GenericMeshVertex); memcpy(host_mem_buffer_mem + offset, mt->topology.vertices.buf, vbo_len); VkBufferCopy ra = {.srcOffset = offset, .dstOffset = 0, .size = vbo_len}; @@ -151,7 +160,7 @@ void SceneTemplate_copy_initial_model_topology_and_rerecord_transfer_cmd( } for (size_t mi = 0; mi < scene_template->shiny_models.len; mi++) { const ShinyMeshInSceneTemplate* mt = VecShinyMeshInSceneTemplate_at(&scene_template->shiny_models, mi); - const ModelOnSceneMem *m_buf = &VecUsedShinyModelOnScene_at(&scene->shiny_models, mi)->model; + const ShinyModelOnSceneMem *m_buf = &VecUsedShinyModelOnScene_at(&scene->shiny_models, mi)->model; size_t vbo_len = mt->topology.vertices.len * sizeof(ShinyMeshVertex); memcpy(host_mem_buffer_mem + offset, mt->topology.vertices.buf, vbo_len); VkBufferCopy ra = {.srcOffset = offset, .dstOffset = 0, .size = vbo_len}; diff --git a/src/l2/tests/r0/textures/log_10_2_6.png b/src/l2/tests/r0/textures/log_10_2_6_diffuse.png similarity index 100% rename from src/l2/tests/r0/textures/log_10_2_6.png rename to src/l2/tests/r0/textures/log_10_2_6_diffuse.png diff --git a/src/l2/tests/r0/textures/log_10_2_6_specular.png b/src/l2/tests/r0/textures/log_10_2_6_specular.png new file mode 100644 index 0000000000000000000000000000000000000000..b2432a56c3b8b23bb077531dcf609c2afce5bd6b GIT binary patch literal 108698 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øM?n$R`d>V(w1 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

HMZr1VeG8|b7El#tSv*SV+A`0w@TrO~`k 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%0AF}j7TwrYVEgMO1J%L&?CudCnRZb#$~ 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 HVbOm9$z?Y& literal 0 HcmV?d00001 diff --git a/src/l2/tests/r0/textures/log_1_10_4_specular.png b/src/l2/tests/r0/textures/log_1_10_4_specular.png new file mode 100644 index 0000000000000000000000000000000000000000..11bf115b5515c05c95821be94335088f233676d6 GIT binary patch literal 57154 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 HVbOm9$z?Y& literal 0 HcmV?d00001 diff --git a/src/l2/tests/r0/textures/log_2_1_6_diffuse.png b/src/l2/tests/r0/textures/log_2_1_6_diffuse.png new file mode 100644 index 0000000000000000000000000000000000000000..06a057594140936ed31ac5507a104a08c0bd479e GIT binary patch literal 2894 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 Date: Tue, 30 Sep 2025 14:23:22 +0300 Subject: [PATCH 7/8] Specular map used --- src/l2/tests/r0/r0.c | 22 +++++++++++++++++- src/l2/tests/r0/shaders/glsl/0/0.frag | 10 ++++---- .../tests/r0/textures/log_10_2_6_specular.png | Bin 108698 -> 78017 bytes 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/l2/tests/r0/r0.c b/src/l2/tests/r0/r0.c index 48f1bcf..21f7ea2 100644 --- a/src/l2/tests/r0/r0.c +++ b/src/l2/tests/r0/r0.c @@ -269,6 +269,12 @@ PipelineHands create_graphics_pipeline_0( .descriptorCount = 1, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, }, + { + .binding = 3, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, + }, }; VkDescriptorSetLayoutCreateInfo descriptor_set_layout_crinfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, @@ -1796,7 +1802,7 @@ int main() { const GenericMeshInSceneTemplate* M = VecGenericMeshInSceneTemplate_at(&vk_ctx->scene_template.generic_models, i); TextureDataR8G8B8A8 reading_diffuse = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)); TextureDataR8G8B8A8 reading_normal = TextureDataR8G8B8A8_read_from_png_nofail(VecU8_to_span(&M->normal_texture_path)); - TextureDataR8 reading_specular = TextureDataR8_read_from_png_nofail(VecU8_to_span(&M->diffuse_texture_path)); + TextureDataR8 reading_specular = TextureDataR8_read_from_png_nofail(VecU8_to_span(&M->specular_texture_path)); VecGenericModelTopAndTexInMemoryInfo_append(&vk_ctx->device_generic_models_top_and_tex, (GenericModelTopAndTexInMemoryInfo){ .vbo = GenericMeshVertex_buffer_crinfo_of_gpu_vbo(M->topology.vertices.len), @@ -2084,6 +2090,11 @@ int main() { .imageView = M->normal_view, .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, }; + VkDescriptorImageInfo image_info_for_descriptor_3_in_set_0a = { + .sampler = vk_ctx->nearest_sampler, + .imageView = M->specular_view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; // todo: add a third binding (for specular shading) VkWriteDescriptorSet writes_in_descriptor_set[] = { { @@ -2113,6 +2124,15 @@ int main() { .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .pImageInfo = &image_info_for_descriptor_2_in_set_0a, }, + { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = M->p_0a_set_0, + .dstBinding = 3, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .pImageInfo = &image_info_for_descriptor_3_in_set_0a, + }, }; vkUpdateDescriptorSets(vk_ctx->device, ARRAY_SIZE(writes_in_descriptor_set), writes_in_descriptor_set, 0, NULL); } diff --git a/src/l2/tests/r0/shaders/glsl/0/0.frag b/src/l2/tests/r0/shaders/glsl/0/0.frag index 8f41989..512d843 100644 --- a/src/l2/tests/r0/shaders/glsl/0/0.frag +++ b/src/l2/tests/r0/shaders/glsl/0/0.frag @@ -3,11 +3,12 @@ layout(location = 0) in vec2 fsin_tex; layout(location = 1) in vec3 fsin_pos; +/* Righ now all in set 0 */ layout(location = 0) out vec4 fin_color; - +/* Yes, even these guys */ layout(binding = 1) uniform sampler2D color_tex; - layout(binding = 2) uniform sampler2D normal_map; +layout(binding = 3) uniform sampler2D specular_map; layout(push_constant, std430) uniform pc { layout(offset = 64) vec3 camera_pos; @@ -57,7 +58,8 @@ void main(){ Pipeline0Spotlight lamp = spotlight_arr[i]; } vec3 natural_color = texture(color_tex, fsin_tex).xyz; - // todo: add specular map texture - vec3 color = natural_color * diffuse_illumination + 0.5 * specular_illumination; + float specular_c = texture(specular_map, fsin_tex).x; + vec3 color = natural_color * diffuse_illumination + specular_c * specular_illumination; fin_color = vec4(color, 1); + // fin_color = vec4(specular_c, 0, 0, 1); } diff --git a/src/l2/tests/r0/textures/log_10_2_6_specular.png b/src/l2/tests/r0/textures/log_10_2_6_specular.png index b2432a56c3b8b23bb077531dcf609c2afce5bd6b..c8154354649bb07d5113cee4b5743e4b899bae28 100644 GIT binary patch literal 78017 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≶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øM?n$R`d>V(w1 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

HMZr1VeG8|b7El#tSv*SV+A`0w@TrO~`k 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%0AF}j7TwrYVEgMO1J%L&?CudCnRZb#$~ zqi;4ovoCNlXCM0d;OA%tFYJdbY=`VPi32AGEgR}DA=uxb8#7t;Em^Kj+0KI0NlZ|H zM$Z6&5}^OkGTYx48ze`?=+U;)Xqm_9O+k}qC*-(F&eay}ZIJ@14$7nYJQbhN>FURY zik|RsqgobZ{kuv+!Kwl)@R#K0w-d-%;uJ^mD=V0f101fNDL>PFJQ&fKz&0hJ!}r+^{yvkG@4P($h*6PNRcZgK zv2e5(#_Z|(wusFJQW<>6&K&pneq$09Ynp+*h@GHXYli`}u9kH}u9n=K?JUGhizE3% zrkvB&u;LZvkV;M0>^5HPd!53d*q58cuCx(4Q|0XhNuC3hGXN_o{ZJsdqRgD zOb}x8c0@lju|V4R87_Cu31iWq8btQgf)j>G@aHoTxh=amLGK;;wp0dm(7XW4BKF7m*;6R?;Wwffa!6w>(w(wI}T3oEQSV8-D?5-~0v|l5cvP|OdLVNBwPj))t zTMXpMUP#yX0ut>2U;InQ(IxJo?fF%G4w;TH_36XD!un&dekuOk^D@rCtqZ#hjr79d z9&%;P(Bq`4qo_AVa6<%$zlG2s?ZDc=gD%17kQwjY-MNuHarIG+15i$BL-k%jRUvbYg? zxVzcv5E%E<)y)N***?+{Ju0)bKd)aJpU*L6;z@&}5jzU#Fr^w$^yP^aOXHuPcw%yL zAQX!9^<~VWO0&^4;fG`lzp&(O3^*Kn`QhM-HFZ&;d;yyR8YvWhw(vu^1PU!^5t`EI z=dR7I%72qWjNKnSE<6t}QCu%&PK!&%dK&ga;dIvJZ%S#YMM$Sz8Kp`h9*uGjaV1}N z1Ny%TR^HBzC6IaaW^mgdu!Df)UF2fIn5E}T_x{%~snJ}}>-4Z)o`E22OVPY?*N#;T z8%ofEH#Et_R12pdWqJk^y|w^fs3S2YPk`S%Bly_R)NjM_{1XbSp>kLTrx%Z7b^MO8 zH_jqQ_!H<@MZ1D+>3NSS6N7ogl9G6IUUi@+dbEjgS|HcBehOeiGkNS3}(_xDuD73(Rn*|%tFKT@iuGwocGk7w0UTiia zHuMwijSkdVDPSBoVS;p(NPKh?=VhMrW4s6O>I@GVzWS4xN}ewHDcczJ#1DDM_vw=cz)jAsO+ID@hW_2*-kf# zBEZ*?of^JIfyv|Q{Vi;3NHq3E5C7}@8lncYn=SU-AJ^i9D1tBi0uVWGF&%Eg#GB5L zGX=gbT3*LEK*Hwel8NuWm_bxw@qW_Hi?$K+0BPaJyH+Hh@L7mG&7t@ox6z;MC?&yt zyU~|BeQ?%a+sAq-z?<5VZe#zo@yQhKDG_%_lAOaE^j_z<=Y{p>#qDXEtF!gGV3(KG z9^pG8Xl=1!WfIBIlVXSF^wU<^@bBL>oNC)lN{vWV7FYKZ8+`>pg_`3xO_4bXwA4#4 zgWd%@IEnl{+IfqaXUv)M)^b}ygBS=3(HFom^xbX5yi|3&nv+!esNaodsyxBt=Fx1n9pY=LKy~598jMsN-G~Twc z8UuONDcQ-CWjID!n>GEhWJ~VPjuLwdv7N`K2io{;-3A}C9n67g=ZyO;f#|L37-3oJ zR#f~7L}ksNtw8aHo6>-Ay7_m3H}{rRWx|BdUV3im?~cDK45yjXV8m%B;C_RwtAnw+ z0psOm;I=>S>+~ndx-;rYI3Q3WjiL!j28ZxBi$~6{Mw)I(%Ip-uD13}_JGm6S#1}ig z^wJ3AKbUEYUHjIRIp3M##>a?!UHaM|krsQ(2hQ|}F%cdV2JzV70>P*|^`k}bnByQb zMuZG6gU%6~-!F)?2^v3|WuWBot61WCF&*9-9R!ET-7Z|TA=%CqgpLQ#9oR3d{eFip zmD6jmF_G7?9P<*;4>I7Ey~%qJ`9)S#W&J~=&Bg2vvqsYV?8Y7J#+$3$&Xz(meURfz z=unYkAfdylyrHpjQV=n(?kGChnpe|{{7Rb}iRw#FE6n=5-k9H#e0pd68@@Su^VdkA zAz-TzIG{LLuma~HB*Spb*mC3heSf9*HyPcyrUv{8e>q+QFNb}2 z3$OS?DytGT13lVQfxBI}+`63OtcTf1fjc~i@`^?-7TT6cSrC5)+>2mh9Kq3;sH(?=k9q!cQy}yALU-fQ~t}^jS{5=n$hUd#> zvTQZWaT;ZwN{{8+Qks3%6~WEEOTGXgSyzM zf81qcZ1>aAoCh7l+MuRod1P?q52KBGG@A&yVXMZT7dT%0bt5R~74V3jQS{(;d>g$F zCxWrTnot8#57fqcbp$a_$ih6p7EeoCq7I7XHv27>DiUiGS~;92 z3fS_xgK;qGm;SS=kYklpKNe8XH_=yg`SZ8&Q|Km)8h7SDKJCbB@SU%wfXT&%e=u(E zuE0V3*Sf~4@(ebTl=)x8X#ILsHF*0FT51O=pJU>hdqLbQ9;UIjj<4ZkVr%I?=nR7`-s|H zU%%8rYphy=@wqQ7s06y?NTJB!T7lG;xp{!e4E7N51*AiL8?fhs%8Tp+W|(Vv49s8B z0nqIly{j~Hx(a3r^tnA0!G{?7ei;&Bj>14ohN>Z$Z;(q;HYfMk7}4UYpH4|o84Ae1 z6Ofd%HQg2)$^#3gtNhiRhKbsb+WZ{wtmCmYbkFFW?BDw5kM3jp0_m~PD5`qfM zS48A~f$pl3@%8IR!xk;LZoC*`WyNz+WDhF$3-(X8tg%2D7uA$RmDxypzsr@vni36g z0bm%fY&RmBm zqAn2EJ_G;uyocW9)2*DGhx-}+$yOk$=zaS}B9R;a^^j z<+QQc+~Z1z%YH7W*x>{O9oW@(=lw`z8l@bNmi=DgK__$kgC});)w1b11rmX*tgzp^qEEzv_p;3Kj(hLsj7H6^vsnXjRj0@tEb#IBJ zRhVwAv^rt<9%7=FCAZc18jJ!m6hU)0#G7lEAY`L0e(A6&l*$v=V!}Jd8jB5)bePJr zAy4f1b8%946SimM@@pyt2MUb?(k&3}J7Su|hhAjp$^JZA%{ z*h0ze8FY`2AvY-YHrdBi{)YFb#Zvn1c=VT9xk%W+HDfUargB7pBsY*ckd{IZCcg65+E-ZT>zUi zB|XO?bfEY2_^JqS zzPXviOZ^i&^sIiwaMSR zjUhj5r6PpM9`MJbAHba8)xgDKw7E_e#GECNtWGF{daB#xY9j4AnkJvYrIs#gdPuu*iEFBI(;i}_q>vYJ> z&%L@TYQ;ae+<9;kfoN(#%p2V#9J8&>%EC8;{~TT-7h@LIxRoxAc^v27P`@8TkwT%A z34!nV9-B}*>OmpBBQow{COU0U&nxO>*DARG81%+Olq0@Jn#eC}ZM@Z;u<@BWzbO3b z`}OCaNM!XH%u7k32Coc|1noLl+86{^Q)?g`|Q{m5O4JVzu|Qv^wk?K4P84#hw8c zSA$JFLU6@m)jZQkAbaBZ0Z+UQTtpCCXb^9!>kI4o3Kh>24wzLpmZ4P_4@ZOLYZYyV z`ZClVvNiD#7vdVO0ccOg_;S|=z^FuSf(Lw?IFg^@U&9;~S7!JDnSb{^IWBwr`Vl?F zkF0Nr5H6>gnew+2%>gb2i6!?(iDQQjiHNnjuH-LKNKmAVx7g8I$CQ6ifIQn6gLg(~ zf_6RK9^ctaXDWE1vzRE}*B<_}tKhzvh4D5=JE8L`FHvV6D$K#v(3>r`6j849>qfl> zb3d3WC7$jZhICKH7Pb!t%6{K`P~t<$`Qu4S=?<&LIC5@p^3ZVOj!8xxyG#!7M16bF$e2R zqm>SCKE8jekUFHO>!GFXI_kQ66*-Bay3JnsAvGZS>)_wZbK$h`d)V^*I!;)vU)@t5_!KW?*G%w^+!97 zfh7JF@<-XAgM^cl)zbz4Fpb?(N;%Iq%9l|xP8Sa(=#&W+E$6F`Bzm!7>^m}dsw$Xv z`i9iRBGZd|a5N~$Ve2c>5;!L};0g|JI<}*6M(|3_cmATMVm>1Z}gxB6qCY1><&B3!9)hPo_2`OM^A<_bZOl~gc79L8ijGU_pAq;W17($_vNc}{ z`9W&gC6@{v5 z*e9-A4^G3gH4xWjh@Bhxqo{yb>CKwuZ|R7oZX>^FMviv)&l`SRyW2t&8~7@%Ap=6z z+pojR6(+oL0%5dvh^9B zft0?P&l<-ikA`vwQO?up3q~8;2gha^&&P&nH`-__t-nRNL?8}@T<6_%Z4%=kW`f-{ zm}g`m?EV?rcj6~j2R2m;PWralSQkxaG{T{QMO6foYw#Yk~B+;c!50BjmL0t%EFMziB zA4&G`RT>pzRyIf{GAOo{_PHsa7^w6$@OKx+qgN|@ifV2zoGO_hMs2U(C!Jm<0OcA_ zEuEJi$O8+T8@SkHVhAA~k<9y2L72cJ(F%I06hCLgKe7pQHWymAwxBw8g~7aG1#@S zM!df*N9E1B09gw+Cygu+W1p|lnPMTOhE7W#+y&=|OCegY;huIw)dz3P+I36uxi7>$ zKmqzbKSZWvohwnYbA}of6|E|@1%diu;$i!4{&m=x**Od=eypzZoVoXC9p)W5`Fw$I z?LvkVEEg9ddvEz#;E`r0J~H$<0?VIi$n1&(0L5`T{HIN`Zgq0bWpBoG8; zy?dip9HYN;RsM0}UfH)x>@5aZf-5MN4)l=+^pOP~-W~Hr&X<~1xWPkLIN5Ks5X9hKQ5vc`W4I*HLjy#qwti?osu;7l+JZTvs>B&03j|2MZ z>*vvtpjiJ7=H{);ZA9DhU~MV9cG zQ+LcoTJHssbn~~|87Y`+Qt)$e7gOV%FrP~L9on75Z52)CJJ?e5_nAz-`Faqwn6+>Y zu1_ri{LMk28*7JR>?G^ZX#53}__t(#u2cpqruOqABay!D7Oz>@%3SjKXNnu6c1?;~ z!K%XLR&>_tWoAtK+!joVOhG^L+~oa^vphItEMSPA z!P9)vXl#{-e1s?XJo7>)HWXn#0UJUBR5`(^Y*z7s%RPm9Cc^_8j}9u@aGsj{!QGf)_2+O2UGvkae@CpcLh z87lTc6+@xZ@xjfg<1+&iW-gBh6*ukry4i}9=I62QX3y7=wd=ucob!lH3_+`%%~tEi=)dgaqqZma+kV*YWN$S-clz(}{51_@PIxUnx=-xg#Yg z^f{oPN801z>5>SW^<_~+t=hI#HupzrD{XP|?M?*b3Di%-2o#Y4lmSc~hYn^=W^iXJ z$kmzE85u6WcR42E)nVUdaikpj{sxcYkqUf={_lv8P@Nz(RxZjh?2@SK=1mQro zubbaB!bBcqW1t>^@#Hr}`?3nNsH@*O!bB-V2}PfYs{SW}`z6&APwA_(%F=qEV4@;- zCGFTtE}pSU^yW^_&V&#lgxE>$?ohpl?h1} ztE@OJMP4?fyDSdWfeP8%5|c9y|d!LnGWd2aLi+RNVR$EMCeb7Ux% zN1zhXe&O?>n554eIJbJndV~Sw7^2Nsk|2#wE> z(@sJRkid}0gGPr%EN(x0~sQnfS*C<(>{a1tk7SKrfcvRw@32p95wek6jvg~qapa~5}t328UxrN0Mh zc}Yw?Sp=Yq$AjfV0QLV1uDKC%^*e|@u6YbP{QPEESi-o#AJM&FbN)0eUq5>BZ<(25 z$gzg)-m47lo8wejSp`95a#BNW1NUhhAT-csHkV}psFiySM0FNh9kcp~l+xt>48lVe ztGpQOz=UD|Kn&>T!U3-Q!AIRHY)Uv@l4Cj~&`5Bg`pUk#M)W%D2{M6+4V>u|Qx%l^5|`}Ps*4IQn5EPL|)+HNHt9DT#0k9kg66@&Y6i^&LA6+?K~|6F_e z_cW@Fra|QF!WmHx+sJHJlmm1RYmeQ}iQq8gcZm+P`sL9x3`{fqoZZy4&Gg=)RKN{T zN!+R|J~bF>YmRwIRaf)h@t91}eSnb@*fuETfY#{J($Y*XUkWwDBUPSWGU>%L1;ei& zus;En?iLpptsZBw=5+p98}N}woclbhxwXA5QTDcmD@;Rag`{(K11%SdN=n`s7*Ob??2+#V3l{@%xK;J_A#t;G?w5ZEjvldK8__hh|8wP_oj>?J zB00OcZN7uu5k!3Xl09iP$0WrV#=j*Wtm#GFv~1_>?3|UG8|W21m4Vxpt_8HnI6psU zVrSn`Vf^nXv&+j-p;%NKzsmHA%F9FEmRRJfEohhye6`78qV%@Mg5(_>*woh7pM_B? z@Bm$}V=YKZN=j~)?R`V9U^hWglK(D}`PE;3x^MJM`pSN#=R>9sV(#RC42^=>OMbAr zCl6^9FuaVTBiGs4*&Ox14>{8S|ElThNB;TqDMVI^1PaDgN1U+YRV$exPl)}`MuxGE zJe@N~dr2jb5L5rf&wsB;oNqwMn))sTYOb6aLJM!k{=AsxF&n)vN)Xj9Hm?`{;@N!$Oj2ban??t}e zkQe6Hi(!F1ApeSxOAIj??>w6=g{FvpT>R zN0>#g5@X!d+9uqKOR^-_iK&RqBJ5vK|NUEd$0-7dC#F7JB-Il_1}wstu|}E!2Lbw4 z7(!MU&1Tse6C9Ek2-J5F2fHIx*jX*Dc52bn^IlwfAeSfJ*c(CF4E^2(}O^| z=+CDBuKtATaf7||j;kplZ|i8hLKCPnN+l8Qzc9nWi94H<*;&(b>Zsp=exM8H#r-!H zpdZ0n8b?9zN7gH{uV)^<$wVw>Xq6mgnREMloQQJCATOH#9R!E@i`#5eFcBTna~n@v zMEY;-x#V9aWlWNG9^lW4=Xhtj02JqRS0b4N7WzTI<8>&~-vD2s?hnlo|LDxC zLi=N)bjdy|q8X2HN#wt+Qb(?jYr^w`QPGn`unm+jNhZw%9ONt&b?2ogvI)$(tyKw+ zv1+@K0#lL#Hg{-`9QBg|O_5Gu!oOG;79VIvO#yTuf6?ygwdH2%2_ ztzd&^-u0yXmEs~8nmreAAjuL5bo;7%UsOk0RQHGOXJ`+$q$xIydeH2;zf(7*ieuIsc23I# zH&6pjJ3+s3;~pez#ufmcF#3NsTZ(zZ$&>b*-Cc}Nip*-<>UM(`HLL)B9-(Q1)cNnd zS0`H#XR+2DZN&H(onZ2`3}4@ugb&L=k7XyhKOiN%d!g>r79J(>zaWKBw(#tDH1s8H zV3KW6D2C#GxGP+DQk-Q*09GM$hE#Rpik?KvQc4hPgZ*EU$U%2o(Gl{j0VCGnG_%4@ zlVWI*URIsDnCtG`ymeG4JV7>wIx{1r``V0^bBh1>FNhwZYdHDm@6lp@&;X!AuXSdYQO`q5c>}+N3=f@?n#*`%ez1cyrG|jkV5Rn$+dx3x34^MdbX%pPrY*5o|>V zHsU4*w^g4#i`SN2y7{@2liH#&&7jWV@=w%+E76@A=G*T7OQuo@INsKnO1|fqU)|j} zWi;(PXq0~06uFQh%afWjYX;={09(|Q^)qI4o&fRxKIW)Gn#&B!hurcp3^0!c(g>q{ zN++zcRFHs$r6-ovvj2nFK{JzrTS-J&mF1EDcW=d8N)~P4gXaORLwI!%s__5g3Cf*x zSUX6{2sAcIVKZ80ss9&q=_UUU*x>n*|GV&Br6ddfE*i>~uTimxDyWI&;y zenc_HVZo><(uw!q?``Jb!kKtD#dGL%h5*F|$gC@6Dl3usXu!wn@%G}OL)!C8&_2C)su(~mV0-SI(_h*NzqD&Q|3kd&6VbL`ffaoLsw;)% zAB2U)zsa4EwCDYM=g!FR*+15?F#RYFbHA(Zdmr-e1`-Xl)eXyJ)%N1LI@2aq1NzgN zSp9pp$azbhFKBUzUoqMyLGtlyPR&&M&<&8HM)_r zevti_VAV~aQiTf~7Vp$FQ6+kt^QEM!m`a)6=$f(dHgC2?IU~Mi4fX&*Z5K&xG@VYo z+WHHuf45_5mNV?QFqM~?L;oE|O5FrSSm>*dD~9Gc(mb}5l=_raomKmC@Qmy_I=cgzFaf1x>Xp(JHThU)2e^;A0Ci{MtvvE56NdklyiPDNEKA(M|ytz;xDVl zsovUMAL?J`)N{)DHlAWDxja+vFeqGu^3Kl{3sLj!!}DB;R^^s%li7bDt1)nVCV6o; zkDXAj(-l3|dm0;t+y7q6{p9&@pUfr}UF+vcz(YiQ%I^5kpp5MYJ*7>Gbm_8nvD<%_ zf-fkloD=3CLZ36I`vp~9!zhaN%kA8%6pSibS=e>9VXgL|^+}V64YGnBdMuOa)jS{Tg>ufFCmvZKlcaW86jSL-vCHH4ZIrj$ z36d@da#GEg)aG6ACbv-FR@}%GxT8v80%)Z+E0`#olJuAAZv9(1M zMzQg)4N0wrS8vK*-)CyZbR#q@dz`Gku)Yd^Jr&=3e99I3kA{+y_Y;_a{f{?>AAzVd z?S@bzxeTfd;}j{Wgcror>RJIRVg;EP;?@(60DO3KzM$q}#$aj|&lLT(k^cAwqhJ-I zbN5snAnnos{I^NDKgv#*ep{|Y8N2!1&mB8`Iagnt`4;bDkZH7mN%t3EIeFZ>J6TOF z`%AxnET+ZkCBziF1={cqxzlj<0Ek{-il zX~`0x<8!Fyy;y=LX&E8G=p|0D>`(hpRdgWI@`Ei}Oa$rGr~3l4h7m@PuyqJ^GS!cz$j%B4tm6S2Z+7dQ9xlSEj6=S{|jgB4sZe9T~rUoL|!qG!H!Mq1*bvJ4xuF$c)F zd8*-`+*R^7IB)3yxKMN$`IPaZkdq35zycs!61ERa zR0NukU&jHN>y8xdf9n5r_HrkruMsXj@92|oDMQ?$UVqw^SqE5)0)<*A!AI27@E`VKUiX-0;S#P?CDPbNn}QcrJ+XL7d3T=r@r z6A;1Y%uB_T8jyFlMZ-xU!~Nj&CXy>?uO28 zhpcV}J6VVNPa!bDvxryDf7x;B|@s!eLeY%B~F?NlxDS8@~h zxica{i0?M{QzY|%wj)*Vj{h@TeQn#S z-r#=GuBP=g=Qri0@PBrly={+mY472J{pEYo9MqUGjoF##B;na?9^%Hp_@e53 z@XJJQO0@T=rAsskagwI7fY6Nr<1z$oVRiiyi@J5gvq4v=FnbsMz{?~n&^EjMwx^zN zxjn+Bgdn~&f{C6^`~&COpKh;#vEiss?RBXPb1!yq+eLH4pk?`caD!b6(Te{F(+@RU z3_ICvZz~jUno~csTD7?0?JSWW7137`6444931&yh6mF|zN8;oDm2S5thS{+Kg`yqbrRDjX&n#>sfCX}@wJn3H@^z2ueREZRM0bs zEHsGL;9rW|S}-hS{{x5@n&r}y`-Q)(CYF|av6(xa5#fGR@Uqyo;SyNkGKbH0p2jde zp32iQXaVZjMGZJaE&(y9(Q_;4P2SI4qm1wBee#B7GW+S)6IR`CRt9lO?=7a?bMX>w zqtwTD=jQsR_MA0lM|V$UV5_=)(SNxax0I6`(eONjn(iBn>2E#g;YUs$Rc);yQMUxZ z96K!B#8KtB*jUu}rSk9rQ_R6`4v@%K?ydzvi&$~Bh!m*%Ix^u2@+uwN^tw>$pxh!X z4+A?Jwh9_p>rGdKcFE7|^RISF*MQ{s`Q*DyBaWS?=!H%^`T~$D*;&=B1)hfz>OIcm zVWth^v5EO9pCkUlAy4EeeGbX>x~X;U{rh0Aey}bgz!P*7(M*O$Lln|)+!BRFn*uwj z3~ATS9s7GFK5$aQM7U;9caUCG+Ukj2-Lrlnshicy=GmKHb1oJHY&|`vN*bm^F7cc^ zWTD5Dn`|u7bi%)`0A%Kv?^(SEiJf>sn`qz3NVTP)@Ssmoq{^>^DnP9bVbgD$IJ2b z6iYb2)u=7bptcRBoLnB>Y+)97g;v(I52h34vS8Wuw?$?#nQrw{2KB6k`&|p@6Z@@% z?s(1SpvHZ_qBx=+V)7^c5suA_qd2F2rjoE|7wLVDc$JUAkI1aHq0l&ptwN#tvA|77 zJxzZ_C-818i4K;;KHn%upnM5P@hBFN_nCSjdqC;|)hBJ6d)Xv&-_d`VmXfcVGnRlV zY7FLivk0-r0^D^p5A(j>stZEC%gmA^*WS$yCcL)ywQqEkExPaZpXn1TBQ<=kr&cU* zrdZDQ-4Z3dbewQFH)_9Fj#4KmJpN_nVV~(UJ(ameA6lqfziRQ-C5BvQY|byfic;jV z<=NSj`g$a@+z0g-tTCenHtFXqW-MIUzpB4-{nd`rZB5K+H$IM|#bBnn z&u7+R7nfEMYL_W5dEfvl=-$m1-CpEr6kQz`3|AZFIE$&vZZXVCDK83v%njcHAFwMn zsnq+7p;Gc6{zusJ!!t*IPhiNvrya$JW;o!uZC_9}k6@)X%7AeSzgspE?kyfq>ZXGh9pY5;TcII=oaF1x1VKRGRN$1N-HwYJaEy(n zIIjkQA@DTbRU*s6VOL1YYSyO0hgZIrtT|{ti(4Z6gl`?TO|}Aa-`4SUe7Ekr5N|A; zesWg{h@Hd!=+|_Ha@hV%ge+&}KI6~^Cm4L|$VSH$0f;;6fzO}b)KwRJOF^PavJl*n zi2DcI&q(}!hW=wWRc72=tEokNY#KYHC{-HkZrcn3Br@xun)UR+5LdU&sD!IO0b&i; z&gEO{>Bck1S2ka3bW&4yqn9+7S0V!T;b9fx;mFRYnSiGF?31Q0gaj1{@4ac4sjS-(DUPV&?? z96_jISREUmkaS(_=<%OgKm+UJ(G5fiD^^mAZE0%7Gmd5VzcyYHh7@Y}+Uz6~#flk;DlD}7i&4!*5`Rv_yquDI}GBb>x{}#xC)y#4ERPxC-LP&(v zZ}RW=^347Q3tAXaZ@mt#1E{l_+ro_mhU7#GlL3Ap16ak(4OFzFury<{iD1PUcd@2m zkD``eh;{sD(V0F*Vln$XaH3)WOHdy*V`CRrUc5h%lyTS3vl^^+FfDE_O7h>6%(Jm( zUpQKplCaQSx-Ypd`EcT;@yxHU?n3g%zP`UMvTU0#sp22QB<1$?ikXRIQZITSGfQzM ziy|%{kvMPq-*Iug$+YO13B6`t7X4{eR|IoK2-d~{+Cy*$fN|Q4UI+HCD+~!0^O5Qd zqpDIo4<%Up*A>MA3lR_vO^XsI2?paDAP-XYbS-iLPS-hN=k<6BS_{BJXjveg>8Q$8 z^}^-e8QU1(#oqpmTB4x-&>1D$$f&+$68$~vG{4JBM&R1AxVeo)xuHU$WVZj(gEEw5 z$I$5X$B~VshqZzJ@QIK?3K{8k^0&V_foaYw(n;@o(hFVLeg=(V?IPF=rHkN^4m=z! zV!IE?`2!$4U-_OgU&w6c&wT)RUF~v9@X|&=SOLHdMzB=+2&U8hV%V~_eTkeyYL3VM zG%wud=SJcwN!p9%d;tsz_M@Ob7iM?!pf~gyLFU17KnQ{h#i*J!Ek|KJe+_)5Fjt$A zq$wvkt#om99i`0qBsW1^QsP%Uk@9KX;YFBkgavdCOSzr2=jKcM^z)lijrF1K#Q_$; zDiidLA)@10IU82`t4DCHv{JsQr_*O-!%?P$$C@a{Xd?*GODWY>lzVJq#J3G zl=>`R9>ArM#cfb4k`#&$k4~`+8v(MTq=A3KobI>}C zW8hLmHzUKqCRE4B_)`!G+0Zs*V}Z4<`Rfiz`%v7ZQ^ND`)%)DNxReb*DiwALuhz1{ zm#3Y|vFWpb`h;3dK~)V4m_-aZ}(uOQ{9Gxb!m;Vkae$ zmaUjc34%8nky2+O0u_I8C9(?>Ww_>d!#Ce<2|ZqD3FvD{Ikp^l$FsCOc+lC5{-_L7 zQq}ZG@xKRPq-T{*q`4Vu^&({n`20J*B#Nnz=$56$ZWdNl0+g?w?mO-2kuRZ%L0>!r znWOqGR&6kMi&Er`>HPUo$uj0b_=FJsfLi2pMQ@2D|c)#zWyOtytCI`z!YExs+Y@2g;srAo%b`kliV20p=MLMd8<@JR zbET6_2Da!^JP#at2qpv-u(gSZd2SM%;Y^s&&f1$V(d^2H)tZ*FjB67pki0;|ej?<< zgJ?yHESF7>79*$sCLak!0@>l4rQOrV3o<6>#osfL68a(5Ra$kt8WmdAV?Ub8Y0b$} zSvZ6g0y<*kmCi7Z85Q6W<;3|m<;O(&U2NjcXHN<;4--oHuRemLlN?I*1g_r4>ae}6 zL_yvGGRE$e4?iAKGBk8b_t_E@5~9m(LcYj(5K+b~lY-f~kZQ@TWfb-xx#5;0n(R6q zS9+rG*K!O6C1M_T(~b%9@|z)A8pe^!$zTlnfU4~kG?CqWDaO);ghY|YhaFzn>0cIi z1a7FTKs@luOM#&G9{0qFS<-rFrPp83rqZ|Je)W+O|8(BHFaQTvN6ek3r{d28S>BNK zU-3Kjw{ma}vQk+gwMq;mNQHoegl8ivMSPo=0lH;o{zHKP#tuJ8jx0&bmr#q)LA8@N z@2zD{7RxCvC&pK<#tIla?c)H+moIBWlcSbfo!G%xe5Q*R$Hf6nUN1d$?N=(?RPk6q zQOrD&&cREP6zqfjrSfKRH0m3&elg_pz!Uy9&f+41W-yeb_44#@c|i?61(p9fh6O>b})a8mN=#v5+2(+oNM?N%YpTt2dC($-4PCv?bPZi9CsF?_qrf z2i-IQ23eox-|@K%%<-@6XTvrt0UNoLVD@J~Wp*!p)mo*eK9kEyG~{|hOzdbZ?9vcJ z;q{YE2y%4MgJss+AL-#Uv&z)^B_6wmU;=badxO4*w*zak0!Gly>-dwsJytmz$+?a< z7E2#9I$^ql-jU$+-OcHG;Cp?pM`6|3Sm?&~Y{?a|H6m9z(rjx68ZGuHS6$jU3VJ;a z&>~LMDZN#Xe=QmurqA1mourk^I$n#7Nna_xim_25vY!v>{wG@EiK|N;=z`PCAMwj6imd{%$t3BH8k?C+Wna8nJgUT|e+8)EDIba>c)|Cc;lGla z9qz@{ttPEDF;HIp_{P>%coT@`#E$Mp-EPvjRbQQ%-!)7>^6&XN1fee~Yb%kZ$f~L2 zUz>@426Pf#UmxBdeO1Z>79P$)rvDUVg?u$OB6U@A#ZTai2(9*pU5gZ^=2o_kDyTb} zQVVNj@O0vhr`+D1d1}>iXPw*5e52U`#0c;$1@)WnKLu*sP8yquJkLW-C3=bAwS&G7(iwW4NdO-d$;k*kcbfrDwFOp$!I zwdq|I$yx+A$_$viE7OFzY44%Gt6xYMvQoLgI4b#Xr326!da6ayhY}A^Go;6@LgymK zx1`aa53~bV1t=Zk1r&XBK)Eb|J4EK{->pO$Yc^iC(tJ1F0xh<$S!D|5DXCys?L{C! zT(m$N+=4hY68?v|qCrAEmD%<>#?ipzF~W|VF_<^Vn@X2Mz(V`7 z`LLchB}x4#|6PHsK2*7PqCT^p9DP#oyYPm{I~!MIl9OIWYvXwh)C7TJ*|3@({!{Ne zVbkcW@OFT0#OyArzls*!?L+c$$HGv+hiUXO3{~U>wX1o*uT%;Sy{l$t1)vt2ar6X8 zlop40=-l*$ zg>u`Twp9jIuBNh1{a3>26K@moUXVW$6W6x+GwQ%nVrKO=5)N_UUhx8Wh2nqp5&2<@ zZYqgqiZYw%Go>Wfz_XYZ4~$mcW3@#pN$MBQTEa1Zbx^kj4KrKCi%O&tY0CYNBbzrB z(yIcSR8hH$%Ywll(r!KTT&z||eS%AGjdkd8qdm|U_V|Ke*-3fM4 zp#fGBE2c-+*8Db#io16e)OO%dP0@~ zF`ez##e1n?qL2MLlc-(JaVRUZp6AC-qrG9&HZq@%anybnMAF7|PHf?VZt^biQFjG` zypDL{3u<_lQ+Kv!meutvSaN%+u+50ytPFJulIy5Wcz3sn%yi{}VwgA5K+HA2`K9i< zt$UPQx~4=XPg+IY=TFzf?yqO9Z{o}O?y;=|0C+k_1TqZtCUJ!-X8D-}pPT@L60zqz zTtPWTbuA$P%aGMJ6^O}1iBZ@oQd83*9j?+PpH;YQ7{H`{Fd91B^f5YN4OcQRbmYpk zvD$qizZ(O02`TxC@^}8ER@1d3owiz46O3*tZ}epzctty^(b9(fI!VX?)C=)~zBVLQ zpU`{!EXH{9;$bP!Vy5P5zxvC*^5k1Wc3!SdRw64dxM3q7;aDL>hDj;ZQqYoN#DW43 zev^FMx%9rWkdQH}3D3L($8+9!eR#!?GmitRsToN|nB&XO0A7MuUet6neF@F=#M4fa z6}sCTb&sZ&kFkf{Z!vG8UAyF^>``<8e%ERgf0Vl82A~L+NJwV5(?=uf#Hv?00;JR^ z2)R!?*+xYP#%FvY=E&Z)c%kE$oH0OGR1>Y3(3GWX(q7{yJGzOvDA)uAmDU7cwvgaS z7gO_#h33V7$BShd%`ylphbfI!2BDjF6%jPS>>3S zYM#b`9$kMYR=TpPXZ^K}ndxPPB`6)$F-bQh&~prtT8=Kw5Ne@V2^@I#*&FBfDcJn8 z@qGB)O^YM3EUOPpMOnq)ImL9gKv8G9NrBTUVgXjXwg=>#;ft;eP<39Vi}qQ_m_rzz z7b$8Ah>T2(y#Aa?G+YIUlQM59=?!!=f)NPH)ZTM4zDf?z!@~2RuM5TT)F{FWLjDUI zs(+<<5kiDx;be^d_j-^F0LOTvP5K0!po|C4zf+ra11gJCQsrZWO75p=8S{a|??V^U zRmA{?1j4Fx)9qQk)umA{S`>WC0fPaO$EnZFD?|~BRwdVU_g9)fy~&J`y^p0{Fl_!K zV(SaaKeNeles{zLfL`Zf7w^>ERHUa*gics&!x*|*kxtR8^oe*oaed?Q-@cRXHI#X5 ztV=spLOfyLiIiYGJC)(xWlSM9^Pu4XlBZ&?C)uf-h2wv_5Z!UapwzMz4B(qHn$;Lg zq&_6bP#3S(Sc5)bzAW9`%2}jz?cJFGoJEc_Y;)!gXMw(v-gBzf3#S<}J@OQ7qedIo zn24@M0pTdnx41u1{i@c#A}+xwAR+u}iHx@ML0>WqcJ@1gs1{uQ0Jd^NjlYj0ka71J;6tO9-fde&K^ zwsCKT1c-eVf^65XuXxofn3_cY!S652&7Jc#?d4=XYz9WgA)$$z3f9&e8<~5*(ZhxI z)Msl-R9Gz_p4ios2GNE%URD8scj+CUu-)fgbRQ`56M!I*$gm3ks1FqHu^ID@YHezJ zYDJFq;Le}bZLtu%Z%SLA@D7pnS|VAVoQq|KyVYgS-8P~Cjrx}AwUEfj@+H@L5N)Q< z%mHAEw2-^k20NKRePqS3E9Lr8Sn_gd2MwOp$CbCZTNIu6dvFK>7OvbW1L1JhV^x!1D{nB-LRE54#f}+Wn>aG1Ry1iFxWKGQ&AkoU{iy2H*Ya|4xue;} zMxwhd<{JCq=Kh3mtb(R$6{o$*>bg+B!HlZ4u8~NQq^Iy$6b;#dkpDNg5swxpe0Nx% z?N_jDL8wf)S%-%WZHlAE1yGY1;yvndU5=)}Y_L?8lmkuGHu`fE%APyIGN? zeFu{t2}esgB7ozh`$`RXmjNLx37Cqoa$Xz;V|u){*&(8djik(E*5Q{LZa$@%FdF($ zJtCF)4g;pW4M+p~oy$u37dkn7CK+*HyG6)m=N#t7NB0d z%DewEg=}I6>F}w)Xwz!aCyPWB;bKI$i#katbir7>h}AQ%Qf1~%*MFd z02M_s46I;oD)((U8|hrR=N{n&4(EOJ=XtE>p;W1cg7W%qN|xkLB;gx{B>tIFPHpe* zS>2^eC>rv=L7I3ypE5$+vKz`k3H5&K3IjC_(}GQVL-LgVFN0sCJQSHr?{6LcG)HEe zJ>!J7e|UfNo4@1c)VYkYkheG9 z=TmKCL&Blec4atw(p}0viAec*EoFD;vp7ETe^Zb&$z5A*T7za|FEyNuX~t};Eo$vt z*srX1CpHpUT}hsZi-E17FJy@NNS-m{55^&Wmf0UJ<{`~yO0h^C56|Az?@ zbkH;9zZ@n(m(86dL8rIR*BGn0F$(dT$y=#(Sk+DZBlPemMX#Zx4-4t)`)nE|wWyK> z!+!|}d83Am^R6B1?$eizo?dp@@teS9Yc{JNJHvOcE-*W&4`ezvUax$ zix5i+4N?|!9rJO_o?BDit(y4$y#^27s6%7Wd5GJ1*XmA!?4lzzs_V}4qplRkjx&tj zt}tlgd#kH`q7{3W@q}ZIFW1W*Dlz1932J>Env$tBrXtE`IIaIC+vC+DnFT=;P7O4> z44PRoJ$emo%}uAjy#A>0#Q6DsgmdU|d1HF=(;*-vSCoisC#_5TrtCC5Z`(M^hSsxd z0IWWG|JC3ldmEX2(sM6L>@+G+KDW;Jf_xru`(QE4=%T(6%rgdmMoIq4Xu0#`SbdC7 zu#B|32f?t65#{Zms(~DZf9^?5vnG*diu*6+;arqH22PB1cukeQ0c1?Ig7`DNUJWzl zYwLL4$?W%rrMJ6oV@v96SYiwAgNu;H7v$<1*)Ax82c;>3(JW*j7B-B9%8SWzLZ&~l zgY0f~>z2r))5Vn`()XoQ_9DhAgw-$B>P1+V=Ce=>jT%+4k4@AsQDQI^r~hH&ic2B# z@cXgH8#=3&Yesih#?rz{1I)~F*VdcLfTbqToN?L;q^SE=3Ky0~B8Z(nWxL%)$9$_$ z=!!u*=SJsFX)FNFnNj^Top9Klsr~9LfN(Q{OcID^WA2T-pZ1r0XjsE6qJdCD+v_n* zq$MVLuvYmmZO+ATFp{~boWg2?z<(pv3hAI3x@=EDAWQo)kcu(G8)O4KY$_m$zuDNx zU9Id*w);LoZLJjo6g+e0uokq|$*s=IqWSD*dfC%^6JF?nBL6+Mu?$#CW_1l7Tm5t&ns8%H-|X9>>!*BL5=y?3EzuMEj?4C z&cn({y_ASu*cFU*pN3g2L~F-?hv9|^jCds87^9dvfGnwgA%N%?ab=}+f${s`?07LJ zTXBONPRLkZf$d=DGnyFS;pn0a!E?s1arX`t4{v=T_RFhYGW&Sl!1cCRFqb4h?(cb& zg_Y;NL=Ct83Ke`OuxS*3ZM2X4LGx_6C;$EHs@Xu`VHM-=L@KJjuBHl4m8Y?SsHXK$ z)}FXUAvHJ;4EEMC*?n1A^!=y{S`>ZYMeWw~V;dKT1i>g48uS!DdY&7rJus{~m0JCy zsv0>EV)dR#11V!BETq;yfA8IAhRN9Snd#eMZZPLGr9USnhZf{`@67x&5ubJ+SuK(M za)lAey9E`d@JItuaj>W2mslt~-Dng(^tc$+FQ7N~d|Y=0Sp5**xgJg$Ib*cRZ-{mq zP6>b4;DV3KdSlsYh=l}lP;>qU>J!P$n|%gM6@_}&y-$CRA+GxDVpO4{KG9W;O(AIj zwv8pW8K`#${XpG-c(IKOeuhQ9)q7t2qA@KI(Qc$hHStZ;&3Z6uOWk_iKSmmVAC%rK z(SD`^+D>Ww#)%!_z#Qdld?6)k)!Ai91K(wJO0U{r9q}mp3G=2Pb-%ra{l*`9oH(z}A>iWGN5{nm$ zhfUtYz^4MY!50nl?KuR3AUdk#n!+q>K>O(K%w77&*8>uoBNG7ExXG)HHZ;N-_uk8x z|ExeZm(@IduO1}p`un1OYw|zb3WSn)Gql)E36@_UJclUzH~>xiz2jQ>gNpk4@#fvR z?2}@Yc5=8|_A&w0^Yr0}pEP9#TiF)`Ml26cEdL~8oc0TvRtU0ipgvLuoH3GFc#$F>g>EYNYaFSrHsQrZf3c5KCR9{Dgo25B?VKv(}bPi3>BE&R^XGt zp;=pIJm#>@D!T@vJ+fVV4mL~J+R=;R0cQF)_ER_ijLb1}-b)OgxqF~Cv*`zcXWY@4 zO(oM?E~qPhx-sGU)6OLqua)avu<`hFJm|G$zc!BBDtE-_=^r746W~@bt>^bnl=QP$ z*jOY#C1H?hI1_W8Nt?BCEdZ{kfQ>94&*U60-mZ1<%oawhuBYAGIfHw6#eQFyUZ1cp@ z;T>sYi9Pw7Y@#i_76&j;?%Xw;(~09IRnWpGq6KqU?(zX@Bc&pfmUMZ{+7wI6x(sbO z8^;sR<|Mcc=taU_#bGPwX%t1LW%z?9H6IA`_NErc8le>m zy(3regzZwvm^1}RWY1p@^lOMjpcsq?vMaHG-NG3zmt39 z_H@?mDFAp&kcOx`;}V^A5Le3$3SUoLI2!J1?010bZEp1>6KUFb+TztvP8UMR=I8$e zYx4|a!Dq3d+kHQV?WXx$bM?F^$krkC!w+|iu0Gz3g(+1^SUCPfcLlOrUN1sayph1@ zHvH#F3JIyCi@UDY$=6~6uGyB)YLp)j1*=saN1Qv)>h@KH|DZ5s=c7`fJSZgrhjgZ} zT(`;t$YLaRpUTJi?sg1KmSN-gzsD1}0Uu=h-S#WWahW`Tr=-R4Hx}*u=}Y?1P!m=0 zXk20n_W$O6b6oazJ6%P=tl%(OesUC}zWXo4lW>B9O{-P~! zB(Z3SyeP1nfpNajGt*d8rVQ&sr{=n6Kj}#OA^?>1!C_|fU5Qmb&JeCVjod8^J{7NS zFlD0ezp!E@nd)T9d3=jb&_z2mq6^GS9DI(?(Bzms2`0Tc#zd`eqLY?tApqIGNR$E7!%P- z=Er2EQeSB%_UF%zNS*s=qf`cEKs#juHQZ;AbzmlHzc8p$4l)(rCjkqSr3f8`kOTHlGZ+y$+FUC(@Bz2A_O^?n+sIC#<7sNrT zd6Y(1zw~ROSHO*T@5Qi2ptcq0<1W9H{P&n|gECr!Hcw2qdGx-ecO8#0VIpTz8)g{2 zd4&Z9vJJL+vcg-NiaRHl#I8J!+~&fvDoVk@-p9fJVyz$T_7GRX;&24Knt8I#-;cg0 zJ364palZWJ7m;7^O^cx6kit3i2`3YeRyVkKsCCaUwKuYRco4OfLmU?TiqYx!yECFL zJ2fs20J^KYGM}W;fk71`OUw73oXv#8)YNJ>!re~$cr$XzG0}^628@^%ZyoK8y^y&Y z-kLUwr@1?(r-^>#DKhY6W#nCG4|$A$fbizqa9-KKp4T8NvyQfO}T+gdk*hj|`!SBZ&AR;Y9ziV7KtQyiG(1?ZLS?dPw5(Y=z0i?qUQh6uyS+ zrLe9tun1KiRc!E$%}@6IZ&eW;R?@FxTyE|SJsbH@{P3RbUR4XXNKyJ>Qhq{uLmw6h z&IYpUGYvn`##%fmnG+j)Qp1^QlREwlsGee@X-jaYPh^f%pX+>BI$G>4zjXPt)}MvQ&p!n8Rs) zUE!^fbg!mHc4uD_pB1=_ACua+UfDjYXk3S9OGZucK~r}R!q@j+4iVr==5$C1AAHu< zy};8j7WKQaEcn{kCtzG)R+az!+XMbL!khf_6x}rj1}d!BR1XLKIR~;Qh)9pwe&1hX ztnK)zf(Jy{h@OedOHP!*Ppj0HrEp%-D2jY6TX9?K@aFJP?NLTX91{F#5Rya>;y5Rv zwDXF5cq8k(p%ZTjXyjFD6}k5!UKhSr%+DBT9JxpD#PD8r`0yG+GG}+(t$IBB?fE#W_9X zVtHYDay9I?=-rGuW&SkpN^JK0&BgM5pKWEqzD5c`S00}{!ec})A7&vk8mwP=_v=`Q zl$_G-*q;$bxi4G`OS2+Yhf#LxEhZK8?6OAPIVt+lGBY@ zOG}o_rVFXy{X#exK^8|)`SqNdQc}9joIhTY(rkd$D_C-`)^qK66(<}?&z@%-QpHe9 zY3kCxf&@2hqnpPokfvX@X#DbmdY1G=x^k@t#r9QQ+ zN~BPZw6n*owLnl#wYKwm1NYGm0v#T>aWs`%u%xi*oCs%6mj9lyax1CIVGSegR&53B z#!wKp0E-!aJDT9=@US;^8%vd7nm@db<5hpNhsl@Nl zsm+;s=ayUFJr9;hHG-QqM9J%rSyD-aBHq`1A-*Lu<_j{p(EXx_JRwUp{o+YqZDW@_ z61ADtn?yvlI&rld&Te09G?7bkmQKT!5=fA3F0 z^F|y`nzAdnNjd*+!|614f=;Cr7PtXh8wm9a(+s*)q0oRf*jM9;&A~FR%N0)ayHg3x zR*arn=ylPD`TIjAnw~7t^9S9)wH)USFTNjseC5~AzEGgRo$90WGx=_(dRO?px9osL z9b0^p)l$;Nl|6KMM($fylrg>~NLA>S*zRtr&E@c@2!K0Nii4fzW{zmMmCh*UF_f^! zyznNz-KtNddkb+T(xN6+=fjH~Y|JZ2k|e%8x+-WcTY9)Hd`BHSG6_D~X^>`cIn&DP zYP|XfarxKwD@yi%K{+K#{Y*|y+p@W#_4aRkiwt@5$ZpC}Hf#V>rMI;*qvoQyu_j^Y z=q*hQbwTD2os#CcRBx~rvD9AHvCU(`jDm)0_NAI&FA-%Suah22s->UEqCXYr#@Cmt6%XSaoFR4;6=Nx>scDJ8r&FUbtPS|Ub9Xa3_DSBY58uO|oMw2@8|m}VS5=*F{ko8A~w&rA?j>g^)9zhaFn!zFxp;fy+3 z_7wDC;zEs~xTdqjf>!SZ-KtX>YnE z(@X3KsZpJ`GwVN7=B=F|9-V*t_F=$M<3U+Zpv3{et`2#TTYSCf`aERqEr#yT3wb+A==Sx!%?Fuxh12LklKGmB88MI~_ys z%{)Sw3D-e;Ui-JK+;j|X)2-!IfXc-tW-DFi>wkm>8MH&6VBC7%w2xMW3zo5o(yXn& z$7tLZFyOFoc)Jju@i830hBZQ4z8EKmU3hr@f+xlxK@3vd0GIC#_3HMMjmjRc9Y9hh zBSRkHadY=Ek?6?+8SV*&Hyt_eHCWM#O>;s+-Zp_uF8A%jUE!-%k0a*N*SdpAwQJ|A zPA`EYQCb?;O=Z@Q2s?j`{-U3uKXMuOsVbtmuv+AYSILSP+rDKVaUpuyACA7;#nq6m zF_ZV1@ni#m{{6-!P03VPe&X=>B@F9$*7jm@XuLGJMyAI?z99-E+`W$Kss!JUWp@MG z#tkzh7e_y`EKB}5Xe)-?KBaX~5|FtN#cXF#68U7{M?R{-C^ z1&$#<+>=-4CAq>N}n^|3$}e8 zvJBI{FCNFG?^7>-rt~kV!QG#GpebRP|1-i@IO$o6^bST^LbKbn)t!D~Nm54s{=nw2 z%i4xnpH9B{;((#{7w*Loz*Z;ixB}spXTx50E~o-i^YS0x+e7C7!D4_ukht^_dz|); ziS+H*x&of0rJ>!U`3asEAOL>AfgXU7?NH{ZLEFafy7ey%A-4m8K$;LZz$j3TUqOO&IaxnwWE)b4nECfk9->mDMw=ER4Abhh3|=Twp( zn$%&dJ(_?4nQtzL-Bw_MM{8;*_}kg-N~H5FOFJ||$TKIReyu7}lvh-hP+(;yqr0`S zY?zL9ZD#Ifw3XrsqQSS&vSTqDfn4WaXe#%VRa=}gYoW6J%J zVe-z)sejCeY=D&e%r$?{6SF7=EHqlDWU^s=Z1iQ=Cytp|JdD6o@K7jw3~zexbo9$% zD@@hGoNSp#gk=!Y+e0E<>vjCoF5MT|Ct*7;*nJsSTvo4FpW@p%D zEFgpk_(aff0yzKdf5^YG&3m(GvfJ;jiiZ+BDss;F&=U6{r9js|C{{KWPe^DC_E$o~ zel$iZHajrJCgOfJ<8#Ua&Y3qPWn2y{P%bRJY(M{J)7S^m|7CPo5e+!)SGXoK8PY}e z(S7`3PIB-4`}B{yt`BORbH3gj=Y2bL`+=(;_{ZIvW%p`J3-2bh;m=%Au5v}wK^+%8 z4#3FQFyN_AKDQu<^GO1x3y=uioX_I#m8yjR8ptcWFq_R`mpw-kQyToR4nSXv+o7f- zmbKln$3!3#a2+m|7triwKO|P~Y^iCg(h&jw+Sw~xBi>Rv? z>I-w{BXJKjb#m9at~l;rKb8ID$FrWO;eHU0cp^zx_UprX{n`h9@JCxsClhs#8J_ux z8(;}32TPe^6Xw9CB5<1?Iv!vLaAww&=+{5FlCMS&mLUFkc&XJn=Xv7XW*_8xb(UpC z8H+6-Fw(a9W~8UG=;DBw_At+TwO{ z0K|DVTXm~%u+j_q*19jKNcw@}vVK=`l#ld(9SBoCv-Zo&SJPI8$X7#6@0VOVjlbWH z{Ba$tqCS<1ZUL6E=@_ZR1t8Vkd^=H)QV6j2? zx`{<61Lz53M2tzK7=c{peRj%1(75vpwS{rd<$1|+J*6N2Vb)3?`w z6FYp{}f$m0af5v;LE0d*`m*LHxlSwjg^k34L8sbiK;{`*Ev@?}Ho( zs$!66(t)E_HHUD9TFQ19dc)MDi>-_BsHp8?OMC8li^;i^gwFp~i$K}&Tp<(!xMuwc zuA)J)%77iHfHtfThbA07S>x^}@(KQOW2ZYWrQ4RWXG|L=i>^y2s{XK(K8ODv%*2TE zA?T`aP)l96PZ~%zrDwIOy{OD&xgn5n((4gdpr9xMp5mplDzE{e%xRfg`3 zf8+Pi#r5juEUOcnGrj0>eonJ@&eI%pu3ZCrzkRjMLx{m)VD=C_E-O|j!i$B7AeWXr zL0di76g#8|1)Jg6>RVX-twWQCq&<0mM?;9kk=RJ7TiT0= z_$Yh1^6^Uqzp=Ux<rz=566<6zjieNfstQM4i3a9n$} zj&^45&gXhXQ9DvY%&>T}15%r7-2rE{sjAbD(%TglLO603>9r`|1XcBQ>1*CGcvS^j z%&5;`?22=zc7;l8n`~Dy8L1`{f#UQ>S|2jG*T_lxXN70$YgK~}L%t?NBEC~$_}_|i zvtlR_7{mag*7%;?ppl>)VxQR1x-|}zC{2>e{{j`q7MJhPZhQQ@+k}dBMk&}Xd*%}2 z{f#@@Y}YRx7Rev4Wi(lXl=ddmSJW;D;}gN+egy*-@S};!QgxH{UkSahifTSvw}L<+ zocqlmLFWWdKmp2d=ziA&%?0|X2B?LgFx!NgU-D(g$d&;MRO^r5byyoIb<0U}TLFso z2#BU;9F6TiQ1|*#s^KU{@Nr5CvG&4v;Q(tX-Pl`eh@|G7|M9_IhHcY^ENxYD)7#!A zkW2Dr5mgO3_W+^mLDHm{2N@$U8{*jGc9ojPU$#Ws8# z9>T=x+WNG_qdhP8)dl5ypZpEe+O@xsJm&PSPv1MyXc1gySs-)GG+`ZWfq~%~dd3Pb z1Sy|@yyVwYm_oApL10D12l`f?G0r8AXMQ3jY323fBiW*Zb#6hf#KgSoWp-YnQh@SY z97+$2v~SXiY+krilMVx6;492p*%0^N>U<`h&nkpE0)wuJJ|60I{XX?MFLNlF9CyTJ z93@4UtzzRzm~a}vhmyJaGyYCOm!0b?IOJblNE02uKOaJ9VGx_JbKLpMH&8 zI7Kkayp9YjeAk3^ag=gWl$R_7C_n8fmnj#{@NIXtPOi14fvV68PDk0Q+AZ#!vRT9^ z5UPrOqkbU$fgtPcfUDZ0)h0VS>N({VDsajLodtla03gjJw*%y$QIUx(F|kHu^0zK^ zsSQKZu@mgFRM_bEm$PaV9@0+=51Qm~P(b4|^D89+?Mkf>!dI{XWxYFg%OXC$qeVI8 z?s+^WVI7$@E&Fv*7kj%l!0BodbvWEGa!oOlH3s&Z!B!Ww6mhSuM9O3ldt8oG-P2nF zME;=#$QEEfa@vkZvTyi~pN^yp0l5QrKIyEvq(d9*q6*DCvUgA{F(CUgq28)BW^x`{kG;(tE=D+8iI>BE(Ysf5+bwjV~U!c zBk6Oi{?y&~?+YIqgLBWU-T7jDa5%8TUX9w6F~iwZ<$uZ&iS2HE{A_5np3>4v^t{i5 z7J$SyWL}_xpd9pF&)-i((wemJpItgKG1)=ghSeyvOU`V!_vCi!B)dRP;DhzAP}j!{h(b!w}H+JlRZ`8mB&&QKFVtMo4?&~(iv2JaK}VXh`lUwrH%or zg#E|AMVu!_slZMfa>{mb0td74f(vn4H*)mF<6BSA?=}K6hu^_E?PH{YgLRyJmJlk<7jEv-rB^6>jH%PL4jF8wvyI!L0wIO`FGTrXYOJDit8nHEuCsa z66+QKT3QfA|M*oNuBS7N#Mgsm28t)vYDN9I0Qb<2^ALpDIDAkFThV;M%L=$a6$iIn ze$)j%77#6Aoz2Zvxz$^%gP#DI8n3Q(HeVhq$HXx^Ua*ruK-dC`w`ldGL;bwR@+cHc z_au`O323rYc+HmqXVtt0lqx^Jf-7gmI7L5RwCCi{X8&toC=OGIi@$)wf*R;~yeX%i z8*Cej2ULQQAS@Sh>!6wr=hyX}mxBoWjk!NAYDKGw`*8wi64~&6wL>xk8UQ=o-*sPJ7lo zQIt{7lL{8_dA)|aw$1qSni@`@Qk{i<8~eAvKZpWG#!&Y8P!_}hP_tDVngP|G_k|90 zglcw($oYAIlqweMY&4J!(`QPoiaL{!4eKQ-6uowN*l!6U7anzD`cv ztEi;Rkf%}D%2If0UVD`E)qp*jJ>_>DZ^qnJe@s(Qr||&!_kR^hbaqCqJ@R!b8Fs^PzC+ zDGHq3A;_H*=5yDZ{=l$SG3c6hZa#_Y$@=w4b%oU=BgNySw8Rdu!%&&K$+9JzR8xEl2_}M4+|KAwNp(P_9q2GPJ`& zpWFAX$e+XkY7HiWQ6SyW%*`+TRqq>TVKGa6?k-L)j-Vs~GDB=tV|jvBNpKx+{|B~lh^sRz54g+xr5e&B= zzrrZcD#xf>PS6fncoXH#-I>%g1WJB@M>Y0B?fOPJT0%Pw)_gLXIskxrrD~GC!%qr5 z*6>O(X}>$Y-Qlc1>4&!U*jD!@#_3rAOp{-lrL8PX=G-u6lnvIUzuVUF7WA~fPM9{t z$-=$-_9l`6lb1PC+0M~LuxR6i9!u@vB1(yYY|87w1g4Pn)Z53NwUlPAWy$%bAl|9# zYW=iswUCJt%MazBGXb^iw($m~wo;I^(4jPa z>km7B@_S4RZ%-l@53#>+@s$n+NRyW+JWise{?n2T>r? zjVdU_kH27qY%;KDSv_9cg>R!ebVGXd8gxeVLGpB;Qf2^}2oP-|guQb1#?Lr;Tm3OJ zl4GT8H|z5O8Xn z+^~cKicN zmo5(;iY&MjOi_9J{+d&h+zf~@!;9^Cxx4zw1u_{;T9L?o9V``u=vBo_*dL{r( z$tfH>&%O<{K*WG+J_tl+yke$S*6N!r$M^m+ z=s`kOab%Cglcjg*FZ-G>enO=UGtldJ80gs#6bC_yw|U_LDqP_^u9jYEkia3HDsg4= z=~o^Y!4k=yXA|+lpaHZpe+JaNZ`85vYg(Y;-Vsqni!=Ac1BsOF5eRv42HK6Mgj0r_P>wXUJbaImRPUqI4vz6*|~+RSyCV zQ^h8fvzPOSH)QX6JGZz-l#T&3>#BHaf4zCZcC_OM05PycyekFJkAa*$^2uG*YiH)z z;{q>2=E0kDtw$ST=>MEiQ`3Q^EZ?uW4DQAOprfjG^X8&JUP^LMT2rUL%YvO*wQ2PF zcBDT21e{7)t4n=d$iz7o)o-plIU&v|9O1kx5{!?3ZS{#?RvS#I;2Fd#^@JCwspN^4p*_YhQ`S! zo$mMlOl}a=($KWY&&Vv~;Gbh5d-D0k*?qANY8+aJMR`?AdQpYgZ%7NtBec7FTCkyC z!+1+??W?1{kq(gJ>%?#N^46{~u-slg{ULPmG)|V&QAUpZ+b%uU&<=&q#6U7XZ>?MK z%0+f8=V02gaH#Vv(;UFS-Gzf0!69YjgSo521F+m&lV%!^Q^HC~O9Rq0j#<@{v(orT z&em-DBN+l5Il0!*L{#8VU+}>wik~8Ma`ms`!g>a%#sWa8akMuCZ5WH;e4sAk>mn^b(ht3SSSuI5Mz%#p$ru2QfkqdMDlP->s!t@M^U zO5#5Xy7&uxmhF#}@2}3~3OC+b$W@q#eymahc=LR{u*dVuTZR{wJ%NAv2sQ8@AynXk z2>YT5n)7S;_}O<57gV8MX1;op)9cyHiMJcy^6_RC&TTh0HsHN#ewR6Y_I1$G!jH!z zc^wRNX1`OPbs+(?KX)E3cIMnUE9|d4s;a9BuVPSWc`?8s4O|k@z4zeVvV9Vv%WAXh zWa9fsw!IVG$g4(?-nA3t3JTFk4VuTdhW*&s(3sZlb&b-d%9n3HbF zZTMX{iZpC3fdJ=U8vp?-IH>gR-7(bKUK2GdPHBYU>o&z$=dH6&ICokOA-J}g(c$6Y z7=<23vXB4<68Gt5eUsge(!1CoUymPpT*+E9$zkZP9rM{CLSQIGzItY6%7Wt&B`QF^ zeoX5p`?l+Q&pz=<1B41Xs5(rESE^&cQk>@Ss!9ctpNB0^>EJi3vvHI&`{BHci5})d zB1Q5J3xgE>p`pP+2q_xJH{?A>8q?5g3E9ffqCVvpvX-h|8bwjr3pkkwe!G${zH>AtJCNv~20f-OI~l zJvyGmX5Us&jdl{BQrNyVlltA>UaXgvq5M~`0~GU@c{4dZg#IYCCH9UQ(wg=oWzEe^ zoz#e8iOYtJl&E-avO9J z@7%qd(>bLp_ls}Tz=xTJA-wmi!(Ma=X*ZU~-AsUd14KdWaa)AwBifUN$8ITF+_a1c z&>3BdaEq6bu1Tpusrw5Ba_LvtV6ceo6M!aqph@_ttx#i6We@v{CeGoNmYPW{`wIWz zes5zhZPmB;)|Q%rBq_1k%c0KoLiM1y05&xAdtg5!*4O3L3aIbeqcBQ+rh?|JY;T}8 ziRrv+8KFs{<1MHGbj${faxmh$2t2>7an32MS6Nf$t`H>6jXdGQf_HJq9TfeqV&oyd zSKpR=04MOghZxQ$pnD|o;0XxmfPL<;h?(1p2D{zV=Ix>I95@6q%W$(0zvPtwLbnB6 zHC;TdLuq4x>FKFkX+mYfX^2B?W1&$My#t-ORYzNvKr3Bcn9*HXbK^G}h!0=srZD4x zR}C?FNKR-`FZ!9fmUiM{i(Ck7VSae5s8&fYne?f@L58uGm1Y|MhQ4y3g6(S!f%X1C ze0wG)PLE4m9R|edKpZy&tgfe!I8kPrIoHLmjBnALw!Sk(V2ZDby*68K>=ttj1S%3J zp_J`FZy2xQvAX5c&3!9Rp7yzV`bpqtS$+12k{oU3a3{>qt(Dnz$H@P9D2Gv>XcLfXMJY&xxD|) z_k7=)^{)3_>s@R8e$V&iN5Z8Pxgm6kv))bzhevs&JGu`9eR@&)oJl#uq4b<@l!5=0 zs^gjgC(4K#51|awrs3baO<6Z=H>98&tzzyl-K+7Jr?bWA(kt1Hi>Poat8(%F^tL~O z6kvZyIQTMZj>ry*+D^Kd5-z(=`mhDZ4?#&W6<@I?kQD|IRxviMEbMk|pvz7N}BfTk-VjZ4D!Ff~FaiFi=Kfp$Z{orC1-$;i_~gp88!2P%T<@NvDJ-ZSk*PLCV&#=s%u(gRQy22goi-u`3=m=SY=TpvWR z#UXM}p{79xexI03{QG=whl-Wu{>|wxdVoHSLEQQ_wTVTG_OAMM+D*&K!WSrALCY5* z;_8nA0+@*KUZ)$9{!dJ@<&npIhMitB>7{kYSE)w_mhuQ`y@eEyyO2TGtWEh|W>6E>&_)21Z5@sQ zsUu?G2+(490RH?e2@=3O*M9!St@NUSGB{OpZ*IBj4LuW+rVYZxwy51(>pUXPc=*HO zRDeZsWj!`p!PJyD)94OIU#^O> zljVliyXD%tOVI%#uF#F7AP#MNOUy#~s*XLWCldvdDRL=ou#JPls7GdN;aSN>qO*Ny zv7}xX{Lz`1$w++J)-2XlW7gS9(+M~V$${mTuOzRG1!NNfYr-Kx$^@G6Nh(DX&$A5h-nxqXM&^U^r+n{dMEH(7DM6iVs z!ha3W@?w~@|Juz-;iCwdeNzZ|Bn-k+(E!^}78MA#@a{b=3N0ItMU*%aD-PQ zfi=2J6JsOj?emIpLQ^2P(v>ZfLyG7E&fMnAZ^MHN0$d` zq(C0hp$muX9DmIXKsp=e7I{B8p{00|9U8Ua9z}rtuaZ@hD5x zemNN--pbxx%nH60W~!`JD3D8JjUH11J+x6h9H$0+Y|Z)GO? zI@H~IHt_%(izUq5-}GD8QKvoKyQ4gyiuY>x^hO+Fv=!}KAx^y|ra{(}B{zR_qB!0w zFz}er8qGPi^*>wT=*HEuqBGYshuvg_R+ Date: Fri, 3 Oct 2025 11:51:19 +0300 Subject: [PATCH 8/8] saving bug fix --- src/l1/core/int_primitives.h | 1 + src/l1/core/uint_segments.h | 29 ++++ src/l1/core/util.h | 1 - src/l1_5/anne/l1_5_templ_very_base.h | 18 ++- .../codegen/all_set_map_templ_util_inst.h | 12 +- .../codegen/rb_tree_set_map_template_inst.h | 126 ++++++++++++++++-- src/l1_5/core/rb_tree_node.h | 4 +- 7 files changed, 175 insertions(+), 16 deletions(-) create mode 100644 src/l1/core/uint_segments.h diff --git a/src/l1/core/int_primitives.h b/src/l1/core/int_primitives.h index 03f48cf..fe7a667 100644 --- a/src/l1/core/int_primitives.h +++ b/src/l1/core/int_primitives.h @@ -3,6 +3,7 @@ #include #include +#include typedef uint8_t U8; typedef uint16_t U16; diff --git a/src/l1/core/uint_segments.h b/src/l1/core/uint_segments.h new file mode 100644 index 0000000..8e57260 --- /dev/null +++ b/src/l1/core/uint_segments.h @@ -0,0 +1,29 @@ +#ifndef prototype1_src_l1_core_uint_segments_h +#define prototype1_src_l1_core_uint_segments_h + +#include "int_primitives.h" + +typedef struct { + U64 start; + U64 len; +} U64Segment; + +bool U64Segment_equal_U64Segment(const U64Segment* A, const U64Segment* B){ + return A->start == B->start && A->len == B->len; +} + +bool U64Segment_equal_by_start(const U64Segment* A, const U64Segment* B){ + return A->start == B->start; +} + +bool U64Segment_less_by_start(const U64Segment* A, const U64Segment* B){ + return A->start < B->start; +} + +bool U64Segment_less_by_len_and_start(const U64Segment* A, const U64Segment* B){ + if (A->len == B->len) + return A->start < B->start; + return A->len < B->len; +} + +#endif \ No newline at end of file diff --git a/src/l1/core/util.h b/src/l1/core/util.h index dfe2826..5011224 100644 --- a/src/l1/core/util.h +++ b/src/l1/core/util.h @@ -2,7 +2,6 @@ #define PROTOTYPE1_SRC_CORE_UTIL_H #include -#include #include #include #include diff --git a/src/l1_5/anne/l1_5_templ_very_base.h b/src/l1_5/anne/l1_5_templ_very_base.h index 479b283..9501ce9 100644 --- a/src/l1_5/anne/l1_5_templ_very_base.h +++ b/src/l1_5/anne/l1_5_templ_very_base.h @@ -4,14 +4,28 @@ #include "../codegen/rb_tree_set_map_template_inst.h" void generate_l1_5_template_instantiation_for_base_types(){ - SpanU8 l = cstr("l1_5"); - SpanU8 ns = cstr(""); + SpanU8 l = cstr("l1_5"), ns = cstr(""); SpanU8 dep = cstr( "#include \"../l1/VecAndSpan_int_primitives.h\"" ); // todo: split VecAndSpan_int_primitives into multiple files (one file per integer type) generate_rb_tree_Set_templ_inst_guarded_header(l, ns, dep, (set_instantiation_op){.T = cstr("U64"), .t_integer = true}); generate_rb_tree_Set_templ_inst_guarded_header(l, ns, dep, (set_instantiation_op){.T = cstr("S64"), .t_integer = true}); + generate_rb_tree_Set_templ_inst_guarded_header(l, ns, cstr("#include \"../../src/l1/core/uint_segments.h\""), + (set_instantiation_op){ + .T = cstr("U64Segment"), + .t_primitive = true, + .alternative_equal = cstr("U64Segment_equal_by_start"), + .alternative_less = cstr("U64Segment_less_by_start"), + .alternative_comp_set_name_embed = cstr("Start") + }); + generate_rb_tree_Set_templ_inst_guarded_header(l, ns, cstr("#include \"../../src/l1/core/uint_segments.h\""), + (set_instantiation_op){ + .T = cstr("U64Segment"), + .t_primitive = true, + .alternative_less = cstr("U64Segment_less_by_len_and_start"), + .alternative_comp_set_name_embed = cstr("LenAndStart") + }); } #endif diff --git a/src/l1_5/codegen/all_set_map_templ_util_inst.h b/src/l1_5/codegen/all_set_map_templ_util_inst.h index 1c0cd06..8d34226 100644 --- a/src/l1_5/codegen/all_set_map_templ_util_inst.h +++ b/src/l1_5/codegen/all_set_map_templ_util_inst.h @@ -3,8 +3,6 @@ #include "../../l1/codegen/util_template_inst.h" -// todo: continue from here - /* We assume that T is trivially movable */ typedef struct { SpanU8 T; @@ -12,10 +10,20 @@ typedef struct { bool t_integer; bool t_primitive; bool t_clonable; + SpanU8 alternative_equal; + SpanU8 alternative_less; + SpanU8 alternative_comp_set_name_embed; } set_instantiation_op; void set_instantiation_op_fix(set_instantiation_op* self){ assert(self->T.len > 0); + assert(!self->t_integer || self->alternative_equal.len == 0); + assert(!self->t_integer || self->alternative_less.len == 0); + assert((self->alternative_less.len == 0 && self->alternative_equal.len + && self->alternative_comp_set_name_embed.len + )||( + self->alternative_comp_set_name_embed.len != 0 && + (self->alternative_less.len != 0 || self->alternative_equal.len != 0))); if (self->t_ptr) self->t_integer = true; if (self->t_integer) diff --git a/src/l1_5/codegen/rb_tree_set_map_template_inst.h b/src/l1_5/codegen/rb_tree_set_map_template_inst.h index cd26652..17f7c23 100644 --- a/src/l1_5/codegen/rb_tree_set_map_template_inst.h +++ b/src/l1_5/codegen/rb_tree_set_map_template_inst.h @@ -7,6 +7,8 @@ NODISCARD VecU8 codegen_rb_tree_set_key_value_NOT_EQUAL_element(set_instantiation_op op){ if (op.t_integer) return VecU8_fmt("key != self->el.buf[cur - 1]"); + if (op.alternative_equal.len != 0) + return VecU8_fmt("!%s(&key, &self->el.buf[cur - 1])", op.alternative_equal); return VecU8_fmt("!%s_equal_%s(&key, &self->el.buf[cur - 1])", op.T, op.T); } @@ -14,6 +16,8 @@ NODISCARD VecU8 codegen_rb_tree_set_key_value_NOT_EQUAL_element(set_instantiatio NODISCARD VecU8 codegen_rb_tree_set_key_value_LESS_element(set_instantiation_op op){ if (op.t_integer) return VecU8_fmt("key < self->el.buf[cur - 1]"); + if (op.alternative_less.len != 0) + return VecU8_fmt("%s(&key, &self->el.buf[cur - 1])", op.alternative_less); return VecU8_fmt("%s_less_%s(&key, &self->el.buf[cur - 1])", op.T, op.T); } @@ -22,6 +26,8 @@ NODISCARD VecU8 codegen_rb_tree_set_key_value_LESS_element(set_instantiation_op NODISCARD VecU8 codegen_rb_tree_set_key_ref_NOT_EQUAL_element(set_instantiation_op op){ if (op.t_integer) return VecU8_fmt("key != self->el.buf[cur - 1]"); + if (op.alternative_equal.len != 0) + return VecU8_fmt("!%s(key, &self->el.buf[cur - 1])", op.alternative_equal); return VecU8_fmt("!%s_equal_%s(key, &self->el.buf[cur - 1])", op.T, op.T); } @@ -29,6 +35,8 @@ NODISCARD VecU8 codegen_rb_tree_set_key_ref_NOT_EQUAL_element(set_instantiation_ NODISCARD VecU8 codegen_rb_tree_set_key_ref_EQUAL_element(set_instantiation_op op){ if (op.t_integer) return VecU8_fmt("key == self->el.buf[cur - 1]"); + if (op.alternative_equal.len != 0) + return VecU8_fmt("%s(key, &self->el.buf[cur - 1])", op.alternative_equal); return VecU8_fmt("%s_equal_%s(ref, &self->el.buf[cur - 1])", op.T, op.T); } @@ -36,6 +44,8 @@ NODISCARD VecU8 codegen_rb_tree_set_key_ref_EQUAL_element(set_instantiation_op o NODISCARD VecU8 codegen_rb_tree_set_key_ref_LESS_element(set_instantiation_op op){ if (op.t_integer) return VecU8_fmt("key < self->el.buf[cur - 1]"); + if (op.alternative_less.len != 0) + return VecU8_fmt("%s(key, &self->el.buf[cur - 1])", op.alternative_less); return VecU8_fmt("%s_less_%s(key, &self->el.buf[cur - 1])", op.T, op.T); } @@ -86,6 +96,12 @@ NODISCARD VecU8 codegen_rb_tree_set_taking_ref_t_argument(set_instantiation_op o return !op.t_integer ? VecU8_fmt("const %s*", op.T) : VecU8_from_span(op.T); } +NODISCARD VecU8 get_name_of_rb_tree_set_structure(set_instantiation_op op){ + if (op.alternative_comp_set_name_embed.len) + return VecU8_fmt("BuffRBTreeBy%s_Set%s", op.alternative_comp_set_name_embed, op.T); + return VecU8_fmt("BuffRBTree_Set%s", op.T); +} + /* Generates methods _insert() _pop_substitute() _erase_substitute() for SetT * Takes ownership of strings Tc, Fc */ void codegen_append_rb_tree_set_insert_kind_method( @@ -175,7 +191,7 @@ void codegen_append_rb_tree_set_erase_kind_method( SPACE "}\n" "%v" /* saving_prev */ SPACE "U64 z = cur;\n" - SPACE "U64 y = (self->tree.buf[z].left == 0 || self->tree.buf[z].right == 0) ? z : RBTree_minimum_in_subtree(self->tree.buf, self->tree.buf[z].right);\n" + SPACE "U64 y = (self->tree.buf[z].left == 0 || self->tree.buf[z].right == 0) ? z : 1(self->tree.buf, self->tree.buf[z].right);\n" SPACE "U64 x = self->tree.buf[y].left != 0 ? self->tree.buf[y].left : self->tree.buf[y].right;\n" SPACE "assert(x != y && x != z);\n" SPACE "U64 x_adopter = self->tree.buf[y].parent;\n" @@ -223,7 +239,7 @@ void codegen_append_rb_tree_set_erase_kind_method( NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op op){ set_instantiation_op_fix(&op); VecU8 res = VecU8_new(); - VecU8 g_set = VecU8_fmt("BuffRBTree_Set%s", op.T); + VecU8 g_set = get_name_of_rb_tree_set_structure(op); SpanU8 set = VecU8_to_span(&g_set); VecU8_append_vec(&res, VecU8_fmt( "typedef struct {\n" @@ -294,7 +310,7 @@ NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op } VecU8_append_vec(&res, VecU8_fmt( - "U64 %s_find(const %s* self, %v key) {\n" /* set, set taking_ref_t_argument */ + "U64 %s_find(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */ SPACE "U64 cur = self->root;\n" SPACE "while (cur != 0 && %v) {\n" /* key reference not equal cur element */ SPACE SPACE "if (%v) {\n" /* key reference less than cue element */ @@ -379,20 +395,111 @@ NODISCARD VecU8 generate_rb_tree_Set_template_instantiation(set_instantiation_op SPACE "return self->root != 0 ? RBTree_maximum_in_subtree(self->tree.buf, self->root) : 0;\n" "}\n\n", set, set)); - // todo: continue from here. Implement method _pop_and_substitute() + VecU8_append_vec(&res, VecU8_fmt( + "U64 %s_find_max_less(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */ + SPACE "U64 last_less = 0;\n" + SPACE "U64 cur = self->root;\n" + SPACE "while (cur != 0) {\n" + SPACE SPACE "if (%v) {\n" /* key_ref_EQUAL_element */ + SPACE SPACE SPACE "cur = cur->left;\n" + SPACE SPACE SPACE "if (cur == 0)\n" + SPACE SPACE SPACE SPACE "return last_less;\n" + SPACE SPACE SPACE "while (self->tree.buf[cur].right != 0)\n" + SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n" + SPACE SPACE SPACE "return cur;\n" + SPACE SPACE "} else if (%v) {\n" /* key_ref_LESS_element */ + SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "last_less = cur;\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n" + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_less;\n" + "}\n\n", + set, set, codegen_rb_tree_set_taking_ref_t_argument(op), + codegen_rb_tree_set_key_ref_EQUAL_element(op), + codegen_rb_tree_set_key_ref_LESS_element(op) + )); - // todo: All the other methods are secondary in importance + VecU8_append_vec(&res, VecU8_fmt( + "U64 %s_find_max_less_or_eq(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */ + SPACE "U64 last_less = 0;\n" + SPACE "U64 cur = self->root;\n" + SPACE "while (cur != 0) {\n" + SPACE SPACE "if (%v) {\n" /* key_ref_EQUAL_element */ + SPACE SPACE SPACE "return cur;\n" + SPACE SPACE "} else if (%v) {\n" /* key_ref_LESS_element */ + SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "last_less = cur;\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n" + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_less;\n" + "}\n\n", + set, set, codegen_rb_tree_set_taking_ref_t_argument(op), + codegen_rb_tree_set_key_ref_EQUAL_element(op), + codegen_rb_tree_set_key_ref_LESS_element(op) + )); + + VecU8_append_vec(&res, VecU8_fmt( + "U64 %s_find_min_grtr(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */ + SPACE "U64 last_grtr = 0;\n" + SPACE "U64 cur = self->root;\n" + SPACE "while (cur != 0) {\n" + SPACE SPACE "if (%v) {\n" /* key_ref_EQUAL_element */ + SPACE SPACE SPACE "cur = cur->right;\n" + SPACE SPACE SPACE "if (cur == 0)\n" + SPACE SPACE SPACE SPACE "return last_grtr;\n" + SPACE SPACE SPACE "while (self->tree.buf[cur].left != 0)\n" + SPACE SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n" + SPACE SPACE SPACE "return cur;\n" + SPACE SPACE "} else if (%v) {\n" /* key_ref_LESS_element */ + SPACE SPACE SPACE "last_grtr = cur;\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n" + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_grtr;\n" + "}\n\n", + set, set, codegen_rb_tree_set_taking_ref_t_argument(op), + codegen_rb_tree_set_key_ref_EQUAL_element(op), + codegen_rb_tree_set_key_ref_LESS_element(op) + )); + + + VecU8_append_vec(&res, VecU8_fmt( + "U64 %s_find_min_grtr_or_eq(const %s* self, %v key) {\n" /* set, set, taking_ref_t_argument */ + SPACE "U64 last_grtr = 0;\n" + SPACE "U64 cur = self->root;\n" + SPACE "while (cur != 0) {\n" + SPACE SPACE "if (%v) {\n" /* key_ref_EQUAL_element */ + SPACE SPACE SPACE "return cur;\n" + SPACE SPACE "} else if (%v) {\n" /* key_ref_LESS_element */ + SPACE SPACE SPACE "last_grtr = cur;\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].left;\n" + SPACE SPACE "} else {\n" + SPACE SPACE SPACE "cur = self->tree.buf[cur].right;\n" + SPACE SPACE "}\n" + SPACE "}\n" + SPACE "return last_grtr;\n" + "}\n\n", + set, set, codegen_rb_tree_set_taking_ref_t_argument(op), + codegen_rb_tree_set_key_ref_EQUAL_element(op), + codegen_rb_tree_set_key_ref_LESS_element(op) + )); VecU8_drop(g_set); return res; } -void generate_rb_tree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, option_template_instantiation_op op) { +void generate_rb_tree_Set_templ_inst_eve_header(SpanU8 layer, SpanU8 bonus_ns, set_instantiation_op op) { VecU8 text = VecU8_from_cstr("/* Automatically generated file. Do not edit it.\n" " * Do not include it in more than one place */\n\n"); - VecU8_append_vec(&text, generate_OptionT_struct_and_methods(op)); - VecU8 nt_path = VecU8_fmt("%s/eve/%s/BuffRBTree_Set%s%c", layer, bonus_ns, op.T, 0); + VecU8_append_vec(&text, generate_rb_tree_Set_template_instantiation(op)); + VecU8 nt_path = VecU8_fmt("%s/eve/%s/%s.h%c", layer, bonus_ns, op.T, get_name_of_rb_tree_set_structure(op)); write_whole_file_or_abort((const char*)nt_path.buf, VecU8_to_span(&text)); VecU8_drop(nt_path); VecU8_drop(text); @@ -402,7 +509,8 @@ void generate_rb_tree_Set_templ_inst_guarded_header( SpanU8 layer, SpanU8 bonus_ns, SpanU8 dependencies, set_instantiation_op op ){ assert(layer.len > 1); - VecU8 path = VecU8_fmt("%s/%s%sBuffRBTree_Set%s.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), op.T); + VecU8 path = VecU8_fmt("%s/%s%s%v.h", layer, bonus_ns, bonus_ns.len ? cstr("/") : cstr(""), + get_name_of_rb_tree_set_structure(op)); GeneratedHeader head = begin_header(VecU8_to_span(&path)); VecU8_drop(path); VecU8_append_span(&head.result, cstr("#include \"../../")); diff --git a/src/l1_5/core/rb_tree_node.h b/src/l1_5/core/rb_tree_node.h index 44771f0..b01d103 100644 --- a/src/l1_5/core/rb_tree_node.h +++ b/src/l1_5/core/rb_tree_node.h @@ -121,7 +121,7 @@ void RBTree_steal_neighbours(RBTreeNode* tree, U64* root, U64 fr, U64 to){ /* helper function (used in _erase, _find_min methods). It is assumed that s is not null. * Guaranteed to return no-null */ -U64 RBTree_minimum_in_subtree(RBTreeNode* tree, U64 s){ +U64 RBTree_minimum_in_subtree(const RBTreeNode* tree, U64 s){ assert(s != 0); while (tree[s].left != 0) s = tree[s].left; @@ -131,7 +131,7 @@ U64 RBTree_minimum_in_subtree(RBTreeNode* tree, U64 s){ /* helper function (used in _find_max, _find_prev methods). It is assumed that s is not null. * Guaranteed to return no-null */ -U64 RBTree_maximum_in_subtree(RBTreeNode* tree, U64 s){ +U64 RBTree_maximum_in_subtree(const RBTreeNode* tree, U64 s){ assert(s != 0); while (tree[s].right != 0) s = tree[s].right;