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>
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
#include "ui/material/scroll_edge_fade.h"
|
||||
#include "ui/node_status_banner.h"
|
||||
#include "ui/staleness_badge.h"
|
||||
#include "ui/effects/effect_clock.h"
|
||||
#include "ui/notifications.h"
|
||||
#include "data/seed_migration_resume.h"
|
||||
#include "data/pin_vault_policy.h"
|
||||
@@ -13492,6 +13493,26 @@ void testPoolFeeParsing()
|
||||
EXPECT_FALSE(ok); // string, not number
|
||||
}
|
||||
|
||||
void testEffectClock() {
|
||||
using namespace dragonx::ui::effects;
|
||||
const double t7d = 7 * 86400.0, dt = 1.0 / 60.0;
|
||||
// smooth after 7 days: consecutive frames advance by rate*dt (0.3/60 = 0.005 cycle)
|
||||
for (int k = 0; k < 120; ++k) {
|
||||
float a = cyclePhase(t7d + k * dt, 0.3), b = cyclePhase(t7d + (k + 1) * dt, 0.3);
|
||||
float d = b - a; if (d < -0.5f) d += 1.0f; // wrap
|
||||
EXPECT_NEAR(d, 0.005f, 1e-4f);
|
||||
}
|
||||
// legacy float clock pins the bug: at 30 days one float ULP is 0.25 s
|
||||
const double t30 = 30 * 86400.0;
|
||||
EXPECT_TRUE((float)(t30 + 0.5 / 60.0) == (float)(t30 + 1.5 / 60.0));
|
||||
EXPECT_TRUE(cyclePhase(t30 + 0.5 / 60.0, 0.3) != cyclePhase(t30 + 1.5 / 60.0, 0.3));
|
||||
// range and negative offsets
|
||||
EXPECT_NEAR(cyclePhase(1.0, 0.0, -0.25), 0.75f, 1e-6f);
|
||||
for (double t = 0; t < 1e7; t += 123457.7) { float p = cyclePhase(t, 0.37, -0.1); EXPECT_TRUE(p >= 0.0f && p < 1.0f); }
|
||||
EXPECT_NEAR(cycleSin(t7d + 0.25, 1.0), 1.0f, 1e-5f);
|
||||
EXPECT_NEAR(radSin(1e6, 0.0, 1.5707963267948966), 1.0f, 1e-6f);
|
||||
}
|
||||
|
||||
// The effective pool list = official pools ∪ saved favorites ∪ current custom pool,
|
||||
// endpoint-deduped, with synthetic user rows flagged official=false.
|
||||
void testEffectivePools()
|
||||
@@ -18227,6 +18248,7 @@ int main()
|
||||
testPoolHashrateParsing();
|
||||
testPoolFeeParsing();
|
||||
testEffectivePools();
|
||||
testEffectClock();
|
||||
testFormatFeePercent();
|
||||
testPoolWeightedSelection();
|
||||
testCoalescingWriter();
|
||||
|
||||
Reference in New Issue
Block a user