From 502d59c2a8d67b94e3b51b08db9820f47d68cce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 30 Dec 2016 01:16:16 +0100 Subject: [PATCH] Math: ability to specify number of integer bits for {un,}pack(). This also allowed me to get rid of the header. --- src/Magnum/Math/Color.h | 2 +- src/Magnum/Math/Packing.h | 94 ++++++++++++++++++++++------ src/Magnum/Math/Test/PackingTest.cpp | 51 ++++++++++++++- 3 files changed, 127 insertions(+), 20 deletions(-) diff --git a/src/Magnum/Math/Color.h b/src/Magnum/Math/Color.h index 0ddf0c2e5..17b54e661 100644 --- a/src/Magnum/Math/Color.h +++ b/src/Magnum/Math/Color.h @@ -201,7 +201,7 @@ template constexpr typename std::enable_if::v return T(1); } template constexpr typename std::enable_if::value, T>::type fullChannel() { - return std::numeric_limits::max(); + return Implementation::bitMax(); } } diff --git a/src/Magnum/Math/Packing.h b/src/Magnum/Math/Packing.h index 5bb75e66b..909ce820b 100644 --- a/src/Magnum/Math/Packing.h +++ b/src/Magnum/Math/Packing.h @@ -25,12 +25,19 @@ DEALINGS IN THE SOFTWARE. */ -#include - #include "Magnum/Math/Functions.h" namespace Magnum { namespace Math { +namespace Implementation { + +template inline constexpr T bitMax() { + return T(typename std::make_unsigned::type(~T{}) >> (sizeof(T)*8 - (std::is_signed::value ? bits - 1 : bits))); +} + +} + +#ifdef DOXYGEN_GENERATING_OUTPUT /** @brief Unpack integral value into a floating-point representation @@ -55,29 +62,57 @@ Float b = Math::unpack('\xFF'); @see @ref pack() */ -/* Signed conversion with max(val, -1) according to - https://www.opengl.org/registry/specs/EXT/texture_snorm.txt */ -#ifdef DOXYGEN_GENERATING_OUTPUT template inline FloatingPoint unpack(const Integral& value); + +/** +@brief Unpack integer bits into a floating-point representation + +Alternative to the above with ability to specify how many bits of the integral +representation to use. Example usage: +@code +Float a = Math::unpack(8191); // 0.124987f +Float b = Math::unpack(8191); // 0.499969f +Float b = Math::unpack(8191u); // 0.499969f +Float b = Math::unpack(8191); // 1.0f +@endcode +*/ +template inline FloatingPoint unpack(const Integral& value); #else -template inline typename std::enable_if::value && std::is_unsigned::value, FloatingPoint>::type unpack(Integral value) { +template inline typename std::enable_if::value && std::is_unsigned::value, FloatingPoint>::type unpack(Integral value) { static_assert(std::is_floating_point::value && std::is_integral::value, - "unpacking must be done from integral to floating-point type"); - return value/FloatingPoint(std::numeric_limits::max()); + "unpacking must be done from integral to floating-point type"); + static_assert(bits <= sizeof(Integral)*8, + "bit count larger than size of the integral type"); + return value/FloatingPoint(Implementation::bitMax()); } -template inline typename std::enable_if::value && std::is_signed::value, FloatingPoint>::type unpack(Integral value) { +template inline typename std::enable_if::value && std::is_signed::value, FloatingPoint>::type unpack(Integral value) { static_assert(std::is_floating_point::value && std::is_integral::value, - "unpacking must be done from integral to floating-point type"); - return Math::max(value/FloatingPoint(std::numeric_limits::max()), FloatingPoint(-1.0)); + "unpacking must be done from integral to floating-point type"); + static_assert(bits <= sizeof(Integral)*8, + "bit count larger than size of the integral type"); + /* According to https://www.opengl.org/registry/specs/EXT/texture_snorm.txt */ + return Math::max(value/FloatingPoint(Implementation::bitMax()), FloatingPoint(-1.0)); } -template FloatingPoint unpack(const Vector& value) { +template FloatingPoint unpack(const Vector& value) { FloatingPoint out{NoInit}; for(std::size_t i = 0; i != size; ++i) - out[i] = unpack(value[i]); + out[i] = unpack(value[i]); return out; } #endif +/** @overload */ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline FloatingPoint unpack(const Integral& value); +#else +template inline typename std::enable_if::value, FloatingPoint>::type unpack(const Integral& value) { + return unpack(value); +} +template inline FloatingPoint unpack(const Vector& value) { + return unpack(value); +} +#endif + #ifdef MAGNUM_BUILD_DEPRECATED /** @copybrief unpack() * @deprecated Use @ref unpack() instead. @@ -107,19 +142,42 @@ integral type. #ifdef DOXYGEN_GENERATING_OUTPUT template inline Integral pack(const FloatingPoint& value); #else -template inline typename std::enable_if::value, Integral>::type pack(FloatingPoint value) { +template inline typename std::enable_if::value, Integral>::type pack(FloatingPoint value) { static_assert(std::is_floating_point::value && std::is_integral::value, - "packing must be done from floating-point to integral type"); - return Integral(value*std::numeric_limits::max()); + "packing must be done from floating-point to integral type"); + static_assert(bits <= sizeof(Integral)*8, + "bit count larger than size of the integral type"); + return Integral(value*Implementation::bitMax()); } -template Integral pack(const Vector& value) { +template Integral pack(const Vector& value) { Integral out{NoInit}; for(std::size_t i = 0; i != size; ++i) - out[i] = pack(value[i]); + out[i] = pack(value[i]); return out; } #endif +/** +@brief Pack floating-point value into integer bits + +Alternative to the above with ability to specify how many bits of the integral +representation to use. Example usage: +@code +auto a = Math::pack(0.5f); // 32767 +auto b = Math::pack(0.5f); // 8191 +@endcode +*/ +#ifdef DOXYGEN_GENERATING_OUTPUT +template inline Integral pack(FloatingPoint value); +#else +template inline typename std::enable_if::value, Integral>::type pack(FloatingPoint value) { + return pack(value); +} +template inline Integral pack(const Vector& value) { + return pack(value); +} +#endif + #ifdef MAGNUM_BUILD_DEPRECATED /** @copybrief pack() * @deprecated Use @ref pack() instead. diff --git a/src/Magnum/Math/Test/PackingTest.cpp b/src/Magnum/Math/Test/PackingTest.cpp index e5bce50b4..35d7fcae5 100644 --- a/src/Magnum/Math/Test/PackingTest.cpp +++ b/src/Magnum/Math/Test/PackingTest.cpp @@ -33,6 +33,8 @@ namespace Magnum { namespace Math { namespace Test { struct PackingTest: Corrade::TestSuite::Tester { explicit PackingTest(); + void bitMax(); + void unpackUnsigned(); void unpackSigned(); void packUnsigned(); @@ -47,7 +49,9 @@ typedef Math::Vector3 Vector3ub; typedef Math::Vector3 Vector3b; PackingTest::PackingTest() { - addTests({&PackingTest::unpackUnsigned, + addTests({&PackingTest::bitMax, + + &PackingTest::unpackUnsigned, &PackingTest::unpackSigned, &PackingTest::packUnsigned, &PackingTest::packSigned, @@ -56,6 +60,24 @@ PackingTest::PackingTest() { &PackingTest::unpackTypeDeduction}); } +void PackingTest::bitMax() { + CORRADE_COMPARE(Implementation::bitMax(), 0xff); + CORRADE_COMPARE(Implementation::bitMax(), 0x7f); + CORRADE_COMPARE(Implementation::bitMax(), 0xffff); + CORRADE_COMPARE(Implementation::bitMax(), 0x7fff); + CORRADE_COMPARE(Implementation::bitMax(), 0xffffffff); + CORRADE_COMPARE(Implementation::bitMax(), 0x7fffffff); + #ifndef CORRADE_TARGET_EMSCRIPTEN + CORRADE_COMPARE(Implementation::bitMax(), 0xffffffffffffffffull); + CORRADE_COMPARE(Implementation::bitMax(), 0x7fffffffffffffffll); + #endif + + CORRADE_COMPARE((Implementation::bitMax()), 16383); + CORRADE_COMPARE((Implementation::bitMax()), 16383); + CORRADE_COMPARE((Implementation::bitMax()), 8191); + CORRADE_COMPARE((Implementation::bitMax()), 8191); +} + void PackingTest::unpackUnsigned() { CORRADE_COMPARE((Math::unpack(0)), 0.0f); CORRADE_COMPARE((Math::unpack(149)), 0.584314f); @@ -75,7 +97,15 @@ void PackingTest::unpackUnsigned() { CORRADE_COMPARE((Math::unpack(8192)), 0.125002f); CORRADE_COMPARE((Math::unpack(49152)), 0.750011f); + /* Bits */ + CORRADE_COMPARE((Math::unpack(8191)), 0.124987f); + CORRADE_COMPARE((Math::unpack(8191)), 0.499969f); + CORRADE_COMPARE((Math::unpack(8191u)), 0.499969f); + CORRADE_COMPARE((Math::unpack(8191)), 1.0f); + + /* Vector overloads */ CORRADE_COMPARE(Math::unpack(Vector3ub(0, 127, 255)), Vector3(0.0f, 0.498039f, 1.0f)); + CORRADE_COMPARE((Math::unpack(Vector3ub(0, 31, 63))), Vector3(0.0f, 0.492063f, 1.0f)); } void PackingTest::unpackSigned() { @@ -102,7 +132,13 @@ void PackingTest::unpackSigned() { CORRADE_COMPARE((Math::unpack(16384)), 0.500015f); CORRADE_COMPARE((Math::unpack(-16384)), -0.500015f); + /* Bits */ + CORRADE_COMPARE((Math::unpack(8191)), 0.249977f); + CORRADE_COMPARE((Math::unpack(8191)), 1.0f); + + /* Vector overloads */ CORRADE_COMPARE(Math::unpack(Vector3b(0, -127, 64)), Vector3(0.0f, -1.0f, 0.503937f)); + CORRADE_COMPARE((Math::unpack(Vector3b(0, -31, 16))), Vector3(0.0f, -1.0f, 0.516129f)); } void PackingTest::packUnsigned() { @@ -129,7 +165,13 @@ void PackingTest::packUnsigned() { CORRADE_COMPARE(Math::pack(0.33f), 21626); CORRADE_COMPARE(Math::pack(0.66f), 43253); + /* Bits */ + CORRADE_COMPARE((Math::pack(0.5f)), 32767); + CORRADE_COMPARE((Math::pack(0.5f)), 8191); + + /* Vector overloads */ CORRADE_COMPARE(Math::pack(Vector3(0.0f, 0.5f, 1.0f)), Vector3ub(0, 127, 255)); + CORRADE_COMPARE((Math::pack(Vector3(0.0f, 0.5f, 1.0f))), Vector3ub(0, 31, 63)); } void PackingTest::packSigned() { @@ -166,7 +208,14 @@ void PackingTest::packSigned() { CORRADE_COMPARE(Math::pack(-0.33f), -10813); CORRADE_COMPARE(Math::pack(0.66f), 21626); + /* Bits */ + CORRADE_COMPARE((Math::pack(-0.5f)), -16383); + CORRADE_COMPARE((Math::pack(-0.5f)), -4095); + + /* Vector overloads */ CORRADE_COMPARE(Math::pack(Vector3(0.0f, -1.0f, 0.5f)), Vector3b(0, -127, 63)); + CORRADE_COMPARE((Math::pack(Vector3(0.0f, -1.0f, 0.5f))), Vector3b(0, -31, 15)); + } void PackingTest::reunpackUnsinged() {