From 6e13ceb267e392ba300c74352cf65ddff4d0f103 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Sat, 21 Feb 2026 03:40:24 +0300 Subject: [PATCH] I was THIS close from drawing amogus with my new widgets --- src/l1/anne/util_temp_geom.h | 2 +- src/l1/anne/util_temp_very_base.h | 4 ++ src/l1_5/marie/graphics_geom.h | 15 ++++++++ src/l2/drawer_2d.h | 12 ++++++ src/l2/gui/colorblock.h | 24 +++++------- src/l2/gui/colorframe.h | 63 +++++++++++++++++++++++++++++++ src/l2/gui/stacks.h | 57 ++++++++++++++++++++++++++++ src/l2/gui/widget.h | 35 +++++------------ src/l3/r4/r4.c | 24 ++++++++++-- 9 files changed, 192 insertions(+), 44 deletions(-) create mode 100644 src/l2/gui/colorframe.h create mode 100644 src/l2/gui/stacks.h diff --git a/src/l1/anne/util_temp_geom.h b/src/l1/anne/util_temp_geom.h index cd755e0..ff1face 100644 --- a/src/l1/anne/util_temp_geom.h +++ b/src/l1/anne/util_temp_geom.h @@ -3,7 +3,7 @@ #include "../codegen/util_template_inst.h" void generate_util_temp_geom_headers() { - SpanU8 T[] = {cstr("cvec3"), cstr("cvec4"), cstr("vec2"), cstr("vec3"), cstr("vec4"), cstr("s64vec2")}; + SpanU8 T[] = {cstr("cvec3"), cstr("cvec4"), cstr("vec2"), cstr("vec3"), cstr("vec4"), cstr("s64vec2"), cstr("ivec2")}; 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); diff --git a/src/l1/anne/util_temp_very_base.h b/src/l1/anne/util_temp_very_base.h index b6ee4b0..e41cd0f 100644 --- a/src/l1/anne/util_temp_very_base.h +++ b/src/l1/anne/util_temp_very_base.h @@ -73,4 +73,8 @@ void generate_util_temp_very_base_headers() { generate_Option_templ_inst_eve_header(l, ns, (option_template_instantiation_op){.T = cstr("Json"), .t_clonable = false}); + + mkdir_nofail("l1/gui"); + generate_guarded_span_company_for_primitive(l, cstr("gui"), cstr("MutRefWidget"), + cstr("#include \"../../../src/l2/gui/widget.h\""), true, false); } diff --git a/src/l1_5/marie/graphics_geom.h b/src/l1_5/marie/graphics_geom.h index 520cb57..5ea6c86 100644 --- a/src/l1_5/marie/graphics_geom.h +++ b/src/l1_5/marie/graphics_geom.h @@ -108,3 +108,18 @@ uvec2 ivec2_to_uvec2(ivec2 v) { ivec2 uvec2_to_ivec2(uvec2 v) { return (ivec2){(S32)v.x, (S32)v.y}; } + +typedef struct{ + ivec2 lt, rb; +} BorderS32; + +bool BorderS32_empty(BorderS32 self){ + return self.lt.x >= self.rb.x || self.lt.y >= self.rb.y; +} + +BorderS32 BorderS32_intersect(BorderS32 a, BorderS32 b){ + return (BorderS32){ + {MAX_S32(a.lt.x, b.lt.x), MAX_S32(a.lt.y, b.lt.y)}, + {MIN_S32(a.rb.x, b.rb.x), MIN_S32(a.rb.y, b.rb.y)}, + }; +} diff --git a/src/l2/drawer_2d.h b/src/l2/drawer_2d.h index 4de0f60..9c24ba3 100644 --- a/src/l2/drawer_2d.h +++ b/src/l2/drawer_2d.h @@ -2,7 +2,9 @@ #include "margaret/vulkan_utils.h" #include "../../gen/l1/geom.h" +#include "../l1_5/marie/graphics_geom.h" +/* todo: replace vec4 color with cvec4 color */ typedef struct { vec2 pos; vec4 color; @@ -103,4 +105,14 @@ void Plain2dShapeRenderer_add_rectangle(Plain2dShapeRenderer* self, vec4 color, (vec2){start.x + width, start.y}, start, (vec2){start.x, start.y + height}); Plain2dShapeRenderer_add_triangle(self, color, (vec2){start.x + width, start.y}, (vec2){start.x, start.y + height}, (vec2){start.x + width, start.y + height}); +} + +void Plain2dShapeRenderer_add_rect_clipped(Plain2dShapeRenderer* self, vec4 color, + ivec2 start, S32 width, S32 height, BorderS32 border) { + BorderS32 rect = BorderS32_intersect(border, + (BorderS32){.lt = start, .rb.x = start.x + width, .rb.y = start.y + height}); + if (!BorderS32_empty(rect)) { + Plain2dShapeRenderer_add_rectangle(self, color, ivec2_to_vec2(rect.lt), + (float)(rect.rb.x - rect.lt.x), (float)(rect.rb.y - rect.lt.y)); + } } \ No newline at end of file diff --git a/src/l2/gui/colorblock.h b/src/l2/gui/colorblock.h index e16f1e8..78ef401 100644 --- a/src/l2/gui/colorblock.h +++ b/src/l2/gui/colorblock.h @@ -2,7 +2,6 @@ #include "../drawer_2d.h" #include "widget.h" -#include "../../l1_5/marie/graphics_geom.h" typedef struct { EmptyWidget base; @@ -17,14 +16,9 @@ uvec2 Widget_Table_ColorblockWidget_DRAW_PREPARE(Widget* ug, uvec2 limits) { void Widget_Table_ColorblockWidget_DRAW(Widget* ug, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border) { ColorblockWidget* self = (ColorblockWidget*)ug; assert_sane_widget_size(self->base.base.sz_my_choice); - BorderS32 rect = BorderS32_intersect( - (BorderS32){.lt = drawing_offset, - .rb = ivec2_add_ivec2(drawing_offset, uvec2_to_ivec2(self->base.base.sz_my_choice))}, - border); - if (BorderS32_empty(rect)) - return; - Plain2dShapeRenderer_add_rectangle(self->drawer, self->color, - ivec2_to_vec2(rect.lt), (float)(rect.rb.x - rect.lt.x), (float)(rect.rb.y - rect.lt.x)); + S32 width = (S32)self->base.base.sz_my_choice.x; + S32 height = (S32)self->base.base.sz_my_choice.y; + Plain2dShapeRenderer_add_rect_clipped(self->drawer, self->color, drawing_offset, width, height, border); } void Widget_Table_ColorblockWidget_drop(Widget* ug) {} @@ -35,13 +29,13 @@ const Widget_Table Widget_Table_ColorblockWidget = { .drop = Widget_Table_ColorblockWidget_drop, }; -ColorblockWidget ColorblockWidget_new(U32 width, U32 height, vec4 color, Plain2dShapeRenderer* drawer) { +ColorblockWidget ColorblockWidget_new(S32 width, S32 height, vec4 color, Plain2dShapeRenderer* drawer) { return (ColorblockWidget){.base = (EmptyWidget){.base = Widget_new(), .width = width, .height = height}, .color = color, .drawer = drawer}; } -BoxWidget ColorblockWidget_new_box(U32 width, U32 height, vec4 color, Plain2dShapeRenderer* drawer){ - ColorblockWidget* r = (ColorblockWidget*)safe_malloc(sizeof(ColorblockWidget)); - *r = ColorblockWidget_new(width, height, color, drawer); - return (BoxWidget){.r = (Widget*)r, .t = &Widget_Table_ColorblockWidget}; -} +// BoxWidget ColorblockWidget_new_box(U32 width, U32 height, vec4 color, Plain2dShapeRenderer* drawer){ +// ColorblockWidget* r = (ColorblockWidget*)safe_malloc(sizeof(ColorblockWidget)); +// *r = ColorblockWidget_new(width, height, color, drawer); +// return (BoxWidget){.r = (Widget*)r, .t = &Widget_Table_ColorblockWidget}; +// } diff --git a/src/l2/gui/colorframe.h b/src/l2/gui/colorframe.h new file mode 100644 index 0000000..7e86b31 --- /dev/null +++ b/src/l2/gui/colorframe.h @@ -0,0 +1,63 @@ +#pragma once + +#include "../drawer_2d.h" +#include "widget.h" + +typedef struct { + Widget base; + S32 left_p, right_p, bottom_p, top_p; + Plain2dShapeRenderer* drawer; + vec4 color; + MutRefWidget child; +} ColorframeWidget; + +uvec2 Widget_Table_ColorframeWidget_DRAW_PREPARE(Widget* ug, uvec2 limits) { + ColorframeWidget* self = (ColorframeWidget*)ug; + S32 taken_width = self->left_p + self->right_p; + S32 taken_height = self->top_p + self->bottom_p; + S32 rem_width = MAX_S32((S32)limits.x - taken_width, 0); + S32 rem_height = MAX_S32((S32)limits.y - taken_height, 0); + /* It can be useful even when one of the dimensions is zero */ + uvec2 child_chose = MutRefWidget_draw_prepare(self->child, (uvec2){rem_width, rem_height}); + return widget_size_min_of_all(limits, (uvec2){child_chose.x + taken_width, child_chose.y + taken_height}); +} + +void Widget_Table_ColorframeWidget_DRAW(Widget* ug, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border) { + ColorframeWidget* self = (ColorframeWidget*)ug; + S32 taken_width = self->left_p + self->right_p; + S32 taken_height = self->top_p + self->bottom_p; + S32 width = (S32)self->base.sz_my_choice.x; + S32 height = (S32)self->base.sz_my_choice.y; + if (width == 0 || height == 0) + return; + if (taken_width >= width || taken_height >= height) { + Plain2dShapeRenderer_add_rect_clipped(self->drawer, self->color, drawing_offset, width, height, border); + } else { + Plain2dShapeRenderer_add_rect_clipped(self->drawer, self->color, drawing_offset, width, self->top_p, border); + Plain2dShapeRenderer_add_rect_clipped(self->drawer, self->color, + (ivec2){drawing_offset.x, drawing_offset.y + self->top_p}, self->left_p, height - taken_height, border); + Plain2dShapeRenderer_add_rect_clipped(self->drawer, self->color, + (ivec2){drawing_offset.x + width - self->right_p, drawing_offset.y + self->top_p}, self->right_p, height - taken_height, border); + Plain2dShapeRenderer_add_rect_clipped(self->drawer, self->color, + (ivec2){drawing_offset.x, drawing_offset.y + height - self->bottom_p}, width, self->bottom_p, border); + MutRefWidget_draw(self->child, (ivec2){drawing_offset.x + self->left_p, drawing_offset.y + self->top_p}, surface_sz, border); + } +} + +void Widget_Table_ColorframeWidget_drop(Widget* ug){} + +const Widget_Table Widget_Table_ColorframeWidget = { + .DRAW_PREPARE = Widget_Table_ColorframeWidget_DRAW_PREPARE, + .DRAW = Widget_Table_ColorframeWidget_DRAW, + .drop = Widget_Table_ColorframeWidget_drop, +}; + + +ColorframeWidget ColorframeWidget_new(S32 left_p, S32 right_p, S32 bottom_p, S32 top_p, + Plain2dShapeRenderer* drawer, vec4 color, MutRefWidget child + ) { + return (ColorframeWidget){.base = Widget_new(), + .left_p = left_p, .right_p = right_p, .bottom_p = bottom_p, .top_p = top_p, + .drawer = drawer, .color = color, .child = child + }; +} \ No newline at end of file diff --git a/src/l2/gui/stacks.h b/src/l2/gui/stacks.h new file mode 100644 index 0000000..4d86aef --- /dev/null +++ b/src/l2/gui/stacks.h @@ -0,0 +1,57 @@ +#pragma once + +#include "widget.h" +#include "../../../gen/l1/gui/VecMutRefWidget.h" +#include "../../../gen/l1/VecAndSpan_S32.h" + +typedef struct { + Widget base; + VecMutRefWidget children; + VecS32 decided_positions; +} LtoRStackWidget; + +uvec2 Widget_Table_LtoRStackWidget_DRAW_PREPARE(Widget* ug, uvec2 limits) { + LtoRStackWidget* self = (LtoRStackWidget*)ug; + S32 pos = 0; + S32 max_w = 0; + self->decided_positions.len = 0; + U64 n = self->children.len; + for (U64 i = 0; i < n; i++) { + if (pos >= (S32)limits.y) + break; + uvec2 child_sz = MutRefWidget_draw_prepare(self->children.buf[i], (uvec2){.x = limits.x, .y = limits.y - pos}); + max_w = MAX_S32(max_w, child_sz.x); + VecS32_append(&self->decided_positions, pos); + pos += (S32)child_sz.y; + } + return (uvec2){max_w, pos}; +} + +void Widget_Table_LtoRStackWidget_DRAW(Widget* ug, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border) { + LtoRStackWidget* self = (LtoRStackWidget*)ug; + for (U64 i = 0; i < self->decided_positions.len; i++) { + S32 pos = self->decided_positions.buf[i]; + assert(i < self->children.len); + MutRefWidget_draw(self->children.buf[i], (ivec2){drawing_offset.x, drawing_offset.y + pos}, surface_sz, border); + } +} + +void LtoRStackWidget_drop(LtoRStackWidget self) { + VecMutRefWidget_drop(self.children); + VecS32_drop(self.decided_positions); +} + +void Widget_Table_LtoRStackWidget_drop(Widget* self) { + LtoRStackWidget_drop(*(LtoRStackWidget*)self); +} + +const Widget_Table Widget_Table_LtoRStack = { + .DRAW_PREPARE = Widget_Table_LtoRStackWidget_DRAW_PREPARE, + .DRAW = Widget_Table_LtoRStackWidget_DRAW, + .drop = Widget_Table_LtoRStackWidget_drop, +}; + +LtoRStackWidget LtoRStackWidget_new() { + return (LtoRStackWidget){.base = Widget_new(), + .children = VecMutRefWidget_new(), .decided_positions = VecS32_new()}; +} \ No newline at end of file diff --git a/src/l2/gui/widget.h b/src/l2/gui/widget.h index 33a9863..d7549b7 100644 --- a/src/l2/gui/widget.h +++ b/src/l2/gui/widget.h @@ -1,7 +1,6 @@ #pragma once -#include "../../../gen/l1/geom.h" -#include "../../l1/core/util.h" +#include "../../l1_5/marie/graphics_geom.h" #define WIDGET_DIM_INF 1000000 @@ -17,21 +16,6 @@ void assert_sane_widget_size_limits(uvec2 max_limits){ assert(max_limits.x <= WIDGET_DIM_INF || max_limits.y <= WIDGET_DIM_INF); } -typedef struct{ - ivec2 lt, rb; -} BorderS32; - -bool BorderS32_empty(BorderS32 self){ - return self.lt.x >= self.rb.x || self.lt.y >= self.rb.y; -} - -BorderS32 BorderS32_intersect(BorderS32 a, BorderS32 b){ - return (BorderS32){ - {MAX_S32(a.lt.x, b.lt.x), MAX_S32(a.lt.y, b.lt.y)}, - {MIN_S32(a.rb.x, b.rb.x), MIN_S32(a.rb.y, b.rb.y)}, - }; -} - uvec2 widget_size_max_of_all(uvec2 a, uvec2 b){ return (uvec2){MAX_U32(a.x, b.x), MAX_U32(a.y, b.y)}; } @@ -76,8 +60,8 @@ void MutRefWidget_draw(MutRefWidget self, ivec2 drawing_offset, uvec2 surface_sz typedef struct { Widget base; - U32 width; - U32 height; + S32 width; + S32 height; } EmptyWidget; uvec2 Widget_Table_EmptyWidget_DRAW_PREPARE(Widget* ug, uvec2 limits){ @@ -98,12 +82,13 @@ const Widget_Table Widget_Table_EmptyWidget = { .drop = Widget_Table_EmptyWidget_drop, }; -EmptyWidget EmptyWidget_new(U32 width, U32 height) { +EmptyWidget EmptyWidget_new(S32 width, S32 height) { + assert(width >= 0 && height >= 0); return (EmptyWidget){.base = Widget_new(), .width = width, .height = height}; } -BoxWidget EmptyWidget_new_box(U32 width, U32 height){ - EmptyWidget* r = safe_malloc(sizeof(EmptyWidget)); - *r = (EmptyWidget){.base = Widget_new(), .width = width, .height = height}; - return (BoxWidget){.r = (Widget*)r, .t = &Widget_Table_EmptyWidget}; -} +// BoxWidget EmptyWidget_new_box(U32 width, U32 height){ +// EmptyWidget* r = safe_malloc(sizeof(EmptyWidget)); +// *r = (EmptyWidget){.base = Widget_new(), .width = width, .height = height}; +// return (BoxWidget){.r = (Widget*)r, .t = &Widget_Table_EmptyWidget}; +// } diff --git a/src/l3/r4/r4.c b/src/l3/r4/r4.c index c4450ed..620cf0f 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -4,6 +4,8 @@ #include "../../../gen/l1/VecAndSpan_vec3.h" #include "../../l1_5/core/color.h" #include "../../l2/gui/colorblock.h" +#include "../../l2/gui/colorframe.h" +#include "../../l2/gui/stacks.h" #include "linux/input-event-codes.h" @@ -26,7 +28,7 @@ typedef struct{ typedef struct { float mass; /* In kg, Not zero */ - quad_form3_t inertia_moment; /* Qadratic form, yields kg*m^2 */ + quad_form3_t inertia_moment; /* Quadratic form, yields kg*m^2 */ /* Center of mass relative to "center of mesh" */ vec3 mass_center; } RigidBodyConfig; @@ -104,6 +106,11 @@ typedef struct{ /* overlay ui */ ColorblockWidget gui_0; + ColorframeWidget gui_1; + ColorblockWidget gui_2; + ColorblockWidget gui_3; + LtoRStackWidget gui_4; + ColorframeWidget gui_5; } R4BetaState; /* We are surrounded by a giant cubic mesh of light sources */ @@ -330,8 +337,19 @@ void run_app(){ LucyRenderer_add_simple_label(&st.alice->lucy_renderer, st.font_face_of_size_40, (vec4){0, 0, 0, 1}, 0, cstr("..."), (ivec2){10, 10}); - st.gui_0 = ColorblockWidget_new(400, 200, (vec4){0.3f, 0.8f, 0.4f, 0.6f}, &alice->plain_shape_renderer); - alice->overlay_ui_root = (MutRefWidget){.r = &st.gui_0.base.base, .t = &Widget_Table_ColorblockWidget}; + /* Recursion depth is 2 */ + st.gui_0 = ColorblockWidget_new(100, 50, (vec4){0.3f, 0.8f, 0.4f, 0.6f}, &alice->plain_shape_renderer); + st.gui_1 = ColorframeWidget_new(100, 300, 150, 50, &alice->plain_shape_renderer, (vec4){0.7f, 0.4f, 0.2f, 0.5f}, + (MutRefWidget){.r = (Widget*)&st.gui_0, .t = &Widget_Table_ColorblockWidget}); + st.gui_2 = ColorblockWidget_new(5000, 30, (vec4){0.1f, 0.5f, 0.6f, 0.4f}, &alice->plain_shape_renderer); + st.gui_3 = ColorblockWidget_new(120, 50, (vec4){0.2f, 0.67f, 0.4f, 0.5f}, &alice->plain_shape_renderer); + st.gui_4 = LtoRStackWidget_new(); + VecMutRefWidget_append(&st.gui_4.children, (MutRefWidget){.r = (Widget*)&st.gui_1, &Widget_Table_ColorframeWidget}); + VecMutRefWidget_append(&st.gui_4.children, (MutRefWidget){.r = (Widget*)&st.gui_2, &Widget_Table_ColorblockWidget}); + VecMutRefWidget_append(&st.gui_4.children, (MutRefWidget){.r = (Widget*)&st.gui_3, &Widget_Table_ColorblockWidget}); + st.gui_5 = ColorframeWidget_new(70, 70, 0, 70, &alice->plain_shape_renderer, (vec4){0.1f, 0.5f, 0.3f, 0.8f}, + (MutRefWidget){.r = (Widget*)&st.gui_4, &Widget_Table_LtoRStack}); + alice->overlay_ui_root = (MutRefWidget){.r = &st.gui_5.base, .t = &Widget_Table_ColorframeWidget}; VecU8 ROA_mesh_path = vcstr("./gen/l2/models/log_10_2_6.AliceGenericMesh"); st.ROA_topology = alice_expect_read_generic_mesh_from_file(ROA_mesh_path);