1 module sily.math; 2 3 import std.math; 4 import std.random; 5 import std.algorithm.comparison; 6 import std.conv; 7 import std.traits; 8 9 // https://github.com/godotengine/godot/blob/master/core/math/math_funcs.cpp 10 11 // float degToRad(float deg) { 12 // return deg * (PI / 180.0f); 13 // } 14 15 // float radToDeg(float rad) { 16 // return rad * (180.0f / PI); 17 // } 18 19 // alias deg2rad = degToRad; 20 // alias rad2deg = radToDeg; 21 22 alias lerp = lerpT!float; 23 alias lerp = lerpT!real; 24 alias lerp = lerpT!double; 25 26 T lerpT(T: float)(T from, T to, T weight) { 27 from += (weight * (to - from)); 28 return from; 29 } 30 31 alias snap = snapT!float; 32 alias snap = snapT!real; 33 alias snap = snapT!double; 34 35 T snapT(T: float)(T p_val, T p_step) { 36 if (p_step != 0) { 37 p_val = floor(p_val / p_step + 0.5) * p_step; 38 } 39 return p_val; 40 } 41 42 class RNG { 43 private Random _rnd; 44 private uint _seed; 45 private ulong _calls; 46 47 this() { this(RNG.defaultSeed); } 48 49 this(uint p_seed) { 50 _seed = p_seed; 51 _rnd = Random(_seed); 52 } 53 54 public void randomize() { 55 _seed = randomSeed; 56 setSeed(_seed); 57 } 58 alias randomise = randomize; 59 60 public void setSeed(uint p_seed) { 61 _seed = p_seed; 62 _rnd.seed(_seed); 63 } 64 65 public uint seed() { return _seed; } 66 67 public static alias defaultSeed = Random.defaultSeed; 68 public static alias randomSeed = unpredictableSeed; 69 70 alias randf = randT!float; 71 alias randr = randT!real; 72 alias randd = randT!double; 73 alias randi = randT!int; 74 alias randl = randT!long; 75 76 template randT(T: float) { 77 static if(isFloatingPoint!T) { 78 T randT() { 79 return random / _rnd.max.to!T; 80 } 81 82 T randT(T min, T max) { 83 return min + (randT!T * (max - min)); 84 } 85 } else { 86 T randT() { 87 return (randr * T.max).to!T; 88 } 89 90 T randT(T min, T max) { 91 return round(min + (randr * (max - min))).to!T; 92 } 93 } 94 } 95 96 public uint random() { 97 uint r = _rnd.front; 98 skip(); 99 return r; 100 } 101 102 public void skip() { 103 _rnd.popFront(); 104 _calls ++; 105 } 106 107 public void skipTo(ulong numCalls) { 108 while(_calls < numCalls) { 109 skip(); 110 } 111 } 112 } 113 114 // FIXME cubic_interpolate 115 /* 116 static _ALWAYS_INLINE_ float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) { 117 return 0.5f * 118 ((p_from * 2.0f) + 119 (-p_pre + p_to) * p_weight + 120 (2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) + 121 (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight)); 122 } 123 124 static _ALWAYS_INLINE_ float lerp_angle(float p_from, float p_to, float p_weight) { 125 float difference = fmod(p_to - p_from, (float)Math_TAU); 126 float distance = fmod(2.0f * difference, (float)Math_TAU) - difference; 127 return p_from + distance * p_weight; 128 } 129 130 static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) { 131 if (is_equal_approx(p_from, p_to)) { 132 return p_from; 133 } 134 float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); 135 return s * s * (3.0f - 2.0f * s); 136 } 137 static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { 138 double range = max - min; 139 return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); 140 } 141 */