1 /** 
2  * Copyright: Enalye
3  * License: Zlib
4  * Authors: Enalye
5  */
6 module grimoire.stdlib.math;
7 
8 import std.random, std.math;
9 import std.algorithm.comparison : clamp;
10 import grimoire.assembly, grimoire.compiler, grimoire.runtime;
11 
12 package(grimoire.stdlib) void grLoadStdLibMath(GrLibrary library) {
13     library.addVariable("pi", grFloat, PI, true);
14 
15     library.addPrimitive(&_min_f, "min", [grFloat, grFloat], [grFloat]);
16     library.addPrimitive(&_min_i, "min", [grInt, grInt], [grInt]);
17     library.addPrimitive(&_max_f, "max", [grFloat, grFloat], [grFloat]);
18     library.addPrimitive(&_max_i, "max", [grInt, grInt], [grInt]);
19 
20     library.addPrimitive(&_clamp, "clamp", [grFloat, grFloat, grFloat], [
21             grFloat
22             ]);
23 
24     library.addPrimitive(&_random01, "rand", [], [grFloat]);
25     library.addPrimitive(&_random_f, "rand", [grFloat, grFloat], [grFloat]);
26     library.addPrimitive(&_random_i, "rand", [grInt, grInt], [grInt]);
27 
28     library.addPrimitive(&_cos, "cos", [grFloat], [grFloat]);
29     library.addPrimitive(&_sin, "sin", [grFloat], [grFloat]);
30     library.addPrimitive(&_tan, "tan", [grFloat], [grFloat]);
31     library.addPrimitive(&_acos, "acos", [grFloat], [grFloat]);
32     library.addPrimitive(&_asin, "asin", [grFloat], [grFloat]);
33     library.addPrimitive(&_atan, "atan", [grFloat], [grFloat]);
34     library.addPrimitive(&_atan2, "atan2", [grFloat, grFloat], [grFloat]);
35 
36     library.addPrimitive(&_exp, "exp", [grFloat], [grFloat]);
37     library.addPrimitive(&_sqrt, "sqrt", [grFloat], [grFloat]);
38     library.addPrimitive(&_pow, "pow", [grFloat, grFloat], [grFloat]);
39 
40     library.addPrimitive(&_lerp, "lerp", [grFloat, grFloat, grFloat], [grFloat]);
41     library.addPrimitive(&_rlerp, "rlerp", [grFloat, grFloat, grFloat], [
42             grFloat
43             ]);
44 
45     library.addPrimitive(&_abs_i, "abs", [grInt], [grInt]);
46     library.addPrimitive(&_abs_f, "abs", [grFloat], [grFloat]);
47     library.addPrimitive(&_floor, "floor", [grFloat], [grFloat]);
48     library.addPrimitive(&_ceil, "ceil", [grFloat], [grFloat]);
49     library.addPrimitive(&_round, "round", [grFloat], [grFloat]);
50     library.addPrimitive(&_truncate, "truncate", [grFloat], [grFloat]);
51     library.addPrimitive(&_positive_i, "positive?", [grInt], [grBool]);
52     library.addPrimitive(&_positive_f, "positive?", [grFloat], [grBool]);
53     library.addPrimitive(&_negative_i, "negative?", [grInt], [grBool]);
54     library.addPrimitive(&_negative_f, "negative?", [grFloat], [grBool]);
55     library.addPrimitive(&_zero_i, "zero?", [grInt], [grBool]);
56     library.addPrimitive(&_zero_f, "zero?", [grFloat], [grBool]);
57     library.addPrimitive(&_nan, "nan?", [grFloat], [grBool]);
58     library.addPrimitive(&_even, "even?", [grInt], [grBool]);
59     library.addPrimitive(&_odd, "odd?", [grInt], [grBool]);
60 }
61 
62 private void _min_f(GrCall call) {
63     const GrFloat a = call.getFloat(0);
64     const GrFloat b = call.getFloat(1);
65     call.setFloat(a < b ? a : b);
66 }
67 
68 private void _min_i(GrCall call) {
69     const GrInt a = call.getInt(0);
70     const GrInt b = call.getInt(1);
71     call.setInt(a < b ? a : b);
72 }
73 
74 private void _max_f(GrCall call) {
75     const GrFloat a = call.getFloat(0);
76     const GrFloat b = call.getFloat(1);
77     call.setFloat(a > b ? a : b);
78 }
79 
80 private void _max_i(GrCall call) {
81     const GrInt a = call.getInt(0);
82     const GrInt b = call.getInt(1);
83     call.setInt(a > b ? a : b);
84 }
85 
86 private void _clamp(GrCall call) {
87     call.setFloat(clamp(call.getFloat(0), call.getFloat(1), call.getFloat(2)));
88 }
89 
90 private void _random01(GrCall call) {
91     call.setFloat(uniform01());
92 }
93 
94 private void _random_f(GrCall call) {
95     const GrFloat a = call.getFloat(0);
96     const GrFloat b = call.getFloat(1);
97     if(a < b)
98         call.setFloat(uniform!"[]"(a, b));
99     else
100         call.setFloat(uniform!"[]"(b, a));
101 }
102 
103 private void _random_i(GrCall call) {
104     const GrInt a = call.getInt(0);
105     const GrInt b = call.getInt(1);
106     if(a < b)
107         call.setInt(uniform!"[]"(a, b));
108     else
109         call.setInt(uniform!"[]"(b, a));
110 }
111 
112 private void _cos(GrCall call) {
113     call.setFloat(cos(call.getFloat(0)));
114 }
115 
116 private void _sin(GrCall call) {
117     call.setFloat(sin(call.getFloat(0)));
118 }
119 
120 private void _tan(GrCall call) {
121     call.setFloat(tan(call.getFloat(0)));
122 }
123 
124 private void _acos(GrCall call) {
125     call.setFloat(acos(call.getFloat(0)));
126 }
127 
128 private void _asin(GrCall call) {
129     call.setFloat(asin(call.getFloat(0)));
130 }
131 
132 private void _atan(GrCall call) {
133     call.setFloat(atan(call.getFloat(0)));
134 }
135 
136 private void _atan2(GrCall call) {
137     call.setFloat(atan2(call.getFloat(0), call.getFloat(1)));
138 }
139 
140 private void _exp(GrCall call) {
141     call.setFloat(exp(call.getFloat(0)));
142 }
143 
144 private void _sqrt(GrCall call) {
145     call.setFloat(sqrt(call.getFloat(0)));
146 }
147 
148 private void _pow(GrCall call) {
149     call.setFloat(pow(call.getFloat(0), call.getFloat(1)));
150 }
151 
152 private void _lerp(GrCall call) {
153     const GrFloat a = call.getFloat(0);
154     const GrFloat b = call.getFloat(1);
155     const GrFloat t = call.getFloat(2);
156     call.setFloat(t * b + (1f - t) * a);
157 }
158 
159 private void _rlerp(GrCall call) {
160     const GrFloat a = call.getFloat(0);
161     const GrFloat b = call.getFloat(1);
162     const GrFloat v = call.getFloat(2);
163     if ((b - a) == 0f) {
164         call.setFloat(0f);
165         return;
166     }
167     call.setFloat((v - a) / (b - a));
168 }
169 
170 private void _abs_i(GrCall call) {
171     call.setInt(abs(call.getInt(0)));
172 }
173 
174 private void _abs_f(GrCall call) {
175     call.setFloat(abs(call.getFloat(0)));
176 }
177 
178 private void _floor(GrCall call) {
179     call.setFloat(floor(call.getFloat(0)));
180 }
181 
182 private void _ceil(GrCall call) {
183     call.setFloat(ceil(call.getFloat(0)));
184 }
185 
186 private void _round(GrCall call) {
187     call.setFloat(round(call.getFloat(0)));
188 }
189 
190 private void _truncate(GrCall call) {
191     call.setFloat(trunc(call.getFloat(0)));
192 }
193 
194 private void _positive_i(GrCall call) {
195     call.setBool(call.getInt(0) > 0);
196 }
197 
198 private void _positive_f(GrCall call) {
199     call.setBool(call.getFloat(0) > 0);
200 }
201 
202 private void _negative_i(GrCall call) {
203     call.setBool(call.getInt(0) < 0);
204 }
205 
206 private void _negative_f(GrCall call) {
207     call.setBool(call.getFloat(0) < 0);
208 }
209 
210 private void _zero_i(GrCall call) {
211     call.setBool(call.getInt(0) == 0);
212 }
213 
214 private void _zero_f(GrCall call) {
215     call.setBool(call.getFloat(0) == 0);
216 }
217 
218 private void _nan(GrCall call) {
219     call.setBool(isNaN(call.getFloat(0)));
220 }
221 
222 private void _even(GrCall call) {
223     call.setBool(!(call.getInt(0) & 0x1));
224 }
225 
226 private void _odd(GrCall call) {
227     call.setBool(call.getInt(0) & 0x1);
228 }