I finally learned how to draw normal perimeters

This commit is contained in:
Андреев Григорий 2025-08-18 20:57:39 +03:00
parent cfd23b1ea5
commit 2b95720d56
9 changed files with 136 additions and 65 deletions

View File

@ -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)
#

View File

@ -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

View File

@ -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 <math.h>\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");

View File

@ -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

View File

@ -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) {

View File

@ -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);
}

View File

@ -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
);

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -12,15 +12,13 @@
#include "../../marie/graphics_geom.h"
#include "../../marie/rasterization.h"
// todo: remove
#include <linux/input-event-codes.h>
#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);