| @@ -26,7 +26,10 @@ namespace lol | |||||
| #undef min | #undef min | ||||
| #undef max | #undef max | ||||
| namespace half_ops { struct base {}; } | |||||
| class half | class half | ||||
| : half_ops::base | |||||
| { | { | ||||
| public: | public: | ||||
| /* Constructors. Always inline so that the code can work in registers | /* Constructors. Always inline so that the code can work in registers | ||||
| @@ -118,6 +121,10 @@ public: | |||||
| static_assert(sizeof(half) == 2, "sizeof(half) == 2"); | 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 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 half max(half a, half b) { return a > b ? a : b; } | ||||
| static inline float fmod(half a, half 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; | 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<typename T> static inline \ | |||||
| typename std::enable_if<std::is_integral<T>::value,half>::type \ | |||||
| operator op(T x, half h) { return (half)(int)x op h; } \ | |||||
| \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_integral<T>::value,T&>::type \ | |||||
| operator op##=(T &x, half h) { return x = x op h; } \ | |||||
| \ | |||||
| /* half + integral */ \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_integral<T>::value,half>::type \ | |||||
| operator op(half h, T x) { return h op (half)(int)x; } \ | |||||
| \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_integral<T>::value,half&>::type \ | |||||
| operator op##=(half &h, T x) { return h = h op x; } \ | |||||
| \ | |||||
| /* floating point + half */ \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_floating_point<T>::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<typename T> static inline \ | |||||
| typename std::enable_if<std::is_floating_point<T>::value,T&>::type \ | |||||
| operator op##=(T &x, half h) { return x = x op h; } \ | |||||
| \ | |||||
| /* half + floating point */ \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_floating_point<T>::value,T>::type \ | |||||
| operator op(half h, T x) { return (T)h op x; } \ | |||||
| \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_floating_point<T>::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<typename T> static inline \ | |||||
| typename std::enable_if<std::is_integral<T>::value,bool>::type \ | |||||
| operator op(T x, half h) { return (half)(int)x op h; } \ | |||||
| \ | |||||
| /* half == integral */ \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_integral<T>::value,bool>::type \ | |||||
| operator op(half h, T x) { return h op (half)(int)x; } \ | |||||
| \ | |||||
| /* floating point == half */ \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_floating_point<T>::value,bool>::type \ | |||||
| operator op(T x, half h) { return x op (T)h; } \ | |||||
| \ | |||||
| /* half == floating point */ \ | |||||
| template<typename T> static inline \ | |||||
| typename std::enable_if<std::is_floating_point<T>::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 */ | } /* namespace lol */ | ||||