diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index b9af871..d7ed12f 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -3436,6 +3436,35 @@ public sealed class GameWindow : IDisposable } } } + + // Rotation integration: if the sequencer's Omega is non-zero + // (TurnRight / TurnLeft / any cycle with baked-in spin), rotate + // the entity's quaternion around the omega axis by |omega|*dt. + // Matches ACE Sequence.apply_physics L221-L229: + // frame.Rotate(Omega * quantum) + // where frame.Rotate treats the argument as a local-axis + // rotation. Only kicks in for Turn cycles (low byte 0x0D/0x0E) + // — other motions either have zero omega or integrate rotation + // server-side. + var seqOmega = ae.Sequencer.CurrentOmega; + if (seqOmega.LengthSquared() > 1e-6f) + { + uint mlo2 = ae.Sequencer.CurrentMotion & 0xFFu; + bool isTurning = mlo2 == 0x0D || mlo2 == 0x0E; // TurnRight / TurnLeft + if (isTurning) + { + // Omega as a scaled axis-angle. Build a delta quaternion + // and compose it on the entity's current rotation. + float angle = seqOmega.Length() * dt; + if (angle > 1e-5f) + { + var axis = System.Numerics.Vector3.Normalize(seqOmega); + var deltaRot = System.Numerics.Quaternion.CreateFromAxisAngle(axis, angle); + ae.Entity.Rotation = System.Numerics.Quaternion.Normalize( + ae.Entity.Rotation * deltaRot); + } + } + } } // ── Get per-part (origin, orientation) from either sequencer or legacy ──