Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

496 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // A class representing a mesh
  4. //
  5. //=============================================================================
  6. #ifndef DMEMESH_H
  7. #define DMEMESH_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "movieobjects/dmeshape.h"
  12. #include "movieobjects/dmevertexdata.h"
  13. #include "materialsystem/MaterialSystemUtil.h"
  14. #include "mathlib/vector.h"
  15. #include "tier1/utllinkedlist.h"
  16. #include "Color.h"
  17. //-----------------------------------------------------------------------------
  18. // Forward declarations
  19. //-----------------------------------------------------------------------------
  20. class CDmElement;
  21. class CDmeFaceSet;
  22. class CDmeVertexData;
  23. class IMaterial;
  24. class IMorph;
  25. class IMesh;
  26. class Vector;
  27. class Vector4D;
  28. class Color;
  29. class CDmeDag;
  30. class CMeshBuilder;
  31. class CDmeCombinationOperator;
  32. class CDmeSingleIndexedComponent;
  33. class CDmeDrawSettings;
  34. class CDmMeshComp;
  35. //-----------------------------------------------------------------------------
  36. // Mesh weights
  37. //-----------------------------------------------------------------------------
  38. enum MeshDeltaWeightType_t
  39. {
  40. MESH_DELTA_WEIGHT_FIRST = 0,
  41. MESH_DELTA_WEIGHT_NORMAL = 0,
  42. MESH_DELTA_WEIGHT_LAGGED,
  43. MESH_DELTA_WEIGHT_TYPE_COUNT,
  44. };
  45. //-----------------------------------------------------------------------------
  46. // Mesh representation
  47. //-----------------------------------------------------------------------------
  48. class CDmeMesh : public CDmeShape
  49. {
  50. DEFINE_ELEMENT( CDmeMesh, CDmeShape );
  51. public:
  52. // resolve internal data from changed attributes
  53. virtual void OnAttributeChanged( CDmAttribute *pAttribute );
  54. void GetBoundingSphere( Vector &c, float &r, CDmeVertexData *pPassedBase, CDmeSingleIndexedComponent *pPassedSelection ) const;
  55. virtual void GetBoundingSphere( Vector &c, float &r ) const { return GetBoundingSphere( c, r, NULL, NULL ); }
  56. void GetBoundingBox( Vector &min, Vector &max, CDmeVertexData *pPassedBase /* = NULL */, CDmeSingleIndexedComponent *pPassedSelection /* = NULL */ ) const;
  57. virtual void GetBoundingBox( Vector &min, Vector &max ) const { return GetBoundingBox( min, max, NULL, NULL ); }
  58. // accessors
  59. int FaceSetCount() const;
  60. CDmeFaceSet *GetFaceSet( int nFaceSetIndex );
  61. const CDmeFaceSet *GetFaceSet( int nFaceSetIndex ) const;
  62. void AddFaceSet( CDmeFaceSet *faceSet );
  63. void RemoveFaceSet( int nFaceSetIndex );
  64. // Base states
  65. int BaseStateCount() const;
  66. CDmeVertexData *GetBaseState( int nBaseIndex ) const;
  67. CDmeVertexData *FindBaseState( const char *pStateName ) const;
  68. CDmeVertexData *FindOrCreateBaseState( const char *pStateName );
  69. bool DeleteBaseState( const char *pStateName );
  70. // Selects a particular base state to be current state
  71. void SetCurrentBaseState( const char *pStateName );
  72. CDmeVertexData *GetCurrentBaseState();
  73. const CDmeVertexData *GetCurrentBaseState() const;
  74. bool SetBindBaseState( CDmeVertexData *pBaseState );
  75. CDmeVertexData *GetBindBaseState();
  76. const CDmeVertexData *GetBindBaseState() const;
  77. // Draws the mesh
  78. void Draw( const matrix3x4_t &shapeToWorld, CDmeDrawSettings *pDrawSettings = NULL );
  79. // Compute triangulated indices
  80. void ComputeTriangulatedIndices( const CDmeVertexData *pBaseState, CDmeFaceSet *pFaceSet, int nFirstIndex, int *pIndices, int nOutCount );
  81. // Compute a default per-vertex tangent given normal data + uv data for all vertex data referenced by this mesh
  82. void ComputeDefaultTangentData( bool bSmoothTangents = false );
  83. // Compute a default per-vertex tangent given normal data + uv data
  84. void ComputeDefaultTangentData( CDmeVertexData *pVertexData, bool bSmoothTangents = false );
  85. // Delta states
  86. int DeltaStateCount() const;
  87. CDmeVertexDeltaData *GetDeltaState( int nDeltaIndex ) const;
  88. CDmeVertexDeltaData *FindDeltaState( const char *pDeltaName ) const;
  89. CDmeVertexDeltaData *FindOrCreateDeltaState( const char *pDeltaName );
  90. bool DeleteDeltaState( const char *pDeltaName );
  91. bool ResetDeltaState( const char *pDeltaName );
  92. int FindDeltaStateIndex( const char *pDeltaName ) const;
  93. void SetDeltaStateWeight( int nDeltaIndex, MeshDeltaWeightType_t type, float flMorphWeight );
  94. void SetDeltaStateWeight( int nDeltaIndex, MeshDeltaWeightType_t type, float flLeftWeight, float flRightWeight );
  95. CDmeVertexDeltaData *ModifyOrCreateDeltaStateFromBaseState( const char *pDeltaName, CDmeVertexData *pPassedBase = NULL, bool absolute = false );
  96. // Sets all of the data in the current base state to be the bind state plus the corrected delta, if delta is NULL then it's set to the bind state
  97. bool SetBaseStateToDelta( const CDmeVertexDeltaData *pDelta, CDmeVertexData *pPassedBase = NULL );
  98. // Selects the vertices from the delta that change position
  99. void SelectVerticesFromDelta( CDmeVertexDeltaData *pDelta, CDmeSingleIndexedComponent *pSelection );
  100. // Selects all the vertices in the mesh
  101. void SelectAllVertices( CDmeSingleIndexedComponent *pSelection, CDmeVertexData *pPassedBase = NULL );
  102. enum SelectHalfType_t
  103. {
  104. kLeft,
  105. kRight
  106. };
  107. // Selects all the vertices in the mesh
  108. void SelectHalfVertices( SelectHalfType_t selectHalfType, CDmeSingleIndexedComponent *pSelection, CDmeVertexData *pPassedBase = NULL );
  109. // Add the delta into the vertex data state weighted by the weight and masked by the weight map
  110. bool AddMaskedDelta(
  111. CDmeVertexDeltaData *pDelta,
  112. CDmeVertexData *pDst = NULL,
  113. float weight = 1.0f,
  114. const CDmeSingleIndexedComponent *pMask = NULL );
  115. // Interpolate between the current state and the specified delta by the specified percentage masked by the selection
  116. bool InterpMaskedDelta(
  117. CDmeVertexDeltaData *pDelta,
  118. CDmeVertexData *pDst = NULL,
  119. float weight = 1.0f,
  120. const CDmeSingleIndexedComponent *pMask = NULL );
  121. // Grows the selection by a specified amount
  122. void GrowSelection( int nSize, CDmeSingleIndexedComponent *pSelection, CDmMeshComp *pPassedMeshComp );
  123. // Shrinks the selection by a specified amount
  124. void ShrinkSelection( int nSize, CDmeSingleIndexedComponent *pSelection, CDmMeshComp *pPassedMeshComp );
  125. enum Falloff_t
  126. {
  127. STRAIGHT = 0,
  128. LINEAR = STRAIGHT,
  129. BELL,
  130. SMOOTH = BELL,
  131. SPIKE,
  132. DOME
  133. };
  134. enum Distance_t
  135. {
  136. DIST_ABSOLUTE = 0,
  137. DIST_RELATIVE,
  138. DIST_DEFAULT
  139. };
  140. CDmeSingleIndexedComponent *FeatherSelection( float falloffDistance, Falloff_t falloffType, Distance_t distanceType, CDmeSingleIndexedComponent *pSelection, CDmMeshComp *pPassedMeshComp );
  141. // Computes new normal deltas for all states based on position deltas
  142. void ComputeDeltaStateNormals();
  143. struct DeltaComputation_t
  144. {
  145. int m_nDeltaIndex;
  146. int m_nDimensionality;
  147. CUtlVector<int> m_DependentDeltas;
  148. };
  149. // Construct list of all n-1 -> 1 dimensional delta states that will be active when this delta state is active
  150. void ComputeDependentDeltaStateList( CUtlVector< DeltaComputation_t > &compList );
  151. // Construct list of all > n dimensional delta states that when active have the specified state as a dependent
  152. bool ComputeSuperiorDeltaStateList( const char *pDeltaName, CUtlVector< int > &superiorDeltaStates );
  153. void SetDeltaNormalDataFromActualNormals( int nDeltaIndex, const CUtlVector<int> &deltaStateList, int nNormalCount, Vector *pNormals );
  154. void ComputeAllCorrectedPositionsFromActualPositions();
  155. // Computes adds a delta to the passed data weighted by the passed weight
  156. template < class T_t > void AddDelta(
  157. const CDmeVertexDeltaData *pDelta, T_t *pFullData, int nFullData, FieldIndex_t fieldIndex, float weight = 1.0f, const CDmeSingleIndexedComponent *pMask = NULL );
  158. template < class T_t > void AddDelta(
  159. const CDmeVertexDeltaData *pDelta, T_t *pFullData, int nFullData, CDmeVertexData::StandardFields_t standardField, float weight = 1.0f, const CDmeSingleIndexedComponent *pMask = NULL );
  160. bool SetBaseStateToDeltas( CDmeVertexData *pPassedBase = NULL );
  161. template < class T_t >
  162. bool SetBaseDataToDeltas( CDmeVertexData *pBase, CDmeVertexData::StandardFields_t nStandardField, CDmrArrayConst< T_t > &srcData, CDmrArray< T_t > &dstData, bool bDoStereo, bool bDoLag );
  163. // Replace all instances of a material with a different material
  164. void ReplaceMaterial( const char *pOldMaterialName, const char *pNewMaterialName );
  165. // makes all the normals in the mesh unit length
  166. void NormalizeNormals();
  167. // Collapses redundant normals in the model
  168. // flNormalBlend is the maximum difference in the dot product between two normals to consider them
  169. // to be the same normal, a value of cos( DEG2RAD( 2.0 ) ) is the default studiomdl uses, for example
  170. void CollapseRedundantNormals( float flNormalBlend );
  171. // SWIG errors on the parsing of something in the private section of DmeMesh, it isn't exposed by SWIG anyway, so have SWIG ignore it
  172. #ifndef SWIG
  173. template < class T_t > static int GenerateCompleteDataForDelta( const CDmeVertexDeltaData *pDelta, T_t *pFullData, int nFullData, CDmeVertexData::StandardFields_t standardField );
  174. private:
  175. friend class CDmMeshComp;
  176. struct FaceSet_t
  177. {
  178. FaceSet_t() : m_bBuilt(false) {}
  179. IMesh *m_pMesh;
  180. bool m_bBuilt;
  181. };
  182. struct Triangle_t
  183. {
  184. int m_nIndex[3];
  185. Vector m_vecTangentS;
  186. Vector m_vecTangentT;
  187. };
  188. struct RenderVertexDelta_t
  189. {
  190. Vector m_vecDeltaPosition;
  191. Vector m_vecDeltaNormal;
  192. Vector2D m_vecDeltaUV;
  193. Vector4D m_vecDeltaColor;
  194. float m_flDeltaWrinkle;
  195. };
  196. VertexFormat_t ComputeHwMeshVertexFormat( void );
  197. IMorph *CreateHwMorph( IMaterial *pMTL );
  198. IMesh *CreateHwMesh( CDmeFaceSet *pFaceSet );
  199. // Draws the mesh when it uses too many bones
  200. void DrawDynamicMesh( CDmeFaceSet *pFaceSet, matrix3x4_t *pPoseToWorld, bool bHasActiveDeltaStates, CDmeDrawSettings *pDrawSettings = NULL );
  201. // Build a map from vertex index to a list of triangles that share the vert.
  202. void BuildTriangleMap( const CDmeVertexData *pBaseState, CDmeFaceSet* pFaceSet, CUtlVector<Triangle_t>& triangles, CUtlVector< CUtlVector<int> >* pVertToTriMap = NULL );
  203. // Computes tangent space data for triangles
  204. void ComputeTriangleTangets( const CDmeVertexData *pVertexData, CUtlVector<Triangle_t>& triangles );
  205. // Build a map from vertex index to a list of triangles that share the vert.
  206. void ComputeAverageTangent( CDmeVertexData *pVertexData, bool bSmoothTangents, CUtlVector< CUtlVector<int> >& vertToTriMap, CUtlVector<Triangle_t>& triangles );
  207. // Do we have active delta state data?
  208. bool HasActiveDeltaStates() const;
  209. // Adds deltas into a delta mesh
  210. template< class T > bool AddVertexDelta( CDmeVertexData *pBaseState, void *pVertexData, int nStride, CDmeVertexDataBase::StandardFields_t fieldId, int nIndex, bool bDoLag );
  211. template< class T > bool AddStereoVertexDelta( CDmeVertexData *pBaseState, void *pVertexData, int nStride, CDmeVertexDataBase::StandardFields_t fieldId, int nIndex, bool bDoLag );
  212. void AddTexCoordDelta( RenderVertexDelta_t *pRenderDelta, float flWeight, CDmeVertexDeltaData *pDeltaState );
  213. void AddColorDelta( RenderVertexDelta_t *pRenderDelta, float flWeight, CDmeVertexDeltaData *pDeltaState );
  214. // Builds deltas based on the current deltas, returns true if there was delta wrinkle data
  215. bool BuildDeltaMesh( int nVertices, RenderVertexDelta_t *pDelta );
  216. // Builds a map from vertex index to all triangles that use it
  217. void BuildVertToTriMap( const CDmeVertexData *pVertexData, CUtlVector<Triangle_t> &triangles, CUtlVector< CUtlVector<int> > &vertToTriMap );
  218. // Compute the dimensionality of the delta state (how many inputs affect it)
  219. int ComputeDeltaStateDimensionality( int nDeltaIndex );
  220. // Discovers the atomic controls used by the various delta states
  221. void BuildAtomicControlLists( int nCount, DeltaComputation_t *pInfo, CUtlVector< CUtlVector< int > > &deltaStateUsage );
  222. // Computes the aggregate position for all vertices after applying a set of delta states
  223. void AddDelta( CDmeVertexData *pBaseState, Vector *pDeltaPosition, int nDeltaStateIndex, CDmeVertexData::StandardFields_t fieldId );
  224. // Converts pose-space normals into deltas appropriate for correction delta states
  225. void ComputeCorrectedNormalsFromActualNormals( const CUtlVector<int> &deltaStateList, int nNormalCount, Vector *pNormals );
  226. // Copies the corrected normal data into a delta state
  227. void SetDeltaNormalData( int nDeltaIndex, int nNormalCount, Vector *pNormals );
  228. // Renders normals
  229. void RenderNormals( matrix3x4_t *pPoseToWorld, RenderVertexDelta_t *pDelta );
  230. // Writes triangulated indices for a face set into a meshbuilder
  231. void WriteTriangluatedIndices( const CDmeVertexData *pBaseState, CDmeFaceSet *pFaceSet, CMeshBuilder &meshBuilder );
  232. // Initializes the normal material
  233. static void InitializeNormalMaterial();
  234. // Sort function
  235. static int DeltaStateLessFunc( const void * lhs, const void * rhs );
  236. // Computes a list of the delta states ordered by dimensionality
  237. void ComputeDeltaStateComputationList( CUtlVector< DeltaComputation_t > &compList );
  238. // Compute the number of combinations of n items taken k at a time nCk - Probably doesn't belong here but it useful for combos
  239. static void Combinations( int n, int k, CUtlVector< CUtlVector< int > > &combos, int *pTmpArray = NULL, int start = 0, int currentK = 0 );
  240. // Splits the passed delta state name on '_' and finds all of the control Delta states which make up the name
  241. bool GetControlDeltaIndices( CDmeVertexDeltaData *pDeltaState, CUtlVector< int > &controlDeltaIndices ) const;
  242. // Splits the passed delta state name on '_' and finds all of the control Delta states which make up the name
  243. bool GetControlDeltaIndices( const char *pDeltaStateName, CUtlVector< int > &controlDeltaIndices ) const;
  244. // Builds a complete list of all of the delta states expressed as the control indices
  245. bool BuildCompleteDeltaStateControlList( CUtlVector< CUtlVector< int > > &deltaStateControlList ) const;
  246. // Given a list of control indices and a complete list of control indices for each delta state, returns the delta index or -1 if it doesn't exist
  247. int FindDeltaIndexFromControlIndices( const CUtlVector< int > &controlIndices, const CUtlVector< CUtlVector< int > > &controlList ) const;
  248. // Builds a list of all of the dependent delta states that do not already exist
  249. bool BuildMissingDependentDeltaList( CDmeVertexDeltaData *pDeltaState, CUtlVector< int > &controlIndices, CUtlVector< CUtlVector< int > > &dependentStates ) const;
  250. static void ComputeCorrectedPositionsFromActualPositions( const CUtlVector< int > &deltaStateList, int nPositionCount, Vector *pPositions );
  251. template < class T_t > void AddCorrectedDelta(
  252. CDmrArray< T_t > &baseDataArray,
  253. const CUtlVector< int > &baseIndices,
  254. const DeltaComputation_t &deltaComputation,
  255. const char *pFieldName,
  256. float weight = 1.0f,
  257. const CDmeSingleIndexedComponent *pMask = NULL );
  258. template < class T_t > void AddCorrectedDelta(
  259. CUtlVector< T_t > &baseData,
  260. const CUtlVector< int > &baseIndices,
  261. const DeltaComputation_t &deltaComputation,
  262. const char *pFieldName,
  263. float weight = 1.0f,
  264. const CDmeSingleIndexedComponent *pMask = NULL );
  265. // Add the delta into the vertex data state weighted by the weight and masked by the weight map
  266. bool AddCorrectedMaskedDelta(
  267. CDmeVertexDeltaData *pDelta,
  268. CDmeVertexData *pDst = NULL,
  269. float weight = 1.0f,
  270. const CDmeSingleIndexedComponent *pMask = NULL );
  271. template < class T_t > void AddRawDelta(
  272. CDmeVertexDeltaData *pDelta,
  273. CDmrArray< T_t > &baseDataArray,
  274. FieldIndex_t nDeltaFieldIndex,
  275. float weight = 1.0f,
  276. const CDmeSingleIndexedComponent *pMask = NULL );
  277. template < class T_t > void AddRawDelta(
  278. CDmeVertexDeltaData *pDelta,
  279. CUtlVector< T_t > &baseData,
  280. FieldIndex_t nDeltaFieldIndex,
  281. float weight = 1.0f,
  282. const CDmeSingleIndexedComponent *pMask = NULL );
  283. friend class CDmxEdit;
  284. bool RemoveBaseState( CDmeVertexData *pBase );
  285. CDmeVertexData *FindOrAddBaseState( CDmeVertexData *pBase );
  286. // CFalloff functors map [0, 1] values to [0, 1] values
  287. template < int T >
  288. class CFalloff
  289. {
  290. public:
  291. virtual inline float operator()( float x ) { return 1 - x; }
  292. };
  293. template<>
  294. class CFalloff< CDmeMesh::LINEAR >
  295. {
  296. public:
  297. virtual inline float operator()( float x ) { return 1 - x; }
  298. };
  299. template<>
  300. class CFalloff< CDmeMesh::SMOOTH >
  301. {
  302. public:
  303. virtual inline float operator()( float x ) {
  304. return ( cosf( x * M_PI ) + 1.0f ) / 2.0f;
  305. }
  306. };
  307. template<>
  308. class CFalloff< CDmeMesh::DOME >
  309. {
  310. public:
  311. virtual inline float operator()( float x ) {
  312. return ( cosf( x * M_PI / 2.0 ) );
  313. }
  314. };
  315. template<>
  316. class CFalloff< CDmeMesh::SPIKE >
  317. {
  318. public:
  319. virtual inline float operator()( float x ) {
  320. return ( 1.0f - cosf( ( 1.0f - x ) * M_PI / 2.0 ) );
  321. }
  322. };
  323. // Feather's the selection by a specified amount, creates a new CDmeSingleIndexedComponent or NULL if error
  324. template < int T >
  325. CDmeSingleIndexedComponent *FeatherSelection( float fFalloffDistance, Distance_t distanceType, CDmeSingleIndexedComponent *pSelection, CDmMeshComp *pPassedMeshComp );
  326. bool CreateDeltaFieldFromBaseField( CDmeVertexData::StandardFields_t nStandardFieldIndex, const CDmrArrayConst< float > &baseArray, const CDmrArrayConst< float > &bindArray, CDmeVertexDeltaData *pDelta );
  327. bool CreateDeltaFieldFromBaseField( CDmeVertexData::StandardFields_t nStandardFieldIndex, const CDmrArrayConst< Vector2D > &baseArray, const CDmrArrayConst< Vector2D > &bindArray, CDmeVertexDeltaData *pDelta );
  328. bool CreateDeltaFieldFromBaseField( CDmeVertexData::StandardFields_t nStandardFieldIndex, const CDmrArrayConst< Vector > &baseArray, const CDmrArrayConst< Vector > &bindArray, CDmeVertexDeltaData *pDelta );
  329. template< class T_t > bool InterpMaskedData(
  330. CDmrArray< T_t > &aData,
  331. const CUtlVector< T_t > &bData,
  332. float weight,
  333. const CDmeSingleIndexedComponent *pMask ) const;
  334. // Interpolate between the current state and the specified delta by the specified percentage masked by the selection
  335. bool InterpMaskedData(
  336. CDmeVertexData *paData,
  337. const CDmeVertexData *pbData,
  338. float weight,
  339. const CDmeSingleIndexedComponent *pMask ) const;
  340. // Find the closest vertex in the specified selection to the passed vertex in the specified base state, if the passed base state is NULL is the current base state
  341. int ClosestSelectedVertex( int vIndex, CDmeSingleIndexedComponent *pSelection, const CDmeVertexData *pPassedBase = NULL ) const;
  342. // Return the distance between the two vertices in the specified base state, if the specified base state is NULL the current state is used
  343. float DistanceBetween( int vIndex0, int vIndex1, const CDmeVertexData *pPassedBase = NULL ) const;
  344. void DrawWireframeFaceSet( CDmeFaceSet *pFaceSet, matrix3x4_t *pPoseToWorld, bool bHasActiveDeltaStates, CDmeDrawSettings *pDrawSettings );
  345. void ComputeNormalsFromPositions( CDmeVertexData *pBase, const Vector *pPosition, const CUtlVector<Triangle_t> &triangles, int nNormalCount, Vector *pNormals );
  346. CDmaElement< CDmeVertexData > m_BindBaseState;
  347. CDmaElement< CDmeVertexData > m_CurrentBaseState;
  348. CDmaElementArray< CDmeVertexData > m_BaseStates;
  349. CDmaElementArray< CDmeVertexDeltaData > m_DeltaStates;
  350. CDmaElementArray< CDmeFaceSet > m_FaceSets;
  351. // x is left value, y is right value. If the delta state isn't split, they are the same value
  352. CDmaArray<Vector2D> m_DeltaStateWeights[MESH_DELTA_WEIGHT_TYPE_COUNT];
  353. // Cached-off map of fields->
  354. CUtlVector< FaceSet_t > m_hwFaceSets;
  355. // Normal rendering materials
  356. static bool s_bNormalMaterialInitialized;
  357. static CMaterialReference s_NormalMaterial;
  358. static CMaterialReference s_NormalErrorMaterial;
  359. static bool s_bMaterialsInitialized;
  360. static CMaterialReference s_WireframeMaterial;
  361. static CMaterialReference s_WireframeOnShadedMaterial;
  362. friend class CRenderInfo;
  363. #endif // ndef SWIG
  364. };
  365. //-----------------------------------------------------------------------------
  366. // Inline methods
  367. //-----------------------------------------------------------------------------
  368. inline int CDmeMesh::BaseStateCount() const
  369. {
  370. return m_BaseStates.Count();
  371. }
  372. inline CDmeVertexData *CDmeMesh::GetBaseState( int nBaseIndex ) const
  373. {
  374. return m_BaseStates[ nBaseIndex ];
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Utility method to compute default tangent data on all meshes in the sub-dag hierarchy
  378. //-----------------------------------------------------------------------------
  379. void ComputeDefaultTangentData( CDmeDag *pDag, bool bSmoothTangents );
  380. #endif // DMEMESH_H