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.

974 lines
28 KiB

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