From 3b581bd0ca88176e9ae015bd21edc925eb141316 Mon Sep 17 00:00:00 2001 From: Hero Date: Thu, 26 Feb 2026 22:22:31 +0200 Subject: [PATCH] better math util because who doesnt like maths --- source/funkin/backend/utils/MathUtil.hx | 414 +++++++++++++----------- 1 file changed, 217 insertions(+), 197 deletions(-) diff --git a/source/funkin/backend/utils/MathUtil.hx b/source/funkin/backend/utils/MathUtil.hx index 2ca2f5a2a8..c71414edf3 100644 --- a/source/funkin/backend/utils/MathUtil.hx +++ b/source/funkin/backend/utils/MathUtil.hx @@ -3,200 +3,220 @@ package funkin.backend.utils; import haxe.macro.Expr; final class MathUtil { - /** - * Returns the maximum value in the arguments. - * @param args Array of values - * - * @return The maximum value - **/ - public static function maxInt(...args:Int):Int { - var max = args[0]; - for(i in 1...args.length) { - var arg = args[i]; - if(arg > max) - max = arg; - } - return max; - } - - /** - * Returns the minimum value in the arguments. - * @param args Array of values - * - * @return The minimum value - **/ - public static function minInt(...args:Int):Int { - var min = args[0]; - for(i in 1...args.length) { - var arg = args[i]; - if(arg < min) - min = arg; - } - return min; - } - - /** - * Returns the maximum value in the arguments. - * - * NOTE: If you are using this in compile time, you should use `MathUtil.maxSmart` instead of this for better performance. - * - * @param args Array of values - * - * @return The maximum value - **/ - public static function max(...args:Float):Float { - var max = args[0]; - for(i in 1...args.length) { - var arg = args[i]; - if(arg > max) - max = arg; - } - return max; - } - - /** - * Returns the minimum value in the arguments. - * - * NOTE: If you are using this in compile time, you should use `MathUtil.minSmart` instead of this for better performance. - * - * @param args Array of values - * - * @return The minimum value - **/ - public static function min(...args:Float):Float { - var min = args[0]; - for(i in 1...args.length) { - var arg = args[i]; - if(arg < min) - min = arg; - } - return min; - } - - /** - * Checks if a is less than b with considering a margin of error. - * - * @param a Float - * @param b Float - * @param margin Float (Default: EPSILON) - * - * @return Bool - **/ - public static function lessThan(a:Float, b:Float, margin:Float = 0.0000001):Bool { - return a < b - margin; - } - - /** - * Checks if a is less than or equally b with considering a margin of error. - * - * @param a Float - * @param b Float - * @param margin Float (Default: EPSILON) - * - * @return Bool - **/ - public static function lessThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { - return a <= b - margin; - } - - /** - * Checks if a is greater than b with considering a margin of error. - * - * @param a Float - * @param b Float - * @param margin Float (Default: EPSILON) - * - * @return Bool - **/ - public static function greaterThan(a:Float, b:Float, margin:Float = 0.0000001):Bool { - return a > b + margin; - } - - /** - * Checks if a is greater than or equally b with considering a margin of error. - * - * @param a Float - * @param b Float - * @param margin Float (Default: EPSILON) - * - * @return Bool - **/ - public static function greaterThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { - return a >= b + margin; - } - - /** - * Checks if a is approximately equal to b. - * - * @param a Float - * @param b Float - * @param margin Float (Default: EPSILON) - * - * @return Bool - **/ - public static function equal(a:Float, b:Float, margin:Float = 0.0000001):Bool { - return Math.abs(a - b) <= margin; - } - - /** - * Checks if a are not approximately equal to b. - * - * @param a Float - * @param b Float - * @param margin Float (Default: EPSILON) - * - * @return Bool - **/ - public static function notEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { - return Math.abs(a - b) > margin; - } - - /** - * Shortcut to `Math.max` but with infinite amount of arguments - * - * Might not preserve the order of arguments, please test this. - * - * Dont use this in hscript, it doesnt work, it only works on compile time - **/ - @:dox(hide) public static macro function maxSmart(..._args:Expr):Expr { - return genericMinMaxSmart(_args.toArray(), "Math.max"); - } - - /** - * Shortcut to `Math.min` but with infinite amount of arguments - * - * Might not preserve the order of arguments, please test this. - * - * Dont use this in hscript, it doesnt work, it only works on compile time - **/ - @:dox(hide) public static macro function minSmart(..._args:Expr):Expr { - return genericMinMaxSmart(_args.toArray(), "Math.min"); - } - - #if macro - @:dox(hide) private static function genericMinMaxSmart(_args:Array, funcPath:String):Expr { - var args = _args.copy(); - if (args.length == 0) return macro 0; - - var func = funcPath.split("."); - - function nested(lst:Array):Expr { - if (lst.length == 1) { - return macro ${lst[0]}; - } else if (lst.length == 2) { - return macro $p{func}(${lst[0]}, ${lst[1]}); - } else { - var mid = Std.int(lst.length / 2); - return macro $p{func}(${nested(lst.slice(0, mid))}, ${nested(lst.slice(mid, lst.length))}); - } - } - - var expr = nested(args); - - //var printer = new haxe.macro.Printer(); - //trace(printer.printExpr(expr)); - - return macro $expr; - } - #end -} \ No newline at end of file + public static inline var EULER:Float = 2.718281828459; + + /** + * Returns the maximum value in the arguments. + * @param args Array of values + * + * @return The maximum value + **/ + public static function maxInt(...args:Int):Int { + var max = args[0]; + for(i in 1...args.length) { + var arg = args[i]; + if(arg > max) + max = arg; + } + return max; + } + + /** + * Returns the minimum value in the arguments. + * @param args Array of values + * + * @return The minimum value + **/ + public static function minInt(...args:Int):Int { + var min = args[0]; + for(i in 1...args.length) { + var arg = args[i]; + if(arg < min) + min = arg; + } + return min; + } + + /** + * Returns the maximum value in the arguments. + * + * NOTE: If you are using this in compile time, you should use `MathUtil.maxSmart` instead of this for better performance. + * + * @param args Array of values + * + * @return The maximum value + **/ + public static function max(...args:Float):Float { + var max = args[0]; + for(i in 1...args.length) { + var arg = args[i]; + if(arg > max) + max = arg; + } + return max; + } + + /** + * Returns the minimum value in the arguments. + * + * NOTE: If you are using this in compile time, you should use `MathUtil.minSmart` instead of this for better performance. + * + * @param args Array of values + * + * @return The minimum value + **/ + public static function min(...args:Float):Float { + var min = args[0]; + for(i in 1...args.length) { + var arg = args[i]; + if(arg < min) + min = arg; + } + return min; + } + + /** + * Checks if a is less than b with considering a margin of error. + * * @param a Float + * @param b Float + * @param margin Float (Default: EPSILON) + * * @return Bool + **/ + public static function lessThan(a:Float, b:Float, margin:Float = 0.0000001):Bool { + return a < b - margin; + } + + /** + * Checks if a is less than or equally b with considering a margin of error. + * * @param a Float + * @param b Float + * @param margin Float (Default: EPSILON) + * * @return Bool + **/ + public static function lessThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { + return a <= b - margin; + } + + /** + * Checks if a is greater than b with considering a margin of error. + * * @param a Float + * @param b Float + * @param margin Float (Default: EPSILON) + * * @return Bool + **/ + public static function greaterThan(a:Float, b:Float, margin:Float = 0.0000001):Bool { + return a > b + margin; + } + + /** + * Checks if a is greater than or equally b with considering a margin of error. + * * @param a Float + * @param b Float + * @param margin Float (Default: EPSILON) + * * @return Bool + **/ + public static function greaterThanEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { + return a >= b + margin; + } + + /** + * Checks if a is approximately equal to b. + * * @param a Float + * @param b Float + * @param margin Float (Default: EPSILON) + * * @return Bool + **/ + public static function equal(a:Float, b:Float, margin:Float = 0.0000001):Bool { + return Math.abs(a - b) <= margin; + } + + /** + * Checks if a are not approximately equal to b. + * * @param a Float + * @param b Float + * @param margin Float (Default: EPSILON) + * * @return Bool + **/ + public static function notEqual(a:Float, b:Float, margin:Float = 0.0000001):Bool { + return Math.abs(a - b) > margin; + } + + /** + * @param edge0 Float + * @param edge1 Float + * @param x Float + * @return Float + **/ + public static function smoothStep(edge0:Float, edge1:Float, x:Float):Float { + var t = (x - edge0) / (edge1 - edge0); + var clamped = t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t); + return clamped * clamped * (3.0 - 2.0 * clamped); + } + + /** + * @param a Float + * @param b Float + * @param v Float + * @return Float + **/ + public static function inverseLerp(a:Float, b:Float, v:Float):Float { + return (v - a) / (b - a); + } + + /** + * @param v Float + * @return Float + **/ + public static function fract(v:Float):Float { + return v - Math.floor(v); + } + + /** + * Shortcut to `Math.max` but with infinite amount of arguments + * + * Might not preserve the order of arguments, please test this. + * + * Dont use this in hscript, it doesnt work, it only works on compile time + **/ + @:dox(hide) public static macro function maxSmart(..._args:Expr):Expr { + return genericMinMaxSmart(_args.toArray(), "Math.max"); + } + + /** + * Shortcut to `Math.min` but with infinite amount of arguments + * + * Might not preserve the order of arguments, please test this. + * + * Dont use this in hscript, it doesnt work, it only works on compile time + **/ + @:dox(hide) public static macro function minSmart(..._args:Expr):Expr { + return genericMinMaxSmart(_args.toArray(), "Math.min"); + } + + #if macro + @:dox(hide) private static function genericMinMaxSmart(_args:Array, funcPath:String):Expr { + var args = _args.copy(); + if (args.length == 0) return macro 0; + + var func = funcPath.split("."); + + function nested(lst:Array):Expr { + if (lst.length == 1) { + return macro ${lst[0]}; + } else if (lst.length == 2) { + return macro $p{func}(${lst[0]}, ${lst[1]}); + } else { + var mid = Std.int(lst.length / 2); + return macro $p{func}(${nested(lst.slice(0, mid))}, ${nested(lst.slice(mid, lst.length))}); + } + } + + var expr = nested(args); + + //var printer = new haxe.macro.Printer(); + //trace(printer.printExpr(expr)); + + return macro $expr; + } + #end +}