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.

1072 lines
34 KiB

  1. //===== Copyright � 2005-2013, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Utility methods for mdl files
  4. //
  5. //===========================================================================//
  6. #include "tier3/mdlutils.h"
  7. #include "tier0/dbg.h"
  8. #include "tier3/tier3.h"
  9. #include "studio.h"
  10. #include "istudiorender.h"
  11. #include "bone_setup.h"
  12. #include "bone_accessor.h"
  13. #include "materialsystem/imaterialvar.h"
  14. #include "vcollide_parse.h"
  15. #include "renderparm.h"
  16. #include "tier2/renderutils.h"
  17. #include "mathlib/camera.h"
  18. // NOTE: This has to be the last file included!
  19. #include "tier0/memdbgon.h"
  20. //-----------------------------------------------------------------------------
  21. // Returns the bounding box for the model
  22. //-----------------------------------------------------------------------------
  23. void GetMDLBoundingBox( Vector *pMins, Vector *pMaxs, MDLHandle_t h, int nSequence )
  24. {
  25. if ( h == MDLHANDLE_INVALID || !g_pMDLCache )
  26. {
  27. pMins->Init();
  28. pMaxs->Init();
  29. return;
  30. }
  31. pMins->Init( FLT_MAX, FLT_MAX );
  32. pMaxs->Init( -FLT_MAX, -FLT_MAX );
  33. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( h );
  34. if ( !VectorCompare( vec3_origin, pStudioHdr->view_bbmin ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax ))
  35. {
  36. // look for view clip
  37. *pMins = pStudioHdr->view_bbmin;
  38. *pMaxs = pStudioHdr->view_bbmax;
  39. }
  40. else if ( !VectorCompare( vec3_origin, pStudioHdr->hull_min ) || !VectorCompare( vec3_origin, pStudioHdr->hull_max ))
  41. {
  42. // look for hull
  43. *pMins = pStudioHdr->hull_min;
  44. *pMaxs = pStudioHdr->hull_max;
  45. }
  46. // Else use the sequence box
  47. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSequence );
  48. VectorMin( seqdesc.bbmin, *pMins, *pMins );
  49. VectorMax( seqdesc.bbmax, *pMaxs, *pMaxs );
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Returns the radius of the model as measured from the origin
  53. //-----------------------------------------------------------------------------
  54. float GetMDLRadius( MDLHandle_t h, int nSequence )
  55. {
  56. Vector vecMins, vecMaxs;
  57. GetMDLBoundingBox( &vecMins, &vecMaxs, h, nSequence );
  58. float flRadius = vecMaxs.Length();
  59. float flRadius2 = vecMins.Length();
  60. if ( flRadius2 > flRadius )
  61. {
  62. flRadius = flRadius2;
  63. }
  64. return flRadius;
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Returns a more accurate bounding sphere
  68. //-----------------------------------------------------------------------------
  69. void GetMDLBoundingSphere( Vector *pVecCenter, float *pRadius, MDLHandle_t h, int nSequence )
  70. {
  71. Vector vecMins, vecMaxs;
  72. GetMDLBoundingBox( &vecMins, &vecMaxs, h, nSequence );
  73. VectorAdd( vecMins, vecMaxs, *pVecCenter );
  74. *pVecCenter *= 0.5f;
  75. *pRadius = vecMaxs.DistTo( *pVecCenter );
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Determines which pose parameters are used by the specified sequence
  79. //-----------------------------------------------------------------------------
  80. void FindSequencePoseParameters( CStudioHdr &hdr, int nSequence, bool *pPoseParameters, int nCount )
  81. {
  82. if ( ( nSequence < 0 ) && ( nSequence >= hdr.GetNumSeq() ) )
  83. return;
  84. const mstudioseqdesc_t &seqdesc = hdr.pSeqdesc( nSequence );
  85. // Add the pose parameters that are directly referenced by this sequence
  86. int nParamIndex;
  87. nParamIndex = hdr.GetSharedPoseParameter( nSequence, seqdesc.paramindex[ 0 ] );
  88. if ( ( nParamIndex >= 0 ) && ( nParamIndex < nCount ) )
  89. {
  90. pPoseParameters[ nParamIndex ] = true;
  91. }
  92. nParamIndex = hdr.GetSharedPoseParameter( nSequence, seqdesc.paramindex[ 1 ] );
  93. if ( ( nParamIndex >= 0 ) && ( nParamIndex < nCount ) )
  94. {
  95. pPoseParameters[ nParamIndex ] = true;
  96. }
  97. if ( seqdesc.flags & STUDIO_CYCLEPOSE )
  98. {
  99. nParamIndex = hdr.GetSharedPoseParameter( nSequence, seqdesc.cycleposeindex );
  100. if ( ( nParamIndex >= 0 ) && ( nParamIndex < nCount ) )
  101. {
  102. pPoseParameters[ nParamIndex ] = true;
  103. }
  104. }
  105. // Now recursively add the parameters for the auto layers
  106. for ( int i = 0; i < seqdesc.numautolayers; ++i )
  107. {
  108. const mstudioautolayer_t *pLayer = seqdesc.pAutolayer( i );
  109. int nLayerSequence = hdr.iRelativeSeq( nSequence, pLayer->iSequence );
  110. if ( nLayerSequence != nSequence )
  111. {
  112. FindSequencePoseParameters( hdr, nLayerSequence, pPoseParameters, nCount );
  113. }
  114. }
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Constructor
  118. //-----------------------------------------------------------------------------
  119. CMDL::CMDL()
  120. {
  121. m_MDLHandle = MDLHANDLE_INVALID;
  122. m_Color.SetColor( 255, 255, 255, 255 );
  123. m_nSkin = 0;
  124. m_nBody = 0;
  125. m_nSequence = 0;
  126. m_nLOD = 0;
  127. m_flPlaybackRate = 30.0f;
  128. m_flTime = 0.0f;
  129. m_vecViewTarget.Init( 0, 0, 0 );
  130. m_bWorldSpaceViewTarget = false;
  131. memset( m_pFlexControls, 0, sizeof(m_pFlexControls) );
  132. m_pProxyData = NULL;
  133. m_bUseSequencePlaybackFPS = false;
  134. m_flTimeBasisAdjustment = 0.0f;
  135. // Deal with the default cubemap
  136. ITexture *pCubemapTexture = g_pMaterialSystem->FindTexture( "editor/cubemap", NULL, true );
  137. m_DefaultEnvCubemap.Init( pCubemapTexture );
  138. pCubemapTexture = g_pMaterialSystem->FindTexture( "editor/cubemap.hdr", NULL, true );
  139. m_DefaultHDREnvCubemap.Init( pCubemapTexture );
  140. m_pSimpleMaterialOverride = NULL;
  141. }
  142. CMDL::~CMDL()
  143. {
  144. m_DefaultEnvCubemap.Shutdown( );
  145. m_DefaultHDREnvCubemap.Shutdown();
  146. if ( m_pSimpleMaterialOverride != NULL )
  147. {
  148. m_pSimpleMaterialOverride.Shutdown();
  149. m_pSimpleMaterialOverride = NULL;
  150. }
  151. UnreferenceMDL();
  152. }
  153. ITexture *CMDL::GetEnvCubeMap()
  154. {
  155. if ( g_pMaterialSystemHardwareConfig->GetHDRType() == HDR_TYPE_NONE )
  156. {
  157. return m_DefaultEnvCubemap;
  158. }
  159. else
  160. {
  161. return m_DefaultHDREnvCubemap;
  162. }
  163. }
  164. void CMDL::SetMDL( MDLHandle_t h )
  165. {
  166. UnreferenceMDL();
  167. m_MDLHandle = h;
  168. if ( m_MDLHandle != MDLHANDLE_INVALID )
  169. {
  170. g_pMDLCache->AddRef( m_MDLHandle );
  171. studiohdr_t *pHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
  172. if ( pHdr )
  173. {
  174. for ( LocalFlexController_t i = LocalFlexController_t(0); i < pHdr->numflexcontrollers; ++i )
  175. {
  176. if ( pHdr->pFlexcontroller( i )->localToGlobal == -1 )
  177. {
  178. pHdr->pFlexcontroller( i )->localToGlobal = i;
  179. }
  180. }
  181. if ( m_Attachments.Count() != pHdr->GetNumAttachments() )
  182. {
  183. m_Attachments.SetSize( pHdr->GetNumAttachments() );
  184. // This is to make sure we don't use the attachment before its been set up
  185. for ( int i=0; i < m_Attachments.Count(); i++ )
  186. {
  187. m_Attachments[i].m_bValid = false;
  188. #ifdef _DEBUG
  189. m_Attachments[i].m_AttachmentToWorld.Invalidate();
  190. #endif
  191. }
  192. }
  193. }
  194. }
  195. }
  196. MDLHandle_t CMDL::GetMDL() const
  197. {
  198. return m_MDLHandle;
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Release the MDL handle
  202. //-----------------------------------------------------------------------------
  203. void CMDL::UnreferenceMDL()
  204. {
  205. if ( !g_pMDLCache )
  206. return;
  207. if ( m_MDLHandle != MDLHANDLE_INVALID )
  208. {
  209. g_pMDLCache->Release( m_MDLHandle );
  210. m_MDLHandle = MDLHANDLE_INVALID;
  211. }
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Gets the studiohdr
  215. //-----------------------------------------------------------------------------
  216. studiohdr_t *CMDL::GetStudioHdr()
  217. {
  218. if ( !g_pMDLCache )
  219. return NULL;
  220. return g_pMDLCache->GetStudioHdr( m_MDLHandle );
  221. }
  222. void CMDL::SetSimpleMaterialOverride( IMaterial *pNewMaterial )
  223. {
  224. m_pSimpleMaterialOverride.Init( pNewMaterial );
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Draws the mesh
  228. //-----------------------------------------------------------------------------
  229. void CMDL::Draw( const matrix3x4_t& rootToWorld, const matrix3x4_t *pBoneToWorld, int flags )
  230. {
  231. if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
  232. return;
  233. if ( m_MDLHandle == MDLHANDLE_INVALID )
  234. return;
  235. // Color + alpha modulation
  236. Vector white( m_Color.r() / 255.0f, m_Color.g() / 255.0f, m_Color.b() / 255.0f );
  237. g_pStudioRender->SetColorModulation( white.Base() );
  238. g_pStudioRender->SetAlphaModulation( m_Color.a() / 255.0f );
  239. DrawModelInfo_t info;
  240. info.m_pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
  241. info.m_pHardwareData = g_pMDLCache->GetHardwareData( m_MDLHandle );
  242. info.m_Decals = STUDIORENDER_DECAL_INVALID;
  243. info.m_Skin = m_nSkin;
  244. info.m_Body = m_nBody;
  245. info.m_HitboxSet = 0;
  246. info.m_pClientEntity = m_pProxyData;
  247. info.m_pColorMeshes = NULL;
  248. info.m_bStaticLighting = false;
  249. info.m_Lod = m_nLOD;
  250. Vector vecWorldViewTarget;
  251. if ( m_bWorldSpaceViewTarget )
  252. {
  253. vecWorldViewTarget = m_vecViewTarget;
  254. }
  255. else
  256. {
  257. VectorTransform( m_vecViewTarget, rootToWorld, vecWorldViewTarget );
  258. }
  259. g_pStudioRender->SetEyeViewTarget( info.m_pStudioHdr, info.m_Body, vecWorldViewTarget );
  260. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  261. CMatRenderData< float > rdFlexWeights( pRenderContext );
  262. // Set default flex values
  263. float *pFlexWeights = NULL;
  264. const int nFlexDescCount = info.m_pStudioHdr->numflexdesc;
  265. if ( nFlexDescCount )
  266. {
  267. CStudioHdr cStudioHdr( info.m_pStudioHdr, g_pMDLCache );
  268. pFlexWeights = rdFlexWeights.Lock( info.m_pStudioHdr->numflexdesc );
  269. cStudioHdr.RunFlexRules( m_pFlexControls, pFlexWeights );
  270. }
  271. Vector vecModelOrigin;
  272. MatrixGetColumn( rootToWorld, 3, vecModelOrigin );
  273. bool bOverride = false;
  274. static ConVarRef cl_custom_material_override( "cl_custom_material_override" );
  275. if ( cl_custom_material_override.IsValid() && cl_custom_material_override.GetBool() && !g_pStudioRender->IsForcedMaterialOverride() )
  276. {
  277. for ( int i = 0; i < GetCustomMaterialCount(); i++ )
  278. {
  279. if ( IsCustomMaterialValid( i ) )
  280. {
  281. g_pStudioRender->ForcedMaterialOverride( GetCustomMaterial( i )->GetMaterial(), OVERRIDE_SELECTIVE, i );
  282. bOverride = true;
  283. }
  284. }
  285. }
  286. if ( m_pSimpleMaterialOverride != NULL )
  287. {
  288. bOverride = true;
  289. g_pStudioRender->ForcedMaterialOverride( m_pSimpleMaterialOverride );
  290. }
  291. g_pStudioRender->DrawModel( NULL, info, const_cast<matrix3x4_t*>( pBoneToWorld ),
  292. pFlexWeights, NULL, vecModelOrigin, STUDIORENDER_DRAW_ENTIRE_MODEL | flags );
  293. if ( bOverride )
  294. {
  295. g_pStudioRender->ForcedMaterialOverride( NULL );
  296. }
  297. }
  298. void CMDL::Draw( const matrix3x4_t &rootToWorld )
  299. {
  300. if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
  301. return;
  302. if ( m_MDLHandle == MDLHANDLE_INVALID )
  303. return;
  304. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
  305. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  306. CMatRenderData< matrix3x4_t > rdBoneToWorld( pRenderContext, pStudioHdr->numbones );
  307. SetUpBones( rootToWorld, pStudioHdr->numbones, rdBoneToWorld.Base() );
  308. Draw( rootToWorld, rdBoneToWorld.Base() );
  309. }
  310. void CMDL::SetUpBones( const matrix3x4_t& rootToWorld, int nMaxBoneCount, matrix3x4_t *pBoneToWorld, const float *pPoseParameters, MDLSquenceLayer_t *pSequenceLayers, int nNumSequenceLayers )
  311. {
  312. MDLCACHE_CRITICAL_SECTION();
  313. CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_MDLHandle ), g_pMDLCache );
  314. // Default to middle of the pose parameter range
  315. float defaultPoseParameters[MAXSTUDIOPOSEPARAM];
  316. if ( pPoseParameters == NULL )
  317. {
  318. Studio_CalcDefaultPoseParameters( &studioHdr, defaultPoseParameters, MAXSTUDIOPOSEPARAM );
  319. pPoseParameters = defaultPoseParameters;
  320. }
  321. int nFrameCount = Studio_MaxFrame( &studioHdr, m_nSequence, pPoseParameters );
  322. if ( nFrameCount == 0 )
  323. {
  324. nFrameCount = 1;
  325. }
  326. float flPlaybackRate = m_bUseSequencePlaybackFPS ? Studio_FPS( &studioHdr, m_nSequence, pPoseParameters ) : m_flPlaybackRate;
  327. float flAdjustedTime = m_flTime - m_flTimeBasisAdjustment;
  328. float flCycle = ( flAdjustedTime * flPlaybackRate ) / nFrameCount;
  329. m_flCurrentAnimEndTime = flPlaybackRate > 0.0f ? float( nFrameCount ) / flPlaybackRate : float( nFrameCount );
  330. if ( flCycle > 1.0f )
  331. {
  332. // We need to rollover into the next sequence followup
  333. if ( flPlaybackRate > 0.0f && flAdjustedTime < float(flPlaybackRate) )
  334. m_flTimeBasisAdjustment += float( nFrameCount ) / float( flPlaybackRate );
  335. else
  336. m_flTimeBasisAdjustment = m_flTime;
  337. if ( m_arrSequenceFollowLoop.Count() )
  338. {
  339. m_nSequence = m_arrSequenceFollowLoop.Head();
  340. m_arrSequenceFollowLoop.RemoveMultipleFromHead( 1 );
  341. // Recurse with the updated sequence
  342. SetUpBones( rootToWorld, nMaxBoneCount, pBoneToWorld, pPoseParameters, pSequenceLayers, nNumSequenceLayers );
  343. return;
  344. }
  345. else
  346. {
  347. flAdjustedTime = m_flTime - m_flTimeBasisAdjustment;
  348. flCycle = ( flAdjustedTime * flPlaybackRate ) / nFrameCount;
  349. }
  350. }
  351. // FIXME: We're always wrapping; may want to determing if we should clamp
  352. flCycle = SubtractIntegerPart(flCycle);
  353. BoneVector pos[MAXSTUDIOBONES];
  354. BoneQuaternionAligned q[MAXSTUDIOBONES];
  355. IBoneSetup boneSetup( &studioHdr, BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ), pPoseParameters, NULL );
  356. boneSetup.InitPose( pos, q );
  357. boneSetup.AccumulatePose( pos, q, m_nSequence, flCycle, 1.0f, flAdjustedTime, NULL );
  358. // Accumulate the additional layers if specified.
  359. if ( pSequenceLayers )
  360. {
  361. int nNumSeq = studioHdr.GetNumSeq();
  362. for ( int i = 0; i < nNumSequenceLayers; ++i )
  363. {
  364. int nSeqIndex = pSequenceLayers[ i ].m_nSequenceIndex;
  365. if ( ( nSeqIndex >= 0 ) && ( nSeqIndex < nNumSeq ) )
  366. {
  367. float flWeight = pSequenceLayers[ i ].m_flWeight;
  368. int nFrameCount = MAX( 1, Studio_MaxFrame( &studioHdr, nSeqIndex, pPoseParameters ) );
  369. float flLayerCycle = ( flAdjustedTime * flPlaybackRate ) / nFrameCount;
  370. // FIXME: We're always wrapping; may want to determing if we should clamp
  371. flLayerCycle = SubtractIntegerPart(flLayerCycle);
  372. boneSetup.AccumulatePose( pos, q, nSeqIndex, flLayerCycle, flWeight, flAdjustedTime, NULL );
  373. }
  374. }
  375. }
  376. // FIXME: Try enabling this?
  377. // CalcAutoplaySequences( pStudioHdr, NULL, pos, q, pPoseParameter, BONE_USED_BY_VERTEX_AT_LOD( m_nLOD ), flTime );
  378. matrix3x4_t temp;
  379. if ( nMaxBoneCount > studioHdr.numbones() )
  380. {
  381. nMaxBoneCount = studioHdr.numbones();
  382. }
  383. for ( int i = 0; i < nMaxBoneCount; i++ )
  384. {
  385. // If it's not being used, fill with NAN for errors
  386. #ifdef _DEBUG
  387. if ( !(studioHdr.pBone( i )->flags & BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ) ) )
  388. {
  389. int j, k;
  390. for (j = 0; j < 3; j++)
  391. {
  392. for (k = 0; k < 4; k++)
  393. {
  394. pBoneToWorld[i][j][k] = VEC_T_NAN;
  395. }
  396. }
  397. continue;
  398. }
  399. #endif
  400. matrix3x4_t boneMatrix;
  401. QuaternionMatrix( q[i], boneMatrix );
  402. MatrixSetColumn( pos[i], 3, boneMatrix );
  403. // WARNING: converting from matrix3x4_t to matrix3x4a_t is going to asplode on a console.
  404. // Calculate helper bones!
  405. AssertAligned( pBoneToWorld );
  406. CBoneAccessor tempCBoneAccessor( ( matrix3x4a_t * )pBoneToWorld );
  407. if ( CalcProceduralBone( &studioHdr, i, tempCBoneAccessor ) )
  408. {
  409. }
  410. else if ( studioHdr.pBone(i)->parent == -1 )
  411. {
  412. ConcatTransforms( rootToWorld, boneMatrix, pBoneToWorld[i] );
  413. }
  414. else
  415. {
  416. ConcatTransforms( pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] );
  417. }
  418. }
  419. Studio_RunBoneFlexDrivers( m_pFlexControls, &studioHdr, pos, pBoneToWorld, rootToWorld );
  420. SetupBones_AttachmentHelper( &studioHdr, pBoneToWorld );
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. //-----------------------------------------------------------------------------
  425. void CMDL::SetupBonesWithBoneMerge( const CStudioHdr *pMergeHdr, matrix3x4_t *pMergeBoneToWorld,
  426. const CStudioHdr *pFollow, const matrix3x4_t *pFollowBoneToWorld,
  427. const matrix3x4_t &matModelToWorld )
  428. {
  429. // Default to middle of the pose parameter range
  430. float flPoseParameter[MAXSTUDIOPOSEPARAM];
  431. Studio_CalcDefaultPoseParameters( pMergeHdr, flPoseParameter, MAXSTUDIOPOSEPARAM );
  432. int nFrameCount = Studio_MaxFrame( pMergeHdr, m_nSequence, flPoseParameter );
  433. if ( nFrameCount == 0 )
  434. {
  435. nFrameCount = 1;
  436. }
  437. float flPlaybackRate = m_bUseSequencePlaybackFPS ? Studio_FPS( pMergeHdr, m_nSequence, flPoseParameter ) : m_flPlaybackRate;
  438. float flAdjustedTime = m_flTime - m_flTimeBasisAdjustment;
  439. float flCycle = ( flAdjustedTime * flPlaybackRate ) / nFrameCount;
  440. m_flCurrentAnimEndTime = flPlaybackRate > 0.0f ? float( nFrameCount ) / flPlaybackRate : float( nFrameCount );
  441. if ( flCycle > 1.0f )
  442. {
  443. // We need to rollover into the next sequence followup
  444. if ( flPlaybackRate > 0.0f && flAdjustedTime < float(flPlaybackRate) )
  445. m_flTimeBasisAdjustment += float( nFrameCount ) / float( flPlaybackRate );
  446. else
  447. m_flTimeBasisAdjustment = m_flTime;
  448. if ( m_arrSequenceFollowLoop.Count() )
  449. {
  450. m_nSequence = m_arrSequenceFollowLoop.Head();
  451. m_arrSequenceFollowLoop.RemoveMultipleFromHead( 1 );
  452. // Recurse with the updated sequence
  453. SetupBonesWithBoneMerge( pMergeHdr, pMergeBoneToWorld, pFollow, pFollowBoneToWorld, matModelToWorld );
  454. return;
  455. }
  456. else
  457. {
  458. flAdjustedTime = m_flTime - m_flTimeBasisAdjustment;
  459. flCycle = ( flAdjustedTime * flPlaybackRate ) / nFrameCount;
  460. }
  461. }
  462. // FIXME: We're always wrapping; may want to determing if we should clamp
  463. flCycle = SubtractIntegerPart(flCycle);
  464. BoneVector pos[MAXSTUDIOBONES];
  465. BoneQuaternionAligned q[MAXSTUDIOBONES];
  466. IBoneSetup boneSetup( pMergeHdr, BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ), flPoseParameter );
  467. boneSetup.InitPose( pos, q );
  468. boneSetup.AccumulatePose( pos, q, m_nSequence, flCycle, 1.0f, flAdjustedTime, NULL );
  469. // Get the merge bone list.
  470. const mstudiobone_t *pMergeBones = pMergeHdr->pBone( 0 );
  471. for ( int iMergeBone = 0; iMergeBone < pMergeHdr->numbones(); ++iMergeBone )
  472. {
  473. // Now find the bone in the parent entity.
  474. bool bMerged = false;
  475. int iParentBoneIndex = Studio_BoneIndexByName( pFollow, pMergeBones[iMergeBone].pszName() );
  476. if ( iParentBoneIndex >= 0 )
  477. {
  478. MatrixCopy( pFollowBoneToWorld[iParentBoneIndex], pMergeBoneToWorld[iMergeBone] );
  479. bMerged = true;
  480. }
  481. if ( !bMerged )
  482. {
  483. // If we get down here, then the bone wasn't merged.
  484. matrix3x4_t matBone;
  485. QuaternionMatrix( q[iMergeBone], pos[iMergeBone], matBone );
  486. if ( pMergeBones[iMergeBone].parent == -1 )
  487. {
  488. ConcatTransforms( matModelToWorld, matBone, pMergeBoneToWorld[iMergeBone] );
  489. }
  490. else
  491. {
  492. ConcatTransforms( pMergeBoneToWorld[pMergeBones[iMergeBone].parent], matBone, pMergeBoneToWorld[iMergeBone] );
  493. }
  494. }
  495. }
  496. }
  497. void CMDL::SetupBones_AttachmentHelper( CStudioHdr *hdr, matrix3x4_t *pBoneToWorld )
  498. {
  499. if ( !hdr || !hdr->GetNumAttachments() )
  500. return;
  501. // calculate attachment points
  502. matrix3x4_t world;
  503. for (int i = 0; i < hdr->GetNumAttachments(); i++)
  504. {
  505. const mstudioattachment_t &pattachment = hdr->pAttachment( i );
  506. int iBone = hdr->GetAttachmentBone( i );
  507. if ( (pattachment.flags & ATTACHMENT_FLAG_WORLD_ALIGN) == 0 )
  508. {
  509. ConcatTransforms( pBoneToWorld[iBone], pattachment.local, world );
  510. }
  511. else
  512. {
  513. Vector vecLocalBonePos, vecWorldBonePos;
  514. MatrixGetColumn( pattachment.local, 3, vecLocalBonePos );
  515. VectorTransform( vecLocalBonePos, pBoneToWorld[iBone], vecWorldBonePos );
  516. SetIdentityMatrix( world );
  517. MatrixSetColumn( vecWorldBonePos, 3, world );
  518. }
  519. PutAttachment( i + 1, world );
  520. }
  521. }
  522. //-----------------------------------------------------------------------------
  523. // Purpose: Put a value into an attachment point by index
  524. // Input : number - which point
  525. // Output : float * - the attachment point
  526. //-----------------------------------------------------------------------------
  527. bool CMDL::PutAttachment( int number, const matrix3x4_t &attachmentToWorld )
  528. {
  529. if ( number < 1 || number > m_Attachments.Count() )
  530. return false;
  531. CMDLAttachmentData *pAtt = &m_Attachments[number-1];
  532. pAtt->m_AttachmentToWorld = attachmentToWorld;
  533. pAtt->m_bValid = true;
  534. return true;
  535. }
  536. bool CMDL::GetAttachment( int number, matrix3x4_t& matrix )
  537. {
  538. if ( number < 1 || number > m_Attachments.Count() )
  539. return false;
  540. if ( !m_Attachments[number-1].m_bValid )
  541. return false;
  542. matrix = m_Attachments[number-1].m_AttachmentToWorld;
  543. return true;
  544. }
  545. bool CMDL::GetAttachment( const char *pszAttachment, matrix3x4_t& matrixOut )
  546. {
  547. if ( GetMDL() == MDLHANDLE_INVALID )
  548. return false;
  549. CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( GetMDL() ), g_pMDLCache );
  550. int iAttachmentNum = Studio_FindAttachment( &studioHdr, pszAttachment );
  551. if ( iAttachmentNum == -1 )
  552. return false;
  553. return GetAttachment( iAttachmentNum + 1, matrixOut );
  554. }
  555. bool CMDL::GetBoundingSphere( Vector &vecCenter, float &flRadius )
  556. {
  557. // Check to see if we have a valid model to look at.
  558. if ( m_MDLHandle == MDLHANDLE_INVALID )
  559. return false;
  560. GetMDLBoundingSphere( &vecCenter, &flRadius, m_MDLHandle, m_nSequence );
  561. return true;
  562. }
  563. void CMDL::AdjustTime( float flAmount )
  564. {
  565. m_flTime += flAmount;
  566. }
  567. MDLData_t::MDLData_t()
  568. {
  569. SetIdentityMatrix( m_MDLToWorld );
  570. m_bRequestBoneMergeTakeover = false;
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Constructor, destructor
  574. //-----------------------------------------------------------------------------
  575. CMergedMDL::CMergedMDL()
  576. {
  577. m_nNumSequenceLayers = 0;
  578. }
  579. CMergedMDL::~CMergedMDL()
  580. {
  581. m_aMergeMDLs.Purge();
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Stores the clip
  585. //-----------------------------------------------------------------------------
  586. void CMergedMDL::SetMDL( MDLHandle_t handle, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData )
  587. {
  588. m_RootMDL.m_MDL.SetMDL( handle );
  589. m_RootMDL.m_MDL.m_pProxyData = pProxyData;
  590. Vector vecMins, vecMaxs;
  591. GetMDLBoundingBox( &vecMins, &vecMaxs, handle, m_RootMDL.m_MDL.m_nSequence );
  592. m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = false;
  593. m_RootMDL.m_MDL.m_vecViewTarget.Init( 100.0f, 0.0f, vecMaxs.z );
  594. if ( pCustomMaterialOwner )
  595. {
  596. pCustomMaterialOwner->DuplicateCustomMaterialsToOther( &m_RootMDL.m_MDL );
  597. }
  598. // Set the pose parameters to the default for the mdl
  599. SetPoseParameters( NULL, 0 );
  600. // Clear any sequence layers
  601. SetSequenceLayers( NULL, 0 );
  602. }
  603. //-----------------------------------------------------------------------------
  604. // An MDL was selected
  605. //-----------------------------------------------------------------------------
  606. void CMergedMDL::SetMDL( const char *pMDLName, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData )
  607. {
  608. MDLHandle_t hMDL = pMDLName ? g_pMDLCache->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
  609. if ( g_pMDLCache->IsErrorModel( hMDL ) )
  610. {
  611. hMDL = MDLHANDLE_INVALID;
  612. }
  613. SetMDL( hMDL, pCustomMaterialOwner, pProxyData );
  614. }
  615. //-----------------------------------------------------------------------------
  616. // Purpose: Returns a model bounding box.
  617. //-----------------------------------------------------------------------------
  618. bool CMergedMDL::GetBoundingBox( Vector &vecBoundsMin, Vector &vecBoundsMax )
  619. {
  620. // Check to see if we have a valid model to look at.
  621. if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
  622. return false;
  623. GetMDLBoundingBox( &vecBoundsMin, &vecBoundsMax, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence );
  624. return true;
  625. }
  626. //-----------------------------------------------------------------------------
  627. // Purpose: Returns a more accurate bounding sphere
  628. //-----------------------------------------------------------------------------
  629. bool CMergedMDL::GetBoundingSphere( Vector &vecCenter, float &flRadius )
  630. {
  631. // Check to see if we have a valid model to look at.
  632. if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
  633. return false;
  634. Vector vecEngineCenter;
  635. GetMDLBoundingSphere( &vecEngineCenter, &flRadius, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence );
  636. VectorTransform( vecEngineCenter, m_RootMDL.m_MDLToWorld, vecCenter );
  637. return true;
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Purpose:
  641. //-----------------------------------------------------------------------------
  642. bool CMergedMDL::GetAttachment( const char *pszAttachment, matrix3x4_t& matrixOut )
  643. {
  644. if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
  645. return false;
  646. CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache );
  647. int iAttachmentNum = Studio_FindAttachment( &studioHdr, pszAttachment );
  648. if ( iAttachmentNum == -1 )
  649. return false;
  650. return GetAttachment( iAttachmentNum + 1, matrixOut );
  651. }
  652. //-----------------------------------------------------------------------------
  653. // Purpose:
  654. //-----------------------------------------------------------------------------
  655. bool CMergedMDL::GetAttachment( int iAttachmentNum, matrix3x4_t& matrixOut )
  656. {
  657. if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
  658. return false;
  659. return m_RootMDL.m_MDL.GetAttachment( iAttachmentNum, matrixOut );
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Purpose:
  663. //-----------------------------------------------------------------------------
  664. void CMergedMDL::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos )
  665. {
  666. SetIdentityMatrix( m_RootMDL.m_MDLToWorld );
  667. AngleMatrix( angRot, vecPos, m_RootMDL.m_MDLToWorld );
  668. }
  669. //-----------------------------------------------------------------------------
  670. // Purpose:
  671. //-----------------------------------------------------------------------------
  672. void CMergedMDL::SetupBonesForAttachmentQueries( void )
  673. {
  674. if ( !g_pMDLCache )
  675. return;
  676. if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
  677. return;
  678. CMatRenderContextPtr pRenderContext( materials );
  679. CStudioHdr *pRootStudioHdr = new CStudioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache );
  680. CMatRenderData< matrix3x4_t > rdBoneToWorld( pRenderContext, pRootStudioHdr->numbones() );
  681. m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, pRootStudioHdr->numbones(), rdBoneToWorld.Base(), m_PoseParameters, m_SequenceLayers, m_nNumSequenceLayers );
  682. delete pRootStudioHdr;
  683. }
  684. //-----------------------------------------------------------------------------
  685. // paint it!
  686. //-----------------------------------------------------------------------------
  687. void CMergedMDL::Draw()
  688. {
  689. if ( !g_pMDLCache )
  690. return;
  691. if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
  692. return;
  693. CMatRenderContextPtr pRenderContext( materials );
  694. // Draw the MDL
  695. CStudioHdr *pRootStudioHdr = new CStudioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache );
  696. CMatRenderData< matrix3x4_t > rdBoneToWorld( pRenderContext, pRootStudioHdr->numbones() );
  697. const matrix3x4_t *pRootMergeHdrModelToWorld = &m_RootMDL.m_MDLToWorld;
  698. const matrix3x4_t *pFollowBoneToWorld = rdBoneToWorld.Base();
  699. m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, pRootStudioHdr->numbones(), rdBoneToWorld.Base(), m_PoseParameters, m_SequenceLayers, m_nNumSequenceLayers );
  700. OnPostSetUpBonesPreDraw();
  701. int nFlags = STUDIORENDER_DRAW_NO_SHADOWS;
  702. OnModelDrawPassStart( 0, pRootStudioHdr, nFlags );
  703. m_RootMDL.m_MDL.Draw( m_RootMDL.m_MDLToWorld, rdBoneToWorld.Base(), nFlags );
  704. OnModelDrawPassFinished( 0, pRootStudioHdr, nFlags );
  705. // Draw the merge MDLs.
  706. matrix3x4_t *pStackCopyOfRootMergeHdrModelToWorld = NULL;
  707. matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES];
  708. int nMergeCount = m_aMergeMDLs.Count();
  709. for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
  710. {
  711. matrix3x4_t *pMergeBoneToWorld = &matMergeBoneToWorld[0];
  712. // Get the merge studio header.
  713. CStudioHdr *pMergeHdr = new CStudioHdr( g_pMDLCache->GetStudioHdr( m_aMergeMDLs[iMerge].m_MDL.GetMDL() ), g_pMDLCache );
  714. m_aMergeMDLs[iMerge].m_MDL.SetupBonesWithBoneMerge( pMergeHdr, pMergeBoneToWorld, pRootStudioHdr, pFollowBoneToWorld, *pRootMergeHdrModelToWorld );
  715. OnModelDrawPassStart( 0, pMergeHdr, nFlags );
  716. m_aMergeMDLs[iMerge].m_MDL.Draw( m_aMergeMDLs[iMerge].m_MDLToWorld, pMergeBoneToWorld, nFlags );
  717. OnModelDrawPassFinished( 0, pMergeHdr, nFlags );
  718. if ( m_aMergeMDLs[iMerge].m_bRequestBoneMergeTakeover && ( iMerge + 1 < nMergeCount ) )
  719. {
  720. // This model is requesting bonemerge takeover and we have more models to render after it
  721. delete pRootStudioHdr;
  722. pRootStudioHdr = pMergeHdr;
  723. pRootMergeHdrModelToWorld = &m_aMergeMDLs[iMerge].m_MDLToWorld;
  724. // Make a copy of bone to world transforms in a separate stack buffer and repoint root transforms
  725. // for future bonemerge into that buffer
  726. if ( !pStackCopyOfRootMergeHdrModelToWorld )
  727. pStackCopyOfRootMergeHdrModelToWorld = ( matrix3x4_t * ) stackalloc( sizeof( matMergeBoneToWorld ) );
  728. Q_memcpy( pStackCopyOfRootMergeHdrModelToWorld, matMergeBoneToWorld, sizeof( matMergeBoneToWorld ) );
  729. pFollowBoneToWorld = pStackCopyOfRootMergeHdrModelToWorld;
  730. }
  731. else
  732. {
  733. delete pMergeHdr;
  734. }
  735. }
  736. rdBoneToWorld.Release();
  737. delete pRootStudioHdr;
  738. }
  739. void CMergedMDL::Draw( const matrix3x4_t &rootToWorld )
  740. {
  741. m_RootMDL.m_MDLToWorld = rootToWorld;
  742. Draw();
  743. }
  744. //-----------------------------------------------------------------------------
  745. // Sets the current sequence
  746. //-----------------------------------------------------------------------------
  747. void CMergedMDL::SetSequence( int nSequence, bool bUseSequencePlaybackFPS )
  748. {
  749. m_RootMDL.m_MDL.m_nSequence = nSequence;
  750. m_RootMDL.m_MDL.m_bUseSequencePlaybackFPS = bUseSequencePlaybackFPS;
  751. m_RootMDL.m_MDL.m_flTimeBasisAdjustment = m_RootMDL.m_MDL.m_flTime;
  752. }
  753. //-----------------------------------------------------------------------------
  754. // Add a follow loop sequence
  755. //-----------------------------------------------------------------------------
  756. void CMergedMDL::AddSequenceFollowLoop( int nSequence, bool bUseSequencePlaybackFPS )
  757. {
  758. Assert( bUseSequencePlaybackFPS == m_RootMDL.m_MDL.m_bUseSequencePlaybackFPS );
  759. m_RootMDL.m_MDL.m_arrSequenceFollowLoop.AddToTail( nSequence );
  760. }
  761. //-----------------------------------------------------------------------------
  762. // Clear any follow loop sequences
  763. //-----------------------------------------------------------------------------
  764. void CMergedMDL::ClearSequenceFollowLoop()
  765. {
  766. m_RootMDL.m_MDL.m_arrSequenceFollowLoop.RemoveAll();
  767. }
  768. //-----------------------------------------------------------------------------
  769. // Set the current pose parameters. If NULL the pose parameters will be reset
  770. // to the default values.
  771. //-----------------------------------------------------------------------------
  772. void CMergedMDL::SetPoseParameters( const float *pPoseParameters, int nCount )
  773. {
  774. if ( pPoseParameters )
  775. {
  776. int nParameters = MIN( MAXSTUDIOPOSEPARAM, nCount );
  777. for ( int iParam = 0; iParam < nParameters; ++iParam )
  778. {
  779. m_PoseParameters[ iParam ] = pPoseParameters[ iParam ];
  780. }
  781. }
  782. else if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID )
  783. {
  784. CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache );
  785. Studio_CalcDefaultPoseParameters( &studioHdr, m_PoseParameters, MAXSTUDIOPOSEPARAM );
  786. }
  787. }
  788. //-----------------------------------------------------------------------------
  789. // Set the overlay sequence layers
  790. //-----------------------------------------------------------------------------
  791. void CMergedMDL::SetSequenceLayers( const MDLSquenceLayer_t *pSequenceLayers, int nCount )
  792. {
  793. if ( pSequenceLayers )
  794. {
  795. m_nNumSequenceLayers = MIN( MAX_SEQUENCE_LAYERS, nCount );
  796. for ( int iLayer = 0; iLayer < m_nNumSequenceLayers; ++iLayer )
  797. {
  798. m_SequenceLayers[ iLayer ] = pSequenceLayers[ iLayer ];
  799. }
  800. }
  801. else
  802. {
  803. m_nNumSequenceLayers = 0;
  804. V_memset( m_SequenceLayers, 0, sizeof( m_SequenceLayers ) );
  805. }
  806. }
  807. void CMergedMDL::SetSkin( int nSkin )
  808. {
  809. m_RootMDL.m_MDL.m_nSkin = nSkin;
  810. }
  811. //-----------------------------------------------------------------------------
  812. // Purpose:
  813. //-----------------------------------------------------------------------------
  814. void CMergedMDL::SetMergeMDL( MDLHandle_t handle, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData, bool bRequestBonemergeTakeover )
  815. {
  816. // Verify that we have a root model to merge to.
  817. if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
  818. return;
  819. int iIndex = m_aMergeMDLs.AddToTail();
  820. if ( !m_aMergeMDLs.IsValidIndex( iIndex ) )
  821. return;
  822. m_aMergeMDLs[iIndex].m_MDL.SetMDL( handle );
  823. m_aMergeMDLs[iIndex].m_MDL.m_pProxyData = pProxyData;
  824. m_aMergeMDLs[iIndex].m_bRequestBoneMergeTakeover = bRequestBonemergeTakeover;
  825. if ( pCustomMaterialOwner )
  826. {
  827. pCustomMaterialOwner->DuplicateCustomMaterialsToOther( &m_aMergeMDLs[iIndex].m_MDL );
  828. }
  829. }
  830. //-----------------------------------------------------------------------------
  831. // Purpose:
  832. //-----------------------------------------------------------------------------
  833. MDLHandle_t CMergedMDL::SetMergeMDL( const char *pMDLName, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData, bool bRequestBonemergeTakeover )
  834. {
  835. if ( g_pMDLCache == NULL )
  836. return MDLHANDLE_INVALID;
  837. MDLHandle_t hMDL = pMDLName ? g_pMDLCache->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
  838. if ( g_pMDLCache->IsErrorModel( hMDL ) )
  839. {
  840. hMDL = MDLHANDLE_INVALID;
  841. }
  842. SetMergeMDL( hMDL, pCustomMaterialOwner, pProxyData, bRequestBonemergeTakeover );
  843. return hMDL;
  844. }
  845. //-----------------------------------------------------------------------------
  846. // Purpose:
  847. //-----------------------------------------------------------------------------
  848. int CMergedMDL::GetMergeMDLIndex( MDLHandle_t handle )
  849. {
  850. int nMergeCount = m_aMergeMDLs.Count();
  851. for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
  852. {
  853. if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle )
  854. return iMerge;
  855. }
  856. return -1;
  857. }
  858. //-----------------------------------------------------------------------------
  859. // Purpose:
  860. //-----------------------------------------------------------------------------
  861. CMDL *CMergedMDL::GetMergeMDL( MDLHandle_t handle )
  862. {
  863. int nMergeCount = m_aMergeMDLs.Count();
  864. for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
  865. {
  866. if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle )
  867. return (&m_aMergeMDLs[iMerge].m_MDL);
  868. }
  869. return NULL;
  870. }
  871. //-----------------------------------------------------------------------------
  872. // Purpose:
  873. //-----------------------------------------------------------------------------
  874. void CMergedMDL::ClearMergeMDLs( void )
  875. {
  876. m_aMergeMDLs.Purge();
  877. }
  878. //-----------------------------------------------------------------------------
  879. // Purpose:
  880. //-----------------------------------------------------------------------------
  881. void CMergedMDL::UpdateModelCustomMaterials( MDLHandle_t handle, CCustomMaterialOwner* pCustomMaterialOwner )
  882. {
  883. CMDL* pMDL = (handle != MDLHANDLE_INVALID) ? GetMergeMDL( handle ) : NULL;
  884. if ( pMDL )
  885. {
  886. if ( pCustomMaterialOwner )
  887. {
  888. pCustomMaterialOwner->DuplicateCustomMaterialsToOther( pMDL );
  889. }
  890. else
  891. {
  892. pMDL->ClearCustomMaterials();
  893. }
  894. }
  895. }