diff --git a/source/ObjectViewer/FunctionScripts.cs b/source/ObjectViewer/FunctionScripts.cs index 5861b646c..ce178840c 100644 --- a/source/ObjectViewer/FunctionScripts.cs +++ b/source/ObjectViewer/FunctionScripts.cs @@ -161,6 +161,105 @@ internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Tr case Instructions.MathPi: Function.Stack[s] = Math.PI; s++; break; + case Instructions.MathLerp: + Function.Stack[s - 3] = Easing.Lerp(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathSmoothstep: + Function.Stack[s - 3] = Easing.Smoothstep(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathSlerp: + Function.Stack[s - 3] = Easing.Slerp(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathEaseInSine: + Function.Stack[s - 1] = Easing.EaseInSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutSine: + Function.Stack[s - 1] = Easing.EaseOutSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutSine: + Function.Stack[s - 1] = Easing.EaseInOutSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuad: + Function.Stack[s - 1] = Easing.EaseInQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuad: + Function.Stack[s - 1] = Easing.EaseOutQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuad: + Function.Stack[s - 1] = Easing.EaseInOutQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInCubic: + Function.Stack[s - 1] = Easing.EaseInCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutCubic: + Function.Stack[s - 1] = Easing.EaseOutCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutCubic: + Function.Stack[s - 1] = Easing.EaseInOutCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuart: + Function.Stack[s - 1] = Easing.EaseInQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuart: + Function.Stack[s - 1] = Easing.EaseOutQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuart: + Function.Stack[s - 1] = Easing.EaseInOutQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuint: + Function.Stack[s - 1] = Easing.EaseInQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuint: + Function.Stack[s - 1] = Easing.EaseOutQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuint: + Function.Stack[s - 1] = Easing.EaseInOutQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInExpo: + Function.Stack[s - 1] = Easing.EaseInExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutExpo: + Function.Stack[s - 1] = Easing.EaseOutExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutExpo: + Function.Stack[s - 1] = Easing.EaseInOutExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInCirc: + Function.Stack[s - 1] = Easing.EaseInCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutCirc: + Function.Stack[s - 1] = Easing.EaseOutCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutCirc: + Function.Stack[s - 1] = Easing.EaseInOutCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInBack: + Function.Stack[s - 1] = Easing.EaseInBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutBack: + Function.Stack[s - 1] = Easing.EaseOutBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutBack: + Function.Stack[s - 1] = Easing.EaseInOutBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInElastic: + Function.Stack[s - 1] = Easing.EaseInElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutElastic: + Function.Stack[s - 1] = Easing.EaseOutElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutElastic: + Function.Stack[s - 1] = Easing.EaseInOutElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInBounce: + Function.Stack[s - 1] = Easing.EaseInBounce(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutBounce: + Function.Stack[s - 1] = Easing.EaseOutBounce(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutBounce: + Function.Stack[s - 1] = Easing.EaseInOutBounce(Function.Stack[s - 1]); + break; // comparisons case Instructions.CompareEqual: Function.Stack[s - 2] = Function.Stack[s - 2] == Function.Stack[s - 1] ? 1.0 : 0.0; diff --git a/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs b/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs index 3710a10d0..4e5f61a6b 100644 --- a/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs +++ b/source/OpenBVE/Game/ObjectManager/AnimatedObjects/FunctionScripts.cs @@ -163,6 +163,105 @@ internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Tr case Instructions.MathPi: Function.Stack[s] = Math.PI; s++; break; + case Instructions.MathLerp: + Function.Stack[s - 3] = Easing.Lerp(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathSmoothstep: + Function.Stack[s - 3] = Easing.Smoothstep(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathSlerp: + Function.Stack[s - 3] = Easing.Slerp(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathEaseInSine: + Function.Stack[s - 1] = Easing.EaseInSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutSine: + Function.Stack[s - 1] = Easing.EaseOutSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutSine: + Function.Stack[s - 1] = Easing.EaseInOutSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuad: + Function.Stack[s - 1] = Easing.EaseInQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuad: + Function.Stack[s - 1] = Easing.EaseOutQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuad: + Function.Stack[s - 1] = Easing.EaseInOutQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInCubic: + Function.Stack[s - 1] = Easing.EaseInCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutCubic: + Function.Stack[s - 1] = Easing.EaseOutCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutCubic: + Function.Stack[s - 1] = Easing.EaseInOutCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuart: + Function.Stack[s - 1] = Easing.EaseInQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuart: + Function.Stack[s - 1] = Easing.EaseOutQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuart: + Function.Stack[s - 1] = Easing.EaseInOutQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuint: + Function.Stack[s - 1] = Easing.EaseInQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuint: + Function.Stack[s - 1] = Easing.EaseOutQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuint: + Function.Stack[s - 1] = Easing.EaseInOutQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInExpo: + Function.Stack[s - 1] = Easing.EaseInExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutExpo: + Function.Stack[s - 1] = Easing.EaseOutExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutExpo: + Function.Stack[s - 1] = Easing.EaseInOutExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInCirc: + Function.Stack[s - 1] = Easing.EaseInCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutCirc: + Function.Stack[s - 1] = Easing.EaseOutCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutCirc: + Function.Stack[s - 1] = Easing.EaseInOutCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInBack: + Function.Stack[s - 1] = Easing.EaseInBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutBack: + Function.Stack[s - 1] = Easing.EaseOutBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutBack: + Function.Stack[s - 1] = Easing.EaseInOutBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInElastic: + Function.Stack[s - 1] = Easing.EaseInElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutElastic: + Function.Stack[s - 1] = Easing.EaseOutElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutElastic: + Function.Stack[s - 1] = Easing.EaseInOutElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInBounce: + Function.Stack[s - 1] = Easing.EaseInBounce(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutBounce: + Function.Stack[s - 1] = Easing.EaseOutBounce(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutBounce: + Function.Stack[s - 1] = Easing.EaseInOutBounce(Function.Stack[s - 1]); + break; // comparisons case Instructions.CompareEqual: Function.Stack[s - 2] = Function.Stack[s - 2] == Function.Stack[s - 1] ? 1.0 : 0.0; diff --git a/source/OpenBveApi/FunctionScripts/FunctionScript.Notation.cs b/source/OpenBveApi/FunctionScripts/FunctionScript.Notation.cs index 95011d77e..9b085a972 100644 --- a/source/OpenBveApi/FunctionScripts/FunctionScript.Notation.cs +++ b/source/OpenBveApi/FunctionScripts/FunctionScript.Notation.cs @@ -203,6 +203,13 @@ public static string GetPostfixNotationFromFunctionNotation(string Expression) { return a[0] + " " + a[1] + " " + f; } throw new System.IO.InvalidDataException(f + " is expected to have 2 arguments in " + Expression); + case "lerp": + case "smoothstep": + case "slerp": + if (n == 3) { + return a[0] + " " + a[1] + " " + a[2] + " " + f; + } + throw new System.IO.InvalidDataException(f + " is expected to have 3 arguments in " + Expression); case "minus": case "reciprocal": case "floor": @@ -217,6 +224,36 @@ public static string GetPostfixNotationFromFunctionNotation(string Expression) { case "cos": case "tan": case "arctan": + case "easeinsine": + case "easeoutsine": + case "easeinoutsine": + case "easeinquad": + case "easeoutquad": + case "easeinoutquad": + case "easeincubic": + case "easeoutcubic": + case "easeinoutcubic": + case "easeinquart": + case "easeoutquart": + case "easeinoutquart": + case "easeinquint": + case "easeoutquint": + case "easeinoutquint": + case "easeinexpo": + case "easeoutexpo": + case "easeinoutexpo": + case "easeincirc": + case "easeoutcirc": + case "easeinoutcirc": + case "easeinback": + case "easeoutback": + case "easeinoutback": + case "easeinelastic": + case "easeoutelastic": + case "easeinoutelastic": + case "easeinbounce": + case "easeoutbounce": + case "easeinoutbounce": if (n == 1) { return a[0] + " " + f; } diff --git a/source/OpenBveApi/FunctionScripts/FunctionScript.cs b/source/OpenBveApi/FunctionScripts/FunctionScript.cs index d9db77f7c..7a97f64e1 100644 --- a/source/OpenBveApi/FunctionScripts/FunctionScript.cs +++ b/source/OpenBveApi/FunctionScripts/FunctionScript.cs @@ -321,6 +321,171 @@ public FunctionScript(HostInterface Host, string Expression, bool Infix) if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); InstructionSet[n] = Instructions.MathPi; n++; s++; if (s >= m) m = s; break; + case "lerp": + if (s < 3) throw new InvalidOperationException(Arguments[i] + " requires at least 3 arguments on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathLerp; + n++; s -= 2; break; + case "smoothstep": + if (s < 3) throw new InvalidOperationException(Arguments[i] + " requires at least 3 arguments on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathSmoothstep; + n++; s -= 2; break; + case "slerp": + if (s < 3) throw new InvalidOperationException(Arguments[i] + " requires at least 3 arguments on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathSlerp; + n++; s -= 2; break; + case "easeinsine": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInSine; + n++; break; + case "easeoutsine": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutSine; + n++; break; + case "easeinoutsine": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutSine; + n++; break; + case "easeinquad": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInQuad; + n++; break; + case "easeoutquad": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutQuad; + n++; break; + case "easeinoutquad": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutQuad; + n++; break; + case "easeincubic": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInCubic; + n++; break; + case "easeoutcubic": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutCubic; + n++; break; + case "easeinoutcubic": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutCubic; + n++; break; + case "easeinquart": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInQuart; + n++; break; + case "easeoutquart": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutQuart; + n++; break; + case "easeinoutquart": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutQuart; + n++; break; + case "easeinquint": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInQuint; + n++; break; + case "easeoutquint": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutQuint; + n++; break; + case "easeinoutquint": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutQuint; + n++; break; + case "easeinexpo": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInExpo; + n++; break; + case "easeoutexpo": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutExpo; + n++; break; + case "easeinoutexpo": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutExpo; + n++; break; + case "easeincirc": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInCirc; + n++; break; + case "easeoutcirc": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutCirc; + n++; break; + case "easeinoutcirc": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutCirc; + n++; break; + case "easeinback": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInBack; + n++; break; + case "easeoutback": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutBack; + n++; break; + case "easeinoutback": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutBack; + n++; break; + case "easeinelastic": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInElastic; + n++; break; + case "easeoutelastic": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutElastic; + n++; break; + case "easeinoutelastic": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutElastic; + n++; break; + case "easeinbounce": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInBounce; + n++; break; + case "easeoutbounce": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseOutBounce; + n++; break; + case "easeinoutbounce": + if (s < 1) throw new InvalidOperationException(Arguments[i] + " requires at least 1 argument on the stack in function script " + Expression); + if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); + InstructionSet[n] = Instructions.MathEaseInOutBounce; + n++; break; case "==": if (s < 2) throw new InvalidOperationException(Arguments[i] + " requires at least 2 arguments on the stack in function script " + Expression); if (n >= InstructionSet.Length) Array.Resize(ref InstructionSet, InstructionSet.Length << 1); diff --git a/source/OpenBveApi/FunctionScripts/Instructions.cs b/source/OpenBveApi/FunctionScripts/Instructions.cs index 355a66bd0..92a04138d 100644 --- a/source/OpenBveApi/FunctionScripts/Instructions.cs +++ b/source/OpenBveApi/FunctionScripts/Instructions.cs @@ -9,6 +9,17 @@ public enum Instructions { MathIncrement, MathDecrement, MathFusedMultiplyAdd, MathQuotient, MathMod, MathFloor, MathCeiling, MathRound, MathMin, MathMax, MathAbs, MathSign, MathExp, MathLog, MathSqrt, MathSin, MathCos, MathTan, MathArcTan, MathPi, + MathLerp, MathSmoothstep, MathSlerp, + MathEaseInSine, MathEaseOutSine, MathEaseInOutSine, + MathEaseInQuad, MathEaseOutQuad, MathEaseInOutQuad, + MathEaseInCubic, MathEaseOutCubic, MathEaseInOutCubic, + MathEaseInQuart, MathEaseOutQuart, MathEaseInOutQuart, + MathEaseInQuint, MathEaseOutQuint, MathEaseInOutQuint, + MathEaseInExpo, MathEaseOutExpo, MathEaseInOutExpo, + MathEaseInCirc, MathEaseOutCirc, MathEaseInOutCirc, + MathEaseInBack, MathEaseOutBack, MathEaseInOutBack, + MathEaseInElastic, MathEaseOutElastic, MathEaseInOutElastic, + MathEaseInBounce, MathEaseOutBounce, MathEaseInOutBounce, CompareEqual, CompareUnequal, CompareLess, CompareGreater, CompareLessEqual, CompareGreaterEqual, CompareConditional, LogicalNot, LogicalAnd, LogicalOr, LogicalNand, LogicalNor, LogicalXor, /* diff --git a/source/OpenBveApi/Math/Easing.cs b/source/OpenBveApi/Math/Easing.cs new file mode 100644 index 000000000..8832afca6 --- /dev/null +++ b/source/OpenBveApi/Math/Easing.cs @@ -0,0 +1,368 @@ +namespace OpenBveApi.Math +{ + /// Provides standard easing and interpolation functions + /// Easing curves follow the reference implementations by Robert Penner and operate on a normalized input in the range 0..1 + public static class Easing + { + /// Linearly interpolates between two values + /// The first value + /// The second value + /// The interpolation factor + public static double Lerp(double a, double b, double t) + { + return a + (b - a) * t; + } + + /// Performs a Hermite (smoothstep) interpolation between two values + /// The first value + /// The second value + /// The interpolation input + public static double Smoothstep(double a, double b, double x) + { + if (a == b) + { + return a; + } + double t = (x - a) / (b - a); + return t * t * (3.0 - 2.0 * t); + } + + /// Spherically (shortest-arc) interpolates between two angles + /// The first angle + /// The second angle + /// The interpolation factor + public static double Slerp(double a, double b, double t) + { + double delta = b - a; + delta = (delta + System.Math.PI) % (2.0 * System.Math.PI); + if (delta < 0.0) delta += 2.0 * System.Math.PI; + delta -= System.Math.PI; + return a + delta * t; + } + + /// Eases the input using a sine curve + /// The input, in the range 0..1 + public static double EaseInSine(double t) + { + return 1.0 - System.Math.Cos(t * System.Math.PI / 2.0); + } + + /// Eases the input using a sine curve + /// The input, in the range 0..1 + public static double EaseOutSine(double t) + { + return System.Math.Sin(t * System.Math.PI / 2.0); + } + + /// Eases the input using a sine curve + /// The input, in the range 0..1 + public static double EaseInOutSine(double t) + { + return -(System.Math.Cos(System.Math.PI * t) - 1.0) / 2.0; + } + + /// Eases the input using a quadratic curve + /// The input, in the range 0..1 + public static double EaseInQuad(double t) + { + return t * t; + } + + /// Eases the input using a quadratic curve + /// The input, in the range 0..1 + public static double EaseOutQuad(double t) + { + double u = 1.0 - t; + return 1.0 - u * u; + } + + /// Eases the input using a quadratic curve + /// The input, in the range 0..1 + public static double EaseInOutQuad(double t) + { + if (t < 0.5) + { + return 2.0 * t * t; + } + double v = -2.0 * t + 2.0; + return 1.0 - v * v / 2.0; + } + + /// Eases the input using a cubic curve + /// The input, in the range 0..1 + public static double EaseInCubic(double t) + { + return t * t * t; + } + + /// Eases the input using a cubic curve + /// The input, in the range 0..1 + public static double EaseOutCubic(double t) + { + double u = 1.0 - t; + return 1.0 - u * u * u; + } + + /// Eases the input using a cubic curve + /// The input, in the range 0..1 + public static double EaseInOutCubic(double t) + { + if (t < 0.5) + { + return 4.0 * t * t * t; + } + double v = -2.0 * t + 2.0; + return 1.0 - v * v * v / 2.0; + } + + /// Eases the input using a quartic curve + /// The input, in the range 0..1 + public static double EaseInQuart(double t) + { + double s = t * t; + return s * s; + } + + /// Eases the input using a quartic curve + /// The input, in the range 0..1 + public static double EaseOutQuart(double t) + { + double u = 1.0 - t; + double s = u * u; + return 1.0 - s * s; + } + + /// Eases the input using a quartic curve + /// The input, in the range 0..1 + public static double EaseInOutQuart(double t) + { + if (t < 0.5) + { + double s = t * t; + return 8.0 * s * s; + } + double v = -2.0 * t + 2.0; + double s2 = v * v; + return 1.0 - s2 * s2 / 2.0; + } + + /// Eases the input using a quintic curve + /// The input, in the range 0..1 + public static double EaseInQuint(double t) + { + double s = t * t; + return s * s * t; + } + + /// Eases the input using a quintic curve + /// The input, in the range 0..1 + public static double EaseOutQuint(double t) + { + double u = 1.0 - t; + double s = u * u; + return 1.0 - s * s * u; + } + + /// Eases the input using a quintic curve + /// The input, in the range 0..1 + public static double EaseInOutQuint(double t) + { + if (t < 0.5) + { + double s = t * t; + return 16.0 * s * s * t; + } + double v = -2.0 * t + 2.0; + double s2 = v * v; + return 1.0 - s2 * s2 * v / 2.0; + } + + /// Eases the input using an exponential curve + /// The input, in the range 0..1 + public static double EaseInExpo(double t) + { + return t == 0.0 ? 0.0 : System.Math.Pow(2.0, 10.0 * t - 10.0); + } + + /// Eases the input using an exponential curve + /// The input, in the range 0..1 + public static double EaseOutExpo(double t) + { + return t == 1.0 ? 1.0 : 1.0 - System.Math.Pow(2.0, -10.0 * t); + } + + /// Eases the input using an exponential curve + /// The input, in the range 0..1 + public static double EaseInOutExpo(double t) + { + if (t == 0.0) + { + return 0.0; + } + if (t == 1.0) + { + return 1.0; + } + if (t < 0.5) + { + return System.Math.Pow(2.0, 20.0 * t - 10.0) / 2.0; + } + return (2.0 - System.Math.Pow(2.0, -20.0 * t + 10.0)) / 2.0; + } + + /// Eases the input using a circular curve + /// The input, in the range 0..1 + public static double EaseInCirc(double t) + { + return 1.0 - Extensions.SqrtC(1.0 - t * t); + } + + /// Eases the input using a circular curve + /// The input, in the range 0..1 + public static double EaseOutCirc(double t) + { + double u = t - 1.0; + return Extensions.SqrtC(1.0 - u * u); + } + + /// Eases the input using a circular curve + /// The input, in the range 0..1 + public static double EaseInOutCirc(double t) + { + if (t < 0.5) + { + return (1.0 - Extensions.SqrtC(1.0 - 4.0 * t * t)) / 2.0; + } + double v = -2.0 * t + 2.0; + return (Extensions.SqrtC(1.0 - v * v) + 1.0) / 2.0; + } + + /// Eases the input using a back curve + /// The input, in the range 0..1 + public static double EaseInBack(double t) + { + const double c1 = 1.70158; + const double c3 = c1 + 1.0; + return c3 * t * t * t - c1 * t * t; + } + + /// Eases the input using a back curve + /// The input, in the range 0..1 + public static double EaseOutBack(double t) + { + const double c1 = 1.70158; + const double c3 = c1 + 1.0; + double u = t - 1.0; + return 1.0 + c3 * u * u * u + c1 * u * u; + } + + /// Eases the input using a back curve + /// The input, in the range 0..1 + public static double EaseInOutBack(double t) + { + const double c1 = 1.70158; + const double c2 = c1 * 1.525; + if (t < 0.5) + { + double v = 2.0 * t; + return (v * v * ((c2 + 1.0) * v - c2)) / 2.0; + } + double w = 2.0 * t - 2.0; + return (w * w * ((c2 + 1.0) * w + c2) + 2.0) / 2.0; + } + + /// Eases the input using an elastic curve + /// The input, in the range 0..1 + public static double EaseInElastic(double t) + { + const double c4 = (2.0 * System.Math.PI) / 3.0; + if (t == 0.0) + { + return 0.0; + } + if (t == 1.0) + { + return 1.0; + } + return -System.Math.Pow(2.0, 10.0 * t - 10.0) * System.Math.Sin((t * 10.0 - 10.75) * c4); + } + + /// Eases the input using an elastic curve + /// The input, in the range 0..1 + public static double EaseOutElastic(double t) + { + const double c4 = (2.0 * System.Math.PI) / 3.0; + if (t == 0.0) + { + return 0.0; + } + if (t == 1.0) + { + return 1.0; + } + return System.Math.Pow(2.0, -10.0 * t) * System.Math.Sin((t * 10.0 - 0.75) * c4) + 1.0; + } + + /// Eases the input using an elastic curve + /// The input, in the range 0..1 + public static double EaseInOutElastic(double t) + { + const double c5 = (2.0 * System.Math.PI) / 4.5; + if (t == 0.0) + { + return 0.0; + } + if (t == 1.0) + { + return 1.0; + } + if (t < 0.5) + { + return -(System.Math.Pow(2.0, 20.0 * t - 10.0) * System.Math.Sin((20.0 * t - 11.125) * c5)) / 2.0; + } + return (System.Math.Pow(2.0, -20.0 * t + 10.0) * System.Math.Sin((20.0 * t - 11.125) * c5)) / 2.0 + 1.0; + } + + /// Eases the input using a bounce curve + /// The input, in the range 0..1 + public static double EaseInBounce(double t) + { + return 1.0 - EaseOutBounce(1.0 - t); + } + + /// Eases the input using a bounce curve + /// The input, in the range 0..1 + public static double EaseOutBounce(double t) + { + const double n1 = 7.5625; + const double d1 = 2.75; + if (t < 1.0 / d1) + { + return n1 * t * t; + } + if (t < 2.0 / d1) + { + double u = t - 1.5 / d1; + return n1 * u * u + 0.75; + } + if (t < 2.5 / d1) + { + double u = t - 2.25 / d1; + return n1 * u * u + 0.9375; + } + double v = t - 2.625 / d1; + return n1 * v * v + 0.984375; + } + + /// Eases the input using a bounce curve + /// The input, in the range 0..1 + public static double EaseInOutBounce(double t) + { + if (t < 0.5) + { + return (1.0 - EaseOutBounce(1.0 - 2.0 * t)) / 2.0; + } + return (1.0 + EaseOutBounce(2.0 * t - 1.0)) / 2.0; + } + } +} diff --git a/source/OpenBveApi/OpenBveApi.csproj b/source/OpenBveApi/OpenBveApi.csproj index 623bd7fd1..8cf63e31d 100644 --- a/source/OpenBveApi/OpenBveApi.csproj +++ b/source/OpenBveApi/OpenBveApi.csproj @@ -131,6 +131,7 @@ + diff --git a/source/RouteViewer/FunctionScripts.cs b/source/RouteViewer/FunctionScripts.cs index 6ec5b6a6e..85efc5a41 100644 --- a/source/RouteViewer/FunctionScripts.cs +++ b/source/RouteViewer/FunctionScripts.cs @@ -160,6 +160,105 @@ internal static void ExecuteFunctionScript(FunctionScript Function, TrainBase Tr case Instructions.MathPi: Function.Stack[s] = Math.PI; s++; break; + case Instructions.MathLerp: + Function.Stack[s - 3] = Easing.Lerp(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathSmoothstep: + Function.Stack[s - 3] = Easing.Smoothstep(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathSlerp: + Function.Stack[s - 3] = Easing.Slerp(Function.Stack[s - 3], Function.Stack[s - 2], Function.Stack[s - 1]); + s -= 2; break; + case Instructions.MathEaseInSine: + Function.Stack[s - 1] = Easing.EaseInSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutSine: + Function.Stack[s - 1] = Easing.EaseOutSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutSine: + Function.Stack[s - 1] = Easing.EaseInOutSine(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuad: + Function.Stack[s - 1] = Easing.EaseInQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuad: + Function.Stack[s - 1] = Easing.EaseOutQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuad: + Function.Stack[s - 1] = Easing.EaseInOutQuad(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInCubic: + Function.Stack[s - 1] = Easing.EaseInCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutCubic: + Function.Stack[s - 1] = Easing.EaseOutCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutCubic: + Function.Stack[s - 1] = Easing.EaseInOutCubic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuart: + Function.Stack[s - 1] = Easing.EaseInQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuart: + Function.Stack[s - 1] = Easing.EaseOutQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuart: + Function.Stack[s - 1] = Easing.EaseInOutQuart(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInQuint: + Function.Stack[s - 1] = Easing.EaseInQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutQuint: + Function.Stack[s - 1] = Easing.EaseOutQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutQuint: + Function.Stack[s - 1] = Easing.EaseInOutQuint(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInExpo: + Function.Stack[s - 1] = Easing.EaseInExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutExpo: + Function.Stack[s - 1] = Easing.EaseOutExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutExpo: + Function.Stack[s - 1] = Easing.EaseInOutExpo(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInCirc: + Function.Stack[s - 1] = Easing.EaseInCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutCirc: + Function.Stack[s - 1] = Easing.EaseOutCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutCirc: + Function.Stack[s - 1] = Easing.EaseInOutCirc(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInBack: + Function.Stack[s - 1] = Easing.EaseInBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutBack: + Function.Stack[s - 1] = Easing.EaseOutBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutBack: + Function.Stack[s - 1] = Easing.EaseInOutBack(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInElastic: + Function.Stack[s - 1] = Easing.EaseInElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutElastic: + Function.Stack[s - 1] = Easing.EaseOutElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutElastic: + Function.Stack[s - 1] = Easing.EaseInOutElastic(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInBounce: + Function.Stack[s - 1] = Easing.EaseInBounce(Function.Stack[s - 1]); + break; + case Instructions.MathEaseOutBounce: + Function.Stack[s - 1] = Easing.EaseOutBounce(Function.Stack[s - 1]); + break; + case Instructions.MathEaseInOutBounce: + Function.Stack[s - 1] = Easing.EaseInOutBounce(Function.Stack[s - 1]); + break; // comparisons case Instructions.CompareEqual: Function.Stack[s - 2] = Function.Stack[s - 2] == Function.Stack[s - 1] ? 1.0 : 0.0;