// Copyright (C) 2007 Id Software, Inc. // #ifndef __DRAWVERT_H__ #define __DRAWVERT_H__ /* =============================================================================== Draw Vertex. =============================================================================== */ #pragma pack( push, 1 ) class idDrawVert { public: /* The sizeof idDrawVert should be at least a multiple of 16 bytes to make the VMX128 code work. Ideally the sizeof idDrawVert will be a power of two to make indexing fast. */ #if defined( SD_USE_DRAWVERT_SIZE_32 ) idVec3 xyz; byte color[4]; short _normal[2]; short _tangent[2]; byte _signs[4]; // 0 == normal z, 1 == tangent.z, 2 == bitangent sign, 3 == unused short _st[2]; #else idVec3 xyz; byte color[4]; idVec3 _normal; byte _color2[4]; idVec4 _tangent; // [3] is texture polarity sign idVec2 _st; idVec2 _st2; #endif float operator[]( const int index ) const; float & operator[]( const int index ); void Clear( void ); #if defined( SD_USE_DRAWVERT_SIZE_32 ) const idVec3 GetNormal( void ) const; #else const idVec3 & GetNormal( void ) const; #endif float GetNormalIdx( int idx ) const; void SetNormal( float x, float y, float z ); void SetNormal( const idVec3 &n ); #if defined( SD_USE_DRAWVERT_SIZE_32 ) const idVec3 GetTangent( void ) const; const idVec4 GetTangentVec4( void ) const; #else const idVec3 & GetTangent( void ) const; const idVec4 & GetTangentVec4( void ) const; #endif void SetTangent( float x, float y, float z ); void SetTangent( const idVec3 &t ); const idVec3 GetBiTangent( void ) const; // derived from normal, tangent, and tangent flag void SetBiTangent( float x, float y, float z ); void SetBiTangent( const idVec3 &t ); float GetBiTangentSign( void ) const; void SetBiTangentSign( float sign ); // either 1.0f or -1.0f void SetColor( dword color ); dword GetColor( void ) const; float GetSTIdx( int idx ) const; void GetST( float &s, float &t ) const; #if defined( SD_USE_DRAWVERT_SIZE_32 ) idVec2 GetST( void ) const; #else const idVec2 & GetST( void ) const; #endif void SetST( bool lowrange, const idVec2 &st ); void SetST( float s, float t ); void SetST( const idVec2 &st ); void SetST( const idDrawVert &dv ); void SetSTIdx( int i, float v ); float GetZ( short x, short y, byte sign ) const; void Normalize( void ); void Lerp( const idDrawVert &a, const idDrawVert &b, const float f ); void LerpAll( const idDrawVert &a, const idDrawVert &b, const float f ); bool operator==( const idDrawVert& rhs ) const; }; #pragma pack( pop ) #define ST_TO_FLOAT 1.0f / 4096.0f #define FLOAT_TO_ST 4096.0f #define ST_TO_FLOAT_LOWRANGE 1.0f / 32767.0f #define FLOAT_TO_ST_LOWRANGE 32767.0f #if defined( SD_USE_DRAWVERT_SIZE_32 ) // offsets for SIMD code #define DRAWVERT_SIZE 32 // sizeof( idDrawVert ) #define DRAWVERT_SIZE_SHIFT 5 // log2( sizeof( idDrawVert ) ) #define DRAWVERT_XYZ_OFFSET (0*4) // offsetof( idDrawVert, xyz ) #define DRAWVERT_NORMAL_OFFSET (4*4) // offsetof( idDrawVert, normal ) #define DRAWVERT_TANGENT_OFFSET (5*4) // offsetof( idDrawVert, tangent ) #else // offsets for SIMD code #define DRAWVERT_SIZE 64 // sizeof( idDrawVert ) #define DRAWVERT_SIZE_SHIFT 6 // log2( sizeof( idDrawVert ) ) #define DRAWVERT_XYZ_OFFSET (0*4) // offsetof( idDrawVert, xyz ) #define DRAWVERT_NORMAL_OFFSET (4*4) // offsetof( idDrawVert, normal ) #define DRAWVERT_TANGENT_OFFSET (8*4) // offsetof( idDrawVert, tangent ) #endif assert_sizeof( idDrawVert, DRAWVERT_SIZE ); assert_sizeof( idDrawVert, (1<= 0 && index < 5 ); return ((float *)(&xyz))[index]; } ID_INLINE float &idDrawVert::operator[]( const int index ) { assert( index >= 0 && index < 5 ); return ((float *)(&xyz))[index]; } ID_INLINE bool idDrawVert::operator==( const idDrawVert& rhs ) const { return ( rhs.xyz.Compare( xyz ) && ( rhs._st[0] == _st[0] && rhs._st[1] == _st[1] ) ); } ID_INLINE void idDrawVert::Clear( void ) { xyz.Zero(); #if defined( SD_USE_DRAWVERT_SIZE_32 ) _normal[0] = _normal[1] = 0; _tangent[0] = _tangent[1] = 0; _signs[0] = _signs[1] = _signs[2] = _signs[3] = 0;//128; _st[0] = _st[1] = 0; color[0] = color[1] = color[2] = color[3] = 0; #else _normal.Zero(); _tangent.Zero(); _st.Zero(); _st2.Zero(); color[0] = color[1] = color[2] = color[3] = 0; _color2[0] = _color2[1] = _color2[2] = _color2[3] = 0; #endif } #if defined( SD_USE_DRAWVERT_SIZE_32 ) ID_INLINE const idVec3 idDrawVert::GetNormal( void ) const { return idVec3( _normal[0] / 32767.0f, _normal[1] / 32767.0f, GetZ( _normal[0], _normal[1], _signs[0] ) ); } #else ID_INLINE const idVec3 &idDrawVert::GetNormal( void ) const { return _normal; } #endif ID_INLINE float idDrawVert::GetNormalIdx( int idx ) const { #if defined( SD_USE_DRAWVERT_SIZE_32 ) if ( idx == 2 ) { return GetZ( _normal[0], _normal[1], _signs[0] ); } else { return _normal[idx] / 32767.0f; } #else return _normal[idx]; #endif } ID_INLINE void idDrawVert::SetNormal( const idVec3 &n ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) _normal[0] = n.x * 32767.0f; _normal[1] = n.y * 32767.0f; _signs[0] = ( n.z > 0.0f ) ? 2 : 0; #else _normal = n; #endif } ID_INLINE void idDrawVert::SetNormal( float x, float y, float z ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) _normal[0] = x * 32767.0f; _normal[1] = y * 32767.0f; _signs[0] = ( z > 0.0f ) ? 2 : 0; #else _normal.Set( x, y, z ); #endif } #if defined( SD_USE_DRAWVERT_SIZE_32 ) ID_INLINE const idVec3 idDrawVert::GetTangent( void ) const { return idVec3( _tangent[0] / 32767.0f, _tangent[1] / 32767.0f, GetZ( _tangent[0], _tangent[1], _signs[1] ) ); } ID_INLINE const idVec4 idDrawVert::GetTangentVec4( void ) const { return idVec4( _tangent[0] / 32767.0f, _tangent[1] / 32767.0f, GetZ( _tangent[0], _tangent[1], _signs[1] ), GetBiTangentSign() ); } #else ID_INLINE const idVec3& idDrawVert::GetTangent( void ) const { return _tangent.ToVec3(); } ID_INLINE const idVec4& idDrawVert::GetTangentVec4( void ) const { return _tangent; } #endif ID_INLINE void idDrawVert::SetTangent( float x, float y, float z ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) _tangent[0] = x * 32767.0f; _tangent[1] = y * 32767.0f; _signs[1] = ( z > 0.0f ) ? 2 : 0; #else _tangent.ToVec3().Set( x, y, z ); #endif } ID_INLINE void idDrawVert::SetTangent( const idVec3 &t ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) _tangent[0] = t.x * 32767.0f; _tangent[1] = t.y * 32767.0f; _signs[1] = ( t.z > 0.0f ) ? 2 : 0; #else _tangent.ToVec3() = t; #endif } ID_INLINE const idVec3 idDrawVert::GetBiTangent( void ) const { #if defined( SD_USE_DRAWVERT_SIZE_32 ) // derive from the normal, tangent, and bitangent direction flag idVec3 normal = GetNormal(); idVec3 tangent = GetTangent(); idVec3 bitangent; bitangent.Cross( normal, tangent ); bitangent *= ( _signs[2] - 1.f ); return bitangent; #else // derive from the normal, tangent, and bitangent direction flag idVec3 bitangent; bitangent.Cross( _normal, _tangent.ToVec3() ); bitangent *= _tangent[3]; return bitangent; #endif } ID_INLINE void idDrawVert::SetBiTangent( float x, float y, float z ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) idVec3 bitangent; bitangent.Cross( GetNormal(), GetTangent() ); _signs[2] = ( bitangent.x * x + bitangent.y * y + bitangent.z * z > 0.0f ) ? 2 : 0; #else idVec3 bitangent; bitangent.Cross( _normal, _tangent.ToVec3() ); _tangent[3] = ( bitangent.x * x + bitangent.y * y + bitangent.z * z > 0.0f ) ? 1.0f : -1.0f; #endif } ID_INLINE void idDrawVert::SetBiTangent( const idVec3 &t ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) idVec3 bitangent; bitangent.Cross( GetNormal(), GetTangent() ); _signs[2] = ( bitangent.x * t.x + bitangent.y * t.y + bitangent.z * t.z > 0.0f ) ? 2 : 0; #else _tangent[3] = idVec3::BiTangentSign( _normal, _tangent.ToVec3(), t ); #endif } ID_INLINE float idDrawVert::GetBiTangentSign( void ) const { #if defined( SD_USE_DRAWVERT_SIZE_32 ) return (_signs[2] - 1.f); #else return _tangent.w; #endif } ID_INLINE void idDrawVert::SetBiTangentSign( float sign ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) _signs[2] = sign > 0.f ? 2 : 0; #else _tangent[3] = sign; #endif } ID_INLINE void idDrawVert::SetColor( dword color ) { *reinterpret_cast(this->color) = color; } ID_INLINE dword idDrawVert::GetColor( void ) const { return *reinterpret_cast(this->color); } #if defined( SD_USE_DRAWVERT_SIZE_32 ) ID_INLINE idVec2 idDrawVert::GetST( void ) const { return idVec2( (float)_st[0] * ST_TO_FLOAT, (float)_st[1] * ST_TO_FLOAT ); } #else ID_INLINE const idVec2& idDrawVert::GetST( void ) const { return _st; } #endif #if defined( SD_USE_DRAWVERT_SIZE_32 ) ID_INLINE void idDrawVert::GetST( float &s, float &t ) const { s = (float)_st[0] * ST_TO_FLOAT; t = (float)_st[1] * ST_TO_FLOAT; } #else ID_INLINE void idDrawVert::GetST( float &s, float &t ) const { s = _st[0]; t = _st[1]; } #endif ID_INLINE float idDrawVert::GetSTIdx( int idx ) const { #if defined( SD_USE_DRAWVERT_SIZE_32 ) return _st[idx] * ST_TO_FLOAT; #else return _st[idx]; #endif } ID_INLINE void idDrawVert::SetST( float s, float t ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) _st[0] = (short)(s * FLOAT_TO_ST); _st[1] = (short)(t * FLOAT_TO_ST); #else _st[0] = s; _st[1] = t; #if 0 if ( _st[0] < -8.f || _st[0] > (32767/4096.f)) { assert(0); } if ( _st[1] < -8.f || _st[1] > (32767/4096.f)) { assert(0); } #endif #endif } ID_INLINE void idDrawVert::SetST( bool lowrange, const idVec2 &st ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) if ( lowrange ) { this->_st[0] = (short)(st.x * FLOAT_TO_ST_LOWRANGE); this->_st[1] = (short)(st.y * FLOAT_TO_ST_LOWRANGE); } else { this->_st[0] = (short)(st.x * FLOAT_TO_ST); this->_st[1] = (short)(st.y * FLOAT_TO_ST); } #else this->_st = st; #if 0 if ( _st[0] < -8.f || _st[0] > (32767/4096.f)) { assert(0); } if ( _st[1] < -8.f || _st[1] > (32767/4096.f)) { assert(0); } #endif #endif } ID_INLINE void idDrawVert::SetST( const idVec2 &st ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) this->_st[0] = (short)(st.x * FLOAT_TO_ST); this->_st[1] = (short)(st.y * FLOAT_TO_ST); #else this->_st = st; #if 0 if ( _st[0] < -8.f || _st[0] > (32767/4096.f)) { assert(0); } if ( _st[1] < -8.f || _st[1] > (32767/4096.f)) { assert(0); } #endif #endif } ID_INLINE void idDrawVert::SetST( const idDrawVert &dv ) { _st[0] = dv._st[0]; _st[1] = dv._st[1]; #if 0 if ( _st[0] < -8.f || _st[0] > (32767/4096.f)) { assert(0); } if ( _st[1] < -8.f || _st[1] > (32767/4096.f)) { assert(0); } #endif } ID_INLINE void idDrawVert::SetSTIdx( int idx, float v ) { #if defined( SD_USE_DRAWVERT_SIZE_32 ) _st[idx] = (short)(v * FLOAT_TO_ST); #else _st[idx] = v; #if 0 if ( _st[0] < -8.f || _st[0] > (32767/4096.f)) { assert(0); } if ( _st[1] < -8.f || _st[1] > (32767/4096.f)) { assert(0); } #endif #endif } ID_INLINE float idDrawVert::GetZ( short x, short y, byte sign ) const { float v = 1.0f - ( x * x + y * y ) / ( 32767.0f * 32767.0f ); float sqrtv = v > 0.f ? sqrtf( v ) : 0.f; return sqrtv * ( (float)sign - 1.f ); } ID_INLINE void idDrawVert::Lerp( const idDrawVert &a, const idDrawVert &b, const float f ) { xyz = a.xyz + f * ( b.xyz - a.xyz ); #if defined( SD_USE_DRAWVERT_SIZE_32 ) idVec2 aST = a.GetST(); idVec2 bST = b.GetST(); SetST( aST + f * ( bST - aST ) ); #else _st = a._st + f * ( b._st - a._st ); #endif } ID_INLINE void idDrawVert::LerpAll( const idDrawVert &a, const idDrawVert &b, const float f ) { xyz = a.xyz + f * ( b.xyz - a.xyz ); #if defined( SD_USE_DRAWVERT_SIZE_32 ) idVec2 ST = a.GetST() + f * ( b.GetST() - a.GetST() ); idVec3 normal = a.GetNormal() + f * ( b.GetNormal() - a.GetNormal() ); idVec3 tangent = a.GetTangent() + f * ( b.GetTangent() - a.GetTangent() ); SetST( ST ); SetNormal( normal ); SetTangent( tangent ); #else _st = a._st + f * ( b._st - a._st ); _normal = a._normal + f * ( b._normal - a._normal ); _tangent = a._tangent + f * ( b._tangent - a._tangent ); #endif color[0] = idMath::Ftob( a.color[0] + f * ( b.color[0] - a.color[0] ) ); color[1] = idMath::Ftob( a.color[1] + f * ( b.color[1] - a.color[1] ) ); color[2] = idMath::Ftob( a.color[2] + f * ( b.color[2] - a.color[2] ) ); color[3] = idMath::Ftob( a.color[3] + f * ( b.color[3] - a.color[3] ) ); } typedef struct shadowCache_s { idVec4 xyz; // we use homogenous coordinate tricks } shadowCache_t; #define SHADOWVERT_SIZE 16 // sizeof( idDrawVert ) #define SHADOWVERT_SIZE_SHIFT 4 // log2( sizeof( idDrawVert ) ) assert_sizeof( shadowCache_t, SHADOWVERT_SIZE ); assert_sizeof( shadowCache_t, (1<