#ifndef Magnum_Color_h #define Magnum_Color_h /* Copyright © 2010, 2011, 2012 Vladimír Vondruš This file is part of Magnum. Magnum is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 only, as published by the Free Software Foundation. Magnum is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License version 3 for more details. */ /** @file * @brief Class Magnum::Color3, Magnum::Color4 */ #include #include "Math/MathTypeTraits.h" #include "Math/Math.h" #include "Math/Vector4.h" namespace Magnum { template class Color3; #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { /* Convert color from HSV */ template inline typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { T hue, saturation, value; std::tie(hue, saturation, value) = hsv; /* Remove repeats */ hue -= int(hue/T(360))*T(360); if(hue < T(0)) hue += T(360); int h = int(hue/T(60)) % 6; T f = hue/T(60) - h; T p = value * (T(1) - saturation); T q = value * (T(1) - f*saturation); T t = value * (T(1) - (T(1) - f)*saturation); switch(h) { case 0: return {value, t, p}; case 1: return {q, value, p}; case 2: return {p, value, t}; case 3: return {p, q, value}; case 4: return {t, p, value}; case 5: return {value, p, q}; default: CORRADE_ASSERT(false, "It shouldn't get here.", {}); } } template inline typename std::enable_if::value, Color3>::type fromHSV(typename Color3::HSV hsv) { return Color3::fromNormalized(fromHSV::FloatingPointType>(hsv)); } /* Internal hue computing function */ template T hue(const Color3& color, T max, T delta) { T deltaInv60 = T(60)/delta; T hue(0); if(delta != T(0)) { if(max == color.r()) hue = (color.g()-color.b())*deltaInv60 + (color.g() < color.b() ? T(360) : T(0)); else if(max == color.g()) hue = (color.b()-color.r())*deltaInv60 + T(120); else /* max == color.b() */ hue = (color.r()-color.g())*deltaInv60 + T(240); } return hue; } /* Hue, saturation, value for floating-point types */ template inline T hue(typename std::enable_if::value, const Color3&>::type color) { T max = color.max(); T delta = max - color.min(); return hue(color, max, delta); } template inline T saturation(typename std::enable_if::value, const Color3&>::type color) { T max = color.max(); T delta = max - color.min(); return max != T(0) ? delta/max : T(0); } template inline T value(typename std::enable_if::value, const Color3&>::type color) { return color.max(); } /* Hue, saturation, value for integral types */ template inline typename Color3::FloatingPointType hue(typename std::enable_if::value, const Color3&>::type color) { return hue::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); } template inline typename Color3::FloatingPointType saturation(typename std::enable_if::value, const Color3&>::type& color) { return saturation::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); } template inline typename Color3::FloatingPointType value(typename std::enable_if::value, const Color3&>::type color) { return Math::normalize::FloatingPointType>(color.max()); } /* Convert color to HSV */ template inline typename Color3::HSV toHSV(typename std::enable_if::value, const Color3&>::type color) { T max = color.max(); T delta = max - color.min(); return typename Color3::HSV(hue::FloatingPointType>(color, max, delta), max != T(0) ? delta/max : T(0), max); } template inline typename Color3::HSV toHSV(typename std::enable_if::value, const Color3&>::type color) { return toHSV::FloatingPointType>(Color3::FloatingPointType>::fromDenormalized(color)); } /* Default alpha value */ template inline constexpr typename std::enable_if::value, T>::type defaultAlpha() { return T(1); } template inline constexpr typename std::enable_if::value, T>::type defaultAlpha() { return std::numeric_limits::max(); } } #endif /** @brief Three-component (RGB) color The class can store both floating-point (normalized) and integral (denormalized) representation of color. You can convert between these two representations using fromNormalized() and fromDenormalized(). Conversion from and to HSV is done always using floating-point types, so hue is always in range in range @f$ [0.0, 360.0] @f$, saturation and value in range @f$ [0.0, 1.0] @f$. @see Color4 @todo Signed normalization to [-1.0, 1.0] like in OpenGL? */ template class Color3: public Math::Vector3 { public: /** @brief Corresponding floating-point type for HSV computation */ typedef typename Math::MathTypeTraits::FloatingPointType FloatingPointType; /** * @brief Type for storing HSV values * * Hue in range @f$ [0.0, 360.0] @f$, saturation and value in * range @f$ [0.0, 1.0] @f$. */ typedef std::tuple HSV; /** * @brief Create integral color from floating-point color * * E.g. `{0.294118, 0.45098, 0.878431}` is converted to * `{75, 115, 224}`, if resulting type is `unsigned char`. * * @note This function is enabled only if source type is floating-point * and destination type is integral. */ template inline constexpr static typename std::enable_if::value && std::is_floating_point::value, Color3>::type fromNormalized(const Color3& color) { return Color3(Math::denormalize(color.r()), Math::denormalize(color.g()), Math::denormalize(color.b())); } /** * @brief Create floating-point color from integral color * * E.g. `{75, 115, 224}` is converted to * `{0.294118, 0.45098, 0.878431}`, if source type is `unsigned char`. * * @note This function is enabled only if source type is integral * and destination type is floating-point. */ template inline constexpr static typename std::enable_if::value && std::is_integral::value, Color3>::type fromDenormalized(const Color3& color) { return Color3(Math::normalize(color.r()), Math::normalize(color.g()), Math::normalize(color.b())); } /** * @brief Create RGB color from HSV representation * @param hsv Hue, saturation and value * * Hue can overflow the range @f$ [0.0, 360.0] @f$. */ inline constexpr static Color3 fromHSV(HSV hsv) { return Implementation::fromHSV(hsv); } /** @overload */ inline constexpr static Color3 fromHSV(FloatingPointType hue, FloatingPointType saturation, FloatingPointType value) { return fromHSV(std::make_tuple(hue, saturation, value)); } /** * @brief Default constructor * * All components are set to zero. */ inline constexpr Color3() {} /** * @brief Gray constructor * @param rgb RGB value */ inline constexpr explicit Color3(T rgb): Math::Vector3(rgb) {} /** @brief Copy constructor */ inline constexpr Color3(const Math::RectangularMatrix<1, 3, T>& other): Math::Vector3(other) {} /** * @brief Constructor * @param r R value * @param g G value * @param b B value */ inline constexpr Color3(T r, T g, T b): Math::Vector3(r, g, b) {} inline constexpr T r() const { return Math::Vector3::x(); } /**< @brief R component */ inline constexpr T g() const { return Math::Vector3::y(); } /**< @brief G component */ inline constexpr T b() const { return Math::Vector3::z(); } /**< @brief B component */ inline void setR(T value) { Math::Vector3::setX(value); } /**< @brief Set R component */ inline void setG(T value) { Math::Vector3::setY(value); } /**< @brief Set G component */ inline void setB(T value) { Math::Vector3::setZ(value); } /**< @brief Set B component */ /** * @brief Convert to HSV * * Example usage: * @code * T hue, saturation, value; * std::tie(hue, saturation, value) = color.toHSV(); * @endcode * * @see hue(), saturation(), value(), fromHSV() */ inline constexpr HSV toHSV() const { return Implementation::toHSV(*this); } /** * @brief Hue * @return Hue in range @f$ [0.0, 360.0] @f$. * * @see saturation(), value(), toHSV(), fromHSV() */ inline constexpr FloatingPointType hue() const { return Implementation::hue(*this); } /** * @brief Saturation * @return Saturation in range @f$ [0.0, 1.0] @f$. * * @see hue(), value(), toHSV(), fromHSV() */ inline constexpr FloatingPointType saturation() const { return Implementation::saturation(*this); } /** * @brief Value * @return Value in range @f$ [0.0, 1.0] @f$. * * @see hue(), saturation(), toHSV(), fromHSV() */ inline constexpr FloatingPointType value() const { return Implementation::value(*this); } }; /** @brief Four-component (RGBA) color See Color3 for more information. */ template class Color4: public Math::Vector4 { public: /** @copydoc Color3::FloatingPointType */ typedef typename Color3::FloatingPointType FloatingPointType; /** @copydoc Color3::HSV */ typedef typename Color3::HSV HSV; /** @copydoc Color3::fromNormalized() */ template inline constexpr static typename std::enable_if::value && std::is_floating_point::value, Color4>::type fromNormalized(const Color4& color) { return Color4(Math::denormalize(color.r()), Math::denormalize(color.g()), Math::denormalize(color.b()), Math::denormalize(color.a())); } /** @copydoc Color3::fromDenormalized() */ template inline constexpr static typename std::enable_if::value && std::is_integral::value, Color4>::type fromDenormalized(const Color4& color) { return Color4(Math::normalize(color.r()), Math::normalize(color.g()), Math::normalize(color.b()), Math::normalize(color.a())); } /** * @copydoc Color3::fromHSV() * @param a Alpha value, defaults to 1.0 for floating-point types * and maximum positive value for integral types. */ inline constexpr static Color4 fromHSV(HSV hsv, T a = Implementation::defaultAlpha()) { return Color4(Implementation::fromHSV(hsv), a); } /** @overload */ inline constexpr static Color4 fromHSV(FloatingPointType hue, FloatingPointType saturation, FloatingPointType value, T alpha) { return fromHSV(std::make_tuple(hue, saturation, value), alpha); } /** * @brief Default constructor * * RGB components are set to zero, A component is set to 1.0 for * floating-point types and maximum positive value for integral types. */ inline constexpr Color4(): Math::Vector4(T(0), T(0), T(0), Implementation::defaultAlpha()) {} /** * @copydoc Color3::Color3(T) * @param alpha Alpha value, defaults to 1.0 for floating-point types * and maximum positive value for integral types. */ inline constexpr explicit Color4(T rgb, T alpha = Implementation::defaultAlpha()): Math::Vector4(rgb, rgb, rgb, alpha) {} /** @brief Copy constructor */ inline constexpr Color4(const Math::RectangularMatrix<1, 4, T>& other): Math::Vector4(other) {} /** * @brief Constructor * @param r R value * @param g G value * @param b B value * @param a A value, defaults to 1.0 for floating-point types and * maximum positive value for integral types. */ inline constexpr Color4(T r, T g, T b, T a = Implementation::defaultAlpha()): Math::Vector4(r, g, b, a) {} /** * @brief Constructor * @param rgb Three-component color * @param a A value */ /* Not marked as explicit, because conversion from Color3 to Color4 is fairly common, nearly always with A set to 1 */ inline constexpr Color4(const Math::Vector<3, T>& rgb, T a = Implementation::defaultAlpha()): Math::Vector4(rgb[0], rgb[1], rgb[2], a) {} inline constexpr T r() const { return Math::Vector4::x(); } /**< @brief R component */ inline constexpr T g() const { return Math::Vector4::y(); } /**< @brief G component */ inline constexpr T b() const { return Math::Vector4::z(); } /**< @brief B component */ inline constexpr T a() const { return Math::Vector4::w(); } /**< @brief A component */ inline void setR(T value) { Math::Vector4::setX(value); } /**< @brief Set R component */ inline void setG(T value) { Math::Vector4::setY(value); } /**< @brief Set G component */ inline void setB(T value) { Math::Vector4::setZ(value); } /**< @brief Set B component */ inline void setA(T value) { Math::Vector4::setW(value); } /**< @brief Set A component */ /** * @brief RGB part of the vector * @return First three components of the vector * * @see swizzle() */ inline constexpr Color3 rgb() const { return Math::Vector4::xyz(); } /** @copydoc Color3::toHSV() */ inline constexpr HSV toHSV() const { return Implementation::toHSV(rgb()); } /** @copydoc Color3::hue() */ inline constexpr FloatingPointType hue() const { return Implementation::hue(rgb()); } /** @copydoc Color3::saturation() */ inline constexpr FloatingPointType saturation() const { return Implementation::saturation(rgb()); } /** @copydoc Color3::value() */ inline constexpr FloatingPointType value() const { return Implementation::value(rgb()); } }; /** @debugoperator{Magnum::Color3} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3& value) { return debug << static_cast&>(value); } /** @debugoperator{Magnum::Color4} */ template Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color4& value) { return debug << static_cast&>(value); } } namespace Corrade { namespace Utility { /** @configurationvalue{Magnum::Color3} */ template struct ConfigurationValue>: public ConfigurationValue> {}; /** @configurationvalue{Magnum::Color4} */ template struct ConfigurationValue>: public ConfigurationValue> {}; }} #endif