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.

868 lines
24 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "mathlib/vmatrix.h"
  9. #include "ragdoll_shared.h"
  10. #include "bone_setup.h"
  11. #include "materialsystem/imesh.h"
  12. #include "engine/ivmodelinfo.h"
  13. #include "iviewrender.h"
  14. #include "tier0/vprof.h"
  15. #include "view.h"
  16. #include "physics_saverestore.h"
  17. #include "vphysics/constraints.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. #ifdef _DEBUG
  21. extern ConVar r_FadeProps;
  22. #endif
  23. CRagdoll::CRagdoll()
  24. {
  25. m_ragdoll.listCount = 0;
  26. m_vecLastOrigin.Init();
  27. m_flLastOriginChangeTime = - 1.0f;
  28. m_lastUpdate = -FLT_MAX;
  29. }
  30. #define DEFINE_RAGDOLL_ELEMENT( i ) \
  31. DEFINE_FIELD( m_ragdoll.list[i].originParentSpace, FIELD_VECTOR ), \
  32. DEFINE_PHYSPTR( m_ragdoll.list[i].pObject ), \
  33. DEFINE_PHYSPTR( m_ragdoll.list[i].pConstraint ), \
  34. DEFINE_FIELD( m_ragdoll.list[i].parentIndex, FIELD_INTEGER )
  35. BEGIN_SIMPLE_DATADESC( CRagdoll )
  36. DEFINE_AUTO_ARRAY( m_ragdoll.boneIndex, FIELD_INTEGER ),
  37. DEFINE_FIELD( m_ragdoll.listCount, FIELD_INTEGER ),
  38. DEFINE_FIELD( m_ragdoll.allowStretch, FIELD_BOOLEAN ),
  39. DEFINE_PHYSPTR( m_ragdoll.pGroup ),
  40. DEFINE_RAGDOLL_ELEMENT( 0 ),
  41. DEFINE_RAGDOLL_ELEMENT( 1 ),
  42. DEFINE_RAGDOLL_ELEMENT( 2 ),
  43. DEFINE_RAGDOLL_ELEMENT( 3 ),
  44. DEFINE_RAGDOLL_ELEMENT( 4 ),
  45. DEFINE_RAGDOLL_ELEMENT( 5 ),
  46. DEFINE_RAGDOLL_ELEMENT( 6 ),
  47. DEFINE_RAGDOLL_ELEMENT( 7 ),
  48. DEFINE_RAGDOLL_ELEMENT( 8 ),
  49. DEFINE_RAGDOLL_ELEMENT( 9 ),
  50. DEFINE_RAGDOLL_ELEMENT( 10 ),
  51. DEFINE_RAGDOLL_ELEMENT( 11 ),
  52. DEFINE_RAGDOLL_ELEMENT( 12 ),
  53. DEFINE_RAGDOLL_ELEMENT( 13 ),
  54. DEFINE_RAGDOLL_ELEMENT( 14 ),
  55. DEFINE_RAGDOLL_ELEMENT( 15 ),
  56. DEFINE_RAGDOLL_ELEMENT( 16 ),
  57. DEFINE_RAGDOLL_ELEMENT( 17 ),
  58. DEFINE_RAGDOLL_ELEMENT( 18 ),
  59. DEFINE_RAGDOLL_ELEMENT( 19 ),
  60. DEFINE_RAGDOLL_ELEMENT( 20 ),
  61. DEFINE_RAGDOLL_ELEMENT( 21 ),
  62. DEFINE_RAGDOLL_ELEMENT( 22 ),
  63. DEFINE_RAGDOLL_ELEMENT( 23 ),
  64. END_DATADESC()
  65. IPhysicsObject *CRagdoll::GetElement( int elementNum )
  66. {
  67. return m_ragdoll.list[elementNum].pObject;
  68. }
  69. void CRagdoll::BuildRagdollBounds( C_BaseEntity *ent )
  70. {
  71. Vector mins, maxs, size;
  72. modelinfo->GetModelBounds( ent->GetModel(), mins, maxs );
  73. size = (maxs - mins) * 0.5;
  74. m_radius = size.Length();
  75. m_mins.Init(-m_radius,-m_radius,-m_radius);
  76. m_maxs.Init(m_radius,m_radius,m_radius);
  77. }
  78. void CRagdoll::Init(
  79. C_BaseEntity *ent,
  80. CStudioHdr *pstudiohdr,
  81. const Vector &forceVector,
  82. int forceBone,
  83. const matrix3x4_t *pDeltaBones0,
  84. const matrix3x4_t *pDeltaBones1,
  85. const matrix3x4_t *pCurrentBonePosition,
  86. float dt,
  87. bool bFixedConstraints )
  88. {
  89. ragdollparams_t params;
  90. params.pGameData = static_cast<void *>( ent );
  91. params.modelIndex = ent->GetModelIndex();
  92. params.pCollide = modelinfo->GetVCollide( params.modelIndex );
  93. params.pStudioHdr = pstudiohdr;
  94. params.forceVector = forceVector;
  95. params.forceBoneIndex = forceBone;
  96. params.forcePosition.Init();
  97. params.pCurrentBones = pCurrentBonePosition;
  98. params.jointFrictionScale = 1.0;
  99. params.allowStretch = false;
  100. params.fixedConstraints = bFixedConstraints;
  101. RagdollCreate( m_ragdoll, params, physenv );
  102. ent->VPhysicsSetObject( NULL );
  103. ent->VPhysicsSetObject( m_ragdoll.list[0].pObject );
  104. // Mark the ragdoll as debris.
  105. ent->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  106. RagdollApplyAnimationAsVelocity( m_ragdoll, pDeltaBones0, pDeltaBones1, dt );
  107. RagdollActivate( m_ragdoll, params.pCollide, ent->GetModelIndex() );
  108. // It's moving now...
  109. m_flLastOriginChangeTime = gpGlobals->curtime;
  110. // So traces hit it.
  111. ent->AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  112. if ( !m_ragdoll.listCount )
  113. return;
  114. BuildRagdollBounds( ent );
  115. for ( int i = 0; i < m_ragdoll.listCount; i++ )
  116. {
  117. g_pPhysSaveRestoreManager->AssociateModel( m_ragdoll.list[i].pObject, ent->GetModelIndex() );
  118. }
  119. #if RAGDOLL_VISUALIZE
  120. memcpy( m_savedBone1, &pDeltaBones0[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
  121. memcpy( m_savedBone2, &pDeltaBones1[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
  122. memcpy( m_savedBone3, &pCurrentBonePosition[0], sizeof(matrix3x4_t) * pstudiohdr->numbones() );
  123. #endif
  124. }
  125. CRagdoll::~CRagdoll( void )
  126. {
  127. for ( int i = 0; i < m_ragdoll.listCount; i++ )
  128. {
  129. IPhysicsObject *pObject = m_ragdoll.list[i].pObject;
  130. if ( pObject )
  131. {
  132. g_pPhysSaveRestoreManager->ForgetModel( m_ragdoll.list[i].pObject );
  133. // Disable collision on all ragdoll parts before calling RagdollDestroy
  134. // (which might cause touch callbacks on the ragdoll otherwise, which is
  135. // very bad for a half deleted ragdoll).
  136. pObject->EnableCollisions( false );
  137. }
  138. }
  139. RagdollDestroy( m_ragdoll );
  140. }
  141. void CRagdoll::RagdollBone( C_BaseEntity *ent, mstudiobone_t *pbones, int boneCount, bool *boneSimulated, CBoneAccessor &pBoneToWorld )
  142. {
  143. for ( int i = 0; i < m_ragdoll.listCount; i++ )
  144. {
  145. if ( RagdollGetBoneMatrix( m_ragdoll, pBoneToWorld, i ) )
  146. {
  147. boneSimulated[m_ragdoll.boneIndex[i]] = true;
  148. }
  149. }
  150. }
  151. const Vector& CRagdoll::GetRagdollOrigin( )
  152. {
  153. m_ragdoll.list[0].pObject->GetPosition( &m_origin, 0 );
  154. return m_origin;
  155. }
  156. void CRagdoll::GetRagdollBounds( Vector &theMins, Vector &theMaxs )
  157. {
  158. theMins = m_mins;
  159. theMaxs = m_maxs;
  160. }
  161. void CRagdoll::VPhysicsUpdate( IPhysicsObject *pPhysics )
  162. {
  163. if ( m_lastUpdate == gpGlobals->curtime )
  164. return;
  165. m_lastUpdate = gpGlobals->curtime;
  166. m_allAsleep = RagdollIsAsleep( m_ragdoll );
  167. if ( m_allAsleep )
  168. {
  169. // NOTE: This is the bbox of the ragdoll's physics
  170. // It's not always correct to use for culling, but it sure beats
  171. // using the radius box!
  172. Vector origin = GetRagdollOrigin();
  173. RagdollComputeExactBbox( m_ragdoll, origin, m_mins, m_maxs );
  174. m_mins -= origin;
  175. m_maxs -= origin;
  176. }
  177. else
  178. {
  179. m_mins.Init(-m_radius,-m_radius,-m_radius);
  180. m_maxs.Init(m_radius,m_radius,m_radius);
  181. if ( m_ragdoll.pGroup->IsInErrorState() )
  182. {
  183. C_BaseEntity *pEntity = static_cast<C_BaseEntity *>(m_ragdoll.list[0].pObject->GetGameData());
  184. RagdollSolveSeparation( m_ragdoll, pEntity );
  185. }
  186. }
  187. // See if we should go to sleep...
  188. CheckSettleStationaryRagdoll();
  189. }
  190. //=============================================================================
  191. // HPE_BEGIN:
  192. // [menglish] Transforms a vector from the given bone's space to world space
  193. //=============================================================================
  194. bool CRagdoll::TransformVectorToWorld(int iBoneIndex, const Vector *vPosition, Vector *vOut)
  195. {
  196. int listIndex = -1;
  197. if( iBoneIndex >= 0 && iBoneIndex < m_ragdoll.listCount)
  198. {
  199. for ( int i = 0; i < m_ragdoll.listCount; ++i )
  200. {
  201. if(m_ragdoll.boneIndex[i] == iBoneIndex)
  202. listIndex = i;
  203. }
  204. if(listIndex != -1)
  205. {
  206. m_ragdoll.list[listIndex].pObject->LocalToWorld(vOut, *vPosition);
  207. return true;
  208. }
  209. }
  210. return false;
  211. }
  212. //=============================================================================
  213. // HPE_END
  214. //=============================================================================
  215. //-----------------------------------------------------------------------------
  216. // Purpose:
  217. // Input : -
  218. //-----------------------------------------------------------------------------
  219. void CRagdoll::PhysForceRagdollToSleep()
  220. {
  221. for ( int i = 0; i < m_ragdoll.listCount; i++ )
  222. {
  223. if ( m_ragdoll.list[i].pObject )
  224. {
  225. PhysForceClearVelocity( m_ragdoll.list[i].pObject );
  226. m_ragdoll.list[i].pObject->Sleep();
  227. }
  228. }
  229. }
  230. #define RAGDOLL_SLEEP_TOLERANCE 1.0f
  231. static ConVar ragdoll_sleepaftertime( "ragdoll_sleepaftertime", "5.0f", 0, "After this many seconds of being basically stationary, the ragdoll will go to sleep." );
  232. void CRagdoll::CheckSettleStationaryRagdoll()
  233. {
  234. Vector delta = GetRagdollOrigin() - m_vecLastOrigin;
  235. m_vecLastOrigin = GetRagdollOrigin();
  236. for ( int i = 0; i < 3; ++i )
  237. {
  238. // It's still moving...
  239. if ( fabs( delta[ i ] ) > RAGDOLL_SLEEP_TOLERANCE )
  240. {
  241. m_flLastOriginChangeTime = gpGlobals->curtime;
  242. // Msg( "%d [%p] Still moving\n", gpGlobals->tickcount, this );
  243. return;
  244. }
  245. }
  246. // It's totally asleep, don't worry about forcing it to settle
  247. if ( m_allAsleep )
  248. return;
  249. // Msg( "%d [%p] Settling\n", gpGlobals->tickcount, this );
  250. // It has stopped moving, see if it
  251. float dt = gpGlobals->curtime - m_flLastOriginChangeTime;
  252. if ( dt < ragdoll_sleepaftertime.GetFloat() )
  253. return;
  254. // Msg( "%d [%p] FORCE SLEEP\n",gpGlobals->tickcount, this );
  255. // Force it to go to sleep
  256. PhysForceRagdollToSleep();
  257. }
  258. void CRagdoll::ResetRagdollSleepAfterTime( void )
  259. {
  260. m_flLastOriginChangeTime = gpGlobals->curtime;
  261. }
  262. void CRagdoll::DrawWireframe()
  263. {
  264. IMaterial *pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
  265. int i;
  266. matrix3x4_t matrix;
  267. for ( i = 0; i < m_ragdoll.listCount; i++ )
  268. {
  269. static color32 debugColor = {0,255,255,0};
  270. // draw the actual physics positions, not the cleaned up animation position
  271. m_ragdoll.list[i].pObject->GetPositionMatrix( &matrix );
  272. const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
  273. engine->DebugDrawPhysCollide( pCollide, pWireframe, matrix, debugColor );
  274. }
  275. #if RAGDOLL_VISUALIZE
  276. for ( i = 0; i < m_ragdoll.listCount; i++ )
  277. {
  278. static color32 debugColor = {255,0,0,0};
  279. const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
  280. engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone1[m_ragdoll.boneIndex[i]], debugColor );
  281. }
  282. for ( i = 0; i < m_ragdoll.listCount; i++ )
  283. {
  284. static color32 debugColor = {0,255,0,0};
  285. const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
  286. engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone2[m_ragdoll.boneIndex[i]], debugColor );
  287. }
  288. for ( i = 0; i < m_ragdoll.listCount; i++ )
  289. {
  290. static color32 debugColor = {0,0,255,0};
  291. const CPhysCollide *pCollide = m_ragdoll.list[i].pObject->GetCollide();
  292. engine->DebugDrawPhysCollide( pCollide, pWireframe, m_savedBone3[m_ragdoll.boneIndex[i]], debugColor );
  293. }
  294. #endif
  295. }
  296. CRagdoll *CreateRagdoll(
  297. C_BaseEntity *ent,
  298. CStudioHdr *pstudiohdr,
  299. const Vector &forceVector,
  300. int forceBone,
  301. const matrix3x4_t *pDeltaBones0,
  302. const matrix3x4_t *pDeltaBones1,
  303. const matrix3x4_t *pCurrentBonePosition,
  304. float dt,
  305. bool bFixedConstraints )
  306. {
  307. CRagdoll *pRagdoll = new CRagdoll;
  308. pRagdoll->Init( ent, pstudiohdr, forceVector, forceBone, pDeltaBones0, pDeltaBones1, pCurrentBonePosition, dt, bFixedConstraints );
  309. if ( !pRagdoll->IsValid() )
  310. {
  311. Msg("Bad ragdoll for %s\n", pstudiohdr->pszName() );
  312. delete pRagdoll;
  313. pRagdoll = NULL;
  314. }
  315. return pRagdoll;
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose:
  319. //-----------------------------------------------------------------------------
  320. class C_ServerRagdoll : public C_BaseAnimating
  321. {
  322. public:
  323. DECLARE_CLASS( C_ServerRagdoll, C_BaseAnimating );
  324. DECLARE_CLIENTCLASS();
  325. DECLARE_INTERPOLATION();
  326. C_ServerRagdoll( void );
  327. virtual void PostDataUpdate( DataUpdateType_t updateType );
  328. virtual int InternalDrawModel( int flags );
  329. virtual CStudioHdr *OnNewModel( void );
  330. virtual unsigned char GetClientSideFade();
  331. virtual void SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights );
  332. void GetRenderBounds( Vector& theMins, Vector& theMaxs );
  333. virtual void AddEntity( void );
  334. virtual void AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime );
  335. virtual void BuildTransformations( CStudioHdr *pStudioHdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed );
  336. IPhysicsObject *GetElement( int elementNum );
  337. virtual void UpdateOnRemove();
  338. virtual float LastBoneChangedTime();
  339. // Incoming from network
  340. Vector m_ragPos[RAGDOLL_MAX_ELEMENTS];
  341. QAngle m_ragAngles[RAGDOLL_MAX_ELEMENTS];
  342. CInterpolatedVarArray< Vector, RAGDOLL_MAX_ELEMENTS > m_iv_ragPos;
  343. CInterpolatedVarArray< QAngle, RAGDOLL_MAX_ELEMENTS > m_iv_ragAngles;
  344. int m_elementCount;
  345. int m_boneIndex[RAGDOLL_MAX_ELEMENTS];
  346. private:
  347. C_ServerRagdoll( const C_ServerRagdoll &src );
  348. typedef CHandle<C_BaseAnimating> CBaseAnimatingHandle;
  349. CNetworkVar( CBaseAnimatingHandle, m_hUnragdoll );
  350. CNetworkVar( float, m_flBlendWeight );
  351. float m_flBlendWeightCurrent;
  352. CNetworkVar( int, m_nOverlaySequence );
  353. float m_flLastBoneChangeTime;
  354. };
  355. EXTERN_RECV_TABLE(DT_Ragdoll);
  356. IMPLEMENT_CLIENTCLASS_DT(C_ServerRagdoll, DT_Ragdoll, CRagdollProp)
  357. RecvPropArray(RecvPropQAngles(RECVINFO(m_ragAngles[0])), m_ragAngles),
  358. RecvPropArray(RecvPropVector(RECVINFO(m_ragPos[0])), m_ragPos),
  359. RecvPropEHandle(RECVINFO(m_hUnragdoll)),
  360. RecvPropFloat(RECVINFO(m_flBlendWeight)),
  361. RecvPropInt(RECVINFO(m_nOverlaySequence)),
  362. END_RECV_TABLE()
  363. C_ServerRagdoll::C_ServerRagdoll( void ) :
  364. m_iv_ragPos("C_ServerRagdoll::m_iv_ragPos"),
  365. m_iv_ragAngles("C_ServerRagdoll::m_iv_ragAngles")
  366. {
  367. m_elementCount = 0;
  368. m_flLastBoneChangeTime = -FLT_MAX;
  369. AddVar( m_ragPos, &m_iv_ragPos, LATCH_SIMULATION_VAR );
  370. AddVar( m_ragAngles, &m_iv_ragAngles, LATCH_SIMULATION_VAR );
  371. m_flBlendWeight = 0.0f;
  372. m_flBlendWeightCurrent = 0.0f;
  373. m_nOverlaySequence = -1;
  374. m_flFadeScale = 1;
  375. }
  376. void C_ServerRagdoll::PostDataUpdate( DataUpdateType_t updateType )
  377. {
  378. BaseClass::PostDataUpdate( updateType );
  379. m_iv_ragPos.NoteChanged( gpGlobals->curtime, true );
  380. m_iv_ragAngles.NoteChanged( gpGlobals->curtime, true );
  381. // this is the local client time at which this update becomes stale
  382. m_flLastBoneChangeTime = gpGlobals->curtime + GetInterpolationAmount(m_iv_ragPos.GetType());
  383. }
  384. float C_ServerRagdoll::LastBoneChangedTime()
  385. {
  386. return m_flLastBoneChangeTime;
  387. }
  388. int C_ServerRagdoll::InternalDrawModel( int flags )
  389. {
  390. int ret = BaseClass::InternalDrawModel( flags );
  391. if ( vcollide_wireframe.GetBool() )
  392. {
  393. vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
  394. IMaterial *pWireframe = materials->FindMaterial("shadertest/wireframevertexcolor", TEXTURE_GROUP_OTHER);
  395. matrix3x4_t matrix;
  396. for ( int i = 0; i < m_elementCount; i++ )
  397. {
  398. static color32 debugColor = {0,255,255,0};
  399. AngleMatrix( m_ragAngles[i], m_ragPos[i], matrix );
  400. engine->DebugDrawPhysCollide( pCollide->solids[i], pWireframe, matrix, debugColor );
  401. }
  402. }
  403. return ret;
  404. }
  405. CStudioHdr *C_ServerRagdoll::OnNewModel( void )
  406. {
  407. CStudioHdr *hdr = BaseClass::OnNewModel();
  408. if ( !m_elementCount )
  409. {
  410. vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
  411. if ( !pCollide )
  412. {
  413. const char *pszName = modelinfo->GetModelName( modelinfo->GetModel( GetModelIndex() ) );
  414. Msg( "*** ERROR: C_ServerRagdoll::InitModel: %s missing vcollide data ***\n", (pszName) ? pszName : "<null>" );
  415. m_elementCount = 0;
  416. }
  417. else
  418. {
  419. m_elementCount = RagdollExtractBoneIndices( m_boneIndex, hdr, pCollide );
  420. }
  421. m_iv_ragPos.SetMaxCount( m_elementCount );
  422. m_iv_ragAngles.SetMaxCount( m_elementCount );
  423. }
  424. return hdr;
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Purpose: clear out any face/eye values stored in the material system
  428. //-----------------------------------------------------------------------------
  429. void C_ServerRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  430. {
  431. BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
  432. CStudioHdr *hdr = GetModelPtr();
  433. if ( !hdr )
  434. return;
  435. int nFlexDescCount = hdr->numflexdesc();
  436. if ( nFlexDescCount )
  437. {
  438. Assert( !pFlexDelayedWeights );
  439. memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) );
  440. }
  441. if ( m_iEyeAttachment > 0 )
  442. {
  443. matrix3x4_t attToWorld;
  444. if (GetAttachment( m_iEyeAttachment, attToWorld ))
  445. {
  446. Vector local, tmp;
  447. local.Init( 1000.0f, 0.0f, 0.0f );
  448. VectorTransform( local, attToWorld, tmp );
  449. modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp );
  450. }
  451. }
  452. }
  453. void C_ServerRagdoll::GetRenderBounds( Vector& theMins, Vector& theMaxs )
  454. {
  455. if( !CollisionProp()->IsBoundsDefinedInEntitySpace() )
  456. {
  457. IRotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), theMins, theMaxs );
  458. }
  459. else
  460. {
  461. theMins = CollisionProp()->OBBMins();
  462. theMaxs = CollisionProp()->OBBMaxs();
  463. }
  464. }
  465. void C_ServerRagdoll::AddEntity( void )
  466. {
  467. BaseClass::AddEntity();
  468. // Move blend weight toward target over 0.2 seconds
  469. m_flBlendWeightCurrent = Approach( m_flBlendWeight, m_flBlendWeightCurrent, gpGlobals->frametime * 5.0f );
  470. }
  471. void C_ServerRagdoll::AccumulateLayers( IBoneSetup &boneSetup, Vector pos[], Quaternion q[], float currentTime )
  472. {
  473. BaseClass::AccumulateLayers( boneSetup, pos, q, currentTime );
  474. if ( m_nOverlaySequence >= 0 && m_nOverlaySequence < boneSetup.GetStudioHdr()->GetNumSeq() )
  475. {
  476. boneSetup.AccumulatePose( pos, q, m_nOverlaySequence, GetCycle(), m_flBlendWeightCurrent, currentTime, m_pIk );
  477. }
  478. }
  479. void C_ServerRagdoll::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed )
  480. {
  481. if ( !hdr )
  482. return;
  483. matrix3x4_t bonematrix;
  484. bool boneSimulated[MAXSTUDIOBONES];
  485. // no bones have been simulated
  486. memset( boneSimulated, 0, sizeof(boneSimulated) );
  487. mstudiobone_t *pbones = hdr->pBone( 0 );
  488. mstudioseqdesc_t *pSeqDesc = NULL;
  489. if ( m_nOverlaySequence >= 0 && m_nOverlaySequence < hdr->GetNumSeq() )
  490. {
  491. pSeqDesc = &hdr->pSeqdesc( m_nOverlaySequence );
  492. }
  493. int i;
  494. for ( i = 0; i < m_elementCount; i++ )
  495. {
  496. int iBone = m_boneIndex[i];
  497. if ( iBone >= 0 )
  498. {
  499. if ( hdr->boneFlags( iBone ) & boneMask )
  500. {
  501. boneSimulated[iBone] = true;
  502. matrix3x4_t &matrix = GetBoneForWrite( iBone );
  503. if ( m_flBlendWeightCurrent != 0.0f && pSeqDesc &&
  504. // FIXME: this bone access is illegal
  505. pSeqDesc->weight( iBone ) != 0.0f )
  506. {
  507. // Use the animated bone position instead
  508. boneSimulated[iBone] = false;
  509. }
  510. else
  511. {
  512. AngleMatrix( m_ragAngles[i], m_ragPos[i], matrix );
  513. }
  514. }
  515. }
  516. }
  517. for ( i = 0; i < hdr->numbones(); i++ )
  518. {
  519. if ( !( hdr->boneFlags( i ) & boneMask ) )
  520. continue;
  521. // BUGBUG: Merge this code with the code in c_baseanimating somehow!!!
  522. // animate all non-simulated bones
  523. if ( boneSimulated[i] ||
  524. CalcProceduralBone( hdr, i, m_BoneAccessor ) )
  525. {
  526. continue;
  527. }
  528. else
  529. {
  530. QuaternionMatrix( q[i], pos[i], bonematrix );
  531. if (pbones[i].parent == -1)
  532. {
  533. ConcatTransforms( cameraTransform, bonematrix, GetBoneForWrite( i ) );
  534. }
  535. else
  536. {
  537. ConcatTransforms( GetBone( pbones[i].parent ), bonematrix, GetBoneForWrite( i ) );
  538. }
  539. }
  540. if ( pbones[i].parent == -1 )
  541. {
  542. // Apply client-side effects to the transformation matrix
  543. // ApplyBoneMatrixTransform( GetBoneForWrite( i ) );
  544. }
  545. }
  546. }
  547. IPhysicsObject *C_ServerRagdoll::GetElement( int elementNum )
  548. {
  549. return NULL;
  550. }
  551. //-----------------------------------------------------------------------------
  552. // Purpose:
  553. // Output : virtual void
  554. //-----------------------------------------------------------------------------
  555. void C_ServerRagdoll::UpdateOnRemove()
  556. {
  557. C_BaseAnimating *anim = m_hUnragdoll.Get();
  558. if ( NULL != anim &&
  559. anim->GetModel() &&
  560. ( anim->GetModel() == GetModel() ) )
  561. {
  562. // Need to tell C_BaseAnimating to blend out of the ragdoll data that we received last
  563. C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false );
  564. anim->CreateUnragdollInfo( this );
  565. }
  566. // Do last to mimic destrictor order
  567. BaseClass::UpdateOnRemove();
  568. }
  569. //-----------------------------------------------------------------------------
  570. // Fade out
  571. //-----------------------------------------------------------------------------
  572. unsigned char C_ServerRagdoll::GetClientSideFade()
  573. {
  574. return UTIL_ComputeEntityFade( this, m_fadeMinDist, m_fadeMaxDist, m_flFadeScale );
  575. }
  576. static int GetHighestBit( int flags )
  577. {
  578. for ( int i = 31; i >= 0; --i )
  579. {
  580. if ( flags & (1<<i) )
  581. return (1<<i);
  582. }
  583. return 0;
  584. }
  585. #define ATTACH_INTERP_TIME 0.2
  586. class C_ServerRagdollAttached : public C_ServerRagdoll
  587. {
  588. DECLARE_CLASS( C_ServerRagdollAttached, C_ServerRagdoll );
  589. public:
  590. C_ServerRagdollAttached( void )
  591. {
  592. m_bHasParent = false;
  593. m_vecOffset.Init();
  594. }
  595. DECLARE_CLIENTCLASS();
  596. bool SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  597. {
  598. if ( GetMoveParent() )
  599. {
  600. // HACKHACK: Force the attached bone to be set up
  601. int iBone = m_boneIndex[m_ragdollAttachedObjectIndex];
  602. int boneFlags = GetModelPtr()->boneFlags( iBone );
  603. if ( !(boneFlags & boneMask) )
  604. {
  605. // BUGBUG: The attached bone is required and this call is going to skip it, so force it
  606. // HACKHACK: Assume the highest bit numbered bone flag is the minimum bone set
  607. boneMask |= GetHighestBit( boneFlags );
  608. }
  609. }
  610. return BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
  611. }
  612. virtual void BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed )
  613. {
  614. VPROF_BUDGET( "C_ServerRagdollAttached::SetupBones", VPROF_BUDGETGROUP_CLIENT_ANIMATION );
  615. if ( !hdr )
  616. return;
  617. float frac = RemapVal( gpGlobals->curtime, m_parentTime, m_parentTime+ATTACH_INTERP_TIME, 0, 1 );
  618. frac = clamp( frac, 0.f, 1.f );
  619. // interpolate offset over some time
  620. Vector offset = m_vecOffset * (1-frac);
  621. C_BaseAnimating *parent = assert_cast< C_BaseAnimating* >( GetMoveParent() );
  622. Vector worldOrigin;
  623. worldOrigin.Init();
  624. if ( parent )
  625. {
  626. Assert( parent != this );
  627. parent->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  628. matrix3x4_t boneToWorld;
  629. parent->GetCachedBoneMatrix( m_boneIndexAttached, boneToWorld );
  630. VectorTransform( m_attachmentPointBoneSpace, boneToWorld, worldOrigin );
  631. }
  632. BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed );
  633. if ( parent )
  634. {
  635. int iBone = m_boneIndex[m_ragdollAttachedObjectIndex];
  636. const matrix3x4_t &matrix = GetBone( iBone );
  637. Vector ragOrigin;
  638. VectorTransform( m_attachmentPointRagdollSpace, matrix, ragOrigin );
  639. offset = worldOrigin - ragOrigin;
  640. // fixes culling
  641. SetAbsOrigin( worldOrigin );
  642. m_vecOffset = offset;
  643. }
  644. for ( int i = 0; i < hdr->numbones(); i++ )
  645. {
  646. if ( !( hdr->boneFlags( i ) & boneMask ) )
  647. continue;
  648. Vector vPos;
  649. matrix3x4_t &matrix = GetBoneForWrite( i );
  650. MatrixGetColumn( matrix, 3, vPos );
  651. vPos += offset;
  652. MatrixSetColumn( vPos, 3, matrix );
  653. }
  654. }
  655. void OnDataChanged( DataUpdateType_t updateType );
  656. virtual float LastBoneChangedTime() { return FLT_MAX; }
  657. Vector m_attachmentPointBoneSpace;
  658. Vector m_vecOffset;
  659. Vector m_attachmentPointRagdollSpace;
  660. int m_ragdollAttachedObjectIndex;
  661. int m_boneIndexAttached;
  662. float m_parentTime;
  663. bool m_bHasParent;
  664. private:
  665. C_ServerRagdollAttached( const C_ServerRagdollAttached & );
  666. };
  667. EXTERN_RECV_TABLE(DT_Ragdoll_Attached);
  668. IMPLEMENT_CLIENTCLASS_DT(C_ServerRagdollAttached, DT_Ragdoll_Attached, CRagdollPropAttached)
  669. RecvPropInt( RECVINFO( m_boneIndexAttached ) ),
  670. RecvPropInt( RECVINFO( m_ragdollAttachedObjectIndex ) ),
  671. RecvPropVector(RECVINFO(m_attachmentPointBoneSpace) ),
  672. RecvPropVector(RECVINFO(m_attachmentPointRagdollSpace) ),
  673. END_RECV_TABLE()
  674. void C_ServerRagdollAttached::OnDataChanged( DataUpdateType_t updateType )
  675. {
  676. BaseClass::OnDataChanged( updateType );
  677. bool bParentNow = GetMoveParent() ? true : false;
  678. if ( m_bHasParent != bParentNow )
  679. {
  680. if ( m_bHasParent )
  681. {
  682. m_parentTime = gpGlobals->curtime;
  683. }
  684. m_bHasParent = bParentNow;
  685. }
  686. }
  687. struct ragdoll_remember_t
  688. {
  689. C_BaseEntity *ragdoll;
  690. int tickCount;
  691. };
  692. struct ragdoll_memory_list_t
  693. {
  694. CUtlVector<ragdoll_remember_t> list;
  695. int tickCount;
  696. void Update()
  697. {
  698. if ( tickCount > gpGlobals->tickcount )
  699. {
  700. list.RemoveAll();
  701. return;
  702. }
  703. for ( int i = list.Count()-1; i >= 0; --i )
  704. {
  705. if ( list[i].tickCount != gpGlobals->tickcount )
  706. {
  707. list.FastRemove(i);
  708. }
  709. }
  710. }
  711. bool IsInList( C_BaseEntity *pRagdoll )
  712. {
  713. for ( int i = list.Count()-1; i >= 0; --i )
  714. {
  715. if ( list[i].ragdoll == pRagdoll )
  716. return true;
  717. }
  718. return false;
  719. }
  720. void AddToList( C_BaseEntity *pRagdoll )
  721. {
  722. Update();
  723. int index = list.AddToTail();
  724. list[index].ragdoll = pRagdoll;
  725. list[index].tickCount = gpGlobals->tickcount;
  726. }
  727. };
  728. static ragdoll_memory_list_t gRagdolls;
  729. void NoteRagdollCreationTick( C_BaseEntity *pRagdoll )
  730. {
  731. gRagdolls.AddToList( pRagdoll );
  732. }
  733. // returns true if the ragdoll was created on this tick
  734. bool WasRagdollCreatedOnCurrentTick( C_BaseEntity *pRagdoll )
  735. {
  736. gRagdolls.Update();
  737. return gRagdolls.IsInList( pRagdoll );
  738. }