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