Browse Source

Added Color3 and Color4 classes with HSV conversion.

They can be used for both floating-point (normalized) and integral
(denormalized) representation and support conversion between them.

HSV conversion is done always using floating-point types.

Getters for RGB(A) were removed from Vector3 and Vector4, they are now
part of Color3 and Color4. Because of this, Framebuffer now accepts
Color instead of Vector.
pull/279/head
Vladimír Vondruš 14 years ago
parent
commit
c8aa005e86
  1. 3
      src/AbstractTexture.h
  2. 1
      src/CMakeLists.txt
  3. 409
      src/Color.h
  4. 3
      src/Framebuffer.h
  5. 16
      src/Math/Vector3.h
  6. 30
      src/Math/Vector4.h
  7. 2
      src/Test/CMakeLists.txt
  8. 121
      src/Test/ColorTest.cpp
  9. 44
      src/Test/ColorTest.h

3
src/AbstractTexture.h

@ -20,6 +20,7 @@
*/
#include "Magnum.h"
#include "Color.h"
namespace Magnum {
@ -611,7 +612,7 @@ class MAGNUM_EXPORT AbstractTexture {
* to `ClampToBorder`.
* @requires_gl
*/
inline void setBorderColor(const Vector4& color) {
inline void setBorderColor(const Color4& color) {
bind();
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, color.data());
}

1
src/CMakeLists.txt

@ -40,6 +40,7 @@ set(Magnum_HEADERS
BufferedTexture.h
Buffer.h
Camera.h
Color.h
CubeMapTextureArray.h
CubeMapTexture.h
Framebuffer.h

409
src/Color.h

@ -0,0 +1,409 @@
#ifndef Magnum_Color_h
#define Magnum_Color_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
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 <tuple>
#include "Math/MathTypeTraits.h"
#include "Math/Math.h"
#include "Math/Vector4.h"
namespace Magnum {
template<class T> class Color3;
#ifndef DOXYGEN_GENERATING_OUTPUT
namespace Implementation {
/* Convert color from HSV */
template<class T> inline typename std::enable_if<std::is_floating_point<T>::value, Color3<T>>::type fromHSV(typename Color3<T>::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<class T> inline typename std::enable_if<std::is_integral<T>::value, Color3<T>>::type fromHSV(typename Color3<T>::HSV hsv) {
return Color3<T>::fromNormalized(fromHSV<typename Color3<T>::FloatingPointType>(hsv));
}
/* Internal hue computing function */
template<class T> T hue(const Color3<T>& 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<class T> inline T hue(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return hue(color, max, delta);
}
template<class T> inline T saturation(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return max != T(0) ? delta/max : T(0);
}
template<class T> inline T value(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
return color.max();
}
/* Hue, saturation, value for integral types */
template<class T> inline typename Color3<T>::FloatingPointType hue(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return hue<typename Color3<T>::FloatingPointType>(Color3<typename Color3<T>::FloatingPointType>::fromDenormalized(color));
}
template<class T> inline typename Color3<T>::FloatingPointType saturation(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type& color) {
return saturation<typename Color3<T>::FloatingPointType>(Color3<typename Color3<T>::FloatingPointType>::fromDenormalized(color));
}
template<class T> inline typename Color3<T>::FloatingPointType value(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return Math::normalize<typename Color3<T>::FloatingPointType>(color.max());
}
/* Convert color to HSV */
template<class T> inline typename Color3<T>::HSV toHSV(typename std::enable_if<std::is_floating_point<T>::value, const Color3<T>&>::type color) {
T max = color.max();
T delta = max - color.min();
return typename Color3<T>::HSV(hue<typename Color3<T>::FloatingPointType>(color, max, delta), max != T(0) ? delta/max : T(0), max);
}
template<class T> inline typename Color3<T>::HSV toHSV(typename std::enable_if<std::is_integral<T>::value, const Color3<T>&>::type color) {
return toHSV<typename Color3<T>::FloatingPointType>(Color3<typename Color3<T>::FloatingPointType>::fromDenormalized(color));
}
/* Default alpha value */
template<class T> inline constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type defaultAlpha() {
return T(1);
}
template<class T> inline constexpr typename std::enable_if<std::is_integral<T>::value, T>::type defaultAlpha() {
return std::numeric_limits<T>::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
*/
template<class T> class Color3: public Math::Vector3<T> {
public:
/** @brief Corresponding floating-point type for HSV computation */
typedef typename Math::MathTypeTraits<T>::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<FloatingPointType, FloatingPointType, FloatingPointType> 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<class U> inline constexpr static typename std::enable_if<std::is_integral<T>::value && std::is_floating_point<U>::value, Color3<T>>::type fromNormalized(const Color3<U>& color) {
return Color3<T>(Math::denormalize<T>(color.r()),
Math::denormalize<T>(color.g()),
Math::denormalize<T>(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<class U> inline constexpr static typename std::enable_if<std::is_floating_point<T>::value && std::is_integral<U>::value, Color3<T>>::type fromDenormalized(const Color3<U>& color) {
return Color3<T>(Math::normalize<T>(color.r()),
Math::normalize<T>(color.g()),
Math::normalize<T>(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<T> fromHSV(HSV hsv) {
return Implementation::fromHSV<T>(hsv);
}
/** @overload */
inline constexpr static Color3<T> 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<T>(rgb) {}
/** @copydoc Math::Vector::Vector(const Vector&) */
inline constexpr Color3(const Math::Vector<3, T>& other): Math::Vector3<T>(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<T>(r, g, b) {}
inline constexpr T r() const { return Math::Vector3<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector3<T>::y(); } /**< @brief G component */
inline constexpr T b() const { return Math::Vector3<T>::z(); } /**< @brief B component */
inline void setR(T value) { Math::Vector3<T>::setX(value); } /**< @brief Set R component */
inline void setG(T value) { Math::Vector3<T>::setY(value); } /**< @brief Set G component */
inline void setB(T value) { Math::Vector3<T>::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<T>(*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<T>(*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<T>(*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<T>(*this);
}
};
/**
@brief Four-component (RGBA) color
See Color3 for more information.
*/
template<class T> class Color4: public Math::Vector4<T> {
public:
/** @copydoc Color3::FloatingPointType */
typedef typename Color3<T>::FloatingPointType FloatingPointType;
/** @copydoc Color3::HSV */
typedef typename Color3<T>::HSV HSV;
/** @copydoc Color3::fromNormalized() */
template<class U> inline constexpr static typename std::enable_if<std::is_integral<T>::value && std::is_floating_point<U>::value, Color4<T>>::type fromNormalized(const Color4<U>& color) {
return Color4<T>(Math::denormalize<T>(color.r()),
Math::denormalize<T>(color.g()),
Math::denormalize<T>(color.b()),
Math::denormalize<T>(color.a()));
}
/** @copydoc Color3::fromDenormalized() */
template<class U> inline constexpr static typename std::enable_if<std::is_floating_point<T>::value && std::is_integral<U>::value, Color4<T>>::type fromDenormalized(const Color4<U>& color) {
return Color4<T>(Math::normalize<T>(color.r()),
Math::normalize<T>(color.g()),
Math::normalize<T>(color.b()),
Math::normalize<T>(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<T> fromHSV(HSV hsv, T a = Implementation::defaultAlpha<T>()) {
return Color4<T>(Implementation::fromHSV<T>(hsv), a);
}
/** @overload */
inline constexpr static Color4<T> 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>(T(0), T(0), T(0), Implementation::defaultAlpha<T>()) {}
/**
* @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<T>()): Math::Vector4<T>(rgb, rgb, rgb, alpha) {}
/** @copydoc Math::Vector::Vector(const Vector&) */
inline constexpr Color4(const Math::Vector<4, T>& other): Math::Vector4<T>(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<T>()): Math::Vector4<T>(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<T>()): Math::Vector4<T>(rgb[0], rgb[1], rgb[2], a) {}
inline constexpr T r() const { return Math::Vector4<T>::x(); } /**< @brief R component */
inline constexpr T g() const { return Math::Vector4<T>::y(); } /**< @brief G component */
inline constexpr T b() const { return Math::Vector4<T>::z(); } /**< @brief B component */
inline constexpr T a() const { return Math::Vector4<T>::w(); } /**< @brief A component */
inline void setR(T value) { Math::Vector4<T>::setX(value); } /**< @brief Set R component */
inline void setG(T value) { Math::Vector4<T>::setY(value); } /**< @brief Set G component */
inline void setB(T value) { Math::Vector4<T>::setZ(value); } /**< @brief Set B component */
inline void setA(T value) { Math::Vector4<T>::setW(value); } /**< @brief Set A component */
/**
* @brief RGB part of the vector
* @return First three components of the vector
*
* @see swizzle()
*/
inline constexpr Color3<T> rgb() const { return Math::Vector4<T>::xyz(); }
/** @copydoc Color3::toHSV() */
inline constexpr HSV toHSV() const {
return Implementation::toHSV<T>(rgb());
}
/** @copydoc Color3::hue() */
inline constexpr FloatingPointType hue() const {
return Implementation::hue<T>(rgb());
}
/** @copydoc Color3::saturation() */
inline constexpr FloatingPointType saturation() const {
return Implementation::saturation<T>(rgb());
}
/** @copydoc Color3::value() */
inline constexpr FloatingPointType value() const {
return Implementation::value<T>(rgb());
}
};
/** @debugoperator{Color3} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color3<T>& value) {
return debug << static_cast<const Magnum::Math::Vector3<T>&>(value);
}
/** @debugoperator{Color4} */
template<class T> Corrade::Utility::Debug operator<<(Corrade::Utility::Debug debug, const Magnum::Color4<T>& value) {
return debug << static_cast<const Magnum::Math::Vector4<T>&>(value);
}
}
#endif

3
src/Framebuffer.h

@ -23,6 +23,7 @@
#include "BufferedImage.h"
#include "CubeMapTexture.h"
#include "Color.h"
#include "Image.h"
#include "Renderbuffer.h"
@ -192,7 +193,7 @@ class MAGNUM_EXPORT Framebuffer {
*
* Initial value is `{0.0f, 0.0f, 0.0f, 1.0f}`.
*/
inline static void setClearColor(const Vector4& color) {
inline static void setClearColor(const Color4<GLfloat>& color) {
glClearColor(color.r(), color.g(), color.b(), color.a());
}

16
src/Math/Vector3.h

@ -57,16 +57,16 @@ template<class T> class Vector3: public Vector<3, T> {
/**
* @brief Constructor
* @param x X / R value
* @param y Y / G value
* @param z Z / B value
* @param x X value
* @param y Y value
* @param z Z value
*/
inline constexpr Vector3(T x, T y, T z): Vector<3, T>(x, y, z) {}
/**
* @brief Constructor
* @param other Two component vector
* @param z Z / B value
* @param z Z value
*/
inline constexpr Vector3(const Vector<2, T>& other, T z): Vector<3, T>(other[0], other[1], z) {}
@ -86,14 +86,6 @@ template<class T> class Vector3: public Vector<3, T> {
*/
inline constexpr Vector2<T> xy() const { return Vector2<T>::from(Vector<3, T>::data()); }
inline constexpr T r() const { return x(); } /**< @brief R component */
inline constexpr T g() const { return y(); } /**< @brief G component */
inline constexpr T b() const { return z(); } /**< @brief B component */
inline void setR(T value) { setX(value); } /**< @brief Set R component */
inline void setG(T value) { setY(value); } /**< @brief Set G component */
inline void setB(T value) { setZ(value); } /**< @brief Set B component */
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector3, 3)
};

30
src/Math/Vector4.h

@ -29,7 +29,7 @@ template<class T> class Vector4: public Vector<4, T> {
/**
* @copydoc Vector::Vector
*
* W / A component is set to one.
* W component is set to one.
*/
inline constexpr Vector4(): Vector<4, T>(T(0), T(0), T(0), T(1)) {}
@ -41,17 +41,17 @@ template<class T> class Vector4: public Vector<4, T> {
/**
* @brief Constructor
* @param x X / R value
* @param y Y / G value
* @param z Z / B value
* @param w W / A value
* @param x X value
* @param y Y value
* @param z Z value
* @param w W value
*/
inline constexpr Vector4(T x, T y, T z, T w = T(1)): Vector<4, T>(x, y, z, w) {}
/**
* @brief Constructor
* @param other Three component vector
* @param w W / A value
* @param w W value
*/
/* Not marked as explicit, because conversion from Vector3 to Vector4
is fairly common, nearly always with W set to 1 */
@ -83,24 +83,6 @@ template<class T> class Vector4: public Vector<4, T> {
*/
inline constexpr Vector2<T> xy() const { return Vector2<T>::from(Vector<4, T>::data()); }
inline constexpr T r() const { return x(); } /**< @brief R component */
inline constexpr T g() const { return y(); } /**< @brief G component */
inline constexpr T b() const { return z(); } /**< @brief B component */
inline constexpr T a() const { return w(); } /**< @brief A component */
inline void setR(T value) { setX(value); } /**< @brief Set R component */
inline void setG(T value) { setY(value); } /**< @brief Set G component */
inline void setB(T value) { setZ(value); } /**< @brief Set B component */
inline void setA(T value) { setW(value); } /**< @brief Set A component */
/**
* @brief RGB part of the vector
* @return First three components of the vector
*
* @see swizzle()
*/
inline constexpr Vector3<T> rgb() const { return xyz(); }
MAGNUM_VECTOR_SUBCLASS_IMPLEMENTATION(Vector4, 4)
};

2
src/Test/CMakeLists.txt

@ -1,3 +1,5 @@
corrade_add_test2(ObjectTest ObjectTest.cpp LIBRARIES MagnumTestLib)
corrade_add_test2(CameraTest CameraTest.cpp LIBRARIES Magnum)
corrade_add_test2(SceneTest SceneTest.cpp LIBRARIES Magnum)
corrade_add_test2(ColorTest ColorTest.cpp)

121
src/Test/ColorTest.cpp

@ -0,0 +1,121 @@
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
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.
*/
#include "ColorTest.h"
#include "Color.h"
using namespace std;
CORRADE_TEST_MAIN(Magnum::Test::ColorTest)
namespace Magnum { namespace Test {
typedef Magnum::Color3<unsigned char> Color3;
typedef Magnum::Color4<unsigned char> Color4;
typedef Magnum::Color3<float> Color3f;
ColorTest::ColorTest() {
addTests(&ColorTest::fromDenormalized,
&ColorTest::fromNormalized,
&ColorTest::fromHue,
&ColorTest::fromSaturation,
&ColorTest::fromValue,
&ColorTest::hue,
&ColorTest::saturation,
&ColorTest::value,
&ColorTest::hsv,
&ColorTest::hsvOverflow,
&ColorTest::hsvAlpha);
}
void ColorTest::fromDenormalized() {
CORRADE_COMPARE(Color3f::fromDenormalized(Color3(75, 115, 224)), Color3f(0.294118, 0.45098, 0.878431));
}
void ColorTest::fromNormalized() {
CORRADE_COMPARE(Color3::fromNormalized(Color3f(0.294118, 0.45098, 0.878431)), Color3(75, 115, 224));
}
void ColorTest::fromHue() {
CORRADE_COMPARE(Color3::fromHSV(27.0f, 1.0f, 1.0f), Color3(255, 115, 0));
CORRADE_COMPARE(Color3::fromHSV(86.0f, 1.0f, 1.0f), Color3(145, 255, 0));
CORRADE_COMPARE(Color3::fromHSV(134.0f, 1.0f, 1.0f), Color3(0, 255, 60));
CORRADE_COMPARE(Color3::fromHSV(191.0f, 1.0f, 1.0f), Color3(0, 208, 255));
CORRADE_COMPARE(Color3::fromHSV(269.0f, 1.0f, 1.0f), Color3(123, 0, 255));
CORRADE_COMPARE(Color3::fromHSV(317.0f, 1.0f, 1.0f), Color3(255, 0, 183));
}
void ColorTest::hue() {
CORRADE_COMPARE(Color3(255, 115, 0).hue(), 27.058824f);
CORRADE_COMPARE(Color3(145, 255, 0).hue(), 85.882353f);
CORRADE_COMPARE(Color3(0, 255, 60).hue(), 134.11765f);
CORRADE_COMPARE(Color3(0, 208, 255).hue(), 191.05882f);
CORRADE_COMPARE(Color3(123, 0, 255).hue(), 268.94117f);
CORRADE_COMPARE(Color3(255, 0, 183).hue(), 316.94117f);
}
void ColorTest::fromSaturation() {
CORRADE_COMPARE(Color3::fromHSV(0.0f, 0.702f, 1.0f), Color3(255, 76, 76));
}
void ColorTest::saturation() {
CORRADE_COMPARE(Color3(255, 76, 76).saturation(), 0.701961f);
CORRADE_COMPARE(Color3().saturation(), 0.0f);
}
void ColorTest::fromValue() {
CORRADE_COMPARE(Color3::fromHSV(0.0f, 1.0f, 0.522f), Color3(133, 0, 0));
}
void ColorTest::value() {
CORRADE_COMPARE(Color3(133, 0, 0).value(), 0.521569f);
}
void ColorTest::hsv() {
CORRADE_COMPARE(Color3::fromHSV(230.0f, 0.749f, 0.427f), Color3(27, 41, 109));
float hue, saturation, value;
tie(hue, saturation, value) = Color3(27, 41, 109).toHSV();
CORRADE_COMPARE(hue, 229.756106f);
CORRADE_COMPARE(saturation, 0.752294f);
CORRADE_COMPARE(value, 0.427451f);
}
void ColorTest::hsvOverflow() {
CORRADE_COMPARE(Color3::fromHSV(27.0f-360.0f, 1.0f, 1.0f), Color3(255, 115, 0));
CORRADE_COMPARE(Color3::fromHSV(86.0f-360.0f, 1.0f, 1.0f), Color3(145, 255, 0));
CORRADE_COMPARE(Color3::fromHSV(134.0f-360.0f, 1.0f, 1.0f), Color3(0, 255, 60));
CORRADE_COMPARE(Color3::fromHSV(191.0f-360.0f, 1.0f, 1.0f), Color3(0, 208, 255));
CORRADE_COMPARE(Color3::fromHSV(269.0f-360.0f, 1.0f, 1.0f), Color3(123, 0, 255));
CORRADE_COMPARE(Color3::fromHSV(317.0f-360.0f, 1.0f, 1.0f), Color3(255, 0, 183));
CORRADE_COMPARE(Color3::fromHSV(360.0f+27.0f, 1.0f, 1.0f), Color3(255, 115, 0));
CORRADE_COMPARE(Color3::fromHSV(360.0f+86.0f, 1.0f, 1.0f), Color3(145, 255, 0));
CORRADE_COMPARE(Color3::fromHSV(360.0f+134.0f, 1.0f, 1.0f), Color3(0, 255, 60));
CORRADE_COMPARE(Color3::fromHSV(360.0f+191.0f, 1.0f, 1.0f), Color3(0, 208, 255));
CORRADE_COMPARE(Color3::fromHSV(360.0f+269.0f, 1.0f, 1.0f), Color3(123, 0, 255));
CORRADE_COMPARE(Color3::fromHSV(360.0f+317.0f, 1.0f, 1.0f), Color3(255, 0, 183));
}
void ColorTest::hsvAlpha() {
CORRADE_COMPARE(Color4::fromHSV(make_tuple(230.0f, 0.749f, 0.427f), 23), Color4(27, 41, 109, 23));
CORRADE_COMPARE(Color4::fromHSV(230.0f, 0.749f, 0.427f, 23), Color4(27, 41, 109, 23));
}
}}

44
src/Test/ColorTest.h

@ -0,0 +1,44 @@
#ifndef Magnum_Test_ColorTest_h
#define Magnum_Test_ColorTest_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
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.
*/
#include <TestSuite/Tester.h>
namespace Magnum { namespace Test {
class ColorTest: public Corrade::TestSuite::Tester<ColorTest> {
public:
ColorTest();
void fromDenormalized();
void fromNormalized();
void fromHue();
void fromSaturation();
void fromValue();
void hue();
void saturation();
void value();
void hsv();
void hsvOverflow();
void hsvAlpha();
};
}}
#endif
Loading…
Cancel
Save