From d88e79cd9e9fcb2ba8117134281dedf0ceb8cfcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 6 Aug 2018 13:10:19 +0200 Subject: [PATCH] Math: new Color[34]::fromSrgb[Alpha]() and Color[34]::toSrgb[Alpha]Int(). For easier conversion of packed 24-/32-bit colors to the Color types. --- doc/changelog.dox | 5 ++ doc/snippets/MagnumMath.cpp | 27 ++++++- src/Magnum/Math/Color.h | 119 +++++++++++++++++++++++++---- src/Magnum/Math/Complex.h | 2 +- src/Magnum/Math/Quaternion.h | 2 +- src/Magnum/Math/Test/ColorTest.cpp | 20 +++++ 6 files changed, 159 insertions(+), 16 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 4fa43cc8a..54cff986e 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -61,6 +61,11 @@ See also: @ref Math::Matrix4::scalingSquared(), @ref Math::Matrix3::scaling() const and @ref Math::Matrix4::scaling() const getters for extracting further properties from the rotation/scaling part of a matrix +- Added @ref Math::Color3::fromSrgb(UnsignedInt), + @ref Math::Color4::fromSrgbAlpha(UnsignedInt), + @ref Math::Color4::fromSrgb(UnsignedInt, T), @ref Math::Color3::toSrgbInt(), + and @ref Math::Color4::toSrgbAlphaInt() for easier conversion of packed + 24-/32-bit sRGB colors to and from @ref Math::Color3 / @ref Math::Color4 - Added @ref Math::Constants::piQuarter() - Added a convenience function @ref Math::select() as a constant interpolation counterpart to @ref Math::lerp() diff --git a/doc/snippets/MagnumMath.cpp b/doc/snippets/MagnumMath.cpp index 92a91ae5f..d2ec57234 100644 --- a/doc/snippets/MagnumMath.cpp +++ b/doc/snippets/MagnumMath.cpp @@ -699,6 +699,15 @@ auto rgb = Color3::fromSrgb(srgb); static_cast(rgb); } +{ +/* [Color3-fromSrgb-int] */ +Color3 a = Color3::fromSrgb(0xff3366); +Color3 b = 0xff3366_srgbf; +/* [Color3-fromSrgb-int] */ +static_cast(a); +static_cast(b); +} + { Color3 color; /* [Color3-toHsv] */ @@ -727,11 +736,27 @@ static_cast(rgba); { /* [Color4-fromSrgb] */ Math::Vector3 srgb; -auto rgba = Color4::fromSrgb(srgb); +auto rgba = Color4::fromSrgb(srgb, 0.5f); /* [Color4-fromSrgb] */ static_cast(rgba); } +{ +/* [Color4-fromSrgbAlpha-int] */ +Color4 a = Color4::fromSrgbAlpha(0xff336680); +Color4 b = 0xff336680_srgbaf; +/* [Color4-fromSrgbAlpha-int] */ +static_cast(a); +static_cast(b); +} + +{ +/* [Color4-fromSrgb-int] */ +Color4 rgba = Color4::fromSrgb(0xff3366, 0.5f); +/* [Color4-fromSrgb-int] */ +static_cast(rgba); +} + { Color4 color; /* [Color4-toHsv] */ diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 2253f483c..ec48c51ed 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -364,7 +364,9 @@ template class Color3: public Vector3 { * \left( \dfrac{\boldsymbol{c}_\mathrm{sRGB} + a}{1 + a} \right)^{2.4}, & \boldsymbol{c}_\mathrm{sRGB} > 0.04045 * \end{cases} * @f] - * @see @link operator""_srgbf() @endlink, @ref toSrgb() + * @see @ref fromSrgb(const Vector3&), @ref fromSrgb(UnsignedInt), + * @link operator""_srgbf() @endlink, @ref toSrgb(), + * @ref Color4::fromSrgbAlpha() */ /* Input is a Vector3 to hint that it doesn't have any (additive, multiplicative) semantics of a linear RGB color */ @@ -381,6 +383,9 @@ template class Color3: public Vector3 { * out of it: * * @snippet MagnumMath.cpp Color3-fromSrgb + * + * @see @ref fromSrgb(UnsignedInt), @link operator""_srgbf() @endlink, + * @ref Color4::fromSrgbAlpha(const Vector4&) */ /* Input is a Vector3 to hint that it doesn't have any (additive, multiplicative) semantics of a linear RGB color */ @@ -388,6 +393,25 @@ template class Color3: public Vector3 { return Implementation::fromSrgbIntegral(srgb); } + /** @overload + * @brief Create linear RGB color from 24-bit sRGB representation + * @param srgb 24-bit sRGB color + * + * See @ref fromSrgb() for more information and @ref toSrgbInt() for an + * inverse operation. There's also a @link operator""_srgbf() @endlink + * that does this conversion directly from hexadecimal literals. The + * following two statements are equivalent: + * + * @snippet MagnumMath.cpp Color3-fromSrgb-int + * + * @see @ref Color4::fromSrgbAlpha(UnsignedInt) + */ + static Color3 fromSrgb(UnsignedInt srgb) { + return fromSrgb({UnsignedByte(srgb >> 16), + UnsignedByte(srgb >> 8), + UnsignedByte(srgb)}); + } + /** * @brief Create RGB color from CIE XYZ representation * @param xyz Color in CIE XYZ color space @@ -525,7 +549,7 @@ template class Color3: public Vector3 { * (1 + a) \boldsymbol{c}_\mathrm{linear}^{1/2.4}-a, & \boldsymbol{c}_\mathrm{linear} > 0.0031308 * \end{cases} * @f] - * @see @ref fromSrgb() + * @see @ref fromSrgb(), @ref toSrgbInt(), @ref Color4::toSrgbAlpha() */ Vector3 toSrgb() const { return Implementation::toSrgb(*this); @@ -538,11 +562,25 @@ template class Color3: public Vector3 { * want to create for example an 8-bit sRGB representation out of it: * * @snippet MagnumMath.cpp Color3-toSrgb + * + * @see @ref toSrgbInt(), @ref Color4::toSrgbAlpha() */ template Vector3 toSrgb() const { return Implementation::toSrgbIntegral(*this); } + /** + * @brief Convert to 24-bit integral sRGB representation + * + * See @ref toSrgb() const for more information and + * @ref fromSrgb(UnsignedInt) for an inverse operation. + * @see @ref Color4::toSrgbAlphaInt() + */ + UnsignedInt toSrgbInt() const { + const auto srgb = toSrgb(); + return (srgb[0] << 16) | (srgb[1] << 8) | srgb[2]; + } + /** * @brief Convert to CIE XYZ representation * @@ -737,9 +775,11 @@ class Color4: public Vector4 { * * Useful in cases where you have for example an 8-bit sRGB + alpha * representation and want to create a floating-point linear RGBA color - * out of it: + * out of it. See @ref Color3::fromSrgb() for more information. * * @snippet MagnumMath.cpp Color4-fromSrgbAlpha + * + * @see @ref fromSrgbAlpha(UnsignedInt) */ /* Input is a Vector4 to hint that it doesn't have any (additive, multiplicative) semantics of a linear RGB color */ @@ -756,9 +796,11 @@ class Color4: public Vector4 { * * Useful in cases where you have for example an 8-bit sRGB * representation and want to create a floating-point linear RGBA color - * out of it: + * out of it. See @ref Color3::fromSrgb() for more information. * * @snippet MagnumMath.cpp Color4-fromSrgb + * + * @see @ref fromSrgb(UnsignedInt, T) */ /* Input is a Vector3 to hint that it doesn't have any (additive, multiplicative) semantics of a linear RGB color */ @@ -766,6 +808,45 @@ class Color4: public Vector4 { return {Implementation::fromSrgbIntegral(srgb), a}; } + /** @overload + * @brief Create linear RGBA color from 32-bit sRGB + alpha representation + * @param srgbAlpha 32-bit sRGB color with linear alpha + * + * See @ref Color3::fromSrgb() for more information and + * @ref toSrgbAlphaInt() for an inverse operation. There's also a + * @link operator""_srgbaf() @endlink that does this conversion + * directly from hexadecimal literals. + * + * @snippet MagnumMath.cpp Color4-fromSrgbAlpha-int + */ + static Color4 fromSrgbAlpha(UnsignedInt srgbAlpha) { + return fromSrgbAlpha({UnsignedByte(srgbAlpha >> 24), + UnsignedByte(srgbAlpha >> 16), + UnsignedByte(srgbAlpha >> 8), + UnsignedByte(srgbAlpha)}); + } + + /** @overload + * @brief Create linear RGBA color from 32-bit sRGB + alpha representation + * @param srgb 24-bit sRGB color + * @param a Alpha value, defaults to @cpp 1.0 @ce for + * floating-point types and maximum positive value for integral + * types + * + * See @ref Color3::fromSrgb() for more information and + * @ref toSrgbAlphaInt() for an inverse operation. There's also a + * @link operator""_srgbaf() @endlink that does this conversion + * directly from hexadecimal literals. The following two statements are + * equivalent: + * + * @snippet MagnumMath.cpp Color4-fromSrgb-int + */ + static Color4 fromSrgb(UnsignedInt srgb, T a = Implementation::fullChannel()) { + return fromSrgb({UnsignedByte(srgb >> 16), + UnsignedByte(srgb >> 8), + UnsignedByte(srgb)}, a); + } + /** * @brief Create RGBA color from CIE XYZ representation * @param xyz Color in CIE XYZ color space @@ -897,7 +978,7 @@ class Color4: public Vector4 { * channel is kept linear. See @ref Color3::toSrgb() for more * information. * - * @see @ref fromSrgbAlpha() + * @see @ref fromSrgbAlpha(), @ref toSrgbAlphaInt() */ Vector4 toSrgbAlpha() const { return Implementation::toSrgbAlpha(*this); @@ -911,11 +992,26 @@ class Color4: public Vector4 { * out of it: * * @snippet MagnumMath.cpp Color4-toSrgbAlpha + * + * @see @ref toSrgbAlphaInt() */ template Vector4 toSrgbAlpha() const { return Implementation::toSrgbAlphaIntegral(*this); } + /** + * @brief Convert to 32-bit integral sRGB + linear alpha representation + * + * See @ref Color3::toSrgb() const for more information and + * @ref fromSrgbAlpha(UnsignedInt) for an inverse operation. Use + * @ref rgb() together with @ref Color3::toSrgbInt() to output a 24-bit + * sRGB color. + */ + UnsignedInt toSrgbAlphaInt() const { + const auto srgbAlpha = toSrgbAlpha(); + return (srgbAlpha[0] << 24) | (srgbAlpha[1] << 16) | (srgbAlpha[2] << 8) | srgbAlpha[3]; + } + /** * @brief Convert to CIE XYZ representation * @@ -1092,9 +1188,7 @@ inline Color3 operator "" _rgbf(unsigned long long value) { /** @relatesalso Magnum::Math::Color3 @brief Float sRGB literal -Unpacks the 8-bit values into three floats and converts the color space from -sRGB to linear RGB. See @ref Color3::fromSrgb() for more information. Example -usage: +Calls @ref Color3::fromSrgb(UnsignedInt) on the literal value. Example usage: @snippet MagnumMath.cpp _srgbf @@ -1103,7 +1197,7 @@ usage: @m_keywords{_srgbf srgbf} */ inline Color3 operator "" _srgbf(unsigned long long value) { - return Color3::fromSrgb({UnsignedByte(value >> 16), UnsignedByte(value >> 8), UnsignedByte(value)}); + return Color3::fromSrgb(value); } /** @relatesalso Magnum::Math::Color4 @@ -1128,9 +1222,8 @@ inline Color4 operator "" _rgbaf(unsigned long long value) { /** @relatesalso Magnum::Math::Color4 @brief Float sRGB + alpha literal -Unpacks the 8-bit values into four floats and converts the color space from -sRGB + alpha to linear RGBA. See @ref Color4::fromSrgbAlpha() for more -information. Example usage: +Calls @ref Color4::fromSrgbAlpha(UnsignedInt) on the literal value. Example +usage: @snippet MagnumMath.cpp _srgbaf @@ -1139,7 +1232,7 @@ information. Example usage: @m_keywords{_srgbaf srgbaf} */ inline Color4 operator "" _srgbaf(unsigned long long value) { - return Color4::fromSrgbAlpha({UnsignedByte(value >> 24), UnsignedByte(value >> 16), UnsignedByte(value >> 8), UnsignedByte(value)}); + return Color4::fromSrgbAlpha(value); } } diff --git a/src/Magnum/Math/Complex.h b/src/Magnum/Math/Complex.h index 6841b5946..ff40522a4 100644 --- a/src/Magnum/Math/Complex.h +++ b/src/Magnum/Math/Complex.h @@ -67,7 +67,7 @@ Expects that both complex numbers are normalized. @f[ @f] @see @ref Complex::isNormalized(), @ref angle(const Quaternion&, const Quaternion&), - @ref angle(const Vector&, const Vector&) + @ref angle(const Vector&, const Vector&) */ template inline Rad angle(const Complex& normalizedA, const Complex& normalizedB) { CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), diff --git a/src/Magnum/Math/Quaternion.h b/src/Magnum/Math/Quaternion.h index 82a1a61ca..366c89bb3 100644 --- a/src/Magnum/Math/Quaternion.h +++ b/src/Magnum/Math/Quaternion.h @@ -70,7 +70,7 @@ Expects that both quaternions are normalized. @f[ @f] @see @ref Quaternion::isNormalized(), @ref angle(const Complex&, const Complex&), - @ref angle(const Vector&, const Vector&) + @ref angle(const Vector&, const Vector&) */ template inline Rad angle(const Quaternion& normalizedA, const Quaternion& normalizedB) { CORRADE_ASSERT(normalizedA.isNormalized() && normalizedB.isNormalized(), diff --git a/src/Magnum/Math/Test/ColorTest.cpp b/src/Magnum/Math/Test/ColorTest.cpp index 87c63604f..d3f6ee5e4 100644 --- a/src/Magnum/Math/Test/ColorTest.cpp +++ b/src/Magnum/Math/Test/ColorTest.cpp @@ -621,26 +621,46 @@ void ColorTest::srgb() { /* Integral 8bit sRGB -- slight precision loss */ CORRADE_COMPARE(Color3::fromSrgb({0xf3, 0x2a, 0x80}), (Color3{0.896269f, 0.0231534f, 0.215861f})); + CORRADE_COMPARE(Color3::fromSrgb(0xf32a80), + (Color3{0.896269f, 0.0231534f, 0.215861f})); CORRADE_COMPARE(Color4::fromSrgbAlpha({0xf3, 0x2a, 0x80, 0x23}), (Color4{0.896269f, 0.0231534f, 0.215861f, 0.137255f})); + CORRADE_COMPARE(Color4::fromSrgbAlpha(0xf32a8023), + (Color4{0.896269f, 0.0231534f, 0.215861f, 0.137255f})); CORRADE_COMPARE(Color4::fromSrgb({0xf3, 0x2a, 0x80}, 0.175f), (Color4{0.896269f, 0.0231534f, 0.215861f, 0.175f})); + CORRADE_COMPARE(Color4::fromSrgb(0xf32a80, 0.175f), + (Color4{0.896269f, 0.0231534f, 0.215861f, 0.175f})); CORRADE_COMPARE((Color3{0.896269f, 0.0231534f, 0.215861f}).toSrgb(), (Math::Vector3{0xf2, 0x2a, 0x80})); + CORRADE_COMPARE((Color3{0.896269f, 0.0231534f, 0.215861f}).toSrgbInt(), + 0xf22a80); CORRADE_COMPARE((Color4{0.896269f, 0.0231534f, 0.215861f, 0.137255f}).toSrgbAlpha(), (Math::Vector4{0xf2, 0x2a, 0x80, 0x23})); + CORRADE_COMPARE((Color4{0.896269f, 0.0231534f, 0.215861f, 0.137255f}).toSrgbAlphaInt(), + 0xf22a8023); /* Integral both -- larger precision loss */ CORRADE_COMPARE(Math::Color3::fromSrgb({0xf3, 0x2a, 0x80}), (Math::Color3{58737, 1517, 14146})); + CORRADE_COMPARE(Math::Color3::fromSrgb(0xf32a80), + (Math::Color3{58737, 1517, 14146})); CORRADE_COMPARE(Math::Color4::fromSrgbAlpha({0xf3, 0x2a, 0x80, 0x23}), (Math::Color4{58737, 1517, 14146, 8995})); + CORRADE_COMPARE(Math::Color4::fromSrgbAlpha(0xf32a8023), + (Math::Color4{58737, 1517, 14146, 8995})); CORRADE_COMPARE(Math::Color4::fromSrgb({0xf3, 0x2a, 0x80}, 15299), (Math::Color4{58737, 1517, 14146, 15299})); + CORRADE_COMPARE(Math::Color4::fromSrgb(0xf32a80, 15299), + (Math::Color4{58737, 1517, 14146, 15299})); CORRADE_COMPARE((Math::Color3{58737, 1517, 14146}).toSrgb(), (Math::Vector3{0xf2, 0x29, 0x7f})); + CORRADE_COMPARE((Math::Color3{58737, 1517, 14146}).toSrgbInt(), + 0xf2297f); CORRADE_COMPARE((Math::Color4{58737, 1517, 14146, 8995}).toSrgbAlpha(), (Math::Vector4{0xf2, 0x29, 0x7f, 0x23})); + CORRADE_COMPARE((Math::Color4{58737, 1517, 14146, 8995}).toSrgbAlphaInt(), + 0xf2297f23); /* Round-trip */ CORRADE_COMPARE(Color3::fromSrgb({0.00646f, 0.403027f, 0.563877f}).toSrgb(),