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

459 lines
13 KiB

  1. //========= Copyright 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 "tier1/callqueue.h"
  9. #include "tier3/tier3.h"
  10. #include "studio.h"
  11. #include "istudiorender.h"
  12. #include "bone_setup.h"
  13. //-----------------------------------------------------------------------------
  14. // Returns the bounding box for the model
  15. //-----------------------------------------------------------------------------
  16. void GetMDLBoundingBox( Vector *pMins, Vector *pMaxs, MDLHandle_t h, int nSequence )
  17. {
  18. if ( h == MDLHANDLE_INVALID || !g_pMDLCache )
  19. {
  20. pMins->Init();
  21. pMaxs->Init();
  22. return;
  23. }
  24. pMins->Init( FLT_MAX, FLT_MAX );
  25. pMaxs->Init( -FLT_MAX, -FLT_MAX );
  26. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( h );
  27. if ( !VectorCompare( vec3_origin, pStudioHdr->view_bbmin ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax ))
  28. {
  29. // look for view clip
  30. *pMins = pStudioHdr->view_bbmin;
  31. *pMaxs = pStudioHdr->view_bbmax;
  32. }
  33. else if ( !VectorCompare( vec3_origin, pStudioHdr->hull_min ) || !VectorCompare( vec3_origin, pStudioHdr->hull_max ))
  34. {
  35. // look for hull
  36. *pMins = pStudioHdr->hull_min;
  37. *pMaxs = pStudioHdr->hull_max;
  38. }
  39. // Else use the sequence box
  40. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSequence );
  41. VectorMin( seqdesc.bbmin, *pMins, *pMins );
  42. VectorMax( seqdesc.bbmax, *pMaxs, *pMaxs );
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Returns the radius of the model as measured from the origin
  46. //-----------------------------------------------------------------------------
  47. float GetMDLRadius( MDLHandle_t h, int nSequence )
  48. {
  49. Vector vecMins, vecMaxs;
  50. GetMDLBoundingBox( &vecMins, &vecMaxs, h, nSequence );
  51. float flRadius = vecMaxs.Length();
  52. float flRadius2 = vecMins.Length();
  53. if ( flRadius2 > flRadius )
  54. {
  55. flRadius = flRadius2;
  56. }
  57. return flRadius;
  58. }
  59. //-----------------------------------------------------------------------------
  60. // Returns a more accurate bounding sphere
  61. //-----------------------------------------------------------------------------
  62. void GetMDLBoundingSphere( Vector *pVecCenter, float *pRadius, MDLHandle_t h, int nSequence )
  63. {
  64. Vector vecMins, vecMaxs;
  65. GetMDLBoundingBox( &vecMins, &vecMaxs, h, nSequence );
  66. VectorAdd( vecMins, vecMaxs, *pVecCenter );
  67. *pVecCenter *= 0.5f;
  68. *pRadius = vecMaxs.DistTo( *pVecCenter );
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Constructor
  72. //-----------------------------------------------------------------------------
  73. CMDL::CMDL()
  74. {
  75. m_MDLHandle = MDLHANDLE_INVALID;
  76. m_Color.SetColor( 255, 255, 255, 255 );
  77. m_nSkin = 0;
  78. m_nBody = 0;
  79. m_nSequence = 0;
  80. m_nLOD = 0;
  81. m_flPlaybackRate = 30.0f;
  82. m_flTime = 0.0f;
  83. m_vecViewTarget.Init( 0, 0, 0 );
  84. m_bWorldSpaceViewTarget = false;
  85. memset( m_pFlexControls, 0, sizeof(m_pFlexControls) );
  86. m_pProxyData = NULL;
  87. }
  88. CMDL::~CMDL()
  89. {
  90. UnreferenceMDL();
  91. }
  92. void CMDL::SetMDL( MDLHandle_t h )
  93. {
  94. UnreferenceMDL();
  95. m_MDLHandle = h;
  96. if ( m_MDLHandle != MDLHANDLE_INVALID )
  97. {
  98. g_pMDLCache->AddRef( m_MDLHandle );
  99. studiohdr_t *pHdr = g_pMDLCache->LockStudioHdr( m_MDLHandle );
  100. if ( pHdr )
  101. {
  102. for ( LocalFlexController_t i = LocalFlexController_t(0); i < pHdr->numflexcontrollers; ++i )
  103. {
  104. if ( pHdr->pFlexcontroller( i )->localToGlobal == -1 )
  105. {
  106. pHdr->pFlexcontroller( i )->localToGlobal = i;
  107. }
  108. }
  109. }
  110. }
  111. }
  112. MDLHandle_t CMDL::GetMDL() const
  113. {
  114. return m_MDLHandle;
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Release the MDL handle
  118. //-----------------------------------------------------------------------------
  119. void CMDL::UnreferenceMDL()
  120. {
  121. if ( !g_pMDLCache )
  122. return;
  123. if ( m_MDLHandle != MDLHANDLE_INVALID )
  124. {
  125. // XXX need to figure out where it is safe to flush the queue during map change to not crash
  126. #if 0
  127. if ( ICallQueue *pCallQueue = materials->GetRenderContext()->GetCallQueue() )
  128. {
  129. // Parallel rendering: don't unlock model data until end of rendering
  130. pCallQueue->QueueCall( g_pMDLCache, &IMDLCache::UnlockStudioHdr, m_MDLHandle );
  131. pCallQueue->QueueCall( g_pMDLCache, &IMDLCache::Release, m_MDLHandle );
  132. }
  133. else
  134. #endif
  135. {
  136. // Immediate-mode rendering, can unlock immediately
  137. g_pMDLCache->UnlockStudioHdr( m_MDLHandle );
  138. g_pMDLCache->Release( m_MDLHandle );
  139. }
  140. m_MDLHandle = MDLHANDLE_INVALID;
  141. }
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Gets the studiohdr
  145. //-----------------------------------------------------------------------------
  146. studiohdr_t *CMDL::GetStudioHdr()
  147. {
  148. if ( !g_pMDLCache )
  149. return NULL;
  150. return g_pMDLCache->GetStudioHdr( m_MDLHandle );
  151. }
  152. //-----------------------------------------------------------------------------
  153. // Draws the mesh
  154. //-----------------------------------------------------------------------------
  155. void CMDL::Draw( const matrix3x4_t& rootToWorld, const matrix3x4_t *pBoneToWorld )
  156. {
  157. if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
  158. return;
  159. if ( m_MDLHandle == MDLHANDLE_INVALID )
  160. return;
  161. // Color + alpha modulation
  162. Vector white( m_Color.r() / 255.0f, m_Color.g() / 255.0f, m_Color.b() / 255.0f );
  163. g_pStudioRender->SetColorModulation( white.Base() );
  164. g_pStudioRender->SetAlphaModulation( m_Color.a() / 255.0f );
  165. DrawModelInfo_t info;
  166. info.m_pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
  167. info.m_pHardwareData = g_pMDLCache->GetHardwareData( m_MDLHandle );
  168. info.m_Decals = STUDIORENDER_DECAL_INVALID;
  169. info.m_Skin = m_nSkin;
  170. info.m_Body = m_nBody;
  171. info.m_HitboxSet = 0;
  172. info.m_pClientEntity = m_pProxyData;
  173. info.m_pColorMeshes = NULL;
  174. info.m_bStaticLighting = false;
  175. info.m_Lod = m_nLOD;
  176. Vector vecWorldViewTarget;
  177. if ( m_bWorldSpaceViewTarget )
  178. {
  179. vecWorldViewTarget = m_vecViewTarget;
  180. }
  181. else
  182. {
  183. VectorTransform( m_vecViewTarget, rootToWorld, vecWorldViewTarget );
  184. }
  185. g_pStudioRender->SetEyeViewTarget( info.m_pStudioHdr, info.m_Body, vecWorldViewTarget );
  186. // FIXME: Why is this necessary!?!?!?
  187. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  188. // Set default flex values
  189. float *pFlexWeights = NULL;
  190. const int nFlexDescCount = info.m_pStudioHdr->numflexdesc;
  191. if ( nFlexDescCount )
  192. {
  193. CStudioHdr cStudioHdr( info.m_pStudioHdr, g_pMDLCache );
  194. g_pStudioRender->LockFlexWeights( info.m_pStudioHdr->numflexdesc, &pFlexWeights );
  195. cStudioHdr.RunFlexRules( m_pFlexControls, pFlexWeights );
  196. g_pStudioRender->UnlockFlexWeights();
  197. }
  198. Vector vecModelOrigin;
  199. MatrixGetColumn( rootToWorld, 3, vecModelOrigin );
  200. g_pStudioRender->DrawModel( NULL, info, const_cast<matrix3x4_t*>( pBoneToWorld ),
  201. pFlexWeights, NULL, vecModelOrigin, STUDIORENDER_DRAW_ENTIRE_MODEL );
  202. }
  203. void CMDL::Draw( const matrix3x4_t &rootToWorld )
  204. {
  205. if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
  206. return;
  207. if ( m_MDLHandle == MDLHANDLE_INVALID )
  208. return;
  209. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
  210. matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( pStudioHdr->numbones );
  211. SetUpBones( rootToWorld, pStudioHdr->numbones, pBoneToWorld );
  212. g_pStudioRender->UnlockBoneMatrices();
  213. Draw( rootToWorld, pBoneToWorld );
  214. }
  215. void CMDL::SetUpBones( const matrix3x4_t& rootToWorld, int nMaxBoneCount, matrix3x4_t *pBoneToWorld, const float *pPoseParameters, MDLSquenceLayer_t *pSequenceLayers, int nNumSequenceLayers )
  216. {
  217. CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_MDLHandle ), g_pMDLCache );
  218. float pPoseParameter[MAXSTUDIOPOSEPARAM];
  219. if ( pPoseParameters )
  220. {
  221. V_memcpy( pPoseParameter, pPoseParameters, sizeof(pPoseParameter) );
  222. }
  223. else
  224. {
  225. // Default to middle of the pose parameter range
  226. int nPoseCount = studioHdr.GetNumPoseParameters();
  227. for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i )
  228. {
  229. pPoseParameter[i] = 0.5f;
  230. if ( i < nPoseCount )
  231. {
  232. const mstudioposeparamdesc_t &Pose = studioHdr.pPoseParameter( i );
  233. // Want to try for a zero state. If one doesn't exist set it to .5 by default.
  234. if ( Pose.start < 0.0f && Pose.end > 0.0f )
  235. {
  236. float flPoseDelta = Pose.end - Pose.start;
  237. pPoseParameter[i] = -Pose.start / flPoseDelta;
  238. }
  239. }
  240. }
  241. }
  242. int nFrameCount = Studio_MaxFrame( &studioHdr, m_nSequence, pPoseParameter );
  243. if ( nFrameCount == 0 )
  244. {
  245. nFrameCount = 1;
  246. }
  247. float flCycle = ( m_flTime * m_flPlaybackRate ) / nFrameCount;
  248. // FIXME: We're always wrapping; may want to determing if we should clamp
  249. flCycle -= (int)(flCycle);
  250. Vector pos[MAXSTUDIOBONES];
  251. Quaternion q[MAXSTUDIOBONES];
  252. IBoneSetup boneSetup( &studioHdr, BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ), pPoseParameter, NULL );
  253. boneSetup.InitPose( pos, q );
  254. boneSetup.AccumulatePose( pos, q, m_nSequence, flCycle, 1.0f, m_flTime, NULL );
  255. // Accumulate the additional layers if specified.
  256. if ( pSequenceLayers )
  257. {
  258. int nNumSeq = studioHdr.GetNumSeq();
  259. for ( int i = 0; i < nNumSequenceLayers; ++i )
  260. {
  261. int nSeqIndex = pSequenceLayers[ i ].m_nSequenceIndex;
  262. if ( ( nSeqIndex >= 0 ) && ( nSeqIndex < nNumSeq ) )
  263. {
  264. float flWeight = pSequenceLayers[ i ].m_flWeight;
  265. float flLayerCycle;
  266. int nLayerFrameCount = MAX( 1, Studio_MaxFrame( &studioHdr, nSeqIndex, pPoseParameter ) );
  267. if ( pSequenceLayers[i].m_bNoLoop )
  268. {
  269. if ( pSequenceLayers[i].m_flCycleBeganAt == 0 )
  270. {
  271. pSequenceLayers[i].m_flCycleBeganAt = m_flTime;
  272. }
  273. float flElapsedTime = m_flTime - pSequenceLayers[i].m_flCycleBeganAt;
  274. flLayerCycle = ( flElapsedTime * m_flPlaybackRate ) / nLayerFrameCount;
  275. // Should we keep playing layers that have ended?
  276. //if ( flLayerCycle >= 1.0 )
  277. //continue;
  278. }
  279. else
  280. {
  281. flLayerCycle = ( m_flTime * m_flPlaybackRate ) / nLayerFrameCount;
  282. // FIXME: We're always wrapping; may want to determing if we should clamp
  283. flLayerCycle -= (int)(flLayerCycle);
  284. }
  285. boneSetup.AccumulatePose( pos, q, nSeqIndex, flLayerCycle, flWeight, m_flTime, NULL );
  286. }
  287. }
  288. }
  289. // FIXME: Try enabling this?
  290. // CalcAutoplaySequences( pStudioHdr, NULL, pos, q, pPoseParameter, BONE_USED_BY_VERTEX_AT_LOD( m_nLOD ), flTime );
  291. matrix3x4_t temp;
  292. if ( nMaxBoneCount > studioHdr.numbones() )
  293. {
  294. nMaxBoneCount = studioHdr.numbones();
  295. }
  296. for ( int i = 0; i < nMaxBoneCount; i++ )
  297. {
  298. // If it's not being used, fill with NAN for errors
  299. #ifdef _DEBUG
  300. if ( !(studioHdr.pBone( i )->flags & BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ) ) )
  301. {
  302. int j, k;
  303. for (j = 0; j < 3; j++)
  304. {
  305. for (k = 0; k < 4; k++)
  306. {
  307. pBoneToWorld[i][j][k] = VEC_T_NAN;
  308. }
  309. }
  310. continue;
  311. }
  312. #endif
  313. matrix3x4_t boneMatrix;
  314. QuaternionMatrix( q[i], boneMatrix );
  315. MatrixSetColumn( pos[i], 3, boneMatrix );
  316. if ( studioHdr.pBone(i)->parent == -1 )
  317. {
  318. ConcatTransforms( rootToWorld, boneMatrix, pBoneToWorld[i] );
  319. }
  320. else
  321. {
  322. ConcatTransforms( pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] );
  323. }
  324. }
  325. Studio_RunBoneFlexDrivers( m_pFlexControls, &studioHdr, pos, pBoneToWorld, rootToWorld );
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Purpose:
  329. //-----------------------------------------------------------------------------
  330. void CMDL::SetupBonesWithBoneMerge( const CStudioHdr *pMergeHdr, matrix3x4_t *pMergeBoneToWorld,
  331. const CStudioHdr *pFollow, const matrix3x4_t *pFollowBoneToWorld,
  332. const matrix3x4_t &matModelToWorld )
  333. {
  334. // Default to middle of the pose parameter range
  335. int nPoseCount = pMergeHdr->GetNumPoseParameters();
  336. float pPoseParameter[MAXSTUDIOPOSEPARAM];
  337. for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i )
  338. {
  339. pPoseParameter[i] = 0.5f;
  340. if ( i < nPoseCount )
  341. {
  342. const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)pMergeHdr)->pPoseParameter( i );
  343. // Want to try for a zero state. If one doesn't exist set it to .5 by default.
  344. if ( Pose.start < 0.0f && Pose.end > 0.0f )
  345. {
  346. float flPoseDelta = Pose.end - Pose.start;
  347. pPoseParameter[i] = -Pose.start / flPoseDelta;
  348. }
  349. }
  350. }
  351. int nFrameCount = Studio_MaxFrame( pMergeHdr, m_nSequence, pPoseParameter );
  352. if ( nFrameCount == 0 )
  353. {
  354. nFrameCount = 1;
  355. }
  356. float flCycle = ( m_flTime * m_flPlaybackRate ) / nFrameCount;
  357. // FIXME: We're always wrapping; may want to determing if we should clamp
  358. flCycle -= (int)(flCycle);
  359. Vector pos[MAXSTUDIOBONES];
  360. Quaternion q[MAXSTUDIOBONES];
  361. IBoneSetup boneSetup( pMergeHdr, BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ), pPoseParameter );
  362. boneSetup.InitPose( pos, q );
  363. boneSetup.AccumulatePose( pos, q, m_nSequence, flCycle, 1.0f, m_flTime, NULL );
  364. // Get the merge bone list.
  365. mstudiobone_t *pMergeBones = pMergeHdr->pBone( 0 );
  366. for ( int iMergeBone = 0; iMergeBone < pMergeHdr->numbones(); ++iMergeBone )
  367. {
  368. // Now find the bone in the parent entity.
  369. bool bMerged = false;
  370. int iParentBoneIndex = Studio_BoneIndexByName( pFollow, pMergeBones[iMergeBone].pszName() );
  371. if ( iParentBoneIndex >= 0 )
  372. {
  373. MatrixCopy( pFollowBoneToWorld[iParentBoneIndex], pMergeBoneToWorld[iMergeBone] );
  374. bMerged = true;
  375. }
  376. if ( !bMerged )
  377. {
  378. // If we get down here, then the bone wasn't merged.
  379. matrix3x4_t matBone;
  380. QuaternionMatrix( q[iMergeBone], pos[iMergeBone], matBone );
  381. if ( pMergeBones[iMergeBone].parent == -1 )
  382. {
  383. ConcatTransforms( matModelToWorld, matBone, pMergeBoneToWorld[iMergeBone] );
  384. }
  385. else
  386. {
  387. ConcatTransforms( pMergeBoneToWorld[pMergeBones[iMergeBone].parent], matBone, pMergeBoneToWorld[iMergeBone] );
  388. }
  389. }
  390. }
  391. }