ui layer testing
This commit is contained in:
parent
b74927602c
commit
fca8ba5a8d
@ -4,6 +4,19 @@
|
||||
#define Tau ((f32)6.28318530717958647693)
|
||||
#define GoldenRatio ((f32)1.61803398874989484820)
|
||||
|
||||
////////////////////////////////
|
||||
//~ Axis types
|
||||
|
||||
Enum(Axis)
|
||||
{
|
||||
Axis_X = 0,
|
||||
Axis_Y = 1,
|
||||
Axis_Z = 2,
|
||||
|
||||
Axis_CountXY = 2,
|
||||
Axis_CountXYZ = 3,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Vector types
|
||||
|
||||
|
||||
305
src/ui/ui.c
305
src/ui/ui.c
@ -1,22 +1,5 @@
|
||||
UI_SharedState UI_shared_state = ZI;
|
||||
|
||||
////////////////////////////////
|
||||
//~ State helpers
|
||||
|
||||
UI_FiberState *UI_GetFiberState(void)
|
||||
{
|
||||
UI_FiberState *f = UI_shared_state.fiber_states[FiberId()];
|
||||
if (!f)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
PushAlign(perm, CachelineSize);
|
||||
f = PushStruct(perm, UI_FiberState);
|
||||
UI_shared_state.fiber_states[FiberId()] = f;
|
||||
PushAlign(perm, CachelineSize);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
@ -25,8 +8,8 @@ UI_Key UI_KeyFromString(u64 seed, String str)
|
||||
/* TOIMPL */
|
||||
if (seed == 0)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
seed = RandU64FromSeeds(f->top_parent->box->key.hash, f->top_tag->hash);
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
seed = RandU64FromSeeds(g->top_parent->box->key.hash, g->top_tag->hash);
|
||||
}
|
||||
UI_Key result = ZI;
|
||||
result.hash = HashFnv64(seed, str);
|
||||
@ -40,27 +23,27 @@ UI_Key UI_KeyFromString(u64 seed, String str)
|
||||
|
||||
void UI_PushTagFromHash(u64 hash)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
if (f->top_tag)
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
if (g->top_tag)
|
||||
{
|
||||
hash = RandU64FromSeeds(hash, f->top_tag->hash);
|
||||
hash = RandU64FromSeeds(hash, g->top_tag->hash);
|
||||
}
|
||||
UI_Tag *tag = PushStruct(f->build_arena, UI_Tag);
|
||||
StackPush(f->top_tag, tag);
|
||||
UI_Tag *tag = PushStruct(g->build_arena, UI_Tag);
|
||||
StackPush(g->top_tag, tag);
|
||||
tag->hash = hash;
|
||||
}
|
||||
|
||||
void UI_PushTagFromString(String str)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
u64 hash = Fnv64Basis;
|
||||
if (f->top_tag)
|
||||
if (g->top_tag)
|
||||
{
|
||||
hash = f->top_tag->hash;
|
||||
hash = g->top_tag->hash;
|
||||
}
|
||||
hash = HashFnv64(hash, str);
|
||||
UI_Tag *tag = PushStruct(f->build_arena, UI_Tag);
|
||||
StackPush(f->top_tag, tag);
|
||||
UI_Tag *tag = PushStruct(g->build_arena, UI_Tag);
|
||||
StackPush(g->top_tag, tag);
|
||||
tag->hash = hash;
|
||||
}
|
||||
|
||||
@ -80,24 +63,24 @@ void UI_PushTagF_(char *fmt_cstr, ...)
|
||||
|
||||
void UI_PopTag(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
StackPop(f->top_tag);
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
StackPop(g->top_tag);
|
||||
}
|
||||
|
||||
//- Parent
|
||||
|
||||
void UI_PushParent(UI_Box *box)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
UI_Parent *parent = PushStruct(f->build_arena, UI_Parent);
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
UI_Parent *parent = PushStruct(g->build_arena, UI_Parent);
|
||||
parent->box = box;
|
||||
StackPush(f->top_parent, parent);
|
||||
StackPush(g->top_parent, parent);
|
||||
}
|
||||
|
||||
void UI_PopParent(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
StackPop(f->top_parent);
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
StackPop(g->top_parent);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@ -105,13 +88,24 @@ void UI_PopParent(void)
|
||||
|
||||
UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
UI_BoxBin *bin = &f->box_bins[key.hash % UI_NumBoxLookupBins];
|
||||
UI_BoxBin *back_bin = &f->back_box_bins[key.hash % UI_NumBoxLookupBins];
|
||||
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];
|
||||
|
||||
UI_Box *box = PushStruct(f->build_arena, UI_Box);
|
||||
UI_Box *box = PushStruct(g->build_arena, UI_Box);
|
||||
if (key.hash != 0)
|
||||
{
|
||||
#if RTC
|
||||
/* Validate box not already built */
|
||||
for (UI_Box *tmp = bin->first; tmp; tmp = tmp->next_in_bin)
|
||||
{
|
||||
if (tmp->key.hash == key.hash)
|
||||
{
|
||||
Assert(0); /* Box with matching key already built */
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DllPushBackNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
||||
}
|
||||
|
||||
@ -133,11 +127,13 @@ UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key)
|
||||
{
|
||||
*box = *back_box;
|
||||
}
|
||||
++g->boxes_count;
|
||||
|
||||
box->key = key;
|
||||
box->flags = flags;
|
||||
box->parent = f->top_parent->box;
|
||||
DllPushBack(f->top_parent->box->first, f->top_parent->box->last, box);
|
||||
box->parent = g->top_parent->box;
|
||||
DllPushBack(g->top_parent->box->first, g->top_parent->box->last, box);
|
||||
++box->parent->count;
|
||||
|
||||
return box;
|
||||
}
|
||||
@ -147,8 +143,8 @@ UI_Box *UI_BuildBox(UI_Flag flags, UI_Key key)
|
||||
|
||||
void UI_SetDisplayText(UI_Box *box, String str)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
String text = PushString(f->build_arena, str);
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
String text = PushString(g->build_arena, str);
|
||||
box->display_text = text;
|
||||
}
|
||||
|
||||
@ -165,38 +161,43 @@ void UI_SetDisplayImage(UI_Box *box, GPU_Resource *img)
|
||||
|
||||
void UI_BeginBuild(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
|
||||
/* Swap front & back build states */
|
||||
{
|
||||
Arena *swp = f->build_arena;
|
||||
f->build_arena = f->back_build_arena;
|
||||
f->back_build_arena = swp;
|
||||
Arena *swp = g->build_arena;
|
||||
g->build_arena = g->back_build_arena;
|
||||
g->back_build_arena = swp;
|
||||
}
|
||||
f->back_box_bins = f->box_bins;
|
||||
f->back_root_box = f->root_box;
|
||||
g->back_box_bins = g->box_bins;
|
||||
g->back_root_box = g->root_box;
|
||||
g->back_boxes_count = g->boxes_count;
|
||||
|
||||
/* Reset front build state */
|
||||
if (!f->build_arena)
|
||||
if (!g->build_arena)
|
||||
{
|
||||
f->build_arena = AcquireArena(Gibi(64));
|
||||
g->build_arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
ResetArena(f->build_arena);
|
||||
ResetArena(g->build_arena);
|
||||
g->boxes_count = 0;
|
||||
|
||||
/* Init bins */
|
||||
f->box_bins = PushStructs(f->build_arena, UI_BoxBin, UI_NumBoxLookupBins);
|
||||
g->box_bins = PushStructs(g->build_arena, UI_BoxBin, UI_NumBoxLookupBins);
|
||||
|
||||
/* Init root box */
|
||||
f->root_box = PushStruct(f->build_arena, UI_Box);
|
||||
f->root_box->key = UI_RootKey;
|
||||
UI_BoxBin *bin = &f->box_bins[f->root_box->key.hash % UI_NumBoxLookupBins];
|
||||
DllPushBackNP(bin->first, bin->last, f->root_box, next_in_bin, prev_in_bin);
|
||||
g->root_box = PushStruct(g->build_arena, UI_Box);
|
||||
g->root_box->key = UI_RootKey;
|
||||
g->root_box->pref_size[Axis_X].kind = UI_SizeKind_Absolute;
|
||||
g->root_box->pref_size[Axis_Y].kind = UI_SizeKind_Absolute;
|
||||
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;
|
||||
|
||||
/* Init stacks */
|
||||
UI_PushTagF("root");
|
||||
UI_PushParent(f->root_box);
|
||||
UI_PushParent(g->root_box);
|
||||
|
||||
if (!f->back_build_arena)
|
||||
if (!g->back_build_arena)
|
||||
{
|
||||
/* Back buffer not initialized, swap again */
|
||||
UI_BeginBuild();
|
||||
@ -208,39 +209,199 @@ void UI_BeginBuild(void)
|
||||
|
||||
GPU_Resource *UI_EndBuild(void)
|
||||
{
|
||||
UI_FiberState *f = UI_GetFiberState();
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
UI_SharedState *g = &UI_shared_state;
|
||||
|
||||
/* TODO: Ensure root is parent */
|
||||
|
||||
////////////////////////////////
|
||||
//- Layout
|
||||
|
||||
/* Init root size */
|
||||
Vec2I32 root_size = VEC2I32(500, 500);
|
||||
g->root_box->p0 = VEC2(0, 0);
|
||||
g->root_box->p1 = VEC2(root_size.x, root_size.y);
|
||||
|
||||
/* Build pre-order & post-order box arrays */
|
||||
u64 boxes_count = g->boxes_count;
|
||||
UI_Box **boxes_pre = PushStructsNoZero(scratch.arena, UI_Box *, boxes_count);
|
||||
UI_Box **boxes_post = PushStructsNoZero(scratch.arena, UI_Box *, boxes_count);
|
||||
{
|
||||
Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; };
|
||||
BoxNode *first_dfs = 0;
|
||||
u64 pre_index = 0;
|
||||
u64 post_index = 0;
|
||||
{
|
||||
BoxNode *n = PushStruct(scratch.arena, BoxNode);
|
||||
n->box = g->root_box;
|
||||
StackPush(first_dfs, n);
|
||||
}
|
||||
while (first_dfs)
|
||||
{
|
||||
BoxNode *n = first_dfs;
|
||||
UI_Box *box = n->box;
|
||||
if (!n->visited)
|
||||
{
|
||||
/* Push children to dfs stack */
|
||||
for (UI_Box *child = box->last; child; child = child->prev)
|
||||
{
|
||||
BoxNode *child_n = PushStruct(scratch.arena, BoxNode);
|
||||
child_n->box = child;
|
||||
StackPush(first_dfs, child_n);
|
||||
}
|
||||
boxes_pre[pre_index++] = box;
|
||||
n->visited = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
StackPop(first_dfs);
|
||||
boxes_post[post_index++] = box;
|
||||
}
|
||||
}
|
||||
Assert(pre_index == boxes_count);
|
||||
Assert(post_index == boxes_count);
|
||||
}
|
||||
|
||||
/* Calculate independent sizes */
|
||||
for (u64 box_index = 1; box_index < boxes_count; ++box_index)
|
||||
{
|
||||
UI_Box *box = boxes_pre[box_index];
|
||||
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
|
||||
{
|
||||
UI_Size pref_size = box->pref_size[axis];
|
||||
if (pref_size.kind == UI_SizeKind_Absolute)
|
||||
{
|
||||
box->solved_size[axis].v = pref_size.v;
|
||||
}
|
||||
else if (pref_size.kind == UI_SizeKind_Text)
|
||||
{
|
||||
/* FIXME: Calculate actual text size here */
|
||||
f32 text_size = 10;
|
||||
box->solved_size[axis].v = text_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate upwards-dependent sizes */
|
||||
for (u64 box_index = 0; box_index < boxes_count; ++box_index)
|
||||
{
|
||||
UI_Box *box = boxes_pre[box_index];
|
||||
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
|
||||
{
|
||||
UI_Size pref_size = box->pref_size[axis];
|
||||
if (pref_size.kind == UI_SizeKind_Percent)
|
||||
{
|
||||
UI_Box *ancestor = box->parent;
|
||||
UI_Size ancestor_size = ZI;
|
||||
for (; ancestor; ancestor = ancestor->parent)
|
||||
{
|
||||
UI_Size tmp = ancestor->solved_size[axis];
|
||||
if (tmp.kind == UI_SizeKind_Absolute || tmp.kind == UI_SizeKind_Text)
|
||||
{
|
||||
ancestor_size = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// box->solved_size =
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Remove this */
|
||||
#if 0
|
||||
{
|
||||
Struct(BoxNode) { BoxNode *next; UI_Box *box; };
|
||||
|
||||
BoxNode *first_dfs = 0;
|
||||
BoxNode *first_dfs_reverse = 0;
|
||||
|
||||
/* Constrain layout downwards */
|
||||
UI_Box *box = g->root_box;
|
||||
while (box)
|
||||
{
|
||||
/* Push to reverse stack */
|
||||
{
|
||||
BoxNode *n = PushStruct(scratch.arena, BoxNode);
|
||||
n->box = box;
|
||||
StackPush(first_dfs_reverse, n);
|
||||
}
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
/* Push children to dfs stack (in reverse) */
|
||||
for (UI_Box *child = box->last; child; child = child->prev)
|
||||
{
|
||||
BoxNode *n = PushStruct(scratch.arena, BoxNode);
|
||||
n->box = child;
|
||||
StackPush(first_dfs, n);
|
||||
}
|
||||
/* Pop dfs stack */
|
||||
if (first_dfs)
|
||||
{
|
||||
box = first_dfs->box;
|
||||
StackPop(first_dfs);
|
||||
}
|
||||
else
|
||||
{
|
||||
box = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//- Build instances
|
||||
|
||||
GPU_QueueKind render_queue = GPU_QueueKind_Direct;
|
||||
Fence *render_fence = GPU_FenceFromQueue(render_queue);
|
||||
|
||||
/* TODO: Real size */
|
||||
Vec2I32 root_size = VEC2I32(500, 500);
|
||||
/* Init render state */
|
||||
if (!g->draw_rects_arena)
|
||||
{
|
||||
g->draw_rects_arena = AcquireArena(Gibi(64));
|
||||
}
|
||||
|
||||
/* Build rect instance data */
|
||||
for (u64 box_index = 0; box_index < boxes_count; ++box_index)
|
||||
{
|
||||
UI_Box *box = boxes_pre[box_index];
|
||||
UI_RectInstance *rect = PushStruct(g->draw_rects_arena, UI_RectInstance);
|
||||
|
||||
rect->p0 = box->p0;
|
||||
rect->p1 = box->p1;
|
||||
rect->tint_srgb = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//- Render
|
||||
|
||||
/* Acquire render target */
|
||||
if (f->render_target && !EqVec2I32(root_size, GPU_GetTextureSize2D(f->render_target)))
|
||||
if (g->render_target && !EqVec2I32(root_size, GPU_GetTextureSize2D(g->render_target)))
|
||||
{
|
||||
YieldOnFence(render_fence, f->render_fence_target);
|
||||
GPU_ReleaseResource(f->render_target, GPU_ReleaseFlag_None);
|
||||
f->render_target = 0;
|
||||
YieldOnFence(render_fence, g->render_fence_target);
|
||||
GPU_ReleaseResource(g->render_target, GPU_ReleaseFlag_None);
|
||||
g->render_target = 0;
|
||||
}
|
||||
if (!f->render_target)
|
||||
if (!g->render_target)
|
||||
{
|
||||
GPU_ResourceDesc desc = ZI;
|
||||
desc.kind = GPU_ResourceKind_Texture2D;
|
||||
desc.flags = GPU_ResourceFlag_Renderable;
|
||||
desc.texture.format = GPU_Format_R8G8B8A8_Unorm;
|
||||
desc.texture.size = VEC3I32(root_size.x, root_size.y, 1);
|
||||
f->render_target = GPU_AcquireResource(desc);
|
||||
g->render_target = GPU_AcquireResource(desc);
|
||||
}
|
||||
|
||||
/* Build command list */
|
||||
GPU_CommandList *cl = GPU_BeginCommandList(render_queue);
|
||||
{
|
||||
|
||||
}
|
||||
f->render_fence_target = GPU_EndCommandList(cl);
|
||||
g->render_fence_target = GPU_EndCommandList(cl);
|
||||
|
||||
return f->render_target;
|
||||
/* Reset render state */
|
||||
ResetArena(g->draw_rects_arena);
|
||||
|
||||
EndScratch(scratch);
|
||||
return g->render_target;
|
||||
}
|
||||
|
||||
48
src/ui/ui.h
48
src/ui/ui.h
@ -9,6 +9,23 @@ Struct(UI_Key)
|
||||
u64 hash;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Size types
|
||||
|
||||
Enum(UI_SizeKind)
|
||||
{
|
||||
UI_SizeKind_Children,
|
||||
UI_SizeKind_Percent,
|
||||
UI_SizeKind_Absolute,
|
||||
UI_SizeKind_Text,
|
||||
};
|
||||
|
||||
Struct(UI_Size)
|
||||
{
|
||||
UI_SizeKind kind;
|
||||
f32 v;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Box types
|
||||
|
||||
@ -21,20 +38,33 @@ Enum(UI_Flag)
|
||||
|
||||
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_Flag flags;
|
||||
|
||||
//- Per-build data
|
||||
UI_Flag flags;
|
||||
String display_text;
|
||||
GPU_Resource *display_image;
|
||||
UI_Size pref_size[Axis_CountXY];
|
||||
|
||||
//- Solver data
|
||||
UI_Size solved_size[Axis_CountXY];
|
||||
|
||||
//- Post-solve data
|
||||
Vec2 p0;
|
||||
Vec2 p1;
|
||||
};
|
||||
|
||||
Struct(UI_BoxBin)
|
||||
@ -54,7 +84,7 @@ Struct(UI_Parent) { UI_Parent *next; UI_Box *box; };
|
||||
|
||||
#define UI_NumBoxLookupBins 16384
|
||||
|
||||
Struct(UI_FiberState)
|
||||
Struct(UI_SharedState)
|
||||
{
|
||||
//- Build state
|
||||
Arena *build_arena;
|
||||
@ -66,6 +96,9 @@ Struct(UI_FiberState)
|
||||
UI_Box *root_box;
|
||||
UI_Box *back_root_box;
|
||||
|
||||
u64 boxes_count;
|
||||
u64 back_boxes_count;
|
||||
|
||||
//- Stack state
|
||||
UI_Tag *top_tag;
|
||||
UI_Parent *top_parent;
|
||||
@ -73,18 +106,9 @@ Struct(UI_FiberState)
|
||||
//- Render state
|
||||
GPU_Resource *render_target;
|
||||
i64 render_fence_target;
|
||||
};
|
||||
|
||||
Struct(UI_SharedState)
|
||||
{
|
||||
UI_FiberState *fiber_states[MaxFibers];
|
||||
Arena *draw_rects_arena;
|
||||
} extern UI_shared_state;
|
||||
|
||||
////////////////////////////////
|
||||
//~ State helpers
|
||||
|
||||
UI_FiberState *UI_GetFiberState(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
|
||||
@ -16,7 +16,9 @@ AssertRootConst(UI_RectSig, 20);
|
||||
|
||||
Struct(UI_RectInstance)
|
||||
{
|
||||
i32 _;
|
||||
Vec2 p0;
|
||||
Vec2 p1;
|
||||
u32 tint_srgb;
|
||||
};
|
||||
#define UI_DefaultRectInstance (UI_RectInstance) { \
|
||||
0 \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user