1#pragma once
2
3#include <basis/seadRawPrint.h>
4#include <cmath>
5#ifndef SEAD_MATH_MATH_CALC_COMMON_H_
6#include <math/seadMathCalcCommon.h>
7#endif
8#include <prim/seadBitUtil.h>
9#include <type_traits>
10
11namespace sead
12{
13template <>
14const MathCalcCommon<float>::SinCosSample MathCalcCommon<float>::cSinCosTbl[];
15
16template <>
17const MathCalcCommon<float>::AtanSample MathCalcCommon<float>::cAtanTbl[];
18
19template <>
20const MathCalcCommon<float>::ExpSample MathCalcCommon<float>::cExpTbl[];
21
22template <>
23const MathCalcCommon<float>::LogSample MathCalcCommon<float>::cLogTbl[];
24
25template <typename T>
26inline T MathCalcCommon<T>::sign(T value)
27{
28 return value < 0 ? -1 : 1;
29}
30
31template <typename T>
32inline T MathCalcCommon<T>::sqrt(T t)
33{
34 return std::sqrt(t);
35}
36
37template <typename T>
38inline T MathCalcCommon<T>::rsqrt(T t)
39{
40 return 1 / std::sqrt(t);
41}
42
43template <typename T>
44inline T MathCalcCommon<T>::pow(T x, T y)
45{
46 return std::pow(x, y);
47}
48
49template <typename T>
50inline T MathCalcCommon<T>::sin(T t)
51{
52 return std::sin(t);
53}
54
55template <typename T>
56inline T MathCalcCommon<T>::cos(T t)
57{
58 return std::cos(t);
59}
60
61template <typename T>
62inline T MathCalcCommon<T>::tan(T t)
63{
64 return std::tan(t);
65}
66
67template <typename T>
68inline T MathCalcCommon<T>::asin(T t)
69{
70 if constexpr (std::is_floating_point<T>())
71 SEAD_ASSERT_MSG(-1.0 <= t && t <= 1.0, "t(%f) is not in [-1, 1].", t);
72 return std::asin(t);
73}
74
75template <typename T>
76inline T MathCalcCommon<T>::acos(T t)
77{
78 if constexpr (std::is_floating_point<T>())
79 SEAD_ASSERT_MSG(-1.0 <= t && t <= 1.0, "t(%f) is not in [-1, 1].", t);
80 return std::acos(t);
81}
82
83template <typename T>
84inline T MathCalcCommon<T>::atan(T t)
85{
86 return std::atan(t);
87}
88
89template <typename T>
90inline T MathCalcCommon<T>::atan2(T y, T x)
91{
92 return std::atan2(y, x);
93}
94
95template <>
96inline f32 MathCalcCommon<f32>::sinIdx(u32 idx)
97{
98 u32 index = (idx >> 24) & 0xff;
99 u32 rest = idx & 0xffffff;
100
101 return cSinCosTbl[index].sin_val + cSinCosTbl[index].sin_delta * rest / 0x1000000;
102}
103
104template <>
105inline f32 MathCalcCommon<f32>::cosIdx(u32 idx)
106{
107 u32 index = (idx >> 24) & 0xff;
108 u32 rest = idx & 0xffffff;
109
110 return cSinCosTbl[index].cos_val + cSinCosTbl[index].cos_delta * rest / 0x1000000;
111}
112
113template <>
114inline f32 MathCalcCommon<f32>::tanIdx(u32 idx)
115{
116 u32 index = (idx >> 24) & 0xff;
117 f32 rest = static_cast<f32>(idx & 0xffffff) / 0x1000000;
118 const SinCosSample& sample = cSinCosTbl[index];
119
120 return (sample.sin_val + sample.sin_delta * rest) / (sample.cos_val + sample.cos_delta * rest);
121}
122
123template <>
124inline u32 MathCalcCommon<f32>::asinIdx(f32 s)
125{
126 SEAD_ASSERT_MSG(s <= 1 && s >= -1, "s(%f) is not in [-1, 1].", s);
127
128 const f32 rsqrt_2 = 0.7071067690849304f; // rsqrt(2)
129
130 if (s >= 0)
131 {
132 if (s > rsqrt_2)
133 return 0x40000000 - atanIdx_(t: sqrt(t: 1 - s * s) / s);
134
135 else
136 return atanIdx_(t: s / sqrt(t: 1 - s * s));
137 }
138 else
139 {
140 if (s < -rsqrt_2)
141 return 0xC0000000 + atanIdx_(t: -sqrt(t: 1 - s * s) / s);
142
143 else
144 return -atanIdx_(t: -s / sqrt(t: 1 - s * s));
145 }
146}
147
148template <>
149inline u32 MathCalcCommon<f32>::acosIdx(f32 c)
150{
151 SEAD_ASSERT_MSG(c <= 1 && c >= -1, "c(%f) is not in [-1, 1].", c);
152
153 const f32 rsqrt_2 = 0.7071067690849304f; // rsqrt(2)
154
155 if (c >= 0)
156 {
157 if (c > rsqrt_2)
158 return atanIdx_(t: sqrt(t: 1 - c * c) / c);
159
160 else
161 return 0x40000000 - atanIdx_(t: c / sqrt(t: 1 - c * c));
162 }
163 else
164 {
165 if (c < -rsqrt_2)
166 return 0x80000000 - atanIdx_(t: -sqrt(t: 1 - c * c) / c);
167
168 else
169 return 0x40000000 + atanIdx_(t: -c / sqrt(t: 1 - c * c));
170 }
171}
172
173template <>
174inline u32 MathCalcCommon<f32>::atanIdx(f32 t)
175{
176 if (t >= 0)
177 {
178 if (t > 1)
179 return 0x40000000 - atanIdx_(t: 1 / t);
180
181 else
182 return atanIdx_(t);
183 }
184 else
185 {
186 if (t < -1)
187 return 0xC0000000 + atanIdx_(t: -1 / t);
188
189 else
190 return -atanIdx_(t: -t);
191 }
192}
193
194template <>
195inline u32 MathCalcCommon<f32>::atan2Idx(f32 y, f32 x)
196{
197 if (x == 0 && y == 0)
198 return 0;
199
200 if (x >= 0)
201 {
202 if (y >= 0)
203 {
204 if (x >= y)
205 return atanIdx_(t: y / x);
206
207 else
208 return 0x40000000 - atanIdx_(t: x / y);
209 }
210 else
211 {
212 if (x >= -y)
213 return -atanIdx_(t: -y / x);
214
215 else
216 return 0xC0000000 + atanIdx_(t: x / -y);
217 }
218 }
219 else
220 {
221 if (y >= 0)
222 {
223 if (-x >= y)
224 return 0x80000000 - atanIdx_(t: y / -x);
225
226 else
227 return 0x40000000 + atanIdx_(t: -x / y);
228 }
229 else
230 {
231 if (x <= y)
232 return 0x80000000 + atanIdx_(t: y / x);
233
234 else
235 return 0xC0000000 - atanIdx_(t: x / y);
236 }
237 }
238}
239
240template <>
241inline void MathCalcCommon<f32>::sinCosIdx(f32* pSin, f32* pCos, u32 idx)
242{
243 u32 index = (idx >> 24) & 0xff;
244 f32 rest = static_cast<f32>(idx & 0xffffff) / 0x1000000;
245 const SinCosSample& sample = cSinCosTbl[index];
246
247 /*if (pSin != NULL)*/ *pSin = sample.sin_val + sample.sin_delta * rest;
248 /*if (pCos != NULL)*/ *pCos = sample.cos_val + sample.cos_delta * rest;
249}
250
251template <typename T>
252inline T MathCalcCommon<T>::exp(T t)
253{
254 return std::exp(t);
255}
256
257template <typename T>
258inline T MathCalcCommon<T>::log(T t)
259{
260 return std::log(t);
261}
262
263template <typename T>
264inline T MathCalcCommon<T>::log2(T n)
265{
266 return std::log2(n);
267}
268
269template <typename T>
270inline T MathCalcCommon<T>::log10(T t)
271{
272 return std::log10(t);
273}
274
275template <typename T>
276inline T MathCalcCommon<T>::minNumber()
277{
278 return std::numeric_limits<T>::min();
279}
280
281template <typename T>
282inline T MathCalcCommon<T>::maxNumber()
283{
284 return std::numeric_limits<T>::max();
285}
286
287template <>
288inline float MathCalcCommon<float>::minNumber()
289{
290 return -std::numeric_limits<float>::max();
291}
292
293template <>
294inline float MathCalcCommon<float>::maxNumber()
295{
296 return std::numeric_limits<float>::max();
297}
298
299template <>
300inline double MathCalcCommon<double>::minNumber()
301{
302 return -std::numeric_limits<double>::max();
303}
304
305template <>
306inline double MathCalcCommon<double>::maxNumber()
307{
308 return std::numeric_limits<double>::max();
309}
310
311template <>
312inline long double MathCalcCommon<long double>::minNumber()
313{
314 return -std::numeric_limits<long double>::max();
315}
316
317template <>
318inline long double MathCalcCommon<long double>::maxNumber()
319{
320 return std::numeric_limits<long double>::max();
321}
322
323template <typename T>
324inline T MathCalcCommon<T>::infinity()
325{
326 return std::numeric_limits<T>::infinity();
327}
328
329template <>
330inline f32 MathCalcCommon<f32>::nan()
331{
332 return BitUtil::bitCast<f32>(value: 0x7FFFFFFF);
333}
334
335template <>
336inline f64 MathCalcCommon<f64>::nan()
337{
338 return BitUtil::bitCast<f64>(value: 0x7FFFFFFFFFFFFFFF);
339}
340
341template <>
342inline s32 MathCalcCommon<s32>::abs(s32 x)
343{
344 return (x ^ x >> 31) - (x >> 31);
345}
346
347template <>
348inline u32 MathCalcCommon<u32>::abs(u32 x)
349{
350 return x;
351}
352
353#ifdef cafe
354
355template <>
356inline f32 MathCalcCommon<f32>::abs(f32 x)
357{
358 return std::abs(x);
359}
360
361template <>
362inline f64 MathCalcCommon<f64>::abs(f64 x)
363{
364 return std::abs(x);
365}
366
367#endif // cafe
368
369template <typename T>
370inline T MathCalcCommon<T>::max(T a, T b)
371{
372 return a > b ? a : b;
373}
374
375template <typename T>
376inline T MathCalcCommon<T>::min(T a, T b)
377{
378 return a < b ? a : b;
379}
380
381template <typename T>
382inline T MathCalcCommon<T>::max3(T a, T b, T c)
383{
384 return max(a: max(a, b), b: c);
385}
386
387template <typename T>
388inline T MathCalcCommon<T>::min3(T a, T b, T c)
389{
390 return min(a: min(a, b), b: c);
391}
392
393template <typename T>
394inline T MathCalcCommon<T>::deg2rad(T deg)
395{
396 return deg * (numbers::pi_v<T> / static_cast<T>(180));
397}
398
399template <typename T>
400inline T MathCalcCommon<T>::rad2deg(T rad)
401{
402 return rad * (static_cast<T>(180) / numbers::pi_v<T>);
403}
404
405template <typename T>
406inline u32 MathCalcCommon<T>::deg2idx(T a)
407{
408 return static_cast<u32>(a * (cHalfRoundIdx / static_cast<T>(180)));
409}
410
411template <typename T>
412inline u32 MathCalcCommon<T>::rad2idx(T a)
413{
414 return static_cast<u32>(a * (cHalfRoundIdx / pi()));
415}
416
417template <typename T>
418inline T MathCalcCommon<T>::idx2deg(u32 a)
419{
420 return static_cast<T>(a * (static_cast<T>(180) / cHalfRoundIdx));
421}
422
423template <typename T>
424inline T MathCalcCommon<T>::idx2rad(u32 a)
425{
426 return static_cast<T>(a * (pi() / cHalfRoundIdx));
427}
428
429template <typename T>
430inline s32 MathCalcCommon<T>::roundOff(T val)
431{
432 return std::floor(val + 0.5f);
433}
434
435template <>
436inline s32 MathCalcCommon<s32>::roundOff(s32 val)
437{
438 return val;
439}
440
441template <typename T>
442inline s32 MathCalcCommon<T>::floor(T val)
443{
444 return std::floor(val);
445}
446
447template <>
448inline s32 MathCalcCommon<s32>::floor(s32 val)
449{
450 return val;
451}
452
453template <typename T>
454inline s32 MathCalcCommon<T>::ceil(T val)
455{
456 return std::ceil(val);
457}
458
459template <>
460inline s32 MathCalcCommon<s32>::ceil(s32 val)
461{
462 return val;
463}
464
465template <typename T>
466inline T MathCalcCommon<T>::roundUp(T x, s32 multNumber)
467{
468 SEAD_ASSERT(multNumber > 0);
469 return (x + multNumber - 1) / multNumber * multNumber;
470}
471
472template <>
473inline s32 MathCalcCommon<u32>::roundUpPow2(u32 val, s32 base)
474{
475 SEAD_ASSERT_MSG((u32(base - 1) & u32(base)) == 0, "illegal param[val:%d, base:%d]", val, base);
476 return (val + base - 1) & (u32)-base;
477}
478
479template <>
480inline s32 MathCalcCommon<s32>::roundUpPow2(s32 val, s32 base)
481{
482 SEAD_ASSERT_MSG(val >= 0 && (u32(base - 1) & u32(base)) == 0, "illegal param[val:%d, base:%d]",
483 val, base);
484 return (val + base - 1) & (u32)-base;
485}
486
487template <typename T>
488inline T MathCalcCommon<T>::clampMax(T val, T max_)
489{
490 return val > max_ ? max_ : val;
491}
492
493template <typename T>
494inline T MathCalcCommon<T>::clampMin(T val, T min_)
495{
496 return val < min_ ? min_ : val;
497}
498
499template <typename T>
500inline T MathCalcCommon<T>::clamp2(T min_, T val, T max_)
501{
502 return clamp(value: val, low: min_, high: max_);
503}
504
505template <typename T>
506inline T MathCalcCommon<T>::clamp(T value, T low, T high)
507{
508 if (value < low)
509 value = low;
510 else if (value > high)
511 value = high;
512 return value;
513}
514
515template <typename T>
516inline bool MathCalcCommon<T>::chase(T* value, T target, T step)
517{
518 const T current = *value;
519
520 if (current < target)
521 {
522 const T new_value = current + step;
523 if (target <= new_value || new_value < current)
524 {
525 *value = target;
526 return true;
527 }
528 *value = new_value;
529 return false;
530 }
531
532 if (current > target)
533 {
534 const T new_value = current - step;
535 if (target >= new_value || current < new_value)
536 {
537 *value = target;
538 return true;
539 }
540 *value = new_value;
541 return false;
542 }
543
544 return true;
545}
546
547template <typename T, typename T2>
548inline T lerp(T a, T b, T2 t)
549{
550 return a + (b - a) * t;
551}
552
553} // namespace sead
554