implement z index in command buffer

This commit is contained in:
Alessandro Mauri 2025-06-03 18:15:46 +02:00
parent f344c989db
commit c9b74aebc7
7 changed files with 66 additions and 40 deletions

View File

@ -40,7 +40,7 @@ fn ElemEvents? Ctx.button(&ctx, String label, Rect size, bool state = false)
}
// Draw the button
ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!;
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!;
return elem.events;
}
@ -80,8 +80,8 @@ fn ElemEvents? Ctx.button_label(&ctx, String label, Rect size = {0,0,short.max,s
Point off = ctx.center_text(text_size, elem.bounds);
text_size.x += off.x;
text_size.y += off.y;
ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!;
ctx.push_string(text_size, label)!;
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!;
ctx.push_string(text_size, label, parent.div.z_index)!;
return elem.events;
}
@ -116,13 +116,13 @@ fn ElemEvents? Ctx.button_icon(&ctx, String label, String icon, String on_icon =
Id tex_id = ctx.sprite_atlas.id;
if (state && on_icon != "") {
ctx.push_sprite(elem.bounds, on_sprite.uv(), tex_id, type: on_sprite.type)!;
ctx.push_sprite(elem.bounds, on_sprite.uv(), tex_id, parent.div.z_index, type: on_sprite.type)!;
} else {
ctx.push_sprite(elem.bounds, def_sprite.uv(), tex_id, type: def_sprite.type)!;
ctx.push_sprite(elem.bounds, def_sprite.uv(), tex_id, parent.div.z_index, type: def_sprite.type)!;
}
// Draw the button
ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!;
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!;
return elem.events;
}
@ -159,7 +159,7 @@ fn void? Ctx.checkbox(&ctx, String label, String description, Point off, bool* s
Color col;
if (tick_sprite != {}) {
col = ctx.style.bgcolor;
ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!;
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!;
if (*state) {
ctx.draw_sprite_raw(tick_sprite, elem.bounds)!;
}
@ -170,7 +170,7 @@ fn void? Ctx.checkbox(&ctx, String label, String description, Point off, bool* s
col = 0xff00ffffu.to_rgba();
}
// Draw the button
ctx.push_rect(elem.bounds, col, do_border: true, do_radius: true)!;
ctx.push_rect(elem.bounds, col, parent.div.z_index, do_border: true, do_radius: true)!;
}
}
@ -211,7 +211,7 @@ fn void? Ctx.toggle(&ctx, String label, String description, Point off, bool* sta
}
// Draw the button
// FIXME: THIS IS SHIT
ctx.push_rect(elem.bounds, ctx.style.bgcolor, do_border: true, do_radius: true)!;
ctx.push_rect(elem.bounds, ctx.style.bgcolor, parent.div.z_index, do_border: true, do_radius: true)!;
Rect t = elem.bounds.add({*state ? (DEFAULT_SWITCH_SIZE+3) : +3, +3, -DEFAULT_SWITCH_SIZE-6, -6});
ctx.push_rect(t, col, do_border: false, do_radius: true)!;
ctx.push_rect(t, col, parent.div.z_index, do_border: false, do_radius: true)!;
}

View File

