//===== Copyright © Valve Corporation, All rights reserved. ======// // // This is a declaration of an abstraction of data used to generate collision mesh and potentially other physics data // #ifndef PHYS_MODEL_SOURCE_HDR #define PHYS_MODEL_SOURCE_HDR #include "mathlib/aabb.h" #include "tier1/utlvector.h" #include "tier1/utlstringtoken.h" #include "bitvec.h" #include "meshutils/mesh.h" #include "movieobjects/dmemodel.h" #include "mathlib/transform.h" class CMesh; enum VertEnumFlagEnum_t { FLAG_ENUMERATE_VERTICES_WITH_SUBTREE = 1 << 0, // enumerate vertices belonging to the given bone and its children FLAG_ENUMERATE_VERTICES_ALL = 1 << 1 }; void ComputeSubtree( const CDmeModel *pDmeModel, int nSubtreeTipBone, CVarBitVec *pSubtree ); // this is an adaptor class so that we can use render mesh or class CPhysModelSource { class CModel; // Source2 model; not supported in Source1 public: CPhysModelSource(): m_pRenderModel( NULL ), m_pDmeModel( NULL ) { } CPhysModelSource( const CModel *pModel ): m_pRenderModel( pModel ), m_pDmeModel( NULL ) { } CPhysModelSource( CDmeModel *pModel ): m_pRenderModel( NULL ), m_pDmeModel( pModel ) { } CPhysModelSource( const CPhysModelSource &source ): m_pRenderModel( source.m_pRenderModel ), m_pDmeModel( source.m_pDmeModel ) { } ~CPhysModelSource() { Purge(); } void SetRenderModel ( const CModel *pModel ) { Purge(); m_pRenderModel = pModel; } void SetDmeModel( CDmeModel *pModel ) { Purge(); m_pDmeModel = pModel; } const CModel *const GetRenderModel() const { return m_pRenderModel; } CDmeModel *GetDmeModel() const { return m_pDmeModel; } void Purge() { m_DmeMeshCache.PurgeAndDeleteElements(); m_pDmeModel = NULL; m_pRenderModel = NULL; } bool IsValid()const { return m_pRenderModel || m_pDmeModel; } int GetBoneCount()const; const char *GetBoneNameByIndex( int nIndex )const; int FindBoneByName( const char *pName )const { for ( int i = 0; i < GetBoneCount(); ++i ) { if ( !V_stricmp( GetBoneNameByIndex( i ), pName ) ) return i; } return -1; } void GetBoneTriangles( CUtlStringToken joint, uint nFlags, float flMinWeight, CUtlVector &arrVertices, CUtlVector &arrIndices )const; bool BoneHasMeat( CUtlStringToken joint, uint nFlags, const CTransform &bindPose ) const; AABB_t GetBoneInfluenceBbox( CUtlStringToken joint, uint nFlags, const CTransform &bindPose, float flMinWeight = 0.5f )const; static bool IsBitInSet( int nBit, const CVarBitVec &bonesInSubtree ) { return uint( nBit ) < uint( bonesInSubtree.GetNumBits() ) && bonesInSubtree.IsBitSet( nBit ); } template void EnumerateBoneVerts( CUtlStringToken joint, uint nFlags, Fn functor )const { /* if( GetRenderModel() ) { ::EnumerateBoneVerts( GetRenderModel(), joint, nFlags, functor ); } else */if( m_pDmeModel ) { CreateDmeModelCache(); int nMeshBoneIndex = m_pDmeModel->GetJointIndex( joint ); for( int nMesh = 0; nMesh < m_DmeMeshCache.Count(); ++nMesh ) { CMesh *pMesh = m_DmeMeshCache[nMesh]; CMesh::SkinningDataFields_t skinData; CVarBitVec bonesInSubtree( m_pDmeModel->GetJointCount() ); if( nMeshBoneIndex >= 0 ) { bonesInSubtree.Set( nMeshBoneIndex ); skinData = pMesh->GetSkinningDataFields(); if( nFlags & FLAG_ENUMERATE_VERTICES_WITH_SUBTREE ) { ComputeSubtree( m_pDmeModel, nMeshBoneIndex, &bonesInSubtree ); } } if( ( nFlags & FLAG_ENUMERATE_VERTICES_ALL ) || ( !skinData.HasSkinningData() && IsBitInSet( GetDmeDagIndex( nMesh ), bonesInSubtree ) ) ) { for( int nVert = 0; nVert < pMesh->VertexCount(); ++nVert ) { // this vertex belongs to this joint functor( pMesh->GetVertexPosition( nVert ), 1.0f ); } } else if( skinData.HasSkinningData() ) { for( int nVert = 0; nVert < pMesh->VertexCount(); ++nVert ) { // this vertex belongs to this joint float flWeight = pMesh->GetVertexJointSumWeight( skinData, nVert, bonesInSubtree ); functor( pMesh->GetVertexPosition( nVert ), flWeight ); } } } } } struct Stats_t { int m_nVertCount; int m_nTriCount; int m_nMeshCount; Stats_t() { m_nVertCount = 0; m_nTriCount = 0; m_nMeshCount = 0; } void operator += ( const Stats_t &that ) { m_nTriCount += that.m_nTriCount; m_nVertCount += that.m_nVertCount; m_nMeshCount += that.m_nMeshCount; } }; Stats_t GetStats( )const; int GetParentJoint( int nJoint )const; void GetBoneSubtree( int nBone, CVarBitVec *pSubtree ) const; // this is O(N) algorithm : starting from the given bone, it finds all (grand)children of that bone and sets corresponding bits in pSubtree; pSubtree must be pre-allocated with the desired number of bones CTransform GetBindPoseParentTransform( int nJointIndex )const; void GetBindPoseWorldTransforms( CUtlVector< CTransform > &transforms )const; bool GetAnimFrame( const char *pAnimName, float flCycle, CUtlVector< CTransform > *pTransformsOut )const; int GetDmeDagIndex( int nMesh )const; protected: void CreateDmeModelCache()const; protected: const CModel *m_pRenderModel; CDmeModel *m_pDmeModel; mutable CUtlVector< CMesh* > m_DmeMeshCache; mutable CUtlVector< int > m_DmeDagIndexCache; // for each DmeMesh, this is the index of DmeDag in the Dme Model }; inline void AdjustLegacyDotaOrientation( CUtlVector< CTransform > &transforms ) { float sin45 = sqrtf( .5f ); CTransform root( vec3_origin, Quaternion( 0, 0, sin45, sin45 ) * Quaternion( sin45, 0, 0, sin45 ) ); for ( int nBone = 0; nBone < transforms.Count( ); ++nBone ) { transforms[ nBone ] = ConcatTransforms( root, transforms[ nBone ] ); } } //void GetBoneTriangles( const CModel *pModel, CUtlStringToken joint, uint nFlags, float flMinWeight, CUtlVector &arrVertices, CUtlVector &arrIndices ); #endif