#pragma once #include #include #ifndef SEAD_MATH_MATH_CALC_COMMON_H_ #include #endif #include #include namespace sead { template <> const MathCalcCommon::SinCosSample MathCalcCommon::cSinCosTbl[]; template <> const MathCalcCommon::AtanSample MathCalcCommon::cAtanTbl[]; template <> const MathCalcCommon::ExpSample MathCalcCommon::cExpTbl[]; template <> const MathCalcCommon::LogSample MathCalcCommon::cLogTbl[]; template inline T MathCalcCommon::sign(T value) { return value < 0 ? -1 : 1; } template inline T MathCalcCommon::sqrt(T t) { return std::sqrt(t); } template inline T MathCalcCommon::rsqrt(T t) { return 1 / std::sqrt(t); } template inline T MathCalcCommon::pow(T x, T y) { return std::pow(x, y); } template inline T MathCalcCommon::sin(T t) { if constexpr (std::is_same_v) { const auto as_int = BitUtil::bitCast(t); const SinCosSample& sample = cSinCosTbl[as_int >> 18]; return sample.sin_val + sample.sin_delta * (as_int & 0xFFFFFFu) * 0x1p-24f; } else { static_assert(!std::is_same(), "Unsupported type"); } } template inline T MathCalcCommon::cos(T t) { if constexpr (std::is_same_v) { const auto as_int = BitUtil::bitCast(t); const SinCosSample& sample = cSinCosTbl[as_int >> 18]; return sample.cos_val + sample.cos_delta * (as_int & 0xFFFFFFu) * 0x1p-24f; } else { static_assert(!std::is_same(), "Unsupported type"); } } template inline T MathCalcCommon::tan(T t) { return std::tan(t); } template inline T MathCalcCommon::asin(T t) { if constexpr (std::is_floating_point()) SEAD_ASSERT_MSG(-1.0 <= t && t <= 1.0, "t(%f) is not in [-1, 1].", t); return std::asin(t); } template inline T MathCalcCommon::acos(T t) { if constexpr (std::is_floating_point()) SEAD_ASSERT_MSG(-1.0 <= t && t <= 1.0, "t(%f) is not in [-1, 1].", t); return std::acos(t); } template inline T MathCalcCommon::atan(T t) { return std::atan(t); } template inline T MathCalcCommon::atan2(T y, T x) { return std::atan2(y, x); } template <> inline f32 MathCalcCommon::sinIdx(u32 idx) { u32 index = (idx >> 24) & 0xff; u32 rest = idx & 0xffffff; return cSinCosTbl[index].sin_val + cSinCosTbl[index].sin_delta * rest / 0x1000000; } template <> inline f32 MathCalcCommon::cosIdx(u32 idx) { u32 index = (idx >> 24) & 0xff; u32 rest = idx & 0xffffff; return cSinCosTbl[index].cos_val + cSinCosTbl[index].cos_delta * rest / 0x1000000; } template <> inline f32 MathCalcCommon::tanIdx(u32 idx) { u32 index = (idx >> 24) & 0xff; f32 rest = static_cast(idx & 0xffffff) / 0x1000000; const SinCosSample& sample = cSinCosTbl[index]; return (sample.sin_val + sample.sin_delta * rest) / (sample.cos_val + sample.cos_delta * rest); } template <> inline u32 MathCalcCommon::asinIdx(f32 s) { SEAD_ASSERT_MSG(s <= 1 && s >= -1, "s(%f) is not in [-1, 1].", s); const f32 rsqrt_2 = 0.7071067690849304f; // rsqrt(2) if (s >= 0) { if (s > rsqrt_2) return 0x40000000 - atanIdx_(sqrt(1 - s * s) / s); else return atanIdx_(s / sqrt(1 - s * s)); } else { if (s < -rsqrt_2) return 0xC0000000 + atanIdx_(-sqrt(1 - s * s) / s); else return -atanIdx_(-s / sqrt(1 - s * s)); } } template <> inline u32 MathCalcCommon::acosIdx(f32 c) { SEAD_ASSERT_MSG(c <= 1 && c >= -1, "c(%f) is not in [-1, 1].", c); const f32 rsqrt_2 = 0.7071067690849304f; // rsqrt(2) if (c >= 0) { if (c > rsqrt_2) return atanIdx_(sqrt(1 - c * c) / c); else return 0x40000000 - atanIdx_(c / sqrt(1 - c * c)); } else { if (c < -rsqrt_2) return 0x80000000 - atanIdx_(-sqrt(1 - c * c) / c); else return 0x40000000 + atanIdx_(-c / sqrt(1 - c * c)); } } template <> inline u32 MathCalcCommon::atanIdx(f32 t) { if (t >= 0) { if (t > 1) return 0x40000000 - atanIdx_(1 / t); else return atanIdx_(t); } else { if (t < -1) return 0xC0000000 + atanIdx_(-1 / t); else return -atanIdx_(-t); } } template <> inline u32 MathCalcCommon::atan2Idx(f32 y, f32 x) { if (x == 0 && y == 0) return 0; if (x >= 0) { if (y >= 0) { if (x >= y) return atanIdx_(y / x); else return 0x40000000 - atanIdx_(x / y); } else { if (x >= -y) return -atanIdx_(-y / x); else return 0xC0000000 + atanIdx_(x / -y); } } else { if (y >= 0) { if (-x >= y) return 0x80000000 - atanIdx_(y / -x); else return 0x40000000 + atanIdx_(-x / y); } else { if (x <= y) return 0x80000000 + atanIdx_(y / x); else return 0xC0000000 - atanIdx_(x / y); } } } template <> inline void MathCalcCommon::sinCosIdx(f32* pSin, f32* pCos, u32 idx) { u32 index = (idx >> 24) & 0xff; f32 rest = static_cast(idx & 0xffffff) / 0x1000000; const SinCosSample& sample = cSinCosTbl[index]; /*if (pSin != NULL)*/ *pSin = sample.sin_val + sample.sin_delta * rest; /*if (pCos != NULL)*/ *pCos = sample.cos_val + sample.cos_delta * rest; } template inline T MathCalcCommon::exp(T t) { return std::exp(t); } template inline T MathCalcCommon::log(T t) { return std::log(t); } template inline T MathCalcCommon::log2(T n) { return std::log2(n); } template inline T MathCalcCommon::log10(T t) { return std::log10(t); } template inline T MathCalcCommon::minNumber() { return std::numeric_limits::min(); } template inline T MathCalcCommon::maxNumber() { return std::numeric_limits::max(); } template <> inline float MathCalcCommon::minNumber() { return -std::numeric_limits::max(); } template <> inline float MathCalcCommon::maxNumber() { return std::numeric_limits::max(); } template <> inline double MathCalcCommon::minNumber() { return -std::numeric_limits::max(); } template <> inline double MathCalcCommon::maxNumber() { return std::numeric_limits::max(); } template <> inline long double MathCalcCommon::minNumber() { return -std::numeric_limits::max(); } template <> inline long double MathCalcCommon::maxNumber() { return std::numeric_limits::max(); } template inline T MathCalcCommon::infinity() { return std::numeric_limits::infinity(); } template <> inline f32 MathCalcCommon::nan() { return BitUtil::bitCast(0x7FFFFFFF); } template <> inline f64 MathCalcCommon::nan() { return BitUtil::bitCast(0x7FFFFFFFFFFFFFFF); } template <> inline s32 MathCalcCommon::abs(s32 x) { return (x ^ x >> 31) - (x >> 31); } template <> inline u32 MathCalcCommon::abs(u32 x) { return x; } #ifdef cafe template <> inline f32 MathCalcCommon::abs(f32 x) { return std::abs(x); } template <> inline f64 MathCalcCommon::abs(f64 x) { return std::abs(x); } #endif // cafe template inline T MathCalcCommon::max(T a, T b) { return a < b ? b : a; } template inline T MathCalcCommon::min(T a, T b) { return a < b ? a : b; } template inline T MathCalcCommon::max3(T a, T b, T c) { return max(max(a, b), c); } template inline T MathCalcCommon::min3(T a, T b, T c) { return min(min(a, b), c); } template inline T MathCalcCommon::deg2rad(T deg) { return deg * (numbers::pi_v / static_cast(180)); } template inline T MathCalcCommon::rad2deg(T rad) { return rad * (static_cast(180) / numbers::pi_v); } template inline u32 MathCalcCommon::deg2idx(T a) { return static_cast(a * (cHalfRoundIdx / static_cast(180))); } template inline u32 MathCalcCommon::rad2idx(T a) { return static_cast(a * (cHalfRoundIdx / pi())); } template inline T MathCalcCommon::idx2deg(u32 a) { return static_cast(a * (static_cast(180) / cHalfRoundIdx)); } template inline T MathCalcCommon::idx2rad(u32 a) { return static_cast(a * (pi() / cHalfRoundIdx)); } template inline s32 MathCalcCommon::roundOff(T val) { return std::floor(val + 0.5f); } template <> inline s32 MathCalcCommon::roundOff(s32 val) { return val; } template inline s32 MathCalcCommon::floor(T val) { return std::floor(val); } template <> inline s32 MathCalcCommon::floor(s32 val) { return val; } template inline s32 MathCalcCommon::ceil(T val) { return std::ceil(val); } template <> inline s32 MathCalcCommon::ceil(s32 val) { return val; } template inline T MathCalcCommon::roundUp(T x, s32 multNumber) { SEAD_ASSERT(multNumber > 0); return (x + multNumber - 1) / multNumber * multNumber; } template <> inline s32 MathCalcCommon::roundUpPow2(u32 val, s32 base) { SEAD_ASSERT_MSG((u32(base - 1) & u32(base)) == 0, "illegal param[val:%d, base:%d]", val, base); return (val + base - 1) & (u32)-base; } template <> inline s32 MathCalcCommon::roundUpPow2(s32 val, s32 base) { SEAD_ASSERT_MSG(val >= 0 && (u32(base - 1) & u32(base)) == 0, "illegal param[val:%d, base:%d]", val, base); return (val + base - 1) & (u32)-base; } template inline T MathCalcCommon::clampMax(T val, T max_) { return min(val, max_); } template inline T MathCalcCommon::clampMin(T val, T min_) { return max(val, min_); } template inline T MathCalcCommon::clamp(T value, T low, T high) { if (value < low) value = low; else if (value > high) value = high; return value; } template inline bool MathCalcCommon::chase(T* value, T target, T step) { const T current = *value; if (current < target) { const T new_value = current + step; if (target <= new_value || new_value < current) { *value = target; return true; } *value = new_value; return false; } if (current > target) { const T new_value = current - step; if (target >= new_value || current < new_value) { *value = target; return true; } *value = new_value; return false; } return true; } template inline T lerp(T a, T b, T2 t) { return a + (b - a) * t; } } // namespace sead