1 /// Custom templated math 2 module sily.math; 3 4 import std.math; 5 import std.random; 6 import std.algorithm.comparison; 7 import std.conv; 8 import std.traits; 9 import std.datetime: Clock; 10 import std.traits: isFloatingPoint; 11 12 // https://github.com/godotengine/godot/blob/master/core/math/math_funcs.cpp 13 14 const double degtorad = PI / 180.0; 15 const double radtodeg = 180.0 / PI; 16 17 alias deg2rad = degtorad; 18 alias rad2deg = radtodeg; 19 20 /// Linearly interpolates value 21 T lerp(T)(T from, T to, T weight) if (isFloatingPoint!T) { 22 from += (weight * (to - from)); 23 return from; 24 } 25 26 /// Snaps value to step 27 T snap(T)(T p_val, T p_step) if (isFloatingPoint!T) { 28 if (p_step != 0) { 29 p_val = floor(p_val / p_step + 0.5) * p_step; 30 } 31 return p_val; 32 } 33 34 /// Snaps value to step, if T is not float, then explicit casts are used 35 /// and it may cause data loss 36 T snap(T)(T p_val, T p_step) if (!isFloatingPoint!T) { 37 if (p_step != 0) { 38 p_val = cast(T) (floor(cast(double) p_val / cast(double) p_step + 0.5) * cast(double) p_step); 39 } 40 return p_val; 41 } 42 43 44 /// std.random wrapper 45 struct RNG { 46 private uint _seed = defaultSeed; 47 private Random _rnd; 48 private ulong _calls; 49 50 /// Creates RNG struct with set seed 51 this(uint p_seed) { 52 _seed = p_seed; 53 _rnd = Random(_seed); 54 } 55 56 /// Randomizes seed 57 public void randomize() { 58 _seed = randomSeed; 59 setSeed(_seed); 60 } 61 /// Ditto 62 alias randomise = randomize; 63 64 /// Sets custom seed `p_seed` 65 public void setSeed(uint p_seed) { 66 _seed = p_seed; 67 _rnd.seed(_seed); 68 } 69 70 /// Returns current seed 71 public uint seed() { return _seed; } 72 73 /// Alias to default seed 74 public static alias defaultSeed = Random.defaultSeed; 75 /// Alias to unpredictable seed 76 public static alias randomSeed = unpredictableSeed; 77 78 /// Typed alias to get random value between 0 and T.max or custom min and max 79 alias randf = rand!float; 80 /// Ditto 81 alias randr = rand!real; 82 /// Ditto 83 alias randd = rand!double; 84 /// Ditto 85 alias randi = rand!int; 86 /// Ditto 87 alias randl = rand!long; 88 89 90 template rand(T) { 91 static if(isFloatingPoint!T) { 92 /// Returns random value between 0 and T.max or custom min and max 93 T rand() { 94 return random / _rnd.max.to!T; 95 } 96 97 /// Ditto 98 T rand(T min, T max) { 99 return min + (rand!T * (max - min)); 100 } 101 } else { 102 /// Ditto 103 T rand() { 104 return (randr * T.max).to!T; 105 } 106 107 /// Ditto 108 T rand(T min, T max) { 109 return round(min + (randr * (max - min))).to!T; 110 } 111 } 112 } 113 114 /// Returns random uint 115 public uint random() { 116 uint r = _rnd.front; 117 skip(); 118 return r; 119 } 120 121 /// Skips current random value 122 public void skip() { 123 _rnd.popFront(); 124 _calls ++; 125 } 126 127 /// Skips N amount of random values 128 public void skipTo(ulong numCalls) { 129 while(_calls < numCalls) { 130 skip(); 131 } 132 } 133 } 134 135 // FIXME cubic_interpolate 136 /* 137 static _ALWAYS_INLINE_ float cubic_interpolate(float p_from, float p_to, float p_pre, float p_post, float p_weight) { 138 return 0.5f * 139 ((p_from * 2.0f) + 140 (-p_pre + p_to) * p_weight + 141 (2.0f * p_pre - 5.0f * p_from + 4.0f * p_to - p_post) * (p_weight * p_weight) + 142 (-p_pre + 3.0f * p_from - 3.0f * p_to + p_post) * (p_weight * p_weight * p_weight)); 143 } 144 145 static _ALWAYS_INLINE_ float lerp_angle(float p_from, float p_to, float p_weight) { 146 float difference = fmod(p_to - p_from, (float)Math_TAU); 147 float distance = fmod(2.0f * difference, (float)Math_TAU) - difference; 148 return p_from + distance * p_weight; 149 } 150 151 static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_s) { 152 if (is_equal_approx(p_from, p_to)) { 153 return p_from; 154 } 155 float s = CLAMP((p_s - p_from) / (p_to - p_from), 0.0f, 1.0f); 156 return s * s * (3.0f - 2.0f * s); 157 } 158 static _ALWAYS_INLINE_ double wrapf(double value, double min, double max) { 159 double range = max - min; 160 return is_zero_approx(range) ? min : value - (range * Math::floor((value - min) / range)); 161 } 162 */