ui control testing

This commit is contained in:
jacob 2025-11-03 00:34:13 -06:00
parent 687cc88a64
commit 67ba54274f
8 changed files with 381 additions and 165 deletions

View File

@ -614,6 +614,7 @@ ForceInline void UnlockTicketMutex(TicketMutex *tm)
#if LanguageIsC #if LanguageIsC
#define STRING(size, data) ((String) { (size), (data) }) #define STRING(size, data) ((String) { (size), (data) })
#define Zstr ((String) { 0, 0})
#define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) } #define Lit(cstr_lit) (String) { (sizeof((cstr_lit)) - 1), (u8 *)(cstr_lit) }
#define LitNoCast(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) } #define LitNoCast(cstr_lit) { .len = (sizeof((cstr_lit)) - 1), .text = (u8 *)(cstr_lit) }
#define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 }) #define StringFromPointers(p0, p1) ((String) { (u8 *)(p1) - (u8 *)(p0), (u8 *)p0 })

View File

@ -146,9 +146,6 @@ Struct(ControllerEvent)
/* ControllerEventKind_MouseMove */ /* ControllerEventKind_MouseMove */
Vec2I32 mouse_delta; Vec2I32 mouse_delta;
/* Should be incremented by systems that want to consume the input */
u32 consumed;
}; };
Struct(ControllerEventsArray) Struct(ControllerEventsArray)

View File

@ -395,14 +395,14 @@ void PP_UpdateUser(void)
g->screen_size.y = MaxI32(g->screen_size.y, 1); g->screen_size.y = MaxI32(g->screen_size.y, 1);
//- Begin UI //- Begin UI
UI_BeginBuild(&controller_events); UI_BeginBuild(controller_events);
UI_Push(LayoutAxis, Axis_Y); UI_Push(LayoutAxis, Axis_Y);
if (window_frame.forced_top) if (window_frame.forced_top)
{ {
UI_SetNext(Border, 10); UI_SetNext(Border, 10);
UI_SetNext(BorderColor, Rgba32F(1, 0, 0, 0.5)); UI_SetNext(BorderColor, Rgba32F(1, 0, 0, 0.5));
} }
UI_Box *pp_root_box = UI_BuildBox(UI_NilKey); UI_Box *pp_root_box = UI_BuildBox(Lit("pp root"));
PP_PushGameUiStyle(); PP_PushGameUiStyle();
UI_Push(Parent, pp_root_box); UI_Push(Parent, pp_root_box);
@ -679,7 +679,7 @@ void PP_UpdateUser(void)
if (g->bind_states[PP_BindKind_DebugLister].num_presses > 0) if (g->bind_states[PP_BindKind_DebugLister].num_presses > 0)
{ {
g->debug_lister = !g->debug_lister; g->lister_active = !g->lister_active;
} }
{ {
@ -1938,10 +1938,18 @@ void PP_UpdateUser(void)
} }
/* Draw lister */ /* Draw lister */
if (g->debug_lister) if (g->lister_active)
{
UI_PushCheckpoint();
{ {
Vec2 size = VEC2(400, 500); Vec2 size = VEC2(400, 500);
UI_Event ev = UI_EventFromKey(g->lister_key);
if (ev.flags & UI_EventFlag_Active)
{
g->lister_pos = SubVec2(g->ui_cursor, ev.activation_offset);
}
UI_SetNext(LayoutAxis, Axis_Y); UI_SetNext(LayoutAxis, Axis_Y);
UI_SetNext(BackgroundColor, Rgba32F(0.075, 0.075, 0.075, 0.99)); UI_SetNext(BackgroundColor, Rgba32F(0.075, 0.075, 0.075, 0.99));
UI_SetNext(BorderColor, Rgba32F(0.2, 0.2, 0.2, 1)); UI_SetNext(BorderColor, Rgba32F(0.2, 0.2, 0.2, 1));
@ -1949,10 +1957,13 @@ void PP_UpdateUser(void)
UI_SetNext(Rounding, 0.1); UI_SetNext(Rounding, 0.1);
UI_SetNext(Parent, pp_root_box); UI_SetNext(Parent, pp_root_box);
UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_ClampFloatingX | UI_BoxFlag_ClampFloatingY); UI_SetNext(Flags, UI_BoxFlag_Floating | UI_BoxFlag_ClampFloatingX | UI_BoxFlag_ClampFloatingY);
UI_SetNext(FloatingPos, g->debug_lister_pos); UI_SetNext(FloatingPos, g->lister_pos);
UI_SetNext(Width, UI_PIX(size.x, 0)); UI_SetNext(Width, UI_PIX(size.x, 0));
UI_SetNext(Height, UI_PIX(size.y, 0)); UI_SetNext(Height, UI_PIX(size.y, 0));
UI_Box *lister_box = UI_BuildBox(UI_NilKey); UI_Box *lister_box = UI_BuildBox(Lit("lister"));
g->lister_key = lister_box->key;
}
UI_PopCheckpoint();
} }
/* Draw debug info */ /* Draw debug info */
@ -1968,7 +1979,7 @@ void PP_UpdateUser(void)
UI_SetNext(Width, UI_FIT(0)); UI_SetNext(Width, UI_FIT(0));
UI_SetNext(Height, UI_FIT(1)); UI_SetNext(Height, UI_FIT(1));
UI_SetNext(Tint, 0); UI_SetNext(Tint, 0);
UI_Box *dbg_box = UI_BuildBox(UI_NilKey); UI_Box *dbg_box = UI_BuildBox(Lit("dbg"));
UI_PushCheckpoint(); UI_PushCheckpoint();
{ {
UI_Push(Parent, dbg_box); UI_Push(Parent, dbg_box);
@ -2272,7 +2283,7 @@ void PP_UpdateUser(void)
} }
/* Render UI */ /* Render UI */
g->gpu_submit_fence_target = UI_EndBuild(g->ui_target); g->gpu_submit_fence_target = UI_EndBuild(g->ui_target, g->ui_to_screen_xf);
////////////////////////////// //////////////////////////////
//- Present & end frame //- Present & end frame

