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 */