Browse Source

Math: ability to specify number of integer bits for {un,}pack().

This also allowed me to get rid of the <limits> header.
pull/190/head
Vladimír Vondruš 9 years ago
parent
commit
502d59c2a8
  1. 2
      src/Magnum/Math/Color.h
  2. 94
      src/Magnum/Math/Packing.h
  3. 51
      src/Magnum/Math/Test/PackingTest.cpp

2
src/Magnum/Math/Color.h

@ -201,7 +201,7 @@ template<class T> constexpr typename std::enable_if<std::is_floating_point<T>::v
return T(1);
}
template<class T> constexpr typename std::enable_if<std::is_integral<T>::value, T>::type fullChannel() {
return std::numeric_limits<T>::max();
return Implementation::bitMax<T>();
}
}

94
src/Magnum/Math/Packing.h

@ -25,12 +25,19 @@
DEALINGS IN THE SOFTWARE.
*/
#include <limits>
#include "Magnum/Math/Functions.h"
namespace Magnum { namespace Math {
namespace Implementation {
template<class T, UnsignedInt bits = sizeof(T)*8> inline constexpr T bitMax() {
return T(typename std::make_unsigned<T>::type(~T{}) >> (sizeof(T)*8 - (std::is_signed<T>::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<Float, UnsignedByte>('\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<class FloatingPoint, class Integral> 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<Float, UnsignedShort>(8191); // 0.124987f
Float b = Math::unpack<Float, UnsignedShort, 14>(8191); // 0.499969f
Float b = Math::unpack<Float, 14>(8191u); // 0.499969f
Float b = Math::unpack<Float, 14>(8191); // 1.0f
@endcode
*/
template<class FloatingPoint, class Integral, UnsignedInt bits> inline FloatingPoint unpack(const Integral& value);
#else
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_unsigned<Integral>::value, FloatingPoint>::type unpack(Integral value) {
template<class FloatingPoint, class Integral, UnsignedInt bits = sizeof(Integral)*8> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_unsigned<Integral>::value, FloatingPoint>::type unpack(Integral value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"unpacking must be done from integral to floating-point type");
return value/FloatingPoint(std::numeric_limits<Integral>::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<Integral, bits>());
}
template<class FloatingPoint, class Integral> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_signed<Integral>::value, FloatingPoint>::type unpack(Integral value) {
template<class FloatingPoint, class Integral, UnsignedInt bits = sizeof(Integral)*8> inline typename std::enable_if<std::is_arithmetic<Integral>::value && std::is_signed<Integral>::value, FloatingPoint>::type unpack(Integral value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"unpacking must be done from integral to floating-point type");
return Math::max(value/FloatingPoint(std::numeric_limits<Integral>::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<Integral, bits>()), FloatingPoint(-1.0));
}
template<class FloatingPoint, std::size_t size, class Integral> FloatingPoint unpack(const Vector<size, Integral>& value) {
template<class FloatingPoint, std::size_t size, class Integral, UnsignedInt bits = sizeof(Integral)*8> FloatingPoint unpack(const Vector<size, Integral>& value) {
FloatingPoint out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = unpack<typename FloatingPoint::Type, Integral>(value[i]);
out[i] = unpack<typename FloatingPoint::Type, Integral, bits>(value[i]);
return out;
}
#endif
/** @overload */
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class FloatingPoint, UnsignedInt bits, class Integral> inline FloatingPoint unpack(const Integral& value);
#else
template<class FloatingPoint, UnsignedInt bits, class Integral> inline typename std::enable_if<std::is_arithmetic<Integral>::value, FloatingPoint>::type unpack(const Integral& value) {
return unpack<FloatingPoint, Integral, bits>(value);
}
template<class FloatingPoint, UnsignedInt bits, std::size_t size, class Integral> inline FloatingPoint unpack(const Vector<size, Integral>& value) {
return unpack<FloatingPoint, size, Integral, bits>(value);
}
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
/** @copybrief unpack()
* @deprecated Use @ref unpack() instead.
@ -107,19 +142,42 @@ integral type.
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class Integral, class FloatingPoint> inline Integral pack(const FloatingPoint& value);
#else
template<class Integral, class FloatingPoint> inline typename std::enable_if<std::is_arithmetic<FloatingPoint>::value, Integral>::type pack(FloatingPoint value) {
template<class Integral, class FloatingPoint, UnsignedInt bits = sizeof(Integral)*8> inline typename std::enable_if<std::is_arithmetic<FloatingPoint>::value, Integral>::type pack(FloatingPoint value) {
static_assert(std::is_floating_point<FloatingPoint>::value && std::is_integral<Integral>::value,
"packing must be done from floating-point to integral type");
return Integral(value*std::numeric_limits<Integral>::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<Integral, bits>());
}
template<class Integral, std::size_t size, class FloatingPoint> Integral pack(const Vector<size, FloatingPoint>& value) {
template<class Integral, std::size_t size, class FloatingPoint, UnsignedInt bits = sizeof(typename Integral::Type)*8> Integral pack(const Vector<size, FloatingPoint>& value) {
Integral out{NoInit};
for(std::size_t i = 0; i != size; ++i)
out[i] = pack<typename Integral::Type, FloatingPoint>(value[i]);
out[i] = pack<typename Integral::Type, FloatingPoint, bits>(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<UnsignedShort>(0.5f); // 32767
auto b = Math::pack<UnsignedShort, 14>(0.5f); // 8191
@endcode
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
template<class Integral, UnsignedInt bits, class FloatingPoint> inline Integral pack(FloatingPoint value);
#else
template<class Integral, UnsignedInt bits, class FloatingPoint> inline typename std::enable_if<std::is_arithmetic<FloatingPoint>::value, Integral>::type pack(FloatingPoint value) {
return pack<Integral, FloatingPoint, bits>(value);
}
template<class Integral, UnsignedInt bits, std::size_t size, class FloatingPoint> inline Integral pack(const Vector<size, FloatingPoint>& value) {
return pack<Integral, size, FloatingPoint, bits>(value);
}
#endif
#ifdef MAGNUM_BUILD_DEPRECATED
/** @copybrief pack()
* @deprecated Use @ref pack() instead.

51
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<UnsignedByte> Vector3ub;
typedef Math::Vector3<Byte> 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<UnsignedByte>(), 0xff);
CORRADE_COMPARE(Implementation::bitMax<Byte>(), 0x7f);
CORRADE_COMPARE(Implementation::bitMax<UnsignedShort>(), 0xffff);
CORRADE_COMPARE(Implementation::bitMax<Short>(), 0x7fff);
CORRADE_COMPARE(Implementation::bitMax<UnsignedInt>(), 0xffffffff);
CORRADE_COMPARE(Implementation::bitMax<Int>(), 0x7fffffff);
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_COMPARE(Implementation::bitMax<UnsignedLong>(), 0xffffffffffffffffull);
CORRADE_COMPARE(Implementation::bitMax<Long>(), 0x7fffffffffffffffll);
#endif
CORRADE_COMPARE((Implementation::bitMax<UnsignedShort, 14>()), 16383);
CORRADE_COMPARE((Implementation::bitMax<UnsignedInt, 14>()), 16383);
CORRADE_COMPARE((Implementation::bitMax<Short, 14>()), 8191);
CORRADE_COMPARE((Implementation::bitMax<Int, 14>()), 8191);
}
void PackingTest::unpackUnsigned() {
CORRADE_COMPARE((Math::unpack<Float, UnsignedByte>(0)), 0.0f);
CORRADE_COMPARE((Math::unpack<Float, UnsignedByte>(149)), 0.584314f);
@ -75,7 +97,15 @@ void PackingTest::unpackUnsigned() {
CORRADE_COMPARE((Math::unpack<Float, UnsignedShort>(8192)), 0.125002f);
CORRADE_COMPARE((Math::unpack<Float, UnsignedShort>(49152)), 0.750011f);
/* Bits */
CORRADE_COMPARE((Math::unpack<Float, UnsignedShort>(8191)), 0.124987f);
CORRADE_COMPARE((Math::unpack<Float, UnsignedShort, 14>(8191)), 0.499969f);
CORRADE_COMPARE((Math::unpack<Float, 14>(8191u)), 0.499969f);
CORRADE_COMPARE((Math::unpack<Float, 14>(8191)), 1.0f);
/* Vector overloads */
CORRADE_COMPARE(Math::unpack<Vector3>(Vector3ub(0, 127, 255)), Vector3(0.0f, 0.498039f, 1.0f));
CORRADE_COMPARE((Math::unpack<Vector3, 6>(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<Float, Short>(16384)), 0.500015f);
CORRADE_COMPARE((Math::unpack<Float, Short>(-16384)), -0.500015f);
/* Bits */
CORRADE_COMPARE((Math::unpack<Float, Short>(8191)), 0.249977f);
CORRADE_COMPARE((Math::unpack<Float, 14>(8191)), 1.0f);
/* Vector overloads */
CORRADE_COMPARE(Math::unpack<Vector3>(Vector3b(0, -127, 64)), Vector3(0.0f, -1.0f, 0.503937f));
CORRADE_COMPARE((Math::unpack<Vector3, 6>(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<UnsignedShort>(0.33f), 21626);
CORRADE_COMPARE(Math::pack<UnsignedShort>(0.66f), 43253);
/* Bits */
CORRADE_COMPARE((Math::pack<UnsignedShort>(0.5f)), 32767);
CORRADE_COMPARE((Math::pack<UnsignedShort, 14>(0.5f)), 8191);
/* Vector overloads */
CORRADE_COMPARE(Math::pack<Vector3ub>(Vector3(0.0f, 0.5f, 1.0f)), Vector3ub(0, 127, 255));
CORRADE_COMPARE((Math::pack<Vector3ub, 6>(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<Short>(-0.33f), -10813);
CORRADE_COMPARE(Math::pack<Short>(0.66f), 21626);
/* Bits */
CORRADE_COMPARE((Math::pack<Short>(-0.5f)), -16383);
CORRADE_COMPARE((Math::pack<Short, 14>(-0.5f)), -4095);
/* Vector overloads */
CORRADE_COMPARE(Math::pack<Vector3b>(Vector3(0.0f, -1.0f, 0.5f)), Vector3b(0, -127, 63));
CORRADE_COMPARE((Math::pack<Vector3b, 6>(Vector3(0.0f, -1.0f, 0.5f))), Vector3b(0, -31, 15));
}
void PackingTest::reunpackUnsinged() {

Loading…
Cancel
Save