From c53c3328dda5c9910b19ccc054fb2119e03a53ff Mon Sep 17 00:00:00 2001 From: Andreev Gregory Date: Wed, 6 Aug 2025 14:59:12 +0300 Subject: [PATCH] first version of pure triangle clipping code generation --- src/l1/codegen/codegen.h | 1 + src/l1/core/Span_Span_int_primitives.h | 12 ++ src/l2/codegen/clipping.h | 273 +++++++++++++++++++++++-- 3 files changed, 268 insertions(+), 18 deletions(-) create mode 100644 src/l1/core/Span_Span_int_primitives.h diff --git a/src/l1/codegen/codegen.h b/src/l1/codegen/codegen.h index 04e3813..36445e5 100644 --- a/src/l1/codegen/codegen.h +++ b/src/l1/codegen/codegen.h @@ -25,6 +25,7 @@ void finish_header(VecU8 text_before_endif, const char* filename) { #define SPACE4 " " #define SPACE8 " " #define SPACE12 " " +#define SPACE16 " " NODISCARD VecU8 generate_type_triv_methods_and_vec(ConstSpanU8 member) { VecU8 res = VecU8_from_cstr("#define "); diff --git a/src/l1/core/Span_Span_int_primitives.h b/src/l1/core/Span_Span_int_primitives.h new file mode 100644 index 0000000..fd2bc93 --- /dev/null +++ b/src/l1/core/Span_Span_int_primitives.h @@ -0,0 +1,12 @@ +#ifndef PROTOTYPE1_SRC_L1_CORE_SPAN_SPAN_INT_PRIMITIVES_H +#define PROTOTYPE1_SRC_L1_CORE_SPAN_SPAN_INT_PRIMITIVES_H + +#include "VecSpan_int_primitives.h" + +// todo: generate all this shit by a codegen script into separate files +// todo: completely get rid of these dumb macroses and these stupid files + +SpanT_struct_Definition(ConstSpanU8) +SpanT_method_Definition(ConstSpanU8) + +#endif diff --git a/src/l2/codegen/clipping.h b/src/l2/codegen/clipping.h index 4c3a49c..35c88a8 100644 --- a/src/l2/codegen/clipping.h +++ b/src/l2/codegen/clipping.h @@ -2,6 +2,7 @@ #define PROTOTYPE1_SRC_L2_CODEGEN_CLIPPING_H #include "../../l1/codegen/codegen.h" +#include "../../l1/core/Span_Span_int_primitives.h" // todo: move all of this to marie namespace @@ -68,31 +69,28 @@ PossiblyNegatedTriangle get_order_var_of_triangle(char tri, int idi, char trj, i */ void append_on_the_left_stmt(VecU8* str, char tri, int idi, char trj, int idj, char tru, int idu) { PossiblyNegatedTriangle measure = get_order_var_of_triangle(tri, idi, trj, idj, tru, idu); - if (measure.negate) - VecU8_append(str, '!'); - VecU8_append_vec(str, VecU8_format("M%d", measure.order)); + VecU8_append_vec(str, VecU8_format("(M%d %s 0)", measure.order, measure.negate ? "<=" : ">=")); } void append_on_the_right_stmt(VecU8* str, char tri, int idi, char trj, int idj, char tru, int idu) { PossiblyNegatedTriangle measure = get_order_var_of_triangle(tri, idi, trj, idj, tru, idu); - if (!measure.negate) - VecU8_append(str, '!'); - VecU8_append_vec(str, VecU8_format("M%d", measure.order)); + VecU8_append_vec(str, VecU8_format("(M%d %s 0)", measure.order, measure.negate ? ">=" : "<=")); } + /* Generates statement that intersects two segments from 2 different triangles: * First segment: (tr1::A1) to (tr1::B1) * Second segment: (tr2::A2) to (tr2::B2) * */ -void append_intersection_stmt(VecU8* str, char tr1, int A1, int B1, char tr2, int A2, int B2) { +void append_intersection_eol_stmt(VecU8* str, char tr1, int A1, int B1, char tr2, int A2, int B2) { assert((tr1 == 'C' && tr2 == 'T') || (tr1 == 'T' && tr2 == 'C')); assert(0 <= A1 && A1 < 3); assert(0 <= B1 && B1 < 3); assert(0 <= A2 && A2 < 3); assert(0 <= B2 && B2 < 3); assert(A1 != B1 && A2 != B2); - VecU8_append_vec(str, VecU8_format("marie_intersect_lines(T.v%d, T.v%d, C.v%d, C.v%d)", - A1, B1, A2, B2)); + VecU8_append_vec(str, VecU8_format("marie_intersect_lines(%c.v%d, %c.v%d, %c.v%d, %c.v%d);\n", + tr1, A1, tr1, B1, tr2, A2, tr2, B2)); } ConstSpanU8 marie_names_of_two_clipping_triangles[6] = { @@ -119,15 +117,29 @@ void append_triangle_registration_stmt(VecU8* str, ConstSpanU8 P0, ConstSpanU8 P VecU8_append_span(str, cstr("});\n")); } +void append_answering_stmt(VecU8* res, ConstSpanConstSpanU8 vertices, int tabulation_lvl) { + size_t n = vertices.len; + assert(n >= 3); + for (int i = 0; i < n - 2; i++) { + for (int sp = 0; sp < tabulation_lvl; sp++) + VecU8_append(res, ' '); + append_triangle_registration_stmt(res, *ConstSpanConstSpanU8_at(vertices, i), + *ConstSpanConstSpanU8_at(vertices, i + 1), *ConstSpanConstSpanU8_at(vertices, n - 1)); + } + for (int sp = 0; sp < tabulation_lvl; sp++) + VecU8_append(res, ' '); + VecU8_append_span(res, cstr("return;\n")); +} + int mod3_inc(int x) { - return x == 2 ? 0 : x + 1; + return x == 2 ? 0 : (x + 1); } int mod3_dec(int x) { - return x ? x - 1 : 2; + return x ? (x - 1) : 2; } -void generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(VecU8* res, char tC, char tT) { +void generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(VecU8* res, char tC, char tT, bool tables_turned) { /* Case where all 3 vertices of tT are inside tC */ VecU8_append_span(res, cstr(SPACE4 "if (")); for (int cs = 0; cs < 3; cs++) { @@ -140,9 +152,234 @@ void generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(VecU8* res VecU8_append_span(res, cstr(") {\n" SPACE8)); append_triangle_registration_stmt(res, get_firstborn_vertex_stmt(tT, 0), get_firstborn_vertex_stmt(tT, 1), get_firstborn_vertex_stmt(tT, 2)); - VecU8_append_span(res, cstr(SPACE8 "return;\n" SPACE4 "}\n")); + VecU8_append_span(res, cstr(SPACE8 "return;\n" SPACE4 "}\n\n")); /* Cases where two vertices of tT are inside tC, but one is outside */ + for (int ti = 0; ti < 3; ti++) { + VecU8_append_span(res, cstr(SPACE4 "if (")); + int TA = mod3_inc(ti); + int TB = mod3_inc(TA); + for (int j = 1; j <= 2; j++) { + for (int cs = 0; cs < 3; cs++) { + if (cs != 0 || j != 1) + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, tC, cs, tC, mod3_inc(cs), tT, (ti + j) % 3); + } + } + VecU8_append_span(res, cstr(") {\n")); + for (int sc = 0; sc < 3; sc++) { + VecU8_append_span(res, cstr(SPACE8 "if (")); + append_on_the_right_stmt(res, tC, sc, tC, mod3_inc(sc), tT, ti); + VecU8_append_span(res, cstr(") {\n")); + { + /* 'Result hits one edge' case */ + VecU8_append_span(res, cstr(SPACE12 "if (")); + append_on_the_left_stmt(res, tT, TA, tC, sc, tT, ti); + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, tT, TB, tC, sc, tT, ti); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, tT, TA, tC, mod3_inc(sc), tT, ti); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, tT, TB, tC, mod3_inc(sc), tT, ti); + VecU8_append_span(res, cstr(") {\n")); + { + VecU8_append_span(res, cstr(SPACE16 "vec2 PB = ")); + append_intersection_eol_stmt(res, tC, sc, mod3_inc(sc), tT, ti, TB); + VecU8_append_span(res, cstr(SPACE16 "vec2 PA = ")); + append_intersection_eol_stmt(res, tC, sc, mod3_inc(sc), tT, ti, TA); + ConstSpanU8 quad[4] = { + get_firstborn_vertex_stmt(tT, TB), cstr("PB"), cstr("PA"), get_firstborn_vertex_stmt(tT, TA) }; + append_answering_stmt(res, (ConstSpanConstSpanU8){.data = quad, .len = ARRAY_SIZE(quad)}, 16); + } + VecU8_append_span(res, cstr(SPACE12 "}\n")); + if (!tables_turned) { + /* 'Result hits the angle and two edges' case */ + VecU8_append_span(res, cstr(SPACE12 "if (")); + append_on_the_left_stmt(res, tT, TA, tC, sc, tT, ti); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, tT, TB, tC, sc, tT, ti); + VecU8_append_span(res, cstr(") {\n")); + { + VecU8_append_span(res, cstr(SPACE16 "vec2 PB = ")); + append_intersection_eol_stmt(res, tC, sc, mod3_dec(sc), tT, ti, TB); + VecU8_append_span(res, cstr(SPACE16 "vec2 PA = ")); + append_intersection_eol_stmt(res, tC, sc, mod3_inc(sc), tT, ti, TA); + ConstSpanU8 pentagon[5] = { get_firstborn_vertex_stmt(tT, TB), cstr("PB"), + get_firstborn_vertex_stmt(tC, sc), cstr("PA"), get_firstborn_vertex_stmt(tT, TA)}; + append_answering_stmt(res, (ConstSpanConstSpanU8){.data = pentagon, .len = ARRAY_SIZE(pentagon)}, 16); + } + VecU8_append_span(res, cstr(SPACE12 "}\n")); + } + } + VecU8_append_span(res, cstr(SPACE8 "}\n")); + } + VecU8_append_span(res, cstr(SPACE4 "}\n\n")); + } + + /* Case where one vertice of tT is inside tC, but other two are outside tC */ + for (int pl = 0; pl < 3; pl++) { + int TA = mod3_inc(pl); + int TB = mod3_inc(TA); + VecU8_append_span(res, cstr(SPACE4 "if (")); + for (int cb = 0; cb < 3; cb++) { + if (cb) + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, tC, cb, tC, mod3_inc(cb), tT, pl); + } + VecU8_append_span(res, cstr(") {\n")); + for (int cr = 0; cr < 3; cr++) { + /* Cases where one vertex (pl) of tT is inside tC, but two other (TA and TB) are in + * the same 'third of a surface' */ + VecU8_append_span(res, cstr(SPACE8 "if (")); + append_on_the_left_stmt(res, tT, pl, tC, cr, tT, TA); + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, tT, pl, tC, cr, tT, TB); + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, tT, pl, tC, mod3_inc(cr), tT, TA); + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, tT, pl, tC, mod3_inc(cr), tT, TB); + VecU8_append_span(res, cstr(") {\n")); + { + VecU8_append_span(res, cstr(SPACE12 "vec2 PA = ")); + append_intersection_eol_stmt(res, tT, pl, TA, tC, cr, mod3_inc(cr)); + VecU8_append_span(res, cstr(SPACE12 "vec2 PB = ")); + append_intersection_eol_stmt(res, tT, pl, TB, tC, cr, mod3_inc(cr)); + ConstSpanU8 trig[3] = {get_firstborn_vertex_stmt(tT, pl), cstr("PA"), cstr("PB")}; + append_answering_stmt(res, (ConstSpanConstSpanU8){.data = trig, .len = ARRAY_SIZE(trig)}, 12); + } + VecU8_append_span(res, cstr(SPACE8 "}\n")); + } + for (int rc = 0; rc < 3; rc++) { + VecU8_append_span(res, cstr(SPACE8 "if (")); + append_on_the_left_stmt(res, tT, pl, tC, rc, tT, TA); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, tT, pl, tC, mod3_inc(rc), tT, TA); + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, tT, pl, tC, mod3_inc(rc), tT, TB); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, tT, pl, tC, mod3_dec(rc), tT, TB); + VecU8_append_span(res, cstr(") {\n")); + { + /* Case where TA and TB are in different 'thirds of surface' and the vertex of tC that defines + * border is outside tT. Result is a pentagon */ + VecU8_append_span(res, cstr(SPACE12 "if (\n")); + append_on_the_right_stmt(res, tT, TA, tT, TB, tC, mod3_inc(rc)); + VecU8_append_span(res, cstr(") {\n")); + { + VecU8_append_span(res, cstr(SPACE16 "vec2 PA = ")); + append_intersection_eol_stmt(res, tT, pl, TA, tC, rc, mod3_inc(rc)); + VecU8_append_span(res, cstr(SPACE16 "vec2 QA = ")); + append_intersection_eol_stmt(res, tT, TA, TB, tC, rc, mod3_inc(rc)); + VecU8_append_span(res, cstr(SPACE16 "vec2 QB = ")); + append_intersection_eol_stmt(res, tT, TA, TB, tC, mod3_inc(rc), mod3_dec(rc)); + VecU8_append_span(res, cstr(SPACE16 "vec2 PB = ")); + append_intersection_eol_stmt(res, tT, pl, TB, tC, mod3_inc(rc), mod3_dec(rc)); + ConstSpanU8 pent[5] = {get_firstborn_vertex_stmt(tT, pl), cstr("PA"), cstr("QA"), cstr("QB"), cstr("PB")}; + append_answering_stmt(res, (ConstSpanConstSpanU8){.data = pent, .len = ARRAY_SIZE(pent)}, 16); + } + VecU8_append_span(res, cstr(SPACE12 "}")); + if (!tables_turned) { + /* Case where TA and TB are in different sectors and rc++ is inside tT + * Result is a quadrangle */ + VecU8_append_span(res, cstr(SPACE12 " else {")); + VecU8_append_span(res, cstr(SPACE16 "vec2 PA = ")); + append_intersection_eol_stmt(res, tT, pl, TA, tC, rc, mod3_inc(rc)); + VecU8_append_span(res, cstr(SPACE16 "vec2 PB = ")); + append_intersection_eol_stmt(res, tT, pl, TB, tC, mod3_inc(rc), mod3_dec(rc)); + ConstSpanU8 quad[4] = {get_firstborn_vertex_stmt(tT, pl), cstr("PA"), + get_firstborn_vertex_stmt(tC, mod3_inc(rc)), cstr("PB")}; + append_answering_stmt(res, (ConstSpanConstSpanU8){.data = quad, .len = ARRAY_SIZE(quad)}, 16); + VecU8_append_span(res, cstr(SPACE12 "}")); + } + VecU8_append_span(res, cstr("\n")); + } + VecU8_append_span(res, cstr(SPACE8 "}\n")); + } + VecU8_append_span(res, cstr(SPACE4 "}\n\n")); + } +} + +/* It is assumed that it goes after two passes of generate_func_clip_triang_on_triang_case_where_some_vertex_stuck */ +void generate_func_clip_triang_on_triang_case_boring(VecU8* res) { + /* Star of David case */ + for (int cb = 0; cb < 3; cb++) { + VecU8_append_span(res, cstr(SPACE4 "if (")); + for (int i = 0; i < 3; i++) { + if (i) + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, 'C', (i + cb) % 3, 'C', (i + cb + 1) % 3, 'T', i); + } + VecU8_append_span(res, cstr(") {\n")); + { + VecU8_append_span(res, cstr(SPACE8 "vec2 hex[6] = {\n")); + for (int ti = 0; ti < 3; ti++) { + for (int cj = 0; cj < 2; cj++) { + VecU8_append_vec(res, VecU8_format(SPACE12 "marie_intersect_lines(T.v%d, T.v%d, C.v%d, C.v%d),\n", + ti, (ti + 1) % 3, (ti + cb + cj) % 3, (ti + cb + cj + 1) % 3)); + } + } + VecU8_append_span(res, cstr(SPACE8 "};\n")); + VecU8_append_span(res, cstr(SPACE8 "for (int i = 0; i < 4; i++)\n" + SPACE12 "VecMarieTriangle_append(pile, (MarieTriangle){hex[i], hex[i + 1], hex[5]});\n")); + } + VecU8_append_span(res, cstr(SPACE4 "}\n")); + } + /* Wedge cases */ + for (int cf = 0; cf < 3; cf++) { + for (int ti = 0; ti < 3; ti++){ + VecU8_append_span(res, cstr(SPACE4 "if (")); + append_on_the_left_stmt(res, 'T', ti, 'T', mod3_dec(ti), 'C', cf); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, 'T', mod3_inc(ti), 'T', mod3_dec(ti), 'C', (cf + 2) % 3); + VecU8_append_span(res, cstr(" && ")); + append_on_the_left_stmt(res, 'C', cf, 'C', (cf + 2) % 3, 'T', (ti + 2) % 3); + VecU8_append_span(res, cstr(") {\n")); + { + ConstSpanU8 quad[4] = {cstr("PA"), cstr("PB"), cstr("PC"), cstr("PD")}; + /* case A */ + VecU8_append_span(res, cstr(SPACE8 "if (")); + append_on_the_left_stmt(res, 'T', ti, 'T', mod3_dec(ti), 'C', mod3_inc(cf)); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, 'C', mod3_inc(cf), 'C', mod3_dec(cf), 'T', ti); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, 'C', mod3_inc(cf), 'C', mod3_dec(cf), 'T', mod3_inc(ti)); + VecU8_append_span(res, cstr(") {\n")); + { + VecU8_append_span(res, cstr(SPACE12 "vec2 PA = ")); + append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', mod3_inc(cf), mod3_dec(cf)); + VecU8_append_span(res, cstr(SPACE12 "vec2 PB = ")); + append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', mod3_inc(cf), mod3_dec(cf)); + VecU8_append_span(res, cstr(SPACE12 "vec2 PC = ")); + append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', mod3_dec(cf), cf); + VecU8_append_span(res, cstr(SPACE12 "vec2 PD = ")); + append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', mod3_dec(cf), cf); + append_answering_stmt(res, (ConstSpanConstSpanU8){.data = quad, ARRAY_SIZE(quad)}, 12); + } + VecU8_append_span(res, cstr(SPACE8 "}\n")); + /* case B */ + VecU8_append_span(res, cstr(SPACE8 "if (")); + append_on_the_right_stmt(res, 'T', mod3_inc(ti), 'T', mod3_dec(ti), 'C', mod3_inc(cf)); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, 'C', cf, 'C', mod3_inc(cf), 'T', ti); + VecU8_append_span(res, cstr(" && ")); + append_on_the_right_stmt(res, 'C', cf, 'C', mod3_inc(cf), 'T', mod3_inc(ti)); + VecU8_append_span(res, cstr(") {\n")); + { + VecU8_append_span(res, cstr(SPACE12 "vec2 PA = ")); + append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', cf, mod3_inc(cf)); + VecU8_append_span(res, cstr(SPACE12 "vec2 PB = ")); + append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', cf, mod3_inc(cf)); + VecU8_append_span(res, cstr(SPACE12 "vec2 PC = ")); + append_intersection_eol_stmt(res, 'T', mod3_inc(ti), mod3_dec(ti), 'C', mod3_dec(cf), cf); + VecU8_append_span(res, cstr(SPACE12 "vec2 PD = ")); + append_intersection_eol_stmt(res, 'T', mod3_dec(ti), ti, 'C', mod3_dec(cf), cf); + append_answering_stmt(res, (ConstSpanConstSpanU8){.data = quad, ARRAY_SIZE(quad)}, 12); + } + VecU8_append_span(res, cstr(SPACE8 "}\n")); + } + VecU8_append_span(res, cstr(SPACE4 "}\n")); + } + } } @@ -150,7 +387,7 @@ NODISCARD VecU8 generate_func_clip_ccw_triang_with_ccw_triang_append_to_Vec() { VecU8 res = VecU8_from_cstr( "void marie_clip_ccw_triang_with_ccw_triang_append_to_Vec(MarieTriangle C, MarieTriangle T, VecMarieTriangle* pile) {\n"); for (int ord = 0; ord < 18; ord++) { - VecU8_append_vec(&res, VecU8_format(SPACE4 "bool M%d = marie_surface(", ord)); + VecU8_append_vec(&res, VecU8_format(SPACE4 "float M%d = marie_surface(", ord)); for (int a = 0; a < 3; a++) { if (a) VecU8_append_span(&res, cstr(", ")); @@ -159,11 +396,11 @@ NODISCARD VecU8 generate_func_clip_ccw_triang_with_ccw_triang_append_to_Vec() { VecU8_append_span(&res, cstr(".v")); VecU8_append(&res, '0' + vsh % 10); } - VecU8_append_span(&res, cstr(") > 0;\n")); + VecU8_append_span(&res, cstr(");\n")); } - generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'C', 'T'); - generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'T', 'C'); - VecU8_append_span(&res, cstr("abortf(\"todo\\n\");\n")); // todo: check for 3 hard cases: David, wedge and non-intersecting + generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'C', 'T', false); + generate_func_clip_triang_on_triang_case_where_some_vertex_stuck(&res, 'T', 'C', true); + generate_func_clip_triang_on_triang_case_boring(&res); VecU8_append_span(&res, cstr("}\n\n")); return res; }