View File

@ -250,8 +250,9 @@ Struct(PP_SharedUserState)
b32 debug_camera_panning; b32 debug_camera_panning;
b32 debug_camera; b32 debug_camera;
b32 debug_lister; b32 lister_active;
Vec2 debug_lister_pos; Vec2 lister_pos;
UI_Key lister_key;
b32 debug_draw; b32 debug_draw;
b32 debug_console; b32 debug_console;

View File

@ -60,7 +60,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
// UI_SetNext(Height, UI_FILL(0.33, 1)); // UI_SetNext(Height, UI_FILL(0.33, 1));
UI_SetNext(Height, UI_FIT(1)); UI_SetNext(Height, UI_FIT(1));
} }
console_box = UI_BuildBox(UI_NilKey); console_box = UI_BuildBox(Lit("Console box"));
UI_Push(Parent, console_box); UI_Push(Parent, console_box);
} }
{ {
@ -124,7 +124,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
UI_SetNext(BorderColor, Rgba32F(0.25, 0.25, 0.25, 1)); UI_SetNext(BorderColor, Rgba32F(0.25, 0.25, 0.25, 1));
UI_SetNext(Rounding, 0); UI_SetNext(Rounding, 0);
UI_SetNext(Border, 1); UI_SetNext(Border, 1);
UI_Box *log_box = UI_BuildBox(UI_NilKey); UI_Box *log_box = UI_BuildBox(Zstr);
UI_Push(Parent, log_box); UI_Push(Parent, log_box);
} }
{ {
@ -135,7 +135,7 @@ UI_Box *PP_BuildDebugConsole(b32 minimized)
UI_SetNext(Width, UI_FILL(1, 0)); UI_SetNext(Width, UI_FILL(1, 0));
UI_SetNext(Height, UI_TXT(1)); UI_SetNext(Height, UI_TXT(1));
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_Box *log_textbox = UI_BuildBox(UI_NilKey); UI_Box *log_textbox = UI_BuildBox(Zstr);
} }
} }
UI_PopCheckpoint(); UI_PopCheckpoint();

View File

