1 /*
2 * This software is licensed under the terms of the MIT License.
3 * See COPYING for further information.
4 * ---
5 * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6 * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7 */
8
9 #include "taisei.h"
10
11 #include "miscmath.h"
12 #include "assert.h"
13
lerp(double v0,double v1,double f)14 double lerp(double v0, double v1, double f) {
15 return f * (v1 - v0) + v0;
16 }
17
clerp(cmplx v0,cmplx v1,double f)18 cmplx clerp(cmplx v0, cmplx v1, double f) {
19 return f * (v1 - v0) + v0;
20 }
21
approach(double v,double t,double d)22 double approach(double v, double t, double d) {
23 if(v < t) {
24 v += d;
25 if(v > t)
26 return t;
27 } else if(v > t) {
28 v -= d;
29 if(v < t)
30 return t;
31 }
32
33 return v;
34 }
35
fapproach(float v,float t,float d)36 float fapproach(float v, float t, float d) {
37 if(v < t) {
38 v += d;
39 if(v > t)
40 return t;
41 } else if(v > t) {
42 v -= d;
43 if(v < t)
44 return t;
45 }
46
47 return v;
48 }
49
approach_p(double * v,double t,double d)50 void approach_p(double *v, double t, double d) {
51 *v = approach(*v, t, d);
52 }
53
fapproach_p(float * v,float t,float d)54 void fapproach_p(float *v, float t, float d) {
55 *v = fapproach(*v, t, d);
56 }
57
approach_asymptotic(double val,double target,double rate,double epsilon)58 double approach_asymptotic(double val, double target, double rate, double epsilon) {
59 if(fabs(val - target) < epsilon || rate >= 1) {
60 return target;
61 }
62
63 return val + (target - val) * rate;
64 }
65
fapproach_asymptotic(float val,float target,float rate,float epsilon)66 float fapproach_asymptotic(float val, float target, float rate, float epsilon) {
67 if(fabsf(val - target) < epsilon || rate >= 1) {
68 return target;
69 }
70
71 return val + (target - val) * rate;
72 }
73
capproach_asymptotic(cmplx val,cmplx target,double rate,double epsilon)74 cmplx capproach_asymptotic(cmplx val, cmplx target, double rate, double epsilon) {
75 if(cabs(val - target) < epsilon || rate >= 1) {
76 return target;
77 }
78
79 return val + (target - val) * rate;
80 }
81
approach_asymptotic_p(double * val,double target,double rate,double epsilon)82 void approach_asymptotic_p(double *val, double target, double rate, double epsilon) {
83 *val = approach_asymptotic(*val, target, rate, epsilon);
84 }
85
fapproach_asymptotic_p(float * val,float target,float rate,float epsilon)86 void fapproach_asymptotic_p(float *val, float target, float rate, float epsilon) {
87 *val = fapproach_asymptotic(*val, target, rate, epsilon);
88 }
89
capproach_asymptotic_p(cmplx * val,cmplx target,double rate,double epsilon)90 void capproach_asymptotic_p(cmplx *val, cmplx target, double rate, double epsilon) {
91 *val = capproach_asymptotic(*val, target, rate, epsilon);
92 }
93
psin(double x)94 double psin(double x) {
95 return 0.5 + 0.5 * sin(x);
96 }
97
min(double a,double b)98 double min(double a, double b) {
99 return (a < b) ? a : b;
100 }
101
max(double a,double b)102 double max(double a, double b) {
103 return (a > b) ? a : b;
104 }
105
imin(intmax_t a,intmax_t b)106 intmax_t imin(intmax_t a, intmax_t b) {
107 return (a < b) ? a : b;
108 }
109
imax(intmax_t a,intmax_t b)110 intmax_t imax(intmax_t a, intmax_t b) {
111 return (a > b) ? a : b;
112 }
113
umin(uintmax_t a,uintmax_t b)114 uintmax_t umin(uintmax_t a, uintmax_t b) {
115 return (a < b) ? a : b;
116 }
117
umax(uintmax_t a,uintmax_t b)118 uintmax_t umax(uintmax_t a, uintmax_t b) {
119 return (a > b) ? a : b;
120 }
121
clamp(double f,double lower,double upper)122 double clamp(double f, double lower, double upper) {
123 assert(lower <= upper);
124
125 if(f < lower) {
126 return lower;
127 }
128
129 if(f > upper) {
130 return upper;
131 }
132
133 return f;
134 }
135
iclamp(intmax_t f,intmax_t lower,intmax_t upper)136 intmax_t iclamp(intmax_t f, intmax_t lower, intmax_t upper) {
137 assert(lower <= upper);
138
139 if(f < lower) {
140 return lower;
141 }
142
143 if(f > upper) {
144 return upper;
145 }
146
147 return f;
148 }
149
smoothstep(double edge0,double edge1,double x)150 double smoothstep(double edge0, double edge1, double x) {
151 x = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
152 return x * x * (3 - 2 * x);
153 }
154
smoothmin(double a,double b,double k)155 double smoothmin(double a, double b, double k) {
156 float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
157 return lerp(b, a, h) - k * h * (1.0 - h);
158 }
159
sign(double x)160 int sign(double x) {
161 return (x > 0) - (x < 0);
162 }
163
swing(double x,double s)164 double swing(double x, double s) {
165 if(x <= 0.5) {
166 x *= 2;
167 return x * x * ((s + 1) * x - s) / 2;
168 }
169
170 x--;
171 x *= 2;
172
173 return x * x * ((s + 1) * x + s) / 2 + 1;
174 }
175
topow2_u32(uint32_t x)176 uint32_t topow2_u32(uint32_t x) {
177 x -= 1;
178 x |= (x >> 1);
179 x |= (x >> 2);
180 x |= (x >> 4);
181 x |= (x >> 8);
182 x |= (x >> 16);
183 return x + 1;
184 }
185
topow2_u64(uint64_t x)186 uint64_t topow2_u64(uint64_t x) {
187 x -= 1;
188 x |= (x >> 1);
189 x |= (x >> 2);
190 x |= (x >> 4);
191 x |= (x >> 8);
192 x |= (x >> 16);
193 x |= (x >> 32);
194 return x + 1;
195 }
196
ftopow2(float x)197 float ftopow2(float x) {
198 // NOTE: obviously this isn't the smallest possible power of two, but for our purposes, it could as well be.
199 float y = 0.0625;
200 while(y < x) y *= 2;
201 return y;
202 }
203
smooth(float x)204 float smooth(float x) {
205 return 1.0 - (0.5 * cos(M_PI * x) + 0.5);
206 }
207
smoothreclamp(float x,float old_min,float old_max,float new_min,float new_max)208 float smoothreclamp(float x, float old_min, float old_max, float new_min, float new_max) {
209 x = (x - old_min) / (old_max - old_min);
210 return new_min + (new_max - new_min) * smooth(x);
211 }
212
sanitize_scale(float scale)213 float sanitize_scale(float scale) {
214 return max(0.1, scale);
215 }
216
normpdf(float x,float sigma)217 float normpdf(float x, float sigma) {
218 return 0.39894 * exp(-0.5 * pow(x, 2) / pow(sigma, 2)) / sigma;
219 }
220
gaussian_kernel_1d(size_t size,float sigma,float kernel[size])221 void gaussian_kernel_1d(size_t size, float sigma, float kernel[size]) {
222 assert(size & 1);
223
224 double sum = 0.0;
225 size_t halfsize = size / 2;
226
227 kernel[halfsize] = normpdf(0, sigma);
228 sum += kernel[halfsize];
229
230 for(size_t i = 1; i <= halfsize; ++i) {
231 float k = normpdf(i, sigma);
232 kernel[halfsize + i] = kernel[halfsize - i] = k;
233 sum += k * 2;
234
235 }
236
237 for(size_t i = 0; i < size; ++i) {
238 kernel[i] /= sum;
239 }
240 }
241
242 static const uint64_t upow10_table[] = {
243 1ull,
244 10ull,
245 100ull,
246 1000ull,
247 10000ull,
248 100000ull,
249 1000000ull,
250 10000000ull,
251 100000000ull,
252 1000000000ull,
253 10000000000ull,
254 100000000000ull,
255 1000000000000ull,
256 10000000000000ull,
257 100000000000000ull,
258 1000000000000000ull,
259 10000000000000000ull,
260 100000000000000000ull,
261 1000000000000000000ull,
262 10000000000000000000ull,
263 };
264
upow10(uint n)265 uint64_t upow10(uint n) {
266 assert(n < sizeof(upow10_table)/sizeof(*upow10_table));
267 return upow10_table[n];
268 }
269
digitcnt(uint64_t x)270 uint digitcnt(uint64_t x) {
271 if(x == 0) {
272 return 1;
273 }
274
275 uint low = 0;
276 uint high = sizeof(upow10_table)/sizeof(*upow10_table) - 1;
277
278 for(;;) {
279 uint mid = (low + high) / 2;
280
281 if(x >= upow10_table[mid]) {
282 if(low == mid) {
283 return mid + 1;
284 }
285
286 low = mid;
287 } else {
288 high = mid;
289 }
290 }
291
292 UNREACHABLE;
293 }
294
295 typedef struct int128_bits {
296 uint64_t hi;
297 uint64_t lo;
298 } int128_bits_t;
299
300 INLINE attr_unused
udiv_128_64(int128_bits_t divident,uint64_t divisor,uint64_t * out_quotient)301 void udiv_128_64(int128_bits_t divident, uint64_t divisor, uint64_t *out_quotient) {
302 /*
303 if(!divident.hi) {
304 *out_quotient = divident.lo / divisor;
305 return;
306 }
307 */
308
309 uint64_t quotient = divident.lo << 1;
310 uint64_t remainder = divident.hi;
311 uint64_t carry = divident.lo >> 63;
312 uint64_t temp_carry = 0;
313
314 for(int i = 0; i < 64; i++) {
315 temp_carry = remainder >> 63;
316 remainder <<= 1;
317 remainder |= carry;
318 carry = temp_carry;
319
320 if(carry == 0) {
321 if(remainder >= divisor) {
322 carry = 1;
323 } else {
324 temp_carry = quotient >> 63;
325 quotient <<= 1;
326 quotient |= carry;
327 carry = temp_carry;
328 continue;
329 }
330 }
331
332 remainder -= divisor;
333 remainder -= (1 - carry);
334 carry = 1;
335 temp_carry = quotient >> 63;
336 quotient <<= 1;
337 quotient |= carry;
338 carry = temp_carry;
339 }
340
341 *out_quotient = quotient;
342 }
343
344 INLINE attr_unused
umul_128_64(uint64_t multiplicant,uint64_t multiplier,int128_bits_t * result)345 void umul_128_64(uint64_t multiplicant, uint64_t multiplier, int128_bits_t *result) {
346 #if defined(__GNUC__) && (defined(__x86_64) || defined(__x86_64__))
347 __asm__ (
348 "mulq %3"
349 : "=a,a" (result->lo), "=d,d" (result->hi)
350 : "%0,0" (multiplicant), "r,m" (multiplier)
351 : "cc"
352 );
353 #else
354 uint64_t u1 = (multiplicant & 0xffffffff);
355 uint64_t v1 = (multiplier & 0xffffffff);
356 uint64_t t = (u1 * v1);
357 uint64_t w3 = (t & 0xffffffff);
358 uint64_t k = (t >> 32);
359
360 multiplicant >>= 32;
361 t = (multiplicant * v1) + k;
362 k = (t & 0xffffffff);
363 uint64_t w1 = (t >> 32);
364
365 multiplier >>= 32;
366 t = (u1 * multiplier) + k;
367 k = (t >> 32);
368
369 result->hi = (multiplicant * multiplier) + w1 + k;
370 result->lo = (t << 32) + w3;
371 #endif
372 }
373
374 INLINE attr_unused
_umuldiv64_slow(uint64_t x,uint64_t multiplier,uint64_t divisor)375 uint64_t _umuldiv64_slow(uint64_t x, uint64_t multiplier, uint64_t divisor) {
376 int128_bits_t intermediate;
377 uint64_t result;
378 umul_128_64(x, multiplier, &intermediate);
379 udiv_128_64(intermediate, divisor, &result);
380 return result;
381 }
382
383 #include "util.h"
384
385 INLINE
_umuldiv64(uint64_t x,uint64_t multiplier,uint64_t divisor)386 uint64_t _umuldiv64(uint64_t x, uint64_t multiplier, uint64_t divisor) {
387 #if defined(TAISEI_BUILDCONF_HAVE_INT128)
388 __extension__ typedef unsigned __int128 uint128_t;
389 return ((uint128_t)x * (uint128_t)multiplier) / divisor;
390 #elif defined(TAISEI_BUILDCONF_HAVE_LONG_DOUBLE)
391 #define UMULDIV64_SANITY_CHECK
392 return ((float64x)x * (float64x)multiplier) / (float64x)divisor;
393 #else
394 return _umuldiv64_slow(x, multiplier, divisor);
395 #endif
396 }
397
umuldiv64(uint64_t x,uint64_t multiplier,uint64_t divisor)398 uint64_t umuldiv64(uint64_t x, uint64_t multiplier, uint64_t divisor) {
399 #ifdef UMULDIV64_SANITY_CHECK
400 static signed char sanity = -1;
401
402 if(sanity < 0) {
403 sanity = (_umuldiv64(UINT64_MAX, UINT64_MAX, UINT64_MAX) == UINT64_MAX);
404 }
405
406 return (sanity ? _umuldiv64 : _umuldiv64_slow)(x, multiplier, divisor);
407 #else
408 return _umuldiv64(x, multiplier, divisor);
409 #endif
410 }
411