retain box state cache within ui core
This commit is contained in:
parent
ad56fafeff
commit
fbf7882db2
@ -277,7 +277,7 @@ Inline void RemoveDictEntry(Dict *dict, DictEntry *entry)
|
|||||||
dict->last = prev;
|
dict->last = prev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Insert into free list */
|
/* Add to free list */
|
||||||
{
|
{
|
||||||
entry->next = dict->first_free;
|
entry->next = dict->first_free;
|
||||||
dict->first_free = entry;
|
dict->first_free = entry;
|
||||||
|
|||||||
@ -31,42 +31,88 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc)
|
|||||||
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
|
GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size)
|
||||||
{
|
{
|
||||||
GC_Run result = Zi;
|
GC_Run result = Zi;
|
||||||
TempArena scratch = BeginScratch(arena);
|
if (str.len > 0)
|
||||||
Arena *perm = PermArena();
|
|
||||||
|
|
||||||
u64 codepoints_count = 0;
|
|
||||||
u32 *codepoints = 0;
|
|
||||||
{
|
{
|
||||||
String32 str32 = String32FromString(scratch.arena, str);
|
TempArena scratch = BeginScratch(arena);
|
||||||
codepoints_count = str32.len;
|
Arena *perm = PermArena();
|
||||||
codepoints = str32.text;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
u64 codepoints_count = 0;
|
||||||
//- Grab glyphs from cache
|
u32 *codepoints = 0;
|
||||||
|
|
||||||
u64 ready_glyphs_count = 0;
|
|
||||||
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count);
|
|
||||||
|
|
||||||
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
|
|
||||||
u64 uncached_codepoints_count = 0;
|
|
||||||
|
|
||||||
/* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */
|
|
||||||
u64 pending_glyphs_count = 0;
|
|
||||||
{
|
|
||||||
if (codepoints_count > 0)
|
|
||||||
{
|
{
|
||||||
Lock lock = LockS(&GC.glyphs_mutex);
|
String32 str32 = String32FromString(scratch.arena, str);
|
||||||
{
|
codepoints_count = str32.len;
|
||||||
i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
|
codepoints = str32.text;
|
||||||
for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
|
}
|
||||||
{
|
|
||||||
u32 codepoint = codepoints[codepoint_idx];
|
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Grab glyphs from cache
|
||||||
|
|
||||||
|
u64 ready_glyphs_count = 0;
|
||||||
|
GC_Glyph **ready_glyphs = PushStructsNoZero(scratch.arena, GC_Glyph *, codepoints_count);
|
||||||
|
|
||||||
|
u32 *uncached_codepoints = PushStructsNoZero(scratch.arena, u32, codepoints_count);
|
||||||
|
u64 uncached_codepoints_count = 0;
|
||||||
|
|
||||||
|
/* TODO: Include advances for glyphs in run that have rasterized but not finished uploading to atlas */
|
||||||
|
u64 pending_glyphs_count = 0;
|
||||||
|
{
|
||||||
|
if (codepoints_count > 0)
|
||||||
|
{
|
||||||
|
Lock lock = LockS(&GC.glyphs_mutex);
|
||||||
|
{
|
||||||
|
i64 completion = G_CompletionValueFromQueue(G_QueueKind_AsyncCopy);
|
||||||
|
for (u64 codepoint_idx = 0; codepoint_idx < codepoints_count; ++codepoint_idx)
|
||||||
|
{
|
||||||
|
u32 codepoint = codepoints[codepoint_idx];
|
||||||
|
|
||||||
|
GC_GlyphDesc desc = Zi;
|
||||||
|
desc.font = font;
|
||||||
|
desc.font_size = font_size;
|
||||||
|
desc.codepoint = codepoint;
|
||||||
|
|
||||||
|
u64 hash = GC_HashFromGlyphDesc(desc);
|
||||||
|
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
||||||
|
GC_Glyph *glyph = bin->first;
|
||||||
|
for (; glyph; glyph = glyph->next)
|
||||||
|
{
|
||||||
|
if (glyph->hash == hash) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glyph == 0)
|
||||||
|
{
|
||||||
|
uncached_codepoints[uncached_codepoints_count] = codepoint;
|
||||||
|
uncached_codepoints_count += 1;
|
||||||
|
}
|
||||||
|
else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target))
|
||||||
|
{
|
||||||
|
pending_glyphs_count += 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ready_glyphs[ready_glyphs_count] = glyph;
|
||||||
|
ready_glyphs_count += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Unlock(&lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Create cache entries
|
||||||
|
|
||||||
|
u64 submit_cmds_count = 0;
|
||||||
|
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
|
||||||
|
if (uncached_codepoints_count > 0)
|
||||||
|
{
|
||||||
|
Lock lock = LockE(&GC.glyphs_mutex);
|
||||||
|
{
|
||||||
|
for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx)
|
||||||
|
{
|
||||||
GC_GlyphDesc desc = Zi;
|
GC_GlyphDesc desc = Zi;
|
||||||
desc.font = font;
|
desc.font = font;
|
||||||
desc.font_size = font_size;
|
desc.font_size = font_size;
|
||||||
desc.codepoint = codepoint;
|
desc.codepoint = uncached_codepoints[uncached_codepoint_idx];
|
||||||
|
|
||||||
u64 hash = GC_HashFromGlyphDesc(desc);
|
u64 hash = GC_HashFromGlyphDesc(desc);
|
||||||
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
||||||
@ -78,140 +124,98 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
|
|||||||
|
|
||||||
if (glyph == 0)
|
if (glyph == 0)
|
||||||
{
|
{
|
||||||
uncached_codepoints[uncached_codepoints_count] = codepoint;
|
glyph = PushStruct(perm, GC_Glyph);
|
||||||
uncached_codepoints_count += 1;
|
glyph->desc = desc;
|
||||||
}
|
glyph->hash = hash;
|
||||||
else if (completion < Atomic64Fetch(&glyph->async_copy_completion_target))
|
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
|
||||||
{
|
SllStackPush(bin->first, glyph);
|
||||||
pending_glyphs_count += 1;
|
/* Create cmd */
|
||||||
}
|
{
|
||||||
else
|
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
|
||||||
{
|
cmd->glyph = glyph;
|
||||||
ready_glyphs[ready_glyphs_count] = glyph;
|
++submit_cmds_count;
|
||||||
ready_glyphs_count += 1;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Unlock(&lock);
|
Unlock(&lock);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Create cache entries
|
//- Submit cmds
|
||||||
|
|
||||||
u64 submit_cmds_count = 0;
|
if (submit_cmds_count > 0)
|
||||||
GC_Cmd *submit_cmds = PushStructsNoZero(scratch.arena, GC_Cmd, uncached_codepoints_count);
|
|
||||||
if (uncached_codepoints_count > 0)
|
|
||||||
{
|
|
||||||
Lock lock = LockE(&GC.glyphs_mutex);
|
|
||||||
{
|
{
|
||||||
for (u64 uncached_codepoint_idx = 0; uncached_codepoint_idx < uncached_codepoints_count; ++uncached_codepoint_idx)
|
Lock lock = LockE(&GC.submit.mutex);
|
||||||
|
for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx)
|
||||||
{
|
{
|
||||||
GC_GlyphDesc desc = Zi;
|
GC_Cmd *src = &submit_cmds[cmd_idx];
|
||||||
desc.font = font;
|
GC_CmdNode *n = GC.submit.first_free;
|
||||||
desc.font_size = font_size;
|
if (n)
|
||||||
desc.codepoint = uncached_codepoints[uncached_codepoint_idx];
|
|
||||||
|
|
||||||
u64 hash = GC_HashFromGlyphDesc(desc);
|
|
||||||
GC_GlyphBin *bin = &GC.glyph_bins[hash % countof(GC.glyph_bins)];
|
|
||||||
GC_Glyph *glyph = bin->first;
|
|
||||||
for (; glyph; glyph = glyph->next)
|
|
||||||
{
|
{
|
||||||
if (glyph->hash == hash) break;
|
SllStackPop(GC.submit.first_free);
|
||||||
|
ZeroStruct(n);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (glyph == 0)
|
|
||||||
{
|
{
|
||||||
glyph = PushStruct(perm, GC_Glyph);
|
n = PushStruct(perm, GC_CmdNode);
|
||||||
glyph->desc = desc;
|
|
||||||
glyph->hash = hash;
|
|
||||||
Atomic64FetchSet(&glyph->async_copy_completion_target, I64Max);
|
|
||||||
SllStackPush(bin->first, glyph);
|
|
||||||
/* Create cmd */
|
|
||||||
{
|
|
||||||
GC_Cmd *cmd = &submit_cmds[submit_cmds_count];
|
|
||||||
cmd->glyph = glyph;
|
|
||||||
++submit_cmds_count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
n->cmd = *src;
|
||||||
|
GC.submit.count += 1;
|
||||||
|
SllQueuePush(GC.submit.first, GC.submit.last, n);
|
||||||
}
|
}
|
||||||
|
Unlock(&lock);
|
||||||
|
SignalAsyncTick();
|
||||||
}
|
}
|
||||||
Unlock(&lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Submit cmds
|
//- Create run from glyphs
|
||||||
|
|
||||||
if (submit_cmds_count > 0)
|
f32 baseline_pos = 0;
|
||||||
{
|
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
|
||||||
Lock lock = LockE(&GC.submit.mutex);
|
result.rects_count = ready_glyphs_count;
|
||||||
for (u64 cmd_idx = 0; cmd_idx < submit_cmds_count; ++cmd_idx)
|
for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx)
|
||||||
{
|
{
|
||||||
GC_Cmd *src = &submit_cmds[cmd_idx];
|
GC_Glyph *glyph = ready_glyphs[glyph_idx];
|
||||||
GC_CmdNode *n = GC.submit.first_free;
|
GC_RunRect *rect = &result.rects[glyph_idx];
|
||||||
if (n)
|
|
||||||
|
rect->tex = glyph->atlas->tex_ref;
|
||||||
|
rect->tex_slice = glyph->tex_slice;
|
||||||
|
rect->tex_slice_uv = glyph->tex_slice_uv;
|
||||||
|
|
||||||
|
rect->baseline_pos = baseline_pos;
|
||||||
|
rect->advance = glyph->advance;
|
||||||
|
|
||||||
|
rect->bounds = glyph->bounds;
|
||||||
|
|
||||||
|
if (glyph_idx == 0)
|
||||||
{
|
{
|
||||||
SllStackPop(GC.submit.first_free);
|
result.bounds = rect->bounds;
|
||||||
ZeroStruct(n);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
n = PushStruct(perm, GC_CmdNode);
|
result.bounds = UnionRng2(result.bounds, rect->bounds);
|
||||||
}
|
}
|
||||||
n->cmd = *src;
|
|
||||||
GC.submit.count += 1;
|
baseline_pos += rect->advance;
|
||||||
SllQueuePush(GC.submit.first, GC.submit.last, n);
|
result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
|
||||||
}
|
}
|
||||||
Unlock(&lock);
|
|
||||||
SignalAsyncTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////
|
if (ready_glyphs_count > 0)
|
||||||
//- Create run from glyphs
|
|
||||||
|
|
||||||
f32 baseline_pos = 0;
|
|
||||||
result.rects = PushStructs(arena, GC_RunRect, ready_glyphs_count);
|
|
||||||
result.rects_count = ready_glyphs_count;
|
|
||||||
for (u64 glyph_idx = 0; glyph_idx < ready_glyphs_count; ++glyph_idx)
|
|
||||||
{
|
|
||||||
GC_Glyph *glyph = ready_glyphs[glyph_idx];
|
|
||||||
GC_RunRect *rect = &result.rects[glyph_idx];
|
|
||||||
|
|
||||||
rect->tex = glyph->atlas->tex_ref;
|
|
||||||
rect->tex_slice = glyph->tex_slice;
|
|
||||||
rect->tex_slice_uv = glyph->tex_slice_uv;
|
|
||||||
|
|
||||||
rect->baseline_pos = baseline_pos;
|
|
||||||
rect->advance = glyph->advance;
|
|
||||||
|
|
||||||
rect->bounds = glyph->bounds;
|
|
||||||
|
|
||||||
if (glyph_idx == 0)
|
|
||||||
{
|
{
|
||||||
result.bounds = rect->bounds;
|
GC_Glyph *glyph = ready_glyphs[0];
|
||||||
}
|
result.font_size = glyph->font_size;
|
||||||
else
|
result.font_ascent = glyph->font_ascent;
|
||||||
{
|
result.font_descent = glyph->font_descent;
|
||||||
result.bounds = UnionRng2(result.bounds, rect->bounds);
|
result.font_cap = glyph->font_cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseline_pos += rect->advance;
|
EndScratch(scratch);
|
||||||
result.baseline_length = MaxF32(result.baseline_length, baseline_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ready_glyphs_count > 0)
|
|
||||||
{
|
|
||||||
GC_Glyph *glyph = ready_glyphs[0];
|
|
||||||
result.font_size = glyph->font_size;
|
|
||||||
result.font_ascent = glyph->font_ascent;
|
|
||||||
result.font_descent = glyph->font_descent;
|
|
||||||
result.font_cap = glyph->font_cap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
|
// result.ready = uncached_codepoints_count == 0 && pending_glyphs_count == 0;
|
||||||
result.ready = 1;
|
result.ready = 1;
|
||||||
|
|
||||||
EndScratch(scratch);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -286,7 +286,7 @@ N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_
|
|||||||
/* FIXME: Ensure chunk_count > 0 */
|
/* FIXME: Ensure chunk_count > 0 */
|
||||||
ma->is_reliable = is_reliable;
|
ma->is_reliable = is_reliable;
|
||||||
|
|
||||||
/* Insert into channel list */
|
/* Add to channel list */
|
||||||
ma->touched_ns = now_ns;
|
ma->touched_ns = now_ns;
|
||||||
if (channel->most_recent_msg_assembler)
|
if (channel->most_recent_msg_assembler)
|
||||||
{
|
{
|
||||||
@ -299,7 +299,7 @@ N_MsgAssembler *N_AcquireMsgAssembler(N_Channel *channel, u64 msg_id, u64 chunk_
|
|||||||
}
|
}
|
||||||
channel->most_recent_msg_assembler = ma;
|
channel->most_recent_msg_assembler = ma;
|
||||||
|
|
||||||
/* Insert into lookup table */
|
/* Add to lookup table */
|
||||||
u64 hash = N_HashFromMsg(channel->id, msg_id);
|
u64 hash = N_HashFromMsg(channel->id, msg_id);
|
||||||
ma->hash = hash;
|
ma->hash = hash;
|
||||||
N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins];
|
N_MsgAssemblerLookupBin *bin = &host->msg_assembler_lookup_bins[hash % host->num_msg_assembler_lookup_bins];
|
||||||
|
|||||||
@ -19,7 +19,12 @@ void V_Shutdown(void)
|
|||||||
|
|
||||||
V_Frame *V_CurrentFrame(void)
|
V_Frame *V_CurrentFrame(void)
|
||||||
{
|
{
|
||||||
return &V.frames[V.current_frame_idx];
|
return &V.frames[V.current_frame_tick % countof(V.frames)];
|
||||||
|
}
|
||||||
|
|
||||||
|
V_Frame *V_LastFrame(void)
|
||||||
|
{
|
||||||
|
return &V.frames[(V.current_frame_tick - 1) % countof(V.frames)];
|
||||||
}
|
}
|
||||||
|
|
||||||
S_Cmd *V_PushSimCmd(S_CmdKind kind)
|
S_Cmd *V_PushSimCmd(S_CmdKind kind)
|
||||||
@ -421,19 +426,13 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
b32 shutdown = 0;
|
b32 shutdown = 0;
|
||||||
while (!shutdown)
|
while (!shutdown)
|
||||||
{
|
{
|
||||||
u64 last_frame_idx = V.current_frame_idx;
|
|
||||||
u64 frame_idx = last_frame_idx + 1;
|
|
||||||
if (frame_idx >= countof(V.frames))
|
|
||||||
{
|
|
||||||
frame_idx = 0;
|
|
||||||
}
|
|
||||||
V.current_frame_idx = frame_idx;
|
|
||||||
V_Frame *last_frame = &V.frames[last_frame_idx];
|
|
||||||
V_Frame *frame = &V.frames[frame_idx];
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Begin frame
|
//- Begin frame
|
||||||
|
|
||||||
|
V.current_frame_tick += 1;
|
||||||
|
V_Frame *last_frame = V_LastFrame();
|
||||||
|
V_Frame *frame = V_CurrentFrame();
|
||||||
|
|
||||||
{
|
{
|
||||||
Arena *old_arena = frame->arena;
|
Arena *old_arena = frame->arena;
|
||||||
Arena *old_dverts_arena = frame->dverts_arena;
|
Arena *old_dverts_arena = frame->dverts_arena;
|
||||||
@ -462,8 +461,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
frame->edit_camera_zoom = last_frame->edit_camera_zoom;
|
frame->edit_camera_zoom = last_frame->edit_camera_zoom;
|
||||||
frame->look = last_frame->look;
|
frame->look = last_frame->look;
|
||||||
|
|
||||||
|
frame->tick = V.current_frame_tick;
|
||||||
frame->time_ns = TimeNs();
|
frame->time_ns = TimeNs();
|
||||||
frame->tick = last_frame->tick + 1;
|
|
||||||
frame->dt_ns = frame->time_ns - last_frame->time_ns;
|
frame->dt_ns = frame->time_ns - last_frame->time_ns;
|
||||||
frame->dt = SecondsFromNs(frame->dt_ns);
|
frame->dt = SecondsFromNs(frame->dt_ns);
|
||||||
|
|
||||||
@ -790,20 +789,29 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
/* TODO: Remove this (testing) */
|
/* TODO: Remove this (testing) */
|
||||||
//- Init test layout
|
//- Init test layout
|
||||||
if (!V.root_space)
|
if (!V.root_panel)
|
||||||
{
|
{
|
||||||
V_Space *space = PushStruct(perm, V_Space);
|
{
|
||||||
space->axis = Axis_X;
|
V_Panel *panel = PushStruct(perm, V_Panel);
|
||||||
V.root_space = space;
|
panel->axis = Axis_X;
|
||||||
|
// panel->pref_size[Axis_X] = UI_PIX(frame->ui_dims.x, 0);
|
||||||
space->pref_size[Axis_X] = UI_GROW(1, 0);
|
// panel->pref_size[Axis_Y] = UI_PIX(frame->ui_dims.y, 0);
|
||||||
space->pref_size[Axis_Y] = UI_GROW(1, 0);
|
panel->key = UI_TransKey(); /* TODO: Don't use transient keys for panels */
|
||||||
|
panel->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||||
|
panel->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||||
|
panel->is_organizing_panel = 1;
|
||||||
|
V.root_panel = panel;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
V_Panel *panel = PushStruct(perm, V_Panel);
|
V_Panel *panel = PushStruct(perm, V_Panel);
|
||||||
panel->space = space;
|
panel->parent = V.root_panel;
|
||||||
DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space);
|
panel->axis = !panel->parent->axis;
|
||||||
++space->panels_count;
|
panel->key = UI_TransKey(); /* TODO: Don't use transient keys for panels */
|
||||||
|
panel->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||||
|
panel->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||||
|
DllQueuePush(panel->parent->first, panel->parent->last, panel);
|
||||||
|
++panel->parent->count;
|
||||||
|
|
||||||
{
|
{
|
||||||
V_Window *window = PushStruct(perm, V_Window);
|
V_Window *window = PushStruct(perm, V_Window);
|
||||||
@ -824,9 +832,13 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
{
|
{
|
||||||
V_Panel *panel = PushStruct(perm, V_Panel);
|
V_Panel *panel = PushStruct(perm, V_Panel);
|
||||||
panel->space = space;
|
panel->parent = V.root_panel;
|
||||||
DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space);
|
panel->axis = !panel->parent->axis;
|
||||||
++space->panels_count;
|
panel->key = UI_TransKey(); /* TODO: Don't use transient keys for panels */
|
||||||
|
panel->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||||
|
panel->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||||
|
DllQueuePush(panel->parent->first, panel->parent->last, panel);
|
||||||
|
++panel->parent->count;
|
||||||
|
|
||||||
{
|
{
|
||||||
V_Window *window = PushStruct(perm, V_Window);
|
V_Window *window = PushStruct(perm, V_Window);
|
||||||
@ -837,6 +849,29 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// {
|
||||||
|
// V_Space *space = PushStruct(perm, V_Space);
|
||||||
|
// space->parent = V.root_space;
|
||||||
|
// space->axis = !space->parent->axis;
|
||||||
|
// space->pref_size[Axis_X] = UI_GROW(1, 0);
|
||||||
|
// space->pref_size[Axis_Y] = UI_GROW(1, 0);
|
||||||
|
// DllQueuePush(space->parent->first, space->parent->last, space);
|
||||||
|
// ++space->parent->count;
|
||||||
|
|
||||||
|
// V_Panel *panel = PushStruct(perm, V_Panel);
|
||||||
|
// panel->space = space;
|
||||||
|
// DllQueuePushNP(space->first_panel, space->last_panel, panel, next_in_space, prev_in_space);
|
||||||
|
// ++space->panels_count;
|
||||||
|
|
||||||
|
// {
|
||||||
|
// V_Window *window = PushStruct(perm, V_Window);
|
||||||
|
// window->panel = panel;
|
||||||
|
// window->is_viewport_window = 1;
|
||||||
|
// DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel);
|
||||||
|
// ++panel->windows_count;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// V_Panel *panel = PushStruct(perm, V_Panel);
|
// V_Panel *panel = PushStruct(perm, V_Panel);
|
||||||
// panel->space = space;
|
// panel->space = space;
|
||||||
@ -855,55 +890,53 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
if (frame->is_editing)
|
if (frame->is_editing)
|
||||||
{
|
{
|
||||||
Struct(SpaceDfsNode) { SpaceDfsNode *next; b32 visited; V_Space *space; UI_Checkpoint cp; };
|
Struct(PanelDfsNode) { PanelDfsNode *next; b32 visited; V_Panel *panel; UI_Checkpoint cp; };
|
||||||
SpaceDfsNode *first_space_dfs = PushStruct(frame->arena, SpaceDfsNode);
|
PanelDfsNode *first_panel_dfs = PushStruct(frame->arena, PanelDfsNode);
|
||||||
first_space_dfs->space = V.root_space;
|
first_panel_dfs->panel = V.root_panel;
|
||||||
|
|
||||||
//- Iterate spaces
|
//- Iterate panels
|
||||||
while (first_space_dfs)
|
while (first_panel_dfs)
|
||||||
{
|
{
|
||||||
SpaceDfsNode *space_dfs = first_space_dfs;
|
PanelDfsNode *panel_dfs = first_panel_dfs;
|
||||||
V_Space *space = space_dfs->space;
|
V_Panel *panel = panel_dfs->panel;
|
||||||
if (!space_dfs->visited)
|
if (!panel_dfs->visited)
|
||||||
{
|
{
|
||||||
space_dfs->visited = 1;
|
panel_dfs->visited = 1;
|
||||||
for (V_Space *child = space->last; child; child = child->prev)
|
for (V_Panel *child = panel->last; child; child = child->prev)
|
||||||
{
|
{
|
||||||
SpaceDfsNode *n = PushStruct(frame->arena, SpaceDfsNode);
|
PanelDfsNode *n = PushStruct(frame->arena, PanelDfsNode);
|
||||||
n->space = child;
|
n->panel = child;
|
||||||
SllStackPush(first_space_dfs, n);
|
SllStackPush(first_panel_dfs, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_Key space_key = UI_TransKey();
|
UI_SetNext(Width, panel->pref_size[Axis_X]);
|
||||||
UI_SetNext(Width, space->pref_size[Axis_X]);
|
UI_SetNext(Height, panel->pref_size[Axis_Y]);
|
||||||
UI_SetNext(Width, space->pref_size[Axis_Y]);
|
if (panel->axis == Axis_X)
|
||||||
if (space->axis == Axis_X)
|
|
||||||
{
|
{
|
||||||
UI_BuildRowEx(space_key);
|
UI_BuildRowEx(panel->key);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UI_BuildColumnEx(space_key);
|
UI_BuildColumnEx(panel->key);
|
||||||
}
|
}
|
||||||
space_dfs->cp = UI_PushCP(space_key);
|
panel_dfs->cp = UI_PushCP(panel->key);
|
||||||
|
|
||||||
//- Build space panels
|
if (!panel->is_organizing_panel)
|
||||||
for (V_Panel *panel = space->first_panel; panel; panel = panel->next_in_space)
|
|
||||||
{
|
{
|
||||||
// UI_SetNext(Width, UI_SHRINK(0, 1));
|
// UI_SetNext(Width, UI_SHRINK(0, 1));
|
||||||
UI_SetNext(Width, UI_GROW(1, 0));
|
// UI_SetNext(Width, UI_GROW(1, 0));
|
||||||
UI_SetNext(Height, UI_GROW(1, 0));
|
// UI_SetNext(Height, UI_GROW(1, 0));
|
||||||
UI_PushCP(UI_BuildColumn());
|
UI_PushCP(UI_BuildColumn());
|
||||||
{
|
{
|
||||||
i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0));
|
i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0));
|
||||||
//- Build panel window tabs
|
//- Build window tabs
|
||||||
f32 tab_spacing = 10;
|
f32 tab_spacing = 10;
|
||||||
V_Window *active_window = 0;
|
V_Window *active_window = 0;
|
||||||
{
|
{
|
||||||
UI_SetNext(Width, UI_SHRINK(0, 0));
|
|
||||||
UI_SetNext(Height, UI_SHRINK(0, 0));
|
|
||||||
UI_PushCP(UI_BuildRow());
|
|
||||||
i64 window_idx = 0;
|
i64 window_idx = 0;
|
||||||
|
UI_SetNext(Width, UI_SHRINK(0, 1));
|
||||||
|
UI_SetNext(Height, UI_SHRINK(0, 1));
|
||||||
|
UI_PushCP(UI_BuildRow());
|
||||||
for (V_Window *window = panel->first_window; window; window = window->next_in_panel)
|
for (V_Window *window = panel->first_window; window; window = window->next_in_panel)
|
||||||
{
|
{
|
||||||
if (!window->is_viewport_window)
|
if (!window->is_viewport_window)
|
||||||
@ -920,8 +953,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
UI_SetNext(BackgroundColor, VEC4(0.2, 0.2, 0.2, 1));
|
UI_SetNext(BackgroundColor, VEC4(0.2, 0.2, 0.2, 1));
|
||||||
UI_SetNext(Border, 1);
|
UI_SetNext(Border, 1);
|
||||||
UI_SetNext(Width, UI_SHRINK(theme.text_padding_x, 0));
|
UI_SetNext(Width, UI_SHRINK(theme.text_padding_x, 1));
|
||||||
UI_SetNext(Height, UI_SHRINK(theme.text_padding_y, 0));
|
UI_SetNext(Height, UI_SHRINK(theme.text_padding_y, 1));
|
||||||
UI_SetNext(ChildAlignment, UI_Alignment_Center);
|
UI_SetNext(ChildAlignment, UI_Alignment_Center);
|
||||||
UI_PushCP(UI_BuildRow());
|
UI_PushCP(UI_BuildRow());
|
||||||
{
|
{
|
||||||
@ -940,7 +973,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
UI_PopCP(UI_TopCP());
|
UI_PopCP(UI_TopCP());
|
||||||
}
|
}
|
||||||
//- Build active panel active_window
|
//- Build active window
|
||||||
if (active_window && !active_window->is_viewport_window)
|
if (active_window && !active_window->is_viewport_window)
|
||||||
{
|
{
|
||||||
V_Window *window = active_window;
|
V_Window *window = active_window;
|
||||||
@ -968,13 +1001,24 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UI_PopCP(UI_TopCP());
|
UI_PopCP(UI_TopCP());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UI_PopCP(space_dfs->cp);
|
UI_PopCP(panel_dfs->cp);
|
||||||
SllStackPop(first_space_dfs);
|
SllStackPop(first_panel_dfs);
|
||||||
|
|
||||||
|
//- Build divider
|
||||||
|
if (panel->next != 0)
|
||||||
|
{
|
||||||
|
UI_Key divider_key = UI_TransKey();
|
||||||
|
UI_SetNext(BackgroundColor, Color_Cyan);
|
||||||
|
// UI_SetNext(Border, 2);
|
||||||
|
UI_SetNext(AxisSize, UI_GROW(1, 1), .axis = panel->axis);
|
||||||
|
UI_SetNext(AxisSize, UI_PIX(5, 1), .axis = !panel->axis);
|
||||||
|
/* FIXME: Non-transient key */
|
||||||
|
UI_BuildBoxEx(divider_key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -149,28 +149,21 @@ Struct(V_CommandsWidget)
|
|||||||
|
|
||||||
/* TODO: Move boolean fields into bitwise property flags */
|
/* TODO: Move boolean fields into bitwise property flags */
|
||||||
|
|
||||||
Struct(V_Space)
|
|
||||||
{
|
|
||||||
V_Space *parent;
|
|
||||||
V_Space *next;
|
|
||||||
V_Space *prev;
|
|
||||||
V_Space *first;
|
|
||||||
V_Space *last;
|
|
||||||
|
|
||||||
i64 panels_count;
|
|
||||||
struct V_Panel *first_panel;
|
|
||||||
struct V_Panel *last_panel;
|
|
||||||
|
|
||||||
UI_Size pref_size[Axis_CountXY];
|
|
||||||
|
|
||||||
Axis axis;
|
|
||||||
};
|
|
||||||
|
|
||||||
Struct(V_Panel)
|
Struct(V_Panel)
|
||||||
{
|
{
|
||||||
V_Space *space;
|
V_Panel *parent;
|
||||||
V_Panel *next_in_space;
|
V_Panel *next;
|
||||||
V_Panel *prev_in_space;
|
V_Panel *prev;
|
||||||
|
V_Panel *first;
|
||||||
|
V_Panel *last;
|
||||||
|
i64 count;
|
||||||
|
|
||||||
|
UI_Key key;
|
||||||
|
|
||||||
|
UI_Size pref_size[Axis_CountXY];
|
||||||
|
Axis axis;
|
||||||
|
|
||||||
|
b32 is_organizing_panel;
|
||||||
|
|
||||||
i64 active_window_idx;
|
i64 active_window_idx;
|
||||||
i64 windows_count;
|
i64 windows_count;
|
||||||
@ -277,12 +270,12 @@ Struct(V_Ctx)
|
|||||||
S_Lookup lookup;
|
S_Lookup lookup;
|
||||||
S_Key player_key;
|
S_Key player_key;
|
||||||
|
|
||||||
V_Space *root_space;
|
V_Panel *root_panel;
|
||||||
|
|
||||||
Atomic32 shutdown;
|
Atomic32 shutdown;
|
||||||
Fence shutdown_complete;
|
Fence shutdown_complete;
|
||||||
|
|
||||||
u64 current_frame_idx;
|
i64 current_frame_tick;
|
||||||
V_Frame frames[2];
|
V_Frame frames[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -298,6 +291,7 @@ void V_Shutdown(void);
|
|||||||
//~ Helpers
|
//~ Helpers
|
||||||
|
|
||||||
V_Frame *V_CurrentFrame(void);
|
V_Frame *V_CurrentFrame(void);
|
||||||
|
V_Frame *V_LastFrame(void);
|
||||||
S_Cmd *V_PushSimCmd(S_CmdKind kind);
|
S_Cmd *V_PushSimCmd(S_CmdKind kind);
|
||||||
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey);
|
String V_StringFromHotkey(Arena *arena, V_Hotkey hotkey);
|
||||||
|
|
||||||
|
|||||||
499
src/ui/ui_core.c
499
src/ui/ui_core.c
@ -1,4 +1,4 @@
|
|||||||
UI_State UI_state = Zi;
|
UI_Ctx UI = Zi;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Bootstrap
|
//~ Bootstrap
|
||||||
@ -18,6 +18,11 @@ GC_FontKey UI_GetDefaultFont(void)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Key helpers
|
//~ Key helpers
|
||||||
|
|
||||||
|
b32 UI_MatchKey(UI_Key a, UI_Key b)
|
||||||
|
{
|
||||||
|
return a.hash == b.hash;
|
||||||
|
}
|
||||||
|
|
||||||
UI_Key UI_KeyFromString(String str)
|
UI_Key UI_KeyFromString(String str)
|
||||||
{
|
{
|
||||||
u64 top_tag = UI_UseTop(Tag);
|
u64 top_tag = UI_UseTop(Tag);
|
||||||
@ -43,8 +48,7 @@ UI_Key UI_KeyF_(String fmt, ...)
|
|||||||
|
|
||||||
UI_Key UI_TransKey(void)
|
UI_Key UI_TransKey(void)
|
||||||
{
|
{
|
||||||
UI_Frame *frame = UI_CurrentFrame();
|
u64 seed = ++UI.transient_key_seed;
|
||||||
u64 seed = ++frame->transient_key_seed;
|
|
||||||
UI_Key key = Zi;
|
UI_Key key = Zi;
|
||||||
key.hash = RandU64FromSeed(seed);
|
key.hash = RandU64FromSeed(seed);
|
||||||
return key;
|
return key;
|
||||||
@ -52,16 +56,14 @@ UI_Key UI_TransKey(void)
|
|||||||
|
|
||||||
UI_Box *UI_BoxFromKey(UI_Key key)
|
UI_Box *UI_BoxFromKey(UI_Key key)
|
||||||
{
|
{
|
||||||
UI_State *g = &UI_state;
|
|
||||||
UI_Box *box = 0;
|
UI_Box *box = 0;
|
||||||
if (key.hash != 0)
|
if (key.hash != 0)
|
||||||
{
|
{
|
||||||
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
|
UI_BoxBin *bin = &UI.box_bins[key.hash % countof(UI.box_bins)];
|
||||||
for (UI_Box *tmp = bin->first; tmp; tmp = tmp->next_in_bin)
|
for (box = bin->first; box; box = box->next_in_bin)
|
||||||
{
|
{
|
||||||
if (tmp->key.hash == key.hash)
|
if (UI_MatchKey(box->key, key))
|
||||||
{
|
{
|
||||||
box = tmp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,6 +71,105 @@ UI_Box *UI_BoxFromKey(UI_Key key)
|
|||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Iteration helpers
|
||||||
|
|
||||||
|
UI_BoxIterResult UI_FirstBox(Arena *arena, UI_BoxIter *iter, UI_Key start_key)
|
||||||
|
{
|
||||||
|
/* Free old stack */
|
||||||
|
if (iter->first)
|
||||||
|
{
|
||||||
|
if (iter->last_free)
|
||||||
|
{
|
||||||
|
iter->last_free->next = iter->first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
iter->first_free = iter->first;
|
||||||
|
}
|
||||||
|
iter->last_free = iter->first;
|
||||||
|
iter->first = 0;
|
||||||
|
}
|
||||||
|
/* Create root dfs node */
|
||||||
|
UI_BoxIterDfsNode *dfs = iter->first_free;
|
||||||
|
if (dfs)
|
||||||
|
{
|
||||||
|
SllQueuePop(iter->first_free, iter->last_free);
|
||||||
|
ZeroStruct(dfs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dfs = PushStruct(arena, UI_BoxIterDfsNode);
|
||||||
|
}
|
||||||
|
dfs->box = UI_BoxFromKey(start_key);
|
||||||
|
iter->first = dfs;
|
||||||
|
return UI_NextBox(arena, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter)
|
||||||
|
{
|
||||||
|
UI_BoxIterResult result = Zi;
|
||||||
|
if (iter->first)
|
||||||
|
{
|
||||||
|
UI_BoxIterDfsNode *dfs = iter->first;
|
||||||
|
UI_Box *box = dfs->box;
|
||||||
|
if (!dfs->visited)
|
||||||
|
{
|
||||||
|
/* Pre order */
|
||||||
|
dfs->visited = 1;
|
||||||
|
result.box = box;
|
||||||
|
result.pre = 1;
|
||||||
|
/* Push floating children to dfs stack */
|
||||||
|
for (UI_Box *child = box->last; child; child = child->prev)
|
||||||
|
{
|
||||||
|
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||||
|
{
|
||||||
|
UI_BoxIterDfsNode *child_dfs = iter->first_free;
|
||||||
|
if (child_dfs)
|
||||||
|
{
|
||||||
|
SllQueuePop(iter->first_free, iter->last_free);
|
||||||
|
ZeroStruct(child_dfs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child_dfs = PushStruct(arena, UI_BoxIterDfsNode);
|
||||||
|
}
|
||||||
|
child_dfs->box = child;
|
||||||
|
SllStackPush(iter->first, child_dfs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Push non-floating children to dfs stack */
|
||||||
|
for (UI_Box *child = box->last; child; child = child->prev)
|
||||||
|
{
|
||||||
|
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||||
|
{
|
||||||
|
UI_BoxIterDfsNode *child_dfs = iter->first_free;
|
||||||
|
if (child_dfs)
|
||||||
|
{
|
||||||
|
SllQueuePop(iter->first_free, iter->last_free);
|
||||||
|
ZeroStruct(child_dfs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child_dfs = PushStruct(arena, UI_BoxIterDfsNode);
|
||||||
|
}
|
||||||
|
child_dfs->box = child;
|
||||||
|
SllStackPush(iter->first, child_dfs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Post order */
|
||||||
|
result.box = box;
|
||||||
|
result.pre = 0;
|
||||||
|
SllStackPop(iter->first);
|
||||||
|
SllQueuePush(iter->first_free, iter->last_free, dfs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ String helpers
|
//~ String helpers
|
||||||
|
|
||||||
@ -410,7 +511,6 @@ UI_Key UI_BuildBoxEx(UI_Key key)
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
|
void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
|
||||||
{
|
{
|
||||||
UI_Frame *frame = UI_CurrentFrame();
|
UI_Frame *frame = UI_CurrentFrame();
|
||||||
@ -430,7 +530,6 @@ void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv)
|
|||||||
|
|
||||||
UI_Report UI_ReportFromKey(UI_Key key)
|
UI_Report UI_ReportFromKey(UI_Key key)
|
||||||
{
|
{
|
||||||
UI_State *g = &UI_state;
|
|
||||||
UI_Report result = Zi;
|
UI_Report result = Zi;
|
||||||
|
|
||||||
UI_Box *box = UI_BoxFromKey(key);
|
UI_Box *box = UI_BoxFromKey(key);
|
||||||
@ -447,38 +546,39 @@ UI_Report UI_ReportFromKey(UI_Key key)
|
|||||||
|
|
||||||
UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
||||||
{
|
{
|
||||||
UI_State *g = &UI_state;
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Init persistent state
|
//- Init persistent state
|
||||||
|
|
||||||
if (!g->box_arena)
|
if (!UI.box_arena)
|
||||||
{
|
{
|
||||||
g->box_arena = AcquireArena(Gibi(64));
|
UI.box_arena = AcquireArena(Gibi(64));
|
||||||
g->box_bins = PushStructs(g->box_arena, UI_BoxBin, UI_NumBoxLookupBins);
|
/* Init frames */
|
||||||
|
for (u64 i = 0; i < countof(UI.frames); ++i)
|
||||||
for (u64 i = 0; i < countof(g->frames); ++i)
|
|
||||||
{
|
{
|
||||||
UI_Frame *frame = &g->frames[i];
|
UI_Frame *frame = &UI.frames[i];
|
||||||
frame->arena = AcquireArena(Gibi(64));
|
frame->arena = AcquireArena(Gibi(64));
|
||||||
frame->rects_arena = AcquireArena(Gibi(64));
|
frame->rects_arena = AcquireArena(Gibi(64));
|
||||||
frame->gpu_arena = G_AcquireArena();
|
frame->gpu_arena = G_AcquireArena();
|
||||||
}
|
}
|
||||||
|
/* Init root box */
|
||||||
|
{
|
||||||
|
UI_Box *box = PushStruct(UI.box_arena, UI_Box);
|
||||||
|
box->key = UI_RootKey;
|
||||||
|
UI.boxes_count += 1;
|
||||||
|
UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)];
|
||||||
|
bin->first = box;
|
||||||
|
bin->last = box;
|
||||||
|
UI.root_box = box;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Begin frame
|
//- Begin frame
|
||||||
|
|
||||||
u64 last_frame_idx = g->current_frame_idx;
|
UI.current_frame_tick += 1;
|
||||||
u64 frame_idx = last_frame_idx + 1;
|
UI_Frame *last_frame = UI_LastFrame();
|
||||||
if (frame_idx >= countof(g->frames))
|
UI_Frame *frame = UI_CurrentFrame();
|
||||||
{
|
|
||||||
frame_idx = 0;
|
|
||||||
}
|
|
||||||
g->current_frame_idx = frame_idx;
|
|
||||||
|
|
||||||
UI_Frame *last_frame = &g->frames[last_frame_idx];
|
|
||||||
UI_Frame *frame = &g->frames[frame_idx];
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Arena *old_arena = frame->arena;
|
Arena *old_arena = frame->arena;
|
||||||
@ -500,7 +600,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
|||||||
i64 dt_ns = now_ns - last_frame->time_ns;
|
i64 dt_ns = now_ns - last_frame->time_ns;
|
||||||
frame->time_ns = now_ns;
|
frame->time_ns = now_ns;
|
||||||
frame->dt_ns = dt_ns;
|
frame->dt_ns = dt_ns;
|
||||||
frame->tick = last_frame->tick + 1;
|
frame->tick = UI.current_frame_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init style stack */
|
/* Init style stack */
|
||||||
@ -538,7 +638,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Init box reports */
|
/* Init box reports */
|
||||||
for (u64 pre_index = g->boxes_count; pre_index-- > 0;)
|
for (u64 pre_index = UI.boxes_count; pre_index-- > 0;)
|
||||||
{
|
{
|
||||||
UI_Box *box = last_frame->boxes_pre[pre_index];
|
UI_Box *box = last_frame->boxes_pre[pre_index];
|
||||||
if (hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable)
|
if (hovered_box == 0 && box->desc.flags & UI_BoxFlag_Interactable)
|
||||||
@ -627,7 +727,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update box hot & active states */
|
/* Update box hot & active states */
|
||||||
for (u64 pre_index = 0; pre_index < g->boxes_count; ++pre_index)
|
for (u64 pre_index = 0; pre_index < UI.boxes_count; ++pre_index)
|
||||||
{
|
{
|
||||||
UI_Box *box = last_frame->boxes_pre[pre_index];
|
UI_Box *box = last_frame->boxes_pre[pre_index];
|
||||||
UI_Report *report = &box->report;
|
UI_Report *report = &box->report;
|
||||||
@ -666,8 +766,12 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
|
|||||||
|
|
||||||
UI_Frame *UI_CurrentFrame(void)
|
UI_Frame *UI_CurrentFrame(void)
|
||||||
{
|
{
|
||||||
UI_State *g = &UI_state;
|
return &UI.frames[UI.current_frame_tick % countof(UI.frames)];
|
||||||
return &g->frames[g->current_frame_idx];
|
};
|
||||||
|
|
||||||
|
UI_Frame *UI_LastFrame(void)
|
||||||
|
{
|
||||||
|
return &UI.frames[(UI.current_frame_tick - 1) % countof(UI.frames)];
|
||||||
};
|
};
|
||||||
|
|
||||||
Arena *UI_FrameArena(void)
|
Arena *UI_FrameArena(void)
|
||||||
@ -686,7 +790,7 @@ Vec2 UI_CursorPos(void)
|
|||||||
void UI_EndFrame(UI_Frame *frame)
|
void UI_EndFrame(UI_Frame *frame)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
UI_State *g = &UI_state;
|
UI_BoxIter box_iter = Zi;
|
||||||
|
|
||||||
Vec2I32 monitor_size = frame->window_frame.monitor_size;
|
Vec2I32 monitor_size = frame->window_frame.monitor_size;
|
||||||
Rng3 monitor_viewport = RNG3(VEC3(0, 0, 0), VEC3(monitor_size.x, monitor_size.y, 1));
|
Rng3 monitor_viewport = RNG3(VEC3(0, 0, 0), VEC3(monitor_size.x, monitor_size.y, 1));
|
||||||
@ -699,184 +803,197 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Process commands
|
//- Process commands
|
||||||
|
|
||||||
g->boxes_count = 0;
|
|
||||||
|
|
||||||
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
|
||||||
{
|
{
|
||||||
UI_Cmd cmd = cmd_node->cmd;
|
//////////////////////////////
|
||||||
|
//- Create boxes from build cmds
|
||||||
|
|
||||||
switch (cmd.kind)
|
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||||
{
|
{
|
||||||
case UI_CmdKind_BuildBox:
|
UI_Cmd cmd = cmd_node->cmd;
|
||||||
|
if (cmd.kind == UI_CmdKind_BuildBox)
|
||||||
{
|
{
|
||||||
UI_Key key = cmd.box.key;
|
UI_Key key = cmd.box.key;
|
||||||
if (key.hash == 0)
|
|
||||||
{
|
|
||||||
key = UI_TransKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
b32 is_root = frame->root_box == 0;
|
|
||||||
UI_Box *parent = 0;
|
|
||||||
if (!is_root)
|
|
||||||
{
|
|
||||||
parent = UI_BoxFromKey(cmd.box.parent);
|
|
||||||
if (!parent)
|
|
||||||
{
|
|
||||||
parent = frame->root_box;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate box */
|
|
||||||
UI_Box *box = 0;
|
UI_Box *box = 0;
|
||||||
{
|
{
|
||||||
UI_BoxBin *bin = &g->box_bins[key.hash % UI_NumBoxLookupBins];
|
UI_BoxBin *bin = &UI.box_bins[key.hash % countof(UI.box_bins)];
|
||||||
for (UI_Box *tmp = bin->first; tmp && !box; tmp = tmp->next_in_bin)
|
for (box = bin->first; box; box = box->next_in_bin)
|
||||||
{
|
{
|
||||||
if (tmp->key.hash == key.hash)
|
if (UI_MatchKey(box->key, key))
|
||||||
{
|
{
|
||||||
box = tmp;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (box)
|
/* Allocate new box */
|
||||||
|
if (box == 0)
|
||||||
{
|
{
|
||||||
/* Remove box from old parent */
|
/* Allocate new box */
|
||||||
if (box->parent)
|
box = UI.first_free_box;
|
||||||
{
|
|
||||||
DllQueueRemove(box->parent->first, box->parent->last, box);
|
|
||||||
--box->parent->count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
box = g->first_free_box;
|
|
||||||
if (box)
|
if (box)
|
||||||
{
|
{
|
||||||
SllStackPop(g->first_free_box);
|
SllStackPop(UI.first_free_box);
|
||||||
ZeroStruct(box);
|
ZeroStruct(box);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
box = PushStruct(g->box_arena, UI_Box);
|
box = PushStruct(UI.box_arena, UI_Box);
|
||||||
}
|
}
|
||||||
|
box->key = key;
|
||||||
DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
||||||
|
++UI.boxes_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++g->boxes_count;
|
box->last_build_tick = frame->tick;
|
||||||
|
}
|
||||||
/* 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 = frame->tick;
|
|
||||||
|
|
||||||
/* Update box */
|
|
||||||
{
|
|
||||||
box->desc = cmd.box;
|
|
||||||
|
|
||||||
/* Insert box into parent */
|
|
||||||
if (parent)
|
|
||||||
{
|
|
||||||
DllQueuePush(parent->first, parent->last, box);
|
|
||||||
box->parent = parent;
|
|
||||||
++parent->count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fetch run */
|
|
||||||
if (box->desc.text.len > 0)
|
|
||||||
{
|
|
||||||
box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_root)
|
|
||||||
{
|
|
||||||
frame->root_box = box;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case UI_CmdKind_SetRawTexture:
|
|
||||||
{
|
|
||||||
UI_Key key = cmd.set_raw_texture.key;
|
|
||||||
UI_Box *box = UI_BoxFromKey(key);
|
|
||||||
if (box)
|
|
||||||
{
|
|
||||||
box->raw_texture = cmd.set_raw_texture.tex;
|
|
||||||
box->raw_texture_slice_uv = cmd.set_raw_texture.slice_uv;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
//- Update boxes from cmds
|
||||||
|
|
||||||
|
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||||
|
{
|
||||||
|
UI_Cmd cmd = cmd_node->cmd;
|
||||||
|
|
||||||
|
switch (cmd.kind)
|
||||||
|
{
|
||||||
|
case UI_CmdKind_BuildBox:
|
||||||
|
{
|
||||||
|
UI_Key key = cmd.box.key;
|
||||||
|
if (UI_MatchKey(key, UI_NilKey))
|
||||||
|
{
|
||||||
|
key = UI_TransKey();
|
||||||
|
}
|
||||||
|
UI_Box *box = UI_BoxFromKey(key);
|
||||||
|
|
||||||
|
UI_Box *parent = 0;
|
||||||
|
if (box != UI.root_box)
|
||||||
|
{
|
||||||
|
parent = UI_BoxFromKey(cmd.box.parent);
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
parent = UI.root_box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update parent */
|
||||||
|
if (box->parent != parent)
|
||||||
|
{
|
||||||
|
if (box->parent)
|
||||||
|
{
|
||||||
|
/* Remove from old parent */
|
||||||
|
DllQueueRemove(box->parent->first, box->parent->last, box);
|
||||||
|
--box->parent->count;
|
||||||
|
}
|
||||||
|
if (parent)
|
||||||
|
{
|
||||||
|
/* Add to new parent */
|
||||||
|
DllQueuePush(parent->first, parent->last, box);
|
||||||
|
++parent->count;
|
||||||
|
}
|
||||||
|
box->parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update box */
|
||||||
|
{
|
||||||
|
box->desc = cmd.box;
|
||||||
|
box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case UI_CmdKind_SetRawTexture:
|
||||||
|
{
|
||||||
|
UI_Key key = cmd.set_raw_texture.key;
|
||||||
|
UI_Box *box = UI_BoxFromKey(key);
|
||||||
|
if (box)
|
||||||
|
{
|
||||||
|
box->raw_texture = cmd.set_raw_texture.tex;
|
||||||
|
box->raw_texture_slice_uv = cmd.set_raw_texture.slice_uv;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Prune boxes
|
//- Prune cached boxes
|
||||||
|
|
||||||
// {
|
{
|
||||||
// u64 cur_tick = frame->tick;
|
u64 prunes_count = 0;
|
||||||
// UI_BoxIter it = UI_ITER(g->root_box);
|
UI_Box **prunes = PushStructsNoZero(scratch.arena, UI_Box *, UI.boxes_count);
|
||||||
// UI_Box *box = UI_NextBox(&it);
|
for (UI_BoxIterResult ir = UI_FirstBox(scratch.arena, &box_iter, UI_RootKey); ir.box; ir = UI_NextBox(scratch.arena, &box_iter))
|
||||||
// while (box != 0)
|
{
|
||||||
// {
|
if (ir.pre)
|
||||||
// UI_Box *next = UI_NextBox(&it);
|
{
|
||||||
// box = next;
|
UI_Box *box = ir.box;
|
||||||
// }
|
if (box->last_build_tick < frame->tick)
|
||||||
// }
|
{
|
||||||
|
prunes[prunes_count++] = box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (u64 prune_idx = 0; prune_idx < prunes_count; ++prune_idx)
|
||||||
|
{
|
||||||
|
UI_Box *box = prunes[prune_idx];
|
||||||
|
UI_Box *parent = box->parent;
|
||||||
|
UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)];
|
||||||
|
/* Re-parent children */
|
||||||
|
if (box->first)
|
||||||
|
{
|
||||||
|
for (UI_Box *child = box->first; child; child = child->next)
|
||||||
|
{
|
||||||
|
child->parent = parent;
|
||||||
|
}
|
||||||
|
if (parent->last)
|
||||||
|
{
|
||||||
|
parent->last->next = box->first;
|
||||||
|
box->first->prev = parent->last;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent->first = box->first;
|
||||||
|
}
|
||||||
|
parent->last = box->last;
|
||||||
|
parent->count += box->count;
|
||||||
|
}
|
||||||
|
/* Remove from parent */
|
||||||
|
DllQueueRemove(parent->first, parent->last, box);
|
||||||
|
--parent->count;
|
||||||
|
/* Remove from lookup table */
|
||||||
|
DllQueueRemoveNP(bin->first, bin->last, box, next_in_bin, prev_in_bin);
|
||||||
|
/* Add to free list */
|
||||||
|
SllStackPush(UI.first_free_box, box);
|
||||||
|
--UI.boxes_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Layout
|
//- Layout
|
||||||
|
|
||||||
/* Build pre-order & post-order box arrays */
|
/* Prepare layout data */
|
||||||
u64 boxes_count = g->boxes_count;
|
u64 boxes_count = UI.boxes_count;
|
||||||
UI_Box **boxes_pre = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
UI_Box **boxes_pre = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
||||||
UI_Box **boxes_post = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
UI_Box **boxes_post = PushStructsNoZero(frame->arena, UI_Box *, boxes_count);
|
||||||
frame->boxes_pre = boxes_pre;
|
frame->boxes_pre = boxes_pre;
|
||||||
frame->boxes_post = boxes_post;
|
frame->boxes_post = boxes_post;
|
||||||
{
|
{
|
||||||
Struct(BoxNode) { BoxNode *next; b32 visited; UI_Box *box; };
|
|
||||||
BoxNode *first_dfs = PushStruct(scratch.arena, BoxNode);
|
|
||||||
u64 pre_index = 0;
|
u64 pre_index = 0;
|
||||||
u64 post_index = 0;
|
u64 post_index = 0;
|
||||||
first_dfs->box = frame->root_box;
|
for (UI_BoxIterResult ir = UI_FirstBox(scratch.arena, &box_iter, UI_RootKey); ir.box; ir = UI_NextBox(scratch.arena, &box_iter))
|
||||||
while (first_dfs)
|
|
||||||
{
|
{
|
||||||
BoxNode *n = first_dfs;
|
UI_Box *box = ir.box;
|
||||||
UI_Box *box = n->box;
|
if (ir.pre)
|
||||||
if (!n->visited)
|
|
||||||
{
|
{
|
||||||
/* Push floating children to dfs stack */
|
box->pre_index = pre_index;
|
||||||
for (UI_Box *child = box->last; child; child = child->prev)
|
boxes_pre[pre_index] = box;
|
||||||
{
|
pre_index += 1;
|
||||||
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
|
||||||
{
|
/* Reset layout data */
|
||||||
BoxNode *child_n = PushStruct(scratch.arena, BoxNode);
|
ZeroStruct(&box->layout);
|
||||||
child_n->box = child;
|
|
||||||
SllStackPush(first_dfs, child_n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Push non-floating children to dfs stack */
|
|
||||||
for (UI_Box *child = box->last; child; child = child->prev)
|
|
||||||
{
|
|
||||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
|
||||||
{
|
|
||||||
BoxNode *child_n = PushStruct(scratch.arena, BoxNode);
|
|
||||||
child_n->box = child;
|
|
||||||
SllStackPush(first_dfs, child_n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
box->pre_index = pre_index++;
|
|
||||||
boxes_pre[box->pre_index] = box;
|
|
||||||
n->visited = 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SllStackPop(first_dfs);
|
box->post_index = post_index;
|
||||||
box->post_index = post_index++;
|
boxes_post[post_index] = box;
|
||||||
boxes_post[box->post_index] = box;
|
post_index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Assert(pre_index == boxes_count);
|
Assert(pre_index == boxes_count);
|
||||||
@ -892,7 +1009,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
UI_Size pref_size = box->desc.pref_size[axis];
|
UI_Size pref_size = box->desc.pref_size[axis];
|
||||||
if (pref_size.kind == UI_SizeKind_Pixel)
|
if (pref_size.kind == UI_SizeKind_Pixel)
|
||||||
{
|
{
|
||||||
box->solved_dims[axis] = pref_size.v;
|
box->layout.solved_dims[axis] = pref_size.v;
|
||||||
}
|
}
|
||||||
else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
|
else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
|
||||||
{
|
{
|
||||||
@ -906,7 +1023,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
{
|
{
|
||||||
text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent;
|
text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent;
|
||||||
}
|
}
|
||||||
box->solved_dims[axis] = text_size + (pref_size.v * 2);
|
box->layout.solved_dims[axis] = text_size + (pref_size.v * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -929,11 +1046,11 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)))
|
if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)))
|
||||||
{
|
{
|
||||||
/* Match independent ancestor */
|
/* Match independent ancestor */
|
||||||
match_size = ancestor->solved_dims[axis];
|
match_size = ancestor->layout.solved_dims[axis];
|
||||||
found_match = 1;
|
found_match = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
box->solved_dims[axis] = match_size * pref_size.v;
|
box->layout.solved_dims[axis] = match_size * pref_size.v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -954,15 +1071,15 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
{
|
{
|
||||||
if (axis == box->desc.child_layout_axis)
|
if (axis == box->desc.child_layout_axis)
|
||||||
{
|
{
|
||||||
accum += child->solved_dims[axis];
|
accum += child->layout.solved_dims[axis];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
accum = MaxF32(child->solved_dims[axis], accum);
|
accum = MaxF32(child->layout.solved_dims[axis], accum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
box->solved_dims[axis] = accum + (pref_size.v * 2);
|
box->layout.solved_dims[axis] = accum + (pref_size.v * 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -977,7 +1094,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
UI_Size pref_size = box->desc.pref_size[axis];
|
UI_Size pref_size = box->desc.pref_size[axis];
|
||||||
if (pref_size.kind == UI_SizeKind_Grow)
|
if (pref_size.kind == UI_SizeKind_Grow)
|
||||||
{
|
{
|
||||||
box->solved_dims[axis] = box->parent->solved_dims[axis] * pref_size.v;
|
box->layout.solved_dims[axis] = box->parent->layout.solved_dims[axis] * pref_size.v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -988,7 +1105,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
UI_Box *box = boxes_pre[pre_index];
|
UI_Box *box = boxes_pre[pre_index];
|
||||||
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
|
for (Axis axis = 0; axis < Axis_CountXY; ++axis)
|
||||||
{
|
{
|
||||||
f32 box_size = box->solved_dims[axis];
|
f32 box_size = box->layout.solved_dims[axis];
|
||||||
/* Solve non-floating violations */
|
/* Solve non-floating violations */
|
||||||
{
|
{
|
||||||
f32 size_accum = 0;
|
f32 size_accum = 0;
|
||||||
@ -997,7 +1114,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
{
|
{
|
||||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||||
{
|
{
|
||||||
f32 size = child->solved_dims[axis];
|
f32 size = child->layout.solved_dims[axis];
|
||||||
f32 strictness = child->desc.pref_size[axis].strictness;
|
f32 strictness = child->desc.pref_size[axis].strictness;
|
||||||
f32 flex = size * (1.0 - strictness);
|
f32 flex = size * (1.0 - strictness);
|
||||||
if (axis == box->desc.child_layout_axis)
|
if (axis == box->desc.child_layout_axis)
|
||||||
@ -1020,7 +1137,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
{
|
{
|
||||||
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating))
|
||||||
{
|
{
|
||||||
f32 size = child->solved_dims[axis];
|
f32 size = child->layout.solved_dims[axis];
|
||||||
f32 strictness = child->desc.pref_size[axis].strictness;
|
f32 strictness = child->desc.pref_size[axis].strictness;
|
||||||
f32 flex = size * (1.0 - strictness);
|
f32 flex = size * (1.0 - strictness);
|
||||||
f32 new_size = size;
|
f32 new_size = size;
|
||||||
@ -1037,24 +1154,24 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
adjusted_size_accum += new_size;
|
adjusted_size_accum += new_size;
|
||||||
child->solved_dims[axis] = new_size;
|
child->layout.solved_dims[axis] = new_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_accum = adjusted_size_accum;
|
size_accum = adjusted_size_accum;
|
||||||
}
|
}
|
||||||
box->final_children_size_accum[axis] = size_accum;
|
box->layout.final_children_size_accum[axis] = size_accum;
|
||||||
}
|
}
|
||||||
/* Solve floating violations */
|
/* Solve floating violations */
|
||||||
for (UI_Box *child = box->first; child; child = child->next)
|
for (UI_Box *child = box->first; child; child = child->next)
|
||||||
{
|
{
|
||||||
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp))
|
if (AnyBit(child->desc.flags, UI_BoxFlag_Floating) && !AnyBit(child->desc.flags, UI_BoxFlag_NoFloatingClamp))
|
||||||
{
|
{
|
||||||
f32 size = child->solved_dims[axis];
|
f32 size = child->layout.solved_dims[axis];
|
||||||
if (size > box_size)
|
if (size > box_size)
|
||||||
{
|
{
|
||||||
f32 strictness = child->desc.pref_size[axis].strictness;
|
f32 strictness = child->desc.pref_size[axis].strictness;
|
||||||
f32 flex = size * (1.0 - strictness);
|
f32 flex = size * (1.0 - strictness);
|
||||||
child->solved_dims[axis] = MaxF32(size - flex, box_size);
|
child->layout.solved_dims[axis] = MaxF32(size - flex, box_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1071,25 +1188,25 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
{
|
{
|
||||||
Axis axis = box->desc.child_layout_axis;
|
Axis axis = box->desc.child_layout_axis;
|
||||||
UI_AxisAlignment alignment = box->desc.child_alignment[axis];
|
UI_AxisAlignment alignment = box->desc.child_alignment[axis];
|
||||||
f32 box_size = box->solved_dims[axis];
|
f32 box_size = box->layout.solved_dims[axis];
|
||||||
f32 size_accum = box->final_children_size_accum[axis];
|
f32 size_accum = box->layout.final_children_size_accum[axis];
|
||||||
switch(alignment)
|
switch(alignment)
|
||||||
{
|
{
|
||||||
default: break;
|
default: break;
|
||||||
case UI_AxisAlignment_Center:
|
case UI_AxisAlignment_Center:
|
||||||
{
|
{
|
||||||
box->layout_cursor = box_size / 2 - size_accum / 2;
|
box->layout.cursor = box_size / 2 - size_accum / 2;
|
||||||
} break;
|
} break;
|
||||||
case UI_AxisAlignment_End:
|
case UI_AxisAlignment_End:
|
||||||
{
|
{
|
||||||
box->layout_cursor = box_size - size_accum;
|
box->layout.cursor = box_size - size_accum;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Position */
|
/* Position */
|
||||||
{
|
{
|
||||||
f32 *dims_arr = box->solved_dims;
|
f32 *dims_arr = box->layout.solved_dims;
|
||||||
Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]);
|
Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]);
|
||||||
Vec2 final_pos = Zi;
|
Vec2 final_pos = Zi;
|
||||||
|
|
||||||
@ -1113,7 +1230,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
/* Non-floating box position */
|
/* Non-floating box position */
|
||||||
else if (parent)
|
else if (parent)
|
||||||
{
|
{
|
||||||
f32 layout_cursor = parent->layout_cursor;
|
f32 layout_cursor = parent->layout.cursor;
|
||||||
f32 offset[2] = Zi;
|
f32 offset[2] = Zi;
|
||||||
/* Compute offset in layout direction */
|
/* Compute offset in layout direction */
|
||||||
{
|
{
|
||||||
@ -1129,13 +1246,13 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
default: break;
|
default: break;
|
||||||
case UI_AxisAlignment_Center:
|
case UI_AxisAlignment_Center:
|
||||||
{
|
{
|
||||||
f32 parent_size = parent->solved_dims[axis];
|
f32 parent_size = parent->layout.solved_dims[axis];
|
||||||
f32 box_size = dims_arr[axis];
|
f32 box_size = dims_arr[axis];
|
||||||
offset[axis] = parent_size / 2 - box_size / 2;
|
offset[axis] = parent_size / 2 - box_size / 2;
|
||||||
} break;
|
} break;
|
||||||
case UI_AxisAlignment_End:
|
case UI_AxisAlignment_End:
|
||||||
{
|
{
|
||||||
f32 parent_size = parent->solved_dims[axis];
|
f32 parent_size = parent->layout.solved_dims[axis];
|
||||||
f32 box_size = dims_arr[axis];
|
f32 box_size = dims_arr[axis];
|
||||||
offset[axis] = parent_size - box_size;
|
offset[axis] = parent_size - box_size;
|
||||||
} break;
|
} break;
|
||||||
@ -1143,7 +1260,7 @@ void UI_EndFrame(UI_Frame *frame)
|
|||||||
}
|
}
|
||||||
final_pos.x = parent->rect.p0.x + offset[0];
|
final_pos.x = parent->rect.p0.x + offset[0];
|
||||||
final_pos.y = parent->rect.p0.y + offset[1];
|
final_pos.y = parent->rect.p0.y + offset[1];
|
||||||
parent->layout_cursor += dims_arr[parent->desc.child_layout_axis];
|
parent->layout.cursor += dims_arr[parent->desc.child_layout_axis];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Submit position */
|
/* Submit position */
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
//~ Key types
|
//~ Key types
|
||||||
|
|
||||||
#define UI_NilKey ((UI_Key) { 0 })
|
#define UI_NilKey ((UI_Key) { 0 })
|
||||||
#define UI_RootKey ((UI_Key) { 0xa3deb3749ef35a7aUll })
|
#define UI_RootKey ((UI_Key) { 0xaaaaaaaaaaaaaaaaUll })
|
||||||
|
|
||||||
Struct(UI_Key)
|
Struct(UI_Key)
|
||||||
{
|
{
|
||||||
@ -253,7 +253,7 @@ Struct(UI_Box)
|
|||||||
UI_Box *next_in_bin;
|
UI_Box *next_in_bin;
|
||||||
UI_Box *prev_in_bin;
|
UI_Box *prev_in_bin;
|
||||||
UI_Report report;
|
UI_Report report;
|
||||||
u64 last_updated_tick;
|
i64 last_build_tick;
|
||||||
|
|
||||||
//- Tree links
|
//- Tree links
|
||||||
UI_Box *parent;
|
UI_Box *parent;
|
||||||
@ -267,16 +267,19 @@ Struct(UI_Box)
|
|||||||
UI_BoxDesc desc;
|
UI_BoxDesc desc;
|
||||||
G_Texture2DRef raw_texture;
|
G_Texture2DRef raw_texture;
|
||||||
Rng2 raw_texture_slice_uv;
|
Rng2 raw_texture_slice_uv;
|
||||||
|
GC_Run glyph_run;
|
||||||
|
|
||||||
//- Pre-layout data
|
//- Pre-layout data
|
||||||
u64 pre_index;
|
u64 pre_index;
|
||||||
u64 post_index;
|
u64 post_index;
|
||||||
|
|
||||||
//- Layout data
|
//- Layout data
|
||||||
GC_Run glyph_run;
|
struct
|
||||||
f32 layout_cursor;
|
{
|
||||||
f32 solved_dims[Axis_CountXY];
|
f32 cursor;
|
||||||
f32 final_children_size_accum[Axis_CountXY];
|
f32 solved_dims[Axis_CountXY];
|
||||||
|
f32 final_children_size_accum[Axis_CountXY];
|
||||||
|
} layout;
|
||||||
|
|
||||||
//- Layout results
|
//- Layout results
|
||||||
Rng2 rect;
|
Rng2 rect;
|
||||||
@ -293,9 +296,30 @@ Struct(UI_BoxBin)
|
|||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ State types
|
//~ Iterator types
|
||||||
|
|
||||||
#define UI_NumBoxLookupBins 16384
|
Struct(UI_BoxIterDfsNode)
|
||||||
|
{
|
||||||
|
UI_BoxIterDfsNode *next;
|
||||||
|
UI_Box *box;
|
||||||
|
b32 visited;
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(UI_BoxIter)
|
||||||
|
{
|
||||||
|
UI_BoxIterDfsNode *first;
|
||||||
|
UI_BoxIterDfsNode *first_free;
|
||||||
|
UI_BoxIterDfsNode *last_free;
|
||||||
|
};
|
||||||
|
|
||||||
|
Struct(UI_BoxIterResult)
|
||||||
|
{
|
||||||
|
UI_Box *box;
|
||||||
|
b32 pre;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Context types
|
||||||
|
|
||||||
Enum(UI_FrameFlag)
|
Enum(UI_FrameFlag)
|
||||||
{
|
{
|
||||||
@ -314,10 +338,8 @@ Struct(UI_Frame)
|
|||||||
G_ResourceHandle backbuffer;
|
G_ResourceHandle backbuffer;
|
||||||
G_CommandListHandle cl;
|
G_CommandListHandle cl;
|
||||||
|
|
||||||
u64 transient_key_seed;
|
|
||||||
|
|
||||||
/* Time */
|
/* Time */
|
||||||
u64 tick;
|
i64 tick;
|
||||||
i64 time_ns;
|
i64 time_ns;
|
||||||
i64 dt_ns;
|
i64 dt_ns;
|
||||||
|
|
||||||
@ -338,21 +360,25 @@ Struct(UI_Frame)
|
|||||||
UI_StyleNode *first_free_style_node;
|
UI_StyleNode *first_free_style_node;
|
||||||
|
|
||||||
/* Layout */
|
/* Layout */
|
||||||
UI_Box *root_box;
|
|
||||||
UI_Box **boxes_pre;
|
UI_Box **boxes_pre;
|
||||||
UI_Box **boxes_post;
|
UI_Box **boxes_post;
|
||||||
};
|
};
|
||||||
|
|
||||||
Struct(UI_State)
|
Struct(UI_Ctx)
|
||||||
{
|
{
|
||||||
Arena *box_arena;
|
|
||||||
UI_BoxBin *box_bins;
|
|
||||||
u64 boxes_count;
|
u64 boxes_count;
|
||||||
|
Arena *box_arena;
|
||||||
|
UI_Box *root_box;
|
||||||
|
UI_BoxBin box_bins[Kibi(256)];
|
||||||
UI_Box *first_free_box;
|
UI_Box *first_free_box;
|
||||||
|
|
||||||
u64 current_frame_idx;
|
u64 transient_key_seed;
|
||||||
|
|
||||||
|
i64 current_frame_tick;
|
||||||
UI_Frame frames[2];
|
UI_Frame frames[2];
|
||||||
} extern UI_state;
|
};
|
||||||
|
|
||||||
|
extern UI_Ctx UI;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Bootstrap
|
//~ Bootstrap
|
||||||
@ -367,14 +393,19 @@ GC_FontKey UI_GetDefaultFont(void);
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Key helpers
|
//~ Key helpers
|
||||||
|
|
||||||
|
b32 UI_MatchKey(UI_Key a, UI_Key b);
|
||||||
UI_Key UI_KeyFromString(String str);
|
UI_Key UI_KeyFromString(String str);
|
||||||
UI_Key UI_KeyF_(String fmt, ...);
|
UI_Key UI_KeyF_(String fmt, ...);
|
||||||
#define UI_KeyF(fmt_cstr, ...) UI_KeyF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd)
|
#define UI_KeyF(fmt_cstr, ...) UI_KeyF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd)
|
||||||
|
|
||||||
UI_Key UI_TransKey(void);
|
UI_Key UI_TransKey(void);
|
||||||
|
|
||||||
UI_Box *UI_BoxFromKey(UI_Key key);
|
UI_Box *UI_BoxFromKey(UI_Key key);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Iteration helpers
|
||||||
|
|
||||||
|
UI_BoxIterResult UI_FirstBox(Arena *arena, UI_BoxIter *iter, UI_Key start_key);
|
||||||
|
UI_BoxIterResult UI_NextBox(Arena *arena, UI_BoxIter *iter);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ String helpers
|
//~ String helpers
|
||||||
|
|
||||||
@ -454,6 +485,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color);
|
|||||||
//~ Frame helpers
|
//~ Frame helpers
|
||||||
|
|
||||||
UI_Frame *UI_CurrentFrame(void);
|
UI_Frame *UI_CurrentFrame(void);
|
||||||
|
UI_Frame *UI_LastFrame(void);
|
||||||
Arena *UI_FrameArena(void);
|
Arena *UI_FrameArena(void);
|
||||||
Vec2 UI_CursorPos(void);
|
Vec2 UI_CursorPos(void);
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user