fix: align animation pacing and transforms with native
This commit is contained in:
@@ -20,10 +20,47 @@ public class FrameClockTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EffectiveBudget_ScalesBySpeed_AndFloorsAtOne()
|
||||
public void Advance_RetainsFractionalMillisecondsAtSlowSpeed()
|
||||
{
|
||||
Assert.Equal(30, new FrameClock { OpsPerFrame = 30, Speed = 1.0 }.EffectiveBudget);
|
||||
Assert.Equal(120, new FrameClock { OpsPerFrame = 30, Speed = 4.0 }.EffectiveBudget);
|
||||
Assert.Equal(1, new FrameClock { OpsPerFrame = 0, Speed = 1.0 }.EffectiveBudget);
|
||||
var c = new FrameClock { Speed = 0.1 };
|
||||
for (int i = 0; i < 10; i++) c.Advance(1.0 / 144.0);
|
||||
Assert.Equal(6, c.NowMs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WallClockPacer_RateDoesNotDependOnRenderCallbackCount()
|
||||
{
|
||||
static long Simulate(int callbacks)
|
||||
{
|
||||
var c = new FrameClock();
|
||||
var p = new WallClockOpPacer(c);
|
||||
long ops = 0;
|
||||
p.OpcodeCompleted(); ops++;
|
||||
for (int frame = 0; frame < callbacks; frame++)
|
||||
{
|
||||
c.Advance(1.0 / callbacks);
|
||||
while (p.CanRunNext) { p.OpcodeCompleted(); ops++; }
|
||||
}
|
||||
return ops;
|
||||
}
|
||||
|
||||
long at60 = Simulate(60), at144 = Simulate(144), at240 = Simulate(240);
|
||||
Assert.InRange(at60, 198, 202);
|
||||
Assert.InRange(at144, 198, 202);
|
||||
Assert.InRange(at240, 198, 202);
|
||||
Assert.InRange(System.Math.Abs(at60 - at144), 0, 2);
|
||||
Assert.InRange(System.Math.Abs(at60 - at240), 0, 2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WallClockPacer_ResetDropsParkedTimeCredit()
|
||||
{
|
||||
var c = new FrameClock();
|
||||
var p = new WallClockOpPacer(c);
|
||||
p.OpcodeCompleted();
|
||||
c.Advance(10);
|
||||
p.Reset();
|
||||
p.OpcodeCompleted();
|
||||
Assert.False(p.CanRunNext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,23 @@ public class GfxAnimationTests
|
||||
Assert.Equal(1, vm.Gfx.AnimClockGeneration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ResetAnimClock_DispatchClearsOnlyGlobalServiceClock()
|
||||
{
|
||||
var t = T();
|
||||
var scene = ScriptAssembler.Assemble(t, "CLOCKRESET", new List<(int, Operand[])>
|
||||
{
|
||||
MovGI(1, 400),
|
||||
(0x238, new[] { G(1) }),
|
||||
(0x243, System.Array.Empty<Operand>()),
|
||||
Exit(),
|
||||
}, System.Array.Empty<string>());
|
||||
var vm = new VirtualMachine(scene, t, new RecordingHost());
|
||||
vm.Run();
|
||||
Assert.Equal(0, vm.Gfx.AnimClockDurationTicks);
|
||||
Assert.Equal(2, vm.Gfx.AnimClockGeneration);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SnapshotSamplesDelayedMatrixChannels_WithoutUsingZAsOpacity()
|
||||
{
|
||||
@@ -138,4 +155,30 @@ public class GfxAnimationTests
|
||||
Assert.True(done.Rotation.Enabled);
|
||||
Assert.Equal(255, done.Alpha); // scale-Z=3, translation-Z=99, rotation-axis-Z=5: still opaque
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Transform2D_UsesNativeAnchoredRowVectorOrder_AndDirectProjection()
|
||||
{
|
||||
var t = new TransformState(2, 3, 99, 10, -7, 1234, 100, 50, 888);
|
||||
var p = Transform2DMath.Apply(120, 60, t);
|
||||
Assert.Equal((150.0, 73.0), p);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Transform2D_NegativeScaleMovesFarEdgeAcrossAnchor()
|
||||
{
|
||||
var t = new TransformState(-2, 1, 1, 0, 0, 0, 100, 0, 0);
|
||||
var left = Transform2DMath.Apply(90, 0, t);
|
||||
var right = Transform2DMath.Apply(110, 0, t);
|
||||
Assert.Equal((120.0, 0.0), left);
|
||||
Assert.Equal((80.0, 0.0), right);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Transform2D_MatchesCapturedNativeSc0000ScaleEndpoint()
|
||||
{
|
||||
// Native handle 0xcbc0: base=(0,600), anchor=(400,1000), scale=5.
|
||||
var t = new TransformState(5, 5, 1, 0, 0, 0, 400, 1000, 0);
|
||||
Assert.Equal((-1600.0, -1000.0), Transform2DMath.Apply(0, 600, t));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user