|
|
@@ -1,8 +1,7 @@ |
|
|
|
// |
|
|
|
// Lol Engine |
|
|
|
// |
|
|
|
// Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net> |
|
|
|
// © 2012—2013 Benjamin “Touky” Huet <huet.benjamin@gmail.com> |
|
|
|
// Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net> |
|
|
|
// |
|
|
|
// Lol Engine is free software. It comes without any warranty, to |
|
|
|
// the extent permitted by applicable law. You can redistribute it |
|
|
@@ -23,74 +22,69 @@ |
|
|
|
#include <cmath> |
|
|
|
#include <cstdio> |
|
|
|
#include <algorithm> |
|
|
|
#include <type_traits> |
|
|
|
|
|
|
|
#include <stdint.h> |
|
|
|
|
|
|
|
namespace lol |
|
|
|
{ |
|
|
|
|
|
|
|
/* This is OUR namespace. Don't let Windows headers mess with it. */ |
|
|
|
// This is OUR namespace. Don't let Windows headers mess with it. |
|
|
|
#undef min |
|
|
|
#undef max |
|
|
|
|
|
|
|
/* Standard cmath functions */ |
|
|
|
LOL_ATTR_NODISCARD static inline double sqrt(double const &x) { return std::sqrt(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float sqrt(float const &x) { return std::sqrt(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double cbrt(double const &x) { return std::cbrt(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float cbrt(float const &x) { return std::cbrt(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double exp(double const &x) { return std::exp(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float exp(float const &x) { return std::exp(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double sin(double const &x) { return std::sin(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double cos(double const &x) { return std::cos(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double tan(double const &x) { return std::tan(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float sin(float const &x) { return std::sin(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float cos(float const &x) { return std::cos(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float tan(float const &x) { return std::tan(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double asin(double const &x) { return std::asin(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double acos(double const &x) { return std::acos(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double atan(double const &x) { return std::atan(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float asin(float const &x) { return std::asin(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float acos(float const &x) { return std::acos(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline float atan(float const &x) { return std::atan(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double atan2(double const &y, double const &x) |
|
|
|
{ |
|
|
|
return std::atan2(y, x); |
|
|
|
} |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline float atan2(float const &y, float const &x) |
|
|
|
{ |
|
|
|
return std::atan2(y, x); |
|
|
|
} |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double pow(double const &x, double const &y) |
|
|
|
{ |
|
|
|
return std::pow(x, y); |
|
|
|
} |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline float pow(float const &x, float const &y) |
|
|
|
{ |
|
|
|
return std::pow(x, y); |
|
|
|
} |
|
|
|
|
|
|
|
/* Our extensions */ |
|
|
|
static inline void sincos(double const &x, double *s, double *c) |
|
|
|
{ |
|
|
|
*s = std::sin(x); |
|
|
|
*c = std::cos(x); |
|
|
|
} |
|
|
|
|
|
|
|
static inline void sincos(float const &x, float *s, float *c) |
|
|
|
// Macros for type traits |
|
|
|
#define LOL_T_ARITHMETIC typename std::enable_if<std::is_arithmetic<T>::value, T>::type |
|
|
|
#define LOL_T_SIGNED typename std::enable_if<std::is_signed<T>::value, T>::type |
|
|
|
#define LOL_T_UNSIGNED typename std::enable_if<std::is_arithmetic<T>::value && \ |
|
|
|
!std::is_signed<T>::value, T>::type |
|
|
|
#define LOL_T_INTEGRAL typename std::enable_if<std::is_integral<T>::value, T>::type |
|
|
|
#define LOL_T_FLOATING_POINT typename std::enable_if<std::is_floating_point<T>::value, T>::type |
|
|
|
|
|
|
|
// Mechanism to import standard cmath functions |
|
|
|
#define LOL_FORWARD_FP_1_ARG(f) \ |
|
|
|
template<typename T, typename T2 = T, typename DUMMY = LOL_T_FLOATING_POINT> \ |
|
|
|
LOL_ATTR_NODISCARD static inline T2 f(T x) { return std::f(x); } |
|
|
|
|
|
|
|
#define LOL_FORWARD_ARITH_2_ARGS(f) \ |
|
|
|
template<typename T, typename T2 = T, typename DUMMY = LOL_T_ARITHMETIC> \ |
|
|
|
LOL_ATTR_NODISCARD static inline T2 f(T x, T y) { return std::f(x, y); } |
|
|
|
|
|
|
|
#define LOL_FORWARD_FP_2_ARGS(f) \ |
|
|
|
template<typename T, typename T2 = T, typename DUMMY = LOL_T_FLOATING_POINT> \ |
|
|
|
LOL_ATTR_NODISCARD static inline T2 f(T x, T y) { return std::f(x, y); } |
|
|
|
|
|
|
|
LOL_FORWARD_FP_1_ARG(sqrt) |
|
|
|
LOL_FORWARD_FP_1_ARG(cbrt) |
|
|
|
|
|
|
|
LOL_FORWARD_FP_1_ARG(exp) |
|
|
|
LOL_FORWARD_FP_2_ARGS(pow) |
|
|
|
|
|
|
|
LOL_FORWARD_FP_1_ARG(sin) |
|
|
|
LOL_FORWARD_FP_1_ARG(cos) |
|
|
|
LOL_FORWARD_FP_1_ARG(tan) |
|
|
|
LOL_FORWARD_FP_1_ARG(asin) |
|
|
|
LOL_FORWARD_FP_1_ARG(acos) |
|
|
|
LOL_FORWARD_FP_1_ARG(atan) |
|
|
|
LOL_FORWARD_FP_2_ARGS(atan2) |
|
|
|
|
|
|
|
LOL_FORWARD_ARITH_2_ARGS(min) |
|
|
|
LOL_FORWARD_ARITH_2_ARGS(max) |
|
|
|
|
|
|
|
LOL_FORWARD_FP_2_ARGS(fmod) |
|
|
|
LOL_FORWARD_FP_1_ARG(floor) |
|
|
|
LOL_FORWARD_FP_1_ARG(ceil) |
|
|
|
LOL_FORWARD_FP_1_ARG(round) |
|
|
|
|
|
|
|
// Our extensions |
|
|
|
template<typename T, typename T2 = LOL_T_FLOATING_POINT> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 sincos(T x, T *s, T *c) |
|
|
|
{ |
|
|
|
*s = std::sin(x); |
|
|
|
*c = std::cos(x); |
|
|
|
} |
|
|
|
|
|
|
|
/* Inherited from GLSL */ |
|
|
|
// Inherited from GLSL |
|
|
|
LOL_ATTR_NODISCARD static inline float degrees(float radians) |
|
|
|
{ |
|
|
|
return radians * (180.0f / F_PI); |
|
|
@@ -121,8 +115,8 @@ LOL_ATTR_NODISCARD static inline ldouble radians(ldouble degrees) |
|
|
|
return degrees * (LD_PI / 180.0L); |
|
|
|
} |
|
|
|
|
|
|
|
/* The integer versions return floating point values. This avoids nasty |
|
|
|
* surprises when calling radians(180) instead of radians(180.0). */ |
|
|
|
// The integer versions return floating point values. This avoids nasty |
|
|
|
// surprises when calling radians(180) instead of radians(180.0). |
|
|
|
LOL_ATTR_NODISCARD static inline float degrees(int8_t x) { return degrees(float(x)); } |
|
|
|
LOL_ATTR_NODISCARD static inline float degrees(uint8_t x) { return degrees(float(x)); } |
|
|
|
LOL_ATTR_NODISCARD static inline float degrees(int16_t x) { return degrees(float(x)); } |
|
|
@@ -141,144 +135,51 @@ LOL_ATTR_NODISCARD static inline double radians(uint32_t x) { return radians(do |
|
|
|
LOL_ATTR_NODISCARD static inline ldouble radians(int64_t x) { return radians(ldouble(x)); } |
|
|
|
LOL_ATTR_NODISCARD static inline ldouble radians(uint64_t x) { return radians(ldouble(x)); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline float mix(float const &a, float const &b, float const &x) |
|
|
|
{ |
|
|
|
return a + (b - a) * x; |
|
|
|
} |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double mix(double const &a, double const &b, double const &x) |
|
|
|
template<typename T, typename T2 = LOL_T_FLOATING_POINT> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 mix(T a, T b, T x) |
|
|
|
{ |
|
|
|
return a + (b - a) * x; |
|
|
|
} |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline ldouble mix(ldouble const &a, ldouble const &b, ldouble const &x) |
|
|
|
{ |
|
|
|
return a + (b - a) * x; |
|
|
|
} |
|
|
|
|
|
|
|
/* Inherited from HLSL */ |
|
|
|
LOL_ATTR_NODISCARD static inline float lerp(float const &a, float const &b, float const &x) |
|
|
|
{ |
|
|
|
return mix(a, b, x); |
|
|
|
} |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline double lerp(double const &a, double const &b, double const &x) |
|
|
|
{ |
|
|
|
return mix(a, b, x); |
|
|
|
} |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline ldouble lerp(ldouble const &a, ldouble const &b, ldouble const &x) |
|
|
|
// Inherited from HLSL |
|
|
|
template<typename T, typename T2 = LOL_T_FLOATING_POINT> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 lerp(T a, T b, T x) |
|
|
|
{ |
|
|
|
return mix(a, b, x); |
|
|
|
} |
|
|
|
|
|
|
|
/* C++ doesn't define abs() and fmod() for all types; we add these for |
|
|
|
* convenience to avoid adding complexity to vector.h. */ |
|
|
|
LOL_ATTR_NODISCARD static inline int8_t abs(int8_t x) { return std::abs(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline uint8_t abs(uint8_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int16_t abs(int16_t x) { return std::abs(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline uint16_t abs(uint16_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int32_t abs(int32_t x) { return std::abs(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline uint32_t abs(uint32_t x) { return x; } |
|
|
|
#if defined __ANDROID__ |
|
|
|
/* The Android toolchain doesn't provide abs() for int64_t. */ |
|
|
|
LOL_ATTR_NODISCARD static inline int64_t abs(int64_t x) { return x > 0 ? x : -x; } |
|
|
|
#else |
|
|
|
LOL_ATTR_NODISCARD static inline int64_t abs(int64_t x) { return std::abs(x); } |
|
|
|
#endif |
|
|
|
LOL_ATTR_NODISCARD static inline uint64_t abs(uint64_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline float abs(float x) { return std::abs(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double abs(double x) { return std::abs(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline ldouble abs(ldouble x) { return std::abs(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline uint8_t fmod(uint8_t x, uint8_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline int8_t fmod(int8_t x, int8_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint16_t fmod(uint16_t x, uint16_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline int16_t fmod(int16_t x, int16_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint32_t fmod(uint32_t x, uint32_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline int32_t fmod(int32_t x, int32_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint64_t fmod(uint64_t x, uint64_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline int64_t fmod(int64_t x, int64_t y) { return x % y; } |
|
|
|
LOL_ATTR_NODISCARD static inline float fmod(float x, float y) { return std::fmod(x, y); } |
|
|
|
LOL_ATTR_NODISCARD static inline double fmod(double x, double y) { return std::fmod(x, y); } |
|
|
|
LOL_ATTR_NODISCARD static inline ldouble fmod(ldouble x, ldouble y) { return std::fmod(x, y); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline uint8_t floor(uint8_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int8_t floor(int8_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint16_t floor(uint16_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int16_t floor(int16_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint32_t floor(uint32_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int32_t floor(int32_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint64_t floor(uint64_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int64_t floor(int64_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline float floor(float x) { return std::floor(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double floor(double x) { return std::floor(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline ldouble floor(ldouble x) { return std::floor(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline uint8_t ceil(uint8_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int8_t ceil(int8_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint16_t ceil(uint16_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int16_t ceil(int16_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint32_t ceil(uint32_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int32_t ceil(int32_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint64_t ceil(uint64_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int64_t ceil(int64_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline float ceil(float x) { return std::ceil(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double ceil(double x) { return std::ceil(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline ldouble ceil(ldouble x) { return std::ceil(x); } |
|
|
|
|
|
|
|
LOL_ATTR_NODISCARD static inline uint8_t round(uint8_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int8_t round(int8_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint16_t round(uint16_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int16_t round(int16_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint32_t round(uint32_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int32_t round(int32_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline uint64_t round(uint64_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline int64_t round(int64_t x) { return x; } |
|
|
|
LOL_ATTR_NODISCARD static inline float round(float x) { return std::round(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline double round(double x) { return std::round(x); } |
|
|
|
LOL_ATTR_NODISCARD static inline ldouble round(ldouble x) { return std::round(x); } |
|
|
|
|
|
|
|
#define LOL_GENERIC_FUNC(T) \ |
|
|
|
LOL_ATTR_NODISCARD static inline T sq(T x) { return x * x; } \ |
|
|
|
LOL_ATTR_NODISCARD static inline T fract(T x) { return x - lol::floor(x); } \ |
|
|
|
LOL_ATTR_NODISCARD static inline T min(T x, T y) { return std::min(x, y); } \ |
|
|
|
LOL_ATTR_NODISCARD static inline T max(T x, T y) { return std::max(x, y); } \ |
|
|
|
LOL_ATTR_NODISCARD static inline T clamp(T x, T y, T z) { return min(max(x, y), z); } \ |
|
|
|
LOL_ATTR_NODISCARD static inline T saturate(T x) { return min(max(x, (T)0), (T)1); } \ |
|
|
|
LOL_ATTR_NODISCARD static inline T gcd(T x, T y) { return y == (T)0 ? lol::abs(x) : lol::gcd(y, lol::fmod(x, y)); } |
|
|
|
|
|
|
|
#define LOL_GENERIC_FUNC_SIGNED(T) \ |
|
|
|
LOL_GENERIC_FUNC(T) \ |
|
|
|
LOL_ATTR_NODISCARD static inline T sign(T x) { return (T)(((T)0 < x) - (x < (T)0)); } |
|
|
|
|
|
|
|
#define LOL_GENERIC_FUNC_UNSIGNED(T) \ |
|
|
|
LOL_GENERIC_FUNC(T) \ |
|
|
|
LOL_ATTR_NODISCARD static inline T sign(T x) { return (T)((T)0 < x); } |
|
|
|
|
|
|
|
LOL_GENERIC_FUNC_UNSIGNED(uint8_t) |
|
|
|
LOL_GENERIC_FUNC_SIGNED(int8_t) |
|
|
|
LOL_GENERIC_FUNC_UNSIGNED(uint16_t) |
|
|
|
LOL_GENERIC_FUNC_SIGNED(int16_t) |
|
|
|
LOL_GENERIC_FUNC_UNSIGNED(uint32_t) |
|
|
|
LOL_GENERIC_FUNC_SIGNED(int32_t) |
|
|
|
LOL_GENERIC_FUNC_UNSIGNED(uint64_t) |
|
|
|
LOL_GENERIC_FUNC_SIGNED(int64_t) |
|
|
|
LOL_GENERIC_FUNC_SIGNED(float) |
|
|
|
LOL_GENERIC_FUNC_SIGNED(double) |
|
|
|
LOL_GENERIC_FUNC_SIGNED(ldouble) |
|
|
|
#undef LOL_GENERIC_FUNC |
|
|
|
|
|
|
|
/* Some additional implementations when ptrdiff_t != int */ |
|
|
|
#define LOL_T_PTRDIFF_T \ |
|
|
|
typename std::enable_if<!std::is_same<ptrdiff_t, int>::value \ |
|
|
|
&& std::is_same<T, ptrdiff_t>::value, T>::type |
|
|
|
template<typename T, typename T2 = LOL_T_PTRDIFF_T> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 max(T x, T y) { return std::max(x, y); } |
|
|
|
|
|
|
|
template<typename T, typename T2 = LOL_T_PTRDIFF_T> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 min(T x, T y) { return std::min(x, y); } |
|
|
|
#undef LOL_T_PTRDIFF_T |
|
|
|
// C++ doesn't define abs() or fmod() for all types; we add these for |
|
|
|
// convenience to avoid adding complexity to vector.h. |
|
|
|
template<typename T, typename T2 = LOL_T_SIGNED> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 abs(T x) { return std::abs(x); } |
|
|
|
template<typename T, typename T2 = T, typename DUMMY = LOL_T_UNSIGNED> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 abs(T x) { return x; } |
|
|
|
|
|
|
|
template<typename T, typename T2 = LOL_T_INTEGRAL> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 fmod(T x, T y) { return x % y; } |
|
|
|
template<typename T, typename T2 = LOL_T_INTEGRAL> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 floor(T x) { return x; } |
|
|
|
template<typename T, typename T2 = LOL_T_INTEGRAL> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 ceil(T x) { return x; } |
|
|
|
template<typename T, typename T2 = LOL_T_INTEGRAL> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 round(T x) { return x; } |
|
|
|
|
|
|
|
template<typename T, typename T2 = LOL_T_ARITHMETIC> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 sq(T x) { return x * x; } |
|
|
|
template<typename T, typename T2 = LOL_T_ARITHMETIC> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 fract(T x) { return x - lol::floor(x); } |
|
|
|
|
|
|
|
template<typename T, typename T2 = LOL_T_ARITHMETIC> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 clamp(T x, T y, T z) { return min(max(x, y), z); } |
|
|
|
template<typename T, typename T2 = LOL_T_ARITHMETIC> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 saturate(T x) { return clamp(x, (T)0, (T)1); } |
|
|
|
template<typename T, typename T2 = LOL_T_ARITHMETIC> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 gcd(T x, T y) { return y == (T)0 ? lol::abs(x) : lol::gcd(y, lol::fmod(x, y)); } |
|
|
|
|
|
|
|
template<typename T, typename T2 = LOL_T_SIGNED> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 sign(T x) { return (T)(((T)0 < x) - (x < (T)0)); } |
|
|
|
template<typename T, typename T2 = T, typename DUMMY = LOL_T_UNSIGNED> |
|
|
|
LOL_ATTR_NODISCARD static inline T2 sign(T x) { return (T)((T)0 < x); } |
|
|
|
|
|
|
|
} /* namespace lol */ |
|
|
|
|