Editor/Embedded/ValveResourceFormat/ResourceTypes/ModelAnimation/AnimationMovement.cs

Editor class representing root motion movement data for a model animation. It parses movement properties from a KVObject, stores scalars and vectors, and provides linear interpolation (MovementData) between two AnimationMovement instances.

File Access
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using HumanoidRetargeter.EditorTools.Embedded.ValveResourceFormat.Utils;
using HumanoidRetargeter.EditorTools.Embedded.ValveResourceFormat.Serialization.KeyValues;

namespace HumanoidRetargeter.EditorTools.Embedded.ValveResourceFormat.ResourceTypes.ModelAnimation;

    /// <summary>
    /// Represents root motion movement data for an animation.
    /// </summary>
    public class AnimationMovement
    {
        /// <summary>
        /// Represents interpolated movement data containing position and angle.
        /// </summary>
        public readonly struct MovementData
        {
            /// <summary>
            /// Gets the position offset.
            /// </summary>
            public global::System.Numerics.Vector3 Position { get; }

            /// <summary>
            /// Gets the angle offset in degrees.
            /// </summary>
            public float Angle { get; }

            /// <summary>
            /// Initializes a new instance of the <see cref="MovementData"/> struct.
            /// </summary>
            public MovementData(global::System.Numerics.Vector3 position, float angle)
            {
                Position = position;
                Angle = angle;
            }
        }

        /// <summary>
        /// Gets the ending frame for this movement.
        /// </summary>
        public int EndFrame { get; }

        /// <summary>
        /// Gets the motion flags for this movement.
        /// </summary>
        public ModelAnimationMotionFlags MotionFlags { get; }

        /// <summary>
        /// Gets the first motion scalar value (v0) for this segment.
        /// </summary>
        public float V0 { get; }

        /// <summary>
        /// Gets the second motion scalar value (v1) for this segment.
        /// </summary>
        public float V1 { get; }

        /// <summary>
        /// Gets the rotation angle in degrees.
        /// </summary>
        public float Angle { get; }

        /// <summary>
        /// Gets the motion vector parameter stored for this segment.
        /// </summary>
        public global::System.Numerics.Vector3 Vector { get; }

        /// <summary>
        /// Gets the translation offset parameter stored for this segment.
        /// </summary>
        public global::System.Numerics.Vector3 Position { get; }

        /// <summary>
        /// Initializes a new instance of the <see cref="AnimationMovement"/> class.
        /// </summary>
        public AnimationMovement(KVObject frameBlock)
        {
            EndFrame = frameBlock.GetInt32Property("endframe");
            MotionFlags = (ModelAnimationMotionFlags)frameBlock.GetInt32Property("motionflags");
            V0 = frameBlock.GetInt32Property("v0");
            V1 = frameBlock.GetInt32Property("v1");
            Angle = frameBlock.GetFloatProperty("angle");
            Vector = new global::System.Numerics.Vector3(frameBlock.GetFloatArray("vector"));
            Position = new global::System.Numerics.Vector3(frameBlock.GetFloatArray("position"));
        }

        /// <summary>
        /// Interpolates linearly between two movement states using <paramref name="t"/> in the range [0, 1].
        /// </summary>
        public static MovementData Lerp(AnimationMovement a, AnimationMovement b, float t)
        {
            if (a == null && b == null)
            {
                return new();
            }

            if (a == null)
            {
                return Lerp(global::System.Numerics.Vector3.Zero, 0, b.Position, b.Angle, t);
            }
            else if (b == null)
            {
                return Lerp(a.Position, a.Angle, global::System.Numerics.Vector3.Zero, 0f, t);
            }
            else
            {
                return Lerp(a.Position, a.Angle, b.Position, b.Angle, t);
            }
        }

        private static MovementData Lerp(global::System.Numerics.Vector3 aPos, float aAngle, global::System.Numerics.Vector3 bPos, float bAngle, float t)
        {
            var position = global::System.Numerics.Vector3.Lerp(aPos, bPos, t);
            var angle = float.Lerp(aAngle, bAngle, t);

            return new MovementData(position, angle);
        }
    }