using Cryville.Common.Buffers; using Cryville.Common.Collections.Specialized; using Cryville.Common.Pdt; using System; using System.Collections.Generic; using System.Globalization; using UnityEngine; namespace Cryville.Crtr { public struct MotionRegistry { readonly Type m_Type; public Type Type { get { return m_Type; } } readonly Vector m_InitValue; public Vector InitValue { get { return m_InitValue.Clone(); } } readonly Vector m_GlobalInitValue; public Vector GlobalInitValue { get { return m_GlobalInitValue.Clone(); } } public MotionRegistry(Type type) : this((Vector)Activator.CreateInstance(type)) { } public MotionRegistry(Vector init) : this(init, init) { } public MotionRegistry(Vector init, Vector globalInit) { m_InitValue = init; m_GlobalInitValue = globalInit; if (!init.GetType().Equals(globalInit.GetType())) throw new ArgumentException(); m_Type = init.GetType(); } } public class RealtimeMotionValue { Type _type; public Vector AbsoluteValue; public Vector RelativeValue; public IntKeyedDictionary RelativeNodes; internal byte CloneTypeFlag; public RealtimeMotionValue Init(Vector init) { _type = init.GetType(); RelativeNodes = new IntKeyedDictionary(); AbsoluteValue = init; RelativeValue = (Vector)Activator.CreateInstance(_type); return this; } public RealtimeMotionValue Clone() { var r = new RealtimeMotionValue() { _type = _type, AbsoluteValue = AbsoluteValue.Clone(), RelativeValue = RelativeValue.Clone(), }; var rel = new IntKeyedDictionary(RelativeNodes.Count); foreach (var node in RelativeNodes) { var dnode = MotionNodePool.Shared.Rent(_type); node.Value.CopyTo(dnode); rel.Add(node.Key, dnode); } r.RelativeNodes = rel; return r; } public void CopyTo(RealtimeMotionValue dest) { AbsoluteValue.CopyTo(dest.AbsoluteValue); RelativeValue.CopyTo(dest.RelativeValue); dest.ReturnAllRelativeNodes(); foreach (var node in RelativeNodes) { var dnode = MotionNodePool.Shared.Rent(_type); node.Value.CopyTo(dnode); dest.RelativeNodes.Add(node.Key, dnode); } } public void ReturnAllRelativeNodes() { foreach (var node in RelativeNodes) { MotionNodePool.Shared.Return(_type, node.Value); } RelativeNodes.Clear(); } public MotionNode GetRelativeNode(short id) { MotionNode result; RelativeNodes.TryGetValue(id, out result); return result; } public void SetRelativeNode(MotionNode node) { MotionNode cnode; if (!RelativeNodes.TryGetValue(node.Id, out cnode)) { cnode = MotionNodePool.Shared.Rent(_type); cnode.Id = node.Id; RelativeNodes.Add(node.Id, cnode); } if (node.Time != null) cnode.Time = node.Time; if (node.EndTime != null) cnode.EndTime = node.EndTime; if (node.Value != null) node.Value.CopyTo(cnode.Value); } /// /// Computes the motion value. /// /// The vector type of the value. /// The result. public void Compute(ref T result) where T : Vector { AbsoluteValue.CopyTo(result); result.ApplyFrom(RelativeValue); } } public class MotionNode { public short Id = -1; public bool Reset; public Vec1 Time; public Vec1 EndTime; public Vector Value; public void Init(Type type) { if (Time == null) Time = new Vec1(float.NegativeInfinity); if (EndTime == null) EndTime = new Vec1(float.NegativeInfinity); if (Value == null) Value = (Vector)Activator.CreateInstance(type); } public void CopyTo(MotionNode dest) { dest.Id = Id; Time.CopyTo(dest.Time); EndTime.CopyTo(dest.EndTime); Value.CopyTo(dest.Value); } public void LerpWith(MotionNode start, float lerpedTime, ref MotionNode result) { result.Id = Id; if (Time == null) result.Time = start.Time; else { var t = (Vector)result.Time; Time.LerpWith(start.Time, lerpedTime, ref t); } if (EndTime == null) result.EndTime = start.EndTime; else { var t = (Vector)result.EndTime; EndTime.LerpWith(start.EndTime, lerpedTime, ref t); } if (Value == null) result.Value = start.Value; else Value.LerpWith(start.Value, lerpedTime, ref result.Value); } } internal class MotionNodePool : CategorizedPool { public static MotionNodePool Shared; private class Bucket : ObjectPool { readonly Type _type; public Bucket(Type type, int capacity) : base(capacity) { _type = type; } protected override MotionNode Construct() { var result = new MotionNode(); result.Init(_type); return result; } } readonly Dictionary> m_buckets; protected override IReadOnlyDictionary> Buckets { get { return m_buckets; } } public MotionNodePool() { m_buckets = new Dictionary>(); foreach (var reg in ChartPlayer.motionRegistry) { var type = reg.Value.Type; if (!m_buckets.ContainsKey(type)) m_buckets.Add(type, new Bucket(type, 4096)); } m_buckets.TrimExcess(); } } public abstract class Vector { public Vector() { } public abstract byte Dimension { get; } public abstract void ApplyFrom(Vector parent); public abstract void LerpWith(Vector start, float lerpedTime, ref Vector result); public abstract override string ToString(); public abstract unsafe void ToArray(float* arr); public Vector Clone() { return (Vector)MemberwiseClone(); } public abstract void CopyTo(Vector dest); static readonly Type[] floatArrayTypeArray = new Type[] { typeof(float[]) }; public static Vector Construct(Type type, float[] values) { if (!typeof(Vector).IsAssignableFrom(type)) throw new ArgumentException("Type is not vector"); return (Vector)type.GetConstructor(floatArrayTypeArray).Invoke(new object[] { values }); } } public class Vec1 : Vector { public float Value; public Vec1() { Value = 0; } public Vec1(float[] v) { Value = v[0]; } public Vec1(float i) { Value = i; } public override byte Dimension { get { return 1; } } public override void ApplyFrom(Vector parent) { var p = (Vec1)parent; Value += p.Value; } public override void LerpWith(Vector start, float lerpedTime, ref Vector result) { var r = (Vec1)result; if (start == null) { r.Value = Value; return; } var s = (Vec1)start; r.Value = s.Value * (1 - lerpedTime) + Value * lerpedTime; } public override void CopyTo(Vector dest) { var d = (Vec1)dest; d.Value = Value; } public override string ToString() { return Value.ToString(CultureInfo.InvariantCulture); } public override unsafe void ToArray(float* arr) { arr[0] = Value; } } public class VecI1 : Vector { public int Value; public VecI1() { Value = 0; } public VecI1(float[] v) { Value = (int)Math.Round(v[0]); } public VecI1(int i) { Value = i; } public override byte Dimension { get { return 1; } } public override void ApplyFrom(Vector parent) { var p = (VecI1)parent; Value += p.Value; } public override void LerpWith(Vector start, float lerpedTime, ref Vector result) { var r = (VecI1)result; if (start == null) { r.Value = Value; return; } var s = (VecI1)start; r.Value = (int)(s.Value * (1 - lerpedTime) + Value * lerpedTime); } public override void CopyTo(Vector dest) { var d = (VecI1)dest; d.Value = Value; } public override string ToString() { return Value.ToString(CultureInfo.InvariantCulture); } public override unsafe void ToArray(float* arr) { arr[0] = Value; } } public class Vec1m : Vector { public float Value; public Vec1m() { Value = 1; } public Vec1m(float[] v) { Value = v[0]; } public Vec1m(float i) : base() { Value = i; } public override byte Dimension { get { return 1; } } public override void ApplyFrom(Vector parent) { var p = (Vec1m)parent; Value *= p.Value; } public override void LerpWith(Vector start, float lerpedTime, ref Vector result) { var r = (Vec1m)result; if (start == null) { r.Value = Value; return; } var s = (Vec1m)start; r.Value = s.Value * (1 - lerpedTime) + Value * lerpedTime; } public override void CopyTo(Vector dest) { var d = (Vec1m)dest; d.Value = Value; } public override string ToString() { return Value.ToString(CultureInfo.InvariantCulture); } public override unsafe void ToArray(float* arr) { arr[0] = Value; } } public class Vec2 : Vector { float x, y; public Vec2() { x = y = 0; } public Vec2(float[] v) { x = v[0]; y = v[1]; } public Vec2(float x, float y) { this.x = x; this.y = y; } public override byte Dimension { get { return 2; } } public override void ApplyFrom(Vector parent) { var p = (Vec2)parent; x += p.x; y += p.y; } public override void LerpWith(Vector start, float lerpedTime, ref Vector result) { var r = (Vec2)result; if (start == null) { r.x = x; r.y = y; return; } var s = (Vec2)start; r.x = s.x * (1 - lerpedTime) + x * lerpedTime; r.y = s.y * (1 - lerpedTime) + y * lerpedTime; } public Vector3 ToVector2() { return new Vector3(x, y); } public override void CopyTo(Vector dest) { var d = (Vec2)dest; d.x = x; d.y = y; } public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "{0},{1}", x, y); } public override unsafe void ToArray(float* arr) { arr[0] = x; arr[1] = y; } } public class Vec3 : Vector { float x, y, z; public Vec3() { x = y = z = 0; } public Vec3(float[] v) { x = v[0]; y = v[1]; z = v[2]; } public Vec3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public override byte Dimension { get { return 3; } } public override void ApplyFrom(Vector parent) { var p = (Vec3)parent; x += p.x; y += p.y; z += p.z; } public override void LerpWith(Vector start, float lerpedTime, ref Vector result) { var r = (Vec3)result; if (start == null) { r.x = x; r.y = y; r.z = z; return; } var s = (Vec3)start; r.x = s.x * (1 - lerpedTime) + x * lerpedTime; r.y = s.y * (1 - lerpedTime) + y * lerpedTime; r.z = s.z * (1 - lerpedTime) + z * lerpedTime; } public Vector3 ToVector3() { return new Vector3(x, y, z); } public override void CopyTo(Vector dest) { var d = (Vec3)dest; d.x = x; d.y = y; d.z = z; } public override string ToString() { return string.Format(CultureInfo.InvariantCulture, "{0},{1},{2}", x, y, z); } public override unsafe void ToArray(float* arr) { arr[0] = x; arr[1] = y; arr[2] = z; } } public unsafe class VectorSrc : PropSrc.FixedBuffer { const int MAX_DIMENSION = 8; protected readonly Func _cb; public VectorSrc(Func cb) : base(PdtInternalType.Vector, MAX_DIMENSION * sizeof(float) + sizeof(int)) { _cb = cb; fixed (byte* rptr = buf) { var ptr = (float*)rptr; *(int*)(ptr + MAX_DIMENSION) = PdtInternalType.Number; } } protected override void InternalGet() { var v = _cb(); if (v.Dimension > MAX_DIMENSION) throw new NotSupportedException("Vector dimension too large"); fixed (byte* rptr = buf) { var ptr = (float*)rptr; v.ToArray(ptr); } } } public class VectorOp : PropOp { readonly Action _cb; public VectorOp(Action cb) { _cb = cb; } protected override unsafe void Execute() { var op = GetOperand(0); float[] values; if (op.Type == PdtInternalType.Number) { values = new float[] { op.AsNumber() }; } else if (op.Type == PdtInternalType.Vector) { int type; op.GetArraySuffix(out type, out _); if (type != PdtInternalType.Number) throw new InvalidOperationException("Not a vector of numbers"); values = new float[(op.Length - sizeof(int)) / sizeof(float)]; fixed (float* ptr = values) { op.CopyTo((byte*)ptr, 0, op.Length - sizeof(int)); } } else throw new InvalidOperationException("Invalid operand"); _cb(values); } } }