diff --git a/CMakeLists.txt b/CMakeLists.txt index 85808a9..18d256e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,5 +62,5 @@ target_link_libraries(r2c -lm) add_executable(l2_tex_gen src/l2/anne/codegen.c) target_link_libraries(l2_tex_gen -lm -lpng) -add_executable(l2_r4 src/l3/r4/r4.c gen/l_wl_protocols/xdg-shell-private.c) -target_link_libraries(l2_r4 -lvulkan -lwayland-client -lm -lxkbcommon -lpng -lfreetype) +add_executable(l3_r4 src/l3/r4/r4.c gen/l_wl_protocols/xdg-shell-private.c) +target_link_libraries(l3_r4 -lvulkan -lwayland-client -lm -lxkbcommon -lpng -lfreetype) diff --git a/src/l1/anne/codegen.c b/src/l1/anne/codegen.c index 2ac9b74..9f3e835 100644 --- a/src/l1/anne/codegen.c +++ b/src/l1/anne/codegen.c @@ -8,7 +8,7 @@ #include "some_tests.h" #include "util_temp_vulkan.h" #include "margaret/margaret_misc.h" -#include "marie/graphics_geom.h" +#include "marie.h" #include "liza.h" #include "embassy_l1_5.h" #include "margaret/png_pixel_masses.h" @@ -24,7 +24,7 @@ int main() { generate_pixel_masses_header(); generate_headers_for_r0_r1_r2_r3(); generate_util_templ_inst_for_vulkan_headers(); - generate_marie_headers_for_graphics_geom(); + generate_l1_headers_for_marie(); generate_liza_l1_headers(); generate_l1_headers_for_l1_5(); generate_margaret_eve_for_vulkan_utils(); /* margaret misc */ diff --git a/src/l1/anne/geom.h b/src/l1/anne/geom.h index 76c6a9e..7211676 100644 --- a/src/l1/anne/geom.h +++ b/src/l1/anne/geom.h @@ -499,7 +499,12 @@ void generate_geom_header() { VecU8_append_span(&res.result, cstr("#include \n\n")); VecU8_append_vec(&res.result, generate_xvec234_structs_and_base_methods(cstr("cvec"), cstr("U8"))); VecU8_append_vec(&res.result, generate_xvec234_structs_and_base_methods(cstr("uvec"), cstr("U32"))); + VecU8_append_vec(&res.result, generate_xvec234_structs_and_base_methods(cstr("s64vec"), cstr("S64"))); VecU8_append_vec(&res.result, generate_xvec234_structs_and_base_methods(cstr("ivec"), cstr("S32"))); + for (U64 i = 2; i <= 4; i++) { + VecU8_append_vec(&res.result, VecU8_fmt("typedef ivec%u s32vec%u;\n", i, i)); + } + VecU8_append_span(&res.result, cstr("\n")); VecU8_append_vec(&res.result, generate_xvec234_structs_and_cool_methods(cstr("vec"), cstr("float"), cstr("sqrtf"))); VecU8_append_vec(&res.result, generate_xvec234_structs_and_cool_methods(cstr("dvec"), cstr("double"), cstr("sqrt"))); diff --git a/src/l1/anne/marie.h b/src/l1/anne/marie.h new file mode 100644 index 0000000..6e9d51c --- /dev/null +++ b/src/l1/anne/marie.h @@ -0,0 +1,21 @@ +#ifndef PROTOTYPE1_SRC_L1_ANNE_MARIE_H +#define PROTOTYPE1_SRC_L1_ANNE_MARIE_H + +#include "../codegen/util_template_inst.h" + +void generate_l1_headers_for_marie() { + SpanU8 l = cstr("l1"); + SpanU8 ns = cstr("marie"); + mkdir_nofail("l1/eve/marie"); + /* graphics_geom */ + generate_eve_span_company_for_primitive(l, ns, cstr("MarieTriangle"), true, false); + generate_eve_span_company_for_primitive(l, ns, cstr("MarieTriangleAttr"), true, false); + /* shape_geom */ + generate_eve_span_company_for_primitive(l, ns, cstr("MarieEarCuttingTriangulVertState"), true, false); + generate_eve_span_company_for_primitive(l, ns, cstr("MarieHoleConnectTriangStackFrame"), true, false); + generate_eve_span_company_for_primitive(l, ns, cstr("MarieHoleAndVertexId"), true, false); + generate_eve_span_company_for_non_primitive_clonable(l, ns, cstr("VecMarieHoleAndVertexId"), true, false); + generate_eve_span_company_for_non_primitive_clonable(l, ns, cstr("VecVecMarieHoleAndVertexId"), true, false); +} + +#endif diff --git a/src/l1/anne/marie/graphics_geom.h b/src/l1/anne/marie/graphics_geom.h deleted file mode 100644 index b61bd3d..0000000 --- a/src/l1/anne/marie/graphics_geom.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef PROTOTYPE1_SRC_L1_ANNE_MARIE_GRAPHICS_GEOM_H -#define PROTOTYPE1_SRC_L1_ANNE_MARIE_GRAPHICS_GEOM_H - -#include "../../codegen/util_template_inst.h" - -void generate_marie_headers_for_graphics_geom() { - SpanU8 l = cstr("l1"); - SpanU8 ns = cstr("marie"); - mkdir_nofail("l1/eve/marie"); - generate_eve_span_company_for_primitive(l, ns, cstr("MarieTriangle"), true, false); - generate_eve_span_company_for_primitive(l, ns, cstr("MarieTriangleAttr"), true, false); -} - -#endif \ No newline at end of file diff --git a/src/l1/anne/util_temp_geom.h b/src/l1/anne/util_temp_geom.h index d443f99..fd7aa50 100644 --- a/src/l1/anne/util_temp_geom.h +++ b/src/l1/anne/util_temp_geom.h @@ -4,11 +4,27 @@ #include "../codegen/util_template_inst.h" void generate_util_temp_geom_headers() { - SpanU8 T[] = {cstr("cvec3"), cstr("cvec4"), cstr("vec2"), cstr("vec3"), cstr("vec4")}; + SpanU8 T[] = {cstr("cvec3"), cstr("cvec4"), cstr("vec2"), cstr("vec3"), cstr("vec4"), cstr("s64vec2")}; for (size_t i = 0; i < ARRAY_SIZE(T); i++) { generate_guarded_span_company_for_primitive(cstr("l1"), cstr(""), T[i], cstr("#include \"geom.h\"\n"), true, true); } + for (size_t i = 0; i < ARRAY_SIZE(T); i++) { + VecU8 Type = VecU8_fmt("Span%s", T[i]); + VecU8 Dep = VecU8_fmt("#include \"VecAndSpan_%s.h\"\n", T[i]); + generate_guarded_span_company_for_primitive(cstr("l1"), cstr(""), VecU8_to_span(&Type), + VecU8_to_span(&Dep), true, false); + VecU8_drop(Type); + VecU8_drop(Dep); + } + for (size_t i = 0; i < ARRAY_SIZE(T); i++) { + VecU8 Type = VecU8_fmt("Vec%s", T[i]); + VecU8 Dep = VecU8_fmt("#include \"VecAndSpan_%s.h\"\n", T[i]); + generate_guarded_span_company_for_non_primitive_clonable(cstr("l1"), cstr(""), VecU8_to_span(&Type), + VecU8_to_span(&Dep), true, false); + VecU8_drop(Type); + VecU8_drop(Dep); + } } #endif \ No newline at end of file diff --git a/src/l1/core/VecU8_as_str.h b/src/l1/core/VecU8_as_str.h index 81ac29c..563a95b 100644 --- a/src/l1/core/VecU8_as_str.h +++ b/src/l1/core/VecU8_as_str.h @@ -253,11 +253,11 @@ U32 SpanU8_decode_as_utf8(SpanU8* rem){ } bool SpanU8_is_prefix(SpanU8 a, SpanU8 str){ - return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, 0, a.len)); + return str.len >= a.len && SpanU8_cont_equal(a, (SpanU8){str.data, a.len}); } bool SpanU8_is_postfix(SpanU8 a, SpanU8 str){ - return str.len >= a.len && SpanU8_cont_equal(a, SpanU8_span(str, str.len - a.len, a.len)); + return str.len >= a.len && SpanU8_cont_equal(a, (SpanU8){str.data + str.len - a.len, a.len}); } #endif diff --git a/src/l1/marie/geom_alg_utils.h b/src/l1/marie/geom_alg_utils.h index dd26bd2..ed26754 100644 --- a/src/l1/marie/geom_alg_utils.h +++ b/src/l1/marie/geom_alg_utils.h @@ -25,7 +25,7 @@ _Static_assert(FLT_MIN_EXP == -125, "Float is not binary32"); uint32_t marie_pun_float2u32(float f) { uint32_t u; - memcpy(&u, &f, sizeof u); + memcpy(&u, &f, sizeof(uint32_t)); return u; } @@ -37,6 +37,8 @@ bool marie_same_dir3(float A0, float A1, float A2, float B) { return A0 == 0 || A1 == 0 || A2 == 0 || (diff & 0x80000000u) == 0; } +// This function uses floating point arithmetic, which is very bad +/* cross product (vi - u) x (vj - u). If {vi, vj, vu} are points of CCW triangle, this will be it's positive surface */ float marie_surface(vec2 vi, vec2 vj, vec2 u) { return u.x * (vi.y - vj.y) + u.y * (vj.x - vi.x) + (vi.x * vj.y - vj.x * vi.y); } diff --git a/src/l2/anne/r4.h b/src/l2/anne/r4.h index 5fef61d..958b1c4 100644 --- a/src/l2/anne/r4.h +++ b/src/l2/anne/r4.h @@ -5,6 +5,7 @@ #include "../../../gen/l1/pixel_masses.h" #include "../marie/rasterization.h" #include "../marie/texture_processing.h" +#include "../marie/shape_geom.h" #include /* generating my cool textures2 */ @@ -287,7 +288,8 @@ typedef struct { void draw_polygon_on_normal_texture_smooth_param_surf_h_draw_cb(void* ug, S32 x, S32 y, vec4 attr) { draw_polygon_on_normal_texture_smooth_param_surf_H_DrawGuest* g = ug; vec3 normal = g->my_client.fn(g->my_client.guest, (vec2){attr.x, attr.y}); - *TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel(normal); + if (TextureDataR8G8B8A8_is_inside(g->tex, x, y)) + *TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel(normal); } void draw_polygon_on_normal_texture_smooth_param_surf( @@ -319,7 +321,8 @@ void draw_polygon_on_normal_texture_exaggerated_param_surf_draw_cb(void* ug, S32 draw_polygon_on_normal_texture_exaggerated_param_surf_H_DrawGuest* g = ug; vec3 normal = g->my_client.fn(g->my_client.guest, (vec3){attr.x, attr.y, attr.z}); vec3 tang_normal = mat3_mul_vec3(g->BNT_trans, normal); - *TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel(tang_normal); + if (TextureDataR8G8B8A8_is_inside(g->tex, x, y)) + *TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel(tang_normal); } /* We can't derive texture coordinates from parameter space coordinates, you have to do it yourself. @@ -341,30 +344,8 @@ void draw_polygon_on_normal_texture_nat_cords_exaggerated_param_surf( // todo: also, maybe, add a function to derive BNT and do cool stuff with trop mat3x2 -typedef struct { - TextureDataR8G8B8A8* tex; -} draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest; - -void draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb(void* ug, S32 x, S32 y, vec4 attr) { - draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest* g = ug; - *TextureDataR8G8B8A8_mat(g->tex, x, y) = compress_normal_vec_into_norm_texel((vec3){0, 1, 0}); -} - -void draw_polygon_on_normal_texture_nat_cords_absolutely_flat(TextureDataR8G8B8A8* tex, - vec2 ta, vec2 tb, vec2 tc - ) { - draw_polygon_on_normal_texture_absolutely_flat_H_DrawGuest aboba = {tex}; - marie_rasterize_triangle_with_attr((MariePlaneVertAttr){.pos = ta}, (MariePlaneVertAttr){.pos = tb}, - (MariePlaneVertAttr){.pos = tc}, (FnMarieRasterizerCallback){ - .fn = draw_polygon_on_normal_texture_absolutely_flat_h_draw_cb, .guest = (void*)&aboba}); -} - -// todo: replace it with a "color everything in one color" function -void draw_polygon_on_normal_texture_absolutely_flat(TextureDataR8G8B8A8* tex, - vec2 pa, vec2 pb, vec2 pc, mat3x2 trop -) { - draw_polygon_on_normal_texture_nat_cords_absolutely_flat(tex, mat3x2_mul_vec3(trop, vec2_and_one(pa)), - mat3x2_mul_vec3(trop, vec2_and_one(pb)), mat3x2_mul_vec3(trop, vec2_and_one(pc))); +void draw_triang_on_normal_tex_absolutely_flat(TextureDataR8G8B8A8* tex, MarieTriangle t){ + TextureDataR8G8B8A8_triangle_set_color_cvec4(tex, compress_normal_vec_into_norm_texel((vec3){0, 1, 0}), t); } @@ -421,58 +402,38 @@ void TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka( } +#include "../../../gen/l1/margaret/png_pixel_masses.h" +#include "../marie/texture_processing.h" +#include "../../l1/system/fsmanip.h" +#include "../alice/model_file.h" -// todo: rewrite this crrp (again) -TextureDataR8G8B8A8 generate_tex_template_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) { +/* Situation: we generated vertices array of generic mesh, we filled .tex attribute (scaled pixel pos) + * Now I want the normally scaled stuff back */ +MarieTriangle restore_triangle_from_mesh_topology(const VecGenericMeshVertexInc* vertices, + U32 texture_width, U32 texture_height, U32 vi1, U32 vi2, U32 vi3){ + vec2 tex1 = VecGenericMeshVertexInc_at(vertices, vi1)->tex; + vec2 tex2 = VecGenericMeshVertexInc_at(vertices, vi2)->tex; + vec2 tex3 = VecGenericMeshVertexInc_at(vertices, vi3)->tex; + return (MarieTriangle){ + .v0 = {tex1.x * (float)texture_width, tex1.y * (float)texture_height}, + .v1 = {tex2.x * (float)texture_width, tex2.y * (float)texture_height}, + .v2 = {tex3.x * (float)texture_width, tex3.y * (float)texture_height}, + }; +} + +MarieTriangle restore_triangle_from_vert_array_complete_mesh_topology(const VecGenericMeshVertexInc* vertices, + U32 texture_width, U32 texture_height, U32 vi1, U32 vi2, U32 vi3, VecU32* indexes){ + VecU32_append_span(indexes, (SpanU32){(U32[]){vi1, vi2, vi3}, 3}); + return restore_triangle_from_mesh_topology(vertices, texture_width, texture_height, vi1, vi2, vi3); +} + +void generate_template_and_normal_and_model_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); - size_t width_pix = (size_t)ceilf(s_resol * (2 * r + w)); - size_t height_pix = (size_t)ceilf(s_resol * (2 * r + (float)k * l)); - 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 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_parametrized_triangle_of_one_color(&res, color_1, (MarieTriangle){v0tex, v4tex, v5tex}, cord_resol_trop); - TextureDataR8G8B8A8_draw_parametrized_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++) { - 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_parametrized_triangle_of_one_color(&res, color_2, (MarieTriangle){v0tex, B, A}, cord_resol_trop); - } - for (size_t i = 1; i <= k; 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_parametrized_triangle_of_one_color(&res, color_3, (MarieTriangle){v1tex, A, B}, cord_resol_trop); - } - 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; - // todo: replace this crrp with something more normal - TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, c, (MarieTriangle){A, B, C}, cord_resol_trop); - TextureDataR8G8B8A8_draw_parametrized_triangle_of_one_color(&res, c, (MarieTriangle){A, C, D}, cord_resol_trop); - } - - Bublazhuzhka crap_on_back_side = fill_rectangle_with_crap(w, r); - 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; } + /* Use it as a callback in normal map drawing functions that work with smooth (smooth / flat / cylindrical) * height maps. Guest pointer is of type Bublazhuzhka* */ vec2 height_map_cb_that_uses_bublazhuzhka(void* ug, vec2 v) { @@ -481,66 +442,27 @@ vec2 height_map_cb_that_uses_bublazhuzhka(void* ug, vec2 v) { } // todo: rewrite this crrp and merge it with other one-fourth-of-a-cylinder generiting functions -TextureDataR8G8B8A8 generate_normal_tex_for_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k) { +void r4_asset_gen_generic_mesh_one_fourth_of_a_cylinder(float s_resol, float w, float r, U32 k, + VecU8 path_to_mesh, VecU8 path_to_template_tex, VecU8 path_to_normal_tex + ) { assert(k >= 1); const float a = M_PI_2f / (float)k; const float l = 2 * r * sinf(M_PI_4f / (float)k); - size_t width_pix = (size_t)ceilf(s_resol * (2 * r + w)); - size_t height_pix = (size_t)ceilf(s_resol * (2 * r + (float)k * l)); - 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 v4tex = {r, 0}; - const vec2 v5tex = {r + w, 0}; - TextureDataR8G8B8A8 res = TextureDataR8G8B8A8_new(width_pix, height_pix); - Bublazhuzhka crap_on_the_back_side = fill_rectangle_with_crap(w, r); - mat3x2 trop_back_side = {.x.x = cord_resol.x, .y.y = cord_resol.y, .z = vec2_mul_vec2((vec2){r, r}, cord_resol)}; - draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){w, 0}, (vec2){w, r}, trop_back_side, - (FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side}); - draw_polygon_on_normal_texture_flat_param_surf(&res, (vec2){0, 0}, (vec2){0, r}, (vec2){w, r}, trop_back_side, - (FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side}); - Bublazhuzhka_drop(crap_on_the_back_side); + float r_mag = r * s_resol; + float w_mag = w * s_resol; + float l_mag = l * s_resol; - mat3x2 str = {.x.x = cord_resol.x, .y.y = cord_resol.y}; - draw_polygon_on_normal_texture_absolutely_flat(&res, v0tex, v1tex, v4tex, str); - draw_polygon_on_normal_texture_absolutely_flat(&res, v1tex, v4tex, v5tex, str); - for (size_t i = 0; i < k; i++) { - vec2 A = {r - sinf((float)i * a) * r, r + cosf((float)i * a) * r}; - vec2 B = {r - sinf((float)(i + 1) * a) * r, r + cosf((float)(i + 1) * a) * r}; - draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r, r}, str); - } - for (size_t i = 0; i < k; i++) { - vec2 A = {r + w + sinf((float)i * a) * r, r + cosf((float)i * a) * r}; - vec2 B = {r + w + sinf((float)(i + 1) * a) * r, r + cosf((float)(i + 1) * a) * r}; - draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, (vec2){r + w, r}, str); - } - for (size_t i = 0; i < k; i++) { - vec2 A = {r, 2 * r + (float)i * l}; - 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}; - draw_polygon_on_normal_texture_absolutely_flat(&res, A, B, C, str); - draw_polygon_on_normal_texture_absolutely_flat(&res, D, B, C, str); - } - return res; -} + U64 texture_width = (U64)ceilf(2 * r_mag + w_mag); + U64 texture_height = (size_t)ceilf(2 * r_mag + (float)k * l_mag); + // todo: aaaa i am gonna go fucking insane who the fuck wrote trhis shit. AAA, I hate this code so much I hate myself so fuckign much + const vec2 v0tex = {r_mag / (float)texture_width, r_mag / (float)texture_height}; + const vec2 v1tex = {(r_mag + w_mag) / (float)texture_width, r_mag / (float)texture_height}; + const vec2 v2tex = {r_mag / (float)texture_width, 2 * r_mag / (float)texture_height}; + const vec2 v3tex = {(r_mag + w_mag) / (float)texture_width, 2 * r_mag / (float)texture_height}; + const vec2 v6tex = {r_mag / (float)texture_width, 0 / (float)texture_height}; + const vec2 v7tex = {(r_mag + w_mag) / (float)texture_width, 0 / (float)texture_height}; - - -GenericMeshTopology generate_one_fourth_of_a_cylinder(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); - float tex_width = 2 * r + w; - float tex_height = 2 * r + (float)k * l; - - const vec2 v0tex = {r / tex_width, r / tex_height}; - const vec2 v1tex = {(r + w) / tex_width, r / tex_height}; - const vec2 v2tex = {r / tex_width, 2 * r / tex_height}; - const vec2 v3tex = {(r + w) / tex_width, 2 * r / tex_height}; VecGenericMeshVertexInc vertices = VecGenericMeshVertexInc_new_reserved(8 + 4 * k + (k + 2) * 2); VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, 0}, .tex = v0tex}); VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, 0}, .tex = v1tex}); @@ -548,18 +470,18 @@ GenericMeshTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) { VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, r, 0}, .tex = v3tex}); VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, 0}, .tex = v0tex}); VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, 0}, .tex = v1tex}); - VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, -r}, .tex = {r / tex_width, 0}}); - VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, -r}, .tex = {(r + w) / tex_width, 0}}); + VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, -r}, .tex = v6tex}); + VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, -r}, .tex = v7tex}); for (U32 i = 0; i < k; i++) { for (int j = 0; j < 2; j++) { VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){ .pos = {0, cosf(a * (float)(i + j)) * r, -sinf(a * (float)(i + j)) * r}, - .tex = {v2tex.x, v2tex.y + (float)(i + j) * l / tex_height} + .tex = {v2tex.x, v2tex.y + (float)(i + j) * l_mag / (float)texture_height} }); VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){ .pos = {w, cosf(a * (float)(i + j)) * r, -sinf(a * (float)(i + j)) * r}, - .tex = {v3tex.x, v3tex.y + (float)(i + j) * l / tex_height} + .tex = {v3tex.x, v3tex.y + (float)(i + j) * l_mag / (float)texture_height} }); } } @@ -568,32 +490,97 @@ GenericMeshTopology generate_one_fourth_of_a_cylinder(float w, float r, U32 k) { for (U32 i = 0; i <= k; i++) { VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){ .pos = {0, cosf(a * (float)i) * r, -sinf(a * (float)i) * r}, - .tex = (vec2){ (r - r *sinf(a * (float)i)) / tex_width, (r + r * cosf(a * (float)i)) / tex_height}, + .tex = (vec2){ + (r_mag - r_mag * sinf(a * (float)i)) / (float)texture_width, + (r_mag + r_mag * cosf(a * (float)i)) / (float)texture_height}, }); } VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {0, 0, 0}, .tex = v0tex}); for (U32 i = 0; i <= k; i++) { VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){ .pos = {w, cosf(a * (float)i) * r, -sinf(a * (float)i) * r}, - .tex = (vec2){ (r + w + r * sinf(a * (float)i)) / tex_width, (r + r * cosf(a * (float)i)) / tex_height}, + .tex = (vec2){ + (r_mag + w_mag + r_mag * sinf(a * (float)i)) / (float)texture_width, + (r_mag + r_mag * cosf(a * (float)i)) / (float)texture_height}, }); } VecGenericMeshVertexInc_append(&vertices, (GenericMeshVertexInc){.pos = {w, 0, 0}, .tex = v1tex}); assert(vertices.len == 8 + 4 * k + (k + 2) * 2); VecU32 indexes = VecU32_new_reserved(3*(4+2*k+2*k)); - U32 _span_0[] = {7, 5, 4, 7, 4, 6, 1, 3, 0, 3, 2, 0}; - VecU32_append_span(&indexes, (SpanU32){.data = _span_0, .len = ARRAY_SIZE(_span_0)}); - for (U32 i = 0; i < k; i++) { - U32 _span_1[] = { - 8 + 4 * k + k + 1, 8 + 4 * k + i, 8 + 4 * k + i + 1, - 8 + 4 * k + 2 * k + 3, 8 + 4 * k + (k + 2) + i + 1, 8 + 4 * k + (k + 2) + i, - 8 + 4 * i + 0, 8 + 4 * i + 1, 8 + 4 * i + 3, - 8 + 4 * i + 0, 8 + 4 * i + 3, 8 + 4 * i + 2, - }; - VecU32_append_span(&indexes, (SpanU32){.data = _span_1, .len = ARRAY_SIZE(_span_1)}); + + TextureDataR8G8B8A8 normal_tex = TextureDataR8G8B8A8_new(texture_width, texture_height); + TextureDataR8G8B8A8 temp_tex = TextureDataR8G8B8A8_new(texture_width, texture_height); + + { + Bublazhuzhka crap_on_the_back_side = fill_rectangle_with_crap(w, r); + mat3x2 trop = (mat3x2){.x.x = s_resol, .y.y = s_resol, .z.x = r_mag, .z.y = r_mag}; + draw_polygon_on_normal_texture_flat_param_surf(&normal_tex, (vec2){0, 0}, (vec2){w, 0}, (vec2){w, r}, trop, + (FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side}); + draw_polygon_on_normal_texture_flat_param_surf(&normal_tex, (vec2){0, 0}, (vec2){0, r}, (vec2){w, r}, trop, + (FnHeightMapGradFlatSurfCallback){.fn = height_map_cb_that_uses_bublazhuzhka, .guest = &crap_on_the_back_side}); + TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka(&temp_tex, &crap_on_the_back_side, (MarieTriangle){{0, r}, {0, 0}, {w, 0}}, trop); + TextureDataR8G8B8A8_draw_triang_part_bublazhuzhka(&temp_tex, &crap_on_the_back_side, (MarieTriangle){{0, r}, {w, 0}, {w, r}}, trop); + Bublazhuzhka_drop(crap_on_the_back_side); + VecU32_append_span(&indexes, (SpanU32){.data = (U32[]){1, 3, 0, 3, 2, 0}, .len = 6}); } - return (GenericMeshTopology){.vertices = vertices, .indexes = indexes}; + { + U32 A = 4, B = 5, C = 6, D = 7; + vec3 c1 = {0.5f, 0.9f, 0.5f}; + MarieTriangle t1 = restore_triangle_from_vert_array_complete_mesh_topology(&vertices, + texture_width, texture_height, D, B, A, &indexes); + MarieTriangle t2 = restore_triangle_from_vert_array_complete_mesh_topology(&vertices, + texture_width, texture_height, D, A, C, &indexes); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&temp_tex, c1, t1); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&temp_tex, c1, t2); + draw_triang_on_normal_tex_absolutely_flat(&normal_tex, t1); + draw_triang_on_normal_tex_absolutely_flat(&normal_tex, t2); + VecU32_append_span(&indexes, (SpanU32){.data = (U32[]){D, B, A, D, A, C}, .len = 6}); + } + + for (size_t i = 0; i < k; i++) { + U32 O = 8 + 4 * k + k + 1, A = 8 + 4 * k + i, B = 8 + 4 * k + i + 1; + vec3 color_2 = {0.1f, 0.25f, 0.66f}; + MarieTriangle t = restore_triangle_from_vert_array_complete_mesh_topology(&vertices, + texture_width, texture_height, O, A, B, &indexes); + draw_triang_on_normal_tex_absolutely_flat(&normal_tex, t); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&temp_tex, color_2, t); + } + + for (size_t i = 0; i < k; i++) { + U32 O = 8 + 4 * k + 2 * k + 3, B = 8 + 4 * k + (k + 2) + i + 1, A = 8 + 4 * k + (k + 2) + i; + vec3 color_3 = {0.2f, 0.3f, 0.9f}; + MarieTriangle t = restore_triangle_from_vert_array_complete_mesh_topology(&vertices, + texture_width, texture_height, O, B, A, &indexes); + draw_triang_on_normal_tex_absolutely_flat(&normal_tex, t); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&temp_tex, color_3, t); + // vec2 A = {r + w + sinf((float)i * a) * r, r + cosf((float)i * a) * r}; + // vec2 B = {r + w + sinf((float)(i + 1) * a) * r, r + cosf((float)(i + 1) * a) * r}; + } + for (size_t i = 0; i < k; i++) { + U32 A = 8 + 4 * i + 0, B = 8 + 4 * i + 1, C = 8 + 4 * i + 2, D = 8 + 4 * i + 3; + vec3 c4 = {0.1f, 0.5f, 0.7f}; + vec3 c5 = {0.7f, 0.05f, 0.2f}; + vec3 c = i % 2 ? c4 : c5; + + MarieTriangle t1 = restore_triangle_from_vert_array_complete_mesh_topology(&vertices, + texture_width, texture_height, A, B, D, &indexes); + MarieTriangle t2 = restore_triangle_from_vert_array_complete_mesh_topology(&vertices, + texture_width, texture_height, A, D, C, &indexes); + draw_triang_on_normal_tex_absolutely_flat(&normal_tex, t1); + draw_triang_on_normal_tex_absolutely_flat(&normal_tex, t2); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&temp_tex, c, t1); + TextureDataR8G8B8A8_draw_triangle_of_one_color(&temp_tex, c, t2); + } + + alice_write_generic_mesh_to_file((GenericMeshTopology){.vertices = vertices, .indexes = indexes}, path_to_mesh); + TextureDataR8G8B8A8_write_to_png_nofail(&normal_tex, VecU8_to_span(&path_to_normal_tex)); + TextureDataR8G8B8A8_drop(normal_tex); + VecU8_drop(path_to_normal_tex); + + TextureDataR8G8B8A8_write_to_png_nofail(&temp_tex, VecU8_to_span(&path_to_template_tex)); + TextureDataR8G8B8A8_drop(temp_tex); + VecU8_drop(path_to_template_tex); } U32 quad_to_triangles_conv_arr[6] = {0, 1, 2, 0, 2, 3}; @@ -666,25 +653,6 @@ CubeVertOfFace CubeVertOfFace_next(CubeVertOfFace vert) { return (CubeVertOfFace){vert.face, (vert.vert_on_it + 1) % 4}; } -#include "../../../gen/l1/margaret/png_pixel_masses.h" -#include "../marie/texture_processing.h" -#include "../../l1/system/fsmanip.h" -#include "../alice/model_file.h" - -/* Situation: we generated vertices array of generic mesh, we filled .tex attribute (scaled pixel pos) - * Now I want the normally scaled stuff back */ -MarieTriangle restore_triangle_from_mesh_topology(const VecGenericMeshVertexInc* vertices, - U32 texture_width, U32 texture_height, U32 vi1, U32 vi2, U32 vi3){ - vec2 tex1 = VecGenericMeshVertexInc_at(vertices, vi1)->tex; - vec2 tex2 = VecGenericMeshVertexInc_at(vertices, vi2)->tex; - vec2 tex3 = VecGenericMeshVertexInc_at(vertices, vi3)->tex; - return (MarieTriangle){ - .v0 = {tex1.x * (float)texture_width, tex1.y * (float)texture_height}, - .v1 = {tex2.x * (float)texture_width, tex2.y * (float)texture_height}, - .v2 = {tex3.x * (float)texture_width, tex3.y * (float)texture_height}, - }; -} - void r4_generate_flat_normal_map(VecU8 save_path){ TextureDataR8G8B8A8 normal = TextureDataR8G8B8A8_new(1, 1); *TextureDataR8G8B8A8_mat(&normal, 0, 0) = compress_normal_vec_into_norm_texel((vec3){0, 1, 0}); @@ -825,36 +793,37 @@ void r4_asset_gen_generic_mesh_quad(float width, float length, VecU8 path_to_sav /* a is r at bottom, b is r on top. y is in [0, height]. Shape is symmetrical from Oy */ ShinyMeshTopology generate_shiny_lamp(float height, float a, float b){ + vec3 d_clr = {0.1f, 0.1f, 0.2f}; ShinyMeshVertexInc vert[24] = { - {{+b, height, +b}}, - {{+b, 0, +b}}, - {{+b, 0, -b}}, - {{+b, height, -b}}, + {{+b, height, +b}, d_clr}, + {{+b, 0, +b}, d_clr}, + {{+b, 0, -b}, d_clr}, + {{+b, height, -b}, d_clr}, - {{-b, 0, -b}}, - {{-b, 0, +b}}, - {{-b, height, +b}}, - {{-b, height, -b}}, + {{-b, 0, -b}, d_clr}, + {{-b, 0, +b}, d_clr}, + {{-b, height, +b}, d_clr}, + {{-b, height, -b}, d_clr}, - {{+b, height, +b}}, - {{+b, height, -b}}, - {{-b, height, -b}}, - {{-b, height, +b}}, + {{+b, height, +b}, d_clr}, + {{+b, height, -b}, d_clr}, + {{-b, height, -b}, d_clr}, + {{-b, height, +b}, d_clr}, - {{-b, 0, -b}}, - {{+b, 0, -b}}, - {{+b, 0, +b}}, - {{-b, 0, +b}}, + {{-b, 0, -b}, d_clr}, + {{+b, 0, -b}, d_clr}, + {{+b, 0, +b}, d_clr}, + {{-b, 0, +b}, d_clr}, - {{+b, height, +b}}, - {{-b, height, +b}}, - {{-b, 0, +b}}, - {{+b, 0, +b}}, + {{+b, height, +b}, d_clr}, + {{-b, height, +b}, d_clr}, + {{-b, 0, +b}, d_clr}, + {{+b, 0, +b}, d_clr}, - {{-b, 0, -b}}, - {{-b, height, -b}}, - {{+b, height, -b}}, - {{+b, 0, -b}}, + {{-b, 0, -b}, d_clr}, + {{-b, height, -b}, d_clr}, + {{+b, height, -b}, d_clr}, + {{+b, 0, -b}, d_clr}, }; VecShinyMeshVertexInc vertices = VecShinyMeshVertexInc_from_span( (SpanShinyMeshVertexInc){ .data = vert, .len = ARRAY_SIZE(vert) }); @@ -866,27 +835,11 @@ ShinyMeshTopology generate_shiny_lamp(float height, float a, float b){ return (ShinyMeshTopology){ .vertices = vertices, .indexes = indexes}; } -void generate_one_forth_of_a_cylinder_with_bublazhuzhka(U64 w, U64 r, U64 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_fmt("l2/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_fmt("l2/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); - } - GenericMeshTopology top = generate_one_fourth_of_a_cylinder((float)w, (float)r, k); - alice_write_generic_mesh_to_file(top, VecU8_fmt("l2/models/log_%u_%u_%u.AliceGenericMesh", w, r, k)); +void r4_asset_gen_generic_mesh_one_fourth_of_a_cylinder_2(U64 w, U64 r, U64 k) { + r4_asset_gen_generic_mesh_one_fourth_of_a_cylinder(120, (float)w, (float)r, k, + VecU8_fmt("l2/models/log_%u_%u_%u.AliceGenericMesh", w, r, k), + VecU8_fmt("l2/textures/log_%u_%u_%u_TEMPLATE.png", w, r, k), + VecU8_fmt("l2/textures/log_%u_%u_%u_NORMAL.png", w, r, k)); } /* We are on l2 */ @@ -894,7 +847,7 @@ int gen_assets_for_r4() { mkdir_nofail("l2/models"); mkdir_nofail("l2/textures"); mkdir_nofail("l2/textures/r4"); - generate_one_forth_of_a_cylinder_with_bublazhuzhka(10, 2, 6); + r4_asset_gen_generic_mesh_one_fourth_of_a_cylinder_2(10, 2, 6); alice_write_shiny_mesh_to_file(generate_shiny_cube((vec3){0.6f, 0.6f, 0.7f}), vcstr("l2/models/cube.AliceShinyMesh")); alice_write_shiny_mesh_to_file(generate_shiny_lamp(0.3f, 0.13f, 0.19f), vcstr("l2/models/lamp.AliceShinyMesh")); r4_asset_gen_generic_mesh_quad(10, 10, vcstr("l2/models/quad.AliceGenericMesh")); diff --git a/src/l2/margaret/vulkan_utils.h b/src/l2/margaret/vulkan_utils.h index 8b5fa05..1159a91 100644 --- a/src/l2/margaret/vulkan_utils.h +++ b/src/l2/margaret/vulkan_utils.h @@ -947,9 +947,9 @@ VkSampler margaret_create_sampler(VkPhysicalDevice physical_device, VkDevice dev .magFilter = make_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, .minFilter = make_linear ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, .mipmapMode = make_linear ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST, - .addressModeU = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - .addressModeV = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, - .addressModeW = VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, + .addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT, + .addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT, + .addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT, .mipLodBias = 0.f, // will understand that when I generate mipmaps .anisotropyEnable = physical_device_features.samplerAnisotropy, // only if feature device_used_features.samplerAnisotropy was enabled diff --git a/src/l2/marie/shape_geom.h b/src/l2/marie/shape_geom.h index 7dcb74c..d4e8b96 100644 --- a/src/l2/marie/shape_geom.h +++ b/src/l2/marie/shape_geom.h @@ -1,22 +1,344 @@ #ifndef PROTOTYPE1_SRC_L2_MARIE_SHAPE_GEOM_H #define PROTOTYPE1_SRC_L2_MARIE_SHAPE_GEOM_H -#include "../../../gen/l1_5/marie/clipping.h" +#include "../../../gen/l1/VecAndSpan_vec2.h" +#include "../../../gen/l1/VecAndSpan_U64.h" +#include "../../../gen/l1/VecAndSpan_U8.h" +#include "../../../gen/l1/VecAndSpan_s64vec2.h" +#include "../../../gen/l1/VecVecs64vec2.h" +#include "../../../gen/l1/VecAndSpan_VecU64.h" +#include +#include -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) { - vec2 t = C.v0; - C.v0 = C.v1; - C.v1 = t; +/* any inv exp q => any abs bitness a => + * vec2#(a)#.(q) -> vec2#(a)#.(q) -> vec2#(a)#.(q) -> vec2#(2a+3)#.(2q) */ +S64 marie_precise_surface(s64vec2 vi, s64vec2 vj, s64vec2 u){ + s64vec2 da = s64vec2_minus_s64vec2(vi, u); + s64vec2 db = s64vec2_minus_s64vec2(vj, u); + /* da, db are vec2#(a+1)#.(q) */ + return da.x * db.y - da.y * db.x; +} + +bool marie_precise_do_intersect_2d_interv_and_seg(s64vec2 a, s64vec2 b, s64vec2 c, s64vec2 d){ + s64vec2 alpha = s64vec2_minus_s64vec2(b, a); + s64vec2 beta = s64vec2_minus_s64vec2(c, d); + s64vec2 gamma = s64vec2_minus_s64vec2(c, a); + S64 det_alpha_beta = alpha.x * beta.y - alpha.y * beta.x; + S64 det_gamma_beta = gamma.x * beta.y - gamma.y * beta.x; + if (det_alpha_beta == 0) { + if (det_gamma_beta != 0) + return false; + if (a.x < b.x) { + return !(c.x <= a.x && d.x <= a.x) && !(b.x <= c.x && b.x <= d.x); + } else if (b.x < a.x) { + return !(c.x <= b.x && d.x <= b.x) && !(a.x <= c.x && a.x <= d.x); + } else if (a.y < b.y) { + return !(c.y <= a.y && d.y <= a.y) && !(b.y <= c.y && b.y <= d.y); + } else if (b.y < a.y) { + return !(c.y <= b.y && d.y <= b.y) && !(a.y <= c.y && a.y <= d.y); + } else + return false; /* This code is unreachable, actually */ } - float ST = marie_surface(T.v0, T.v1, T.v2); - if (ST < 0) { - vec2 t = T.v0; - T.v0 = T.v1; - T.v1 = t; + /* Return det_gamma_beta/det_alpha_beta in (0; 1) */ + return 0 < det_gamma_beta && det_gamma_beta < det_alpha_beta; +} + +/* Does not work for degenerate case where s(b_prev, b, b_next) = 0. + * Returns false if a is on the edge of angle(b_prev, b, b_next) */ +bool marie_precise_is_in_ccw_angle(s64vec2 b_prev, s64vec2 b, s64vec2 b_next, s64vec2 a){ + S64 sx = marie_precise_surface(b_prev, b, b_next); + S64 sy = marie_precise_surface(b_prev, b, a); + S64 sz = marie_precise_surface(b, b_next, a); + if (sx < 0) { + return sy > 0 || sz > 0; + } else { + return sy > 0 && sz > 0; } - marie_clip_ccw_triang_with_ccw_triang_append_to_Vec(C, T, pile); +} + +/* Read source code to understand */ +bool marie_order_s64vec2_less(s64vec2 a, s64vec2 b){ + return a.x < b.x || (a.x == b.x && a.y < b.y); +} + +typedef struct{ + U64 prev, next; + bool definitely_ear; +} MarieEarCuttingTriangulVertState; + +#include "../../../gen/l1/eve/marie/VecMarieEarCuttingTriangulVertState.h" + +/* P : Span, but widest computational bitness is #(2a + 3) */ +void marie_ear_cutting_triangulation_check_vertex(Spans64vec2 P, const VecMarieEarCuttingTriangulVertState* rem, + VecU64* ear_queue, U64 x + ){ + U64 xp = rem->buf[x].prev; + U64 xn = rem->buf[x].next; + U64 xnn = rem->buf[xn].next; + s64vec2 A = P.data[xp]; + s64vec2 B = P.data[x]; + s64vec2 C = P.data[xn]; + if (marie_precise_surface(A, B, C) <= 0) { + /* We may get input case where C == B (triangle of two vertices). This if block handles that case */ + return; + } + for (U64 i = xnn; i != xp; i = rem->buf[i].next) { + s64vec2 S = P.data[i]; + if (marie_precise_surface(A, B, S) >= 0 || + marie_precise_surface(B, C, S) >= 0 || marie_precise_surface(C, A, S) >= 0) { + return; + } + } + if (!rem->buf[x].definitely_ear) { + rem->buf[x].definitely_ear = true; + VecU64_append(ear_queue, x); + } +} + +/* P must be CCW and non-self-intersecting, + * P : Span, but widest computational bitness is #(2a + 3) + * Throws exceptions if your numbers are bad */ +VecU64 marie_polygon_ear_cutting_triangulation(Spans64vec2 P){ + assert(P.len >= 3 && P.len < INT32_MAX); + VecMarieEarCuttingTriangulVertState vertices = VecMarieEarCuttingTriangulVertState_new_zeroinit(P.len); + for (size_t i = 0; i < P.len - 1; i++) { + vertices.buf[i].next = i + 1; + } + for (size_t i = 1; i < P.len; i++) { + vertices.buf[i].prev = i - 1; + } + VecU64 triangles = VecU64_new(); + VecU64 ear_queue = VecU64_new(); + U64 n = P.len; /* will decrease to 2 */ + for (U64 i = 0; i < n; i++) { + marie_ear_cutting_triangulation_check_vertex(P, &vertices, &ear_queue, i); + } + while (n > 2) { + if (ear_queue.len == 0) { + abortf("FATAL EXCEPTION. You messed up floating grid resolution and now marie polygon " + "ear cutting algorithm couldn't find " + "an ear to cut. If that happened in production, well, you suck\n"); + } + U64 B = VecU64_pop(&ear_queue); + assert(vertices.buf[B].definitely_ear); + U64 A = vertices.buf[B].prev; + U64 C = vertices.buf[B].next; + assert(A != C); + vertices.buf[A].next = C; + vertices.buf[C].prev = A; + marie_ear_cutting_triangulation_check_vertex(P, &vertices, &ear_queue, A); + marie_ear_cutting_triangulation_check_vertex(P, &vertices, &ear_queue, C); + VecU64_append_span(&triangles, (SpanU64){.data = (U64[]){A, B, C}, .len = 3}); + n--; + } + + return triangles; +} + +/* Recursion is dead. Recursion remains dead. And we have killed it. + * Used in hole-connecting triangulation algorithm */ +typedef struct { + U64 hole_id; + U64 vertex_in_hole_id; + U64 progress; + U64 progress_in_starting_vertex; +} MarieHoleConnectTriangStackFrame; + +#include "../../../gen/l1/eve/marie/VecMarieHoleConnectTriangStackFrame.h" + +/* Used in hole-connecting triangulation algorithm */ +typedef struct{ + U64 hole_id; + U64 vertex_in_hole_id; +} MarieHoleAndVertexId; + +#include "../../../gen/l1/eve/marie/VecMarieHoleAndVertexId.h" +#include "../../../gen/l1/eve/marie/VecVecMarieHoleAndVertexId.h" +#include "../../../gen/l1/eve/marie/VecVecVecMarieHoleAndVertexId.h" + +typedef struct { + const VecVecs64vec2* P; + s64vec2 o; +} marie_polygon_hole_removal_H_CompConnGuest; + +int marie_polygon_hole_removal_h_comp_connection(const void* A_ptr, const void* B_ptr, void* ug){ + MarieHoleAndVertexId A = *(MarieHoleAndVertexId*)A_ptr; + MarieHoleAndVertexId B = *(MarieHoleAndVertexId*)B_ptr; + const marie_polygon_hole_removal_H_CompConnGuest* g = + (const marie_polygon_hole_removal_H_CompConnGuest*)ug; + const VecVecs64vec2* P = ((const marie_polygon_hole_removal_H_CompConnGuest*)ug)->P; + s64vec2 o = ((const marie_polygon_hole_removal_H_CompConnGuest*)ug)->o; + s64vec2 a = P->buf[A.hole_id].buf[A.vertex_in_hole_id]; + s64vec2 b = P->buf[B.hole_id].buf[B.vertex_in_hole_id]; + assert(marie_order_s64vec2_less(a, o)); + assert(marie_order_s64vec2_less(b, o)); + S64 s = marie_precise_surface(a, o, b); + assert(s != 0); + return s > 0 ? 1 : -1; +} + +/* Holes must not touch each other and must not touch outer polygon, + * lowest S64 value is taken by special purpose. But don't worry about that */ +VecMarieHoleAndVertexId marie_polygon_hole_removal(const VecVecs64vec2* P){ + assert(P->len >= 1); + assert(P->buf[0].len >= 3); + size_t HN = P->len; + + VecU64 rightest_vertex = VecU64_new_zeroinit(HN); + for (size_t hole = 1; hole < HN; hole++) { + U64 ans = UINT64_MAX; + size_t hs = P->buf[hole].len; + assert(hs >= 3); + s64vec2 old_v = {INT64_MIN, INT64_MIN}; + bool got_neg_surf = false; + for (size_t ai = 0; ai < hs; ai++) { + size_t a_prev = ai > 0 ? ai - 1 : hs - 1; + size_t a_next = ai + 1 < hs ? ai + 1 : 0; + s64vec2 new_v = P->buf[hole].buf[ai]; + s64vec2 a_prev_v = P->buf[hole].buf[a_prev]; + s64vec2 a_next_v = P->buf[hole].buf[a_next]; + bool this_is_neg_surf = marie_precise_surface(a_prev_v, new_v, a_next_v) < 0; + if (new_v.x > old_v.x || (new_v.x == old_v.x && new_v.y > old_v.y) || + (new_v.x == old_v.x && new_v.y == old_v.y && this_is_neg_surf)){ + /* two 'negative-surface' vertices of a hole sharing the same position is illegal */ + assert(!this_is_neg_surf || !got_neg_surf); + ans = ai; + old_v = new_v; + got_neg_surf = this_is_neg_surf; + } + } + /* Most-right not being 'negative-surface' vertice is impossible */ + assert(got_neg_surf); + rightest_vertex.buf[hole] = ans; + } + /* Topmost polygon perimeter (hole zero) has no umbilical vertex, therefore we set it to some impossibly big value*/ + rightest_vertex.buf[0] = UINT64_MAX; + + VecVecVecMarieHoleAndVertexId connections = VecVecVecMarieHoleAndVertexId_new_reserved(HN); + for (size_t hole = 0; hole < HN; hole++) { + size_t hs = P->buf[hole].len; + VecVecVecMarieHoleAndVertexId_append(&connections, VecVecMarieHoleAndVertexId_new_reserved(hs)); + for (size_t p = 0; p < hs; p++) { + VecVecMarieHoleAndVertexId_append(&connections.buf[hole], VecMarieHoleAndVertexId_new()); + } + } + VecMarieHoleAndVertexId parent_vertex_of_hole = VecMarieHoleAndVertexId_new_zeroinit(HN); + for (size_t hole = 1; hole < HN; hole++) { + size_t a_hs = P->buf[hole].len; + U64 ai = rightest_vertex.buf[hole]; + s64vec2 a = P->buf[hole].buf[ai]; + U64 ai_next = ai + 1 < a_hs ? ai + 1 : 0; + /* Fake child, indicates we need to detour around the perimeter of a hole. + * FOr vertices that have umbilical cord attached, this 'special connection' is appended prior to + * sorting. Sorting it is possible because because pos(ai_next) < a. For other 'non-childish' + * vertices 'special connection' is also appended, but only after we sort everything + */ + assert(marie_order_s64vec2_less(P->buf[hole].buf[ai_next], a)); + VecMarieHoleAndVertexId_append(&connections.buf[hole].buf[ai], (MarieHoleAndVertexId){hole, ai_next}); + + for (size_t b_hole = 0; b_hole < HN; b_hole++) { + if (b_hole == hole) + continue; + size_t b_hs = P->buf[b_hole].len; + for (size_t bi = 0; bi < b_hs; bi++) { + size_t bi_prev = bi > 0 ? bi - 1 : b_hs - 1; + size_t bi_next = bi + 1 < b_hs ? bi + 1 : 0; + s64vec2 b_prev = P->buf[b_hole].buf[bi_prev]; + s64vec2 b = P->buf[b_hole].buf[bi]; + s64vec2 b_next = P->buf[b_hole].buf[bi_next]; + if (!(b.x > a.x || (b.x == a.x && b.y > a.y))) + goto bi_bad_continue; + if (!marie_precise_is_in_ccw_angle(b_prev, b, b_next, a)) + goto bi_bad_continue; + for (size_t c_hole = 0; c_hole < HN; c_hole++) { + size_t c_hs = P->buf[c_hole].len; + for (size_t ci = 0; ci < c_hs; ci++) { + size_t ci_next = ci + 1 < c_hs ? ci + 1 : 0; + s64vec2 c = P->buf[c_hole].buf[ci]; + s64vec2 d = P->buf[c_hole].buf[ci_next]; + if (marie_precise_do_intersect_2d_interv_and_seg(a, b, c, d)) + goto bi_bad_continue; + } + } + /* We are here => current b is good, we need to connect */ + VecMarieHoleAndVertexId_append(&connections.buf[b_hole].buf[bi], (MarieHoleAndVertexId){hole, ai}); + parent_vertex_of_hole.buf[hole] = (MarieHoleAndVertexId){b_hole, bi}; + goto bi_search_end; + bi_bad_continue:{} + } + } + /* We are here => b was not found, which is impossible */ + assert(false); + bi_search_end:{} + } + + for (size_t hole = 0; hole < HN; hole++) { + size_t hs = P->buf[hole].len; + assert(hole == 0 || connections.buf[hole].buf[rightest_vertex.buf[hole]].len >= 1); + for (size_t ai = 0; ai < hs; ai++) { + marie_polygon_hole_removal_H_CompConnGuest aboba = {.P = P, .o = P->buf[hole].buf[ai]}; + VecMarieHoleAndVertexId* vertex_connections = &connections.buf[hole].buf[ai]; + qsort_r(vertex_connections->buf, vertex_connections->len, sizeof(MarieHoleAndVertexId), + marie_polygon_hole_removal_h_comp_connection, &aboba); + if (rightest_vertex.buf[hole] != ai) { + U64 ai_next = ai + 1 < hs ? ai + 1 : 0; + VecMarieHoleAndVertexId_append(vertex_connections, (MarieHoleAndVertexId){hole, ai_next}); + } + assert(vertex_connections->len >= 1); + } + } + for (size_t hole = 0; hole < HN; hole++) { + U64 a = rightest_vertex.buf[hole]; + MarieHoleAndVertexId b = parent_vertex_of_hole.buf[hole]; + VecMarieHoleAndVertexId_append(&connections.buf[hole].buf[a], b); + } + + VecVecU64 progress = VecVecU64_new_reserved(HN); + for (size_t h = 0; h < HN; h++) { + VecVecU64_append(&progress, VecU64_new_zeroinit(P->buf[h].len)); + } + + /* Mapping */ + VecMarieHoleAndVertexId detour = VecMarieHoleAndVertexId_new(); + MarieHoleAndVertexId cur = {0, 0}; + while (true) { + VecMarieHoleAndVertexId* conn = &connections.buf[cur.hole_id].buf[cur.vertex_in_hole_id]; + size_t* p = &progress.buf[cur.hole_id].buf[cur.vertex_in_hole_id]; + if (*p == conn->len) + break; + assert(*p < conn->len); + VecMarieHoleAndVertexId_append(&detour, cur); + cur = conn->buf[*(p++)]; + } + + VecU64_drop(rightest_vertex); + VecVecVecMarieHoleAndVertexId_drop(connections); + VecMarieHoleAndVertexId_drop(parent_vertex_of_hole); + VecVecU64_drop(progress); + return detour; +} + +VecMarieHoleAndVertexId marie_polygon_hole_removal_triangulation(const VecVecs64vec2* P){ + VecMarieHoleAndVertexId detour = marie_polygon_hole_removal(P); + Vecs64vec2 fabricated_mono_polygon = Vecs64vec2_new_zeroinit(detour.len); + for (size_t i = 0; i < detour.len; i++) { + MarieHoleAndVertexId vid = detour.buf[i]; + fabricated_mono_polygon.buf[i] = P->buf[vid.hole_id].buf[vid.vertex_in_hole_id]; + } + VecU64 mono_polygon_triangulation = marie_polygon_ear_cutting_triangulation(Vecs64vec2_to_span(&fabricated_mono_polygon)); + + VecMarieHoleAndVertexId back_translated_triangulation = + VecMarieHoleAndVertexId_new_zeroinit(mono_polygon_triangulation.len); + for (size_t i = 0; i < mono_polygon_triangulation.len; i++) { + U64 fake_vertex_id = mono_polygon_triangulation.buf[i]; + assert(fake_vertex_id < detour.len); + back_translated_triangulation.buf[i] = detour.buf[fake_vertex_id]; + } + + VecMarieHoleAndVertexId_drop(detour); + Vecs64vec2_drop(fabricated_mono_polygon); + VecU64_drop(mono_polygon_triangulation); + return back_translated_triangulation; } #endif diff --git a/src/l2/marie/texture_processing.h b/src/l2/marie/texture_processing.h index f35b25f..7b8a1e8 100644 --- a/src/l2/marie/texture_processing.h +++ b/src/l2/marie/texture_processing.h @@ -85,4 +85,13 @@ void TextureDataR8G8B8A8_draw_triangle_of_one_color(TextureDataR8G8B8A8* self, v .guest = &aboba}); } + +void TextureDataR8G8B8A8_triangle_set_color_cvec4(TextureDataR8G8B8A8* self, cvec4 c, MarieTriangle trig){ + TextureDataR8G8B8A8_draw_triangle_of_one_color_H_DrawGuest aboba = { self, c }; + marie_rasterize_triangle_with_attr( + (MariePlaneVertAttr){trig.v0, {}}, (MariePlaneVertAttr){trig.v1, {}}, (MariePlaneVertAttr){trig.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/l3/r4/r4.c b/src/l3/r4/r4.c index b25897b..2d2cf0a 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -18,10 +18,16 @@ AliceGenericMeshPath AliceGenericMeshPath_for_puck(){ }; } +vec3 project_dir_onto_plane_xz(vec3 v){ + vec2 xz = vec2_normalize((vec2){v.x, v.z}); + return (vec3){xz.x, 0, xz.y}; +} + typedef struct{ Alice* alice; LucyFace* font_face; RBTreeNodeLucyFaceFixedSize* font_face_of_size_40; + vec3 hero_pos; } R4AlphaStuff; void main_h_on_wayland_keyboard_key(void* data, U32 keysym, U32 act){ @@ -30,7 +36,30 @@ void main_h_on_wayland_keyboard_key(void* data, U32 keysym, U32 act){ void main_h_on_another_frame(void* data, float fl){ R4AlphaStuff *st = data; Alice* alice = st->alice; - margaret_ns_time TIME = margaret_clock_gettime_monotonic_raw(); + vec3 proj_back = project_dir_onto_plane_xz(alice->cam_info.cam.cam_basis.z); + vec3 proj_right = project_dir_onto_plane_xz(alice->cam_info.cam.cam_basis.x); + const float max_speed = 10.f; + if (alice->wl.first_0x80_keys['w']) { + st->hero_pos = vec3_minus_vec3(st->hero_pos, vec3_mul_scal(proj_back, fl * max_speed)); + } + if (alice->wl.first_0x80_keys['s']) { + st->hero_pos = vec3_add_vec3(st->hero_pos, vec3_mul_scal(proj_back, fl * max_speed)); + } + if (alice->wl.first_0x80_keys['a']) { + st->hero_pos = vec3_minus_vec3(st->hero_pos, vec3_mul_scal(proj_right, fl * max_speed)); + } + if (alice->wl.first_0x80_keys['d']) { + st->hero_pos = vec3_add_vec3(st->hero_pos, vec3_mul_scal(proj_right, fl * max_speed)); + } + if (alice->wl.first_0x80_keys['e']) { + st->hero_pos = vec3_add_vec3(st->hero_pos, (vec3){0, max_speed * fl, 0}); + } + if (alice->wl.first_0x80_keys['q']) { + st->hero_pos = vec3_add_vec3(st->hero_pos, (vec3){0, -max_speed * fl, 0}); + } + alice->cam_info.cam.pos = st->hero_pos; + + // margaret_ns_time TIME = margaret_clock_gettime_monotonic_raw(); // printf("Updating text\n"); // LucyRenderer_clear(&alice->lucy_renderer); // VecU8 text = VecU8_fmt("Time is %u.%u\nHave a good day sir\n", (U64)TIME.tv_sec, (U64)TIME.tv_nsec); @@ -40,6 +69,7 @@ void main_h_on_another_frame(void* data, float fl){ int main(){ R4AlphaStuff st; + st.hero_pos = (vec3){0, 0.81f, 0}; Alice* alice = Alice_new(); st.alice = alice; st.alice->guest = &st; @@ -67,16 +97,16 @@ int main(){ LucyRenderer_add_simple_label(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0, cstr("Bebra budet\nотнюхана\n"), (ivec2){10, 10}); - // ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6)); - // AliceGenericMeshHand_resize_instance_arr(st.alice, &model_gen->el, 1); - // - // for (int X = 0; X < 1; X++) { - // for (int Z = 0; Z < 1; Z++) { - // AliceGenericMeshHand_set_inst(&model_gen->el, X * 10 + Z, (GenericMeshInstanceInc){ - // .model_t = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}), - // }); - // } - // } + ListNodeAliceGenericMeshHand* model_gen = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_log(cstr("."), 10, 2, 6)); + AliceGenericMeshHand_resize_instance_arr(st.alice, &model_gen->el, 1); + + for (int X = 0; X < 1; X++) { + for (int Z = 0; Z < 1; Z++) { + AliceGenericMeshHand_set_inst(&model_gen->el, X * 10 + Z, (GenericMeshInstanceInc){ + .model_t = marie_translation_mat4((vec3){11.f * (float)X, -6, 4.f * (float)Z}), + }); + } + } ListNodeAliceShinyMeshHand *model_sh = Alice_add_shiny_mesh(st.alice, vcstr("./gen/l2/models/cube.AliceShinyMesh")); AliceShinyMeshHand_resize_instance_arr(st.alice, &model_sh->el, 100); @@ -117,15 +147,15 @@ int main(){ .model_t = marie_translation_mat4((vec3){5.f, -3, 12.f}), }); - // ListNodeAliceGenericMeshHand* model_puck = Alice_add_generic_mesh(st->alice, AliceGenericMeshPath_for_puck()); - // AliceGenericMeshHand_resize_instance_arr(st->alice, &model_puck->el, 100); - // for (int X = 0; X < 10; X++) { - // for (int Z = 0; Z < 10; Z++) { - // AliceGenericMeshHand_set_inst(&model_puck->el, X * 10 + Z, (GenericMeshInstanceInc){ - // .model_t = marie_translation_mat4((vec3){11.f * (float)X - 20, -1, 4.f * (float)Z - 10}), - // }); - // } - // } + ListNodeAliceGenericMeshHand* model_puck = Alice_add_generic_mesh(st.alice, AliceGenericMeshPath_for_puck()); + AliceGenericMeshHand_resize_instance_arr(st.alice, &model_puck->el, 100); + for (int X = 0; X < 10; X++) { + for (int Z = 0; Z < 10; Z++) { + AliceGenericMeshHand_set_inst(&model_puck->el, X * 10 + Z, (GenericMeshInstanceInc){ + .model_t = marie_translation_mat4((vec3){11.f * (float)X - 20, -1, 4.f * (float)Z - 10}), + }); + } + } Alice_mainloop(st.alice, &(AliceCallbacks){ .on_wl_keyboard_key = main_h_on_wayland_keyboard_key, .on_another_frame = main_h_on_another_frame,