@ -3,12 +3,11 @@
UI_Box *UI_BuildLabel(String text) UI_Box *UI_BuildLabel(String text)
{ {
UI_Key key = UI_KeyFromString(0, text);
UI_SetNext(Width, UI_TXT(0)); UI_SetNext(Width, UI_TXT(0));
UI_SetNext(Height, UI_TXT(0)); UI_SetNext(Height, UI_TXT(0));
UI_SetNext(Text, text); UI_SetNext(Text, text);
UI_SetNext(Flags, UI_BoxFlag_DrawText); UI_SetNext(Flags, UI_BoxFlag_DrawText);
UI_Box *box = UI_BuildBox(UI_NilKey); UI_Box *box = UI_BuildBox(Zstr);
return box; return box;
} }
@ -41,6 +40,6 @@ UI_Box *UI_BuildSpacer(UI_Size size)
{ {
UI_SetNext(Height, size); UI_SetNext(Height, size);
} }
UI_Box *box = UI_BuildBox(UI_NilKey); UI_Box *box = UI_BuildBox(Zstr);
return box; return box;
} }

View File

@ -21,27 +21,42 @@ ResourceKey UI_GetDefaultFontResource(void)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key helpers //~ Key helpers
u64 UI_HashFromTop(void) UI_Box *UI_BackBoxFromKey(UI_Key key)
{ {
UI_Box *parent_box = UI_PeekTop(Parent); UI_SharedState *g = &UI_shared_state;
u64 tag_hash = UI_PeekTop(Tag); UI_Box *back_box = 0;
return RandU64FromSeeds(parent_box->key.hash, tag_hash); if (key.hash != 0)
}
u64 UI_HashFromString(u64 seed, String str)
{
if (seed == 0)
{ {
seed = UI_HashFromTop(); UI_BoxBin *back_bin = &g->back_box_bins[key.hash % UI_NumBoxLookupBins];
for (UI_Box *tmp = back_bin->first; tmp; tmp = tmp->next_in_bin)
{
if (tmp->key.hash == key.hash)
{
back_box = tmp;
break;
} }
return HashFnv64(seed, str); }
}
return back_box;
} }
UI_Key UI_KeyFromString(u64 seed, String str) UI_Box *UI_FrontBoxFromKey(UI_Key key)
{ {
UI_Key result = ZI; UI_SharedState *g = &UI_shared_state;
result.hash = UI_HashFromString(seed, str); UI_Box *front_box = 0;
return result; if (key.hash != 0)
{
UI_BoxBin *front_bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
for (UI_Box *tmp = front_bin->first; tmp; tmp = tmp->next_in_bin)
{
if (tmp->key.hash == key.hash)
{
front_box = tmp;
break;
}
}
}
return front_box;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -70,10 +85,7 @@ void UI_PopCheckpoint(void)
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
UI_Checkpoint *cp = g->top_checkpoint; UI_Checkpoint *cp = g->top_checkpoint;
u64 v = cp->v; u64 v = cp->v;
if (v == 0) /* Pop styles */
{
DEBUGBREAKABLE;
}
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
{ {
UI_StyleNode *n = g->style_tops[kind]; UI_StyleNode *n = g->style_tops[kind];
@ -99,6 +111,7 @@ UI_StyleNode *UI_PushStyleNode(UI_Style desc)
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
UI_StyleNode *n = g->style_tops[desc.kind]; UI_StyleNode *n = g->style_tops[desc.kind];
if (!n->style.forced) if (!n->style.forced)
{
{ {
if (n->style.pop_when_used) if (n->style.pop_when_used)
{ {
@ -120,6 +133,9 @@ UI_StyleNode *UI_PushStyleNode(UI_Style desc)
} }
n->style = desc; n->style = desc;
n->checkpoint = g->top_checkpoint->v; n->checkpoint = g->top_checkpoint->v;
}
/* Initialize style data from desc */
switch (desc.kind) switch (desc.kind)
{ {
default: break; default: break;
@ -128,6 +144,15 @@ UI_StyleNode *UI_PushStyleNode(UI_Style desc)
{ {
n->style.Text = PushString(g->build_arena, desc.Text); n->style.Text = PushString(g->build_arena, desc.Text);
} break; } break;
case UI_StyleKind_Tag:
{
n->style.Tag.name = PushString(g->build_arena, desc.Tag.name);
if (n->style.Tag.hash == 0)
{
n->style.Tag.hash = HashFnv64(g->style_tops[desc.kind]->style.Tag.hash, n->style.Tag.name);
}
} break;
} }
} }
g->style_tops[desc.kind] = n; g->style_tops[desc.kind] = n;
@ -169,13 +194,25 @@ UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 use)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Box helpers //~ Box helpers
UI_Box *UI_BuildBox(UI_Key key) UI_Box *UI_BuildBox(String seed)
{ {
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
UI_BoxBin *back_bin = &g->back_box_bins[key.hash % UI_NumBoxLookupBins];
/* Calculate key */
UI_Box *parent = UI_UseTop(Parent);
UI_Tag tag = UI_UseTop(Tag);
UI_Key key = ZI;
if (seed.len > 0)
{
key.hash = RandU64FromSeeds(key.hash, parent->key.hash);
key.hash = RandU64FromSeeds(key.hash, tag.hash);
key.hash = HashFnv64(key.hash, seed);
}
/* Insert into lookup */
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
UI_Box *box = PushStruct(g->build_arena, UI_Box); UI_Box *box = PushStruct(g->build_arena, UI_Box);
UI_Box *back_box = 0;
if (key.hash != 0) if (key.hash != 0)
{ {
#if RtcIsEnabled #if RtcIsEnabled
@ -190,33 +227,20 @@ UI_Box *UI_BuildBox(UI_Key key)
} }
#endif #endif
DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
back_box = UI_BackBoxFromKey(key);
} }
box->parent = parent;
/* Find previous build's box from hash */ box->key = key;
UI_Box *back_box = 0;
if (key.hash != 0)
{
for (UI_Box *tmp = back_bin->first; tmp; tmp = tmp->next_in_bin)
{
if (tmp->key.hash == key.hash)
{
back_box = tmp;
break;
}
}
}
if (back_box)
{
*box = *back_box;
}
++g->boxes_count; ++g->boxes_count;
box->key = key; /* Persist data from back box */
if (back_box != 0)
{
box->event = back_box->event;
}
/* Pull from style stack */ /* Pull from style stack */
box->flags = UI_UseTop(Flags); box->flags = UI_UseTop(Flags);
box->parent = UI_UseTop(Parent);
box->pref_size[Axis_X] = UI_UseTop(Width); box->pref_size[Axis_X] = UI_UseTop(Width);
box->pref_size[Axis_Y] = UI_UseTop(Height); box->pref_size[Axis_Y] = UI_UseTop(Height);
box->layout_axis = UI_UseTop(LayoutAxis); box->layout_axis = UI_UseTop(LayoutAxis);
@ -237,8 +261,8 @@ UI_Box *UI_BuildBox(UI_Key key)
box->font = F_LoadFontAsync(box->font_resource, box->font_size); box->font = F_LoadFontAsync(box->font_resource, box->font_size);
} }
DllPushBack(box->parent->first, box->parent->last, box); DllPushBack(parent->first, parent->last, box);
++box->parent->count; ++parent->count;
return box; return box;
} }
@ -250,14 +274,140 @@ void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2
box->background_texture_uv1 = uv1; box->background_texture_uv1 = uv1;
} }
////////////////////////////////////////////////////////////
//~ Event
UI_Event UI_EventFromKey(UI_Key key)
{
UI_SharedState *g = &UI_shared_state;
UI_Event result = ZI;
UI_Box *back_box = UI_BackBoxFromKey(key);
if (back_box)
{
result = back_box->event;
}
return result;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Begin build //~ Begin build
void UI_BeginBuild(ControllerEventsArray *controller_events) void UI_BeginBuild(ControllerEventsArray controller_events)
{ {
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
/* Swap front & back build states */ //////////////////////////////
//- Process controller events
if (g->build_arena != 0 && g->back_build_arena != 0)
{
Xform screen_to_ui_xf = InvertXform(g->ui_to_screen_xf);
/* Locate boxes */
UI_Box *hovered_box = 0;
UI_Box *active_box = 0;
for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
{
UI_Box *box = g->boxes_pre[pre_index];
if (hovered_box == 0 && box->event.flags & UI_EventFlag_Hovered)
{
hovered_box = box;
}
if (active_box == 0 && box->event.flags & UI_EventFlag_Active)
{
active_box = box;
}
}
// /* Refresh initial box events */
// for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
// {
// UI_Box *box = g->boxes_pre[pre_index];
// if (g->cursor_pos.x > box->p0.x && g->cursor_pos.x < box->p1.x &&
// g->cursor_pos.y > box->p0.y && g->cursor_pos.y < box->p1.y)
// {
// box->event.flags |= UI_EventFlag_Hovered;
// hovered_box = box;
// }
// else
// {
// box->event.flags &= ~UI_EventFlag_Hovered;
// hovered_box = 0;
// }
// if (box->event.flags & UI_EventFlag_Active)
// {
// active_box = box;
// }
// }
/* Update state from controller events */
for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index)
{
ControllerEvent cev = controller_events.events[cev_index];
switch (cev.kind)
{
default: break;
case ControllerEventKind_CursorMove:
{
g->cursor_pos = MulXformV2(screen_to_ui_xf, Vec2FromFields(cev.cursor_pos));
/* Iterate boxes in reverse render order */
for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
{
UI_Box *box = g->boxes_pre[pre_index];
if (g->cursor_pos.x > box->p0.x && g->cursor_pos.x < box->p1.x &&
g->cursor_pos.y > box->p0.y && g->cursor_pos.y < box->p1.y)
{
if (hovered_box)
{
hovered_box->event.flags &= ~UI_EventFlag_Hovered;
}
box->event.flags |= UI_EventFlag_Hovered;
hovered_box = box;
break;
}
}
} break;
case ControllerEventKind_ButtonDown:
{
if (cev.button == Btn_M1)
{
UI_Box *box = hovered_box;
if (box)
{
box->event.flags |= UI_EventFlag_Active;
box->event.activation_offset = SubVec2(g->cursor_pos, box->p0);
active_box = box;
}
}
} break;
case ControllerEventKind_ButtonUp:
{
if (cev.button == Btn_M1)
{
UI_Box *box = active_box;
if (box)
{
box->event.flags &= ~UI_EventFlag_Active;
active_box = 0;
}
}
} break;
}
}
}
//////////////////////////////
//- Swap front & back
{
{ {
Arena *swp = g->build_arena; Arena *swp = g->build_arena;
g->build_arena = g->back_build_arena; g->build_arena = g->back_build_arena;
@ -266,8 +416,14 @@ void UI_BeginBuild(ControllerEventsArray *controller_events)
g->back_box_bins = g->box_bins; g->back_box_bins = g->box_bins;
g->back_root_box = g->root_box; g->back_root_box = g->root_box;
g->back_boxes_count = g->boxes_count; g->back_boxes_count = g->boxes_count;
g->back_boxes_pre = g->boxes_pre;
g->back_boxes_post = g->boxes_post;
}
/* Reset front build state */ //////////////////////////////
//- Reset build state
{
if (!g->build_arena) if (!g->build_arena)
{ {
g->build_arena = AcquireArena(Gibi(64)); g->build_arena = AcquireArena(Gibi(64));
@ -287,6 +443,18 @@ void UI_BeginBuild(ControllerEventsArray *controller_events)
DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin); DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin);
++g->boxes_count; ++g->boxes_count;
if (!g->back_build_arena)
{
/* Back buffer not initialized, swap again */
UI_BeginBuild(controller_events);
}
}
//////////////////////////////
//- Init style stack
{
/* Init checkpoints */ /* Init checkpoints */
g->top_checkpoint = PushStruct(g->build_arena, UI_Checkpoint); g->top_checkpoint = PushStruct(g->build_arena, UI_Checkpoint);
@ -300,19 +468,15 @@ void UI_BeginBuild(ControllerEventsArray *controller_events)
style->kind = kind; style->kind = kind;
g->style_tops[kind] = n; g->style_tops[kind] = n;
} }
g->style_tops[UI_StyleKind_Tag]->style.Tag = HashFnv64(Fnv64Basis, Lit("root"));
g->style_tops[UI_StyleKind_Parent]->style.Parent = g->root_box; g->style_tops[UI_StyleKind_Parent]->style.Parent = g->root_box;
g->style_tops[UI_StyleKind_Width]->style.Width = UI_FILL(1, 0); g->style_tops[UI_StyleKind_Width]->style.Width = UI_FILL(1, 0);
g->style_tops[UI_StyleKind_Height]->style.Height = UI_FILL(1, 0); g->style_tops[UI_StyleKind_Height]->style.Height = UI_FILL(1, 0);
g->style_tops[UI_StyleKind_Font]->style.Font = UI_GetDefaultFontResource(); g->style_tops[UI_StyleKind_Font]->style.Font = UI_GetDefaultFontResource();
g->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f; g->style_tops[UI_StyleKind_FontSize]->style.FontSize = 16.0f;
g->style_tops[UI_StyleKind_Tint]->style.Tint = 0xFFFFFFFF; g->style_tops[UI_StyleKind_Tint]->style.Tint = 0xFFFFFFFF;
g->style_tops[UI_StyleKind_Tag]->style.Tag.name = Lit("root");
g->style_tops[UI_StyleKind_Tag]->style.Tag.hash = HashFnv64(Fnv64Basis, g->style_tops[UI_StyleKind_Tag]->style.Tag.name);
} }
if (!g->back_build_arena)
{
/* Back buffer not initialized, swap again */
UI_BeginBuild(controller_events);
} }
} }
@ -329,10 +493,11 @@ GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size)
return desc; return desc;
} }
i64 UI_EndBuild(GPU_Resource *render_target) i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf)
{ {
TempArena scratch = BeginScratchNoConflict(); TempArena scratch = BeginScratchNoConflict();
UI_SharedState *g = &UI_shared_state; UI_SharedState *g = &UI_shared_state;
g->ui_to_screen_xf = ui_to_screen_xf;
Vec2I32 render_target_size = GPU_GetTextureSize2D(render_target); Vec2I32 render_target_size = GPU_GetTextureSize2D(render_target);
Rect render_viewport = ZI; Rect render_viewport = ZI;
@ -352,8 +517,10 @@ i64 UI_EndBuild(GPU_Resource *render_target)
/* Build pre-order & post-order box arrays */ /* Build pre-order & post-order box arrays */
u64 boxes_count = g->boxes_count; u64 boxes_count = g->boxes_count;
UI_Box **boxes_pre = PushStructsNoZero(scratch.arena, UI_Box *, boxes_count); UI_Box **boxes_pre = PushStructsNoZero(g->build_arena, UI_Box *, boxes_count);
UI_Box **boxes_post = PushStructsNoZero(scratch.arena, UI_Box *, boxes_count); UI_Box **boxes_post = PushStructsNoZero(g->build_arena, UI_Box *, boxes_count);
g->boxes_pre = boxes_pre;
g->boxes_post = boxes_post;
{ {
Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; }; Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; };
BoxNode *first_dfs = 0; BoxNode *first_dfs = 0;
@ -390,13 +557,15 @@ i64 UI_EndBuild(GPU_Resource *render_target)
StackPush(first_dfs, child_n); StackPush(first_dfs, child_n);
} }
} }
boxes_pre[pre_index++] = box; box->pre_index = pre_index++;
boxes_pre[box->pre_index] = box;
n->visited = 1; n->visited = 1;
} }
else else
{ {
StackPop(first_dfs); StackPop(first_dfs);
boxes_post[post_index++] = box; box->post_index = post_index++;
boxes_post[box->post_index] = box;
} }
} }
Assert(pre_index == boxes_count); Assert(pre_index == boxes_count);

