Code/Binder/Properties/AnimParam.cs
using System;
using System.Xml.Linq;
using static Sandbox.SkinnedModelRenderer;
namespace Sandbox.MovieMaker.Properties;
#nullable enable
/// <summary>
/// Reads / writes an anim graph parameter on a <see cref="SkinnedModelRenderer"/>.
/// </summary>
file sealed record AnimParamProperty<T>( ITrackProperty<ParameterAccessor?> Parent, string Name )
: ITrackProperty<T>
{
private IAnimParamAccessor<T> Accessor { get; } = DefaultAnimParamAccessor.Instance as IAnimParamAccessor<T> ?? throw new NotImplementedException();
public bool IsBound => Parent.Value?.Graph?.GetParameterType( Name ) == typeof(T);
public T Value
{
get => Parent.Value is { } accessor ? Accessor.Get( accessor, Name ) : default!;
set
{
if ( Parent.Value is { } accessor )
{
Accessor.Set( accessor, Name, value );
}
}
}
ITrackTarget ITrackProperty.Parent => Parent;
}
file sealed class AnimParamPropertyFactory : ITrackPropertyFactory<ITrackProperty<ParameterAccessor?>>
{
string ITrackPropertyFactory.CategoryName => "Anim Graph";
public IEnumerable<string> GetPropertyNames( ITrackProperty<ParameterAccessor?> parent )
{
var graph = parent is { IsBound: true } ? parent.Value?.Graph : null;
if ( graph is null ) yield break;
for ( var i = 0; i < graph.ParamCount; ++i )
{
yield return graph.GetParameterName( i );
}
}
/// <summary>
/// Any property in a <see cref="ParameterAccessor"/> is an anim graph parameter, but we
/// can only determine the type if it actually exists.
/// </summary>
public Type GetTargetType( ITrackProperty<ParameterAccessor?> parent, string name )
{
var graph = parent is { IsBound: true } ? parent.Value?.Graph : null;
return graph?.GetParameterType( name ) ?? typeof(Unknown);
}
public ITrackProperty<T> CreateProperty<T>( ITrackProperty<ParameterAccessor?> parent, string name ) =>
new AnimParamProperty<T>( parent, name );
}
file interface IAnimParamAccessor<T>
{
T Get( ParameterAccessor accessor, string name );
void Set( ParameterAccessor accessor, string name, T value );
}
file sealed class DefaultAnimParamAccessor :
IAnimParamAccessor<bool>, IAnimParamAccessor<byte>, IAnimParamAccessor<int>, IAnimParamAccessor<float>,
IAnimParamAccessor<Vector3>, IAnimParamAccessor<Rotation>
{
public static DefaultAnimParamAccessor Instance { get; } = new();
bool IAnimParamAccessor<bool>.Get( ParameterAccessor accessor, string name ) => accessor.GetBool( name );
byte IAnimParamAccessor<byte>.Get( ParameterAccessor accessor, string name ) => (byte)accessor.GetInt( name );
int IAnimParamAccessor<int>.Get( ParameterAccessor accessor, string name ) => accessor.GetInt( name );
float IAnimParamAccessor<float>.Get( ParameterAccessor accessor, string name ) => accessor.GetFloat( name );
Vector3 IAnimParamAccessor<Vector3>.Get( ParameterAccessor accessor, string name ) => accessor.GetVector( name );
Rotation IAnimParamAccessor<Rotation>.Get( ParameterAccessor accessor, string name ) => accessor.GetRotation( name );
void IAnimParamAccessor<bool>.Set( ParameterAccessor accessor, string name, bool value ) => accessor.Set( name, value );
void IAnimParamAccessor<byte>.Set( ParameterAccessor accessor, string name, byte value ) => accessor.Set( name, value );
void IAnimParamAccessor<int>.Set( ParameterAccessor accessor, string name, int value ) => accessor.Set( name, value );
void IAnimParamAccessor<float>.Set( ParameterAccessor accessor, string name, float value ) => accessor.Set( name, value );
void IAnimParamAccessor<Vector3>.Set( ParameterAccessor accessor, string name, Vector3 value ) => accessor.Set( name, value );
void IAnimParamAccessor<Rotation>.Set( ParameterAccessor accessor, string name, Rotation value ) => accessor.Set( name, value );
}