@ -1,6 +1,7 @@
module ugui;
import std::ascii;
import std::io;
// command type
enum CmdType {
@ -37,8 +38,9 @@ struct CmdScissor {
}
// command structure
struct Cmd {
struct Cmd (Printable) {
CmdType type;
int z_index;
union {
CmdRect rect;
CmdUpdateAtlas update_atlas;
@ -47,6 +49,12 @@ struct Cmd {
}
}
// implement the Printable interface
fn usz? Cmd.to_format(Cmd* cmd, Formatter *f) @dynamic
{
return f.printf("Cmd{ type: %s, z_index: %d }", cmd.type, cmd.z_index);
}
macro bool cull_rect(Rect rect, Rect clip = {0,0,short.max,short.max})
{
bool no_area = rect.w <= 0 || rect.h <= 0;
@ -54,8 +62,9 @@ macro bool cull_rect(Rect rect, Rect clip = {0,0,short.max,short.max})
}
// FIXME: this whole thing could be done at compile time, maybe
macro Ctx.push_cmd(&ctx, Cmd *cmd)
macro Ctx.push_cmd(&ctx, Cmd *cmd, int z_index)
{
cmd.z_index = z_index;
Rect rect;
switch (cmd.type) {
case CMD_RECT: rect = cmd.rect.rect;
@ -66,9 +75,18 @@ macro Ctx.push_cmd(&ctx, Cmd *cmd)
return ctx.cmd_queue.enqueue(cmd);
}
fn void? Ctx.push_scissor(&ctx, Rect rect, int z_index)
{
Cmd sc = {
.type = CMD_SCISSOR,
.scissor.rect = rect.intersection(ctx.div_scissor),
};
ctx.push_cmd(&sc, z_index)!;
}
// 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)
fn void? Ctx.push_rect(&ctx, Rect rect, Color color, int z_index, bool do_border = false, bool do_padding = false, bool do_radius = false)
{
Rect border = ctx.style.border;
Rect padding = ctx.style.padding;
@ -82,7 +100,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.push_cmd(&cmd)!;
ctx.push_cmd(&cmd, z_index)!;
}
Cmd cmd = {
@ -97,11 +115,11 @@ fn void? Ctx.push_rect(&ctx, Rect rect, Color color, bool do_border = false, boo
.rect.radius = do_radius ? radius : 0,
};
if (cull_rect(cmd.rect.rect, ctx.div_scissor)) return;
ctx.push_cmd(&cmd)!;
ctx.push_cmd(&cmd, z_index)!;
}
// TODO: add texture id
fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, Color hue = 0xffffffffu.to_rgba(), SpriteType type = SPRITE_NORMAL)
fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, int z_index, Color hue = 0xffffffffu.to_rgba(), SpriteType type = SPRITE_NORMAL)
{
Cmd cmd = {
.type = CMD_SPRITE,
@ -111,16 +129,16 @@ fn void? Ctx.push_sprite(&ctx, Rect bounds, Rect texture, Id texture_id, Color h
.sprite.texture_id = texture_id,
.sprite.hue = hue,
};
ctx.push_cmd(&cmd)!;
ctx.push_cmd(&cmd, z_index)!;
}
fn void? Ctx.push_string(&ctx, Rect bounds, String text, Color hue = 0xffffffffu.to_rgba())
fn void? Ctx.push_string(&ctx, Rect bounds, String text, int z_index, Color hue = 0xffffffffu.to_rgba())
{
if (text.len == 0) {
return;
}
ctx.push_scissor(bounds)!;
ctx.push_scissor(bounds, z_index)!;
short baseline = (short)ctx.font.ascender;
short line_height = (short)ctx.font.ascender - (short)ctx.font.descender;
@ -152,7 +170,7 @@ fn void? Ctx.push_string(&ctx, Rect bounds, String text, Color hue = 0xffffffffu
.h = gp.h,
};
// push the sprite only if it collides with the bounds
if (!cull_rect(gb, bounds)) ctx.push_sprite(gb, gt, texture_id, hue)!;
if (!cull_rect(gb, bounds)) ctx.push_sprite(gb, gt, texture_id, z_index, hue)!;
line_len += gp.adv;
} else if (cp == '\n'){
orig.y += line_height + line_gap;
@ -163,7 +181,7 @@ fn void? Ctx.push_string(&ctx, Rect bounds, String text, Color hue = 0xffffffffu
}
// FIXME: we never get here if an error was thrown before
ctx.push_scissor({})!;
ctx.push_scissor({}, z_index)!;
}
fn void? Ctx.push_update_atlas(&ctx, Atlas* atlas)
@ -178,14 +196,7 @@ fn void? Ctx.push_update_atlas(&ctx, Atlas* atlas)
.bpp = (ushort)atlas.type.bpp(),
},
};
ctx.push_cmd(&up)!;
// update the atlases before everything else
ctx.push_cmd(&up, -1)!;
}
fn void? Ctx.push_scissor(&ctx, Rect rect)
{
Cmd sc = {
.type = CMD_SCISSOR,
.scissor.rect = rect.intersection(ctx.div_scissor),
};
ctx.push_cmd(&sc)!;
}

View File

