From 169b5e1dfdec39f353398ad6e46e6a84557bd2f3 Mon Sep 17 00:00:00 2001 From: Alessandro Mauri Date: Mon, 23 Dec 2024 15:49:46 +0100 Subject: [PATCH] cull commands that result in zero-area bounding boxes --- src/main.c3 | 48 +++++++++++++++++++++++++----------------------- src/ugui_cmd.c3 | 45 ++++++++++++++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/main.c3 b/src/main.c3 index 311bd85..0650e4e 100644 --- a/src/main.c3 +++ b/src/main.c3 @@ -66,6 +66,16 @@ void main() } `; +macro rl::Color ugui::Color.conv(color) +{ + return rl::Color{.r = color.r, .g = color.g, .b = color.b, .a = color.a}; +} + +macro rl::Rectangle ugui::Rect.conv(rect) +{ + return rl::Rectangle{.x = rect.x, .y = rect.y, .width = rect.w, .height = rect.h}; +} + fn int main(String[] args) { ugui::Ctx ui; @@ -96,6 +106,17 @@ fn int main(String[] args) while (!rl::window_should_close()) { clock.mark(); + KeyboardKey k; + do { + k = rl::get_key_pressed(); + if (!k) { break; } + if (rl::is_key_down(k)) { io::print("down "); } + if (rl::is_key_pressed(k)) { io::print("pressed "); } + if (rl::is_key_released(k)) { io::print("released "); } + io::printfn("%s", k); + } while (k != 0); + + /* Start Input Handling */ if (rl::is_window_resized()) { width = (short)rl::get_screen_width(); @@ -197,27 +218,14 @@ fn int main(String[] args) rl::begin_drawing(); // ClearBackground(BLACK); - rl::Color c; - rl::Rectangle r; for (Cmd* cmd; (cmd = ui.cmd_queue.dequeue() ?? null) != null;) { switch (cmd.type) { case ugui::CmdType.CMD_RECT: - c = rl::Color{ - .r = cmd.rect.color.r, - .g = cmd.rect.color.g, - .b = cmd.rect.color.b, - .a = cmd.rect.color.a, - }; - r = rl::Rectangle{ - .x = cmd.rect.rect.x, - .y = cmd.rect.rect.y, - .height = cmd.rect.rect.h, - .width = cmd.rect.rect.w, - }; + Rect r = cmd.rect.rect; float rad = cmd.rect.radius; // for some weird-ass reason the straight forward inverse formula does not work - float roundness = r.width > r.height ? (2.1*rad)/r.height : (2.1*rad)/r.width; - rl::draw_rectangle_rounded(r, roundness, 0, c); + float roundness = r.w > r.h ? (2.1f*rad)/(float)r.h : (2.1f*rad)/(float)r.w; + rl::draw_rectangle_rounded(cmd.rect.rect.conv(), roundness, 0, cmd.rect.color.conv()); case ugui::CmdType.CMD_UPDATE_ATLAS: if (cmd.update_atlas.id != font_id) { break; } //rl::unload_image(font_atlas); @@ -233,18 +241,12 @@ fn int main(String[] args) font_texture = rl::load_texture_from_image(font_atlas); case ugui::CmdType.CMD_SPRITE: if (cmd.sprite.texture_id != font_id) { break; } - rl::Rectangle source = { - .x = cmd.sprite.texture_rect.x, - .y = cmd.sprite.texture_rect.y, - .width = cmd.sprite.texture_rect.w, - .height = cmd.sprite.texture_rect.h, - }; rl::Vector2 position = { .x = cmd.sprite.rect.x, .y = cmd.sprite.rect.y, }; rl::begin_shader_mode(font_shader); - rl::draw_texture_rec(font_texture, source, position, rl::WHITE); + rl::draw_texture_rec(font_texture, cmd.sprite.texture_rect.conv(), position, cmd.sprite.hue.conv()); rl::end_shader_mode(); case ugui::CmdType.CMD_SCISSOR: if (cmd.scissor.rect.w == 0 && cmd.scissor.rect.h == 0) { diff --git a/src/ugui_cmd.c3 b/src/ugui_cmd.c3 index ba6c208..36b970b 100644 --- a/src/ugui_cmd.c3 +++ b/src/ugui_cmd.c3 @@ -29,6 +29,7 @@ struct CmdUpdateAtlas { struct CmdSprite { Rect rect; Rect texture_rect; + Color hue; Id texture_id; } @@ -48,15 +49,29 @@ struct Cmd { } } +macro bool cull_rect(Rect rect, Rect clip = {0,0,short.max,short.max}) +{ + bool no_area = rect.w <= 0 || rect.h <= 0; + return no_area || !rect.collides(clip); +} + +// FIXME: this whole thing could be done at compile time, maybe +macro Ctx.push_cmd(&ctx, Cmd *cmd) +{ + Rect rect; + switch (cmd.type) { + case CMD_RECT: rect = cmd.rect.rect; + case CMD_SPRITE: rect = cmd.sprite.rect; + default: return ctx.cmd_queue.enqueue(cmd); + } + if (cull_rect(rect, ctx.div_scissor)) return; + return ctx.cmd_queue.enqueue(cmd); +} + // FIXME: is this really the best solution? // "rect" is the bounding box of the element, which includes the border and the padding (so not just the content) fn void! Ctx.push_rect(&ctx, Rect rect, Color color, bool do_border = false, bool do_padding = false, bool do_radius = false) { - // FIXME: this should be culled higher up, maybe - if (rect.w <= 0 || rect.h <= 0) { - return; - } - Rect border = ctx.style.border; Rect padding = ctx.style.padding; ushort radius = ctx.style.radius; @@ -69,7 +84,7 @@ fn void! Ctx.push_rect(&ctx, Rect rect, Color color, bool do_border = false, boo .rect.color = border_color, .rect.radius = do_radius ? radius : 0, }; - ctx.cmd_queue.enqueue(&cmd)!; + ctx.push_cmd(&cmd)!; } Cmd cmd = { @@ -83,22 +98,24 @@ fn void! Ctx.push_rect(&ctx, Rect rect, Color color, bool do_border = false, boo .rect.color = color, .rect.radius = do_radius ? radius : 0, }; - ctx.cmd_queue.enqueue(&cmd)!; + if (cull_rect(cmd.rect.rect, ctx.div_scissor)) return; + ctx.push_cmd(&cmd)!; } // TODO: add texture id -fn void! Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id) +fn void! Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, Color hue = uint_to_rgba(0xffffffff)) { Cmd cmd = { .type = CMD_SPRITE, .sprite.rect = bounds, .sprite.texture_rect = texture, .sprite.texture_id = texture_id, + .sprite.hue = hue, }; - ctx.cmd_queue.enqueue(&cmd)!; + ctx.push_cmd(&cmd)!; } -fn void! Ctx.push_string(&ctx, Rect bounds, String text) +fn void! Ctx.push_string(&ctx, Rect bounds, String text, Color hue = uint_to_rgba(0xffffffff)) { if (text.len == 0) { return; @@ -136,9 +153,7 @@ fn void! Ctx.push_string(&ctx, Rect bounds, String text) .h = gp.h, }; // push the sprite only if it collides with the bounds - if (gb.collides(bounds)) { - ctx.push_sprite(gb, gt, texture_id)!; - } + if (!cull_rect(gb, bounds)) ctx.push_sprite(gb, gt, texture_id, hue)!; line_len += gp.adv; } else if (cp == '\n'){ orig.y += line_height + line_gap; @@ -164,7 +179,7 @@ fn void! Ctx.push_update_atlas(&ctx, Atlas* atlas) .bpp = (ushort)atlas.type.bpp(), }, }; - ctx.cmd_queue.enqueue(&up)!; + ctx.push_cmd(&up)!; } fn void! Ctx.push_scissor(&ctx, Rect rect) @@ -173,5 +188,5 @@ fn void! Ctx.push_scissor(&ctx, Rect rect) .type = CMD_SCISSOR, .scissor.rect = rect.intersection(ctx.div_scissor), }; - ctx.cmd_queue.enqueue(&sc)!; + ctx.push_cmd(&sc)!; }