Files
ObsidianDragon/src/ui/effects/effect_clock.h
T
DanSandClaude Opus 4.8 fbc429f914 perf(effects): keep the theme animation clock in double precision
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>
2026-10-13 13:30:20 -05:00

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