| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
- //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
- #pragma once
- #include "BsPrerequisitesUtil.h"
- namespace bs
- {
- /** @addtogroup General
- * @{
- */
- /** Floating point number broken down into components for easier access. */
- union Float754
- {
- UINT32 raw;
- float value;
- struct {
- #if BS_ENDIAN == BS_ENDIAN_BIG
- UINT32 negative : 1;
- UINT32 exponent : 8;
- UINT32 mantissa : 23;
- #else
- UINT32 mantissa : 23;
- UINT32 exponent : 8;
- UINT32 negative : 1;
- #endif
- } field;
- };
- /** 10-bit floating point number broken down into components for easier access. */
- union Float10
- {
- UINT32 raw;
- struct {
- #if BS_ENDIAN == BS_ENDIAN_BIG
- UINT32 exponent : 5;
- UINT32 mantissa : 5;
- #else
- UINT32 mantissa : 5;
- UINT32 exponent : 5;
- #endif
- } field;
- };
- /** 11-bit floating point number broken down into components for easier access. */
- union Float11
- {
- UINT32 raw;
- struct {
- #if BS_ENDIAN == BS_ENDIAN_BIG
- UINT32 exponent : 5;
- UINT32 mantissa : 6;
- #else
- UINT32 mantissa : 6;
- UINT32 exponent : 5;
- #endif
- } field;
- };
- /** Class for manipulating bit patterns. */
- class Bitwise
- {
- public:
- /** Returns the most significant bit set in a value. */
- static UINT32 mostSignificantBitSet(unsigned int value)
- {
- UINT32 result = 0;
- while (value != 0) {
- ++result;
- value >>= 1;
- }
- return result - 1;
- }
- /** Returns the power-of-two number greater or equal to the provided value. */
- static UINT32 nextPow2(UINT32 n)
- {
- --n;
- n |= n >> 16;
- n |= n >> 8;
- n |= n >> 4;
- n |= n >> 2;
- n |= n >> 1;
- ++n;
- return n;
- }
- /** Returns the power-of-two number closest to the provided value. */
- static UINT32 closestPow2(UINT32 n)
- {
- UINT32 next = nextPow2(n);
- UINT32 prev = next >> 1;
- if (n - prev < next - n)
- return prev;
-
- return next;
- }
- /** Determines whether the number is power-of-two or not. */
- template<typename T>
- static bool isPow2(T n)
- {
- return (n & (n - 1)) == 0;
- }
- /** Returns the number of bits a pattern must be shifted right by to remove right-hand zeros. */
- template<typename T>
- static unsigned int getBitShift(T mask)
- {
- if (mask == 0)
- return 0;
- unsigned int result = 0;
- while ((mask & 1) == 0) {
- ++result;
- mask >>= 1;
- }
- return result;
- }
- /** Takes a value with a given src bit mask, and produces another value with a desired bit mask. */
- template<typename SrcT, typename DestT>
- static DestT convertBitPattern(SrcT srcValue, SrcT srcBitMask, DestT destBitMask)
- {
- // Mask off irrelevant source value bits (if any)
- srcValue = srcValue & srcBitMask;
- // Shift source down to bottom of DWORD
- const unsigned int srcBitShift = getBitShift(srcBitMask);
- srcValue >>= srcBitShift;
- // Get max value possible in source from srcMask
- const SrcT srcMax = srcBitMask >> srcBitShift;
- // Get max available in dest
- const unsigned int destBitShift = getBitShift(destBitMask);
- const DestT destMax = destBitMask >> destBitShift;
- // Scale source value into destination, and shift back
- DestT destValue = (srcValue * destMax) / srcMax;
- return (destValue << destBitShift);
- }
- /**
- * Convert N bit color channel value to P bits. It fills P bits with the bit pattern repeated.
- * (this is /((1<<n)-1) in fixed point).
- */
- static unsigned int fixedToFixed(UINT32 value, unsigned int n, unsigned int p)
- {
- if (n > p)
- {
- // Less bits required than available; this is easy
- value >>= n - p;
- }
- else if (n < p)
- {
- // More bits required than are there, do the fill
- // Use old fashioned division, probably better than a loop
- if (value == 0)
- value = 0;
- else if (value == (static_cast<unsigned int>(1) << n) - 1)
- value = (1 << p) - 1;
- else value = value*(1 << p) / ((1 << n) - 1);
- }
- return value;
- }
- /**
- * Converts floating point value in range [0, 1] to an unsigned integer of a certain number of bits. Works for any
- * value of bits between 0 and 31.
- */
- static unsigned int unormToUint(float value, unsigned int bits)
- {
- if (value <= 0.0f) return 0;
- else if (value >= 1.0f) return (1 << bits) - 1;
- else return (unsigned int)(value * (1 << bits));
- }
- /**
- * Converts floating point value in range [-1, 1] to an unsigned integer of a certain number of bits. Works for any
- * value of bits between 0 and 31.
- */
- static unsigned int snormToUint(float value, unsigned int bits)
- {
- return unormToUint((value + 1.0f) * 0.5f, bits);
- }
- /** Converts an unsigned integer to a floating point in range [0, 1]. */
- static float uintToUnorm(unsigned value, unsigned int bits)
- {
- return (float)value / (float)((1 << bits) - 1);
- }
- /** Converts an unsigned integer to a floating point in range [-1, 1]. */
- static float uintToSnorm(unsigned value, unsigned int bits)
- {
- return uintToUnorm(value, bits) * 2.0f - 1.0f;
- }
- /** Write a n*8 bits integer value to memory in native endian. */
- static void intWrite(void *dest, const int n, const unsigned int value)
- {
- switch(n) {
- case 1:
- ((UINT8*)dest)[0] = (UINT8)value;
- break;
- case 2:
- ((UINT16*)dest)[0] = (UINT16)value;
- break;
- case 3:
- #if BS_ENDIAN == BS_ENDIAN_BIG
- ((UINT8*)dest)[0] = (UINT8)((value >> 16) & 0xFF);
- ((UINT8*)dest)[1] = (UINT8)((value >> 8) & 0xFF);
- ((UINT8*)dest)[2] = (UINT8)(value & 0xFF);
- #else
- ((UINT8*)dest)[2] = (UINT8)((value >> 16) & 0xFF);
- ((UINT8*)dest)[1] = (UINT8)((value >> 8) & 0xFF);
- ((UINT8*)dest)[0] = (UINT8)(value & 0xFF);
- #endif
- break;
- case 4:
- ((UINT32*)dest)[0] = (UINT32)value;
- break;
- }
- }
- /** Read a n*8 bits integer value to memory in native endian. */
- static unsigned int intRead(const void *src, int n) {
- switch(n) {
- case 1:
- return ((UINT8*)src)[0];
- case 2:
- return ((UINT16*)src)[0];
- case 3:
- #if BS_ENDIAN == BS_ENDIAN_BIG
- return ((UINT32)((UINT8*)src)[0]<<16)|
- ((UINT32)((UINT8*)src)[1]<<8)|
- ((UINT32)((UINT8*)src)[2]);
- #else
- return ((UINT32)((UINT8*)src)[0])|
- ((UINT32)((UINT8*)src)[1]<<8)|
- ((UINT32)((UINT8*)src)[2]<<16);
- #endif
- case 4:
- return ((UINT32*)src)[0];
- }
- return 0; // ?
- }
- /** Convert a float32 to a float16 (NV_half_float). */
- static UINT16 floatToHalf(float i)
- {
- union { float f; UINT32 i; } v;
- v.f = i;
- return floatToHalfI(v.i);
- }
- /** Converts float in UINT32 format to a a half in UINT16 format. */
- static UINT16 floatToHalfI(UINT32 i)
- {
- int s = (i >> 16) & 0x00008000;
- int e = ((i >> 23) & 0x000000ff) - (127 - 15);
- int m = i & 0x007fffff;
-
- if (e <= 0)
- {
- if (e < -10)
- {
- return 0;
- }
- m = (m | 0x00800000) >> (1 - e);
-
- return static_cast<UINT16>(s | (m >> 13));
- }
- else if (e == 0xff - (127 - 15))
- {
- if (m == 0) // Inf
- {
- return static_cast<UINT16>(s | 0x7c00);
- }
- else // NAN
- {
- m >>= 13;
- return static_cast<UINT16>(s | 0x7c00 | m | (m == 0));
- }
- }
- else
- {
- if (e > 30) // Overflow
- {
- return static_cast<UINT16>(s | 0x7c00);
- }
-
- return static_cast<UINT16>(s | (e << 10) | (m >> 13));
- }
- }
-
- /** Convert a float16 (NV_half_float) to a float32. */
- static float halfToFloat(UINT16 y)
- {
- union { float f; UINT32 i; } v;
- v.i = halfToFloatI(y);
- return v.f;
- }
- /** Converts a half in UINT16 format to a float in UINT32 format. */
- static UINT32 halfToFloatI(UINT16 y)
- {
- int s = (y >> 15) & 0x00000001;
- int e = (y >> 10) & 0x0000001f;
- int m = y & 0x000003ff;
-
- if (e == 0)
- {
- if (m == 0) // Plus or minus zero
- {
- return s << 31;
- }
- else // Denormalized number -- renormalize it
- {
- while (!(m & 0x00000400))
- {
- m <<= 1;
- e -= 1;
- }
-
- e += 1;
- m &= ~0x00000400;
- }
- }
- else if (e == 31)
- {
- if (m == 0) // Inf
- {
- return (s << 31) | 0x7f800000;
- }
- else // NaN
- {
- return (s << 31) | 0x7f800000 | (m << 13);
- }
- }
-
- e = e + (127 - 15);
- m = m << 13;
-
- return (s << 31) | (e << 23) | m;
- }
- /** Converts a 32-bit float to a 10-bit float according to OpenGL packed_float extension. */
- static UINT32 floatToFloat10(float v)
- {
- Float754 f;
- f.value = v;
- if (f.field.exponent == 0xFF)
- {
- // NAN or INF
- if (f.field.mantissa > 0)
- return 0x3E0 | (((f.raw >> 18) | (f.raw >> 13) | (f.raw >> 3) | f.raw) & 0x1F);
- else if (f.field.negative)
- return 0; // Negative infinity clamped to 0
- else
- return 0x3E0; // Positive infinity
- }
- else if (f.field.negative)
- return 0; // Negative clamped to 0, no negatives allowed
- else if (f.raw > 0x477C0000)
- return 0x3DF; // Too large, clamp to max value
- else
- {
- UINT32 val;
- if (f.raw < 0x38800000U)
- {
- // Too small to be represented as a normalized float, convert to denormalized value
- UINT32 shift = 113 - f.field.exponent;
- val = (0x800000U | f.field.mantissa) >> shift;
- }
- else
- {
- // Rebias exponent
- val = f.raw + 0xC8000000;
- }
- return ((val + 0x1FFFFU + ((val >> 18) & 1)) >> 18) & 0x3FF;
- }
- }
- /** Converts a 32-bit float to a 11-bit float according to OpenGL packed_float extension. */
- static UINT32 floatToFloat11(float v)
- {
- Float754 f;
- f.value = v;
- if (f.field.exponent == 0xFF)
- {
- // NAN or INF
- if (f.field.mantissa > 0)
- return 0x7C0 | (((f.raw >> 17) | (f.raw >> 11) | (f.raw >> 6) | f.raw) & 0x3F);
- else if (f.field.negative)
- return 0; // Negative infinity clamped to 0
- else
- return 0x7C0; // Positive infinity
- }
- else if (f.field.negative)
- return 0; // Negative clamped to 0, no negatives allowed
- else if (f.raw > 0x477E0000)
- return 0x7BF; // Too large, clamp to max value
- else
- {
- UINT32 val;
- if(f.raw < 0x38800000U)
- {
- // Too small to be represented as a normalized float, convert to denormalized value
- UINT32 shift = 113 - f.field.exponent;
- val = (0x800000U | f.field.mantissa) >> shift;
- }
- else
- {
- // Rebias exponent
- val = f.raw + 0xC8000000;
- }
- return ((val + 0xFFFFU + ((val >> 17) & 1)) >> 17) & 0x7FF;
- }
- }
- /** Converts a 10-bit float to a 32-bit float according to OpenGL packed_float extension. */
- static float float10ToFloat(UINT32 v)
- {
- Float10 f;
- f.raw = v;
- UINT32 output;
- if (f.field.exponent == 0x1F) // INF or NAN
- {
- output = 0x7f800000 | (f.field.mantissa << 17);
- }
- else
- {
- UINT32 exponent;
- UINT32 mantissa = f.field.mantissa;
- if (f.field.exponent != 0) // The value is normalized
- exponent = f.field.exponent;
- else if (mantissa != 0) // The value is denormalized
- {
- // Normalize the value in the resulting float
- exponent = 1;
- do
- {
- exponent--;
- mantissa <<= 1;
- } while ((mantissa & 0x20) == 0);
- mantissa &= 0x1F;
- }
- else // The value is zero
- exponent = (UINT32)-112;
- output = ((exponent + 112) << 23) | (mantissa << 18);
- }
- return *(float*)&output;
- }
- /** Converts a 11-bit float to a 32-bit float according to OpenGL packed_float extension. */
- static float float11ToFloat(UINT32 v)
- {
- Float11 f;
- f.raw = v;
- UINT32 output;
- if (f.field.exponent == 0x1F) // INF or NAN
- {
- output = 0x7f800000 | (f.field.mantissa << 17);
- }
- else
- {
- UINT32 exponent;
- UINT32 mantissa = f.field.mantissa;
- if (f.field.exponent != 0) // The value is normalized
- exponent = f.field.exponent;
- else if (mantissa != 0) // The value is denormalized
- {
- // Normalize the value in the resulting float
- exponent = 1;
- do
- {
- exponent--;
- mantissa <<= 1;
- } while ((mantissa & 0x40) == 0);
- mantissa &= 0x3F;
- }
- else // The value is zero
- exponent = (UINT32)-112;
- output = ((exponent + 112) << 23) | (mantissa << 17);
- }
- return *(float*)&output;
- }
- /** Converts a float in range [-1,1] into an unsigned 8-bit integer. */
- static UINT8 quantize8BitSigned(float v)
- {
- return quantize8BitUnsigned(v * 0.5f + 0.5f);
- }
- /** Converts a float in range [0,1] into an unsigned 8-bit integer. */
- static UINT8 quantize8BitUnsigned(float v)
- {
- return (UINT8)(v * 255.999f);
- }
- };
- /** @} */
- }
|