From 2b95720d56dfaf35b892a7eb3ed0f225d71ab488 Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Mon, 18 Aug 2025 20:57:39 +0300 Subject: [PATCH] I finally learned how to draw normal perimeters --- CMakeLists.txt | 10 +-- Makefile | 21 ++--- src/l2/codegen/geom.h | 29 +++++-- src/l2/marie/geom_alg_utils.h | 4 + src/l2/marie/shape_geom.h | 5 -- src/l2/tests/r0/r0_assets.h | 107 ++++++++++++++++++------- src/l2/tests/r0/r0_scene.h | 6 +- src/l2/tests/r0/test_textures/test.png | Bin 0 -> 33146 bytes src/l2/tests/r1/r1.c | 19 +++-- 9 files changed, 136 insertions(+), 65 deletions(-) create mode 100644 src/l2/tests/r0/test_textures/test.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 88c76d0..0dde950 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,13 +19,13 @@ add_executable(codegen_l2 src/l2/codegen/codegen.c) add_executable(0_render_test src/l2/tests/r0/r0.c) target_link_libraries(0_render_test -lvulkan -lX11 -lm) -# + add_executable(0_render_test_tex_init_prep src/l2/tests/r0/r0_tex_init_prep.c) target_link_libraries(0_render_test_tex_init_prep -lm) -# -#add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c) -#target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon) -# + +add_executable(1_render_test src/l2/tests/r1/r1.c gen/l_wl_protocols/xdg-shell-private.c) +target_link_libraries(1_render_test -lwayland-client -lrt -lm -lxkbcommon) + #add_executable(0_play_test src/l3/tests/p0.c) #target_link_libraries(0_play_test -lncurses) # diff --git a/Makefile b/Makefile index 92629ee..3563c9e 100644 --- a/Makefile +++ b/Makefile @@ -49,20 +49,21 @@ gen/l_wl_protocols/xdg-shell-client.h: $(wl_protocols)/stable/xdg-shell/xdg-shel gen/l_wl_protocols/xdg-shell-private.c: $(wl_protocols)/stable/xdg-shell/xdg-shell.xml mkdir -p gen/l_wl_protocols wayland-scanner private-code $< $@ -# -# -# -#out/l2/r0: src/l2/tests/r0/r0.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) -# mkdir -p out/l2 -# $(cc) $(cflags) -o $@ $< -lvulkan -lX11 -lm -# + + + +out/l2/r0: src/l2/tests/r0/r0.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) + mkdir -p out/l2 + $(cc) $(cflags) -o $@ $< -lvulkan -lX11 -lm + #out/l2/r0: src/l2/tests/r0/r0_tex_init_prep.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) # mkdir -p out/l2 # $(cc) $(cflags) -o $@ $< -lm # -#out/l2/r1: src/l2/tests/r1/r1.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) -# mkdir -p out/l2 -# $(cc) $(cflags) -o $@ $< gen/l_wl_protocols/xdg-shell-private.c -lwayland-client -lrt -lxkbcommon +out/l2/r1: src/l2/tests/r1/r1.c $(HEADERS_gen_l2) $(HEADERS_src_l2) $(HEADERS_gen_l1) $(HEADERS_src_l1) \ + gen/l_wl_protocols/xdg-shell-client.h gen/l_wl_protocols/xdg-shell-private.c + mkdir -p out/l2 + $(cc) $(cflags) -o $@ $< gen/l_wl_protocols/xdg-shell-private.c -lwayland-client -lrt -lxkbcommon -lm clean: rm -rf gen out diff --git a/src/l2/codegen/geom.h b/src/l2/codegen/geom.h index 8af3f7b..9641ee2 100644 --- a/src/l2/codegen/geom.h +++ b/src/l2/codegen/geom.h @@ -63,10 +63,21 @@ NODISCARD VecU8 generate_xvecn_struct_and_base_methods(SpanU8 xvec, SpanU8 memb, return res; } -NODISCARD VecU8 generate_xvecn_struct_and_cool_methods(SpanU8 xvec, SpanU8 memb, int n) { +NODISCARD VecU8 generate_xvecn_struct_and_cool_methods(SpanU8 xvec, SpanU8 memb, int n, SpanU8 sqrt_func) { VecU8 g_xvecn = codegen_name_xvecn(xvec, n); SpanU8 xvecn = VecU8_to_span(&g_xvecn); VecU8 res = generate_xvecn_struct_and_base_methods(xvec, memb, n); + /* xvecn_length method */ + VecU8_append_vec(&res, VecU8_fmt( + "%s %s_length(%s A) {\n" + SPACE4 "return %s(", + memb, xvecn, xvecn, sqrt_func)); + for (int i = 0; i < n; i++) { + if (i) + VecU8_append_span(&res, cstr(" + ")); + VecU8_append_vec(&res, VecU8_fmt("A.%s * A.%s", vec_field_name(i), vec_field_name(i))); + } + VecU8_append_span(&res, cstr(");\n}\n\n")); /* xvecn_mul_scal method */ VecU8_append_vec(&res, VecU8_fmt( "%s %s_mul_scal(%s A, %s B) {\n" @@ -105,6 +116,11 @@ NODISCARD VecU8 generate_xvecn_struct_and_cool_methods(SpanU8 xvec, SpanU8 memb, VecU8_append_vec(&res, VecU8_fmt("A.%s * B.%s", vec_field_name(i), vec_field_name(i))); } VecU8_append_span(&res, cstr(";\n}\n\n")); + /* xvecn_normalize method */ + VecU8_append_vec(&res, VecU8_fmt( + "%s %s_normalize(%s A) {\n" + SPACE4 "return %s_div_by_scal(A, %s_length(A));\n" + "}\n\n", xvecn, xvecn, xvecn, xvecn, xvecn)); VecU8_drop(g_xvecn); return res; @@ -368,10 +384,10 @@ NODISCARD VecU8 generate_xvec234_structs_and_base_methods(SpanU8 xvec, SpanU8 me return res; } -NODISCARD VecU8 generate_xvec234_structs_and_cool_methods(SpanU8 xvec, SpanU8 memb) { +NODISCARD VecU8 generate_xvec234_structs_and_cool_methods(SpanU8 xvec, SpanU8 memb, SpanU8 sqrt_func) { VecU8 res = VecU8_new(); for (int n = 2; n <= 4; n++) - VecU8_append_vec(&res, generate_xvecn_struct_and_cool_methods(xvec, memb, n)); + VecU8_append_vec(&res, generate_xvecn_struct_and_cool_methods(xvec, memb, n, sqrt_func)); for (int n = 2; n <= 3; n++) VecU8_append_vec(&res, generate_xvecn_method_and_one(xvec, n)); VecU8_append_vec(&res, generate_xvec3_method_cross(xvec)); @@ -405,12 +421,13 @@ NODISCARD VecU8 generate_xmat234x234_structs_methods(SpanU8 xmat, SpanU8 xvec, S void generate_geom_header() { VecU8 res = begin_header(cstr("PROTOTYPE1_GEN_L2_GEOM")); - VecU8_append_span(&res, cstr("#include \"../../src/l1/core/int_primitives.h\"\n\n")); + VecU8_append_span(&res, cstr("#include \"../../src/l1/core/int_primitives.h\"\n")); + VecU8_append_span(&res, cstr("#include \n\n")); VecU8_append_vec(&res, generate_xvec234_structs_and_base_methods(cstr("cvec"), cstr("U8"))); VecU8_append_vec(&res, generate_xvec234_structs_and_base_methods(cstr("ivec"), cstr("S32"))); - VecU8_append_vec(&res, generate_xvec234_structs_and_cool_methods(cstr("vec"), cstr("float"))); - VecU8_append_vec(&res, generate_xvec234_structs_and_cool_methods(cstr("dvec"), cstr("double"))); + VecU8_append_vec(&res, generate_xvec234_structs_and_cool_methods(cstr("vec"), cstr("float"), cstr("sqrtf"))); + VecU8_append_vec(&res, generate_xvec234_structs_and_cool_methods(cstr("dvec"), cstr("double"), cstr("sqrt"))); VecU8_append_vec(&res, generate_xmat234x234_structs_methods(cstr("mat"), cstr("vec"), cstr("float"), sizeof(float))); VecU8_append_vec(&res, generate_xmat234x234_structs_methods(cstr("dmat"), cstr("dvec"), cstr("double"), sizeof(double))); finish_header(res, "l2/geom.h"); diff --git a/src/l2/marie/geom_alg_utils.h b/src/l2/marie/geom_alg_utils.h index 4b9ed5c..8712afc 100644 --- a/src/l2/marie/geom_alg_utils.h +++ b/src/l2/marie/geom_alg_utils.h @@ -74,4 +74,8 @@ vec2 marie_intersect_lines(vec2 A1, vec2 B1, vec2 A2, vec2 B2) { return vec2_add_vec2(A1, vec2_mul_scal(alpha, t1)); } +float marie_clamp_float(float a, float l, float r) { + return (a < l) ? l : ((a <= r) ? a : r); +} + #endif diff --git a/src/l2/marie/shape_geom.h b/src/l2/marie/shape_geom.h index ed64938..1dd46ec 100644 --- a/src/l2/marie/shape_geom.h +++ b/src/l2/marie/shape_geom.h @@ -3,11 +3,6 @@ #include "../../../gen/l2/marie/clipping.h" - -// // todo: move to autogenerated files (and autogenerate span and vector definitions) -// SpanT_struct_Definition(vec2) -// SpanT_method_Definition(vec2) - void marie_clip_triang_with_triang_append_to_Vec(MarieTriangle C, MarieTriangle T, VecMarieTriangle* pile) { float SC = marie_surface(C.v0, C.v1, C.v2); if (SC < 0) { diff --git a/src/l2/tests/r0/r0_assets.h b/src/l2/tests/r0/r0_assets.h index 9a9230f..51c034d 100644 --- a/src/l2/tests/r0/r0_assets.h +++ b/src/l2/tests/r0/r0_assets.h @@ -229,21 +229,75 @@ ModelTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) { return (ModelTopology){.vertices = vertices, .indexes = indexes}; } -/* todo: write it myself using triangles and LINES -void TextureDataR8_draw_perimeter_maxing(TextureDataR8* self, Spanvec2 P) { - float r_cut = 2; - float r_decay = 1; - size_t S = P.len; - for (size_t i = 0; i < S; i++) { - TextureDataR8_draw_spot_maxing(self, *Spanvec2_at(P, i), r_cut, r_decay); - } - for (size_t i = 1; i < S; i++) { - TextureDataR8_draw_inner_line_maxing(self, *Spanvec2_at(P, i - 1), *Spanvec2_at(P, i), r_cut, r_decay); - } - if (S > 2) - TextureDataR8_draw_inner_line_maxing(self, *Spanvec2_at(P, S - 1), *Spanvec2_at(P, 0), r_cut, r_decay); +vec2 perimeter_line_get_thorn_on_vertex(Spanvec2 P, size_t i, float thickness) { + assert(P.len >= 3 && i < P.len); + vec2 A = *Spanvec2_at(P, i ? i - 1 : P.len - 1); + vec2 B = *Spanvec2_at(P, i); + vec2 C = *Spanvec2_at(P, i == P.len - 1 ? 0 : i + 1); + vec2 b = vec2_normalize(vec2_minus_vec2(A, B)); + vec2 f = vec2_minus_vec2(C, B); + float cr = b.x * f.y - b.y * f.x; + float dt = b.x * f.x + b.y * f.y; + float a = M_PIf + atan2f(cr, dt); + float t = M_PI_2f + a / 2; + return vec2_mul_scal(mat2_mul_vec2(marie_2d_rot_mat2(t), b), thickness / sinf(t)); +} + +/* It is assumed that A != B */ +float distance_to_segment(vec2 A, vec2 B, vec2 P) { + vec2 seg = vec2_minus_vec2(B, A); + vec2 tg = vec2_minus_vec2(P, A); + float t = vec2_dot(seg, tg) / vec2_dot(seg, seg); + float c = marie_clamp_float(t, 0, 1); + vec2 closest = vec2_add_vec2(A, vec2_mul_scal(seg, c)); + float len = vec2_length(vec2_minus_vec2(P, closest)); + return len; +} + +typedef struct { + TextureDataR8* texture; + vec2 A; + vec2 B; + float r_cut; + float r_decay; +} TextureDataR8_draw_perimeter_maxing_H_DrawGuest; + +void TextureDataR8_draw_perimeter_maxing_h_draw_guest(void* ug, S32 x, S32 y, vec4 attr) { + TextureDataR8_draw_perimeter_maxing_H_DrawGuest* g = ug; + if (TextureDataR8_is_inside(g->texture, x, y)) { + vec2 P = {attr.x, attr.y}; + U8 clr = a_small_cute_gradient(g->r_cut, g->r_decay, distance_to_segment(g->A, g->B, P)); + TextureDataR8_pixel_maxing(g->texture, x, y, clr); + } +} + +void TextureDataR8_draw_perimeter_maxing_h_draw_triangle( + TextureDataR8_draw_perimeter_maxing_H_DrawGuest* aboba, vec2 a, vec2 b, vec2 c + ) { + marie_rasterize_triangle_with_attr((MariePlaneVertAttr){a, {a.x, a.y, 0, 0}}, + (MariePlaneVertAttr){b, {b.x, b.y, 0, 0}}, (MariePlaneVertAttr){c, {c.x, c.y, 0, 0}}, + (FnMarieRasterizerCallback){TextureDataR8_draw_perimeter_maxing_h_draw_guest, aboba}); +} + +/* It is assumed that P[i] != P[i + 1] foreach i from 0 to P.len - 1 */ +void TextureDataR8_draw_perimeter_maxing(TextureDataR8* self, Spanvec2 P) { + float r_cut = 5; + float r_decay = 2; + for (size_t i = 0; i < P.len; i++) { + size_t ia = i == P.len - 1 ? 0 : i + 1; + vec2 A = *Spanvec2_at(P, i); + vec2 B = *Spanvec2_at(P, ia); + vec2 hA = perimeter_line_get_thorn_on_vertex(P, i, r_cut); + vec2 hB = perimeter_line_get_thorn_on_vertex(P, ia, r_cut); + vec2 q0 = vec2_add_vec2(A, hA); + vec2 q1 = vec2_add_vec2(B, hB); + vec2 q2 = vec2_minus_vec2(B, hB); + vec2 q3 = vec2_minus_vec2(A, hA); + TextureDataR8_draw_perimeter_maxing_H_DrawGuest aboba = { self, A, B, r_cut, r_decay }; + TextureDataR8_draw_perimeter_maxing_h_draw_triangle(&aboba, q0, q1, q2); + TextureDataR8_draw_perimeter_maxing_h_draw_triangle(&aboba, q0, q2, q3); + } } -*/ typedef struct { vec2 bl; @@ -290,20 +344,20 @@ void Bublazhuzhka_TextureDataR8_draw_maxing(const Bublazhuzhka* self, TextureDat vec2 p1[4] = {mat3x2_mul_vec3(trop, vec2_and_one(A)), mat3x2_mul_vec3(trop, vec2_and_one(B)), mat3x2_mul_vec3(trop, vec2_and_one(D)), mat3x2_mul_vec3(trop, vec2_and_one(C))}; - // TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p1, ARRAY_SIZE(p1)}); + TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p1, ARRAY_SIZE(p1)}); vec2 p2[4] = {mat3x2_mul_vec3(trop, vec2_and_one(E)), mat3x2_mul_vec3(trop, vec2_and_one(F)), mat3x2_mul_vec3(trop, vec2_and_one(H)), mat3x2_mul_vec3(trop, vec2_and_one(G))}; - // TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p2, ARRAY_SIZE(p2)}); + TextureDataR8_draw_perimeter_maxing(canvas, (Spanvec2){.data = p2, ARRAY_SIZE(p2)}); } - // todo: draw all these cool perimeters myself for (size_t i = 0; i < self->nibzles.len; i++) { Nibzle sphere = *VecNibzle_at(&self->nibzles, i); Vecvec2 p = Vecvec2_new_zeroinit(13); for (int j = 0; j < 13; j++) { float a = (float)j * 2 * M_PIf / 13; - *Vecvec2_mat(&p, j) = vec2_add_vec2(sphere.center, vec2_mul_scal(marie_trigonom_circle(a), sphere.rad)); + *Vecvec2_mat(&p, j) = mat3x2_mul_vec3(trop, vec2_and_one(vec2_add_vec2(sphere.center, + vec2_mul_scal(marie_trigonom_circle(a), sphere.rad)))); } - // TextureDataR8_draw_perimeter_maxing(canvas, Vecvec2_to_Spanvec2(&p)); + TextureDataR8_draw_perimeter_maxing(canvas, Vecvec2_to_span(&p)); Vecvec2_drop(p); TextureDataR8_draw_spot_maxing(canvas, mat3x2_mul_vec3(trop, vec2_and_one(sphere.center)), 3, 1); } @@ -493,7 +547,7 @@ TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, 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(); // todo: reserve 6 + k * 4 + 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 @@ -515,13 +569,12 @@ TextureDataR8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, for (size_t i = 0; i < P.len; i++) { *Vecvec2_mat(&P, i) = vec2_mul_vec2(*Vecvec2_at(&P, i), cord_resol); } - // todo: actually draw this perimeter - // TextureDataR8_draw_perimeter_maxing(&res, Vecvec2_to_Spanvec2(&P)); + TextureDataR8_draw_perimeter_maxing(&res, Vecvec2_to_span(&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)}); + 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)}); return res; } @@ -541,8 +594,8 @@ TextureDataR8G8B8 generate_normal_tex_for_one_fourth_of_a_cylinder(float s_resol vec2 cord_resol = {(float)width_pix / (2 * r + w), (float)height_pix / (2 * r + (float)k * l)}; const vec2 v0tex = {r, r}; const vec2 v1tex = {r + w, r}; - const vec2 v2tex = {r, 2 * r}; - const vec2 v3tex = {r + w, 2 * r}; + // const vec2 v2tex = {r, 2 * r}; + // const vec2 v3tex = {r + w, 2 * r}; const vec2 v4tex = {r, 0}; const vec2 v5tex = {r + w, 0}; TextureDataR8G8B8 res = TextureDataR8G8B8_new(width_pix, height_pix); @@ -573,7 +626,7 @@ TextureDataR8G8B8 generate_normal_tex_for_one_fourth_of_a_cylinder(float s_resol vec2 B = {r + w, 2 * r + (float)i * l}; vec2 C = {r, 2 * r + (float)i * l + l}; vec2 D = {r + w, 2 * r + (float)i * l + l}; - vec3 n = {0, cosf(a / 2 + a * (float)i), -sinf(a / 2 + a * i)}; + vec3 n = {0, cosf(a / 2 + a * (float)i), -sinf(a / 2 + a * (float)i)}; draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, C, str, n); draw_polygon_on_normal_texture_absolutely_flat(&res, D, B, C, str, n); } diff --git a/src/l2/tests/r0/r0_scene.h b/src/l2/tests/r0/r0_scene.h index f76e477..838d5ee 100644 --- a/src/l2/tests/r0/r0_scene.h +++ b/src/l2/tests/r0/r0_scene.h @@ -76,13 +76,9 @@ CamControlInfo CamControlInfo_new() { }; } -float clamp_float(float a, float l, float r) { - return (a < l) ? l : ((a <= r) ? a : r); -} - void CamControlInfo_update_direction(CamControlInfo* self, int win_width, int win_height, int pointer_x, int pointer_y) { float yaw = ((float)win_width / 2 - (float)pointer_x) * self->sensitivity; - float pitch = clamp_float( + float pitch = marie_clamp_float( ((float)win_height / 2 - (float)pointer_y) * self->sensitivity, -self->pitch_cap, self->pitch_cap ); diff --git a/src/l2/tests/r0/test_textures/test.png b/src/l2/tests/r0/test_textures/test.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb49a0dab1659a0dc8e82d03a38f9e306122376 GIT binary patch literal 33146 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 Hw_pAng{5!; literal 0 HcmV?d00001 diff --git a/src/l2/tests/r1/r1.c b/src/l2/tests/r1/r1.c index c5baf49..3fa6539 100644 --- a/src/l2/tests/r1/r1.c +++ b/src/l2/tests/r1/r1.c @@ -12,15 +12,13 @@ #include "../../marie/graphics_geom.h" #include "../../marie/rasterization.h" -// todo: remove -#include - #define MAX_BUFFER_WIDTH 1000 #define MAX_BUFFER_HEIGHT 800 #define SWAPCHAIN_SLOTS 2 _Static_assert(INT32_MAX / MAX_BUFFER_WIDTH / MAX_BUFFER_HEIGHT / 4 / SWAPCHAIN_SLOTS > 1, "Swapchain is too big"); +// todo: write something normal here /* Shared memory support code */ static void randname(char *buf) { struct timespec ts; @@ -495,18 +493,25 @@ static const struct wl_callback_listener main_h_wl_surface_frame_listener = { }; -int main(int argc, char *argv[]) { +int main() { my_state state = { .width = 800, .height = 480 }; state.v0 = (durackaya_tochka){.pos = {10, 10}, .speed = {100, 100}}; state.v1 = (durackaya_tochka){.pos = {100, 10}, .speed = {100, -50}}; state.v2 = (durackaya_tochka){.pos = {5, 330}, .speed = {-20, 170}}; state.wl_display = wl_display_connect(NULL); + if (!state.wl_display) + abortf("Could not connect"); state.wl_registry = wl_display_get_registry(state.wl_display); + if (!state.wl_registry) + abortf("wl_display_get_registry"); wl_registry_add_listener(state.wl_registry, &main_h_wl_registry_listener, &state); wl_display_roundtrip(state.wl_display); - assert(state.wl_shm); - assert(state.wl_compositor); - assert(state.xdg_wm_base); + if (!state.wl_shm) + abortf("No wl_shm"); + if (!state.wl_compositor) + abortf("No wl_compositor"); + if (!state.xdg_wm_base) + abortf("No xdg_wm_base"); { size_t size = SWAPCHAIN_SLOTS * MAX_BUFFER_WIDTH * MAX_BUFFER_HEIGHT * 4; assert(size < INT32_MAX);