| @@ -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<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 */ | |||