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.

8839 lines
253 KiB

  1. //===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "c_baseanimating.h"
  9. #include "c_sprite.h"
  10. #include "model_types.h"
  11. #include "bone_setup.h"
  12. #if defined( _PS3 )
  13. #include "bone_setup_PS3.h"
  14. #endif
  15. #include "ivrenderview.h"
  16. #include "r_efx.h"
  17. #include "dlight.h"
  18. #include "beamdraw.h"
  19. #include "cl_animevent.h"
  20. #include "engine/IEngineSound.h"
  21. #include "c_te_legacytempents.h"
  22. #include "activitylist.h"
  23. #include "animation.h"
  24. #include "tier0/vprof.h"
  25. #include "IEffects.h"
  26. #include "engine/ivmodelinfo.h"
  27. #include "engine/ivdebugoverlay.h"
  28. #include "c_te_effect_dispatch.h"
  29. #include <keyvalues.h>
  30. #include "c_rope.h"
  31. #include "isaverestore.h"
  32. #include "datacache/imdlcache.h"
  33. #include "eventlist.h"
  34. #include "saverestore.h"
  35. #include "physics_saverestore.h"
  36. #include "vphysics/constraints.h"
  37. #include "ragdoll_shared.h"
  38. #include "view.h"
  39. #include "c_ai_basenpc.h"
  40. #include "c_entitydissolve.h"
  41. #include "saverestoretypes.h"
  42. #include "c_fire_smoke.h"
  43. #include "input.h"
  44. #include "soundinfo.h"
  45. #include "shaderapi/ishaderapi.h"
  46. #include "tools/bonelist.h"
  47. #include "toolframework/itoolframework.h"
  48. #include "datacache/idatacache.h"
  49. #include "gamestringpool.h"
  50. #include "engine/ivdebugoverlay.h"
  51. #include "jigglebones.h"
  52. #include "toolframework_client.h"
  53. #include "vstdlib/jobthread.h"
  54. #include "bonetoworldarray.h"
  55. #include "posedebugger.h"
  56. #include "tier0/icommandline.h"
  57. #include <ctype.h>
  58. #include "prediction.h"
  59. #include "c_entityflame.h"
  60. #include "npcevent.h"
  61. #include "replay_ragdoll.h"
  62. #include "physics_softbody.h"
  63. #if defined ( PORTAL2 )
  64. #include "c_portal_player.h"
  65. #include "portal2/portal_grabcontroller_shared.h"
  66. #endif
  67. #include "clientalphaproperty.h"
  68. #ifdef DEMOPOLISH_ENABLED
  69. #include "demo_polish/demo_polish.h"
  70. #endif
  71. // memdbgon must be the last include file in a .cpp file!!!
  72. #include "tier0/memdbgon.h"
  73. static ConVar cl_SetupAllBones( "cl_SetupAllBones", "0" );
  74. ConVar r_sequence_debug( "r_sequence_debug", "" );
  75. ConVar r_debug_sequencesets( "r_debug_sequencesets", "-2" );
  76. ConVar r_jiggle_bones( "r_jiggle_bones", "1" );
  77. ConVar RagdollImpactStrength( "z_ragdoll_impact_strength", "500" );
  78. ConVar cl_disable_ragdolls( "cl_disable_ragdolls", "0", FCVAR_CHEAT );
  79. ConVar r_debug_ik( "r_debug_ik", "" );
  80. ConVar cl_ejectbrass( "cl_ejectbrass", "1" );
  81. ConVar cl_minimal_rtt_shadows( "cl_minimal_rtt_shadows", "1", FCVAR_ARCHIVE );
  82. ConVar cl_custom_material_override( "cl_custom_material_override", "1", FCVAR_CLIENTDLL | FCVAR_DEVELOPMENTONLY, "allow custom material override" );
  83. // [mariod] - am comparing two optimisations to remove what seems like unnecessary bonesetup, particularly during input/aiment code
  84. // method 1. just use stale data in setupbones, by ignoring the condition that enables the path to recalc them
  85. // method 2. Only allow the invalidation of bonecaches to happen during specific sections of the frame
  86. // method 1 uses Enable/DisableNewBoneSetupRequest over critical sections
  87. // method 2 uses Enable/DisableInvalidateBoneCache
  88. // method 2 is enabled, method 1 disabled for now, needs more thorough testing, but I can't see issues on CS:GO with this config
  89. // Have spoken to Yahn about this, and he seems to agree that either the invalidatebonecache calls shouldn't be there,
  90. // and/or the use of stale data during input code should be fine
  91. bool C_BaseAnimating::s_bEnableInvalidateBoneCache = true;
  92. bool C_BaseAnimating::s_bEnableNewBoneSetupRequest = true;
  93. #if defined( _PS3 )
  94. //#define DEBUG_BONESETUP_THREADVSNONTHREAD
  95. ConVar cl_PS3_SPU_bones("cl_PS3_SPU_bones", "1", 0, "0: ignore SPU path. 1: run SPU path. 2: emulate SPU path on PPU" );
  96. ConVar cl_PS3_SPU_bones_debug("cl_PS3_SPU_bones_debug", "0", 0, "0: default, run as normal. 1: Force non-parallel SPU jobs, 2: Force debugger break on job entry and PPU execute after SPU job" );
  97. ConVar cl_PS3_SPU_bones_minbonecount("cl_PS3_SPU_bones_minbonecount", "0", 0, "0: default. number of bones below which the bonejob is not pushed to SPU" );
  98. ConVar cl_PS3_SPU_bones_safesync("cl_PS3_SPU_bones_safesync", "1", 1, "0: potentially unsafe sync of dependant jobs, more PPU/SPU overlap, get bone access errors. 1: default safer sync between dependant jobs" );
  99. #endif
  100. // If an NPC is moving faster than this, he should play the running footstep sound
  101. const float RUN_SPEED_ESTIMATE_SQR = 150.0f * 150.0f;
  102. // Removed macro used by shared code stuff
  103. #if defined( CBaseAnimating )
  104. #undef CBaseAnimating
  105. #endif
  106. ConVar sfm_record_hz( "sfm_record_hz", "30" );
  107. static bool g_bInThreadedBoneSetup;
  108. mstudioevent_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc );
  109. C_EntityDissolve *DissolveEffect( C_BaseAnimating *pTarget, float flTime );
  110. C_EntityFlame *FireEffect( C_BaseAnimating *pTarget, C_BaseEntity *pServerFire, float *flScaleEnd, float *flTimeStart, float *flTimeEnd );
  111. bool NPC_IsImportantNPC( C_BaseAnimating *pAnimating );
  112. void VCollideWireframe_ChangeCallback( IConVar *pConVar, char const *pOldString, float flOldValue );
  113. ConVar vcollide_wireframe( "vcollide_wireframe", "0", FCVAR_CHEAT, "Render physics collision models in wireframe", VCollideWireframe_ChangeCallback );
  114. ConVar enable_skeleton_draw( "enable_skeleton_draw", "0", FCVAR_CHEAT, "Render skeletons in wireframe" );
  115. extern ConVar r_shadow_deferred;
  116. bool C_AnimationLayer::IsActive( void )
  117. {
  118. return (m_nOrder != C_BaseAnimatingOverlay::MAX_OVERLAYS);
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Base Animating
  122. //-----------------------------------------------------------------------------
  123. struct clientanimating_t
  124. {
  125. C_BaseAnimating *pAnimating;
  126. unsigned int flags;
  127. clientanimating_t(C_BaseAnimating *_pAnim, unsigned int _flags ) : pAnimating(_pAnim), flags(_flags) {}
  128. };
  129. const unsigned int FCLIENTANIM_SEQUENCE_CYCLE = 0x00000001;
  130. static CUtlVector< clientanimating_t > g_ClientSideAnimationList;
  131. BEGIN_RECV_TABLE_NOBASE( C_BaseAnimating, DT_ServerAnimationData )
  132. RecvPropFloat(RECVINFO(m_flCycle)),
  133. END_RECV_TABLE()
  134. void RecvProxy_Sequence( const CRecvProxyData *pData, void *pStruct, void *pOut )
  135. {
  136. // Have the regular proxy store the data.
  137. RecvProxy_Int32ToInt32( pData, pStruct, pOut );
  138. C_BaseAnimating *pAnimating = (C_BaseAnimating *)pStruct;
  139. if ( !pAnimating )
  140. return;
  141. pAnimating->SetReceivedSequence();
  142. // render bounds may have changed
  143. pAnimating->UpdateVisibility();
  144. /*
  145. if (r_sequence_debug.GetInt() == pAnimating->entindex() )
  146. {
  147. DevMsgRT( "%d : RecvProxy_Sequence( %d:%s )\n", pAnimating->entindex(), pAnimating->GetSequence(), pAnimating->GetSequenceName( pAnimating->GetSequence() ) );
  148. Assert( 1 );
  149. }
  150. */
  151. }
  152. IMPLEMENT_CLIENTCLASS_DT(C_BaseAnimating, DT_BaseAnimating, CBaseAnimating)
  153. RecvPropInt(RECVINFO(m_nSequence), 0, RecvProxy_Sequence),
  154. RecvPropInt(RECVINFO(m_nForceBone)),
  155. RecvPropVector(RECVINFO(m_vecForce)),
  156. RecvPropInt(RECVINFO(m_nSkin)),
  157. RecvPropInt(RECVINFO(m_nBody)),
  158. RecvPropInt(RECVINFO(m_nHitboxSet)),
  159. RecvPropFloat(RECVINFO(m_flModelScale)),
  160. // RecvPropArray(RecvPropFloat(RECVINFO(m_flPoseParameter[0])), m_flPoseParameter),
  161. RecvPropArray3(RECVINFO_ARRAY(m_flPoseParameter), RecvPropFloat(RECVINFO(m_flPoseParameter[0])) ),
  162. RecvPropFloat(RECVINFO(m_flPlaybackRate)),
  163. RecvPropArray3( RECVINFO_ARRAY(m_flEncodedController), RecvPropFloat(RECVINFO(m_flEncodedController[0]))),
  164. RecvPropInt( RECVINFO( m_bClientSideAnimation )),
  165. RecvPropInt( RECVINFO( m_bClientSideFrameReset )),
  166. RecvPropBool( RECVINFO( m_bClientSideRagdoll )),
  167. RecvPropInt( RECVINFO( m_nNewSequenceParity )),
  168. RecvPropInt( RECVINFO( m_nResetEventsParity )),
  169. RecvPropInt( RECVINFO( m_nMuzzleFlashParity ) ),
  170. RecvPropEHandle(RECVINFO(m_hLightingOrigin)),
  171. RecvPropDataTable( "serveranimdata", 0, 0, &REFERENCE_RECV_TABLE( DT_ServerAnimationData ) ),
  172. RecvPropFloat( RECVINFO( m_flFrozen ) ),
  173. RecvPropInt( RECVINFO( m_ScaleType ) ),
  174. RecvPropBool( RECVINFO( m_bSuppressAnimSounds ) )
  175. END_RECV_TABLE()
  176. BEGIN_PREDICTION_DATA( C_BaseAnimating )
  177. DEFINE_PRED_FIELD( m_nSkin, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  178. DEFINE_PRED_FIELD( m_nBody, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  179. // DEFINE_PRED_FIELD( m_nHitboxSet, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  180. // DEFINE_PRED_FIELD( m_flModelScale, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  181. //DEFINE_PRED_FIELD( m_nSequence, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  182. DEFINE_PRED_FIELD( m_flPlaybackRate, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  183. //DEFINE_PRED_FIELD( m_flCycle, FIELD_FLOAT, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  184. // DEFINE_PRED_ARRAY( m_flPoseParameter, FIELD_FLOAT, MAXSTUDIOPOSEPARAM, FTYPEDESC_INSENDTABLE ),
  185. DEFINE_PRED_ARRAY_TOL( m_flEncodedController, FIELD_FLOAT, MAXSTUDIOBONECTRLS, FTYPEDESC_INSENDTABLE, 0.02f ),
  186. //DEFINE_FIELD( m_flPrevEventCycle, FIELD_FLOAT ),
  187. //DEFINE_FIELD( m_flEventCycle, FIELD_FLOAT ),
  188. //DEFINE_FIELD( m_nEventSequence, FIELD_INTEGER ),
  189. DEFINE_PRED_FIELD( m_nNewSequenceParity, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  190. DEFINE_PRED_FIELD( m_nResetEventsParity, FIELD_INTEGER, FTYPEDESC_INSENDTABLE | FTYPEDESC_NOERRORCHECK ),
  191. // DEFINE_PRED_FIELD( m_nPrevResetEventsParity, FIELD_INTEGER, 0 ),
  192. DEFINE_PRED_FIELD( m_nMuzzleFlashParity, FIELD_CHARACTER, FTYPEDESC_INSENDTABLE ),
  193. //DEFINE_FIELD( m_nOldMuzzleFlashParity, FIELD_CHARACTER ),
  194. //DEFINE_FIELD( m_nPrevNewSequenceParity, FIELD_INTEGER ),
  195. // DEFINE_PRED_FIELD( m_vecForce, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
  196. // DEFINE_PRED_FIELD( m_nForceBone, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  197. // DEFINE_PRED_FIELD( m_bClientSideAnimation, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  198. // DEFINE_PRED_FIELD( m_bClientSideFrameReset, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  199. // DEFINE_FIELD( m_pRagdollInfo, RagdollInfo_t ),
  200. // DEFINE_FIELD( m_CachedBones, CUtlVector < CBoneCacheEntry > ),
  201. // DEFINE_FIELD( m_pActualAttachmentAngles, FIELD_VECTOR ),
  202. // DEFINE_FIELD( m_pActualAttachmentOrigin, FIELD_VECTOR ),
  203. // DEFINE_FIELD( m_animationQueue, CUtlVector < CAnimationLayer > ),
  204. // DEFINE_FIELD( m_pIk, CIKContext ),
  205. // DEFINE_FIELD( m_bLastClientSideFrameReset, FIELD_BOOLEAN ),
  206. // DEFINE_FIELD( hdr, studiohdr_t ),
  207. // DEFINE_FIELD( m_pRagdoll, IRagdoll ),
  208. // DEFINE_FIELD( m_bStoreRagdollInfo, FIELD_BOOLEAN ),
  209. // DEFINE_FIELD( C_BaseFlex, m_iEyeAttachment, FIELD_INTEGER ),
  210. END_PREDICTION_DATA()
  211. LINK_ENTITY_TO_CLASS_CLIENTONLY( client_ragdoll, C_ClientRagdoll );
  212. BEGIN_DATADESC( C_ClientRagdoll )
  213. DEFINE_FIELD( m_bFadeOut, FIELD_BOOLEAN ),
  214. DEFINE_FIELD( m_bImportant, FIELD_BOOLEAN ),
  215. DEFINE_FIELD( m_iCurrentFriction, FIELD_INTEGER ),
  216. DEFINE_FIELD( m_iMinFriction, FIELD_INTEGER ),
  217. DEFINE_FIELD( m_iMaxFriction, FIELD_INTEGER ),
  218. DEFINE_FIELD( m_flFrictionModTime, FIELD_FLOAT ),
  219. DEFINE_FIELD( m_flFrictionTime, FIELD_TIME ),
  220. DEFINE_FIELD( m_iFrictionAnimState, FIELD_INTEGER ),
  221. DEFINE_FIELD( m_bReleaseRagdoll, FIELD_BOOLEAN ),
  222. DEFINE_FIELD( m_nBody, FIELD_INTEGER ),
  223. DEFINE_FIELD( m_nSkin, FIELD_INTEGER ),
  224. DEFINE_FIELD( m_nRenderFX, FIELD_CHARACTER ),
  225. DEFINE_FIELD( m_nRenderMode, FIELD_CHARACTER ),
  226. DEFINE_FIELD( m_clrRender, FIELD_COLOR32 ),
  227. DEFINE_FIELD( m_flEffectTime, FIELD_TIME ),
  228. DEFINE_FIELD( m_bFadingOut, FIELD_BOOLEAN ),
  229. DEFINE_AUTO_ARRAY( m_flScaleEnd, FIELD_FLOAT ),
  230. DEFINE_AUTO_ARRAY( m_flScaleTimeStart, FIELD_FLOAT ),
  231. DEFINE_AUTO_ARRAY( m_flScaleTimeEnd, FIELD_FLOAT ),
  232. DEFINE_EMBEDDEDBYREF( m_pRagdoll ),
  233. DEFINE_AUTO_ARRAY( m_flScaleEnd, FIELD_FLOAT ),
  234. DEFINE_AUTO_ARRAY( m_flScaleTimeStart, FIELD_FLOAT ),
  235. DEFINE_AUTO_ARRAY( m_flScaleTimeEnd, FIELD_FLOAT ),
  236. //DEFINE_EMBEDDEDBYREF( m_pRagdoll ), // TODO: FIX: This is dynamically-typed
  237. END_DATADESC()
  238. BEGIN_ENT_SCRIPTDESC( C_BaseAnimating, C_BaseEntity, "Animating models client-side" )
  239. DEFINE_SCRIPTFUNC_NAMED( ScriptSetPoseParameter, "SetPoseParameter", "Set the specified pose parameter to the specified value" )
  240. DEFINE_SCRIPTFUNC( IsSequenceFinished, "Ask whether the main sequence is done playing" )
  241. END_SCRIPTDESC();
  242. C_ClientRagdoll::C_ClientRagdoll( bool bRestoring , bool fullInit)
  243. {
  244. m_iCurrentFriction = 0;
  245. m_iFrictionAnimState = RAGDOLL_FRICTION_NONE;
  246. m_bReleaseRagdoll = false;
  247. m_bFadeOut = false;
  248. m_bFadingOut = false;
  249. m_bImportant = false;
  250. if(fullInit)
  251. {
  252. SetClassname("client_ragdoll");
  253. if ( bRestoring == true )
  254. {
  255. m_pRagdoll = new CRagdoll;
  256. }
  257. }
  258. }
  259. void C_ClientRagdoll::OnSave( void )
  260. {
  261. }
  262. void C_ClientRagdoll::OnRestore( void )
  263. {
  264. CStudioHdr *hdr = GetModelPtr();
  265. if ( hdr == NULL )
  266. {
  267. const char *pModelName = STRING( GetModelName() );
  268. SetModel( pModelName );
  269. hdr = GetModelPtr();
  270. if ( hdr == NULL )
  271. return;
  272. }
  273. if ( m_pRagdoll == NULL )
  274. return;
  275. ragdoll_t *pRagdollT = m_pRagdoll->GetRagdoll();
  276. if ( pRagdollT == NULL || pRagdollT->list[0].pObject == NULL )
  277. {
  278. m_bReleaseRagdoll = true;
  279. m_pRagdoll = NULL;
  280. Assert( !"Attempted to restore a ragdoll without physobjects!" );
  281. return;
  282. }
  283. if ( GetFlags() & FL_DISSOLVING )
  284. {
  285. DissolveEffect( this, m_flEffectTime );
  286. }
  287. else if ( GetFlags() & FL_ONFIRE )
  288. {
  289. C_EntityFlame *pFireChild = dynamic_cast<C_EntityFlame *>( GetEffectEntity() );
  290. C_EntityFlame *pNewFireChild = FireEffect( this, pFireChild, m_flScaleEnd, m_flScaleTimeStart, m_flScaleTimeEnd );
  291. //Set the new fire child as the new effect entity.
  292. SetEffectEntity( pNewFireChild );
  293. }
  294. VPhysicsSetObject( NULL );
  295. VPhysicsSetObject( pRagdollT->list[0].pObject );
  296. SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  297. pRagdollT->list[0].parentIndex = -1;
  298. pRagdollT->list[0].originParentSpace.Init();
  299. RagdollActivate( *pRagdollT, modelinfo->GetVCollide( GetModelIndex() ), GetModelIndex(), true );
  300. RagdollSetupAnimatedFriction( physenv, pRagdollT, GetModelIndex() );
  301. m_pRagdoll->BuildRagdollBounds( this );
  302. // UNDONE: The shadow & leaf system cleanup should probably be in C_BaseEntity::OnRestore()
  303. // this must be recomputed because the model was NULL when this was set up
  304. RemoveFromLeafSystem();
  305. AddToLeafSystem( false );
  306. DestroyShadow();
  307. CreateShadow();
  308. SetNextClientThink( CLIENT_THINK_ALWAYS );
  309. if ( m_bFadeOut == true )
  310. {
  311. s_RagdollLRU.MoveToTopOfLRU( this, m_bImportant );
  312. }
  313. NoteRagdollCreationTick( this );
  314. BaseClass::OnRestore();
  315. RagdollMoved();
  316. }
  317. void C_ClientRagdoll::ImpactTrace( trace_t *pTrace, int iDamageType, char *pCustomImpactName )
  318. {
  319. VPROF( "C_ClientRagdoll::ImpactTrace" );
  320. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  321. if( !pPhysicsObject )
  322. return;
  323. if ( !pPhysicsObject->IsCollisionEnabled() )
  324. return;
  325. Vector dir = pTrace->endpos - pTrace->startpos;
  326. if ( iDamageType & DMG_BLAST )
  327. {
  328. dir *= 500; // adjust impact strenght
  329. // apply force at object mass center
  330. pPhysicsObject->ApplyForceCenter( dir );
  331. }
  332. else
  333. {
  334. Vector hitpos;
  335. VectorMA( pTrace->startpos, pTrace->fraction, dir, hitpos );
  336. VectorNormalize( dir );
  337. dir *= RagdollImpactStrength.GetFloat(); // adjust impact strength
  338. // apply force where we hit it
  339. pPhysicsObject->ApplyForceOffset( dir, hitpos );
  340. }
  341. m_pRagdoll->ResetRagdollSleepAfterTime();
  342. }
  343. ConVar g_debug_ragdoll_visualize( "g_debug_ragdoll_visualize", "0", FCVAR_CHEAT );
  344. void C_ClientRagdoll::HandleAnimatedFriction( void )
  345. {
  346. if ( m_iFrictionAnimState == RAGDOLL_FRICTION_OFF )
  347. return;
  348. ragdoll_t *pRagdollT = NULL;
  349. int iBoneCount = 0;
  350. if ( m_pRagdoll )
  351. {
  352. pRagdollT = m_pRagdoll->GetRagdoll();
  353. iBoneCount = m_pRagdoll->RagdollBoneCount();
  354. }
  355. if ( pRagdollT == NULL )
  356. return;
  357. switch ( m_iFrictionAnimState )
  358. {
  359. case RAGDOLL_FRICTION_NONE:
  360. {
  361. m_iMinFriction = pRagdollT->animfriction.minFriction;
  362. m_iMaxFriction = pRagdollT->animfriction.maxFriction;
  363. if ( m_iMinFriction != 0 || m_iMaxFriction != 0 )
  364. {
  365. m_iFrictionAnimState = RAGDOLL_FRICTION_IN;
  366. m_flFrictionModTime = pRagdollT->animfriction.timeIn;
  367. m_flFrictionTime = gpGlobals->curtime + m_flFrictionModTime;
  368. m_iCurrentFriction = m_iMinFriction;
  369. }
  370. else
  371. {
  372. m_iFrictionAnimState = RAGDOLL_FRICTION_OFF;
  373. }
  374. break;
  375. }
  376. case RAGDOLL_FRICTION_IN:
  377. {
  378. float flDeltaTime = (m_flFrictionTime - gpGlobals->curtime);
  379. m_iCurrentFriction = RemapValClamped( flDeltaTime , m_flFrictionModTime, 0, m_iMinFriction, m_iMaxFriction );
  380. if ( flDeltaTime <= 0.0f )
  381. {
  382. m_flFrictionModTime = pRagdollT->animfriction.timeHold;
  383. m_flFrictionTime = gpGlobals->curtime + m_flFrictionModTime;
  384. m_iFrictionAnimState = RAGDOLL_FRICTION_HOLD;
  385. }
  386. break;
  387. }
  388. case RAGDOLL_FRICTION_HOLD:
  389. {
  390. if ( m_flFrictionTime < gpGlobals->curtime )
  391. {
  392. m_flFrictionModTime = pRagdollT->animfriction.timeOut;
  393. m_flFrictionTime = gpGlobals->curtime + m_flFrictionModTime;
  394. m_iFrictionAnimState = RAGDOLL_FRICTION_OUT;
  395. }
  396. break;
  397. }
  398. case RAGDOLL_FRICTION_OUT:
  399. {
  400. float flDeltaTime = (m_flFrictionTime - gpGlobals->curtime);
  401. m_iCurrentFriction = RemapValClamped( flDeltaTime , 0, m_flFrictionModTime, m_iMinFriction, m_iMaxFriction );
  402. if ( flDeltaTime <= 0.0f )
  403. {
  404. m_iFrictionAnimState = RAGDOLL_FRICTION_OFF;
  405. }
  406. break;
  407. }
  408. }
  409. for ( int i = 0; i < iBoneCount; i++ )
  410. {
  411. if ( pRagdollT->list[i].pConstraint )
  412. pRagdollT->list[i].pConstraint->SetAngularMotor( 0, m_iCurrentFriction );
  413. }
  414. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  415. if ( pPhysicsObject )
  416. {
  417. pPhysicsObject->Wake();
  418. }
  419. }
  420. ConVar g_ragdoll_fadespeed( "g_ragdoll_fadespeed", "600" );
  421. ConVar g_ragdoll_lvfadespeed( "g_ragdoll_lvfadespeed", "100" );
  422. void C_ClientRagdoll::OnPVSStatusChanged( bool bInPVS )
  423. {
  424. if ( bInPVS )
  425. {
  426. CreateShadow();
  427. }
  428. else
  429. {
  430. DestroyShadow();
  431. }
  432. }
  433. void C_ClientRagdoll::FadeOut( void )
  434. {
  435. if ( m_bFadingOut == false )
  436. {
  437. return;
  438. }
  439. int iAlpha = GetRenderAlpha();
  440. int iFadeSpeed = ( g_RagdollLVManager.IsLowViolence() ) ? g_ragdoll_lvfadespeed.GetInt() : g_ragdoll_fadespeed.GetInt();
  441. iAlpha = MAX( iAlpha - ( iFadeSpeed * gpGlobals->frametime ), 0 );
  442. SetRenderMode( kRenderTransAlpha );
  443. SetRenderAlpha( iAlpha );
  444. if ( iAlpha == 0 )
  445. {
  446. m_bReleaseRagdoll = true;
  447. }
  448. }
  449. void C_ClientRagdoll::SUB_Remove( void )
  450. {
  451. m_bFadingOut = true;
  452. SetNextClientThink( CLIENT_THINK_ALWAYS );
  453. }
  454. //--------------------------------------------------------------------------------------------------------
  455. void C_ClientRagdoll::ClientThink( void )
  456. {
  457. if ( m_bReleaseRagdoll == true )
  458. {
  459. DestroyBoneAttachments();
  460. Release();
  461. return;
  462. }
  463. if ( g_debug_ragdoll_visualize.GetBool() )
  464. {
  465. Vector vMins, vMaxs;
  466. Vector origin = m_pRagdoll->GetRagdollOrigin();
  467. m_pRagdoll->GetRagdollBounds( vMins, vMaxs );
  468. debugoverlay->AddBoxOverlay( origin, vMins, vMaxs, QAngle( 0, 0, 0 ), 0, 255, 0, 16, 0 );
  469. }
  470. HandleAnimatedFriction();
  471. FadeOut();
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Purpose: clear out any face/eye values stored in the material system
  475. //-----------------------------------------------------------------------------
  476. float C_ClientRagdoll::LastBoneChangedTime()
  477. {
  478. // When did this last change?
  479. return m_pRagdoll ? m_pRagdoll->GetLastVPhysicsUpdateTime() : -FLT_MAX;
  480. }
  481. //----------------------------------------------------------------------------
  482. // Hooks into the fast path render system
  483. //----------------------------------------------------------------------------
  484. IClientModelRenderable* C_ClientRagdoll::GetClientModelRenderable()
  485. {
  486. if ( !BaseClass::GetClientModelRenderable() )
  487. return NULL;
  488. // NOTE: This is because of code in SetupWeights, which calls SetViewTarget.
  489. // The view target is a per-instance piece of state which is not yet
  490. // supported by the model fast path. Once it is, we can eliminate this
  491. // code and make it so ragdolls always use the fast path
  492. if ( m_iEyeAttachment > 0 )
  493. return NULL;
  494. return this;
  495. }
  496. //-----------------------------------------------------------------------------
  497. // Purpose: clear out any face/eye values stored in the material system
  498. //-----------------------------------------------------------------------------
  499. void C_ClientRagdoll::SetupWeights( const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights )
  500. {
  501. BaseClass::SetupWeights( pBoneToWorld, nFlexWeightCount, pFlexWeights, pFlexDelayedWeights );
  502. CStudioHdr *hdr = GetModelPtr();
  503. if ( !hdr )
  504. return;
  505. int nFlexDescCount = hdr->numflexdesc();
  506. if ( nFlexDescCount )
  507. {
  508. memset( pFlexWeights, 0, nFlexWeightCount * sizeof(float) );
  509. if ( pFlexDelayedWeights )
  510. {
  511. memset( pFlexDelayedWeights, 0, nFlexWeightCount * sizeof(float) );
  512. }
  513. }
  514. if ( m_iEyeAttachment > 0 )
  515. {
  516. matrix3x4_t attToWorld;
  517. if ( GetAttachment( m_iEyeAttachment, attToWorld ) )
  518. {
  519. Vector local, tmp;
  520. local.Init( 1000.0f, 0.0f, 0.0f );
  521. VectorTransform( local, attToWorld, tmp );
  522. modelrender->SetViewTarget( GetModelPtr(), GetBody(), tmp );
  523. }
  524. }
  525. }
  526. void C_ClientRagdoll::Release( void )
  527. {
  528. C_BaseEntity *pChild = GetEffectEntity();
  529. if ( pChild && pChild->IsMarkedForDeletion() == false )
  530. {
  531. UTIL_Remove( pChild );
  532. }
  533. if ( GetThinkHandle() != INVALID_THINK_HANDLE )
  534. {
  535. ClientThinkList()->RemoveThinkable( GetClientHandle() );
  536. }
  537. ClientEntityList().RemoveEntity( GetClientHandle() );
  538. ::partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() );
  539. RemoveFromLeafSystem();
  540. BaseClass::Release();
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Incremented each frame in InvalidateModelBones. Models compare this value to what it
  544. // was last time they setup their bones to determine if they need to re-setup their bones.
  545. static unsigned long g_iModelBoneCounter = 0;
  546. CUtlVector<C_BaseAnimating *> g_PreviousBoneSetups;
  547. static unsigned long g_iPreviousBoneCounter = (unsigned)-1;
  548. unsigned int g_nNumBonesSetupBlendingRulesOnly;
  549. unsigned int g_nNumBonesSetupBlendingRulesOnlyTemp;
  550. unsigned int g_nNumBonesSetupAll;
  551. unsigned int g_nNumBonesSetupAllTemp;
  552. class C_BaseAnimatingGameSystem : public CAutoGameSystem
  553. {
  554. void LevelShutdownPostEntity()
  555. {
  556. g_iPreviousBoneCounter = (unsigned)-1;
  557. if ( g_PreviousBoneSetups.Count() != 0 )
  558. {
  559. Msg( "%d entities in bone setup array. Should have been cleaned up by now\n", g_PreviousBoneSetups.Count() );
  560. g_PreviousBoneSetups.RemoveAll();
  561. }
  562. }
  563. } g_BaseAnimatingGameSystem;
  564. //-----------------------------------------------------------------------------
  565. // Purpose: convert axis rotations to a quaternion
  566. //-----------------------------------------------------------------------------
  567. C_BaseAnimating::C_BaseAnimating() :
  568. m_iv_flCycle( "C_BaseAnimating::m_iv_flCycle" ),
  569. m_iv_flPoseParameter( "C_BaseAnimating::m_iv_flPoseParameter" ),
  570. m_iv_flEncodedController("C_BaseAnimating::m_iv_flEncodedController")
  571. {
  572. Assert( (reinterpret_cast<uintp>(this) & 0x0F) == 0 ); // I should be aligned!
  573. m_nLastNonSkippedFrame = 0;
  574. m_nCustomBlendingRuleMask = -1;
  575. ClearAnimLODflags();
  576. m_nComputedLODframe = 0;
  577. m_flDistanceFromCamera = 0;
  578. m_bMaintainSequenceTransitions = true;
  579. m_iEjectBrassAttachment = -1;
  580. m_vecForce.Init();
  581. m_nForceBone = -1;
  582. SetGlobalFadeScale( 1.0f );
  583. m_ScaleType = HIERARCHICAL_MODEL_SCALE;
  584. m_ClientSideAnimationListHandle = INVALID_CLIENTSIDEANIMATION_LIST_HANDLE;
  585. m_bCanUseFastPath = false;
  586. m_bIsUsingRelativeLighting = false;
  587. m_bIsStaticProp = false;
  588. m_pRagdoll = NULL;
  589. m_pClientsideRagdoll = NULL;
  590. m_builtRagdoll = false;
  591. int i;
  592. for ( i = 0; i < ARRAYSIZE( m_flEncodedController ); i++ )
  593. {
  594. m_flEncodedController[ i ] = 0.0f;
  595. }
  596. AddBaseAnimatingInterpolatedVars();
  597. m_iMostRecentModelBoneCounter = 0xFFFFFFFF;
  598. m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter - 1;
  599. m_flLastBoneSetupTime = -FLT_MAX;
  600. m_pNextForThreadedBoneSetup = NULL;
  601. m_vecPreRagdollMins = vec3_origin;
  602. m_vecPreRagdollMaxs = vec3_origin;
  603. m_bStoreRagdollInfo = false;
  604. m_pRagdollInfo = NULL;
  605. m_flPlaybackRate = 1.0f;
  606. m_nEventSequence = -1;
  607. m_pIk = NULL;
  608. // Assume false. Derived classes might fill in a receive table entry
  609. // and in that case this would show up as true
  610. m_bClientSideAnimation = false;
  611. m_nPrevNewSequenceParity = -1;
  612. m_nPrevResetEventsParity = -1;
  613. m_nOldMuzzleFlashParity = 0;
  614. m_nMuzzleFlashParity = 0;
  615. m_boneIndexAttached = -1;
  616. m_flModelScale = 1.0f;
  617. m_iEyeAttachment = 0;
  618. m_pStudioHdr = NULL;
  619. m_hStudioHdr = MDLHANDLE_INVALID;
  620. m_bReceivedSequence = false;
  621. m_bBonePolishSetup = false;
  622. m_prevClientCycle = 0;
  623. m_prevClientAnimTime = 0;
  624. m_flOldModelScale = 0.0f;
  625. m_vecRenderOriginOverride = vec3_invalid;
  626. m_pJiggleBones = NULL;
  627. m_isJiggleBonesEnabled = true;
  628. AddToEntityList(ENTITY_LIST_SIMULATE);
  629. m_bForceRTTShadows = false;
  630. m_flCycle = 0;
  631. m_bUseParentLightingOrigin = false;
  632. for ( int i=0; i<MAXSTUDIOBONES; i++ )
  633. {
  634. m_pos_cached[i].Init();
  635. m_q_cached[i].Init();
  636. }
  637. }
  638. //-----------------------------------------------------------------------------
  639. // Purpose: cleanup
  640. //-----------------------------------------------------------------------------
  641. C_BaseAnimating::~C_BaseAnimating()
  642. {
  643. Assert( !g_bInThreadedBoneSetup );
  644. if ( m_iMostRecentBoneSetupRequest == g_iPreviousBoneCounter )
  645. {
  646. int i = g_PreviousBoneSetups.Find( this );
  647. Assert( i != -1 );
  648. if ( i != -1 )
  649. g_PreviousBoneSetups.FastRemove( i );
  650. }
  651. else
  652. {
  653. Assert( g_PreviousBoneSetups.Find( this ) == -1 );
  654. }
  655. RemoveFromClientSideAnimationList();
  656. TermRopes();
  657. delete m_pRagdollInfo;
  658. Assert(!m_pRagdoll);
  659. delete m_pIk;
  660. delete m_pBoneMergeCache;
  661. InvalidateMdlCache();
  662. if ( m_pJiggleBones )
  663. {
  664. delete m_pJiggleBones;
  665. m_pJiggleBones = NULL;
  666. }
  667. // Kill off anything bone attached to us.
  668. DestroyBoneAttachments();
  669. // clear off any custom materials we might have
  670. ClearCustomMaterials();
  671. }
  672. bool C_BaseAnimating::UsesPowerOfTwoFrameBufferTexture( void )
  673. {
  674. return modelinfo->IsUsingFBTexture( GetModel(), GetSkin(), GetBody(), GetClientRenderable() );
  675. }
  676. int C_BaseAnimating::GetRenderFlags( void )
  677. {
  678. int nRet = 0;
  679. if ( modelinfo->IsUsingFBTexture( GetModel(), GetSkin(), GetBody(), GetClientRenderable() ) )
  680. nRet |= ERENDERFLAGS_NEEDS_POWER_OF_TWO_FB;
  681. return nRet;
  682. }
  683. //-----------------------------------------------------------------------------
  684. // VPhysics object
  685. //-----------------------------------------------------------------------------
  686. int C_BaseAnimating::VPhysicsGetObjectList( IPhysicsObject **pList, int listMax )
  687. {
  688. if ( IsRagdoll() )
  689. {
  690. int i;
  691. for ( i = 0; i < m_pRagdoll->RagdollBoneCount(); ++i )
  692. {
  693. if ( i >= listMax )
  694. break;
  695. pList[i] = m_pRagdoll->GetElement(i);
  696. }
  697. return i;
  698. }
  699. return BaseClass::VPhysicsGetObjectList( pList, listMax );
  700. }
  701. //-----------------------------------------------------------------------------
  702. // Should this object cast render-to-texture shadows?
  703. //-----------------------------------------------------------------------------
  704. ShadowType_t C_BaseAnimating::ShadowCastType()
  705. {
  706. CStudioHdr *pStudioHdr = GetModelPtr();
  707. if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() )
  708. return SHADOWS_NONE;
  709. if ( IsEffectActive(EF_NODRAW | EF_NOSHADOW) )
  710. return SHADOWS_NONE;
  711. if ( cl_minimal_rtt_shadows.GetBool() && m_bForceRTTShadows == false )
  712. {
  713. return SHADOWS_NONE;
  714. }
  715. else
  716. {
  717. return GetShadowCastTypeForStudio( pStudioHdr );
  718. }
  719. }
  720. ShadowType_t C_BaseAnimating::GetShadowCastTypeForStudio( CStudioHdr *pStudioHdr )
  721. {
  722. if (pStudioHdr->GetNumSeq() == 0)
  723. return SHADOWS_RENDER_TO_TEXTURE;
  724. if ( !IsRagdoll() )
  725. {
  726. // If we have pose parameters, always update
  727. if ( pStudioHdr->GetNumPoseParameters() > 0 )
  728. return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
  729. // If we have bone controllers, always update
  730. if ( pStudioHdr->numbonecontrollers() > 0 )
  731. return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
  732. // If we use IK, always update
  733. if ( pStudioHdr->numikchains() > 0 )
  734. return SHADOWS_RENDER_TO_TEXTURE_DYNAMIC;
  735. }
  736. // FIXME: Do something to check to see how many frames the current animation has
  737. // If we do this, we have to be able to handle the case of changing ShadowCastTypes
  738. // at the moment, they are assumed to be constant.
  739. return SHADOWS_RENDER_TO_TEXTURE;
  740. }
  741. //-----------------------------------------------------------------------------
  742. // Purpose: convert axis rotations to a quaternion
  743. //-----------------------------------------------------------------------------
  744. void C_BaseAnimating::SetPredictable( bool state )
  745. {
  746. BaseClass::SetPredictable( state );
  747. UpdateRelevantInterpolatedVars();
  748. }
  749. //-----------------------------------------------------------------------------
  750. // Purpose: sets client side animation
  751. //-----------------------------------------------------------------------------
  752. void C_BaseAnimating::UseClientSideAnimation()
  753. {
  754. m_bClientSideAnimation = true;
  755. }
  756. void C_BaseAnimating::UpdateRelevantInterpolatedVars()
  757. {
  758. // Remove any interpolated vars that need to be removed.
  759. MDLCACHE_CRITICAL_SECTION();
  760. if ( !GetPredictable() && !IsClientCreated() && GetModelPtr() && GetModelPtr()->SequencesAvailable() && WantsInterpolatedVars() )
  761. {
  762. AddBaseAnimatingInterpolatedVars();
  763. }
  764. else
  765. {
  766. RemoveBaseAnimatingInterpolatedVars();
  767. }
  768. }
  769. void C_BaseAnimating::AddBaseAnimatingInterpolatedVars()
  770. {
  771. AddVar( m_flEncodedController, &m_iv_flEncodedController, LATCH_ANIMATION_VAR, true );
  772. int flags = LATCH_ANIMATION_VAR;
  773. if ( m_bClientSideAnimation )
  774. flags |= EXCLUDE_AUTO_INTERPOLATE;
  775. AddVar( m_flPoseParameter, &m_iv_flPoseParameter, flags, true );
  776. AddVar( &m_flCycle, &m_iv_flCycle, flags, true );
  777. }
  778. void C_BaseAnimating::RemoveBaseAnimatingInterpolatedVars()
  779. {
  780. RemoveVar( m_flEncodedController, false );
  781. RemoveVar( m_flPoseParameter, false );
  782. RemoveVar( &m_flCycle, false );
  783. }
  784. void C_BaseAnimating::LockStudioHdr()
  785. {
  786. AUTO_LOCK( m_StudioHdrInitLock );
  787. const model_t *mdl = GetModel();
  788. if (mdl)
  789. {
  790. m_hStudioHdr = modelinfo->GetCacheHandle( mdl );
  791. if ( m_hStudioHdr != MDLHANDLE_INVALID )
  792. {
  793. const studiohdr_t *pStudioHdr = mdlcache->LockStudioHdr( m_hStudioHdr );
  794. CStudioHdr *pStudioHdrContainer = NULL;
  795. if ( !m_pStudioHdr )
  796. {
  797. if ( pStudioHdr )
  798. {
  799. pStudioHdrContainer = new CStudioHdr;
  800. pStudioHdrContainer->Init( pStudioHdr, mdlcache );
  801. pStudioHdrContainer->InitSoftbody( &g_SoftbodyEnvironment );
  802. }
  803. else
  804. {
  805. m_hStudioHdr = MDLHANDLE_INVALID;
  806. }
  807. }
  808. else
  809. {
  810. pStudioHdrContainer = m_pStudioHdr;
  811. }
  812. Assert( ( pStudioHdr == NULL && pStudioHdrContainer == NULL ) || pStudioHdrContainer->GetRenderHdr() == pStudioHdr );
  813. if ( pStudioHdrContainer && pStudioHdrContainer->GetVirtualModel() )
  814. {
  815. MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( pStudioHdrContainer->GetRenderHdr()->VirtualModel() );
  816. mdlcache->LockStudioHdr( hVirtualModel );
  817. }
  818. m_pStudioHdr = pStudioHdrContainer; // must be last to ensure virtual model correctly set up
  819. }
  820. }
  821. }
  822. void C_BaseAnimating::UnlockStudioHdr()
  823. {
  824. if ( m_pStudioHdr )
  825. {
  826. m_pStudioHdr->FreeSoftbody();
  827. const model_t *mdl = GetModel();
  828. if (mdl)
  829. {
  830. mdlcache->UnlockStudioHdr( m_hStudioHdr );
  831. if ( m_pStudioHdr->GetVirtualModel() )
  832. {
  833. MDLHandle_t hVirtualModel = VoidPtrToMDLHandle( m_pStudioHdr->GetRenderHdr()->VirtualModel() );
  834. mdlcache->UnlockStudioHdr( hVirtualModel );
  835. }
  836. }
  837. }
  838. }
  839. CStudioHdr *C_BaseAnimating::OnNewModel()
  840. {
  841. BaseClass::OnNewModel();
  842. m_bCanUseFastPath = false;
  843. InvalidateMdlCache();
  844. // remove transition animations playback
  845. m_SequenceTransitioner.RemoveAll();
  846. if (m_pJiggleBones)
  847. {
  848. delete m_pJiggleBones;
  849. m_pJiggleBones = NULL;
  850. }
  851. if ( !GetModel() )
  852. return NULL;
  853. LockStudioHdr();
  854. UpdateRelevantInterpolatedVars();
  855. CStudioHdr *hdr = GetModelPtr();
  856. if (hdr == NULL)
  857. return NULL;
  858. m_bIsStaticProp = ( hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP ) ? true : false;
  859. // Can we use the model fast path?
  860. m_bCanUseFastPath = !modelinfo->ModelHasMaterialProxy( GetModel() ) && GetCustomMaterialCount() == 0;
  861. if ( m_bCanUseFastPath && m_nSkin != 0 && m_pStudioHdr && m_pStudioHdr->numskinfamilies() > 1 )
  862. {
  863. // [REI] Note that this doesn't currently handle the case of a model that starts as skin 0 but
  864. // then changes to a different skin index (without triggering NewModel()).
  865. //
  866. // $$$REI NOTE THIS DOESN'T SEEM TO BE THE RIGHT ANSWER; the problem we are fixing is that
  867. // $$$REI material color doesn't seem to work in the fastpath. But the bug is only triggered
  868. // $$$REI by WillS colored eggs which use material color set differently on many skins of
  869. // $$$REI the same model.
  870. DevWarning( "Model '%s' has skin but thinks it can render fastpath\n", m_pStudioHdr->pszName() );
  871. m_bCanUseFastPath = false;
  872. }
  873. InvalidateBoneCache();
  874. if ( m_pBoneMergeCache )
  875. {
  876. delete m_pBoneMergeCache;
  877. m_pBoneMergeCache = NULL;
  878. // recreated in BuildTransformations
  879. }
  880. // Make sure m_CachedBones has space.
  881. if ( m_CachedBoneData.Count() != hdr->numbones() )
  882. {
  883. m_CachedBoneData.SetSize( hdr->numbones() );
  884. for ( int i=0; i < hdr->numbones(); i++ )
  885. {
  886. SetIdentityMatrix( m_CachedBoneData[i] );
  887. }
  888. }
  889. m_BoneAccessor.Init( this, m_CachedBoneData.Base() ); // Always call this in case the studiohdr_t has changed.
  890. // Free any IK data
  891. if (m_pIk)
  892. {
  893. delete m_pIk;
  894. m_pIk = NULL;
  895. }
  896. // Don't reallocate unless a different size.
  897. if ( m_Attachments.Count() != hdr->GetNumAttachments() )
  898. {
  899. m_Attachments.SetSize( hdr->GetNumAttachments() );
  900. // This is to make sure we don't use the attachment before its been set up
  901. for ( int i=0; i < m_Attachments.Count(); i++ )
  902. {
  903. m_Attachments[i].m_bAnglesComputed = false;
  904. m_Attachments[i].m_nLastFramecount = 0;
  905. #ifdef _DEBUG
  906. m_Attachments[i].m_AttachmentToWorld.Invalidate();
  907. m_Attachments[i].m_angRotation.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN );
  908. m_Attachments[i].m_vOriginVelocity.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN );
  909. #endif
  910. }
  911. }
  912. Assert( hdr->GetNumPoseParameters() <= ARRAYSIZE( m_flPoseParameter ) );
  913. m_iv_flPoseParameter.SetMaxCount( gpGlobals->curtime, hdr->GetNumPoseParameters() );
  914. int i;
  915. for ( i = 0; i < hdr->GetNumPoseParameters() ; i++ )
  916. {
  917. const mstudioposeparamdesc_t &Pose = hdr->pPoseParameter( i );
  918. m_iv_flPoseParameter.SetLooping( Pose.loop != 0.0f, i );
  919. // Note: We can't do this since if we get a DATA_UPDATE_CREATED (i.e., new entity) with both a new model and some valid pose parameters this will slam the
  920. // pose parameters to zero and if the model goes dormant the pose parameter field will never be set to the true value. We shouldn't have to zero these out
  921. // as they are under the control of the server and should be properly set
  922. if ( !IsServerEntity() )
  923. {
  924. SetPoseParameter( hdr, i, 0.0 );
  925. }
  926. }
  927. int boneControllerCount = MIN( hdr->numbonecontrollers(), ARRAYSIZE( m_flEncodedController ) );
  928. m_iv_flEncodedController.SetMaxCount( gpGlobals->curtime, boneControllerCount );
  929. for ( i = 0; i < boneControllerCount ; i++ )
  930. {
  931. bool loop = (hdr->pBonecontroller( i )->type & (STUDIO_XR | STUDIO_YR | STUDIO_ZR)) != 0;
  932. m_iv_flEncodedController.SetLooping( loop, i );
  933. SetBoneController( i, 0.0 );
  934. }
  935. InitModelEffects();
  936. // lookup generic eye attachment, if exists
  937. m_iEyeAttachment = LookupAttachment( "eyes" );
  938. // If we didn't have a model before, then we might need to go in the interpolation list now.
  939. if ( ShouldInterpolate() )
  940. AddToEntityList( ENTITY_LIST_INTERPOLATE );
  941. // objects with attachment points need to be queryable even if they're not solid
  942. if ( hdr->GetNumAttachments() != 0 )
  943. {
  944. AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  945. }
  946. // Most entities clear out their sequences when they change models on the server, but
  947. // not all entities network down their m_nSequence (like multiplayer game player entities),
  948. // so we need to clear it out here.
  949. if ( ShouldResetSequenceOnNewModel() )
  950. {
  951. SetSequence(0);
  952. }
  953. return hdr;
  954. }
  955. //-----------------------------------------------------------------------------
  956. // Purpose: Returns index number of a given named bone
  957. // Input : name of a bone
  958. // Output : Bone index number or -1 if bone not found
  959. //-----------------------------------------------------------------------------
  960. int C_BaseAnimating::LookupBone( const char *szName )
  961. {
  962. Assert( GetModelPtr() );
  963. if( !GetModelPtr() )
  964. {
  965. return -1;
  966. }
  967. //AssertMsg( !Q_stristr( szName, "ValveBiped" ), "ValveBiped bone names are deprecated!" );
  968. int ret = Studio_BoneIndexByName( GetModelPtr(), szName );
  969. if ( ret == -1 )
  970. {
  971. // Try to fix up some common old bone names to new bone names, until I can go through the code and fix all cases or write a data-driven solution.
  972. if ( Q_stristr( szName, "weapon_bone" ) )
  973. {
  974. ret = Studio_BoneIndexByName( GetModelPtr(), "hand_R" );
  975. }
  976. else if ( Q_stristr( szName, "Bip01_Head" ) )
  977. {
  978. ret = Studio_BoneIndexByName( GetModelPtr(), "head_0" );
  979. }
  980. else if ( Q_stristr( szName, "L_Hand" ) )
  981. {
  982. ret = Studio_BoneIndexByName( GetModelPtr(), "hand_L" );
  983. }
  984. else if ( Q_stristr( szName, "R_Hand" ) )
  985. {
  986. ret = Studio_BoneIndexByName( GetModelPtr(), "hand_R" );
  987. }
  988. //AssertMsg( ret > 0, "Failed to find an alternate bone name!" );
  989. }
  990. return ret;
  991. }
  992. //=========================================================
  993. //=========================================================
  994. void C_BaseAnimating::GetBonePosition ( int iBone, Vector &origin, QAngle &angles )
  995. {
  996. matrix3x4_t bonetoworld;
  997. GetBoneTransform( iBone, bonetoworld );
  998. MatrixAngles( bonetoworld, angles, origin );
  999. }
  1000. //=========================================================
  1001. //=========================================================
  1002. void C_BaseAnimating::GetBonePosition ( int iBone, Vector &origin )
  1003. {
  1004. matrix3x4_t bonetoworld;
  1005. GetBoneTransform( iBone, bonetoworld );
  1006. MatrixPosition( bonetoworld, origin );
  1007. }
  1008. //=========================================================
  1009. //=========================================================
  1010. void C_BaseAnimating::GetHitboxBonePosition ( int iBone, Vector &origin, QAngle &angles, QAngle hitboxOrientation )
  1011. {
  1012. matrix3x4_t bonetoworld;
  1013. GetBoneTransform( iBone, bonetoworld );
  1014. matrix3x4_t temp;
  1015. AngleMatrix( hitboxOrientation, temp);
  1016. MatrixMultiply( bonetoworld, temp, temp );
  1017. MatrixAngles( temp, angles, origin );
  1018. }
  1019. void C_BaseAnimating::GetHitboxBoneTransform( int iBone, QAngle hitboxOrientation, matrix3x4_t &pOut )
  1020. {
  1021. matrix3x4_t bonetoworld;
  1022. GetBoneTransform( iBone, bonetoworld );
  1023. matrix3x4_t temp;
  1024. AngleMatrix( hitboxOrientation, temp);
  1025. MatrixMultiply( bonetoworld, temp, pOut );
  1026. }
  1027. void C_BaseAnimating::GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld )
  1028. {
  1029. CStudioHdr *hdr = GetModelPtr();
  1030. if ( hdr && iBone >= 0 && iBone < hdr->numbones() )
  1031. {
  1032. if ( !IsBoneCacheValid() )
  1033. {
  1034. SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  1035. }
  1036. GetCachedBoneMatrix( iBone, pBoneToWorld );
  1037. }
  1038. else
  1039. {
  1040. AssertMsg( false, "Bone index out of range or null model header." );
  1041. MatrixCopy( EntityToWorldTransform(), pBoneToWorld );
  1042. }
  1043. }
  1044. //-----------------------------------------------------------------------------
  1045. // Purpose: Finds the bone associated with the given hitbox
  1046. //-----------------------------------------------------------------------------
  1047. int C_BaseAnimating::GetHitboxBone( int hitboxIndex )
  1048. {
  1049. CStudioHdr *pStudioHdr = GetModelPtr();
  1050. if ( pStudioHdr )
  1051. {
  1052. mstudiohitboxset_t *set =pStudioHdr->pHitboxSet( m_nHitboxSet );
  1053. if ( set && hitboxIndex < set->numhitboxes )
  1054. {
  1055. return set->pHitbox( hitboxIndex )->bone;
  1056. }
  1057. }
  1058. return 0;
  1059. }
  1060. //-----------------------------------------------------------------------------
  1061. // Purpose: Setup to initialize our model effects once the model's loaded
  1062. //-----------------------------------------------------------------------------
  1063. void C_BaseAnimating::InitModelEffects( void )
  1064. {
  1065. m_bInitModelEffects = true;
  1066. AddToEntityList(ENTITY_LIST_SIMULATE);
  1067. TermRopes();
  1068. }
  1069. //-----------------------------------------------------------------------------
  1070. // Purpose: Load the model's keyvalues section and create effects listed inside it
  1071. //-----------------------------------------------------------------------------
  1072. void C_BaseAnimating::DelayedInitModelEffects( void )
  1073. {
  1074. m_bInitModelEffects = false;
  1075. // Parse the keyvalues and see if they want to make ropes on this model.
  1076. KeyValues * modelKeyValues = new KeyValues("");
  1077. if ( modelKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), modelinfo->GetModelKeyValueText( GetModel() ) ) )
  1078. {
  1079. ParseModelEffects( modelKeyValues );
  1080. }
  1081. modelKeyValues->deleteThis();
  1082. }
  1083. void C_BaseAnimating::ParseModelEffects( KeyValues *modelKeyValues )
  1084. {
  1085. // Do we have a cables section?
  1086. KeyValues *pkvAllCables = modelKeyValues->FindKey("Cables");
  1087. if ( pkvAllCables )
  1088. {
  1089. // Start grabbing the sounds and slotting them in
  1090. for ( KeyValues *pSingleCable = pkvAllCables->GetFirstSubKey(); pSingleCable; pSingleCable = pSingleCable->GetNextKey() )
  1091. {
  1092. C_RopeKeyframe *pRope = C_RopeKeyframe::CreateFromKeyValues( this, pSingleCable );
  1093. m_Ropes.AddToTail( pRope );
  1094. }
  1095. }
  1096. // Do we have a particles section?
  1097. KeyValues *pkvAllParticleEffects = modelKeyValues->FindKey("Particles");
  1098. if ( pkvAllParticleEffects )
  1099. {
  1100. // Start grabbing the sounds and slotting them in
  1101. for ( KeyValues *pSingleEffect = pkvAllParticleEffects->GetFirstSubKey(); pSingleEffect; pSingleEffect = pSingleEffect->GetNextKey() )
  1102. {
  1103. const char *pszParticleEffect = pSingleEffect->GetString( "name", "" );
  1104. const char *pszAttachment = pSingleEffect->GetString( "attachment_point", "" );
  1105. const char *pszAttachType = pSingleEffect->GetString( "attachment_type", "" );
  1106. const char *pszAttachOffset = pSingleEffect->GetString( "attachment_offset", "" );
  1107. // Convert attach type
  1108. int iAttachType = GetAttachTypeFromString( pszAttachType );
  1109. if ( iAttachType == -1 )
  1110. {
  1111. Warning("Invalid attach type specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' with attach type of '%s'\n", GetModelName(), pszParticleEffect, pszAttachType );
  1112. return;
  1113. }
  1114. // Convert attachment point
  1115. int iAttachment = atoi(pszAttachment);
  1116. // See if we can find any attachment points matching the name
  1117. if ( pszAttachment[0] != '0' && iAttachment == 0 )
  1118. {
  1119. iAttachment = LookupAttachment( pszAttachment );
  1120. if ( iAttachment == -1 )
  1121. {
  1122. Warning("Failed to find attachment point specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' on attachment named '%s'\n", GetModelName(), pszParticleEffect, pszAttachment );
  1123. return;
  1124. }
  1125. }
  1126. Vector vecOffset = vec3_origin;
  1127. if ( pszAttachOffset )
  1128. {
  1129. float flVec[3];
  1130. UTIL_StringToVector( flVec, pszAttachOffset );
  1131. vecOffset = Vector( flVec[0], flVec[1], flVec[2] );
  1132. }
  1133. CUtlReference<CNewParticleEffect> hModelEffect;
  1134. // Spawn the particle effectw
  1135. hModelEffect = ParticleProp()->Create( pszParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment, vecOffset );
  1136. KeyValues *pkvAllControlPoints = pSingleEffect->FindKey("ControlPoints");
  1137. if ( pkvAllControlPoints )
  1138. {
  1139. // Start grabbing the CPs and slotting them in
  1140. for ( KeyValues *pSingleCP = pkvAllControlPoints->GetFirstSubKey(); pSingleCP; pSingleCP = pSingleCP->GetNextKey() )
  1141. {
  1142. const char *pszControlPoint = pSingleCP->GetString( "cp_number", "" );
  1143. const char *pszAttachment = pSingleCP->GetString( "attachment_point", "" );
  1144. const char *pszAttachType = pSingleCP->GetString( "attachment_type", "" );
  1145. const char *pszAttachOffset = pSingleCP->GetString( "attachment_offset", "" );
  1146. // Convert control point
  1147. int iControlPoint = atoi(pszControlPoint);
  1148. // Convert attach type
  1149. int iAttachType = GetAttachTypeFromString( pszAttachType );
  1150. if ( iAttachType == -1 )
  1151. {
  1152. Warning("Invalid attach type specified for particle effect in model '%s' keyvalues section. Trying to spawn effect '%s' with attach type of '%s'\n", GetModelName(), pszParticleEffect, pszAttachType );
  1153. return;
  1154. }
  1155. Vector vecOffset = vec3_origin;
  1156. if ( pszAttachOffset )
  1157. {
  1158. float flVec[3];
  1159. UTIL_StringToVector( flVec, pszAttachOffset );
  1160. vecOffset = Vector( flVec[0], flVec[1], flVec[2] );
  1161. }
  1162. // Add the control point if we already have the effect
  1163. if ( hModelEffect )
  1164. {
  1165. if ( iAttachType == PATTACH_WORLDORIGIN )
  1166. ParticleProp()->AddControlPoint( hModelEffect, iControlPoint, NULL, (ParticleAttachment_t)iAttachType, NULL, vecOffset );
  1167. else
  1168. ParticleProp()->AddControlPoint( hModelEffect, iControlPoint, this, (ParticleAttachment_t)iAttachType, pszAttachment, vecOffset );
  1169. }
  1170. }
  1171. }
  1172. }
  1173. }
  1174. }
  1175. void C_BaseAnimating::TermRopes()
  1176. {
  1177. FOR_EACH_LL( m_Ropes, i )
  1178. {
  1179. UTIL_Remove( m_Ropes[i] );
  1180. }
  1181. m_Ropes.Purge();
  1182. }
  1183. // FIXME: redundant?
  1184. void C_BaseAnimating::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS])
  1185. {
  1186. // interpolate two 0..1 encoded controllers to a single 0..1 controller
  1187. int i;
  1188. for( i=0; i < MAXSTUDIOBONECTRLS; i++ )
  1189. {
  1190. controllers[ i ] = m_flEncodedController[ i ];
  1191. }
  1192. }
  1193. float C_BaseAnimating::GetPoseParameterRaw( int iPoseParameter )
  1194. {
  1195. CStudioHdr *pStudioHdr = GetModelPtr();
  1196. if ( pStudioHdr == NULL )
  1197. return 0.0f;
  1198. if ( pStudioHdr->GetNumPoseParameters() < iPoseParameter )
  1199. return 0.0f;
  1200. if ( iPoseParameter < 0 )
  1201. return 0.0f;
  1202. return m_flPoseParameter[iPoseParameter];
  1203. }
  1204. // FIXME: redundant?
  1205. void C_BaseAnimating::GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM])
  1206. {
  1207. if ( !pStudioHdr )
  1208. return;
  1209. // interpolate pose parameters
  1210. int i;
  1211. for( i=0; i < pStudioHdr->GetNumPoseParameters(); i++)
  1212. {
  1213. poseParameter[i] = m_flPoseParameter[i];
  1214. }
  1215. #if 0 // _DEBUG
  1216. if (r_sequence_debug.GetInt() == entindex())
  1217. {
  1218. DevMsgRT( "%s\n", pStudioHdr->pszName() );
  1219. DevMsgRT( "%6.2f : ", gpGlobals->curtime );
  1220. for( i=0; i < pStudioHdr->GetNumPoseParameters(); i++)
  1221. {
  1222. const mstudioposeparamdesc_t &Pose = pStudioHdr->pPoseParameter( i );
  1223. DevMsgRT( "%s %6.2f ", Pose.pszName(), poseParameter[i] * Pose.end + (1 - poseParameter[i]) * Pose.start );
  1224. }
  1225. DevMsgRT( "\n" );
  1226. }
  1227. #endif
  1228. }
  1229. float C_BaseAnimating::ClampCycle( float flCycle, bool isLooping )
  1230. {
  1231. if (isLooping)
  1232. {
  1233. // FIXME: does this work with negative framerate?
  1234. flCycle = SubtractIntegerPart(flCycle);
  1235. if (flCycle < 0.0f)
  1236. {
  1237. flCycle += 1.0f;
  1238. }
  1239. }
  1240. else
  1241. {
  1242. flCycle = clamp( flCycle, 0.0f, 0.999f );
  1243. }
  1244. return flCycle;
  1245. }
  1246. void C_BaseAnimating::EnableJiggleBones( void )
  1247. {
  1248. m_isJiggleBonesEnabled = true;
  1249. }
  1250. void C_BaseAnimating::DisableJiggleBones( void )
  1251. {
  1252. m_isJiggleBonesEnabled = false;
  1253. // clear old data so any jiggle bones don't pop if they're enabled again
  1254. if ( m_pJiggleBones )
  1255. {
  1256. delete m_pJiggleBones;
  1257. m_pJiggleBones = NULL;
  1258. }
  1259. }
  1260. void C_BaseAnimating::ScriptSetPoseParameter( const char *szName, float fValue )
  1261. {
  1262. CStudioHdr *pHdr = GetModelPtr();
  1263. if ( pHdr == NULL )
  1264. return;
  1265. int iPoseParam = LookupPoseParameter( pHdr, szName );
  1266. SetPoseParameter( pHdr, iPoseParam, fValue );
  1267. }
  1268. void C_BaseAnimating::SetRenderOriginOverride( const Vector &vec )
  1269. {
  1270. if( m_vecRenderOriginOverride != vec )
  1271. {
  1272. InvalidateBoneCache();
  1273. }
  1274. m_vecRenderOriginOverride = vec;
  1275. }
  1276. void C_BaseAnimating::DisableRenderOriginOverride( void )
  1277. {
  1278. if( m_vecRenderOriginOverride != vec3_invalid )
  1279. {
  1280. InvalidateBoneCache();
  1281. }
  1282. m_vecRenderOriginOverride = vec3_invalid;
  1283. }
  1284. void C_BaseAnimating::GetCachedBoneMatrix( int boneIndex, matrix3x4_t &out )
  1285. {
  1286. MatrixCopy( GetBone( boneIndex ), out );
  1287. }
  1288. void C_BaseAnimating::CalcBoneMerge( int boneMask )
  1289. {
  1290. // For EF_BONEMERGE entities, copy the bone matrices for any bones that have matching names.
  1291. bool boneMerge = IsEffectActive( EF_BONEMERGE );
  1292. if ( boneMerge || m_pBoneMergeCache )
  1293. {
  1294. if ( boneMerge )
  1295. {
  1296. if ( !m_pBoneMergeCache )
  1297. {
  1298. m_pBoneMergeCache = new CBoneMergeCache;
  1299. m_pBoneMergeCache->Init( this );
  1300. }
  1301. m_pBoneMergeCache->MergeMatchingBones( boneMask );
  1302. }
  1303. else
  1304. {
  1305. delete m_pBoneMergeCache;
  1306. m_pBoneMergeCache = NULL;
  1307. }
  1308. }
  1309. }
  1310. //-----------------------------------------------------------------------------
  1311. // Purpose: move position and rotation transforms into global matrices
  1312. //-----------------------------------------------------------------------------
  1313. void C_BaseAnimating::BuildTransformations( CStudioHdr *hdr, BoneVector *pos, BoneQuaternion *q, const matrix3x4_t &cameraTransform, int boneMask, CBoneBitList &boneComputed )
  1314. {
  1315. VPROF_BUDGET( "C_BaseAnimating::BuildTransformations", ( !g_bInThreadedBoneSetup ) ? VPROF_BUDGETGROUP_CLIENT_ANIMATION : "Client_Animation_Threaded" );
  1316. // SNPROF_ANIM( "C_BaseAnimating::BuildTransformations" );
  1317. if ( !hdr )
  1318. return;
  1319. matrix3x4a_t bonematrix;
  1320. bool boneSimulated[MAXSTUDIOBONES];
  1321. // no bones have been simulated
  1322. memset( boneSimulated, 0, sizeof(boneSimulated) );
  1323. const mstudiobone_t *pbones = hdr->pBone( 0 );
  1324. bool bFixupSimulatedPositions = false;
  1325. if ( m_pRagdoll )
  1326. {
  1327. // simulate bones and update flags
  1328. int oldWritableBones = m_BoneAccessor.GetWritableBones();
  1329. int oldReadableBones = m_BoneAccessor.GetReadableBones();
  1330. m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING );
  1331. m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING );
  1332. // If we're playing back a demo, override the ragdoll bones with cached version if available - otherwise, simulate.
  1333. #if defined( REPLAY_ENABLED )
  1334. if ( ( !engine->IsPlayingDemo() && !engine->IsPlayingTimeDemo() ) ||
  1335. !CReplayRagdollCache::Instance().IsInitialized() ||
  1336. !CReplayRagdollCache::Instance().GetFrame( this, engine->GetDemoPlaybackTick(), boneSimulated, &m_BoneAccessor ) )
  1337. #endif
  1338. {
  1339. m_pRagdoll->RagdollBone( this, pbones, hdr->numbones(), boneSimulated, m_BoneAccessor );
  1340. }
  1341. m_BoneAccessor.SetWritableBones( oldWritableBones );
  1342. m_BoneAccessor.SetReadableBones( oldReadableBones );
  1343. bFixupSimulatedPositions = !m_pRagdoll->GetRagdoll()->allowStretch;
  1344. }
  1345. CalcBoneMerge( boneMask );
  1346. if ( CSoftbody *pSoftbody = hdr->GetSoftbody() )
  1347. {
  1348. bool bTeleported = ( Teleported() || IsEffectActive( EF_NOINTERP ) );
  1349. pSoftbody->SetAbsOrigin( GetRenderOrigin(), bTeleported );
  1350. pSoftbody->SetAbsAngles( GetRenderAngles(), bTeleported );
  1351. pSoftbody->SetModelScale( GetModelScale() );
  1352. }
  1353. for (int i = 0; i < hdr->numbones(); ++i)
  1354. {
  1355. // Only update bones reference by the bone mask.
  1356. if ( !( hdr->boneFlags( i ) & boneMask ) )
  1357. continue;
  1358. if ( m_pBoneMergeCache && m_pBoneMergeCache->IsBoneMerged( i ) )
  1359. continue;
  1360. PREFETCH360( &GetBoneForWrite( i ), 0 );
  1361. // animate all non-simulated bones
  1362. if ( boneSimulated[i] )
  1363. {
  1364. ApplyBoneMatrixTransform( GetBoneForWrite( i ) );
  1365. if ( bFixupSimulatedPositions && pbones[i].parent != -1 )
  1366. {
  1367. Vector boneOrigin;
  1368. VectorTransform( pos[i], GetBone(pbones[i].parent), boneOrigin );
  1369. PositionMatrix( boneOrigin, GetBoneForWrite( i ) );
  1370. }
  1371. continue;
  1372. }
  1373. else if ( CalcProceduralBone( hdr, i, m_BoneAccessor ))
  1374. {
  1375. continue;
  1376. }
  1377. // skip bones that the IK has already setup
  1378. else if (boneComputed.IsBoneMarked( i ))
  1379. {
  1380. // dummy operation, just used to verify in debug that this should have happened
  1381. GetBoneForWrite( i );
  1382. }
  1383. else
  1384. {
  1385. QuaternionMatrix( q[i], pos[i], bonematrix );
  1386. Assert( fabs( pos[i].x ) < 100000 );
  1387. Assert( fabs( pos[i].y ) < 100000 );
  1388. Assert( fabs( pos[i].z ) < 100000 );
  1389. if ( (hdr->boneFlags( i ) & BONE_ALWAYS_PROCEDURAL) &&
  1390. (hdr->pBone( i )->proctype & STUDIO_PROC_JIGGLE) &&
  1391. !r_jiggle_bones.GetBool() )
  1392. {
  1393. if ( m_pJiggleBones )
  1394. {
  1395. delete m_pJiggleBones;
  1396. m_pJiggleBones = NULL;
  1397. }
  1398. }
  1399. if ( (hdr->boneFlags( i ) & BONE_ALWAYS_PROCEDURAL) &&
  1400. (hdr->pBone( i )->proctype & STUDIO_PROC_JIGGLE) &&
  1401. r_jiggle_bones.GetBool() && m_isJiggleBonesEnabled )
  1402. {
  1403. //
  1404. // Physics-based "jiggle" bone
  1405. // Bone is assumed to be along the Z axis
  1406. // Pitch around X, yaw around Y
  1407. //
  1408. // compute desired bone orientation
  1409. matrix3x4a_t goalMX;
  1410. if (pbones[i].parent == -1)
  1411. {
  1412. ConcatTransforms( cameraTransform, bonematrix, goalMX );
  1413. }
  1414. else
  1415. {
  1416. ConcatTransforms_Aligned( GetBone( pbones[i].parent ), bonematrix, goalMX );
  1417. }
  1418. // get jiggle properties from QC data
  1419. mstudiojigglebone_t *jiggleInfo = (mstudiojigglebone_t *)pbones[i].pProcedure( );
  1420. if (!m_pJiggleBones)
  1421. {
  1422. m_pJiggleBones = new CJiggleBones;
  1423. }
  1424. // do jiggle physics
  1425. m_pJiggleBones->BuildJiggleTransformations( i, gpGlobals->curtime, jiggleInfo, goalMX, GetBoneForWrite( i ), ShouldFlipModel() );
  1426. }
  1427. else if (hdr->boneParent(i) == -1)
  1428. {
  1429. ConcatTransforms( cameraTransform, bonematrix, GetBoneForWrite( i ) );
  1430. }
  1431. else
  1432. {
  1433. ConcatTransforms_Aligned( GetBone( hdr->boneParent(i) ), bonematrix, GetBoneForWrite( i ) );
  1434. }
  1435. if (hdr->boneFlags( i ) & BONE_WORLD_ALIGN)
  1436. {
  1437. Vector vecOrigin = GetBone(i).GetOrigin();
  1438. GetBoneForWrite( i ).Init( Vector(1,0,0), Vector(0,1,0), Vector(0,0,1), vecOrigin );
  1439. }
  1440. }
  1441. if (hdr->boneParent(i) == -1)
  1442. {
  1443. // Apply client-side effects to the transformation matrix
  1444. ApplyBoneMatrixTransform( GetBoneForWrite( i ) );
  1445. }
  1446. }
  1447. PostBuildTransformations( hdr, pos, q );
  1448. // If a nonhierarchical scale is being applied
  1449. const float scale = GetModelScale();
  1450. if( GetModelScaleType() == NONHIERARCHICAL_MODEL_SCALE &&
  1451. scale > 1.0f+FLT_EPSILON || scale < 1.0f-FLT_EPSILON )
  1452. {
  1453. for( int i = 0; i < hdr->numbones(); ++i )
  1454. {
  1455. // Only update bones reference by the bone mask.
  1456. if( !( hdr->boneFlags(i) & boneMask ) )
  1457. continue;
  1458. if( m_pBoneMergeCache && m_pBoneMergeCache->IsBoneMerged(i) )
  1459. continue;
  1460. PREFETCH360( &GetBoneForWrite(i), 0 );
  1461. matrix3x4_t& transform = GetBoneForWrite(i);
  1462. VectorScale( transform[0], scale, transform[0] );
  1463. VectorScale( transform[1], scale, transform[1] );
  1464. VectorScale( transform[2], scale, transform[2] );
  1465. }
  1466. }
  1467. if ( CSoftbody *pSoftbody = hdr->GetSoftbody() )
  1468. {
  1469. pSoftbody->GoWakeup();
  1470. matrix3x4a_t *pBones = m_BoneAccessor.GetBoneArrayForWrite();
  1471. pSoftbody->SetAnimatedTransforms( pBones );
  1472. pSoftbody->FilterTransforms( pBones );
  1473. }
  1474. UpdateBoneAttachments();
  1475. }
  1476. //-----------------------------------------------------------------------------
  1477. // Purpose: Special effects
  1478. // Input : transform -
  1479. //-----------------------------------------------------------------------------
  1480. void C_BaseAnimating::ApplyBoneMatrixTransform( matrix3x4_t& transform )
  1481. {
  1482. float scale = GetModelHierarchyScale();
  1483. if ( scale > 1.0f+FLT_EPSILON || scale < 1.0f-FLT_EPSILON )
  1484. {
  1485. // The bone transform is in worldspace, so to scale this, we need to translate it back
  1486. Vector pos;
  1487. MatrixGetColumn( transform, 3, pos );
  1488. pos -= GetRenderOrigin();
  1489. pos *= scale;
  1490. pos += GetRenderOrigin();
  1491. MatrixSetColumn( pos, 3, transform );
  1492. VectorScale( transform[0], scale, transform[0] );
  1493. VectorScale( transform[1], scale, transform[1] );
  1494. VectorScale( transform[2], scale, transform[2] );
  1495. }
  1496. }
  1497. void C_BaseAnimating::CreateUnragdollInfo( C_BaseAnimating *pRagdoll )
  1498. {
  1499. CStudioHdr *hdr = GetModelPtr();
  1500. if ( !hdr )
  1501. {
  1502. return;
  1503. }
  1504. // It's already an active ragdoll, sigh
  1505. if ( m_pRagdollInfo && m_pRagdollInfo->m_bActive )
  1506. {
  1507. Assert( 0 );
  1508. return;
  1509. }
  1510. // Now do the current bone setup
  1511. pRagdoll->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  1512. matrix3x4_t parentTransform;
  1513. QAngle newAngles( 0, pRagdoll->GetAbsAngles()[YAW], 0 );
  1514. AngleMatrix( GetAbsAngles(), GetAbsOrigin(), parentTransform );
  1515. // pRagdoll->SaveRagdollInfo( hdr->numbones, parentTransform, m_BoneAccessor );
  1516. if ( !m_pRagdollInfo )
  1517. {
  1518. m_pRagdollInfo = new RagdollInfo_t;
  1519. Assert( m_pRagdollInfo );
  1520. if ( !m_pRagdollInfo )
  1521. {
  1522. Msg( "Memory allocation of RagdollInfo_t failed!\n" );
  1523. return;
  1524. }
  1525. }
  1526. Q_memset( m_pRagdollInfo, 0, sizeof( *m_pRagdollInfo ) );
  1527. int numbones = hdr->numbones();
  1528. m_pRagdollInfo->m_bActive = true;
  1529. m_pRagdollInfo->m_flSaveTime = gpGlobals->curtime;
  1530. m_pRagdollInfo->m_nNumBones = numbones;
  1531. for ( int i = 0; i < numbones; i++ )
  1532. {
  1533. matrix3x4_t inverted;
  1534. matrix3x4_t output;
  1535. if ( hdr->boneParent(i) == -1 )
  1536. {
  1537. // Decompose into parent space
  1538. MatrixInvert( parentTransform, inverted );
  1539. }
  1540. else
  1541. {
  1542. MatrixInvert( pRagdoll->m_BoneAccessor.GetBone( hdr->boneParent(i) ), inverted );
  1543. }
  1544. ConcatTransforms( inverted, pRagdoll->m_BoneAccessor.GetBone( i ), output );
  1545. MatrixAngles( output,
  1546. m_pRagdollInfo->m_rgBoneQuaternion[ i ],
  1547. m_pRagdollInfo->m_rgBonePos[ i ] );
  1548. }
  1549. }
  1550. void C_BaseAnimating::SaveRagdollInfo( int numbones, const matrix3x4_t &cameraTransform, CBoneAccessor &pBoneToWorld )
  1551. {
  1552. CStudioHdr *hdr = GetModelPtr();
  1553. if ( !hdr )
  1554. {
  1555. return;
  1556. }
  1557. if ( !m_pRagdollInfo )
  1558. {
  1559. m_pRagdollInfo = new RagdollInfo_t;
  1560. Assert( m_pRagdollInfo );
  1561. if ( !m_pRagdollInfo )
  1562. {
  1563. Msg( "Memory allocation of RagdollInfo_t failed!\n" );
  1564. return;
  1565. }
  1566. memset( m_pRagdollInfo, 0, sizeof( *m_pRagdollInfo ) );
  1567. }
  1568. const mstudiobone_t *pbones = hdr->pBone( 0 );
  1569. m_pRagdollInfo->m_bActive = true;
  1570. m_pRagdollInfo->m_flSaveTime = gpGlobals->curtime;
  1571. m_pRagdollInfo->m_nNumBones = numbones;
  1572. for ( int i = 0; i < numbones; i++ )
  1573. {
  1574. matrix3x4_t inverted;
  1575. matrix3x4_t output;
  1576. if ( pbones[i].parent == -1 )
  1577. {
  1578. // Decompose into parent space
  1579. MatrixInvert( cameraTransform, inverted );
  1580. }
  1581. else
  1582. {
  1583. MatrixInvert( pBoneToWorld.GetBone( pbones[ i ].parent ), inverted );
  1584. }
  1585. ConcatTransforms( inverted, pBoneToWorld.GetBone( i ), output );
  1586. MatrixAngles( output,
  1587. m_pRagdollInfo->m_rgBoneQuaternion[ i ],
  1588. m_pRagdollInfo->m_rgBonePos[ i ] );
  1589. }
  1590. }
  1591. bool C_BaseAnimating::RetrieveRagdollInfo( BoneVector *pos, BoneQuaternion *q )
  1592. {
  1593. if ( !m_bStoreRagdollInfo || !m_pRagdollInfo || !m_pRagdollInfo->m_bActive )
  1594. return false;
  1595. for ( int i = 0; i < m_pRagdollInfo->m_nNumBones; i++ )
  1596. {
  1597. pos[ i ] = m_pRagdollInfo->m_rgBonePos[ i ];
  1598. q[ i ] = m_pRagdollInfo->m_rgBoneQuaternion[ i ];
  1599. }
  1600. return true;
  1601. }
  1602. //-----------------------------------------------------------------------------
  1603. // Should we collide?
  1604. //-----------------------------------------------------------------------------
  1605. CollideType_t C_BaseAnimating::GetCollideType( void )
  1606. {
  1607. if ( IsRagdoll() )
  1608. return ENTITY_SHOULD_RESPOND;
  1609. return BaseClass::GetCollideType();
  1610. }
  1611. //-----------------------------------------------------------------------------
  1612. // Purpose: if the active sequence changes, keep track of the previous ones and decay them based on their decay rate
  1613. //-----------------------------------------------------------------------------
  1614. void C_BaseAnimating::MaintainSequenceTransitions( IBoneSetup &boneSetup, float flCycle, BoneVector pos[], BoneQuaternion q[] )
  1615. {
  1616. VPROF( "C_BaseAnimating::MaintainSequenceTransitions" );
  1617. if ( !m_bMaintainSequenceTransitions )
  1618. return;
  1619. if ( !boneSetup.GetStudioHdr() )
  1620. return;
  1621. if ( prediction->InPrediction() )
  1622. {
  1623. m_nPrevNewSequenceParity = m_nNewSequenceParity;
  1624. return;
  1625. }
  1626. if ( IsPlayer() )
  1627. {
  1628. return;
  1629. }
  1630. if ( IsViewModel() && m_nNewSequenceParity != m_nPrevNewSequenceParity && !IsSequenceLooping( GetSequence() ) )
  1631. {
  1632. C_BaseViewModel *pViewModel = assert_cast< C_BaseViewModel* >( this );
  1633. C_BasePlayer *pPlayer = ToBasePlayer( pViewModel->GetOwner() );
  1634. if ( pPlayer && pPlayer->IsHoldingLookAtWeapon() )
  1635. {
  1636. // If we're setting a view model to play the same sequence we need to force the cycle back to zero!
  1637. // For looking at your weapon the client and server timings need to match up so that it can loop properly!
  1638. pViewModel->m_fCycleOffset = -1.0f * ( ( gpGlobals->curtime - m_flAnimTime ) * GetSequenceCycleRate( GetModelPtr(), GetSequence() ) );
  1639. flCycle = 0.0f;
  1640. }
  1641. else
  1642. {
  1643. // Non-lookat animations don't need this offset goofiness
  1644. pViewModel->m_fCycleOffset = 0.0f;
  1645. }
  1646. }
  1647. m_SequenceTransitioner.CheckForSequenceChange(
  1648. boneSetup.GetStudioHdr(),
  1649. GetSequence(),
  1650. m_nNewSequenceParity != m_nPrevNewSequenceParity,
  1651. !IsEffectActive(EF_NOINTERP)
  1652. );
  1653. m_nPrevNewSequenceParity = m_nNewSequenceParity;
  1654. // Update the transition sequence list.
  1655. m_SequenceTransitioner.UpdateCurrent(
  1656. boneSetup.GetStudioHdr(),
  1657. GetSequence(),
  1658. flCycle,
  1659. GetPlaybackRate(),
  1660. gpGlobals->curtime
  1661. );
  1662. // process previous sequences
  1663. for (int i = m_SequenceTransitioner.m_animationQueue.Count() - 2; i >= 0; i--)
  1664. {
  1665. CAnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i];
  1666. float dt = (gpGlobals->curtime - blend->m_flLayerAnimtime);
  1667. flCycle = blend->GetCycle() + dt * blend->GetPlaybackRate() * GetSequenceCycleRate( boneSetup.GetStudioHdr(), blend->GetSequence() );
  1668. flCycle = ClampCycle( flCycle, IsSequenceLooping( boneSetup.GetStudioHdr(), blend->GetSequence() ) );
  1669. #if 1 // _DEBUG
  1670. if (r_sequence_debug.GetInt() == entindex())
  1671. {
  1672. DevMsgRT( "%8.4f : %30s : %5.3f : %4.2f +\n", gpGlobals->curtime, boneSetup.GetStudioHdr()->pSeqdesc( blend->GetSequence() ).pszLabel(), flCycle, (float)blend->GetWeight() );
  1673. }
  1674. #endif
  1675. boneSetup.AccumulatePose( pos, q, blend->GetSequence(), flCycle, blend->GetWeight(), gpGlobals->curtime, m_pIk );
  1676. }
  1677. }
  1678. //-----------------------------------------------------------------------------
  1679. // Purpose:
  1680. // Input : *hdr -
  1681. // pos[] -
  1682. // q[] -
  1683. //-----------------------------------------------------------------------------
  1684. void C_BaseAnimating::UnragdollBlend( CStudioHdr *hdr, BoneVector pos[], BoneQuaternion q[], float currentTime )
  1685. {
  1686. // SNPROF_ANIM( "C_BaseAnimating::UnragdollBlend" );
  1687. if ( !hdr )
  1688. {
  1689. return;
  1690. }
  1691. if ( !m_pRagdollInfo || !m_pRagdollInfo->m_bActive )
  1692. return;
  1693. float dt = currentTime - m_pRagdollInfo->m_flSaveTime;
  1694. if ( dt > 0.2f )
  1695. {
  1696. m_pRagdollInfo->m_bActive = false;
  1697. return;
  1698. }
  1699. // Slerp bone sets together
  1700. float frac = dt / 0.2f;
  1701. frac = clamp( frac, 0.0f, 1.0f );
  1702. int i;
  1703. for ( i = 0; i < hdr->numbones(); i++ )
  1704. {
  1705. VectorLerp( m_pRagdollInfo->m_rgBonePos[ i ], pos[ i ], frac, pos[ i ] );
  1706. QuaternionSlerp( m_pRagdollInfo->m_rgBoneQuaternion[ i ], q[ i ], frac, q[ i ] );
  1707. }
  1708. }
  1709. void C_BaseAnimating::AccumulateLayers( IBoneSetup &boneSetup, BoneVector pos[], BoneQuaternion q[], float currentTime )
  1710. {
  1711. // Nothing here
  1712. }
  1713. //-----------------------------------------------------------------------------
  1714. // Purpose: Do the default sequence blending rules as done in HL1
  1715. //-----------------------------------------------------------------------------
  1716. void C_BaseAnimating::StandardBlendingRules( CStudioHdr *hdr, BoneVector pos[], BoneQuaternionAligned q[], float currentTime, int boneMask )
  1717. {
  1718. VPROF( "C_BaseAnimating::StandardBlendingRules" );
  1719. // SNPROF_ANIM( "C_BaseAnimating::StandardBlendingRules" );
  1720. float poseparam[MAXSTUDIOPOSEPARAM];
  1721. if ( !hdr )
  1722. return;
  1723. if ( !hdr->SequencesAvailable() )
  1724. {
  1725. return;
  1726. }
  1727. if (GetSequence() >= hdr->GetNumSeq() || GetSequence() == -1 )
  1728. {
  1729. SetSequence( 0 );
  1730. }
  1731. #ifdef DEMOPOLISH_ENABLED
  1732. if ( IsDemoPolishPlaying() && IsPlayer() )
  1733. {
  1734. float const flDemoPlaybackTime = DemoPolish_GetController().GetAdjustedPlaybackTime();
  1735. int const iSequenceOverride = DemoPolish_GetController().GetSequenceOverride( entindex(), flDemoPlaybackTime );
  1736. if ( iSequenceOverride >= 0 )
  1737. {
  1738. // Override.
  1739. SetSequence( iSequenceOverride );
  1740. }
  1741. }
  1742. #endif
  1743. GetPoseParameters( hdr, poseparam );
  1744. // build root animation
  1745. float fCycle = GetCycle();
  1746. #if 1 //_DEBUG
  1747. if (r_sequence_debug.GetInt() == entindex())
  1748. {
  1749. DevMsgRT( "%8.4f : %30s(%d) : %5.3f : %4.2f\n", currentTime, hdr->pSeqdesc( GetSequence() ).pszLabel(), GetSequence(), fCycle, 1.0 );
  1750. }
  1751. #endif
  1752. IBoneSetup boneSetup( hdr, boneMask, poseparam );
  1753. boneSetup.InitPose( pos, q );
  1754. boneSetup.AccumulatePose( pos, q, GetSequence(), fCycle, 1.0, currentTime, m_pIk );
  1755. // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), 0, 0, "%30s %6.2f : %6.2f", hdr->pSeqdesc( GetSequence() )->pszLabel( ), fCycle, 1.0 );
  1756. MaintainSequenceTransitions( boneSetup, fCycle, pos, q );
  1757. AccumulateLayers( boneSetup, pos, q, currentTime );
  1758. CIKContext auto_ik;
  1759. auto_ik.Init( hdr, GetRenderAngles(), GetRenderOrigin(), currentTime, gpGlobals->framecount, boneMask );
  1760. boneSetup.CalcAutoplaySequences( pos, q, currentTime, &auto_ik );
  1761. if ( hdr->numbonecontrollers() )
  1762. {
  1763. float controllers[MAXSTUDIOBONECTRLS];
  1764. GetBoneControllers(controllers);
  1765. boneSetup.CalcBoneAdj( pos, q, controllers );
  1766. }
  1767. UnragdollBlend( hdr, pos, q, currentTime );
  1768. #ifdef STUDIO_ENABLE_PERF_COUNTERS
  1769. #if _DEBUG
  1770. /*
  1771. if (r_sequence_debug.GetInt() == entindex() )
  1772. {
  1773. DevMsgRT( "layers %4d : bones %4d : animated %4d\n", hdr->m_nPerfAnimationLayers, hdr->m_nPerfUsedBones, hdr->m_nPerfAnimatedBones );
  1774. }
  1775. */
  1776. #endif
  1777. #endif
  1778. }
  1779. //-----------------------------------------------------------------------------
  1780. // Purpose: Put a value into an attachment point by index
  1781. // Input : number - which point
  1782. // Output : float * - the attachment point
  1783. //-----------------------------------------------------------------------------
  1784. bool C_BaseAnimating::PutAttachment( int number, const matrix3x4_t &attachmentToWorld )
  1785. {
  1786. if ( number < 1 || number > m_Attachments.Count() )
  1787. return false;
  1788. CAttachmentData *pAtt = &m_Attachments[number-1];
  1789. if ( gpGlobals->frametime > 0 && pAtt->m_nLastFramecount > 0 && pAtt->m_nLastFramecount == gpGlobals->framecount - 1 )
  1790. {
  1791. Vector vecPreviousOrigin, vecOrigin;
  1792. MatrixPosition( pAtt->m_AttachmentToWorld, vecPreviousOrigin );
  1793. MatrixPosition( attachmentToWorld, vecOrigin );
  1794. pAtt->m_vOriginVelocity = (vecOrigin - vecPreviousOrigin) / gpGlobals->frametime;
  1795. }
  1796. else
  1797. {
  1798. pAtt->m_vOriginVelocity.Init();
  1799. }
  1800. pAtt->m_nLastFramecount = gpGlobals->framecount;
  1801. pAtt->m_bAnglesComputed = false;
  1802. pAtt->m_AttachmentToWorld = attachmentToWorld;
  1803. #ifdef _DEBUG
  1804. pAtt->m_angRotation.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN );
  1805. #endif
  1806. return true;
  1807. }
  1808. // when hierarchy changes, these are no longer valid for comparison. munge the frame counter so they
  1809. // get ignored
  1810. void C_BaseAnimating::InvalidateAttachments()
  1811. {
  1812. int frameCount = -1;
  1813. for ( int i = 0; i < m_Attachments.Count(); i++ )
  1814. {
  1815. m_Attachments[i].m_nLastFramecount = frameCount;
  1816. }
  1817. }
  1818. void C_BaseAnimating::SetupBones_AttachmentHelper( CStudioHdr *hdr )
  1819. {
  1820. if ( !hdr || !hdr->GetNumAttachments() )
  1821. return;
  1822. // calculate attachment points
  1823. matrix3x4_t world;
  1824. for (int i = 0; i < hdr->GetNumAttachments(); i++)
  1825. {
  1826. const mstudioattachment_t &pattachment = hdr->pAttachment( i );
  1827. int iBone = hdr->GetAttachmentBone( i );
  1828. if ( (pattachment.flags & ATTACHMENT_FLAG_WORLD_ALIGN) == 0 )
  1829. {
  1830. ConcatTransforms( GetBone( iBone ), pattachment.local, world );
  1831. }
  1832. else
  1833. {
  1834. Vector vecLocalBonePos, vecWorldBonePos;
  1835. MatrixGetColumn( pattachment.local, 3, vecLocalBonePos );
  1836. VectorTransform( vecLocalBonePos, GetBone( iBone ), vecWorldBonePos );
  1837. SetIdentityMatrix( world );
  1838. PositionMatrix( vecWorldBonePos, world );
  1839. }
  1840. // FIXME: this shouldn't be here, it should client side on-demand only and hooked into the bone cache!!
  1841. FormatViewModelAttachment( i, world );
  1842. PutAttachment( i + 1, world );
  1843. }
  1844. }
  1845. bool C_BaseAnimating::CalcAttachments()
  1846. {
  1847. VPROF( "C_BaseAnimating::CalcAttachments" );
  1848. // SNPROF_ANIM( "C_BaseAnimating::CalcAttachments" );
  1849. // Make sure m_CachedBones is valid.
  1850. return SetupBones( NULL, -1, BONE_USED_BY_ATTACHMENT, gpGlobals->curtime );
  1851. }
  1852. //-----------------------------------------------------------------------------
  1853. // Purpose: Returns the world location and world angles of an attachment
  1854. // Input : attachment name
  1855. // Output : location and angles
  1856. //-----------------------------------------------------------------------------
  1857. bool C_BaseAnimating::GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles )
  1858. {
  1859. return GetAttachment( LookupAttachment( szName ), absOrigin, absAngles );
  1860. }
  1861. //-----------------------------------------------------------------------------
  1862. // Purpose: Get attachment point by index
  1863. // Input : number - which point
  1864. // Output : float * - the attachment point
  1865. //-----------------------------------------------------------------------------
  1866. bool C_BaseAnimating::GetAttachment( int number, Vector &origin, QAngle &angles )
  1867. {
  1868. // Note: this could be more efficient, but we want the matrix3x4_t version of GetAttachment to be the origin of
  1869. // attachment generation, so a derived class that wants to fudge attachments only
  1870. // has to reimplement that version. This also makes it work like the server in that regard.
  1871. if ( number < 1 || number > m_Attachments.Count() || !CalcAttachments() )
  1872. {
  1873. // Set this to the model origin/angles so that we don't have stack fungus in origin and angles.
  1874. origin = GetAbsOrigin();
  1875. angles = GetAbsAngles();
  1876. return false;
  1877. }
  1878. CAttachmentData *pData = &m_Attachments[number-1];
  1879. if ( !pData->m_bAnglesComputed )
  1880. {
  1881. MatrixAngles( pData->m_AttachmentToWorld, pData->m_angRotation );
  1882. pData->m_bAnglesComputed = true;
  1883. }
  1884. angles = pData->m_angRotation;
  1885. MatrixPosition( pData->m_AttachmentToWorld, origin );
  1886. return true;
  1887. }
  1888. bool C_BaseAnimating::GetAttachment( int number, matrix3x4_t& matrix )
  1889. {
  1890. if ( number < 1 || number > m_Attachments.Count() )
  1891. return false;
  1892. if ( !CalcAttachments() )
  1893. return false;
  1894. matrix = m_Attachments[number-1].m_AttachmentToWorld;
  1895. return true;
  1896. }
  1897. //-----------------------------------------------------------------------------
  1898. // Purpose: Get attachment point by index (position only)
  1899. // Input : number - which point
  1900. //-----------------------------------------------------------------------------
  1901. bool C_BaseAnimating::GetAttachment( int number, Vector &origin )
  1902. {
  1903. // Note: this could be more efficient, but we want the matrix3x4_t version of GetAttachment to be the origin of
  1904. // attachment generation, so a derived class that wants to fudge attachments only
  1905. // has to reimplement that version. This also makes it work like the server in that regard.
  1906. matrix3x4_t attachmentToWorld;
  1907. if ( !GetAttachment( number, attachmentToWorld ) )
  1908. {
  1909. // Set this to the model origin/angles so that we don't have stack fungus in origin and angles.
  1910. origin = GetAbsOrigin();
  1911. return false;
  1912. }
  1913. MatrixPosition( attachmentToWorld, origin );
  1914. return true;
  1915. }
  1916. bool C_BaseAnimating::GetAttachment( const char *szName, Vector &absOrigin )
  1917. {
  1918. return GetAttachment( LookupAttachment( szName ), absOrigin );
  1919. }
  1920. bool C_BaseAnimating::ComputeLightingOrigin( int nAttachmentIndex, Vector modelLightingCenter, const matrix3x4_t &matrix, Vector &transformedLightingCenter )
  1921. {
  1922. if ( m_bUseParentLightingOrigin )
  1923. {
  1924. if ( GetMoveParent() != NULL )
  1925. {
  1926. C_BaseAnimating *attachmentParent = GetMoveParent()->GetBaseAnimating();
  1927. if ( NULL != attachmentParent )
  1928. {
  1929. if ( attachmentParent->ComputeLightingOrigin(nAttachmentIndex, attachmentParent->GetModelPtr()->illumposition(), attachmentParent->RenderableToWorldTransform(), transformedLightingCenter) )
  1930. return true;
  1931. }
  1932. }
  1933. }
  1934. return BaseClass::ComputeLightingOrigin( nAttachmentIndex, modelLightingCenter, matrix, transformedLightingCenter );
  1935. }
  1936. bool C_BaseAnimating::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
  1937. {
  1938. if ( number < 1 || number > m_Attachments.Count() )
  1939. {
  1940. return false;
  1941. }
  1942. if ( !CalcAttachments() )
  1943. return false;
  1944. originVel = m_Attachments[number-1].m_vOriginVelocity;
  1945. angleVel.Init();
  1946. return true;
  1947. }
  1948. //-----------------------------------------------------------------------------
  1949. // Returns the attachment in local space
  1950. //-----------------------------------------------------------------------------
  1951. bool C_BaseAnimating::GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal )
  1952. {
  1953. matrix3x4_t attachmentToWorld;
  1954. if (!GetAttachment(iAttachment, attachmentToWorld))
  1955. return false;
  1956. matrix3x4_t worldToEntity;
  1957. MatrixInvert( EntityToWorldTransform(), worldToEntity );
  1958. ConcatTransforms( worldToEntity, attachmentToWorld, attachmentToLocal );
  1959. return true;
  1960. }
  1961. bool C_BaseAnimating::GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles )
  1962. {
  1963. matrix3x4_t attachmentToEntity;
  1964. if ( GetAttachmentLocal( iAttachment, attachmentToEntity ) )
  1965. {
  1966. origin.Init( attachmentToEntity[0][3], attachmentToEntity[1][3], attachmentToEntity[2][3] );
  1967. MatrixAngles( attachmentToEntity, angles );
  1968. return true;
  1969. }
  1970. return false;
  1971. }
  1972. bool C_BaseAnimating::GetAttachmentLocal( int iAttachment, Vector &origin )
  1973. {
  1974. matrix3x4_t attachmentToEntity;
  1975. if ( GetAttachmentLocal( iAttachment, attachmentToEntity ) )
  1976. {
  1977. MatrixPosition( attachmentToEntity, origin );
  1978. return true;
  1979. }
  1980. return false;
  1981. }
  1982. //-----------------------------------------------------------------------------
  1983. // Purpose: Move sound location to center of body
  1984. //-----------------------------------------------------------------------------
  1985. bool C_BaseAnimating::GetSoundSpatialization( SpatializationInfo_t& info )
  1986. {
  1987. {
  1988. C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, false );
  1989. if ( !BaseClass::GetSoundSpatialization( info ) )
  1990. return false;
  1991. }
  1992. // move sound origin to center if npc has IK
  1993. if ( info.pOrigin && IsNPC() && m_pIk)
  1994. {
  1995. *info.pOrigin = GetAbsOrigin();
  1996. Vector mins, maxs, center;
  1997. modelinfo->GetModelBounds( GetModel(), mins, maxs );
  1998. VectorAdd( mins, maxs, center );
  1999. VectorScale( center, 0.5f, center );
  2000. (*info.pOrigin) += center;
  2001. }
  2002. return true;
  2003. }
  2004. bool C_BaseAnimating::IsViewModel() const
  2005. {
  2006. return false;
  2007. }
  2008. bool C_BaseAnimating::IsViewModelOrAttachment() const
  2009. {
  2010. return false;
  2011. }
  2012. bool C_BaseAnimating::IsMenuModel() const
  2013. {
  2014. return false;
  2015. }
  2016. class CTraceFilterSkipNPCsAndPlayers : public CTraceFilterSimple
  2017. {
  2018. public:
  2019. CTraceFilterSkipNPCsAndPlayers( const IHandleEntity *passentity, int collisionGroup )
  2020. : CTraceFilterSimple( passentity, collisionGroup )
  2021. {
  2022. }
  2023. virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
  2024. {
  2025. if ( CTraceFilterSimple::ShouldHitEntity(pServerEntity, contentsMask) )
  2026. {
  2027. C_BaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
  2028. if ( !pEntity )
  2029. return true;
  2030. do
  2031. {
  2032. if ( pEntity->IsNPC() || pEntity->IsPlayer() )
  2033. {
  2034. return false;
  2035. }
  2036. } while ( ( pEntity = pEntity->GetMoveParent() ) != NULL );
  2037. return true;
  2038. }
  2039. return false;
  2040. }
  2041. };
  2042. /*
  2043. void drawLine(const Vector& origin, const Vector& dest, int r, int g, int b, bool noDepthTest, float duration)
  2044. {
  2045. debugoverlay->AddLineOverlay( origin, dest, r, g, b, noDepthTest, duration );
  2046. }
  2047. */
  2048. //-----------------------------------------------------------------------------
  2049. // Purpose: update latched IK contacts if they're in a moving reference frame.
  2050. //-----------------------------------------------------------------------------
  2051. void C_BaseAnimating::UpdateIKLocks( float currentTime )
  2052. {
  2053. if (!m_pIk)
  2054. return;
  2055. int targetCount = m_pIk->m_target.Count();
  2056. if ( targetCount == 0 )
  2057. return;
  2058. for (int i = 0; i < targetCount; i++)
  2059. {
  2060. CIKTarget *pTarget = &m_pIk->m_target[i];
  2061. if (!pTarget->IsActive())
  2062. continue;
  2063. if (pTarget->GetOwner() != -1)
  2064. {
  2065. C_BaseEntity *pOwner = cl_entitylist->GetEnt( pTarget->GetOwner() );
  2066. if (pOwner != NULL)
  2067. {
  2068. pTarget->UpdateOwner( pOwner->entindex(), pOwner->GetAbsOrigin(), pOwner->GetAbsAngles() );
  2069. }
  2070. }
  2071. }
  2072. }
  2073. //-----------------------------------------------------------------------------
  2074. // Purpose: Find the ground or external attachment points needed by IK rules
  2075. //-----------------------------------------------------------------------------
  2076. void C_BaseAnimating::CalculateIKLocks( float currentTime )
  2077. {
  2078. // SNPROF_ANIM( "C_BaseAnimating::CalculateIKLocks" );
  2079. if (!m_pIk)
  2080. return;
  2081. int targetCount = m_pIk->m_target.Count();
  2082. if ( targetCount == 0 )
  2083. return;
  2084. // In TF, we might be attaching a player's view to a walking model that's using IK. If we are, it can
  2085. // get in here during the view setup code, and it's not normally supposed to be able to access the spatial
  2086. // partition that early in the rendering loop. So we allow access right here for that special case.
  2087. SpatialPartitionListMask_t curSuppressed = ::partition->GetSuppressedLists();
  2088. ::partition->SuppressLists( PARTITION_ALL_CLIENT_EDICTS, false );
  2089. CBaseEntity::PushEnableAbsRecomputations( false );
  2090. Ray_t ray;
  2091. CTraceFilterSkipNPCsAndPlayers traceFilter( this, GetCollisionGroup() );
  2092. // FIXME: trace based on gravity or trace based on angles?
  2093. Vector up;
  2094. AngleVectors( GetRenderAngles(), NULL, NULL, &up );
  2095. for (int i = 0; i < targetCount; i++)
  2096. {
  2097. trace_t trace;
  2098. CIKTarget *pTarget = &m_pIk->m_target[i];
  2099. if (!pTarget->IsActive())
  2100. continue;
  2101. switch( pTarget->type)
  2102. {
  2103. case IK_GROUND:
  2104. {
  2105. Vector estGround;
  2106. // adjust ground to original ground position
  2107. estGround = (pTarget->est.pos - GetRenderOrigin());
  2108. // estGround = estGround - (estGround * up) * up;
  2109. estGround = GetAbsOrigin() + estGround;
  2110. estGround.z = GetAbsOrigin().z;
  2111. pTarget->SetPos( estGround );
  2112. pTarget->SetAngles( GetRenderAngles() );
  2113. pTarget->SetOnWorld( true );
  2114. /*
  2115. if ( pTarget->est.flWeight == 1.0f )
  2116. {
  2117. debugoverlay->AddBoxOverlay( estGround, Vector( -5, -5, -1 ), Vector( 5, 5, 0), QAngle( 0, 0, 0 ), 255, 0, 0, 0, 1.0f );
  2118. }
  2119. */
  2120. /*
  2121. debugoverlay->AddTextOverlay( p1, i, 0, "%d %.1f %.1f %.1f ", i,
  2122. pTarget->latched.deltaPos.x, pTarget->latched.deltaPos.y, pTarget->latched.deltaPos.z );
  2123. debugoverlay->AddBoxOverlay( pTarget->est.pos, Vector( -r, -r, -1 ), Vector( r, r, 1), QAngle( 0, 0, 0 ), 255, 0, 0, 0, 0 );
  2124. */
  2125. // debugoverlay->AddBoxOverlay( pTarget->latched.pos, Vector( -2, -2, 2 ), Vector( 2, 2, 6), QAngle( 0, 0, 0 ), 0, 255, 0, 0, 0 );
  2126. }
  2127. break;
  2128. case IK_ATTACHMENT:
  2129. {
  2130. C_BaseEntity *pEntity = NULL;
  2131. float flDist = pTarget->est.radius;
  2132. // FIXME: make entity finding sticky!
  2133. // FIXME: what should the radius check be?
  2134. for ( CEntitySphereQuery sphere( pTarget->est.pos, 64, 0, PARTITION_CLIENT_IK_ATTACHMENT ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
  2135. {
  2136. C_BaseAnimating *pAnim = pEntity->GetBaseAnimating( );
  2137. if (!pAnim)
  2138. continue;
  2139. int iAttachment = pAnim->LookupAttachment( pTarget->offset.pAttachmentName );
  2140. if (iAttachment <= 0)
  2141. continue;
  2142. Vector origin;
  2143. QAngle angles;
  2144. pAnim->GetAttachment( iAttachment, origin, angles );
  2145. // debugoverlay->AddBoxOverlay( origin, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), QAngle( 0, 0, 0 ), 255, 0, 0, 0, 0 );
  2146. float d = (pTarget->est.pos - origin).Length();
  2147. if ( d >= flDist)
  2148. continue;
  2149. flDist = d;
  2150. pTarget->SetPos( origin );
  2151. pTarget->SetAngles( angles );
  2152. // debugoverlay->AddBoxOverlay( pTarget->est.pos, Vector( -pTarget->est.radius, -pTarget->est.radius, -pTarget->est.radius ), Vector( pTarget->est.radius, pTarget->est.radius, pTarget->est.radius), QAngle( 0, 0, 0 ), 0, 255, 0, 0, 0 );
  2153. }
  2154. if (flDist >= pTarget->est.radius)
  2155. {
  2156. // debugoverlay->AddBoxOverlay( pTarget->est.pos, Vector( -pTarget->est.radius, -pTarget->est.radius, -pTarget->est.radius ), Vector( pTarget->est.radius, pTarget->est.radius, pTarget->est.radius), QAngle( 0, 0, 0 ), 0, 0, 255, 0, 0 );
  2157. // no solution, disable ik rule
  2158. pTarget->IKFailed( );
  2159. }
  2160. }
  2161. break;
  2162. }
  2163. }
  2164. #if defined( HL2_CLIENT_DLL )
  2165. if (minHeight < FLT_MAX)
  2166. {
  2167. input->AddIKGroundContactInfo( entindex(), minHeight, maxHeight );
  2168. }
  2169. #endif
  2170. CBaseEntity::PopEnableAbsRecomputations();
  2171. ::partition->SuppressLists( curSuppressed, true );
  2172. }
  2173. bool C_BaseAnimating::GetPoseParameterRange( int index, float &minValue, float &maxValue )
  2174. {
  2175. CStudioHdr *pStudioHdr = GetModelPtr();
  2176. if (pStudioHdr)
  2177. {
  2178. if (index >= 0 && index < pStudioHdr->GetNumPoseParameters())
  2179. {
  2180. const mstudioposeparamdesc_t &pose = pStudioHdr->pPoseParameter( index );
  2181. minValue = pose.start;
  2182. maxValue = pose.end;
  2183. return true;
  2184. }
  2185. }
  2186. minValue = 0.0f;
  2187. maxValue = 1.0f;
  2188. return false;
  2189. }
  2190. //-----------------------------------------------------------------------------
  2191. // Purpose: Do HL1 style lipsynch
  2192. //-----------------------------------------------------------------------------
  2193. void C_BaseAnimating::ControlMouth( CStudioHdr *pstudiohdr )
  2194. {
  2195. if ( !MouthInfo().NeedsEnvelope() )
  2196. return;
  2197. if ( !pstudiohdr )
  2198. return;
  2199. int index = LookupPoseParameter( pstudiohdr, LIPSYNC_POSEPARAM_NAME );
  2200. if ( index != -1 )
  2201. {
  2202. float value = GetMouth()->mouthopen / 64.0;
  2203. float raw = value;
  2204. if ( value > 1.0 )
  2205. value = 1.0;
  2206. float start, end;
  2207. GetPoseParameterRange( index, start, end );
  2208. value = (1.0 - value) * start + value * end;
  2209. //Adrian - Set the pose parameter value.
  2210. //It has to be called "mouth".
  2211. SetPoseParameter( pstudiohdr, index, value );
  2212. // Reset interpolation here since the client is controlling this rather than the server...
  2213. m_iv_flPoseParameter.SetHistoryValuesForItem( index, raw );
  2214. }
  2215. }
  2216. CMouthInfo *C_BaseAnimating::GetMouth( void )
  2217. {
  2218. return &m_mouth;
  2219. }
  2220. #ifdef DEBUG_BONE_SETUP_THREADING
  2221. ConVar cl_warn_thread_contested_bone_setup("cl_warn_thread_contested_bone_setup", "0" );
  2222. #endif
  2223. // 7LS - turning off threaded bones on X360 until we find out why there is a perf hit, even though we are running the bonesetups in parallel!
  2224. ConVar cl_threaded_bone_setup( "cl_threaded_bone_setup", IsX360() ? "1" : (IsPS3() ? "2" : "0"), FCVAR_RELEASE, "Enable parallel processing of bones" );
  2225. //-----------------------------------------------------------------------------
  2226. // Purpose: Do the default sequence blending rules as done in HL1
  2227. //-----------------------------------------------------------------------------
  2228. #ifdef DEBUG_BONE_SETUP_THREADING
  2229. CThreadLocalInt<> *pCount;
  2230. #endif
  2231. void C_BaseAnimating::SetupBonesOnBaseAnimating( C_BaseAnimating *&pBaseAnimating )
  2232. {
  2233. C_BaseAnimating *pCurrent = pBaseAnimating;
  2234. C_BaseAnimating *pNext;
  2235. while ( pCurrent )
  2236. {
  2237. pNext = pCurrent->m_pNextForThreadedBoneSetup;
  2238. pCurrent->m_pNextForThreadedBoneSetup = NULL;
  2239. pCurrent->SetupBones( NULL, -1, -1, gpGlobals->curtime );
  2240. pCurrent = pNext;
  2241. }
  2242. #ifdef DEBUG_BONE_SETUP_THREADING
  2243. (*pCount)++;
  2244. #endif
  2245. }
  2246. static void PreThreadedBoneSetup()
  2247. {
  2248. mdlcache->BeginCoarseLock();
  2249. mdlcache->BeginLock();
  2250. }
  2251. static void PostThreadedBoneSetup()
  2252. {
  2253. mdlcache->EndLock();
  2254. mdlcache->EndCoarseLock();
  2255. #ifdef DEBUG_BONE_SETUP_THREADING
  2256. Msg( " %x done, %d\n", ThreadGetCurrentId(), (int)(*pCount) );
  2257. (*pCount) = 0;
  2258. #endif
  2259. }
  2260. static bool g_bDoThreadedBoneSetup;
  2261. IThreadPool *g_pBoneSetupThreadPool;
  2262. void C_BaseAnimating::InitBoneSetupThreadPool()
  2263. {
  2264. #ifdef DEBUG_BONE_SETUP_THREADING
  2265. pCount = new CThreadLocalInt<>;
  2266. #endif
  2267. #ifdef _X360
  2268. if ( g_pAlternateThreadPool )
  2269. {
  2270. g_pBoneSetupThreadPool = g_pAlternateThreadPool;
  2271. }
  2272. else
  2273. #endif
  2274. {
  2275. g_pBoneSetupThreadPool = g_pThreadPool;
  2276. }
  2277. // setup SPU bonejobs
  2278. #if defined( _PS3 )
  2279. g_pBoneJobs->Init();
  2280. #endif
  2281. }
  2282. void C_BaseAnimating::ShutdownBoneSetupThreadPool()
  2283. {
  2284. }
  2285. void C_BaseAnimating::MarkForThreadedBoneSetup()
  2286. {
  2287. // SNPROF_ANIM( "C_BaseAnimating::MarkForThreadedBoneSetup" );
  2288. if ( g_bDoThreadedBoneSetup && !g_bInThreadedBoneSetup && m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter )
  2289. {
  2290. if ( !IsViewModel() )
  2291. {
  2292. // This function is protected by m_BoneSetupLock (see SetupBones)
  2293. if ( m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter )
  2294. {
  2295. // SNPROF_ANIM( "C_BaseAnimating::MarkForThreadedBoneSetup_AddToTail" );
  2296. #ifdef DEBUG_BONESETUP_THREADVSNONTHREAD
  2297. Msg("MARK FOR THREADED: %x\n", this );
  2298. #endif
  2299. m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter;
  2300. LOCAL_THREAD_LOCK();
  2301. Assert( g_PreviousBoneSetups.Find( this ) == -1 );
  2302. g_PreviousBoneSetups.AddToTail( this );
  2303. }
  2304. }
  2305. }
  2306. }
  2307. void C_BaseAnimating::ThreadedBoneSetup()
  2308. {
  2309. #ifdef _PS3
  2310. g_bDoThreadedBoneSetup = 1;
  2311. #else
  2312. g_bDoThreadedBoneSetup = ( g_pBoneSetupThreadPool && g_pBoneSetupThreadPool->NumThreads() && cl_threaded_bone_setup.GetInt() );
  2313. #endif
  2314. if ( g_bDoThreadedBoneSetup )
  2315. {
  2316. int nCount = g_PreviousBoneSetups.Count();
  2317. #if defined( _PS3 )
  2318. if ( nCount > 0 )
  2319. #else
  2320. if ( nCount > 1 )
  2321. #endif
  2322. {
  2323. VPROF_BUDGET( "C_BaseAnimating::ThreadedBoneSetup", "Client_Animation_Threaded" );
  2324. SNPROF_ANIM( "C_BaseAnimating::ThreadedBoneSetup" );
  2325. #ifdef DEBUG_BONE_SETUP_THREADING
  2326. Msg( "{\n" );
  2327. #endif
  2328. // This loop is here rather than the mark function so we don't have to worry about the list being threadsafe, or worry about entity destruction
  2329. #ifdef _DEBUG
  2330. CUtlVector<C_BaseAnimating *> test;
  2331. test.AddVectorToTail( g_PreviousBoneSetups );
  2332. #endif
  2333. for ( int i = g_PreviousBoneSetups.Count() - 1; i >= 0; i-- )
  2334. {
  2335. C_BaseAnimating *pAnimating = g_PreviousBoneSetups[i];
  2336. C_BaseAnimating *pDependancy;
  2337. if ( (pDependancy = pAnimating->GetBoneSetupDependancy()) != NULL )
  2338. {
  2339. Assert( pAnimating->m_pNextForThreadedBoneSetup == NULL );
  2340. C_BaseAnimating *pNextDependancy;
  2341. while ( (pNextDependancy = pDependancy->GetBoneSetupDependancy()) != NULL )
  2342. {
  2343. pDependancy = pNextDependancy;
  2344. }
  2345. pAnimating->m_pNextForThreadedBoneSetup = pDependancy->m_pNextForThreadedBoneSetup;
  2346. pDependancy->m_pNextForThreadedBoneSetup = pAnimating;
  2347. g_PreviousBoneSetups.FastRemove( i );
  2348. if ( pDependancy->m_iMostRecentBoneSetupRequest != g_iPreviousBoneCounter )
  2349. {
  2350. Assert( g_PreviousBoneSetups.Find( pDependancy ) == -1 );
  2351. pDependancy->m_iMostRecentBoneSetupRequest = g_iPreviousBoneCounter;
  2352. g_PreviousBoneSetups.AddToTail( pDependancy );
  2353. }
  2354. }
  2355. }
  2356. nCount = g_PreviousBoneSetups.Count();
  2357. g_bInThreadedBoneSetup = true;
  2358. if ( cl_threaded_bone_setup.GetInt() == 1 )
  2359. {
  2360. CParallelProcessor<C_BaseAnimating *, CFuncJobItemProcessor<C_BaseAnimating *>, 2 > processor;
  2361. processor.m_ItemProcessor.Init( &SetupBonesOnBaseAnimating, &PreThreadedBoneSetup, &PostThreadedBoneSetup );
  2362. processor.Run( g_PreviousBoneSetups.Base(), nCount, 1, INT_MAX, g_pBoneSetupThreadPool );
  2363. }
  2364. else
  2365. {
  2366. #if defined( _PS3 )
  2367. ThreadedBoneSetup_PS3( nCount );
  2368. #else
  2369. for ( int i = 0; i < nCount; i++ )
  2370. {
  2371. SetupBonesOnBaseAnimating( g_PreviousBoneSetups[i] );
  2372. }
  2373. #endif
  2374. }
  2375. g_bInThreadedBoneSetup = false;
  2376. #ifdef _DEBUG
  2377. for ( int i = test.Count() - 1; i > 0; i-- )
  2378. {
  2379. Assert( test[i]->m_pNextForThreadedBoneSetup == NULL );
  2380. }
  2381. #endif
  2382. #ifdef DEBUG_BONE_SETUP_THREADING
  2383. Msg( "} \n" );
  2384. #endif
  2385. }
  2386. }
  2387. g_iPreviousBoneCounter++;
  2388. g_PreviousBoneSetups.RemoveAll();
  2389. }
  2390. bool C_BaseAnimating::InThreadedBoneSetup()
  2391. {
  2392. return g_bInThreadedBoneSetup;
  2393. }
  2394. #ifdef DEBUG
  2395. ConVar cl_limit_anim_fps("cl_limit_anim_fps", "1");
  2396. #endif
  2397. #define FPS_TO_FRAMETIME_SECS( _n ) (1000.0f / _n) * 0.001f
  2398. bool C_BaseAnimating::ShouldSkipAnimationFrame( float currentTime )
  2399. {
  2400. #ifdef DEBUG
  2401. if ( !cl_limit_anim_fps.GetBool() )
  2402. return false;
  2403. #endif
  2404. // only applies to players
  2405. if ( !IsPlayer() )
  2406. return false;
  2407. int nFrameCount = gpGlobals->framecount;
  2408. if ( !m_nLastNonSkippedFrame || abs( nFrameCount - m_nLastNonSkippedFrame ) >= 2 )
  2409. return false;
  2410. if ( gpGlobals->frametime < FPS_TO_FRAMETIME_SECS(300.0f) )
  2411. {
  2412. nFrameCount += (entindex() % 3); // offset lookups
  2413. if ( (nFrameCount % 3) != 0 ) // at 300+ fps, compute every third animation frame to floor animation at 100fps
  2414. {
  2415. return true;
  2416. }
  2417. }
  2418. else if ( gpGlobals->frametime < FPS_TO_FRAMETIME_SECS(200.0f) )
  2419. {
  2420. nFrameCount += (entindex() % 2); // offset lookups
  2421. if ( (nFrameCount % 2) != 0 ) // at 200+ fps, compute every other animation frame to floor animation at 100fps
  2422. {
  2423. return true;
  2424. }
  2425. }
  2426. else if ( gpGlobals->frametime < FPS_TO_FRAMETIME_SECS(150.0f) )
  2427. {
  2428. nFrameCount += (entindex() % 3); // offset lookups
  2429. if ( (nFrameCount % 3) == 0 ) // at 150+ fps, skip every third animation frame to floor animation at 100fps
  2430. {
  2431. return true;
  2432. }
  2433. }
  2434. return false;
  2435. }
  2436. extern ConVar cl_countbones;
  2437. bool C_BaseAnimating::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  2438. {
  2439. VPROF_BUDGET( "C_BaseAnimating::SetupBones", ( !g_bInThreadedBoneSetup ) ? VPROF_BUDGETGROUP_CLIENT_ANIMATION : "Client_Animation_Threaded" );
  2440. SNPROF_ANIM( "C_BaseAnimating::SetupBones" );
  2441. // [pfreese] Added the check for pBoneToWorldOut != NULL in this debug warning
  2442. // code. SetupBones is called in the CSS anytime an attachment wants its
  2443. // parent's transform, hence this warning is hit extremely frequently.
  2444. // I'm not actually sure if this is the right "fix" for this, as the bones are
  2445. // actually accessed as part of the setup process, but since I'm not clear on the
  2446. // purpose of this dev warning, I'm including this comment block.
  2447. if ( pBoneToWorldOut != NULL && !IsBoneAccessAllowed() )
  2448. {
  2449. static float lastWarning = 0.0f;
  2450. // Prevent spammage!!!
  2451. if ( gpGlobals->realtime >= lastWarning + 1.0f )
  2452. {
  2453. DevMsgRT( "*** ERROR: Bone access not allowed (entity %i:%s)\n", index, GetClassname() );
  2454. lastWarning = gpGlobals->realtime;
  2455. }
  2456. }
  2457. //boneMask = BONE_USED_BY_ANYTHING; // HACK HACK - this is a temp fix until we have accessors for bones to find out where problems are.
  2458. // some bones are tagged to always setup, they get OR'd in now
  2459. boneMask |= BONE_ALWAYS_SETUP;
  2460. if ( GetSequence() == -1 )
  2461. return false;
  2462. if ( boneMask == -1 )
  2463. {
  2464. boneMask = m_iPrevBoneMask;
  2465. }
  2466. // We should get rid of this someday when we have solutions for the odd cases where a bone doesn't
  2467. // get setup and its transform is asked for later.
  2468. if ( cl_SetupAllBones.GetInt() )
  2469. {
  2470. boneMask |= BONE_USED_BY_ANYTHING;
  2471. }
  2472. // Set up all bones if recording, too
  2473. if ( IsToolRecording() )
  2474. {
  2475. boneMask |= BONE_USED_BY_ANYTHING;
  2476. }
  2477. // Or lastly if demo polish recording
  2478. #ifdef DEMOPOLISH_ENABLED
  2479. if ( IsDemoPolishRecording() && IsPlayer() )
  2480. {
  2481. boneMask |= BONE_USED_BY_ANYTHING;
  2482. }
  2483. #endif // DEMO_POLISH
  2484. if ( g_bInThreadedBoneSetup )
  2485. {
  2486. // boneMask |= ( BONE_USED_BY_ATTACHMENT | BONE_USED_BY_BONE_MERGE | BONE_USED_BY_HITBOX );
  2487. if ( !m_BoneSetupLock.TryLock() )
  2488. {
  2489. // someone else is handling
  2490. // bones are in some intermediate state, wait until the other thread is done.
  2491. // If they've setup what bones we want, it'll early out down below
  2492. m_BoneSetupLock.Lock();
  2493. }
  2494. // else, we have the lock
  2495. }
  2496. else
  2497. {
  2498. m_BoneSetupLock.Lock();
  2499. }
  2500. // If we're setting up LOD N, we have set up all lower LODs also
  2501. // because lower LODs always use subsets of the bones of higher LODs.
  2502. int nLOD = 0;
  2503. int nMask = BONE_USED_BY_VERTEX_LOD0;
  2504. for( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 )
  2505. {
  2506. if ( boneMask & nMask )
  2507. break;
  2508. }
  2509. for( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 )
  2510. {
  2511. boneMask |= nMask;
  2512. }
  2513. #ifdef DEBUG_BONE_SETUP_THREADING
  2514. if ( cl_warn_thread_contested_bone_setup.GetBool() )
  2515. {
  2516. if ( !m_BoneSetupLock.TryLock() )
  2517. {
  2518. Msg( "Contested bone setup in frame %d!\n", gpGlobals->framecount );
  2519. }
  2520. else
  2521. {
  2522. m_BoneSetupLock.Unlock();
  2523. }
  2524. }
  2525. #endif
  2526. // A bit of a hack, but this way when in prediction we use the "correct" gpGlobals->curtime -- rather than the
  2527. // one that the player artificially advances
  2528. if ( GetPredictable() &&
  2529. prediction->InPrediction() )
  2530. {
  2531. currentTime = prediction->GetSavedTime();
  2532. }
  2533. #if defined(_DEBUG_SPUvPPU_ANIMATION)
  2534. m_BoneAccessor.SetReadableBones( 0 );
  2535. m_BoneAccessor.SetWritableBones( 0 );
  2536. m_flLastBoneSetupTime = 0.0f;
  2537. m_iPrevBoneMask = m_iAccumulatedBoneMask;
  2538. m_iAccumulatedBoneMask = 0;
  2539. #else
  2540. if( ( m_iMostRecentModelBoneCounter != g_iModelBoneCounter ) && s_bEnableNewBoneSetupRequest )
  2541. {
  2542. // Clear out which bones we've touched this frame if this is
  2543. // the first time we've seen this object this frame.
  2544. // BUGBUG: Time can go backward due to prediction, catch that here until a better solution is found
  2545. if ( LastBoneChangedTime() >= m_flLastBoneSetupTime || currentTime < m_flLastBoneSetupTime )
  2546. {
  2547. // SNPROF_ANIM("Anim_NewSetupBones");
  2548. #ifdef DEBUG_BONESETUP_THREADVSNONTHREAD
  2549. Msg("SetupBones 1st time: %x, mask: %d, mrmbc: %d, time:%f\n", this, boneMask, m_iMostRecentModelBoneCounter, currentTime );
  2550. #endif
  2551. m_BoneAccessor.SetReadableBones( 0 );
  2552. m_BoneAccessor.SetWritableBones( 0 );
  2553. m_flLastBoneSetupTime = currentTime;
  2554. #if defined( DBGFLAG_ASSERT )
  2555. m_vBoneSetupCachedOrigin = GetRenderOrigin();
  2556. m_qBoneSetupCachedAngles = GetRenderAngles();
  2557. #endif
  2558. }
  2559. m_iPrevBoneMask = m_iAccumulatedBoneMask;
  2560. m_iAccumulatedBoneMask = 0;
  2561. #ifdef STUDIO_ENABLE_PERF_COUNTERS
  2562. CStudioHdr *hdr = GetModelPtr();
  2563. if (hdr)
  2564. {
  2565. hdr->ClearPerfCounters();
  2566. }
  2567. #endif
  2568. }
  2569. #endif
  2570. MarkForThreadedBoneSetup();
  2571. // Keep track of everthing asked for over the entire frame
  2572. // But not those things asked for during bone setup
  2573. {
  2574. m_iAccumulatedBoneMask |= boneMask;
  2575. }
  2576. // Make sure that we know that we've already calculated some bone stuff this time around.
  2577. #if !defined(_DEBUG_SPUvPPU_ANIMATION)
  2578. m_iMostRecentModelBoneCounter = g_iModelBoneCounter;
  2579. #endif
  2580. // Have we cached off all bones meeting the flag set?
  2581. if( ( m_BoneAccessor.GetReadableBones() & boneMask ) != boneMask )
  2582. {
  2583. CStudioHdr *hdr = GetModelPtr();
  2584. if ( !hdr || !hdr->SequencesAvailable() )
  2585. {
  2586. m_BoneSetupLock.Unlock();
  2587. return false;
  2588. }
  2589. #if defined( DBGFLAG_ASSERT )
  2590. bool bHadDirtyAbsTransform = IsEFlagSet( EFL_DIRTY_ABSTRANSFORM );
  2591. #endif
  2592. // Setup our transform based on render angles and origin.
  2593. ALIGN16 matrix3x4_t parentTransform ALIGN16_POST;
  2594. AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform );
  2595. AssertMsg( !bHadDirtyAbsTransform || !IsEFlagSet( EFL_DIRTY_ABSTRANSFORM ), "Using an old origin/angles and unable to recompute before caching off the bones" );
  2596. // Load the boneMask with the total of what was asked for last frame.
  2597. // WHY??
  2598. boneMask |= m_iPrevBoneMask;
  2599. // Allow access to the bones we're setting up so we don't get asserts in here.
  2600. int oldReadableBones = m_BoneAccessor.GetReadableBones();
  2601. m_BoneAccessor.SetWritableBones( m_BoneAccessor.GetReadableBones() | boneMask );
  2602. m_BoneAccessor.SetReadableBones( m_BoneAccessor.GetWritableBones() );
  2603. // label the entities if we're trying to figure out who is who
  2604. if ( r_sequence_debug.GetInt() == -1)
  2605. {
  2606. Vector theMins, theMaxs;
  2607. GetRenderBounds( theMins, theMaxs );
  2608. debugoverlay->AddTextOverlay( GetAbsOrigin() + (theMins + theMaxs) * 0.5f, 0, 0.0f, "%d:%s", entindex(), hdr->name() );
  2609. }
  2610. if (hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP)
  2611. {
  2612. MatrixCopy( parentTransform, GetBoneForWrite( 0 ) );
  2613. }
  2614. else
  2615. {
  2616. #ifdef DEBUG_BONE_SETUP_THREADING
  2617. if ( !g_bInThreadedBoneSetup )
  2618. {
  2619. Msg("!%x\n", this );
  2620. }
  2621. #endif
  2622. if ( !g_bInThreadedBoneSetup )
  2623. {
  2624. TrackBoneSetupEnt( this );
  2625. }
  2626. // This is necessary because it's possible that CalculateIKLocks will trigger our move children
  2627. // to call GetAbsOrigin(), and they'll use our OLD bone transforms to get their attachments
  2628. // since we're right in the middle of setting up our new transforms.
  2629. //
  2630. // Setting this flag forces move children to keep their abs transform invalidated.
  2631. AddEFlags( EFL_SETTING_UP_BONES );
  2632. // NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated
  2633. // [msmith]: What game is it that want's to do model scaling and needs to opt out of IK? It seems as if opting out of IK should be the exception and not the rule here.
  2634. // I suggest we change the #ifdef such that only the games that need to kill IK get used here... rather than ORing in all other games that use this engine in the future.
  2635. #if defined( PORTAL2 ) || defined( INFESTED ) || defined( CSTRIKE15 )
  2636. // only allocate an ik block if the npc can use it
  2637. if ( !m_pIk && hdr->numikchains() > 0 && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) )
  2638. m_pIk = new CIKContext;
  2639. #endif // PORTAL2
  2640. #if defined( _PS3 )
  2641. BoneVector pos[MAXSTUDIOBONES] ALIGN128;
  2642. BoneQuaternionAligned q[MAXSTUDIOBONES] ALIGN128;
  2643. #else
  2644. BoneVector pos[MAXSTUDIOBONES];
  2645. BoneQuaternionAligned q[MAXSTUDIOBONES];
  2646. #endif
  2647. if ( m_pIk )
  2648. {
  2649. if (Teleported() || IsEffectActive(EF_NOINTERP))
  2650. {
  2651. m_pIk->ClearTargets();
  2652. }
  2653. m_pIk->Init( hdr, GetRenderAngles(), GetRenderOrigin(), currentTime, gpGlobals->framecount, boneMask );
  2654. }
  2655. // Let pose debugger know that we are blending
  2656. g_pPoseDebugger->StartBlending( this, hdr );
  2657. bool bSkipThisFrame = ShouldSkipAnimationFrame( currentTime );
  2658. CBoneBitList boneComputed;
  2659. if ( !bSkipThisFrame )
  2660. {
  2661. int nTempMask = boneMask;
  2662. if ( m_nCustomBlendingRuleMask != -1 )
  2663. {
  2664. nTempMask &= m_nCustomBlendingRuleMask;
  2665. }
  2666. nTempMask |= BONE_ALWAYS_SETUP; // make sure we always set up these bones
  2667. if ( cl_countbones.GetBool() )
  2668. {
  2669. for ( int i = 0; i < hdr->numbones(); ++i )
  2670. {
  2671. if ( hdr->boneFlags(i) & nTempMask )
  2672. g_nNumBonesSetupBlendingRulesOnlyTemp++;
  2673. }
  2674. }
  2675. StandardBlendingRules( hdr, pos, q, currentTime, nTempMask );
  2676. if ( IsPlayer() && nTempMask != boneMask )
  2677. {
  2678. // restore the saved transforms of the leafy bones that got re-initialized during StandardBlendingRules.
  2679. // This will hold bones in their last computed pose and hide the lod pop on the way out (they may still pop on the way in)
  2680. for ( int i = 0; i < hdr->numbones(); ++i )
  2681. {
  2682. if ( (hdr->boneFlags(i) & (BONE_USED_BY_ATTACHMENT | BONE_USED_BY_HITBOX | BONE_ALWAYS_SETUP) ) == 0 )
  2683. {
  2684. pos[i] = m_pos_cached[i];
  2685. q[i] = m_q_cached[i];
  2686. }
  2687. }
  2688. }
  2689. if ( cl_countbones.GetBool() )
  2690. {
  2691. Vector from, to;
  2692. for ( int i = 0; i < hdr->numbones(); ++i )
  2693. {
  2694. if ( !(hdr->boneFlags( i ) & nTempMask) )
  2695. continue;
  2696. int const iParentIndex = hdr->boneParent( i );
  2697. if ( iParentIndex < 0 )
  2698. continue;
  2699. MatrixPosition( m_BoneAccessor[ i ], from );
  2700. MatrixPosition( m_BoneAccessor[ iParentIndex ], to );
  2701. if ( IsPlayer() )
  2702. {
  2703. debugoverlay->AddLineOverlay( from, to, 0, 255, 255, true, 0.0f );
  2704. }
  2705. else
  2706. {
  2707. debugoverlay->AddLineOverlay( from + Vector(2,0,0), to + Vector(2,0,0), 200, 0, 255, true, 0.0f );
  2708. }
  2709. }
  2710. }
  2711. m_nLastNonSkippedFrame = gpGlobals->framecount;
  2712. }
  2713. else
  2714. {
  2715. memcpy( pos, m_pos_cached, sizeof( BoneVector ) * hdr->numbones() );
  2716. memcpy( q, m_q_cached, sizeof( BoneQuaternionAligned ) * hdr->numbones() );
  2717. boneComputed.ClearAll(); // because we need to re-BuildTransformations on all our bones with a new root xform
  2718. boneMask = m_BoneAccessor.GetWritableBones();
  2719. }
  2720. #ifdef DEMOPOLISH_ENABLED
  2721. bool const bShouldPolish = IsDemoPolishEnabled() && IsPlayer();
  2722. if ( bShouldPolish && engine->IsPlayingDemo() )
  2723. {
  2724. DemoPolish_GetController().MakeLocalAdjustments( entindex(), hdr, boneMask, pos, q, boneComputed );
  2725. }
  2726. #endif
  2727. // don't calculate IK on ragdolls
  2728. if ( m_pIk && !IsRagdoll() )
  2729. {
  2730. UpdateIKLocks( currentTime );
  2731. m_pIk->UpdateTargets( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
  2732. CalculateIKLocks( currentTime );
  2733. m_pIk->SolveDependencies( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
  2734. if ( IsPlayer() && ( (BONE_USED_BY_VERTEX_LOD0 & boneMask) == BONE_USED_BY_VERTEX_LOD0 ) )
  2735. {
  2736. // only do extra bone processing when setting up bones that influence renderable vertices, and not for attachment position requests
  2737. DoExtraBoneProcessing( hdr, pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed, m_pIk );
  2738. }
  2739. }
  2740. #ifdef DEMOPOLISH_ENABLED
  2741. if ( m_bBonePolishSetup && bShouldPolish && engine->IsRecordingDemo() )
  2742. {
  2743. DemoPolish_GetRecorder().RecordAnimData( entindex(), hdr, GetCycle(), parentTransform, pos, q, boneMask, m_BoneAccessor );
  2744. }
  2745. #endif
  2746. BuildTransformations( hdr, pos, q, parentTransform, boneMask, boneComputed );
  2747. #if defined(_DEBUG_SPUvPPU_ANIMATION)
  2748. // m_PPUboneMaskUsed = bonesMaskNeedRecalc;
  2749. // memcpy( ppuP, pos, m_pStudioHdr->numbones() * sizeof(BoneVector));
  2750. // memcpy( ppuQ, q, m_pStudioHdr->numbones() * sizeof(BoneQuaternion));
  2751. #endif
  2752. #ifdef DEMOPOLISH_ENABLED
  2753. // Override bones?
  2754. if ( bShouldPolish && engine->IsPlayingDemo() )
  2755. {
  2756. DemoPolish_GetController().MakeGlobalAdjustments( entindex(), hdr, boneMask, m_BoneAccessor );
  2757. }
  2758. #endif
  2759. if ( cl_countbones.GetBool() )
  2760. {
  2761. for ( int i = 0; i < hdr->numbones(); ++i )
  2762. {
  2763. if ( hdr->boneFlags(i) & boneMask )
  2764. g_nNumBonesSetupAllTemp++;
  2765. }
  2766. }
  2767. // Draw skeleton?
  2768. if ( enable_skeleton_draw.GetBool() )
  2769. {
  2770. DrawSkeleton( hdr, boneMask );
  2771. }
  2772. RemoveEFlags( EFL_SETTING_UP_BONES );
  2773. ControlMouth( hdr );
  2774. if ( !bSkipThisFrame )
  2775. {
  2776. memcpy( m_pos_cached, pos, sizeof( BoneVector ) * hdr->numbones() );
  2777. memcpy( m_q_cached, q, sizeof( BoneQuaternionAligned ) * hdr->numbones() );
  2778. }
  2779. }
  2780. if( !( oldReadableBones & BONE_USED_BY_ATTACHMENT ) && ( boneMask & BONE_USED_BY_ATTACHMENT ) )
  2781. {
  2782. SetupBones_AttachmentHelper( hdr );
  2783. }
  2784. }
  2785. // Do they want to get at the bone transforms? If it's just making sure an aiment has
  2786. // its bones setup, it doesn't need the transforms yet.
  2787. if ( pBoneToWorldOut )
  2788. {
  2789. AssertMsgOnce( !IsEFlagSet( EFL_DIRTY_ABSTRANSFORM ), "Cached bone data has old abs origin/angles" );
  2790. //AssertMsgOnce( (m_vBoneSetupCachedOrigin == GetRenderOrigin()) && (m_qBoneSetupCachedAngles == GetRenderAngles()), "Renderable moved since cached" );
  2791. if ( nMaxBones >= m_CachedBoneData.Count() )
  2792. {
  2793. Plat_FastMemcpy( pBoneToWorldOut, m_CachedBoneData.Base(), sizeof( matrix3x4_t ) * m_CachedBoneData.Count() );
  2794. }
  2795. else
  2796. {
  2797. Warning( "SetupBones: invalid bone array size (%d - needs %d)\n", nMaxBones, m_CachedBoneData.Count() );
  2798. m_BoneSetupLock.Unlock();
  2799. return false;
  2800. }
  2801. }
  2802. m_BoneSetupLock.Unlock();
  2803. return true;
  2804. }
  2805. //-----------------------------------------------------------------------------
  2806. //
  2807. // START OF PS3 BONE JOBS
  2808. //
  2809. //-----------------------------------------------------------------------------
  2810. #if defined( _PS3 )
  2811. //-----------------------------------------------------------------------------
  2812. // Purpose: to run setupbonesonbaseanimating efficiently on PS3
  2813. //
  2814. // Take one of three paths depending on cl_PS3_SPU_bones convar:
  2815. //
  2816. // 0: path as in ThreadedBoneSetup with cl_threaded_bone_setup = 2.
  2817. // 1: run on SPU. Right now this means running AccumulatePose on SPU with pre and post AccumulatePose running on PPU.
  2818. // In order to use as many SPU's as possible we will run all the pre steps first, then kick off as many SPU jobs as we can so that AccumulatePose can run in parallel
  2819. // The prologue can only run when the SPU job has finished so we wait until the appropriate job is done before finishing up on PPU
  2820. // 2: run as "1" but run job on PPU to ensure rearranging the code this way works!
  2821. //
  2822. // Note we assume that only one thread will be responsible for kicking off this path on PS3
  2823. //-----------------------------------------------------------------------------
  2824. //-----------------------------------------------------------------------------
  2825. // base class empty implementation
  2826. //-----------------------------------------------------------------------------
  2827. void C_BaseAnimating::AccumulateLayers_AddPoseCalls( IBoneSetup_PS3 &boneSetup, BoneVector pos[], BoneQuaternion q[], float currentTime )
  2828. {
  2829. // Nothing here
  2830. }
  2831. //-----------------------------------------------------------------------------
  2832. // save some state in case we need to start the job over again
  2833. // this should only happen if we get a data request during the SPU job which means the anim data isn't loaded yet
  2834. // since this is rare, we'll reset and run the job from scratch on PPU
  2835. //-----------------------------------------------------------------------------
  2836. void C_BaseAnimating::SaveSetupBones_PS3( void )
  2837. {
  2838. // save so we can reset and run setupbones all over again... don't really want to save the whole class each time
  2839. m_iMostRecentModelBoneCounter_SAVE = m_iMostRecentModelBoneCounter;
  2840. m_iMostRecentBoneSetupRequest_SAVE = m_iMostRecentBoneSetupRequest;
  2841. m_iPrevBoneMask_SAVE = m_iPrevBoneMask;
  2842. m_iAccumulatedBoneMask_SAVE = m_iAccumulatedBoneMask;
  2843. m_iOldWriteableBones_SAVE = m_BoneAccessor.GetWritableBones();
  2844. m_iOldReadableBones_SAVE = m_BoneAccessor.GetReadableBones();
  2845. m_flLastBoneSetupTime_SAVE = m_flLastBoneSetupTime;
  2846. }
  2847. //-----------------------------------------------------------------------------
  2848. // restore for above
  2849. //-----------------------------------------------------------------------------
  2850. void C_BaseAnimating::RestoreSetupBones_PS3( void )
  2851. {
  2852. // reset so we can run setupbones all over again...
  2853. // if it got to a job, these will have been initialised just fine.
  2854. m_iMostRecentModelBoneCounter = m_iMostRecentModelBoneCounter_SAVE;
  2855. m_iMostRecentBoneSetupRequest = m_iMostRecentBoneSetupRequest_SAVE;
  2856. m_iPrevBoneMask = m_iPrevBoneMask_SAVE;
  2857. m_iAccumulatedBoneMask = m_iAccumulatedBoneMask_SAVE;
  2858. m_BoneAccessor.SetWritableBones( m_iOldWriteableBones_SAVE );
  2859. m_BoneAccessor.SetReadableBones( m_iOldReadableBones_SAVE );
  2860. m_flLastBoneSetupTime = m_flLastBoneSetupTime_SAVE;
  2861. }
  2862. //-----------------------------------------------------------------------------
  2863. // start PS3 anim jobs, order is implied since there is an external loop that
  2864. // rolls over the generations in order, guaranteeing all parent jobs started as
  2865. // much ahead of their children as possible giving the SPU job the best chance
  2866. // of finishing it before results are needed.
  2867. // This call effectively only runs the baseanimating setupbones() for generation nGen
  2868. //-----------------------------------------------------------------------------
  2869. int C_BaseAnimating::SetupBonesOnBaseAnimating_PS3( C_BaseAnimating *&pBaseAnimating, int nGen )
  2870. {
  2871. // SNPROF_ANIM( "C_BaseAnimating::SetupBonesOnBaseAnimating_PS3" );
  2872. C_BaseAnimating *pCurrent = pBaseAnimating;
  2873. C_BaseAnimating *pNext;
  2874. int nDependantID = -1;
  2875. while ( pCurrent )
  2876. {
  2877. pNext = pCurrent->m_pNextForThreadedBoneSetup;
  2878. if( nGen == pCurrent->m_iPS3BoneJob_Gen )
  2879. {
  2880. pCurrent->m_iPS3BoneJob_DependantID = nDependantID;
  2881. // save off data we may need to reset if job gets to run and fails
  2882. pCurrent->SaveSetupBones_PS3();
  2883. // init new job
  2884. pCurrent->PS3BoneJob_Start( gpGlobals->curtime );
  2885. // TESTING - immediate reset and do over
  2886. //pCurrent->ResetSetupBones();
  2887. //pCurrent->SetupBones( NULL, -1, -1, gpGlobals->curtime );
  2888. return 1;
  2889. }
  2890. nDependantID = pCurrent->m_iPS3BoneJob_ID;
  2891. pCurrent = pNext;
  2892. }
  2893. return 0;
  2894. }
  2895. //-----------------------------------------------------------------------------
  2896. // reset critical fields and count the max number of potential bone jobs
  2897. // also sets the generation field appropriately for sorting later
  2898. //-----------------------------------------------------------------------------
  2899. int C_BaseAnimating::InitAllPS3BoneJobs( int nCount )
  2900. {
  2901. // SNPROF_ANIM( "C_BaseAnimating::InitAllPS3BoneJobs" );
  2902. int nTotal = 0;
  2903. for ( int i = 0; i < nCount; i++ )
  2904. {
  2905. C_BaseAnimating *pCurrent = g_PreviousBoneSetups[ i ];
  2906. C_BaseAnimating *pNext;
  2907. int nGen = 0;
  2908. while ( pCurrent )
  2909. {
  2910. // reset
  2911. pCurrent->m_iPS3BoneJob_ID = -1;
  2912. pCurrent->m_iPS3BoneJob_DependantID = -1;
  2913. pCurrent->m_iPS3BoneJob_Gen = nGen;
  2914. pCurrent->m_iPS3BoneJob_Port = -1;
  2915. pCurrent = pCurrent->m_pNextForThreadedBoneSetup;
  2916. nGen++;
  2917. nTotal++;
  2918. }
  2919. }
  2920. return nTotal;
  2921. }
  2922. //-----------------------------------------------------------------------------
  2923. // Add all AccumulatePose calls from MaintainSequenceTransitions to bonejob
  2924. //-----------------------------------------------------------------------------
  2925. void C_BaseAnimating::MaintainSequenceTransitions_AddPoseCalls( IBoneSetup_PS3 &boneSetup, float flCycle, BoneVector pos[], BoneQuaternion q[] )
  2926. {
  2927. if ( !boneSetup.GetStudioHdr() )
  2928. return;
  2929. if ( prediction->InPrediction() )
  2930. {
  2931. m_nPrevNewSequenceParity = m_nNewSequenceParity;
  2932. return;
  2933. }
  2934. m_SequenceTransitioner.CheckForSequenceChange(
  2935. boneSetup.GetStudioHdr(),
  2936. GetSequence(),
  2937. m_nNewSequenceParity != m_nPrevNewSequenceParity,
  2938. !IsEffectActive(EF_NOINTERP)
  2939. );
  2940. m_nPrevNewSequenceParity = m_nNewSequenceParity;
  2941. // Update the transition sequence list.
  2942. m_SequenceTransitioner.UpdateCurrent(
  2943. boneSetup.GetStudioHdr(),
  2944. GetSequence(),
  2945. flCycle,
  2946. GetPlaybackRate(),
  2947. gpGlobals->curtime
  2948. );
  2949. // process previous sequences
  2950. for (int i = m_SequenceTransitioner.m_animationQueue.Count() - 2; i >= 0; i--)
  2951. {
  2952. CAnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i];
  2953. float dt = (gpGlobals->curtime - blend->m_flLayerAnimtime);
  2954. flCycle = blend->GetCycle() + dt * blend->GetPlaybackRate() * GetSequenceCycleRate( boneSetup.GetStudioHdr(), blend->GetSequence() );
  2955. flCycle = ClampCycle( flCycle, IsSequenceLooping( boneSetup.GetStudioHdr(), blend->GetSequence() ) );
  2956. // original call boneSetup.AccumulatePose( pos, q, blend->GetSequence(), flCycle, blend->GetWeight(), gpGlobals->curtime, m_pIk );
  2957. boneSetup.AccumulatePose_AddToBoneJob( boneSetup.GetBoneJobSPU(), blend->GetSequence(), flCycle, blend->GetWeight(), m_pIk, 0 );
  2958. }
  2959. }
  2960. //-----------------------------------------------------------------------------
  2961. //
  2962. //-----------------------------------------------------------------------------
  2963. void C_BaseAnimating::PS3BoneJob_PreInit( void )
  2964. {
  2965. //m_iPS3BoneJob_Port = -1;
  2966. m_iPS3BoneJob_ID = g_pBoneJobs->AddBoneJob();
  2967. PS3BoneJobData *pBoneJobData = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  2968. bonejob_PPU *pBonejobPPU = &pBoneJobData->bonejobPPU;
  2969. pBonejobPPU->pBaseAnimating = this;
  2970. }
  2971. //-----------------------------------------------------------------------------
  2972. // Initialise a PS3 bone job
  2973. // ensure any dependant jobs are finished first
  2974. //-----------------------------------------------------------------------------
  2975. void C_BaseAnimating::PS3BoneJob_Start( float currentTime )
  2976. {
  2977. // SNPROF_ANIM( "C_BaseAnimating::PS3BoneJob_Start" );
  2978. #ifdef DEBUG_BONESETUP_THREADVSNONTHREAD
  2979. Msg("BONEJOB: %x\n", this );
  2980. #endif
  2981. // too many bones for SPU?
  2982. if( m_pStudioHdr->numbones() > MAXSTUDIOBONES_PS3 )
  2983. {
  2984. // Not able to run job on SPU, rerun on PPU
  2985. PS3BoneJob_RestartPPU();
  2986. return;
  2987. }
  2988. // if 'this' is already running in a job (<-- see how often this happens?)
  2989. // SPU - sync on port, and exec pass 2 HERE guaranteeing that we are finished before we start the next job. flag as finished preventing subsequent pass 2 loop execution.
  2990. // PPU - exec pass 2 on the previous job, and flag it as finished preventing from executing in pass 2 loop, then continue
  2991. if( cl_PS3_SPU_bones_safesync.GetInt() )
  2992. {
  2993. if( m_iPS3BoneJob_Port >= 0 )
  2994. {
  2995. Assert( m_iPS3BoneJob_ID >= 0 );
  2996. // in a bone job already on 'this'
  2997. // on SPU
  2998. // 1. sync on port to wait for finish of previous job
  2999. // 2. exec pass 2 & 3 of previous job here
  3000. // 3. continue with current job
  3001. // on PPU
  3002. // 1. exec pass 2 & 3 of previous job here
  3003. // 2. continue with current job
  3004. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3005. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3006. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3007. }
  3008. // we need a way on handling dependant jobs when running bonejobs on SPU
  3009. // here seems a good place to sync on those jobs
  3010. // in order to maximise parallelism, we should have not started child jobs immediately after their parents
  3011. // otherwise we'll get immediately here and have to wait
  3012. // we should push some non-dependant jobs first, giving the PPU time to get to a point where the first job might be done
  3013. // i.e.
  3014. // * push all parent jobs
  3015. // * push 1st generation children
  3016. // * push 2nd generation children
  3017. //
  3018. // The current order of jobs (in threadedbonesetup and then setupbonesonbaseanimating) has dependant following their parents, so this will need to change.
  3019. // note: this PS3 path is now sorted by generation
  3020. // if waiting on a parent/dependant job to finish
  3021. // SPU - sync on port of parent job, exec pass 2 & 3 of parent job HERE guaranteeing a safe continue
  3022. // OR add a SYNC command so can carry on with PPU
  3023. // PPU - exec pass 2 & 3 of parent job and continue
  3024. if( m_iPS3BoneJob_DependantID != -1 )
  3025. {
  3026. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( m_iPS3BoneJob_DependantID );
  3027. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3028. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3029. }
  3030. // reset
  3031. PS3BoneJob_PreInit();
  3032. }
  3033. // PASS 1
  3034. SetupBones_Pass1( currentTime );
  3035. }
  3036. //-----------------------------------------------------------------------------
  3037. // Run a PS3 bone job
  3038. //
  3039. // collate data for SPU packet and kick SPU job
  3040. //-----------------------------------------------------------------------------
  3041. void C_BaseAnimating::PS3BoneJob_Run( CStudioHdr *hdr, float currentTime, float fCycle, int nMaxBones, int boneMask, int bonesMaskNeedRecalc, int oldReadableBones, matrix3x4_t &parentTransform, float* poseparam )
  3042. {
  3043. // SNPROF_ANIM( "C_BaseAnimating::PS3BoneJob_Run" );
  3044. // if job already running on this, need to sync to it at some point before starting another job on this
  3045. int thisJobID = m_iPS3BoneJob_ID;
  3046. if( !cl_PS3_SPU_bones_safesync.GetInt() )
  3047. {
  3048. // reset here
  3049. PS3BoneJob_PreInit();
  3050. }
  3051. // curr job data, write p, q and other stuff we need in pass 2 here
  3052. PS3BoneJobData *pBoneJobData = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3053. bonejob_PPU *pBonejobPPU = &pBoneJobData->bonejobPPU;
  3054. bonejob_SPU *pBonejobSPU = &pBoneJobData->bonejobSPU;
  3055. // init bonesetup
  3056. IBoneSetup_PS3 boneSetup( hdr, boneMask, poseparam, pBonejobSPU );
  3057. boneSetup.InitPose_PS3( pBoneJobData->pos, pBoneJobData->q );
  3058. pBoneJobData->addDep_numIKRules = 0;
  3059. // now push job to SPU (or just execute AccumulatePose on PPU), and finish here for pass 1
  3060. // take a copy of source params to be used in pass 2
  3061. // SPU source data
  3062. memcpy( pBonejobSPU->poseparam, poseparam, MAXSTUDIOPOSEPARAM );
  3063. pBonejobSPU->currentTime = currentTime;
  3064. pBonejobSPU->pEA_hdr = (void *)hdr;
  3065. pBonejobSPU->numBones = hdr->numbones();
  3066. pBonejobSPU->maxBones = pBonejobSPU->numBones;
  3067. pBonejobSPU->pEA_IKContext = m_pIk;
  3068. pBonejobSPU->boneMask = boneMask;
  3069. pBonejobSPU->pEA_pos = pBoneJobData->pos;
  3070. pBonejobSPU->pEA_q = pBoneJobData->q;
  3071. pBonejobSPU->pEA_addDep_IKRules = pBoneJobData->addDep_IKRules;
  3072. pBonejobSPU->pEA_addDep_numIKRules = &pBoneJobData->addDep_numIKRules;
  3073. for (int i = 0; i < hdr->numbones(); i++)
  3074. {
  3075. pBonejobSPU->boneFlags[i] = hdr->pBone( i )->flags;
  3076. pBonejobSPU->boneParent[i] = hdr->pBone( i )->parent;
  3077. }
  3078. pBonejobSPU->pEA_studiohdr_ikchains = (void *)hdr->pIKChain( 0 );
  3079. pBonejobSPU->numikchains = hdr->numikchains();
  3080. pBonejobSPU->pEA_studiohdr_bones = (void *)hdr->pBone( 0 );
  3081. pBonejobSPU->pEA_studiohdr_bones_pos = (void *)(&hdr->pBone( 0 )->pos);
  3082. pBonejobSPU->studiobone_posoffset = (int)(&hdr->pBone( 0 )->pos) - (int)(hdr->pBone( 0 ));
  3083. mstudiolinearbone_t *pLinearBones = hdr->pLinearBones();
  3084. pBonejobSPU->pEA_studiohdr_linearBones = (void *)pLinearBones;
  3085. if( pLinearBones )
  3086. {
  3087. pBonejobSPU->pEA_linearbones_pos = (void *)(((byte *)pLinearBones) + pLinearBones->posindex);
  3088. pBonejobSPU->pEA_linearbones_posscale = (void *)(((byte *)pLinearBones) + pLinearBones->posscaleindex);
  3089. pBonejobSPU->pEA_linearbones_rot = (void *)(((byte *)pLinearBones) + pLinearBones->rotindex);
  3090. pBonejobSPU->pEA_linearbones_rotscale = (void *)(((byte *)pLinearBones) + pLinearBones->rotscaleindex);
  3091. pBonejobSPU->pEA_linearbones_flags = (void *)(((byte *)pLinearBones) + pLinearBones->flagsindex);
  3092. pBonejobSPU->pEA_linearbones_quat = (void *)(((byte *)pLinearBones) + pLinearBones->quatindex);
  3093. pBonejobSPU->pEA_linearbones_qalignment = (void *)(((byte *)pLinearBones) + pLinearBones->qalignmentindex);
  3094. }
  3095. virtualmodel_t *pVModel = hdr->GetVirtualModel();
  3096. if( pVModel )
  3097. {
  3098. pBonejobSPU->pEA_studiohdr_vmodel = (void *)pVModel;
  3099. }
  3100. else
  3101. {
  3102. pBonejobSPU->pEA_studiohdr_vmodel = NULL;
  3103. }
  3104. // debug SPU?
  3105. pBonejobSPU->debugJob = cl_PS3_SPU_bones_debug.GetInt() == 2;
  3106. // PPU data
  3107. pBonejobPPU->cycle = fCycle;
  3108. pBonejobPPU->maxBones = nMaxBones;
  3109. pBonejobPPU->boneMask = boneMask;
  3110. pBonejobPPU->bonesMaskNeedsRecalc = bonesMaskNeedRecalc;
  3111. pBonejobPPU->oldReadableBones = oldReadableBones;
  3112. pBonejobPPU->pBaseAnimating = this;
  3113. pBonejobPPU->pStudioHdr = hdr;
  3114. pBonejobPPU->pBoneToWorldOut = NULL;
  3115. BoneVector* pos = pBoneJobData->pos;
  3116. BoneQuaternion* q = pBoneJobData->q;
  3117. //---------------------------------------------------------------------------------------------------------------------------------
  3118. // Data prep for SPU, dummy run of AccumulatePose calls, accumulating data for SPU
  3119. //---------------------------------------------------------------------------------------------------------------------------------
  3120. //---------------------------------------------------------------------------------------------------------------------------------
  3121. // build a list of AccumulatePose() calls that will need to be made in the job.
  3122. // there is always at least one.
  3123. // the regular calls that are made in StandardBlendingRules
  3124. // 1. boneSetup.AccumulatePose()
  3125. // 2. MaintainSequenceTransitions() <-- may contain AccumPose calls
  3126. // 3. AccumulateLayers() <-- may contain AccumPose calls
  3127. // 4. CalcAutoplaySequences() <-- may contain AccumPose calls, and take care since they're bracketed by some IK autoplaylocks
  3128. //---------------------------------------------------------------------------------------------------------------------------------
  3129. boneSetup.ResetErrorFlags();
  3130. // execute dummy versions of 2 and 3 and build a list of call arguments to AccumulatePose()
  3131. // the only arguments we need to cache are sequence, cycle and weight - the others: pos, q, time, m_pIK stay the same for all calls
  3132. // reset
  3133. pBonejobSPU->numTotalPoses = 0;
  3134. pBonejobSPU->numPoses_PreAutoSeq = 0;
  3135. pBonejobSPU->numPoses_AutoSeq = 0;
  3136. // add first call boneSetup.AccumulatePose()
  3137. boneSetup.AccumulatePose_AddToBoneJob( boneSetup.GetBoneJobSPU(), GetSequence(), fCycle, 1.0, m_pIk, 0 );
  3138. if( boneSetup.ErrorFlags() ) goto skip;
  3139. // add calls from MaintainSequenceTransitions
  3140. MaintainSequenceTransitions_AddPoseCalls( boneSetup, fCycle, pos, q );
  3141. if( boneSetup.ErrorFlags() ) goto skip;
  3142. // add calls from AccumulateLayers
  3143. AccumulateLayers_AddPoseCalls( boneSetup, pos, q, currentTime );
  3144. if( boneSetup.ErrorFlags() ) goto skip;
  3145. // get number of AccumPose calls to this point since we do some other work on pos and q before potentially adding
  3146. // more AccumPose calls via CalcAutoplaySequences
  3147. pBonejobSPU->numPoses_PreAutoSeq = pBonejobSPU->numTotalPoses;
  3148. // execute dummy version of 4 and build a list of call arguments to AccumulatePose()
  3149. // we need a new IKcontext so store the data required to build it
  3150. // init IK context for autoplay sequences - no need, done internally
  3151. pBonejobSPU->autoikOrigin = GetRenderOrigin();
  3152. pBonejobSPU->autoikAngles = GetRenderAngles();
  3153. pBonejobSPU->autoikFramecount = gpGlobals->framecount;
  3154. pBonejobSPU->numikAutoplayLocks = hdr->GetNumIKAutoplayLocks();
  3155. boneSetup.CalcAutoplaySequences_AddPoseCalls( currentTime );
  3156. if( boneSetup.ErrorFlags() ) goto skip;
  3157. // get number of AccumPose calls during CalcAutoplaySequences
  3158. pBonejobSPU->numPoses_AutoSeq = pBonejobSPU->numTotalPoses - pBonejobSPU->numPoses_PreAutoSeq;
  3159. if( !cl_PS3_SPU_bones_safesync.GetInt() )
  3160. {
  3161. if( m_iPS3BoneJob_Port >= 0 )
  3162. {
  3163. Assert( thisJobID >= 0 );
  3164. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( thisJobID );
  3165. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3166. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3167. }
  3168. if( m_iPS3BoneJob_DependantID != -1 )
  3169. {
  3170. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( m_iPS3BoneJob_DependantID );
  3171. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3172. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3173. }
  3174. if ( m_pIk )
  3175. {
  3176. if (Teleported() || IsEffectActive(EF_NOINTERP))
  3177. {
  3178. m_pIk->ClearTargets();
  3179. }
  3180. m_pIk->Init( hdr, GetRenderAngles(), GetRenderOrigin(), currentTime, gpGlobals->framecount, bonesMaskNeedRecalc );
  3181. }
  3182. ALIGN16 matrix3x4_t parentTransform2 ALIGN16_POST;
  3183. AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform2 );
  3184. MatrixCopy( parentTransform2, pBonejobPPU->parentTransform );
  3185. }
  3186. else
  3187. {
  3188. MatrixCopy( parentTransform, pBonejobPPU->parentTransform );
  3189. }
  3190. pBonejobSPU->autoikOrigin = GetRenderOrigin();
  3191. pBonejobSPU->autoikAngles = GetRenderAngles();
  3192. // run SPU jobs
  3193. // everything now ready to push to SPU job
  3194. if( cl_PS3_SPU_bones.GetInt() == 1 )
  3195. {
  3196. // SPU path
  3197. m_iPS3BoneJob_Port = boneSetup.RunAccumulatePoseJobs_SPU( pBonejobSPU, &pBoneJobData->jobDescriptor );
  3198. }
  3199. else
  3200. {
  3201. // PPU path
  3202. m_iPS3BoneJob_Port = boneSetup.RunAccumulatePoseJobs_PPU( pBonejobSPU );
  3203. }
  3204. return;
  3205. skip:
  3206. // Not able to run job on SPU
  3207. // finish any running/dependant jobs
  3208. // rerun on PPU
  3209. PS3BoneJob_RestartPPU();
  3210. return;
  3211. }
  3212. //-----------------------------------------------------------------------------
  3213. // Finishes up a PS3 bone job (may have already been finished via WaitForFinish, in which
  3214. // case this will tidy up the m_pNextForThreadedBoneSetup ptr)
  3215. //
  3216. //-----------------------------------------------------------------------------
  3217. void C_BaseAnimating::PS3BoneJob_End( void )
  3218. {
  3219. // proper finish
  3220. m_pNextForThreadedBoneSetup = NULL;
  3221. if( ( m_iPS3BoneJob_ID != -1 ) && ( m_iPS3BoneJob_Port != -1 ) ) // job started and running
  3222. {
  3223. if( ( cl_PS3_SPU_bones.GetInt() == 1 ) &&
  3224. ( cl_PS3_SPU_bones_debug.GetInt() == 0 ) &&
  3225. ( m_iPS3BoneJob_Port < VJobsRoot::MAXPORTS_ANIM ) )
  3226. {
  3227. SNPROF_ANIM( "sync(0) end" );
  3228. PS3BoneJobData *pBoneJobData = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3229. // sync on port
  3230. //Msg("sync job End %d\n", m_iPS3BoneJob_Port);
  3231. CELL_VERIFY( g_pBoneJobs->m_pRoot->m_queuePortAnim[ m_iPS3BoneJob_Port ].sync( 0 ) );
  3232. }
  3233. // PASS 2
  3234. StandardBlendingRules_Pass2();
  3235. SetupBones_Pass2();
  3236. // ensure lock released
  3237. m_BoneSetupLock.Unlock();
  3238. }
  3239. // mark as not started, not running
  3240. m_iPS3BoneJob_ID = -1;
  3241. m_iPS3BoneJob_Port = -1;
  3242. }
  3243. //-----------------------------------------------------------------------------
  3244. // when another bonejob is trying to start, but is dependant on the results of this one
  3245. // we must wait for this job to finish before continuing.
  3246. //
  3247. // this will only happen during pass1 (i.e. when bone jobs are started)
  3248. // => we must:
  3249. // 1. wait for pass1 to finish on SPU
  3250. // 2. Run pass2 on PPU only
  3251. // 3. Run pass3 (PPU only)
  3252. // 4. continue
  3253. //
  3254. // Only makes sense when running on SPU
  3255. //-----------------------------------------------------------------------------
  3256. void C_BaseAnimating::PS3BoneJob_WaitForFinish( void )
  3257. {
  3258. // SPU path only
  3259. // sync on dependant job port2->sync(tag)
  3260. if( ( m_iPS3BoneJob_ID != -1 ) && ( m_iPS3BoneJob_Port != -1 ) ) // job started and running
  3261. {
  3262. if( ( cl_PS3_SPU_bones.GetInt() == 1 ) &&
  3263. ( cl_PS3_SPU_bones_debug.GetInt() == 0 ) &&
  3264. ( m_iPS3BoneJob_Port < VJobsRoot::MAXPORTS_ANIM ) )
  3265. {
  3266. SNPROF_ANIM( "sync(0) waitforfinish" );
  3267. // sync on port
  3268. PS3BoneJobData *pBoneJobData = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3269. // sync on port
  3270. //Msg("sync job wait for finish %d\n", m_iPS3BoneJob_Port);
  3271. CELL_VERIFY( g_pBoneJobs->m_pRoot->m_queuePortAnim[ m_iPS3BoneJob_Port ].sync( 0 ) );
  3272. }
  3273. // PASS 2
  3274. StandardBlendingRules_Pass2();
  3275. SetupBones_Pass2();
  3276. // ensure lock released
  3277. m_BoneSetupLock.Unlock();
  3278. }
  3279. // mark as not started, not running
  3280. m_iPS3BoneJob_ID = -1;
  3281. m_iPS3BoneJob_Port = -1;
  3282. }
  3283. //-----------------------------------------------------------------------------
  3284. // When an error has occured when initialising a bonejob (too many bones, or an unsupported SPU path encountered)
  3285. // we re-run the job over on PPU
  3286. //-----------------------------------------------------------------------------
  3287. void C_BaseAnimating::PS3BoneJob_RestartPPU( void )
  3288. {
  3289. SNPROF_ANIM( "C_BaseAnimating::PS3BoneJob_RestartPPU" );
  3290. // we will have locked the bones, so release the lock
  3291. m_BoneSetupLock.Unlock();
  3292. // start job over on PPU after resetting
  3293. RestoreSetupBones_PS3();
  3294. // call original (non-PS3) SetupBones
  3295. //pBaseAnimating->SetupBones( NULL, -1, -1, g_pPS3BoneJobData[ lp ].m_boneJobSrcParams.m_fCurrentTime );
  3296. SetupBones( NULL, -1, -1, gpGlobals->curtime );
  3297. // mark as not started, not running
  3298. m_iPS3BoneJob_ID = -1;
  3299. m_iPS3BoneJob_Port = -1;
  3300. }
  3301. //-----------------------------------------------------------------------------
  3302. // main entry point for PS3 bone jobs
  3303. //
  3304. // run the g_PreviousBoneSetups list in two parts: things before we can run a job
  3305. // and things to do after the job has finished.
  3306. //
  3307. // a bone job is defined as whatever we have managed to comfortably/sensible push
  3308. // onto SPU (should be the bulk of the work) - right now it's the main core of
  3309. // standardblendingrules, which includes accumulatepose, the largest time sink.
  3310. //-----------------------------------------------------------------------------
  3311. void C_BaseAnimating::ThreadedBoneSetup_PS3( int nCount )
  3312. {
  3313. SNPROF_ANIM( "C_BaseAnimating::ThreadedBoneSetup_PS3" );
  3314. #ifdef DEBUG_BONESETUP_THREADVSNONTHREAD
  3315. Msg("*************************************************************\n" );
  3316. Msg("*** THREADED BONESETUP START: gmbc: %d, time: %f ***\n", g_iModelBoneCounter, gpGlobals->curtime );
  3317. Msg("*************************************************************\n" );
  3318. #endif
  3319. switch( cl_PS3_SPU_bones.GetInt() )
  3320. {
  3321. case 0:
  3322. // as before
  3323. for ( int i = 0; i < nCount; i++ )
  3324. {
  3325. SetupBonesOnBaseAnimating( g_PreviousBoneSetups[i] );
  3326. }
  3327. break;
  3328. case 1:
  3329. case 2:
  3330. {
  3331. int lp;
  3332. // allocate working data set (that is live between pass 1 and 2)
  3333. // init
  3334. int nMaxBoneJobs = InitAllPS3BoneJobs( nCount );
  3335. g_pBoneJobs->StartFrame( nMaxBoneJobs );
  3336. ////////////////////////////////////////////////////////////////////////////////////////
  3337. // Pass 1: prologue
  3338. // and kick off AccumulatePose jobs
  3339. // sort in place to process jobs in generation order: parent jobs first, then children, then 2nd generation, etc
  3340. ////////////////////////////////////////////////////////////////////////////////////////
  3341. g_pBoneJobs->ResetBoneJobs();
  3342. int nGen = 0;
  3343. int nCount_Gen = 0;
  3344. // generation order
  3345. while( nCount_Gen < nMaxBoneJobs )
  3346. {
  3347. for ( lp = 0; lp < nCount; lp++ )
  3348. {
  3349. nCount_Gen += SetupBonesOnBaseAnimating_PS3( g_PreviousBoneSetups[ lp ], nGen );
  3350. }
  3351. nGen++;
  3352. }
  3353. ////////////////////////////////////////////////////////////////////////////////////////
  3354. //
  3355. ////////////////////////////////////////////////////////////////////////////////////////
  3356. ////////////////////////////////////////////////////////////////////////////////////////
  3357. // Epilogue - tidy up unfinished jobs
  3358. ////////////////////////////////////////////////////////////////////////////////////////
  3359. for( lp = 0; lp < g_pBoneJobs->GetNumBoneJobs(); lp++ )
  3360. {
  3361. PS3BoneJobData* pBoneJobData = g_pBoneJobs->GetJobData( lp );
  3362. C_BaseAnimating* pBaseAnimating = (C_BaseAnimating *)pBoneJobData->bonejobPPU.pBaseAnimating;
  3363. pBaseAnimating->PS3BoneJob_End();
  3364. }
  3365. // free working data set
  3366. g_pBoneJobs->EndFrame();
  3367. }
  3368. break;
  3369. default:
  3370. // as before
  3371. for ( int i = 0; i < nCount; i++ )
  3372. {
  3373. SetupBonesOnBaseAnimating( g_PreviousBoneSetups[i] );
  3374. }
  3375. break;
  3376. }
  3377. #ifdef DEBUG_BONESETUP_THREADVSNONTHREAD
  3378. Msg("********************************\n" );
  3379. Msg("*** THREADED BONESETUP END ***\n" );
  3380. Msg("********************************\n" );
  3381. #endif
  3382. }
  3383. //-----------------------------------------------------------------------------
  3384. // pre bone job pass for standardblendingrules
  3385. // this will end up actually running the job
  3386. //-----------------------------------------------------------------------------
  3387. bool C_BaseAnimating::StandardBlendingRules_Pass1( CStudioHdr *hdr, float currentTime, int nMaxBones, int boneMask, int bonesMaskNeedRecalc, int oldReadableBones, matrix3x4_t &parentTransform )
  3388. {
  3389. // SNPROF_ANIM( "C_BaseAnimating::StandardBlendingRules_Pass1" );
  3390. float poseparam[MAXSTUDIOPOSEPARAM];
  3391. if( !hdr )
  3392. return false;
  3393. if( !hdr->SequencesAvailable() )
  3394. {
  3395. return false;
  3396. }
  3397. if( GetSequence() >= hdr->GetNumSeq() || GetSequence() == -1 )
  3398. {
  3399. SetSequence( 0 );
  3400. }
  3401. #ifdef DEMOPOLISH_ENABLED
  3402. if ( IsDemoPolishPlaying() && IsPlayer() )
  3403. {
  3404. float const flDemoPlaybackTime = DemoPolish_GetController().GetAdjustedPlaybackTime();
  3405. int const iSequenceOverride = DemoPolish_GetController().GetSequenceOverride( entindex(), flDemoPlaybackTime );
  3406. if ( iSequenceOverride >= 0 )
  3407. {
  3408. // Override.
  3409. SetSequence( iSequenceOverride );
  3410. }
  3411. }
  3412. #endif
  3413. GetPoseParameters( hdr, poseparam );
  3414. // SET UP AND FIRE OFF JOB
  3415. PS3BoneJob_Run( hdr, currentTime, GetCycle(), nMaxBones, boneMask, bonesMaskNeedRecalc, oldReadableBones, parentTransform, poseparam );
  3416. // p and q filled - end of pass 1
  3417. return true;
  3418. }
  3419. //-----------------------------------------------------------------------------
  3420. // post bone job pass of standardblendingrules
  3421. // should be the first thing that happens next when a bone job finishes
  3422. //-----------------------------------------------------------------------------
  3423. bool C_BaseAnimating::StandardBlendingRules_Pass2( void )
  3424. {
  3425. // SNPROF_ANIM( "C_BaseAnimating::StandardBlendingRules_Pass2" );
  3426. Assert( m_iPS3BoneJob_ID != -1 );
  3427. PS3BoneJobData *pBoneJobData = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3428. bonejob_PPU *pBonejob_PPU = &pBoneJobData->bonejobPPU;
  3429. bonejob_SPU *pBonejob_SPU = &pBoneJobData->bonejobSPU;
  3430. // re-setup with original args
  3431. IBoneSetup boneSetup( pBonejob_PPU->pStudioHdr, pBonejob_PPU->boneMask, pBonejob_SPU->poseparam );
  3432. //
  3433. BoneVector *pos = pBoneJobData->pos;
  3434. BoneQuaternion *q = pBoneJobData->q;
  3435. float currentTime = pBonejob_SPU->currentTime;
  3436. float fCycle = pBonejob_PPU->cycle;
  3437. CStudioHdr *hdr = pBonejob_PPU->pStudioHdr;
  3438. int boneMask = pBonejob_SPU->boneMask;
  3439. if( hdr->numbonecontrollers() )
  3440. {
  3441. float controllers[ MAXSTUDIOBONECTRLS ];
  3442. GetBoneControllers( controllers );
  3443. boneSetup.CalcBoneAdj( pos, q, controllers );
  3444. }
  3445. UnragdollBlend( hdr, pos, q, currentTime );
  3446. return true;
  3447. }
  3448. //-----------------------------------------------------------------------------
  3449. // pre bone job pass for setupbones
  3450. // determines whether the job should run
  3451. //-----------------------------------------------------------------------------
  3452. bool C_BaseAnimating::SetupBones_Pass1( float currentTime )
  3453. {
  3454. // SNPROF_ANIM( "C_BaseAnimating::SetupBones_Pass1" );
  3455. int boneMask = -1;//m_iAccumulatedBoneMask;//-1;
  3456. int nMaxBones = -1;
  3457. // for now, we MUST be in threaded bone setup
  3458. if( GetSequence() == -1 )
  3459. return false;
  3460. if( boneMask == -1 )
  3461. {
  3462. boneMask = m_iPrevBoneMask;
  3463. }
  3464. // We should get rid of this someday when we have solutions for the odd cases where a bone doesn't
  3465. // get setup and its transform is asked for later.
  3466. // if ( cl_SetupAllBones.GetInt() )
  3467. // {
  3468. // boneMask |= BONE_USED_BY_ANYTHING;
  3469. // }
  3470. if ( !m_BoneSetupLock.TryLock() )
  3471. {
  3472. // someone else is handling
  3473. // bones are in some intermediate state, wait until the other thread is done.
  3474. // If they've setup what bones we want, it'll early out down below
  3475. m_BoneSetupLock.Lock();
  3476. }
  3477. // else, we have the lock
  3478. // If we're setting up LOD N, we have set up all lower LODs also
  3479. // because lower LODs always use subsets of the bones of higher LODs.
  3480. int nLOD = 0;
  3481. int nMask = BONE_USED_BY_VERTEX_LOD0;
  3482. for( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 )
  3483. {
  3484. if ( boneMask & nMask )
  3485. break;
  3486. }
  3487. for( ; nLOD < MAX_NUM_LODS; ++nLOD, nMask <<= 1 )
  3488. {
  3489. boneMask |= nMask;
  3490. }
  3491. // A bit of a hack, but this way when in prediction we use the "correct" gpGlobals->curtime -- rather than the
  3492. // one that the player artificially advances
  3493. if ( GetPredictable() &&
  3494. prediction->InPrediction() )
  3495. {
  3496. currentTime = prediction->GetSavedTime();
  3497. }
  3498. #if defined(_DEBUG_SPUvPPU_ANIMATION)
  3499. m_BoneAccessor.SetReadableBones( 0 );
  3500. m_BoneAccessor.SetWritableBones( 0 );
  3501. m_flLastBoneSetupTime = 0.0f;
  3502. m_iPrevBoneMask = m_iAccumulatedBoneMask;
  3503. m_iAccumulatedBoneMask = 0;
  3504. #else
  3505. if( m_iMostRecentModelBoneCounter != g_iModelBoneCounter )
  3506. {
  3507. // Clear out which bones we've touched this frame if this is
  3508. // the first time we've seen this object this frame.
  3509. // BUGBUG: Time can go backward due to prediction, catch that here until a better solution is found
  3510. if ( LastBoneChangedTime() >= m_flLastBoneSetupTime || currentTime < m_flLastBoneSetupTime )
  3511. {
  3512. #ifdef DEBUG_BONESETUP_THREADVSNONTHREAD
  3513. Msg("_Pass1 1st time: %x, mask: %d, mrmbc: %d, time:%f\n", this, boneMask, m_iMostRecentModelBoneCounter, currentTime );
  3514. #endif
  3515. m_BoneAccessor.SetReadableBones( 0 );
  3516. m_BoneAccessor.SetWritableBones( 0 );
  3517. m_flLastBoneSetupTime = currentTime;
  3518. #if defined( DBGFLAG_ASSERT )
  3519. m_vBoneSetupCachedOrigin = GetRenderOrigin();
  3520. m_qBoneSetupCachedAngles = GetRenderAngles();
  3521. #endif
  3522. }
  3523. m_iPrevBoneMask = m_iAccumulatedBoneMask;
  3524. m_iAccumulatedBoneMask = 0;
  3525. }
  3526. #endif
  3527. // Keep track of everthing asked for over the entire frame
  3528. // But not those things asked for during bone setup
  3529. // if ( !g_bInThreadedBoneSetup )
  3530. {
  3531. m_iAccumulatedBoneMask |= boneMask;
  3532. }
  3533. #if !defined(_DEBUG_SPUvPPU_ANIMATION)
  3534. // Make sure that we know that we've already calculated some bone stuff this time around.
  3535. m_iMostRecentModelBoneCounter = g_iModelBoneCounter;
  3536. #endif
  3537. // Have we cached off all bones meeting the flag set?
  3538. if( ( m_BoneAccessor.GetReadableBones() & boneMask ) != boneMask )
  3539. {
  3540. CStudioHdr *hdr = GetModelPtr();
  3541. if ( !hdr || !hdr->SequencesAvailable() )
  3542. {
  3543. m_BoneSetupLock.Unlock();
  3544. return false;
  3545. }
  3546. #if defined( DBGFLAG_ASSERT )
  3547. bool bHadDirtyAbsTransform = IsEFlagSet( EFL_DIRTY_ABSTRANSFORM );
  3548. #endif
  3549. // Setup our transform based on render angles and origin.
  3550. ALIGN16 matrix3x4_t parentTransform ALIGN16_POST;
  3551. if( cl_PS3_SPU_bones_safesync.GetInt() )
  3552. {
  3553. AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform );
  3554. AssertMsg( !bHadDirtyAbsTransform || !IsEFlagSet( EFL_DIRTY_ABSTRANSFORM ), "Using an old origin/angles and unable to recompute before caching off the bones" );
  3555. }
  3556. // Load the boneMask with the total of what was asked for last frame.
  3557. // WHY??
  3558. boneMask |= m_iPrevBoneMask;
  3559. // Allow access to the bones we're setting up so we don't get asserts in here.
  3560. int oldReadableBones = m_BoneAccessor.GetReadableBones();
  3561. m_BoneAccessor.SetWritableBones( m_BoneAccessor.GetReadableBones() | boneMask );
  3562. m_BoneAccessor.SetReadableBones( m_BoneAccessor.GetWritableBones() );
  3563. if (hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP)
  3564. {
  3565. if( !cl_PS3_SPU_bones_safesync.GetInt() )
  3566. {
  3567. if( m_iPS3BoneJob_Port >= 0 )
  3568. {
  3569. Assert( m_iPS3BoneJob_ID >= 0 );
  3570. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3571. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3572. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3573. }
  3574. if( m_iPS3BoneJob_DependantID != -1 )
  3575. {
  3576. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( m_iPS3BoneJob_DependantID );
  3577. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3578. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3579. }
  3580. // reset
  3581. PS3BoneJob_PreInit();
  3582. AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform );
  3583. }
  3584. MatrixCopy( parentTransform, GetBoneForWrite( 0 ) );
  3585. }
  3586. else
  3587. {
  3588. //---------------------------------------------------------------------------
  3589. // NOTE: This is the only path taken that actually creates real PS3 bone jobs
  3590. //---------------------------------------------------------------------------
  3591. // This is necessary because it's possible that CalculateIKLocks will trigger our move children
  3592. // to call GetAbsOrigin(), and they'll use our OLD bone transforms to get their attachments
  3593. // since we're right in the middle of setting up our new transforms.
  3594. //
  3595. // Setting this flag forces move children to keep their abs transform invalidated.
  3596. AddEFlags( EFL_SETTING_UP_BONES );
  3597. // NOTE: For model scaling, we need to opt out of IK because it will mark the bones as already being calculated
  3598. // [msmith]: What game is it that want's to do model scaling and needs to opt out of IK? It seems as if opting out of IK should be the exception and not the rule here.
  3599. // I suggest we change the #ifdef such that only the games that need to kill IK get used here... rather than ORing in all other games that use this engine in the future.
  3600. #if defined( PORTAL2 ) || defined( INFESTED ) || defined( CSTRIKE15 )
  3601. // only allocate an ik block if the npc can use it
  3602. if ( !m_pIk && hdr->numikchains() > 0 && !(m_EntClientFlags & ENTCLIENTFLAG_DONTUSEIK) )
  3603. m_pIk = new CIKContext;
  3604. #endif // PORTAL2
  3605. int bonesMaskNeedRecalc = boneMask | oldReadableBones; // Hack to always recalc bones, to fix the arm jitter in the new CS player anims until Ken makes the real fix
  3606. if( cl_PS3_SPU_bones_safesync.GetInt() )
  3607. {
  3608. if ( m_pIk )
  3609. {
  3610. if (Teleported() || IsEffectActive(EF_NOINTERP))
  3611. {
  3612. m_pIk->ClearTargets();
  3613. }
  3614. m_pIk->Init( hdr, GetRenderAngles(), GetRenderOrigin(), currentTime, gpGlobals->framecount, bonesMaskNeedRecalc );
  3615. }
  3616. }
  3617. // return here, and notify that we've set up a pass1 job
  3618. return StandardBlendingRules_Pass1( hdr, currentTime, nMaxBones, boneMask, bonesMaskNeedRecalc, oldReadableBones, parentTransform );
  3619. }
  3620. if( !( oldReadableBones & BONE_USED_BY_ATTACHMENT ) && ( boneMask & BONE_USED_BY_ATTACHMENT ) )
  3621. {
  3622. SetupBones_AttachmentHelper( hdr );
  3623. }
  3624. }
  3625. else
  3626. {
  3627. if( !cl_PS3_SPU_bones_safesync.GetInt() )
  3628. {
  3629. if( m_iPS3BoneJob_Port >= 0 )
  3630. {
  3631. Assert( m_iPS3BoneJob_ID >= 0 );
  3632. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3633. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3634. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3635. }
  3636. if( m_iPS3BoneJob_DependantID != -1 )
  3637. {
  3638. PS3BoneJobData *pBoneJob = g_pBoneJobs->GetJobData( m_iPS3BoneJob_DependantID );
  3639. C_BaseAnimating *pDependantBaseAnim = (C_BaseAnimating *)pBoneJob->bonejobPPU.pBaseAnimating;
  3640. pDependantBaseAnim->PS3BoneJob_WaitForFinish();
  3641. }
  3642. // reset
  3643. PS3BoneJob_PreInit();
  3644. }
  3645. }
  3646. m_BoneSetupLock.Unlock();
  3647. return false;
  3648. }
  3649. //-----------------------------------------------------------------------------
  3650. // post bone job pass for setupbones
  3651. // should be the first thing that follows pass2 of standardblendingrules
  3652. //-----------------------------------------------------------------------------
  3653. bool C_BaseAnimating::SetupBones_Pass2( void )
  3654. {
  3655. SNPROF_ANIM( "C_BaseAnimating::SetupBones_Pass2" );
  3656. if( m_iPS3BoneJob_ID < 0 )
  3657. return false;
  3658. PS3BoneJobData *pJobData = g_pBoneJobs->GetJobData( m_iPS3BoneJob_ID );
  3659. bonejob_PPU *pBonejobPPU = &pJobData->bonejobPPU;
  3660. bonejob_SPU *pBonejobSPU = &pJobData->bonejobSPU;
  3661. CStudioHdr *hdr = pBonejobPPU->pStudioHdr;
  3662. int boneMask = pBonejobPPU->boneMask;
  3663. int oldReadableBones = pBonejobPPU->oldReadableBones;
  3664. float currentTime = pBonejobSPU->currentTime;
  3665. int bonesMaskNeedRecalc = pBonejobPPU->bonesMaskNeedsRecalc;
  3666. BoneVector *pos = pJobData->pos;
  3667. BoneQuaternion *q = pJobData->q;
  3668. matrix3x4_t parentTransform;
  3669. MatrixCopy( pBonejobPPU->parentTransform, parentTransform );
  3670. CBoneBitList boneComputed;
  3671. // finish _pass2 of AddDependencies
  3672. // IKOFF
  3673. if( m_pIk && !IsRagdoll() )
  3674. {
  3675. // don't calculate IK on ragdolls
  3676. m_pIk->AddAllDependencies_PS3( pJobData->addDep_IKRules, pJobData->addDep_numIKRules );
  3677. UpdateIKLocks( currentTime );
  3678. m_pIk->UpdateTargets( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
  3679. CalculateIKLocks( currentTime );
  3680. m_pIk->SolveDependencies( pos, q, m_BoneAccessor.GetBoneArrayForWrite(), boneComputed );
  3681. }
  3682. BuildTransformations( hdr, pos, q, parentTransform, bonesMaskNeedRecalc, boneComputed );
  3683. // Draw skeleton?
  3684. if( enable_skeleton_draw.GetBool() )
  3685. {
  3686. DrawSkeleton( hdr, boneMask );
  3687. }
  3688. RemoveEFlags( EFL_SETTING_UP_BONES );
  3689. ControlMouth( hdr );
  3690. if( !( oldReadableBones & BONE_USED_BY_ATTACHMENT ) && ( boneMask & BONE_USED_BY_ATTACHMENT ) )
  3691. {
  3692. SetupBones_AttachmentHelper( hdr );
  3693. }
  3694. return true;
  3695. }
  3696. #endif // _PS3
  3697. //-----------------------------------------------------------------------------
  3698. //
  3699. // END OF PS3 BONE JOBS
  3700. //
  3701. //-----------------------------------------------------------------------------
  3702. C_BaseAnimating* C_BaseAnimating::FindFollowedEntity()
  3703. {
  3704. C_BaseEntity *follow = GetFollowedEntity();
  3705. if ( !follow )
  3706. return NULL;
  3707. if ( follow->IsDormant() )
  3708. return NULL;
  3709. if ( !follow->GetModel() )
  3710. {
  3711. Warning( "mod_studio: MOVETYPE_FOLLOW with no model.\n" );
  3712. return NULL;
  3713. }
  3714. if ( modelinfo->GetModelType( follow->GetModel() ) != mod_studio )
  3715. {
  3716. Warning( "Attached %s (mod_studio) to %s (%d)\n",
  3717. modelinfo->GetModelName( GetModel() ),
  3718. modelinfo->GetModelName( follow->GetModel() ),
  3719. modelinfo->GetModelType( follow->GetModel() ) );
  3720. return NULL;
  3721. }
  3722. return assert_cast< C_BaseAnimating* >( follow );
  3723. }
  3724. void C_BaseAnimating::InvalidateBoneCache()
  3725. {
  3726. // mariod - testing
  3727. if( !s_bEnableInvalidateBoneCache )
  3728. return;
  3729. // SNPROF_ANIM("Anim_InvalidateBoneCache");
  3730. m_iMostRecentModelBoneCounter = g_iModelBoneCounter - 1;
  3731. m_flLastBoneSetupTime = -FLT_MAX;
  3732. }
  3733. bool C_BaseAnimating::IsBoneCacheValid() const
  3734. {
  3735. return m_iMostRecentModelBoneCounter == g_iModelBoneCounter;
  3736. }
  3737. // Causes an assert to happen if bones or attachments are used while this is false.
  3738. struct BoneAccess
  3739. {
  3740. BoneAccess()
  3741. {
  3742. bAllowBoneAccessForNormalModels = false;
  3743. bAllowBoneAccessForViewModels = false;
  3744. tag = NULL;
  3745. }
  3746. bool bAllowBoneAccessForNormalModels;
  3747. bool bAllowBoneAccessForViewModels;
  3748. char const *tag;
  3749. };
  3750. static CUtlVector< BoneAccess > g_BoneAccessStack;
  3751. static BoneAccess g_BoneAcessBase;
  3752. bool C_BaseAnimating::IsBoneAccessAllowed() const
  3753. {
  3754. if ( !ThreadInMainThread() )
  3755. {
  3756. return true;
  3757. }
  3758. if ( IsViewModel() )
  3759. return g_BoneAcessBase.bAllowBoneAccessForViewModels;
  3760. else
  3761. return g_BoneAcessBase.bAllowBoneAccessForNormalModels;
  3762. }
  3763. // (static function)
  3764. void C_BaseAnimating::PushAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels, char const *tagPush )
  3765. {
  3766. if ( !ThreadInMainThread() )
  3767. {
  3768. return;
  3769. }
  3770. BoneAccess save = g_BoneAcessBase;
  3771. g_BoneAccessStack.AddToTail( save );
  3772. Assert( g_BoneAccessStack.Count() < 32 ); // Most likely we are leaking "PushAllowBoneAccess" calls if PopBoneAccess is never called. Consider using AutoAllowBoneAccess.
  3773. g_BoneAcessBase.bAllowBoneAccessForNormalModels = bAllowForNormalModels;
  3774. g_BoneAcessBase.bAllowBoneAccessForViewModels = bAllowForViewModels;
  3775. g_BoneAcessBase.tag = tagPush;
  3776. }
  3777. void C_BaseAnimating::PopBoneAccess( char const *tagPop )
  3778. {
  3779. if ( !ThreadInMainThread() )
  3780. {
  3781. return;
  3782. }
  3783. // Validate that pop matches the push
  3784. Assert( ( g_BoneAcessBase.tag == tagPop ) || ( g_BoneAcessBase.tag && g_BoneAcessBase.tag != ( char const * ) 1 && tagPop && tagPop != ( char const * ) 1 && !strcmp( g_BoneAcessBase.tag, tagPop ) ) );
  3785. int lastIndex = g_BoneAccessStack.Count() - 1;
  3786. if ( lastIndex < 0 )
  3787. {
  3788. Assert( !"C_BaseAnimating::PopBoneAccess: Stack is empty!!!" );
  3789. return;
  3790. }
  3791. g_BoneAcessBase = g_BoneAccessStack[lastIndex ];
  3792. g_BoneAccessStack.Remove( lastIndex );
  3793. }
  3794. C_BaseAnimating::AutoAllowBoneAccess::AutoAllowBoneAccess( bool bAllowForNormalModels, bool bAllowForViewModels )
  3795. {
  3796. C_BaseAnimating::PushAllowBoneAccess( bAllowForNormalModels, bAllowForViewModels, ( char const * ) 1 );
  3797. }
  3798. C_BaseAnimating::AutoAllowBoneAccess::~AutoAllowBoneAccess( )
  3799. {
  3800. C_BaseAnimating::PopBoneAccess( ( char const * ) 1 );
  3801. }
  3802. // (static function)
  3803. void C_BaseAnimating::InvalidateBoneCaches()
  3804. {
  3805. g_nNumBonesSetupAll = g_nNumBonesSetupAllTemp;
  3806. g_nNumBonesSetupAllTemp = 0;
  3807. g_nNumBonesSetupBlendingRulesOnly = g_nNumBonesSetupBlendingRulesOnlyTemp;
  3808. g_nNumBonesSetupBlendingRulesOnlyTemp = 0;
  3809. g_iModelBoneCounter++;
  3810. }
  3811. //-----------------------------------------------------------------------------
  3812. // Purpose:
  3813. //-----------------------------------------------------------------------------
  3814. bool C_BaseAnimating::GetRootBone( matrix3x4_t &rootBone )
  3815. {
  3816. if ( IsEffectActive( EF_BONEMERGE ) && GetMoveParent() && m_pBoneMergeCache )
  3817. return m_pBoneMergeCache->GetRootBone( rootBone );
  3818. GetBoneTransform( 0, rootBone );
  3819. return true;
  3820. }
  3821. ConVar r_drawothermodels( "r_drawothermodels", "1", FCVAR_CHEAT, "0=Off, 1=Normal, 2=Wireframe" );
  3822. bool C_BaseAnimating::UpdateBlending( int flags, const RenderableInstance_t &instance )
  3823. {
  3824. if ( flags & STUDIO_RENDER )
  3825. {
  3826. // Determine blending amount and tell engine
  3827. float blend = (float)( instance.m_nAlpha / 255.0f );
  3828. // Totally gone
  3829. if ( blend <= 0.0f )
  3830. return false;
  3831. // Tell engine
  3832. render->SetBlend( blend );
  3833. float color[3];
  3834. GetColorModulation( color );
  3835. render->SetColorModulation( color );
  3836. }
  3837. return true;
  3838. }
  3839. //-----------------------------------------------------------------------------
  3840. // Purpose: Draws the object
  3841. // Input : flags -
  3842. //-----------------------------------------------------------------------------
  3843. ConVar r_drawmodelnames("r_drawmodelnames", "0", FCVAR_CHEAT|FCVAR_REPLICATED);
  3844. int C_BaseAnimating::DrawModel( int flags, const RenderableInstance_t &instance )
  3845. {
  3846. VPROF_BUDGET( "C_BaseAnimating::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING );
  3847. if ( !m_bReadyToDraw )
  3848. return 0;
  3849. float flPrevBlend = render->GetBlend();
  3850. if ( IsRenderForceOpaquePass() && GetRenderAlpha() < 255 )
  3851. {
  3852. // if this model is being forced into the opaque pass, it may have non-opaque alpha that should be respected.
  3853. RenderableInstance_t temp;
  3854. temp.m_nAlpha = GetRenderAlpha();
  3855. if ( !UpdateBlending( flags, temp ) )
  3856. {
  3857. return 0;
  3858. }
  3859. }
  3860. #if defined ( PORTAL2 )
  3861. if ( IsRenderingWithViewModels() )
  3862. {
  3863. if ( !UpdateBlending( flags, instance ) )
  3864. {
  3865. return 0;
  3866. }
  3867. }
  3868. #endif
  3869. int drawn = 0;
  3870. if ( r_drawothermodels.GetInt() )
  3871. {
  3872. MDLCACHE_CRITICAL_SECTION();
  3873. int extraFlags = 0;
  3874. if ( r_drawothermodels.GetInt() == 2 )
  3875. {
  3876. extraFlags |= STUDIO_WIREFRAME;
  3877. }
  3878. if ( flags & STUDIO_SHADOWDEPTHTEXTURE )
  3879. {
  3880. extraFlags |= STUDIO_SHADOWDEPTHTEXTURE;
  3881. }
  3882. if ( flags & STUDIO_SSAODEPTHTEXTURE )
  3883. {
  3884. extraFlags |= STUDIO_SSAODEPTHTEXTURE;
  3885. }
  3886. if ( flags & STUDIO_AOPREPASSTEXURE )
  3887. {
  3888. extraFlags |= STUDIO_AOPREPASSTEXURE;
  3889. }
  3890. if ( flags & STUDIO_DONOTMODIFYSTENCILSTATE )
  3891. {
  3892. extraFlags |= STUDIO_DONOTMODIFYSTENCILSTATE;
  3893. }
  3894. if ( flags & STUDIO_SKIP_DECALS )
  3895. {
  3896. extraFlags |= STUDIO_SKIP_DECALS;
  3897. }
  3898. // Necessary for lighting blending
  3899. CreateModelInstance();
  3900. if ( !IsFollowingEntity() )
  3901. {
  3902. drawn = InternalDrawModel( flags|extraFlags, instance );
  3903. }
  3904. else
  3905. {
  3906. // this doesn't draw unless master entity is visible and it's a studio model!!!
  3907. C_BaseAnimating *follow = FindFollowedEntity();
  3908. if ( follow )
  3909. {
  3910. // recompute master entity bone structure
  3911. int baseDrawn = follow->DrawModel( 0, instance );
  3912. // draw entity
  3913. // FIXME: Currently only draws if aiment is drawn.
  3914. // BUGBUG: Fixup bbox and do a separate cull for follow object
  3915. if ( baseDrawn )
  3916. {
  3917. drawn = InternalDrawModel( flags|extraFlags, instance );
  3918. }
  3919. }
  3920. }
  3921. }
  3922. render->SetBlend( flPrevBlend );
  3923. // If we're visualizing our bboxes, draw them
  3924. DrawBBoxVisualizations();
  3925. if ( r_drawmodelnames.GetBool() && m_pStudioHdr )
  3926. {
  3927. debugoverlay->AddTextOverlay( GetAbsOrigin(), 0, "Model: %s", m_pStudioHdr->name() );
  3928. }
  3929. return drawn;
  3930. }
  3931. //-----------------------------------------------------------------------------
  3932. // Purpose: Draw skeleton topology & coordinate systems
  3933. //-----------------------------------------------------------------------------
  3934. void C_BaseAnimating::DrawSkeleton( CStudioHdr const* pHdr, int iBoneMask ) const
  3935. {
  3936. if ( !pHdr )
  3937. return;
  3938. Vector from, to;
  3939. for ( int i = 0; i < pHdr->numbones(); ++i )
  3940. {
  3941. if ( !(pHdr->boneFlags( i ) & iBoneMask) )
  3942. continue;
  3943. debugoverlay->AddCoordFrameOverlay( m_BoneAccessor[ i ], 3.0f );
  3944. int const iParentIndex = pHdr->boneParent( i );
  3945. if ( iParentIndex < 0 )
  3946. continue;
  3947. MatrixPosition( m_BoneAccessor[ i ], from );
  3948. MatrixPosition( m_BoneAccessor[ iParentIndex ], to );
  3949. debugoverlay->AddLineOverlay( from, to, 0, 255, 255, true, 0.0f );
  3950. }
  3951. }
  3952. //-----------------------------------------------------------------------------
  3953. // Gets the hitbox-to-world transforms, returns false if there was a problem
  3954. //-----------------------------------------------------------------------------
  3955. bool C_BaseAnimating::HitboxToWorldTransforms( matrix3x4_t *pHitboxToWorld[MAXSTUDIOBONES] )
  3956. {
  3957. if ( !IsBoneCacheValid() )
  3958. {
  3959. MDLCACHE_CRITICAL_SECTION();
  3960. if ( !GetModel() )
  3961. return false;
  3962. CStudioHdr *pStudioHdr = GetModelPtr();
  3963. if (!pStudioHdr)
  3964. return false;
  3965. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( GetHitboxSet() );
  3966. if ( !set )
  3967. return false;
  3968. if ( !set->numhitboxes )
  3969. return false;
  3970. SetupBones( NULL, -1, BONE_USED_BY_HITBOX, gpGlobals->curtime );
  3971. }
  3972. for ( int i = 0; i < m_CachedBoneData.Count(); i++ )
  3973. {
  3974. // UNDONE: Some of these bones haven't been set up. Is it necessary to check each
  3975. // one for membership in the hitbox set and NULL it if it isn't present?
  3976. pHitboxToWorld[i] = &m_CachedBoneData[i];
  3977. }
  3978. return true;
  3979. }
  3980. //-----------------------------------------------------------------------------
  3981. //
  3982. //-----------------------------------------------------------------------------
  3983. bool C_BaseAnimating::OnPostInternalDrawModel( ClientModelRenderInfo_t *pInfo )
  3984. {
  3985. return true;
  3986. }
  3987. //----------------------------------------------------------------------------
  3988. // Hooks into the fast path render system
  3989. //----------------------------------------------------------------------------
  3990. static ConVar r_drawmodelstatsoverlay( "r_drawmodelstatsoverlay", "0", FCVAR_CHEAT );
  3991. IClientModelRenderable* C_BaseAnimating::GetClientModelRenderable()
  3992. {
  3993. // Cannot participate if it has a render clip plane
  3994. if ( !m_bCanUseFastPath || m_bIsUsingRelativeLighting )
  3995. return NULL;
  3996. if ( r_drawothermodels.GetInt() != 1 || r_drawmodelstatsoverlay.GetInt() != 0 || mat_wireframe.GetInt() != 0 )
  3997. return NULL;
  3998. if ( IsFollowingEntity() && !FindFollowedEntity() )
  3999. return NULL;
  4000. #ifdef PORTAL
  4001. if ( GetRenderClipPlane() != NULL )
  4002. return NULL;
  4003. #endif
  4004. return this;
  4005. }
  4006. //----------------------------------------------------------------------------
  4007. // Hooks into the fast path render system
  4008. //----------------------------------------------------------------------------
  4009. bool C_BaseAnimating::GetRenderData( void *pData, ModelDataCategory_t nCategory )
  4010. {
  4011. switch ( nCategory )
  4012. {
  4013. case MODEL_DATA_LIGHTING_MODEL:
  4014. // Necessary for lighting blending
  4015. CreateModelInstance();
  4016. *(RenderableLightingModel_t*)pData = LIGHTING_MODEL_STANDARD;
  4017. return true;
  4018. case MODEL_DATA_STENCIL:
  4019. return ComputeStencilState( (ShaderStencilState_t*)pData );
  4020. default:
  4021. return false;
  4022. // return BaseClass::GetRenderData( pData, nCategory );
  4023. }
  4024. }
  4025. //-----------------------------------------------------------------------------
  4026. //
  4027. //-----------------------------------------------------------------------------
  4028. bool C_BaseAnimating::OnInternalDrawModel( ClientModelRenderInfo_t *pInfo )
  4029. {
  4030. if ( m_hLightingOrigin )
  4031. {
  4032. pInfo->pLightingOrigin = &(m_hLightingOrigin->GetAbsOrigin());
  4033. }
  4034. return true;
  4035. }
  4036. //-----------------------------------------------------------------------------
  4037. //
  4038. //-----------------------------------------------------------------------------
  4039. void C_BaseAnimating::DoInternalDrawModel( IMatRenderContext *pRenderContext, ClientModelRenderInfo_t *pInfo, DrawModelState_t *pState, matrix3x4_t *pBoneToWorldArray )
  4040. {
  4041. if ( pState)
  4042. {
  4043. modelrender->DrawModelExecute( pRenderContext, *pState, *pInfo, pBoneToWorldArray );
  4044. }
  4045. if ( vcollide_wireframe.GetBool() )
  4046. {
  4047. if ( IsRagdoll() )
  4048. {
  4049. m_pRagdoll->DrawWireframe();
  4050. }
  4051. else if ( IsSolid() && CollisionProp()->GetSolid() == SOLID_VPHYSICS )
  4052. {
  4053. vcollide_t *pCollide = modelinfo->GetVCollide( GetModelIndex() );
  4054. if ( pCollide && pCollide->solidCount == 1 )
  4055. {
  4056. static color32 debugColor = {0,255,255,0};
  4057. matrix3x4_t matrix;
  4058. AngleMatrix( GetAbsAngles(), GetAbsOrigin(), matrix );
  4059. engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColor );
  4060. if ( VPhysicsGetObject() )
  4061. {
  4062. static color32 debugColorPhys = {255,0,0,0};
  4063. matrix3x4_t matrix;
  4064. VPhysicsGetObject()->GetPositionMatrix( &matrix );
  4065. engine->DebugDrawPhysCollide( pCollide->solids[0], NULL, matrix, debugColorPhys );
  4066. }
  4067. }
  4068. }
  4069. }
  4070. }
  4071. //----------------------------------------------------------------------------
  4072. // Computes stencil settings
  4073. //----------------------------------------------------------------------------
  4074. bool C_BaseAnimating::ComputeStencilState( ShaderStencilState_t *pStencilState )
  4075. {
  4076. #if defined( _X360 )
  4077. if ( !r_shadow_deferred.GetBool() )
  4078. {
  4079. // Early out if we don't care about deferred shadow masks
  4080. return false;
  4081. }
  4082. uint32 mask = 0x0;
  4083. uint32 nRef = mask;
  4084. mask |= 1 << 2; // Stencil for masking deferred shadows uses 0x4
  4085. bool bCastsShadows = ( ShadowCastType() != SHADOWS_NONE );
  4086. nRef |= bCastsShadows << 2;
  4087. pStencilState->m_bEnable = true;
  4088. pStencilState->m_nTestMask = 0xFFFFFFFF;
  4089. pStencilState->m_nWriteMask = mask;
  4090. pStencilState->m_nReferenceValue = nRef;
  4091. pStencilState->m_CompareFunc = SHADER_STENCILFUNC_ALWAYS;
  4092. pStencilState->m_PassOp = SHADER_STENCILOP_SET_TO_REFERENCE;
  4093. pStencilState->m_FailOp = SHADER_STENCILOP_KEEP;
  4094. pStencilState->m_ZFailOp = SHADER_STENCILOP_KEEP;
  4095. // Deferred shadow rendering:
  4096. // set or clear hi-stencil depending on shadow cast type
  4097. pStencilState->m_bHiStencilEnable = false;
  4098. pStencilState->m_bHiStencilWriteEnable = true;
  4099. pStencilState->m_HiStencilCompareFunc = SHADER_HI_STENCILFUNC_NOTEQUAL;
  4100. pStencilState->m_nHiStencilReferenceValue = 0;
  4101. /*
  4102. // The old hi-stencil state, that unmasked too many tiles for things receiving shadows
  4103. pStencilState->m_HiStencilCompareFunc = bCastsShadows ? SHADER_HI_STENCILFUNC_NOTEQUAL : SHADER_HI_STENCILFUNC_EQUAL;
  4104. pStencilState->m_nHiStencilReferenceValue = bCastsShadows ? 0 : 1;
  4105. */
  4106. return true;
  4107. #else
  4108. return false;
  4109. #endif
  4110. }
  4111. //-----------------------------------------------------------------------------
  4112. // Purpose: Draws the object
  4113. // Input : flags -
  4114. //-----------------------------------------------------------------------------
  4115. int C_BaseAnimating::InternalDrawModel( int flags, const RenderableInstance_t &instance )
  4116. {
  4117. VPROF( "C_BaseAnimating::InternalDrawModel" );
  4118. if ( !GetModel() )
  4119. return 0;
  4120. // This should never happen, but if the server class hierarchy has bmodel entities derived from CBaseAnimating or does a
  4121. // SetModel with the wrong type of model, this could occur.
  4122. if ( modelinfo->GetModelType( GetModel() ) != mod_studio )
  4123. {
  4124. return BaseClass::DrawModel( flags, instance );
  4125. }
  4126. // Make sure hdr is valid for drawing
  4127. if ( !GetModelPtr() )
  4128. return 0;
  4129. bool bUsingStencil = false;
  4130. CMatRenderContextPtr pRenderContext( materials );
  4131. if ( !( flags & STUDIO_DONOTMODIFYSTENCILSTATE ) && !( flags & STUDIO_SHADOWDEPTHTEXTURE ) && ( flags & STUDIO_RENDER ) )
  4132. {
  4133. ShaderStencilState_t state;
  4134. bUsingStencil = ComputeStencilState( &state );
  4135. if ( bUsingStencil )
  4136. {
  4137. pRenderContext->SetStencilState( state );
  4138. }
  4139. }
  4140. ClientModelRenderInfo_t info;
  4141. ClientModelRenderInfo_t *pInfo;
  4142. pInfo = &info;
  4143. pInfo->flags = flags;
  4144. pInfo->pRenderable = this;
  4145. pInfo->instance = GetModelInstance();
  4146. pInfo->entity_index = index;
  4147. pInfo->pModel = GetModel();
  4148. pInfo->origin = GetRenderOrigin();
  4149. pInfo->angles = GetRenderAngles();
  4150. pInfo->skin = GetSkin();
  4151. pInfo->body = m_nBody;
  4152. pInfo->hitboxset = m_nHitboxSet;
  4153. bool bMarkAsDrawn = false;
  4154. if ( OnInternalDrawModel( pInfo ) )
  4155. {
  4156. Assert( !pInfo->pModelToWorld);
  4157. if ( !pInfo->pModelToWorld )
  4158. {
  4159. pInfo->pModelToWorld = &pInfo->modelToWorld;
  4160. // Turns the origin + angles into a matrix
  4161. AngleMatrix( pInfo->angles, pInfo->origin, pInfo->modelToWorld );
  4162. }
  4163. // Suppress unlocking
  4164. CMatRenderDataReference rd( pRenderContext );
  4165. DrawModelState_t state;
  4166. matrix3x4_t *pBoneToWorld;
  4167. bMarkAsDrawn = modelrender->DrawModelSetup( pRenderContext, *pInfo, &state, &pBoneToWorld );
  4168. // Scale the base transform if we don't have a bone hierarchy
  4169. if ( GetModelScale() > 1.0f+FLT_EPSILON || GetModelScale() < 1.0f-FLT_EPSILON )
  4170. {
  4171. CStudioHdr *pHdr = GetModelPtr();
  4172. if ( pHdr && pBoneToWorld && pHdr->numbones() == 1 )
  4173. {
  4174. // Scale the bone to world at this point
  4175. const float flScale = GetModelHierarchyScale();
  4176. VectorScale( (*pBoneToWorld)[0], flScale, (*pBoneToWorld)[0] );
  4177. VectorScale( (*pBoneToWorld)[1], flScale, (*pBoneToWorld)[1] );
  4178. VectorScale( (*pBoneToWorld)[2], flScale, (*pBoneToWorld)[2] );
  4179. }
  4180. }
  4181. bool bOverride = false;
  4182. if ( cl_custom_material_override.GetBool() && ( flags & STUDIO_RENDER ) && !modelrender->IsForcedMaterialOverride() && GetCustomMaterialCount() > 0 )
  4183. {
  4184. for ( int i = 0; i < GetCustomMaterialCount(); i++ )
  4185. {
  4186. if ( IsCustomMaterialValid( i ) )
  4187. {
  4188. modelrender->ForcedMaterialOverride( GetCustomMaterial( i )->GetMaterial(), OVERRIDE_SELECTIVE, i );
  4189. bOverride = true;
  4190. }
  4191. }
  4192. }
  4193. DoInternalDrawModel( pRenderContext, pInfo, ( bMarkAsDrawn && ( pInfo->flags & STUDIO_RENDER ) ) ? &state : NULL, pBoneToWorld );
  4194. if ( bOverride )
  4195. {
  4196. modelrender->ForcedMaterialOverride( NULL );
  4197. }
  4198. }
  4199. if ( bUsingStencil )
  4200. {
  4201. ShaderStencilState_t state;
  4202. state.m_bEnable = false;
  4203. #if defined( _X360 )
  4204. // Deferred shadow rendering: Disable Hi-Stencil
  4205. state.m_bHiStencilEnable = false;
  4206. state.m_bHiStencilWriteEnable = false;
  4207. #endif
  4208. pRenderContext->SetStencilState( state );
  4209. }
  4210. OnPostInternalDrawModel( pInfo );
  4211. return bMarkAsDrawn;
  4212. }
  4213. extern ConVar muzzleflash_light;
  4214. void C_BaseAnimating::ProcessMuzzleFlashEvent()
  4215. {
  4216. // If we have an attachment, then stick a light on it.
  4217. if ( muzzleflash_light.GetBool() )
  4218. {
  4219. //FIXME: We should really use a named attachment for this
  4220. if ( m_Attachments.Count() > 0 )
  4221. {
  4222. Vector vAttachment;
  4223. QAngle dummyAngles;
  4224. // NOTE! This is typically "1" by name. Also, if you add an illumination position, the illumination position will usually take the 1 slot which will cause the light to flash at the illumination position.
  4225. AssertMsg(false, "This code assumes that the first attachment in all models is the muzzle flash. Make sure this is guaranteed or fix this code.");
  4226. GetAttachment( 1, vAttachment, dummyAngles );
  4227. // Make an elight
  4228. dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_MUZZLEFLASH + index );
  4229. el->origin = vAttachment;
  4230. el->radius = random->RandomInt( 32, 64 );
  4231. el->decay = el->radius / 0.05f;
  4232. el->die = gpGlobals->curtime + 0.05f;
  4233. el->color.r = 255;
  4234. el->color.g = 192;
  4235. el->color.b = 64;
  4236. el->color.exponent = 5;
  4237. }
  4238. }
  4239. }
  4240. //-----------------------------------------------------------------------------
  4241. // Internal routine to process animation events for studiomodels
  4242. //-----------------------------------------------------------------------------
  4243. void C_BaseAnimating::DoAnimationEvents( CStudioHdr *pStudioHdr )
  4244. {
  4245. bool watch = false;//IsPlayer(); // Q_strstr( hdr->name, "rifle" ) ? true : false;
  4246. //Adrian: eh? This should never happen.
  4247. if ( GetSequence() == -1 )
  4248. return;
  4249. // build root animation
  4250. float flEventCycle = GetCycle();
  4251. // If we're invisible, don't draw the muzzle flash
  4252. bool bIsInvisible = !IsVisibleToAnyPlayer() && !IsViewModel() && !IsMenuModel();
  4253. if ( bIsInvisible && !clienttools->IsInRecordingMode() )
  4254. return;
  4255. #if !defined( CSTRIKE15 )
  4256. // We already handle muzzle flash events in CSTRIKE15.
  4257. // Also this code has a bug in that it always uses attachment 1 instead of by name.
  4258. // add in muzzleflash effect
  4259. if ( ShouldMuzzleFlash() )
  4260. {
  4261. DisableMuzzleFlash();
  4262. ProcessMuzzleFlashEvent();
  4263. }
  4264. #endif
  4265. // If we're invisible, don't process animation events.
  4266. if ( bIsInvisible )
  4267. return;
  4268. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( GetSequence() );
  4269. if (seqdesc.numevents == 0)
  4270. return;
  4271. // Forces anim event indices to get set and returns pEvent(0);
  4272. mstudioevent_t *pevent = GetEventIndexForSequence( seqdesc );
  4273. if ( watch )
  4274. {
  4275. Msg( "%i cycle %f\n", gpGlobals->tickcount, GetCycle() );
  4276. }
  4277. bool resetEvents = m_nResetEventsParity != m_nPrevResetEventsParity;
  4278. m_nPrevResetEventsParity = m_nResetEventsParity;
  4279. if (m_nEventSequence != GetSequence() || resetEvents )
  4280. {
  4281. if ( watch )
  4282. {
  4283. Msg( "new seq: %i - old seq: %i - reset: %s - m_flCycle %f - Model Name: %s - (time %.3f)\n",
  4284. GetSequence(), m_nEventSequence,
  4285. resetEvents ? "true" : "false",
  4286. GetCycle(), pStudioHdr->pszName(),
  4287. gpGlobals->curtime);
  4288. }
  4289. m_nEventSequence = GetSequence();
  4290. flEventCycle = 0.0f;
  4291. m_flPrevEventCycle = -0.01; // back up to get 0'th frame animations
  4292. }
  4293. // stalled?
  4294. if (flEventCycle == m_flPrevEventCycle)
  4295. return;
  4296. if ( watch )
  4297. {
  4298. Msg( "%i (seq %d cycle %.3f ) evcycle %.3f prevevcycle %.3f (time %.3f)\n",
  4299. gpGlobals->tickcount,
  4300. GetSequence(),
  4301. GetCycle(),
  4302. flEventCycle,
  4303. m_flPrevEventCycle,
  4304. gpGlobals->curtime );
  4305. }
  4306. // check for looping
  4307. BOOL bLooped = false;
  4308. if (flEventCycle <= m_flPrevEventCycle)
  4309. {
  4310. if (m_flPrevEventCycle - flEventCycle > 0.5)
  4311. {
  4312. bLooped = true;
  4313. }
  4314. else
  4315. {
  4316. // things have backed up, which is bad since it'll probably result in a hitch in the animation playback
  4317. // but, don't play events again for the same time slice
  4318. return;
  4319. }
  4320. }
  4321. // This makes sure events that occur at the end of a sequence occur are
  4322. // sent before events that occur at the beginning of a sequence.
  4323. if (bLooped)
  4324. {
  4325. for (int i = 0; i < (int)seqdesc.numevents; i++)
  4326. {
  4327. // ignore all non-client-side events
  4328. if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM )
  4329. {
  4330. if ( !( pevent[i].type & AE_TYPE_CLIENT ) )
  4331. continue;
  4332. }
  4333. else if ( pevent[i].Event_OldSystem() < EVENT_CLIENT ) //Adrian - Support the old event system
  4334. continue;
  4335. if ( pevent[i].cycle <= m_flPrevEventCycle )
  4336. continue;
  4337. if ( watch )
  4338. {
  4339. Msg( "%i FE %i Looped cycle %f, prev %f ev %f (time %.3f)\n",
  4340. gpGlobals->tickcount,
  4341. pevent[i].Event(),
  4342. pevent[i].cycle,
  4343. m_flPrevEventCycle,
  4344. flEventCycle,
  4345. gpGlobals->curtime );
  4346. }
  4347. FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].Event(), pevent[ i ].pszOptions() );
  4348. }
  4349. // Necessary to get the next loop working
  4350. m_flPrevEventCycle = -0.01;
  4351. }
  4352. for (int i = 0; i < (int)seqdesc.numevents; i++)
  4353. {
  4354. if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM )
  4355. {
  4356. if ( !( pevent[i].type & AE_TYPE_CLIENT ) )
  4357. continue;
  4358. }
  4359. else if ( pevent[i].Event_OldSystem() < EVENT_CLIENT ) //Adrian - Support the old event system
  4360. continue;
  4361. if ( (pevent[i].cycle > m_flPrevEventCycle && pevent[i].cycle <= flEventCycle) )
  4362. {
  4363. if ( watch )
  4364. {
  4365. Msg( "%i (seq: %d/%s) FE %i Normal cycle %f, prev %f ev %f (time %.3f) (options %s)\n",
  4366. gpGlobals->tickcount,
  4367. GetSequence(),
  4368. GetSequenceActivityName( GetSequence() ),
  4369. pevent[i].Event(),
  4370. pevent[i].cycle,
  4371. m_flPrevEventCycle,
  4372. flEventCycle,
  4373. gpGlobals->curtime,
  4374. pevent[ i ].pszOptions() );
  4375. }
  4376. FireEvent( GetAbsOrigin(), GetAbsAngles(), pevent[ i ].Event(), pevent[ i ].pszOptions() );
  4377. }
  4378. }
  4379. m_flPrevEventCycle = GetCycle();
  4380. }
  4381. //-----------------------------------------------------------------------------
  4382. // Purpose: Parses a muzzle effect event and sends it out for drawing
  4383. // Input : *options - event parameters in text format
  4384. // isFirstPerson - whether this is coming from an NPC or the player
  4385. // Output : Returns true on success, false on failure.
  4386. //-----------------------------------------------------------------------------
  4387. bool C_BaseAnimating::DispatchMuzzleEffect( const char *options, bool isFirstPerson )
  4388. {
  4389. const char *p = options;
  4390. char token[128];
  4391. int weaponType = 0;
  4392. // Get the first parameter
  4393. p = nexttoken( token, p, ' ' );
  4394. // Find the weapon type
  4395. if ( token )
  4396. {
  4397. //TODO: Parse the type from a list instead
  4398. if ( Q_stricmp( token, "COMBINE" ) == 0 )
  4399. {
  4400. weaponType = MUZZLEFLASH_COMBINE;
  4401. }
  4402. else if ( Q_stricmp( token, "SMG1" ) == 0 )
  4403. {
  4404. weaponType = MUZZLEFLASH_SMG1;
  4405. }
  4406. else if ( Q_stricmp( token, "PISTOL" ) == 0 )
  4407. {
  4408. weaponType = MUZZLEFLASH_PISTOL;
  4409. }
  4410. else if ( Q_stricmp( token, "SHOTGUN" ) == 0 )
  4411. {
  4412. weaponType = MUZZLEFLASH_SHOTGUN;
  4413. }
  4414. else if ( Q_stricmp( token, "357" ) == 0 )
  4415. {
  4416. weaponType = MUZZLEFLASH_357;
  4417. }
  4418. else if ( Q_stricmp( token, "RPG" ) == 0 )
  4419. {
  4420. weaponType = MUZZLEFLASH_RPG;
  4421. }
  4422. else
  4423. {
  4424. //NOTENOTE: This means you specified an invalid muzzleflash type, check your spelling?
  4425. Assert( 0 );
  4426. }
  4427. }
  4428. else
  4429. {
  4430. //NOTENOTE: This means that there wasn't a proper parameter passed into the animevent
  4431. Assert( 0 );
  4432. return false;
  4433. }
  4434. // Get the second parameter
  4435. p = nexttoken( token, p, ' ' );
  4436. int attachmentIndex = -1;
  4437. // Find the attachment name
  4438. if ( token )
  4439. {
  4440. attachmentIndex = LookupAttachment( token );
  4441. // Found an invalid attachment
  4442. if ( attachmentIndex <= 0 )
  4443. {
  4444. //NOTENOTE: This means that the attachment you're trying to use is invalid
  4445. Assert( 0 );
  4446. return false;
  4447. }
  4448. }
  4449. else
  4450. {
  4451. //NOTENOTE: This means that there wasn't a proper parameter passed into the animevent
  4452. Assert( 0 );
  4453. return false;
  4454. }
  4455. // Send it out
  4456. tempents->MuzzleFlash( weaponType, GetRefEHandle(), attachmentIndex, isFirstPerson );
  4457. return true;
  4458. }
  4459. //-----------------------------------------------------------------------------
  4460. //-----------------------------------------------------------------------------
  4461. void MaterialFootstepSound( C_BaseAnimating *pEnt, bool bLeftFoot, float flVolume )
  4462. {
  4463. trace_t tr;
  4464. Vector traceStart;
  4465. QAngle angles;
  4466. int attachment;
  4467. //!!!PERF - These string lookups here aren't the swiftest, but
  4468. // this doesn't get called very frequently unless a lot of NPCs
  4469. // are using this code.
  4470. if( bLeftFoot )
  4471. {
  4472. attachment = pEnt->LookupAttachment( "LeftFoot" );
  4473. }
  4474. else
  4475. {
  4476. attachment = pEnt->LookupAttachment( "RightFoot" );
  4477. }
  4478. if( attachment == -1 )
  4479. {
  4480. // Exit if this NPC doesn't have the proper attachments.
  4481. return;
  4482. }
  4483. pEnt->GetAttachment( attachment, traceStart, angles );
  4484. UTIL_TraceLine( traceStart, traceStart - Vector( 0, 0, 48.0f), MASK_SHOT_HULL, pEnt, COLLISION_GROUP_NONE, &tr );
  4485. if( tr.fraction < 1.0 && tr.m_pEnt )
  4486. {
  4487. surfacedata_t *psurf = physprops->GetSurfaceData( tr.surface.surfaceProps );
  4488. if( psurf )
  4489. {
  4490. EmitSound_t params;
  4491. if( bLeftFoot )
  4492. {
  4493. params.m_pSoundName = physprops->GetString(psurf->sounds.runStepLeft);
  4494. }
  4495. else
  4496. {
  4497. params.m_pSoundName = physprops->GetString(psurf->sounds.runStepRight);
  4498. }
  4499. CPASAttenuationFilter filter( pEnt, params.m_pSoundName );
  4500. params.m_bWarnOnDirectWaveReference = true;
  4501. params.m_flVolume = flVolume;
  4502. pEnt->EmitSound( filter, pEnt->entindex(), params );
  4503. }
  4504. }
  4505. }
  4506. //-----------------------------------------------------------------------------
  4507. // Purpose: Creates a particle effect and ejects a single shell. If
  4508. // the effect is already active, it just restarts it to eject another shell.
  4509. //-----------------------------------------------------------------------------
  4510. void C_BaseAnimating::EjectParticleBrass( const char *pEffectName, const int iAttachment )
  4511. {
  4512. if ( cl_ejectbrass.GetBool() == false )
  4513. return;
  4514. // TODO: Can we change the attachment for an active particle system?
  4515. if ( !m_ejectBrassEffect || m_iEjectBrassAttachment != iAttachment )
  4516. {
  4517. m_iEjectBrassAttachment = iAttachment;
  4518. m_ejectBrassEffect = ParticleProp()->Create( pEffectName, PATTACH_POINT_FOLLOW, iAttachment );
  4519. }
  4520. else
  4521. {
  4522. m_ejectBrassEffect->Restart();
  4523. }
  4524. }
  4525. //-----------------------------------------------------------------------------
  4526. // Purpose:
  4527. // Input : *origin -
  4528. // *angles -
  4529. // event -
  4530. // *options -
  4531. // numAttachments -
  4532. // attachments[] -
  4533. //-----------------------------------------------------------------------------
  4534. void C_BaseAnimating::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  4535. {
  4536. Vector attachOrigin;
  4537. QAngle attachAngles;
  4538. switch( event )
  4539. {
  4540. case AE_CL_CREATE_PARTICLE_EFFECT:
  4541. {
  4542. int iAttachment = -1;
  4543. int iAttachType = PATTACH_ABSORIGIN_FOLLOW;
  4544. int iAttachmentCP1 = -1;
  4545. int iAttachTypeCP1 = PATTACH_ABSORIGIN_FOLLOW;
  4546. char token[256];
  4547. char szParticleEffect[256];
  4548. // Get the particle effect name
  4549. const char *p = options;
  4550. p = nexttoken(token, p, ' ');
  4551. if ( token )
  4552. {
  4553. const char* mtoken = ModifyEventParticles( token );
  4554. Q_strncpy( szParticleEffect, mtoken, sizeof(szParticleEffect) );
  4555. }
  4556. // Get the attachment type
  4557. p = nexttoken(token, p, ' ');
  4558. if ( token )
  4559. {
  4560. iAttachType = GetAttachTypeFromString( token );
  4561. if ( iAttachType == -1 )
  4562. {
  4563. Warning("Invalid attach type specified for particle effect anim event. Trying to spawn effect '%s' with attach type of '%s'\n", szParticleEffect, token );
  4564. return;
  4565. }
  4566. }
  4567. // Get the attachment point index
  4568. p = nexttoken(token, p, ' ');
  4569. if ( token )
  4570. {
  4571. iAttachment = atoi(token);
  4572. // See if we can find any attachment points matching the name
  4573. if ( token[0] != '0' && iAttachment == 0 )
  4574. {
  4575. iAttachment = LookupAttachment( token );
  4576. if ( iAttachment == -1 )
  4577. {
  4578. Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token );
  4579. return;
  4580. }
  4581. }
  4582. }
  4583. // Spawn the particle effect
  4584. CNewParticleEffect *pEffect = ParticleProp()->Create( szParticleEffect, (ParticleAttachment_t)iAttachType, iAttachment );
  4585. // Get the attachment type for CP1
  4586. p = nexttoken(token, p, ' ');
  4587. if ( !p )
  4588. return;
  4589. if ( token )
  4590. {
  4591. iAttachTypeCP1 = GetAttachTypeFromString( token );
  4592. if ( iAttachTypeCP1 == -1 )
  4593. {
  4594. Warning("Invalid attach type specified for particle effect anim event. Trying to spawn effect '%s' with attach type of '%s'\n", szParticleEffect, token );
  4595. return;
  4596. }
  4597. }
  4598. // Get the attachment point index
  4599. p = nexttoken(token, p, ' ');
  4600. if ( token )
  4601. {
  4602. iAttachmentCP1 = atoi(token);
  4603. // See if we can find any attachment points matching the name
  4604. if ( token[0] != '0' && iAttachmentCP1 == 0 )
  4605. {
  4606. iAttachmentCP1 = LookupAttachment( token );
  4607. if ( iAttachmentCP1 == -1 )
  4608. {
  4609. Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token );
  4610. return;
  4611. }
  4612. }
  4613. ParticleProp()->AddControlPoint( pEffect, 1, this, (ParticleAttachment_t)iAttachTypeCP1, token );
  4614. }
  4615. }
  4616. break;
  4617. case AE_CL_STOP_PARTICLE_EFFECT:
  4618. {
  4619. char token[256];
  4620. char szParticleEffect[256];
  4621. // Get the particle effect name
  4622. const char *p = options;
  4623. p = nexttoken(token, p, ' ');
  4624. if ( token )
  4625. {
  4626. Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) );
  4627. }
  4628. // Get the attachment point index
  4629. p = nexttoken(token, p, ' ');
  4630. bool bStopInstantly = ( token && !Q_stricmp( token, "instantly" ) );
  4631. ParticleProp()->StopParticlesNamed( szParticleEffect, bStopInstantly );
  4632. }
  4633. break;
  4634. case AE_CL_ADD_PARTICLE_EFFECT_CP:
  4635. {
  4636. int iControlPoint = 1;
  4637. int iAttachment = -1;
  4638. int iAttachType = PATTACH_ABSORIGIN_FOLLOW;
  4639. int iEffectIndex = -1;
  4640. char token[256];
  4641. char szParticleEffect[256];
  4642. // Get the particle effect name
  4643. const char *p = options;
  4644. p = nexttoken(token, p, ' ');
  4645. if ( token )
  4646. {
  4647. Q_strncpy( szParticleEffect, token, sizeof(szParticleEffect) );
  4648. }
  4649. // Get the control point number
  4650. p = nexttoken(token, p, ' ');
  4651. if ( token )
  4652. {
  4653. iControlPoint = atoi( token );
  4654. }
  4655. // Get the attachment type
  4656. p = nexttoken(token, p, ' ');
  4657. if ( token )
  4658. {
  4659. iAttachType = GetAttachTypeFromString( token );
  4660. if ( iAttachType == -1 )
  4661. {
  4662. Warning("Invalid attach type specified for particle effect anim event. Trying to spawn effect '%s' with attach type of '%s'\n", szParticleEffect, token );
  4663. return;
  4664. }
  4665. }
  4666. // Get the attachment point index
  4667. p = nexttoken(token, p, ' ');
  4668. if ( token )
  4669. {
  4670. iAttachment = atoi(token);
  4671. // See if we can find any attachment points matching the name
  4672. if ( token[0] != '0' && iAttachment == 0 )
  4673. {
  4674. iAttachment = LookupAttachment( token );
  4675. if ( iAttachment == -1 )
  4676. {
  4677. Warning("Failed to find attachment point specified for particle effect anim event. Trying to spawn effect '%s' on attachment named '%s'\n", szParticleEffect, token );
  4678. return;
  4679. }
  4680. }
  4681. }
  4682. iEffectIndex = ParticleProp()->FindEffect( szParticleEffect );
  4683. if ( iEffectIndex == -1 )
  4684. {
  4685. Warning("Failed to find specified particle effect. Trying to add CP to '%s' on attachment named '%s'\n", szParticleEffect, token );
  4686. return;
  4687. }
  4688. ParticleProp()->AddControlPoint( iEffectIndex, iControlPoint, this, (ParticleAttachment_t)iAttachType, iAttachment );
  4689. }
  4690. break;
  4691. case AE_CL_PLAYSOUND:
  4692. {
  4693. if ( m_bSuppressAnimSounds )
  4694. return;
  4695. CLocalPlayerFilter filter;
  4696. if ( m_Attachments.Count() > 0)
  4697. {
  4698. GetAttachment( 1, attachOrigin, attachAngles );
  4699. EmitSound( filter, GetSoundSourceIndex(), options, &attachOrigin );
  4700. }
  4701. else
  4702. {
  4703. EmitSound( filter, GetSoundSourceIndex(), options, &GetAbsOrigin() );
  4704. }
  4705. }
  4706. break;
  4707. case AE_CL_STOPSOUND:
  4708. {
  4709. StopSound( GetSoundSourceIndex(), options );
  4710. }
  4711. break;
  4712. case CL_EVENT_FOOTSTEP_LEFT:
  4713. {
  4714. char pSoundName[256];
  4715. if ( !options || !options[0] )
  4716. {
  4717. options = "NPC_CombineS";
  4718. }
  4719. Vector vel;
  4720. EstimateAbsVelocity( vel );
  4721. // If he's moving fast enough, play the run sound
  4722. if ( vel.Length2DSqr() > RUN_SPEED_ESTIMATE_SQR )
  4723. {
  4724. Q_snprintf( pSoundName, 256, "%s.RunFootstepLeft", options );
  4725. }
  4726. else
  4727. {
  4728. Q_snprintf( pSoundName, 256, "%s.FootstepLeft", options );
  4729. }
  4730. EmitSound( pSoundName );
  4731. }
  4732. break;
  4733. case CL_EVENT_FOOTSTEP_RIGHT:
  4734. {
  4735. char pSoundName[256];
  4736. if ( !options || !options[0] )
  4737. {
  4738. options = "NPC_CombineS";
  4739. }
  4740. Vector vel;
  4741. EstimateAbsVelocity( vel );
  4742. // If he's moving fast enough, play the run sound
  4743. if ( vel.Length2DSqr() > RUN_SPEED_ESTIMATE_SQR )
  4744. {
  4745. Q_snprintf( pSoundName, 256, "%s.RunFootstepRight", options );
  4746. }
  4747. else
  4748. {
  4749. Q_snprintf( pSoundName, 256, "%s.FootstepRight", options );
  4750. }
  4751. EmitSound( pSoundName );
  4752. }
  4753. break;
  4754. case CL_EVENT_MFOOTSTEP_LEFT:
  4755. {
  4756. MaterialFootstepSound( this, true, VOL_NORM * 0.5f );
  4757. }
  4758. break;
  4759. case CL_EVENT_MFOOTSTEP_RIGHT:
  4760. {
  4761. MaterialFootstepSound( this, false, VOL_NORM * 0.5f );
  4762. }
  4763. break;
  4764. case CL_EVENT_MFOOTSTEP_LEFT_LOUD:
  4765. {
  4766. MaterialFootstepSound( this, true, VOL_NORM );
  4767. }
  4768. break;
  4769. case CL_EVENT_MFOOTSTEP_RIGHT_LOUD:
  4770. {
  4771. MaterialFootstepSound( this, false, VOL_NORM );
  4772. }
  4773. break;
  4774. // Eject brass
  4775. case CL_EVENT_EJECTBRASS1:
  4776. if ( m_Attachments.Count() > 0 )
  4777. {
  4778. DevWarning( "Unhandled eject brass animevent\n" );
  4779. }
  4780. break;
  4781. case AE_MUZZLEFLASH:
  4782. {
  4783. // Send out the effect for a player
  4784. DispatchMuzzleEffect( options, true );
  4785. break;
  4786. }
  4787. case AE_NPC_MUZZLEFLASH:
  4788. {
  4789. // Send out the effect for an NPC
  4790. DispatchMuzzleEffect( options, false );
  4791. break;
  4792. }
  4793. // OBSOLETE EVENTS. REPLACED BY NEWER SYSTEMS.
  4794. // See below in FireObsoleteEvent() for comments on what to use instead.
  4795. case AE_CLIENT_EFFECT_ATTACH:
  4796. case CL_EVENT_DISPATCHEFFECT0:
  4797. case CL_EVENT_DISPATCHEFFECT1:
  4798. case CL_EVENT_DISPATCHEFFECT2:
  4799. case CL_EVENT_DISPATCHEFFECT3:
  4800. case CL_EVENT_DISPATCHEFFECT4:
  4801. case CL_EVENT_DISPATCHEFFECT5:
  4802. case CL_EVENT_DISPATCHEFFECT6:
  4803. case CL_EVENT_DISPATCHEFFECT7:
  4804. case CL_EVENT_DISPATCHEFFECT8:
  4805. case CL_EVENT_DISPATCHEFFECT9:
  4806. case CL_EVENT_MUZZLEFLASH0:
  4807. case CL_EVENT_MUZZLEFLASH1:
  4808. case CL_EVENT_MUZZLEFLASH2:
  4809. case CL_EVENT_MUZZLEFLASH3:
  4810. case CL_EVENT_NPC_MUZZLEFLASH0:
  4811. case CL_EVENT_NPC_MUZZLEFLASH1:
  4812. case CL_EVENT_NPC_MUZZLEFLASH2:
  4813. case CL_EVENT_NPC_MUZZLEFLASH3:
  4814. case CL_EVENT_SPARK0:
  4815. case CL_EVENT_SOUND:
  4816. FireObsoleteEvent( origin, angles, event, options );
  4817. break;
  4818. case AE_CL_ENABLE_BODYGROUP:
  4819. {
  4820. int index = FindBodygroupByName( options );
  4821. if ( index >= 0 )
  4822. {
  4823. SetBodygroup( index, 1 );
  4824. }
  4825. }
  4826. break;
  4827. case AE_CL_DISABLE_BODYGROUP:
  4828. {
  4829. int index = FindBodygroupByName( options );
  4830. if ( index >= 0 )
  4831. {
  4832. SetBodygroup( index, 0 );
  4833. }
  4834. }
  4835. break;
  4836. case AE_CL_BODYGROUP_SET_VALUE:
  4837. {
  4838. char szBodygroupName[256];
  4839. int value = 0;
  4840. char token[256];
  4841. const char *p = options;
  4842. // Bodygroup Name
  4843. p = nexttoken(token, p, ' ');
  4844. if ( token )
  4845. {
  4846. Q_strncpy( szBodygroupName, token, sizeof(szBodygroupName) );
  4847. }
  4848. // Get the desired value
  4849. p = nexttoken(token, p, ' ');
  4850. if ( token )
  4851. {
  4852. value = atoi( token );
  4853. }
  4854. int index = FindBodygroupByName( szBodygroupName );
  4855. if ( index >= 0 )
  4856. {
  4857. SetBodygroup( index, value );
  4858. }
  4859. }
  4860. break;
  4861. // case AE_BEGIN_TAUNT_LOOP:
  4862. // {
  4863. // if ( IsViewModel() )
  4864. // {
  4865. // C_BaseViewModel *pViewModel = assert_cast< C_BaseViewModel* >( this );
  4866. // C_BaseCombatWeapon *pWeapon = pViewModel->GetOwningWeapon();
  4867. //
  4868. // if ( pWeapon )
  4869. // {
  4870. // C_BasePlayer *pPlayer = dynamic_cast< C_BasePlayer* >( pWeapon->GetOwner() );
  4871. // if ( pPlayer && pPlayer->IsHoldingTaunt() )
  4872. // {
  4873. // float flCycle = GetCycle();
  4874. // pViewModel->SetCycle( V_atof( options ) );
  4875. // pViewModel->m_fCycleOffset += ( GetCycle() - flCycle );
  4876. // }
  4877. // }
  4878. // }
  4879. // }
  4880. // break;
  4881. case AE_BEGIN_TAUNT_LOOP:
  4882. {
  4883. if ( IsViewModel() )
  4884. {
  4885. C_BaseViewModel *pViewModel = assert_cast< C_BaseViewModel* >( this );
  4886. C_BaseCombatWeapon *pWeapon = pViewModel->GetOwningWeapon();
  4887. if ( pWeapon )
  4888. {
  4889. C_BasePlayer *pPlayer = dynamic_cast< C_BasePlayer* >( pWeapon->GetOwner() );
  4890. if ( pPlayer && pPlayer->IsHoldingLookAtWeapon() )
  4891. {
  4892. float flCycle = GetCycle();
  4893. pViewModel->SetCycle( V_atof( options ) );
  4894. pViewModel->m_fCycleOffset += ( GetCycle() - flCycle );
  4895. }
  4896. }
  4897. }
  4898. }
  4899. break;
  4900. default:
  4901. break;
  4902. }
  4903. }
  4904. //-----------------------------------------------------------------------------
  4905. // Purpose: These events are all obsolete events, left here to support old games.
  4906. // Their systems have all been replaced with better ones.
  4907. //-----------------------------------------------------------------------------
  4908. void C_BaseAnimating::FireObsoleteEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  4909. {
  4910. Vector attachOrigin;
  4911. QAngle attachAngles;
  4912. switch( event )
  4913. {
  4914. // Obsolete. Use the AE_CL_CREATE_PARTICLE_EFFECT event instead, which uses the artist driven particle system & editor.
  4915. case AE_CLIENT_EFFECT_ATTACH:
  4916. {
  4917. int iAttachment = -1;
  4918. int iParam = 0;
  4919. char token[128];
  4920. char effectFunc[128];
  4921. const char *p = options;
  4922. p = nexttoken(token, p, ' ');
  4923. if( token )
  4924. {
  4925. Q_strncpy( effectFunc, token, sizeof(effectFunc) );
  4926. }
  4927. p = nexttoken(token, p, ' ');
  4928. if( token )
  4929. {
  4930. if ( V_isdigit( *token ) )
  4931. {
  4932. iAttachment = atoi(token);
  4933. }
  4934. else
  4935. {
  4936. iAttachment = LookupAttachment( token );
  4937. }
  4938. }
  4939. p = nexttoken(token, p, ' ');
  4940. if( token )
  4941. {
  4942. iParam = atoi(token);
  4943. }
  4944. if ( iAttachment != -1 && m_Attachments.Count() >= iAttachment )
  4945. {
  4946. GetAttachment( iAttachment, attachOrigin, attachAngles );
  4947. // Fill out the generic data
  4948. CEffectData data;
  4949. data.m_vOrigin = attachOrigin;
  4950. data.m_vAngles = attachAngles;
  4951. AngleVectors( attachAngles, &data.m_vNormal );
  4952. data.m_hEntity = GetRefEHandle();
  4953. data.m_nAttachmentIndex = iAttachment + 1;
  4954. data.m_fFlags = iParam;
  4955. DispatchEffect( effectFunc, data );
  4956. }
  4957. }
  4958. break;
  4959. // Obsolete. Use the AE_CL_CREATE_PARTICLE_EFFECT event instead, which uses the artist driven particle system & editor.
  4960. case CL_EVENT_DISPATCHEFFECT0:
  4961. case CL_EVENT_DISPATCHEFFECT1:
  4962. case CL_EVENT_DISPATCHEFFECT2:
  4963. case CL_EVENT_DISPATCHEFFECT3:
  4964. case CL_EVENT_DISPATCHEFFECT4:
  4965. case CL_EVENT_DISPATCHEFFECT5:
  4966. case CL_EVENT_DISPATCHEFFECT6:
  4967. case CL_EVENT_DISPATCHEFFECT7:
  4968. case CL_EVENT_DISPATCHEFFECT8:
  4969. case CL_EVENT_DISPATCHEFFECT9:
  4970. {
  4971. int iAttachment = -1;
  4972. // First person muzzle flashes
  4973. switch (event)
  4974. {
  4975. case CL_EVENT_DISPATCHEFFECT0:
  4976. iAttachment = 0;
  4977. break;
  4978. case CL_EVENT_DISPATCHEFFECT1:
  4979. iAttachment = 1;
  4980. break;
  4981. case CL_EVENT_DISPATCHEFFECT2:
  4982. iAttachment = 2;
  4983. break;
  4984. case CL_EVENT_DISPATCHEFFECT3:
  4985. iAttachment = 3;
  4986. break;
  4987. case CL_EVENT_DISPATCHEFFECT4:
  4988. iAttachment = 4;
  4989. break;
  4990. case CL_EVENT_DISPATCHEFFECT5:
  4991. iAttachment = 5;
  4992. break;
  4993. case CL_EVENT_DISPATCHEFFECT6:
  4994. iAttachment = 6;
  4995. break;
  4996. case CL_EVENT_DISPATCHEFFECT7:
  4997. iAttachment = 7;
  4998. break;
  4999. case CL_EVENT_DISPATCHEFFECT8:
  5000. iAttachment = 8;
  5001. break;
  5002. case CL_EVENT_DISPATCHEFFECT9:
  5003. iAttachment = 9;
  5004. break;
  5005. }
  5006. if ( iAttachment != -1 && m_Attachments.Count() > iAttachment )
  5007. {
  5008. GetAttachment( iAttachment+1, attachOrigin, attachAngles );
  5009. // Fill out the generic data
  5010. CEffectData data;
  5011. data.m_vOrigin = attachOrigin;
  5012. data.m_vAngles = attachAngles;
  5013. AngleVectors( attachAngles, &data.m_vNormal );
  5014. data.m_hEntity = GetRefEHandle();
  5015. data.m_nAttachmentIndex = iAttachment + 1;
  5016. DispatchEffect( options, data );
  5017. }
  5018. }
  5019. break;
  5020. // Obsolete. Use the AE_MUZZLEFLASH / AE_NPC_MUZZLEFLASH events instead.
  5021. case CL_EVENT_MUZZLEFLASH0:
  5022. case CL_EVENT_MUZZLEFLASH1:
  5023. case CL_EVENT_MUZZLEFLASH2:
  5024. case CL_EVENT_MUZZLEFLASH3:
  5025. case CL_EVENT_NPC_MUZZLEFLASH0:
  5026. case CL_EVENT_NPC_MUZZLEFLASH1:
  5027. case CL_EVENT_NPC_MUZZLEFLASH2:
  5028. case CL_EVENT_NPC_MUZZLEFLASH3:
  5029. {
  5030. int iAttachment = -1;
  5031. bool bFirstPerson = true;
  5032. // First person muzzle flashes
  5033. switch (event)
  5034. {
  5035. case CL_EVENT_MUZZLEFLASH0:
  5036. iAttachment = 0;
  5037. break;
  5038. case CL_EVENT_MUZZLEFLASH1:
  5039. iAttachment = 1;
  5040. break;
  5041. case CL_EVENT_MUZZLEFLASH2:
  5042. iAttachment = 2;
  5043. break;
  5044. case CL_EVENT_MUZZLEFLASH3:
  5045. iAttachment = 3;
  5046. break;
  5047. // Third person muzzle flashes
  5048. case CL_EVENT_NPC_MUZZLEFLASH0:
  5049. iAttachment = 0;
  5050. bFirstPerson = false;
  5051. break;
  5052. case CL_EVENT_NPC_MUZZLEFLASH1:
  5053. iAttachment = 1;
  5054. bFirstPerson = false;
  5055. break;
  5056. case CL_EVENT_NPC_MUZZLEFLASH2:
  5057. iAttachment = 2;
  5058. bFirstPerson = false;
  5059. break;
  5060. case CL_EVENT_NPC_MUZZLEFLASH3:
  5061. iAttachment = 3;
  5062. bFirstPerson = false;
  5063. break;
  5064. }
  5065. if ( iAttachment != -1 && m_Attachments.Count() > iAttachment )
  5066. {
  5067. GetAttachment( iAttachment+1, attachOrigin, attachAngles );
  5068. int entId = render->GetViewEntity();
  5069. ClientEntityHandle_t hEntity = ClientEntityList().EntIndexToHandle( entId );
  5070. tempents->MuzzleFlash( attachOrigin, attachAngles, atoi( options ), hEntity, bFirstPerson );
  5071. }
  5072. }
  5073. break;
  5074. // Obsolete: Use the AE_CL_CREATE_PARTICLE_EFFECT event instead, which uses the artist driven particle system & editor.
  5075. case CL_EVENT_SPARK0:
  5076. {
  5077. Vector vecForward;
  5078. GetAttachment( 1, attachOrigin, attachAngles );
  5079. AngleVectors( attachAngles, &vecForward );
  5080. g_pEffects->Sparks( attachOrigin, atoi( options ), 1, &vecForward );
  5081. }
  5082. break;
  5083. // Obsolete: Use the AE_CL_PLAYSOUND event instead, which doesn't rely on a magic number in the .qc
  5084. case CL_EVENT_SOUND:
  5085. {
  5086. CLocalPlayerFilter filter;
  5087. if ( m_Attachments.Count() > 0)
  5088. {
  5089. GetAttachment( 1, attachOrigin, attachAngles );
  5090. EmitSound( filter, GetSoundSourceIndex(), options, &attachOrigin );
  5091. }
  5092. else
  5093. {
  5094. EmitSound( filter, GetSoundSourceIndex(), options );
  5095. }
  5096. }
  5097. break;
  5098. default:
  5099. break;
  5100. }
  5101. }
  5102. //-----------------------------------------------------------------------------
  5103. // Purpose:
  5104. //-----------------------------------------------------------------------------
  5105. bool C_BaseAnimating::IsSelfAnimating()
  5106. {
  5107. if ( m_bClientSideAnimation )
  5108. return true;
  5109. // Yes, we use animtime.
  5110. int iMoveType = GetMoveType();
  5111. if ( iMoveType != MOVETYPE_STEP &&
  5112. iMoveType != MOVETYPE_NONE &&
  5113. iMoveType != MOVETYPE_WALK &&
  5114. iMoveType != MOVETYPE_FLY &&
  5115. iMoveType != MOVETYPE_FLYGRAVITY )
  5116. {
  5117. return true;
  5118. }
  5119. return false;
  5120. }
  5121. //-----------------------------------------------------------------------------
  5122. // Purpose: Called by networking code when an entity is new to the PVS or comes down with the EF_NOINTERP flag set.
  5123. // The position history data is flushed out right after this call, so we need to store off the current data
  5124. // in the latched fields so we try to interpolate
  5125. // Input : *ent -
  5126. // full_reset -
  5127. //-----------------------------------------------------------------------------
  5128. void C_BaseAnimating::ResetLatched( void )
  5129. {
  5130. // Reset the IK
  5131. if ( m_pIk )
  5132. {
  5133. delete m_pIk;
  5134. m_pIk = NULL;
  5135. }
  5136. BaseClass::ResetLatched();
  5137. }
  5138. //-----------------------------------------------------------------------------
  5139. // Purpose:
  5140. // Output : Returns true on success, false on failure.
  5141. //-----------------------------------------------------------------------------
  5142. bool C_BaseAnimating::Interpolate( float flCurrentTime )
  5143. {
  5144. // ragdolls don't need interpolation
  5145. if ( m_pRagdoll )
  5146. return true;
  5147. VPROF( "C_BaseAnimating::Interpolate" );
  5148. Vector oldOrigin;
  5149. QAngle oldAngles;
  5150. float flOldCycle = GetCycle();
  5151. int nChangeFlags = 0;
  5152. if ( !m_bClientSideAnimation )
  5153. m_iv_flCycle.SetLooping( IsSequenceLooping( GetSequence() ) );
  5154. int bNoMoreChanges;
  5155. int retVal = BaseInterpolatePart1( flCurrentTime, oldOrigin, oldAngles, bNoMoreChanges );
  5156. if ( retVal == INTERPOLATE_STOP )
  5157. {
  5158. if ( bNoMoreChanges )
  5159. RemoveFromEntityList(ENTITY_LIST_INTERPOLATE);
  5160. return true;
  5161. }
  5162. // Did cycle change?
  5163. if( GetCycle() != flOldCycle )
  5164. nChangeFlags |= ANIMATION_CHANGED;
  5165. if ( bNoMoreChanges )
  5166. RemoveFromEntityList(ENTITY_LIST_INTERPOLATE);
  5167. BaseInterpolatePart2( oldOrigin, oldAngles, nChangeFlags );
  5168. return true;
  5169. }
  5170. //-----------------------------------------------------------------------------
  5171. // returns true if we're currently being ragdolled
  5172. //-----------------------------------------------------------------------------
  5173. bool C_BaseAnimating::IsRagdoll() const
  5174. {
  5175. return m_pRagdoll && m_bClientSideRagdoll;
  5176. }
  5177. Vector C_BaseAnimating::GetThirdPersonViewPosition( void )
  5178. {
  5179. return GetRenderOrigin() + GetViewOffset();
  5180. }
  5181. //-----------------------------------------------------------------------------
  5182. // implements these so ragdolls can handle frustum culling & leaf visibility
  5183. //-----------------------------------------------------------------------------
  5184. void C_BaseAnimating::GetRenderBounds( Vector& theMins, Vector& theMaxs )
  5185. {
  5186. if ( IsRagdoll() )
  5187. {
  5188. m_pRagdoll->GetRagdollBounds( theMins, theMaxs );
  5189. Vector vecBloat( 5.0f, 5.0f, 5.0f );
  5190. theMins -= vecBloat;
  5191. theMaxs += vecBloat;
  5192. }
  5193. else if ( GetModel() )
  5194. {
  5195. MDLCACHE_CRITICAL_SECTION();
  5196. CStudioHdr *pStudioHdr = GetModelPtr();
  5197. if ( !pStudioHdr|| !pStudioHdr->SequencesAvailable() || GetSequence() == -1 )
  5198. {
  5199. theMins = vec3_origin;
  5200. theMaxs = vec3_origin;
  5201. return;
  5202. }
  5203. if (!VectorCompare( vec3_origin, pStudioHdr->view_bbmin() ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax() ))
  5204. {
  5205. // clipping bounding box
  5206. VectorCopy ( pStudioHdr->view_bbmin(), theMins);
  5207. VectorCopy ( pStudioHdr->view_bbmax(), theMaxs);
  5208. }
  5209. else
  5210. {
  5211. // movement bounding box
  5212. VectorCopy ( pStudioHdr->hull_min(), theMins);
  5213. VectorCopy ( pStudioHdr->hull_max(), theMaxs);
  5214. }
  5215. mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( GetSequence() );
  5216. VectorMin( seqdesc.bbmin, theMins, theMins );
  5217. VectorMax( seqdesc.bbmax, theMaxs, theMaxs );
  5218. }
  5219. else
  5220. {
  5221. theMins = vec3_origin;
  5222. theMaxs = vec3_origin;
  5223. }
  5224. // Scale this up depending on if our model is currently scaling
  5225. const float flScale = GetModelHierarchyScale();
  5226. theMaxs *= flScale;
  5227. theMins *= flScale;
  5228. }
  5229. //-----------------------------------------------------------------------------
  5230. // implements these so ragdolls can handle frustum culling & leaf visibility
  5231. //-----------------------------------------------------------------------------
  5232. const Vector& C_BaseAnimating::GetRenderOrigin( void )
  5233. {
  5234. #ifdef DEMOPOLISH_ENABLED
  5235. if ( DemoPolish_ShouldReplaceRoot( entindex() ) )
  5236. {
  5237. return DemoPolish_GetController().GetRenderOrigin( entindex() );
  5238. }
  5239. else
  5240. #endif
  5241. if ( IsRagdoll() )
  5242. {
  5243. return m_pRagdoll->GetRagdollOrigin();
  5244. }
  5245. if ( m_vecRenderOriginOverride != vec3_invalid )
  5246. {
  5247. return m_vecRenderOriginOverride;
  5248. }
  5249. return BaseClass::GetRenderOrigin();
  5250. }
  5251. const QAngle& C_BaseAnimating::GetRenderAngles( void )
  5252. {
  5253. #ifdef DEMOPOLISH_ENABLED
  5254. if ( DemoPolish_ShouldReplaceRoot( entindex() ) )
  5255. {
  5256. return DemoPolish_GetController().GetRenderAngles( entindex() );
  5257. }
  5258. else
  5259. #endif
  5260. if ( IsRagdoll() )
  5261. {
  5262. return vec3_angle;
  5263. }
  5264. return BaseClass::GetRenderAngles();
  5265. }
  5266. void C_BaseAnimating::RagdollMoved( void )
  5267. {
  5268. SetAbsOrigin( m_pRagdoll->GetRagdollOrigin() );
  5269. SetAbsAngles( vec3_angle );
  5270. Vector mins, maxs;
  5271. m_pRagdoll->GetRagdollBounds( mins, maxs );
  5272. SetCollisionBounds( mins, maxs );
  5273. // If the ragdoll moves, its render-to-texture shadow is dirty
  5274. InvalidatePhysicsRecursive( BOUNDS_CHANGED );
  5275. }
  5276. //-----------------------------------------------------------------------------
  5277. // Purpose: My physics object has been updated, react or extract data
  5278. //-----------------------------------------------------------------------------
  5279. void C_BaseAnimating::VPhysicsUpdate( IPhysicsObject *pPhysics )
  5280. {
  5281. // FIXME: Should make sure the physics objects being passed in
  5282. // is the ragdoll physics object, but I think it's pretty safe not to check
  5283. if (IsRagdoll())
  5284. {
  5285. m_pRagdoll->VPhysicsUpdate( pPhysics );
  5286. RagdollMoved();
  5287. return;
  5288. }
  5289. BaseClass::VPhysicsUpdate( pPhysics );
  5290. }
  5291. //-----------------------------------------------------------------------------
  5292. // Purpose:
  5293. // Input : updateType -
  5294. //-----------------------------------------------------------------------------
  5295. void C_BaseAnimating::PreDataUpdate( DataUpdateType_t updateType )
  5296. {
  5297. m_flOldCycle = GetCycle();
  5298. m_nOldSequence = GetSequence();
  5299. m_flOldModelScale = GetModelHierarchyScale();
  5300. int i;
  5301. for ( i=0;i<MAXSTUDIOBONECTRLS;i++ )
  5302. {
  5303. m_flOldEncodedController[i] = m_flEncodedController[i];
  5304. }
  5305. for ( i=0;i<MAXSTUDIOPOSEPARAM;i++ )
  5306. {
  5307. m_flOldPoseParameters[i] = m_flPoseParameter[i];
  5308. }
  5309. BaseClass::PreDataUpdate( updateType );
  5310. }
  5311. void C_BaseAnimating::NotifyShouldTransmit( ShouldTransmitState_t state )
  5312. {
  5313. BaseClass::NotifyShouldTransmit( state );
  5314. if ( state == SHOULDTRANSMIT_START )
  5315. {
  5316. // If he's been firing a bunch, then he comes back into the PVS, his muzzle flash
  5317. // will show up even if he isn't firing now.
  5318. DisableMuzzleFlash();
  5319. m_nPrevResetEventsParity = m_nResetEventsParity;
  5320. m_nEventSequence = GetSequence();
  5321. }
  5322. }
  5323. //-----------------------------------------------------------------------------
  5324. // Purpose:
  5325. // Input : updateType -
  5326. //-----------------------------------------------------------------------------
  5327. void C_BaseAnimating::PostDataUpdate( DataUpdateType_t updateType )
  5328. {
  5329. BaseClass::PostDataUpdate( updateType );
  5330. if ( m_bClientSideAnimation )
  5331. {
  5332. SetCycle( m_flOldCycle );
  5333. AddToClientSideAnimationList();
  5334. }
  5335. else
  5336. {
  5337. RemoveFromClientSideAnimationList();
  5338. }
  5339. bool bBoneControllersChanged = false;
  5340. int i;
  5341. for ( i=0;i<MAXSTUDIOBONECTRLS && !bBoneControllersChanged;i++ )
  5342. {
  5343. if ( m_flOldEncodedController[i] != m_flEncodedController[i] )
  5344. {
  5345. bBoneControllersChanged = true;
  5346. }
  5347. }
  5348. bool bPoseParametersChanged = false;
  5349. for ( i=0;i<MAXSTUDIOPOSEPARAM && !bPoseParametersChanged;i++ )
  5350. {
  5351. if ( m_flOldPoseParameters[i] != m_flPoseParameter[i] )
  5352. {
  5353. bPoseParametersChanged = true;
  5354. }
  5355. }
  5356. // Cycle change? Then re-render
  5357. bool bAnimationChanged = m_flOldCycle != GetCycle() || bBoneControllersChanged || bPoseParametersChanged;
  5358. bool bSequenceChanged = m_nOldSequence != GetSequence();
  5359. bool bScaleChanged = ( m_flOldModelScale != GetModelHierarchyScale() );
  5360. if ( bAnimationChanged || bSequenceChanged || bScaleChanged )
  5361. {
  5362. int nFlags = bAnimationChanged ? ANIMATION_CHANGED : 0;
  5363. if ( bSequenceChanged )
  5364. {
  5365. nFlags |= BOUNDS_CHANGED | SEQUENCE_CHANGED;
  5366. }
  5367. if ( bScaleChanged )
  5368. {
  5369. nFlags |= BOUNDS_CHANGED;
  5370. }
  5371. InvalidatePhysicsRecursive( nFlags );
  5372. if ( IsViewModel() )
  5373. {
  5374. C_BaseViewModel *pViewModel = assert_cast< C_BaseViewModel* >( this );
  5375. pViewModel->m_fCycleOffset = 0.0f;
  5376. }
  5377. }
  5378. if ( bAnimationChanged || bSequenceChanged )
  5379. {
  5380. if ( m_bClientSideAnimation )
  5381. {
  5382. ClientSideAnimationChanged();
  5383. }
  5384. }
  5385. // reset prev cycle if new sequence
  5386. if (m_nNewSequenceParity != m_nPrevNewSequenceParity)
  5387. {
  5388. // It's important not to call Reset() on a static prop, because if we call
  5389. // Reset(), then the entity will stay in the interpolated entities list
  5390. // forever, wasting CPU.
  5391. MDLCACHE_CRITICAL_SECTION();
  5392. CStudioHdr *hdr = GetModelPtr();
  5393. if ( hdr && !( hdr->flags() & STUDIOHDR_FLAGS_STATIC_PROP ) )
  5394. {
  5395. m_iv_flCycle.Reset( gpGlobals->curtime );
  5396. }
  5397. }
  5398. }
  5399. //-----------------------------------------------------------------------------
  5400. // Purpose:
  5401. // Input : bnewentity -
  5402. //-----------------------------------------------------------------------------
  5403. void C_BaseAnimating::OnPreDataChanged( DataUpdateType_t updateType )
  5404. {
  5405. BaseClass::OnPreDataChanged( updateType );
  5406. m_nPrevBody = GetBody();
  5407. m_nPrevSkin = GetSkin();
  5408. m_bLastClientSideFrameReset = m_bClientSideFrameReset;
  5409. }
  5410. void C_BaseAnimating::ForceSetupBonesAtTime( matrix3x4a_t *pBonesOut, float flTime )
  5411. {
  5412. // blow the cached prev bones
  5413. InvalidateBoneCache();
  5414. // reset root position to flTime
  5415. Interpolate( flTime );
  5416. if ( m_bClientSideAnimation )
  5417. {
  5418. float saveCycle = GetCycle();
  5419. float oldCycle = m_prevClientCycle;
  5420. if ( oldCycle > saveCycle )
  5421. {
  5422. oldCycle -= 1.0f;
  5423. }
  5424. float cycleInterp = RemapVal( flTime, m_prevClientAnimTime, m_flAnimTime, oldCycle, saveCycle );
  5425. cycleInterp = clamp( cycleInterp, 0.0f, 1.0f );
  5426. SetCycle( cycleInterp );
  5427. // Setup bone state at the given time
  5428. SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, flTime );
  5429. SetCycle( saveCycle );
  5430. }
  5431. else
  5432. {
  5433. // Setup bone state at the given time
  5434. SetupBones( pBonesOut, MAXSTUDIOBONES, BONE_USED_BY_ANYTHING, flTime );
  5435. }
  5436. }
  5437. void C_BaseAnimating::GetRagdollInitBoneArrays( matrix3x4a_t *pDeltaBones0, matrix3x4a_t *pDeltaBones1, matrix3x4a_t *pCurrentBones, float boneDt )
  5438. {
  5439. ForceSetupBonesAtTime( pDeltaBones0, gpGlobals->curtime - boneDt );
  5440. ForceSetupBonesAtTime( pDeltaBones1, gpGlobals->curtime );
  5441. float ragdollCreateTime = PhysGetSyncCreateTime();
  5442. if ( ragdollCreateTime != gpGlobals->curtime )
  5443. {
  5444. // The next simulation frame begins before the end of this frame
  5445. // so initialize the ragdoll at that time so that it will reach the current
  5446. // position at curtime. Otherwise the ragdoll will simulate forward from curtime
  5447. // and pop into the future a bit at this point of transition
  5448. ForceSetupBonesAtTime( pCurrentBones, ragdollCreateTime );
  5449. }
  5450. else
  5451. {
  5452. Plat_FastMemcpy( pCurrentBones, m_CachedBoneData.Base(), sizeof( matrix3x4a_t ) * m_CachedBoneData.Count() );
  5453. }
  5454. }
  5455. C_ClientRagdoll *C_BaseAnimating::CreateClientRagdoll( bool bRestoring )
  5456. {
  5457. DevMsg( "Creating ragdoll at tick %d\n", gpGlobals->tickcount );
  5458. return new C_ClientRagdoll( bRestoring );
  5459. }
  5460. C_BaseAnimating *C_BaseAnimating::CreateRagdollCopy()
  5461. {
  5462. //Adrian: We now create a separate entity that becomes this entity's ragdoll.
  5463. //That way the server side version of this entity can go away.
  5464. //Plus we can hook save/restore code to these ragdolls so they don't fall on restore anymore.
  5465. C_ClientRagdoll *pRagdoll = CreateClientRagdoll( false );
  5466. if ( pRagdoll == NULL )
  5467. return NULL;
  5468. TermRopes();
  5469. const model_t *model = GetModel();
  5470. const char *pModelName = modelinfo->GetModelName( model );
  5471. if ( pRagdoll->InitializeAsClientEntity( pModelName, false ) == false )
  5472. {
  5473. pRagdoll->Release();
  5474. return NULL;
  5475. }
  5476. // move my current model instance to the ragdoll's so decals are preserved.
  5477. SnatchModelInstance( pRagdoll );
  5478. // We need to take these from the entity
  5479. pRagdoll->SetAbsOrigin( GetAbsOrigin() );
  5480. pRagdoll->SetAbsAngles( GetAbsAngles() );
  5481. pRagdoll->IgniteRagdoll( this );
  5482. pRagdoll->TransferDissolveFrom( this );
  5483. pRagdoll->InitModelEffects();
  5484. if ( AddRagdollToFadeQueue() == true )
  5485. {
  5486. pRagdoll->m_bImportant = NPC_IsImportantNPC( this );
  5487. s_RagdollLRU.MoveToTopOfLRU( pRagdoll, pRagdoll->m_bImportant );
  5488. pRagdoll->m_bFadeOut = true;
  5489. }
  5490. m_builtRagdoll = true;
  5491. AddEffects( EF_NODRAW );
  5492. if ( IsEffectActive( EF_NOSHADOW ) )
  5493. {
  5494. pRagdoll->AddEffects( EF_NOSHADOW );
  5495. }
  5496. pRagdoll->m_bClientSideRagdoll = true;
  5497. pRagdoll->SetRenderMode( GetRenderMode() );
  5498. pRagdoll->SetRenderColor( GetRenderColor().r, GetRenderColor().g, GetRenderColor().b );
  5499. pRagdoll->SetRenderAlpha( GetRenderAlpha() );
  5500. pRagdoll->SetGlobalFadeScale( GetGlobalFadeScale() );
  5501. pRagdoll->SetBody( GetBody() );
  5502. pRagdoll->SetSkin( GetSkin() );
  5503. pRagdoll->m_vecForce = m_vecForce;
  5504. pRagdoll->m_nForceBone = m_nForceBone;
  5505. pRagdoll->SetNextClientThink( CLIENT_THINK_ALWAYS );
  5506. pRagdoll->SetModelName( AllocPooledString(pModelName) );
  5507. pRagdoll->CopySequenceTransitions(this);
  5508. pRagdoll->SetModelScale( this->GetModelScale(), this->GetModelScaleType() );
  5509. return pRagdoll;
  5510. }
  5511. void C_BaseAnimating::CopySequenceTransitions( C_BaseAnimating *pCopyFrom )
  5512. {
  5513. m_SequenceTransitioner.m_animationQueue.RemoveAll();
  5514. int count = pCopyFrom->m_SequenceTransitioner.m_animationQueue.Count();
  5515. m_SequenceTransitioner.m_animationQueue.EnsureCount(count);
  5516. for ( int i = 0; i < count; i++ )
  5517. {
  5518. m_SequenceTransitioner.m_animationQueue[i] = pCopyFrom->m_SequenceTransitioner.m_animationQueue[i];
  5519. }
  5520. }
  5521. C_BaseAnimating *C_BaseAnimating::BecomeRagdollOnClient()
  5522. {
  5523. MoveToLastReceivedPosition( true );
  5524. GetAbsOrigin();
  5525. m_pClientsideRagdoll = CreateRagdollCopy();
  5526. if ( !m_pClientsideRagdoll )
  5527. return NULL;
  5528. matrix3x4a_t boneDelta0[MAXSTUDIOBONES];
  5529. matrix3x4a_t boneDelta1[MAXSTUDIOBONES];
  5530. matrix3x4a_t currentBones[MAXSTUDIOBONES];
  5531. const float boneDt = 0.1f;
  5532. GetRagdollInitBoneArrays( boneDelta0, boneDelta1, currentBones, boneDt );
  5533. m_pClientsideRagdoll->InitAsClientRagdoll( boneDelta0, boneDelta1, currentBones, boneDt );
  5534. return m_pClientsideRagdoll;
  5535. }
  5536. bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, Vector vecForceOverride, bool bleedOut )
  5537. {
  5538. CStudioHdr *hdr = GetModelPtr();
  5539. if ( !hdr || m_pRagdoll || m_builtRagdoll )
  5540. return false;
  5541. m_builtRagdoll = true;
  5542. // Store off our old mins & maxs
  5543. m_vecPreRagdollMins = WorldAlignMins();
  5544. m_vecPreRagdollMaxs = WorldAlignMaxs();
  5545. // Force MOVETYPE_STEP interpolation
  5546. SetMoveType( MOVETYPE_STEP );
  5547. // HACKHACK: force time to last interpolation position
  5548. m_flPlaybackRate = 1;
  5549. m_pRagdoll = CreateRagdoll( this, hdr, vecForceOverride, m_nForceBone, pDeltaBones0, pDeltaBones1, pCurrentBonePosition, boneDt, false, bleedOut );
  5550. // Cause the entity to recompute its shadow type and make a
  5551. // version which only updates when physics state changes
  5552. // NOTE: We have to do this after m_pRagdoll is assigned above
  5553. // because that's what ShadowCastType uses to figure out which type of shadow to use.
  5554. DestroyShadow();
  5555. CreateShadow();
  5556. // Cache off ragdoll bone positions/quaternions
  5557. if ( m_bStoreRagdollInfo && m_pRagdoll )
  5558. {
  5559. matrix3x4_t parentTransform;
  5560. AngleMatrix( GetAbsAngles(), GetAbsOrigin(), parentTransform );
  5561. // FIXME/CHECK: This might be too expensive to do every frame???
  5562. SaveRagdollInfo( hdr->numbones(), parentTransform, m_BoneAccessor );
  5563. }
  5564. // Now set the dieragdoll sequence to get transforms for all
  5565. // non-simulated bones
  5566. SetSequence( SelectWeightedSequence( ACT_DIERAGDOLL ) );
  5567. m_flPlaybackRate = 0;
  5568. UpdatePartitionListEntry();
  5569. NoteRagdollCreationTick( this );
  5570. UpdateVisibility();
  5571. #if defined( REPLAY_ENABLED )
  5572. // If replay is enabled on server, add an entry to the ragdoll recorder for this entity
  5573. ConVar* pReplayEnable = (ConVar*)cvar->FindVar( "replay_enable" );
  5574. if ( pReplayEnable && pReplayEnable->GetInt() && !engine->IsPlayingDemo() && !engine->IsPlayingTimeDemo() )
  5575. {
  5576. CReplayRagdollRecorder& RagdollRecorder = CReplayRagdollRecorder::Instance();
  5577. int nStartTick = TIME_TO_TICKS( engine->GetLastTimeStamp() );
  5578. RagdollRecorder.AddEntry( this, nStartTick, m_pRagdoll->RagdollBoneCount() );
  5579. }
  5580. #endif
  5581. return true;
  5582. }
  5583. bool C_BaseAnimating::InitAsClientRagdoll( const matrix3x4_t *pDeltaBones0, const matrix3x4_t *pDeltaBones1, const matrix3x4_t *pCurrentBonePosition, float boneDt, bool bleedOut )
  5584. {
  5585. return InitAsClientRagdoll( pDeltaBones0, pDeltaBones1, pCurrentBonePosition, boneDt, m_vecForce, bleedOut );
  5586. }
  5587. #if defined ( CSTRIKE15 )
  5588. // [msmith] We want shadows for the following entity classes.
  5589. // We could probably just get rid of this and turn on rtt shadows for everything that would use them.
  5590. // This this is playing it safe until we look at perf etc.
  5591. static const char* g_pszForceRTTClassnames[] =
  5592. {
  5593. "class CPhysicsPropMultiplayer",
  5594. "class C_PhysicsProp",
  5595. "class C_CSRagdoll",
  5596. "class C_ServerRagdoll",
  5597. "class C_CHostage",
  5598. };
  5599. #else
  5600. // This just looks like portal 2 stuff
  5601. static const char* g_pszForceRTTClassnames[] =
  5602. {
  5603. "prop_weighted_cube",
  5604. "class C_NPC_Portal_FloorTurret",
  5605. "class C_NPC_Personality_Core",
  5606. "class C_PhysicsProp",
  5607. //"prop_box_monster",
  5608. };
  5609. #endif
  5610. void C_BaseAnimating::CheckIfEntityShouldForceRTTShadows( void )
  5611. {
  5612. for ( int i = 0; i < ARRAYSIZE( g_pszForceRTTClassnames ); ++i )
  5613. {
  5614. if ( FClassnameIs( this, g_pszForceRTTClassnames[i] ) )
  5615. {
  5616. m_bForceRTTShadows = true;
  5617. return;
  5618. }
  5619. }
  5620. }
  5621. //-----------------------------------------------------------------------------
  5622. // Purpose:
  5623. // Input : bnewentity -
  5624. //-----------------------------------------------------------------------------
  5625. void C_BaseAnimating::OnDataChanged( DataUpdateType_t updateType )
  5626. {
  5627. if (updateType == DATA_UPDATE_CREATED)
  5628. {
  5629. // Now that the data has come down from the server, double-check that the clientside animation variables are handled properly
  5630. UpdateRelevantInterpolatedVars();
  5631. // Check if this is one of the ents that wants RTT shadows
  5632. CheckIfEntityShouldForceRTTShadows();
  5633. }
  5634. bool modelchanged = false;
  5635. // UNDONE: The base class does this as well. So this is kind of ugly
  5636. // but getting a model by index is pretty cheap...
  5637. const model_t *pModel = modelinfo->GetModel( GetModelIndex() );
  5638. if ( pModel != GetModel() )
  5639. {
  5640. modelchanged = true;
  5641. }
  5642. BaseClass::OnDataChanged( updateType );
  5643. if ( m_nPrevBody != GetBody() || m_nPrevSkin != GetSkin() )
  5644. {
  5645. OnTranslucencyTypeChanged();
  5646. }
  5647. if ( (updateType == DATA_UPDATE_CREATED) || modelchanged )
  5648. {
  5649. ResetLatched();
  5650. // if you have this pose parameter, activate HL1-style lipsync/wave envelope tracking
  5651. if ( LookupPoseParameter( LIPSYNC_POSEPARAM_NAME ) != -1 )
  5652. {
  5653. MouthInfo().ActivateEnvelope();
  5654. }
  5655. if ( m_pStudioHdr )
  5656. {
  5657. if ( CSoftbody *pSoftbody = m_pStudioHdr->GetSoftbody() )
  5658. {
  5659. pSoftbody->SetAbsOrigin( GetAbsOrigin(), true );
  5660. pSoftbody->SetAbsAngles( GetAbsAngles(), true );
  5661. }
  5662. }
  5663. }
  5664. // If there's a significant change, make sure the shadow updates
  5665. if ( modelchanged )
  5666. {
  5667. InvalidatePhysicsRecursive( BOUNDS_CHANGED | SEQUENCE_CHANGED );
  5668. }
  5669. // Only need to think if animating client side
  5670. if ( m_bClientSideAnimation )
  5671. {
  5672. // Check to see if we should reset our frame
  5673. if ( m_bClientSideFrameReset != m_bLastClientSideFrameReset )
  5674. {
  5675. SetCycle( 0 );
  5676. }
  5677. }
  5678. // build a ragdoll if necessary
  5679. if ( m_bClientSideRagdoll && !m_builtRagdoll )
  5680. {
  5681. if ( !cl_disable_ragdolls.GetBool() )
  5682. {
  5683. BecomeRagdollOnClient( );
  5684. }
  5685. }
  5686. //HACKHACK!!!
  5687. if ( m_bClientSideRagdoll && m_builtRagdoll == true )
  5688. {
  5689. if ( m_pRagdoll == NULL )
  5690. AddEffects( EF_NODRAW );
  5691. }
  5692. if ( m_pRagdoll && !m_bClientSideRagdoll || !m_bClientSideRagdoll && m_builtRagdoll )
  5693. {
  5694. ClearRagdoll();
  5695. }
  5696. // If ragdolling and get EF_NOINTERP, we probably were dead and are now respawning,
  5697. // don't do blend out of ragdoll at respawn spot.
  5698. if ( IsEffectActive( EF_NOINTERP ) )
  5699. {
  5700. if ( m_pRagdollInfo && m_pRagdollInfo->m_bActive )
  5701. {
  5702. Msg( "delete ragdoll due to nointerp\n" );
  5703. // Remove ragdoll info
  5704. delete m_pRagdollInfo;
  5705. m_pRagdollInfo = NULL;
  5706. }
  5707. AddToEntityList(ENTITY_LIST_SIMULATE);
  5708. }
  5709. m_bIsUsingRelativeLighting = ( m_hLightingOrigin.Get() != NULL );
  5710. }
  5711. //-----------------------------------------------------------------------------
  5712. // Purpose: Get the index of the attachment point with the specified name
  5713. //-----------------------------------------------------------------------------
  5714. int C_BaseAnimating::LookupAttachment( const char *pAttachmentName )
  5715. {
  5716. CStudioHdr *hdr = GetModelPtr();
  5717. if ( !hdr )
  5718. {
  5719. return -1;
  5720. }
  5721. // NOTE: Currently, the network uses 0 to mean "no attachment"
  5722. // thus the client must add one to the index of the attachment
  5723. // UNDONE: Make the server do this too to be consistent.
  5724. return Studio_FindAttachment( hdr, pAttachmentName ) + 1;
  5725. }
  5726. //-----------------------------------------------------------------------------
  5727. // Purpose: Get a random index of an attachment point with the specified substring in its name
  5728. //-----------------------------------------------------------------------------
  5729. int C_BaseAnimating::LookupRandomAttachment( const char *pAttachmentNameSubstring )
  5730. {
  5731. CStudioHdr *hdr = GetModelPtr();
  5732. if ( !hdr )
  5733. {
  5734. return -1;
  5735. }
  5736. // NOTE: Currently, the network uses 0 to mean "no attachment"
  5737. // thus the client must add one to the index of the attachment
  5738. // UNDONE: Make the server do this too to be consistent.
  5739. return Studio_FindRandomAttachment( hdr, pAttachmentNameSubstring ) + 1;
  5740. }
  5741. void C_BaseAnimating::ClientSideAnimationChanged()
  5742. {
  5743. if ( !m_bClientSideAnimation || m_ClientSideAnimationListHandle == INVALID_CLIENTSIDEANIMATION_LIST_HANDLE )
  5744. return;
  5745. MDLCACHE_CRITICAL_SECTION();
  5746. clientanimating_t &anim = g_ClientSideAnimationList.Element(m_ClientSideAnimationListHandle);
  5747. Assert(anim.pAnimating == this);
  5748. anim.flags = ComputeClientSideAnimationFlags();
  5749. m_SequenceTransitioner.CheckForSequenceChange(
  5750. GetModelPtr(),
  5751. GetSequence(),
  5752. m_nNewSequenceParity != m_nPrevNewSequenceParity,
  5753. !IsEffectActive(EF_NOINTERP)
  5754. );
  5755. }
  5756. unsigned int C_BaseAnimating::ComputeClientSideAnimationFlags()
  5757. {
  5758. return FCLIENTANIM_SEQUENCE_CYCLE;
  5759. }
  5760. void C_BaseAnimating::UpdateClientSideAnimation()
  5761. {
  5762. // Update client side animation
  5763. if ( m_bClientSideAnimation )
  5764. {
  5765. Assert( m_ClientSideAnimationListHandle != INVALID_CLIENTSIDEANIMATION_LIST_HANDLE );
  5766. if ( GetSequence() != -1 )
  5767. {
  5768. #ifdef DOTA_DLL
  5769. if ( IsVisibleToAnyPlayer() )
  5770. #endif
  5771. {
  5772. // latch old values
  5773. OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR );
  5774. // move frame forward
  5775. FrameAdvance( 0.0f ); // 0 means to use the time we last advanced instead of a constant
  5776. }
  5777. }
  5778. }
  5779. else
  5780. {
  5781. Assert( m_ClientSideAnimationListHandle == INVALID_CLIENTSIDEANIMATION_LIST_HANDLE );
  5782. }
  5783. }
  5784. bool C_BaseAnimating::Simulate()
  5785. {
  5786. bool bRet = !m_bIsStaticProp; // static prop defaults to false
  5787. if ( m_bInitModelEffects )
  5788. {
  5789. DelayedInitModelEffects();
  5790. }
  5791. if ( gpGlobals->frametime != 0.0f )
  5792. {
  5793. CStudioHdr *pStudio = GetModelPtr();
  5794. if ( pStudio && pStudio->SequencesAvailable() )
  5795. {
  5796. if ( pStudio->GetRenderHdr()->flags & STUDIOHDR_FLAGS_NO_ANIM_EVENTS )
  5797. {
  5798. bRet = false;
  5799. }
  5800. else
  5801. {
  5802. DoAnimationEvents( pStudio );
  5803. }
  5804. }
  5805. }
  5806. if ( BaseClass::Simulate() )
  5807. {
  5808. bRet = true;
  5809. }
  5810. // Server says don't interpolate this frame, so set previous info to new info.
  5811. if ( IsEffectActive(EF_NOINTERP) )
  5812. {
  5813. ResetLatched();
  5814. }
  5815. if ( GetSequence() != -1 && m_pRagdoll && ( !m_bClientSideRagdoll ) )
  5816. {
  5817. ClearRagdoll();
  5818. }
  5819. return bRet;
  5820. }
  5821. bool C_BaseAnimating::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  5822. {
  5823. if ( ray.m_IsRay && IsSolidFlagSet( FSOLID_CUSTOMRAYTEST ))
  5824. {
  5825. if (!TestHitboxes( ray, fContentsMask, tr ))
  5826. return true;
  5827. return tr.DidHit();
  5828. }
  5829. if ( !ray.m_IsRay && IsSolidFlagSet( FSOLID_CUSTOMBOXTEST ))
  5830. {
  5831. if (!TestHitboxes( ray, fContentsMask, tr ))
  5832. return true;
  5833. return true;
  5834. }
  5835. // We shouldn't get here.
  5836. Assert(0);
  5837. return false;
  5838. }
  5839. // UNDONE: This almost works. The client entities have no control over their solid box
  5840. // Also they have no ability to expose FSOLID_ flags to the engine to force the accurate
  5841. // collision tests.
  5842. // Add those and the client hitboxes will be robust
  5843. bool C_BaseAnimating::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  5844. {
  5845. VPROF( "C_BaseAnimating::TestHitboxes" );
  5846. MDLCACHE_CRITICAL_SECTION();
  5847. CStudioHdr *pStudioHdr = GetModelPtr();
  5848. if (!pStudioHdr)
  5849. return false;
  5850. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  5851. if ( !set || !set->numhitboxes )
  5852. return false;
  5853. // Use vcollide for box traces.
  5854. if ( !ray.m_IsRay )
  5855. return false;
  5856. // This *has* to be true for the existing code to function correctly.
  5857. Assert( ray.m_StartOffset == vec3_origin );
  5858. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  5859. HitboxToWorldTransforms( hitboxbones );
  5860. if ( TraceToStudioCsgoHitgroupsPriority( physprops, ray, pStudioHdr, set, hitboxbones, fContentsMask, GetRenderOrigin(), GetModelHierarchyScale(), tr ) )
  5861. {
  5862. mstudiobbox_t *pbox = set->pHitbox( tr.hitbox );
  5863. const mstudiobone_t *pBone = pStudioHdr->pBone(pbox->bone);
  5864. tr.surface.name = "**studio**";
  5865. tr.surface.flags = SURF_HITBOX;
  5866. tr.surface.surfaceProps = pBone->GetSurfaceProp();
  5867. if ( IsRagdoll() )
  5868. {
  5869. IPhysicsObject *pReplace = m_pRagdoll->GetElement( tr.physicsbone );
  5870. if ( pReplace )
  5871. {
  5872. VPhysicsSetObject( NULL );
  5873. VPhysicsSetObject( pReplace );
  5874. }
  5875. }
  5876. }
  5877. return true;
  5878. }
  5879. //-----------------------------------------------------------------------------
  5880. // Purpose: Check sequence framerate
  5881. // Input : iSequence -
  5882. // Output : float
  5883. //-----------------------------------------------------------------------------
  5884. float C_BaseAnimating::GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence )
  5885. {
  5886. if ( !pStudioHdr )
  5887. return 0.0f;
  5888. return Studio_CPS( pStudioHdr, pStudioHdr->pSeqdesc(iSequence), iSequence, m_flPoseParameter );
  5889. }
  5890. float C_BaseAnimating::GetAnimTimeInterval( void ) const
  5891. {
  5892. #define MAX_ANIMTIME_INTERVAL 0.2f
  5893. float flInterval = MIN( gpGlobals->curtime - m_flAnimTime, MAX_ANIMTIME_INTERVAL );
  5894. return flInterval;
  5895. }
  5896. //-----------------------------------------------------------------------------
  5897. // Sets the cycle, marks the entity as being dirty
  5898. //-----------------------------------------------------------------------------
  5899. void C_BaseAnimating::SetCycle( float flCycle )
  5900. {
  5901. if ( m_flCycle != flCycle )
  5902. {
  5903. if ( !IsFinite( flCycle ) )
  5904. {
  5905. Assert( false );
  5906. return;
  5907. }
  5908. m_flCycle = flCycle;
  5909. InvalidatePhysicsRecursive( ANIMATION_CHANGED );
  5910. /*
  5911. if (r_sequence_debug.GetInt() == entindex() )
  5912. {
  5913. DevMsgRT("%d : SetCycle %s:%.3f\n", entindex(), GetSequenceName( GetSequence() ), flCycle );
  5914. }
  5915. */
  5916. }
  5917. }
  5918. //-----------------------------------------------------------------------------
  5919. // Reset any global fields that are dependant on the sequence
  5920. //-----------------------------------------------------------------------------
  5921. void C_BaseAnimating::OnNewSequence( void )
  5922. {
  5923. CStudioHdr *pStudioHdr = GetModelPtr();
  5924. // Assert( pStudioHdr );
  5925. if ( pStudioHdr )
  5926. {
  5927. m_bSequenceLoops = ((GetSequenceFlags( pStudioHdr, GetSequence() ) & STUDIO_LOOPING) != 0);
  5928. m_flGroundSpeed = GetSequenceGroundSpeed( pStudioHdr, GetSequence() );
  5929. // FIXME: why is this called here? Nothing should have changed to make this nessesary
  5930. SetEventIndexForSequence( pStudioHdr->pSeqdesc( GetSequence() ) );
  5931. }
  5932. }
  5933. //-----------------------------------------------------------------------------
  5934. // Sets the sequence, marks the entity as being dirty
  5935. //-----------------------------------------------------------------------------
  5936. void C_BaseAnimating::SetSequence( int nSequence )
  5937. {
  5938. if ( m_nSequence != nSequence )
  5939. {
  5940. /*
  5941. CStudioHdr *hdr = GetModelPtr();
  5942. // Assert( hdr );
  5943. if ( hdr )
  5944. {
  5945. Assert( nSequence >= 0 && nSequence < hdr->GetNumSeq() );
  5946. }
  5947. */
  5948. if (r_debug_sequencesets.GetInt() == entindex())
  5949. {
  5950. Msg("%s : %s : SetSequence\n", GetClassname(), GetSequenceName( GetSequence() ));
  5951. }
  5952. m_nSequence = nSequence;
  5953. InvalidatePhysicsRecursive( BOUNDS_CHANGED | SEQUENCE_CHANGED );
  5954. if ( m_bClientSideAnimation )
  5955. {
  5956. ClientSideAnimationChanged();
  5957. }
  5958. OnNewSequence();
  5959. /*
  5960. if (r_sequence_debug.GetInt() == entindex() )
  5961. {
  5962. DevMsgRT("%d : SetSequence %s\n", entindex(), GetSequenceName( GetSequence() ) );
  5963. }
  5964. */
  5965. }
  5966. }
  5967. //-----------------------------------------------------------------------------
  5968. // Extracts the bounding box
  5969. //-----------------------------------------------------------------------------
  5970. void C_BaseAnimating::ExtractBbox( int nSequence, Vector &mins, Vector &maxs )
  5971. {
  5972. CStudioHdr *pStudioHdr = GetModelPtr();
  5973. Assert( pStudioHdr );
  5974. ::ExtractBbox( pStudioHdr, nSequence, mins, maxs );
  5975. }
  5976. //=========================================================
  5977. // StudioFrameAdvance - advance the animation frame up some interval (default 0.1) into the future
  5978. //=========================================================
  5979. void C_BaseAnimating::StudioFrameAdvance()
  5980. {
  5981. if ( m_bClientSideAnimation )
  5982. return;
  5983. CStudioHdr *hdr = GetModelPtr();
  5984. if ( !hdr )
  5985. return;
  5986. bool watch = false; //Q_strstr( hdr->name(), "grip" ) ? true : false;
  5987. //if (!anim.prevanimtime)
  5988. //{
  5989. //anim.prevanimtime = m_flAnimTime = gpGlobals->curtime;
  5990. //}
  5991. // How long since last animtime
  5992. float flInterval = GetAnimTimeInterval();
  5993. if (flInterval <= 0.001)
  5994. {
  5995. // Msg("%s : %s : %5.3f (skip)\n", STRING(pev->classname), GetSequenceName( GetSequence() ), GetCycle() );
  5996. return;
  5997. }
  5998. //anim.prevanimtime = m_flAnimTime;
  5999. float cycleAdvance = flInterval * GetSequenceCycleRate( hdr, GetSequence() ) * GetPlaybackRate();
  6000. float flNewCycle = GetCycle() + cycleAdvance;
  6001. m_flAnimTime = gpGlobals->curtime;
  6002. if ( watch )
  6003. {
  6004. Msg("%s %6.3f : %6.3f (%.3f)\n", GetClassname(), gpGlobals->curtime, m_flAnimTime, flInterval );
  6005. }
  6006. if ( flNewCycle < 0.0f || flNewCycle >= 1.0f )
  6007. {
  6008. if ( IsSequenceLooping( hdr, GetSequence() ) )
  6009. {
  6010. flNewCycle = SubtractIntegerPart(flNewCycle);
  6011. }
  6012. else
  6013. {
  6014. flNewCycle = (flNewCycle < 0.0f) ? 0.0f : 1.0f;
  6015. }
  6016. m_bSequenceFinished = true; // just in case it wasn't caught in GetEvents
  6017. }
  6018. SetCycle( flNewCycle );
  6019. m_flGroundSpeed = GetSequenceGroundSpeed( hdr, GetSequence() );
  6020. #if 0
  6021. // I didn't have a test case for this, but it seems like the right thing to do. Check multi-player!
  6022. // Msg("%s : %s : %5.1f\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() );
  6023. InvalidatePhysicsRecursive( ANIMATION_CHANGED );
  6024. #endif
  6025. if ( watch )
  6026. {
  6027. Msg("%s : %s : %1.3f\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() );
  6028. }
  6029. }
  6030. float C_BaseAnimating::GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence )
  6031. {
  6032. float t = SequenceDuration( pStudioHdr, iSequence );
  6033. if (t > 0)
  6034. {
  6035. return GetSequenceMoveDist( pStudioHdr, iSequence ) / t;
  6036. }
  6037. else
  6038. {
  6039. return 0;
  6040. }
  6041. }
  6042. //-----------------------------------------------------------------------------
  6043. // Purpose:
  6044. //
  6045. // Input : iSequence -
  6046. //
  6047. // Output : float
  6048. //-----------------------------------------------------------------------------
  6049. float C_BaseAnimating::GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence )
  6050. {
  6051. Vector vecReturn;
  6052. ::GetSequenceLinearMotion( pStudioHdr, iSequence, m_flPoseParameter, &vecReturn );
  6053. return vecReturn.Length();
  6054. }
  6055. //-----------------------------------------------------------------------------
  6056. // Purpose:
  6057. //
  6058. // Input : iSequence -
  6059. // *pVec -
  6060. //
  6061. //-----------------------------------------------------------------------------
  6062. void C_BaseAnimating::GetSequenceLinearMotion( int iSequence, Vector *pVec )
  6063. {
  6064. ::GetSequenceLinearMotion( GetModelPtr(), iSequence, m_flPoseParameter, pVec );
  6065. }
  6066. float C_BaseAnimating::GetSequenceLinearMotionAndDuration( int iSequence, Vector *pVec )
  6067. {
  6068. return ::GetSequenceLinearMotionAndDuration( GetModelPtr(), iSequence, m_flPoseParameter, pVec );
  6069. }
  6070. //-----------------------------------------------------------------------------
  6071. // Purpose:
  6072. // Output :
  6073. //-----------------------------------------------------------------------------
  6074. bool C_BaseAnimating::GetSequenceMovement( int nSequence, float fromCycle, float toCycle, Vector &deltaPosition, QAngle &deltaAngles )
  6075. {
  6076. CStudioHdr *pstudiohdr = GetModelPtr( );
  6077. if (! pstudiohdr)
  6078. return false;
  6079. return Studio_SeqMovement( pstudiohdr, nSequence, fromCycle, toCycle, m_flPoseParameter, deltaPosition, deltaAngles );
  6080. }
  6081. //-----------------------------------------------------------------------------
  6082. // Purpose:
  6083. //
  6084. // Input : *pVec -
  6085. //-----------------------------------------------------------------------------
  6086. void C_BaseAnimating::GetBlendedLinearVelocity( Vector *pVec )
  6087. {
  6088. Vector vecDist;
  6089. float flDuration = GetSequenceLinearMotionAndDuration( GetSequence(), &vecDist );
  6090. VectorScale( vecDist, 1.0 / flDuration, *pVec );
  6091. Vector tmp;
  6092. for (int i = m_SequenceTransitioner.m_animationQueue.Count() - 2; i >= 0; i--)
  6093. {
  6094. CAnimationLayer *blend = &m_SequenceTransitioner.m_animationQueue[i];
  6095. float flWeight = blend->GetFadeout( gpGlobals->curtime );
  6096. if ( flWeight == 0.0f )
  6097. continue;
  6098. flDuration = GetSequenceLinearMotionAndDuration( blend->GetSequence(), &vecDist );
  6099. VectorScale( vecDist, 1.0 / flDuration, tmp );
  6100. *pVec = Lerp( flWeight, *pVec, tmp );
  6101. }
  6102. }
  6103. //-----------------------------------------------------------------------------
  6104. // Purpose: convert local movement into pose parameters that take account of blending
  6105. // Input: vecLocalVelocity - local velocity in right-hand-rule coordinates
  6106. // iMoveX, iMoveY - pose parameter indexes for movement
  6107. // Output :
  6108. //-----------------------------------------------------------------------------
  6109. #define MOVEMENT_ERROR_LIMIT 1.0
  6110. void C_BaseAnimating::SetMovementPoseParams( const Vector &vecLocalVelocity, int iMoveX, int iMoveY, int iXSign, int iYSign )
  6111. {
  6112. CStudioHdr *pStudioHdr = GetModelPtr( );
  6113. if (! pStudioHdr)
  6114. return;
  6115. Vector2D vecCurrentPose( 0.0f, 0.0f );
  6116. // set the pose parameters to the correct direction, but not value
  6117. if ( vecLocalVelocity.x != 0.0f && fabs( vecLocalVelocity.x ) > fabs( vecLocalVelocity.y ) )
  6118. {
  6119. vecCurrentPose.x = ((vecLocalVelocity.x < 0.0) ? -iXSign : iXSign);
  6120. vecCurrentPose.y = iYSign * (vecLocalVelocity.y / fabs( vecLocalVelocity.x ));
  6121. }
  6122. else if (vecLocalVelocity.y != 0.0f)
  6123. {
  6124. vecCurrentPose.x = iXSign * (vecLocalVelocity.x / fabs( vecLocalVelocity.y ));
  6125. vecCurrentPose.y = ((vecLocalVelocity.y < 0.0) ? -iYSign : iYSign);
  6126. }
  6127. if (vecCurrentPose.x == 0.0f && vecCurrentPose.y == 0.0f)
  6128. {
  6129. SetPoseParameter( pStudioHdr, iMoveX, vecCurrentPose.x );
  6130. SetPoseParameter( pStudioHdr, iMoveY, vecCurrentPose.y );
  6131. return;
  6132. }
  6133. // refine pose parameters to be more accurate
  6134. int i = 0;
  6135. float dx, dy;
  6136. Vector vecAnimVelocity;
  6137. // Set the initial 9-way blend movement pose parameters.
  6138. SetPoseParameter( pStudioHdr, iMoveX, vecCurrentPose.x );
  6139. SetPoseParameter( pStudioHdr, iMoveY, vecCurrentPose.y );
  6140. /*
  6141. if ( r_sequence_debug.GetInt() == entindex() )
  6142. {
  6143. DevMsgRT("%d (%d) : %.2f %.2f : %.2f %.2f : %.3f %.3f\n", entindex(), -1, vecLocalVelocity.x, vecLocalVelocity.y, vecAnimVelocity.x, vecAnimVelocity.y, vecCurrentPose.x, vecCurrentPose.y );
  6144. }
  6145. */
  6146. bool retry = true;
  6147. do
  6148. {
  6149. GetBlendedLinearVelocity( &vecAnimVelocity );
  6150. // adjust X pose parameter based on movement error
  6151. if (fabs( vecAnimVelocity.x ) > 0.001)
  6152. {
  6153. vecCurrentPose.x *= vecLocalVelocity.x / vecAnimVelocity.x;
  6154. }
  6155. else
  6156. {
  6157. // too slow, set to zero so it can optimized out during bone setup
  6158. vecCurrentPose.x = 0;
  6159. }
  6160. SetPoseParameter( pStudioHdr, iMoveX, vecCurrentPose.x );
  6161. // adjust Y pose parameter based on movement error
  6162. if (fabs( vecAnimVelocity.y ) > 0.001)
  6163. {
  6164. vecCurrentPose.y *= vecLocalVelocity.y / vecAnimVelocity.y;
  6165. }
  6166. else
  6167. {
  6168. // too slow, set to zero so it can optimized out during bone setup
  6169. vecCurrentPose.y = 0;
  6170. }
  6171. SetPoseParameter( pStudioHdr, iMoveY, vecCurrentPose.y );
  6172. /*
  6173. if ( r_sequence_debug.GetInt() == entindex() )
  6174. {
  6175. DevMsgRT("%d (%d) : %.2f %.2f : %.2f %.2f : %.3f %.3f\n", entindex(), i, vecLocalVelocity.x, vecLocalVelocity.y, vecAnimVelocity.x, vecAnimVelocity.y, vecCurrentPose.x, vecCurrentPose.y );
  6176. }
  6177. */
  6178. dx = vecLocalVelocity.x - vecAnimVelocity.x;
  6179. dy = vecLocalVelocity.y - vecAnimVelocity.y;
  6180. retry = (vecCurrentPose.x < 1.0 && vecCurrentPose.x > -1.0) && (dx < -MOVEMENT_ERROR_LIMIT || dx > MOVEMENT_ERROR_LIMIT);
  6181. retry = retry || ((vecCurrentPose.y < 1.0 && vecCurrentPose.y > -1.0) && (dy < -MOVEMENT_ERROR_LIMIT || dy > MOVEMENT_ERROR_LIMIT));
  6182. } while (i++ < 5 && retry);
  6183. }
  6184. //-----------------------------------------------------------------------------
  6185. // Purpose:
  6186. // Input : flInterval -
  6187. // Output : float
  6188. //-----------------------------------------------------------------------------
  6189. float C_BaseAnimating::FrameAdvance( float flInterval )
  6190. {
  6191. CStudioHdr *hdr = GetModelPtr();
  6192. if ( !hdr )
  6193. return 0.0f;
  6194. bool bWatch = false; // Q_strstr( hdr->name, "commando" ) ? true : false;
  6195. float curtime = gpGlobals->curtime;
  6196. if (flInterval == 0.0f)
  6197. {
  6198. flInterval = ( curtime - m_flAnimTime );
  6199. if (flInterval <= 0.001f)
  6200. {
  6201. return 0.0f;
  6202. }
  6203. }
  6204. if ( !m_flAnimTime )
  6205. {
  6206. flInterval = 0.0f;
  6207. }
  6208. float cyclerate = GetSequenceCycleRate( hdr, GetSequence() );
  6209. float addcycle = flInterval * cyclerate * GetPlaybackRate();
  6210. m_prevClientCycle = GetCycle();
  6211. m_prevClientAnimTime = m_flAnimTime;
  6212. if( GetServerIntendedCycle() != -1.0f )
  6213. {
  6214. // The server would like us to ease in a correction so that we will animate the same on the client and server.
  6215. // So we will actually advance the average of what we would have done and what the server wants.
  6216. float serverCycle = GetServerIntendedCycle();
  6217. float serverAdvance = serverCycle - GetCycle();
  6218. bool adjustOkay = serverAdvance > 0.0f;// only want to go forward. backing up looks really jarring, even when slight
  6219. if( serverAdvance < -0.8f )
  6220. {
  6221. // Oh wait, it was just a wraparound from .9 to .1.
  6222. serverAdvance += 1;
  6223. adjustOkay = true;
  6224. }
  6225. if( adjustOkay )
  6226. {
  6227. float originalAdvance;
  6228. originalAdvance = addcycle;
  6229. addcycle = (serverAdvance + addcycle) / 2;
  6230. const float MAX_CYCLE_ADJUSTMENT = 0.1f;
  6231. addcycle = MIN( MAX_CYCLE_ADJUSTMENT, addcycle );// Don't do too big of a jump; it's too jarring as well.
  6232. DevMsg( 2, "(%d): Cycle latch used to correct %.2f in to %.2f instead of %.2f.\n",
  6233. entindex(), GetCycle(), GetCycle() + addcycle, GetCycle() + originalAdvance );
  6234. }
  6235. SetServerIntendedCycle(-1.0f); // Only use a correction once, it isn't valid any time but right now.
  6236. }
  6237. float flNewCycle = GetCycle() + addcycle;
  6238. m_flAnimTime = curtime;
  6239. if ( bWatch )
  6240. {
  6241. Msg("%i CLIENT Time: %6.3f : (Interval %f) : cycle %f rate %f add %f\n",
  6242. gpGlobals->tickcount, gpGlobals->curtime, flInterval, flNewCycle, cyclerate, addcycle );
  6243. }
  6244. if ( (flNewCycle < 0.0f) || (flNewCycle >= 1.0f) )
  6245. {
  6246. if (flNewCycle >= 1.0f)
  6247. {
  6248. ReachedEndOfSequence();
  6249. }
  6250. if ( IsSequenceLooping( hdr, GetSequence() ) )
  6251. {
  6252. flNewCycle = SubtractIntegerPart(flNewCycle);
  6253. }
  6254. else
  6255. {
  6256. flNewCycle = (flNewCycle < 0.0f) ? 0.0f : 1.0f;
  6257. }
  6258. m_bSequenceFinished = true;
  6259. }
  6260. SetCycle( flNewCycle );
  6261. InvalidatePhysicsRecursive( ANIMATION_CHANGED );
  6262. m_flGroundSpeed = GetSequenceGroundSpeed( hdr, GetSequence() );
  6263. return flInterval;
  6264. }
  6265. // Stubs for weapon prediction
  6266. void C_BaseAnimating::ResetSequenceInfo( void )
  6267. {
  6268. if (GetSequence() == -1)
  6269. {
  6270. SetSequence( 0 );
  6271. }
  6272. /*
  6273. if (r_sequence_debug.GetInt() == entindex() )
  6274. {
  6275. DevMsgRT("%d : client reset %s\n", entindex(), GetSequenceName( GetSequence() ) );
  6276. }
  6277. */
  6278. m_flPlaybackRate = 1.0;
  6279. m_bSequenceFinished = false;
  6280. m_flLastEventCheck = 0;
  6281. if ( !IsPlayer() )
  6282. {
  6283. m_nNewSequenceParity = ( ++m_nNewSequenceParity ) & EF_PARITY_MASK;
  6284. }
  6285. m_nResetEventsParity = ( ++m_nResetEventsParity ) & EF_PARITY_MASK;
  6286. }
  6287. //=========================================================
  6288. //=========================================================
  6289. bool C_BaseAnimating::IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence )
  6290. {
  6291. return (::GetSequenceFlags( pStudioHdr, iSequence ) & STUDIO_LOOPING) != 0;
  6292. }
  6293. float C_BaseAnimating::SequenceDuration( CStudioHdr *pStudioHdr, int iSequence )
  6294. {
  6295. if ( !pStudioHdr )
  6296. {
  6297. return 0.1f;
  6298. }
  6299. if (iSequence >= pStudioHdr->GetNumSeq() || iSequence < 0 )
  6300. {
  6301. DevWarning( 2, "C_BaseAnimating::SequenceDuration( %d ) out of range\n", iSequence );
  6302. return 0.1;
  6303. }
  6304. return Studio_Duration( pStudioHdr, iSequence, m_flPoseParameter );
  6305. }
  6306. int C_BaseAnimating::FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir )
  6307. {
  6308. CStudioHdr *hdr = GetModelPtr();
  6309. if ( !hdr )
  6310. {
  6311. return -1;
  6312. }
  6313. if (piDir == NULL)
  6314. {
  6315. int iDir = 1;
  6316. int sequence = ::FindTransitionSequence( hdr, iCurrentSequence, iGoalSequence, &iDir );
  6317. if (iDir != 1)
  6318. return -1;
  6319. else
  6320. return sequence;
  6321. }
  6322. return ::FindTransitionSequence( hdr, iCurrentSequence, iGoalSequence, piDir );
  6323. }
  6324. void C_BaseAnimating::SetSkin( int iSkin )
  6325. {
  6326. if ( m_nSkin != iSkin )
  6327. {
  6328. m_nSkin = iSkin;
  6329. OnTranslucencyTypeChanged();
  6330. }
  6331. }
  6332. void C_BaseAnimating::SetBody( int iBody )
  6333. {
  6334. if ( m_nBody != iBody )
  6335. {
  6336. m_nBody = iBody;
  6337. OnTranslucencyTypeChanged();
  6338. }
  6339. }
  6340. void C_BaseAnimating::SetBodygroup( int iGroup, int iValue )
  6341. {
  6342. Assert( GetModelPtr() );
  6343. int nOldBody = m_nBody;
  6344. ::SetBodygroup( GetModelPtr( ), m_nBody, iGroup, iValue );
  6345. if ( nOldBody != m_nBody )
  6346. {
  6347. OnTranslucencyTypeChanged();
  6348. }
  6349. }
  6350. void C_BaseAnimating::SetBodygroupPreset( char const *szName )
  6351. {
  6352. Assert( GetModelPtr() );
  6353. int nOldBody = m_nBody;
  6354. ::SetBodygroupPreset( GetModelPtr( ), m_nBody, szName );
  6355. if ( nOldBody != m_nBody )
  6356. {
  6357. OnTranslucencyTypeChanged();
  6358. }
  6359. }
  6360. int C_BaseAnimating::GetBodygroup( int iGroup )
  6361. {
  6362. Assert( GetModelPtr() );
  6363. return ::GetBodygroup( GetModelPtr( ), m_nBody, iGroup );
  6364. }
  6365. const char *C_BaseAnimating::GetBodygroupName( int iGroup )
  6366. {
  6367. Assert( GetModelPtr() );
  6368. return ::GetBodygroupName( GetModelPtr( ), iGroup );
  6369. }
  6370. int C_BaseAnimating::FindBodygroupByName( const char *name )
  6371. {
  6372. Assert( GetModelPtr() );
  6373. return ::FindBodygroupByName( GetModelPtr( ), name );
  6374. }
  6375. int C_BaseAnimating::GetBodygroupCount( int iGroup )
  6376. {
  6377. Assert( GetModelPtr() );
  6378. return ::GetBodygroupCount( GetModelPtr( ), iGroup );
  6379. }
  6380. int C_BaseAnimating::GetNumBodyGroups( void )
  6381. {
  6382. Assert( GetModelPtr() );
  6383. return ::GetNumBodyGroups( GetModelPtr( ) );
  6384. }
  6385. //-----------------------------------------------------------------------------
  6386. // Purpose:
  6387. // Input : setnum -
  6388. //-----------------------------------------------------------------------------
  6389. void C_BaseAnimating::SetHitboxSet( int setnum )
  6390. {
  6391. #ifdef _DEBUG
  6392. CStudioHdr *pStudioHdr = GetModelPtr();
  6393. if ( !pStudioHdr )
  6394. return;
  6395. if (setnum > pStudioHdr->numhitboxsets())
  6396. {
  6397. // Warn if an bogus hitbox set is being used....
  6398. static bool s_bWarned = false;
  6399. if (!s_bWarned)
  6400. {
  6401. Warning("Using bogus hitbox set in entity %s!\n", GetClassname() );
  6402. s_bWarned = true;
  6403. }
  6404. setnum = 0;
  6405. }
  6406. #endif
  6407. m_nHitboxSet = setnum;
  6408. }
  6409. //-----------------------------------------------------------------------------
  6410. // Purpose:
  6411. // Input : *setname -
  6412. //-----------------------------------------------------------------------------
  6413. void C_BaseAnimating::SetHitboxSetByName( const char *setname )
  6414. {
  6415. m_nHitboxSet = FindHitboxSetByName( GetModelPtr(), setname );
  6416. }
  6417. //-----------------------------------------------------------------------------
  6418. // Purpose:
  6419. // Output : int
  6420. //-----------------------------------------------------------------------------
  6421. int C_BaseAnimating::GetHitboxSet( void )
  6422. {
  6423. return m_nHitboxSet;
  6424. }
  6425. //-----------------------------------------------------------------------------
  6426. // Purpose:
  6427. // Output : char const
  6428. //-----------------------------------------------------------------------------
  6429. const char *C_BaseAnimating::GetHitboxSetName( void )
  6430. {
  6431. return ::GetHitboxSetName( GetModelPtr(), m_nHitboxSet );
  6432. }
  6433. //-----------------------------------------------------------------------------
  6434. // Purpose:
  6435. // Output : int
  6436. //-----------------------------------------------------------------------------
  6437. int C_BaseAnimating::GetHitboxSetCount( void )
  6438. {
  6439. return ::GetHitboxSetCount( GetModelPtr() );
  6440. }
  6441. static Vector hullcolor[8] =
  6442. {
  6443. Vector( 1.0, 1.0, 1.0 ),
  6444. Vector( 1.0, 0.5, 0.5 ),
  6445. Vector( 0.5, 1.0, 0.5 ),
  6446. Vector( 1.0, 1.0, 0.5 ),
  6447. Vector( 0.5, 0.5, 1.0 ),
  6448. Vector( 1.0, 0.5, 1.0 ),
  6449. Vector( 0.5, 1.0, 1.0 ),
  6450. Vector( 1.0, 1.0, 1.0 )
  6451. };
  6452. //-----------------------------------------------------------------------------
  6453. // Purpose: Draw the current hitboxes
  6454. //-----------------------------------------------------------------------------
  6455. void C_BaseAnimating::DrawClientHitboxes( float duration /*= 0.0f*/, bool monocolor /*= false*/ )
  6456. {
  6457. CStudioHdr *pStudioHdr = GetModelPtr();
  6458. if ( !pStudioHdr )
  6459. return;
  6460. mstudiohitboxset_t *set =pStudioHdr->pHitboxSet( m_nHitboxSet );
  6461. if ( !set )
  6462. return;
  6463. Vector position;
  6464. QAngle angles;
  6465. int r = 100;
  6466. int g = 0;
  6467. int b = 0;
  6468. for ( int i = 0; i < set->numhitboxes; i++ )
  6469. {
  6470. mstudiobbox_t *pbox = set->pHitbox( i );
  6471. if ( !monocolor )
  6472. {
  6473. int j = (pbox->group % 8);
  6474. r = ( int ) ( 255.0f * hullcolor[j][0] );
  6475. g = ( int ) ( 255.0f * hullcolor[j][1] );
  6476. b = ( int ) ( 255.0f * hullcolor[j][2] );
  6477. }
  6478. if ( pbox->flCapsuleRadius > 0 )
  6479. {
  6480. matrix3x4_t temp;
  6481. GetHitboxBoneTransform( pbox->bone, pbox->angOffsetOrientation, temp );
  6482. Vector vecCapsuleCenters[ 2 ];
  6483. VectorTransform( pbox->bbmin, temp, vecCapsuleCenters[0] );
  6484. VectorTransform( pbox->bbmax, temp, vecCapsuleCenters[1] );
  6485. debugoverlay->AddCapsuleOverlay( vecCapsuleCenters[0], vecCapsuleCenters[1], pbox->flCapsuleRadius, r, g, b, 255, duration );
  6486. }
  6487. else
  6488. {
  6489. GetHitboxBonePosition( pbox->bone, position, angles, pbox->angOffsetOrientation );
  6490. debugoverlay->AddBoxOverlay( position, pbox->bbmin, pbox->bbmax, angles, r, g, b, 0 ,duration );
  6491. }
  6492. }
  6493. }
  6494. //-----------------------------------------------------------------------------
  6495. // Purpose:
  6496. // Input : activity -
  6497. // Output : int C_BaseAnimating::SelectWeightedSequence
  6498. //-----------------------------------------------------------------------------
  6499. int C_BaseAnimating::SelectWeightedSequence ( int activity )
  6500. {
  6501. Assert( activity != ACT_INVALID );
  6502. return ::SelectWeightedSequence( GetModelPtr(), activity, -1 );
  6503. }
  6504. int C_BaseAnimating::SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount )
  6505. {
  6506. Assert( activity != ACT_INVALID );
  6507. Assert( GetModelPtr() );
  6508. return GetModelPtr()->SelectWeightedSequenceFromModifiers( activity, pActivityModifiers, iModifierCount );
  6509. }
  6510. //=========================================================
  6511. //=========================================================
  6512. int C_BaseAnimating::LookupPoseParameter( CStudioHdr *pstudiohdr, const char *szName )
  6513. {
  6514. if ( !pstudiohdr )
  6515. return -1;
  6516. for (int i = 0; i < pstudiohdr->GetNumPoseParameters(); i++)
  6517. {
  6518. if (stricmp( pstudiohdr->pPoseParameter( i ).pszName(), szName ) == 0)
  6519. {
  6520. return i;
  6521. }
  6522. }
  6523. // AssertMsg( 0, UTIL_VarArgs( "poseparameter %s couldn't be mapped!!!\n", szName ) );
  6524. return -1; // Error
  6525. }
  6526. //=========================================================
  6527. //=========================================================
  6528. float C_BaseAnimating::SetPoseParameter( CStudioHdr *pStudioHdr, const char *szName, float flValue )
  6529. {
  6530. return SetPoseParameter( pStudioHdr, LookupPoseParameter( pStudioHdr, szName ), flValue );
  6531. }
  6532. float C_BaseAnimating::SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue )
  6533. {
  6534. if ( !pStudioHdr )
  6535. {
  6536. Assert(!"C_BaseAnimating::SetPoseParameter: model missing");
  6537. return flValue;
  6538. }
  6539. Assert( IsFinite( flValue ) );
  6540. if ( iParameter >= 0 )
  6541. {
  6542. float flNewValue;
  6543. flValue = Studio_SetPoseParameter( pStudioHdr, iParameter, flValue, flNewValue );
  6544. m_flPoseParameter[ iParameter ] = flNewValue;
  6545. }
  6546. return flValue;
  6547. }
  6548. float C_BaseAnimating::GetPoseParameter( int iParameter )
  6549. {
  6550. CStudioHdr *pStudioHdr = GetModelPtr();
  6551. if ( pStudioHdr == NULL )
  6552. return 0.0f;
  6553. if ( !pStudioHdr )
  6554. {
  6555. Assert(!"C_BaseAnimating::SetPoseParameter: model missing");
  6556. return 0.0f;
  6557. }
  6558. if ( iParameter >= 0 )
  6559. {
  6560. return Studio_GetPoseParameter( pStudioHdr, iParameter, m_flPoseParameter[ iParameter ] );
  6561. }
  6562. return 0.0f;
  6563. }
  6564. //-----------------------------------------------------------------------------
  6565. float C_BaseAnimating::GetFirstSequenceAnimTag( int sequence, int nDesiredTag, float flStart, float flEnd )
  6566. {
  6567. Assert( GetModelPtr() );
  6568. return ::GetFirstSequenceAnimTag( GetModelPtr(), sequence, nDesiredTag, flStart, flEnd );
  6569. }
  6570. float C_BaseAnimating::GetAnySequenceAnimTag( int sequence, int nDesiredTag, float flDefault )
  6571. {
  6572. Assert( GetModelPtr() );
  6573. return ::GetAnySequenceAnimTag( GetModelPtr(), sequence, nDesiredTag, flDefault );
  6574. }
  6575. //-----------------------------------------------------------------------------
  6576. // Purpose:
  6577. // Input : *label -
  6578. // Output : int
  6579. //-----------------------------------------------------------------------------
  6580. int C_BaseAnimating::LookupSequence( const char *label )
  6581. {
  6582. Assert( GetModelPtr() );
  6583. return ::LookupSequence( GetModelPtr(), label );
  6584. }
  6585. int C_BaseAnimating::LookupSequence( CStudioHdr* pHdr, const char *label )
  6586. {
  6587. Assert( pHdr );
  6588. return ::LookupSequence( pHdr, label );
  6589. }
  6590. void C_BaseAnimating::Release()
  6591. {
  6592. ClearRagdoll();
  6593. BaseClass::Release();
  6594. }
  6595. void C_BaseAnimating::Clear( void )
  6596. {
  6597. Q_memset(&m_mouth, 0, sizeof(m_mouth));
  6598. BaseClass::Clear();
  6599. }
  6600. //-----------------------------------------------------------------------------
  6601. // Purpose: Clear current ragdoll
  6602. //-----------------------------------------------------------------------------
  6603. void C_BaseAnimating::ClearRagdoll()
  6604. {
  6605. if ( m_pRagdoll )
  6606. {
  6607. // immediately mark the member ragdoll as being NULL,
  6608. // so that we have no reentrancy problems with the delete
  6609. // (such as the disappearance of the ragdoll physics waking up
  6610. // IVP which causes other objects to move and have a touch
  6611. // callback on the ragdoll entity, which was a crash on TF)
  6612. // That is to say: it is vital that the member be cleared out
  6613. // BEFORE the delete occurs.
  6614. CRagdoll * RESTRICT pDoomed = m_pRagdoll;
  6615. m_pRagdoll = NULL;
  6616. delete pDoomed;
  6617. // Set to null so that the destructor's call to DestroyObject won't destroy
  6618. // m_pObjects[ 0 ] twice since that's the physics object for the prop
  6619. VPhysicsSetObject( NULL );
  6620. // If we have ragdoll mins/maxs, we've just come out of ragdoll, so restore them
  6621. if ( m_vecPreRagdollMins != vec3_origin || m_vecPreRagdollMaxs != vec3_origin )
  6622. {
  6623. SetCollisionBounds( m_vecPreRagdollMins, m_vecPreRagdollMaxs );
  6624. }
  6625. #if defined( REPLAY_ENABLED )
  6626. // Delete entry from ragdoll recorder if Replay is enabled on server
  6627. ConVar* pReplayEnable = (ConVar*)cvar->FindVar( "replay_enable" );
  6628. if ( pReplayEnable && pReplayEnable->GetInt() && !engine->IsPlayingDemo() && !engine->IsPlayingTimeDemo() )
  6629. {
  6630. CReplayRagdollRecorder& RagdollRecorder = CReplayRagdollRecorder::Instance();
  6631. RagdollRecorder.StopRecordingRagdoll( this );
  6632. }
  6633. #endif
  6634. }
  6635. m_builtRagdoll = false;
  6636. }
  6637. //-----------------------------------------------------------------------------
  6638. // Purpose: Looks up an activity by name.
  6639. // Input : label - Name of the activity, ie "ACT_IDLE".
  6640. // Output : Returns the activity ID or ACT_INVALID.
  6641. //-----------------------------------------------------------------------------
  6642. int C_BaseAnimating::LookupActivity( const char *label )
  6643. {
  6644. Assert( GetModelPtr() );
  6645. return ::LookupActivity( GetModelPtr(), label );
  6646. }
  6647. //-----------------------------------------------------------------------------
  6648. // Purpose:
  6649. //
  6650. // Input : iSequence -
  6651. //
  6652. // Output : char
  6653. //-----------------------------------------------------------------------------
  6654. const char *C_BaseAnimating::GetSequenceActivityName( int iSequence )
  6655. {
  6656. if( iSequence == -1 )
  6657. {
  6658. return "Not Found!";
  6659. }
  6660. if ( !GetModelPtr() )
  6661. return "No model!";
  6662. return ::GetSequenceActivityName( GetModelPtr(), iSequence );
  6663. }
  6664. //=========================================================
  6665. //=========================================================
  6666. float C_BaseAnimating::SetBoneController ( int iController, float flValue )
  6667. {
  6668. Assert( GetModelPtr() );
  6669. CStudioHdr *pmodel = GetModelPtr();
  6670. Assert(iController >= 0 && iController < NUM_BONECTRLS);
  6671. float controller = m_flEncodedController[iController];
  6672. float retVal = Studio_SetController( pmodel, iController, flValue, controller );
  6673. m_flEncodedController[iController] = controller;
  6674. return retVal;
  6675. }
  6676. void C_BaseAnimating::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles )
  6677. {
  6678. CBaseEntity *pMoveParent;
  6679. if ( IsEffectActive( EF_BONEMERGE ) && IsEffectActive( EF_BONEMERGE_FASTCULL ) && (pMoveParent = GetMoveParent()) != NULL )
  6680. {
  6681. // Doing this saves a lot of CPU.
  6682. *pAbsOrigin = pMoveParent->GetRenderOrigin();
  6683. *pAbsAngles = pMoveParent->GetRenderAngles();
  6684. }
  6685. else
  6686. {
  6687. if ( !m_pBoneMergeCache || !m_pBoneMergeCache->GetAimEntOrigin( pAbsOrigin, pAbsAngles ) )
  6688. BaseClass::GetAimEntOrigin( pAttachedTo, pAbsOrigin, pAbsAngles );
  6689. }
  6690. }
  6691. //-----------------------------------------------------------------------------
  6692. // Purpose:
  6693. //
  6694. // Input : iSequence -
  6695. //
  6696. // Output : char
  6697. //-----------------------------------------------------------------------------
  6698. const char *C_BaseAnimating::GetSequenceName( int iSequence )
  6699. {
  6700. if( iSequence == -1 )
  6701. {
  6702. return "Not Found!";
  6703. }
  6704. if ( !GetModelPtr() )
  6705. return "No model!";
  6706. return ::GetSequenceName( GetModelPtr(), iSequence );
  6707. }
  6708. Activity C_BaseAnimating::GetSequenceActivity( int iSequence )
  6709. {
  6710. if( iSequence == -1 )
  6711. {
  6712. return ACT_INVALID;
  6713. }
  6714. if ( !GetModelPtr() )
  6715. return ACT_INVALID;
  6716. return (Activity)::GetSequenceActivity( GetModelPtr(), iSequence );
  6717. }
  6718. //-----------------------------------------------------------------------------
  6719. // Computes a box that surrounds all hitboxes
  6720. //-----------------------------------------------------------------------------
  6721. bool C_BaseAnimating::ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
  6722. {
  6723. // Note that this currently should not be called during position recomputation because of IK.
  6724. // The code below recomputes bones so as to get at the hitboxes,
  6725. // which causes IK to trigger, which causes raycasts against the other entities to occur,
  6726. // which is illegal to do while in the computeabsposition phase.
  6727. CStudioHdr *pStudioHdr = GetModelPtr();
  6728. if (!pStudioHdr)
  6729. return false;
  6730. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  6731. if ( !set || !set->numhitboxes )
  6732. return false;
  6733. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  6734. HitboxToWorldTransforms( hitboxbones );
  6735. // Compute a box in world space that surrounds this entity
  6736. pVecWorldMins->Init( FLT_MAX, FLT_MAX, FLT_MAX );
  6737. pVecWorldMaxs->Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  6738. Vector vecBoxAbsMins, vecBoxAbsMaxs;
  6739. for ( int i = 0; i < set->numhitboxes; i++ )
  6740. {
  6741. mstudiobbox_t *pbox = set->pHitbox(i);
  6742. TransformAABB( *hitboxbones[pbox->bone], pbox->bbmin, pbox->bbmax, vecBoxAbsMins, vecBoxAbsMaxs );
  6743. VectorMin( *pVecWorldMins, vecBoxAbsMins, *pVecWorldMins );
  6744. VectorMax( *pVecWorldMaxs, vecBoxAbsMaxs, *pVecWorldMaxs );
  6745. }
  6746. return true;
  6747. }
  6748. //-----------------------------------------------------------------------------
  6749. // Computes a box that surrounds all hitboxes, in entity space
  6750. //-----------------------------------------------------------------------------
  6751. bool C_BaseAnimating::ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
  6752. {
  6753. // Note that this currently should not be called during position recomputation because of IK.
  6754. // The code below recomputes bones so as to get at the hitboxes,
  6755. // which causes IK to trigger, which causes raycasts against the other entities to occur,
  6756. // which is illegal to do while in the computeabsposition phase.
  6757. CStudioHdr *pStudioHdr = GetModelPtr();
  6758. if (!pStudioHdr)
  6759. return false;
  6760. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  6761. if ( !set || !set->numhitboxes )
  6762. return false;
  6763. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  6764. HitboxToWorldTransforms( hitboxbones );
  6765. // Compute a box in world space that surrounds this entity
  6766. pVecWorldMins->Init( FLT_MAX, FLT_MAX, FLT_MAX );
  6767. pVecWorldMaxs->Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  6768. matrix3x4_t worldToEntity, boneToEntity;
  6769. MatrixInvert( EntityToWorldTransform(), worldToEntity );
  6770. Vector vecBoxAbsMins, vecBoxAbsMaxs;
  6771. for ( int i = 0; i < set->numhitboxes; i++ )
  6772. {
  6773. mstudiobbox_t *pbox = set->pHitbox(i);
  6774. ConcatTransforms( worldToEntity, *hitboxbones[pbox->bone], boneToEntity );
  6775. TransformAABB( boneToEntity, pbox->bbmin, pbox->bbmax, vecBoxAbsMins, vecBoxAbsMaxs );
  6776. VectorMin( *pVecWorldMins, vecBoxAbsMins, *pVecWorldMins );
  6777. VectorMax( *pVecWorldMaxs, vecBoxAbsMaxs, *pVecWorldMaxs );
  6778. }
  6779. return true;
  6780. }
  6781. //-----------------------------------------------------------------------------
  6782. // Purpose:
  6783. // Input : scale -
  6784. //-----------------------------------------------------------------------------
  6785. void C_BaseAnimating::SetModelScale( float scale, ModelScaleType_t scaleType /*= HIERARCHICAL_MODEL_SCALE*/ )
  6786. {
  6787. if ( m_flModelScale != scale || scaleType != m_ScaleType )
  6788. {
  6789. m_flModelScale = scale;
  6790. SetModelScaleType( scaleType );
  6791. InvalidatePhysicsRecursive( BOUNDS_CHANGED );
  6792. }
  6793. }
  6794. float C_BaseAnimating::GetModelHierarchyScale() const
  6795. {
  6796. if ( GetModelScaleType() == HIERARCHICAL_MODEL_SCALE )
  6797. return m_flModelScale;
  6798. CStudioHdr* pHdr = GetModelPtr();
  6799. return ( pHdr && pHdr->numbones() == 1 ) ? m_flModelScale : 1.0f;
  6800. }
  6801. ModelScaleType_t C_BaseAnimating::GetModelScaleType() const
  6802. {
  6803. return m_ScaleType;
  6804. }
  6805. void C_BaseAnimating::SetModelScaleType( ModelScaleType_t scaleType )
  6806. {
  6807. m_ScaleType = scaleType;
  6808. }
  6809. void C_BaseAnimating::SetCustomMaterial( ICustomMaterial *pCustomMaterial, int nIndex )
  6810. {
  6811. if ( !pCustomMaterial )
  6812. return;
  6813. const char* szCustomMatName = pCustomMaterial->GetBaseMaterialName();
  6814. studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( m_hStudioHdr );
  6815. for ( int i = 0; i < pStudioHdr->numtextures; ++i )
  6816. {
  6817. mstudiotexture_t *pTexture = pStudioHdr->pTexture( i );
  6818. if ( V_strcasecmp( szCustomMatName, V_UnqualifiedFileName( pTexture->pszName() ) ) == 0 )
  6819. {
  6820. CCustomMaterialOwner::SetCustomMaterial( pCustomMaterial, i );
  6821. m_bCanUseFastPath = false;
  6822. return;
  6823. }
  6824. }
  6825. Assert( 0 );
  6826. Warning( "Failed to set custom material for '%s', no matching material name found on model %s\n", szCustomMatName, GetModel() ? modelinfo->GetModelName( GetModel() ) : "<nomodel>" );
  6827. }
  6828. //-----------------------------------------------------------------------------
  6829. // Purpose: Clientside bone follower class. Used just to visualize them.
  6830. // Bone followers WON'T be sent to the client if VISUALIZE_FOLLOWERS is
  6831. // undefined in the server's physics_bone_followers.cpp
  6832. //-----------------------------------------------------------------------------
  6833. class C_BoneFollower : public C_BaseEntity
  6834. {
  6835. DECLARE_CLASS( C_BoneFollower, C_BaseEntity );
  6836. DECLARE_CLIENTCLASS();
  6837. public:
  6838. C_BoneFollower( void )
  6839. {
  6840. }
  6841. bool ShouldDraw( void );
  6842. int DrawModel( int flags, const RenderableInstance_t &instance );
  6843. bool TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace );
  6844. private:
  6845. int m_modelIndex;
  6846. int m_solidIndex;
  6847. };
  6848. IMPLEMENT_CLIENTCLASS_DT( C_BoneFollower, DT_BoneFollower, CBoneFollower )
  6849. RecvPropInt( RECVINFO( m_modelIndex ) ),
  6850. RecvPropInt( RECVINFO( m_solidIndex ) ),
  6851. END_RECV_TABLE()
  6852. void VCollideWireframe_ChangeCallback( IConVar *pConVar, char const *pOldString, float flOldValue )
  6853. {
  6854. for ( C_BaseEntity *pEntity = ClientEntityList().FirstBaseEntity(); pEntity; pEntity = ClientEntityList().NextBaseEntity(pEntity) )
  6855. {
  6856. pEntity->UpdateVisibility();
  6857. }
  6858. }
  6859. //-----------------------------------------------------------------------------
  6860. // Purpose: Returns whether object should render.
  6861. //-----------------------------------------------------------------------------
  6862. bool C_BoneFollower::ShouldDraw( void )
  6863. {
  6864. return ( vcollide_wireframe.GetBool() ); //MOTODO
  6865. }
  6866. //-----------------------------------------------------------------------------
  6867. // Purpose:
  6868. //-----------------------------------------------------------------------------
  6869. int C_BoneFollower::DrawModel( int flags, const RenderableInstance_t &instance )
  6870. {
  6871. vcollide_t *pCollide = modelinfo->GetVCollide( m_modelIndex );
  6872. if ( pCollide )
  6873. {
  6874. static color32 debugColor = {0,255,255,0};
  6875. matrix3x4_t matrix;
  6876. AngleMatrix( GetAbsAngles(), GetAbsOrigin(), matrix );
  6877. engine->DebugDrawPhysCollide( pCollide->solids[m_solidIndex], NULL, matrix, debugColor );
  6878. }
  6879. return 1;
  6880. }
  6881. bool C_BoneFollower::TestCollision( const Ray_t &ray, unsigned int mask, trace_t& trace )
  6882. {
  6883. vcollide_t *pCollide = modelinfo->GetVCollide( m_modelIndex );
  6884. Assert( pCollide && pCollide->solidCount > m_solidIndex );
  6885. if ( !pCollide )
  6886. {
  6887. DevWarning("Failed to get collision model (%d, %d), %s (%s)\n", m_modelIndex, m_solidIndex, modelinfo->GetModelName(modelinfo->GetModel(m_modelIndex)), IsDormant() ? "dormant" : "active" );
  6888. return false;
  6889. }
  6890. physcollision->TraceBox( ray, pCollide->solids[m_solidIndex], GetAbsOrigin(), GetAbsAngles(), &trace );
  6891. if ( trace.fraction >= 1 )
  6892. return false;
  6893. // return owner as trace hit
  6894. trace.m_pEnt = GetOwnerEntity();
  6895. trace.hitgroup = 0;//m_hitGroup;
  6896. trace.physicsbone = 0;//m_physicsBone; // UNDONE: Get physics bone index & hitgroup
  6897. return trace.DidHit();
  6898. }
  6899. void C_BaseAnimating::DisableMuzzleFlash()
  6900. {
  6901. m_nOldMuzzleFlashParity = m_nMuzzleFlashParity;
  6902. }
  6903. void C_BaseAnimating::DoMuzzleFlash()
  6904. {
  6905. m_nMuzzleFlashParity = (m_nMuzzleFlashParity+1) & ((1 << EF_MUZZLEFLASH_BITS) - 1);
  6906. }
  6907. //-----------------------------------------------------------------------------
  6908. // Purpose:
  6909. //-----------------------------------------------------------------------------
  6910. void DevMsgRT( PRINTF_FORMAT_STRING char const* pMsg, ... )
  6911. {
  6912. if (!engine->Con_IsVisible())
  6913. {
  6914. va_list argptr;
  6915. va_start( argptr, pMsg );
  6916. //
  6917. {
  6918. static char string[1024];
  6919. Q_vsnprintf (string, sizeof( string ), pMsg, argptr);
  6920. DevMsg( 1, "%s", string );
  6921. }
  6922. // DevMsg( pMsg, argptr );
  6923. va_end( argptr );
  6924. }
  6925. }
  6926. void C_BaseAnimating::ForceClientSideAnimationOn()
  6927. {
  6928. m_bClientSideAnimation = true;
  6929. AddToClientSideAnimationList();
  6930. }
  6931. void C_BaseAnimating::AddToClientSideAnimationList()
  6932. {
  6933. // Already in list
  6934. if ( m_ClientSideAnimationListHandle != INVALID_CLIENTSIDEANIMATION_LIST_HANDLE )
  6935. return;
  6936. clientanimating_t list( this, 0 );
  6937. m_ClientSideAnimationListHandle = g_ClientSideAnimationList.AddToTail( list );
  6938. ClientSideAnimationChanged();
  6939. }
  6940. void C_BaseAnimating::RemoveFromClientSideAnimationList()
  6941. {
  6942. // Not in list yet
  6943. if ( INVALID_CLIENTSIDEANIMATION_LIST_HANDLE == m_ClientSideAnimationListHandle )
  6944. return;
  6945. unsigned int c = g_ClientSideAnimationList.Count();
  6946. Assert( m_ClientSideAnimationListHandle < c );
  6947. unsigned int last = c - 1;
  6948. if ( last == m_ClientSideAnimationListHandle )
  6949. {
  6950. // Just wipe the final entry
  6951. g_ClientSideAnimationList.FastRemove( last );
  6952. }
  6953. else
  6954. {
  6955. clientanimating_t lastEntry = g_ClientSideAnimationList[ last ];
  6956. // Remove the last entry
  6957. g_ClientSideAnimationList.FastRemove( last );
  6958. // And update it's handle to point to this slot.
  6959. lastEntry.pAnimating->m_ClientSideAnimationListHandle = m_ClientSideAnimationListHandle;
  6960. g_ClientSideAnimationList[ m_ClientSideAnimationListHandle ] = lastEntry;
  6961. }
  6962. // Invalidate our handle no matter what.
  6963. m_ClientSideAnimationListHandle = INVALID_CLIENTSIDEANIMATION_LIST_HANDLE;
  6964. }
  6965. // static method
  6966. void C_BaseAnimating::UpdateClientSideAnimations()
  6967. {
  6968. SNPROF_ANIM( "C_BaseAnimating::UpdateClientSideAnimations" );
  6969. VPROF_BUDGET( "UpdateClientSideAnimations", VPROF_BUDGETGROUP_CLIENT_ANIMATION );
  6970. int c = g_ClientSideAnimationList.Count();
  6971. for ( int i = 0; i < c ; ++i )
  6972. {
  6973. clientanimating_t &anim = g_ClientSideAnimationList.Element(i);
  6974. if ( !(anim.flags & FCLIENTANIM_SEQUENCE_CYCLE) )
  6975. continue;
  6976. Assert( anim.pAnimating );
  6977. anim.pAnimating->UpdateClientSideAnimation();
  6978. }
  6979. }
  6980. CBoneList *C_BaseAnimating::RecordBones( CStudioHdr *hdr, matrix3x4_t *pBoneState )
  6981. {
  6982. if ( !ToolsEnabled() )
  6983. return NULL;
  6984. VPROF_BUDGET( "C_BaseAnimating::RecordBones", VPROF_BUDGETGROUP_TOOLS );
  6985. // Possible optimization: Instead of inverting everything while recording, record the pos/q stuff into a structure instead?
  6986. Assert( hdr );
  6987. // Setup our transform based on render angles and origin.
  6988. matrix3x4_t parentTransform;
  6989. AngleMatrix( GetRenderAngles(), GetRenderOrigin(), parentTransform );
  6990. Assert( !m_bBoneListInUse );
  6991. CBoneList *boneList = m_bBoneListInUse ? CBoneList::Alloc() : &m_recordingBoneList;
  6992. m_bBoneListInUse = true;
  6993. boneList->m_nBones = hdr->numbones();
  6994. for ( int i = 0; i < hdr->numbones(); i++ )
  6995. {
  6996. matrix3x4_t inverted;
  6997. matrix3x4_t output;
  6998. const mstudiobone_t *bone = hdr->pBone( i );
  6999. // Only update bones referenced during setup
  7000. if ( !(bone->flags & BONE_USED_BY_ANYTHING ) )
  7001. {
  7002. boneList->m_quatRot[ i ].Init( 0.0f, 0.0f, 0.0f, 1.0f ); // Init by default sets all 0's, which is invalid
  7003. boneList->m_vecPos[ i ].Init();
  7004. continue;
  7005. }
  7006. if ( bone->parent == -1 )
  7007. {
  7008. // Decompose into parent space
  7009. MatrixInvert( parentTransform, inverted );
  7010. }
  7011. else
  7012. {
  7013. MatrixInvert( pBoneState[ bone->parent ], inverted );
  7014. }
  7015. ConcatTransforms( inverted, pBoneState[ i ], output );
  7016. MatrixAngles( output,
  7017. boneList->m_quatRot[ i ],
  7018. boneList->m_vecPos[ i ] );
  7019. }
  7020. return boneList;
  7021. }
  7022. void C_BaseAnimating::GetToolRecordingState( KeyValues *msg )
  7023. {
  7024. if ( !ToolsEnabled() )
  7025. return;
  7026. VPROF_BUDGET( "C_BaseAnimating::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
  7027. // Force the animation to drive bones
  7028. CStudioHdr *hdr = GetModelPtr();
  7029. matrix3x4a_t *pBones = (matrix3x4a_t*)stackalloc( ( hdr ? hdr->numbones() : 1 ) * sizeof(matrix3x4_t) );
  7030. if ( hdr )
  7031. {
  7032. SetupBones( pBones, hdr->numbones(), BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  7033. }
  7034. else
  7035. {
  7036. SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  7037. }
  7038. BaseClass::GetToolRecordingState( msg );
  7039. static BaseAnimatingRecordingState_t state;
  7040. state.m_nSkin = GetSkin();
  7041. state.m_nBody = GetBody();
  7042. state.m_nSequence = m_nSequence;
  7043. state.m_pBoneList = hdr ? RecordBones( hdr, pBones ) : NULL;
  7044. msg->SetPtr( "baseanimating", &state );
  7045. msg->SetBool( "viewmodel", IsViewModelOrAttachment() );
  7046. if ( IsViewModel() )
  7047. {
  7048. C_BaseViewModel *pViewModel = assert_cast< C_BaseViewModel* >( this );
  7049. C_BaseCombatWeapon *pWeapon = pViewModel->GetOwningWeapon();
  7050. if ( pWeapon )
  7051. {
  7052. pWeapon->GetToolViewModelState( msg );
  7053. }
  7054. }
  7055. }
  7056. void C_BaseAnimating::CleanupToolRecordingState( KeyValues *msg )
  7057. {
  7058. if ( !ToolsEnabled() )
  7059. return;
  7060. BaseAnimatingRecordingState_t *pState = (BaseAnimatingRecordingState_t*)msg->GetPtr( "baseanimating" );
  7061. if ( pState && pState->m_pBoneList )
  7062. {
  7063. if ( pState->m_pBoneList != &m_recordingBoneList )
  7064. {
  7065. pState->m_pBoneList->Release();
  7066. }
  7067. else
  7068. {
  7069. Assert( m_bBoneListInUse );
  7070. m_bBoneListInUse = false;
  7071. }
  7072. }
  7073. BaseClass::CleanupToolRecordingState( msg );
  7074. }
  7075. LocalFlexController_t C_BaseAnimating::GetNumFlexControllers( void )
  7076. {
  7077. CStudioHdr *pstudiohdr = GetModelPtr( );
  7078. if (! pstudiohdr)
  7079. return LocalFlexController_t(0);
  7080. return pstudiohdr->numflexcontrollers();
  7081. }
  7082. const char *C_BaseAnimating::GetFlexDescFacs( int iFlexDesc )
  7083. {
  7084. CStudioHdr *pstudiohdr = GetModelPtr( );
  7085. if (! pstudiohdr)
  7086. return 0;
  7087. mstudioflexdesc_t *pflexdesc = pstudiohdr->pFlexdesc( iFlexDesc );
  7088. return pflexdesc->pszFACS( );
  7089. }
  7090. const char *C_BaseAnimating::GetFlexControllerName( LocalFlexController_t iFlexController )
  7091. {
  7092. CStudioHdr *pstudiohdr = GetModelPtr( );
  7093. if (! pstudiohdr)
  7094. return 0;
  7095. mstudioflexcontroller_t *pflexcontroller = pstudiohdr->pFlexcontroller( iFlexController );
  7096. return pflexcontroller->pszName( );
  7097. }
  7098. const char *C_BaseAnimating::GetFlexControllerType( LocalFlexController_t iFlexController )
  7099. {
  7100. CStudioHdr *pstudiohdr = GetModelPtr( );
  7101. if (! pstudiohdr)
  7102. return 0;
  7103. mstudioflexcontroller_t *pflexcontroller = pstudiohdr->pFlexcontroller( iFlexController );
  7104. return pflexcontroller->pszType( );
  7105. }
  7106. //-----------------------------------------------------------------------------
  7107. // Purpose: Note that we've been transmitted a sequence
  7108. //-----------------------------------------------------------------------------
  7109. void C_BaseAnimating::SetReceivedSequence( void )
  7110. {
  7111. m_bReceivedSequence = true;
  7112. }
  7113. //-----------------------------------------------------------------------------
  7114. // Purpose: See if we should force reset our sequence on a new model
  7115. //-----------------------------------------------------------------------------
  7116. bool C_BaseAnimating::ShouldResetSequenceOnNewModel( void )
  7117. {
  7118. return ( m_bReceivedSequence == false );
  7119. }
  7120. //-----------------------------------------------------------------------------
  7121. // Purpose:
  7122. //-----------------------------------------------------------------------------
  7123. void C_BaseAnimating::UpdateBoneAttachments( void )
  7124. {
  7125. if ( !m_pAttachedTo )
  7126. return;
  7127. // Assert( IsFollowingEntity() );
  7128. // Assert( m_boneIndexAttached >= 0 );
  7129. C_BaseAnimating *follow = FindFollowedEntity();
  7130. if ( follow && (m_boneIndexAttached >= 0) )
  7131. {
  7132. matrix3x4_t boneToWorld, localSpace;
  7133. follow->GetCachedBoneMatrix( m_boneIndexAttached, boneToWorld );
  7134. AngleMatrix( m_boneAngles, m_bonePosition, localSpace );
  7135. ConcatTransforms( boneToWorld, localSpace, GetBoneForWrite( 0 ) );
  7136. Vector absOrigin;
  7137. MatrixGetColumn( GetBone( 0 ), 3, absOrigin );
  7138. SetAbsOrigin( absOrigin );
  7139. QAngle absAngle;
  7140. MatrixAngles( GetBone( 0 ), absAngle );
  7141. SetAbsAngles( absAngle);
  7142. }
  7143. }
  7144. //-----------------------------------------------------------------------------
  7145. // Purpose:
  7146. //-----------------------------------------------------------------------------
  7147. void C_BaseAnimating::AttachEntityToBone( C_BaseAnimating* attachTarget, int boneIndexAttached, Vector bonePosition, QAngle boneAngles )
  7148. {
  7149. if ( !attachTarget )
  7150. return;
  7151. SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  7152. FollowEntity( attachTarget );
  7153. SetOwnerEntity( attachTarget );
  7154. // Assert( boneIndexAttached >= 0 ); // We should be attaching to a bone.
  7155. if ( boneIndexAttached >= 0 )
  7156. {
  7157. m_boneIndexAttached = boneIndexAttached;
  7158. m_bonePosition = bonePosition;
  7159. m_boneAngles = boneAngles;
  7160. }
  7161. m_BoneAccessor.SetReadableBones( BONE_USED_BY_ANYTHING );
  7162. m_BoneAccessor.SetWritableBones( BONE_USED_BY_ANYTHING );
  7163. attachTarget->AddBoneAttachment( this );
  7164. NotifyBoneAttached( attachTarget );
  7165. }
  7166. //-----------------------------------------------------------------------------
  7167. // Purpose:
  7168. //-----------------------------------------------------------------------------
  7169. void C_BaseAnimating::NotifyBoneAttached( C_BaseAnimating* attachTarget )
  7170. {
  7171. // If we're already attached to something, remove us from it.
  7172. if ( m_pAttachedTo )
  7173. {
  7174. m_pAttachedTo->RemoveBoneAttachment( this );
  7175. m_pAttachedTo = NULL;
  7176. }
  7177. // Remember the new attach target.
  7178. m_pAttachedTo = attachTarget;
  7179. // Special case: if we just attached to the local player and he is hidden, hide us as well.
  7180. C_BasePlayer *pPlayer = dynamic_cast< C_BasePlayer* >( attachTarget );
  7181. if ( pPlayer && pPlayer->IsLocalPlayer() )
  7182. {
  7183. if ( !pPlayer->ShouldDrawLocalPlayer() )
  7184. {
  7185. AddEffects( EF_NODRAW );
  7186. }
  7187. }
  7188. else
  7189. {
  7190. RemoveEffects( EF_NODRAW );
  7191. }
  7192. }
  7193. //-----------------------------------------------------------------------------
  7194. // Purpose:
  7195. //-----------------------------------------------------------------------------
  7196. void C_BaseAnimating::AddBoneAttachment( C_BaseAnimating* newBoneAttachment )
  7197. {
  7198. if ( !newBoneAttachment )
  7199. return;
  7200. m_BoneAttachments.AddToTail( newBoneAttachment );
  7201. }
  7202. //-----------------------------------------------------------------------------
  7203. // Purpose:
  7204. //-----------------------------------------------------------------------------
  7205. void C_BaseAnimating::RemoveBoneAttachment( C_BaseAnimating* boneAttachment )
  7206. {
  7207. if ( !boneAttachment )
  7208. return;
  7209. m_BoneAttachments.FindAndRemove( boneAttachment );
  7210. }
  7211. //-----------------------------------------------------------------------------
  7212. // Purpose:
  7213. //-----------------------------------------------------------------------------
  7214. int C_BaseAnimating::GetNumBoneAttachments()
  7215. {
  7216. return m_BoneAttachments.Count();
  7217. }
  7218. //-----------------------------------------------------------------------------
  7219. // Purpose:
  7220. //-----------------------------------------------------------------------------
  7221. C_BaseAnimating* C_BaseAnimating::GetBoneAttachment( int i )
  7222. {
  7223. if ( m_BoneAttachments.IsValidIndex(i) )
  7224. {
  7225. return m_BoneAttachments[i];
  7226. }
  7227. return NULL;
  7228. }
  7229. //-----------------------------------------------------------------------------
  7230. // Purpose:
  7231. //-----------------------------------------------------------------------------
  7232. void C_BaseAnimating::DestroyBoneAttachments()
  7233. {
  7234. while ( GetNumBoneAttachments() )
  7235. {
  7236. C_BaseAnimating *pAttachment = GetBoneAttachment(0);
  7237. if ( pAttachment )
  7238. {
  7239. pAttachment->Release();
  7240. }
  7241. else
  7242. {
  7243. m_BoneAttachments.Remove(0);
  7244. }
  7245. }
  7246. }
  7247. //-----------------------------------------------------------------------------
  7248. // Purpose:
  7249. //-----------------------------------------------------------------------------
  7250. void C_BaseAnimating::MoveBoneAttachments( C_BaseAnimating* attachTarget )
  7251. {
  7252. if ( !attachTarget )
  7253. return;
  7254. // Move all of our bone attachments to this new object.
  7255. // Preserves the specific bone and attachment location information.
  7256. while ( GetNumBoneAttachments() )
  7257. {
  7258. C_BaseAnimating *pAttachment = GetBoneAttachment(0);
  7259. if ( pAttachment )
  7260. {
  7261. pAttachment->AttachEntityToBone( attachTarget );
  7262. }
  7263. else
  7264. {
  7265. m_BoneAttachments.Remove(0);
  7266. }
  7267. }
  7268. }
  7269. bool C_BaseAnimating::m_bBoneListInUse = false;
  7270. CBoneList C_BaseAnimating::m_recordingBoneList;