etqw-sdk/source/idlib/geometry/DrawVert.h

494 lines
13 KiB
C++

// 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<<DRAWVERT_SIZE_SHIFT) );
assert_offsetof( idDrawVert, xyz, DRAWVERT_XYZ_OFFSET );
assert_offsetof( idDrawVert, _normal, DRAWVERT_NORMAL_OFFSET );
assert_offsetof( idDrawVert, _tangent, DRAWVERT_TANGENT_OFFSET );
ID_INLINE float idDrawVert::operator[]( const int index ) const {
assert( index >= 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<dword *>(this->color) = color;
}
ID_INLINE dword idDrawVert::GetColor( void ) const {
return *reinterpret_cast<const dword *>(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<<SHADOWVERT_SIZE_SHIFT) );
#endif /* !__DRAWVERT_H__ */