@ -244,6 +244,7 @@ fn void? Ctx.frame_begin(&ctx)
},
.div = {
.layout = LAYOUT_ROW,
.z_index = 0,
.children_bounds = {
.w = ctx.width,
.h = ctx.height,
@ -263,6 +264,8 @@ fn void? Ctx.frame_begin(&ctx)
// TODO: add a background color taken from a theme or config
}
const int DEBUG = 1;
fn void? Ctx.frame_end(&ctx)
{
Elem* root = ctx.get_elem_by_tree_idx(0)!;
@ -285,10 +288,12 @@ fn void? Ctx.frame_end(&ctx)
ctx.sprite_atlas.should_update = false;
}
$if 1:
// debug
$if DEBUG == 1:
// draw mouse position
Cmd cmd = {
.type = CMD_RECT,
.z_index = int.max, // hopefully over everything else
.rect.rect = {
.x = ctx.input.mouse.pos.x - 2,
.y = ctx.input.mouse.pos.y - 2,
@ -298,6 +303,12 @@ $if 1:
.rect.color = 0xff00ffffu.to_rgba()
};
ctx.cmd_queue.enqueue(&cmd)!;
// dump the command buffer
io::printn("Command Buffer Dump:");
foreach(idx, c: ctx.cmd_queue) {
io::printfn("\t [%d] = {%s}", idx, c);
}
$endif
}

View File

@ -18,6 +18,7 @@ struct ElemDiv {
bool on;
float value;
}
int z_index;
Rect children_bounds; // current frame children bounds
Rect pcb; // previous frame children bounds
Point origin_r, origin_c;
@ -46,6 +47,8 @@ fn void? Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, boo
}
elem.div.scroll_x.enabled = scroll_x;
elem.div.scroll_y.enabled = scroll_y;
elem.div.z_index = parent.div.z_index + 1;
io::printn(elem.div.z_index);
// 2. layout the element
Rect wanted_size = {
@ -59,7 +62,7 @@ fn void? Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, boo
// update the ctx scissor
ctx.div_scissor = elem.bounds;
ctx.push_scissor(elem.bounds)!;
ctx.push_scissor(elem.bounds, elem.div.z_index)!;
// 4. Fill the div fields
elem.div.origin_c = {
@ -71,7 +74,7 @@ fn void? Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, boo
// Add the background to the draw stack
bool do_border = parent.div.layout == LAYOUT_FLOATING;
ctx.push_rect(elem.bounds, ctx.style.bgcolor, do_border: do_border)!;
ctx.push_rect(elem.bounds, ctx.style.bgcolor, elem.div.z_index, do_border: do_border)!;
elem.events = ctx.get_elem_events(elem);

View File

@ -61,8 +61,8 @@ fn ElemEvents? Ctx.slider_hor(&ctx,
}
// Draw the slider background and handle
ctx.push_rect(elem.bounds, bgcolor)!;
ctx.push_rect(elem.slider.handle, handlecolor)!;
ctx.push_rect(elem.bounds, bgcolor, parent.div.z_index)!;
ctx.push_rect(elem.slider.handle, handlecolor, parent.div.z_index)!;
return elem.events;
}
@ -124,8 +124,8 @@ fn ElemEvents? Ctx.slider_ver(&ctx,
}
// Draw the slider background and handle
ctx.push_rect(elem.bounds, bgcolor)!;
ctx.push_rect(elem.slider.handle, handlecolor)!;
ctx.push_rect(elem.bounds, bgcolor, parent.div.z_index)!;
ctx.push_rect(elem.slider.handle, handlecolor, parent.div.z_index)!;
return elem.events;
}

View File

@ -164,12 +164,13 @@ fn void? Ctx.draw_sprite(&ctx, String label, String name, Point off = {0,0})
Id tex_id = ctx.sprite_atlas.id;
return ctx.push_sprite(elem.bounds, uv, tex_id)!;
return ctx.push_sprite(elem.bounds, uv, tex_id, parent.div.z_index)!;
}
fn void? Ctx.draw_sprite_raw(&ctx, String name, Rect bounds)
{
Elem *parent = ctx.get_parent()!;
Sprite* sprite = ctx.sprite_atlas.get(name)!;
Id tex_id = ctx.sprite_atlas.id;
return ctx.push_sprite(bounds, sprite.uv(), tex_id, type: sprite.type)!;
return ctx.push_sprite(bounds, sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
}

View File

@ -26,5 +26,5 @@ fn void? Ctx.text_unbounded(&ctx, String label, String text)
elem.bounds = ctx.position_element(parent, text_size, true);
if (elem.bounds.is_null()) { return; }
ctx.push_string(elem.bounds, text)!;
ctx.push_string(elem.bounds, text, parent.div.z_index)!;
}