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 0000000..ccb49a0 Binary files /dev/null and b/src/l2/tests/r0/test_textures/test.png differ 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);