//======= Copyright © 1996-2006, Valve Corporation, All rights reserved. ====== // // Mesh Manipulation Utilities // //============================================================================= #ifndef DMMESHUTILS_H #define DMMESHUTILS_H #if defined( _WIN32 ) #pragma once #endif #include "movieobjects/dmedag.h" #include "movieobjects/dmmeshcomp.h" #include "movieobjects/dmevertexdata.h" #include "tier1/utlstring.h" #include "tier1/UtlStringMap.h" #include "tier1/utlvector.h" class CDmeMesh; class CDmeModel; class CDmMeshComp::CEdge; class CDmeCombinationOperator; class CDmePreset; class CDmePresetGroup; class CDmeFaceSet; class CMesh; bool SaveMeshesToDMX( CUtlVector &inputMeshes, const char *pDMXFile, bool bForce2DTexcoords = true ); bool LoadMeshesFromDMX( CUtlVector &outputMeshes, const char *pDMXFile ); bool LoadMeshes( CUtlVector &outputMeshes, CDmeModel *pModel, float flScale, int *pBoneRemap = NULL ); bool LoadCollisionMeshes( CUtlVector< CMesh* > &outputMeshes, CUtlVector< CDmeDag* > &outputDags, CDmeModel *pModel, float flScale ); bool ConvertMeshFromDMX( CMesh *pMeshOut, CDmeMesh *pDmeMesh ); void ConvertMeshToDMX( CDmeMesh *pDmeMeshOut, CMesh *pMeshIn, bool bForce2DTexcoords ); //----------------------------------------------------------------------------- // Mesh Utility function class (more like a namespace) //----------------------------------------------------------------------------- class CDmMeshUtils { public: static bool RemoveLargeAxisAlignedPlanarFaces( CDmeMesh *pMesh ); static bool RemoveFacesWithMaterial( CDmeMesh *pMesh, const char *pMaterialName ); static bool RemoveFacesWithMoreThanNVerts( CDmeMesh *pMesh, const int nVertexCount ); enum Axis_t { kXAxis, kYAxis, kZAxis }; static bool Mirror( CDmeMesh *pMesh, int axis = kXAxis ); static bool RemapMaterial( CDmeMesh *pMesh, const CUtlString &src, const CUtlString &dst ); static bool RemapMaterial( CDmeMesh *pMesh, const int nMaterialIndex, const CUtlString &dst ); // Merge the specified mesh onto the first mesh under pRoot that fits it static bool Merge( CDmeMesh *pSrcMesh, CDmElement *pRoot ); static bool Merge( CDmeMesh *pSrcMesh, CDmeMesh *pDstMesh, int nSkinningJointIndex, CUtlMap< int, int > *pJointMap = NULL ); static bool CreateDeltasFromPresets( CDmeMesh *pMesh, CDmeVertexData *pPassedDst, const CUtlStringMap< CUtlString > &presetMap, bool bPurge, const CUtlVector< CUtlString > *pPurgeAllButThese = NULL ); static bool PurgeUnusedDeltas( CDmeMesh *pMesh ); enum WrinkleOp { kReplace, kAdd }; static bool CreateWrinkleDeltaFromBaseState( CDmeVertexDeltaData *pDelta, float flScale = 1.0f, WrinkleOp wrinkleOp = kReplace, CDmeMesh *pMesh = NULL, CDmeVertexData *pBind = NULL, CDmeVertexData *pCurrent = NULL, bool bUseNormalForSign = false ); static int FindMergeSocket( const CUtlVector< CUtlVector< CDmMeshComp::CEdge * > > &srcBorderEdgesList, CDmeMesh *pDstMesh ); static bool Merge( CDmMeshComp &srcComp, const CUtlVector< CDmMeshComp::CEdge * > &edgeList, CDmeMesh *pDstMesh ); static bool NewMerge( CDmeMesh *pDstMesh, CDmeMesh *pSrcMesh, const CUtlVector< CDmMeshComp::CEdge * > &edgeList, float flTolerance = 1.0e-4, float flTexCoordTolerance = 1.0e-6 ); static CDmeModel *GetDmeModelFromMesh( CDmeMesh *pDmeMesh ); // Does a depth first walk of the DmeDag hierarchy specified until a DmeDag with the // requested name is found, returns that dag if found, NULL if not found or on error static CDmeDag *FindDagByNameInHierarchy( CDmeDag *pSearchDag, const char *pszSearchName ); // Adds the joint to the specified model by finding the common ancestor // Duplicates the required hierarchy of the source joint static CDmeDag *AddJointToModel( CDmeModel *pDstModel, CDmeDag *pSrcJoint ); static bool MergeMeshAndSkeleton( CDmeMesh *pDstMesh, CDmeMesh *pSrcMesh ); protected: static const int *BuildDataMirrorMap( CDmeVertexData *pBase, int axis, CDmeVertexData::StandardFields_t standardField, CUtlVector< int > &dataMirrorMap ); static bool MirrorVertices( CDmeMesh *pMesh, CDmeVertexData *pBase, int axis, CUtlVector< int > &mirrorMap ); static bool MirrorVertices( CDmeVertexData *pBase, int axis, int nOldVertexCount, int nMirrorCount, const CUtlVector< int > &mirrorMap, const CUtlVector< int > &posMirrorMap, const CUtlVector< int > &normalMirrorMap, const CUtlVector< int > &uvMirrorMap ); static void MirrorVertices( CDmeVertexData *pBase, FieldIndex_t fieldIndex, int nOldVertexCount, int nMirrorCount, const CUtlVector< int > &baseIndices, const CUtlVector< int > &mirrorMap ); static bool MirrorDelta( CDmeVertexDeltaData *pDelta, int axis, const CUtlVector< int > &posMirrorMap, const CUtlVector< int > &normalMirrorMap, const CUtlVector< int > &uvMirrorMap ); static bool PurgeUnusedData( CDmeMesh *pMesh ); static void CreateDeltasFromPresetGroup( CDmePresetGroup *pPresetGroup, CDmeCombinationOperator * pComboOp, const CUtlVector< CUtlString > * pPurgeAllButThese, CDmeMesh * pMesh, CDmeVertexData * pDst, CUtlStringMap< CUtlString > &conflictingNames, CUtlStringMap< CDmePreset * > &presetMap ); static void PurgeUnreferencedDeltas( CDmeMesh *pMesh, CUtlStringMap< CDmePreset * > &presetMap, const CUtlVector< CUtlString > *pPurgeAllButThese, CDmeCombinationOperator *pComboOp ); }; //----------------------------------------------------------------------------- // Iterate over all of the faces in a mesh. Use it like this: // // for ( CDmMeshFaceIt fIt( pMesh ); !fIt.IsDone(); fIt.Next() ) // { // } //----------------------------------------------------------------------------- class CDmMeshFaceIt { public: // Constructs a new face iterator for the specified mesh CDmMeshFaceIt( const CDmeMesh *pMesh, const CDmeVertexData *pVertexData = NULL ); // Resets the iterator to the start of the specified mesh or for another iteration of the // current mesh if the specified mesh is NULL bool Reset( const CDmeMesh *pMesh = NULL, const CDmeVertexData *pVertexData = NULL ); // Returns the total number of faces in the mesh int Count() const; // The number of vertices in the face int VertexCount() const; // Is the iterator at the end of the mesh? bool IsDone() const; // Move the iterator to the next face bool Next(); // Returns opposite sense of IsDone(), i.e. !IsDone() so true if iterator still has stuff to do operator bool() const { return !IsDone(); } // Prefix ++ which just calls Next() for syntax sugar CDmMeshFaceIt &operator ++() { Next(); return *this; } // Postfix ++ which just calls Next() for syntax sugar CDmMeshFaceIt operator ++( int ) { const CDmMeshFaceIt thisCopy( *this ); ++( *this ); return thisCopy; } // Gets the vertex indices for the vertices of this face bool GetVertexIndices( int *pIndices, int nIndices ) const; // Gets the vertex indices for the vertices of this face bool GetVertexIndices( CUtlVector< int > &vertexIndices ) const; // Gets the mesh relative vertex index given the face relative vertex index int GetVertexIndex( int nFaceRelativeVertexIndex ) const; // Gets the specified vertex data for the vertices of this face (if it exists) and the type matches template < class T_t > bool GetVertexData( CUtlVector< T_t > &vertexData, CDmeVertexDataBase::StandardFields_t nStandardField, CDmeVertexData *pPassedBase = NULL ) const; protected: bool SetFaceSet(); const CDmeMesh *m_pMesh; // Current Mesh const CDmeVertexData *m_pVertexData; // Current Vertex Data int m_nFaceSetCount; // Number of face sets in current mesh: m_pMesh->FaceSetCount(); int m_nFaceSetIndex; // Index of current face set: [ 0, m_nFaceSetCount ] const CDmeFaceSet *m_pFaceSet; // Current face set: m_pMesh->GetFaceSet( m_nFaceSetIndex ) int m_nFaceSetIndexCount; // Number of indices in current face set: m_pFaceSet->NumIndices(); int m_nFaceSetIndexIndex; // Index of current face set's indices: [ 0, m_nFaceSetIndexCount ] int m_nFaceCount; // Number of faces in current mesh int m_nFaceIndex; // The current face in the iteration [ 0, m_nFaceCount ] }; //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- template < class T_t > inline bool CDmMeshFaceIt::GetVertexData( CUtlVector< T_t > &vertexData, CDmeVertexDataBase::StandardFields_t nStandardField, CDmeVertexData *pPassedBase /* = NULL */ ) const { vertexData.RemoveAll(); if ( IsDone() ) return false; CDmeVertexData *pBase = pPassedBase ? pPassedBase : m_pMesh->GetCurrentBaseState(); if ( !pBase ) return false; const FieldIndex_t nFieldIndex = pBase->FindFieldIndex( nStandardField ); if ( nFieldIndex < 0 ) return false; CDmAttribute *pDataAttr = pBase->GetVertexData( nFieldIndex ); if ( pDataAttr->GetType() != CDmAttributeInfo< CUtlVector< T_t > >().AttributeType() ) return false; const CDmrArrayConst< T_t > data( pDataAttr ); const CUtlVector< int > &indices( pBase->GetVertexIndexData( nFieldIndex ) ); } #endif // DMMESHUTILS_H