// Math for Game Programmers: Fast and Funky 1D Nonlinear Transformations // https://www.youtube.com/watch?v=mr5xkf6zSzk // // Thread safety: Safe for concurrent use (no shared state, pure functions). // Macros: Namespaced INTERP_* variants are collision-safe. Legacy un-prefixed // names are provided via #ifndef guard — if your code already defines e.g. // "mix", the library will not override it. #ifndef INTERPOLATE_H #define INTERPOLATE_H // Namespaced macros (safe from collisions). Use these in new code. #ifndef INTERP_FLIP #define INTERP_FLIP(x) (1.0 - (double)(x)) #endif #ifndef INTERP_SCALE #define INTERP_SCALE(a, t) ((double)(t) * (double)(a)) #endif #ifndef INTERP_REVERSE_SCALE #define INTERP_REVERSE_SCALE(a, t) ((1.0 - (double)(t)) * (double)(a)) #endif #ifndef INTERP_MIX #define INTERP_MIX(a, b, b_weight) ((double)(a) + (double)(b_weight) * ((double)(b) - (double)(a))) #endif #ifndef INTERP_CROSSFADE #define INTERP_CROSSFADE(a, b, t) ((double)(a) + (double)(t) * ((double)(b) - (double)(a))) #endif #ifndef INTERP_SMOOTH_START_2 #define INTERP_SMOOTH_START_2(t) ((double)(t) * (double)(t)) #endif #ifndef INTERP_SMOOTH_START_3 #define INTERP_SMOOTH_START_3(t) (INTERP_SMOOTH_START_2(t) * (double)(t)) #endif #ifndef INTERP_SMOOTH_START_4 #define INTERP_SMOOTH_START_4(t) (INTERP_SMOOTH_START_3(t) * (double)(t)) #endif #ifndef INTERP_SMOOTH_START_5 #define INTERP_SMOOTH_START_5(t) (INTERP_SMOOTH_START_4(t) * (double)(t)) #endif #ifndef INTERP_SMOOTH_START_6 #define INTERP_SMOOTH_START_6(t) (INTERP_SMOOTH_START_5(t) * (double)(t)) #endif #ifndef INTERP_SMOOTH_STOP_2 #define INTERP_SMOOTH_STOP_2(t) (INTERP_FLIP(INTERP_SMOOTH_START_2(INTERP_FLIP(t)))) #endif #ifndef INTERP_SMOOTH_STOP_3 #define INTERP_SMOOTH_STOP_3(t) (INTERP_FLIP(INTERP_SMOOTH_START_3(INTERP_FLIP(t)))) #endif #ifndef INTERP_SMOOTH_STOP_4 #define INTERP_SMOOTH_STOP_4(t) (INTERP_FLIP(INTERP_SMOOTH_START_4(INTERP_FLIP(t)))) #endif #ifndef INTERP_SMOOTH_STOP_5 #define INTERP_SMOOTH_STOP_5(t) (INTERP_FLIP(INTERP_SMOOTH_START_5(INTERP_FLIP(t)))) #endif #ifndef INTERP_SMOOTH_STOP_6 #define INTERP_SMOOTH_STOP_6(t) (INTERP_FLIP(INTERP_SMOOTH_START_6(INTERP_FLIP(t)))) #endif #ifndef INTERP_SMOOTH_STEP_3 #define INTERP_SMOOTH_STEP_3(t) (INTERP_CROSSFADE(INTERP_SMOOTH_START_2(t), INTERP_SMOOTH_STOP_2(t), (double)(t))) #endif #ifndef INTERP_ARCH_2 #define INTERP_ARCH_2(t) (INTERP_SCALE(INTERP_FLIP(t), (double)(t))) #endif #ifndef INTERP_SMOOTH_START_ARCH_3 #define INTERP_SMOOTH_START_ARCH_3(t) (INTERP_SCALE(INTERP_ARCH_2(t), (double)(t))) #endif #ifndef INTERP_SMOOTH_STOP_ARCH_3 #define INTERP_SMOOTH_STOP_ARCH_3(t) (INTERP_REVERSE_SCALE(INTERP_ARCH_2(t), (double)(t))) #endif // Legacy macro names — alias to namespaced variants when not already defined by user. #ifndef flip #define flip(x) INTERP_FLIP(x) #endif #ifndef scale #define scale(a, t) INTERP_SCALE(a, t) #endif #ifndef reverse_scale #define reverse_scale(a, t) INTERP_REVERSE_SCALE(a, t) #endif #ifndef mix #define mix(a, b, b_weight) INTERP_MIX(a, b, b_weight) #endif #ifndef crossfade #define crossfade(a, b, t) INTERP_CROSSFADE(a, b, t) #endif #ifndef smooth_start_2 #define smooth_start_2(t) INTERP_SMOOTH_START_2(t) #endif #ifndef smooth_start_3 #define smooth_start_3(t) INTERP_SMOOTH_START_3(t) #endif #ifndef smooth_start_4 #define smooth_start_4(t) INTERP_SMOOTH_START_4(t) #endif #ifndef smooth_start_5 #define smooth_start_5(t) INTERP_SMOOTH_START_5(t) #endif #ifndef smooth_start_6 #define smooth_start_6(t) INTERP_SMOOTH_START_6(t) #endif #ifndef smooth_stop_2 #define smooth_stop_2(t) INTERP_SMOOTH_STOP_2(t) #endif #ifndef smooth_stop_3 #define smooth_stop_3(t) INTERP_SMOOTH_STOP_3(t) #endif #ifndef smooth_stop_4 #define smooth_stop_4(t) INTERP_SMOOTH_STOP_4(t) #endif #ifndef smooth_stop_5 #define smooth_stop_5(t) INTERP_SMOOTH_STOP_5(t) #endif #ifndef smooth_stop_6 #define smooth_stop_6(t) INTERP_SMOOTH_STOP_6(t) #endif #ifndef smooth_step_3 #define smooth_step_3(t) INTERP_SMOOTH_STEP_3(t) #endif #ifndef arch_2 #define arch_2(t) INTERP_ARCH_2(t) #endif #ifndef smooth_start_arch_3 #define smooth_start_arch_3(t) INTERP_SMOOTH_START_ARCH_3(t) #endif #ifndef smooth_stop_arch_3 #define smooth_stop_arch_3(t) INTERP_SMOOTH_STOP_ARCH_3(t) #endif /* Function wrappers for debuggability (use these instead of macros when debugging) */ #ifdef __cplusplus extern "C" { #endif double interpolate_flip(double t); double interpolate_scale(double a, double t); double interpolate_reverse_scale(double a, double t); double interpolate_mix(double a, double b, double b_weight); double interpolate_crossfade(double a, double b, double t); double interpolate_smooth_start_2(double t); double interpolate_smooth_start_3(double t); double interpolate_smooth_start_4(double t); double interpolate_smooth_start_5(double t); double interpolate_smooth_start_6(double t); double interpolate_smooth_stop_2(double t); double interpolate_smooth_stop_3(double t); double interpolate_smooth_stop_4(double t); double interpolate_smooth_stop_5(double t); double interpolate_smooth_stop_6(double t); double interpolate_smooth_step_3(double t); double interpolate_arch_2(double t); double interpolate_smooth_start_arch_3(double t); double interpolate_smooth_stop_arch_3(double t); #ifdef __cplusplus } #endif #endif #ifdef INTERPOLATE_IMPLEMENTATION #ifndef INTERPOLATE_IMPLEMENTED #define INTERPOLATE_IMPLEMENTED double interpolate_flip(double t) { return flip(t); } double interpolate_scale(double a, double t) { return scale(a, t); } double interpolate_reverse_scale(double a, double t) { return reverse_scale(a, t); } double interpolate_mix(double a, double b, double b_weight) { return mix(a, b, b_weight); } double interpolate_crossfade(double a, double b, double t) { return crossfade(a, b, t); } double interpolate_smooth_start_2(double t) { return smooth_start_2(t); } double interpolate_smooth_start_3(double t) { return smooth_start_3(t); } double interpolate_smooth_start_4(double t) { return smooth_start_4(t); } double interpolate_smooth_start_5(double t) { return smooth_start_5(t); } double interpolate_smooth_start_6(double t) { return smooth_start_6(t); } double interpolate_smooth_stop_2(double t) { return smooth_stop_2(t); } double interpolate_smooth_stop_3(double t) { return smooth_stop_3(t); } double interpolate_smooth_stop_4(double t) { return smooth_stop_4(t); } double interpolate_smooth_stop_5(double t) { return smooth_stop_5(t); } double interpolate_smooth_stop_6(double t) { return smooth_stop_6(t); } double interpolate_smooth_step_3(double t) { return smooth_step_3(t); } double interpolate_arch_2(double t) { return arch_2(t); } double interpolate_smooth_start_arch_3(double t) { return smooth_start_arch_3(t); } double interpolate_smooth_stop_arch_3(double t) { return smooth_stop_arch_3(t); } #endif /* INTERPOLATE_IMPLEMENTED */ #endif // INTERPOLATE_IMPLEMENTATION