ui animation scaling adjustments

This commit is contained in:
jacob 2025-12-29 19:44:42 -06:00
parent e69aa09212
commit d1fe4593da
6 changed files with 77 additions and 58 deletions

View File

@ -1173,6 +1173,13 @@ u32 U32FromVec4(Vec4 v)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Range //~ Range
//- Rng1
f32 NormRng(Rng r, f32 v)
{
return (r.max - r.min) / v;
}
//- Rng2 //- Rng2
Vec2 DimsFromRng2(Rng2 r) Vec2 DimsFromRng2(Rng2 r)
@ -1192,6 +1199,21 @@ Vec2 CenterFromRng2(Rng2 r)
return result; return result;
} }
Vec2 NormRng2(Rng2 r, Vec2 v)
{
Vec2 result = Zi;
Vec2 dims = SubVec2(r.p1, r.p0);
if (dims.x != 0)
{
result.x = v.x / dims.x;
}
if (dims.y != 0)
{
result.y = v.y / dims.y;
}
return result;
}
Rng2 UnionRng2(Rng2 a, Rng2 b) Rng2 UnionRng2(Rng2 a, Rng2 b)
{ {
Rng2 result = Zi; Rng2 result = Zi;

View File

@ -390,9 +390,14 @@ u32 U32FromVec4(Vec4 v);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Range //~ Range
//- Rng1
f32 NormRng(Rng r, f32 v);
#define Norm(min, max, v) NormRng(RNG((min), (max)), (v))
//- Rng2 //- Rng2
Vec2 DimsFromRng2(Rng2 r); Vec2 DimsFromRng2(Rng2 r);
Vec2 CenterFromRng2(Rng2 r); Vec2 CenterFromRng2(Rng2 r);
Vec2 NormRng2(Rng2 r, Vec2 v);
Rng2 UnionRng2(Rng2 a, Rng2 b); Rng2 UnionRng2(Rng2 a, Rng2 b);
Rng2 AddRng2Vec2(Rng2 r, Vec2 v); Rng2 AddRng2Vec2(Rng2 r, Vec2 v);
Rng2 MulRng2Vec2(Rng2 a, Vec2 v); Rng2 MulRng2Vec2(Rng2 a, Vec2 v);

View File

@ -178,14 +178,13 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
{ {
GC_Glyph *glyph = ready_glyphs[glyph_idx]; GC_Glyph *glyph = ready_glyphs[glyph_idx];
GC_RunRect *rect = &result.rects[glyph_idx]; GC_RunRect *rect = &result.rects[glyph_idx];
f32 advance = glyph->advance * scale;
f32 advance = RoundF32(glyph->advance * scale);
Rng2 bounds = Zi; Rng2 bounds = Zi;
bounds.p0 = MulVec2(glyph->bounds.p0, scale); bounds.p0 = glyph->bounds.p0;
bounds.p1 = MulVec2(glyph->bounds.p1, scale); bounds.p1 = glyph->bounds.p1;
bounds.p0 = RoundVec2(bounds.p0); bounds.p0 = MulVec2(bounds.p0, scale);
bounds.p1 = RoundVec2(bounds.p1); bounds.p1 = MulVec2(bounds.p1, scale);
rect->tex = glyph->atlas->tex_ref; rect->tex = glyph->atlas->tex_ref;
rect->tex_slice = glyph->tex_slice; rect->tex_slice = glyph->tex_slice;
@ -211,7 +210,6 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size
if (ready_glyphs_count > 0) if (ready_glyphs_count > 0)
{ {
// TOOD: Round these too?
GC_Glyph *glyph = ready_glyphs[0]; GC_Glyph *glyph = ready_glyphs[0];
result.font_size = glyph->font_size * scale; result.font_size = glyph->font_size * scale;
result.font_ascent = glyph->font_ascent * scale; result.font_ascent = glyph->font_ascent * scale;

View File

@ -140,6 +140,8 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
UI_Key titlebar_key = UI_KeyF("title bar"); UI_Key titlebar_key = UI_KeyF("title bar");
UI_Report titlebar_rep = UI_ReportFromKey(titlebar_key); UI_Report titlebar_rep = UI_ReportFromKey(titlebar_key);
UI_Report widget_rep = UI_ReportFromKey(widget->key);
Vec2 widget_half_dims = MulVec2(DimsFromRng2(widget_rep.screen_rect), 0.5);
Vec4 window_background_color = theme.window_background_color; Vec4 window_background_color = theme.window_background_color;
// Vec4 window_background_color = VEC4(0, 0, 0, 0); // Vec4 window_background_color = VEC4(0, 0, 0, 0);
@ -149,13 +151,16 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
Vec4 divider_color = theme.divider_color; Vec4 divider_color = theme.divider_color;
if (titlebar_rep.m1.held) if (titlebar_rep.m1.held)
{ {
widget->pos = SubVec2(cursor_pos, titlebar_rep.last_mouse_down_cursor_offset); widget->pos = AddVec2(SubVec2(cursor_pos, titlebar_rep.last_mouse_down_cursor_offset), widget_half_dims);
} }
// window_border_color = LerpSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), titlebar_rep.hot);
window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot); window_border_color = LerpSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot);
UI_Push(Scale, titlebar_rep.exists); UI_Push(Scale, LerpF32(0.75, 1, widget_rep.selected));
UI_Push(Tint, VEC4(1, 1, 1, titlebar_rep.exists)); UI_Push(Tint, VEC4(1, 1, 1, widget_rep.selected));
if (widget_rep.selected < 0.25)
{
UI_Push(OmitFlags, UI_UseTop(OmitFlags) | UI_BoxFlag_Interactable);
}
UI_Push(BackgroundColor, window_background_color); UI_Push(BackgroundColor, window_background_color);
UI_Push(BorderColor, window_border_color); UI_Push(BorderColor, window_border_color);
@ -164,8 +169,8 @@ void V_EndCommandsWidget(V_CommandsWidget *widget)
UI_Push(Width, UI_PIX(theme.window_width, 0)); UI_Push(Width, UI_PIX(theme.window_width, 0));
UI_Push(Height, UI_SHRINK(0, 0)); UI_Push(Height, UI_SHRINK(0, 0));
UI_Push(ChildLayoutAxis, Axis_Y); UI_Push(ChildLayoutAxis, Axis_Y);
UI_Push(FloatingPos, widget->pos); UI_Push(FloatingPos, SubVec2(widget->pos, widget_half_dims));
UI_SetNext(Flags, UI_BoxFlag_Floating); UI_SetNext(Flags, UI_BoxFlag_Floating | (UI_BoxFlag_Selected * frame->show_command_palette));
UI_PushCP(UI_BuildBoxEx(widget->key)); UI_PushCP(UI_BuildBoxEx(widget->key));
{ {
// Title bar // Title bar
@ -1079,7 +1084,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Build tab row //- Build tab row
f32 tab_spacing = 10; f32 tab_spacing = 5;
V_Window *active_window = 0; V_Window *active_window = 0;
V_Window *close_window = 0; V_Window *close_window = 0;
{ {
@ -1491,7 +1496,7 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Build command palette //- Build command palette
if (frame->show_command_palette) // if (frame->show_command_palette)
{ {
V_BeginCommandsWidget(&frame->commands_widget); V_BeginCommandsWidget(&frame->commands_widget);
{ {

View File

@ -265,6 +265,7 @@ void UI_PushDefaults(void)
case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break; case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break;
case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break; case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break;
case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break; case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break;
case UI_StyleKind_InvisibleDebugColor: { desc.style.InvisibleDebugColor = Rgba(0, 1, 1, 0.25); } break;
case UI_StyleKind_BackgroundTextureSliceUv: { desc.style.BackgroundTextureSliceUv = RNG2(VEC2(0, 0), VEC2(1, 1)); } break; case UI_StyleKind_BackgroundTextureSliceUv: { desc.style.BackgroundTextureSliceUv = RNG2(VEC2(0, 0), VEC2(1, 1)); } break;
}; };
UI_PushStyle(desc); UI_PushStyle(desc);
@ -385,11 +386,6 @@ void UI_PushStyle(UI_StyleDesc desc)
{ {
default: break; default: break;
case UI_StyleKind_Text:
{
n->style.Text = PushString(frame->arena, desc.style.Text);
} break;
case UI_StyleKind_Tag: case UI_StyleKind_Tag:
{ {
if (n->next != 0) if (n->next != 0)
@ -397,6 +393,11 @@ void UI_PushStyle(UI_StyleDesc desc)
n->style.Tag = RandU64FromSeeds(n->next->style.Tag, n->style.Tag); n->style.Tag = RandU64FromSeeds(n->next->style.Tag, n->style.Tag);
} }
} break; } break;
case UI_StyleKind_Text:
{
n->style.Text = PushString(frame->arena, n->style.Text);
} break;
} }
} }
} }
@ -504,7 +505,7 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key)
n->cmd.box.key = key; n->cmd.box.key = key;
n->cmd.box.is_transient = is_transient; n->cmd.box.is_transient = is_transient;
n->cmd.box.parent = UI_UseTop(Parent); n->cmd.box.parent = UI_UseTop(Parent);
n->cmd.box.flags = UI_UseTop(Flags); n->cmd.box.flags = (UI_UseTop(Flags) | UI_UseTop(OrFlags)) & ~UI_UseTop(OmitFlags);
n->cmd.box.pref_semantic_dims[Axis_X] = UI_UseTop(Width); n->cmd.box.pref_semantic_dims[Axis_X] = UI_UseTop(Width);
n->cmd.box.pref_semantic_dims[Axis_Y] = UI_UseTop(Height); n->cmd.box.pref_semantic_dims[Axis_Y] = UI_UseTop(Height);
n->cmd.box.scale = UI_UseTop(Scale); n->cmd.box.scale = UI_UseTop(Scale);
@ -514,6 +515,7 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key)
n->cmd.box.background_color = UI_UseTop(BackgroundColor); n->cmd.box.background_color = UI_UseTop(BackgroundColor);
n->cmd.box.border_color = UI_UseTop(BorderColor); n->cmd.box.border_color = UI_UseTop(BorderColor);
n->cmd.box.debug_color = UI_UseTop(DebugColor); n->cmd.box.debug_color = UI_UseTop(DebugColor);
n->cmd.box.invisible_debug_color = UI_UseTop(InvisibleDebugColor);
n->cmd.box.tint = UI_UseTop(Tint); n->cmd.box.tint = UI_UseTop(Tint);
n->cmd.box.border = UI_UseTop(Border); n->cmd.box.border = UI_UseTop(Border);
n->cmd.box.font = UI_UseTop(Font); n->cmd.box.font = UI_UseTop(Font);
@ -809,11 +811,11 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color)
f32 target_active = box == active_box; f32 target_active = box == active_box;
f32 target_selected = !!(box->desc.flags & UI_BoxFlag_Selected); f32 target_selected = !!(box->desc.flags & UI_BoxFlag_Selected);
f32 exists_blend_rate = (30 * frame->dt); f32 exists_blend_rate = (40 * frame->dt);
f32 hot_blend_rate = target_hot == 1 ? 1 : (15 * frame->dt); f32 hot_blend_rate = target_hot == 1 ? 1 : (15 * frame->dt);
f32 active_blend_rate = target_active == 1 ? 1 : (15 * frame->dt); f32 active_blend_rate = target_active == 1 ? 1 : (15 * frame->dt);
f32 hovered_blend_rate = target_hovered == 1 ? 1 : (15 * frame->dt); f32 hovered_blend_rate = target_hovered == 1 ? 1 : (15 * frame->dt);
f32 selected_blend_rate = target_selected == 1 ? 1 : (15 * frame->dt); f32 selected_blend_rate = (40 * frame->dt);
report->exists = LerpF32(report->exists, target_exists, exists_blend_rate); report->exists = LerpF32(report->exists, target_exists, exists_blend_rate);
report->hot = LerpF32(report->hot, target_hot, hot_blend_rate); report->hot = LerpF32(report->hot, target_hot, hot_blend_rate);
@ -935,7 +937,6 @@ void UI_EndFrame(UI_Frame *frame)
for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (UI_CmdNode *cmd_node = frame->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
UI_Cmd cmd = cmd_node->cmd; UI_Cmd cmd = cmd_node->cmd;
switch (cmd.kind) switch (cmd.kind)
{ {
case UI_CmdKind_BuildBox: case UI_CmdKind_BuildBox:
@ -974,9 +975,7 @@ void UI_EndFrame(UI_Frame *frame)
box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size, box->desc.scale); box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size, box->desc.scale);
} }
box->last_build_tick = frame->tick; box->last_build_tick = frame->tick;
} break; } break;
case UI_CmdKind_SetRawTexture: case UI_CmdKind_SetRawTexture:
@ -1088,21 +1087,6 @@ void UI_EndFrame(UI_Frame *frame)
Assert(post_index == boxes_count); Assert(post_index == boxes_count);
} }
// Scale semantic pixel sizes
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{
UI_Box *box = boxes_pre[pre_index];
for (Axis axis = 0; axis < Axis_COUNTXY; ++axis)
{
UI_Size *sem_dims = &box->desc.pref_semantic_dims[axis];
b32 skip = sem_dims->kind != UI_SizeKind_Pixel;
if (!skip)
{
sem_dims->v *= box->desc.scale;
}
}
}
// Compute independent sizes // Compute independent sizes
for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index) for (u64 pre_index = 0; pre_index < boxes_count; ++pre_index)
{ {
@ -1112,7 +1096,7 @@ void UI_EndFrame(UI_Frame *frame)
UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Pixel) if (sem_dims.kind == UI_SizeKind_Pixel)
{ {
box->solved_dims[axis] = sem_dims.v; box->solved_dims[axis] = RoundF32(sem_dims.v * box->desc.scale);
} }
else if (sem_dims.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)) else if (sem_dims.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))
{ {
@ -1126,7 +1110,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 + (sem_dims.v * 2); box->solved_dims[axis] = RoundF32(text_size + (sem_dims.v * 2 * box->desc.scale));
} }
} }
} }
@ -1153,7 +1137,7 @@ void UI_EndFrame(UI_Frame *frame)
found_match = 1; found_match = 1;
} }
} }
box->solved_dims[axis] = match_size * sem_dims.v; box->solved_dims[axis] = RoundF32(match_size * sem_dims.v);
} }
} }
} }
@ -1182,7 +1166,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
} }
box->solved_dims[axis] = accum + (sem_dims.v * 2); box->solved_dims[axis] = CeilF32(accum + (sem_dims.v * 2));
} }
} }
} }
@ -1197,7 +1181,7 @@ void UI_EndFrame(UI_Frame *frame)
UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; UI_Size sem_dims = box->desc.pref_semantic_dims[axis];
if (sem_dims.kind == UI_SizeKind_Grow) if (sem_dims.kind == UI_SizeKind_Grow)
{ {
box->solved_dims[axis] = box->parent->solved_dims[axis] * sem_dims.v; box->solved_dims[axis] = RoundF32(box->parent->solved_dims[axis] * sem_dims.v);
} }
} }
} }
@ -1257,7 +1241,7 @@ void UI_EndFrame(UI_Frame *frame)
} }
} }
adjusted_size_accum += new_size; adjusted_size_accum += new_size;
child->solved_dims[axis] = new_size; child->solved_dims[axis] = RoundF32(new_size);
} }
} }
size_accum = adjusted_size_accum; size_accum = adjusted_size_accum;
@ -1274,7 +1258,7 @@ void UI_EndFrame(UI_Frame *frame)
{ {
f32 strictness = child->desc.pref_semantic_dims[axis].strictness; f32 strictness = child->desc.pref_semantic_dims[axis].strictness;
f32 flex = size * (1.0 - strictness); f32 flex = size * (1.0 - strictness);
child->solved_dims[axis] = MaxF32(size - flex, box_size); child->solved_dims[axis] = RoundF32(MaxF32(size - flex, box_size));
} }
} }
} }
@ -1367,10 +1351,9 @@ void UI_EndFrame(UI_Frame *frame)
} }
// Submit position // Submit position
Vec2 rounded_final_pos = RoundVec2(final_pos); Vec2 rounded_final_pos = FloorVec2(final_pos);
Vec2 rounded_dims = RoundVec2(dims_vec); box->rect.p0 = rounded_final_pos;
box->rect.p0 = FloorVec2(rounded_final_pos); box->rect.p1 = AddVec2(rounded_final_pos, dims_vec);
box->rect.p1 = AddVec2(rounded_final_pos, rounded_dims);
} }
// Rounding // Rounding
@ -1437,11 +1420,12 @@ void UI_EndFrame(UI_Frame *frame)
{ {
UI_Box *box = boxes_pre[pre_index]; UI_Box *box = boxes_pre[pre_index];
b32 is_visible = 1; b32 is_visible = 1;
is_visible = is_visible && (box->desc.tint.w != 0); is_visible = is_visible && (box->desc.tint.w >= 0.001);
is_visible = is_visible && (box->rect.p1.x > box->rect.p0.x); is_visible = is_visible && (box->rect.p1.x - box->rect.p0.x >= 1);
is_visible = is_visible && (box->rect.p1.y > box->rect.p0.y); is_visible = is_visible && (box->rect.p1.y - box->rect.p0.y >= 1);
if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug)) if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug))
{ {
Vec4 debug_lin = is_visible ? LinearFromSrgb(box->desc.debug_color) : LinearFromSrgb(box->desc.invisible_debug_color);
// Box rect // Box rect
{ {
@ -1449,7 +1433,7 @@ void UI_EndFrame(UI_Frame *frame)
rect->bounds = box->rect; rect->bounds = box->rect;
rect->background_lin = LinearFromSrgb(box->desc.background_color); rect->background_lin = LinearFromSrgb(box->desc.background_color);
rect->border_lin = LinearFromSrgb(box->desc.border_color); rect->border_lin = LinearFromSrgb(box->desc.border_color);
rect->debug_lin = LinearFromSrgb(box->desc.debug_color); rect->debug_lin = debug_lin;
rect->tint_lin = LinearFromSrgb(box->desc.tint); rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->border = box->desc.border; rect->border = box->desc.border;
rect->tl_rounding = box->rounding_tl; rect->tl_rounding = box->rounding_tl;
@ -1568,7 +1552,7 @@ void UI_EndFrame(UI_Frame *frame)
if (glyph_dims.x != 0 || glyph_dims.y != 0) if (glyph_dims.x != 0 || glyph_dims.y != 0)
{ {
UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect); UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect);
rect->debug_lin = LinearFromSrgb(box->desc.debug_color); rect->debug_lin = debug_lin;
rect->tint_lin = LinearFromSrgb(box->desc.tint); rect->tint_lin = LinearFromSrgb(box->desc.tint);
rect->tex = rr.tex; rect->tex = rr.tex;
rect->tex_slice_uv = rr.tex_slice_uv; rect->tex_slice_uv = rr.tex_slice_uv;

View File

@ -92,6 +92,8 @@ Enum(UI_BoxFlag)
//~ Style types //~ Style types
#define UI_StyleKindsXMacro(X) \ #define UI_StyleKindsXMacro(X) \
X(OmitFlags, UI_BoxFlag) \
X(OrFlags, UI_BoxFlag) \
X(Flags, UI_BoxFlag) \ X(Flags, UI_BoxFlag) \
X(Parent, UI_Key) \ X(Parent, UI_Key) \
X(Tag, u64) \ X(Tag, u64) \
@ -104,6 +106,7 @@ Enum(UI_BoxFlag)
X(BackgroundColor, Vec4) \ X(BackgroundColor, Vec4) \
X(BorderColor, Vec4) \ X(BorderColor, Vec4) \
X(DebugColor, Vec4) \ X(DebugColor, Vec4) \
X(InvisibleDebugColor, Vec4) \
X(Tint, Vec4) \ X(Tint, Vec4) \
X(Border, f32) \ X(Border, f32) \
X(FloatingPos, Vec2) \ X(FloatingPos, Vec2) \
@ -117,6 +120,7 @@ Enum(UI_BoxFlag)
/* --------------- Virtual styles -------------- */ \ /* --------------- Virtual styles -------------- */ \
/* --------------------------------------------- */ \ /* --------------------------------------------- */ \
X(BeginVirtualStyles_, i8) \ X(BeginVirtualStyles_, i8) \
/* --------------------------------------------- */ \
X(ChildAlignment, UI_Alignment) \ X(ChildAlignment, UI_Alignment) \
X(AxisSize, UI_Size) \ X(AxisSize, UI_Size) \
/* ------------------------------------------------- */ /* ------------------------------------------------- */
@ -227,6 +231,7 @@ Struct(UI_BoxDesc)
Vec4 background_color; Vec4 background_color;
Vec4 border_color; Vec4 border_color;
Vec4 debug_color; Vec4 debug_color;
Vec4 invisible_debug_color;
Vec4 tint; Vec4 tint;
f32 border; f32 border;
f32 scale; f32 scale;