diff options
Diffstat (limited to 'movieobjects/dmevertexdata.cpp')
| -rw-r--r-- | movieobjects/dmevertexdata.cpp | 1023 |
1 files changed, 1023 insertions, 0 deletions
diff --git a/movieobjects/dmevertexdata.cpp b/movieobjects/dmevertexdata.cpp new file mode 100644 index 0000000..6de6f7a --- /dev/null +++ b/movieobjects/dmevertexdata.cpp @@ -0,0 +1,1023 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "movieobjects/dmevertexdata.h" +#include "movieobjects_interfaces.h" +#include <limits.h> +#include "tier3/tier3.h" +#include "tier0/dbg.h" +#include "datamodel/dmelementfactoryhelper.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +//----------------------------------------------------------------------------- +// Standard vertex fields +//----------------------------------------------------------------------------- +static char *g_pStandardFieldNames[] = +{ + "positions", + "normals", + "tangents", + "textureCoordinates", + "colors", + "jointWeights", + "jointIndices", + "balance", + "speed", + "wrinkle", + "weight" +}; + +static DmAttributeType_t g_pStandardFieldTypes[] = +{ + AT_VECTOR3_ARRAY, + AT_VECTOR3_ARRAY, + AT_VECTOR4_ARRAY, + AT_VECTOR2_ARRAY, + AT_COLOR_ARRAY, + AT_FLOAT_ARRAY, + AT_INT_ARRAY, + AT_FLOAT_ARRAY, + AT_FLOAT_ARRAY, + AT_FLOAT_ARRAY, + AT_FLOAT_ARRAY +}; + + + +//----------------------------------------------------------------------------- +// Expose this class to the scene database +//----------------------------------------------------------------------------- +IMPLEMENT_ELEMENT_FACTORY( DmeVertexDataBase, CDmeVertexDataBase ); + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::OnConstruction() +{ + m_nVertexCount = 0; + memset( m_pStandardFieldIndex, 0xFF, sizeof(m_pStandardFieldIndex) ); + m_VertexFormat.Init( this, "vertexFormat" ); + + m_nJointCount.Init( this, "jointCount" ); + m_bFlipVCoordinates.Init( this, "flipVCoordinates" ); +} + +void CDmeVertexDataBase::OnDestruction() +{ +} + + +//----------------------------------------------------------------------------- +// Updates info for fast lookups for well-known fields +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::UpdateStandardFieldInfo( int nFieldIndex, const char *pFieldName, DmAttributeType_t attrType ) +{ + COMPILE_TIME_ASSERT( ARRAYSIZE(g_pStandardFieldNames) == STANDARD_FIELD_COUNT ); + COMPILE_TIME_ASSERT( ARRAYSIZE(g_pStandardFieldTypes) == STANDARD_FIELD_COUNT ); + + for ( int i = 0; i < STANDARD_FIELD_COUNT; ++i ) + { + if ( !Q_stricmp( pFieldName, g_pStandardFieldNames[i] ) ) + { + if ( attrType != g_pStandardFieldTypes[i] ) + { + Warning( "Standard field %s has incorrect attribute type!\n", pFieldName ); + return; + } + m_pStandardFieldIndex[i] = nFieldIndex; + break; + } + } +} + + +//----------------------------------------------------------------------------- +// Computes information about how to find particular fields +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::ComputeFieldInfo() +{ + // Clear existing field info, + // but keep the old names around so field indices remain constant + int nCurrentCount = m_FieldInfo.Count(); + for ( int i = 0; i < nCurrentCount; ++i ) + { + m_FieldInfo[i].m_pIndexData = NULL; + m_FieldInfo[i].m_pVertexData = NULL; + } + + // FIXME: Want to maintain field indices as constants for all time + int nFieldCount = m_VertexFormat.Count(); + for ( int i = 0; i < nFieldCount; ++i ) + { + const char *pFieldName = m_VertexFormat[i]; + int nLen = Q_strlen( pFieldName ) + 21; + char *pIndicesName = (char*)_alloca( nLen ); + Q_snprintf( pIndicesName, nLen, "%sIndices", pFieldName ); + + CDmAttribute *pVerticesArray = GetAttribute( pFieldName ); + if ( !pVerticesArray || !IsArrayType( pVerticesArray->GetType() ) ) + continue; + + CDmAttribute *pIndicesArray = NULL; + if ( Q_stricmp( pFieldName, g_pStandardFieldNames[FIELD_JOINT_WEIGHTS] ) && + Q_stricmp( pFieldName, g_pStandardFieldNames[FIELD_JOINT_INDICES] ) ) + { + pIndicesArray = GetAttribute( pIndicesName ); + if ( !pIndicesArray || pIndicesArray->GetType() != AT_INT_ARRAY ) + continue; + } + + FieldIndex_t nFieldIndex = FindFieldIndex( pFieldName ); + if ( nFieldIndex < 0 ) + { + nFieldIndex = m_FieldInfo.AddToTail(); + m_FieldInfo[nFieldIndex].m_Name = pFieldName; + m_FieldInfo[nFieldIndex].m_bInverseMapDirty = true; + UpdateStandardFieldInfo( nFieldIndex, pFieldName, pVerticesArray->GetType() ); + } + m_FieldInfo[nFieldIndex].m_pVertexData = pVerticesArray; + m_FieldInfo[nFieldIndex].m_pIndexData = pIndicesArray; + } +} + + +//----------------------------------------------------------------------------- +// Computes the vertex count ( min of the index buffers ) +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::ComputeVertexCount() +{ + int nCount = m_FieldInfo.Count(); + if ( nCount == 0 ) + { + m_nVertexCount = 0; + return; + } + + m_nVertexCount = INT_MAX; + for ( int i = 0; i < nCount; ++i ) + { + if ( !m_FieldInfo[i].m_pIndexData ) + continue; + + CDmrGenericArray array( m_FieldInfo[i].m_pIndexData ); + int nFieldCount = array.Count(); + if ( nFieldCount < m_nVertexCount ) + { + m_nVertexCount = nFieldCount; + } + } +} + + +//----------------------------------------------------------------------------- +// resolve internal data from changed attributes +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::Resolve() +{ + BaseClass::Resolve(); + + if ( m_VertexFormat.IsDirty() ) + { + ComputeFieldInfo(); + } + + if ( !IsVertexDeltaData() ) + { + ComputeVertexCount(); + } + + // Mark inverse map dirty if necessary + int nCount = m_FieldInfo.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( m_FieldInfo[i].m_pIndexData && m_FieldInfo[i].m_pIndexData->IsFlagSet( FATTRIB_DIRTY ) ) + { + m_FieldInfo[i].m_bInverseMapDirty = true; + } + } +} + + +//----------------------------------------------------------------------------- +// Returns indices into the various fields +//----------------------------------------------------------------------------- +int CDmeVertexDataBase::GetPositionIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_POSITION ); +} + +int CDmeVertexDataBase::GetNormalIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_NORMAL ); +} + +int CDmeVertexDataBase::GetTangentIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_TANGENT ); +} + +int CDmeVertexDataBase::GetTexCoordIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_TEXCOORD ); +} + +int CDmeVertexDataBase::GetColorIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_COLOR ); +} + +int CDmeVertexDataBase::GetBalanceIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_BALANCE ); +} + +int CDmeVertexDataBase::GetMorphSpeedIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_MORPH_SPEED ); +} + +int CDmeVertexDataBase::GetWrinkleIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_WRINKLE ); +} + +int CDmeVertexDataBase::GetWeightIndex( int nVertexIndex ) const +{ + return GetFieldIndex( nVertexIndex, FIELD_WEIGHT ); +} + + +//----------------------------------------------------------------------------- +// Vertex accessors +//----------------------------------------------------------------------------- +const Vector& CDmeVertexDataBase::GetPosition( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_POSITION]; + if ( nFieldIndex < 0 ) + return vec3_origin; + + CDmrArrayConst<int> indices( GetIndexData( nFieldIndex ) ); + CDmrArrayConst<Vector> vertexData( GetVertexData( nFieldIndex ) ); + return vertexData[ indices[nIndex] ]; +} + +const float *CDmeVertexDataBase::GetJointWeights( int nVertexIndex ) const +{ + Assert( IsVertexDeltaData() || nVertexIndex < m_nVertexCount ); + FieldIndex_t nPosFieldIndex = m_pStandardFieldIndex[FIELD_POSITION]; + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_JOINT_WEIGHTS]; + if ( nPosFieldIndex < 0 || nFieldIndex < 0 ) + return NULL; + + CDmrArrayConst<int> indices = GetIndexData( nPosFieldIndex ); + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return &vertexData[ indices[ nVertexIndex ] * m_nJointCount ]; +} + + +//----------------------------------------------------------------------------- +// Same as GetJointWeights except it uses a direct position index instead of +// the vertex index to access the data +//----------------------------------------------------------------------------- +const float *CDmeVertexDataBase::GetJointPositionWeights( int nPositionIndex ) const +{ + Assert( !IsVertexDeltaData() ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_JOINT_WEIGHTS]; + if ( nFieldIndex < 0 ) + return NULL; + + CDmrArrayConst< float > jointWeights = GetVertexData( nFieldIndex ); + Assert( nPositionIndex * m_nJointCount < jointWeights.Count() ); + return &jointWeights[ nPositionIndex * m_nJointCount ]; +} + +const int *CDmeVertexDataBase::GetJointIndices( int nVertexIndex ) const +{ + Assert( IsVertexDeltaData() || nVertexIndex < m_nVertexCount ); + FieldIndex_t nPosFieldIndex = m_pStandardFieldIndex[FIELD_POSITION]; + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_JOINT_INDICES]; + if ( nPosFieldIndex < 0 || nFieldIndex < 0 ) + return NULL; + + CDmrArrayConst<int> indices = GetIndexData( nPosFieldIndex ); + CDmrArrayConst<int> vertexData = GetVertexData( nFieldIndex ); + return &vertexData[ indices[ nVertexIndex ] * m_nJointCount ]; +} + + +//----------------------------------------------------------------------------- +// Same as GetJointIndices except it uses a direct position index instead of +// the vertex index to access the data +//----------------------------------------------------------------------------- +const int *CDmeVertexDataBase::GetJointPositionIndices( int nPositionIndex ) const +{ + Assert( !IsVertexDeltaData() ); + FieldIndex_t nJointIndicesField = m_pStandardFieldIndex[ FIELD_JOINT_INDICES ]; + if ( nJointIndicesField < 0 ) + return NULL; + + CDmrArrayConst<int> jointIndices = GetVertexData( nJointIndicesField ); + Assert( nPositionIndex * m_nJointCount < jointIndices.Count() ); + return &jointIndices[ nPositionIndex * m_nJointCount ]; +} + +const Vector& CDmeVertexDataBase::GetNormal( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_NORMAL]; + if ( nFieldIndex < 0 ) + return vec3_origin; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<Vector> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + +const Vector4D& CDmeVertexDataBase::GetTangent( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_TANGENT]; + if ( nFieldIndex < 0 ) + return vec4_origin; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<Vector4D> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + +const Vector2D& CDmeVertexDataBase::GetTexCoord( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_TEXCOORD]; + if ( nFieldIndex < 0 ) + return vec2_origin; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<Vector2D> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + +static Color s_Black( 0, 0, 0, 255 ); +const Color& CDmeVertexDataBase::GetColor( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_COLOR]; + if ( nFieldIndex < 0 ) + return s_Black; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<Color> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + +float CDmeVertexDataBase::GetBalance( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_BALANCE]; + if ( nFieldIndex < 0 ) + return 0.5f; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + +float CDmeVertexDataBase::GetMorphSpeed( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_MORPH_SPEED]; + if ( nFieldIndex < 0 ) + return 1.0f; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + +float CDmeVertexDataBase::GetWrinkle( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_WRINKLE]; + if ( nFieldIndex < 0 ) + return 1.0f; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +float CDmeVertexDataBase::GetWeight( int nIndex ) const +{ + Assert( IsVertexDeltaData() || nIndex < m_nVertexCount ); + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_WEIGHT]; + if ( nFieldIndex < 0 ) + return 1.0f; + + CDmrArrayConst<int> indices = GetIndexData( nFieldIndex ); + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData[ indices[ nIndex ] ]; +} + + +//----------------------------------------------------------------------------- +// Adds a field to the vertex format +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::FindOrAddVertexField( const char *pFieldName ) +{ + int i; + int nFormatCount = m_VertexFormat.Count(); + for ( i = 0; i < nFormatCount; ++i ) + { + if ( !Q_stricmp( pFieldName, m_VertexFormat[i] ) ) + return; + } + m_VertexFormat.AddToTail( pFieldName ); +} + + +//----------------------------------------------------------------------------- +// Returns the field index of a particular field +//----------------------------------------------------------------------------- +FieldIndex_t CDmeVertexDataBase::CreateField( const char *pFieldName, DmAttributeType_t type ) +{ + Assert( Q_stricmp( pFieldName, g_pStandardFieldNames[FIELD_JOINT_WEIGHTS] ) ); + Assert( Q_stricmp( pFieldName, g_pStandardFieldNames[FIELD_JOINT_INDICES] ) ); + if ( !Q_stricmp( pFieldName, g_pStandardFieldNames[FIELD_JOINT_WEIGHTS] ) || + !Q_stricmp( pFieldName, g_pStandardFieldNames[FIELD_JOINT_INDICES] ) ) + { + return -1; + } + + AddAttribute( pFieldName, type ); + + int nLen = Q_strlen( pFieldName ) + 21; + char *pIndicesName = (char*)_alloca( nLen ); + Q_snprintf( pIndicesName, nLen, "%sIndices", pFieldName ); + AddAttribute( pIndicesName, AT_INT_ARRAY ); + + FindOrAddVertexField( pFieldName ); + + // FIXME: Not hugely efficient, is there a better way of doing this? + // Necessary to return a field index for the name + ComputeFieldInfo(); + FieldIndex_t nFieldIndex = FindFieldIndex( pFieldName ); + if ( !IsVertexDeltaData() && m_nVertexCount > 0 ) + { + CDmrArray<int> indices( GetIndexData( nFieldIndex ) ); + indices.EnsureCount( m_nVertexCount ); + } + return nFieldIndex; +} + + +//----------------------------------------------------------------------------- +// Creates a field given a file ID +//----------------------------------------------------------------------------- +FieldIndex_t CDmeVertexDataBase::CreateField( StandardFields_t fieldId ) +{ + return CreateField( g_pStandardFieldNames[fieldId], g_pStandardFieldTypes[fieldId] ); +} + + +//----------------------------------------------------------------------------- +// Use this to create vertex fields for joint weights + indices +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::CreateJointWeightsAndIndices( int nJointCount, FieldIndex_t *pJointWeightsField, FieldIndex_t *pJointIndicesField ) +{ + m_nJointCount = nJointCount; + + AddAttribute( g_pStandardFieldNames[FIELD_JOINT_WEIGHTS], AT_FLOAT_ARRAY ); + AddAttribute( g_pStandardFieldNames[FIELD_JOINT_INDICES], AT_INT_ARRAY ); + + FindOrAddVertexField( g_pStandardFieldNames[FIELD_JOINT_WEIGHTS] ); + FindOrAddVertexField( g_pStandardFieldNames[FIELD_JOINT_INDICES] ); + + + // FIXME: Not hugely efficient, is there a better way of doing this? + // Necessary to return a field index for the name + ComputeFieldInfo(); + *pJointWeightsField = FindFieldIndex( g_pStandardFieldNames[FIELD_JOINT_WEIGHTS] ); + *pJointIndicesField = FindFieldIndex( g_pStandardFieldNames[FIELD_JOINT_INDICES] ); +} + + +//----------------------------------------------------------------------------- +// Adds a new vertex; creates a new entry in all vertex data fields +// Returns the vertex index +//----------------------------------------------------------------------------- +int CDmeVertexDataBase::AddVertexData( FieldIndex_t nFieldIndex, int nCount ) +{ + CDmrGenericArray array( m_FieldInfo[nFieldIndex].m_pVertexData ); + int nDataCount = array.Count(); + array.EnsureCount( nDataCount + nCount ); + + // DmeMeshDeltaData must have the same number of vertices + indices + if ( IsVertexDeltaData() ) + { + CDmrArray<int> indices( GetIndexData( nFieldIndex ) ); + Assert( nDataCount == indices.Count() ); + indices.EnsureCount( nDataCount + nCount ); + } + + return nDataCount; +} + + +//----------------------------------------------------------------------------- +// Sets vertex data +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::SetVertexData( FieldIndex_t nFieldIndex, int nFirstVertex, int nCount, DmAttributeType_t valueType, const void *pData ) +{ + CDmrGenericArray array( m_FieldInfo[nFieldIndex].m_pVertexData ); + Assert( nFirstVertex + nCount <= array.Count() ); + array.SetMultiple( nFirstVertex, nCount, valueType, pData ); +} + +void CDmeVertexDataBase::SetVertexIndices( FieldIndex_t nFieldIndex, int nFirstIndex, int nCount, const int *pIndices ) +{ + CDmrArray<int> array( GetIndexData( nFieldIndex ) ); + Assert( nFirstIndex + nCount <= array.Count() ); + array.SetMultiple( nFirstIndex, nCount, pIndices ); +} + + +//----------------------------------------------------------------------------- +// Removes all vertex data associated with a particular field +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::RemoveAllVertexData( FieldIndex_t nFieldIndex ) +{ + CDmrGenericArray array( m_FieldInfo[nFieldIndex].m_pVertexData ); + array.RemoveAll(); + if ( IsVertexDeltaData() ) + { + CDmrArray<int> arrayDelta( m_FieldInfo[nFieldIndex].m_pIndexData ); + arrayDelta.RemoveAll(); + } +} + + +//----------------------------------------------------------------------------- +// Returns the field index of a particular field +//----------------------------------------------------------------------------- +FieldIndex_t CDmeVertexDataBase::FindFieldIndex( const char *pFieldName ) const +{ + int nCount = m_FieldInfo.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( !Q_stricmp( m_FieldInfo[i].m_Name, pFieldName ) ) + return i; + } + return -1; +} + + +//----------------------------------------------------------------------------- +// Returns well-known vertex data +//----------------------------------------------------------------------------- +static CUtlVector<Vector4D> s_EmptyVector4D; +static CUtlVector<Vector> s_EmptyVector; +static CUtlVector<Vector2D> s_EmptyVector2D; +static CUtlVector<Color> s_EmptyColor; +static CUtlVector<float> s_EmptyFloat; + +const CUtlVector<Vector> &CDmeVertexDataBase::GetPositionData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_POSITION ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyVector; + + CDmrArrayConst<Vector> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const CUtlVector<Vector> &CDmeVertexDataBase::GetNormalData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_NORMAL ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyVector; + + CDmrArrayConst<Vector> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const CUtlVector<Vector4D> &CDmeVertexDataBase::GetTangentData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_TANGENT ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyVector4D; + + CDmrArrayConst<Vector4D> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const CUtlVector<Vector2D> &CDmeVertexDataBase::GetTextureCoordData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_TEXCOORD ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyVector2D; + + CDmrArrayConst<Vector2D> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const CUtlVector<Color> &CDmeVertexDataBase::GetColorData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_COLOR ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyColor; + + CDmrArrayConst<Color> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const float *CDmeVertexDataBase::GetJointWeightData( int nDataIndex ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_JOINT_WEIGHTS]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return NULL; + + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return &vertexData[ nDataIndex * m_nJointCount ]; +} + +const int *CDmeVertexDataBase::GetJointIndexData( int nDataIndex ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[FIELD_JOINT_INDICES]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return NULL; + + CDmrArrayConst<int> vertexData = GetVertexData( nFieldIndex ); + return &vertexData.Element( nDataIndex * m_nJointCount ); +} + +const CUtlVector<float> &CDmeVertexDataBase::GetBalanceData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_BALANCE ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyFloat; + + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const CUtlVector<float> &CDmeVertexDataBase::GetMorphSpeedData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_MORPH_SPEED ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyFloat; + + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const CUtlVector<float> &CDmeVertexDataBase::GetWrinkleData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_WRINKLE ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyFloat; + + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + +const CUtlVector<float> &CDmeVertexDataBase::GetWeightData( ) const +{ + FieldIndex_t nFieldIndex = m_pStandardFieldIndex[ FIELD_WEIGHT ]; + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyFloat; + + CDmrArrayConst<float> vertexData = GetVertexData( nFieldIndex ); + return vertexData.Get(); +} + + +//----------------------------------------------------------------------------- +// Returns well-known index data +//----------------------------------------------------------------------------- +static CUtlVector<int> s_EmptyInt; +const CUtlVector<int> &CDmeVertexDataBase::GetVertexIndexData( FieldIndex_t nFieldIndex ) const +{ + if ( nFieldIndex < 0 || nFieldIndex >= m_FieldInfo.Count() ) + return s_EmptyInt; + + CDmrArrayConst<int> indexData = GetIndexData( nFieldIndex ); + return indexData.Get(); +} + +const CUtlVector<int> &CDmeVertexDataBase::GetVertexIndexData( StandardFields_t fieldId ) const +{ + return GetVertexIndexData( m_pStandardFieldIndex[fieldId] ); +} + + +//----------------------------------------------------------------------------- +// Returns an inverse map from vertex data index to vertex index +//----------------------------------------------------------------------------- +const CUtlVector< int > &CDmeVertexDataBase::FindVertexIndicesFromDataIndex( FieldIndex_t nFieldIndex, int nDataIndex ) +{ + if ( nFieldIndex < 0 ) + return s_EmptyInt; + + FieldInfo_t &info = m_FieldInfo[nFieldIndex]; + if ( info.m_bInverseMapDirty ) + { + CDmrArrayConst<int> array( info.m_pIndexData ); + CDmrGenericArray vertexArray( info.m_pVertexData ); + + int nDataCount = vertexArray.Count(); + int nCount = array.Count(); + + // Clear out the utlvectors + info.m_InverseMap.RemoveAll(); + info.m_InverseMap.SetCount( nDataCount ); + + for ( int i = 0; i < nCount; ++i ) + { + int nIndex = array[ i ]; + info.m_InverseMap[nIndex].AddToTail( i ); + } + info.m_bInverseMapDirty = false; + } + + return info.m_InverseMap[ nDataIndex ]; +} + +const CUtlVector< int > &CDmeVertexDataBase::FindVertexIndicesFromDataIndex( StandardFields_t fieldId, int nDataIndex ) +{ + // NOTE! Wrinkles don't exist in the base state, therefore we use the index to index + // into the TEXCOORD base state fields instead of the wrinkle fields + if ( fieldId == FIELD_WRINKLE ) + { + fieldId = FIELD_TEXCOORD; + } + + return FindVertexIndicesFromDataIndex( m_pStandardFieldIndex[fieldId], nDataIndex ); +} + + +//----------------------------------------------------------------------------- +// Do we have skinning data? +//----------------------------------------------------------------------------- +bool CDmeVertexDataBase::HasSkinningData() const +{ + if ( m_nJointCount == 0 ) + return false; + FieldIndex_t nWeightFieldIndex = m_pStandardFieldIndex[FIELD_JOINT_WEIGHTS]; + if ( nWeightFieldIndex < 0 ) + return false; + FieldIndex_t nIndexFieldIndex = m_pStandardFieldIndex[FIELD_JOINT_INDICES]; + if ( nIndexFieldIndex < 0 ) + return false; + + CDmrArrayConst<float> weightData = GetVertexData( nWeightFieldIndex ); + CDmrArrayConst<int> indexData = GetVertexData( nIndexFieldIndex ); + return ( weightData.Count() > 0 && indexData.Count() > 0 ); +} + + +//----------------------------------------------------------------------------- +// Do we need tangent data? (Utility method for applications to know if they should call ComputeDefaultTangentData) +//----------------------------------------------------------------------------- +bool CDmeVertexDataBase::NeedsTangentData() const +{ + FieldIndex_t posField = m_pStandardFieldIndex[CDmeVertexDataBase::FIELD_POSITION]; + FieldIndex_t normalField = m_pStandardFieldIndex[CDmeVertexDataBase::FIELD_NORMAL]; + FieldIndex_t uvField = m_pStandardFieldIndex[CDmeVertexDataBase::FIELD_TEXCOORD]; + FieldIndex_t tangentField = m_pStandardFieldIndex[CDmeVertexDataBase::FIELD_TANGENT]; + return ( posField >= 0 && uvField >= 0 && normalField >= 0 && tangentField < 0 ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +int CDmeVertexDataBase::FieldCount() const +{ + return m_VertexFormat.Count(); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +const char *CDmeVertexDataBase::FieldName( int i ) const +{ + if ( i < 0 || i >= m_VertexFormat.Count() ) + return NULL; + + return m_VertexFormat[ i ]; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::CopyFrom( CDmeVertexDataBase *pSrc ) +{ + pSrc->CopyTo( this ); +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +void CDmeVertexDataBase::CopyTo( CDmeVertexDataBase *pDst ) const +{ + // Preserve the name of the destination + const CUtlString dstName = pDst->GetName(); + + CopyAttributesTo( pDst ); + + pDst->SetName( dstName ); // The Copy really copies everything! + pDst->Resolve(); +} + + +//----------------------------------------------------------------------------- +// Expose this class to the scene database +//----------------------------------------------------------------------------- +IMPLEMENT_ELEMENT_FACTORY( DmeVertexData, CDmeVertexData ); +IMPLEMENT_ELEMENT_FACTORY( DmeVertexDeltaData, CDmeVertexDeltaData ); + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDmeVertexData::OnConstruction() +{ +} + +void CDmeVertexData::OnDestruction() +{ +} + +void CDmeVertexDeltaData::OnConstruction() +{ + m_bCorrected.InitAndSet( this, "corrected", false ); +} + +void CDmeVertexDeltaData::OnDestruction() +{ +} + + +//----------------------------------------------------------------------------- +// Method to add vertex indices for normal vertex data +//----------------------------------------------------------------------------- +int CDmeVertexData::AddVertexIndices( int nIndexCount ) +{ + int nFirstVertex = m_nVertexCount; + m_nVertexCount += nIndexCount; + int nCount = m_FieldInfo.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( m_FieldInfo[i].m_pIndexData ) + { + CDmrArray<int> indices( m_FieldInfo[i].m_pIndexData ); + indices.EnsureCount( m_nVertexCount ); + } + } + return nFirstVertex; +} + + +//----------------------------------------------------------------------------- +// Computes max positional delta length +//----------------------------------------------------------------------------- +float CDmeVertexDeltaData::ComputeMaxDeflection( ) +{ + float flMaxDeflection = 0.0f; + + const CUtlVector<Vector> &pos = GetPositionData(); + int nCount = pos.Count(); + for ( int i = 0; i < nCount; ++i ) + { + float flDeflection = pos[i].Length(); + if ( flMaxDeflection < flDeflection ) + { + flMaxDeflection = flDeflection; + } + } + return flMaxDeflection; +} + + +//----------------------------------------------------------------------------- +// Computes wrinkle data from position deltas +//----------------------------------------------------------------------------- +void CDmeVertexDeltaData::GenerateWrinkleDelta( CDmeVertexData *pBindState, float flScale, bool bOverwrite ) +{ + FieldIndex_t nPosIndex = FindFieldIndex( FIELD_POSITION ); + if ( nPosIndex < 0 ) + return; + + FieldIndex_t nBaseTexCoordIndex = pBindState->FindFieldIndex( FIELD_TEXCOORD ); + if ( nBaseTexCoordIndex < 0 ) + return; + + FieldIndex_t nWrinkleIndex = FindFieldIndex( FIELD_WRINKLE ); + if ( nWrinkleIndex < 0 ) + { + nWrinkleIndex = CreateField( FIELD_WRINKLE ); + } + else if ( !bOverwrite ) + return; + + RemoveAllVertexData( nWrinkleIndex ); + if ( flScale == 0.0f ) + return; + + const float flMaxDeflection( ComputeMaxDeflection() ); + if ( flMaxDeflection == 0.0f ) + return; + + const double scaledInverseMaxDeflection = static_cast< double >( flScale ) / static_cast< double >( flMaxDeflection ); + + const CUtlVector<int> &positionIndices = GetVertexIndexData( nPosIndex ); + const CUtlVector<Vector> &pos = GetPositionData(); + const CUtlVector<int> &baseTexCoordIndices = pBindState->GetVertexIndexData( nBaseTexCoordIndex ); + + CDmrArrayConst<Vector2D> texData( pBindState->GetVertexData( nBaseTexCoordIndex ) ); + int nBaseTexCoordCount = texData.Count(); + int nBufSize = ( ( nBaseTexCoordCount + 7 ) >> 3 ); + unsigned char *pUsedBits = (unsigned char*)_alloca( nBufSize ); + memset( pUsedBits, 0, nBufSize ); + + int nCount = pos.Count(); + for ( int i = 0; i < nCount; ++i ) + { + float flWrinkleDelta = static_cast< float >( static_cast< double >( pos[i].Length() ) * scaledInverseMaxDeflection ); + Assert( fabs( flWrinkleDelta ) <= fabs( flScale ) ); + + // NOTE: This will produce bad behavior in cases where two positions share the + // same texcoord, which shouldn't theoretically happen. + const CUtlVector< int > &baseVerts = pBindState->FindVertexIndicesFromDataIndex( FIELD_POSITION, positionIndices[i] ); + int nBaseVertCount = baseVerts.Count(); + for ( int j = 0; j < nBaseVertCount; ++j ) + { + // See if we have a delta for this texcoord... + int nTexCoordIndex = baseTexCoordIndices[ baseVerts[j] ]; + if ( pUsedBits[ nTexCoordIndex >> 3 ] & ( 1 << ( nTexCoordIndex & 0x7 ) ) ) + continue; + + pUsedBits[ nTexCoordIndex >> 3 ] |= 1 << ( nTexCoordIndex & 0x7 ); + + int nDeltaIndex = AddVertexData( nWrinkleIndex, 1 ); + SetVertexIndices( nWrinkleIndex, nDeltaIndex, 1, &nTexCoordIndex ); + SetVertexData( nWrinkleIndex, nDeltaIndex, 1, AT_FLOAT, &flWrinkleDelta ); + } + } +} + +//----------------------------------------------------------------------------- +// Computes weight data from position deltas +//----------------------------------------------------------------------------- +float CDmeVertexDeltaData::GenerateWeightDelta( CDmeVertexData *pBindState ) +{ + FieldIndex_t nPosIndex = FindFieldIndex( FIELD_POSITION ); + if ( nPosIndex < 0 ) + return 0.0; + + FieldIndex_t nFieldIndex = FindFieldIndex( FIELD_WEIGHT ); + if ( nFieldIndex < 0 ) + { + nFieldIndex = CreateField( FIELD_WEIGHT ); + } + + RemoveAllVertexData( nFieldIndex ); + + const float maxDeflection( static_cast< double >( ComputeMaxDeflection() ) ); + + if ( maxDeflection == 0.0 ) + return maxDeflection; + + const CUtlVector<Vector> &pos( GetPositionData() ); + const CUtlVector< int > &posIndices( GetVertexIndexData( nPosIndex ) ); + + float flDeltaDistance; + int nDeltaIndex; + const int nCount = pos.Count(); + for ( int i = 0; i < nCount; ++i ) + { + flDeltaDistance = pos[ i ].Length(); + + nDeltaIndex = AddVertexData( nFieldIndex, 1 ); + SetVertexData( nFieldIndex, nDeltaIndex, 1, AT_FLOAT, &flDeltaDistance ); + } + + SetVertexIndices( nFieldIndex, 0, posIndices.Count(), posIndices.Base() ); + + return maxDeflection; +}
\ No newline at end of file |