using System.Collections.Generic; using Age.Engine.Model; using Age.Engine.Sys4; using Age.Engine.Vm; using Xunit; public class GfxAnimationTests { // ---- Task 2: GfxState animation-channel data model (revised global-clock model, see engine-re.md) ---- [Fact] public void SetAnimTransform_RecordsTargetParamsAndEnables() { var g = new GfxState(); g.SetAnimTransform(0x1000, p1: 7, p2: 9, target: (100, 100, 100), normalized: true); var o = g.TryGet(0x1000)!; Assert.Equal((100L, 100L, 100L), o.AnimTarget); Assert.Equal(7, o.AnimParam1); Assert.Equal(9, o.AnimParam2); Assert.True(o.AnimNormalized); Assert.True(o.AnimEnabled); } [Fact] public void StartAnim_SetsTargetDurationEnablesAndBumpsGeneration() { var g = new GfxState(); g.StartAnim(0x1000, durationTicks: 30, target: (0, 0, 5)); var o = g.TryGet(0x1000)!; Assert.Equal((0L, 0L, 5L), o.AnimTarget); Assert.Equal(30, o.AnimDurationTicks); Assert.True(o.AnimEnabled); Assert.Equal(1, o.AnimGeneration); // fresh object starts at 0, one anim-start -> 1 } [Fact] public void SetAnimClock_SetsGlobalDurationAndBumpsClockGeneration() { var g = new GfxState(); var cg0 = g.AnimClockGeneration; g.SetAnimClock(400); Assert.Equal(400, g.AnimClockDurationTicks); Assert.Equal(cg0 + 1, g.AnimClockGeneration); } // ---- Tasks 3-5: VM dispatch + snapshot (synthesized scenes) ---- private static OpcodeTable T() => OpcodeTableJson.Load(Paths.OpcodesJson); private static Operand G(int a) => new(3, a); private static Operand I(long v) => new(0, v); private static (int, Operand[]) MovGI(int d, long v) => (0x55, new[] { G(d), I(v) }); private static (int, Operand[]) Exit() => (0x2, System.Array.Empty()); [Fact] public void SetAnimTransformAbs_DispatchRecordsChannel() { var t = T(); // handle g[1]=0x1000; p1 g[2]=7; p2 g[3]=9; target g[4,5,6]=(800,500,0) var scene = ScriptAssembler.Assemble(t, "ANIM", new List<(int, Operand[])> { MovGI(1, 0x1000), MovGI(2, 7), MovGI(3, 9), MovGI(4, 800), MovGI(5, 500), MovGI(6, 0), (0x220, new[] { G(1), G(2), G(3), G(4), G(5), G(6) }), Exit(), }, System.Array.Empty()); var vm = new VirtualMachine(scene, t, new RecordingHost()); vm.Run(); var o = vm.Gfx.TryGet(0x1000)!; Assert.Equal((800L, 500L, 0L), o.AnimTarget); Assert.False(o.AnimNormalized); Assert.True(o.AnimEnabled); } [Fact] public void AnimStartAndClock_DispatchSetTargetDurationClockAndGeneration() { var t = T(); // anim-start(handle=0x1000, duration=30, target=(0,0,5)); set-anim-clock(400) var scene = ScriptAssembler.Assemble(t, "ANIM", new List<(int, Operand[])> { MovGI(1, 0x1000), MovGI(2, 30), MovGI(3, 0), MovGI(4, 0), MovGI(5, 5), MovGI(6, 400), (0x234, new[] { G(1), G(2), G(3), G(4), G(5) }), (0x238, new[] { G(6) }), Exit(), }, System.Array.Empty()); var vm = new VirtualMachine(scene, t, new RecordingHost()); vm.Run(); var o = vm.Gfx.TryGet(0x1000)!; Assert.Equal((0L, 0L, 5L), o.AnimTarget); Assert.Equal(30, o.AnimDurationTicks); Assert.Equal(1, o.AnimGeneration); Assert.True(o.AnimEnabled); Assert.Equal(400, vm.Gfx.AnimClockDurationTicks); Assert.Equal(1, vm.Gfx.AnimClockGeneration); } }