diff --git a/doc/changelog.dox b/doc/changelog.dox index baa74fc48..ba790c792 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -114,6 +114,9 @@ See also: - @ref Math::Frustum::begin() / @ref Math::Frustum::end() accessors for easy range-for access to @ref Math::Frustum planes +- @ref Color3ub and @ref Color4ub can be printed with + @ref Corrade::Utility::Debug as actual colors using the + @ref Corrade::Utility::Debug::color modifier - Added convenience @ref BoolVector2, @ref BoolVector3 and @ref BoolVector4 typedefs to the root namespace diff --git a/doc/snippets/MagnumMath.cpp b/doc/snippets/MagnumMath.cpp index eafcaf6b2..bef1f956a 100644 --- a/doc/snippets/MagnumMath.cpp +++ b/doc/snippets/MagnumMath.cpp @@ -777,6 +777,21 @@ Math::Vector4 srgbAlpha = color.toSrgbAlpha(); static_cast(srgbAlpha); } +{ +/* [Color3-debug] */ +Debug{Debug::Flag::Color} << 0xdcdcdc_rgb << 0xa5c9ea_rgb << 0x3bd267_rgb + << 0xc7cf2f_rgb << 0xcd3431_rgb << 0x2f83cc_rgb << 0x747474_rgb; +/* [Color3-debug] */ +} + +{ +/* [Color4-debug] */ +Debug{Debug::Flag::Color} + << 0x3bd26700_rgba << 0x3bd26733_rgba << 0x3bd26766_rgba + << 0x3bd26799_rgba << 0x3bd267cc_rgba << 0x3bd267ff_rgba; +/* [Color4-debug] */ +} + { /* [_rgb] */ using namespace Math::Literals; diff --git a/src/Magnum/Math/Color.cpp b/src/Magnum/Math/Color.cpp index fa71039ac..649fb5a00 100644 --- a/src/Magnum/Math/Color.cpp +++ b/src/Magnum/Math/Color.cpp @@ -39,27 +39,106 @@ namespace { } Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const Color3& value) { - char out[] = "#______"; - out[1] = Hex[(value.r() >> 4) & 0xf]; - out[2] = Hex[(value.r() >> 0) & 0xf]; - out[3] = Hex[(value.g() >> 4) & 0xf]; - out[4] = Hex[(value.g() >> 0) & 0xf]; - out[5] = Hex[(value.b() >> 4) & 0xf]; - out[6] = Hex[(value.b() >> 0) & 0xf]; - return debug << out; + /* Print an actual colored square if requested */ + if(debug.immediateFlags() & Corrade::Utility::Debug::Flag::Color) { + /* Pick a shade based on calculated lightness */ + const Float valueValue = value.value(); + const char* shade; + if(valueValue <= 0.2f) shade = " "; + else if(valueValue <= 0.4f) shade = "░░"; + else if(valueValue <= 0.6f) shade = "▒▒"; + else if(valueValue <= 0.8f) shade = "▓▓"; + else shade = "██"; + + /* If ANSI colors are disabled, use just the shade */ + if(debug.immediateFlags() & Corrade::Utility::Debug::Flag::DisableColors) + return debug << shade; + else { + debug << "\033[38;2;"; + + /* Disable space between values for everything after the initial + value */ + const Corrade::Utility::Debug::Flags previousFlags = debug.flags(); + debug.setFlags(previousFlags|Corrade::Utility::Debug::Flag::NoSpace); + + /* Set both background and foreground, reset back after */ + debug << int(value.r()) << ";" << int(value.g()) << ";" + << int(value.b()) << "m\033[48;2;" << int(value.r()) << ";" << + int(value.g()) << ";" << int(value.b()) << "m" << shade << "\033[0m"; + + /* Reset original flags */ + debug.setFlags(previousFlags); + return debug; + } + + /* Otherwise print a CSS color */ + } else { + char out[] = "#______"; + out[1] = Hex[(value.r() >> 4) & 0xf]; + out[2] = Hex[(value.r() >> 0) & 0xf]; + out[3] = Hex[(value.g() >> 4) & 0xf]; + out[4] = Hex[(value.g() >> 0) & 0xf]; + out[5] = Hex[(value.b() >> 4) & 0xf]; + out[6] = Hex[(value.b() >> 0) & 0xf]; + return debug << out; + } } Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const Color4& value) { - char out[] = "#________"; - out[1] = Hex[(value.r() >> 4) & 0xf]; - out[2] = Hex[(value.r() >> 0) & 0xf]; - out[3] = Hex[(value.g() >> 4) & 0xf]; - out[4] = Hex[(value.g() >> 0) & 0xf]; - out[5] = Hex[(value.b() >> 4) & 0xf]; - out[6] = Hex[(value.b() >> 0) & 0xf]; - out[7] = Hex[(value.a() >> 4) & 0xf]; - out[8] = Hex[(value.a() >> 0) & 0xf]; - return debug << out; + /* Print an actual colored square if requested */ + if(debug.immediateFlags() & Corrade::Utility::Debug::Flag::Color) { + /* Pick a shade based on calculated lightness */ + const Float valueValue = value.value(); + const Float alpha = Math::unpack(value.a()); + const Float valueAlpha = valueValue*alpha; + const char* shade; + if(valueAlpha <= 0.2f) shade = " "; + else if(valueAlpha <= 0.4f) shade = "░░"; + else if(valueAlpha <= 0.6f) shade = "▒▒"; + else if(valueAlpha <= 0.8f) shade = "▓▓"; + else shade = "██"; + + /* If ANSI colors are disabled, use just the shade */ + if(debug.immediateFlags() & Corrade::Utility::Debug::Flag::DisableColors) + return debug << shade; + else { + debug << "\033[38;2;"; + + /* Disable space between values for everything after the initial + value */ + const Corrade::Utility::Debug::Flags previousFlags = debug.flags(); + debug.setFlags(previousFlags|Corrade::Utility::Debug::Flag::NoSpace); + + /* Print foreground color */ + debug << int(value.r()) << ";" << int(value.g()) << ";" + << int(value.b()) << "m"; + + /* If alpha is larger than perceived value, set also background */ + if(alpha > valueValue) + debug << "\033[48;2;" << int(value.r()) << ";" << + int(value.g()) << ";" << int(value.b()) << "m"; + + /* Print the shade and reset color back */ + debug << shade << "\033[0m"; + + /* Reset original flags */ + debug.setFlags(previousFlags); + return debug; + } + + /* Otherwise print a CSS color */ + } else { + char out[] = "#________"; + out[1] = Hex[(value.r() >> 4) & 0xf]; + out[2] = Hex[(value.r() >> 0) & 0xf]; + out[3] = Hex[(value.g() >> 4) & 0xf]; + out[4] = Hex[(value.g() >> 0) & 0xf]; + out[5] = Hex[(value.b() >> 4) & 0xf]; + out[6] = Hex[(value.b() >> 0) & 0xf]; + out[7] = Hex[(value.a() >> 4) & 0xf]; + out[8] = Hex[(value.a() >> 0) & 0xf]; + return debug << out; + } } }} diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 5895118b2..b896889c5 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -1292,16 +1292,69 @@ inline Color4 operator "" _srgbaf(unsigned long long value) { /** @debugoperator{Color3} -Prints the value as hex color (e.g. @cb{.shell-session} #ff33aa @ce). Other -underlying types are handled by @ref operator<<(Corrade::Utility::Debug&, const Vector&). +If @ref Corrade::Utility::Debug::Flag::Color is enabled or +@ref Corrade::Utility::Debug::color was set immediately before, prints the +value as an ANSI 24bit color escape sequence using two successive Unicode block +characters (to have it roughly square). To preserve at least some information +when text is copied, the square consists of one of the five +@cb{.shell-session} ░▒▓█ @ce shades, however the color is set for both +foreground and background so the actual block character is indistinguishable +when seen on a terminal. + +If @ref Corrade::Utility::Debug::Flag::Color is enabled and +@ref Corrade::Utility::Debug::Flag::DisableColors is set, only the shaded +character is used, without any ANSI color escape sequence. + +If @ref Corrade::Utility::Debug::Flag::Color is not enabled, the value is +printed as a hex color (e.g. @cb{.shell-session} #ff33aa @ce). Other underlying +types are handled by @ref operator<<(Corrade::Utility::Debug&, const Vector&). + +For example, the following snippet: + +@snippet MagnumMath.cpp Color3-debug + + + +@m_class{m-noindent} + +prints the following on terminals that support it: + +@include MathColor3-debug.ansi */ MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const Color3& value); /** @debugoperator{Color4} -Prints the value as hex color (e.g. @cb{.shell-session} #9933aaff @ce). Other +If @ref Corrade::Utility::Debug::Flag::Color is enabled or +@ref Corrade::Utility::Debug::color was set immediately before, prints the +value as an ANSI 24bit color escape sequence using two successive Unicode block +characters (to have it roughly square). To preserve at least some information +when text is copied, the square consists of one of the five +@cb{.shell-session} ░▒▓█ @ce shades. The square shade is calculated as a +product of @ref Color4::value() and @ref Color4::a(). If calculated color value +is less than alpha, the colored square has the color set for both background +and foreground, otherwise the background is left at the default. + +If @ref Corrade::Utility::Debug::Flag::Color is enabled and +@ref Corrade::Utility::Debug::Flag::DisableColors is set, only the shaded +character is used, without any ANSI color escape sequence. + +If @ref Corrade::Utility::Debug::Flag::Color is not enabled, the value is +printed as a hex color (e.g. @cb{.shell-session} #ff33aaff @ce). Other underlying types are handled by @ref operator<<(Corrade::Utility::Debug&, const Vector&). + +For example, the following snippet: + +@snippet MagnumMath.cpp Color4-debug + + + +@m_class{m-noindent} + +prints the following on terminals that support it: + +@include MathColor4-debug.ansi */ MAGNUM_EXPORT Corrade::Utility::Debug& operator<<(Corrade::Utility::Debug& debug, const Color4& value); #endif diff --git a/src/Magnum/Math/Test/ColorTest.cpp b/src/Magnum/Math/Test/ColorTest.cpp index 0932b12e0..b02ec4e81 100644 --- a/src/Magnum/Math/Test/ColorTest.cpp +++ b/src/Magnum/Math/Test/ColorTest.cpp @@ -122,6 +122,8 @@ struct ColorTest: Corrade::TestSuite::Tester { void swizzleType(); void debug(); void debugUb(); + void debugUbColor(); + void debugUbColorColorsDisabled(); void debugHsv(); #if defined(DOXYGEN_GENERATING_OUTPUT) || defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) || defined(CORRADE_TARGET_EMSCRIPTEN) @@ -246,6 +248,8 @@ ColorTest::ColorTest() { &ColorTest::swizzleType, &ColorTest::debug, &ColorTest::debugUb, + &ColorTest::debugUbColor, + &ColorTest::debugUbColorColorsDisabled, &ColorTest::debugHsv}); #if defined(DOXYGEN_GENERATING_OUTPUT) || defined(CORRADE_TARGET_UNIX) || (defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)) || defined(CORRADE_TARGET_EMSCRIPTEN) @@ -1019,6 +1023,52 @@ void ColorTest::debugUb() { CORRADE_COMPARE(o.str(), "#12345678 #90abcdef\n"); } +void ColorTest::debugUbColor() { + Debug{} << "The following should be the Magnum / m.css color palette:"; + + Debug{Debug::Flag::Color} + << 0xdcdcdc_rgb << 0xa5c9ea_rgb << 0x3bd267_rgb + << 0xc7cf2f_rgb << 0xcd3431_rgb << 0x2f83cc_rgb << 0x747474_rgb; + + Debug{} << "The following should have increasing (overmultiplied) alpha:"; + + Debug{Debug::Flag::Color} + << 0x3bd26700_rgba << 0x3bd26733_rgba << 0x3bd26766_rgba + << 0x3bd26799_rgba << 0x3bd267cc_rgba << 0x3bd267ff_rgba; + + /* It should work just for the immediately following value */ + std::ostringstream out; + Debug{&out} + << Debug::color << 0x3bd267_rgb + << Debug::color << 0x2f83cc99_rgba + << 0x3bd267_rgb << 0x2f83cc99_rgba; + CORRADE_COMPARE(out.str(), + "\033[38;2;59;210;103m\033[48;2;59;210;103m██\033[0m " + "\033[38;2;47;131;204m▒▒\033[0m #3bd267 #2f83cc99\n"); +} + +void ColorTest::debugUbColorColorsDisabled() { + Debug{} << "The following should be the Magnum / m.css uncolored palette:"; + + Debug{Debug::Flag::Color|Debug::Flag::DisableColors} + << 0xdcdcdc_rgb << 0xa5c9ea_rgb << 0x3bd267_rgb + << 0xc7cf2f_rgb << 0xcd3431_rgb << 0x2f83cc_rgb << 0x747474_rgb; + + Debug{} << "The following should have increasing (overmultiplied) alpha:"; + + Debug{Debug::Flag::Color|Debug::Flag::DisableColors} + << 0x3bd26700_rgba << 0x3bd26733_rgba << 0x3bd26766_rgba + << 0x3bd26799_rgba << 0x3bd267cc_rgba << 0x3bd267ff_rgba; + + /* It should work just for the immediately following value */ + std::ostringstream out; + Debug{&out, Debug::Flag::DisableColors} + << Debug::color << 0x2f83cc_rgb + << Debug::color << 0x2f83cc99_rgba + << 0x2f83cc_rgb << 0x2f83cc99_rgba; + CORRADE_COMPARE(out.str(), "▓▓ ▒▒ #2f83cc #2f83cc99\n"); +} + void ColorTest::debugHsv() { std::ostringstream out; Debug{&out} << ColorHsv(135.0_degf, 0.75f, 0.3f);