#ifndef SPLINE_H
#define SPLINE_H

#include "HandmadeMath.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
    These were already in your original header:
*/

// Adaptive Catmull–Rom in 2D / 3D / 4D (by minimum angle):
HMM_Vec2 *catmull_rom_ma_v2(HMM_Vec2 *cp, float ma);
HMM_Vec3 *catmull_rom_ma_v3(HMM_Vec3 *cp, float ma); /* not yet implemented in .c, placeholder */
HMM_Vec4 *catmull_rom_ma_v4(HMM_Vec4 *cp, float ma); /* not yet implemented in .c, placeholder */

// Adaptive Bezier in 2D (by minimum angle):
HMM_Vec2 *bezier_cb_ma_v2(HMM_Vec2 *cp, float ma);

// Generic “single-segment” query for 2D control points + basis matrix:
HMM_Vec2 spline_query(HMM_Vec2 *cp, float d, HMM_Mat4 *basis);

// Catmull–Rom “entire spline” queries:
HMM_Vec2 catmull_rom_pos(HMM_Vec2 *cp, float d);   // position
HMM_Vec2 catmull_rom_tan(HMM_Vec2 *cp, float d);   // tangent
HMM_Vec2 catmull_rom_curv(HMM_Vec2 *cp, float d);  // curvature
HMM_Vec2 catmull_rom_wig(HMM_Vec2 *cp, float d);   // 3rd derivative (“wiggle”)

// Computes approximate length of a 2D Catmull–Rom spline:
float catmull_rom_len(HMM_Vec2 *cp);

// Returns closest point on a 2D Catmull–Rom curve given an external 2D point `p`:
HMM_Vec2 catmull_rom_closest(HMM_Vec2 *cp, HMM_Vec2 p);


/*
    Additional convenience functions for *single-segment* cubic splines:

    Each of these expects exactly 4 control points in `p[0..3]`,
    and a parameter t in [0..1]. They pick the appropriate matrix internally.
*/

// Hermite:
HMM_Vec2 cubic_hermite_pos(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_tan(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_curv(HMM_Vec2 *p, float d);
HMM_Vec2 cubic_hermite_wig(HMM_Vec2 *p, float d);

// B-spline:
HMM_Vec2 b_spline_pos(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_tan(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_curv(HMM_Vec2 *p, float d);
HMM_Vec2 b_spline_wig(HMM_Vec2 *p, float d);

// Bezier:
HMM_Vec2 bezier_pos(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_tan(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_curv(HMM_Vec2 *p, float d);
HMM_Vec2 bezier_wig(HMM_Vec2 *p, float d);


/*
    Uniform sampling of a *single* 4-point segment in 2D:
    Returns an array of points (stb_ds dynamic array).
*/
HMM_Vec2 *spline_v2(HMM_Vec2 *p, HMM_Mat4 *m, int segs);

/*
    Adaptive subdivision routines (single-segment) in 2D:
    - Subdivide by min segment length
    - Subdivide by “max angle” proxy
*/
HMM_Vec2 *spline2d_min_seg(float u0, float u1, float min_seg, HMM_Mat4 *C, HMM_Vec2 *ret);
HMM_Vec2 *catmull_rom_min_seg(HMM_Vec2 *a, HMM_Vec2 *b, HMM_Vec2 *c, HMM_Vec2 *d, float min_seg);

HMM_Vec2 *spline2d_min_angle_2(float u0, float u1, float max_angle, HMM_Mat4 *C, HMM_Vec2 *arr);
HMM_Vec2 *spline_min_angle(HMM_Vec2 *p, const HMM_Mat4 *B, float min_angle, HMM_Vec2 *arr);

#ifdef __cplusplus
}
#endif

#endif /* SPLINE_H */
