From 2655c2be3e89dfcdf0edf50d02f1663577105d26 Mon Sep 17 00:00:00 2001 From: Andreew Gregory Date: Fri, 20 Feb 2026 22:24:11 +0300 Subject: [PATCH] Added first gui widget + worked on gui --- src/l1_5/marie/graphics_geom.h | 10 +++++++- src/l2/alice/engine.h | 16 +++++++++++- src/l2/gui/colorblock.h | 47 ++++++++++++++++++++++++++++++++++ src/l2/gui/label.h | 2 ++ src/l2/gui/widget.h | 12 +++++++-- src/l3/r4/r4.c | 13 ++++------ 6 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 src/l2/gui/colorblock.h diff --git a/src/l1_5/marie/graphics_geom.h b/src/l1_5/marie/graphics_geom.h index b08815f..520cb57 100644 --- a/src/l1_5/marie/graphics_geom.h +++ b/src/l1_5/marie/graphics_geom.h @@ -46,7 +46,7 @@ mat4 marie_mat3_to_mat4_transposed(mat3 A) { 0, 0, 0, 1); } -mat4 marie_3d_rot_mat4(vec3 r, double a) { +mat4 marie_3d_rot_mat4(vec3 r, float a) { return marie_mat3_to_mat4(marie_3d_rot_mat3(r, a)); } @@ -100,3 +100,11 @@ mat4 marie_3d_scal_mat4(float scale){ vec2 ivec2_to_vec2(ivec2 v){ return (vec2){(float)v.x, (float)v.y}; } + +uvec2 ivec2_to_uvec2(ivec2 v) { + return (uvec2){v.x, v.y}; +} + +ivec2 uvec2_to_ivec2(uvec2 v) { + return (ivec2){(S32)v.x, (S32)v.y}; +} diff --git a/src/l2/alice/engine.h b/src/l2/alice/engine.h index e347a5c..e4d766f 100644 --- a/src/l2/alice/engine.h +++ b/src/l2/alice/engine.h @@ -6,6 +6,7 @@ #include "transfer_in_mainloop.h" #include "../drawer_2d.h" #include "../lucy/glyph_render.h" +#include "../gui/widget.h" typedef struct { size_t indexes; @@ -748,6 +749,8 @@ struct Alice { FT_Library ft_library; LucyGlyphCache lucy_cache; LucyRenderer lucy_renderer; + /* For now all my ui is placed 'on top' of the scene */ + MutRefWidget overlay_ui_root; VkImageView zbuffer_view; VkImageView IT1_view; @@ -1063,13 +1066,19 @@ void alice_frame_drawing(Alice* alice) { abortf("vkAcquireNextImageKHR"); } + U32 win_width = alice->wl.width_confirmed; + U32 win_height = alice->wl.height_confirmed; mat4 projection_matrix = marie_perspective_projection_fov_mat4( - (float)alice->wl.width_confirmed, (float)alice->wl.height_confirmed, + (float)win_width, (float)win_height, alice->cam_info.cam.fov, 0.01f, 1000); mat4 camera_rotation_matrix = marie_mat3_to_mat4_transposed(alice->cam_info.cam.cam_basis); mat4 camera_translation_matrix = marie_translation_mat4(vec3_minus(alice->cam_info.cam.pos)); mat4 t_mat = mat4_mul_mat4(projection_matrix, mat4_mul_mat4(camera_rotation_matrix, camera_translation_matrix)); + /* This is not related to command recording */ + Plain2dShapeRenderer_clear(&alice->plain_shape_renderer); + LucyRenderer_clear(&alice->lucy_renderer); + if (!alice->transfer_command_buf_already_reset) { Abigail_wipe_old_staging(&alice->abigail, alice->device, alice->staging_buffers); margaret_reset_and_begin_command_buffer(alice->transfer_command_buf); @@ -1081,6 +1090,9 @@ void alice_frame_drawing(Alice* alice) { alice->callbacks.on_another_frame(alice->guest, (float)(alice->wl.cur_frame_time - alice->wl.last_frame_time) / 1000); AliceScene__another_frame(alice); // LucyGlyphCache_another_frame(&alice->lucy_cache); lucy cache has no business here... Well, maybe later + MutRefWidget_draw_prepare(alice->overlay_ui_root, (uvec2){win_width, win_height}); + MutRefWidget_draw(alice->overlay_ui_root, (ivec2){0}, (uvec2){win_width, win_height}, (BorderS32){.lt = {0}, + .rb.x = (S32)win_width, .rb.y = (S32)win_height}); Plain2dShapeRenderer_another_frame(&alice->plain_shape_renderer); LucyRenderer_another_frame(&alice->lucy_renderer); margaret_end_command_buffer(alice->transfer_command_buf); @@ -1627,6 +1639,8 @@ Alice* Alice_new(){ alice->lucy_renderer = LucyRenderer_new(engine_reference, &alice->lucy_cache, root_dir, alice->render_pass_1, 0); + alice->overlay_ui_root = (MutRefWidget){NULL, NULL}; + // Creating framebuffer for IT1, image views for IT1 and zbuffer // Creating descriptor set for pipeline 0b and for pipeline 1 (containing IT1 sampler) alice_create_mem_dependant_vk_obj(alice); diff --git a/src/l2/gui/colorblock.h b/src/l2/gui/colorblock.h new file mode 100644 index 0000000..e16f1e8 --- /dev/null +++ b/src/l2/gui/colorblock.h @@ -0,0 +1,47 @@ +#pragma once + +#include "../drawer_2d.h" +#include "widget.h" +#include "../../l1_5/marie/graphics_geom.h" + +typedef struct { + EmptyWidget base; + Plain2dShapeRenderer* drawer; + vec4 color; +} ColorblockWidget; + +uvec2 Widget_Table_ColorblockWidget_DRAW_PREPARE(Widget* ug, uvec2 limits) { + return Widget_Table_EmptyWidget_DRAW_PREPARE(ug, 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)); +} + +void Widget_Table_ColorblockWidget_drop(Widget* ug) {} + +const Widget_Table Widget_Table_ColorblockWidget = { + .DRAW_PREPARE = Widget_Table_ColorblockWidget_DRAW_PREPARE, + .DRAW = Widget_Table_ColorblockWidget_DRAW, + .drop = Widget_Table_ColorblockWidget_drop, +}; + +ColorblockWidget ColorblockWidget_new(U32 width, U32 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}; +} diff --git a/src/l2/gui/label.h b/src/l2/gui/label.h index 9185e4a..c2d5e5d 100644 --- a/src/l2/gui/label.h +++ b/src/l2/gui/label.h @@ -1,3 +1,5 @@ #pragma once #include "../lucy/glyph_render.h" + +// todo: add что-то \ No newline at end of file diff --git a/src/l2/gui/widget.h b/src/l2/gui/widget.h index 1fc3912..33a9863 100644 --- a/src/l2/gui/widget.h +++ b/src/l2/gui/widget.h @@ -28,7 +28,7 @@ bool BorderS32_empty(BorderS32 self){ 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)}, - {MAX_S32(a.rb.x, b.rb.x), MAX_S32(a.rb.y, b.rb.y)}, + {MIN_S32(a.rb.x, b.rb.x), MIN_S32(a.rb.y, b.rb.y)}, }; } @@ -53,6 +53,7 @@ Widget Widget_new(){ #include "../../../gen/l1_5/eve/gui/Widget.h" +/* NULL can be passed here */ uvec2 MutRefWidget_draw_prepare(MutRefWidget self, uvec2 max_limits){ if (!self.r) return (uvec2){0}; @@ -61,12 +62,13 @@ uvec2 MutRefWidget_draw_prepare(MutRefWidget self, uvec2 max_limits){ return self.r->sz_my_choice; } +/* NULL can be passed here */ void MutRefWidget_draw(MutRefWidget self, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border){ if (!self.r) return; if (self.r->sz_my_choice.x >= WIDGET_DIM_INF) abortf("Drawing widget before negotiating it's size\n"); - MutRefWidget_draw(self, drawing_offset, surface_sz, border); + MutRefWidget_DRAW(self, drawing_offset, surface_sz, border); self.r->sz_my_choice = (uvec2){WIDGET_DIM_INF, 0}; } @@ -81,9 +83,11 @@ typedef struct { uvec2 Widget_Table_EmptyWidget_DRAW_PREPARE(Widget* ug, uvec2 limits){ EmptyWidget* self = (EmptyWidget*)ug; uvec2 R = widget_size_min_of_all((uvec2){self->width, self->height}, limits); + /* Please, do not put infinite widget into infinite box, I don't want to see what happens */ return is_widget_size_limit_contain_inf(R) ? (uvec2){0, 0} : R; } +// todo: remove `surface_sz` argument void Widget_Table_EmptyWidget_DRAW(Widget* ug, ivec2 drawing_offset, uvec2 surface_sz, BorderS32 border){} void Widget_Table_EmptyWidget_drop(Widget* ug){} @@ -94,6 +98,10 @@ const Widget_Table Widget_Table_EmptyWidget = { .drop = Widget_Table_EmptyWidget_drop, }; +EmptyWidget EmptyWidget_new(U32 width, U32 height) { + 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}; diff --git a/src/l3/r4/r4.c b/src/l3/r4/r4.c index 9d32094..c4450ed 100644 --- a/src/l3/r4/r4.c +++ b/src/l3/r4/r4.c @@ -3,6 +3,7 @@ #include "../../l1_5/marie/prim_shape_geom.h" #include "../../../gen/l1/VecAndSpan_vec3.h" #include "../../l1_5/core/color.h" +#include "../../l2/gui/colorblock.h" #include "linux/input-event-codes.h" @@ -101,7 +102,8 @@ typedef struct{ U64 hits_count; Vecvec3 bullets_stuck_on_ROA; - MargaretSubbuf sb; + /* overlay ui */ + ColorblockWidget gui_0; } R4BetaState; /* We are surrounded by a giant cubic mesh of light sources */ @@ -328,13 +330,8 @@ 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}); - // Just a little test of plain shape drawing - for (int i = 0; i < 10; i++) { - for (int j = 0; j < 5; j++) { - Plain2dShapeRenderer_add_rectangle(&alice->plain_shape_renderer, - vec3_and_one(sample_rainbow_color()), (vec2){20 + 60 * (float)i, 60 + 30 * (float)j }, 50, 20); - } - } + 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}; 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);