Files
crtr/Assets/Cryville/Crtr/Motion.cs
2023-03-03 13:34:12 +08:00

992 lines
27 KiB
C#

using Cryville.Common;
using Cryville.Common.Pdt;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Cryville.Crtr {
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,
}
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)ReflectionHelper.InvokeEmptyConstructor(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 double Delerp<T>(T value, double tt, T tv, double ft, T fv, TransitionType type, float rate) where T : Vector {
if (fv == null) fv = (T)ReflectionHelper.InvokeEmptyConstructor(tv.GetType());
var t = Delerp(value, fv, tv, type, rate);
return ft * (1 - t) + tt * t;
}
public static float Delerp<T>(T value, T from, T to, TransitionType type, float rate) where T : Vector {
if (value.CompareTo(to) >= 0) return 1;
if (value.CompareTo(from) < 0) return 0;
float lerpedTime = to.DelerpWith(from, value);
return GetUneaseTime(lerpedTime, type, rate);
}
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 GetUneaseTime(float time, TransitionType type, float rate) {
switch ((byte)type & 3) {
case (byte)TransitionType.In:
return 1 - GetUneaseOutTime(1 - time, type, rate);
case (byte)TransitionType.Out:
return GetUneaseOutTime(time, type, rate);
case (byte)TransitionType.InOut:
time *= 2;
if (time <= 1) return (1 - GetUneaseOutTime(1 - time, type, rate)) / 2;
else return (GetUneaseOutTime(time - 1, type, rate) + 1) / 2;
case (byte)TransitionType.OutIn:
time *= 2;
if (time <= 1) return GetUneaseOutTime(time, type, rate) / 2;
else return (2 - GetUneaseOutTime(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");
}
}
static float GetUneaseOutTime(float p, TransitionType type, float rate) {
switch ((byte)type & 252) {
case (byte)TransitionType.Ease:
return 1 - Mathf.Pow(1 - p, 1 / rate);
case (byte)TransitionType.Sine:
return Mathf.Asin(p) / (Mathf.PI / 2);
case (byte)TransitionType.Expo:
return -Mathf.Log(1 - p, 2) / 10;
case (byte)TransitionType.Circ:
return 1 - Mathf.Sqrt(1 - p * p);
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)ReflectionHelper.InvokeEmptyConstructor(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),
Rate = new Vec1(1),
Value = init
}
};
AbsoluteValue = (Vector)ReflectionHelper.InvokeEmptyConstructor(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(ushort id) {
int i = RelativeNodes.FindIndex(n => n.Id == id);
if (i == -1) {
var r = GetRelativeNode((ushort)(id - 1));
r.Time = null;
r.Id = id;
return r;
}
return RelativeNodes[i];
}
public MotionNode QueryRelativeNode(ushort id) {
int i = RelativeNodes.FindIndex(n => n.Id == id);
MotionNode cnode;
if (i == -1) cnode = new MotionNode() { Id = id };
else cnode = RelativeNodes[i];
return cnode;
}
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),
Rate = new Vec1(1),
Value = (Vector)ReflectionHelper.InvokeEmptyConstructor(node.Value.GetType())
};
}
else {
cnode = RelativeNodes[i];
RelativeNodes.RemoveAt(i);
}
if (node.Time != null) cnode.Time = node.Time;
if (node.Transition.HasValue) cnode.Transition = node.Transition.Value;
if (node.Rate != null) cnode.Rate = node.Rate;
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>
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 ushort Id;
public Vec1 Time;
float CmpTime { get { return Time != null ? Time.Value : 0; } }
public TransitionType? Transition;
public Vec1 Rate;
public Vector Value;
public MotionNode Clone() {
return new MotionNode() {
Id = Id,
Time = (Vec1)Time.Clone(),
Transition = Transition,
Rate = (Vec1)Rate.Clone(),
Value = Value.Clone()
};
}
public void CopyTo(MotionNode dest) {
dest.Id = Id;
Time.CopyTo(dest.Time);
dest.Transition = Transition;
Rate.CopyTo(dest.Rate);
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 = null;
else {
var t = (Vector)result.Time;
Time.LerpWith(start.Time, lerpedTime, ref t);
}
result.Transition = Transition;
if (Rate == null) result.Rate = null;
else {
var t = (Vector)result.Rate;
Rate.LerpWith(start.Rate, lerpedTime, ref t);
}
if (Value == null) result.Value = null;
else Value.LerpWith(start.Value, lerpedTime, ref result.Value);
}
}
public abstract class Vector : IComparable<Vector> {
public Vector() { }
public abstract byte Dimension { get; }
public abstract int CompareTo(Vector other);
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 float DelerpWith(Vector start, Vector value);
public abstract bool IsZero();
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[] stringTypeArray = new Type[] { typeof(string) };
static readonly Type[] floatArrayTypeArray = new Type[] { typeof(float[]) };
public static Vector Construct(Type type, string s) {
if (!typeof(Vector).IsAssignableFrom(type)) throw new ArgumentException("Type is not vector");
return (Vector)type.GetConstructor(stringTypeArray).Invoke(new object[] { s });
}
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, IComparable<Vec1> {
public float Value;
public Vec1() { Value = 0; }
public Vec1(string s) {
Value = float.Parse(s);
}
public Vec1(float[] v) {
Value = v[0];
}
public Vec1(float i) {
Value = i;
}
public override byte Dimension { get { return 1; } }
public override int CompareTo(Vector other) {
return CompareTo((Vec1)other);
}
public int CompareTo(Vec1 other) {
return Value.CompareTo(other.Value);
}
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 float DelerpWith(Vector start, Vector value) {
var s = (Vec1)start;
var v = (Vec1)value;
return (v.Value - s.Value) / (this.Value - s.Value);
}
public override bool IsZero() {
throw new NotImplementedException();
}
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(string s) {
Value = int.Parse(s);
}
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 int CompareTo(Vector other) {
throw new NotImplementedException();
}
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 float DelerpWith(Vector start, Vector value) {
throw new NotImplementedException();
}
public override bool IsZero() {
throw new NotImplementedException();
}
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(string s) {
Value = float.Parse(s);
}
public Vec1m(float[] v) {
Value = v[0];
}
public Vec1m(float i) : base() {
Value = i;
}
public override byte Dimension { get { return 1; } }
public override int CompareTo(Vector other) {
throw new NotImplementedException();
}
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 float DelerpWith(Vector start, Vector value) {
throw new NotImplementedException();
}
public override bool IsZero() {
throw new NotImplementedException();
}
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 VecPtComp : Vector {
float? w, h;
public VecPtComp() { w = h = 0; }
public VecPtComp(string s) {
Parse(s, out w, out h);
}
public VecPtComp(float[] v) {
w = v[0]; h = v[1];
}
public VecPtComp(float w, float h) : base() {
this.w = w;
this.h = h;
}
public override byte Dimension { get { return 2; } }
public static void Parse(string s, out float? w, out float? h) {
string[] c = s.Split('+');
float rw = 0, rh = 0;
bool aw = false, ah = false;
if (s != "") {
foreach (var i in c) {
if (i == "0") {
aw = true;
ah = true;
continue;
}
float n = float.Parse(i.Substring(0, i.Length - 1));
if (i.EndsWith("w")) {
rw += n;
aw = true;
}
else if (i.EndsWith("h")) {
rh += n;
ah = true;
}
}
}
w = aw ? rw : null;
h = ah ? rh : null;
}
public static VecPtComp Parse(string s) {
var r = new VecPtComp();
float? w, h;
Parse(s, out w, out h);
r.w = w; r.h = h;
return r;
}
public override int CompareTo(Vector other) {
throw new NotImplementedException();
}
public override void ApplyFrom(Vector parent) {
var p = (VecPtComp)parent;
w += p.w ?? 0; h += p.h ?? 0;
}
public override void ReplaceFrom(Vector parent) {
var p = (VecPtComp)parent;
if (p.w.HasValue) w = p.w;
if (p.h.HasValue) h = p.h;
}
public override void LerpWith(Vector start, float lerpedTime, ref Vector result) {
throw new NotImplementedException();
}
public override float DelerpWith(Vector start, Vector value) {
throw new NotImplementedException();
}
public override bool IsZero() {
throw new NotImplementedException();
}
public float ToFloat(Rect rect) {
return (w ?? 0) * rect.width + (h ?? 0) * rect.height;
}
public override void CopyTo(Vector dest) {
var d = (VecPtComp)dest;
d.w = w; d.h = h;
}
public static string ToString(float? w, float? h) {
List<string> list = new List<string>();
if (w != null) list.Add(w.Value.ToString(CultureInfo.InvariantCulture) + "w");
if (h != null) list.Add(h.Value.ToString(CultureInfo.InvariantCulture) + "h");
return string.Join("+", list.ToArray());
}
public override string ToString() {
return ToString(w, h);
}
public override unsafe void ToArray(float* arr) {
arr[0] = w.Value;
arr[1] = h.Value;
}
}
public class Vec3 : Vector {
float? x, y, z;
public Vec3() { x = y = z = 0; }
public Vec3(string s) {
Match m = Regex.Match(s, @"^(\^?)(.*?),(.*?),(.*?)$");
if (m.Groups[1].Value != "") {
float tx = 0, ty = 0, tz = 0;
if (m.Groups[2].Value != "")
tx = VecPtComp.Parse(m.Groups[2].Value).ToFloat(ChartPlayer.hitRect);
if (m.Groups[3].Value != "")
ty = VecPtComp.Parse(m.Groups[3].Value).ToFloat(ChartPlayer.hitRect);
if (m.Groups[4].Value != "")
tz = VecPtComp.Parse(m.Groups[4].Value).ToFloat(ChartPlayer.hitRect);
Vector3 r = Quaternion.LookRotation(new Vector3(tx, ty, tz)).eulerAngles;
x = r.x; y = r.y; z = r.z;
}
else {
if (m.Groups[2].Value != "")
x = float.Parse(m.Groups[2].Value);
if (m.Groups[3].Value != "")
y = float.Parse(m.Groups[3].Value);
if (m.Groups[4].Value != "")
z = float.Parse(m.Groups[4].Value);
}
}
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 int CompareTo(Vector other) {
throw new NotImplementedException();
}
public override void ApplyFrom(Vector parent) {
var p = (Vec3)parent;
x += p.x ?? 0; y += p.y ?? 0; z += p.z ?? 0;
}
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 override float DelerpWith(Vector start, Vector value) {
throw new NotImplementedException();
}
public override bool IsZero() {
throw new NotImplementedException();
}
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 class VecPt : Vector {
public float? xw, xh, yw, yh;
public VecPt() { xw = xh = yw = yh = 0; }
public VecPt(string s) {
Match m = Regex.Match(s, "^(.*?),(.*?)$");
VecPtComp.Parse(m.Groups[1].Value, out xw, out xh);
VecPtComp.Parse(m.Groups[2].Value, out yw, out yh);
}
public VecPt(float[] v) {
xw = v[0]; xh = v[1]; yw = v[2]; yh = v[3];
}
public VecPt(float xw, float xh, float yw, float yh) {
this.xw = xw; this.xh = xh; this.yw = yw; this.yh = yh;
}
public override byte Dimension { get { return 4; } }
public override int CompareTo(Vector other) {
throw new NotImplementedException();
}
public override void ApplyFrom(Vector parent) {
var p = (VecPt)parent;
xw += p.xw ?? 0; xh += p.xh ?? 0;
yw += p.yw ?? 0; yh += p.yh ?? 0;
}
public override void ReplaceFrom(Vector parent) {
var p = (VecPt)parent;
if (p.xw.HasValue) xw = p.xw;
if (p.xh.HasValue) xh = p.xh;
if (p.yw.HasValue) yw = p.yw;
if (p.yh.HasValue) yh = p.yh;
}
public override void LerpWith(Vector start, float lerpedTime, ref Vector result) {
var r = (VecPt)result;
if (start == null) {
r.xw = xw;
r.xh = xh;
r.yw = yw;
r.yh = yh;
return;
}
var s = (VecPt)start;
r.xw = xw.HasValue ? (s.xw.Value * (1 - lerpedTime) + xw.Value * lerpedTime) : s.xw.Value;
r.xh = xh.HasValue ? (s.xh.Value * (1 - lerpedTime) + xh.Value * lerpedTime) : s.xh.Value;
r.yw = yw.HasValue ? (s.yw.Value * (1 - lerpedTime) + yw.Value * lerpedTime) : s.yw.Value;
r.yh = yh.HasValue ? (s.yh.Value * (1 - lerpedTime) + yh.Value * lerpedTime) : s.yh.Value;
}
public override float DelerpWith(Vector start, Vector value) {
throw new NotImplementedException();
}
public override bool IsZero() {
throw new NotImplementedException();
}
public Vector2 ToVector2(Rect rect) {
return new Vector2(
xw.Value * rect.width + xh.Value * rect.height,
yw.Value * rect.width + yh.Value * rect.height
);
}
public override void CopyTo(Vector dest) {
var d = (VecPt)dest;
d.xw = xw; d.xh = xh; d.yw = yw; d.yh = yh;
}
public override string ToString() {
return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh);
}
public override unsafe void ToArray(float* arr) {
arr[0] = xw.Value;
arr[1] = xh.Value;
arr[2] = yw.Value;
arr[3] = yh.Value;
}
}
public class VecCtrl : Vector {
public float? xw, xh, yw, yh, z;
public VecCtrl() { xw = xh = yw = yh = z = 0; }
public VecCtrl(string s) {
Match m = Regex.Match(s, "^(.*?),(.*?),(.*?)$");
VecPtComp.Parse(m.Groups[1].Value, out xw, out xh);
VecPtComp.Parse(m.Groups[2].Value, out yw, out yh);
if (m.Groups[3].Value != "") z = float.Parse(m.Groups[3].Value);
}
public VecCtrl(float[] v) {
xw = v[0]; xh = v[1]; yw = v[2]; yh = v[3]; z = v[4];
}
public VecCtrl(float xw, float xh, float yw, float yh, float z) {
this.xw = xw; this.xh = xh; this.yw = yw; this.yh = yh; this.z = z;
}
public override byte Dimension { get { return 5; } }
public override int CompareTo(Vector other) {
throw new NotImplementedException();
}
public override void ApplyFrom(Vector parent) {
var p = (VecCtrl)parent;
xw += p.xw ?? 0; xh += p.xh ?? 0;
yw += p.yw ?? 0; yh += p.yh ?? 0;
z += p.z ?? 0;
}
public override void ReplaceFrom(Vector parent) {
var p = (VecCtrl)parent;
if (p.xw.HasValue) xw = p.xw;
if (p.xh.HasValue) xh = p.xh;
if (p.yw.HasValue) yw = p.yw;
if (p.yh.HasValue) yh = p.yh;
if (p.z.HasValue) z = p.z;
}
public override void LerpWith(Vector start, float lerpedTime, ref Vector result) {
var r = (VecCtrl)result;
if (start == null) {
r.xw = xw;
r.xh = xh;
r.yw = yw;
r.yh = yh;
r.z = z;
return;
}
var s = (VecCtrl)start;
r.xw = xw.HasValue ? (s.xw.Value * (1 - lerpedTime) + xw.Value * lerpedTime) : s.xw.Value;
r.xh = xh.HasValue ? (s.xh.Value * (1 - lerpedTime) + xh.Value * lerpedTime) : s.xh.Value;
r.yw = yw.HasValue ? (s.yw.Value * (1 - lerpedTime) + yw.Value * lerpedTime) : s.yw.Value;
r.yh = yh.HasValue ? (s.yh.Value * (1 - lerpedTime) + yh.Value * lerpedTime) : s.yh.Value;
r.z = z.HasValue ? (s.z.Value * (1 - lerpedTime) + z.Value * lerpedTime) : s.z.Value;
}
public override float DelerpWith(Vector start, Vector value) {
throw new NotImplementedException();
}
public override bool IsZero() {
if (xw == null || xw != 0) return false;
if (xh == null || xh != 0) return false;
if (yw == null || yw != 0) return false;
if (xh == null || xh != 0) return false;
if (z == null || z != 0) return false;
return true;
}
public Vector3 ToVector3(Rect rect, float deltaz) {
return new Vector3(
xw.Value * rect.width + xh.Value * rect.height,
yw.Value * rect.width + yh.Value * rect.height,
z.Value * deltaz
);
}
public override void CopyTo(Vector dest) {
var d = (VecCtrl)dest;
d.xw = xw; d.xh = xh; d.yw = yw; d.yh = yh; d.z = z;
}
public override string ToString() {
return VecPtComp.ToString(xw, xh) + "," + VecPtComp.ToString(yw, yh) + "," + (z != null ? z.Value.ToString(CultureInfo.InvariantCulture) : "");
}
public override unsafe void ToArray(float* arr) {
arr[0] = xw.Value;
arr[1] = xh.Value;
arr[2] = yw.Value;
arr[3] = yh.Value;
arr[4] = z.Value;
}
}
public class VectorSrc : PropSrc.FixedBuffer {
protected readonly Func<Vector> _cb;
public VectorSrc(Func<Vector> cb) : base(PdtInternalType.Vector, 8 * sizeof(float) + sizeof(int)) { _cb = cb; }
protected override unsafe void InternalGet() {
var v = _cb();
if (v.Dimension > 8) throw new NotSupportedException("Vector dimension too large");
fixed (byte* rptr = buf) {
var ptr = (float*)rptr;
v.ToArray(ptr);
*(int*)(ptr + v.Dimension) = PdtInternalType.Number;
}
}
}
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)];
fixed (float* ptr = values) {
op.CopyTo((byte*)ptr, 0, op.Length - sizeof(int));
}
}
else throw new InvalidOperationException("Invalid operand");
_cb(values);
}
}
}