433 lines
10 KiB
C#
433 lines
10 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using Godot;
|
|
using System.Text;
|
|
using System;
|
|
|
|
namespace Rokojori
|
|
{
|
|
public class MathX
|
|
{
|
|
public const float fps120Delta = 1/120f;
|
|
|
|
static Dictionary<int,int> factorialLookUp = new Dictionary<int, int>();
|
|
|
|
public static int Factorial( int i )
|
|
{
|
|
if ( factorialLookUp.ContainsKey( i ) )
|
|
{
|
|
return factorialLookUp[ i ];
|
|
}
|
|
|
|
var result = 1;
|
|
|
|
if ( i > 1 )
|
|
{
|
|
var before = Factorial( i - 1 );
|
|
result = before * i;
|
|
}
|
|
|
|
factorialLookUp[ i ] = result;
|
|
|
|
return factorialLookUp[ i ];
|
|
|
|
}
|
|
|
|
public static float Min( params float[] values )
|
|
{
|
|
var value = float.MaxValue;
|
|
|
|
for ( int i = 0; i < values.Length; i++ )
|
|
{
|
|
value = Mathf.Min( values[ i ], value );
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public static float Max( params float[] values )
|
|
{
|
|
var value = - float.MaxValue;
|
|
|
|
for ( int i = 0; i < values.Length; i++ )
|
|
{
|
|
value = Mathf.Max( values[ i ], value );
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public static float Sample( float tl, float tr, float bl, float br, Vector2 uv )
|
|
{
|
|
return Mathf.Lerp( tl, tr, uv.X ) +
|
|
( bl - tl ) * uv.Y * ( 1.0f - uv.X ) +
|
|
( br - tr ) * uv.X * uv.Y;
|
|
}
|
|
|
|
public static float Sample(
|
|
float ba, float bb, float bc, float bd,
|
|
float ta, float tb, float tc, float td,
|
|
Vector3 uvw
|
|
)
|
|
{
|
|
var bottom = Sample( ba, bb, bc, bd, new Vector2( uvw.X, uvw.Y ) );
|
|
var top = Sample( ta, tb, tc, td, new Vector2( uvw.X, uvw.Y ) );
|
|
|
|
return Mathf.Lerp( bottom, top, uvw.Z );
|
|
}
|
|
|
|
public static float Fract( float value )
|
|
{
|
|
return value - Mathf.Floor( value );
|
|
}
|
|
|
|
public static float TimeLerpAmountExp( float t, float time )
|
|
{
|
|
return Mathf.Exp( -t * time );
|
|
}
|
|
|
|
public static float TimeLerp( float lastValue, float nextValue, float t, float time )
|
|
{
|
|
return Mathf.Lerp( nextValue, lastValue, TimeLerpAmountExp( t, time ) );
|
|
}
|
|
|
|
public static float AbsoluteDeltaAngle( float degreesA, float degreesB )
|
|
{
|
|
return Mathf.Abs( AngleDelta( degreesA, degreesB ) );
|
|
}
|
|
|
|
public static float Smoothstep ( float edge0, float edge1, float x )
|
|
{
|
|
x = MathX.Clamp01( ( x - edge0 ) / ( edge1 - edge0 ) );
|
|
|
|
return x * x * ( 3.0f - 2.0f * x );
|
|
}
|
|
|
|
public static float SnapRounded( float value, float snappingDistance )
|
|
{
|
|
return Mathf.Round( value / snappingDistance ) * snappingDistance;
|
|
}
|
|
|
|
public static float SnapCeiled( float value, float snappingDistance )
|
|
{
|
|
return Mathf.Ceil( value / snappingDistance ) * snappingDistance;
|
|
}
|
|
|
|
public static float SnapFloored( float value, float snappingDistance )
|
|
{
|
|
return Mathf.Floor( value / snappingDistance ) * snappingDistance;
|
|
}
|
|
|
|
public static float AngleDelta( float degreesA, float degreesB)
|
|
{
|
|
var angleDelta = degreesB - degreesA;
|
|
angleDelta = (angleDelta + 180f) % 360f - 180f;
|
|
return angleDelta;
|
|
}
|
|
|
|
static float CustomModulo( float a, float n )
|
|
{
|
|
return a - Mathf.Floor( a / n ) * n;
|
|
}
|
|
|
|
public static float Clamp01( float value )
|
|
{
|
|
return Mathf.Clamp( value, 0, 1 );
|
|
}
|
|
|
|
public static float Normalize( float value, float min, float max )
|
|
{
|
|
return ( value - min ) / ( max - min );
|
|
}
|
|
|
|
public static float NormalizeClamped( float value, float min, float max )
|
|
{
|
|
return MathX.Clamp01( Normalize( value, min, max ) );
|
|
}
|
|
|
|
public static float Map( float value, float inputMin, float inputMax,
|
|
float outputMin, float outputMax )
|
|
{
|
|
var normalized = Normalize( value, inputMin, inputMax );
|
|
return normalized * ( outputMax - outputMin ) + outputMin;
|
|
}
|
|
|
|
public static float MapPositive( float value, float inputMax, float outputMax )
|
|
{
|
|
return Map( value, 0, inputMax, 0, outputMax );
|
|
}
|
|
|
|
|
|
public static float MapClamped( float value, float inputMin, float inputMax,
|
|
float outputMin, float outputMax )
|
|
{
|
|
var normalized = NormalizeClamped( value, inputMin, inputMax );
|
|
return normalized * ( outputMax - outputMin ) + outputMin;
|
|
}
|
|
|
|
public static float Map01( float value, float outputMin, float outputMax )
|
|
{
|
|
return value * ( outputMax - outputMin ) + outputMin;
|
|
}
|
|
|
|
public static float MapPolar( float value, float min, float max )
|
|
{
|
|
return Map01( value * 0.5f + 0.5f, min, max );
|
|
}
|
|
|
|
public static float MapPolarTo01( float value)
|
|
{
|
|
return value * 0.5f + 0.5f;
|
|
}
|
|
|
|
public static float Repeat( float value, float length )
|
|
{
|
|
while ( value > length )
|
|
{
|
|
value -=length;
|
|
}
|
|
|
|
while ( value < 0 )
|
|
{
|
|
value += length;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public static float Triangle( float value )
|
|
{
|
|
value = MathX.Repeat( value, 1 ) * 2;
|
|
|
|
if ( value > 1 )
|
|
{
|
|
value = 2 - value;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public static float EaseSine( float value )
|
|
{
|
|
return Mathf.Sin( Mathf.Pi * ( value * 0.5f + 1.5f ) ) + 1;
|
|
}
|
|
|
|
public static int Sign( int value )
|
|
{
|
|
return value == 0 ? 0 : value < 0 ? -1 : 1;
|
|
}
|
|
|
|
|
|
public static T LerpList<T>( List<T> data, float t, Func<T,T,float,T> lerpElementsFunction,
|
|
int dataFillSize = -1 )
|
|
{
|
|
dataFillSize = dataFillSize == -1 ? data.Count : dataFillSize;
|
|
var floatIndex = t * dataFillSize;
|
|
|
|
if ( floatIndex <= 0 )
|
|
{
|
|
return data[ 0 ];
|
|
}
|
|
|
|
if ( floatIndex >= ( dataFillSize - 1 ) )
|
|
{
|
|
return data[ dataFillSize - 1 ];
|
|
}
|
|
|
|
var flooredIndex = Mathf.FloorToInt( floatIndex );
|
|
var ceiledIndex = flooredIndex + 1;
|
|
|
|
var flooredValue = data[ flooredIndex ];
|
|
var ceiledValue = data[ ceiledIndex ];
|
|
|
|
var interpolationAmount = floatIndex - flooredIndex;
|
|
|
|
return lerpElementsFunction( flooredValue, ceiledValue, interpolationAmount );
|
|
|
|
}
|
|
|
|
public static float PolarTriangle( float value )
|
|
{
|
|
return Triangle( value ) * 2f - 1f;
|
|
}
|
|
|
|
public static float Step( float phase, float phaseStart, float phaseEnd )
|
|
{
|
|
if ( phase < phaseStart )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( phase >= phaseEnd )
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return ( phase - phaseStart ) / ( phaseStart - phaseEnd );
|
|
}
|
|
|
|
public static int SafeIndex( int index, int maxElements, bool wrap = false )
|
|
{
|
|
if ( wrap )
|
|
{
|
|
return MathX.Repeat( index, maxElements );
|
|
}
|
|
else
|
|
{
|
|
return Mathf.Clamp( index, 0, maxElements - 1 );
|
|
}
|
|
}
|
|
|
|
|
|
public static int Repeat( int value, int range )
|
|
{
|
|
while ( value < 0 )
|
|
{
|
|
value += range;
|
|
}
|
|
|
|
while ( value >= range )
|
|
{
|
|
value -= range;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public static float PolarRepeat( float value, float range )
|
|
{
|
|
while ( value < -range )
|
|
{
|
|
value += range * 2;
|
|
}
|
|
|
|
while ( value >= range )
|
|
{
|
|
value -= range * 2;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public static Curve Curve( float y0, float y1 )
|
|
{
|
|
var curve = new Curve();
|
|
curve.AddPoint( new Vector2( 0, y0 ) );
|
|
curve.AddPoint( new Vector2( 1, y1 ) );
|
|
|
|
curve.SetPointRightMode( 0, Godot.Curve.TangentMode.Linear );
|
|
curve.SetPointLeftMode( 1, Godot.Curve.TangentMode.Linear );
|
|
|
|
return curve;
|
|
}
|
|
|
|
public static Curve Curve( float y )
|
|
{
|
|
return Curve( y, y );
|
|
}
|
|
|
|
public static float CurveAngle( Curve c, float t, float samplingRange = 0.01f )
|
|
{
|
|
var x0 = Mathf.Max( t - samplingRange, 0 );
|
|
var x1 = Mathf.Min( t + samplingRange, 1 );
|
|
|
|
var y0 = c.Sample( x0 );
|
|
var y1 = c.Sample( x1 );
|
|
|
|
return Mathf.Atan2( y1 - y0, x1 - x0 );
|
|
}
|
|
|
|
public static float CurveMaximum( Curve c, int numSamples = 20 )
|
|
{
|
|
var max = 0f;
|
|
|
|
for ( int i = 0; i < numSamples; i++ )
|
|
{
|
|
max = Mathf.Max( max, c.Sample( (float) i / ( numSamples - 1 ) ) );
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
public static List<float> GetCurveWeights( Curve curve, int num, bool normalize = true )
|
|
{
|
|
var sum = 0f;
|
|
|
|
var weights = new List<float>();
|
|
|
|
for ( int i = 0; i < num; i++ )
|
|
{
|
|
var t = (float)i / ( num - 1 );
|
|
var w = curve.Sample( t );
|
|
sum += w;
|
|
weights.Add( w );
|
|
}
|
|
|
|
if ( normalize )
|
|
{
|
|
for ( int i = 0; i < num; i++ )
|
|
{
|
|
weights[ i ] = weights[ i ] / sum;
|
|
}
|
|
}
|
|
|
|
return weights;
|
|
}
|
|
|
|
public static float Exponent( float base_, float power )
|
|
{
|
|
return Mathf.Log( power ) / Mathf.Log( base_ );
|
|
}
|
|
|
|
public static float Base( float exponent, float power )
|
|
{
|
|
return Mathf.Pow( power, 1f / exponent );
|
|
}
|
|
|
|
public static float SmoothingCoefficient( float ms, float reachingTarget = 0.1f, float frameDurationMS = MathX.fps120Delta )
|
|
{
|
|
return 1f - Base( ms / frameDurationMS, reachingTarget );
|
|
}
|
|
|
|
public static float SmoothValue( float oldValue, float newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = MathX.fps120Delta )
|
|
{
|
|
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
|
}
|
|
|
|
public static float SmoothDegrees( float oldValue, float newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = MathX.fps120Delta )
|
|
{
|
|
oldValue = Mathf.Wrap( oldValue, 0, 360 );
|
|
newValue = Mathf.Wrap( newValue, 0, 360 );
|
|
|
|
var difference = newValue - oldValue;
|
|
|
|
if ( Mathf.Abs( difference ) > 180 )
|
|
{
|
|
if ( newValue > oldValue )
|
|
{
|
|
oldValue += 360;
|
|
}
|
|
else
|
|
{
|
|
newValue += 360;
|
|
}
|
|
}
|
|
|
|
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
|
}
|
|
|
|
public static Vector3 SmoothVector3( Vector3 oldValue, Vector3 newValue, float ms, float reachingTarget = 0.1f, float frameDurationMS = 8.33333333333f )
|
|
{
|
|
return oldValue + SmoothingCoefficient( ms, reachingTarget, frameDurationMS ) * ( newValue - oldValue );
|
|
}
|
|
|
|
|
|
|
|
|
|
public static float PolarAxis( bool negative, bool positive )
|
|
{
|
|
return ( negative ? -1 : 0 ) + ( positive ? 1 : 0 );
|
|
}
|
|
|
|
}
|
|
} |