diff --git a/src/base/base.h b/src/base/base.h index ff2d547d..6f935bb4 100644 --- a/src/base/base.h +++ b/src/base/base.h @@ -434,8 +434,10 @@ void __asan_unpoison_memory_region(void const volatile *add, size_t); #endif //- struct region -#define StructRegion(name) i8 name -#define CopyStructRegion(dst, src, r0, r1) CopyBytes(&dst->r0, &src->r0, (u8 *)&dst->r1 - (u8 *)&dst->r0) +#define BeginFieldRegion(name) i8 __begfieldreg__##name +#define EndFieldRegion(name) i8 __endfieldreg___##name +#define CopyFieldRegion(dst, src, r) CopyBytes(&dst->(__begfieldreg__##r), &src->(__begfieldreg__##r), (u8 *)&dst->(__endfieldreg__##r) - (u8 *)&dst->(__begfieldreg__##r)) +#define ZeroFieldRegion(dst, src, r) ZeroBytes(&dst->(__begfieldreg__##r), &src->(__begfieldreg__##r), (u8 *)&dst->(__endfieldreg__##r) - (u8 *)&dst->(__begfieldreg__##r)) //- Packed #if CompilerIsMsvc diff --git a/src/proto/pp_game.c b/src/proto/pp_game.c index b9b5c553..34a2a61e 100644 --- a/src/proto/pp_game.c +++ b/src/proto/pp_game.c @@ -113,9 +113,11 @@ JobDef(PP_VisWorker, sig, job_id) { PP_CommandsWidget commands_widget; b32 ui_debug; + b32 show_console; }; VisPersist persist = ZI; String window_restore = ZI; + // persist.ui_debug = 1; ////////////////////////////// //- Swap in @@ -174,6 +176,7 @@ JobDef(PP_VisWorker, sig, job_id) ////////////////////////////// //- Build console + if (persist.show_console) { b32 minimized = 1; PP_BuildConsoleWidget(minimized); @@ -188,6 +191,15 @@ JobDef(PP_VisWorker, sig, job_id) { persist.ui_debug = !persist.ui_debug; } + if (PP_PushCommandsWidgetItem(&persist.commands_widget, Lit("Console")).m1_presses > 0) + { + b32 new = !persist.show_console; + if (new) + { + LogInfoF("Enabled console"); + } + persist.show_console = new; + } if (PP_PushCommandsWidgetItem(&persist.commands_widget, Lit("Fullscreen")).m1_presses > 0) { b32 new = !window_frame.fullscreen; diff --git a/src/proto/pp_widgets.c b/src/proto/pp_widgets.c index c215bb8c..726419e8 100644 --- a/src/proto/pp_widgets.c +++ b/src/proto/pp_widgets.c @@ -32,16 +32,16 @@ void PP_PushWidgetThemeStyles(PP_WidgetTheme theme) void PP_BeginCommandsWidget(PP_CommandsWidget *widget) { ZeroStruct(&widget->build); - widget->build.cp = UI_PushCP(0); + widget->build.cp = UI_PushCP(UI_NilKey); UI_Push(Tag, HashF("commands widget")); } UI_Report PP_PushCommandsWidgetItem(PP_CommandsWidget *widget, String name) { - Arena *build_arena = UI_GetFrameArena(); + Arena *frame_arena = UI_FrameArena(); UI_Key key = UI_KeyF("btn%F", FmtSint(widget->build.num_items)); - PP_CommandsWidgetItem *item = PushStruct(build_arena, PP_CommandsWidgetItem); + PP_CommandsWidgetItem *item = PushStruct(frame_arena, PP_CommandsWidgetItem); item->name = name; item->key = key; QueuePush(widget->build.first_item, widget->build.last_item, item); @@ -53,7 +53,7 @@ UI_Report PP_PushCommandsWidgetItem(PP_CommandsWidget *widget, String name) void PP_EndCommandsWidget(PP_CommandsWidget *widget) { PP_WidgetTheme theme = PP_GetWidgetTheme(); - Vec2 cursor_pos = UI_GetCursorPos(); + Vec2 cursor_pos = UI_CursorPos(); UI_Push(Tag, HashF("commands widget")); @@ -83,10 +83,10 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(FloatingPos, widget->pos); UI_SetNext(Flags, UI_BoxFlag_Floating); - UI_PushCP(UI_BuildBox(UI_KeyF("titlebar"))); + UI_PushCP(UI_BuildBoxEx(UI_KeyF("titlebar"))); { /* Title bar */ - UI_PushCP(0); + UI_PushCP(UI_NilKey); { UI_Push(BackgroundColor, titlebar_color); UI_Push(BorderColor, titlebar_border_color); @@ -95,13 +95,13 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) UI_Push(Width, UI_GROW(1, 0)); UI_Push(Height, UI_FNT(2, 1)); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildBox(titlebar_key)); + UI_PushCP(UI_BuildBoxEx(titlebar_key)); { UI_Push(Width, UI_GROW(1, 0)); UI_Push(BorderColor, 0); /* Left title box */ - UI_BuildRow(UI_NilKey); + UI_BuildRow(); /* Title box */ UI_SetNext(FontSize, theme.window_title_font_size); @@ -109,10 +109,10 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) UI_SetNext(Width, UI_SHRINK(0, 1)); UI_SetNext(Text, Lit("Commands")); UI_SetNext(Flags, UI_BoxFlag_DrawText); - UI_BuildBox(UI_NilKey); + UI_BuildBox(); /* Right title box */ - UI_BuildRow(UI_NilKey); + UI_BuildRow(); } UI_PopCP(UI_TopCP()); } @@ -122,18 +122,18 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) f32 padding = theme.window_border; UI_SetNext(Tint, 0); UI_SetNext(Rounding, 0); - UI_PushCP(UI_BuildRow(UI_NilKey)); + UI_PushCP(UI_BuildRow()); { - UI_BuildSpacer(UI_PIX(padding, 1)); + UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); { UI_SetNext(Tint, 0); UI_SetNext(Rounding, 0); UI_SetNext(Width, UI_GROW(1, 0)); - UI_PushCP(UI_BuildColumn(UI_NilKey)); + UI_PushCP(UI_BuildColumn()); { for (PP_CommandsWidgetItem *item = widget->build.first_item; item; item = item->next) { - UI_BuildDivider(UI_PIX(1, 1), theme.divider_color); + UI_BuildDivider(UI_PIX(1, 1), theme.divider_color, Axis_Y); UI_Key btn_key = item->key; UI_Report btn_rep = UI_ReportFromKey(btn_key); @@ -153,7 +153,7 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) UI_SetNext(Rounding, 0); UI_SetNext(Tint, 0); - UI_PushCP(UI_BuildRow(UI_NilKey)); + UI_PushCP(UI_BuildRow()); { UI_SetNext(BorderColor, border_color); UI_SetNext(BackgroundColor, color); @@ -162,16 +162,16 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) UI_SetNext(Height, UI_FNT(1.5, 1)); UI_SetNext(ChildAlignment, UI_Alignment_Left); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildRow(btn_key)); + UI_PushCP(UI_BuildRowEx(btn_key)); { /* Begin spacer */ - UI_BuildSpacer(UI_PIX(20, 1)); + UI_BuildSpacer(UI_PIX(20, 1), Axis_X); /* Command label */ UI_BuildLabel(item->name); /* Middle spacer */ - UI_BuildSpacer(UI_GROW(1, 0)); + UI_BuildSpacer(UI_GROW(1, 0), Axis_X); /* Command hotkey button */ UI_SetNext(Text, UI_StringF("Test")); @@ -182,14 +182,14 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) UI_SetNext(BackgroundColor, Color_Cyan); UI_SetNext(ChildAlignment, UI_Alignment_Center); UI_SetNext(Flags, UI_BoxFlag_DrawText | UI_BoxFlag_Interactable); - UI_PushCP(UI_BuildRow(UI_NilKey)); + UI_PushCP(UI_BuildRow()); { } UI_PopCP(UI_TopCP()); /* End spacer */ - UI_BuildSpacer(UI_PIX(20, 1)); + UI_BuildSpacer(UI_PIX(20, 1), Axis_X); } UI_PopCP(UI_TopCP()); } @@ -198,18 +198,18 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget) } UI_PopCP(UI_TopCP()); } - UI_BuildSpacer(UI_PIX(padding, 1)); + UI_BuildSpacer(UI_PIX(padding, 1), Axis_X); } UI_PopCP(UI_TopCP()); - UI_BuildSpacer(UI_PIX(padding, 1)); + UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y); UI_PopCP(UI_TopCP()); } //////////////////////////////////////////////////////////// //~ Console widget -UI_Box *PP_BuildConsoleWidget(b32 minimized) +UI_Key PP_BuildConsoleWidget(b32 minimized) { /* TODO: Remove this whole thing */ __prof; @@ -246,7 +246,7 @@ UI_Box *PP_BuildConsoleWidget(b32 minimized) f32 fade_curve = 0.5; i64 now_ns = TimeNs(); - UI_Box *console_box = 0; + UI_Key console_box = ZI; { UI_SetNext(Border, 0); if (minimized) @@ -261,7 +261,7 @@ UI_Box *PP_BuildConsoleWidget(b32 minimized) UI_SetNext(Width, UI_GROW(1, 0)); UI_SetNext(Height, UI_SHRINK(0, 1)); } - console_box = UI_BuildColumn(UI_KeyF("Console box")); + console_box = UI_BuildColumnEx(UI_KeyF("Console box")); UI_PushCP(console_box); { /* Gather display logs */ @@ -312,7 +312,7 @@ UI_Box *PP_BuildConsoleWidget(b32 minimized) FmtUintZ(datetime.milliseconds, 3), FmtString(text)); } - UI_PushCP(0); + UI_PushCP(UI_NilKey); { Vec4 tint = VEC4(1, 1, 1, opacity); UI_Push(Tint, tint); @@ -325,17 +325,17 @@ UI_Box *PP_BuildConsoleWidget(b32 minimized) UI_Push(Rounding, UI_RPIX(0)); UI_Push(Border, 1); UI_Push(ChildAlignment, UI_Alignment_Left); - UI_PushCP(UI_BuildRow(UI_NilKey)); + UI_PushCP(UI_BuildRow()); { // UI_SetNext(Height, UI_PIX(100, 0)); - UI_BuildSpacer(UI_PIX(10, 0)); + UI_BuildSpacer(UI_PIX(10, 0), Axis_X); UI_Push(BackgroundColor, 0); UI_Push(Border, 0); UI_Push(Text, text); UI_Push(Width, UI_GROW(1, 0)); UI_Push(Height, UI_SHRINK(0, 1)); UI_Push(Flags, UI_BoxFlag_DrawText); - UI_BuildBox(UI_NilKey); + UI_BuildBox(); } UI_PopCP(UI_TopCP()); } diff --git a/src/proto/pp_widgets.h b/src/proto/pp_widgets.h index bc6a5e2f..e69c659f 100644 --- a/src/proto/pp_widgets.h +++ b/src/proto/pp_widgets.h @@ -60,4 +60,4 @@ void PP_EndCommandsWidget(PP_CommandsWidget *widget); //////////////////////////////////////////////////////////// //~ Console widget -UI_Box *PP_BuildConsoleWidget(b32 minimized); +UI_Key PP_BuildConsoleWidget(b32 minimized); diff --git a/src/ui/ui_common.c b/src/ui/ui_common.c index 636fccf0..a68d733c 100644 --- a/src/ui/ui_common.c +++ b/src/ui/ui_common.c @@ -1,15 +1,15 @@ //////////////////////////////////////////////////////////// //~ Label helpers -UI_Box *UI_BuildLabel(String text) +UI_Key UI_BuildLabel(String text) { - UI_Box *parent = UI_UseTop(Parent); + UI_Key parent = UI_UseTop(Parent); ResourceKey font = UI_UseTop(Font); f32 font_size = UI_UseTop(FontSize); Vec4 tint = UI_UseTop(Tint); - UI_Box *box = 0; - UI_PushCP(0); + UI_Key key = ZI; + UI_PushCP(UI_NilKey); { UI_PushDefaults(); UI_Push(Parent, parent); @@ -20,13 +20,13 @@ UI_Box *UI_BuildLabel(String text) UI_SetNext(Height, UI_SHRINK(0, 1)); UI_SetNext(Text, text); UI_SetNext(Flags, UI_BoxFlag_DrawText); - box = UI_BuildBox(UI_NilKey); + key = UI_BuildBox(); } UI_PopCP(UI_TopCP()); - return box; + return key; } -UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...) +UI_Key UI_BuildLabelF_(char *fmt_cstr, ...) { TempArena scratch = BeginScratchNoConflict(); String str = ZI; @@ -36,39 +36,37 @@ UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...) str = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), va); va_end(va); } - UI_Box *box = UI_BuildLabel(str); + UI_Key key = UI_BuildLabel(str); EndScratch(scratch); - return box; + return key; } //////////////////////////////////////////////////////////// //~ Spacing helpers -UI_Box *UI_BuildSpacer(UI_Size size) +UI_Key UI_BuildSpacer(UI_Size size, Axis axis) { - UI_Box *box = 0; - UI_Box *parent = UI_UseTop(Parent); - Axis axis = parent->child_layout_axis; - UI_PushCP(0); + UI_Key parent = UI_UseTop(Parent); + UI_Key key = ZI; + UI_PushCP(UI_NilKey); { UI_PushDefaults(); UI_Push(Parent, parent); UI_Push(Tint, 0); UI_Push(AxisSize, UI_GROW(1, 0), .axis = !axis); UI_Push(AxisSize, size, .axis = axis); - box = UI_BuildBox(UI_NilKey); + key = UI_BuildBox(); } UI_PopCP(UI_TopCP()); - return box; + return key; } -UI_Box *UI_BuildDivider(UI_Size size, Vec4 color) +UI_Key UI_BuildDivider(UI_Size size, Vec4 color, Axis axis) { - UI_Box *box = 0; - UI_Box *parent = UI_UseTop(Parent); + UI_Key key = ZI; + UI_Key parent = UI_UseTop(Parent); Vec4 tint = UI_UseTop(Tint); - Axis axis = parent->child_layout_axis; - UI_PushCP(0); + UI_PushCP(UI_NilKey); { UI_PushDefaults(); UI_Push(Parent, parent); @@ -76,25 +74,23 @@ UI_Box *UI_BuildDivider(UI_Size size, Vec4 color) UI_Push(BackgroundColor, color); UI_Push(AxisSize, UI_GROW(1, 0), .axis = !axis); UI_Push(AxisSize, size, .axis = axis); - box = UI_BuildBox(UI_NilKey); + key = UI_BuildBox(); } UI_PopCP(UI_TopCP()); - return box; + return key; } //////////////////////////////////////////////////////////// //~ Layout helpers -UI_Box *UI_BuildColumn(UI_Key key) +UI_Key UI_BuildColumnEx(UI_Key key) { UI_SetNext(ChildLayoutAxis, Axis_Y); - UI_Box *box = UI_BuildBox(key); - return box; + return UI_BuildBoxEx(key); } -UI_Box *UI_BuildRow(UI_Key key) +UI_Key UI_BuildRowEx(UI_Key key) { UI_SetNext(ChildLayoutAxis, Axis_X); - UI_Box *box = UI_BuildBox(key); - return box; + return UI_BuildBoxEx(key); } diff --git a/src/ui/ui_common.h b/src/ui/ui_common.h index 75ee7ccc..e390ad5b 100644 --- a/src/ui/ui_common.h +++ b/src/ui/ui_common.h @@ -1,18 +1,21 @@ //////////////////////////////////////////////////////////// //~ Label helpers -UI_Box *UI_BuildLabel(String text); +UI_Key UI_BuildLabel(String text); #define UI_BuildLabelF(fmt_cstr, ...) UI_BuildLabelF_(fmt_cstr, __VA_ARGS__, FmtEnd) -UI_Box *UI_BuildLabelF_(char *fmt_cstr, ...); +UI_Key UI_BuildLabelF_(char *fmt_cstr, ...); //////////////////////////////////////////////////////////// //~ Spacing helpers -UI_Box *UI_BuildSpacer(UI_Size size); -UI_Box *UI_BuildDivider(UI_Size size, Vec4 color); +UI_Key UI_BuildSpacer(UI_Size size, Axis axis); +UI_Key UI_BuildDivider(UI_Size size, Vec4 color, Axis axis); //////////////////////////////////////////////////////////// //~ Layout helpers -UI_Box *UI_BuildColumn(UI_Key key); -UI_Box *UI_BuildRow(UI_Key key); +UI_Key UI_BuildColumnEx(UI_Key key); +UI_Key UI_BuildRowEx(UI_Key key); + +#define UI_BuildColumn() UI_BuildColumnEx(UI_TransKey()) +#define UI_BuildRow() UI_BuildRowEx(UI_TransKey()) diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index e9f41017..60802335 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -1,4 +1,4 @@ -UI_SharedState UI_shared_state = ZI; +UI_State UI_state = ZI; //////////////////////////////////////////////////////////// //~ Startup @@ -44,28 +44,18 @@ UI_Key UI_KeyF_(String fmt, ...) return key; } -UI_Box *UI_BackBoxFromKey(UI_Key key) +UI_Key UI_TransKey(void) { - UI_SharedState *g = &UI_shared_state; - UI_Box *back_box = 0; - if (key.hash != 0) - { - 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 back_box; + UI_State *g = &UI_state; + u64 seed = ++g->bframe.transient_key_seed; + UI_Key key = ZI; + key.hash = RandU64FromSeed(seed); + return key; } -UI_Box *UI_FrontBoxFromKey(UI_Key key) +UI_Box *UI_BoxFromKey(UI_Key key) { - UI_SharedState *g = &UI_shared_state; + UI_State *g = &UI_state; UI_Box *front_box = 0; if (key.hash != 0) { @@ -87,10 +77,10 @@ UI_Box *UI_FrontBoxFromKey(UI_Key key) String UI_StringF_(String fmt, ...) { - UI_SharedState *g = &UI_shared_state; + UI_State *g = &UI_state; va_list args; va_start(args, fmt); - String str = FormatStringV(g->build_arena, fmt, args); + String str = FormatStringV(g->bframe.cmds_arena, fmt, args); va_end(args); return str; } @@ -98,12 +88,12 @@ String UI_StringF_(String fmt, ...) //////////////////////////////////////////////////////////// //~ Checkpoint helpers -UI_Checkpoint UI_PushCP(UI_Box *parent) +UI_Checkpoint UI_PushCP(UI_Key parent) { - UI_SharedState *g = &UI_shared_state; - UI_Stack *stack = g->top_stack; + UI_State *g = &UI_state; + UI_Stack *stack = g->bframe.top_stack; stack->top_checkpoint.v += 1; - if (parent != 0) + if (parent.hash != 0) { UI_Push(Parent, parent); } @@ -112,16 +102,16 @@ UI_Checkpoint UI_PushCP(UI_Box *parent) void UI_PopCP(UI_Checkpoint cp) { - UI_SharedState *g = &UI_shared_state; - UI_Stack *stack = g->top_stack; + UI_State *g = &UI_state; + UI_Stack *stack = g->bframe.top_stack; for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) { UI_StyleNode *n = stack->style_tops[kind]; while (n && n->checkpoint.v >= cp.v) { UI_StyleNode *next = n->next; - n->next = g->first_free_style_node; - g->first_free_style_node = n; + n->next = g->bframe.first_free_style_node; + g->bframe.first_free_style_node = n; stack->style_tops[kind] = next; n = next; } @@ -131,8 +121,8 @@ void UI_PopCP(UI_Checkpoint cp) UI_Checkpoint UI_TopCP(void) { - UI_SharedState *g = &UI_shared_state; - UI_Stack *stack = g->top_stack; + UI_State *g = &UI_state; + UI_Stack *stack = g->bframe.top_stack; return stack->top_checkpoint; } @@ -141,8 +131,8 @@ UI_Checkpoint UI_TopCP(void) void UI_PushDefaults(void) { - UI_SharedState *g = &UI_shared_state; - UI_Stack *stack = g->top_stack; + UI_State *g = &UI_state; + UI_Stack *stack = g->bframe.top_stack; UI_Checkpoint checkpoint = stack->top_checkpoint; { for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind) @@ -152,14 +142,15 @@ void UI_PushDefaults(void) switch (kind) { default: break; - case UI_StyleKind_Parent: { desc.style.Parent = g->root_box; } break; - case UI_StyleKind_Width: { desc.style.Width = UI_GROW(1, 0); } break; - case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); } break; - case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFontResource(); } break; - case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break; - case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break; - case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break; - case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break; + case UI_StyleKind_Parent: { desc.style.Parent = UI_RootKey; } break; + case UI_StyleKind_Width: { desc.style.Width = UI_GROW(1, 0); } break; + case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); } break; + case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFontResource(); } break; + case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break; + case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break; + case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break; + case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break; + case UI_StyleKind_BackgroundTextureUv1: { desc.style.BackgroundTextureUv1 = VEC2(1, 1); } break; }; UI_PushStyle(desc); } @@ -168,8 +159,8 @@ void UI_PushDefaults(void) void UI_PushStyle(UI_StyleDesc desc) { - UI_SharedState *g = &UI_shared_state; - UI_Stack *stack = g->top_stack; + UI_State *g = &UI_state; + UI_Stack *stack = g->bframe.top_stack; UI_StyleKind kind = desc.style.kind; if (kind >= UI_StyleKind_BeginVirtualStyles_) { @@ -255,15 +246,15 @@ void UI_PushStyle(UI_StyleDesc desc) } else { - n = g->first_free_style_node; + n = g->bframe.first_free_style_node; if (n) { - g->first_free_style_node = n->next; + g->bframe.first_free_style_node = n->next; ZeroStruct(n); } else { - n = PushStruct(g->build_arena, UI_StyleNode); + n = PushStruct(g->bframe.cmds_arena, UI_StyleNode); } n->next = stack->style_tops[kind]; stack->style_tops[kind] = n; @@ -281,7 +272,7 @@ void UI_PushStyle(UI_StyleDesc desc) case UI_StyleKind_Text: { - n->style.Text = PushString(g->build_arena, desc.style.Text); + n->style.Text = PushString(g->bframe.cmds_arena, desc.style.Text); } break; case UI_StyleKind_Tag: @@ -298,8 +289,8 @@ void UI_PushStyle(UI_StyleDesc desc) UI_Style UI_PopStyle(UI_StyleDesc desc) { - UI_SharedState *g = &UI_shared_state; - UI_Stack *stack = g->top_stack; + UI_State *g = &UI_state; + UI_Stack *stack = g->bframe.top_stack; UI_Style result = ZI; UI_StyleKind kind = desc.style.kind; result.kind = kind; @@ -331,118 +322,43 @@ UI_Style UI_PopStyle(UI_StyleDesc desc) if (desc.use && n->pop_when_used) { stack->style_tops[kind] = n->next; - n->next = g->first_free_style_node; - g->first_free_style_node = n; + n->next = g->bframe.first_free_style_node; + g->bframe.first_free_style_node = n; } } return result; } //////////////////////////////////////////////////////////// -//~ Box +//~ Command helpers -UI_Box *UI_BuildBox(UI_Key key) +UI_Key UI_BuildBoxEx(UI_Key key) { - UI_SharedState *g = &UI_shared_state; - - UI_Box *parent = UI_UseTop(Parent); - - UI_Box *box = PushStruct(g->build_arena, UI_Box); - box->key = key; - - /* Insert into lookup */ - if (box->key.hash != 0) + UI_State *g = &UI_state; + UI_CmdNode *n = PushStruct(g->bframe.cmds_arena, UI_CmdNode); { - UI_BoxBin *bin = &g->box_bins[box->key.hash % UI_NumBoxLookupBins]; -#if RtcIsEnabled - /* Validate box not already built */ - for (UI_Box *tmp = bin->first; tmp; tmp = tmp->next_in_bin) - { - if (tmp->key.hash == box->key.hash) - { - Assert(0); /* Box with matching key already built */ - break; - } - } -#endif - DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); + n->cmd.key = key; + n->cmd.parent = UI_UseTop(Parent); + n->cmd.flags = UI_UseTop(Flags); + n->cmd.pref_size[Axis_X] = UI_UseTop(Width); + n->cmd.pref_size[Axis_Y] = UI_UseTop(Height); + n->cmd.child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX); + n->cmd.child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY); + n->cmd.child_layout_axis = UI_UseTop(ChildLayoutAxis); + n->cmd.background_color = UI_UseTop(BackgroundColor); + n->cmd.border_color = UI_UseTop(BorderColor); + n->cmd.debug_color = UI_UseTop(DebugColor); + n->cmd.tint = UI_UseTop(Tint); + n->cmd.border = UI_UseTop(Border); + n->cmd.font_resource = UI_UseTop(Font); + n->cmd.font_size = UI_UseTop(FontSize); + n->cmd.rounding = UI_UseTop(Rounding); + n->cmd.text = UI_UseTop(Text); + n->cmd.floating_pos = UI_UseTop(FloatingPos); } - ++g->boxes_count; - - /* Insert into parent */ - DllPushBack(parent->first, parent->last, box); - box->parent = parent; - ++parent->count; - - /* Persist state from back box */ - UI_Box *back_box = UI_BackBoxFromKey(key); - if (back_box) - { - box->report = back_box->report; - } - - /* Pull from style stack */ - box->flags = UI_UseTop(Flags); - box->pref_size[Axis_X] = UI_UseTop(Width); - box->pref_size[Axis_Y] = UI_UseTop(Height); - box->child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX); - box->child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY); - box->child_layout_axis = UI_UseTop(ChildLayoutAxis); - box->background_color = UI_UseTop(BackgroundColor); - box->border_color = UI_UseTop(BorderColor); - box->debug_color = UI_UseTop(DebugColor); - box->tint = UI_UseTop(Tint); - box->border = UI_UseTop(Border); - box->font_resource = UI_UseTop(Font); - box->font_size = UI_UseTop(FontSize); - box->rounding = UI_UseTop(Rounding); - box->text = UI_UseTop(Text); - box->floating_pos = UI_UseTop(FloatingPos); - - /* Prefetch font */ - if (box->text.len > 0) - { - box->font = F_LoadFontAsync(box->font_resource, box->font_size); - if (box->font) - { - box->glyph_run = F_RunFromString(g->build_arena, box->font, box->text); - } - } - - return box; -} - -void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2 uv1) -{ - box->background_texture = texture; - box->background_texture_uv0 = uv0; - box->background_texture_uv1 = uv1; -} - -b32 UI_IsPointInBox(UI_Box *box, Vec2 point) -{ - /* TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. */ - Vec2 p0 = box->p0; - Vec2 p1 = box->p1; - b32 is_corner = 0; - f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y)); - f32 corner_edge_dist = non_corner_edge_dist; - if (non_corner_edge_dist >= 0) - { - f32 tl_radius = box->rounding_tl; - f32 tr_radius = box->rounding_tr; - f32 br_radius = box->rounding_br; - f32 bl_radius = box->rounding_bl; - Vec2 tl = VEC2(p0.x + tl_radius, p0.y + tl_radius); - Vec2 tr = VEC2(p1.x - tr_radius, p0.y + tr_radius); - Vec2 br = VEC2(p1.x - br_radius, p1.y - br_radius); - Vec2 bl = VEC2(p0.x + bl_radius, p1.y - bl_radius); - if (point.x < tl.x && point.y < tl.y) corner_edge_dist = MinF32(corner_edge_dist, tl_radius - Vec2Len(SubVec2(tl, point))); - if (point.x > tr.x && point.y < tr.y) corner_edge_dist = MinF32(corner_edge_dist, tr_radius - Vec2Len(SubVec2(tr, point))); - if (point.x > br.x && point.y > br.y) corner_edge_dist = MinF32(corner_edge_dist, br_radius - Vec2Len(SubVec2(br, point))); - if (point.x < bl.x && point.y > bl.y) corner_edge_dist = MinF32(corner_edge_dist, bl_radius - Vec2Len(SubVec2(bl, point))); - } - return non_corner_edge_dist >= 0 && corner_edge_dist >= 0; + ++g->bframe.cmds_count; + QueuePush(g->bframe.first_cmd_node, g->bframe.last_cmd_node, n); + return key; } //////////////////////////////////////////////////////////// @@ -450,10 +366,10 @@ b32 UI_IsPointInBox(UI_Box *box, Vec2 point) UI_Report UI_ReportFromKey(UI_Key key) { - UI_SharedState *g = &UI_shared_state; + UI_State *g = &UI_state; UI_Report result = ZI; - UI_Box *box = UI_BackBoxFromKey(key); + UI_Box *box = UI_BoxFromKey(key); if (box) { result = box->report; @@ -467,40 +383,77 @@ UI_Report UI_ReportFromKey(UI_Key key) UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) { - UI_SharedState *g = &UI_shared_state; - UI_Frame frame = ZI; + UI_State *g = &UI_state; + UI_Frame result = ZI; + UI_BFrameState old_bframe = g->bframe; ////////////////////////////// //- Wait on swapchain - if (g->swapchain) + if (g->eframe.swapchain) { - GPU_YieldOnSwapchain(g->swapchain); + GPU_YieldOnSwapchain(g->eframe.swapchain); } + ////////////////////////////// + //- Init persistent state + + if (!g->box_arena) + { + g->box_arena = AcquireArena(Gibi(64)); + g->box_bins = PushStructs(g->box_arena, UI_BoxBin, UI_NumBoxLookupBins); + } + + ////////////////////////////// + //- Reset state + + /* Zero frame data */ + { + ZeroStruct(&g->bframe); + g->bframe.cmds_arena = old_bframe.cmds_arena; + g->bframe.transient_key_seed; + } + if (!g->bframe.cmds_arena) + { + g->bframe.cmds_arena = AcquireArena(Gibi(64)); + } + + { + i64 now_ns = TimeNs(); + i64 dt_ns = now_ns - old_bframe.time_ns; + g->bframe.time_ns = now_ns; + g->bframe.dt_ns = dt_ns; + g->bframe.tick = old_bframe.tick + 1; + } + ResetArena(g->bframe.cmds_arena); + + /* Init style stack */ + { + g->bframe.top_stack = PushStruct(g->bframe.cmds_arena, UI_Stack); + UI_PushDefaults(); + } + + g->bframe.frame_flags = frame_flags; + ////////////////////////////// //- Begin window frame - frame.window_frame = WND_BeginFrame(); + g->bframe.window_frame = WND_BeginFrame(); ////////////////////////////// //- Process controller events - i64 now_ns = TimeNs(); - i64 dt_ns = now_ns - g->last_frame_begin_ns; - f64 dt = SecondsFromNs(dt_ns); - f64 inv_dt = 1.0 / dt; - g->last_frame_begin_ns = now_ns; - - ControllerEventsArray controller_events = frame.window_frame.controller_events; - - if (g->build_arena != 0 && g->back_build_arena != 0) + if (g->eframe.boxes_pre != 0) { + ControllerEventsArray controller_events = g->bframe.window_frame.controller_events; + + g->bframe.cursor_pos = old_bframe.cursor_pos; + f64 dt = SecondsFromNs(g->bframe.dt_ns); + f64 inv_dt = 1.0 / dt; + /* Locate boxes */ - UI_Box *old_hovered_box = UI_FrontBoxFromKey(g->hovered_box); - UI_Box *old_active_box = UI_FrontBoxFromKey(g->active_box); UI_Box *hovered_box = 0; - UI_Box *active_box = old_active_box; + UI_Box *active_box = UI_BoxFromKey(old_bframe.active_box); /* Update cursor pos */ for (u64 cev_index = 0; cev_index < controller_events.count; ++cev_index) @@ -508,17 +461,44 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) ControllerEvent cev = controller_events.events[cev_index]; if (cev.kind == ControllerEventKind_CursorMove) { - g->cursor_pos = Vec2FromFields(cev.cursor_pos); + g->bframe.cursor_pos = Vec2FromFields(cev.cursor_pos); } } /* Init box reports */ for (u64 pre_index = g->boxes_count; pre_index-- > 0;) { - UI_Box *box = g->boxes_pre[pre_index]; - if (hovered_box == 0 && box->flags & UI_BoxFlag_Interactable) + UI_Box *box = g->eframe.boxes_pre[pre_index]; + if (hovered_box == 0 && box->cmd.flags & UI_BoxFlag_Interactable) { - if (UI_IsPointInBox(box, g->cursor_pos)) + b32 is_cursor_in_box = 0; + { + /* TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. */ + Vec2 p0 = box->p0; + Vec2 p1 = box->p1; + Vec2 point = g->bframe.cursor_pos; + b32 is_corner = 0; + f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y)); + f32 corner_edge_dist = non_corner_edge_dist; + if (non_corner_edge_dist >= 0) + { + f32 tl_radius = box->rounding_tl; + f32 tr_radius = box->rounding_tr; + f32 br_radius = box->rounding_br; + f32 bl_radius = box->rounding_bl; + Vec2 tl = VEC2(p0.x + tl_radius, p0.y + tl_radius); + Vec2 tr = VEC2(p1.x - tr_radius, p0.y + tr_radius); + Vec2 br = VEC2(p1.x - br_radius, p1.y - br_radius); + Vec2 bl = VEC2(p0.x + bl_radius, p1.y - bl_radius); + if (point.x < tl.x && point.y < tl.y) corner_edge_dist = MinF32(corner_edge_dist, tl_radius - Vec2Len(SubVec2(tl, point))); + if (point.x > tr.x && point.y < tr.y) corner_edge_dist = MinF32(corner_edge_dist, tr_radius - Vec2Len(SubVec2(tr, point))); + if (point.x > br.x && point.y > br.y) corner_edge_dist = MinF32(corner_edge_dist, br_radius - Vec2Len(SubVec2(br, point))); + if (point.x < bl.x && point.y > bl.y) corner_edge_dist = MinF32(corner_edge_dist, bl_radius - Vec2Len(SubVec2(bl, point))); + } + is_cursor_in_box = non_corner_edge_dist >= 0 && corner_edge_dist >= 0; + } + + if (is_cursor_in_box) { hovered_box = box; } @@ -544,7 +524,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) { ++hovered_box->report.m1_downs; hovered_box->report.m1_held = 1; - hovered_box->report.last_m1_offset = SubVec2(g->cursor_pos, hovered_box->p0); + hovered_box->report.last_m1_offset = SubVec2(g->bframe.cursor_pos, hovered_box->p0); active_box = hovered_box; } } @@ -577,7 +557,7 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) /* Update box hot & active states */ for (u64 pre_index = 0; pre_index < g->boxes_count; ++pre_index) { - UI_Box *box = g->boxes_pre[pre_index]; + UI_Box *box = g->eframe.boxes_pre[pre_index]; UI_Report *report = &box->report; f32 target_hot = box == active_box || (box == hovered_box && (box == active_box || active_box == 0)); f32 target_active = box == active_box; @@ -590,81 +570,38 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags) report->hovered = LerpF32(report->hovered, target_hovered, hovered_blend_rate); } - g->hovered_box = hovered_box ? hovered_box->key : UI_NilKey; - g->active_box = active_box ? active_box->key : UI_NilKey; + g->bframe.hovered_box = hovered_box ? hovered_box->key : UI_NilKey; + g->bframe.active_box = active_box ? active_box->key : UI_NilKey; } ////////////////////////////// - //- Swap front & back + //- Build root box { - { - Arena *swp = g->build_arena; - g->build_arena = g->back_build_arena; - g->back_build_arena = swp; - } - g->back_box_bins = g->box_bins; - g->back_root_box = g->root_box; - g->back_boxes_count = g->boxes_count; - g->back_boxes_pre = g->boxes_pre; - g->back_boxes_post = g->boxes_post; - g->back_frame_flags = g->frame_flags; + UI_SetNext(Width, UI_PIX(g->bframe.window_frame.draw_size.x, 1)); + UI_SetNext(Height, UI_PIX(g->bframe.window_frame.draw_size.y, 1)); + UI_SetNext(Parent, UI_NilKey); + UI_BuildBoxEx(UI_RootKey); } - ////////////////////////////// - //- Reset build state - - { - if (!g->build_arena) - { - g->build_arena = AcquireArena(Gibi(64)); - } - ResetArena(g->build_arena); - g->boxes_count = 0; - g->first_free_style_node = 0; - - g->frame_flags = frame_flags; - - /* Init bins */ - g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins); - - /* Init root box */ - g->root_box = PushStruct(g->build_arena, UI_Box); - g->root_box->key = UI_RootKey; - UI_BoxBin *bin = &g->box_bins[g->root_box->key.hash % UI_NumBoxLookupBins]; - DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin); - ++g->boxes_count; - - if (!g->back_build_arena) - { - /* Back buffer not initialized, swap again */ - UI_BeginFrame(frame_flags); - } - } - - ////////////////////////////// - //- Init style stack - - g->top_stack = PushStruct(g->build_arena, UI_Stack); - UI_PushDefaults(); - - frame.cursor_pos = g->cursor_pos; - return frame; + result.window_frame = g->bframe.window_frame; + result.cursor_pos = g->bframe.cursor_pos; + return result; } //////////////////////////////////////////////////////////// //~ Frame helpers -Arena *UI_GetFrameArena(void) +Arena *UI_FrameArena(void) { - UI_SharedState *g = &UI_shared_state; - return g->build_arena; + UI_State *g = &UI_state; + return g->bframe.cmds_arena; } -Vec2 UI_GetCursorPos(void) +Vec2 UI_CursorPos(void) { - UI_SharedState *g = &UI_shared_state; - return g->cursor_pos; + UI_State *g = &UI_state; + return g->bframe.cursor_pos; } //////////////////////////////////////////////////////////// @@ -673,7 +610,34 @@ Vec2 UI_GetCursorPos(void) i64 UI_EndFrame(UI_Frame frame) { TempArena scratch = BeginScratchNoConflict(); - UI_SharedState *g = &UI_shared_state; + UI_State *g = &UI_state; + UI_EFrameState old_eframe = g->eframe; + + ////////////////////////////// + //- Reset state + + { + ZeroStruct(&g->eframe); + g->eframe.layout_arena = old_eframe.layout_arena; + g->eframe.rects_arena = old_eframe.rects_arena; + g->eframe.render_target = old_eframe.render_target; + g->eframe.swapchain = old_eframe.swapchain; + g->eframe.gpu_submit_fence_target = old_eframe.gpu_submit_fence_target; + g->eframe.draw_rects_tbuff = old_eframe.draw_rects_tbuff; + g->eframe.tick = old_eframe.tick; + } + if (!g->eframe.layout_arena) + { + g->eframe.layout_arena = AcquireArena(Gibi(64)); + g->eframe.rects_arena = AcquireArena(Gibi(64)); + g->eframe.draw_rects_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(UI_RectInstance)); + } + ResetArena(g->eframe.layout_arena); + ResetArena(g->eframe.rects_arena); + + ////////////////////////////// + //- Init render state + Vec2I32 draw_size = frame.window_frame.draw_size; Vec2I32 monitor_size = frame.window_frame.monitor_size; @@ -681,14 +645,14 @@ i64 UI_EndFrame(UI_Frame frame) Fence *submit_fence = GPU_FenceFromQueue(gpu_render_queue); /* Acquire render target */ - if (g->render_target && !MatchVec2I32(monitor_size, GPU_GetTextureSize2D(g->render_target))) + if (g->eframe.render_target && !MatchVec2I32(monitor_size, GPU_GetTextureSize2D(g->eframe.render_target))) { __profn("Release ui render target"); - YieldOnFence(submit_fence, g->gpu_submit_fence_target); - GPU_ReleaseResource(g->render_target, GPU_ReleaseFlag_None); - g->render_target = 0; + YieldOnFence(submit_fence, g->eframe.gpu_submit_fence_target); + GPU_ReleaseResource(g->eframe.render_target, GPU_ReleaseFlag_None); + g->eframe.render_target = 0; } - if (!g->render_target) + if (!g->eframe.render_target) { __profn("Acquire ui render target"); GPU_ResourceDesc desc = ZI; @@ -697,7 +661,7 @@ i64 UI_EndFrame(UI_Frame frame) // desc.texture.format = GPU_Format_R8G8B8A8_Unorm; desc.texture.format = GPU_Format_R16G16B16A16_Float; desc.texture.size = VEC3I32(monitor_size.x, monitor_size.y, 1); - g->render_target = GPU_AcquireResource(desc); + g->eframe.render_target = GPU_AcquireResource(desc); } Rect render_viewport = ZI; @@ -705,20 +669,129 @@ i64 UI_EndFrame(UI_Frame frame) render_viewport.size = VEC2(draw_size.x, draw_size.y); ////////////////////////////// - //- Layout + //- Process commands - /* Init root size */ - g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Pixel; - g->root_box->pref_size[Axis_X].v = render_viewport.size.x; - g->root_box->pref_size[Axis_Y].kind = UI_SizeKind_Pixel; - g->root_box->pref_size[Axis_Y].v = render_viewport.size.y; + g->boxes_count = 0; + + for (UI_CmdNode *cmd_node = g->bframe.first_cmd_node; cmd_node; cmd_node = cmd_node->next) + { + UI_Cmd cmd = cmd_node->cmd; + UI_Key key = cmd.key; + + b32 is_root = g->eframe.root_box == 0; + UI_Box *parent = 0; + if (!is_root) + { + parent = UI_BoxFromKey(cmd.parent); + if (!parent) + { + parent = g->eframe.root_box; + } + } + + /* Allocate box */ + UI_Box *box = 0; + { + UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins]; + if (key.hash != 0) + { + for (UI_Box *tmp = bin->first; tmp && !box; tmp = tmp->next_in_bin) + { + if (tmp->key.hash == key.hash) + { + box = tmp; + } + } + } + if (box) + { + /* Remove box from old parent */ + if (box->parent) + { + DllRemove(box->parent->first, box->parent->last, box); + --box->parent->count; + } + } + else + { + box = g->first_free_box; + if (box) + { + StackPop(g->first_free_box); + ZeroStruct(box); + } + else + { + box = PushStruct(g->box_arena, UI_Box); + } + DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); + } + } + ++g->boxes_count; + + /* Reset box */ + UI_Box old_box = *box; + { + ZeroStruct(box); + box->next_in_bin = old_box.next_in_bin; + box->prev_in_bin = old_box.prev_in_bin; + box->report = old_box.report; + } + box->key = key; + box->last_updated_tick = g->eframe.tick; + + /* Update box */ + { + box->cmd = cmd; + + /* Insert box into parent */ + if (parent) + { + DllPushBack(parent->first, parent->last, box); + box->parent = parent; + ++parent->count; + } + + /* Prefetch font */ + if (box->cmd.text.len > 0) + { + box->font = F_LoadFontAsync(box->cmd.font_resource, box->cmd.font_size); + if (box->font) + { + box->glyph_run = F_RunFromString(g->eframe.layout_arena, box->font, box->cmd.text); + } + } + } + + if (is_root) + { + g->eframe.root_box = box; + } + } + + ////////////////////////////// + //- Prune boxes + + // { + // u64 cur_tick = g->eframe.tick; + // UI_BoxIter it = UI_ITER(g->root_box); + // UI_Box *box = UI_NextBox(&it); + // while (box != 0) + // { + // UI_Box *next = UI_NextBox(&it); + // box = next; + // } + // } + + ////////////////////////////// + //- Layout /* Build pre-order & post-order box arrays */ u64 boxes_count = g->boxes_count; - UI_Box **boxes_pre = PushStructsNoZero(g->build_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; + UI_Box **boxes_pre = PushStructsNoZero(g->eframe.layout_arena, UI_Box *, boxes_count); + UI_Box **boxes_post = PushStructsNoZero(g->eframe.layout_arena, UI_Box *, boxes_count); + g->eframe.boxes_pre = boxes_pre; + g->eframe.boxes_post = boxes_post; { Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; }; BoxNode *first_dfs = 0; @@ -726,7 +799,7 @@ i64 UI_EndFrame(UI_Frame frame) u64 post_index = 0; { BoxNode *n = PushStruct(scratch.arena, BoxNode); - n->box = g->root_box; + n->box = g->eframe.root_box; StackPush(first_dfs, n); } while (first_dfs) @@ -738,7 +811,7 @@ i64 UI_EndFrame(UI_Frame frame) /* Push floating children to dfs stack */ for (UI_Box *child = box->last; child; child = child->prev) { - if (AnyBit(child->flags, UI_BoxFlag_Floating)) + if (AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) { BoxNode *child_n = PushStruct(scratch.arena, BoxNode); child_n->box = child; @@ -748,7 +821,7 @@ i64 UI_EndFrame(UI_Frame frame) /* Push non-floating children to dfs stack */ for (UI_Box *child = box->last; child; child = child->prev) { - if (!AnyBit(child->flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) { BoxNode *child_n = PushStruct(scratch.arena, BoxNode); child_n->box = child; @@ -776,12 +849,12 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_pre[pre_index]; for (Axis axis = 0; axis < Axis_CountXY; ++axis) { - UI_Size pref_size = box->pref_size[axis]; + UI_Size pref_size = box->cmd.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Pixel) { box->solved_dims[axis] = pref_size.v; } - else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->flags, UI_BoxFlag_DrawText)) + else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->cmd.flags, UI_BoxFlag_DrawText)) { /* TODO: Distinguish between baseline alignment & visual alignment */ f32 text_size = 0; @@ -812,16 +885,16 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_pre[pre_index]; if (box->parent) { - Axis axis = box->parent->child_layout_axis; - UI_Size pref_size = box->pref_size[axis]; + Axis axis = box->parent->cmd.child_layout_axis; + UI_Size pref_size = box->cmd.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Grow) { f32 match_size = 0; b32 found_match = 0; for (UI_Box *ancestor = box->parent; ancestor != 0 && !found_match; ancestor = ancestor->parent) { - UI_Size ancestor_size = ancestor->pref_size[axis]; - if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->flags, UI_BoxFlag_DrawText))) + UI_Size ancestor_size = ancestor->cmd.pref_size[axis]; + if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->cmd.flags, UI_BoxFlag_DrawText))) { /* Match independent ancestor */ match_size = ancestor->solved_dims[axis]; @@ -839,15 +912,15 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_post[post_index]; for (Axis axis = 0; axis < Axis_CountXY; ++axis) { - UI_Size pref_size = box->pref_size[axis]; - if (pref_size.kind == UI_SizeKind_Shrink && !AnyBit(box->flags, UI_BoxFlag_DrawText)) + UI_Size pref_size = box->cmd.pref_size[axis]; + if (pref_size.kind == UI_SizeKind_Shrink && !AnyBit(box->cmd.flags, UI_BoxFlag_DrawText)) { f32 accum = 0; for (UI_Box *child = box->first; child; child = child->next) { - if (!AnyBit(child->flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) { - if (axis == box->child_layout_axis) + if (axis == box->cmd.child_layout_axis) { accum += child->solved_dims[axis]; } @@ -868,8 +941,8 @@ i64 UI_EndFrame(UI_Frame frame) UI_Box *box = boxes_pre[pre_index]; if (box->parent) { - Axis axis = !box->parent->child_layout_axis; - UI_Size pref_size = box->pref_size[axis]; + Axis axis = !box->parent->cmd.child_layout_axis; + UI_Size pref_size = box->cmd.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Grow) { box->solved_dims[axis] = box->parent->solved_dims[axis] * pref_size.v; @@ -890,12 +963,12 @@ i64 UI_EndFrame(UI_Frame frame) f32 flex_accum = 0; for (UI_Box *child = box->first; child; child = child->next) { - if (!AnyBit(child->flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) { f32 size = child->solved_dims[axis]; - f32 strictness = child->pref_size[axis].strictness; + f32 strictness = child->cmd.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); - if (axis == box->child_layout_axis) + if (axis == box->cmd.child_layout_axis) { size_accum += size; flex_accum += flex; @@ -913,13 +986,13 @@ i64 UI_EndFrame(UI_Frame frame) f32 adjusted_size_accum = 0; for (UI_Box *child = box->first; child; child = child->next) { - if (!AnyBit(child->flags, UI_BoxFlag_Floating)) + if (!AnyBit(child->cmd.flags, UI_BoxFlag_Floating)) { f32 size = child->solved_dims[axis]; - f32 strictness = child->pref_size[axis].strictness; + f32 strictness = child->cmd.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); f32 new_size = size; - if (axis == box->child_layout_axis) + if (axis == box->cmd.child_layout_axis) { f32 chopoff = MinF32(flex, violation * (flex / flex_accum)); new_size = size - chopoff; @@ -942,12 +1015,12 @@ i64 UI_EndFrame(UI_Frame frame) /* Solve floating violations */ for (UI_Box *child = box->first; child; child = child->next) { - if (AnyBit(child->flags, UI_BoxFlag_Floating) && !AnyBit(child->flags, UI_BoxFlag_NoFloatingClamp)) + if (AnyBit(child->cmd.flags, UI_BoxFlag_Floating) && !AnyBit(child->cmd.flags, UI_BoxFlag_NoFloatingClamp)) { f32 size = child->solved_dims[axis]; if (size > box_size) { - f32 strictness = child->pref_size[axis].strictness; + f32 strictness = child->cmd.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); child->solved_dims[axis] = MaxF32(size - flex, box_size); } @@ -964,8 +1037,8 @@ i64 UI_EndFrame(UI_Frame frame) /* Initialize layout cursor based on alignment */ { - Axis axis = box->child_layout_axis; - UI_AxisAlignment alignment = box->child_alignment[axis]; + Axis axis = box->cmd.child_layout_axis; + UI_AxisAlignment alignment = box->cmd.child_alignment[axis]; f32 box_size = box->solved_dims[axis]; f32 size_accum = box->final_children_size_accum[axis]; switch(alignment) @@ -989,11 +1062,11 @@ i64 UI_EndFrame(UI_Frame frame) Vec2 final_pos = ZI; /* Floating box position */ - if (AnyBit(box->flags, UI_BoxFlag_Floating)) + if (AnyBit(box->cmd.flags, UI_BoxFlag_Floating)) { - Vec2 offset = box->floating_pos; + Vec2 offset = box->cmd.floating_pos; final_pos = AddVec2(parent->p0, offset); - if (!AnyBit(box->flags, UI_BoxFlag_NoFloatingClamp)) + if (!AnyBit(box->cmd.flags, UI_BoxFlag_NoFloatingClamp)) { { f32 overshoot = MaxF32(0, (final_pos.x + dims_vec.x) - parent->p1.x); @@ -1012,13 +1085,13 @@ i64 UI_EndFrame(UI_Frame frame) f32 offset[2] = ZI; /* Calculate offset in layout direction */ { - Axis axis = parent->child_layout_axis; + Axis axis = parent->cmd.child_layout_axis; offset[axis] = layout_cursor; } /* Calculate offset in non-layout direction (based on alignment) */ { - Axis axis = !parent->child_layout_axis; - UI_AxisAlignment alignment = parent->child_alignment[axis]; + Axis axis = !parent->cmd.child_layout_axis; + UI_AxisAlignment alignment = parent->cmd.child_alignment[axis]; switch(alignment) { default: break; @@ -1038,7 +1111,7 @@ i64 UI_EndFrame(UI_Frame frame) } final_pos.x = parent->p0.x + offset[0]; final_pos.y = parent->p0.y + offset[1]; - parent->layout_cursor += dims_arr[parent->child_layout_axis]; + parent->layout_cursor += dims_arr[parent->cmd.child_layout_axis]; } /* Submit position */ @@ -1050,7 +1123,7 @@ i64 UI_EndFrame(UI_Frame frame) /* Rounding */ { - UI_Round rounding = box->rounding; + UI_Round rounding = box->cmd.rounding; Vec2 half_dims = MulVec2(SubVec2(box->p1, box->p0), 0.5); f32 min_half_dims = MinF32(half_dims.x, half_dims.y); f32 final_rounding_tl = 0; @@ -1077,7 +1150,7 @@ i64 UI_EndFrame(UI_Frame frame) } break; } - if (parent && !AllBits(box->flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp)) + if (parent && !AllBits(box->cmd.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp)) { Vec2 vtl = SubVec2(VEC2(parent->p0.x, parent->p0.y), VEC2(box->p0.x, box->p0.y)); Vec2 vtr = SubVec2(VEC2(parent->p1.x, parent->p0.y), VEC2(box->p1.x, box->p0.y)); @@ -1100,13 +1173,6 @@ i64 UI_EndFrame(UI_Frame frame) ////////////////////////////// //- Build render data - /* Init transient buffers */ - if (!g->draw_rects_arena) - { - g->draw_rects_tbuff = GPU_AcquireTransientBuffer(GPU_QueueKind_Direct, sizeof(UI_RectInstance)); - g->draw_rects_arena = AcquireArena(Gibi(64)); - } - GPU_QueueKind render_queue = GPU_QueueKind_Direct; Fence *render_fence = GPU_FenceFromQueue(render_queue); @@ -1115,40 +1181,40 @@ i64 UI_EndFrame(UI_Frame frame) { UI_Box *box = boxes_pre[pre_index]; b32 is_visible = 1; - is_visible = is_visible && (box->tint.w != 0); + is_visible = is_visible && (box->cmd.tint.w != 0); is_visible = is_visible && (box->p1.x > box->p0.x); is_visible = is_visible && (box->p1.y > box->p0.y); - if (is_visible || AnyBit(g->frame_flags, UI_FrameFlag_Debug)) + if (is_visible || AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug)) { /* Box rect */ { - UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance); - rect->flags |= UI_RectFlag_DrawTexture * !!(box->background_texture != 0); + UI_RectInstance *rect = PushStruct(g->eframe.rects_arena, UI_RectInstance); + rect->flags |= UI_RectFlag_DrawTexture * !!(box->cmd.background_texture != 0); rect->p0 = box->p0; rect->p1 = box->p1; rect->tex_uv0 = VEC2(0, 0); rect->tex_uv1 = VEC2(1, 1); - rect->background_lin = LinearFromSrgb(box->background_color); - rect->border_lin = LinearFromSrgb(box->border_color); - rect->debug_lin = LinearFromSrgb(box->debug_color); - rect->tint_lin = LinearFromSrgb(box->tint); - rect->border = box->border; + rect->background_lin = LinearFromSrgb(box->cmd.background_color); + rect->border_lin = LinearFromSrgb(box->cmd.border_color); + rect->debug_lin = LinearFromSrgb(box->cmd.debug_color); + rect->tint_lin = LinearFromSrgb(box->cmd.tint); + rect->border = box->cmd.border; rect->tl_rounding = box->rounding_tl; rect->tr_rounding = box->rounding_tr; rect->br_rounding = box->rounding_br; rect->bl_rounding = box->rounding_bl; /* Texture */ - if (box->background_texture != 0) + if (box->cmd.background_texture != 0) { - rect->tex = GPU_Texture2DRidFromResource(box->background_texture); - rect->tex_uv0 = box->background_texture_uv0; - rect->tex_uv1 = box->background_texture_uv1; + rect->tex = GPU_Texture2DRidFromResource(box->cmd.background_texture); + rect->tex_uv0 = box->cmd.background_texture_uv0; + rect->tex_uv1 = box->cmd.background_texture_uv1; } } /* Text rects */ - if (AnyBit(box->flags, UI_BoxFlag_DrawText) && box->glyph_run.count > 0 && box->font) + if (AnyBit(box->cmd.flags, UI_BoxFlag_DrawText) && box->glyph_run.count > 0 && box->font) { Texture2DRid tex_rid = GPU_Texture2DRidFromResource(box->font->texture); Vec2 inv_font_image_size = VEC2(1.0f / (f32)box->font->image_width, 1.0f / (f32)box->font->image_height); @@ -1158,10 +1224,10 @@ i64 UI_EndFrame(UI_Frame frame) b32 should_truncate = run.count > 0 && (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) > max_baseline; /* Truncate run */ - if (should_truncate && !AnyBit(box->flags, UI_BoxFlag_NoTextTruncation)) + if (should_truncate && !AnyBit(box->cmd.flags, UI_BoxFlag_NoTextTruncation)) { /* Get elipses run */ - F_Run trunc_run = F_RunFromString(g->build_arena, box->font, Lit("...")); + F_Run trunc_run = F_RunFromString(scratch.arena, box->font, Lit("...")); if (trunc_run.count > 0) { max_baseline -= trunc_run.rects[trunc_run.count - 1].pos + trunc_run.rects[trunc_run.count - 1].advance; @@ -1181,7 +1247,7 @@ i64 UI_EndFrame(UI_Frame frame) /* Merge trunc rects */ F_RunRect *new_rects = 0; { - new_rects = PushStructsNoZero(g->build_arena, F_RunRect, run.count + trunc_run.count); + new_rects = PushStructsNoZero(scratch.arena, F_RunRect, run.count + trunc_run.count); CopyStructs(new_rects, run.rects, run.count); f32 trunc_offset = run.count > 0 ? (run.rects[run.count - 1].pos + run.rects[run.count - 1].advance) : 0; for (u32 i = 0; i < trunc_run.count; ++i) @@ -1195,8 +1261,8 @@ i64 UI_EndFrame(UI_Frame frame) run.rects = new_rects; } - UI_AxisAlignment x_alignment = box->child_alignment[Axis_X]; - UI_AxisAlignment y_alignment = box->child_alignment[Axis_Y]; + UI_AxisAlignment x_alignment = box->cmd.child_alignment[Axis_X]; + UI_AxisAlignment y_alignment = box->cmd.child_alignment[Axis_Y]; if (should_truncate) { x_alignment = UI_AxisAlignment_Start; @@ -1258,13 +1324,13 @@ i64 UI_EndFrame(UI_Frame frame) Vec2 glyph_size = SubVec2(atlas_p1, atlas_p0); if (glyph_size.x != 0 || glyph_size.y != 0) { - UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance); + UI_RectInstance *rect = PushStruct(g->eframe.rects_arena, UI_RectInstance); rect->flags |= UI_RectFlag_DrawTexture; rect->p0 = AddVec2(baseline, VEC2(rr.pos, 0)); rect->p0 = AddVec2(rect->p0, rr.offset); rect->p1 = AddVec2(rect->p0, glyph_size); - rect->debug_lin = LinearFromSrgb(box->debug_color); - rect->tint_lin = LinearFromSrgb(box->tint); + rect->debug_lin = LinearFromSrgb(box->cmd.debug_color); + rect->tint_lin = LinearFromSrgb(box->cmd.tint); rect->tex_uv0 = MulVec2Vec2(atlas_p0, inv_font_image_size); rect->tex_uv1 = MulVec2Vec2(atlas_p1, inv_font_image_size); rect->tex = tex_rid; @@ -1278,7 +1344,7 @@ i64 UI_EndFrame(UI_Frame frame) //- Render /* Upload transient buffers */ - GPU_Resource *draw_rects_buffer = GPU_UploadTransientBufferFromArena(&g->draw_rects_tbuff, g->draw_rects_arena); + GPU_Resource *draw_rects_buffer = GPU_UploadTransientBufferFromArena(&g->eframe.draw_rects_tbuff, g->eframe.rects_arena); u32 draw_rects_count = GPU_GetBufferCount(draw_rects_buffer); /* Build command list */ @@ -1288,8 +1354,8 @@ i64 UI_EndFrame(UI_Frame frame) { __profn("Clear target"); GPU_ProfN(cl, Lit("Clear target")); - GPU_TransitionToRenderable(cl, g->render_target, 0); - GPU_ClearRenderable(cl, g->render_target); + GPU_TransitionToRenderable(cl, g->eframe.render_target, 0); + GPU_ClearRenderable(cl, g->eframe.render_target); } //- Rect pass @@ -1319,7 +1385,7 @@ i64 UI_EndFrame(UI_Frame frame) } /* Render rect wireframes */ - if (AnyBit(g->frame_flags, UI_FrameFlag_Debug)) + if (AnyBit(g->bframe.frame_flags, UI_FrameFlag_Debug)) { UI_RectSig sig = ZI; sig.viewport_size = RoundVec2ToVec2I32(render_viewport.size); @@ -1338,29 +1404,31 @@ i64 UI_EndFrame(UI_Frame frame) } } } - g->gpu_submit_fence_target = GPU_EndCommandList(cl); + g->eframe.gpu_submit_fence_target = GPU_EndCommandList(cl); /* Reset render data */ - GPU_ResetTransientBuffer(&g->draw_rects_tbuff, g->gpu_submit_fence_target); - ResetArena(g->draw_rects_arena); + GPU_ResetTransientBuffer(&g->eframe.draw_rects_tbuff, g->eframe.gpu_submit_fence_target); + ResetArena(g->eframe.rects_arena); ////////////////////////////// //- Present & end frame { Vec2I32 backbuffer_size = monitor_size; - if (!g->swapchain) + if (!g->eframe.swapchain) { - g->swapchain = GPU_AcquireSwapchain(frame.window_frame.window_handle, GPU_Format_R16G16B16A16_Float, backbuffer_size); + g->eframe.swapchain = GPU_AcquireSwapchain(frame.window_frame.window_handle, GPU_Format_R16G16B16A16_Float, backbuffer_size); } Vec2I32 dst_p0 = VEC2I32(0, 0); Vec2I32 dst_p1 = VEC2I32(0, 0); Vec2I32 src_p0 = VEC2I32(0, 0); Vec2I32 src_p1 = draw_size; - g->gpu_submit_fence_target = GPU_PresentSwapchain(g->swapchain, g->render_target, AnyBit(g->frame_flags, UI_FrameFlag_Vsync), backbuffer_size, dst_p0, dst_p1, src_p0, src_p1); + g->eframe.gpu_submit_fence_target = GPU_PresentSwapchain(g->eframe.swapchain, g->eframe.render_target, AnyBit(g->bframe.frame_flags, UI_FrameFlag_Vsync), backbuffer_size, dst_p0, dst_p1, src_p0, src_p1); } WND_EndFrame(frame.window_frame); + ++g->eframe.tick; + EndScratch(scratch); - return g->gpu_submit_fence_target; + return g->eframe.gpu_submit_fence_target; } diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index f06cbee7..a3117cf8 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -90,32 +90,35 @@ Enum(UI_BoxFlag) //////////////////////////////////////////////////////////// //~ Style types -#define UI_StyleKindsXMacro(x) \ - x(Flags, UI_BoxFlag) \ - x(Parent, struct UI_Box *) \ - x(Tag, u64) \ - x(ChildLayoutAxis, Axis) \ - x(ChildAlignmentX, UI_AxisAlignment) \ - x(ChildAlignmentY, UI_AxisAlignment) \ - x(Width, UI_Size) \ - x(Height, UI_Size) \ - x(BackgroundColor, Vec4) \ - x(BorderColor, Vec4) \ - x(DebugColor, Vec4) \ - x(Tint, Vec4) \ - x(Border, f32) \ - x(FloatingPos, Vec2) \ - x(Rounding, UI_Round) \ - x(Font, ResourceKey) \ - x(FontSize, u32) \ - x(Text, String) \ - /* ----------------------------------- */ \ - /* --------- Virtual styles --------- */ \ - /* ----------------------------------- */ \ - x(BeginVirtualStyles_, i8) \ - x(ChildAlignment, UI_Alignment) \ - x(AxisSize, UI_Size) \ -/* ------------------------------------------- */ +#define UI_StyleKindsXMacro(X) \ + X(Flags, UI_BoxFlag) \ + X(Parent, UI_Key) \ + X(Tag, u64) \ + X(ChildLayoutAxis, Axis) \ + X(ChildAlignmentX, UI_AxisAlignment) \ + X(ChildAlignmentY, UI_AxisAlignment) \ + X(Width, UI_Size) \ + X(Height, UI_Size) \ + X(BackgroundColor, Vec4) \ + X(BorderColor, Vec4) \ + X(DebugColor, Vec4) \ + X(Tint, Vec4) \ + X(Border, f32) \ + X(FloatingPos, Vec2) \ + X(Rounding, UI_Round) \ + X(Font, ResourceKey) \ + X(FontSize, u32) \ + X(Text, String) \ + X(BackgroundTexture, GPU_Resource *) \ + X(BackgroundTextureUv0, Vec2) \ + X(BackgroundTextureUv1, Vec2) \ + /* --------------------------------------- */ \ + /* ----------- Virtual styles ----------- */ \ + /* --------------------------------------- */ \ + X(BeginVirtualStyles_, i8) \ + X(ChildAlignment, UI_Alignment) \ + X(AxisSize, UI_Size) \ +/* -------------------------------------------------- */ Enum(UI_StyleKind) { @@ -189,29 +192,15 @@ Struct(UI_Report) }; //////////////////////////////////////////////////////////// -//~ Box types +//~ Command types -Struct(UI_Box) +Struct(UI_Cmd) { - //- Hash list - UI_Box *next_in_bin; - UI_Box *prev_in_bin; - - //- Tree - UI_Box *parent; - UI_Box *first; - UI_Box *last; - UI_Box *next; - UI_Box *prev; - u64 count; - - //- Persistent data - UI_Key key; - UI_Report report; - - //- Per-build data UI_BoxFlag flags; + UI_Key key; + UI_Key parent; + GPU_Resource *background_texture; Vec2 background_texture_uv0; Vec2 background_texture_uv1; @@ -229,6 +218,37 @@ Struct(UI_Box) f32 font_size; Axis child_layout_axis; UI_AxisAlignment child_alignment[Axis_CountXY]; +}; + +Struct(UI_CmdNode) +{ + UI_CmdNode *next; + UI_Cmd cmd; +}; + +//////////////////////////////////////////////////////////// +//~ Box types + +Struct(UI_Box) +{ + UI_Key key; + + //- Persistent data + UI_Box *next_in_bin; + UI_Box *prev_in_bin; + UI_Report report; + u64 last_updated_tick; + + //- Tree links + UI_Box *parent; + UI_Box *first; + UI_Box *last; + UI_Box *next; + UI_Box *prev; + u64 count; + + //- Cmd data + UI_Cmd cmd; //- Pre-layout data u64 pre_index; @@ -241,7 +261,7 @@ Struct(UI_Box) f32 solved_dims[Axis_CountXY]; f32 final_children_size_accum[Axis_CountXY]; - //- Post-layout data + //- Layout results Vec2 p0; Vec2 p1; f32 rounding_tl; @@ -277,47 +297,71 @@ Struct(UI_Frame) #define UI_NumBoxLookupBins 16384 -Struct(UI_SharedState) +Struct(UI_BFrameState); +Struct(UI_EFrameState); + +Struct(UI_State) { - //- Control state - i64 last_frame_begin_ns; - Vec2 cursor_pos; - UI_Key hovered_box; - UI_Key active_box; - - //- Build state - Arena *build_arena; - Arena *back_build_arena; - - UI_FrameFlag frame_flags; - UI_FrameFlag back_frame_flags; + ////////////////////////////// + //- Persistent sate + Arena *box_arena; UI_BoxBin *box_bins; - UI_BoxBin *back_box_bins; - - UI_Box *root_box; - UI_Box *back_root_box; - u64 boxes_count; - u64 back_boxes_count; + UI_Box *first_free_box; - UI_Stack *top_stack; - UI_StyleNode *first_free_style_node; + ////////////////////////////// + //- Frame-begin state - //- Layout state - UI_Box **boxes_pre; - UI_Box **boxes_post; - UI_Box **back_boxes_pre; - UI_Box **back_boxes_post; + struct UI_BFrameState + { + Arena *cmds_arena; + WND_Frame window_frame; - //- Render state - GPU_Resource *render_target; - GPU_Swapchain *swapchain; - i64 gpu_submit_fence_target; - GPU_TransientBuffer draw_rects_tbuff; - Arena *draw_rects_arena; + u64 transient_key_seed; -} extern UI_shared_state; + /* Time */ + u64 tick; + i64 time_ns; + i64 dt_ns; + + /* Control */ + Vec2 cursor_pos; + UI_Key hovered_box; + UI_Key active_box; + + /* Cmds */ + UI_FrameFlag frame_flags; + UI_CmdNode *first_cmd_node; + UI_CmdNode *last_cmd_node; + u64 cmds_count; + + /* Style stack */ + UI_Stack *top_stack; + UI_StyleNode *first_free_style_node; + } bframe; + + ////////////////////////////// + //- Frame-end state + + struct UI_EFrameState + { + Arena *layout_arena; + Arena *rects_arena; + u64 tick; + + /* Render */ + GPU_Resource *render_target; + GPU_Swapchain *swapchain; + i64 gpu_submit_fence_target; + GPU_TransientBuffer draw_rects_tbuff; + + /* Layout */ + UI_Box *root_box; + UI_Box **boxes_pre; + UI_Box **boxes_post; + } eframe; +} extern UI_state; //////////////////////////////////////////////////////////// //~ Startup @@ -336,8 +380,9 @@ UI_Key UI_KeyFromString(String str); UI_Key UI_KeyF_(String fmt, ...); #define UI_KeyF(fmt_cstr, ...) UI_KeyF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) -UI_Box *UI_BackBoxFromKey(UI_Key key); -UI_Box *UI_FrontBoxFromKey(UI_Key key); +UI_Key UI_TransKey(void); + +UI_Box *UI_BoxFromKey(UI_Key key); //////////////////////////////////////////////////////////// //~ String helpers @@ -348,7 +393,7 @@ String UI_StringF_(String fmt, ...); //////////////////////////////////////////////////////////// //~ Checkpoint helpers -UI_Checkpoint UI_PushCP(UI_Box *parent); +UI_Checkpoint UI_PushCP(UI_Key parent); void UI_PopCP(UI_Checkpoint pop_to); UI_Checkpoint UI_TopCP(void); @@ -397,12 +442,10 @@ UI_Style UI_PopStyle(UI_StyleDesc desc); #define UI_RGROW(_v) UI_ROUND(UI_RoundKind_Fill, (_v)) //////////////////////////////////////////////////////////// -//~ Box +//~ Command helpers -UI_Box *UI_BuildBox(UI_Key key); - -void UI_SetBackgroundTexture(UI_Box *box, GPU_Resource *texture, Vec2 uv0, Vec2 uv1); -b32 UI_IsPointInBox(UI_Box *box, Vec2 point); +UI_Key UI_BuildBoxEx(UI_Key key); +#define UI_BuildBox() UI_BuildBoxEx(UI_TransKey()) //////////////////////////////////////////////////////////// //~ Report @@ -417,8 +460,8 @@ UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags); //////////////////////////////////////////////////////////// //~ Frame helpers -Arena *UI_GetFrameArena(void); -Vec2 UI_GetCursorPos(void); +Arena *UI_FrameArena(void); +Vec2 UI_CursorPos(void); //////////////////////////////////////////////////////////// //~ End frame