#pragma once #include #include #include namespace dragonx { namespace ui { // One step of a displayed balance rolling toward its real value. Returns true while still moving. // // The per-step factor dt*speed is clamped to 1, so a long frame (the main loop idles between frames, // and dt reaches the 0.25 s clamp) lands on the target instead of overshooting: the old unclamped // `disp += diff*dt*speed` flipped between two wrong values at dt*speed == 2 and diverged to inf/NaN // at Reduce Motion's speed of 999. `instant` (Reduce Motion) snaps to the target. A non-finite display // value recovers on the next step, and the relative snap keeps the roll from stalling a few ULPs short // of large targets (>= 2^23), where `disp + diff*a` stops changing. inline bool StepDisplayLerp(double& disp, double target, float dt, float speed, bool instant) { if (instant || !std::isfinite(disp) || !std::isfinite(target)) { disp = target; return false; } const double diff = target - disp; if (diff == 0.0) return false; const double a = std::clamp(static_cast(dt) * static_cast(speed), 0.0, 1.0); const double next = disp + diff * a; if (next == disp || std::abs(target - next) <= std::max(5e-9, 4.0 * std::abs(target) * DBL_EPSILON)) { disp = target; return false; } disp = next; return true; } } // namespace ui } // namespace dragonx