diff --git a/doc/changelog.dox b/doc/changelog.dox index 676329c5f..3f5df63cf 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -307,6 +307,11 @@ See also: - @ref Math::Vector, @ref Math::RectangularMatrix and all their subclasses can be now constructed from fixed-size arrays without having to use the potentially dangerous and non-constexpr @ref Math::Vector::from() API +- New @link Literals::ColorLiterals::operator""_rgbh() _rgbh @endlink, + @link Literals::ColorLiterals::operator""_rgbah() _rgbah @endlink, + @link Literals::ColorLiterals::operator""_srgbh() _srgbh @endlink and + @link Literals::ColorLiterals::operator""_srgbah() _srgbah @endlink + literals for convenient @ref Color3h and @ref Color4h creation @subsubsection changelog-latest-new-materialtools MaterialTools library diff --git a/doc/snippets/Math.cpp b/doc/snippets/Math.cpp index 3e4cadd2f..cc226d04b 100644 --- a/doc/snippets/Math.cpp +++ b/doc/snippets/Math.cpp @@ -568,9 +568,11 @@ using namespace Math::Literals; Color3 a = 0x33b27f_srgbf; // {0.0331048f, 0.445201f, 0.212231f} Color4ub b = 0x33b27fcc_rgba; // {0x33, 0xb2, 0x7f, 0xcc} +Color3h c = 0x33b27f_rgbh; // {0.2_h, 0.6982_h, 0.498_h} /* [types-literals-colors] */ static_cast(a); static_cast(b); +static_cast(c); } { @@ -1040,6 +1042,38 @@ Color4 a = 0x33b27fcc_srgbaf; // {0.0331048f, 0.445201f, 0.212231f, 0.8f} static_cast(a); } +{ +/* [_rgbh] */ +using namespace Math::Literals; +Color3h a = 0x33b27f_rgbh; // {0.2_h, 0.6982_h, 0.498_h} +/* [_rgbh] */ +static_cast(a); +} + +{ +/* [_srgbh] */ +using namespace Math::Literals; +Color3h a = 0x33b27f_srgbh; // {0.03311_h, 0.4453_h, 0.2123_h} +/* [_srgbh] */ +static_cast(a); +} + +{ +/* [_rgbah] */ +using namespace Math::Literals; +Color4h a = 0x33b27fcc_rgbah; // {0.2_h, 0.6982_h, 0.498_h, 0.7998_h} +/* [_rgbah] */ +static_cast(a); +} + +{ +/* [_srgbah] */ +using namespace Math::Literals; +Color4h a = 0x33b27fcc_srgbah; // {0.03311_h, 0.4453_h, 0.2123_h, 0.7998_h} +/* [_srgbah] */ +static_cast(a); +} + { /* [CubicHermite-fromBezier] */ CubicBezier2D segment; diff --git a/doc/types.dox b/doc/types.dox index c34615b46..b4d879975 100644 --- a/doc/types.dox +++ b/doc/types.dox @@ -119,13 +119,17 @@ would be, such as matrix multiplication. The @ref Matrix2x1, @ref Matrix3x1 and For easier entering of (s)RGB colors in hexadecimal format there are @link Math::Literals::ColorLiterals::operator""_srgb() _srgb @endlink / -@link Math::Literals::ColorLiterals::operator""_srgbf() _srgbf @endlink, +@link Math::Literals::ColorLiterals::operator""_srgbf() _srgbf @endlink / +@link Math::Literals::ColorLiterals::operator""_srgbh() _srgbh @endlink, @link Math::Literals::ColorLiterals::operator""_srgba() _srgba @endlink / -@link Math::Literals::ColorLiterals::operator""_srgbaf() _srgbaf @endlink, +@link Math::Literals::ColorLiterals::operator""_srgbaf() _srgbaf @endlink / +@link Math::Literals::ColorLiterals::operator""_srgbah() _srgbah @endlink, @link Math::Literals::ColorLiterals::operator""_rgb() _rgb @endlink / -@link Math::Literals::ColorLiterals::operator""_rgbf() _rgbf @endlink and +@link Math::Literals::ColorLiterals::operator""_rgbf() _rgbf @endlink / +@link Math::Literals::ColorLiterals::operator""_rgbh() _rgbh @endlink and @link Math::Literals::ColorLiterals::operator""_rgba() _rgba @endlink / -@link Math::Literals::ColorLiterals::operator""_rgbaf() _rgbaf @endlink +@link Math::Literals::ColorLiterals::operator""_rgbaf() _rgbaf @endlink / +@link Math::Literals::ColorLiterals::operator""_rgbah() _rgbah @endlink literals in the @ref Math::Literals namespace. See their documentation for more information about the differences. diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 3158c39e5..c770103a4 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -27,7 +27,7 @@ */ /** @file - * @brief Class @ref Magnum::Math::Color3, @ref Magnum::Math::Color4, literal @link Magnum::Math::Literals::ColorLiterals::operator""_rgb() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgba() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbaf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgb() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgba() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbaf() @endlink + * @brief Class @ref Magnum::Math::Color3, @ref Magnum::Math::Color4, literal @link Magnum::Math::Literals::ColorLiterals::operator""_rgb() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgba() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbaf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbh() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_rgbah() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgb() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgba() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbaf() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbh() @endlink, @link Magnum::Math::Literals::ColorLiterals::operator""_srgbah() @endlink */ /* std::declval() is said to be in but libstdc++, libc++ and MSVC STL @@ -339,8 +339,10 @@ value in range @f$ [0.0, 1.0] @f$. @see @link Literals::ColorLiterals::operator""_rgb() @endlink, @link Literals::ColorLiterals::operator""_rgbf() @endlink, + @link Literals::ColorLiterals::operator""_rgbh() @endlink, @link Literals::ColorLiterals::operator""_srgb() @endlink, @link Literals::ColorLiterals::operator""_srgbf() @endlink, + @link Literals::ColorLiterals::operator""_srgbh() @endlink, @ref Color4, @ref Magnum::Color3, @ref Magnum::Color3h, @ref Magnum::Color3ub, @ref Magnum::Color3us */ @@ -777,8 +779,10 @@ _MAGNUM_VECTORn_OPERATOR_IMPLEMENTATION(3, Color3) See @ref Color3 for more information. @see @link Literals::ColorLiterals::operator""_rgba() @endlink, @link Literals::ColorLiterals::operator""_rgbaf() @endlink, + @link Literals::ColorLiterals::operator""_rgbah() @endlink, @link Literals::ColorLiterals::operator""_srgba() @endlink, @link Literals::ColorLiterals::operator""_srgbaf() @endlink, + @link Literals::ColorLiterals::operator""_srgbah() @endlink, @ref Magnum::Color4, @ref Magnum::Color4h, @ref Magnum::Color4ub, @ref Magnum::Color4us */ @@ -1460,6 +1464,13 @@ template for the half-float + literals */ +template struct HalfColor { + typedef Color3 Type3; + typedef Color4 Type4; +}; + } /* Unlike STL, where there's e.g. std::literals::string_literals with both @@ -1503,7 +1514,8 @@ Unpacks the literal into three 8-bit values. Example usage: to linear RGB first. To convey such meaning, use the @link operator""_srgb() @endlink literal instead. -@see @link operator""_rgba() @endlink, @link operator""_rgbf() @endlink +@see @link operator""_rgba() @endlink, @link operator""_rgbf() @endlink, + @link operator""_rgbh() @endlink @m_keywords{_rgb rgb} */ template constexpr Color3 operator"" _rgb() { @@ -1527,7 +1539,8 @@ RGB. Use this literal to document that given value is in sRGB. Example usage: representation directly or convert the value using @ref Color3::fromSrgb() / @ref Color3::fromSrgbInt(). -@see @link operator""_srgba() @endlink, @link operator""_srgbf() @endlink +@see @link operator""_srgba() @endlink, @link operator""_srgbf() @endlink, + @link operator""_srgbh() @endlink @m_keywords{_srgb srgb} */ /* Output is a Vector3 to hint that it doesn't have any (additive, @@ -1548,7 +1561,8 @@ Unpacks the literal into four 8-bit values. Example usage: to linear RGB first. To convey such meaning, use the @link operator""_srgba() @endlink literal instead. -@see @link operator""_rgb() @endlink, @link operator""_rgbaf() @endlink +@see @link operator""_rgb() @endlink, @link operator""_rgbaf() @endlink, + @link operator""_rgbah() @endlink @m_keywords{_rgba rgba} */ template constexpr Color4 operator"" _rgba() { @@ -1573,7 +1587,8 @@ usage: representation directly or convert the value using @ref Color4::fromSrgbAlpha() / @ref Color4::fromSrgbAlphaInt(). -@see @link operator""_srgb() @endlink, @link operator""_rgbaf() @endlink +@see @link operator""_srgb() @endlink, @link operator""_rgbaf() @endlink, + @link operator""_rgbah() @endlink @m_keywords{_srgba srgba} */ /* Output is a Vector3 to hint that it doesn't have any (additive, @@ -1595,7 +1610,8 @@ Example usage: to linear RGB first. In that case use the @link operator""_srgbf() @endlink literal instead. -@see @link operator""_rgbaf() @endlink, @link operator""_rgb() @endlink +@see @link operator""_rgbaf() @endlink, @link operator""_rgb() @endlink, + @link operator""_rgbh() @endlink @m_keywords{_rgbf rgbf} */ template constexpr Color3 operator"" _rgbf() { @@ -1611,7 +1627,7 @@ usage: @snippet Math.cpp _srgbf @see @link operator""_srgbaf() @endlink, @link operator""_srgb() @endlink, - @link operator""_rgbf() @endlink + @link operator""_srgbh() @endlink, @link operator""_rgbf() @endlink @m_keywords{_srgbf srgbf} */ template inline Color3 operator"" _srgbf() { @@ -1631,7 +1647,8 @@ Example usage: to linear RGB first. In that case use the @link operator""_srgbaf() @endlink literal instead. -@see @link operator""_rgbf() @endlink, @link operator""_rgba() @endlink +@see @link operator""_rgbf() @endlink, @link operator""_rgba() @endlink, + @link operator""_rgbah() @endlink @m_keywords{_rgbaf rgbaf} */ template constexpr Color4 operator"" _rgbaf() { @@ -1647,12 +1664,114 @@ Example usage: @snippet Math.cpp _srgbaf @see @link operator""_srgbf() @endlink, @link operator""_srgba() @endlink, - @link operator""_rgbaf() @endlink + @link operator""_srgbah() @endlink, @link operator""_rgbaf() @endlink @m_keywords{_srgbaf srgbaf} */ template inline Color4 operator"" _srgbaf() { return Color4::fromSrgbAlpha(Implementation::color4Literal, 1, sizeof...(chars), chars...>()); } + +/** @relatesalso Magnum::Math::Color3 +@brief Half-float linear RGB literal +@m_since_latest + +Equivalent to calling @ref Color3::fromLinearRgbInt() on the literal value and +then casting from a float to a half-float type. Example usage: + +@snippet Math.cpp _rgbh + +@attention 8bit-per-channel colors are commonly treated as being in sRGB color + space, which is not directly usable in calculations and has to be converted + to linear RGB first. In that case use the @link operator""_srgbh() @endlink + literal instead. + +@see @link operator""_rgbah() @endlink, @link operator""_rgb() @endlink, + @link operator""_rgbf() @endlink +@m_keywords{_rgbh rgbh} +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Color3 /* to avoid including Half.h */ +#else +typename Implementation::HalfColor::Type3 +#endif +operator"" _rgbh() { + return Color3{Implementation::color3Literal, 255, sizeof...(chars), chars...>()}; +} + +/** @relatesalso Magnum::Math::Color3 +@brief Half-float sRGB literal +@m_since_latest + +Equivalent to calling @ref Color3::fromSrgbInt() on the literal value and then +casting from a float to a half-float type. Example usage: + +@snippet Math.cpp _srgbh + +@see @link operator""_srgbah() @endlink, @link operator""_srgb() @endlink, + @link operator""_srgbf() @endlink, @link operator""_rgbh() @endlink +@m_keywords{_srgbh srgbh} +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Color3 /* to avoid including Half.h */ +#else +typename Implementation::HalfColor::Type3 +#endif +operator"" _srgbh() { + return Color3{Color3::fromSrgb(Implementation::color3Literal, 1, sizeof...(chars), chars...>())}; +} + +/** @relatesalso Magnum::Math::Color4 +@brief Half-float linear RGBA literal +@m_since_latest + +Equivalent to calling @ref Color4::fromLinearRgbaInt() on the literal value and +then casting from a float to a half-float type. Example usage: + +@snippet Math.cpp _rgbah + +@attention 8bit-per-channel colors are commonly treated as being in sRGB color + space, which is not directly usable in calculations and has to be converted + to linear RGB first. In that case use the @link operator""_srgbah() @endlink + literal instead. + +@see @link operator""_rgbh() @endlink, @link operator""_rgba() @endlink, + @link operator""_rgbaf() @endlink +@m_keywords{_rgbah rgbah} +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Color4 /* to avoid including Half.h */ +#else +typename Implementation::HalfColor::Type4 +#endif +operator"" _rgbah() { + return Color4{Implementation::color4Literal, 255, sizeof...(chars), chars...>()}; +} + +/** @relatesalso Magnum::Math::Color4 +@brief Half-float sRGB + alpha literal +@m_since_latest + +Equivalent to calling @ref Color4::fromSrgbAlphaInt() on the literal value and +then casting from a float to a half-float type. Example usage: + +@snippet Math.cpp _srgbah + +@see @link operator""_srgbh() @endlink, @link operator""_srgba() @endlink, + @link operator""_srgbaf() @endlink, @link operator""_rgbah() @endlink +@m_keywords{_srgbah srgbah} +*/ +template inline +#ifdef DOXYGEN_GENERATING_OUTPUT +Color4 /* to avoid including Half.h */ +#else +typename Implementation::HalfColor::Type4 +#endif +operator"" _srgbah() { + return Color4{Color4::fromSrgbAlpha(Implementation::color4Literal, 1, sizeof...(chars), chars...>())}; +} #if defined(CORRADE_TARGET_CLANG) && __clang_major__ >= 17 #pragma clang diagnostic pop #endif diff --git a/src/Magnum/Math/Test/ColorTest.cpp b/src/Magnum/Math/Test/ColorTest.cpp index bb007558d..072fb256f 100644 --- a/src/Magnum/Math/Test/ColorTest.cpp +++ b/src/Magnum/Math/Test/ColorTest.cpp @@ -124,8 +124,10 @@ struct ColorTest: TestSuite::Tester { void literalParsing(); void literals(); void literalsFloat(); + void literalsHalf(); void literalsSrgb(); void literalsSrgbFloat(); + void literalsSrgbHalf(); void xyz(); void fromXyzDefaultAlpha(); @@ -277,8 +279,10 @@ ColorTest::ColorTest() { &ColorTest::literalParsing, &ColorTest::literals, &ColorTest::literalsFloat, + &ColorTest::literalsHalf, &ColorTest::literalsSrgb, &ColorTest::literalsSrgbFloat, + &ColorTest::literalsSrgbHalf, &ColorTest::premultiplied, &ColorTest::premultipliedRoundtrip, @@ -1207,10 +1211,10 @@ void ColorTest::literalParsing() { // 0xccff33a_srgba; /* too short 32-bit color */ // 0xccff33aa_rgbaf; /* too long 32-bit color */ // 01234567_rgbf; /* 8-char octal literal (fails due to no 0x) */ - // 01234.56_rgbf; /* 8-char float literal (fails due to no 0x) */ - // .0123456_rgbf; /* 8-char float literal with leading period */ - // 0001234567_rgba; /* 10-char octal literal (fails due to no 0x) */ - // 012345.678_rgba; /* 10-char float literal (fails due to no 0x) */ + // 01234.56_rgbh; /* 8-char float literal (fails due to no 0x) */ + // .0123456_srgbh; /* 8-char float literal with leading period */ + // 0001234567_rgbah; /* 10-char octal literal (fails due to no 0x) */ + // 012345.678_srgbah; /* 10-char float literal (fails due to no 0x) */ // .012345678_rgba; /* 10-char float literal with leading period */ // 0xap3510_srgb; /* 6-char C++17 hex float literal, p at 1 */ // 0xaP3510_srgb; /* 6-char C++17 hex float literal, P at 1 */ @@ -1274,6 +1278,27 @@ void ColorTest::literalsFloat() { CORRADE_COMPARE(0x00000000_rgbaf, (Color4{0.0f, 0.0f})); } +void ColorTest::literalsHalf() { + /* Verifies mainly that the output is correctly unpacked, consistent with + the runtime API, the actual character parsing is checked thoroughly in + literalParsing() above. Comparing to fromIntegralLinearRgb() / unpack() + tests as the ground truth. */ + CORRADE_COMPARE(0xf32a80_rgbh, Color3h{Color3::fromLinearRgbInt(0xf32a80)}); + CORRADE_COMPARE(0xf32a80_rgbh, (Color3h{0.952941_h, 0.164706_h, 0.501961_h})); + CORRADE_COMPARE(0xf32a8023_rgbah, Color4h{Color4::fromLinearRgbaInt(0xf32a8023)}); + CORRADE_COMPARE(0xf32a8023_rgbah, (Color4h{0.952941_h, 0.164706_h, 0.501961_h, 0.137255_h})); + + /* These are not constexpr yet */ + + /* Test also boundary values to be sure */ + /** @todo is it possible to verify *all* values for roundtrip, without some + crazy template madness? */ + CORRADE_COMPARE(0xffffff_rgbh, Color3h{1.0_h}); + CORRADE_COMPARE(0x000000_rgbh, Color3h{0.0_h}); + CORRADE_COMPARE(0xffffffff_rgbah, Color4h{1.0_h}); + CORRADE_COMPARE(0x00000000_rgbah, (Color4h{0.0_h, 0.0_h})); +} + void ColorTest::literalsSrgb() { /* Should be the same as literals(), just giving back a non-Color type */ CORRADE_COMPARE(0x3f568a_srgb, (Vector3ub{0x3f, 0x56, 0x8a})); @@ -1304,6 +1329,25 @@ void ColorTest::literalsSrgbFloat() { CORRADE_COMPARE(0x00000000_srgbaf, (Color4{0.0f, 0.0f})); } +void ColorTest::literalsSrgbHalf() { + /* Verifies mainly that the output is correctly unpacked and converted, + consistent with the runtime API, the actual character parsing is checked + thoroughly in literalParsing() above. Comparing to fromIntegralSrgb() + tests as the ground truth. */ + CORRADE_COMPARE(0xf32a8023_srgbah, Color4h{Color4::fromSrgbAlphaInt(0xf32a8023)}); + CORRADE_COMPARE(0xf32a8023_srgbah, (Color4h{0.896269_h, 0.0231534_h, 0.215861_h, 0.137255_h})); + + /* These are not constexpr yet */ + + /* Test also boundary values to be sure */ + /** @todo is it possible to verify *all* values for roundtrip, without some + crazy template madness? */ + CORRADE_COMPARE(0xffffff_srgbh, Color3h{1.0_h}); + CORRADE_COMPARE(0x000000_srgbh, Color3h{0.0_h}); + CORRADE_COMPARE(0xffffffff_srgbah, Color4h{1.0_h}); + CORRADE_COMPARE(0x00000000_srgbah, (Color4h{0.0_h, 0.0_h})); +} + void ColorTest::premultiplied() { /* Usual scenario */ CORRADE_COMPARE((Color4{0.6f, 0.8f, 0.4f, 0.25f}).premultiplied(), (Color4{0.15f, 0.2f, 0.1f, 0.25f}));