ui checkpoints
This commit is contained in:
parent
a5f10a2312
commit
e64ae8e71c
15
src/pp/pp.c
15
src/pp/pp.c
@ -452,7 +452,7 @@ void UpdateUser(P_Window *window)
|
||||
//- Begin UI
|
||||
UI_BeginBuild();
|
||||
UI_Box *pp_root_box = UI_BuildBox(UI_Flag_DrawImage, UI_NilKey);
|
||||
UI_PushParent(pp_root_box);
|
||||
UI_Push(Parent, pp_root_box);
|
||||
|
||||
//- Init render data buffers
|
||||
if (!g->material_instances_arena)
|
||||
@ -2006,10 +2006,12 @@ void UpdateUser(P_Window *window)
|
||||
__profn("Draw debug info");
|
||||
|
||||
UI_Box *dbg_box = UI_BuildBox(0, UI_NilKey);
|
||||
UI_PushParent(dbg_box);
|
||||
UI_PushSize(Axis_X, UI_SizeKind_Pixel, 5, 0);
|
||||
UI_PushSize(Axis_Y, UI_SizeKind_Pixel, 5, 0);
|
||||
UI_PushCheckpoint();
|
||||
{
|
||||
UI_Push(Parent, dbg_box);
|
||||
UI_Push(Width, UI_PixelSize(5, 0));
|
||||
UI_Push(Height, UI_PixelSize(5, 0));
|
||||
|
||||
UI_BuildLabelF("blended world entities: %F/%F", FmtUint(g->ss_blended->num_ents_allocated), FmtUint(g->ss_blended->num_ents_reserved));
|
||||
UI_BuildSeparator();
|
||||
|
||||
@ -2105,9 +2107,7 @@ void UpdateUser(P_Window *window)
|
||||
draw_text(g->render_sig, D_TEXTPARAMS(.font = font, .pos = pos, .str = text, .offset_y = offset_y, .color = ColorWhite));
|
||||
#endif
|
||||
}
|
||||
UI_PopSize(Axis_X);
|
||||
UI_PopSize(Axis_Y);
|
||||
UI_PopParent();
|
||||
UI_PopCheckpoint();
|
||||
}
|
||||
#else
|
||||
if (g->debug_draw)
|
||||
@ -2545,7 +2545,6 @@ void UpdateUser(P_Window *window)
|
||||
}
|
||||
|
||||
/* Render UI */
|
||||
UI_PopParent();
|
||||
UI_SetDisplayImage(pp_root_box, g->ui_target);
|
||||
GPU_Resource *ui_render = UI_EndBuild(ui_viewport);
|
||||
|
||||
|
||||
231
src/ui/ui.c
231
src/ui/ui.c
@ -3,118 +3,128 @@ UI_SharedState UI_shared_state = ZI;
|
||||
////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
UI_Key UI_KeyFromString(u64 seed, String str)
|
||||
u64 UI_HashFromTop(void)
|
||||
{
|
||||
UI_Box *parent_box = UI_PeekTop(Parent);
|
||||
u64 tag_hash = UI_PeekTop(Tag);
|
||||
return RandU64FromSeeds(parent_box->key.hash, tag_hash);
|
||||
}
|
||||
|
||||
u64 UI_HashFromString(u64 seed, String str)
|
||||
{
|
||||
/* TOIMPL */
|
||||
if (seed == 0)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
seed = RandU64FromSeeds(g->top_parent->box->key.hash, g->top_tag->hash);
|
||||
seed = UI_HashFromTop();
|
||||
}
|
||||
return HashFnv64(seed, str);
|
||||
}
|
||||
|
||||
UI_Key UI_KeyFromString(u64 seed, String str)
|
||||
{
|
||||
UI_Key result = ZI;
|
||||
result.hash = HashFnv64(seed, str);
|
||||
result.hash = UI_HashFromString(seed, str);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Stack helpers
|
||||
//~ Checkpoint helpers
|
||||
|
||||
//- Tag
|
||||
|
||||
void UI_PushTagFromHash(u64 hash)
|
||||
void UI_PushCheckpoint(void)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
if (g->top_tag)
|
||||
UI_Checkpoint *cp = g->first_free_checkpoint;
|
||||
if (cp)
|
||||
{
|
||||
hash = RandU64FromSeeds(hash, g->top_tag->hash);
|
||||
g->first_free_checkpoint = cp->next;
|
||||
ZeroStruct(cp);
|
||||
}
|
||||
UI_TagNode *n = PushStruct(g->build_arena, UI_TagNode);
|
||||
StackPush(g->top_tag, n);
|
||||
n->hash = hash;
|
||||
}
|
||||
|
||||
void UI_PushTagFromString(String str)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
u64 hash = Fnv64Basis;
|
||||
if (g->top_tag)
|
||||
else
|
||||
{
|
||||
hash = g->top_tag->hash;
|
||||
cp = PushStruct(g->build_arena, UI_Checkpoint);
|
||||
}
|
||||
hash = HashFnv64(hash, str);
|
||||
UI_TagNode *n = PushStruct(g->build_arena, UI_TagNode);
|
||||
n->hash = hash;
|
||||
StackPush(g->top_tag, n);
|
||||
cp->v = g->top_checkpoint->v + 1;
|
||||
g->top_checkpoint = cp;
|
||||
}
|
||||
|
||||
void UI_PushTagF_(char *fmt_cstr, ...)
|
||||
void UI_PopCheckpoint(void)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
String str = ZI;
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_Checkpoint *cp = g->top_checkpoint;
|
||||
u64 v = cp->v;
|
||||
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt_cstr);
|
||||
str = FormatStringV(scratch.arena, StringFromCstrNoLimit(fmt_cstr), va);
|
||||
va_end(va);
|
||||
UI_StyleNode *n = g->style_tops[kind];
|
||||
while (n && n->checkpoint >= v)
|
||||
{
|
||||
UI_StyleNode *next = n->next;
|
||||
g->style_tops[kind] = next;
|
||||
n->next = g->first_free_style_node;
|
||||
g->first_free_style_node = n;
|
||||
n = next;
|
||||
}
|
||||
}
|
||||
UI_PushTagFromString(str);
|
||||
EndScratch(scratch);
|
||||
}
|
||||
|
||||
void UI_PopTag(void)
|
||||
{
|
||||
StackPop(UI_shared_state.top_tag);
|
||||
}
|
||||
|
||||
//- Parent
|
||||
|
||||
void UI_PushParent(UI_Box *box)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_ParentNode *n = PushStruct(g->build_arena, UI_ParentNode);
|
||||
n->box = box;
|
||||
StackPush(g->top_parent, n);
|
||||
}
|
||||
|
||||
void UI_PopParent(void)
|
||||
{
|
||||
StackPop(UI_shared_state.top_parent);
|
||||
}
|
||||
|
||||
//- Size
|
||||
|
||||
void UI_PushSize(Axis axis, UI_SizeKind kind, f32 v, f32 strictness)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_SizeNode *n = PushStruct(g->build_arena, UI_SizeNode);
|
||||
n->size.kind = kind;
|
||||
n->size.v = v;
|
||||
n->size.strictness = strictness;
|
||||
StackPush(g->top_size[axis], n);
|
||||
}
|
||||
|
||||
void UI_PopSize(Axis axis)
|
||||
{
|
||||
StackPop(UI_shared_state.top_size[axis]);
|
||||
}
|
||||
|
||||
//- Layout dir
|
||||
|
||||
void UI_PushLayoutDir(Axis dir)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_AxisNode *n = PushStruct(g->build_arena, UI_AxisNode);
|
||||
n->axis = dir;
|
||||
StackPush(g->top_layout_dir, n);
|
||||
}
|
||||
|
||||
void UI_PopLayoutDir(void)
|
||||
{
|
||||
StackPop(UI_shared_state.top_layout_dir);
|
||||
cp->next = g->first_free_checkpoint;
|
||||
g->first_free_checkpoint = cp;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Box helpers
|
||||
//~ Style stack helpers
|
||||
|
||||
UI_StyleNode *UI_PushStyleNode(UI_StyleKind kind, b32 pop_when_touched, UI_Style desc)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_StyleNode *n = g->first_free_style_node;
|
||||
if (n)
|
||||
{
|
||||
g->first_free_style_node = n->next;
|
||||
ZeroStruct(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
n = PushStruct(g->build_arena, UI_StyleNode);
|
||||
}
|
||||
n->pop_when_touched = pop_when_touched;
|
||||
n->style = desc;
|
||||
n->next = g->style_tops[kind];
|
||||
n->checkpoint = g->top_checkpoint->v;
|
||||
g->style_tops[kind] = n;
|
||||
return n;
|
||||
}
|
||||
|
||||
UI_Style UI_PopStyleNode(UI_StyleKind kind)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_StyleNode *n = g->style_tops[kind];
|
||||
UI_Style style = n->style;
|
||||
g->style_tops[kind] = n->next;
|
||||
n->next = g->first_free_style_node;
|
||||
g->first_free_style_node = n;
|
||||
return style;
|
||||
}
|
||||
|
||||
UI_StyleNode *UI_PeekStyleNode(UI_StyleKind kind)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_StyleNode *n = g->style_tops[kind];
|
||||
return n;
|
||||
}
|
||||
|
||||
UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 touch)
|
||||
{
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_StyleNode *n = g->style_tops[kind];
|
||||
UI_Style style = n->style;
|
||||
if (touch && n->pop_when_touched)
|
||||
{
|
||||
g->style_tops[kind] = n->next;
|
||||
n->next = g->first_free_style_node;
|
||||
g->first_free_style_node = n;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Box helper s
|
||||
|
||||
UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key)
|
||||
{
|
||||
@ -164,13 +174,13 @@ UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key)
|
||||
|
||||
box->tint = 0xFFFFFFFF;
|
||||
|
||||
/* Pull from stack */
|
||||
box->parent = g->top_parent->box;
|
||||
box->pref_size[Axis_X] = g->top_size[Axis_X]->size;
|
||||
box->pref_size[Axis_Y] = g->top_size[Axis_Y]->size;
|
||||
box->layout_dir = g->top_layout_dir->axis;
|
||||
/* Pull from style stack */
|
||||
box->parent = UI_TouchTop(Parent);
|
||||
box->pref_size[Axis_X] = UI_TouchTop(Width);
|
||||
box->pref_size[Axis_Y] = UI_TouchTop(Height);
|
||||
box->layout_axis = UI_TouchTop(LayoutAxis);
|
||||
|
||||
DllPushBack(g->top_parent->box->first, g->top_parent->box->last, box);
|
||||
DllPushBack(box->parent->first, box->parent->last, box);
|
||||
++box->parent->count;
|
||||
|
||||
return box;
|
||||
@ -212,6 +222,7 @@ void UI_BeginBuild(void)
|
||||
}
|
||||
ResetArena(g->build_arena);
|
||||
g->boxes_count = 0;
|
||||
g->first_free_style_node = 0;
|
||||
|
||||
/* Init bins */
|
||||
g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins);
|
||||
@ -223,12 +234,28 @@ void UI_BeginBuild(void)
|
||||
DllPushBackNP(bin->first, bin->last, g->root_box, next_in_bin, prev_in_bin);
|
||||
++g->boxes_count;
|
||||
|
||||
/* Init stacks */
|
||||
UI_PushTagF("root");
|
||||
UI_PushParent(g->root_box);
|
||||
UI_PushSize(Axis_X, UI_SizeKind_Percent, 1, 0);
|
||||
UI_PushSize(Axis_Y, UI_SizeKind_Percent, 1, 0);
|
||||
UI_PushLayoutDir(Axis_X);
|
||||
/* Init checkpoints */
|
||||
g->top_checkpoint = PushStruct(g->build_arena, UI_Checkpoint);
|
||||
|
||||
/* Init styles */
|
||||
{
|
||||
UI_StyleNode *nodes = PushStructs(g->build_arena, UI_StyleNode, UI_StyleKind_Count);
|
||||
for (UI_StyleKind kind = UI_StyleKind_None; kind < UI_StyleKind_Count; ++kind)
|
||||
{
|
||||
UI_StyleNode *n = &nodes[kind];
|
||||
UI_Style *style = &n->style;
|
||||
style->kind = kind;
|
||||
g->style_tops[kind] = n;
|
||||
switch(kind)
|
||||
{
|
||||
default: break;
|
||||
case UI_StyleKind_Tag: { style->Tag = HashFnv64(Fnv64Basis, Lit("root")); } break;
|
||||
case UI_StyleKind_Parent: { style->Parent = g->root_box; } break;
|
||||
case UI_StyleKind_Width: { style->Width = UI_RatioSize(1, 0); } break;
|
||||
case UI_StyleKind_Height: { style->Height = UI_RatioSize(1, 0); } break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!g->back_build_arena)
|
||||
{
|
||||
@ -323,7 +350,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
|
||||
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
|
||||
{
|
||||
UI_Size pref_size = box->pref_size[axis];
|
||||
if (pref_size.kind == UI_SizeKind_Percent)
|
||||
if (pref_size.kind == UI_SizeKind_Ratio)
|
||||
{
|
||||
UI_Box *ancestor = box->parent;
|
||||
f32 ancestor_size = 0;
|
||||
@ -349,7 +376,7 @@ GPU_Resource *UI_EndBuild(Rect render_viewport)
|
||||
Vec2 final_size = VEC2(box->solved_dims[0], box->solved_dims[1]);
|
||||
if (parent)
|
||||
{
|
||||
b32 is_layout_x = parent->layout_dir == Axis_X;
|
||||
b32 is_layout_x = parent->layout_axis == Axis_X;
|
||||
f32 layout_cursor = parent->layout_cursor;
|
||||
Vec2 offset = VEC2(layout_cursor * is_layout_x, layout_cursor * !is_layout_x);
|
||||
parent->layout_cursor += final_size.x * is_layout_x + final_size.y * is_layout_x;
|
||||
|
||||
109
src/ui/ui.h
109
src/ui/ui.h
@ -15,7 +15,7 @@ Struct(UI_Key)
|
||||
Enum(UI_SizeKind)
|
||||
{
|
||||
UI_SizeKind_Children,
|
||||
UI_SizeKind_Percent,
|
||||
UI_SizeKind_Ratio,
|
||||
UI_SizeKind_Pixel,
|
||||
UI_SizeKind_Text,
|
||||
};
|
||||
@ -52,7 +52,7 @@ Struct(UI_Box)
|
||||
String display_text;
|
||||
GPU_Resource *display_image;
|
||||
UI_Size pref_size[Axis_CountXY];
|
||||
Axis layout_dir;
|
||||
Axis layout_axis;
|
||||
u32 tint;
|
||||
|
||||
//- Layout data
|
||||
@ -71,12 +71,56 @@ Struct(UI_BoxBin)
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Stack types
|
||||
//~ Style types
|
||||
|
||||
Struct(UI_TagNode) { UI_TagNode *next; u64 hash; };
|
||||
Struct(UI_ParentNode) { UI_ParentNode *next; UI_Box *box; };
|
||||
Struct(UI_SizeNode) { UI_SizeNode *next; UI_Size size; };
|
||||
Struct(UI_AxisNode) { UI_AxisNode *next; Axis axis; };
|
||||
//- Style data
|
||||
#define UI_StyleKindsXMacro(x) \
|
||||
x(Tag, u64) \
|
||||
x(Parent, UI_Box *) \
|
||||
x(LayoutAxis, Axis) \
|
||||
x(Width, UI_Size) \
|
||||
x(Height, UI_Size) \
|
||||
x(BackgroundColor, u32) \
|
||||
x(Opacity, f32) \
|
||||
|
||||
//- Style node
|
||||
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 data types */
|
||||
union
|
||||
{
|
||||
#define X(name, type) type name;
|
||||
UI_StyleKindsXMacro(X)
|
||||
#undef X
|
||||
};
|
||||
};
|
||||
|
||||
Struct(UI_StyleNode)
|
||||
{
|
||||
UI_StyleNode *next;
|
||||
b32 pop_when_touched;
|
||||
u64 checkpoint;
|
||||
UI_Style style;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Checkpoint types
|
||||
|
||||
Struct(UI_Checkpoint)
|
||||
{
|
||||
UI_Checkpoint *next;
|
||||
u64 v;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ State types
|
||||
@ -98,17 +142,16 @@ Struct(UI_SharedState)
|
||||
u64 boxes_count;
|
||||
u64 back_boxes_count;
|
||||
|
||||
//- Stack state
|
||||
UI_TagNode *top_tag;
|
||||
UI_ParentNode *top_parent;
|
||||
UI_SizeNode *top_size[Axis_CountXY];
|
||||
UI_AxisNode *top_layout_dir;
|
||||
UI_Checkpoint *top_checkpoint;
|
||||
UI_Checkpoint *first_free_checkpoint;
|
||||
|
||||
UI_StyleNode *style_tops[UI_StyleKind_Count];
|
||||
UI_StyleNode *first_free_style_node;
|
||||
|
||||
//- Render state
|
||||
GPU_Resource *render_target;
|
||||
i64 render_fence_target;
|
||||
|
||||
|
||||
GPU_TransientBuffer draw_rects_tbuff;
|
||||
Arena *draw_rects_arena;
|
||||
|
||||
@ -117,29 +160,37 @@ Struct(UI_SharedState)
|
||||
////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
u64 UI_HashFromTop(void);
|
||||
u64 UI_HashFromString(u64 seed, String str);
|
||||
UI_Key UI_KeyFromString(u64 seed, String str);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Stack helpers
|
||||
//~ Checkpoint helpers
|
||||
|
||||
//- Tag
|
||||
void UI_PushTagFromHash(u64 hash);
|
||||
void UI_PushTagFromString(String str);
|
||||
#define UI_PushTagF(fmt_cstr, ...) UI_PushTagF_(fmt_cstr, __VA_ARGS__, FmtEnd);
|
||||
void UI_PushTagF_(char *fmt_cstr, ...);
|
||||
void UI_PopTag(void);
|
||||
void UI_PushCheckpoint(void);
|
||||
void UI_PopCheckpoint(void);
|
||||
|
||||
//- Parent
|
||||
void UI_PushParent(UI_Box *box);
|
||||
void UI_PopParent(void);
|
||||
////////////////////////////////
|
||||
//~ Style stack helpers
|
||||
|
||||
//- Size
|
||||
void UI_PushSize(Axis axis, UI_SizeKind kind, f32 v, f32 strictness);
|
||||
void UI_PopSize(Axis axis);
|
||||
UI_StyleNode *UI_PushStyleNode(UI_StyleKind kind, b32 pop_when_touched, UI_Style desc);
|
||||
UI_Style UI_PopStyleNode(UI_StyleKind kind);
|
||||
UI_StyleNode *UI_PeekTopStyleNode(UI_StyleKind kind);
|
||||
UI_Style UI_StyleFromTopNode(UI_StyleKind kind, b32 touch);
|
||||
|
||||
//- Layout dir
|
||||
void UI_PushLayoutDir(Axis dir);
|
||||
void UI_PopLayoutDir(void);
|
||||
#define UI_SetNext(name, ...) UI_PushStyleNode(UI_StyleKind_##name, 1, (UI_Style) { .name = __VA_ARGS__ })
|
||||
#define UI_Push(name, ...) UI_PushStyleNode(UI_StyleKind_##name, 0, (UI_Style) { .name = __VA_ARGS__ })
|
||||
#define UI_Pop(name, ...) UI_PopStyleNode(UI_StyleKind_##name).name
|
||||
#define UI_TouchTop(name) UI_StyleFromTopNode(UI_StyleKind_##name, 1).name
|
||||
#define UI_PeekTop(name) UI_StyleFromTopNode(UI_StyleKind_##name, 0).name
|
||||
|
||||
////////////////////////////////
|
||||
//~ Size helpers
|
||||
|
||||
#define UI_ChildrenSize(_strictness) ((UI_Size) { .kind = UI_SizeKind_Children, .strictness = strictness_ })
|
||||
#define UI_RatioSize(_ratio, _strictness) ((UI_Size) { .kind = UI_SizeKind_Ratio, .v = _ratio, .strictness = _strictness })
|
||||
#define UI_PixelSize(_pixels, _strictness) ((UI_Size) { .kind = UI_SizeKind_Pixel, .v = _pixels, .strictness = _strictness })
|
||||
#define UI_TextSize(_strictness) ((UI_Size) { .kind = UI_SizeKind_Text, .strictness = _strictness })
|
||||
|
||||
////////////////////////////////
|
||||
//~ Box
|
||||
|
||||
Loading…
Reference in New Issue
Block a user