620 lines
16 KiB
C#
620 lines
16 KiB
C#
using Cryville.Common.Pdt;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text.RegularExpressions;
|
|
using UnityEngine;
|
|
|
|
namespace Cryville.Crtr {
|
|
[Obsolete]
|
|
public enum TransitionType : byte {
|
|
In = 0,
|
|
Out = 1,
|
|
InOut = 2,
|
|
OutIn = 3,
|
|
|
|
Ease = 0,
|
|
Sine = 4,
|
|
Expo = 8,
|
|
Circ = 12,
|
|
Elastic = 16,
|
|
Back = 20,
|
|
Bounce = 24,
|
|
}
|
|
|
|
[Obsolete]
|
|
public static class MotionLerper {
|
|
public static void Lerp<T>(double time, double tt, T tv, double ft, T fv, TransitionType type, float rate, ref T result) where T : Vector {
|
|
if (fv == null) fv = (T)Activator.CreateInstance(tv.GetType());
|
|
Lerp((float)((time - ft) / (tt - ft)), fv, tv, type, rate, ref result);
|
|
}
|
|
|
|
public static void Lerp<T>(float scaledTime, T from, T to, TransitionType type, float rate, ref T result) where T : Vector {
|
|
if (scaledTime >= 1) { result = to; return; }
|
|
if (scaledTime < 0) { result = from; return; }
|
|
var r = (Vector)result;
|
|
to.LerpWith(from, GetEaseTime(scaledTime, type, rate), ref r);
|
|
}
|
|
|
|
public static float GetEaseTime(float time, TransitionType type, float rate) {
|
|
switch ((byte)type & 3) {
|
|
case (byte)TransitionType.In:
|
|
return 1 - GetEaseOutTime(1 - time, type, rate);
|
|
case (byte)TransitionType.Out:
|
|
return GetEaseOutTime(time, type, rate);
|
|
case (byte)TransitionType.InOut:
|
|
time *= 2;
|
|
if (time <= 1) return (1 - GetEaseOutTime(1 - time, type, rate)) / 2;
|
|
else return (GetEaseOutTime(time - 1, type, rate) + 1) / 2;
|
|
case (byte)TransitionType.OutIn:
|
|
time *= 2;
|
|
if (time <= 1) return GetEaseOutTime(time, type, rate) / 2;
|
|
else return (2 - GetEaseOutTime(2 - time, type, rate)) / 2;
|
|
default:
|
|
throw new ArgumentException("Unknown transition");
|
|
}
|
|
}
|
|
|
|
static float GetEaseOutTime(float p, TransitionType type, float rate) {
|
|
switch ((byte)type & 252) {
|
|
case (byte)TransitionType.Ease:
|
|
return 1 - Mathf.Pow(1 - p, rate);
|
|
case (byte)TransitionType.Sine:
|
|
return Mathf.Sin(p * (Mathf.PI / 2));
|
|
case (byte)TransitionType.Expo:
|
|
return 1 - Mathf.Pow(2, -10 * p);
|
|
case (byte)TransitionType.Circ:
|
|
p -= 1;
|
|
return Mathf.Sqrt(1 - p * p);
|
|
case (byte)TransitionType.Elastic:
|
|
float s = rate / (2 * Mathf.PI) * Mathf.Asin(1);
|
|
return Mathf.Pow(2, -10 * p) * Mathf.Sin((p - s) * (2 * Mathf.PI) / rate) + 1;
|
|
case (byte)TransitionType.Back:
|
|
p -= 1;
|
|
return p * p * ((rate + 1) * p + rate) + 1;
|
|
case (byte)TransitionType.Bounce:
|
|
if (p < 1 / 2.75) {
|
|
return 7.5625f * p * p;
|
|
}
|
|
else if (p < (2 / 2.75)) {
|
|
p -= 1.5f / 2.75f;
|
|
return 7.5625f * p * p + .75f;
|
|
}
|
|
else if (p < 2.5 / 2.75) {
|
|
p -= 2.25f / 2.75f;
|
|
return 7.5625f * p * p + .9375f;
|
|
}
|
|
else {
|
|
p -= 2.625f / 2.75f;
|
|
return 7.5625f * p * p + .984375f;
|
|
}
|
|
default:
|
|
throw new ArgumentException("Unknown transition");
|
|
}
|
|
}
|
|
}
|
|
|
|
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 {
|
|
public Vector AbsoluteValue;
|
|
List<MotionNode> RelativeNodes;
|
|
internal byte CloneTypeFlag;
|
|
|
|
public RealtimeMotionValue Init(Vector init) {
|
|
RelativeNodes = new List<MotionNode> {
|
|
new MotionNode() {
|
|
Id = 0,
|
|
Time = new Vec1(0),
|
|
EndTime = new Vec1(0),
|
|
Value = init
|
|
}
|
|
};
|
|
AbsoluteValue = (Vector)Activator.CreateInstance(init.GetType());
|
|
return this;
|
|
}
|
|
|
|
public RealtimeMotionValue Clone() {
|
|
var r = new RealtimeMotionValue() {
|
|
AbsoluteValue = AbsoluteValue.Clone()
|
|
};
|
|
|
|
var rel = new List<MotionNode>(RelativeNodes.Count);
|
|
for (var i = 0; i < RelativeNodes.Count; i++) {
|
|
rel.Add(RelativeNodes[i].Clone());
|
|
}
|
|
r.RelativeNodes = rel;
|
|
|
|
return r;
|
|
}
|
|
|
|
public void CopyTo(RealtimeMotionValue dest) {
|
|
AbsoluteValue.CopyTo(dest.AbsoluteValue);
|
|
int tcount = RelativeNodes.Count;
|
|
int dcount = dest.RelativeNodes.Count;
|
|
int count = Math.Min(tcount, dcount);
|
|
for (int i = 0; i < count; i++) {
|
|
RelativeNodes[i].CopyTo(dest.RelativeNodes[i]);
|
|
}
|
|
if (tcount > dcount)
|
|
for (int i = dcount; i < tcount; i++)
|
|
dest.RelativeNodes.Add(RelativeNodes[i].Clone());
|
|
else
|
|
dest.RelativeNodes.RemoveRange(tcount, dcount - tcount);
|
|
}
|
|
|
|
public MotionNode GetRelativeNode(short id) {
|
|
return RelativeNodes.Find(n => n.Id == id);
|
|
}
|
|
|
|
public void SetRelativeNode(MotionNode node) {
|
|
int i = RelativeNodes.FindIndex(n => n.Id == node.Id);
|
|
MotionNode cnode;
|
|
if (i == -1) {
|
|
cnode = new MotionNode {
|
|
Id = node.Id,
|
|
Time = new Vec1(0),
|
|
EndTime = new Vec1(0),
|
|
Value = (Vector)Activator.CreateInstance(AbsoluteValue.GetType())
|
|
};
|
|
}
|
|
else {
|
|
cnode = RelativeNodes[i];
|
|
RelativeNodes.RemoveAt(i);
|
|
}
|
|
if (node.Time != null) cnode.Time = node.Time;
|
|
if (node.EndTime != null) cnode.EndTime = node.EndTime;
|
|
if (node.Value != null) cnode.Value.ReplaceFrom(node.Value);
|
|
|
|
int i2 = RelativeNodes.BinarySearch(cnode);
|
|
if (i2 < 0) i2 = ~i2;
|
|
RelativeNodes.Insert(i2, cnode);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Computes the motion value at the given relative time.
|
|
/// </summary>
|
|
/// <typeparam name="T">The vector type of the value.</typeparam>
|
|
/// <param name="reltime">The relative time.</param>
|
|
/// <param name="result">The result.</param>
|
|
/// <returns></returns>
|
|
[Obsolete]
|
|
public void GetValue<T>(float reltime, ref T result) where T : Vector {
|
|
int i = BinarySearch(reltime);
|
|
if (i >= 0) RelativeNodes[i].Value.CopyTo(result);
|
|
else {
|
|
i = ~i;
|
|
if (i >= RelativeNodes.Count) {
|
|
RelativeNodes[i - 1].Value.CopyTo(result);
|
|
}
|
|
else if (i == 0) {
|
|
RelativeNodes[0].Value.CopyTo(result);
|
|
}
|
|
else {
|
|
MotionNode t = RelativeNodes[i], f = RelativeNodes[i - 1];
|
|
MotionLerper.Lerp(reltime, t.Time.Value, (T)t.Value, f.Time.Value, (T)f.Value, t.Transition.Value, t.Rate.Value, ref result);
|
|
}
|
|
}
|
|
result.ApplyFrom(AbsoluteValue);
|
|
}
|
|
|
|
// Adopted from System.Collections.Generic.ArraySortHelper<T>.InternalBinarySearch(T[] array, int index, int length, T value, IComparer<T> comparer)
|
|
int BinarySearch(float value) {
|
|
int num = 0;
|
|
int num2 = RelativeNodes.Count - 1;
|
|
while (num <= num2) {
|
|
int num3 = num + (num2 - num >> 1);
|
|
int num4 = RelativeNodes[num3].Time.Value.CompareTo(value);
|
|
if (num4 == 0) return num3;
|
|
if (num4 < 0) num = num3 + 1;
|
|
else num2 = num3 - 1;
|
|
}
|
|
return ~num;
|
|
}
|
|
}
|
|
|
|
public class MotionNode : IComparable<MotionNode> {
|
|
public short Id = -1;
|
|
public bool Reset;
|
|
public Vec1 Time;
|
|
public Vec1 EndTime;
|
|
float CmpTime { get { return Time != null ? Time.Value : 0; } }
|
|
[Obsolete]
|
|
public TransitionType? Transition;
|
|
[Obsolete]
|
|
public Vec1 Rate;
|
|
public Vector Value;
|
|
|
|
public MotionNode Clone() {
|
|
return new MotionNode() {
|
|
Id = Id,
|
|
Time = (Vec1)Time.Clone(),
|
|
EndTime = (Vec1)EndTime.Clone(),
|
|
Value = Value.Clone()
|
|
};
|
|
}
|
|
|
|
public void CopyTo(MotionNode dest) {
|
|
dest.Id = Id;
|
|
Time.CopyTo(dest.Time);
|
|
EndTime.CopyTo(dest.EndTime);
|
|
Value.CopyTo(dest.Value);
|
|
}
|
|
|
|
public int CompareTo(MotionNode other) {
|
|
return CmpTime.CompareTo(other.CmpTime);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
public abstract class Vector {
|
|
public Vector() { }
|
|
|
|
public abstract byte Dimension { get; }
|
|
|
|
public abstract void ApplyFrom(Vector parent);
|
|
public abstract void ReplaceFrom(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 ReplaceFrom(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 ReplaceFrom(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 ReplaceFrom(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.GetValueOrDefault(); y += p.y.GetValueOrDefault();
|
|
}
|
|
|
|
public override void ReplaceFrom(Vector parent) {
|
|
var p = (Vec2)parent;
|
|
if (p.x.HasValue) x = p.x;
|
|
if (p.y.HasValue) 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 = x.HasValue ? (s.x.Value * (1 - lerpedTime) + x.Value * lerpedTime) : s.x.Value;
|
|
r.y = y.HasValue ? (s.y.Value * (1 - lerpedTime) + y.Value * lerpedTime) : s.y.Value;
|
|
}
|
|
|
|
public Vector3 ToVector2() {
|
|
return new Vector3(x.Value, y.Value);
|
|
}
|
|
|
|
public override void CopyTo(Vector dest) {
|
|
var d = (Vec2)dest;
|
|
d.x = x; d.y = y;
|
|
}
|
|
|
|
public override string ToString() {
|
|
return string.Format("{0},{1}",
|
|
x != null ? x.Value.ToString(CultureInfo.InvariantCulture) : "",
|
|
y != null ? y.Value.ToString(CultureInfo.InvariantCulture) : ""
|
|
);
|
|
}
|
|
|
|
public override unsafe void ToArray(float* arr) {
|
|
arr[0] = x.Value;
|
|
arr[1] = y.Value;
|
|
}
|
|
}
|
|
|
|
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.GetValueOrDefault(); y += p.y.GetValueOrDefault(); z += p.z.GetValueOrDefault();
|
|
}
|
|
|
|
public override void ReplaceFrom(Vector parent) {
|
|
var p = (Vec3)parent;
|
|
if (p.x.HasValue) x = p.x;
|
|
if (p.y.HasValue) y = p.y;
|
|
if (p.z.HasValue) 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 = x.HasValue ? (s.x.Value * (1 - lerpedTime) + x.Value * lerpedTime) : s.x.Value;
|
|
r.y = y.HasValue ? (s.y.Value * (1 - lerpedTime) + y.Value * lerpedTime) : s.y.Value;
|
|
r.z = z.HasValue ? (s.z.Value * (1 - lerpedTime) + z.Value * lerpedTime) : s.z.Value;
|
|
}
|
|
|
|
public Vector3 ToVector3() {
|
|
return new Vector3(x.Value, y.Value, z.Value);
|
|
}
|
|
|
|
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("{0},{1},{2}",
|
|
x != null ? x.Value.ToString(CultureInfo.InvariantCulture) : "",
|
|
y != null ? y.Value.ToString(CultureInfo.InvariantCulture) : "",
|
|
z != null ? z.Value.ToString(CultureInfo.InvariantCulture) : ""
|
|
);
|
|
}
|
|
|
|
public override unsafe void ToArray(float* arr) {
|
|
arr[0] = x.Value;
|
|
arr[1] = y.Value;
|
|
arr[2] = z.Value;
|
|
}
|
|
}
|
|
|
|
public unsafe class VectorSrc : PropSrc.FixedBuffer {
|
|
const int MAX_DIMENSION = 8;
|
|
protected readonly Func<Vector> _cb;
|
|
public VectorSrc(Func<Vector> 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<float[]> _cb;
|
|
public VectorOp(Action<float[]> 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);
|
|
}
|
|
}
|
|
}
|