The theme effects stored their animation time in a 32-bit float taken from the ImGui clock. After a few days of uptime a float can no longer resolve a single frame step, so every oscillation, drift and sweep began to stutter, snapping forward a frame at a time instead of moving smoothly. - The clock is now held as a double, and the phase/oscillator maths runs through a small set of shared helpers that reduce the argument in double before returning a float. A float clock at 30 days steps by a quarter second per ULP; the double clock stays frame-accurate. - Hue cycling, the rainbow and gradient borders, shimmer, specular glare, glow pulse, edge trace, embers, the sandstorm and the viewport wash all use the shared helpers, so their timing no longer drifts with uptime. Tests: the helpers advance smoothly after seven days, pin the legacy float breakdown at 30 days, and stay in range for negative offsets. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
35 lines
1.4 KiB
C++
35 lines
1.4 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
#pragma once
|
|
#include <cmath>
|
|
|
|
namespace dragonx { namespace ui { namespace effects {
|
|
|
|
constexpr double kEffectTwoPi = 6.283185307179586476925286766559;
|
|
|
|
/// Fractional part in [0,1) of t*rate + offset, evaluated in double so the result stays
|
|
/// smooth after days of uptime (a float clock steps at one-frame granularity from ~3 days).
|
|
inline double cyclePhaseD(double t, double rate, double offset = 0.0) {
|
|
double p = std::fmod(t * rate + offset, 1.0);
|
|
if (p < 0.0) p += 1.0;
|
|
if (p >= 1.0) p = 0.0; // p was -tiny: p + 1.0 rounded up to 1.0
|
|
return p;
|
|
}
|
|
inline float cyclePhase(double t, double rate, double offset = 0.0) {
|
|
return static_cast<float>(cyclePhaseD(t, rate, offset));
|
|
}
|
|
/// sin(2*pi*(t*cycles + offset)) - oscillator whose speed is in cycles per second.
|
|
inline float cycleSin(double t, double cycles, double offset = 0.0) {
|
|
return static_cast<float>(std::sin(kEffectTwoPi * cyclePhaseD(t, cycles, offset)));
|
|
}
|
|
/// sin/cos(t*omega + offset), omega in rad/s; argument reduced in double.
|
|
inline float radSin(double t, double omega, double offset = 0.0) {
|
|
return static_cast<float>(std::sin(std::fmod(t * omega + offset, kEffectTwoPi)));
|
|
}
|
|
inline float radCos(double t, double omega, double offset = 0.0) {
|
|
return static_cast<float>(std::cos(std::fmod(t * omega + offset, kEffectTwoPi)));
|
|
}
|
|
|
|
}}} // namespace
|