text: //========= 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( fabsf( vOther.x ), fabsf( vOther.y ) );
  	fmax = Max( fmax, (float)fabsf( 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;
  		unsigned int rawInteger;
  		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);
  
  			output.rawInteger = 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
  
  