View File

@ -44,9 +44,9 @@ Enum(UI_BoxFlag)
//~ Style types //~ Style types
#define UI_StyleKindsXMacro(x) \ #define UI_StyleKindsXMacro(x) \
x(Tag, u64) \
x(Flags, UI_BoxFlag) \ x(Flags, UI_BoxFlag) \
x(Parent, struct UI_Box *) \ x(Parent, struct UI_Box *) \
x(Tag, UI_Tag) \
x(LayoutAxis, Axis) \ x(LayoutAxis, Axis) \
x(Width, UI_Size) \ x(Width, UI_Size) \
x(Height, UI_Size) \ x(Height, UI_Size) \
@ -63,6 +63,12 @@ Enum(UI_BoxFlag)
x(FloatingPos, Vec2) \ x(FloatingPos, Vec2) \
/* ------------------------------------------- */ /* ------------------------------------------- */
Struct(UI_Tag)
{
String name;
u64 hash;
};
Enum(UI_StyleKind) Enum(UI_StyleKind)
{ {
#define X(name, type) UI_StyleKind_##name, #define X(name, type) UI_StyleKind_##name,
@ -93,6 +99,31 @@ Struct(UI_StyleNode)
UI_Style style; UI_Style style;
}; };
////////////////////////////////////////////////////////////
//~ Checkpoint types
Struct(UI_Checkpoint)
{
UI_Checkpoint *next;
u64 v;
};
////////////////////////////////////////////////////////////
//~ Event types
Enum(UI_EventFlag)
{
UI_EventFlag_None = 0,
UI_EventFlag_Active = (1 << 0),
UI_EventFlag_Hovered = (1 << 1),
};
Struct(UI_Event)
{
UI_EventFlag flags;
Vec2 activation_offset;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Box types //~ Box types
@ -112,18 +143,15 @@ Struct(UI_Box)
//- Persistent data //- Persistent data
UI_Key key; UI_Key key;
UI_Event event;
//- Per-build data //- Per-build data
UI_BoxFlag flags; UI_BoxFlag flags;
String display_text;
GPU_Resource *background_texture; GPU_Resource *background_texture;
Vec2 background_texture_uv0; Vec2 background_texture_uv0;
Vec2 background_texture_uv1; Vec2 background_texture_uv1;
Axis layout_axis;
UI_Size pref_size[Axis_CountXY]; UI_Size pref_size[Axis_CountXY];
u32 background_color; u32 background_color;
u32 border_color; u32 border_color;
@ -133,35 +161,32 @@ Struct(UI_Box)
f32 text_padding; f32 text_padding;
f32 rounding; f32 rounding;
Vec2 floating_pos; Vec2 floating_pos;
String display_text;
Axis layout_axis;
ResourceKey font_resource; ResourceKey font_resource;
f32 font_size; f32 font_size;
//- Pre-layout data
u64 pre_index;
u64 post_index;
//- Layout data //- Layout data
F_Run glyph_run; F_Run glyph_run;
F_Font *font; F_Font *font;
f32 solved_dims[Axis_CountXY]; f32 solved_dims[Axis_CountXY];
f32 layout_cursor; f32 layout_cursor;
//- Post-solve data //- Post-layout data
Vec2 p0; Vec2 p0;
Vec2 p1; Vec2 p1;
}; };
Struct(UI_BoxBin) Struct(UI_BoxBin)
{ {
UI_Box *first; UI_Box *first;
UI_Box *last; UI_Box *last;
}; };
////////////////////////////////////////////////////////////
//~ Checkpoint types
Struct(UI_Checkpoint)
{
UI_Checkpoint *next;
u64 v;
};
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ State types //~ State types
@ -169,6 +194,10 @@ Struct(UI_Checkpoint)
Struct(UI_SharedState) Struct(UI_SharedState)
{ {
//- Control state
Vec2 cursor_pos;
Xform ui_to_screen_xf;
//- Build state //- Build state
Arena *build_arena; Arena *build_arena;
Arena *back_build_arena; Arena *back_build_arena;
@ -183,11 +212,16 @@ Struct(UI_SharedState)
u64 back_boxes_count; u64 back_boxes_count;
UI_Checkpoint *top_checkpoint; UI_Checkpoint *top_checkpoint;
UI_Checkpoint *first_free_checkpoint;
UI_StyleNode *style_tops[UI_StyleKind_Count]; UI_StyleNode *style_tops[UI_StyleKind_Count];
UI_Checkpoint *first_free_checkpoint;
UI_StyleNode *first_free_style_node; UI_StyleNode *first_free_style_node;
//- Layout state
UI_Box **boxes_pre;
UI_Box **boxes_post;
UI_Box **back_boxes_pre;
UI_Box **back_boxes_post;
//- Render state //- Render state
i64 gpu_submit_fence_target; i64 gpu_submit_fence_target;
GPU_TransientBuffer draw_rects_tbuff; GPU_TransientBuffer draw_rects_tbuff;
@ -208,9 +242,8 @@ ResourceKey UI_GetDefaultFontResource(void);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key helpers //~ Key helpers
u64 UI_HashFromTop(void); UI_Box *UI_BackBoxFromKey(UI_Key key);
u64 UI_HashFromString(u64 seed, String str); UI_Box *UI_FrontBoxFromKey(UI_Key key);
UI_Key UI_KeyFromString(u64 seed, String str);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Checkpoint helpers //~ Checkpoint helpers
@ -248,17 +281,22 @@ UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 use);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Box //~ Box
UI_Box *UI_BuildBox(UI_Key key); UI_Box *UI_BuildBox(String seed);
void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2 uv1); void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2 uv1);
////////////////////////////////////////////////////////////
//~ Event
UI_Event UI_EventFromKey(UI_Key key);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Begin build //~ Begin build
void UI_BeginBuild(ControllerEventsArray *controller_events); void UI_BeginBuild(ControllerEventsArray controller_events);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ End build //~ End build
GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size); GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size);
i64 UI_EndBuild(GPU_Resource *render_target); i64 UI_EndBuild(GPU_Resource *render_target, Xform ui_to_screen_xf);