Files
aego/tests/integration/camera_rewind_test.go
sanspie 55871f666b Stage 11e: rewind keyframes (D346)
Adaptive keyframes with age thinning, a scrub cache, allocation-free replay, idle pacing in paused Play; job workers start before the engine returns.
2026-10-25 15:31:22 +03:00

62 lines
1.6 KiB
Go

package integration
import (
"testing"
"aego/editor/core/play"
"aego/gpu"
"aego/modules/camera"
"aego/render/rt"
)
// A zone blend that starts while a seek replays undrawn ticks must not blend from a zero or stale pose.
func TestCameraRewindKeepsZoom(t *testing.T) {
for _, every := range []uint64{60, 1 << 30} {
s, pc := rewindSession(t)
pc.SetKeyEvery(every)
e := s.Host.Engine
pool := rt.New(e.GPU(), gpu.TexSRGBA8, "test.camera")
tgt, err := pool.Resize(nil, 320, 180, true)
if err != nil {
t.Fatal(err)
}
render := func() float32 {
frame := e.GPU().BeginFrame(320, 180)
if err := s.Renderer.BeginFrame(frame, 320, 180, 1); err != nil {
t.Fatal(err)
}
pc.Render(tgt)
s.Renderer.EndFrame()
e.GPU().EndFrame()
return camera.Of(pc.World()).Render("").Zoom
}
zoom := map[int]float32{}
lo, hi := float32(1e9), float32(0)
drive(e, pc, 0, 800, func(f int) {
z := render()
zoom[f] = z
lo, hi = min(lo, z), max(hi, z)
})
// Without keys, seeks jump past the scrub cache (TransientSpan) so each one replays from the start.
step := 13
if every > 1000 {
step = play.TransientSpan + 13
}
for n := 790; n > 0; n -= step {
if err := pc.Seek(n); err != nil {
t.Fatal(err)
}
z := render()
if z < lo-0.01 || z > hi+0.01 {
t.Fatalf("keys every %d, seek %d: zoom %v outside the run's %v..%v", every, n, z, lo, hi)
}
// Restoring a keyframe finishes unscaled blends (D306); a replay from the start keeps them.
if every > 1000 && (z < zoom[n]-0.01 || z > zoom[n]+0.01) {
t.Fatalf("replayed seek %d: zoom %v, was %v", n, z, zoom[n])
}
}
pool.Release(tgt)
pool.Close()
}
}