//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #ifndef COMPRESSED_VECTOR_H #define COMPRESSED_VECTOR_H #ifdef _WIN32 #pragma once #endif #include #include // For vec_t, put this somewhere else? #include "../tier0/basetypes.h" // For rand(). We really need a library! #include #include "../tier0/dbg.h" #include "vector.h" #include "mathlib.h" #if defined(_X360) #pragma bitfield_order(push, lsb_to_msb) #endif //========================================================= // fit a 3D vector into 32 bits //========================================================= class Vector32 { public: // Construction/destruction: Vector32(void); Vector32(vec_t X, vec_t Y, vec_t Z); // assignment Vector32 &operator=(const Vector &vOther); operator Vector(); private: unsigned short x : 10; unsigned short y : 10; unsigned short z : 10; unsigned short exp : 2; }; inline Vector32 &Vector32::operator=(const Vector &vOther) { CHECK_VALID(vOther); static float expScale[4] = {4.0f, 16.0f, 32.f, 64.f}; float fmax = Max(fabs(vOther.x), fabs(vOther.y)); fmax = Max(fmax, (float)fabs(vOther.z)); for (exp = 0; exp < 3; exp++) { if (fmax < expScale[exp]) break; } Assert(fmax < expScale[exp]); float fexp = 512.0f / expScale[exp]; x = Clamp((int)(vOther.x * fexp) + 512, 0, 1023); y = Clamp((int)(vOther.y * fexp) + 512, 0, 1023); z = Clamp((int)(vOther.z * fexp) + 512, 0, 1023); return *this; } inline Vector32::operator Vector() { Vector tmp; static float expScale[4] = {4.0f, 16.0f, 32.f, 64.f}; float fexp = expScale[exp] / 512.0f; tmp.x = (((int)x) - 512) * fexp; tmp.y = (((int)y) - 512) * fexp; tmp.z = (((int)z) - 512) * fexp; return tmp; } //========================================================= // Fit a unit vector into 32 bits //========================================================= class Normal32 { public: // Construction/destruction: Normal32(void); Normal32(vec_t X, vec_t Y, vec_t Z); // assignment Normal32 &operator=(const Vector &vOther); operator Vector(); private: unsigned short x : 15; unsigned short y : 15; unsigned short zneg : 1; }; inline Normal32 &Normal32::operator=(const Vector &vOther) { CHECK_VALID(vOther); x = Clamp((int)(vOther.x * 16384) + 16384, 0, 32767); y = Clamp((int)(vOther.y * 16384) + 16384, 0, 32767); zneg = (vOther.z < 0); // x = vOther.x; // y = vOther.y; // z = vOther.z; return *this; } inline Normal32::operator Vector() { Vector tmp; tmp.x = ((int)x - 16384) * (1 / 16384.0); tmp.y = ((int)y - 16384) * (1 / 16384.0); tmp.z = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y); if (zneg) tmp.z = -tmp.z; return tmp; } //========================================================= // 64 bit Quaternion //========================================================= class Quaternion64 { public: // Construction/destruction: Quaternion64(void); Quaternion64(vec_t X, vec_t Y, vec_t Z); // assignment // Quaternion& operator=(const Quaternion64 &vOther); Quaternion64 &operator=(const Quaternion &vOther); operator Quaternion(); private: uint64 x : 21; uint64 y : 21; uint64 z : 21; uint64 wneg : 1; }; inline Quaternion64::operator Quaternion() { Quaternion tmp; // shift to -1048576, + 1048575, then round down slightly to -1.0 < x < 1.0 tmp.x = ((int)x - 1048576) * (1 / 1048576.5f); tmp.y = ((int)y - 1048576) * (1 / 1048576.5f); tmp.z = ((int)z - 1048576) * (1 / 1048576.5f); tmp.w = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z); if (wneg) tmp.w = -tmp.w; return tmp; } inline Quaternion64 &Quaternion64::operator=(const Quaternion &vOther) { CHECK_VALID(vOther); x = Clamp((int)(vOther.x * 1048576) + 1048576, 0, 2097151); y = Clamp((int)(vOther.y * 1048576) + 1048576, 0, 2097151); z = Clamp((int)(vOther.z * 1048576) + 1048576, 0, 2097151); wneg = (vOther.w < 0); return *this; } //========================================================= // 48 bit Quaternion //========================================================= class Quaternion48 { public: // Construction/destruction: Quaternion48(void); Quaternion48(vec_t X, vec_t Y, vec_t Z); // assignment // Quaternion& operator=(const Quaternion48 &vOther); Quaternion48 &operator=(const Quaternion &vOther); operator Quaternion(); private: unsigned short x : 16; unsigned short y : 16; unsigned short z : 15; unsigned short wneg : 1; }; inline Quaternion48::operator Quaternion() { Quaternion tmp; tmp.x = ((int)x - 32768) * (1 / 32768.0); tmp.y = ((int)y - 32768) * (1 / 32768.0); tmp.z = ((int)z - 16384) * (1 / 16384.0); tmp.w = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z); if (wneg) tmp.w = -tmp.w; return tmp; } inline Quaternion48 &Quaternion48::operator=(const Quaternion &vOther) { CHECK_VALID(vOther); x = Clamp((int)(vOther.x * 32768) + 32768, 0, 65535); y = Clamp((int)(vOther.y * 32768) + 32768, 0, 65535); z = Clamp((int)(vOther.z * 16384) + 16384, 0, 32767); wneg = (vOther.w < 0); return *this; } //========================================================= // 32 bit Quaternion //========================================================= class Quaternion32 { public: // Construction/destruction: Quaternion32(void); Quaternion32(vec_t X, vec_t Y, vec_t Z); // assignment // Quaternion& operator=(const Quaternion48 &vOther); Quaternion32 &operator=(const Quaternion &vOther); operator Quaternion(); private: unsigned int x : 11; unsigned int y : 10; unsigned int z : 10; unsigned int wneg : 1; }; inline Quaternion32::operator Quaternion() { Quaternion tmp; tmp.x = ((int)x - 1024) * (1 / 1024.0); tmp.y = ((int)y - 512) * (1 / 512.0); tmp.z = ((int)z - 512) * (1 / 512.0); tmp.w = sqrt(1 - tmp.x * tmp.x - tmp.y * tmp.y - tmp.z * tmp.z); if (wneg) tmp.w = -tmp.w; return tmp; } inline Quaternion32 &Quaternion32::operator=(const Quaternion &vOther) { CHECK_VALID(vOther); x = Clamp((int)(vOther.x * 1024) + 1024, 0, 2047); y = Clamp((int)(vOther.y * 512) + 512, 0, 1023); z = Clamp((int)(vOther.z * 512) + 512, 0, 1023); wneg = (vOther.w < 0); return *this; } //========================================================= // 16 bit float //========================================================= const int float32bias = 127; const int float16bias = 15; const float maxfloat16bits = 65504.0f; class float16 { public: // float16() {} // float16( float f ) { m_storage.rawWord = ConvertFloatTo16bits(f); } void Init() { m_storage.rawWord = 0; } // float16& operator=(const float16 &other) { m_storage.rawWord = //other.m_storage.rawWord; return *this; } float16& operator=(const float //&other) { m_storage.rawWord = ConvertFloatTo16bits(other); return *this; } // operator unsigned short () { return m_storage.rawWord; } // operator float () { return Convert16bitFloatTo32bits( m_storage.rawWord //); } unsigned short GetBits() const { return m_storage.rawWord; } float GetFloat() const { return Convert16bitFloatTo32bits(m_storage.rawWord); } void SetFloat(float in) { m_storage.rawWord = ConvertFloatTo16bits(in); } bool IsInfinity() const { return m_storage.bits.biased_exponent == 31 && m_storage.bits.mantissa == 0; } bool IsNaN() const { return m_storage.bits.biased_exponent == 31 && m_storage.bits.mantissa != 0; } bool operator==(const float16 other) const { return m_storage.rawWord == other.m_storage.rawWord; } bool operator!=(const float16 other) const { return m_storage.rawWord != other.m_storage.rawWord; } // bool operator< (const float other) const { return GetFloat() < //other; } bool operator> (const float other) const { return GetFloat() > //other; } protected: union float32bits { float rawFloat; struct { unsigned int mantissa : 23; unsigned int biased_exponent : 8; unsigned int sign : 1; } bits; }; union float16bits { unsigned short rawWord; struct { unsigned short mantissa : 10; unsigned short biased_exponent : 5; unsigned short sign : 1; } bits; }; static bool IsNaN(float16bits in) { return in.bits.biased_exponent == 31 && in.bits.mantissa != 0; } static bool IsInfinity(float16bits in) { return in.bits.biased_exponent == 31 && in.bits.mantissa == 0; } // 0x0001 - 0x03ff static unsigned short ConvertFloatTo16bits(float input) { if (input > maxfloat16bits) input = maxfloat16bits; else if (input < -maxfloat16bits) input = -maxfloat16bits; float16bits output; float32bits inFloat; inFloat.rawFloat = input; output.bits.sign = inFloat.bits.sign; if ((inFloat.bits.biased_exponent == 0) && (inFloat.bits.mantissa == 0)) { // zero output.bits.mantissa = 0; output.bits.biased_exponent = 0; } else if ((inFloat.bits.biased_exponent == 0) && (inFloat.bits.mantissa != 0)) { // denorm -- denorm float maps to 0 half output.bits.mantissa = 0; output.bits.biased_exponent = 0; } else if ((inFloat.bits.biased_exponent == 0xff) && (inFloat.bits.mantissa == 0)) { #if 0 // infinity output.bits.mantissa = 0; output.bits.biased_exponent = 31; #else // infinity maps to maxfloat output.bits.mantissa = 0x3ff; output.bits.biased_exponent = 0x1e; #endif } else if ((inFloat.bits.biased_exponent == 0xff) && (inFloat.bits.mantissa != 0)) { #if 0 // NaN output.bits.mantissa = 1; output.bits.biased_exponent = 31; #else // NaN maps to zero output.bits.mantissa = 0; output.bits.biased_exponent = 0; #endif } else { // regular number int new_exp = inFloat.bits.biased_exponent - 127; if (new_exp < -24) { // this maps to 0 output.bits.mantissa = 0; output.bits.biased_exponent = 0; } if (new_exp < -14) { // this maps to a denorm output.bits.biased_exponent = 0; unsigned int exp_val = (unsigned int)(-14 - (inFloat.bits.biased_exponent - float32bias)); if (exp_val > 0 && exp_val < 11) { output.bits.mantissa = (1 << (10 - exp_val)) + (inFloat.bits.mantissa >> (13 + exp_val)); } } else if (new_exp > 15) { #if 0 // map this value to infinity output.bits.mantissa = 0; output.bits.biased_exponent = 31; #else // to big. . . maps to maxfloat output.bits.mantissa = 0x3ff; output.bits.biased_exponent = 0x1e; #endif } else { output.bits.biased_exponent = new_exp + 15; output.bits.mantissa = (inFloat.bits.mantissa >> 13); } } return output.rawWord; } static float Convert16bitFloatTo32bits(unsigned short input) { float32bits output; const float16bits &inFloat = *((float16bits *)&input); if (IsInfinity(inFloat)) { return maxfloat16bits * ((inFloat.bits.sign == 1) ? -1.0f : 1.0f); } if (IsNaN(inFloat)) { return 0.0; } if (inFloat.bits.biased_exponent == 0 && inFloat.bits.mantissa != 0) { // denorm const float half_denorm = (1.0f / 16384.0f); // 2^-14 float mantissa = ((float)(inFloat.bits.mantissa)) / 1024.0f; float sgn = (inFloat.bits.sign) ? -1.0f : 1.0f; output.rawFloat = sgn * mantissa * half_denorm; } else { // regular number unsigned mantissa = inFloat.bits.mantissa; unsigned biased_exponent = inFloat.bits.biased_exponent; unsigned sign = ((unsigned)inFloat.bits.sign) << 31; biased_exponent = ((biased_exponent - float16bias + float32bias) * (biased_exponent != 0)) << 23; mantissa <<= (23 - 10); *((unsigned *)&output) = (mantissa | biased_exponent | sign); } return output.rawFloat; } float16bits m_storage; }; class float16_with_assign : public float16 { public: float16_with_assign() {} float16_with_assign(float f) { m_storage.rawWord = ConvertFloatTo16bits(f); } float16 &operator=(const float16 &other) { m_storage.rawWord = ((float16_with_assign &)other).m_storage.rawWord; return *this; } float16 &operator=(const float &other) { m_storage.rawWord = ConvertFloatTo16bits(other); return *this; } // operator unsigned short () const { return m_storage.rawWord; } operator float() const { return Convert16bitFloatTo32bits(m_storage.rawWord); } }; //========================================================= // Fit a 3D vector in 48 bits //========================================================= class Vector48 { public: // Construction/destruction: Vector48(void) {} Vector48(vec_t X, vec_t Y, vec_t Z) { x.SetFloat(X); y.SetFloat(Y); z.SetFloat(Z); } // assignment Vector48 &operator=(const Vector &vOther); operator Vector(); const float operator[](int i) const { return (((float16 *)this)[i]).GetFloat(); } float16 x; float16 y; float16 z; }; inline Vector48 &Vector48::operator=(const Vector &vOther) { CHECK_VALID(vOther); x.SetFloat(vOther.x); y.SetFloat(vOther.y); z.SetFloat(vOther.z); return *this; } inline Vector48::operator Vector() { Vector tmp; tmp.x = x.GetFloat(); tmp.y = y.GetFloat(); tmp.z = z.GetFloat(); return tmp; } //========================================================= // Fit a 2D vector in 32 bits //========================================================= class Vector2d32 { public: // Construction/destruction: Vector2d32(void) {} Vector2d32(vec_t X, vec_t Y) { x.SetFloat(X); y.SetFloat(Y); } // assignment Vector2d32 &operator=(const Vector &vOther); Vector2d32 &operator=(const Vector2D &vOther); operator Vector2D(); void Init(vec_t ix = 0.f, vec_t iy = 0.f); float16_with_assign x; float16_with_assign y; }; inline Vector2d32 &Vector2d32::operator=(const Vector2D &vOther) { x.SetFloat(vOther.x); y.SetFloat(vOther.y); return *this; } inline Vector2d32::operator Vector2D() { Vector2D tmp; tmp.x = x.GetFloat(); tmp.y = y.GetFloat(); return tmp; } inline void Vector2d32::Init(vec_t ix, vec_t iy) { x.SetFloat(ix); y.SetFloat(iy); } #if defined(_X360) #pragma bitfield_order(pop) #endif #endif