summaryrefslogtreecommitdiff
path: root/src/code/z_fcurve_data.c
diff options
context:
space:
mode:
authorEllipticEllipsis <elliptic.ellipsis@gmail.com>2022-06-19 03:38:10 +0100
committerGitHub <noreply@github.com>2022-06-19 03:38:10 +0100
commitaf0123de1eb774aebb88b26e5d719b3406f51eb9 (patch)
treeef80dcb96198082164637f104245c5a6d4e79bd1 /src/code/z_fcurve_data.c
parent5ae4ef87cd8b1bd94cdc63174bfe6bd3f8183723 (diff)
`z_fcurve_data` OK, match last function in `z_fcurve_data_skelanime`, document SkelCurve system (#776)
* Match SkelCurve_Update Co-authored-by: Kelebek1 <34639600+Kelebek1@users.noreply.github.com> * Match and document z_fcurve_data * Begin documenting SkelCurve * More documentation * Deformat header * Pluralise knotCount * Sort out jointTable * Rename frameCount * Format * More documentation * Cleanup on DemoEffect * Remove space on typedef * Format, couple of fixes in the header * Review * Oops * Fix EnBox, DemoTreLgt, use macros in EnTorch Co-authored-by: Kelebek1 <34639600+Kelebek1@users.noreply.github.com>
Diffstat (limited to 'src/code/z_fcurve_data.c')
-rw-r--r--src/code/z_fcurve_data.c85
1 files changed, 83 insertions, 2 deletions
diff --git a/src/code/z_fcurve_data.c b/src/code/z_fcurve_data.c
index a0bf887e1..5c0aa066a 100644
--- a/src/code/z_fcurve_data.c
+++ b/src/code/z_fcurve_data.c
@@ -1,5 +1,86 @@
+/**
+ * @file z_fcurve_data.c
+ * @brief Interpolation functions for use with Curve SkelAnime
+ */
#include "global.h"
+#include "z64curve.h"
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data/func_800F23E0.s")
+#define FCURVE_INTERP_CUBIC 0 // Interpolate using a Hermite cubic spline
+#define FCURVE_INTERP_NONE 1 // Return the value at the left endpoint instead of interpolating
+#define FCURVE_INTERP_LINEAR 2 // Interpolate linearly
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data/func_800F2478.s")
+/**
+ * Hermite cubic spline interpolation between two endpoints, a,b. More information available at
+ * https://en.wikipedia.org/wiki/Cubic_Hermite_spline
+ *
+ * @param t interpolation parameter rescaled to lie in [0,1], (x-a)/(b-a)
+ * @param interval distance (b-a) between the endpoints
+ * @param y0 p(a)
+ * @param y1 p(b)
+ * @param m0 p'(a)
+ * @param m1 p'(b)
+ * @return f32 p(t), value of the cubic interpolating polynomial
+ */
+f32 Curve_CubicHermiteSpline(f32 t, f32 interval, f32 y0, f32 y1, f32 m0, f32 m1) {
+ f32 t2 = t * t;
+ f32 t3 = t2 * t;
+ f32 t3x2 = t3 * 2.0f;
+ f32 t2x3 = t2 * 3.0f;
+
+ // Hermite basis cubics h_{ij} satisfy h_{ij}^{(j)}(i) = 1, the other three values being 0
+ f32 h00 = t3x2 - t2x3 + 1.0f; // h_{00}(t) = 2t^3 - 3t^2 + 1
+ f32 h01 = t2x3 - t3x2; // h_{01}(t) = 3t^2 - 2t^3
+ f32 h10 = t3 - t2 * 2.0f + t; // h_{10}(t) = t^3 - 2t^2 + t
+ f32 h11 = t3 - t2; // h_{11}(t) = t^3 - t^2
+
+ f32 ret = h00 * y0;
+
+ ret += h01 * y1;
+ ret += h10 * m0 * interval;
+ ret += h11 * m1 * interval;
+
+ return ret;
+}
+
+/**
+ * Interpolates based on an array of CurveInterpKnot.
+ *
+ * @param x point at which to interpolate.
+ * @param knots Beginning of CurveInterpKnot array to use.
+ * @param knotCount number of knots to read from the array.
+ * @return f32 interpolated value
+ */
+f32 Curve_Interpolate(f32 x, CurveInterpKnot* knots, s32 knotCount) {
+ // If outside the entire interpolation interval, return the value at the near endpoint.
+ if (x <= knots[0].abscissa) {
+ return knots[0].ordinate;
+ } else if (x >= knots[knotCount - 1].abscissa) {
+ return knots[knotCount - 1].ordinate;
+ } else {
+ s32 cur;
+
+ for (cur = 0;; cur++) {
+ s32 next = cur + 1;
+
+ // Find the subinterval in which x lies
+ if (x < knots[next].abscissa) {
+ if (knots[cur].flags & FCURVE_INTERP_NONE) {
+ // No interpolation
+ return knots[cur].ordinate;
+ } else if (knots[cur].flags & FCURVE_INTERP_LINEAR) {
+ // Linear interpolation
+ return knots[cur].ordinate +
+ ((x - (f32)knots[cur].abscissa) / ((f32)knots[next].abscissa - (f32)knots[cur].abscissa)) *
+ (knots[next].ordinate - knots[cur].ordinate);
+ } else {
+ // Cubic interpolation
+ f32 diff = (f32)knots[next].abscissa - (f32)knots[cur].abscissa;
+ f32 t = (x - (f32)knots[cur].abscissa) / ((f32)knots[next].abscissa - (f32)knots[cur].abscissa);
+
+ return Curve_CubicHermiteSpline(t, diff * (1.0f / 30.0f), knots[cur].ordinate, knots[next].ordinate,
+ knots[cur].rightGradient, knots[next].leftGradient);
+ }
+ }
+ }
+ }
+}