You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
608 lines
14 KiB
608 lines
14 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
|
|
#ifndef COMPRESSED_VECTOR_H |
|
#define COMPRESSED_VECTOR_H |
|
|
|
#ifdef _WIN32 |
|
#pragma once |
|
#endif |
|
|
|
#include <math.h> |
|
#include <float.h> |
|
|
|
// For vec_t, put this somewhere else? |
|
#include "basetypes.h" |
|
|
|
// For rand(). We really need a library! |
|
#include <stdlib.h> |
|
|
|
#include "tier0/dbg.h" |
|
#include "mathlib/vector.h" |
|
|
|
#include "mathlib/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 |
|
|
|
|