diff --git a/src/glyph_cache/glyph_cache.c b/src/glyph_cache/glyph_cache.c index 195fa4b9..16682c8f 100644 --- a/src/glyph_cache/glyph_cache.c +++ b/src/glyph_cache/glyph_cache.c @@ -28,7 +28,7 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc) //~ Run // TODO: Thread-local cache -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, f32 scale) { GC_Run result = Zi; if (str.len > 0) @@ -179,14 +179,20 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size GC_Glyph *glyph = ready_glyphs[glyph_idx]; GC_RunRect *rect = &result.rects[glyph_idx]; + f32 advance = RoundF32(glyph->advance * scale); + + Rng2 bounds = Zi; + bounds.p0 = MulVec2(glyph->bounds.p0, scale); + bounds.p1 = MulVec2(glyph->bounds.p1, scale); + 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->advance = advance; - rect->bounds = glyph->bounds; + rect->bounds = bounds; if (glyph_idx == 0) { @@ -204,10 +210,10 @@ GC_Run GC_RunFromString(Arena *arena, String str, GC_FontKey font, f32 font_size 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.font_size = glyph->font_size * scale; + result.font_ascent = glyph->font_ascent * scale; + result.font_descent = glyph->font_descent * scale; + result.font_cap = glyph->font_cap * scale; } EndScratch(scratch); diff --git a/src/glyph_cache/glyph_cache.h b/src/glyph_cache/glyph_cache.h index 4d924e54..3d15bf40 100644 --- a/src/glyph_cache/glyph_cache.h +++ b/src/glyph_cache/glyph_cache.h @@ -155,7 +155,7 @@ u64 GC_HashFromGlyphDesc(GC_GlyphDesc desc); //////////////////////////////////////////////////////////// //~ Run -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, f32 scale); //////////////////////////////////////////////////////////// //~ Async diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index 7ccf0d84..58e8ecea 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -138,6 +138,10 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) Vec2 cursor_pos = UI_CursorPos(); UI_Key titlebar_key = UI_KeyF("title bar"); + UI_Report titlebar_rep = UI_ReportFromKey(titlebar_key); + + UI_Push(Scale, titlebar_rep.exists); + UI_Push(Tint, VEC4(1, 1, 1, titlebar_rep.exists)); Vec4 window_background_color = theme.window_background_color; // Vec4 window_background_color = VEC4(0, 0, 0, 0); @@ -145,15 +149,12 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) Vec4 titlebar_color = Zi; Vec4 titlebar_border_color = Zi; Vec4 divider_color = theme.divider_color; + if (titlebar_rep.m1.held) { - UI_Report rep = UI_ReportFromKey(titlebar_key); - if (rep.m1.held) - { - widget->pos = SubVec2(cursor_pos, rep.last_down_mouse_offset); - } - // window_border_color = BlendSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), rep.hot); - window_border_color = BlendSrgb(window_border_color, Rgb32(0x0078a6), rep.hot); + widget->pos = SubVec2(cursor_pos, titlebar_rep.last_down_mouse_offset); } + // window_border_color = BlendSrgb(window_border_color, Rgb(0.5, 0.5, 0.5), titlebar_rep.hot); + window_border_color = BlendSrgb(window_border_color, Rgb32(0x0078a6), titlebar_rep.hot); UI_Push(BackgroundColor, window_background_color); UI_Push(BorderColor, window_border_color); @@ -243,7 +244,8 @@ void V_EndCommandsWidget(V_CommandsWidget *widget) UI_BuildSpacer(UI_PIX(20, 1), Axis_X); // Command label - UI_SetNext(ChildAlignment, UI_Alignment_Center); + // UI_SetNext(ChildAlignment, UI_Alignment_Center); + UI_SetNext(ChildAlignment, UI_Alignment_Left); UI_BuildLabel(item->desc.display_name); // Middle spacer @@ -1055,7 +1057,7 @@ void V_TickForever(WaveLaneCtx *lane) i64 new_active_window_idx = panel->active_window_idx; UI_PushCP(UI_BuildColumn()); { - UI_Push(Tint, VEC4(1, 1, 1, 0.90)); + UI_Push(Tint, VEC4(1, 1, 1, 0.90 * panel_rep.exists)); i64 active_window_idx = ClampI64(panel->active_window_idx, 0, MaxI64(panel->windows_count - 1, 0)); //- Build tab row diff --git a/src/ttf/ttf_dwrite/ttf_dwrite.c b/src/ttf/ttf_dwrite/ttf_dwrite.c index 0549dd1d..4521ec1b 100644 --- a/src/ttf/ttf_dwrite/ttf_dwrite.c +++ b/src/ttf/ttf_dwrite/ttf_dwrite.c @@ -246,7 +246,6 @@ TTF_GlyphResult TTF_RasterizeGlyphFromCodepoint(Arena *arena, u32 codepoint, Res hr = IDWriteFontFace_GetDesignGlyphMetrics(font->face, &glyph_idx, 1, &m, 0); } f32 advance = (f32)m.advanceWidth * pixels_per_design_unit; - advance = RoundF32(advance); // Best-guess a position in the middle of the render target based on metrics Vec2I32 rt_baseline = Zi; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index cc199ead..55409559 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -253,6 +253,7 @@ void UI_PushDefaults(void) case UI_StyleKind_Parent: { desc.style.Parent = UI_RootKey; } break; case UI_StyleKind_Width: { desc.style.Width = UI_GROW(1, 0); } break; case UI_StyleKind_Height: { desc.style.Height = UI_GROW(1, 0); } + case UI_StyleKind_Scale: { desc.style.Scale = 1; } break; case UI_StyleKind_Font: { desc.style.Font = UI_GetDefaultFont(); } break; u8 prefetch[127] = Zi; @@ -506,6 +507,7 @@ UI_Key UI_BuildBoxEx(UI_Key semantic_key) n->cmd.box.flags = UI_UseTop(Flags); 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.scale = UI_UseTop(Scale); n->cmd.box.child_alignment[Axis_X] = UI_UseTop(ChildAlignmentX); n->cmd.box.child_alignment[Axis_Y] = UI_UseTop(ChildAlignmentY); n->cmd.box.child_layout_axis = UI_UseTop(ChildLayoutAxis); @@ -778,29 +780,35 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) } } - // Update box hot & active states UI_Box *hot_box = active_box; if (hovered_box && !active_box) { hot_box = hovered_box; } + // Update box reports for (u64 pre_index = 0; pre_index < UI.boxes_count; ++pre_index) { UI_Box *box = last_frame->boxes_pre[pre_index]; UI_Report *report = &box->report; - report->is_hovered = box == hovered_box; - report->is_hot = box == hot_box; - f32 target_hovered = report->is_hovered; - f32 target_hot = report->is_hot; - f32 target_active = box == active_box; + report->is_hovered = box == hovered_box; + report->is_hot = box == hot_box; + + f32 target_exists = box->last_build_tick >= (frame->tick - 1); + f32 target_hovered = report->is_hovered; + f32 target_hot = report->is_hot; + f32 target_active = box == active_box; f32 target_selected = !!(box->desc.flags & UI_BoxFlag_Selected); - f32 hot_blend_rate = target_hot == 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 selected_blend_rate = target_selected == 1 ? 1 : (15 * frame->dt); - report->hot = LerpF32(report->hot, target_hot, hot_blend_rate); - report->active = LerpF32(report->active, target_active, active_blend_rate); + + f32 exists_blend_rate = (30 * 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 hovered_blend_rate = target_hovered == 1 ? 1 : (15 * frame->dt); + f32 selected_blend_rate = target_selected == 1 ? 1 : (15 * frame->dt); + + report->exists = LerpF32(report->exists, target_exists, exists_blend_rate); + report->hot = LerpF32(report->hot, target_hot, hot_blend_rate); + report->active = LerpF32(report->active, target_active, active_blend_rate); report->hovered = LerpF32(report->hovered, target_hovered, hovered_blend_rate); report->selected = LerpF32(report->selected, target_selected, selected_blend_rate); report->screen_rect = box->rect; @@ -954,7 +962,8 @@ void UI_EndFrame(UI_Frame *frame) // Update box from cmd { box->desc = cmd.box; - box->glyph_run = GC_RunFromString(frame->arena, box->desc.text, box->desc.font, box->desc.font_size); + + 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; @@ -975,46 +984,6 @@ void UI_EndFrame(UI_Frame *frame) } } - ////////////////////////////// - //- Interpolate box sizes - - for (UI_BoxIterResult ir = UI_FirstBox(scratch.arena, &box_iter, UI_RootKey); ir.box; ir = UI_NextBox(scratch.arena, &box_iter)) - { - if (ir.pre) - { - UI_Box *box = ir.box; - - for (Axis axis = 0; axis < countof(box->semantic_dims); ++axis) - { - UI_Size *dst_sem_size = &box->semantic_dims[axis]; - UI_Size *pref_sem_size = &box->desc.pref_semantic_dims[axis]; - b32 was_built = box->last_build_tick >= frame->tick; - b32 is_new = box->gen != box->old_gen; - if (!was_built) - { - *pref_sem_size = UI_PIX(0, 0); - } - else if (is_new) - { - dst_sem_size->v = 0; - dst_sem_size->strictness = 0; - } - - f32 lerp_rate = 20.0 * frame->dt; - // f32 lerp_rate = 1; - if (box->desc.is_transient || dst_sem_size->kind != pref_sem_size->kind) - { - lerp_rate = 1; - } - lerp_rate = ClampF32(lerp_rate, 0, 1); - - dst_sem_size->kind = pref_sem_size->kind; - dst_sem_size->v = LerpF32(dst_sem_size->v, pref_sem_size->v, lerp_rate); - dst_sem_size->strictness = LerpF32(dst_sem_size->strictness, pref_sem_size->strictness, lerp_rate); - } - } - } - ////////////////////////////// //- Prune cached boxes @@ -1026,29 +995,15 @@ void UI_EndFrame(UI_Frame *frame) if (ir.pre) { UI_Box *box = ir.box; - // if (box->last_build_tick < frame->tick) + if (box->last_build_tick < frame->tick) { - b32 should_prune = 0; - for (Axis axis = 0; axis < countof(box->semantic_dims); ++axis) + // Cause children to prune + for (UI_Box *child = box->first; child; child = child->next) { - UI_Size sem_size = box->semantic_dims[axis]; - if (sem_size.kind != UI_SizeKind_Shrink && sem_size.v <= 0) - { - should_prune = 1; - } - } - - if (should_prune) - { - // Cause children to prune - for (UI_Box *child = box->first; child; child = child->next) - { - child->semantic_dims[Axis_X] = UI_PIX(0, 0); - child->semantic_dims[Axis_Y] = UI_PIX(0, 0); - } - // Push box to prunes array - prunes[prunes_count++] = box; + child->last_build_tick = box->last_build_tick; } + // Push box to prunes array + prunes[prunes_count++] = box; } } } @@ -1124,13 +1079,24 @@ void UI_EndFrame(UI_Frame *frame) Assert(post_index == boxes_count); } + // Apply scales + 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]; + sem_dims->v *= box->desc.scale; + } + } + // Compute independent 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->semantic_dims[axis]; + UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; if (sem_dims.kind == UI_SizeKind_Pixel) { box->solved_dims[axis] = sem_dims.v; @@ -1141,7 +1107,7 @@ void UI_EndFrame(UI_Frame *frame) f32 text_size = 0; if (axis == Axis_X) { - text_size = box->glyph_run.baseline_length; + text_size = CeilF32(box->glyph_run.baseline_length); } else { @@ -1159,14 +1125,14 @@ void UI_EndFrame(UI_Frame *frame) if (box->parent) { Axis axis = box->parent->desc.child_layout_axis; - UI_Size sem_dims = box->semantic_dims[axis]; + UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; if (sem_dims.kind == UI_SizeKind_Grow) { f32 match_size = 0; b32 found_match = 0; for (UI_Box *ancestor = box->parent; ancestor != 0 && !found_match; ancestor = ancestor->parent) { - UI_Size ancestor_size = ancestor->semantic_dims[axis]; + UI_Size ancestor_size = ancestor->desc.pref_semantic_dims[axis]; if (ancestor_size.kind == UI_SizeKind_Pixel || (ancestor_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText))) { // Match independent ancestor @@ -1185,7 +1151,7 @@ void UI_EndFrame(UI_Frame *frame) UI_Box *box = boxes_post[post_index]; for (Axis axis = 0; axis < Axis_COUNTXY; ++axis) { - UI_Size sem_dims = box->semantic_dims[axis]; + UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; if (sem_dims.kind == UI_SizeKind_Shrink && !AnyBit(box->desc.flags, UI_BoxFlag_DrawText)) { f32 accum = 0; @@ -1215,7 +1181,7 @@ void UI_EndFrame(UI_Frame *frame) if (box->parent) { Axis axis = !box->parent->desc.child_layout_axis; - UI_Size sem_dims = box->semantic_dims[axis]; + UI_Size sem_dims = box->desc.pref_semantic_dims[axis]; if (sem_dims.kind == UI_SizeKind_Grow) { box->solved_dims[axis] = box->parent->solved_dims[axis] * sem_dims.v; @@ -1239,7 +1205,7 @@ void UI_EndFrame(UI_Frame *frame) if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { f32 size = child->solved_dims[axis]; - f32 strictness = child->semantic_dims[axis].strictness; + f32 strictness = child->desc.pref_semantic_dims[axis].strictness; f32 flex = size * (1.0 - strictness); if (axis == box->desc.child_layout_axis) { @@ -1262,7 +1228,7 @@ void UI_EndFrame(UI_Frame *frame) if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { f32 size = child->solved_dims[axis]; - f32 strictness = child->semantic_dims[axis].strictness; + f32 strictness = child->desc.pref_semantic_dims[axis].strictness; f32 flex = size * (1.0 - strictness); f32 new_size = size; if (axis == box->desc.child_layout_axis) @@ -1293,7 +1259,7 @@ void UI_EndFrame(UI_Frame *frame) f32 size = child->solved_dims[axis]; if (size > box_size) { - f32 strictness = child->semantic_dims[axis].strictness; + f32 strictness = child->desc.pref_semantic_dims[axis].strictness; f32 flex = size * (1.0 - strictness); child->solved_dims[axis] = MaxF32(size - flex, box_size); } @@ -1495,7 +1461,7 @@ void UI_EndFrame(UI_Frame *frame) if (should_truncate) { // Get elipses run - GC_Run elipses_run = GC_RunFromString(scratch.arena, Lit("..."), box->desc.font, box->desc.font_size); + GC_Run elipses_run = GC_RunFromString(scratch.arena, Lit("..."), box->desc.font, box->desc.font_size, box->desc.scale); f32 truncation_offset = max_baseline - elipses_run.baseline_length; // Append non-overflowed rects diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 817e89c1..389b0a57 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -100,6 +100,7 @@ Enum(UI_BoxFlag) X(ChildAlignmentY, UI_AxisAlignment) \ X(Width, UI_Size) \ X(Height, UI_Size) \ + X(Scale, f32) \ X(BackgroundColor, Vec4) \ X(BorderColor, Vec4) \ X(DebugColor, Vec4) \ @@ -186,6 +187,7 @@ Struct(UI_Report) b32 is_hovered; b32 is_hot; + f32 exists; f32 hovered; f32 hot; f32 active; @@ -227,6 +229,7 @@ Struct(UI_BoxDesc) Vec4 debug_color; Vec4 tint; f32 border; + f32 scale; Vec2 floating_pos; String text; GC_FontKey font; @@ -287,7 +290,6 @@ Struct(UI_Box) GC_Run glyph_run; //- Pre-layout data - UI_Size semantic_dims[Axis_COUNTXY]; u64 pre_index; u64 post_index; diff --git a/src/ui/ui_extras.c b/src/ui/ui_extras.c index e1e95e0d..e0b71488 100644 --- a/src/ui/ui_extras.c +++ b/src/ui/ui_extras.c @@ -6,6 +6,7 @@ UI_Key UI_BuildLabel(String text) UI_Key parent = UI_UseTop(Parent); GC_FontKey font = UI_UseTop(Font); f32 font_size = UI_UseTop(FontSize); + f32 scale = UI_UseTop(Scale); Vec4 tint = UI_UseTop(Tint); UI_Alignment alignment = UI_UseTop(ChildAlignment); @@ -14,14 +15,15 @@ UI_Key UI_BuildLabel(String text) { UI_PushDefaults(); UI_Push(Parent, parent); - UI_SetNext(Tint, tint); - UI_SetNext(Font, font); - UI_SetNext(FontSize, font_size); - UI_SetNext(Width, UI_SHRINK(0, 1)); - UI_SetNext(Height, UI_SHRINK(0, 1)); - UI_SetNext(Text, text); - UI_SetNext(ChildAlignment, alignment); - UI_SetNext(Flags, UI_BoxFlag_DrawText); + UI_Push(Scale, scale); + UI_Push(Tint, tint); + UI_Push(Font, font); + UI_Push(FontSize, font_size); + UI_Push(Width, UI_SHRINK(0, 1)); + UI_Push(Height, UI_SHRINK(0, 1)); + UI_Push(Text, text); + UI_Push(ChildAlignment, alignment); + UI_Push(Flags, UI_BoxFlag_DrawText); key = UI_BuildBox(); } UI_PopCP(UI_TopCP()); @@ -50,10 +52,12 @@ UI_Key UI_BuildSpacer(UI_Size size, Axis axis) { UI_Key parent = UI_UseTop(Parent); UI_Key key = Zi; + f32 scale = UI_UseTop(Scale); UI_PushCP(UI_NilKey); { UI_PushDefaults(); UI_Push(Parent, parent); + UI_Push(Scale, scale); UI_Push(Tint, 0); UI_Push(AxisSize, UI_GROW(1, 0), .axis = !axis); UI_Push(AxisSize, size, .axis = axis); @@ -67,11 +71,13 @@ UI_Key UI_BuildDivider(UI_Size size, Vec4 color, Axis axis) { UI_Key key = Zi; UI_Key parent = UI_UseTop(Parent); + f32 scale = UI_UseTop(Scale); Vec4 tint = UI_UseTop(Tint); UI_PushCP(UI_NilKey); { UI_PushDefaults(); UI_Push(Parent, parent); + UI_Push(Scale, scale); UI_Push(Tint, tint); UI_Push(BackgroundColor, color); UI_Push(AxisSize, UI_GROW(1, 0), .axis = !axis);