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

Represents a single animation frame for a model. Stores per-bone FrameBone entries, per-flex float data array, a frame index and movement data, and provides setters for position/angle/scale/data and a Clear method to reset to skeleton bind pose.

Reflection
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using HumanoidRetargeter.EditorTools.Embedded.ValveResourceFormat.Utils;
using HumanoidRetargeter.EditorTools.Embedded.ValveResourceFormat.ResourceTypes.ModelFlex;

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

    /// <summary>
    /// Represents a single frame of animation data.
    /// </summary>
    public class Frame
    {
        /// <summary>
        /// Gets or sets the frame index.
        /// </summary>
        public int FrameIndex { get; set; } = 1;

        /// <summary>
        /// Gets the bone transforms for this frame.
        /// </summary>
        public FrameBone[] Bones { get; }

        /// <summary>
        /// Gets the flex controller data for this frame.
        /// </summary>
        public float[] Datas { get; }

        /// <summary>
        /// Gets or sets the movement data for this frame.
        /// </summary>
        public AnimationMovement.MovementData Movement { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Frame"/> class.
        /// </summary>
        public Frame(Skeleton skeleton, FlexController[] flexControllers)
        {
            Bones = new FrameBone[skeleton.Bones.Length];
            Datas = new float[flexControllers.Length];
            Clear(skeleton);
        }

        /// <summary>
        /// Sets a global::System.Numerics.Vector3 attribute for a bone in this frame.
        /// </summary>
        public void SetAttribute(int bone, AnimationChannelAttribute attribute, global::System.Numerics.Vector3 data)
        {
            switch (attribute)
            {
                case AnimationChannelAttribute.Position:
                    Bones[bone].Position = data;
                    break;

#if DEBUG
                default:
                    Console.WriteLine($"Unknown frame attribute '{attribute}' encountered with global::System.Numerics.Vector3 data");
                    break;
#endif
            }
        }

        /// <summary>
        /// Sets a global::System.Numerics.Quaternion attribute for a bone in this frame.
        /// </summary>
        public void SetAttribute(int bone, AnimationChannelAttribute attribute, global::System.Numerics.Quaternion data)
        {
            switch (attribute)
            {
                case AnimationChannelAttribute.Angle:
                    Bones[bone].Angle = data;
                    break;

#if DEBUG
                default:
                    Console.WriteLine($"Unknown frame attribute '{attribute}' encountered with global::System.Numerics.Quaternion data");
                    break;
#endif
            }
        }

        /// <summary>
        /// Sets a float attribute for a bone or flex controller in this frame.
        /// </summary>
        public void SetAttribute(int bone, AnimationChannelAttribute attribute, float data)
        {
            switch (attribute)
            {
                case AnimationChannelAttribute.Scale:
                    Bones[bone].Scale = data;
                    break;

                case AnimationChannelAttribute.Data:
                    Datas[bone] = data;
                    break;

#if DEBUG
                default:
                    Console.WriteLine($"Unknown frame attribute '{attribute}' encountered with float data");
                    break;
#endif
            }
        }

        /// <summary>
        /// Resets frame bones to their bind pose.
        /// Should be used on animation change.
        /// </summary>
        /// <param name="skeleton">The same skeleton that was passed to the constructor.</param>
        public void Clear(Skeleton skeleton)
        {
            FrameIndex = -1;

            for (var i = 0; i < Bones.Length; i++)
            {
                Bones[i].Position = skeleton.Bones[i].Position;
                Bones[i].Angle = skeleton.Bones[i].Angle;
                Bones[i].Scale = 1;
            }
        }
    }