105 lines
5.7 KiB
C
105 lines
5.7 KiB
C
#ifndef GUF_MATH_H
|
|
#define GUF_MATH_H
|
|
#include "guf_assert.h"
|
|
|
|
#define GUF_PI 3.14159265358979323846264338327950288
|
|
|
|
// Rotate left.
|
|
static inline uint64_t guf_rotl_u64(uint64_t x, int k) {return (x << k) | (x >> (64 - k));}
|
|
static inline uint32_t guf_rotl_u32(uint32_t x, int k) {return (x << k) | (x >> (32 - k));}
|
|
|
|
#define GUF_DEFINE_MIN_MAX_CLAMP(int_type, int_type_name)\
|
|
static inline int_type GUF_CAT(guf_min_, int_type_name)(int_type a, int_type b) {return a < b ? a : b;}\
|
|
static inline int_type GUF_CAT(guf_max_, int_type_name)(int_type a, int_type b) {return a > b ? a : b;}\
|
|
static inline int_type GUF_CAT(guf_clamp_, int_type_name)(int_type x, int_type min, int_type max) {if (x < min) {return min;} if (x > max) {return max;} return x;}
|
|
|
|
GUF_DEFINE_MIN_MAX_CLAMP(char, char)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(int, int)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(long, long)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(long long, long_long)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(int8_t, i8)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(int16_t, i16)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(int32_t, i32)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(int64_t, i64)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(ptrdiff_t, ptrdiff_t)
|
|
|
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned char, uchar)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned, unsigned)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned long, ulong)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(unsigned long long, ulong_long)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(uint8_t, u8)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(uint16_t, u16)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(uint32_t, u32)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(uint64_t, u64)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(size_t, size_t)
|
|
|
|
GUF_DEFINE_MIN_MAX_CLAMP(float, f32)
|
|
GUF_DEFINE_MIN_MAX_CLAMP(double, f64)
|
|
|
|
#undef GUF_DEFINE_MIN_MAX_CLAMP
|
|
|
|
static inline int guf_abs_int(int x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT_MIN); return -x;} // I would not drink that...
|
|
static inline int8_t guf_abs_i8 (int8_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT8_MIN); return -x;}
|
|
static inline int16_t guf_abs_i16(int16_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT16_MIN); return -x;}
|
|
static inline int32_t guf_abs_i32(int32_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT32_MIN); return -x;}
|
|
static inline int64_t guf_abs_i64(int64_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > INT64_MIN); return -x;}
|
|
static inline ptrdiff_t guf_abs_ptrdiff(ptrdiff_t x) {if (x >= 0) {return x;} GUF_ASSERT_RELEASE(x > PTRDIFF_MIN); return -x;}
|
|
|
|
static inline unsigned char guf_uabs_char(char x) {if (x >= 0) {return x;} else if (x == CHAR_MIN) {return (unsigned char)CHAR_MAX + 1;} else {return -x;}}
|
|
static inline unsigned guf_uabs_int(int x) {if (x >= 0) {return x;} else if (x == INT_MIN) {return (unsigned)INT_MAX + 1;} else {return -x;}}
|
|
static inline uint8_t guf_uabs_i8(int8_t x) {if (x >= 0) {return x;} else if (x == INT8_MIN) {return (uint8_t)INT8_MAX + 1;} else {return -x;}}
|
|
static inline uint16_t guf_uabs_i16(int16_t x) {if (x >= 0) {return x;} else if (x == INT16_MIN) {return (uint16_t)INT16_MAX + 1;} else {return -x;}}
|
|
static inline uint32_t guf_uabs_i32(int32_t x) {if (x >= 0) {return x;} else if (x == INT32_MIN) {return (uint32_t)INT32_MAX + 1;} else {return -x;}}
|
|
static inline uint64_t guf_uabs_i64(int64_t x) {if (x >= 0) {return x;} else if (x == INT64_MIN) {return (uint64_t)INT64_MAX + 1;} else {return -x;}}
|
|
|
|
static inline unsigned char guf_absdiff_char(char a, char b) {return a > b ? (unsigned char)a - (unsigned char)b : (unsigned char)b - (unsigned char)a;}
|
|
static inline unsigned guf_absdiff_int(int a, int b) {return a > b ? (unsigned)a - (unsigned)b : (unsigned)b - (unsigned)a;}
|
|
static inline uint8_t guf_absdiff_i8(int8_t a, int8_t b) {return a > b ? (uint8_t)a - (uint8_t)b : (uint8_t)b - (uint8_t)a;}
|
|
static inline uint16_t guf_absdiff_i16(int16_t a, int16_t b) {return a > b ? (uint16_t)a - (uint16_t)b : (uint16_t)b - (uint16_t)a;}
|
|
static inline uint32_t guf_absdiff_i32(int32_t a, int32_t b) {return a > b ? (uint32_t)a - (uint32_t)b : (uint32_t)b - (uint32_t)a;}
|
|
static inline uint64_t guf_absdiff_i64(int64_t a, int64_t b) {return a > b ? (uint64_t)a - (uint64_t)b : (uint64_t)b - (uint64_t)a;}
|
|
|
|
// An alternative lerp would be a + alpha * (b - a) (advantage: would be weakly monotonic, disadvantage: would not guarantee a for alpha = 0 and b for alpha = 1)
|
|
static inline float guf_lerp_f32(float a, float b, float alpha) {return (1 - alpha) * a + alpha * b;}
|
|
static inline double guf_lerp_f64(double a, double b, double alpha) {return (1 - alpha) * a + alpha * b;}
|
|
|
|
/*
|
|
smoothstep interpolation, cf. https://en.wikipedia.org/wiki/Smoothstep (last-retrieved 2025-02-18)
|
|
*/
|
|
|
|
static inline float guf_smoothstep_f32(float edge0, float edge1, float x)
|
|
{
|
|
if (edge0 == edge1) { // Prevent division by zero.
|
|
return 1;
|
|
}
|
|
x = guf_clamp_f32((x - edge0) / (edge1 - edge0), 0, 1); // Bring in range [0, 1]
|
|
return x * x * (3.f - 2.f * x);
|
|
}
|
|
static inline float guf_smootherstep_f32(float edge0, float edge1, float x)
|
|
{
|
|
if (edge0 == edge1) { // Prevent division by zero.
|
|
return 1;
|
|
}
|
|
x = guf_clamp_f32((x - edge0) / (edge1 - edge0), 0, 1); // Bring in range [0, 1]
|
|
return x * x * x * (x * (6.f * x - 15.f) + 10.f);
|
|
}
|
|
|
|
static inline double guf_smoothstep_f64(double edge0, double edge1, double x)
|
|
{
|
|
if (edge0 == edge1) { // Prevent division by zero.
|
|
return 1;
|
|
}
|
|
x = guf_clamp_f64((x - edge0) / (edge1 - edge0), 0, 1); // Bring in range [0, 1]
|
|
return x * x * (3.0 - 2.0 * x);
|
|
}
|
|
static inline double guf_smootherstep_f64(double edge0, double edge1, double x)
|
|
{
|
|
if (edge0 == edge1) { // Prevent division by zero.
|
|
return 1;
|
|
}
|
|
x = guf_clamp_f64((x - edge0) / (edge1 - edge0), 0, 1); // Bring in range [0, 1]
|
|
return x * x * x * (x * (6.0 * x - 15.0) + 10.0);
|
|
}
|
|
|
|
#endif
|