Counter Strike : Global Offensive Source Code
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.

5257 lines
167 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. // Standard includes
  7. #include <limits.h>
  8. // Valve includes
  9. #include "movieobjects/dmemesh.h"
  10. #include "movieobjects/dmevertexdata.h"
  11. #include "movieobjects/dmefaceset.h"
  12. #include "movieobjects/dmematerial.h"
  13. #include "movieobjects/dmetransform.h"
  14. #include "movieobjects/dmemodel.h"
  15. #include "movieobjects_interfaces.h"
  16. #include "movieobjects/dmecombinationoperator.h"
  17. #include "movieobjects/dmeselection.h"
  18. #include "movieobjects/dmedrawsettings.h"
  19. #include "movieobjects/dmmeshcomp.h"
  20. #include "tier3/tier3.h"
  21. #include "tier1/keyvalues.h"
  22. #include "tier0/dbg.h"
  23. #include "datamodel/dmelementfactoryhelper.h"
  24. #include "materialsystem/imaterialsystem.h"
  25. #include "materialsystem/imorph.h"
  26. #include "materialsystem/imesh.h"
  27. #include "materialsystem/imaterialvar.h"
  28. #include "istudiorender.h"
  29. #include "studio.h"
  30. // memdbgon must be the last include file in a .cpp file!!!
  31. #include "tier0/memdbgon.h"
  32. //-----------------------------------------------------------------------------
  33. // Normal rendering materials
  34. //-----------------------------------------------------------------------------
  35. bool CDmeMesh::s_bNormalMaterialInitialized;
  36. CMaterialReference CDmeMesh::s_NormalMaterial;
  37. //-----------------------------------------------------------------------------
  38. // Wireframe rendering materials
  39. //-----------------------------------------------------------------------------
  40. bool CDmeMesh::s_bWireframeMaterialInitialized;
  41. CMaterialReference CDmeMesh::s_WireframeMaterial;
  42. //-----------------------------------------------------------------------------
  43. // Computes a skin matrix
  44. //-----------------------------------------------------------------------------
  45. static const matrix3x4_t *ComputeSkinMatrix( int nBoneCount, const float *pJointWeight, const int *pJointIndices, const matrix3x4_t *pPoseToWorld, matrix3x4_t &result )
  46. {
  47. float flWeight0, flWeight1, flWeight2, flWeight3;
  48. switch( nBoneCount )
  49. {
  50. default:
  51. case 1:
  52. return &pPoseToWorld[pJointIndices[0]];
  53. case 2:
  54. {
  55. const matrix3x4_t &boneMat0 = pPoseToWorld[pJointIndices[0]];
  56. const matrix3x4_t &boneMat1 = pPoseToWorld[pJointIndices[1]];
  57. flWeight0 = pJointWeight[0];
  58. flWeight1 = pJointWeight[1];
  59. // NOTE: Inlining here seems to make a fair amount of difference
  60. result[0][0] = boneMat0[0][0] * flWeight0 + boneMat1[0][0] * flWeight1;
  61. result[0][1] = boneMat0[0][1] * flWeight0 + boneMat1[0][1] * flWeight1;
  62. result[0][2] = boneMat0[0][2] * flWeight0 + boneMat1[0][2] * flWeight1;
  63. result[0][3] = boneMat0[0][3] * flWeight0 + boneMat1[0][3] * flWeight1;
  64. result[1][0] = boneMat0[1][0] * flWeight0 + boneMat1[1][0] * flWeight1;
  65. result[1][1] = boneMat0[1][1] * flWeight0 + boneMat1[1][1] * flWeight1;
  66. result[1][2] = boneMat0[1][2] * flWeight0 + boneMat1[1][2] * flWeight1;
  67. result[1][3] = boneMat0[1][3] * flWeight0 + boneMat1[1][3] * flWeight1;
  68. result[2][0] = boneMat0[2][0] * flWeight0 + boneMat1[2][0] * flWeight1;
  69. result[2][1] = boneMat0[2][1] * flWeight0 + boneMat1[2][1] * flWeight1;
  70. result[2][2] = boneMat0[2][2] * flWeight0 + boneMat1[2][2] * flWeight1;
  71. result[2][3] = boneMat0[2][3] * flWeight0 + boneMat1[2][3] * flWeight1;
  72. }
  73. return &result;
  74. case 3:
  75. {
  76. const matrix3x4_t &boneMat0 = pPoseToWorld[pJointIndices[0]];
  77. const matrix3x4_t &boneMat1 = pPoseToWorld[pJointIndices[1]];
  78. const matrix3x4_t &boneMat2 = pPoseToWorld[pJointIndices[2]];
  79. flWeight0 = pJointWeight[0];
  80. flWeight1 = pJointWeight[1];
  81. flWeight2 = pJointWeight[2];
  82. result[0][0] = boneMat0[0][0] * flWeight0 + boneMat1[0][0] * flWeight1 + boneMat2[0][0] * flWeight2;
  83. result[0][1] = boneMat0[0][1] * flWeight0 + boneMat1[0][1] * flWeight1 + boneMat2[0][1] * flWeight2;
  84. result[0][2] = boneMat0[0][2] * flWeight0 + boneMat1[0][2] * flWeight1 + boneMat2[0][2] * flWeight2;
  85. result[0][3] = boneMat0[0][3] * flWeight0 + boneMat1[0][3] * flWeight1 + boneMat2[0][3] * flWeight2;
  86. result[1][0] = boneMat0[1][0] * flWeight0 + boneMat1[1][0] * flWeight1 + boneMat2[1][0] * flWeight2;
  87. result[1][1] = boneMat0[1][1] * flWeight0 + boneMat1[1][1] * flWeight1 + boneMat2[1][1] * flWeight2;
  88. result[1][2] = boneMat0[1][2] * flWeight0 + boneMat1[1][2] * flWeight1 + boneMat2[1][2] * flWeight2;
  89. result[1][3] = boneMat0[1][3] * flWeight0 + boneMat1[1][3] * flWeight1 + boneMat2[1][3] * flWeight2;
  90. result[2][0] = boneMat0[2][0] * flWeight0 + boneMat1[2][0] * flWeight1 + boneMat2[2][0] * flWeight2;
  91. result[2][1] = boneMat0[2][1] * flWeight0 + boneMat1[2][1] * flWeight1 + boneMat2[2][1] * flWeight2;
  92. result[2][2] = boneMat0[2][2] * flWeight0 + boneMat1[2][2] * flWeight1 + boneMat2[2][2] * flWeight2;
  93. result[2][3] = boneMat0[2][3] * flWeight0 + boneMat1[2][3] * flWeight1 + boneMat2[2][3] * flWeight2;
  94. }
  95. return &result;
  96. case 4:
  97. {
  98. const matrix3x4_t &boneMat0 = pPoseToWorld[pJointIndices[0]];
  99. const matrix3x4_t &boneMat1 = pPoseToWorld[pJointIndices[1]];
  100. const matrix3x4_t &boneMat2 = pPoseToWorld[pJointIndices[2]];
  101. const matrix3x4_t &boneMat3 = pPoseToWorld[pJointIndices[3]];
  102. flWeight0 = pJointWeight[0];
  103. flWeight1 = pJointWeight[1];
  104. flWeight2 = pJointWeight[2];
  105. flWeight3 = pJointWeight[3];
  106. result[0][0] = boneMat0[0][0] * flWeight0 + boneMat1[0][0] * flWeight1 + boneMat2[0][0] * flWeight2 + boneMat3[0][0] * flWeight3;
  107. result[0][1] = boneMat0[0][1] * flWeight0 + boneMat1[0][1] * flWeight1 + boneMat2[0][1] * flWeight2 + boneMat3[0][1] * flWeight3;
  108. result[0][2] = boneMat0[0][2] * flWeight0 + boneMat1[0][2] * flWeight1 + boneMat2[0][2] * flWeight2 + boneMat3[0][2] * flWeight3;
  109. result[0][3] = boneMat0[0][3] * flWeight0 + boneMat1[0][3] * flWeight1 + boneMat2[0][3] * flWeight2 + boneMat3[0][3] * flWeight3;
  110. result[1][0] = boneMat0[1][0] * flWeight0 + boneMat1[1][0] * flWeight1 + boneMat2[1][0] * flWeight2 + boneMat3[1][0] * flWeight3;
  111. result[1][1] = boneMat0[1][1] * flWeight0 + boneMat1[1][1] * flWeight1 + boneMat2[1][1] * flWeight2 + boneMat3[1][1] * flWeight3;
  112. result[1][2] = boneMat0[1][2] * flWeight0 + boneMat1[1][2] * flWeight1 + boneMat2[1][2] * flWeight2 + boneMat3[1][2] * flWeight3;
  113. result[1][3] = boneMat0[1][3] * flWeight0 + boneMat1[1][3] * flWeight1 + boneMat2[1][3] * flWeight2 + boneMat3[1][3] * flWeight3;
  114. result[2][0] = boneMat0[2][0] * flWeight0 + boneMat1[2][0] * flWeight1 + boneMat2[2][0] * flWeight2 + boneMat3[2][0] * flWeight3;
  115. result[2][1] = boneMat0[2][1] * flWeight0 + boneMat1[2][1] * flWeight1 + boneMat2[2][1] * flWeight2 + boneMat3[2][1] * flWeight3;
  116. result[2][2] = boneMat0[2][2] * flWeight0 + boneMat1[2][2] * flWeight1 + boneMat2[2][2] * flWeight2 + boneMat3[2][2] * flWeight3;
  117. result[2][3] = boneMat0[2][3] * flWeight0 + boneMat1[2][3] * flWeight1 + boneMat2[2][3] * flWeight2 + boneMat3[2][3] * flWeight3;
  118. }
  119. return &result;
  120. }
  121. Assert(0);
  122. return NULL;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Constructor
  126. //-----------------------------------------------------------------------------
  127. CDmeMeshRenderInfo::CDmeMeshRenderInfo( CDmeVertexData *pBaseState ) :
  128. m_PositionIndices( pBaseState->GetVertexIndexData( CDmeVertexData::FIELD_POSITION ) ),
  129. m_PositionData( pBaseState->GetPositionData() ),
  130. m_NormalIndices( pBaseState->GetVertexIndexData( CDmeVertexData::FIELD_NORMAL ) ),
  131. m_NormalData( pBaseState->GetNormalData() ),
  132. m_TangentIndices( pBaseState->GetVertexIndexData( CDmeVertexData::FIELD_TANGENT ) ),
  133. m_TangentData( pBaseState->GetTangentData() )
  134. {
  135. m_pBaseState = pBaseState;
  136. m_bHasPositionData = m_PositionIndices.Count() > 0;
  137. m_bHasNormalData = m_NormalIndices.Count() > 0;
  138. m_bHasTangentData = m_TangentIndices.Count() > 0;
  139. m_nJointCount = pBaseState->JointCount();
  140. m_bHasSkinningData = pBaseState->HasSkinningData() && m_nJointCount > 0;
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Computes where a vertex is
  144. //-----------------------------------------------------------------------------
  145. void CDmeMeshRenderInfo::ComputePosition( int nPosIndex, const matrix3x4_t *pPoseToWorld, Vector *pDeltaPosition, Vector *pPosition )
  146. {
  147. matrix3x4_t result;
  148. Vector vecMorphPosition;
  149. const matrix3x4_t *pSkinMatrix = pPoseToWorld;
  150. if ( m_bHasSkinningData )
  151. {
  152. const FieldIndex_t nJointWeightsFieldIndex = m_pBaseState->FindFieldIndex( CDmeVertexData::FIELD_JOINT_WEIGHTS );
  153. if ( nJointWeightsFieldIndex >= 0 )
  154. {
  155. const FieldIndex_t nJointIndicesFieldIndex = m_pBaseState->FindFieldIndex( CDmeVertexData::FIELD_JOINT_INDICES );
  156. if ( nJointIndicesFieldIndex >= 0 )
  157. {
  158. const CDmrArrayConst< float > jointWeights( m_pBaseState->GetVertexData( nJointWeightsFieldIndex ) );
  159. const float *pJointWeight = &jointWeights[ nPosIndex * m_pBaseState->JointCount() ];
  160. const CDmrArrayConst< int > jointIndices( m_pBaseState->GetVertexData( nJointIndicesFieldIndex ) );
  161. const int *pJointIndices = &jointIndices[ nPosIndex * m_pBaseState->JointCount() ];
  162. pSkinMatrix = ComputeSkinMatrix( m_nJointCount, pJointWeight, pJointIndices, pPoseToWorld, result );
  163. }
  164. }
  165. }
  166. const Vector *pPositionData = &m_PositionData[ nPosIndex ];
  167. if ( pDeltaPosition )
  168. {
  169. VectorAdd( *pPositionData, *( pDeltaPosition + nPosIndex ), vecMorphPosition );
  170. pPositionData = &vecMorphPosition;
  171. }
  172. VectorTransform( *pPositionData, *pSkinMatrix, *( pPosition + nPosIndex ) );
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Computes where a vertex is
  176. //-----------------------------------------------------------------------------
  177. void CDmeMeshRenderInfo::ComputePosition(
  178. int nPosIndex,
  179. const matrix3x4_t *pPoseToWorld,
  180. CDmeMesh::RenderVertexDelta_t *pDelta,
  181. Vector *pPosition )
  182. {
  183. matrix3x4_t result;
  184. Vector vecMorphPosition, vecMorphNormal;
  185. const matrix3x4_t *pSkinMatrix = pPoseToWorld;
  186. if ( m_bHasSkinningData )
  187. {
  188. const FieldIndex_t nJointWeightsFieldIndex = m_pBaseState->FindFieldIndex( CDmeVertexData::FIELD_JOINT_WEIGHTS );
  189. if ( nJointWeightsFieldIndex >= 0 )
  190. {
  191. const FieldIndex_t nJointIndicesFieldIndex = m_pBaseState->FindFieldIndex( CDmeVertexData::FIELD_JOINT_INDICES );
  192. if ( nJointIndicesFieldIndex >= 0 )
  193. {
  194. const CDmrArrayConst< float > jointWeights( m_pBaseState->GetVertexData( nJointWeightsFieldIndex ) );
  195. const float *pJointWeight = &jointWeights[ nPosIndex * m_pBaseState->JointCount() ];
  196. const CUtlVector< int > &jointIndices = m_pBaseState->GetVertexIndexData( nJointIndicesFieldIndex );
  197. const int *pJointIndices = &jointIndices[ nPosIndex * m_pBaseState->JointCount() ];
  198. pSkinMatrix = ComputeSkinMatrix( m_nJointCount, pJointWeight, pJointIndices, pPoseToWorld, result );
  199. }
  200. }
  201. }
  202. const Vector *pPositionData = &m_PositionData[ nPosIndex ];
  203. if ( pDelta )
  204. {
  205. VectorAdd( *pPositionData, pDelta[ nPosIndex ].m_vecDeltaPosition, vecMorphPosition );
  206. pPositionData = &vecMorphPosition;
  207. }
  208. VectorTransform( *pPositionData, *pSkinMatrix, *pPosition );
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Computes where a vertex is
  212. //-----------------------------------------------------------------------------
  213. void CDmeMeshRenderInfo::ComputeVertex(
  214. int vi,
  215. const matrix3x4_t *pPoseToWorld,
  216. CDmeMesh::RenderVertexDelta_t *pDelta,
  217. Vector *pPosition, Vector *pNormal, Vector4D *pTangent )
  218. {
  219. matrix3x4_t result;
  220. Vector vecMorphPosition, vecMorphNormal;
  221. const matrix3x4_t *pSkinMatrix = pPoseToWorld;
  222. if ( m_bHasSkinningData )
  223. {
  224. const float *pJointWeight = m_pBaseState->GetJointWeights( vi );
  225. const int *pJointIndices = m_pBaseState->GetJointIndices( vi );
  226. pSkinMatrix = ComputeSkinMatrix( m_nJointCount, pJointWeight, pJointIndices, pPoseToWorld, result );
  227. }
  228. int pi = m_PositionIndices[ vi ];
  229. const Vector *pPositionData = &m_PositionData[ pi ];
  230. if ( pDelta )
  231. {
  232. VectorAdd( *pPositionData, pDelta[ pi ].m_vecDeltaPosition, vecMorphPosition );
  233. pPositionData = &vecMorphPosition;
  234. }
  235. VectorTransform( *pPositionData, *pSkinMatrix, *pPosition );
  236. if ( m_bHasNormalData )
  237. {
  238. int ni = m_NormalIndices[ vi ];
  239. const Vector *pNormalData = &m_NormalData[ ni ];
  240. if ( pDelta )
  241. {
  242. VectorAdd( *pNormalData, pDelta[ni].m_vecDeltaNormal, vecMorphNormal );
  243. pNormalData = &vecMorphNormal;
  244. }
  245. VectorRotate( *pNormalData, *pSkinMatrix, *pNormal );
  246. VectorNormalize( *pNormal );
  247. }
  248. else
  249. {
  250. pNormal->Init( 0.0f, 0.0f, 1.0f );
  251. }
  252. if ( m_bHasTangentData )
  253. {
  254. const Vector4D &tangentData = m_TangentData[ m_TangentIndices[ vi ] ];
  255. VectorRotate( tangentData.AsVector3D(), *pSkinMatrix, pTangent->AsVector3D() );
  256. VectorNormalize( pTangent->AsVector3D() );
  257. pTangent->w = tangentData.w;
  258. }
  259. else
  260. {
  261. pTangent->Init( 1.0f, 0.0f, 0.0f, 1.0f );
  262. }
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Expose this class to the scene database
  266. //-----------------------------------------------------------------------------
  267. IMPLEMENT_ELEMENT_FACTORY( DmeMesh, CDmeMesh );
  268. //-----------------------------------------------------------------------------
  269. // Purpose:
  270. //-----------------------------------------------------------------------------
  271. void CDmeMesh::OnConstruction()
  272. {
  273. m_BindBaseState.Init( this, "bindState" );
  274. m_CurrentBaseState.Init( this, "currentState" );
  275. m_BaseStates.Init( this, "baseStates", FATTRIB_MUSTCOPY );
  276. m_DeltaStates.Init( this, "deltaStates", FATTRIB_MUSTCOPY | FATTRIB_HAS_CALLBACK );
  277. m_FaceSets.Init( this, "faceSets", FATTRIB_MUSTCOPY );
  278. m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL].Init( this, "deltaStateWeights" );
  279. m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED].Init( this, "deltaStateWeightsLagged" );
  280. }
  281. void CDmeMesh::OnDestruction()
  282. {
  283. if ( g_pMaterialSystem )
  284. {
  285. CleanupHWMesh();
  286. }
  287. m_hwFaceSets.RemoveAll();
  288. DeleteAttributeVarElementArray( m_BaseStates );
  289. DeleteAttributeVarElementArray( m_DeltaStates );
  290. DeleteAttributeVarElementArray( m_FaceSets );
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Cleans up the HW mesh in case of destruction or rebuild necessary
  294. //-----------------------------------------------------------------------------
  295. void CDmeMesh::CleanupHWMesh()
  296. {
  297. if ( !g_pMaterialSystem )
  298. return;
  299. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  300. int nCount = m_hwFaceSets.Count();
  301. for ( int i = 0; i < nCount; ++i )
  302. {
  303. if ( !m_hwFaceSets[i].m_bBuilt )
  304. continue;
  305. if ( m_hwFaceSets[i].m_pMesh )
  306. {
  307. pRenderContext->DestroyStaticMesh( m_hwFaceSets[i].m_pMesh );
  308. m_hwFaceSets[i].m_pMesh = NULL;
  309. }
  310. m_hwFaceSets[i].m_bBuilt = false;
  311. }
  312. }
  313. //-----------------------------------------------------------------------------
  314. // Initializes the normal material
  315. //-----------------------------------------------------------------------------
  316. void CDmeMesh::InitializeNormalMaterial()
  317. {
  318. if ( !s_bNormalMaterialInitialized )
  319. {
  320. s_bNormalMaterialInitialized = true;
  321. KeyValues *pVMTKeyValues = new KeyValues( "wireframe" );
  322. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  323. pVMTKeyValues->SetInt( "$decal", 1 );
  324. s_NormalMaterial.Init( "__DmeMeshNormalMaterial", pVMTKeyValues );
  325. }
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Initializes the normal material
  329. //-----------------------------------------------------------------------------
  330. void CDmeMesh::InitializeWireframeMaterial()
  331. {
  332. if ( !s_bWireframeMaterialInitialized )
  333. {
  334. s_bWireframeMaterialInitialized = true;
  335. KeyValues *pVMTKeyValues = new KeyValues( "wireframe" );
  336. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  337. s_WireframeMaterial.Init( "__DmeMeshWireframeMaterial", pVMTKeyValues );
  338. }
  339. }
  340. //-----------------------------------------------------------------------------
  341. // resolve internal data from changed attributes
  342. //-----------------------------------------------------------------------------
  343. void CDmeMesh::OnAttributeChanged( CDmAttribute *pAttribute )
  344. {
  345. BaseClass::OnAttributeChanged( pAttribute );
  346. if ( pAttribute == m_DeltaStates.GetAttribute() )
  347. {
  348. int nDeltaStateCount = m_DeltaStates.Count();
  349. for ( int i = 0; i < MESH_DELTA_WEIGHT_TYPE_COUNT; ++i )
  350. {
  351. // Make sure we have the correct number of weights
  352. int nWeightCount = m_DeltaStateWeights[i].Count();
  353. if ( nWeightCount < nDeltaStateCount )
  354. {
  355. for ( int j = nWeightCount; j < nDeltaStateCount; ++j )
  356. {
  357. m_DeltaStateWeights[i].AddToTail( Vector2D( 0.0f, 0.0f ) );
  358. }
  359. }
  360. else if ( nDeltaStateCount > nWeightCount )
  361. {
  362. m_DeltaStateWeights[i].RemoveMultiple( nWeightCount, nWeightCount - nDeltaStateCount );
  363. }
  364. }
  365. }
  366. }
  367. //-----------------------------------------------------------------------------
  368. // Adds deltas into a delta mesh
  369. //-----------------------------------------------------------------------------
  370. template< class T > bool CDmeMesh::AddVertexDelta(
  371. CDmeVertexData *pBaseState,
  372. void *pVertexData, int nStride, CDmeVertexDataBase::StandardFields_t fieldId, int nIndex, bool bDoLag )
  373. {
  374. CDmeVertexDeltaData *pDeltaState = GetDeltaState( nIndex );
  375. if ( !pBaseState || !pDeltaState )
  376. return false;
  377. const FieldIndex_t nBaseFieldIndex = pBaseState->FindFieldIndex( fieldId == CDmeVertexData::FIELD_WRINKLE ? CDmeVertexData::FIELD_TEXCOORD : fieldId );
  378. const FieldIndex_t nDeltaFieldIndex = pDeltaState->FindFieldIndex( fieldId );
  379. if ( nBaseFieldIndex < 0 || nDeltaFieldIndex < 0 )
  380. return false;
  381. const CDmrArray<int> indices = pDeltaState->GetIndexData( nDeltaFieldIndex );
  382. const CDmrArray<T> delta = pDeltaState->GetVertexData( nDeltaFieldIndex );
  383. const int nDeltaCount = indices.Count();
  384. const float flWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][nIndex].x;
  385. const FieldIndex_t nSpeedFieldIndex = pBaseState->FindFieldIndex( CDmeVertexData::FIELD_MORPH_SPEED );
  386. const int nVertexCount = pBaseState->VertexCount();
  387. if ( !bDoLag || nSpeedFieldIndex < 0 )
  388. {
  389. for ( int j = 0; j < nDeltaCount; ++j )
  390. {
  391. int nDataIndex = indices.Get( j );
  392. if ( nDataIndex < 0 || nDataIndex >= nVertexCount )
  393. {
  394. Assert( nDataIndex >= 0 && nDataIndex < nVertexCount );
  395. continue;
  396. }
  397. T* pDeltaData = (T*)( (char*)pVertexData + nStride * nDataIndex );
  398. *pDeltaData += delta.Get( j ) * flWeight;
  399. }
  400. return true;
  401. }
  402. const float flLaggedWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][nIndex].x;
  403. const CDmrArrayConst<int> speedIndices = pBaseState->GetIndexData( nSpeedFieldIndex );
  404. const CDmrArrayConst<float> speedDelta = pBaseState->GetVertexData( nSpeedFieldIndex );
  405. for ( int j = 0; j < nDeltaCount; ++j )
  406. {
  407. int nDataIndex = indices.Get( j );
  408. const CUtlVector<int> &list = pBaseState->FindVertexIndicesFromDataIndex( nBaseFieldIndex, nDataIndex );
  409. Assert( list.Count() > 0 );
  410. // FIXME: Average everything in the list.. shouldn't be necessary though
  411. float flSpeed = speedDelta.Get( speedIndices.Get( list[0] ) );
  412. float flActualWeight = Lerp( flSpeed, flLaggedWeight, flWeight );
  413. T* pDeltaData = (T*)( (char*)pVertexData + nStride * nDataIndex );
  414. *pDeltaData += delta.Get( j ) * flActualWeight;
  415. }
  416. return true;
  417. }
  418. //-----------------------------------------------------------------------------
  419. //
  420. //-----------------------------------------------------------------------------
  421. void CDmeMesh::AddTexCoordDelta( RenderVertexDelta_t *pRenderDelta, float flWeight, CDmeVertexDeltaData *pDeltaState )
  422. {
  423. if ( !pDeltaState )
  424. return;
  425. FieldIndex_t nFieldIndex = pDeltaState->FindFieldIndex( CDmeVertexDeltaData::FIELD_TEXCOORD );
  426. if ( nFieldIndex < 0 )
  427. return;
  428. bool bIsVCoordinateFlipped = pDeltaState->IsVCoordinateFlipped();
  429. const CDmrArray<int> indices = pDeltaState->GetIndexData( nFieldIndex );
  430. const CDmrArray<Vector2D> delta = pDeltaState->GetVertexData( nFieldIndex );
  431. int nDeltaCount = indices.Count();
  432. for ( int j = 0; j < nDeltaCount; ++j )
  433. {
  434. Vector2D uvDelta = delta.Get( j );
  435. if ( bIsVCoordinateFlipped )
  436. {
  437. uvDelta.y = -uvDelta.y;
  438. }
  439. Vector2D &vec2D = pRenderDelta[ indices.Get( j ) ].m_vecDeltaUV;
  440. Vector2DMA( vec2D, flWeight, uvDelta, vec2D );
  441. }
  442. }
  443. //-----------------------------------------------------------------------------
  444. //
  445. //-----------------------------------------------------------------------------
  446. void CDmeMesh::AddColorDelta( RenderVertexDelta_t *pRenderDelta, float flWeight, CDmeVertexDeltaData *pDeltaState )
  447. {
  448. if ( !pDeltaState )
  449. return;
  450. FieldIndex_t nFieldIndex = pDeltaState->FindFieldIndex( CDmeVertexDeltaData::FIELD_COLOR );
  451. if ( nFieldIndex < 0 )
  452. return;
  453. const CDmrArray<int> indices = pDeltaState->GetIndexData( nFieldIndex );
  454. const CDmrArray<Color> delta = pDeltaState->GetVertexData( nFieldIndex );
  455. int nDeltaCount = indices.Count();
  456. for ( int j = 0; j < nDeltaCount; ++j )
  457. {
  458. const Color &srcDeltaColor = delta[ j ];
  459. Vector4D &vecDelta = pRenderDelta[ indices[ j ] ].m_vecDeltaColor;
  460. vecDelta[0] += flWeight * srcDeltaColor.r();
  461. vecDelta[1] += flWeight * srcDeltaColor.g();
  462. vecDelta[2] += flWeight * srcDeltaColor.b();
  463. vecDelta[3] += flWeight * srcDeltaColor.a();
  464. }
  465. }
  466. template< class T > bool CDmeMesh::AddStereoVertexDelta(
  467. CDmeVertexData *pBaseState,
  468. void *pVertexData, int nStride, CDmeVertexDataBase::StandardFields_t fieldId, int nIndex, bool bDoLag )
  469. {
  470. CDmeVertexDeltaData *pDeltaState = GetDeltaState( nIndex );
  471. if ( !pBaseState || !pDeltaState )
  472. return false;
  473. const FieldIndex_t nBaseFieldIndex = pBaseState->FindFieldIndex( fieldId == CDmeVertexData::FIELD_WRINKLE ? CDmeVertexData::FIELD_TEXCOORD : fieldId );
  474. const FieldIndex_t nDeltaFieldIndex = pDeltaState->FindFieldIndex( fieldId );
  475. if ( nBaseFieldIndex < 0 || nDeltaFieldIndex < 0 )
  476. return false;
  477. float flLeftWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][nIndex].x;
  478. float flRightWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][nIndex].y;
  479. const CDmrArray<int> indices = pDeltaState->GetIndexData( nDeltaFieldIndex );
  480. const CDmrArray<T> delta = pDeltaState->GetVertexData( nDeltaFieldIndex );
  481. const CUtlVector<int>& balanceIndices = pBaseState->GetVertexIndexData( CDmeVertexData::FIELD_BALANCE );
  482. const CUtlVector<float> &balanceDelta = pBaseState->GetBalanceData();
  483. const int nDeltaCount = indices.Count();
  484. const FieldIndex_t nSpeedFieldIndex = pBaseState->FindFieldIndex( CDmeVertexData::FIELD_MORPH_SPEED );
  485. if ( !bDoLag || nSpeedFieldIndex < 0 )
  486. {
  487. for ( int j = 0; j < nDeltaCount; ++j )
  488. {
  489. int nDataIndex = indices.Get( j );
  490. const CUtlVector<int> &list = pBaseState->FindVertexIndicesFromDataIndex( nBaseFieldIndex, nDataIndex );
  491. Assert( list.Count() > 0 );
  492. // FIXME: Average everything in the list.. shouldn't be necessary though
  493. float flRightAmount = balanceDelta[ balanceIndices[ list[0] ] ];
  494. float flWeight = Lerp( flRightAmount, flLeftWeight, flRightWeight );
  495. T* pDeltaData = (T*)( (char*)pVertexData + nStride * nDataIndex );
  496. *pDeltaData += delta.Get( j ) * flWeight;
  497. }
  498. return true;
  499. }
  500. float flLeftWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][nIndex].x;
  501. float flRightWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][nIndex].y;
  502. const CDmrArray<int> pSpeedIndices = pBaseState->GetIndexData( nSpeedFieldIndex );
  503. const CDmrArray<float> pSpeedDelta = pBaseState->GetVertexData( nSpeedFieldIndex );
  504. for ( int j = 0; j < nDeltaCount; ++j )
  505. {
  506. int nDataIndex = indices.Get( j );
  507. const CUtlVector<int> &list = pBaseState->FindVertexIndicesFromDataIndex( nBaseFieldIndex, nDataIndex );
  508. Assert( list.Count() > 0 );
  509. // FIXME: Average everything in the list.. shouldn't be necessary though
  510. float flRightAmount = balanceDelta[ balanceIndices[ list[0] ] ];
  511. float flWeight = Lerp( flRightAmount, flLeftWeight, flRightWeight );
  512. float flLaggedWeight = Lerp( flRightAmount, flLeftWeightLagged, flRightWeightLagged );
  513. float flSpeed = pSpeedDelta.Get( pSpeedIndices.Get( list[0] ) );
  514. float flActualWeight = Lerp( flSpeed, flLaggedWeight, flWeight );
  515. T* pDeltaData = (T*)( (char*)pVertexData + nStride * nDataIndex );
  516. *pDeltaData += delta.Get( j ) * flActualWeight;
  517. }
  518. return true;
  519. }
  520. //-----------------------------------------------------------------------------
  521. // Build a color map of one value for each position data value. The color
  522. // is the length of the delta normalized by the maximum delta length
  523. // if delta state is tagged to be highlighted
  524. //-----------------------------------------------------------------------------
  525. Color *BuildDeltaColorMap( CUtlVector< Color > &colorMapDelta, CDmeMesh *pDmeMesh, const Color &cHighlight )
  526. {
  527. CDmeVertexData *pDmeBind = pDmeMesh->GetBindBaseState();
  528. if ( !pDmeBind )
  529. return NULL;
  530. const FieldIndex_t nBasePosField = pDmeBind->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  531. if ( nBasePosField < 0 )
  532. return NULL;
  533. const CUtlVector< Vector > &basePosData = CDmrArrayConst< Vector >( pDmeBind->GetVertexData( nBasePosField ) ).Get();
  534. const int nBasePosCount = basePosData.Count();
  535. if ( nBasePosCount <= 0 )
  536. return NULL;
  537. float *pflDeltaLengths = reinterpret_cast< float * >( stackalloc( nBasePosCount * sizeof( float ) ) );
  538. Q_memset( pflDeltaLengths, 0, nBasePosCount * sizeof( float ) );
  539. float flMaxDeltaLen = 0.0f;
  540. const int nDeltaCount = pDmeMesh->DeltaStateCount();
  541. for ( int i = 0; i < nDeltaCount; ++i )
  542. {
  543. CDmeVertexDeltaData *pDmeDelta = pDmeMesh->GetDeltaState( i );
  544. if ( !pDmeDelta || !pDmeDelta->m_bRenderVerts )
  545. continue;
  546. const FieldIndex_t nDeltaPosField = pDmeDelta->FindFieldIndex( CDmeVertexDeltaData::FIELD_POSITION );
  547. if ( nDeltaPosField < 0 )
  548. continue;
  549. const CUtlVector< Vector > &posData = CDmrArrayConst< Vector >( pDmeDelta->GetVertexData( nDeltaPosField ) ).Get();
  550. const CUtlVector< int > &posIndices = pDmeDelta->GetVertexIndexData( CDmeVertexDeltaData::FIELD_POSITION );
  551. const int nDeltaPosCount = MIN( posData.Count(), posIndices.Count() );
  552. for ( int j = 0; j < nDeltaPosCount; ++j )
  553. {
  554. const float flDeltaLen = posData[j].Length();
  555. if ( flDeltaLen > flMaxDeltaLen )
  556. {
  557. flMaxDeltaLen = flDeltaLen;
  558. }
  559. pflDeltaLengths[posIndices[j]] = MAX( pflDeltaLengths[posIndices[j]], flDeltaLen );
  560. }
  561. }
  562. if ( flMaxDeltaLen <= 0.0f )
  563. return NULL;
  564. flMaxDeltaLen = 1.0f / flMaxDeltaLen;
  565. colorMapDelta.SetCount( nBasePosCount );
  566. color32 c32;
  567. c32.a = 0xff;
  568. const color32 cHighlight32 = cHighlight.ToColor32();
  569. float flLerp = 0.0f;
  570. for ( int i = 0; i < nBasePosCount; ++i )
  571. {
  572. flLerp = pflDeltaLengths[i] * flMaxDeltaLen;
  573. c32.r = Lerp< byte >( flLerp, 0xff, cHighlight32.r );
  574. c32.g = Lerp< byte >( flLerp, 0xff, cHighlight32.g );
  575. c32.b = Lerp< byte >( flLerp, 0xff, cHighlight32.b );
  576. colorMapDelta[i] = c32;
  577. }
  578. return colorMapDelta.Base();
  579. }
  580. //-----------------------------------------------------------------------------
  581. // Draws the mesh when it uses too many bones
  582. //-----------------------------------------------------------------------------
  583. bool CDmeMesh::BuildDeltaMesh( int nVertices, RenderVertexDelta_t *pRenderDelta )
  584. {
  585. bool bHasWrinkleDelta = false;
  586. memset( pRenderDelta, 0, nVertices * sizeof( RenderVertexDelta_t ) );
  587. int nCount = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL].Count();
  588. Assert( m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL].Count() == m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED].Count() );
  589. CDmeVertexData *pBindState = GetBindBaseState();
  590. const FieldIndex_t nBalanceFieldIndex = pBindState->FindFieldIndex( CDmeVertexDeltaData::FIELD_BALANCE );
  591. const FieldIndex_t nSpeedFieldIndex = pBindState->FindFieldIndex( CDmeVertexDeltaData::FIELD_MORPH_SPEED );
  592. const bool bDoLag = nSpeedFieldIndex >= 0;
  593. if ( nBalanceFieldIndex < 0 )
  594. {
  595. for ( int i = 0; i < nCount; ++i )
  596. {
  597. float flWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].x;
  598. float flLaggedWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].x;
  599. if ( flWeight <= 0.0f && flLaggedWeight <= 0.0f )
  600. continue;
  601. // prepare vertices
  602. CDmeVertexDeltaData *pDeltaState = GetDeltaState(i);
  603. AddVertexDelta<Vector>( pBindState, &pRenderDelta->m_vecDeltaPosition, sizeof(RenderVertexDelta_t), CDmeVertexDeltaData::FIELD_POSITION, i, bDoLag );
  604. AddVertexDelta<Vector>( pBindState, &pRenderDelta->m_vecDeltaNormal, sizeof(RenderVertexDelta_t), CDmeVertexDeltaData::FIELD_NORMAL, i, bDoLag );
  605. AddTexCoordDelta( pRenderDelta, flWeight, pDeltaState );
  606. AddColorDelta( pRenderDelta, flWeight, pDeltaState );
  607. bool bWrinkle = AddVertexDelta<float>( pBindState, &pRenderDelta->m_flDeltaWrinkle, sizeof(RenderVertexDelta_t), CDmeVertexDeltaData::FIELD_WRINKLE, i, bDoLag );
  608. bHasWrinkleDelta = bHasWrinkleDelta || bWrinkle;
  609. }
  610. return bHasWrinkleDelta;
  611. }
  612. for ( int i = 0; i < nCount; ++i )
  613. {
  614. float flLeftWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].x;
  615. float flRightWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].y;
  616. float flLeftWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].x;
  617. float flRightWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].y;
  618. if ( flLeftWeight <= 0.0f && flRightWeight <= 0.0f && flLeftWeightLagged <= 0.0f && flRightWeightLagged <= 0.0f )
  619. continue;
  620. // FIXME: Need to make balanced versions of texcoord + color
  621. bool bWrinkle;
  622. CDmeVertexDeltaData *pDeltaState = GetDeltaState(i);
  623. AddStereoVertexDelta<Vector>( pBindState, &pRenderDelta->m_vecDeltaPosition, sizeof(RenderVertexDelta_t), CDmeVertexDeltaData::FIELD_POSITION, i, bDoLag );
  624. AddStereoVertexDelta<Vector>( pBindState, &pRenderDelta->m_vecDeltaNormal, sizeof(RenderVertexDelta_t), CDmeVertexDeltaData::FIELD_NORMAL, i, bDoLag );
  625. bWrinkle = AddStereoVertexDelta<float>( pBindState, &pRenderDelta->m_flDeltaWrinkle, sizeof(RenderVertexDelta_t), CDmeVertexDeltaData::FIELD_WRINKLE, i, bDoLag);
  626. bHasWrinkleDelta = bHasWrinkleDelta || bWrinkle;
  627. AddTexCoordDelta( pRenderDelta, flLeftWeight, pDeltaState );
  628. AddColorDelta( pRenderDelta, flLeftWeight, pDeltaState );
  629. }
  630. return bHasWrinkleDelta;
  631. }
  632. //-----------------------------------------------------------------------------
  633. // Writes triangulated indices for a face set into a meshbuilder
  634. //-----------------------------------------------------------------------------
  635. void CDmeMesh::WriteTriangluatedIndices( const CDmeVertexData *pBaseState, CDmeFaceSet *pFaceSet, CMeshBuilder &meshBuilder )
  636. {
  637. int indices[ 256 ];
  638. // prepare indices
  639. int nFirstIndex = 0;
  640. int nIndexCount = pFaceSet->NumIndices();
  641. while ( nFirstIndex < nIndexCount )
  642. {
  643. int nVertexCount = pFaceSet->GetNextPolygonVertexCount( nFirstIndex );
  644. if ( nVertexCount >= 3 )
  645. {
  646. int nOutCount = ( nVertexCount-2 ) * 3;
  647. int *pIndices = ( nOutCount > ARRAYSIZE( indices ) ) ? new int[ nOutCount ] : indices;
  648. ComputeTriangulatedIndices( pBaseState, pFaceSet, nFirstIndex, pIndices, nOutCount );
  649. for ( int ii = 0; ii < nOutCount; ++ii )
  650. {
  651. meshBuilder.FastIndex( pIndices[ii] );
  652. }
  653. if ( pIndices != indices )
  654. {
  655. delete[] pIndices;
  656. }
  657. }
  658. nFirstIndex += nVertexCount + 1;
  659. }
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Draws the mesh when it uses too many bones
  663. //-----------------------------------------------------------------------------
  664. void CDmeMesh::DrawDynamicMesh( CDmeFaceSet *pFaceSet, matrix3x4_t *pPoseToWorld, bool bHasActiveDeltaStates, CDmeDrawSettings *pDrawSettings /* = NULL */ )
  665. {
  666. CDmeVertexData *pBindBase = GetCurrentBaseState();
  667. if ( !pBindBase )
  668. return;
  669. // NOTE: This is inherently inefficient; we re-skin the *entire* mesh,
  670. // even if it's not being used by the entire model. This is because we can't
  671. // guarantee the various materials from the various face sets use the
  672. // same vertex format (even though they should), and we don't want to
  673. // spend the work to detemine the sub-part of the mesh used by this face set.
  674. // Compute vertex deltas for rendering
  675. const int nVertices = pBindBase->VertexCount();
  676. // NOTE: The Delta Data is actually indexed by the pPositionIndices, pNormalIndices, etc.
  677. // The fact that we're storing one delta per final vertex nVertices
  678. // is a waste of memory and simply implementational convenience.
  679. CUtlVector< RenderVertexDelta_t > vertexDelta( 0, nVertices );
  680. CUtlVector< Color > deltaColorMap;
  681. Color *pDeltaColorMap = NULL;
  682. if ( pDrawSettings && pDrawSettings->GetDeltaHighlight() )
  683. {
  684. pDeltaColorMap = BuildDeltaColorMap( deltaColorMap, this, pDrawSettings->m_cHighlightColor );
  685. }
  686. bool bHasActiveWrinkle = false;
  687. RenderVertexDelta_t *pVertexDelta = vertexDelta.Base();
  688. if ( bHasActiveDeltaStates )
  689. {
  690. bHasActiveWrinkle = BuildDeltaMesh( nVertices, pVertexDelta );
  691. }
  692. else
  693. {
  694. pVertexDelta = NULL;
  695. }
  696. CDmeMeshRenderInfo renderInfo( pBindBase );
  697. Assert( renderInfo.HasPositionData() );
  698. // prepare vertices
  699. FieldIndex_t uvField = pBindBase->FindFieldIndex( CDmeVertexData::FIELD_TEXCOORD );
  700. FieldIndex_t colorField = pBindBase->FindFieldIndex( CDmeVertexData::FIELD_COLOR );
  701. bool bHasTexCoords = ( uvField >= 0 );
  702. bool bHasColors = ( colorField >= 0 );
  703. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  704. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  705. const CDmrArrayConst<int> pUVIndices = bHasTexCoords ? pBindBase->GetIndexData( uvField ) : NULL;
  706. if ( bHasActiveWrinkle && bHasTexCoords )
  707. {
  708. // Create the wrinkle flex mesh
  709. IMesh *pFlexDelta = pRenderContext->GetFlexMesh();
  710. int nFlexVertexOffset = 0;
  711. CMeshBuilder meshBuilder;
  712. meshBuilder.Begin( pFlexDelta, MATERIAL_HETEROGENOUS, nVertices, 0, &nFlexVertexOffset );
  713. for ( int j=0; j < nVertices; j++ )
  714. {
  715. // NOTE: The UV indices are also used to index into wrinkle data
  716. int nUVIndex = pUVIndices.Get( j );
  717. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  718. meshBuilder.NormalDelta3f( 0.0f, 0.0f, 0.0f );
  719. meshBuilder.Wrinkle1f( pVertexDelta[nUVIndex].m_flDeltaWrinkle );
  720. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVENORMAL, 0>();
  721. }
  722. meshBuilder.End( false, false );
  723. pMesh->SetFlexMesh( pFlexDelta, nFlexVertexOffset );
  724. }
  725. // build the mesh
  726. int nIndices = pFaceSet->GetTriangulatedIndexCount();
  727. CMeshBuilder meshBuilder;
  728. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertices, nIndices );
  729. const CDmrArrayConst<Vector2D> pUVData = bHasTexCoords ? pBindBase->GetVertexData( uvField ) : NULL;
  730. const CDmrArrayConst<int> pColorIndices = bHasColors ? pBindBase->GetIndexData( colorField ) : NULL;
  731. const CDmrArrayConst<Color> pColorData = bHasColors ? pBindBase->GetVertexData( colorField ) : NULL;
  732. const CUtlVector< int > &basePosIndices = pBindBase->GetVertexIndexData( CDmeVertexData::FIELD_POSITION );
  733. Vector vecPosition, vecNormal;
  734. Vector4D vecTangent;
  735. for ( int vi = 0; vi < nVertices; ++vi )
  736. {
  737. renderInfo.ComputeVertex( vi, pPoseToWorld, pVertexDelta, &vecPosition, &vecNormal, &vecTangent );
  738. meshBuilder.Position3fv( vecPosition.Base() );
  739. meshBuilder.Normal3fv( vecNormal.Base() );
  740. meshBuilder.UserData( vecTangent.Base() );
  741. if ( pUVData.IsValid() )
  742. {
  743. int uvi = pUVIndices.Get( vi );
  744. Vector2D uv = pUVData.Get( uvi );
  745. if ( pBindBase->IsVCoordinateFlipped() )
  746. {
  747. uv.y = 1.0f - uv.y;
  748. }
  749. if ( bHasActiveDeltaStates )
  750. {
  751. uv += pVertexDelta[uvi].m_vecDeltaUV;
  752. }
  753. meshBuilder.TexCoord2fv( 0, uv.Base() );
  754. }
  755. else
  756. {
  757. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  758. }
  759. if ( pDeltaColorMap )
  760. {
  761. int cColor = pDeltaColorMap[ basePosIndices[ vi ] ].GetRawColor();
  762. meshBuilder.Color4ubv( (unsigned char*)&cColor );
  763. }
  764. else
  765. {
  766. if ( pColorIndices.IsValid() )
  767. {
  768. int ci = pColorIndices.Get( vi );
  769. int color = pColorData.Get( ci ).GetRawColor();
  770. meshBuilder.Color4ubv( (unsigned char*)&color );
  771. }
  772. else
  773. {
  774. meshBuilder.Color4ub( 255, 255, 255, 255 );
  775. }
  776. }
  777. meshBuilder.AdvanceVertexF<VTX_HAVEALL, 1>();
  778. }
  779. WriteTriangluatedIndices( pBindBase, pFaceSet, meshBuilder );
  780. meshBuilder.End();
  781. pMesh->Draw();
  782. if ( pDrawSettings && pDrawSettings->GetNormals() )
  783. {
  784. RenderNormals( pPoseToWorld, bHasActiveDeltaStates ? pVertexDelta : NULL );
  785. }
  786. // CacheHighlightVerts( pPoseToWorld, bHasActiveDeltaStates ? pVertexDelta : NULL, pDrawSettings );
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Renders normals
  790. //-----------------------------------------------------------------------------
  791. #define NORMAL_LINE_SIZE 0.25f
  792. void CDmeMesh::RenderNormals( matrix3x4_t *pPoseToWorld, RenderVertexDelta_t *pDelta )
  793. {
  794. CDmeVertexData *pBind = GetBindBaseState();
  795. if ( !pBind )
  796. return;
  797. CDmeMeshRenderInfo renderInfo( pBind );
  798. Assert( renderInfo.HasPositionData() );
  799. if ( !renderInfo.HasNormalData() )
  800. return;
  801. bool bHasTangents = renderInfo.HasTangentData();
  802. // build the mesh
  803. InitializeNormalMaterial();
  804. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  805. pRenderContext->Bind( s_NormalMaterial );
  806. IMesh *pMesh = pRenderContext->GetDynamicMesh( );
  807. int nMaxIndices, nMaxVertices;
  808. pRenderContext->GetMaxToRender( pMesh, false, &nMaxVertices, &nMaxIndices );
  809. int nFirstVertex = 0;
  810. int nVerticesRemaining = pBind->VertexCount();;
  811. int nFactor = bHasTangents ? 6 : 2;
  812. while ( nVerticesRemaining > 0 )
  813. {
  814. int nVertices = nVerticesRemaining;
  815. if ( nVertices > nMaxVertices / nFactor )
  816. {
  817. nVertices = nMaxVertices / nFactor;
  818. }
  819. if ( nVertices > nMaxIndices / nFactor )
  820. {
  821. nVertices = nMaxIndices / nFactor;
  822. }
  823. nVerticesRemaining -= nVertices;
  824. CMeshBuilder meshBuilder;
  825. meshBuilder.Begin( pMesh, MATERIAL_LINES, bHasTangents ? nVertices * 3 : nVertices );
  826. Vector vecPosition, vecNormal, vecEndPoint, vecTangentS, vecTangentT;
  827. Vector4D vecTangent;
  828. for ( int vi = nFirstVertex; vi < nVertices; ++vi )
  829. {
  830. renderInfo.ComputeVertex( vi, pPoseToWorld, pDelta, &vecPosition, &vecNormal, &vecTangent );
  831. meshBuilder.Position3fv( vecPosition.Base() );
  832. meshBuilder.Color4ub( 0, 0, 255, 255 );
  833. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  834. VectorMA( vecPosition, NORMAL_LINE_SIZE, vecNormal, vecEndPoint );
  835. meshBuilder.Position3fv( vecEndPoint.Base() );
  836. meshBuilder.Color4ub( 0, 0, 255, 255 );
  837. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  838. continue;
  839. if ( !bHasTangents )
  840. continue;
  841. CrossProduct( vecNormal, vecTangent.AsVector3D(), vecTangentT );
  842. VectorNormalize( vecTangentT );
  843. // NOTE: This is the new, desired tangentS morphing behavior
  844. // CrossProduct( vecTangentT, vecNormal, vecTangentS );
  845. VectorCopy( vecTangent.AsVector3D(), vecTangentS );
  846. vecTangentT *= vecTangent.w;
  847. meshBuilder.Position3fv( vecPosition.Base() );
  848. meshBuilder.Color4ub( 255, 0, 0, 255 );
  849. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  850. VectorMA( vecPosition, NORMAL_LINE_SIZE, vecTangentS, vecEndPoint );
  851. meshBuilder.Position3fv( vecEndPoint.Base() );
  852. meshBuilder.Color4ub( 255, 0, 0, 255 );
  853. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  854. meshBuilder.Position3fv( vecPosition.Base() );
  855. meshBuilder.Color4ub( 0, 255, 0, 255 );
  856. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  857. VectorMA( vecPosition, NORMAL_LINE_SIZE, vecTangentT, vecEndPoint );
  858. meshBuilder.Position3fv( vecEndPoint.Base() );
  859. meshBuilder.Color4ub( 0, 255, 0, 255 );
  860. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  861. }
  862. meshBuilder.End();
  863. pMesh->Draw();
  864. nFirstVertex += nVertices;
  865. }
  866. }
  867. //-----------------------------------------------------------------------------
  868. //
  869. //-----------------------------------------------------------------------------
  870. void CDmeMesh::CacheHighlightVerts( matrix3x4_t *pPoseToWorld, RenderVertexDelta_t *pDelta, CDmeDrawSettings *pDmeDrawSettings )
  871. {
  872. if ( !pDmeDrawSettings )
  873. return;
  874. CDmeVertexData *pBind = GetBindBaseState();
  875. if ( !pBind )
  876. return;
  877. const CUtlVector< Vector > &posData = pBind->GetPositionData();
  878. const int nPosCount = posData.Count();
  879. bool *pbHighlight = reinterpret_cast< bool * >( stackalloc( nPosCount * sizeof( bool ) ) );
  880. Q_memset( pbHighlight, 0, nPosCount * sizeof( bool ) );
  881. for ( int i = 0; i < m_DeltaStates.Count(); ++i )
  882. {
  883. CDmeVertexDeltaData *pDmeDelta = m_DeltaStates[i];
  884. if ( !pDmeDelta || !pDmeDelta->m_bRenderVerts )
  885. continue;
  886. const CUtlVector< int > &deltaIndices = pDmeDelta->GetVertexIndexData( CDmeVertexDeltaData::FIELD_POSITION );
  887. for ( int j = 0; j < deltaIndices.Count(); ++j )
  888. {
  889. pbHighlight[deltaIndices[j]] = true;
  890. }
  891. }
  892. CDmeMeshRenderInfo renderInfo( pBind );
  893. Assert( renderInfo.HasPositionData() );
  894. CUtlVector< Vector > &highlightPoints = pDmeDrawSettings->GetHighlightPoints();
  895. Vector vPosition;
  896. for ( int i = 0; i < nPosCount; ++i )
  897. {
  898. if ( !pbHighlight[i] )
  899. continue;
  900. renderInfo.ComputePosition( i, pPoseToWorld, pDelta, &vPosition );
  901. highlightPoints.AddToTail( vPosition );
  902. }
  903. }
  904. //-----------------------------------------------------------------------------
  905. // Draws the passed DmeFaceSet in wireframe mode
  906. //-----------------------------------------------------------------------------
  907. void CDmeMesh::DrawWireframeFaceSet(
  908. CDmeFaceSet *pDmeFaceSet,
  909. matrix3x4_t *pPoseToWorld,
  910. bool bHasActiveDeltaStates,
  911. CDmeDrawSettings *pDmeDrawSettings )
  912. {
  913. CDmeVertexData *pBind = GetBindBaseState();
  914. if ( !pBind )
  915. return;
  916. const FieldIndex_t posField = pBind->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  917. if ( posField < 0 )
  918. return;
  919. const CUtlVector< Vector > &posData( CDmrArrayConst< Vector >( pBind->GetVertexData( posField ) ).Get() );
  920. const int nPosCount = posData.Count();
  921. const CUtlVector< int > &posIndices( CDmrArrayConst< int >( pBind->GetIndexData( posField ) ).Get() );
  922. Vector *pDeltaVertices = bHasActiveDeltaStates ? pDeltaVertices = reinterpret_cast< Vector * >( alloca( nPosCount * sizeof( Vector ) ) ) : NULL;
  923. if ( bHasActiveDeltaStates )
  924. {
  925. memset( pDeltaVertices, 0, sizeof( Vector ) * nPosCount );
  926. const int nCount = m_DeltaStateWeights[ MESH_DELTA_WEIGHT_NORMAL ].Count();
  927. const FieldIndex_t nBalanceFieldIndex = pBind->FindFieldIndex( CDmeVertexDeltaData::FIELD_BALANCE );
  928. const FieldIndex_t nSpeedFieldIndex = pBind->FindFieldIndex( CDmeVertexDeltaData::FIELD_MORPH_SPEED );
  929. const bool bDoLag = ( nSpeedFieldIndex >= 0 );
  930. if ( nBalanceFieldIndex < 0 )
  931. {
  932. for ( int i = 0; i < nCount; ++i )
  933. {
  934. float flWeight = m_DeltaStateWeights[ MESH_DELTA_WEIGHT_NORMAL ][ i ].x;
  935. float flLaggedWeight = m_DeltaStateWeights[ MESH_DELTA_WEIGHT_LAGGED ][ i ].x;
  936. if ( flWeight <= 0.0f && ( !bDoLag || flLaggedWeight <= 0.0f ) )
  937. continue;
  938. AddVertexDelta< Vector >( pBind, pDeltaVertices, sizeof( Vector ), CDmeVertexDeltaData::FIELD_POSITION, i, bDoLag );
  939. }
  940. }
  941. else
  942. {
  943. for ( int i = 0; i < nCount; ++i )
  944. {
  945. float flLeftWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].x;
  946. float flRightWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].y;
  947. float flLeftWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].x;
  948. float flRightWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].y;
  949. if ( flLeftWeight <= 0.0f && flRightWeight <= 0.0f && ( !bDoLag || ( flLeftWeightLagged <= 0.0f && flRightWeightLagged <= 0.0f ) ) )
  950. continue;
  951. AddStereoVertexDelta< Vector >( pBind, pDeltaVertices, sizeof( Vector ), CDmeVertexDeltaData::FIELD_POSITION, i, bDoLag );
  952. }
  953. }
  954. }
  955. Vector *pVertices = reinterpret_cast< Vector * >( alloca( nPosCount * sizeof( Vector ) ) );
  956. bool *pbHighlight = reinterpret_cast< bool * >( stackalloc( nPosCount * sizeof( bool ) ) );
  957. Q_memset( pbHighlight, 0, nPosCount * sizeof( bool ) );
  958. for ( int i = 0; i < m_DeltaStates.Count(); ++i )
  959. {
  960. CDmeVertexDeltaData *pDmeDelta = m_DeltaStates[i];
  961. if ( !pDmeDelta || !pDmeDelta->m_bRenderVerts )
  962. continue;
  963. const CUtlVector< int > &deltaIndices = pDmeDelta->GetVertexIndexData( CDmeVertexDeltaData::FIELD_POSITION );
  964. for ( int j = 0; j < deltaIndices.Count(); ++j )
  965. {
  966. pbHighlight[deltaIndices[j]] = true;
  967. }
  968. }
  969. CDmeMeshRenderInfo renderInfo( pBind );
  970. Assert( renderInfo.HasPositionData() );
  971. if ( false && pDmeDrawSettings )
  972. {
  973. CUtlVector< Vector > &highlightPoints = pDmeDrawSettings->GetHighlightPoints();
  974. for ( int pi = 0; pi < nPosCount; ++pi )
  975. {
  976. renderInfo.ComputePosition( pi, pPoseToWorld, pDeltaVertices, pVertices );
  977. if ( !pbHighlight[pi] )
  978. continue;
  979. highlightPoints.AddToTail( pVertices[pi] );
  980. }
  981. }
  982. else
  983. {
  984. for ( int pi = 0; pi < nPosCount; ++pi )
  985. {
  986. renderInfo.ComputePosition( pi, pPoseToWorld, pDeltaVertices, pVertices );
  987. }
  988. }
  989. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  990. if ( !pDmeDrawSettings || !pDmeDrawSettings->IsAMaterialBound() )
  991. {
  992. InitializeWireframeMaterial();
  993. pRenderContext->Bind( s_WireframeMaterial );
  994. }
  995. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  996. // build the mesh
  997. CMeshBuilder meshBuilder;
  998. // Draw the polygons in the face set
  999. const int nFaceSetIndices = pDmeFaceSet->NumIndices();
  1000. const int *pFaceSetIndices = pDmeFaceSet->GetIndices();
  1001. int vR = 0;
  1002. int vG = 0;
  1003. int vB = 0;
  1004. if ( pDmeDrawSettings )
  1005. {
  1006. const Color &vColor = pDmeDrawSettings->GetColor();
  1007. vR = vColor.r();
  1008. vG = vColor.g();
  1009. vB = vColor.b();
  1010. }
  1011. int nFaceIndices;
  1012. for ( int i = 0; i < nFaceSetIndices; )
  1013. {
  1014. nFaceIndices = pDmeFaceSet->GetNextPolygonVertexCount( i );
  1015. meshBuilder.Begin( pMesh, MATERIAL_LINES, nFaceIndices );
  1016. for ( int j = 0; j < nFaceIndices; ++j )
  1017. {
  1018. Assert( i < nFaceSetIndices );
  1019. int vIndex0 = posIndices[ pFaceSetIndices[ i + j ] ];
  1020. Assert( vIndex0 < nPosCount );
  1021. meshBuilder.Position3fv( reinterpret_cast< float * >( pVertices + vIndex0 ) );
  1022. meshBuilder.Color3ub( vR, vG, vB );
  1023. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  1024. int vIndex1 = posIndices[ pFaceSetIndices[ i + ( ( j + 1 ) % nFaceIndices ) ] ];
  1025. Assert( vIndex1 < nPosCount );
  1026. meshBuilder.Position3fv( reinterpret_cast< float * >( pVertices + vIndex1) );
  1027. meshBuilder.Color3ub( vR, vG, vB );
  1028. meshBuilder.AdvanceVertexF<VTX_HAVEPOS | VTX_HAVECOLOR, 0>();
  1029. }
  1030. meshBuilder.End();
  1031. i += nFaceIndices + 1;
  1032. }
  1033. pMesh->Draw();
  1034. }
  1035. //-----------------------------------------------------------------------------
  1036. // Do we have active delta state data?
  1037. //-----------------------------------------------------------------------------
  1038. bool CDmeMesh::HasActiveDeltaStates() const
  1039. {
  1040. for ( int t = 0; t < MESH_DELTA_WEIGHT_TYPE_COUNT; ++t )
  1041. {
  1042. int nCount = m_DeltaStateWeights[t].Count();
  1043. for ( int i = 0; i < nCount; ++i )
  1044. {
  1045. if ( m_DeltaStateWeights[t][i].x != 0.0f || m_DeltaStateWeights[t][i].y != 0.0f )
  1046. return true;
  1047. }
  1048. }
  1049. return false;
  1050. }
  1051. //-----------------------------------------------------------------------------
  1052. // Draws the mesh
  1053. //-----------------------------------------------------------------------------
  1054. void CDmeMesh::Draw( const matrix3x4_t &shapeToWorld, CDmeDrawSettings *pDrawSettings /* = NULL */ )
  1055. {
  1056. CDmeVertexData *pBind = GetBindBaseState();
  1057. if ( !pBind || !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
  1058. return;
  1059. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1060. const bool bHasActiveDeltaStates = HasActiveDeltaStates();
  1061. const bool bDrawNormals = pDrawSettings ? pDrawSettings->GetNormals() : false;
  1062. const CDmeDrawSettings::DrawType_t drawType = pDrawSettings ? pDrawSettings->GetDrawType() : CDmeDrawSettings::DRAW_SMOOTH;
  1063. const bool bShaded = ( drawType == CDmeDrawSettings::DRAW_SMOOTH || drawType == CDmeDrawSettings::DRAW_FLAT );
  1064. const bool bWireframe = ( drawType == CDmeDrawSettings::DRAW_WIREFRAME );
  1065. // const bool bBoundingBox = ( drawType == CDmeDrawSettings::DRAW_BOUNDINGBOX );
  1066. const bool bDeltaHighlight = pDrawSettings ? pDrawSettings->GetDeltaHighlight() : false;
  1067. const bool bSoftwareSkinning = bHasActiveDeltaStates | bDrawNormals | bWireframe | bDeltaHighlight;
  1068. matrix3x4_t *pPoseToWorld = CDmeModel::SetupModelRenderState( shapeToWorld, pBind->HasSkinningData(), bSoftwareSkinning );
  1069. pRenderContext->SetNumBoneWeights( pPoseToWorld ? 0 : pBind->JointCount() );
  1070. int nFaceSets = FaceSetCount();
  1071. m_hwFaceSets.EnsureCount( nFaceSets );
  1072. const bool bindMaterial = pDrawSettings ? !pDrawSettings->IsAMaterialBound() : true;
  1073. for ( int fi = 0; fi < nFaceSets; ++fi )
  1074. {
  1075. CDmeFaceSet *pFaceSet = GetFaceSet( fi );
  1076. if ( bWireframe )
  1077. {
  1078. DrawWireframeFaceSet( pFaceSet, pPoseToWorld, bHasActiveDeltaStates, pDrawSettings );
  1079. continue;
  1080. }
  1081. if ( bindMaterial )
  1082. {
  1083. pRenderContext->Bind( pFaceSet->GetMaterial()->GetCachedMTL() );
  1084. }
  1085. if ( pPoseToWorld || ( bShaded && bSoftwareSkinning ) )
  1086. {
  1087. DrawDynamicMesh( pFaceSet, pPoseToWorld, bHasActiveDeltaStates, pDrawSettings );
  1088. continue;
  1089. }
  1090. // TODO: figure out how to tell the mesh when the faceset's indices change
  1091. if ( !m_hwFaceSets[fi].m_bBuilt )
  1092. {
  1093. m_hwFaceSets[fi].m_pMesh = CreateHwMesh( pFaceSet );
  1094. m_hwFaceSets[fi].m_bBuilt = true;
  1095. }
  1096. if ( m_hwFaceSets[fi].m_pMesh )
  1097. {
  1098. m_hwFaceSets[fi].m_pMesh->Draw();
  1099. }
  1100. }
  1101. pRenderContext->SetNumBoneWeights( 0 );
  1102. CDmeModel::CleanupModelRenderState();
  1103. }
  1104. //-----------------------------------------------------------------------------
  1105. // Face sets
  1106. //-----------------------------------------------------------------------------
  1107. int CDmeMesh::FaceSetCount() const
  1108. {
  1109. return m_FaceSets.Count();
  1110. }
  1111. CDmeFaceSet *CDmeMesh::GetFaceSet( int faceSetIndex )
  1112. {
  1113. return m_FaceSets[ faceSetIndex ];
  1114. }
  1115. const CDmeFaceSet *CDmeMesh::GetFaceSet( int faceSetIndex ) const
  1116. {
  1117. return m_FaceSets[ faceSetIndex ];
  1118. }
  1119. void CDmeMesh::AddFaceSet( CDmeFaceSet *faceSet )
  1120. {
  1121. m_FaceSets.AddToTail( faceSet );
  1122. }
  1123. void CDmeMesh::RemoveFaceSet( int faceSetIndex )
  1124. {
  1125. m_FaceSets.Remove( faceSetIndex );
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. // Find a base state by name
  1129. //-----------------------------------------------------------------------------
  1130. CDmeVertexData *CDmeMesh::FindBaseState( const char *pStateName ) const
  1131. {
  1132. const int nBaseStateCount = BaseStateCount();
  1133. for ( int i = 0; i < nBaseStateCount; ++i )
  1134. {
  1135. CDmeVertexData *pBaseState = GetBaseState( i );
  1136. if ( !Q_stricmp( pStateName, pBaseState->GetName() ) )
  1137. return pBaseState;
  1138. }
  1139. return NULL;
  1140. }
  1141. //-----------------------------------------------------------------------------
  1142. // Find a base state by name, add a new one if not found
  1143. //-----------------------------------------------------------------------------
  1144. CDmeVertexData *CDmeMesh::FindOrCreateBaseState( const char *pStateName )
  1145. {
  1146. CDmeVertexData *pBaseState = FindBaseState( pStateName );
  1147. if ( pBaseState )
  1148. return pBaseState;
  1149. pBaseState = CreateElement< CDmeVertexData >( pStateName, GetFileId() );
  1150. m_BaseStates.AddToTail( pBaseState );
  1151. return pBaseState;
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // Remove a base state by name
  1155. //-----------------------------------------------------------------------------
  1156. bool CDmeMesh::DeleteBaseState( const char *pStateName )
  1157. {
  1158. const int nBaseStateCount = BaseStateCount();
  1159. for ( int i = 0; i < nBaseStateCount; ++i )
  1160. {
  1161. const CDmeVertexData *pBaseState = GetBaseState( i );
  1162. if ( !Q_stricmp( pStateName, pBaseState->GetName() ) )
  1163. {
  1164. m_BaseStates.Remove( i );
  1165. g_pDataModel->DestroyElement( pBaseState->GetHandle() );
  1166. // TODO: Fix up all dependent states
  1167. return true;
  1168. }
  1169. }
  1170. return false;
  1171. }
  1172. //-----------------------------------------------------------------------------
  1173. // Selects a particular base state to be current state
  1174. //-----------------------------------------------------------------------------
  1175. void CDmeMesh::SetCurrentBaseState( const char *pStateName )
  1176. {
  1177. m_CurrentBaseState = FindBaseState( pStateName );
  1178. }
  1179. //-----------------------------------------------------------------------------
  1180. // Selects a particular base state to be current state
  1181. //-----------------------------------------------------------------------------
  1182. CDmeVertexData *CDmeMesh::GetCurrentBaseState()
  1183. {
  1184. return m_CurrentBaseState;
  1185. }
  1186. //-----------------------------------------------------------------------------
  1187. // Selects a particular base state to be current state
  1188. //-----------------------------------------------------------------------------
  1189. const CDmeVertexData *CDmeMesh::GetCurrentBaseState() const
  1190. {
  1191. return m_CurrentBaseState;
  1192. }
  1193. //-----------------------------------------------------------------------------
  1194. //
  1195. //-----------------------------------------------------------------------------
  1196. bool CDmeMesh::SetBindBaseState( CDmeVertexData *pBaseState )
  1197. {
  1198. if ( !pBaseState )
  1199. return false;
  1200. CDmeVertexData *pCheckState = FindBaseState( pBaseState->GetName() );
  1201. if ( pCheckState != pBaseState )
  1202. return false;
  1203. return true;
  1204. }
  1205. //-----------------------------------------------------------------------------
  1206. //
  1207. //-----------------------------------------------------------------------------
  1208. CDmeVertexData *CDmeMesh::GetBindBaseState()
  1209. {
  1210. if ( m_BindBaseState.GetElement() )
  1211. return m_BindBaseState;
  1212. // Backwards compatibility
  1213. return FindBaseState( "bind" );
  1214. }
  1215. //-----------------------------------------------------------------------------
  1216. //
  1217. //-----------------------------------------------------------------------------
  1218. const CDmeVertexData *CDmeMesh::GetBindBaseState() const
  1219. {
  1220. if ( m_BindBaseState.GetElement() )
  1221. return m_BindBaseState;
  1222. // Backwards compatibility
  1223. return FindBaseState( "bind" );
  1224. }
  1225. //-----------------------------------------------------------------------------
  1226. // Delta states
  1227. //-----------------------------------------------------------------------------
  1228. int CDmeMesh::DeltaStateCount() const
  1229. {
  1230. return m_DeltaStates.Count();
  1231. }
  1232. //-----------------------------------------------------------------------------
  1233. // Returns the delta
  1234. //-----------------------------------------------------------------------------
  1235. CDmeVertexDeltaData *CDmeMesh::GetDeltaState( int nDeltaIndex ) const
  1236. {
  1237. if ( nDeltaIndex < 0 || nDeltaIndex >= m_DeltaStates.Count() )
  1238. return NULL;
  1239. return m_DeltaStates[ nDeltaIndex ];
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. // Finds a delta state by name. If it isn't found, return NULL
  1243. //-----------------------------------------------------------------------------
  1244. CDmeVertexDeltaData *CDmeMesh::FindDeltaState( const char *pDeltaName, bool bSortDeltaName /* = true */ ) const
  1245. {
  1246. return GetDeltaState( FindDeltaStateIndex( pDeltaName, bSortDeltaName ) );
  1247. }
  1248. //-----------------------------------------------------------------------------
  1249. //
  1250. //-----------------------------------------------------------------------------
  1251. int SortDeltaNameFunc( const void *a, const void *b )
  1252. {
  1253. return Q_strcmp( *( const char ** )( a ), *( const char ** )( b ) );
  1254. }
  1255. //-----------------------------------------------------------------------------
  1256. // If the name doe
  1257. //-----------------------------------------------------------------------------
  1258. static const char *SortDeltaName( CUtlString &sDeltaName, const char *pszInDeltaName )
  1259. {
  1260. if ( !pszInDeltaName || !strchr( pszInDeltaName, '_' ) )
  1261. return pszInDeltaName;
  1262. CUtlVector< char *, CUtlMemory< char *, int > > nameComponents;
  1263. V_SplitString( pszInDeltaName, "\\", nameComponents );
  1264. if ( nameComponents.Count() > 0 )
  1265. {
  1266. CUtlVector< char * > deltaNames;
  1267. for ( int i = 0; i < nameComponents.Count(); ++i )
  1268. {
  1269. deltaNames.AddToTail( nameComponents[ i ] );
  1270. }
  1271. qsort( deltaNames.Base(), deltaNames.Count(), sizeof( char * ), SortDeltaNameFunc );
  1272. sDeltaName.Clear();
  1273. for ( int i = 0; i < deltaNames.Count(); ++i )
  1274. {
  1275. if ( V_strlen( deltaNames[i] ) <= 0 )
  1276. continue;
  1277. if ( sDeltaName.Length() > 0 )
  1278. {
  1279. sDeltaName += "_";
  1280. }
  1281. sDeltaName += deltaNames[i];
  1282. }
  1283. }
  1284. nameComponents.PurgeAndDeleteElements();
  1285. return sDeltaName.Get();
  1286. }
  1287. //-----------------------------------------------------------------------------
  1288. //
  1289. //-----------------------------------------------------------------------------
  1290. CDmeVertexDeltaData *CDmeMesh::FindOrCreateDeltaState( const char *pInDeltaName, bool bSortDeltaName /* = true */ )
  1291. {
  1292. CDmeVertexDeltaData *pDeltaState = FindDeltaState( pInDeltaName, bSortDeltaName );
  1293. if ( pDeltaState )
  1294. return pDeltaState;
  1295. CUtlString sDeltaName( pInDeltaName );
  1296. if ( bSortDeltaName )
  1297. {
  1298. SortDeltaName( sDeltaName, pInDeltaName );
  1299. }
  1300. pDeltaState = CreateElement< CDmeVertexDeltaData >( sDeltaName.Get(), GetFileId() );
  1301. if ( pDeltaState )
  1302. {
  1303. m_DeltaStates.AddToTail( pDeltaState );
  1304. }
  1305. return pDeltaState;
  1306. }
  1307. //-----------------------------------------------------------------------------
  1308. // Finds a delta state index by comparing names, if it can't be found
  1309. // searches for all permutations of the delta name
  1310. //-----------------------------------------------------------------------------
  1311. int CDmeMesh::FindDeltaStateIndex( const char *pInDeltaName, bool bSortDeltaName /* = true */ ) const
  1312. {
  1313. CUtlString sDeltaName( pInDeltaName );
  1314. const int nDeltaStateCount = DeltaStateCount();
  1315. for ( int i = 0; i < nDeltaStateCount; ++i )
  1316. {
  1317. CDmeVertexDeltaData *pDeltaState = GetDeltaState( i );
  1318. if ( !V_stricmp( sDeltaName.Get(), pDeltaState->GetName() ) )
  1319. return i;
  1320. }
  1321. if ( bSortDeltaName && strchr( sDeltaName.Get(), '_' ) )
  1322. {
  1323. SortDeltaName( sDeltaName, pInDeltaName );
  1324. }
  1325. for ( int i = 0; i < nDeltaStateCount; ++i )
  1326. {
  1327. CDmeVertexDeltaData *pDeltaState = GetDeltaState( i );
  1328. if ( !V_stricmp( sDeltaName.Get(), pDeltaState->GetName() ) )
  1329. return i;
  1330. }
  1331. return -1;
  1332. }
  1333. //-----------------------------------------------------------------------------
  1334. //
  1335. //-----------------------------------------------------------------------------
  1336. void CDmeMesh::SetDeltaStateWeight( int nDeltaIndex, MeshDeltaWeightType_t type, float flMorphWeight )
  1337. {
  1338. if ( nDeltaIndex < m_DeltaStateWeights[type].Count() )
  1339. {
  1340. m_DeltaStateWeights[type].Set( nDeltaIndex, Vector2D( flMorphWeight, flMorphWeight ) );
  1341. }
  1342. }
  1343. //-----------------------------------------------------------------------------
  1344. //
  1345. //-----------------------------------------------------------------------------
  1346. void CDmeMesh::SetDeltaStateWeight( int nDeltaIndex, MeshDeltaWeightType_t type, float flLeftWeight, float flRightWeight )
  1347. {
  1348. if ( nDeltaIndex < m_DeltaStateWeights[type].Count() )
  1349. {
  1350. m_DeltaStateWeights[type].Set( nDeltaIndex, Vector2D( flLeftWeight, flRightWeight ) );
  1351. }
  1352. }
  1353. //-----------------------------------------------------------------------------
  1354. // Determines the appropriate vertex format for hardware meshes
  1355. //-----------------------------------------------------------------------------
  1356. VertexFormat_t CDmeMesh::ComputeHwMeshVertexFormat( void )
  1357. {
  1358. VertexFormat_t vertexFormat = VERTEX_POSITION | VERTEX_COLOR | VERTEX_NORMAL | VERTEX_TEXCOORD_SIZE(0,2) | VERTEX_BONEWEIGHT(2) | VERTEX_BONE_INDEX
  1359. | VERTEX_USERDATA_SIZE(4);
  1360. // FIXME: set VERTEX_FORMAT_COMPRESSED if there are no artifacts and if it saves enough memory (use 'mem_dumpvballocs')
  1361. // vertexFormat |= VERTEX_FORMAT_COMPRESSED;
  1362. // FIXME: check for and strip unused vertex elements (see 'bHasNormals', etc, in CreateHwMesh below)
  1363. return vertexFormat;
  1364. }
  1365. //-----------------------------------------------------------------------------
  1366. // Builds a hardware mesh
  1367. //-----------------------------------------------------------------------------
  1368. IMesh *CDmeMesh::CreateHwMesh( CDmeFaceSet *pFaceSet )
  1369. {
  1370. const CDmeVertexData *pBind = GetBindBaseState();
  1371. if ( !pBind )
  1372. return NULL;
  1373. // NOTE: This is memory inefficient. We create a copy of all vertices
  1374. // for each face set, even if those vertices aren't used by the face set
  1375. // Mostly chose to do this for code simplicity, although it also is faster to generate meshes
  1376. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1377. VertexFormat_t vertexFormat = ComputeHwMeshVertexFormat( );
  1378. IMesh *pMesh = pRenderContext->CreateStaticMesh( vertexFormat, "dmemesh" );
  1379. CMeshBuilder meshBuilder;
  1380. // prepare vertices
  1381. FieldIndex_t posField = pBind->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  1382. FieldIndex_t normalField = pBind->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  1383. FieldIndex_t tangentField = pBind->FindFieldIndex( CDmeVertexData::FIELD_TANGENT );
  1384. FieldIndex_t uvField = pBind->FindFieldIndex( CDmeVertexData::FIELD_TEXCOORD );
  1385. FieldIndex_t colorField = pBind->FindFieldIndex( CDmeVertexData::FIELD_COLOR );
  1386. Assert( posField >= 0 );
  1387. bool bHasNormals = ( normalField >= 0 );
  1388. bool bHasTangent = ( tangentField >= 0 );
  1389. bool bHasTexCoords = ( uvField >= 0 );
  1390. bool bHasColors = ( colorField >= 0 );
  1391. // build the mesh
  1392. int nIndices = pFaceSet->GetTriangulatedIndexCount();
  1393. int nVertices = pBind->VertexCount();
  1394. int nJointCount = pBind->JointCount();
  1395. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, nVertices, nIndices );
  1396. const CDmrArrayConst<int> pPositionIndices = pBind->GetIndexData( posField );
  1397. const CDmrArrayConst<Vector> pPositionData = pBind->GetVertexData( posField );
  1398. const CDmrArrayConst<int> pNormalIndices = bHasNormals ? pBind->GetIndexData( normalField ) : NULL;
  1399. const CDmrArrayConst<Vector> pNormalData = bHasNormals ? pBind->GetVertexData( normalField ) : NULL;
  1400. const CDmrArrayConst<int> pTangentIndices = bHasTangent ? pBind->GetIndexData( tangentField ) : NULL;
  1401. const CDmrArrayConst<Vector4D> pTangentData = bHasTangent ? pBind->GetVertexData( tangentField ) : NULL;
  1402. const CDmrArrayConst<int> pUVIndices = bHasTexCoords ? pBind->GetIndexData( uvField ) : NULL;
  1403. const CDmrArrayConst<Vector2D> pUVData = bHasTexCoords ? pBind->GetVertexData( uvField ) : NULL;
  1404. const CDmrArrayConst<int> pColorIndices = bHasColors ? pBind->GetIndexData( colorField ) : NULL;
  1405. const CDmrArrayConst<Color> pColorData = bHasColors ? pBind->GetVertexData( colorField ) : NULL;
  1406. Vector4D defaultTangentS( 1.0f, 0.0f, 0.0f, 1.0f );
  1407. for ( int vi = 0; vi < nVertices; ++vi )
  1408. {
  1409. meshBuilder.Position3fv( pPositionData.Get( pPositionIndices.Get( vi ) ).Base() );
  1410. if ( pNormalData.IsValid() )
  1411. {
  1412. meshBuilder.Normal3fv( pNormalData.Get( pNormalIndices.Get( vi ) ).Base() );
  1413. }
  1414. else
  1415. {
  1416. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  1417. }
  1418. if ( pTangentData.IsValid() )
  1419. {
  1420. meshBuilder.UserData( pTangentData.Get( pTangentIndices.Get( vi ) ).Base() );
  1421. }
  1422. else
  1423. {
  1424. meshBuilder.UserData( defaultTangentS.Base() );
  1425. }
  1426. if ( pUVData.IsValid() )
  1427. {
  1428. const Vector2D &uv = pUVData.Get( pUVIndices.Get( vi ) );
  1429. if ( !pBind->IsVCoordinateFlipped() )
  1430. {
  1431. meshBuilder.TexCoord2fv( 0, uv.Base() );
  1432. }
  1433. else
  1434. {
  1435. meshBuilder.TexCoord2f( 0, uv.x, 1.0f - uv.y );
  1436. }
  1437. }
  1438. else
  1439. {
  1440. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  1441. }
  1442. if ( pColorIndices.IsValid() )
  1443. {
  1444. int color = pColorData.Get( pColorIndices.Get( vi ) ).GetRawColor();
  1445. meshBuilder.Color4ubv( (unsigned char*)&color );
  1446. }
  1447. else
  1448. {
  1449. meshBuilder.Color4ub( 255, 255, 255, 255 );
  1450. }
  1451. // FIXME: Note that this will break once we exceeed the max joint count
  1452. // that the hardware can handle
  1453. const float *pJointWeight = pBind->GetJointWeights( vi );
  1454. const int *pJointIndices = pBind->GetJointIndices( vi );
  1455. for ( int i = 0; i < nJointCount; ++i )
  1456. {
  1457. meshBuilder.BoneWeight( i, pJointWeight[i] );
  1458. meshBuilder.BoneMatrix( i, pJointIndices[i] );
  1459. }
  1460. for ( int i = nJointCount; i < 4; ++i )
  1461. {
  1462. meshBuilder.BoneWeight( i, ( i == 0 ) ? 1.0f : 0.0f );
  1463. meshBuilder.BoneMatrix( i, 0 );
  1464. }
  1465. meshBuilder.AdvanceVertexF<VTX_HAVEALL, 1>();
  1466. }
  1467. WriteTriangluatedIndices( pBind, pFaceSet, meshBuilder );
  1468. meshBuilder.End();
  1469. return pMesh;
  1470. }
  1471. //-----------------------------------------------------------------------------
  1472. // Compute triangulated indices
  1473. //-----------------------------------------------------------------------------
  1474. void CDmeMesh::ComputeTriangulatedIndices( const CDmeVertexData *pBaseState, const CDmeFaceSet *pFaceSet, int nFirstIndex, int *pIndices, int nOutCount ) const
  1475. {
  1476. // FIXME: Come up with a more efficient way of computing this
  1477. // This involves a bunch of recomputation of distances
  1478. float flMinDistance = FLT_MAX;
  1479. int nMinIndex = 0;
  1480. int nVertexCount = pFaceSet->GetNextPolygonVertexCount( nFirstIndex );
  1481. // Optimization for quads + triangles.. it's totally symmetric
  1482. int nLoopCount = nVertexCount;
  1483. if ( nVertexCount <= 3 )
  1484. {
  1485. nLoopCount = 0;
  1486. }
  1487. else if ( nVertexCount == 4 )
  1488. {
  1489. nLoopCount = 2;
  1490. }
  1491. for ( int i = 0; i < nLoopCount; ++i )
  1492. {
  1493. float flDistance = 0.0f;
  1494. const Vector &vecCenter = pBaseState->GetPosition( pFaceSet->GetIndex( nFirstIndex+i ) );
  1495. for ( int j = 2; j < nVertexCount-1; ++j )
  1496. {
  1497. int vi = ( i + j ) % nVertexCount;
  1498. const Vector &vecEdge = pBaseState->GetPosition( pFaceSet->GetIndex( nFirstIndex+vi ) );
  1499. flDistance += vecEdge.DistTo( vecCenter );
  1500. }
  1501. if ( flDistance < flMinDistance )
  1502. {
  1503. nMinIndex = i;
  1504. flMinDistance = flDistance;
  1505. }
  1506. }
  1507. // Compute the triangulation indices
  1508. Assert( nOutCount == ( nVertexCount - 2 ) * 3 );
  1509. int nOutIndex = 0;
  1510. for ( int i = 1; i < nVertexCount - 1; ++i )
  1511. {
  1512. pIndices[nOutIndex++] = pFaceSet->GetIndex( nFirstIndex + nMinIndex );
  1513. pIndices[nOutIndex++] = pFaceSet->GetIndex( nFirstIndex + ((nMinIndex + i) % nVertexCount) );
  1514. pIndices[nOutIndex++] = pFaceSet->GetIndex( nFirstIndex + ((nMinIndex + i + 1) % nVertexCount) );
  1515. }
  1516. }
  1517. //-----------------------------------------------------------------------------
  1518. // Build a map from vertex index to a list of triangles that share the vert.
  1519. //-----------------------------------------------------------------------------
  1520. void CDmeMesh::BuildTriangleMap( const CDmeVertexData *pBaseState, CDmeFaceSet* pFaceSet, CUtlVector<Triangle_t>& triangles, CUtlVector< CUtlVector<int> >* pVertToTriMap )
  1521. {
  1522. int indices[ 256 ];
  1523. // prepare indices
  1524. int nFirstIndex = 0;
  1525. int nIndexCount = pFaceSet->NumIndices();
  1526. while ( nFirstIndex < nIndexCount )
  1527. {
  1528. int nVertexCount = pFaceSet->GetNextPolygonVertexCount( nFirstIndex );
  1529. if ( nVertexCount >= 3 )
  1530. {
  1531. int nOutCount = ( nVertexCount-2 ) * 3;
  1532. int *pIndices = ( nOutCount > ARRAYSIZE( indices ) ) ? new int[ nOutCount ] : indices;
  1533. ComputeTriangulatedIndices( pBaseState, pFaceSet, nFirstIndex, pIndices, nOutCount );
  1534. for ( int ii = 0; ii < nOutCount; ii += 3 )
  1535. {
  1536. int t = triangles.AddToTail();
  1537. Triangle_t& triangle = triangles[t];
  1538. triangle.m_nIndex[0] = pIndices[ii];
  1539. triangle.m_nIndex[1] = pIndices[ii+1];
  1540. triangle.m_nIndex[2] = pIndices[ii+2];
  1541. if ( pVertToTriMap )
  1542. {
  1543. (*pVertToTriMap)[ pIndices[ii] ].AddToTail( t );
  1544. (*pVertToTriMap)[ pIndices[ii+1] ].AddToTail( t );
  1545. (*pVertToTriMap)[ pIndices[ii+2] ].AddToTail( t );
  1546. }
  1547. }
  1548. if ( pIndices != indices )
  1549. {
  1550. delete[] pIndices;
  1551. }
  1552. }
  1553. nFirstIndex += nVertexCount + 1;
  1554. }
  1555. }
  1556. //-----------------------------------------------------------------------------
  1557. // Computes tangent space data for triangles
  1558. //-----------------------------------------------------------------------------
  1559. void CDmeMesh::ComputeTriangleTangets( const CDmeVertexData *pVertexData, CUtlVector<Triangle_t>& triangles )
  1560. {
  1561. // Calculate the tangent space for each triangle.
  1562. int nTriangleCount = triangles.Count();
  1563. for ( int triID = 0; triID < nTriangleCount; triID++ )
  1564. {
  1565. Triangle_t &triangle = triangles[triID];
  1566. const Vector &p0 = pVertexData->GetPosition( triangle.m_nIndex[0] );
  1567. const Vector &p1 = pVertexData->GetPosition( triangle.m_nIndex[1] );
  1568. const Vector &p2 = pVertexData->GetPosition( triangle.m_nIndex[2] );
  1569. const Vector2D &t0 = pVertexData->GetTexCoord( triangle.m_nIndex[0] );
  1570. const Vector2D &t1 = pVertexData->GetTexCoord( triangle.m_nIndex[1] );
  1571. const Vector2D &t2 = pVertexData->GetTexCoord( triangle.m_nIndex[2] );
  1572. CalcTriangleTangentSpace( p0, p1, p2, t0, t1, t2, triangle.m_vecTangentS, triangle.m_vecTangentT );
  1573. }
  1574. }
  1575. //-----------------------------------------------------------------------------
  1576. // Build a map from vertex index to a list of triangles that share the vert.
  1577. //-----------------------------------------------------------------------------
  1578. void CDmeMesh::ComputeAverageTangent( CDmeVertexData *pVertexData, bool bSmoothTangents, CUtlVector< CUtlVector<int> >& vertToTriMap, CUtlVector<Triangle_t>& triangles )
  1579. {
  1580. FieldIndex_t posField = pVertexData->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  1581. FieldIndex_t normalField = pVertexData->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  1582. FieldIndex_t tangentField = pVertexData->FindFieldIndex( CDmeVertexData::FIELD_TANGENT );
  1583. const CDmrArray<int> pPositionIndices = pVertexData->GetIndexData( posField );
  1584. const CDmrArray<Vector> pPositionData = pVertexData->GetVertexData( posField );
  1585. const CDmrArray<int> pNormalIndices = pVertexData->GetIndexData( normalField );
  1586. const CDmrArray<Vector> pNormalData = pVertexData->GetVertexData( normalField );
  1587. // calculate an average tangent space for each vertex.
  1588. int nVertexCount = pVertexData->VertexCount();
  1589. Vector4D finalSVect;
  1590. for( int vertID = 0; vertID < nVertexCount; vertID++ )
  1591. {
  1592. CUtlVector<int> &triangleList = vertToTriMap[vertID];
  1593. Vector sVect, tVect;
  1594. sVect.Init( 0.0f, 0.0f, 0.0f );
  1595. tVect.Init( 0.0f, 0.0f, 0.0f );
  1596. int nTriangleCount = triangleList.Count();
  1597. for ( int triID = 0; triID < nTriangleCount; triID++ )
  1598. {
  1599. Triangle_t &tri = triangles[ triangleList[triID] ];
  1600. sVect += tri.m_vecTangentS;
  1601. tVect += tri.m_vecTangentT;
  1602. }
  1603. // In the case of zbrush, everything needs to be treated as smooth.
  1604. if ( bSmoothTangents )
  1605. {
  1606. const Vector &vertPos1 = pPositionData.Get( pPositionIndices.Get( vertID ) );
  1607. for( int vertID2 = 0; vertID2 < nVertexCount; vertID2++ )
  1608. {
  1609. if ( vertID2 == vertID )
  1610. continue;
  1611. const Vector &vertPos2 = pPositionData.Get( pPositionIndices.Get( vertID2 ) );
  1612. if ( vertPos1 != vertPos2 )
  1613. continue;
  1614. CUtlVector<int> &triangleList2 = vertToTriMap[vertID2];
  1615. int nTriangleCount2 = triangleList2.Count();
  1616. for ( int triID2 = 0; triID2 < nTriangleCount2; triID2++ )
  1617. {
  1618. Triangle_t &tri2 = triangles[ triangleList2[triID2] ];
  1619. sVect += tri2.m_vecTangentS;
  1620. tVect += tri2.m_vecTangentT;
  1621. }
  1622. }
  1623. }
  1624. // make an orthonormal system.
  1625. // need to check if we are left or right handed.
  1626. Vector tmpVect;
  1627. CrossProduct( sVect, tVect, tmpVect );
  1628. const Vector &normal = pNormalData.Get( pNormalIndices.Get( vertID ) );
  1629. bool bLeftHanded = DotProduct( tmpVect, normal ) < 0.0f;
  1630. if ( !bLeftHanded )
  1631. {
  1632. CrossProduct( normal, sVect, tVect );
  1633. CrossProduct( tVect, normal, sVect );
  1634. VectorNormalize( sVect );
  1635. VectorNormalize( tVect );
  1636. finalSVect[0] = sVect[0];
  1637. finalSVect[1] = sVect[1];
  1638. finalSVect[2] = sVect[2];
  1639. finalSVect[3] = 1.0f;
  1640. }
  1641. else
  1642. {
  1643. CrossProduct( sVect, normal, tVect );
  1644. CrossProduct( normal, tVect, sVect );
  1645. VectorNormalize( sVect );
  1646. VectorNormalize( tVect );
  1647. finalSVect[0] = sVect[0];
  1648. finalSVect[1] = sVect[1];
  1649. finalSVect[2] = sVect[2];
  1650. finalSVect[3] = -1.0f;
  1651. }
  1652. pVertexData->SetVertexData( tangentField, vertID, 1, AT_VECTOR4, &finalSVect );
  1653. pVertexData->SetVertexIndices( tangentField, vertID, 1, &vertID );
  1654. }
  1655. }
  1656. //-----------------------------------------------------------------------------
  1657. // Builds a map from vertex index to all triangles that use it
  1658. //-----------------------------------------------------------------------------
  1659. void CDmeMesh::BuildVertToTriMap( const CDmeVertexData *pVertexData, CUtlVector<Triangle_t> &triangles, CUtlVector< CUtlVector<int> > &vertToTriMap )
  1660. {
  1661. vertToTriMap.AddMultipleToTail( pVertexData->VertexCount() );
  1662. int nCount = FaceSetCount();
  1663. for ( int i = 0; i < nCount; ++i )
  1664. {
  1665. CDmeFaceSet *pFaceSet = GetFaceSet( i );
  1666. BuildTriangleMap( pVertexData, pFaceSet, triangles, &vertToTriMap );
  1667. }
  1668. }
  1669. //-----------------------------------------------------------------------------
  1670. // Compute a default per-vertex tangent given normal data + uv data
  1671. //-----------------------------------------------------------------------------
  1672. void CDmeMesh::ComputeDefaultTangentData( CDmeVertexData *pVertexData, bool bSmoothTangents )
  1673. {
  1674. if ( !pVertexData )
  1675. return;
  1676. // Need to have valid pos, uv, and normal to perform this operation
  1677. FieldIndex_t posField = pVertexData->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  1678. FieldIndex_t normalField = pVertexData->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  1679. FieldIndex_t uvField = pVertexData->FindFieldIndex( CDmeVertexData::FIELD_TEXCOORD );
  1680. if ( posField < 0 || uvField < 0 || normalField < 0 )
  1681. return;
  1682. // FIXME: Need to do a pass to make sure no vertex is referenced by
  1683. // multiple facesets that have different materials in them.
  1684. // In that case, we need to add extra copies of that vertex and modify
  1685. // the face set data to refer to the new vertices
  1686. // Build a map from vertex to a list of triangles that share the vert.
  1687. CUtlVector<Triangle_t> triangles( 0, 1024 );
  1688. CUtlVector< CUtlVector<int> > vertToTriMap;
  1689. vertToTriMap.AddMultipleToTail( pVertexData->VertexCount() );
  1690. int nCount = FaceSetCount();
  1691. for ( int i = 0; i < nCount; ++i )
  1692. {
  1693. CDmeFaceSet *pFaceSet = GetFaceSet( i );
  1694. BuildTriangleMap( pVertexData, pFaceSet, triangles, &vertToTriMap );
  1695. }
  1696. ComputeTriangleTangets( pVertexData, triangles );
  1697. // FIXME: We could do a pass to determine the unique combinations of
  1698. // position + tangent indices in the vertex data. We only need to have
  1699. // a unique tangent for each of these unique vertices. For simplicity
  1700. // (and speed), I'll assume all tangents are unique per vertex.
  1701. FieldIndex_t tangent = pVertexData->CreateField<Vector4D>( "tangents" );
  1702. pVertexData->RemoveAllVertexData( tangent );
  1703. pVertexData->AddVertexData( tangent, pVertexData->VertexCount() );
  1704. ComputeAverageTangent( pVertexData, bSmoothTangents, vertToTriMap, triangles );
  1705. }
  1706. //-----------------------------------------------------------------------------
  1707. // Compute a default per-vertex tangent given normal data + uv data for all vertex data referenced by this mesh
  1708. //-----------------------------------------------------------------------------
  1709. void CDmeMesh::ComputeDefaultTangentData( bool bSmoothTangents )
  1710. {
  1711. const int nBaseStateCount = m_BaseStates.Count();
  1712. for ( int i = 0; i < nBaseStateCount; ++i )
  1713. {
  1714. if ( m_BaseStates[i] && m_BaseStates[i]->NeedsTangentData() )
  1715. {
  1716. ComputeDefaultTangentData( m_BaseStates[i], bSmoothTangents );
  1717. }
  1718. }
  1719. }
  1720. //-----------------------------------------------------------------------------
  1721. // Utility method to compute default tangent data on all meshes in the sub-dag hierarchy
  1722. //-----------------------------------------------------------------------------
  1723. void ComputeDefaultTangentData( CDmeDag *pDag, bool bSmoothTangents )
  1724. {
  1725. if ( !pDag )
  1726. return;
  1727. CDmeMesh *pMesh = CastElement< CDmeMesh >( pDag->GetShape() );
  1728. if ( pMesh )
  1729. {
  1730. pMesh->ComputeDefaultTangentData( bSmoothTangents );
  1731. }
  1732. int nChildCount = pDag->GetChildCount();
  1733. for ( int i = 0; i < nChildCount; ++i )
  1734. {
  1735. ComputeDefaultTangentData( pDag->GetChild( i ), bSmoothTangents );
  1736. }
  1737. }
  1738. //-----------------------------------------------------------------------------
  1739. // Compute the dimensionality of the delta state (how many inputs affect it)
  1740. //-----------------------------------------------------------------------------
  1741. int CDmeMesh::ComputeDeltaStateDimensionality( int nDeltaIndex )
  1742. {
  1743. CDmeVertexDeltaData *pDeltaState = GetDeltaState( nDeltaIndex );
  1744. const char *pDeltaStateName = pDeltaState->GetName();
  1745. const char *pUnderBar = pDeltaStateName;
  1746. int nDimensions = 0;
  1747. while ( pUnderBar )
  1748. {
  1749. ++nDimensions;
  1750. pUnderBar = strchr( pUnderBar, '_' );
  1751. if ( pUnderBar )
  1752. {
  1753. ++pUnderBar;
  1754. }
  1755. }
  1756. return nDimensions;
  1757. }
  1758. //-----------------------------------------------------------------------------
  1759. // Computes the aggregate position for all vertices after applying a set of delta states
  1760. //-----------------------------------------------------------------------------
  1761. void CDmeMesh::AddDelta( CDmeVertexData *pBaseState, Vector *pDeltaPosition, int nDeltaStateIndex, CDmeVertexData::StandardFields_t fieldId )
  1762. {
  1763. CDmeVertexDeltaData *pDeltaState = GetDeltaState( nDeltaStateIndex );
  1764. FieldIndex_t nFieldIndex = pDeltaState->FindFieldIndex( fieldId );
  1765. if ( nFieldIndex < 0 )
  1766. return;
  1767. if ( pBaseState->FindFieldIndex( CDmeVertexData::FIELD_BALANCE ) != -1 )
  1768. {
  1769. AddStereoVertexDelta<Vector>( pBaseState, pDeltaPosition, sizeof(Vector), fieldId, nDeltaStateIndex, true );
  1770. }
  1771. else
  1772. {
  1773. AddVertexDelta<Vector>( pBaseState, pDeltaPosition, sizeof(Vector), fieldId, nDeltaStateIndex, true );
  1774. }
  1775. }
  1776. //-----------------------------------------------------------------------------
  1777. // Computes correctly averaged vertex normals from position data
  1778. //-----------------------------------------------------------------------------
  1779. void CDmeMesh::ComputeNormalsFromPositions(
  1780. CDmeVertexData *pBase,
  1781. const Vector *pPosition,
  1782. const CUtlVector<Triangle_t> &triangles,
  1783. int nNormalCount,
  1784. Vector *pNormals )
  1785. {
  1786. Assert( nNormalCount == pBase->GetNormalData().Count() );
  1787. int *pNormalsAdded = (int*)_alloca( nNormalCount * sizeof(int) );
  1788. memset( pNormalsAdded, 0, nNormalCount * sizeof(int) );
  1789. memset( pNormals, 0, nNormalCount * sizeof(Vector) );
  1790. const CUtlVector<int> &positionIndices = pBase->GetVertexIndexData( CDmeVertexData::FIELD_POSITION );
  1791. const CUtlVector<int> &normalIndices = pBase->GetVertexIndexData( CDmeVertexData::FIELD_NORMAL );
  1792. int nTriangleCount = triangles.Count();
  1793. for ( int i = 0; i < nTriangleCount; ++i )
  1794. {
  1795. const Triangle_t &tri = triangles[i];
  1796. int p1 = positionIndices[ tri.m_nIndex[0] ];
  1797. int p2 = positionIndices[ tri.m_nIndex[1] ];
  1798. int p3 = positionIndices[ tri.m_nIndex[2] ];
  1799. int n1 = normalIndices[ tri.m_nIndex[0] ];
  1800. int n2 = normalIndices[ tri.m_nIndex[1] ];
  1801. int n3 = normalIndices[ tri.m_nIndex[2] ];
  1802. Vector vecDelta, vecDelta2, vecNormal;
  1803. VectorSubtract( pPosition[p2], pPosition[p1], vecDelta );
  1804. VectorSubtract( pPosition[p3], pPosition[p1], vecDelta2 );
  1805. CrossProduct( vecDelta, vecDelta2, vecNormal );
  1806. VectorNormalize( vecNormal );
  1807. pNormals[n1] += vecNormal;
  1808. pNormals[n2] += vecNormal;
  1809. pNormals[n3] += vecNormal;
  1810. ++pNormalsAdded[n1]; ++pNormalsAdded[n2]; ++pNormalsAdded[n3];
  1811. }
  1812. for ( int i = 0; i < nNormalCount; ++i )
  1813. {
  1814. if ( pNormalsAdded[i] > 0 )
  1815. {
  1816. pNormals[i] /= pNormalsAdded[i];
  1817. VectorNormalize( pNormals[i] );
  1818. }
  1819. else
  1820. {
  1821. pNormals[i].Init( 0, 1, 0 );
  1822. }
  1823. }
  1824. }
  1825. //-----------------------------------------------------------------------------
  1826. // Converts pose-space normals into deltas appropriate for correction delta states
  1827. //-----------------------------------------------------------------------------
  1828. void CDmeMesh::ComputeCorrectedNormalsFromActualNormals( const CUtlVector<int> &deltaStateList, int nNormalCount, Vector *pNormals )
  1829. {
  1830. CDmeVertexData *pBind = GetBindBaseState();
  1831. if ( !pBind )
  1832. return;
  1833. Assert( nNormalCount == pBind->GetNormalData().Count() );
  1834. // Subtract out all other normal contributions
  1835. Vector *pUncorrectedNormals = (Vector*)_alloca( nNormalCount * sizeof(Vector) );
  1836. memcpy( pUncorrectedNormals, pBind->GetNormalData().Base(), nNormalCount * sizeof( Vector ) );
  1837. int nDeltaStateCount = deltaStateList.Count();
  1838. for ( int i = 0; i < nDeltaStateCount; ++i )
  1839. {
  1840. AddDelta( pBind, pUncorrectedNormals, deltaStateList[i], CDmeVertexData::FIELD_NORMAL );
  1841. }
  1842. for ( int i = 0; i < nNormalCount; ++i )
  1843. {
  1844. pNormals[i] -= pUncorrectedNormals[i];
  1845. }
  1846. }
  1847. //-----------------------------------------------------------------------------
  1848. // Copies the corrected normal data into a delta state
  1849. //-----------------------------------------------------------------------------
  1850. void CDmeMesh::SetDeltaNormalData( int nDeltaIndex, int nNormalCount, Vector *pNormals )
  1851. {
  1852. // pNormals represents the correct normal delta state for this combination
  1853. // Copy it into the delta state for this combination.
  1854. // Use tolerance to deal with precision errors introduced by the various computations
  1855. CDmeVertexDeltaData *pDeltaState = GetDeltaState( nDeltaIndex );
  1856. FieldIndex_t nNormalField = pDeltaState->FindFieldIndex( CDmeVertexDeltaData::FIELD_NORMAL );
  1857. if ( nNormalField >= 0 )
  1858. {
  1859. pDeltaState->RemoveAllVertexData( nNormalField );
  1860. }
  1861. else
  1862. {
  1863. nNormalField = pDeltaState->CreateField( CDmeVertexDeltaData::FIELD_NORMAL );
  1864. }
  1865. for ( int i = 0; i < nNormalCount; ++i )
  1866. {
  1867. if ( pNormals[i].LengthSqr() < 1e-4 )
  1868. continue;
  1869. int nNormalIndex = pDeltaState->AddVertexData( nNormalField, 1 );
  1870. pDeltaState->SetVertexData( nNormalField, nNormalIndex, 1, AT_VECTOR3, &pNormals[i] );
  1871. pDeltaState->SetVertexIndices( nNormalField, nNormalIndex, 1, &i );
  1872. }
  1873. }
  1874. //-----------------------------------------------------------------------------
  1875. // Discovers the atomic controls used by the various delta states
  1876. //-----------------------------------------------------------------------------
  1877. static int DeltaStateUsageLessFunc( const int * lhs, const int * rhs )
  1878. {
  1879. return *lhs - *rhs;
  1880. }
  1881. //-----------------------------------------------------------------------------
  1882. //
  1883. //-----------------------------------------------------------------------------
  1884. void CDmeMesh::BuildAtomicControlLists( int nCount, DeltaComputation_t *pInfo, CUtlVector< CUtlVector< int > > &deltaStateUsage )
  1885. {
  1886. CUtlVector< CUtlString > atomicControls;
  1887. deltaStateUsage.SetCount( nCount );
  1888. // Build a list of atomic controls
  1889. int nCurrentDelta;
  1890. for ( nCurrentDelta = 0; nCurrentDelta < nCount; ++nCurrentDelta )
  1891. {
  1892. if ( pInfo[nCurrentDelta].m_nDimensionality != 1 )
  1893. break;
  1894. int j = atomicControls.AddToTail( GetDeltaState( pInfo[nCurrentDelta].m_nDeltaIndex )->GetName() );
  1895. deltaStateUsage[ nCurrentDelta ].AddToTail( j );
  1896. }
  1897. char tempBuf[ 256 ];
  1898. for ( ; nCurrentDelta < nCount; ++nCurrentDelta )
  1899. {
  1900. CDmeVertexDeltaData *pDeltaState = GetDeltaState( pInfo[nCurrentDelta].m_nDeltaIndex );
  1901. int nLen = Q_strlen( pDeltaState->GetName() ) + 1;
  1902. char *pTempBuf = ( nLen > ARRAYSIZE( tempBuf ) ) ? new char[ nLen ] : tempBuf;
  1903. memcpy( pTempBuf, pDeltaState->GetName(), nLen );
  1904. char *pNext;
  1905. for ( char *pUnderBar = pTempBuf; pUnderBar; pUnderBar = pNext )
  1906. {
  1907. pNext = strchr( pUnderBar, '_' );
  1908. if ( pNext )
  1909. {
  1910. *pNext = 0;
  1911. ++pNext;
  1912. }
  1913. // Find this name in the list of strings
  1914. int j;
  1915. int nControlCount = atomicControls.Count();
  1916. for ( j = 0; j < nControlCount; ++j )
  1917. {
  1918. if ( !Q_stricmp( pUnderBar, atomicControls[j] ) )
  1919. break;
  1920. }
  1921. if ( j == nControlCount )
  1922. {
  1923. j = atomicControls.AddToTail( pUnderBar );
  1924. }
  1925. deltaStateUsage[ nCurrentDelta ].AddToTail( j );
  1926. }
  1927. deltaStateUsage[ nCurrentDelta ].Sort( DeltaStateUsageLessFunc );
  1928. if ( pTempBuf != tempBuf )
  1929. {
  1930. delete[] pTempBuf;
  1931. }
  1932. }
  1933. }
  1934. //-----------------------------------------------------------------------------
  1935. // Construct list of all n-1 -> 1 dimensional delta states
  1936. // that will be active when this delta state is active
  1937. //-----------------------------------------------------------------------------
  1938. void CDmeMesh::ComputeDependentDeltaStateList( CUtlVector< DeltaComputation_t > &compList )
  1939. {
  1940. if ( compList.Count() == 0 )
  1941. {
  1942. ComputeDeltaStateComputationList( compList );
  1943. }
  1944. CUtlVector< CUtlVector< int > > deltaStateUsage;
  1945. const int nCount( compList.Count() );
  1946. BuildAtomicControlLists( nCount, compList.Base(), deltaStateUsage );
  1947. // Now build up a list of dependent delta states based on usage
  1948. // NOTE: Usage is sorted in ascending order.
  1949. for ( int i = 1; i < nCount; ++i )
  1950. {
  1951. int nUsageCount1 = deltaStateUsage[i].Count();
  1952. for ( int j = 0; j < i; ++j )
  1953. {
  1954. // At the point they have the same dimensionality, no more need to check
  1955. if ( compList[j].m_nDimensionality == compList[i].m_nDimensionality )
  1956. break;
  1957. int ii = 0;
  1958. bool bSubsetFound = true;
  1959. int nUsageCount2 = deltaStateUsage[j].Count();
  1960. for ( int ji = 0; ji < nUsageCount2; ++ji )
  1961. {
  1962. for ( bSubsetFound = false; ii < nUsageCount1; ++ii )
  1963. {
  1964. if ( deltaStateUsage[j][ji] == deltaStateUsage[i][ii] )
  1965. {
  1966. ++ii;
  1967. bSubsetFound = true;
  1968. break;
  1969. }
  1970. if ( deltaStateUsage[j][ji] < deltaStateUsage[i][ii] )
  1971. break;
  1972. }
  1973. if ( !bSubsetFound )
  1974. break;
  1975. }
  1976. if ( bSubsetFound )
  1977. {
  1978. compList[i].m_DependentDeltas.AddToTail( compList[j].m_nDeltaIndex );
  1979. }
  1980. }
  1981. }
  1982. }
  1983. //-----------------------------------------------------------------------------
  1984. // Sorts DeltaComputation_t's by dimensionality
  1985. //-----------------------------------------------------------------------------
  1986. int CDmeMesh::DeltaStateLessFunc( const void * lhs, const void * rhs )
  1987. {
  1988. DeltaComputation_t &info1 = *(DeltaComputation_t*)lhs;
  1989. DeltaComputation_t &info2 = *(DeltaComputation_t*)rhs;
  1990. return info1.m_nDimensionality - info2.m_nDimensionality;
  1991. }
  1992. //-----------------------------------------------------------------------------
  1993. // Generates a sorted list in order of dimensionality of the delta states
  1994. // NOTE: This assumes a naming scheme where delta state names have _ that separate control names
  1995. //-----------------------------------------------------------------------------
  1996. void CDmeMesh::ComputeDeltaStateComputationList( CUtlVector< DeltaComputation_t > &compList )
  1997. {
  1998. // Do all combinations in order of dimensionality, lowest dimension first
  1999. const int nCount = DeltaStateCount();
  2000. compList.EnsureCount( nCount ); // Resets the CUtlVector
  2001. for ( int i = 0; i < nCount; ++i )
  2002. {
  2003. compList[i].m_nDeltaIndex = i;
  2004. compList[i].m_nDimensionality = ComputeDeltaStateDimensionality( i );
  2005. }
  2006. qsort( compList.Base(), nCount, sizeof(DeltaComputation_t), DeltaStateLessFunc );
  2007. }
  2008. //-----------------------------------------------------------------------------
  2009. // Computes normal deltas for all delta states based on position deltas
  2010. // NOTE: This assumes a naming scheme where delta state names have _ that separate control names
  2011. //-----------------------------------------------------------------------------
  2012. void CDmeMesh::ComputeDeltaStateNormals()
  2013. {
  2014. CDmeVertexData *pBind = GetBindBaseState();
  2015. if ( !pBind )
  2016. return;
  2017. const FieldIndex_t nBindNormalIndex = pBind->CreateField( CDmeVertexData::FIELD_NORMAL );
  2018. const CUtlVector< Vector > &basePosData = pBind->GetPositionData();
  2019. const int nPosCount = basePosData.Count();
  2020. // Build a map from vertex to a list of triangles that share the vert.
  2021. CUtlVector< Triangle_t > triangles( 0, 1024 );
  2022. CUtlVector< CUtlVector<int> > vertToTriMap;
  2023. vertToTriMap.AddMultipleToTail( pBind->VertexCount() );
  2024. const int nFaceSetCount = FaceSetCount();
  2025. for ( int i = 0; i < nFaceSetCount; ++i )
  2026. {
  2027. CDmeFaceSet *pFaceSet = GetFaceSet( i );
  2028. BuildTriangleMap( pBind, pFaceSet, triangles, &vertToTriMap );
  2029. }
  2030. // Temporary storage for normals
  2031. Vector *pNormals = reinterpret_cast< Vector * >( alloca( nPosCount * sizeof( Vector ) ) );
  2032. // Make all of the normals in the bind pose smooth
  2033. {
  2034. const CUtlVector< int > &basePosIndices = pBind->GetVertexIndexData( CDmeVertexData::FIELD_POSITION );
  2035. pBind->SetVertexIndices( nBindNormalIndex, 0, basePosIndices.Count(), basePosIndices.Base() );
  2036. pBind->RemoveAllVertexData( nBindNormalIndex );
  2037. pBind->AddVertexData( nBindNormalIndex, nPosCount );
  2038. ComputeNormalsFromPositions( pBind, basePosData.Base(), triangles, nPosCount, pNormals );
  2039. pBind->SetVertexData( nBindNormalIndex, 0, nPosCount, AT_VECTOR3, pNormals );
  2040. // Fix up the current state to have smooth normals if current is not bind
  2041. CDmeVertexData *pCurrent = GetCurrentBaseState();
  2042. if ( pCurrent != pBind )
  2043. {
  2044. const FieldIndex_t nCurrentNormalIndex = pCurrent->CreateField( CDmeVertexData::FIELD_NORMAL );
  2045. pCurrent->SetVertexIndices( nCurrentNormalIndex, 0, basePosIndices.Count(), basePosIndices.Base() );
  2046. pCurrent->RemoveAllVertexData( nCurrentNormalIndex );
  2047. pCurrent->AddVertexData( nCurrentNormalIndex, nPosCount );
  2048. const CUtlVector< Vector > &currPosData = pCurrent->GetPositionData();
  2049. ComputeNormalsFromPositions( pCurrent, currPosData.Base(), triangles, nPosCount, pNormals );
  2050. pCurrent->SetVertexData( nCurrentNormalIndex, 0, nPosCount, AT_VECTOR3, pNormals );
  2051. }
  2052. }
  2053. // Temporary storage for the positions
  2054. Vector *pPosData = reinterpret_cast< Vector * >( alloca( nPosCount * sizeof( Vector ) ) );
  2055. // Compute the dependent delta state list like thing
  2056. CUtlVector< DeltaComputation_t > computationOrder;
  2057. ComputeDependentDeltaStateList( computationOrder );
  2058. const int nDeltaStateCount = computationOrder.Count();
  2059. for ( int i = 0; i < nDeltaStateCount; ++i )
  2060. {
  2061. const DeltaComputation_t &deltaComputation = computationOrder[ i ];
  2062. memcpy( pPosData, basePosData.Base(), nPosCount * sizeof( Vector ) );
  2063. const CUtlVector< int > &depDeltas = deltaComputation.m_DependentDeltas;
  2064. const int nDepStateCount = depDeltas.Count();
  2065. for ( int j = 0; j < nDepStateCount; ++j )
  2066. {
  2067. AddDelta( GetDeltaState( depDeltas[ j ] ), pPosData, nPosCount, CDmeVertexData::FIELD_POSITION );
  2068. }
  2069. AddDelta( GetDeltaState( deltaComputation.m_nDeltaIndex ), pPosData, nPosCount, CDmeVertexData::FIELD_POSITION );
  2070. ComputeNormalsFromPositions( pBind, pPosData, triangles, nPosCount, pNormals );
  2071. SetDeltaNormalDataFromActualNormals( computationOrder[ i ].m_nDeltaIndex, depDeltas, nPosCount, pNormals );
  2072. }
  2073. }
  2074. //-----------------------------------------------------------------------------
  2075. // Computes normal deltas for all delta states based on position deltas
  2076. // NOTE: This assumes a naming scheme where delta state names have _ that separate control names
  2077. //-----------------------------------------------------------------------------
  2078. void CDmeMesh::SetDeltaNormalDataFromActualNormals( int nDeltaIndex, const CUtlVector<int> &deltaStateList, int nNormalCount, Vector *pNormals )
  2079. {
  2080. // Store off the current state values
  2081. CUtlVector< Vector2D > deltaStateWeights[MESH_DELTA_WEIGHT_TYPE_COUNT];
  2082. for ( int i = 0; i < MESH_DELTA_WEIGHT_TYPE_COUNT; ++i )
  2083. {
  2084. deltaStateWeights[i] = m_DeltaStateWeights[i].Get();
  2085. // Turn on the current weights to all be 1 to get max effect of morphs
  2086. int nCount = m_DeltaStateWeights[i].Count();
  2087. for ( int j = 0; j < nCount; ++j )
  2088. {
  2089. m_DeltaStateWeights[i].Set( j, Vector2D( 1.0f, 1.0f ) );
  2090. }
  2091. }
  2092. ComputeCorrectedNormalsFromActualNormals( deltaStateList, nNormalCount, pNormals );
  2093. // Finally, store the corrected normals into the delta state
  2094. SetDeltaNormalData( nDeltaIndex, nNormalCount, pNormals );
  2095. // Restore weights to their current value
  2096. for ( int i = 0; i < MESH_DELTA_WEIGHT_TYPE_COUNT; ++i )
  2097. {
  2098. m_DeltaStateWeights[i] = deltaStateWeights[i];
  2099. }
  2100. }
  2101. //-----------------------------------------------------------------------------
  2102. // A recursive algorithm to compute nCk, i.e. the number of order independent
  2103. // Combinations without any repeats of k items taking n at a time
  2104. // The size of the returned array is:
  2105. //
  2106. // n!
  2107. // -------------
  2108. // k! ( n - r )!
  2109. //
  2110. // e.g. 4C4 = { 0 1 2 3 }
  2111. // e.g. 3C4 = { 0 1 2 }, { 0 1 3 }, { 0 2 3 }, { 1 2 3 }
  2112. // e.g. 2C4 = { 0 1 }, { 0 2 }, { 0 3 }, { 1 2 }, { 1 3 }, { 2 3 }
  2113. // e.g. 1C4 = { 0 }, { 1 }, { 2 }, { 3 }
  2114. //
  2115. // It's recursive and meant to be called by the user with just n, k and combos
  2116. // the other default arguments are for the recursive steps
  2117. //-----------------------------------------------------------------------------
  2118. void CDmeMesh::Combinations(
  2119. int n,
  2120. int k,
  2121. CUtlVector< CUtlVector< int > > &combos,
  2122. int *pTmpArray,
  2123. int start,
  2124. int currentK )
  2125. {
  2126. if ( !pTmpArray )
  2127. {
  2128. pTmpArray = reinterpret_cast< int * >( alloca( k * sizeof( int ) ) );
  2129. memset( pTmpArray, 0, k * sizeof( int ) );
  2130. }
  2131. if ( currentK >= k )
  2132. {
  2133. combos[ combos.AddToTail() ].CopyArray( pTmpArray, k );
  2134. return;
  2135. }
  2136. for ( int i( start ); i < n; ++i )
  2137. {
  2138. pTmpArray[ currentK ] = i;
  2139. Combinations( n, k, combos, pTmpArray, i + 1, currentK + 1 );
  2140. }
  2141. }
  2142. //-----------------------------------------------------------------------------
  2143. // Takes an incoming Delta state, splits it's name '_' and then finds the
  2144. // control delta (a state without a '_' in its name) and adds the index
  2145. // of that control delta to the referenced array
  2146. //
  2147. // Returns true if all of the control states exist, false otherwise
  2148. //-----------------------------------------------------------------------------
  2149. bool CDmeMesh::GetControlDeltaIndices(
  2150. CDmeVertexDeltaData *pDeltaState,
  2151. CUtlVector< int > &controlDeltaIndices ) const
  2152. {
  2153. Assert( pDeltaState );
  2154. return GetControlDeltaIndices( pDeltaState->GetName(), controlDeltaIndices );
  2155. }
  2156. //-----------------------------------------------------------------------------
  2157. // Same as above but just uses the name of a delta
  2158. //-----------------------------------------------------------------------------
  2159. bool CDmeMesh::GetControlDeltaIndices(
  2160. const char *pDeltaStateName,
  2161. CUtlVector< int > &controlDeltaIndices ) const
  2162. {
  2163. Assert( pDeltaStateName );
  2164. controlDeltaIndices.RemoveAll();
  2165. const int nDeltaStateName( Q_strlen( pDeltaStateName ) );
  2166. char *pTmpBuf( reinterpret_cast< char * >( alloca( nDeltaStateName + 1 ) ) );
  2167. Q_strncpy( pTmpBuf, pDeltaStateName, nDeltaStateName + 1 );
  2168. char *pNext;
  2169. for ( char *pCurr = pTmpBuf; pCurr; pCurr = pNext )
  2170. {
  2171. pNext = strchr( pCurr, '_' );
  2172. if ( pNext )
  2173. {
  2174. *pNext = '\0';
  2175. ++pNext;
  2176. }
  2177. if ( Q_strlen( pCurr ) )
  2178. {
  2179. const int controlDeltaIndex( FindDeltaStateIndex( pCurr ) );
  2180. if ( controlDeltaIndex >= 0 )
  2181. {
  2182. controlDeltaIndices.AddToTail( controlDeltaIndex );
  2183. }
  2184. else
  2185. {
  2186. controlDeltaIndices.RemoveAll();
  2187. return false;
  2188. }
  2189. }
  2190. }
  2191. return true;
  2192. }
  2193. //-----------------------------------------------------------------------------
  2194. // Builds a list of all of the underlying control delta indices for each
  2195. // delta state in the mesh
  2196. //
  2197. // e.g. Say the delta states are (in this order): A, B, C, A_C, A_B_C
  2198. //
  2199. // Will build: {
  2200. // { 0 },
  2201. // { 1 },
  2202. // { 2 },
  2203. // { 0, 2 },
  2204. // { 0, 1, 2 }
  2205. // }
  2206. //
  2207. // Returns true if all of the control states exist, false otherwise
  2208. //-----------------------------------------------------------------------------
  2209. bool CDmeMesh::BuildCompleteDeltaStateControlList(
  2210. CUtlVector< CUtlVector< int > > &deltaStateControlList ) const
  2211. {
  2212. deltaStateControlList.RemoveAll();
  2213. CUtlVector< int > tmpControlDeltaIndices;
  2214. const int nDeltas( m_DeltaStates.Count() );
  2215. for ( int i = 0; i < nDeltas; ++i )
  2216. {
  2217. if ( !GetControlDeltaIndices( m_DeltaStates[ i ], tmpControlDeltaIndices ) )
  2218. return false;
  2219. deltaStateControlList[ deltaStateControlList.AddToTail() ].CopyArray( tmpControlDeltaIndices.Base(), tmpControlDeltaIndices.Count() );
  2220. }
  2221. return true;
  2222. }
  2223. //-----------------------------------------------------------------------------
  2224. // Searches controlList for a sub array that has exactly the same indices as
  2225. // controlIndices. The order of the indices do not have to match but all of
  2226. // them must be present and no extras can be present.
  2227. // It assumes that the controlList is in the same order as m_deltaStates
  2228. //-----------------------------------------------------------------------------
  2229. int CDmeMesh::FindDeltaIndexFromControlIndices(
  2230. const CUtlVector< int > &controlIndices,
  2231. const CUtlVector< CUtlVector< int > > &controlList ) const
  2232. {
  2233. const int nControlIndices( controlIndices.Count() );
  2234. const int nControlList( controlList.Count() );
  2235. int nControlListIndices;
  2236. int foundCount;
  2237. for ( int i = 0; i < nControlList; ++i )
  2238. {
  2239. const CUtlVector< int > &controlListIndices( controlList[ i ] );
  2240. nControlListIndices = controlListIndices.Count();
  2241. if ( nControlListIndices == nControlIndices )
  2242. {
  2243. foundCount = 0;
  2244. for ( int j( 0 ); j < nControlListIndices; ++j )
  2245. {
  2246. for ( int k( 0 ); k < nControlIndices; ++k )
  2247. {
  2248. if ( controlListIndices[ j ] == controlIndices[ k ] )
  2249. {
  2250. ++foundCount;
  2251. break;
  2252. }
  2253. }
  2254. }
  2255. if ( foundCount == nControlIndices )
  2256. return i;
  2257. }
  2258. }
  2259. return -1;
  2260. }
  2261. //-----------------------------------------------------------------------------
  2262. // Builds a list of all of the required underlying deltas that make up this
  2263. // state whether that do not exist. All of the control deltas must exist
  2264. // though (Deltas without '_' in their name).
  2265. //
  2266. // e.g. Say only Delta states A, B, C, D, A_B_C_D exist and A_B_C_D is
  2267. // passed in. This function will return:
  2268. //
  2269. // A_B_C, A_B_D, A_C_D, B_C_D, A_B, A_C, A_D, B_C, B_D, C_D
  2270. //
  2271. // Returns true if all of the control states exist, false otherwise
  2272. //-----------------------------------------------------------------------------
  2273. bool CDmeMesh::BuildMissingDependentDeltaList(
  2274. CDmeVertexDeltaData *pDeltaState,
  2275. CUtlVector< int > &controlIndices,
  2276. CUtlVector< CUtlVector< int > > &dependentStates ) const
  2277. {
  2278. dependentStates.RemoveAll();
  2279. CUtlVector< CUtlVector< int > > deltaStateControlList;
  2280. BuildCompleteDeltaStateControlList( deltaStateControlList );
  2281. if ( !GetControlDeltaIndices( pDeltaState, controlIndices ) )
  2282. return false;
  2283. const int nControlIndices( controlIndices.Count() );
  2284. CUtlVector< int > comboControls;
  2285. for ( int i( nControlIndices - 1 ); i > 0; --i )
  2286. {
  2287. CUtlVector< CUtlVector< int > > combos;
  2288. Combinations( nControlIndices, i, combos );
  2289. const int nCombos( combos.Count() );
  2290. for ( int j( 0 ); j < nCombos; ++j )
  2291. {
  2292. const CUtlVector< int > &comboIndices( combos[ j ] );
  2293. const int nComboIndices( comboIndices.Count() );
  2294. if ( comboIndices.Count() )
  2295. {
  2296. comboControls.RemoveAll();
  2297. comboControls.EnsureCapacity( nComboIndices );
  2298. for ( int k( 0 ); k < nComboIndices; ++k )
  2299. {
  2300. comboControls.AddToTail( controlIndices[ comboIndices[ k ] ] );
  2301. }
  2302. if ( FindDeltaIndexFromControlIndices( comboControls, deltaStateControlList) < 0 )
  2303. {
  2304. dependentStates[ dependentStates.AddToTail() ].CopyArray( comboControls.Base(), comboControls.Count() );
  2305. }
  2306. }
  2307. }
  2308. }
  2309. return true;
  2310. }
  2311. //-----------------------------------------------------------------------------
  2312. //
  2313. //-----------------------------------------------------------------------------
  2314. template < class T_t >
  2315. int CDmeMesh::GenerateCompleteDataForDelta(
  2316. const CDmeVertexDeltaData *pDelta,
  2317. T_t *pFullData,
  2318. int nFullData,
  2319. CDmeVertexData::StandardFields_t standardField )
  2320. {
  2321. memset( pFullData, 0, nFullData * sizeof( T_t ) );
  2322. const FieldIndex_t fIndex( pDelta->FindFieldIndex( standardField ) );
  2323. if ( fIndex >= 0 )
  2324. {
  2325. CDmrArrayConst< T_t > fDataArray( pDelta->GetVertexData( fIndex ) );
  2326. const CUtlVector< T_t > &fData( fDataArray.Get() );
  2327. const CUtlVector< int > &fIndexData( pDelta->GetVertexIndexData( fIndex ) );
  2328. const int nIndexData( fIndexData.Count() );
  2329. Assert( nIndexData <= nFullData );
  2330. int index;
  2331. int i( 0 );
  2332. for ( int j( 0 ); j < nIndexData; ++j )
  2333. {
  2334. index = fIndexData[ j ];
  2335. while ( index > i )
  2336. {
  2337. ++i;
  2338. }
  2339. Assert( i < nFullData );
  2340. pFullData[ i ] = fData[ j ];
  2341. }
  2342. return nIndexData;
  2343. }
  2344. return 0;
  2345. }
  2346. //-----------------------------------------------------------------------------
  2347. //
  2348. //-----------------------------------------------------------------------------
  2349. template < class T_t >
  2350. void CDmeMesh::AddDelta(
  2351. const CDmeVertexDeltaData *pDelta,
  2352. T_t *pFullData,
  2353. int nFullData,
  2354. FieldIndex_t fieldIndex,
  2355. float weight,
  2356. const CDmeSingleIndexedComponent *pMask )
  2357. {
  2358. if ( fieldIndex >= 0 )
  2359. {
  2360. CDmrArrayConst< T_t > fDataArray( pDelta->GetVertexData( fieldIndex ) );
  2361. const CUtlVector< T_t > &fData( fDataArray.Get() );
  2362. const CUtlVector< int > &fIndexData( pDelta->GetVertexIndexData( fieldIndex ) );
  2363. const int nIndexData( fIndexData.Count() );
  2364. T_t t;
  2365. Assert( nIndexData <= nFullData );
  2366. int index;
  2367. int i( 0 );
  2368. if ( pMask )
  2369. {
  2370. float cWeight;
  2371. for ( int j( 0 ); j < nIndexData; ++j )
  2372. {
  2373. index = fIndexData[ j ];
  2374. if ( !pMask->GetWeight( index, cWeight ) )
  2375. continue;
  2376. while ( index > i )
  2377. {
  2378. ++i;
  2379. }
  2380. Assert( i < nFullData );
  2381. t = fData[ j ];
  2382. t *= ( weight * cWeight );
  2383. pFullData[ i ] += t;
  2384. }
  2385. }
  2386. else
  2387. {
  2388. for ( int j( 0 ); j < nIndexData; ++j )
  2389. {
  2390. index = fIndexData[ j ];
  2391. while ( index > i )
  2392. {
  2393. ++i;
  2394. }
  2395. Assert( i < nFullData );
  2396. t = fData[ j ];
  2397. t *= weight;
  2398. pFullData[ i ] += t;
  2399. }
  2400. }
  2401. }
  2402. }
  2403. template void CDmeMesh::AddDelta< float >( const CDmeVertexDeltaData *, float *, int, FieldIndex_t, float, const CDmeSingleIndexedComponent * );
  2404. template void CDmeMesh::AddDelta< Vector2D >( const CDmeVertexDeltaData *, Vector2D *, int, FieldIndex_t, float, const CDmeSingleIndexedComponent * );
  2405. template void CDmeMesh::AddDelta< Vector >( const CDmeVertexDeltaData *, Vector *, int, FieldIndex_t, float, const CDmeSingleIndexedComponent * );
  2406. //-----------------------------------------------------------------------------
  2407. //
  2408. //-----------------------------------------------------------------------------
  2409. template < class T_t >
  2410. void CDmeMesh::AddDelta(
  2411. const CDmeVertexDeltaData *pDelta,
  2412. T_t *pFullData,
  2413. int nFullData,
  2414. CDmeVertexData::StandardFields_t standardField,
  2415. float weight,
  2416. const CDmeSingleIndexedComponent *pMask )
  2417. {
  2418. const FieldIndex_t fIndex( pDelta->FindFieldIndex( standardField ) );
  2419. AddDelta( pDelta, pFullData, nFullData, fIndex, weight, pMask );
  2420. }
  2421. template void CDmeMesh::AddDelta< float >( const CDmeVertexDeltaData *, float *, int, CDmeVertexData::StandardFields_t, float, const CDmeSingleIndexedComponent * );
  2422. template void CDmeMesh::AddDelta< Vector2D >( const CDmeVertexDeltaData *, Vector2D *, int, CDmeVertexData::StandardFields_t, float, const CDmeSingleIndexedComponent * );
  2423. template void CDmeMesh::AddDelta< Vector >( const CDmeVertexDeltaData *, Vector *, int, CDmeVertexData::StandardFields_t, float, const CDmeSingleIndexedComponent * );
  2424. //-----------------------------------------------------------------------------
  2425. //
  2426. //-----------------------------------------------------------------------------
  2427. void CDmeMesh::ComputeAllCorrectedPositionsFromActualPositions()
  2428. {
  2429. const CDmeVertexData *pBase = GetBindBaseState();
  2430. if ( !pBase )
  2431. return;
  2432. CUtlVector< DeltaComputation_t > deltaList;
  2433. ComputeDependentDeltaStateList( deltaList );
  2434. const int nDeltas( deltaList.Count() );
  2435. const int nPositions( pBase->GetPositionData().Count() );
  2436. Vector *pPositions( reinterpret_cast< Vector * >( alloca( nPositions * sizeof( Vector ) ) ) );
  2437. int *pIndices( reinterpret_cast< int * >( alloca( nPositions * sizeof( int ) ) ) );
  2438. int pCount;
  2439. for ( int i = 0; i < nDeltas; ++i )
  2440. {
  2441. const DeltaComputation_t &deltaComputation( deltaList[ i ] );
  2442. CDmeVertexDeltaData *pDelta( m_DeltaStates[ deltaComputation.m_nDeltaIndex ] );
  2443. if ( !pDelta->GetValue< bool >( "corrected" ) )
  2444. {
  2445. const FieldIndex_t pIndex( pDelta->FindFieldIndex( CDmeVertexDeltaData::FIELD_POSITION ) );
  2446. if ( pIndex < 0 )
  2447. continue;
  2448. GenerateCompleteDataForDelta( pDelta, pPositions, nPositions, CDmeVertexData::FIELD_POSITION );
  2449. const CUtlVector< int > &dependentDeltas( deltaComputation.m_DependentDeltas );
  2450. const int nDependentDeltas( dependentDeltas.Count() );
  2451. for ( int j( 0 ); j < nDependentDeltas; ++j )
  2452. {
  2453. const CDmeVertexDeltaData *pDependentDelta( m_DeltaStates[ dependentDeltas[ j ] ] );
  2454. const CUtlVector< Vector > &dPositions( pDependentDelta->GetPositionData() );
  2455. const CUtlVector<int> &dIndices( pDependentDelta->GetVertexIndexData( CDmeVertexData::FIELD_POSITION ) );
  2456. Assert( dPositions.Count() == dIndices.Count() );
  2457. const int nIndices( dIndices.Count() );
  2458. int index;
  2459. int k( 0 );
  2460. for ( int l( 0 ); l < nIndices; ++l )
  2461. {
  2462. index = dIndices[ l ];
  2463. while ( index > k )
  2464. {
  2465. ++k;
  2466. }
  2467. Assert( k < nPositions );
  2468. pPositions[ k ] -= dPositions[ l ];
  2469. }
  2470. }
  2471. pCount = 0;
  2472. for ( int j( 0 ); j < nPositions; ++j )
  2473. {
  2474. const Vector &v( pPositions[ j ] );
  2475. // Kind of a magic number but it's because of 16 bit compression of the delta values
  2476. if ( fabs( v.x ) >= ( 1 / 4096.0f ) || fabs( v.y ) >= ( 1 / 4096.0f ) || fabs( v.z ) >= ( 1 / 4096.0f ) )
  2477. {
  2478. pPositions[ pCount ] = v;
  2479. pIndices[ pCount ] = j;
  2480. ++pCount;
  2481. }
  2482. }
  2483. pDelta->RemoveAllVertexData( pIndex );
  2484. if ( pCount )
  2485. {
  2486. pDelta->AddVertexData( pIndex, pCount );
  2487. pDelta->SetVertexData( pIndex, 0, pCount, AT_VECTOR3, pPositions );
  2488. pDelta->SetVertexIndices( pIndex, 0, pCount, pIndices );
  2489. }
  2490. pDelta->SetValue( "corrected", true );
  2491. }
  2492. }
  2493. }
  2494. //-----------------------------------------------------------------------------
  2495. // There's no guarantee that fields are added in any order, nor that only
  2496. // standard fields exist...
  2497. //-----------------------------------------------------------------------------
  2498. template < class T_t >
  2499. void CDmeMesh::AddCorrectedDelta(
  2500. CDmrArray< T_t > &baseDataArray,
  2501. const CUtlVector< int > &baseIndices,
  2502. const DeltaComputation_t &deltaComputation,
  2503. const char *pFieldName,
  2504. float weight,
  2505. const CDmeSingleIndexedComponent *pMask )
  2506. {
  2507. const CUtlVector< T_t > &baseData( baseDataArray.Get() );
  2508. const int nData( baseData.Count() );
  2509. T_t *pData( reinterpret_cast< T_t * >( alloca( nData * sizeof( T_t ) ) ) );
  2510. Q_memcpy( pData, baseData.Base(), nData * sizeof( T_t ) );
  2511. CDmeVertexDeltaData *pDelta( GetDeltaState( deltaComputation.m_nDeltaIndex ) );
  2512. const int deltaFieldIndex( pDelta->FindFieldIndex( pFieldName ) );
  2513. if ( deltaFieldIndex < 0 )
  2514. return;
  2515. AddDelta( pDelta, pData, nData, deltaFieldIndex, weight, pMask );
  2516. const CUtlVector< int > &depDeltas( deltaComputation.m_DependentDeltas );
  2517. const int nDepDeltas( depDeltas.Count() );
  2518. for ( int j( 0 ); j < nDepDeltas; ++j )
  2519. {
  2520. pDelta = GetDeltaState( depDeltas[ j ] );
  2521. int depFieldIndex = pDelta->FindFieldIndex( pFieldName );
  2522. if ( depFieldIndex < 0 )
  2523. continue;
  2524. AddDelta( pDelta, pData, nData, depFieldIndex, weight, pMask );
  2525. }
  2526. baseDataArray.CopyArray( pData, nData );
  2527. }
  2528. //-----------------------------------------------------------------------------
  2529. //
  2530. //-----------------------------------------------------------------------------
  2531. template < class T_t >
  2532. void CDmeMesh::AddCorrectedDelta(
  2533. CUtlVector< T_t > &baseData,
  2534. const CUtlVector< int > &baseIndices,
  2535. const DeltaComputation_t &deltaComputation,
  2536. const char *pFieldName,
  2537. float weight,
  2538. const CDmeSingleIndexedComponent *pMask )
  2539. {
  2540. const int nData( baseData.Count() );
  2541. CDmeVertexDeltaData *pDelta( GetDeltaState( deltaComputation.m_nDeltaIndex ) );
  2542. const int deltaFieldIndex( pDelta->FindFieldIndex( pFieldName ) );
  2543. if ( deltaFieldIndex < 0 )
  2544. return;
  2545. AddDelta( pDelta, baseData.Base(), nData, deltaFieldIndex, weight, pMask );
  2546. const CUtlVector< int > &depDeltas( deltaComputation.m_DependentDeltas );
  2547. const int nDepDeltas( depDeltas.Count() );
  2548. for ( int j( 0 ); j < nDepDeltas; ++j )
  2549. {
  2550. pDelta = GetDeltaState( depDeltas[ j ] );
  2551. int depFieldIndex = pDelta->FindFieldIndex( pFieldName );
  2552. if ( depFieldIndex < 0 )
  2553. continue;
  2554. AddDelta( pDelta, baseData.Base(), nData, depFieldIndex, weight, pMask );
  2555. }
  2556. }
  2557. //-----------------------------------------------------------------------------
  2558. // There's no guarantee that fields are added in any order, nor that only
  2559. // standard fields exist...
  2560. //-----------------------------------------------------------------------------
  2561. template < class T_t >
  2562. void CDmeMesh::AddRawDelta(
  2563. CDmeVertexDeltaData *pDelta,
  2564. CDmrArray< T_t > &baseDataArray,
  2565. FieldIndex_t nDeltaFieldIndex,
  2566. float weight,
  2567. const CDmeSingleIndexedComponent *pMask )
  2568. {
  2569. if ( !pDelta || nDeltaFieldIndex < 0 )
  2570. return;
  2571. const CUtlVector< T_t > &baseData( baseDataArray.Get() );
  2572. const int nData( baseData.Count() );
  2573. T_t *pData( reinterpret_cast< T_t * >( alloca( nData * sizeof( T_t ) ) ) );
  2574. Q_memcpy( pData, baseData.Base(), nData * sizeof( T_t ) );
  2575. AddDelta( pDelta, pData, nData, nDeltaFieldIndex, weight, pMask );
  2576. baseDataArray.CopyArray( pData, nData );
  2577. }
  2578. //-----------------------------------------------------------------------------
  2579. //
  2580. //-----------------------------------------------------------------------------
  2581. template < class T_t >
  2582. void CDmeMesh::AddRawDelta(
  2583. CDmeVertexDeltaData *pDelta,
  2584. CUtlVector< T_t > &baseData,
  2585. FieldIndex_t nDeltaFieldIndex,
  2586. float weight,
  2587. const CDmeSingleIndexedComponent *pMask )
  2588. {
  2589. if ( !pDelta || nDeltaFieldIndex < 0 )
  2590. return;
  2591. const int nData( baseData.Count() );
  2592. AddDelta( pDelta, baseData.Base(), nData, nDeltaFieldIndex, weight, pMask );
  2593. }
  2594. //-----------------------------------------------------------------------------
  2595. // Sets the specified base state to the specified delta
  2596. // If no delta is specified then the current state is copied from the bind state
  2597. // If no base state is specified then the current base state is used
  2598. // The specified base state or the current base state cannot be the bind state
  2599. //-----------------------------------------------------------------------------
  2600. bool CDmeMesh::SetBaseStateToDelta( const CDmeVertexDeltaData *pDelta, CDmeVertexData *pPassedBase /* = NULL */ )
  2601. {
  2602. CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  2603. const CDmeVertexData *pBind = GetBindBaseState();
  2604. if ( !pBase || !pBind || pBase == pBind )
  2605. return false;
  2606. pBind->CopyTo( pBase );
  2607. if ( !pDelta )
  2608. return true;
  2609. // This should be cached and recomputed only when states are added
  2610. CUtlVector< DeltaComputation_t > compList;
  2611. ComputeDependentDeltaStateList( compList );
  2612. const int nDeltas( compList.Count() );
  2613. for ( int i = 0; i < nDeltas; ++i )
  2614. {
  2615. if ( pDelta != GetDeltaState( compList[ i ].m_nDeltaIndex ) )
  2616. continue;
  2617. const int nBaseField( pBase->FieldCount() );
  2618. const int nDeltaField( pDelta->FieldCount() );
  2619. for ( int j( 0 ); j < nBaseField; ++j )
  2620. {
  2621. const CUtlString &baseFieldName( pBase->FieldName( j ) );
  2622. for ( int k( 0 ); k < nDeltaField; ++k )
  2623. {
  2624. const CUtlString &deltaFieldName( pDelta->FieldName( k ) );
  2625. if ( baseFieldName != deltaFieldName )
  2626. continue;
  2627. const FieldIndex_t baseFieldIndex( pBase->FindFieldIndex( baseFieldName ) );
  2628. const FieldIndex_t deltaFieldIndex( pDelta->FindFieldIndex( deltaFieldName ) );
  2629. if ( baseFieldIndex < 0 || deltaFieldIndex < 0 )
  2630. break;
  2631. CDmAttribute *pBaseData( pBase->GetVertexData( baseFieldIndex ) );
  2632. const CDmAttribute *pDeltaData( pDelta->GetVertexData( deltaFieldIndex ) );
  2633. if ( pBaseData->GetType() != pDeltaData->GetType() )
  2634. break;
  2635. const CUtlVector< int > &baseIndices( pBase->GetVertexIndexData( baseFieldIndex ) );
  2636. switch ( pBaseData->GetType() )
  2637. {
  2638. case AT_FLOAT_ARRAY:
  2639. AddCorrectedDelta( CDmrArray< float >( pBaseData ), baseIndices, compList[ i ], baseFieldName );
  2640. break;
  2641. case AT_COLOR_ARRAY:
  2642. AddCorrectedDelta( CDmrArray< Vector >( pBaseData ), baseIndices, compList[ i ], baseFieldName );
  2643. break;
  2644. case AT_VECTOR2_ARRAY:
  2645. AddCorrectedDelta( CDmrArray< Vector2D >( pBaseData ), baseIndices, compList[ i ], baseFieldName );
  2646. break;
  2647. case AT_VECTOR3_ARRAY:
  2648. AddCorrectedDelta( CDmrArray< Vector >( pBaseData ), baseIndices, compList[ i ], baseFieldName );
  2649. break;
  2650. default:
  2651. break;
  2652. }
  2653. break;
  2654. }
  2655. }
  2656. }
  2657. return true;
  2658. }
  2659. //-----------------------------------------------------------------------------
  2660. //
  2661. //-----------------------------------------------------------------------------
  2662. void CDmeMesh::SelectVerticesFromDelta(
  2663. CDmeVertexDeltaData *pDelta,
  2664. CDmeSingleIndexedComponent *pSelection )
  2665. {
  2666. if ( !pSelection )
  2667. return;
  2668. pSelection->Clear();
  2669. if ( !pDelta )
  2670. return;
  2671. const FieldIndex_t pField( pDelta->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) );
  2672. if ( pField < 0 )
  2673. return;
  2674. const CUtlVector< int > &pIndicies( pDelta->GetVertexIndexData( CDmeVertexData::FIELD_POSITION ) );
  2675. pSelection->AddComponents( pIndicies );
  2676. }
  2677. //-----------------------------------------------------------------------------
  2678. //
  2679. //-----------------------------------------------------------------------------
  2680. void CDmeMesh::SelectAllVertices( CDmeSingleIndexedComponent *pSelection, CDmeVertexData *pPassedBase /* = NULL */ )
  2681. {
  2682. const CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  2683. if ( !pBase )
  2684. {
  2685. pBase = GetBindBaseState();
  2686. }
  2687. if ( !pBase )
  2688. return;
  2689. if ( !pSelection )
  2690. return;
  2691. pSelection->Clear();
  2692. const FieldIndex_t pField( pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) );
  2693. if ( pField < 0 )
  2694. return;
  2695. CUtlVector< int > indices;
  2696. indices.EnsureCount( CDmrArrayConst< Vector >( pBase->GetVertexData( pField ) ).Count() );
  2697. const int nIndices = indices.Count();
  2698. for ( int i = 0; i < nIndices; ++i )
  2699. {
  2700. indices[ i ] = i;
  2701. }
  2702. pSelection->AddComponents( indices );
  2703. }
  2704. //-----------------------------------------------------------------------------
  2705. //
  2706. //-----------------------------------------------------------------------------
  2707. void CDmeMesh::SelectHalfVertices( SelectHalfType_t selectHalfType, CDmeSingleIndexedComponent *pSelection, CDmeVertexData *pPassedBase /* = NULL */ )
  2708. {
  2709. const CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  2710. if ( !pBase )
  2711. {
  2712. pBase = GetBindBaseState();
  2713. }
  2714. if ( !pBase )
  2715. return;
  2716. if ( !pSelection )
  2717. return;
  2718. pSelection->Clear();
  2719. const FieldIndex_t pField( pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION ) );
  2720. if ( pField < 0 )
  2721. return;
  2722. const CDmrArrayConst< Vector > pos( pBase->GetVertexData( pField ) );
  2723. const int nPosCount = pos.Count();
  2724. CUtlVector< int > indices;
  2725. indices.EnsureCapacity( nPosCount );
  2726. if ( selectHalfType == kRight )
  2727. {
  2728. for ( int i = 0; i < nPosCount; ++i )
  2729. {
  2730. if ( pos[ i ].x <= 0.0f )
  2731. {
  2732. indices.AddToTail( i );
  2733. }
  2734. }
  2735. }
  2736. else
  2737. {
  2738. for ( int i = 0; i < nPosCount; ++i )
  2739. {
  2740. if ( pos[ i ].x >= 0.0f )
  2741. {
  2742. indices.AddToTail( i );
  2743. }
  2744. }
  2745. }
  2746. pSelection->AddComponents( indices );
  2747. }
  2748. //-----------------------------------------------------------------------------
  2749. //
  2750. //-----------------------------------------------------------------------------
  2751. bool CDmeMesh::CreateDeltaFieldFromBaseField(
  2752. CDmeVertexData::StandardFields_t nStandardFieldIndex,
  2753. const CDmrArrayConst< float > &baseArray,
  2754. const CDmrArrayConst< float > &bindArray,
  2755. CDmeVertexDeltaData *pDelta )
  2756. {
  2757. const int nData( baseArray.Count() );
  2758. if ( nData != bindArray.Count() )
  2759. return false;
  2760. const float *pBaseData( baseArray.Get().Base() );
  2761. const float *pBindData( bindArray.Get().Base() );
  2762. float *pData( reinterpret_cast< float * >( nData * sizeof( float ) ) );
  2763. Q_memcpy( pData, pBaseData, nData * sizeof( float ) );
  2764. int *pIndices( reinterpret_cast< int * >( nData * sizeof( int ) ) );
  2765. float v;
  2766. int nDeltaCount( 0 );
  2767. for ( int i = 0; i < nData; ++i )
  2768. {
  2769. v = pBaseData[ i ] - pBindData[ i ];
  2770. // Kind of a magic number but it's because of 16 bit compression of the delta values
  2771. if ( fabs( v ) >= ( 1 / 4096.0f ) )
  2772. {
  2773. pData[ nDeltaCount ] = v;
  2774. pIndices[ nDeltaCount ] = i;
  2775. ++nDeltaCount;
  2776. }
  2777. }
  2778. if ( nDeltaCount <= 0 )
  2779. return true;
  2780. FieldIndex_t fieldIndex( pDelta->CreateField( nStandardFieldIndex ) );
  2781. if ( fieldIndex < 0 )
  2782. return false;
  2783. pDelta->AddVertexData( fieldIndex, nDeltaCount );
  2784. pDelta->SetVertexData( fieldIndex, 0, nDeltaCount, AT_FLOAT, pData );
  2785. pDelta->SetVertexIndices( fieldIndex, 0, nDeltaCount, pIndices );
  2786. return true;
  2787. }
  2788. //-----------------------------------------------------------------------------
  2789. //
  2790. //-----------------------------------------------------------------------------
  2791. bool CDmeMesh::CreateDeltaFieldFromBaseField(
  2792. CDmeVertexData::StandardFields_t nStandardFieldIndex,
  2793. const CDmrArrayConst< Vector2D > &baseArray,
  2794. const CDmrArrayConst< Vector2D > &bindArray,
  2795. CDmeVertexDeltaData *pDelta )
  2796. {
  2797. const int nData( baseArray.Count() );
  2798. if ( nData != bindArray.Count() )
  2799. return false;
  2800. const Vector2D *pBaseData( baseArray.Get().Base() );
  2801. const Vector2D *pBindData( bindArray.Get().Base() );
  2802. Vector2D *pData( reinterpret_cast< Vector2D * >( nData * sizeof( Vector2D ) ) );
  2803. Q_memcpy( pData, pBaseData, nData * sizeof( Vector2D ) );
  2804. int *pIndices( reinterpret_cast< int * >( nData * sizeof( int ) ) );
  2805. Vector2D v;
  2806. int nDeltaCount( 0 );
  2807. for ( int i = 0; i < nData; ++i )
  2808. {
  2809. v = pBaseData[ i ] - pBindData[ i ];
  2810. // Kind of a magic number but it's because of 16 bit compression of the delta values
  2811. if ( fabs( v.x ) >= ( 1 / 4096.0f ) || fabs( v.y ) >= ( 1 / 4096.0f ) )
  2812. {
  2813. pData[ nDeltaCount ] = v;
  2814. pIndices[ nDeltaCount ] = i;
  2815. ++nDeltaCount;
  2816. }
  2817. }
  2818. if ( nDeltaCount <= 0 )
  2819. return true;
  2820. FieldIndex_t fieldIndex( pDelta->CreateField( nStandardFieldIndex ) );
  2821. if ( fieldIndex < 0 )
  2822. return false;
  2823. pDelta->AddVertexData( fieldIndex, nDeltaCount );
  2824. pDelta->SetVertexData( fieldIndex, 0, nDeltaCount, AT_VECTOR2, pData );
  2825. pDelta->SetVertexIndices( fieldIndex, 0, nDeltaCount, pIndices );
  2826. return true;
  2827. }
  2828. //-----------------------------------------------------------------------------
  2829. //
  2830. //-----------------------------------------------------------------------------
  2831. bool CDmeMesh::CreateDeltaFieldFromBaseField(
  2832. CDmeVertexData::StandardFields_t nStandardFieldIndex,
  2833. const CDmrArrayConst< Vector > &baseArray,
  2834. const CDmrArrayConst< Vector > &bindArray,
  2835. CDmeVertexDeltaData *pDelta )
  2836. {
  2837. const int nData( baseArray.Count() );
  2838. if ( nData != bindArray.Count() )
  2839. return false;
  2840. const Vector *pBaseData( baseArray.Get().Base() );
  2841. const Vector *pBindData( bindArray.Get().Base() );
  2842. Vector *pData( reinterpret_cast< Vector * >( alloca( nData * sizeof( Vector ) ) ) );
  2843. Q_memcpy( pData, pBaseData, nData * sizeof( Vector ) );
  2844. int *pIndices( reinterpret_cast< int * >( alloca( nData * sizeof( int ) ) ) );
  2845. Vector v;
  2846. int nDeltaCount( 0 );
  2847. for ( int i = 0; i < nData; ++i )
  2848. {
  2849. v = pBaseData[ i ] - pBindData[ i ];
  2850. // Kind of a magic number but it's because of 16 bit compression of the delta values
  2851. if ( fabs( v.x ) >= ( 1 / 4096.0f ) || fabs( v.y ) >= ( 1 / 4096.0f ) || fabs( v.z ) >= ( 1 / 4096.0f ) )
  2852. {
  2853. pData[ nDeltaCount ] = v;
  2854. pIndices[ nDeltaCount ] = i;
  2855. ++nDeltaCount;
  2856. }
  2857. }
  2858. if ( nDeltaCount <= 0 )
  2859. return true;
  2860. FieldIndex_t fieldIndex( pDelta->CreateField( nStandardFieldIndex ) );
  2861. if ( fieldIndex < 0 )
  2862. return false;
  2863. pDelta->AddVertexData( fieldIndex, nDeltaCount );
  2864. pDelta->SetVertexData( fieldIndex, 0, nDeltaCount, AT_VECTOR3, pData );
  2865. pDelta->SetVertexIndices( fieldIndex, 0, nDeltaCount, pIndices );
  2866. return true;
  2867. }
  2868. //-----------------------------------------------------------------------------
  2869. // Creates a delta from the difference between the bind base state and the
  2870. // specified base state. If pBaseName is NULL the current base state is used
  2871. //-----------------------------------------------------------------------------
  2872. CDmeVertexDeltaData *CDmeMesh::ModifyOrCreateDeltaStateFromBaseState( const char *pDeltaName, CDmeVertexData *pPassedBase /* = NULL */, bool absolute /* = false */ )
  2873. {
  2874. // Find All States Which Have This Guy
  2875. CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  2876. if ( !pBase )
  2877. return NULL;
  2878. CDmeVertexData *pBind = GetBindBaseState();
  2879. if ( !pBind )
  2880. return NULL;
  2881. // It's ok if pBase == pBind
  2882. CUtlVector< int > superiorDeltaStates;
  2883. ComputeSuperiorDeltaStateList( pDeltaName, superiorDeltaStates );
  2884. const int nSuperior = superiorDeltaStates.Count();
  2885. if ( nSuperior > 0 )
  2886. {
  2887. UniqueId_t id;
  2888. char idBuf[ MAX_PATH ];
  2889. CDmeVertexData *pTmpBaseState = NULL;
  2890. do
  2891. {
  2892. CreateUniqueId( &id );
  2893. UniqueIdToString( id, idBuf, sizeof( idBuf ) );
  2894. pTmpBaseState = FindBaseState( idBuf );
  2895. } while( pTmpBaseState != NULL );
  2896. pTmpBaseState = FindOrCreateBaseState( idBuf );
  2897. if ( !pTmpBaseState )
  2898. return NULL;
  2899. for ( int i = 0; i < nSuperior; ++i )
  2900. {
  2901. Assert( superiorDeltaStates[ i ] < DeltaStateCount() );
  2902. CDmeVertexDeltaData *pSuperiorDelta = GetDeltaState( superiorDeltaStates[ i ] );
  2903. if ( pSuperiorDelta->GetValue< bool >( "corrected" ) )
  2904. {
  2905. // Only fiddle with states that are "corrected"
  2906. if ( !SetBaseStateToDelta( pSuperiorDelta, pTmpBaseState ) )
  2907. return NULL;
  2908. if ( !ModifyOrCreateDeltaStateFromBaseState( CUtlString( pSuperiorDelta->GetName() ), pTmpBaseState, true ) )
  2909. return NULL;
  2910. }
  2911. }
  2912. DeleteBaseState( idBuf );
  2913. }
  2914. ResetDeltaState( pDeltaName );
  2915. CDmeVertexDeltaData *pDelta = FindOrCreateDeltaState( pDeltaName );
  2916. if ( !pDelta )
  2917. return NULL;
  2918. CDmeVertexData::StandardFields_t deltaFields[] =
  2919. {
  2920. CDmeVertexData::FIELD_POSITION,
  2921. CDmeVertexData::FIELD_NORMAL,
  2922. CDmeVertexData::FIELD_WRINKLE
  2923. };
  2924. for ( int i = 0; i < sizeof( deltaFields ) / sizeof( deltaFields[ 0 ] ); ++i )
  2925. {
  2926. CDmeVertexData::StandardFields_t standardFieldIndex( deltaFields[ i ] );
  2927. const FieldIndex_t baseFieldIndex( pBase->FindFieldIndex( standardFieldIndex ) );
  2928. const FieldIndex_t bindFieldIndex( pBind->FindFieldIndex( standardFieldIndex ) );
  2929. if ( baseFieldIndex < 0 || bindFieldIndex < 0 )
  2930. continue;
  2931. CDmAttribute *pBaseData( pBase->GetVertexData( baseFieldIndex ) );
  2932. CDmAttribute *pBindData( pBind->GetVertexData( bindFieldIndex ) );
  2933. if ( pBaseData->GetType() != pBindData->GetType() )
  2934. continue;
  2935. switch ( pBaseData->GetType() )
  2936. {
  2937. case AT_FLOAT_ARRAY:
  2938. CreateDeltaFieldFromBaseField( standardFieldIndex, CDmrArrayConst< float >( pBaseData ), CDmrArrayConst< float >( pBindData ), pDelta );
  2939. break;
  2940. case AT_COLOR_ARRAY:
  2941. CreateDeltaFieldFromBaseField( standardFieldIndex, CDmrArrayConst< Vector >( pBaseData ), CDmrArrayConst< Vector >( pBindData ), pDelta );
  2942. break;
  2943. case AT_VECTOR2_ARRAY:
  2944. CreateDeltaFieldFromBaseField( standardFieldIndex, CDmrArrayConst< Vector2D >( pBaseData ), CDmrArrayConst< Vector2D >( pBindData ), pDelta );
  2945. break;
  2946. case AT_VECTOR3_ARRAY:
  2947. CreateDeltaFieldFromBaseField( standardFieldIndex, CDmrArrayConst< Vector >( pBaseData ), CDmrArrayConst< Vector >( pBindData ), pDelta );
  2948. break;
  2949. default:
  2950. break;
  2951. }
  2952. }
  2953. if ( !strchr( pDelta->GetName(), '_' ) )
  2954. {
  2955. const static CUtlSymbolLarge symTargets = g_pDataModel->GetSymbol( "targets" );
  2956. CDmeCombinationOperator *pCombo( FindReferringElement< CDmeCombinationOperator >( this, symTargets ) );
  2957. if ( pCombo )
  2958. {
  2959. pCombo->FindOrCreateControl( pDelta->GetName(), false, true );
  2960. }
  2961. }
  2962. if ( !absolute )
  2963. {
  2964. ComputeAllCorrectedPositionsFromActualPositions();
  2965. }
  2966. return pDelta;
  2967. }
  2968. //-----------------------------------------------------------------------------
  2969. // TODO: Uncorrect all superior states and then correct them afterwards
  2970. //-----------------------------------------------------------------------------
  2971. bool CDmeMesh::DeleteDeltaState( const char *pDeltaName )
  2972. {
  2973. const int nDeltaIndex = FindDeltaStateIndex( pDeltaName );
  2974. if ( nDeltaIndex < 0 )
  2975. return false;
  2976. Assert( m_DeltaStates.Count() == m_DeltaStateWeights[ MESH_DELTA_WEIGHT_NORMAL ].Count() );
  2977. Assert( m_DeltaStates.Count() == m_DeltaStateWeights[ MESH_DELTA_WEIGHT_LAGGED ].Count() );
  2978. CDmeVertexDeltaData *pDelta( m_DeltaStates[ nDeltaIndex ] );
  2979. if ( !pDelta )
  2980. return false;
  2981. m_DeltaStates.Remove( nDeltaIndex );
  2982. m_DeltaStateWeights[ MESH_DELTA_WEIGHT_NORMAL ].Remove( nDeltaIndex );
  2983. m_DeltaStateWeights[ MESH_DELTA_WEIGHT_LAGGED ].Remove( nDeltaIndex );
  2984. g_pDataModel->DestroyElement( pDelta->GetHandle() );
  2985. const static CUtlSymbolLarge symTargets = g_pDataModel->GetSymbol( "targets" );
  2986. CDmeCombinationOperator *pCombo( FindReferringElement< CDmeCombinationOperator >( this, symTargets ) );
  2987. if ( pCombo )
  2988. {
  2989. pCombo->Purge();
  2990. }
  2991. return true;
  2992. }
  2993. //-----------------------------------------------------------------------------
  2994. // TODO: Uncorrect all superior states and then correct them afterwards
  2995. //-----------------------------------------------------------------------------
  2996. bool CDmeMesh::ResetDeltaState( const char *pDeltaName )
  2997. {
  2998. const int nDeltaIndex = FindDeltaStateIndex( pDeltaName );
  2999. if ( nDeltaIndex < 0 )
  3000. return false;
  3001. CDmeVertexDeltaData *pOldDelta = m_DeltaStates[ nDeltaIndex ];
  3002. CDmeVertexDeltaData *pNewDelta = CreateElement< CDmeVertexDeltaData >( pOldDelta->GetName(), GetFileId() );
  3003. if ( !pNewDelta )
  3004. return false;
  3005. m_DeltaStates.Set( nDeltaIndex, pNewDelta );
  3006. g_pDataModel->DestroyElement( pOldDelta->GetHandle() );
  3007. return true;
  3008. }
  3009. //-----------------------------------------------------------------------------
  3010. //
  3011. //-----------------------------------------------------------------------------
  3012. class CSelectionHelper
  3013. {
  3014. public:
  3015. class CVert
  3016. {
  3017. public:
  3018. int m_index;
  3019. int m_count;
  3020. float m_weight;
  3021. };
  3022. void AddVert( int vIndex, float weight = 1.0f );
  3023. int AddToSelection( CDmeSingleIndexedComponent *pSelection ) const;
  3024. int RemoveFromSelection( CDmeSingleIndexedComponent *pSelection, bool bAllowEmpty ) const;
  3025. protected:
  3026. CUtlVector< CVert > m_verts;
  3027. int BinarySearch( int component ) const;
  3028. };
  3029. //-----------------------------------------------------------------------------
  3030. //
  3031. //-----------------------------------------------------------------------------
  3032. void CSelectionHelper::AddVert( int vIndex, float weight /* = 1.0f */ )
  3033. {
  3034. // Find the vertex, add it if necessary
  3035. const int index = BinarySearch( vIndex );
  3036. if ( index == m_verts.Count() )
  3037. {
  3038. // New Add to end
  3039. CVert &v( m_verts[ m_verts.AddToTail() ] );
  3040. v.m_index = vIndex;
  3041. v.m_count = 1;
  3042. v.m_weight = weight;
  3043. }
  3044. else if ( vIndex == m_verts[ index ].m_index )
  3045. {
  3046. // Existing, increment
  3047. CVert &v( m_verts[ index ] );
  3048. Assert( v.m_index == vIndex );
  3049. v.m_count += 1;
  3050. v.m_weight += weight;
  3051. }
  3052. else
  3053. {
  3054. // New insert before index
  3055. CVert &v( m_verts[ m_verts.InsertBefore( index ) ] );
  3056. v.m_index = vIndex;
  3057. v.m_count = 1;
  3058. v.m_weight = weight;
  3059. }
  3060. }
  3061. //-----------------------------------------------------------------------------
  3062. //
  3063. //-----------------------------------------------------------------------------
  3064. int CSelectionHelper::AddToSelection( CDmeSingleIndexedComponent *pSelection ) const
  3065. {
  3066. const int nVerts = m_verts.Count();
  3067. for ( int i = 0; i < nVerts; ++i )
  3068. {
  3069. const CVert &v( m_verts[ i ] );
  3070. Assert( !pSelection->HasComponent( v.m_index ) );
  3071. pSelection->AddComponent( v.m_index, v.m_weight / static_cast< float >( v.m_count ) );
  3072. }
  3073. return nVerts;
  3074. }
  3075. //-----------------------------------------------------------------------------
  3076. //
  3077. //-----------------------------------------------------------------------------
  3078. int CSelectionHelper::RemoveFromSelection( CDmeSingleIndexedComponent *pSelection, bool bAllowEmpty ) const
  3079. {
  3080. const int nVerts = m_verts.Count();
  3081. int nVertsRemovedCount = 0;
  3082. for ( int i = 0; i < nVerts; ++i )
  3083. {
  3084. const CVert &v( m_verts[ i ] );
  3085. if ( bAllowEmpty || pSelection->Count() > 1 )
  3086. {
  3087. pSelection->RemoveComponent( v.m_index );
  3088. ++nVertsRemovedCount;
  3089. }
  3090. }
  3091. return nVertsRemovedCount;
  3092. }
  3093. //-----------------------------------------------------------------------------
  3094. // Searches for the component in the sorted component list and returns the
  3095. // index if it's found or if it's not found, returns the index at which it
  3096. // should be inserted to maintain the sorted order of the component list
  3097. //-----------------------------------------------------------------------------
  3098. int CSelectionHelper::BinarySearch( int vIndex ) const
  3099. {
  3100. const int nVerts( m_verts.Count() );
  3101. int left( 0 );
  3102. int right( nVerts - 1 );
  3103. int mid;
  3104. while ( left <= right )
  3105. {
  3106. mid = ( left + right ) >> 1; // floor( ( left + right ) / 2.0 )
  3107. if ( vIndex > m_verts[ mid ].m_index )
  3108. {
  3109. left = mid + 1;
  3110. }
  3111. else if ( vIndex < m_verts[ mid ].m_index )
  3112. {
  3113. right = mid - 1;
  3114. }
  3115. else
  3116. {
  3117. return mid;
  3118. }
  3119. }
  3120. return left;
  3121. }
  3122. //-----------------------------------------------------------------------------
  3123. //
  3124. //-----------------------------------------------------------------------------
  3125. void CDmeMesh::GrowSelection( int nSize, CDmeSingleIndexedComponent *pSelection, CDmMeshComp *pPassedMeshComp )
  3126. {
  3127. if ( nSize <= 0 || !pSelection )
  3128. return;
  3129. CUtlVector< int > sIndices;
  3130. CUtlVector< float > sWeights;
  3131. pSelection->GetComponents( sIndices, sWeights );
  3132. const int nVertices = sIndices.Count();
  3133. CDmMeshComp *pMeshComp = pPassedMeshComp ? pPassedMeshComp : new CDmMeshComp( this );
  3134. CUtlVector< CDmMeshComp::CVert * > neighbours;
  3135. CSelectionHelper sHelper;
  3136. for ( int i = 0; i < nVertices; ++i )
  3137. {
  3138. const int nNeighbours = pMeshComp->FindNeighbouringVerts( sIndices[ i ], neighbours );
  3139. for ( int j = 0; j < nNeighbours; ++j )
  3140. {
  3141. CDmMeshComp::CVert *pNeighbour = neighbours[ j ];
  3142. Assert( pNeighbour );
  3143. if ( pNeighbour )
  3144. {
  3145. const int vIndex = pNeighbour->PositionIndex();
  3146. if ( !pSelection->HasComponent( vIndex ) )
  3147. {
  3148. sHelper.AddVert( vIndex, sWeights[ i ] );
  3149. }
  3150. }
  3151. }
  3152. }
  3153. if ( sHelper.AddToSelection( pSelection ) > 0 )
  3154. {
  3155. GrowSelection( nSize - 1, pSelection, pMeshComp );
  3156. }
  3157. if ( pMeshComp != pPassedMeshComp )
  3158. {
  3159. delete pMeshComp;
  3160. }
  3161. }
  3162. //-----------------------------------------------------------------------------
  3163. //
  3164. //-----------------------------------------------------------------------------
  3165. void CDmeMesh::ShrinkSelection( int nSize, CDmeSingleIndexedComponent *pSelection, CDmMeshComp *pPassedMeshComp )
  3166. {
  3167. if ( nSize <= 0 || !pSelection )
  3168. return;
  3169. CUtlVector< int > sIndices;
  3170. CUtlVector< float > sWeights;
  3171. pSelection->GetComponents( sIndices, sWeights );
  3172. const int nVertices = sIndices.Count();
  3173. CDmMeshComp *pMeshComp = pPassedMeshComp ? pPassedMeshComp : new CDmMeshComp( this );
  3174. CUtlVector< CDmMeshComp::CVert * > neighbours;
  3175. CSelectionHelper sHelper;
  3176. for ( int i = 0; i < nVertices; ++i )
  3177. {
  3178. bool hasSelectedNeighbour = false;
  3179. bool hasUnselectedNeighbour = false;
  3180. const int vIndex = sIndices[ i ];
  3181. const int nNeighbours = pMeshComp->FindNeighbouringVerts( vIndex, neighbours );
  3182. for ( int j = 0; j < nNeighbours; ++j )
  3183. {
  3184. const int nvIndex = neighbours[ j ]->PositionIndex();
  3185. if ( pSelection->HasComponent( nvIndex ) )
  3186. {
  3187. hasSelectedNeighbour = true;
  3188. if ( hasUnselectedNeighbour )
  3189. {
  3190. sHelper.AddVert( vIndex );
  3191. break;
  3192. }
  3193. }
  3194. else
  3195. {
  3196. hasUnselectedNeighbour = true;
  3197. if ( hasSelectedNeighbour )
  3198. {
  3199. sHelper.AddVert( vIndex );
  3200. break;
  3201. }
  3202. }
  3203. }
  3204. }
  3205. if ( sHelper.RemoveFromSelection( pSelection, false ) > 0 )
  3206. {
  3207. ShrinkSelection( nSize - 1, pSelection, pMeshComp );
  3208. }
  3209. if ( pMeshComp != pPassedMeshComp )
  3210. {
  3211. delete pMeshComp;
  3212. }
  3213. }
  3214. CDmeSingleIndexedComponent *CDmeMesh::FeatherSelection(
  3215. float falloffDistance,
  3216. Falloff_t falloffType,
  3217. Distance_t distanceType,
  3218. CDmeSingleIndexedComponent *pSelection,
  3219. CDmMeshComp *pPassedMeshComp )
  3220. {
  3221. switch ( falloffType )
  3222. {
  3223. case SMOOTH:
  3224. return FeatherSelection< SMOOTH >( falloffDistance, distanceType, pSelection, pPassedMeshComp );
  3225. case SPIKE:
  3226. return FeatherSelection< SPIKE >( falloffDistance, distanceType, pSelection, pPassedMeshComp );
  3227. case DOME:
  3228. return FeatherSelection< DOME >( falloffDistance, distanceType, pSelection, pPassedMeshComp );
  3229. default:
  3230. return FeatherSelection< LINEAR >( falloffDistance, distanceType, pSelection, pPassedMeshComp );
  3231. }
  3232. }
  3233. //-----------------------------------------------------------------------------
  3234. //
  3235. //-----------------------------------------------------------------------------
  3236. template < int T >
  3237. CDmeSingleIndexedComponent *CDmeMesh::FeatherSelection(
  3238. float fDistance, Distance_t distanceType,
  3239. CDmeSingleIndexedComponent *pSelection, CDmMeshComp *pPassedMeshComp )
  3240. {
  3241. // TODO: Support feathering inward instead of just outward
  3242. if ( fDistance <= 0.0f || !pSelection )
  3243. return NULL;
  3244. // Make a new CDmeSingleIndexedComponent to do all of the dirty work
  3245. CDmeSingleIndexedComponent *pNewSelection = CreateElement< CDmeSingleIndexedComponent >( "feather", pSelection->GetFileId() );
  3246. pSelection->CopyAttributesTo( pNewSelection );
  3247. CDmMeshComp *pMeshComp = pPassedMeshComp ? pPassedMeshComp : new CDmMeshComp( this );
  3248. CDmeVertexData *pBase = pMeshComp->BaseState();
  3249. if ( distanceType == DIST_RELATIVE )
  3250. {
  3251. Vector vCenter;
  3252. float flRadius;
  3253. GetBoundingSphere( vCenter, flRadius, pBase, pSelection );
  3254. fDistance *= flRadius;
  3255. }
  3256. const CUtlVector< Vector > &positions( pBase->GetPositionData() );
  3257. const int nPositions = positions.Count();
  3258. if ( !pBase )
  3259. return NULL;
  3260. CUtlVector< int > sIndices;
  3261. int insideCount = 0;
  3262. CFalloff< T > falloff;
  3263. do
  3264. {
  3265. insideCount = 0;
  3266. CUtlVector< CDmMeshComp::CVert * > neighbours;
  3267. CSelectionHelper sHelper;
  3268. pNewSelection->GetComponents( sIndices );
  3269. int nVertices = sIndices.Count();
  3270. for ( int i = 0; i < nVertices; ++i )
  3271. {
  3272. const int nNeighbours = pMeshComp->FindNeighbouringVerts( sIndices[ i ], neighbours );
  3273. for ( int j = 0; j < nNeighbours; ++j )
  3274. {
  3275. const int vIndex = neighbours[ j ]->PositionIndex();
  3276. if ( pNewSelection->HasComponent( vIndex ) )
  3277. continue;
  3278. const int closestVert = ClosestSelectedVertex( vIndex, pSelection, pBase );
  3279. if ( closestVert < 0 || closestVert >= nPositions )
  3280. continue;
  3281. const float vDistance = positions[ vIndex ].DistTo( positions[ closestVert ] );
  3282. if ( vDistance <= fDistance )
  3283. {
  3284. sHelper.AddVert( vIndex, falloff( vDistance / fDistance ) );
  3285. ++insideCount;
  3286. }
  3287. }
  3288. }
  3289. sHelper.AddToSelection( pNewSelection );
  3290. } while ( insideCount > 0 );
  3291. return pNewSelection;
  3292. }
  3293. //-----------------------------------------------------------------------------
  3294. // Add the specified delta, scaled by the weight value to the DmeVertexData
  3295. // base state specified. Optionally the add can be masked by a specified
  3296. // weight map.
  3297. //
  3298. // If a DmeVertexData is not explicitly specified, the current state of the
  3299. // mesh is modified unless it's the bind state. The bind state will never
  3300. // be modified even if it is explicitly specified.
  3301. //
  3302. // Only the delta specified is added. No dependent states are added.
  3303. //-----------------------------------------------------------------------------
  3304. bool CDmeMesh::AddMaskedDelta(
  3305. CDmeVertexDeltaData *pDelta,
  3306. CDmeVertexData *pDst /* = NULL */,
  3307. float weight /* = 1.0f */,
  3308. const CDmeSingleIndexedComponent *pMask /* = NULL */ )
  3309. {
  3310. CDmeVertexData *pBase = pDst ? pDst : GetCurrentBaseState();
  3311. if ( !pBase || pBase == GetBindBaseState() )
  3312. return false;
  3313. bool retVal = true;
  3314. const int nBaseField( pBase->FieldCount() );
  3315. const int nDeltaField( pDelta->FieldCount() );
  3316. // Try to add every field of the base state
  3317. for ( int j( 0 ); j < nBaseField; ++j )
  3318. {
  3319. const CUtlString &baseFieldName( pBase->FieldName( j ) );
  3320. // Find the corresponding field in the delta
  3321. for ( int k( 0 ); k < nDeltaField; ++k )
  3322. {
  3323. const CUtlString &deltaFieldName( pDelta->FieldName( k ) );
  3324. if ( baseFieldName != deltaFieldName )
  3325. continue;
  3326. const FieldIndex_t baseFieldIndex( pBase->FindFieldIndex( baseFieldName ) );
  3327. const FieldIndex_t deltaFieldIndex( pDelta->FindFieldIndex( deltaFieldName ) );
  3328. if ( baseFieldIndex < 0 || deltaFieldIndex < 0 )
  3329. break;
  3330. CDmAttribute *pBaseData( pBase->GetVertexData( baseFieldIndex ) );
  3331. CDmAttribute *pDeltaData( pDelta->GetVertexData( deltaFieldIndex ) );
  3332. if ( pBaseData->GetType() != pDeltaData->GetType() )
  3333. break;
  3334. switch ( pBaseData->GetType() )
  3335. {
  3336. case AT_FLOAT_ARRAY:
  3337. AddRawDelta( pDelta, CDmrArray< float >( pBaseData ), baseFieldIndex, weight, pMask );
  3338. break;
  3339. case AT_COLOR_ARRAY:
  3340. // TODO: Color is missing some algebraic operators
  3341. // AddRawDelta( pDelta, CDmrArray< Color >( pBaseData ), baseFieldIndex, weight, pMask );
  3342. break;
  3343. case AT_VECTOR2_ARRAY:
  3344. AddRawDelta( pDelta, CDmrArray< Vector2D >( pBaseData ), baseFieldIndex, weight, pMask );
  3345. break;
  3346. case AT_VECTOR3_ARRAY:
  3347. AddRawDelta( pDelta, CDmrArray< Vector >( pBaseData ), baseFieldIndex, weight, pMask );
  3348. break;
  3349. default:
  3350. break;
  3351. }
  3352. break;
  3353. }
  3354. }
  3355. return retVal;
  3356. }
  3357. //-----------------------------------------------------------------------------
  3358. // Add the specified delta, scaled by the weight value to the DmeVertexData
  3359. // base state specified. Optionally the add can be masked by a specified
  3360. // weight map.
  3361. //
  3362. // If a DmeVertexData is not explicitly specified, the current state of the
  3363. // mesh is modified unless it's the bind state. The bind state will never
  3364. // be modified even if it is explicitly specified.
  3365. //
  3366. // Only the delta specified is added. No dependent states are added.
  3367. //-----------------------------------------------------------------------------
  3368. bool CDmeMesh::AddCorrectedMaskedDelta(
  3369. CDmeVertexDeltaData *pDelta,
  3370. CDmeVertexData *pDst /* = NULL */,
  3371. float weight /* = 1.0f */,
  3372. const CDmeSingleIndexedComponent *pMask /* = NULL */ )
  3373. {
  3374. CDmeVertexData *pBase = pDst ? pDst : GetCurrentBaseState();
  3375. if ( !pBase || pBase == GetBindBaseState() )
  3376. return false;
  3377. bool retVal = true;
  3378. const int nBaseField( pBase->FieldCount() );
  3379. const int nDeltaField( pDelta->FieldCount() );
  3380. // This should be cached and recomputed only when states are added
  3381. CUtlVector< DeltaComputation_t > compList;
  3382. ComputeDependentDeltaStateList( compList );
  3383. const int nDeltas( compList.Count() );
  3384. for ( int i = 0; i < nDeltas; ++i )
  3385. {
  3386. if ( pDelta != GetDeltaState( compList[ i ].m_nDeltaIndex ) )
  3387. continue;
  3388. // Try to add every field of the base state
  3389. for ( int j( 0 ); j < nBaseField; ++j )
  3390. {
  3391. const CUtlString &baseFieldName( pBase->FieldName( j ) );
  3392. // Find the corresponding field in the delta
  3393. for ( int k( 0 ); k < nDeltaField; ++k )
  3394. {
  3395. const CUtlString &deltaFieldName( pDelta->FieldName( k ) );
  3396. if ( baseFieldName != deltaFieldName )
  3397. continue;
  3398. const FieldIndex_t baseFieldIndex( pBase->FindFieldIndex( baseFieldName ) );
  3399. const FieldIndex_t deltaFieldIndex( pDelta->FindFieldIndex( deltaFieldName ) );
  3400. if ( baseFieldIndex < 0 || deltaFieldIndex < 0 )
  3401. break;
  3402. CDmAttribute *pBaseData( pBase->GetVertexData( baseFieldIndex ) );
  3403. CDmAttribute *pDeltaData( pDelta->GetVertexData( deltaFieldIndex ) );
  3404. if ( pBaseData->GetType() != pDeltaData->GetType() )
  3405. break;
  3406. const CUtlVector< int > &baseIndices( pBase->GetVertexIndexData( baseFieldIndex ) );
  3407. switch ( pBaseData->GetType() )
  3408. {
  3409. case AT_FLOAT_ARRAY:
  3410. AddCorrectedDelta( CDmrArray< float >( pBaseData ), baseIndices, compList[ i ], baseFieldName, weight, pMask );
  3411. break;
  3412. case AT_COLOR_ARRAY:
  3413. AddCorrectedDelta( CDmrArray< Vector >( pBaseData ), baseIndices, compList[ i ], baseFieldName, weight, pMask );
  3414. break;
  3415. case AT_VECTOR2_ARRAY:
  3416. AddCorrectedDelta( CDmrArray< Vector2D >( pBaseData ), baseIndices, compList[ i ], baseFieldName, weight, pMask );
  3417. break;
  3418. case AT_VECTOR3_ARRAY:
  3419. AddCorrectedDelta( CDmrArray< Vector >( pBaseData ), baseIndices, compList[ i ], baseFieldName, weight, pMask );
  3420. break;
  3421. default:
  3422. break;
  3423. }
  3424. break;
  3425. }
  3426. }
  3427. }
  3428. return retVal;
  3429. }
  3430. //-----------------------------------------------------------------------------
  3431. // Interpolates between two arrays of values and stores the result in a
  3432. // CDmrArray.
  3433. //
  3434. // result = ( ( 1 - weight ) * a ) + ( weight * b )
  3435. //
  3436. //-----------------------------------------------------------------------------
  3437. template< class T_t >
  3438. bool CDmeMesh::InterpMaskedData(
  3439. CDmrArray< T_t > &aData,
  3440. const CUtlVector< T_t > &bData,
  3441. float weight,
  3442. const CDmeSingleIndexedComponent *pMask ) const
  3443. {
  3444. const int nDst = aData.Count();
  3445. if ( bData.Count() != nDst )
  3446. return false;
  3447. // The wacky way of writing these expression is because Vector4D is missing operators
  3448. // And this probably works better because of fewer temporaries
  3449. T_t a;
  3450. T_t b;
  3451. if ( pMask )
  3452. {
  3453. // With a weight mask
  3454. float vWeight;
  3455. for ( int i = 0; i < nDst; ++i )
  3456. {
  3457. if ( pMask->GetWeight( i, vWeight ) )
  3458. {
  3459. vWeight *= weight; // Specifically not clamping
  3460. a = aData.Get( i );
  3461. a *= ( 1.0f - vWeight );
  3462. b = bData[ i ];
  3463. b *= vWeight;
  3464. b += a;
  3465. aData.Set( i, b );
  3466. }
  3467. }
  3468. }
  3469. else
  3470. {
  3471. // Without a weight mask
  3472. const float oneMinusWeight( 1.0f - weight );
  3473. for ( int i = 0; i < nDst; ++i )
  3474. {
  3475. a = aData.Get( i );
  3476. a *= oneMinusWeight;
  3477. b = bData[ i ];
  3478. b *= weight;
  3479. b += a;
  3480. aData.Set( i, b );
  3481. }
  3482. }
  3483. return true;
  3484. }
  3485. //-----------------------------------------------------------------------------
  3486. // Interpolates between two CDmeVertexData's
  3487. //
  3488. // paData = ( ( 1 - weight ) * a ) + ( weight * b )
  3489. //-----------------------------------------------------------------------------
  3490. bool CDmeMesh::InterpMaskedData(
  3491. CDmeVertexData *paData,
  3492. const CDmeVertexData *pbData,
  3493. float weight,
  3494. const CDmeSingleIndexedComponent *pMask ) const
  3495. {
  3496. if ( !paData || !pbData || paData == pbData )
  3497. return false;
  3498. const int naField = paData->FieldCount();
  3499. const int nbField = pbData->FieldCount();
  3500. for ( int i = 0; i < naField; ++i )
  3501. {
  3502. const CUtlString &aFieldName( paData->FieldName( i ) );
  3503. for ( int j = 0; j < nbField; ++j )
  3504. {
  3505. const CUtlString &bFieldName( pbData->FieldName( j ) );
  3506. if ( aFieldName != bFieldName )
  3507. continue;
  3508. const FieldIndex_t aFieldIndex( paData->FindFieldIndex( aFieldName ) );
  3509. const FieldIndex_t bFieldIndex( pbData->FindFieldIndex( bFieldName ) );
  3510. if ( aFieldIndex < 0 || bFieldIndex < 0 )
  3511. break;
  3512. CDmAttribute *paAttr( paData->GetVertexData( aFieldIndex ) );
  3513. const CDmAttribute *pbAttr( pbData->GetVertexData( bFieldIndex ) );
  3514. if ( paAttr->GetType() != pbAttr->GetType() )
  3515. break;
  3516. if ( paData->GetVertexIndexData( aFieldIndex ).Count() != pbData->GetVertexIndexData( bFieldIndex ).Count() )
  3517. break;
  3518. switch ( paAttr->GetType() )
  3519. {
  3520. case AT_FLOAT_ARRAY:
  3521. InterpMaskedData( CDmrArray< float >( paAttr ), CDmrArrayConst< float >( pbAttr ).Get(), weight, pMask );
  3522. break;
  3523. case AT_COLOR_ARRAY:
  3524. InterpMaskedData( CDmrArray< Vector4D >( paAttr ), CDmrArrayConst< Vector4D >( pbAttr ).Get(), weight, pMask );
  3525. break;
  3526. case AT_VECTOR2_ARRAY:
  3527. InterpMaskedData( CDmrArray< Vector2D >( paAttr ), CDmrArrayConst< Vector2D >( pbAttr ).Get(), weight, pMask );
  3528. break;
  3529. case AT_VECTOR3_ARRAY:
  3530. InterpMaskedData( CDmrArray< Vector >( paAttr ), CDmrArrayConst< Vector >( pbAttr ).Get(), weight, pMask );
  3531. break;
  3532. default:
  3533. break;
  3534. }
  3535. break;
  3536. }
  3537. }
  3538. return true;
  3539. }
  3540. //-----------------------------------------------------------------------------
  3541. // Interpolates between the specified VertexData and the specified Delta
  3542. // If pBase is NULL it will become the current state
  3543. // If pDelta is NULL then the state to interpolate to will be the bind state
  3544. //-----------------------------------------------------------------------------
  3545. bool CDmeMesh::InterpMaskedDelta(
  3546. CDmeVertexDeltaData *pDelta,
  3547. CDmeVertexData *pDst /* = NULL */,
  3548. float weight /*= 1.0f */,
  3549. const CDmeSingleIndexedComponent *pMask /*= NULL */ )
  3550. {
  3551. CDmeVertexData *pDstBase = pDst ? pDst : GetCurrentBaseState();
  3552. CDmeVertexData *pBind = GetBindBaseState();
  3553. if ( !pDstBase || !pBind || pDstBase == pBind )
  3554. return false;
  3555. if ( pDelta == NULL )
  3556. {
  3557. // Interpolate between specified state and bind state
  3558. return InterpMaskedData( pDstBase, pBind, weight, pMask );
  3559. }
  3560. // This should be cached and recomputed only when states are added
  3561. CUtlVector< DeltaComputation_t > compList;
  3562. ComputeDependentDeltaStateList( compList );
  3563. bool retVal = false;
  3564. const int nDeltas( compList.Count() );
  3565. for ( int i = 0; i < nDeltas; ++i )
  3566. {
  3567. if ( pDelta != GetDeltaState( compList[ i ].m_nDeltaIndex ) )
  3568. continue;
  3569. retVal = true;
  3570. const int nBaseField( pDstBase->FieldCount() );
  3571. const int nBindField( pBind->FieldCount() );
  3572. const int nDeltaField( pDelta->FieldCount() );
  3573. CUtlVector< float > floatData;
  3574. CUtlVector< Vector2D > vector2DData;
  3575. CUtlVector< Vector > vectorData;
  3576. CUtlVector< Vector4D > vector4DData;
  3577. for ( int j( 0 ); j < nBaseField; ++j )
  3578. {
  3579. const CUtlString &baseFieldName( pDstBase->FieldName( j ) );
  3580. for ( int k = 0; k < nBindField; ++k )
  3581. {
  3582. const CUtlString &bindFieldName( pBind->FieldName( k ) );
  3583. if ( baseFieldName != bindFieldName )
  3584. continue;
  3585. for ( int l = 0; l < nDeltaField; ++l )
  3586. {
  3587. const CUtlString &deltaFieldName( pDelta->FieldName( l ) );
  3588. if ( bindFieldName != deltaFieldName )
  3589. continue;
  3590. const FieldIndex_t baseFieldIndex( pDstBase->FindFieldIndex( baseFieldName ) );
  3591. const FieldIndex_t bindFieldIndex( pBind->FindFieldIndex( bindFieldName ) );
  3592. const FieldIndex_t deltaFieldIndex( pDelta->FindFieldIndex( deltaFieldName ) );
  3593. if ( baseFieldIndex < 0 || bindFieldIndex < 0 || deltaFieldIndex < 0 )
  3594. break;
  3595. CDmAttribute *pDstBaseData( pDstBase->GetVertexData( baseFieldIndex ) );
  3596. CDmAttribute *pBindData( pBind->GetVertexData( bindFieldIndex ) );
  3597. CDmAttribute *pDeltaData( pDelta->GetVertexData( deltaFieldIndex ) );
  3598. if ( pDstBaseData->GetType() != pBindData->GetType() || pBindData->GetType() != pDeltaData->GetType() )
  3599. break;
  3600. const CUtlVector< int > &bindIndices( pBind->GetVertexIndexData( bindFieldIndex ) );
  3601. switch ( pDstBaseData->GetType() )
  3602. {
  3603. case AT_FLOAT_ARRAY:
  3604. floatData = CDmrArrayConst< float >( pBindData ).Get();
  3605. AddCorrectedDelta( floatData, bindIndices, compList[ i ], baseFieldName );
  3606. InterpMaskedData( CDmrArray< float >( pDstBaseData ), floatData, weight, pMask );
  3607. break;
  3608. case AT_COLOR_ARRAY:
  3609. vector4DData = CDmrArrayConst< Vector4D >( pBindData ).Get();
  3610. AddCorrectedDelta( vector4DData, bindIndices, compList[ i ], baseFieldName );
  3611. InterpMaskedData( CDmrArray< Vector4D >( pDstBaseData ), vector4DData, weight, pMask );
  3612. break;
  3613. case AT_VECTOR2_ARRAY:
  3614. vector2DData = CDmrArrayConst< Vector2D >( pBindData ).Get();
  3615. AddCorrectedDelta( vector2DData, bindIndices, compList[ i ], baseFieldName );
  3616. InterpMaskedData( CDmrArray< Vector2D >( pDstBaseData ), vector2DData, weight, pMask );
  3617. break;
  3618. case AT_VECTOR3_ARRAY:
  3619. vectorData = CDmrArrayConst< Vector >( pBindData ).Get();
  3620. AddCorrectedDelta( vectorData, bindIndices, compList[ i ], baseFieldName );
  3621. InterpMaskedData( CDmrArray< Vector >( pDstBaseData ), vectorData, weight, pMask );
  3622. break;
  3623. default:
  3624. break;
  3625. }
  3626. break;
  3627. }
  3628. }
  3629. }
  3630. }
  3631. return retVal;
  3632. }
  3633. //-----------------------------------------------------------------------------
  3634. // Returns the index of the closest selected vertex in the mesh to vIndex
  3635. // -1 on failure
  3636. //-----------------------------------------------------------------------------
  3637. int CDmeMesh::ClosestSelectedVertex( int vIndex, CDmeSingleIndexedComponent *pSelection, const CDmeVertexData *pPassedBase /* = NULL */ ) const
  3638. {
  3639. const CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  3640. if ( !pBase )
  3641. return -1;
  3642. const CUtlVector< Vector > &positions( pBase->GetPositionData() );
  3643. if ( vIndex >= positions.Count() )
  3644. return -1;
  3645. const Vector &p( positions[ vIndex ] );
  3646. CUtlVector< int > verts;
  3647. pSelection->GetComponents( verts );
  3648. const int nVerts = verts.Count();
  3649. if ( nVerts <= 0 )
  3650. return -1;
  3651. float minSqDist = p.DistToSqr( positions[ verts[ 0 ] ] );
  3652. float tmpSqDist;
  3653. int retVal = verts[ 0 ];
  3654. for ( int i = 1; i < nVerts; ++i )
  3655. {
  3656. tmpSqDist = p.DistToSqr( positions[ verts[ i ] ] );
  3657. if ( tmpSqDist < minSqDist )
  3658. {
  3659. minSqDist = tmpSqDist;
  3660. retVal = verts[ i ];
  3661. }
  3662. }
  3663. return retVal;
  3664. }
  3665. //-----------------------------------------------------------------------------
  3666. //
  3667. //-----------------------------------------------------------------------------
  3668. float CDmeMesh::DistanceBetween( int vIndex0, int vIndex1, const CDmeVertexData *pPassedBase /*= NULL */ ) const
  3669. {
  3670. const CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  3671. if ( !pBase )
  3672. return 0.0f;
  3673. const CUtlVector< Vector > &positions( pBase->GetPositionData() );
  3674. const int nPositions = positions.Count();
  3675. if ( vIndex0 >= nPositions || vIndex1 >= nPositions )
  3676. return 0.0f;
  3677. return positions[ vIndex0 ].DistTo( positions[ vIndex1 ] );
  3678. }
  3679. //-----------------------------------------------------------------------------
  3680. // Sorts DeltaComputation_t's by dimensionality
  3681. //-----------------------------------------------------------------------------
  3682. int ControlIndexLessFunc( const void *lhs, const void *rhs )
  3683. {
  3684. const int &lVal = *reinterpret_cast< const int * >( lhs );
  3685. const int &rVal = *reinterpret_cast< const int * >( rhs );
  3686. return lVal - rVal;
  3687. }
  3688. //-----------------------------------------------------------------------------
  3689. // This will compute a list of delta states that are superior to the passed
  3690. // delta state name (which has the form of <NAME>[_<NAME>]..., i.e. controls
  3691. // separated by underscores. The states will be returned in order from
  3692. // most superior to least superior. Since the deltas need to be broken down
  3693. // by the control deltas, if any control delta doesn't exist it will return false.
  3694. //
  3695. // A superior delta state is defined as a delta which has this delta as
  3696. // a dependent (or inferior) delta.
  3697. //
  3698. // Given the network of:
  3699. //
  3700. // A, B, C
  3701. // A_B, A_C, B_C
  3702. // A_B_C
  3703. //
  3704. // A_B_C is superior to A, B, A_B, A_C & B_C
  3705. // A_B is superior to A, B & C
  3706. // A_C is superior to A, B & C
  3707. // B_C is superior to A, B & C
  3708. //
  3709. // Input Output
  3710. // ------- --------------------
  3711. // A A_B_C, A_B, A_C, B_C
  3712. // B A_B_C, A_B, A_C, B_C
  3713. // C A_B_C, A_B, A_C, B_C
  3714. // A_B A_B_C
  3715. // A_C A_B_C
  3716. // B_C A_B_C
  3717. // A_B_C
  3718. //-----------------------------------------------------------------------------
  3719. bool CDmeMesh::ComputeSuperiorDeltaStateList( const char *pInferiorDeltaName, CUtlVector< int > &superiorDeltaStates )
  3720. {
  3721. // TODO: Compute this data only when the deltas are added, removed or renamed
  3722. CUtlVector< DeltaComputation_t > compList;
  3723. ComputeDeltaStateComputationList( compList );
  3724. // Typically the passed delta won't be in the list yet, but it could be, that's ok
  3725. // Treat it like it isn't to be sure.
  3726. CUtlVector< int > inferiorIndices;
  3727. if ( !GetControlDeltaIndices( pInferiorDeltaName, inferiorIndices ) )
  3728. return false;
  3729. const int nInferiorIndices = inferiorIndices.Count();
  3730. qsort( inferiorIndices.Base(), nInferiorIndices, sizeof( int ), ControlIndexLessFunc );
  3731. CUtlVector< int > superiorIndices;
  3732. int nSuperiorIndices;
  3733. CDmeVertexDeltaData *pSuperiorDelta;
  3734. for ( int i = compList.Count() - 1; i >= 0; --i )
  3735. {
  3736. const DeltaComputation_t &deltaComp = compList[ i ];
  3737. // For a delta to be superior, it has to have more control inputs than the specified delta
  3738. // compList is sorted in order of dimensionality, so safe to abort
  3739. if ( nInferiorIndices >= deltaComp.m_nDimensionality )
  3740. break;
  3741. pSuperiorDelta = GetDeltaState( deltaComp.m_nDeltaIndex );
  3742. if ( !pSuperiorDelta )
  3743. continue;
  3744. if ( !GetControlDeltaIndices( pSuperiorDelta, superiorIndices ) )
  3745. continue;
  3746. nSuperiorIndices = superiorIndices.Count();
  3747. qsort( superiorIndices.Base(), nSuperiorIndices, sizeof( int ), ControlIndexLessFunc );
  3748. int nFound = 0;
  3749. int si = 0;
  3750. for ( int ii = 0; ii < nInferiorIndices; ++ii )
  3751. {
  3752. const int &iIndex = inferiorIndices[ ii ];
  3753. while ( si < nSuperiorIndices && iIndex != superiorIndices[ si ] )
  3754. {
  3755. ++si;
  3756. }
  3757. if ( si < nSuperiorIndices )
  3758. {
  3759. ++nFound;
  3760. }
  3761. }
  3762. if ( nFound == nInferiorIndices )
  3763. {
  3764. superiorDeltaStates.AddToTail( deltaComp.m_nDeltaIndex );
  3765. }
  3766. }
  3767. return true;
  3768. }
  3769. //-----------------------------------------------------------------------------
  3770. // Removes the passed base state from the list of base states in the mesh
  3771. // if it exists in the list of base states in the mesh, but doesn't delete
  3772. // the element itself
  3773. //-----------------------------------------------------------------------------
  3774. bool CDmeMesh::RemoveBaseState( CDmeVertexData *pBase )
  3775. {
  3776. const int nBaseStates = m_BaseStates.Count();
  3777. for ( int i = 0; i < nBaseStates; ++i )
  3778. {
  3779. CDmeVertexData *pTmpBase = m_BaseStates[ i ];
  3780. if ( pTmpBase == pBase )
  3781. {
  3782. m_BaseStates.Remove( i );
  3783. return true;
  3784. }
  3785. }
  3786. return false;
  3787. }
  3788. //-----------------------------------------------------------------------------
  3789. // Adds an existing element to the list of base states of the mesh if it
  3790. // isn't already one of the base states
  3791. //-----------------------------------------------------------------------------
  3792. CDmeVertexData *CDmeMesh::FindOrAddBaseState( CDmeVertexData *pBase )
  3793. {
  3794. const int nBaseStates = m_BaseStates.Count();
  3795. for ( int i = 0; i < nBaseStates; ++i )
  3796. {
  3797. if ( m_BaseStates[ i ] == pBase )
  3798. {
  3799. return pBase;
  3800. }
  3801. }
  3802. return m_BaseStates[ m_BaseStates.AddToTail( pBase ) ];
  3803. }
  3804. //-----------------------------------------------------------------------------
  3805. // TODO: Current state is insufficient as long as the current state isn't
  3806. // created from the current delta weights
  3807. //-----------------------------------------------------------------------------
  3808. void CDmeMesh::GetBoundingSphere(
  3809. Vector &c, float &r,
  3810. CDmeVertexData *pPassedBase /* = NULL */, CDmeSingleIndexedComponent *pPassedSelection /* = NULL */ ) const
  3811. {
  3812. c.Zero();
  3813. r = 0.0f;
  3814. const CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  3815. if ( !pBase )
  3816. return;
  3817. const FieldIndex_t pIndex = pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  3818. if ( pIndex < 0 )
  3819. return;
  3820. const CUtlVector< Vector > &pData( pBase->GetPositionData() );
  3821. const int nPositions = pData.Count();
  3822. if ( pPassedSelection )
  3823. {
  3824. const int nSelectionCount = pPassedSelection->Count();
  3825. int nIndex;
  3826. float fWeight;
  3827. for ( int i = 0; i < nSelectionCount; ++i )
  3828. {
  3829. pPassedSelection->GetComponent( i, nIndex, fWeight );
  3830. c += pData[ nIndex ];
  3831. }
  3832. c /= static_cast< float >( nSelectionCount );
  3833. float sqDist;
  3834. for ( int i = 0; i < nSelectionCount; ++i )
  3835. {
  3836. for ( int i = 0; i < nPositions; ++i )
  3837. {
  3838. sqDist = c.DistToSqr( pData[ i ] );
  3839. if ( sqDist > r )
  3840. {
  3841. r = sqDist;
  3842. }
  3843. }
  3844. }
  3845. }
  3846. else
  3847. {
  3848. for ( int i = 0; i < nPositions; ++i )
  3849. {
  3850. c += pData[ i ];
  3851. }
  3852. c /= static_cast< float >( nPositions );
  3853. float sqDist;
  3854. for ( int i = 0; i < nPositions; ++i )
  3855. {
  3856. for ( int i = 0; i < nPositions; ++i )
  3857. {
  3858. sqDist = c.DistToSqr( pData[ i ] );
  3859. if ( sqDist > r )
  3860. {
  3861. r = sqDist;
  3862. }
  3863. }
  3864. }
  3865. }
  3866. r = sqrt( r );
  3867. }
  3868. //-----------------------------------------------------------------------------
  3869. //
  3870. //-----------------------------------------------------------------------------
  3871. void CDmeMesh::GetBoundingBox( Vector &min, Vector &max, CDmeVertexData *pPassedBase /* = NULL */, CDmeSingleIndexedComponent *pPassedSelection /* = NULL */ ) const
  3872. {
  3873. min.Zero();
  3874. max.Zero();
  3875. const CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  3876. if ( !pBase )
  3877. return;
  3878. const FieldIndex_t pIndex = pBase->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  3879. if ( pIndex < 0 )
  3880. return;
  3881. const CUtlVector< Vector > &pData( pBase->GetPositionData() );
  3882. const int nPositions = pData.Count();
  3883. if ( pPassedSelection )
  3884. {
  3885. const int nSelectionCount = pPassedSelection->Count();
  3886. if ( nSelectionCount > 0 )
  3887. {
  3888. int nIndex;
  3889. float fWeight;
  3890. pPassedSelection->GetComponent( 0, nIndex, fWeight );
  3891. min = pData[ nIndex ];
  3892. max = min;
  3893. for ( int i = 1; i < nSelectionCount; ++i )
  3894. {
  3895. pPassedSelection->GetComponent( i, nIndex, fWeight );
  3896. const Vector &p = pData[ nIndex ];
  3897. if ( p.x < min.x )
  3898. {
  3899. min.x = p.x;
  3900. }
  3901. else if ( p.x > max.x )
  3902. {
  3903. max.x = p.x;
  3904. }
  3905. if ( p.y < min.y )
  3906. {
  3907. min.y = p.y;
  3908. }
  3909. else if ( p.y > max.y )
  3910. {
  3911. max.y = p.y;
  3912. }
  3913. if ( p.z < min.z )
  3914. {
  3915. min.z = p.z;
  3916. }
  3917. else if ( p.z > max.z )
  3918. {
  3919. max.z = p.z;
  3920. }
  3921. }
  3922. }
  3923. }
  3924. else
  3925. {
  3926. if ( nPositions > 0 )
  3927. {
  3928. min = pData[ 0 ];
  3929. max = min;
  3930. for ( int i = 1; i < nPositions; ++i )
  3931. {
  3932. const Vector &p = pData[ i ];
  3933. if ( p.x < min.x )
  3934. {
  3935. min.x = p.x;
  3936. }
  3937. else if ( p.x > max.x )
  3938. {
  3939. max.x = p.x;
  3940. }
  3941. if ( p.y < min.y )
  3942. {
  3943. min.y = p.y;
  3944. }
  3945. else if ( p.y > max.y )
  3946. {
  3947. max.y = p.y;
  3948. }
  3949. if ( p.z < min.z )
  3950. {
  3951. min.z = p.z;
  3952. }
  3953. else if ( p.z > max.z )
  3954. {
  3955. max.z = p.z;
  3956. }
  3957. }
  3958. }
  3959. }
  3960. }
  3961. //-----------------------------------------------------------------------------
  3962. //
  3963. //-----------------------------------------------------------------------------
  3964. template < class T_t >
  3965. bool CDmeMesh::SetBaseDataToDeltas(
  3966. CDmeVertexData *pBase,
  3967. CDmeVertexData::StandardFields_t nStandardField, CDmrArrayConst< T_t > &srcData, CDmrArray< T_t > &dstData, bool bDoStereo, bool bDoLag )
  3968. {
  3969. const int nDataCount = dstData.Count();
  3970. if ( srcData.Count() != nDataCount )
  3971. return false;
  3972. // Create the temp buffer for the data
  3973. T_t *pData = reinterpret_cast< T_t * >( alloca( nDataCount * sizeof( T_t ) ) );
  3974. // Copy the data from the src base state
  3975. memcpy( pData, srcData.Base(), nDataCount * sizeof( T_t ) );
  3976. const int nCount = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL].Count();
  3977. Assert( m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL].Count() == m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED].Count() );
  3978. if ( bDoStereo )
  3979. {
  3980. for ( int i = 0; i < nCount; ++i )
  3981. {
  3982. float flLeftWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].x;
  3983. float flRightWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].y;
  3984. float flLeftWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].x;
  3985. float flRightWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].y;
  3986. if ( flLeftWeight <= 0.0f && flRightWeight <= 0.0f && ( !bDoLag || ( flLeftWeightLagged <= 0.0f && flRightWeightLagged <= 0.0f ) ) )
  3987. continue;
  3988. AddStereoVertexDelta< T_t >( pBase, pData, sizeof( T_t ), nStandardField, i, bDoLag );
  3989. }
  3990. }
  3991. else
  3992. {
  3993. for ( int i = 0; i < nCount; ++i )
  3994. {
  3995. float flWeight = m_DeltaStateWeights[MESH_DELTA_WEIGHT_NORMAL][i].x;
  3996. float flWeightLagged = m_DeltaStateWeights[MESH_DELTA_WEIGHT_LAGGED][i].x;
  3997. if ( flWeight < 0.0f && ( !bDoLag || flWeightLagged <= 0.0f ) )
  3998. continue;
  3999. AddVertexDelta< T_t >( pBase, pData, sizeof( T_t ), nStandardField, i, bDoLag );
  4000. }
  4001. }
  4002. dstData.SetMultiple( 0, nDataCount, pData );
  4003. return true;
  4004. }
  4005. //-----------------------------------------------------------------------------
  4006. // Sets the specified based state to the version of the mesh specified by the
  4007. // current weighted deltas
  4008. // It's ok to modify the bind state... if you know what you're doing
  4009. //-----------------------------------------------------------------------------
  4010. bool CDmeMesh::SetBaseStateToDeltas( CDmeVertexData *pPassedBase /*= NULL */ )
  4011. {
  4012. CDmeVertexData *pBind = GetBindBaseState();
  4013. CDmeVertexData *pBase = pPassedBase ? pPassedBase : GetCurrentBaseState();
  4014. if ( !pBind || !pBase )
  4015. return false;
  4016. CDmeVertexData::StandardFields_t deltaFields[] =
  4017. {
  4018. CDmeVertexData::FIELD_POSITION,
  4019. CDmeVertexData::FIELD_NORMAL,
  4020. CDmeVertexData::FIELD_WRINKLE
  4021. };
  4022. const bool bDoStereo = ( pBind->FindFieldIndex( CDmeVertexDeltaData::FIELD_BALANCE ) >= 0 );
  4023. for ( int i = 0; i < sizeof( deltaFields ) / sizeof( deltaFields[ 0 ] ); ++i )
  4024. {
  4025. const CDmeVertexDeltaData::StandardFields_t nStandardField = deltaFields[ i ];
  4026. const int nSrcField = pBind->FindFieldIndex( nStandardField );
  4027. const int nDstField = pBase->FindFieldIndex( nStandardField );
  4028. if ( nSrcField < 0 || nDstField < 0 )
  4029. continue;
  4030. const CDmAttribute *pSrcAttr = pBind->GetVertexData( nSrcField );
  4031. CDmAttribute *pDstAttr = pBase->GetVertexData( nDstField );
  4032. if ( !pSrcAttr || !pDstAttr || pSrcAttr->GetType() != pDstAttr->GetType() )
  4033. continue;
  4034. switch ( pDstAttr->GetType() )
  4035. {
  4036. case AT_FLOAT_ARRAY:
  4037. SetBaseDataToDeltas( pBind, nStandardField, CDmrArrayConst< float >( pSrcAttr ), CDmrArray< float >( pDstAttr ), bDoStereo, false );
  4038. break;
  4039. case AT_VECTOR3_ARRAY:
  4040. SetBaseDataToDeltas( pBind, nStandardField, CDmrArrayConst< Vector >( pSrcAttr ), CDmrArray< Vector >( pDstAttr ), bDoStereo, false );
  4041. break;
  4042. default:
  4043. Assert( 0 );
  4044. break;
  4045. }
  4046. }
  4047. return true;
  4048. }
  4049. //-----------------------------------------------------------------------------
  4050. // Replace all instances of a material with a different material
  4051. //-----------------------------------------------------------------------------
  4052. void CDmeMesh::ReplaceMaterial( const char *pOldMaterialName, const char *pNewMaterialName )
  4053. {
  4054. char pOldFixedName[MAX_PATH];
  4055. char pNewFixedName[MAX_PATH];
  4056. char pFixedName[MAX_PATH];
  4057. if ( pOldMaterialName )
  4058. {
  4059. Q_FixupPathName( pOldFixedName, sizeof(pOldFixedName), pOldMaterialName );
  4060. }
  4061. Q_FixupPathName( pNewFixedName, sizeof(pNewFixedName), pNewMaterialName );
  4062. CDmeMaterial *pReplacementMaterial = NULL;
  4063. int nCount = m_FaceSets.Count();
  4064. for ( int i = 0; i < nCount; ++i )
  4065. {
  4066. CDmeFaceSet *pFaceSet = m_FaceSets[i];
  4067. CDmeMaterial *pMaterial = pFaceSet->GetMaterial();
  4068. if ( pOldMaterialName )
  4069. {
  4070. const char *pMaterialName = pMaterial->GetMaterialName();
  4071. Q_FixupPathName( pFixedName, sizeof(pFixedName), pMaterialName );
  4072. if ( Q_stricmp( pFixedName, pOldFixedName ) )
  4073. continue;
  4074. }
  4075. if ( !pReplacementMaterial )
  4076. {
  4077. pReplacementMaterial = CreateElement< CDmeMaterial >( pMaterial->GetName(), pMaterial->GetFileId() );
  4078. pReplacementMaterial->SetMaterial( pNewFixedName );
  4079. }
  4080. pFaceSet->SetMaterial( pReplacementMaterial );
  4081. }
  4082. }
  4083. //-----------------------------------------------------------------------------
  4084. // Reskins the mesh to new bones
  4085. // The joint index remap maps an initial bone index to a new bone index
  4086. //-----------------------------------------------------------------------------
  4087. void CDmeMesh::Reskin( const int *pJointTransformIndexRemap )
  4088. {
  4089. CleanupHWMesh();
  4090. int nCount = m_BaseStates.Count();
  4091. for ( int i = 0; i < nCount; ++i )
  4092. {
  4093. m_BaseStates[i]->Reskin( pJointTransformIndexRemap );
  4094. }
  4095. }
  4096. //-----------------------------------------------------------------------------
  4097. // Cleans up delta data that is referring to normals which have been merged out
  4098. //-----------------------------------------------------------------------------
  4099. static void CollapseRedundantDeltaNormals( CDmeVertexDeltaData *pDmeDelta, const CUtlVector< int > &normalMap )
  4100. {
  4101. if ( !pDmeDelta )
  4102. return;
  4103. FieldIndex_t nNormalFieldIndex = pDmeDelta->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  4104. if ( nNormalFieldIndex < 0 )
  4105. return; // No normal deltas
  4106. const CUtlVector< Vector > &oldNormalData = pDmeDelta->GetNormalData();
  4107. const CUtlVector< int > &oldNormalIndices = pDmeDelta->GetVertexIndexData( nNormalFieldIndex );
  4108. Assert( oldNormalData.Count() == oldNormalIndices.Count() );
  4109. CUtlVector< bool > done;
  4110. done.SetCount( normalMap.Count() );
  4111. Q_memset( done.Base(), 0, done.Count() * sizeof( bool ) );
  4112. CUtlVector< Vector > newNormalData;
  4113. CUtlVector< int > newNormalIndices;
  4114. for ( int i = 0; i < oldNormalIndices.Count(); ++i )
  4115. {
  4116. const int nNewIndex = normalMap[ oldNormalIndices[i] ];
  4117. if ( nNewIndex < 0 || done[ nNewIndex ] )
  4118. continue;
  4119. done[ nNewIndex ] = true;
  4120. newNormalData.AddToTail( oldNormalData[i] );
  4121. newNormalIndices.AddToTail( nNewIndex );
  4122. }
  4123. pDmeDelta->RemoveAllVertexData( nNormalFieldIndex );
  4124. nNormalFieldIndex = pDmeDelta->CreateField( CDmeVertexDeltaData::FIELD_NORMAL );
  4125. pDmeDelta->AddVertexData( nNormalFieldIndex, newNormalData.Count() );
  4126. pDmeDelta->SetVertexData( nNormalFieldIndex, 0, newNormalData.Count(), AT_VECTOR3, newNormalData.Base() );
  4127. pDmeDelta->SetVertexIndices( nNormalFieldIndex, 0, newNormalIndices.Count(), newNormalIndices.Base() );
  4128. }
  4129. //-----------------------------------------------------------------------------
  4130. // Remove redundant normals from a DMX Mesh
  4131. // Looks at all of the normals around each position vertex and merges normals
  4132. // which are numerically similar (within flNormalBlend which by default in
  4133. // studiomdl is within 2 degrees) around that vertex
  4134. //
  4135. // If this would result in more normals being created, then don't do anything
  4136. // return false.
  4137. //-----------------------------------------------------------------------------
  4138. static bool CollapseRedundantBaseNormals( CDmeVertexData *pDmeVertexData, CUtlVector< int > &normalMap, float flNormalBlend )
  4139. {
  4140. if ( !pDmeVertexData )
  4141. return false;
  4142. FieldIndex_t nPositionFieldIndex = pDmeVertexData->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  4143. FieldIndex_t nNormalFieldIndex = pDmeVertexData->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  4144. if ( nPositionFieldIndex < 0 || nNormalFieldIndex < 0 )
  4145. return false;
  4146. const CUtlVector< Vector > &oldNormalData = pDmeVertexData->GetNormalData();
  4147. const CUtlVector< int > &oldNormalIndices = pDmeVertexData->GetVertexIndexData( nNormalFieldIndex );
  4148. CUtlVector< Vector > newNormalData;
  4149. CUtlVector< int > newNormalIndices;
  4150. newNormalIndices.SetCount( oldNormalIndices.Count() );
  4151. for ( int i = 0; i < newNormalIndices.Count(); ++i )
  4152. {
  4153. newNormalIndices[i] = -1;
  4154. }
  4155. const int nPositionDataCount = pDmeVertexData->GetPositionData().Count();
  4156. for ( int i = 0; i < nPositionDataCount; ++i )
  4157. {
  4158. int nNewNormalDataIndex = newNormalData.Count();
  4159. const CUtlVector< int > &vertexIndices = pDmeVertexData->FindVertexIndicesFromDataIndex( CDmeVertexData::FIELD_POSITION, i );
  4160. for ( int j = 0; j < vertexIndices.Count(); ++j )
  4161. {
  4162. bool bUnique = true;
  4163. const int nVertexIndex = vertexIndices[j];
  4164. const Vector &vNormal = oldNormalData[ oldNormalIndices[ vertexIndices[j] ] ];
  4165. for ( int k = nNewNormalDataIndex; k < newNormalData.Count(); ++k )
  4166. {
  4167. if ( DotProduct( vNormal, newNormalData[k] ) > flNormalBlend )
  4168. {
  4169. newNormalIndices[ nVertexIndex ] = k;
  4170. bUnique = false;
  4171. break;
  4172. }
  4173. }
  4174. if ( !bUnique )
  4175. continue;
  4176. newNormalIndices[ nVertexIndex ] = newNormalData.AddToTail( vNormal );
  4177. }
  4178. }
  4179. for ( int i = 0; i < newNormalIndices.Count(); ++i )
  4180. {
  4181. if ( newNormalIndices[i] == -1 )
  4182. {
  4183. newNormalIndices[i] = newNormalData.AddToTail( oldNormalData[ oldNormalIndices[i] ] );
  4184. }
  4185. }
  4186. // If it's the same or more don't do anything
  4187. if ( newNormalData.Count() >= oldNormalData.Count() )
  4188. return false;
  4189. normalMap.SetCount( oldNormalData.Count() );
  4190. for ( int i = 0; i < normalMap.Count(); ++i )
  4191. {
  4192. normalMap[i] = -1;
  4193. }
  4194. Assert( newNormalIndices.Count() == oldNormalIndices.Count() );
  4195. for ( int i = 0; i < oldNormalIndices.Count(); ++i )
  4196. {
  4197. if ( normalMap[ oldNormalIndices[i] ] == -1 )
  4198. {
  4199. normalMap[ oldNormalIndices[i] ] = newNormalIndices[i];
  4200. }
  4201. else
  4202. {
  4203. Assert( normalMap[ oldNormalIndices[i] ] == newNormalIndices[i] );
  4204. }
  4205. }
  4206. pDmeVertexData->RemoveAllVertexData( nNormalFieldIndex );
  4207. nNormalFieldIndex = pDmeVertexData->CreateField( CDmeVertexDeltaData::FIELD_NORMAL );
  4208. pDmeVertexData->AddVertexData( nNormalFieldIndex, newNormalData.Count() );
  4209. pDmeVertexData->SetVertexData( nNormalFieldIndex, 0, newNormalData.Count(), AT_VECTOR3, newNormalData.Base() );
  4210. pDmeVertexData->SetVertexIndices( nNormalFieldIndex, 0, newNormalIndices.Count(), newNormalIndices.Base() );
  4211. return true;
  4212. }
  4213. //-----------------------------------------------------------------------------
  4214. // Collapse all normals with the same numerical value into the same normal
  4215. //-----------------------------------------------------------------------------
  4216. static bool CollapseRedundantBaseNormalsAggressive( CDmeVertexData *pDmeVertexData, float flNormalBlend )
  4217. {
  4218. if ( !pDmeVertexData )
  4219. return false;
  4220. FieldIndex_t nNormalFieldIndex = pDmeVertexData->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  4221. if ( nNormalFieldIndex < 0 )
  4222. return false;
  4223. const CUtlVector< Vector > &oldNormalData = pDmeVertexData->GetNormalData();
  4224. const CUtlVector< int > &oldNormalIndices = pDmeVertexData->GetVertexIndexData( nNormalFieldIndex );
  4225. CUtlVector< int > normalMap;
  4226. normalMap.SetCount( oldNormalData.Count() );
  4227. CUtlVector< Vector > newNormalData;
  4228. for ( int i = 0; i < oldNormalData.Count(); ++i )
  4229. {
  4230. bool bUnique = true;
  4231. const Vector &vNormal = oldNormalData[ i ];
  4232. for ( int j = 0; j < newNormalData.Count(); ++j )
  4233. {
  4234. if ( DotProduct( vNormal, newNormalData[j] ) > flNormalBlend )
  4235. {
  4236. normalMap[ i ] = j;
  4237. bUnique = false;
  4238. break;
  4239. }
  4240. }
  4241. if ( !bUnique )
  4242. continue;
  4243. normalMap[ i ] = newNormalData.AddToTail( vNormal );
  4244. }
  4245. // If it's the same then don't do anything.
  4246. if ( newNormalData.Count() >= oldNormalData.Count() )
  4247. return false;
  4248. CUtlVector< int > newNormalIndices;
  4249. newNormalIndices.SetCount( oldNormalIndices.Count() );
  4250. for ( int i = 0; i < oldNormalIndices.Count(); ++i )
  4251. {
  4252. newNormalIndices[i] = normalMap[ oldNormalIndices[i] ];
  4253. }
  4254. pDmeVertexData->RemoveAllVertexData( nNormalFieldIndex );
  4255. nNormalFieldIndex = pDmeVertexData->CreateField( CDmeVertexDeltaData::FIELD_NORMAL );
  4256. pDmeVertexData->AddVertexData( nNormalFieldIndex, newNormalData.Count() );
  4257. pDmeVertexData->SetVertexData( nNormalFieldIndex, 0, newNormalData.Count(), AT_VECTOR3, newNormalData.Base() );
  4258. pDmeVertexData->SetVertexIndices( nNormalFieldIndex, 0, newNormalIndices.Count(), newNormalIndices.Base() );
  4259. return true;
  4260. }
  4261. //-----------------------------------------------------------------------------
  4262. //
  4263. //-----------------------------------------------------------------------------
  4264. void CDmeMesh::NormalizeNormals()
  4265. {
  4266. Vector vNormal;
  4267. for ( int i = 0; i < this->BaseStateCount(); ++i )
  4268. {
  4269. CDmeVertexData *pDmeVertexData = GetBaseState( i );
  4270. if ( !pDmeVertexData )
  4271. continue;
  4272. FieldIndex_t nNormalIndex = pDmeVertexData->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  4273. if ( nNormalIndex < 0 )
  4274. continue;
  4275. CDmAttribute *pDmNormalAttr = pDmeVertexData->GetVertexData( nNormalIndex );
  4276. if ( !pDmNormalAttr )
  4277. continue;
  4278. CDmrArray< Vector > normalData( pDmNormalAttr );
  4279. for ( int j = 0; j < normalData.Count(); ++j )
  4280. {
  4281. vNormal = normalData.Get( j );
  4282. VectorNormalize( vNormal );
  4283. normalData.Set( j, vNormal );
  4284. }
  4285. }
  4286. }
  4287. //-----------------------------------------------------------------------------
  4288. //
  4289. //-----------------------------------------------------------------------------
  4290. void CDmeMesh::CollapseRedundantNormals( float flNormalBlend )
  4291. {
  4292. NormalizeNormals();
  4293. CDmeVertexData *pDmeBind = GetBindBaseState();
  4294. if ( !pDmeBind )
  4295. return;
  4296. CUtlVector< int > normalMap;
  4297. const int nDeltaStateCount = DeltaStateCount();
  4298. if ( nDeltaStateCount <= 0 )
  4299. {
  4300. // No deltas
  4301. if ( CollapseRedundantBaseNormalsAggressive( pDmeBind, flNormalBlend ) )
  4302. {
  4303. // Collapse any other states
  4304. for ( int i = 0; i < BaseStateCount(); ++i )
  4305. {
  4306. CDmeVertexData *pDmeVertexData = GetBaseState( i );
  4307. if ( !pDmeVertexData || pDmeVertexData == pDmeBind )
  4308. continue;
  4309. CollapseRedundantBaseNormalsAggressive( pDmeVertexData, flNormalBlend );
  4310. }
  4311. }
  4312. }
  4313. else
  4314. {
  4315. // Collapse the base state
  4316. if ( CollapseRedundantBaseNormals( pDmeBind, normalMap, flNormalBlend ) )
  4317. {
  4318. // Collapse any delta states using the baseState normal map
  4319. for ( int i = 0; i < DeltaStateCount(); ++i )
  4320. {
  4321. CDmeVertexDeltaData *pDmeDeltaData = GetDeltaState( i );
  4322. if ( !pDmeDeltaData )
  4323. continue;
  4324. CollapseRedundantDeltaNormals( pDmeDeltaData, normalMap );
  4325. }
  4326. // Collapse any other states
  4327. for ( int i = 0; i < BaseStateCount(); ++i )
  4328. {
  4329. CDmeVertexData *pDmeVertexData = GetBaseState( i );
  4330. if ( !pDmeVertexData || pDmeVertexData == pDmeBind )
  4331. continue;
  4332. CollapseRedundantBaseNormals( pDmeVertexData, normalMap, flNormalBlend );
  4333. }
  4334. }
  4335. }
  4336. }