diff --git a/src/lol/math/half.h b/src/lol/math/half.h index 65a46eec..17d9699e 100644 --- a/src/lol/math/half.h +++ b/src/lol/math/half.h @@ -26,7 +26,10 @@ namespace lol #undef min #undef max +namespace half_ops { struct base {}; } + class half + : half_ops::base { public: /* Constructors. Always inline so that the code can work in registers @@ -118,6 +121,10 @@ public: static_assert(sizeof(half) == 2, "sizeof(half) == 2"); +/* + * Standard math and GLSL functions + */ + static inline half min(half a, half b) { return a < b ? a : b; } static inline half max(half a, half b) { return a > b ? a : b; } static inline float fmod(half a, half b) @@ -135,51 +142,88 @@ static inline half clamp(half x, half a, half b) return (x < a) ? a : (x > b) ? b : x; } +/* + * Standard math operators + */ -#define DECLARE_COERCE_HALF_NUMERIC_OPS(op, type, ret, x2, h2) \ - inline ret operator op(type x, half h) { return x2 op h2; } \ - inline ret operator op(half h, type x) { return h2 op x2; } \ - inline type &operator op##=(type &x, half h) { return x = x op h2; } \ - inline half &operator op##=(half &h, type x) { return h = h op x2; } - -#define DECLARE_COERCE_HALF_BOOL_OPS(op, type, x2, h2) \ - inline bool operator op(type x, half h) { return x2 op h2; } \ - inline bool operator op(half h, type x) { return h2 op x2; } +namespace half_ops +{ -#define DECLARE_COERCE_HALF_OPS(type, ret, x2, h2) \ - DECLARE_COERCE_HALF_NUMERIC_OPS(+, type, ret, x2, h2) \ - DECLARE_COERCE_HALF_NUMERIC_OPS(-, type, ret, x2, h2) \ - DECLARE_COERCE_HALF_NUMERIC_OPS(*, type, ret, x2, h2) \ - DECLARE_COERCE_HALF_NUMERIC_OPS(/, type, ret, x2, h2) \ +#define DECLARE_HALF_NUMERIC_OPS(op) \ + /* integral + half */ \ + template static inline \ + typename std::enable_if::value,half>::type \ + operator op(T x, half h) { return (half)(int)x op h; } \ + \ + template static inline \ + typename std::enable_if::value,T&>::type \ + operator op##=(T &x, half h) { return x = x op h; } \ + \ + /* half + integral */ \ + template static inline \ + typename std::enable_if::value,half>::type \ + operator op(half h, T x) { return h op (half)(int)x; } \ + \ + template static inline \ + typename std::enable_if::value,half&>::type \ + operator op##=(half &h, T x) { return h = h op x; } \ + \ + /* floating point + half */ \ + template static inline \ + typename std::enable_if::value,T>::type \ + operator op(T x, half h) { return x op (T)h; } \ \ - DECLARE_COERCE_HALF_BOOL_OPS(==, type, x2, h2) \ - DECLARE_COERCE_HALF_BOOL_OPS(!=, type, x2, h2) \ - DECLARE_COERCE_HALF_BOOL_OPS(>=, type, x2, h2) \ - DECLARE_COERCE_HALF_BOOL_OPS(<=, type, x2, h2) \ - DECLARE_COERCE_HALF_BOOL_OPS(>, type, x2, h2) \ - DECLARE_COERCE_HALF_BOOL_OPS(<, type, x2, h2) - -#define DECLARE_COERCE_TO_HALF_OPS(type) \ - DECLARE_COERCE_HALF_OPS(type, half, (half)(int)x, h) - -#define DECLARE_COERCE_FROM_HALF_OPS(type) \ - DECLARE_COERCE_HALF_OPS(type, type, x, (type)h) - -/* Only provide coercion rules above int32_t, since the standard says - * all smaller base types are coerced to int. */ -DECLARE_COERCE_TO_HALF_OPS(int32_t) -DECLARE_COERCE_TO_HALF_OPS(uint32_t) -DECLARE_COERCE_TO_HALF_OPS(int64_t) -DECLARE_COERCE_TO_HALF_OPS(uint64_t) - -DECLARE_COERCE_FROM_HALF_OPS(float) -DECLARE_COERCE_FROM_HALF_OPS(double) -DECLARE_COERCE_FROM_HALF_OPS(ldouble) - -#undef DECLARE_COERCE_HALF_NUMERIC_OPS -#undef DECLARE_COERCE_HALF_OPS -#undef DECLARE_COERCE_TO_HALF_OPS -#undef DECLARE_COERCE_FROM_HALF_OPS + template static inline \ + typename std::enable_if::value,T&>::type \ + operator op##=(T &x, half h) { return x = x op h; } \ + \ + /* half + floating point */ \ + template static inline \ + typename std::enable_if::value,T>::type \ + operator op(half h, T x) { return (T)h op x; } \ + \ + template static inline \ + typename std::enable_if::value,half&>::type \ + operator op##=(half &h, T x) { return h = h op x; } + +DECLARE_HALF_NUMERIC_OPS(+) +DECLARE_HALF_NUMERIC_OPS(-) +DECLARE_HALF_NUMERIC_OPS(*) +DECLARE_HALF_NUMERIC_OPS(/) + +#undef DECLARE_HALF_NUMERIC_OPS + +#define DECLARE_HALF_BOOL_OPS(op) \ + /* integral == half */ \ + template static inline \ + typename std::enable_if::value,bool>::type \ + operator op(T x, half h) { return (half)(int)x op h; } \ + \ + /* half == integral */ \ + template static inline \ + typename std::enable_if::value,bool>::type \ + operator op(half h, T x) { return h op (half)(int)x; } \ + \ + /* floating point == half */ \ + template static inline \ + typename std::enable_if::value,bool>::type \ + operator op(T x, half h) { return x op (T)h; } \ + \ + /* half == floating point */ \ + template static inline \ + typename std::enable_if::value,bool>::type \ + operator op(half h, T x) { return (T)h op x; } + +DECLARE_HALF_BOOL_OPS(==) +DECLARE_HALF_BOOL_OPS(!=) +DECLARE_HALF_BOOL_OPS(>) +DECLARE_HALF_BOOL_OPS(<) +DECLARE_HALF_BOOL_OPS(>=) +DECLARE_HALF_BOOL_OPS(<=) + +#undef DECLARE_HALF_BOOL_OPS + +} /* namespace half_ops */ } /* namespace lol */