//////////////////////////////////////////////////////////// //~ Key types #define UI_NilKey ((UI_Key) { 0 }) #define UI_RootKey ((UI_Key) { 0xa3deb3749ef35a7aUll }) Struct(UI_Key) { u64 hash; }; //////////////////////////////////////////////////////////// //~ Size types Enum(UI_SizeKind) { UI_SizeKind_Pixel, /* Exact size */ UI_SizeKind_Fill, /* Size as percent of parent size */ UI_SizeKind_Fit, /* Size to contents */ }; Struct(UI_Size) { UI_SizeKind kind; f32 v; f32 strictness; }; //////////////////////////////////////////////////////////// //~ Rounding types Enum(UI_RoundKind) { UI_RoundKind_Pixel, /* Exact radius */ UI_RoundKind_Fill, /* Radius as percent of size */ }; Struct(UI_Round) { UI_RoundKind kind; f32 v; }; //////////////////////////////////////////////////////////// //~ Alignment types Enum(UI_Alignment) { UI_Alignment_TopLeft, UI_Alignment_Top, UI_Alignment_TopRight, UI_Alignment_Left, UI_Alignment_Center, UI_Alignment_Right, UI_Alignment_BottomLeft, UI_Alignment_Bottom, UI_Alignment_BottomRight, }; Enum(UI_AxisAlignment) { UI_AxisAlignment_Start, UI_AxisAlignment_Center, UI_AxisAlignment_End, }; //////////////////////////////////////////////////////////// //~ Checkpoint types Struct(UI_Checkpoint) { UI_Checkpoint *next; u64 v; }; //////////////////////////////////////////////////////////// //~ Box flags Enum(UI_BoxFlag) { UI_BoxFlag_None = 0, UI_BoxFlag_DrawText = (1 << 0), UI_BoxFlag_Interactable = (1 << 1), UI_BoxFlag_NoTextTruncation = (1 << 2), UI_BoxFlag_Floating = (1 << 3), UI_BoxFlag_NoFloatingClamp = (1 << 4), }; //////////////////////////////////////////////////////////// //~ 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, u32) \ x(BorderColor, u32) \ x(DebugColor, u32) \ x(Tint, u32) \ 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) \ /* ------------------------------------------- */ Enum(UI_StyleKind) { #define X(name, type) UI_StyleKind_##name, UI_StyleKind_None, UI_StyleKindsXMacro(X) UI_StyleKind_Count, #undef X }; Struct(UI_Style) { UI_StyleKind kind; /* Union of all style fields */ union { #define X(name, type) type name; UI_StyleKindsXMacro(X) #undef X }; }; Struct(UI_StyleDesc) { Axis axis; UI_Style style; /* Push */ b32 pop_when_used; b32 override; /* Pop */ b32 force_pop; b32 use; }; Struct(UI_StyleNode) { UI_StyleNode *next; UI_Style style; b32 pop_when_used; b32 override; u64 checkpoint; }; Struct(UI_Stack) { UI_Stack *next; UI_Checkpoint *top_checkpoint; UI_StyleNode *style_tops[UI_StyleKind_Count]; }; //////////////////////////////////////////////////////////// //~ Report types Struct(UI_Report) { b32 m1_held; f32 hovered; f32 hot; f32 active; b32 m1_downs; b32 m1_ups; b32 m1_presses; Vec2 last_m1_offset; /* Where was this box last rendered in screen coordinates */ Vec2 screen_p0; Vec2 screen_p1; }; //////////////////////////////////////////////////////////// //~ Box types Struct(UI_Box) { //- 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; GPU_Resource *background_texture; Vec2 background_texture_uv0; Vec2 background_texture_uv1; UI_Size pref_size[Axis_CountXY]; UI_Round rounding; u32 background_color; u32 border_color; u32 debug_color; u32 text_color; u32 tint; f32 border; Vec2 floating_pos; String text; ResourceKey font_resource; f32 font_size; Axis child_layout_axis; UI_AxisAlignment child_alignment[Axis_CountXY]; //- Pre-layout data u64 pre_index; u64 post_index; //- Layout data F_Run glyph_run; F_Font *font; f32 layout_cursor; f32 solved_dims[Axis_CountXY]; f32 final_children_size_accum[Axis_CountXY]; //- Post-layout data Vec2 p0; Vec2 p1; f32 rounding_tl; f32 rounding_tr; f32 rounding_br; f32 rounding_bl; }; Struct(UI_BoxBin) { UI_Box *first; UI_Box *last; }; //////////////////////////////////////////////////////////// //~ Frame types Enum(UI_FrameFlag) { UI_FrameFlag_None = 0, UI_FrameFlag_Debug = (1 << 0), UI_FrameFlag_Vsync = (1 << 1), }; Struct(UI_Frame) { WND_Frame window_frame; }; //////////////////////////////////////////////////////////// //~ State types #define UI_NumBoxLookupBins 16384 Struct(UI_SharedState) { //- 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; 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_Stack *top_stack; UI_Stack *first_free_stack; UI_Checkpoint *first_free_checkpoint; 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 GPU_Resource *render_target; GPU_Swapchain *swapchain; i64 gpu_submit_fence_target; GPU_TransientBuffer draw_rects_tbuff; Arena *draw_rects_arena; } extern UI_shared_state; //////////////////////////////////////////////////////////// //~ Startup void UI_Startup(void); //////////////////////////////////////////////////////////// //~ Font helpers ResourceKey UI_GetDefaultFontResource(void); //////////////////////////////////////////////////////////// //~ Key helpers 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); //////////////////////////////////////////////////////////// //~ String helpers String UI_StringF_(String fmt, ...); #define UI_StringF(fmt_cstr, ...) UI_StringF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) //////////////////////////////////////////////////////////// //~ Checkpoint helpers UI_Box *UI_PushCP(UI_Box *parent); void UI_PopCP(void); //////////////////////////////////////////////////////////// //~ Style stack helpers void UI_PushEmptyStack(void); void UI_PopStack(void); void UI_PushStyle(UI_StyleDesc desc); UI_Style UI_PopStyle(UI_StyleDesc desc); #define UI_STYLEDESC(name, ...) (UI_StyleDesc) { .style.kind = UI_StyleKind_##name, __VA_ARGS__ } #define UI_SetNext(name, ...) UI_PushStyle(UI_STYLEDESC(name, .pop_when_used = 1, .style.name = __VA_ARGS__)) #define UI_Push(name, ...) UI_PushStyle(UI_STYLEDESC(name, .style.name = __VA_ARGS__)) #define UI_ForceNext(name, ...) UI_PushStyle(UI_STYLEDESC(name, .pop_when_used = 1, .forced = 1, .style.name = __VA_ARGS__)) #define UI_ForcePush(name, ...) UI_PushStyle(UI_STYLEDESC(name, .forced = 1, .style.name = __VA_ARGS__)) #define UI_Pop(name, ...) UI_PopStyle(UI_STYLEDESC(name, .forced_pop = 1, __VA_ARGS__)).name #define UI_PeekTop(name, ...) UI_PopStyle(UI_STYLEDESC(name, __VA_ARGS__)).name #define UI_UseTop(name, ...) UI_PopStyle(UI_STYLEDESC(name, .use = 1, __VA_ARGS__)).name #define UI_PushCopy(name, src, ...) do { \ UI_StyleDesc _new = src; \ _new.style.kind = UI_StyleKind_##name; \ _new.style.name = __VA_ARGS__; \ UI_PushStyle(_new); \ } while (0) //////////////////////////////////////////////////////////// //~ Size helpers #define UI_SIZE(_kind, _v, _s) (UI_Size) { .kind = (_kind), .v = (_v), .strictness = (_s) } #define UI_PIX(_v, _s) UI_SIZE(UI_SizeKind_Pixel, (_v), (_s)) #define UI_FIT(_s) UI_SIZE(UI_SizeKind_Fit, 0, (_s)) #define UI_FILL(_v, _s) UI_SIZE(UI_SizeKind_Fill, (_v), (_s)) #define UI_FNT(_v, _s) UI_SIZE(UI_SizeKind_Pixel, (f32)UI_PeekTop(FontSize) * (_v), (_s)) //////////////////////////////////////////////////////////// //~ Rounding helpers #define UI_ROUND(_kind, _v) (UI_Round) { .kind = (_kind), .v = (_v)} #define UI_RPIX(_v) UI_ROUND(UI_RoundKind_Pixel, (_v)) #define UI_RFILL(_v) UI_ROUND(UI_RoundKind_Fill, (_v)) //////////////////////////////////////////////////////////// //~ Box 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); //////////////////////////////////////////////////////////// //~ Report UI_Report UI_ReportFromKey(UI_Key key); //////////////////////////////////////////////////////////// //~ Begin frame UI_Frame UI_BeginFrame(UI_FrameFlag frame_flags); //////////////////////////////////////////////////////////// //~ End build GPU_ResourceDesc UI_GetRenderTargetDesc(Vec2I32 size); i64 UI_EndFrame(UI_Frame frame);