| 1 | #include "hostio/seadHostIOCurve.h" |
| 2 | #include <cmath> |
| 3 | #include "math/seadMathCalcCommon.h" |
| 4 | #include "math/seadMathNumbers.h" |
| 5 | |
| 6 | namespace sead::hostio |
| 7 | { |
| 8 | template <typename T> |
| 9 | constexpr CurveFunctionTable<T> makeTable_() |
| 10 | { |
| 11 | return {{ |
| 12 | curveLinear_, |
| 13 | curveHermit_, |
| 14 | curveStep_, |
| 15 | curveSin_, |
| 16 | curveCos_, |
| 17 | curveSinPow2_, |
| 18 | curveLinear2D_, |
| 19 | curveHermit2D_, |
| 20 | curveStep2D_, |
| 21 | curveNonuniformSpline_, |
| 22 | curveHermit2DSmooth_, |
| 23 | }}; |
| 24 | } |
| 25 | |
| 26 | template <typename T> |
| 27 | constexpr CurveFunctionTableVec2<T> makeTableVec2_() |
| 28 | { |
| 29 | return {{ |
| 30 | curveLinearVec2_, |
| 31 | curveHermitVec2_, |
| 32 | curveStepVec2_, |
| 33 | curveSinVec2_, |
| 34 | curveCosVec2_, |
| 35 | curveSinPow2Vec2_, |
| 36 | curveLinear2DVec2_, |
| 37 | curveHermit2DVec2_, |
| 38 | curveStep2DVec2_, |
| 39 | curveNonuniformSplineVec2_, |
| 40 | curveHermit2DSmoothVec2_, |
| 41 | }}; |
| 42 | } |
| 43 | |
| 44 | CurveFunctionTable<f32> sCurveFunctionTbl_f32 = makeTable_<f32>(); |
| 45 | CurveFunctionTable<f64> sCurveFunctionTbl_f64 = makeTable_<f64>(); |
| 46 | |
| 47 | CurveFunctionTableVec2<f32> sCurveFunctionTbl_Vec2f = makeTableVec2_<f32>(); |
| 48 | CurveFunctionTableVec2<f64> sCurveFunctionTbl_Vec2d = makeTableVec2_<f64>(); |
| 49 | |
| 50 | template <typename T> |
| 51 | static T fracPart(T x) |
| 52 | { |
| 53 | return x - T(int(x)); |
| 54 | } |
| 55 | |
| 56 | template <typename T> |
| 57 | T curveLinear_(f32 t, const CurveDataInfo* info, const T* f) |
| 58 | { |
| 59 | if (t < 0) |
| 60 | return f[0]; |
| 61 | |
| 62 | const auto n = info->numUse - 1; |
| 63 | const int i = n * t; |
| 64 | if (i >= n) |
| 65 | return f[n]; |
| 66 | return f[i] + (fracPart(x: n * t) * (f[i + 1] - f[i])); |
| 67 | } |
| 68 | |
| 69 | // NON_MATCHING: instruction ordering |
| 70 | template <typename T> |
| 71 | T curveHermit_(f32 t, const CurveDataInfo* info, const T* f) |
| 72 | { |
| 73 | if (info->numUse % 2 == 1) |
| 74 | return 0; |
| 75 | if (t < 0) |
| 76 | return f[0]; |
| 77 | |
| 78 | const auto n = (info->numUse / 2) - 1; |
| 79 | const int i = n * t; |
| 80 | const int j = 2 * i; |
| 81 | if (i >= n) |
| 82 | return f[j]; |
| 83 | |
| 84 | const auto x = fracPart(x: n * t); |
| 85 | const auto coeff = &f[j]; |
| 86 | |
| 87 | return ((2 * x * x * x) - (3 * x * x) + 1) * coeff[0] // (2t^3 - 3t^2 + 1)p0 |
| 88 | + ((-2 * x * x * x) + (3 * x * x)) * coeff[2] // (-2t^3 + 2t^2)p1 |
| 89 | + ((x * x * x) - (x * x)) * coeff[3] // (t^3 - t^2)m1 |
| 90 | + ((x * x * x) - (2 * x * x) + x) * f[j | 1] // (t^3 - 2t^2 + t)m0 |
| 91 | ; |
| 92 | } |
| 93 | |
| 94 | template <typename T> |
| 95 | T curveStep_(f32 t, const CurveDataInfo* info, const T* f) |
| 96 | { |
| 97 | const f32 x = Mathf::clamp(value: t, low: 0.0, high: 1.0); |
| 98 | return f[int(x * (info->numUse - 1))]; |
| 99 | } |
| 100 | |
| 101 | template <typename T> |
| 102 | T curveSin_(f32 t_, const CurveDataInfo*, const T* f) |
| 103 | { |
| 104 | const T t = t_; |
| 105 | return std::sin(f[0] * t * (2 * numbers::pi_v<T>)) * f[1]; |
| 106 | } |
| 107 | |
| 108 | template <typename T> |
| 109 | T curveCos_(f32 t_, const CurveDataInfo*, const T* f) |
| 110 | { |
| 111 | const T t = t_; |
| 112 | return std::cos(f[0] * T(t) * (2 * numbers::pi_v<T>)) * f[1]; |
| 113 | } |
| 114 | |
| 115 | template <typename T> |
| 116 | T curveSinPow2_(f32 t_, const CurveDataInfo*, const T* f) |
| 117 | { |
| 118 | const T t = t_; |
| 119 | const auto y = std::sin(f[0] * t * (2 * numbers::pi_v<T>)); |
| 120 | return y * y * f[1]; |
| 121 | } |
| 122 | |
| 123 | // NON_MATCHING: instruction reordering (which results in localized regalloc differences) |
| 124 | template <typename T> |
| 125 | T curveLinear2D_(f32 t_, const CurveDataInfo* info, const T* f) |
| 126 | { |
| 127 | const T t = t_; |
| 128 | if (f[0] >= t) |
| 129 | return f[1]; |
| 130 | |
| 131 | const auto n = info->numUse / 2; |
| 132 | if (f[2 * (n - 1)] <= t) |
| 133 | return f[2 * (n - 1) + 1]; |
| 134 | |
| 135 | for (s32 i = 0; i < n; ++i) |
| 136 | { |
| 137 | const auto j = 2 * i; |
| 138 | if (f[j + 2] > t) |
| 139 | return f[j + 1] + ((t - f[j]) / (f[j + 2] - f[j])) * (f[j + 3] - f[j + 1]); |
| 140 | } |
| 141 | return 0; |
| 142 | } |
| 143 | |
| 144 | // NON_MATCHING: same as curveHermit_<T> |
| 145 | template <typename T> |
| 146 | T curveHermit2D_(f32 t_, const CurveDataInfo* info, const T* f) |
| 147 | { |
| 148 | const T t = t_; |
| 149 | const s8 n = info->numUse / 3; |
| 150 | if (f[0] >= t) |
| 151 | return f[1]; |
| 152 | |
| 153 | if (f[3 * (n - 1)] <= t) |
| 154 | return f[3 * (n - 1) + 1]; |
| 155 | |
| 156 | for (s32 i = 0; i < n; ++i) |
| 157 | { |
| 158 | const auto j = 3 * i; |
| 159 | if (f[j + 3] > t) |
| 160 | { |
| 161 | const auto x = (t - f[j]) / (f[j + 3] - f[j]); |
| 162 | return ((2 * x * x * x) - (3 * x * x) + 1) * f[j + 1] // (2t^3 - 3t^2 + 1)p0 |
| 163 | + ((-2 * x * x * x) + (3 * x * x)) * f[j + 4] // (-2t^3 + 2t^2)p1 |
| 164 | + ((x * x * x) - (x * x)) * f[j + 5] // (t^3 - t^2)m1 |
| 165 | + ((x * x * x) - (2 * x * x) + x) * f[j + 2] // (t^3 - 2t^2 + t)m0 |
| 166 | ; |
| 167 | } |
| 168 | } |
| 169 | |
| 170 | return 0; |
| 171 | } |
| 172 | |
| 173 | template <typename T> |
| 174 | T curveStep2D_(f32 t_, const CurveDataInfo* info, const T* f) |
| 175 | { |
| 176 | const T t = t_; |
| 177 | const s8 n = info->numUse / 2; |
| 178 | if (t <= f[0]) |
| 179 | return f[1]; |
| 180 | |
| 181 | if (t >= f[2 * (n - 1)]) |
| 182 | return f[2 * (n - 1) + 1]; |
| 183 | |
| 184 | for (s32 i = 0; i < n; ++i) |
| 185 | { |
| 186 | if (t < f[2 * i + 2]) |
| 187 | return f[2 * i + 1]; |
| 188 | } |
| 189 | return 0; |
| 190 | } |
| 191 | |
| 192 | template <typename T> |
| 193 | T curveNonuniformSpline_(f32, const CurveDataInfo*, const T*) |
| 194 | { |
| 195 | SEAD_ASSERT_MSG(false, "You must call ICurve::interpolateToVec2 at this curve type." ); |
| 196 | return 0; |
| 197 | } |
| 198 | |
| 199 | template <typename T> |
| 200 | Vector2<T> curveLinearVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 201 | { |
| 202 | return {t, curveLinear_(t, info, f)}; |
| 203 | } |
| 204 | |
| 205 | template <typename T> |
| 206 | Vector2<T> curveHermitVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 207 | { |
| 208 | return {t, curveHermit_(t, info, f)}; |
| 209 | } |
| 210 | |
| 211 | template <typename T> |
| 212 | Vector2<T> curveStepVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 213 | { |
| 214 | return {t, curveStep_(t, info, f)}; |
| 215 | } |
| 216 | |
| 217 | template <typename T> |
| 218 | Vector2<T> curveSinVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 219 | { |
| 220 | return {t, curveSin_(t, info, f)}; |
| 221 | } |
| 222 | |
| 223 | template <typename T> |
| 224 | Vector2<T> curveCosVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 225 | { |
| 226 | return {t, curveCos_(t, info, f)}; |
| 227 | } |
| 228 | |
| 229 | template <typename T> |
| 230 | Vector2<T> curveSinPow2Vec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 231 | { |
| 232 | return {t, curveSinPow2_(t, info, f)}; |
| 233 | } |
| 234 | |
| 235 | template <typename T> |
| 236 | Vector2<T> curveLinear2DVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 237 | { |
| 238 | return {t, curveLinear2D_(t, info, f)}; |
| 239 | } |
| 240 | |
| 241 | template <typename T> |
| 242 | Vector2<T> curveHermit2DVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 243 | { |
| 244 | return {t, curveHermit2D_(t, info, f)}; |
| 245 | } |
| 246 | |
| 247 | template <typename T> |
| 248 | Vector2<T> curveStep2DVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 249 | { |
| 250 | return {t, curveStep2D_(t, info, f)}; |
| 251 | } |
| 252 | |
| 253 | // curveNonuniformSplineVec2_ has an assertion |
| 254 | |
| 255 | template <typename T> |
| 256 | Vector2<T> curveHermit2DSmoothVec2_(f32 t, const CurveDataInfo* info, const T* f) |
| 257 | { |
| 258 | return {t, curveHermit2DSmooth_(t, info, f)}; |
| 259 | } |
| 260 | } // namespace sead::hostio |
| 261 | |