diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index aa7fcebe..63f7df27 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -747,7 +747,7 @@ void V_TickForever(WaveLaneCtx *lane) { if (last_frame->tick == 0) { - frame->camera_lerp_ratio = 1; + frame->camera_lerp_rate = 1; } else if (frame->is_editing) { @@ -757,21 +757,20 @@ void V_TickForever(WaveLaneCtx *lane) // When panning & not zooming, we want camera interpolation to be // instant (no smoothing). However, the transition to non // interpolation must be smooth. - frame->camera_lerp_ratio += last_frame->camera_lerp_ratio + (5 * frame->dt); - frame->camera_lerp_ratio = MinF32(frame->camera_lerp_ratio, 1); + frame->camera_lerp_rate += last_frame->camera_lerp_rate + (5 * frame->dt); } else { - frame->camera_lerp_ratio = 40.0 * frame->dt; + frame->camera_lerp_rate = 40.0 * frame->dt; } } else { - frame->camera_lerp_ratio = 15.0 * frame->dt; + frame->camera_lerp_rate = 15.0 * frame->dt; } - - frame->camera_pos = LerpVec2(last_frame->camera_pos, target_camera_pos, frame->camera_lerp_ratio); - frame->camera_zoom = LerpF32(last_frame->camera_zoom, target_camera_zoom, frame->camera_lerp_ratio); + frame->camera_lerp_rate = ClampF32(frame->camera_lerp_rate, 0, 1); + frame->camera_pos = LerpVec2(last_frame->camera_pos, target_camera_pos, frame->camera_lerp_rate); + frame->camera_zoom = LerpF32(last_frame->camera_zoom, target_camera_zoom, frame->camera_lerp_rate); { f32 camera_scale = (f32)frame->draw_dims.x / (meters_per_draw_width * frame->camera_zoom); frame->world_to_ui_xf = XformFromScale(VEC2(camera_scale, camera_scale)); @@ -870,7 +869,7 @@ void V_TickForever(WaveLaneCtx *lane) { { V_Panel *panel = PushStruct(perm, V_Panel); - panel->key = UI_TransKey(); // TODO: Don't use transient keys for panels + panel->key = UI_RandKey(); // TODO: Don't use random keys for panels panel->axis = Axis_X; panel->pref_ratio = 1; panel->is_organizing_panel = 1; @@ -880,7 +879,7 @@ void V_TickForever(WaveLaneCtx *lane) { V_Panel *panel = PushStruct(perm, V_Panel); panel->parent = V.root_panel; - panel->key = UI_TransKey(); // TODO: Don't use transient keys + panel->key = UI_RandKey(); // TODO: Don't use random keys panel->axis = !panel->parent->axis; panel->pref_ratio = 0.25; DllQueuePush(panel->parent->first, panel->parent->last, panel); @@ -889,7 +888,7 @@ void V_TickForever(WaveLaneCtx *lane) { V_Window *window = PushStruct(perm, V_Window); window->panel = panel; - window->key = UI_TransKey(); // TODO: Don't use transient keys + window->key = UI_RandKey(); // TODO: Don't use random keys // window->is_tile_window = 1; DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); ++panel->windows_count; @@ -897,7 +896,7 @@ void V_TickForever(WaveLaneCtx *lane) { V_Window *window = PushStruct(perm, V_Window); window->panel = panel; - window->key = UI_TransKey(); // TODO: Don't use transient keys + window->key = UI_RandKey(); // TODO: Don't use random keys window->is_tile_window = 1; DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); ++panel->windows_count; @@ -908,7 +907,7 @@ void V_TickForever(WaveLaneCtx *lane) { V_Panel *panel = PushStruct(perm, V_Panel); panel->parent = V.root_panel; - panel->key = UI_TransKey(); // TODO: Don't use transient keys + panel->key = UI_RandKey(); // TODO: Don't use random keys panel->axis = !panel->parent->axis; DllQueuePush(panel->parent->first, panel->parent->last, panel); ++panel->parent->count; @@ -919,7 +918,7 @@ void V_TickForever(WaveLaneCtx *lane) // { // V_Window *window = PushStruct(perm, V_Window); // window->panel = panel; - // window->key = UI_TransKey(); // TODO: Don't use transient keys + // window->key = UI_RandKey(); // TODO: Don't use random keys // window->is_viewport_window = 1; // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // ++panel->windows_count; @@ -929,7 +928,7 @@ void V_TickForever(WaveLaneCtx *lane) // { // V_Panel *panel = PushStruct(perm, V_Panel); // panel->parent = V.root_panel; - // panel->key = UI_TransKey(); // TODO: Don't use transient keys + // panel->key = UI_RandKey(); // TODO: Don't use random keys // panel->axis = !panel->parent->axis; // DllQueuePush(panel->parent->first, panel->parent->last, panel); // ++panel->parent->count; @@ -937,7 +936,7 @@ void V_TickForever(WaveLaneCtx *lane) // { // V_Window *window = PushStruct(perm, V_Window); // window->panel = panel; - // window->key = UI_TransKey(); // TODO: Don't use transient keys + // window->key = UI_RandKey(); // TODO: Don't use random keys // // window->is_tile_window = 1; // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // ++panel->windows_count; @@ -945,7 +944,7 @@ void V_TickForever(WaveLaneCtx *lane) // { // V_Window *window = PushStruct(perm, V_Window); // window->panel = panel; - // window->key = UI_TransKey(); // TODO: Don't use transient keys + // window->key = UI_RandKey(); // TODO: Don't use random keys // window->is_tile_window = 1; // DllQueuePushNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); // ++panel->windows_count; @@ -1062,6 +1061,7 @@ void V_TickForever(WaveLaneCtx *lane) //- Build tab row f32 tab_spacing = 10; V_Window *active_window = 0; + V_Window *close_window = 0; { i64 window_idx = 0; UI_SetNext(Width, UI_GROW(1, 0)); @@ -1145,6 +1145,11 @@ void V_TickForever(WaveLaneCtx *lane) UI_SetNext(Width, UI_SHRINK(6, 0)); UI_SetNext(Height, UI_SHRINK(2, 0)); UI_BuildRowEx(close_key); + + if (close_rep.m1.presses) + { + close_window = window; + } } } UI_PopCP(UI_TopCP()); @@ -1241,6 +1246,15 @@ void V_TickForever(WaveLaneCtx *lane) } UI_PopCP(UI_TopCP()); } + //- Close window + if (close_window != 0) + { + V_Window *window = close_window; + // TODO: Add window to free list + // TODO: Remove panel if windowless + DllQueueRemoveNP(panel->first_window, panel->last_window, window, next_in_panel, prev_in_panel); + panel->windows_count -= 1; + } } UI_PopCP(UI_TopCP()); panel->active_window_idx = new_active_window_idx; diff --git a/src/pp/pp_vis/pp_vis_core.h b/src/pp/pp_vis/pp_vis_core.h index 640a47c6..1398aa16 100644 --- a/src/pp/pp_vis/pp_vis_core.h +++ b/src/pp/pp_vis/pp_vis_core.h @@ -240,7 +240,7 @@ Struct(V_Frame) f32 edit_camera_zoom; // Camera - f32 camera_lerp_ratio; + f32 camera_lerp_rate; Vec2 camera_pos; f32 camera_zoom; diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 9c9533eb..cec147e6 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -51,9 +51,9 @@ UI_Key UI_KeyF_(String fmt, ...) return key; } -UI_Key UI_TransKey(void) +UI_Key UI_RandKey(void) { - u64 seed = ++UI.transient_key_seed; + u64 seed = ++UI.rand_key_seed; UI_Key key = Zi; key.hash = RandU64FromSeed(seed); return key; @@ -486,13 +486,22 @@ UI_Style UI_PopStyle(UI_StyleDesc desc) //////////////////////////////////////////////////////////// //~ Command helpers -UI_Key UI_BuildBoxEx(UI_Key key) +UI_Key UI_BuildBoxEx(UI_Key semantic_key) { + UI_Key key = semantic_key; + b32 is_transient = 0; + if (UI_IsKeyNil(key)) + { + key = UI_RandKey(); + is_transient = 1; + } + UI_Frame *frame = UI_CurrentFrame(); UI_CmdNode *n = PushStruct(frame->arena, UI_CmdNode); n->cmd.kind = UI_CmdKind_BuildBox; { n->cmd.box.key = key; + n->cmd.box.is_transient = is_transient; n->cmd.box.parent = UI_UseTop(Parent); n->cmd.box.flags = UI_UseTop(Flags); n->cmd.box.pref_size[Axis_X] = UI_UseTop(Width); @@ -570,6 +579,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) { UI_Box *box = PushStruct(UI.box_arena, UI_Box); box->key = UI_RootKey; + box->gen = 1; UI.boxes_count += 1; UI_BoxBin *bin = &UI.box_bins[box->key.hash % countof(UI.box_bins)]; bin->first = box; @@ -605,6 +615,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) i64 dt_ns = now_ns - last_frame->time_ns; frame->time_ns = now_ns; frame->dt_ns = dt_ns; + frame->dt = SecondsFromNs(frame->dt_ns); frame->tick = UI.current_frame_tick; } @@ -625,8 +636,6 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) ControllerEventsArray controller_events = frame->window_frame.controller_events; frame->cursor_pos = last_frame->cursor_pos; - f64 dt = SecondsFromNs(frame->dt_ns); - f64 inv_dt = 1.0 / dt; // Locate boxes UI_Box *hovered_box = 0; @@ -651,18 +660,18 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) b32 is_cursor_in_box = 0; { // TODO: More efficient test. This logic is just copied from the renderer's SDF function for now. - Vec2 p0 = box->rect.p0; - Vec2 p1 = box->rect.p1; + Vec2 p0 = box->draw_rect.p0; + Vec2 p1 = box->draw_rect.p1; Vec2 point = frame->cursor_pos; b32 is_corner = 0; f32 non_corner_edge_dist = MinF32(MinF32(point.x - p0.x, p1.x - point.x), MinF32(point.y - p0.y, p1.y - point.y)); f32 corner_edge_dist = non_corner_edge_dist; if (non_corner_edge_dist >= 0) { - f32 tl_radius = box->rounding_tl; - f32 tr_radius = box->rounding_tr; - f32 br_radius = box->rounding_br; - f32 bl_radius = box->rounding_bl; + f32 tl_radius = box->draw_rounding_tl; + f32 tr_radius = box->draw_rounding_tr; + f32 br_radius = box->draw_rounding_br; + f32 bl_radius = box->draw_rounding_bl; Vec2 tl = VEC2(p0.x + tl_radius, p0.y + tl_radius); Vec2 tr = VEC2(p1.x - tr_radius, p0.y + tr_radius); Vec2 br = VEC2(p1.x - br_radius, p1.y - br_radius); @@ -705,7 +714,7 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) { if (hovered_box) { - hovered_box->report.last_down_mouse_offset = SubVec2(frame->cursor_pos, hovered_box->rect.p0); + hovered_box->report.last_down_mouse_offset = SubVec2(frame->cursor_pos, hovered_box->draw_rect.p0); if (cev.button == Button_M1) { ++hovered_box->report.m1.downs; @@ -786,15 +795,15 @@ UI_Frame *UI_BeginFrame(UI_FrameFlag frame_flags, Vec4 swapchain_color) 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 * dt); - f32 active_blend_rate = target_active == 1 ? 1 : (15 * dt); - f32 hovered_blend_rate = target_hovered == 1 ? 1 : (15 * dt); - f32 selected_blend_rate = target_selected == 1 ? 1 : (15 * 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->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; + report->screen_rect = box->draw_rect; } frame->hovered_box = hovered_box ? hovered_box->key : UI_NilKey; @@ -882,8 +891,10 @@ void UI_EndFrame(UI_Frame *frame) { // Allocate new box box = UI.first_free_box; + i64 old_gen = 0; if (box) { + old_gen = box->gen; SllStackPop(UI.first_free_box); ZeroStruct(box); } @@ -892,6 +903,8 @@ void UI_EndFrame(UI_Frame *frame) box = PushStruct(UI.box_arena, UI_Box); } box->key = key; + box->old_gen = old_gen; + box->gen = old_gen + 1; DllQueuePushNP(bin->first, bin->last, box, next_in_bin, prev_in_bin); ++UI.boxes_count; } @@ -914,7 +927,7 @@ void UI_EndFrame(UI_Frame *frame) UI_Key key = cmd.box.key; if (UI_MatchKey(key, UI_NilKey)) { - key = UI_TransKey(); + key = UI_RandKey(); } UI_Box *box = UI_BoxFromKey(key); @@ -967,6 +980,8 @@ void UI_EndFrame(UI_Frame *frame) ////////////////////////////// //- Prune cached boxes + i64 box_grace_frames = 10; + { u64 prunes_count = 0; UI_Box **prunes = PushStructsNoZero(scratch.arena, UI_Box *, UI.boxes_count); @@ -977,7 +992,12 @@ void UI_EndFrame(UI_Frame *frame) UI_Box *box = ir.box; if (box->last_build_tick < frame->tick) { - prunes[prunes_count++] = box; + box->desc.pref_size[Axis_X] = UI_PIX(0, 0); + // box->desc.pref_size[Axis_Y] = UI_PIX(0, 0); + if (box->desc.is_transient || (frame->tick - box->last_build_tick > box_grace_frames)) + { + prunes[prunes_count++] = box; + } } } } @@ -1038,7 +1058,9 @@ void UI_EndFrame(UI_Frame *frame) pre_index += 1; // Reset layout data - ZeroStruct(&box->layout); + box->cursor = 0; + ZeroStructs(box->final_children_size_accum, countof(box->final_children_size_accum)); + ZeroStructs(box->target_dims, countof(box->target_dims)); } else { @@ -1060,7 +1082,7 @@ void UI_EndFrame(UI_Frame *frame) UI_Size pref_size = box->desc.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Pixel) { - box->layout.solved_dims[axis] = pref_size.v; + box->target_dims[axis] = pref_size.v; } else if (pref_size.kind == UI_SizeKind_Shrink && AnyBit(box->desc.flags, UI_BoxFlag_DrawText)) { @@ -1074,7 +1096,7 @@ void UI_EndFrame(UI_Frame *frame) { text_size = box->glyph_run.font_ascent + box->glyph_run.font_descent; } - box->layout.solved_dims[axis] = text_size + (pref_size.v * 2); + box->target_dims[axis] = text_size + (pref_size.v * 2); } } } @@ -1097,11 +1119,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))) { // Match independent ancestor - match_size = ancestor->layout.solved_dims[axis]; + match_size = ancestor->target_dims[axis]; found_match = 1; } } - box->layout.solved_dims[axis] = match_size * pref_size.v; + box->target_dims[axis] = match_size * pref_size.v; } } } @@ -1122,15 +1144,15 @@ void UI_EndFrame(UI_Frame *frame) { if (axis == box->desc.child_layout_axis) { - accum += child->layout.solved_dims[axis]; + accum += child->target_dims[axis]; } else { - accum = MaxF32(child->layout.solved_dims[axis], accum); + accum = MaxF32(child->target_dims[axis], accum); } } } - box->layout.solved_dims[axis] = accum + (pref_size.v * 2); + box->target_dims[axis] = accum + (pref_size.v * 2); } } } @@ -1145,7 +1167,7 @@ void UI_EndFrame(UI_Frame *frame) UI_Size pref_size = box->desc.pref_size[axis]; if (pref_size.kind == UI_SizeKind_Grow) { - box->layout.solved_dims[axis] = box->parent->layout.solved_dims[axis] * pref_size.v; + box->target_dims[axis] = box->parent->target_dims[axis] * pref_size.v; } } } @@ -1156,7 +1178,7 @@ void UI_EndFrame(UI_Frame *frame) UI_Box *box = boxes_pre[pre_index]; for (Axis axis = 0; axis < Axis_COUNTXY; ++axis) { - f32 box_size = box->layout.solved_dims[axis]; + f32 box_size = box->target_dims[axis]; // Solve non-floating violations { f32 size_accum = 0; @@ -1165,7 +1187,7 @@ void UI_EndFrame(UI_Frame *frame) { if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { - f32 size = child->layout.solved_dims[axis]; + f32 size = child->target_dims[axis]; f32 strictness = child->desc.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); if (axis == box->desc.child_layout_axis) @@ -1188,7 +1210,7 @@ void UI_EndFrame(UI_Frame *frame) { if (!AnyBit(child->desc.flags, UI_BoxFlag_Floating)) { - f32 size = child->layout.solved_dims[axis]; + f32 size = child->target_dims[axis]; f32 strictness = child->desc.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); f32 new_size = size; @@ -1205,24 +1227,24 @@ void UI_EndFrame(UI_Frame *frame) } } adjusted_size_accum += new_size; - child->layout.solved_dims[axis] = new_size; + child->target_dims[axis] = new_size; } } size_accum = adjusted_size_accum; } - box->layout.final_children_size_accum[axis] = size_accum; + box->final_children_size_accum[axis] = size_accum; } // Solve floating violations 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)) { - f32 size = child->layout.solved_dims[axis]; + f32 size = child->target_dims[axis]; if (size > box_size) { f32 strictness = child->desc.pref_size[axis].strictness; f32 flex = size * (1.0 - strictness); - child->layout.solved_dims[axis] = MaxF32(size - flex, box_size); + child->target_dims[axis] = MaxF32(size - flex, box_size); } } } @@ -1235,29 +1257,51 @@ void UI_EndFrame(UI_Frame *frame) UI_Box *box = boxes_pre[pre_index]; UI_Box *parent = box->parent; + f32 lerp_rate = 20.0 * frame->dt; + if (box->gen != box->old_gen) + { + box->draw_dims[Axis_X] = 0; + box->draw_dims[Axis_Y] = 0; + } + if (box->desc.is_transient) + { + lerp_rate = 1; + } + lerp_rate = ClampF32(lerp_rate, 0, 1); + + + box->draw_dims[Axis_X] = LerpF32(box->draw_dims[Axis_X], box->target_dims[Axis_X], lerp_rate); + box->draw_dims[Axis_Y] = LerpF32(box->draw_dims[Axis_Y], box->target_dims[Axis_Y], lerp_rate); + + Rng2 target_rect = Zi; + f32 target_rounding_tl = 0; + f32 target_rounding_tr = 0; + f32 target_rounding_br = 0; + f32 target_rounding_bl = 0; + // Initialize layout cursor based on alignment { Axis axis = box->desc.child_layout_axis; UI_AxisAlignment alignment = box->desc.child_alignment[axis]; - f32 box_size = box->layout.solved_dims[axis]; - f32 size_accum = box->layout.final_children_size_accum[axis]; + f32 box_size = box->draw_dims[axis]; + f32 size_accum = box->final_children_size_accum[axis]; switch(alignment) { default: break; case UI_AxisAlignment_Center: { - box->layout.cursor = box_size / 2 - size_accum / 2; + box->cursor = box_size / 2 - size_accum / 2; } break; case UI_AxisAlignment_End: { - box->layout.cursor = box_size - size_accum; + box->cursor = box_size - size_accum; } break; } } // Position { - f32 *dims_arr = box->layout.solved_dims; + f32 *dims_arr = box->draw_dims; Vec2 dims_vec = VEC2(dims_arr[0], dims_arr[1]); Vec2 final_pos = Zi; @@ -1265,23 +1309,23 @@ void UI_EndFrame(UI_Frame *frame) if (AnyBit(box->desc.flags, UI_BoxFlag_Floating)) { Vec2 offset = box->desc.floating_pos; - final_pos = AddVec2(parent->rect.p0, offset); + final_pos = AddVec2(parent->draw_rect.p0, offset); if (!AnyBit(box->desc.flags, UI_BoxFlag_NoFloatingClamp)) { { - f32 overshoot = MaxF32(0, (final_pos.x + dims_vec.x) - parent->rect.p1.x); - final_pos.x = MaxF32(parent->rect.p0.x, final_pos.x - overshoot); + f32 overshoot = MaxF32(0, (final_pos.x + dims_vec.x) - parent->draw_rect.p1.x); + final_pos.x = MaxF32(parent->draw_rect.p0.x, final_pos.x - overshoot); } { - f32 overshoot = MaxF32((final_pos.y + dims_vec.y) - parent->rect.p1.y, 0); - final_pos.y = MaxF32(parent->rect.p0.y, final_pos.y - overshoot); + f32 overshoot = MaxF32((final_pos.y + dims_vec.y) - parent->draw_rect.p1.y, 0); + final_pos.y = MaxF32(parent->draw_rect.p0.y, final_pos.y - overshoot); } } } // Non-floating box position else if (parent) { - f32 layout_cursor = parent->layout.cursor; + f32 layout_cursor = parent->cursor; f32 offset[2] = Zi; // Compute offset in layout direction { @@ -1297,34 +1341,34 @@ void UI_EndFrame(UI_Frame *frame) default: break; case UI_AxisAlignment_Center: { - f32 parent_size = parent->layout.solved_dims[axis]; + f32 parent_size = parent->draw_dims[axis]; f32 box_size = dims_arr[axis]; offset[axis] = parent_size / 2 - box_size / 2; } break; case UI_AxisAlignment_End: { - f32 parent_size = parent->layout.solved_dims[axis]; + f32 parent_size = parent->draw_dims[axis]; f32 box_size = dims_arr[axis]; offset[axis] = parent_size - box_size; } break; } } - final_pos.x = parent->rect.p0.x + offset[0]; - final_pos.y = parent->rect.p0.y + offset[1]; - parent->layout.cursor += dims_arr[parent->desc.child_layout_axis]; + final_pos.x = parent->draw_rect.p0.x + offset[0]; + final_pos.y = parent->draw_rect.p0.y + offset[1]; + parent->cursor += dims_arr[parent->desc.child_layout_axis]; } // Submit position Vec2 rounded_final_pos = RoundVec2(final_pos); Vec2 rounded_dims = RoundVec2(dims_vec); - box->rect.p0 = FloorVec2(rounded_final_pos); - box->rect.p1 = AddVec2(rounded_final_pos, rounded_dims); + target_rect.p0 = FloorVec2(rounded_final_pos); + target_rect.p1 = AddVec2(rounded_final_pos, rounded_dims); } // Rounding { UI_Round rounding = box->desc.rounding; - Vec2 half_dims = MulVec2(SubVec2(box->rect.p1, box->rect.p0), 0.5); + Vec2 half_dims = MulVec2(SubVec2(target_rect.p1, target_rect.p0), 0.5); f32 min_half_dims = MinF32(half_dims.x, half_dims.y); f32 final_rounding_tl = 0; f32 final_rounding_tr = 0; @@ -1352,22 +1396,61 @@ void UI_EndFrame(UI_Frame *frame) if (parent && !AllBits(box->desc.flags, UI_BoxFlag_Floating | UI_BoxFlag_NoFloatingClamp)) { - Vec2 vtl = SubVec2(VEC2(parent->rect.p0.x, parent->rect.p0.y), VEC2(box->rect.p0.x, box->rect.p0.y)); - Vec2 vtr = SubVec2(VEC2(parent->rect.p1.x, parent->rect.p0.y), VEC2(box->rect.p1.x, box->rect.p0.y)); - Vec2 vbr = SubVec2(VEC2(parent->rect.p1.x, parent->rect.p1.y), VEC2(box->rect.p1.x, box->rect.p1.y)); - Vec2 vbl = SubVec2(VEC2(parent->rect.p0.x, parent->rect.p1.y), VEC2(box->rect.p0.x, box->rect.p1.y)); - final_rounding_tl = MaxF32(final_rounding_tl, parent->rounding_tl - Vec2Len(vtl)); - final_rounding_tr = MaxF32(final_rounding_tr, parent->rounding_tr - Vec2Len(vtr)); - final_rounding_br = MaxF32(final_rounding_br, parent->rounding_br - Vec2Len(vbr)); - final_rounding_bl = MaxF32(final_rounding_bl, parent->rounding_bl - Vec2Len(vbl)); + Vec2 vtl = SubVec2(VEC2(parent->draw_rect.p0.x, parent->draw_rect.p0.y), VEC2(target_rect.p0.x, target_rect.p0.y)); + Vec2 vtr = SubVec2(VEC2(parent->draw_rect.p1.x, parent->draw_rect.p0.y), VEC2(target_rect.p1.x, target_rect.p0.y)); + Vec2 vbr = SubVec2(VEC2(parent->draw_rect.p1.x, parent->draw_rect.p1.y), VEC2(target_rect.p1.x, target_rect.p1.y)); + Vec2 vbl = SubVec2(VEC2(parent->draw_rect.p0.x, parent->draw_rect.p1.y), VEC2(target_rect.p0.x, target_rect.p1.y)); + final_rounding_tl = MaxF32(final_rounding_tl, parent->draw_rounding_tl - Vec2Len(vtl)); + final_rounding_tr = MaxF32(final_rounding_tr, parent->draw_rounding_tr - Vec2Len(vtr)); + final_rounding_br = MaxF32(final_rounding_br, parent->draw_rounding_br - Vec2Len(vbr)); + final_rounding_bl = MaxF32(final_rounding_bl, parent->draw_rounding_bl - Vec2Len(vbl)); } // Submit rounding - box->rounding_tl = final_rounding_tl; - box->rounding_tr = final_rounding_tr; - box->rounding_br = final_rounding_br; - box->rounding_bl = final_rounding_bl; + target_rounding_tl = final_rounding_tl; + target_rounding_tr = final_rounding_tr; + target_rounding_br = final_rounding_br; + target_rounding_bl = final_rounding_bl; } + + // Interpolate target into final rect + // { + // f32 lerp_rate = 30.0 * frame->dt; + // if (box->gen != box->old_gen) + // { + // lerp_rate = 1; + // } + + // box->draw_rect.p0 = LerpVec2(box->draw_rect.p0, box->target_rect.p0, lerp_rate); + // box->draw_rect.p1 = LerpVec2(box->draw_rect.p1, box->target_rect.p1, lerp_rate); + // box->draw_rounding_tl = LerpF32(box->draw_rounding_tl, box->target_rounding_tl, lerp_rate); + // box->draw_rounding_tr = LerpF32(box->draw_rounding_tr, box->target_rounding_tr, lerp_rate); + // box->draw_rounding_br = LerpF32(box->draw_rounding_br, box->target_rounding_br, lerp_rate); + // box->draw_rounding_bl = LerpF32(box->draw_rounding_bl, box->target_rounding_bl, lerp_rate); + // } + + + + + // { + // box->draw_rect.p0 = LerpVec2(box->draw_rect.p0, target_rect.p0, lerp_rate); + // box->draw_rect.p1 = LerpVec2(box->draw_rect.p1, target_rect.p1, lerp_rate); + // box->draw_rounding_tl = LerpF32(box->draw_rounding_tl, target_rounding_tl, lerp_rate); + // box->draw_rounding_tr = LerpF32(box->draw_rounding_tr, target_rounding_tr, lerp_rate); + // box->draw_rounding_br = LerpF32(box->draw_rounding_br, target_rounding_br, lerp_rate); + // box->draw_rounding_bl = LerpF32(box->draw_rounding_bl, target_rounding_bl, lerp_rate); + // } + + { + box->draw_rect.p0 = target_rect.p0; + box->draw_rect.p1 = target_rect.p1; + box->draw_rounding_tl = target_rounding_tl; + box->draw_rounding_tr = target_rounding_tr; + box->draw_rounding_br = target_rounding_br; + box->draw_rounding_bl = target_rounding_bl; + } + + box->gen = box->old_gen; } ////////////////////////////// @@ -1384,24 +1467,24 @@ void UI_EndFrame(UI_Frame *frame) UI_Box *box = boxes_pre[pre_index]; b32 is_visible = 1; is_visible = is_visible && (box->desc.tint.w != 0); - is_visible = is_visible && (box->rect.p1.x > box->rect.p0.x); - is_visible = is_visible && (box->rect.p1.y > box->rect.p0.y); + is_visible = is_visible && (box->draw_rect.p1.x > box->draw_rect.p0.x); + is_visible = is_visible && (box->draw_rect.p1.y > box->draw_rect.p0.y); if (is_visible || AnyBit(frame->frame_flags, UI_FrameFlag_Debug)) { // Box rect { UI_DRect *rect = PushStruct(frame->rects_arena, UI_DRect); - rect->bounds = box->rect; + rect->bounds = box->draw_rect; rect->background_lin = LinearFromSrgb(box->desc.background_color); rect->border_lin = LinearFromSrgb(box->desc.border_color); rect->debug_lin = LinearFromSrgb(box->desc.debug_color); rect->tint_lin = LinearFromSrgb(box->desc.tint); rect->border = box->desc.border; - rect->tl_rounding = box->rounding_tl; - rect->tr_rounding = box->rounding_tr; - rect->br_rounding = box->rounding_br; - rect->bl_rounding = box->rounding_bl; + rect->tl_rounding = box->draw_rounding_tl; + rect->tr_rounding = box->draw_rounding_tr; + rect->br_rounding = box->draw_rounding_br; + rect->bl_rounding = box->draw_rounding_bl; rect->tex = box->raw_texture; rect->tex_slice_uv = box->raw_texture_slice_uv; } @@ -1410,7 +1493,7 @@ void UI_EndFrame(UI_Frame *frame) GC_Run raw_run = box->glyph_run; if (AnyBit(box->desc.flags, UI_BoxFlag_DrawText) && raw_run.ready) { - f32 max_baseline = DimsFromRng2(box->rect).x; + f32 max_baseline = DimsFromRng2(box->draw_rect).x; b32 should_truncate = raw_run.baseline_length > max_baseline && !AnyBit(box->desc.flags, UI_BoxFlag_NoTextTruncation); // Truncate run @@ -1466,22 +1549,22 @@ void UI_EndFrame(UI_Frame *frame) f32 font_descent = raw_run.font_descent; f32 cap = raw_run.font_cap; f32 baseline_height = ascent + font_descent; - Vec2 box_dims = DimsFromRng2(box->rect); + Vec2 box_dims = DimsFromRng2(box->draw_rect); Vec2 baseline = Zi; switch (x_alignment) { case UI_AxisAlignment_Start: { - baseline.x = box->rect.p0.x; + baseline.x = box->draw_rect.p0.x; } break; case UI_AxisAlignment_End: { - baseline.x = box->rect.p1.x; + baseline.x = box->draw_rect.p1.x; baseline.x -= final_baseline_length; } break; case UI_AxisAlignment_Center: { - baseline.x = box->rect.p0.x; + baseline.x = box->draw_rect.p0.x; baseline.x += (box_dims.x - final_baseline_length) / 2; } break; } @@ -1489,17 +1572,17 @@ void UI_EndFrame(UI_Frame *frame) { case UI_AxisAlignment_Start: { - baseline.y = box->rect.p0.y; + baseline.y = box->draw_rect.p0.y; baseline.y += ascent; } break; case UI_AxisAlignment_End: { - baseline.y = box->rect.p1.y; + baseline.y = box->draw_rect.p1.y; baseline.y -= font_descent; } break; case UI_AxisAlignment_Center: { - baseline.y = box->rect.p0.y; + baseline.y = box->draw_rect.p0.y; baseline.y += box_dims.y / 2; baseline.y += cap / 2; } break; diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 159b1409..123ef49c 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -218,6 +218,8 @@ Struct(UI_BoxDesc) UI_Key key; UI_Key parent; + b32 is_transient; + UI_Size pref_size[Axis_COUNTXY]; UI_Round rounding; Vec4 background_color; @@ -267,6 +269,9 @@ Struct(UI_Box) UI_Report report; i64 last_build_tick; + i64 old_gen; + i64 gen; + //- Tree links UI_Box *parent; UI_Box *first; @@ -286,19 +291,17 @@ Struct(UI_Box) u64 post_index; //- Layout data - struct - { - f32 cursor; - f32 solved_dims[Axis_COUNTXY]; - f32 final_children_size_accum[Axis_COUNTXY]; - } layout; + f32 cursor; + f32 final_children_size_accum[Axis_COUNTXY]; + f32 target_dims[Axis_COUNTXY]; + f32 draw_dims[Axis_COUNTXY]; //- Layout results - Rng2 rect; - f32 rounding_tl; - f32 rounding_tr; - f32 rounding_br; - f32 rounding_bl; + Rng2 draw_rect; + f32 draw_rounding_tl; + f32 draw_rounding_tr; + f32 draw_rounding_br; + f32 draw_rounding_bl; }; Struct(UI_BoxBin) @@ -354,6 +357,7 @@ Struct(UI_Frame) i64 tick; i64 time_ns; i64 dt_ns; + f64 dt; // Control Vec2 cursor_pos; @@ -385,7 +389,7 @@ Struct(UI_Ctx) UI_BoxBin box_bins[Kibi(256)]; UI_Box *first_free_box; - u64 transient_key_seed; + u64 rand_key_seed; i64 current_frame_tick; UI_Frame frames[2]; @@ -411,7 +415,7 @@ b32 UI_IsKeyNil(UI_Key key); UI_Key UI_KeyFromString(String str); UI_Key UI_KeyF_(String fmt, ...); #define UI_KeyF(fmt_cstr, ...) UI_KeyF_(StringFromCstrNoLimit(fmt_cstr), __VA_ARGS__, FmtEnd) -UI_Key UI_TransKey(void); +UI_Key UI_RandKey(void); UI_Box *UI_BoxFromKey(UI_Key key); //////////////////////////////////////////////////////////// @@ -480,8 +484,8 @@ UI_Style UI_PopStyle(UI_StyleDesc desc); //////////////////////////////////////////////////////////// //~ Command helpers -UI_Key UI_BuildBoxEx(UI_Key key); -#define UI_BuildBox() UI_BuildBoxEx(UI_TransKey()) +UI_Key UI_BuildBoxEx(UI_Key semantic_key); +#define UI_BuildBox() UI_BuildBoxEx(UI_NilKey) void UI_SetRawTexture(UI_Key key, G_Texture2DRef tex, Rng2 uv); diff --git a/src/ui/ui_extras.h b/src/ui/ui_extras.h index 713caea1..c903d27c 100644 --- a/src/ui/ui_extras.h +++ b/src/ui/ui_extras.h @@ -17,5 +17,5 @@ UI_Key UI_BuildDivider(UI_Size size, Vec4 color, Axis axis); UI_Key UI_BuildRowEx(UI_Key key); UI_Key UI_BuildColumnEx(UI_Key key); -#define UI_BuildRow() UI_BuildRowEx(UI_TransKey()) -#define UI_BuildColumn() UI_BuildColumnEx(UI_TransKey()) +#define UI_BuildRow() UI_BuildRowEx(UI_NilKey) +#define UI_BuildColumn() UI_BuildColumnEx(UI_NilKey)