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

511 lines
15 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Client side view model implementation. Responsible for drawing
  4. // the view model.
  5. //
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "c_baseviewmodel.h"
  10. #include "model_types.h"
  11. #include "hud.h"
  12. #include "view_shared.h"
  13. #include "iviewrender.h"
  14. #include "view.h"
  15. #include "mathlib/vmatrix.h"
  16. #include "cl_animevent.h"
  17. #include "eventlist.h"
  18. #include "tools/bonelist.h"
  19. #include <KeyValues.h>
  20. #include "hltvcamera.h"
  21. #ifdef TF_CLIENT_DLL
  22. #include "tf_weaponbase.h"
  23. #endif
  24. #if defined( REPLAY_ENABLED )
  25. #include "replay/replaycamera.h"
  26. #include "replay/ireplaysystem.h"
  27. #include "replay/ienginereplay.h"
  28. #endif
  29. // NVNT haptics system interface
  30. #include "haptics/ihaptics.h"
  31. // memdbgon must be the last include file in a .cpp file!!!
  32. #include "tier0/memdbgon.h"
  33. #ifdef CSTRIKE_DLL
  34. ConVar cl_righthand( "cl_righthand", "1", FCVAR_ARCHIVE, "Use right-handed view models." );
  35. #endif
  36. #ifdef TF_CLIENT_DLL
  37. ConVar cl_flipviewmodels( "cl_flipviewmodels", "0", FCVAR_USERINFO | FCVAR_ARCHIVE | FCVAR_NOT_CONNECTED, "Flip view models." );
  38. #endif
  39. void PostToolMessage( HTOOLHANDLE hEntity, KeyValues *msg );
  40. void FormatViewModelAttachment( Vector &vOrigin, bool bInverse )
  41. {
  42. // Presumably, SetUpView has been called so we know our FOV and render origin.
  43. const CViewSetup *pViewSetup = view->GetPlayerViewSetup();
  44. float worldx = tan( pViewSetup->fov * M_PI/360.0 );
  45. float viewx = tan( pViewSetup->fovViewmodel * M_PI/360.0 );
  46. // aspect ratio cancels out, so only need one factor
  47. // the difference between the screen coordinates of the 2 systems is the ratio
  48. // of the coefficients of the projection matrices (tan (fov/2) is that coefficient)
  49. // NOTE: viewx was coming in as 0 when folks set their viewmodel_fov to 0 and show their weapon.
  50. float factorX = viewx ? ( worldx / viewx ) : 0.0f;
  51. float factorY = factorX;
  52. // Get the coordinates in the viewer's space.
  53. Vector tmp = vOrigin - pViewSetup->origin;
  54. Vector vTransformed( MainViewRight().Dot( tmp ), MainViewUp().Dot( tmp ), MainViewForward().Dot( tmp ) );
  55. // Now squash X and Y.
  56. if ( bInverse )
  57. {
  58. if ( factorX != 0 && factorY != 0 )
  59. {
  60. vTransformed.x /= factorX;
  61. vTransformed.y /= factorY;
  62. }
  63. else
  64. {
  65. vTransformed.x = 0.0f;
  66. vTransformed.y = 0.0f;
  67. }
  68. }
  69. else
  70. {
  71. vTransformed.x *= factorX;
  72. vTransformed.y *= factorY;
  73. }
  74. // Transform back to world space.
  75. Vector vOut = (MainViewRight() * vTransformed.x) + (MainViewUp() * vTransformed.y) + (MainViewForward() * vTransformed.z);
  76. vOrigin = pViewSetup->origin + vOut;
  77. }
  78. void C_BaseViewModel::FormatViewModelAttachment( int nAttachment, matrix3x4_t &attachmentToWorld )
  79. {
  80. Vector vecOrigin;
  81. MatrixPosition( attachmentToWorld, vecOrigin );
  82. ::FormatViewModelAttachment( vecOrigin, false );
  83. PositionMatrix( vecOrigin, attachmentToWorld );
  84. }
  85. bool C_BaseViewModel::IsViewModel() const
  86. {
  87. return true;
  88. }
  89. void C_BaseViewModel::UncorrectViewModelAttachment( Vector &vOrigin )
  90. {
  91. // Unformat the attachment.
  92. ::FormatViewModelAttachment( vOrigin, true );
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose
  96. //-----------------------------------------------------------------------------
  97. void C_BaseViewModel::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
  98. {
  99. // We override sound requests so that we can play them locally on the owning player
  100. if ( ( event == AE_CL_PLAYSOUND ) || ( event == CL_EVENT_SOUND ) )
  101. {
  102. // Only do this if we're owned by someone
  103. if ( GetOwner() != NULL )
  104. {
  105. CLocalPlayerFilter filter;
  106. EmitSound( filter, GetOwner()->GetSoundSourceIndex(), options, &GetAbsOrigin() );
  107. return;
  108. }
  109. }
  110. // Otherwise pass the event to our associated weapon
  111. C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
  112. if ( pWeapon )
  113. {
  114. // NVNT notify the haptics system of our viewmodel's event
  115. if ( haptics )
  116. haptics->ProcessHapticEvent(4,"Weapons",pWeapon->GetName(),"AnimationEvents",VarArgs("%i",event));
  117. bool bResult = pWeapon->OnFireEvent( this, origin, angles, event, options );
  118. if ( !bResult )
  119. {
  120. BaseClass::FireEvent( origin, angles, event, options );
  121. }
  122. }
  123. }
  124. bool C_BaseViewModel::Interpolate( float currentTime )
  125. {
  126. CStudioHdr *pStudioHdr = GetModelPtr();
  127. // Make sure we reset our animation information if we've switch sequences
  128. UpdateAnimationParity();
  129. bool bret = BaseClass::Interpolate( currentTime );
  130. // Hack to extrapolate cycle counter for view model
  131. float elapsed_time = currentTime - m_flAnimTime;
  132. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  133. // Predicted viewmodels have fixed up interval
  134. if ( GetPredictable() || IsClientCreated() )
  135. {
  136. Assert( pPlayer );
  137. float curtime = pPlayer ? pPlayer->GetFinalPredictedTime() : gpGlobals->curtime;
  138. elapsed_time = curtime - m_flAnimTime;
  139. // Adjust for interpolated partial frame
  140. if ( !engine->IsPaused() )
  141. {
  142. elapsed_time += ( gpGlobals->interpolation_amount * TICK_INTERVAL );
  143. }
  144. }
  145. // Prediction errors?
  146. if ( elapsed_time < 0 )
  147. {
  148. elapsed_time = 0;
  149. }
  150. float dt = elapsed_time * GetSequenceCycleRate( pStudioHdr, GetSequence() ) * GetPlaybackRate();
  151. if ( dt >= 1.0f )
  152. {
  153. if ( !IsSequenceLooping( GetSequence() ) )
  154. {
  155. dt = 0.999f;
  156. }
  157. else
  158. {
  159. dt = fmod( dt, 1.0f );
  160. }
  161. }
  162. SetCycle( dt );
  163. return bret;
  164. }
  165. bool C_BaseViewModel::ShouldFlipViewModel()
  166. {
  167. #ifdef CSTRIKE_DLL
  168. // If cl_righthand is set, then we want them all right-handed.
  169. CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
  170. if ( pWeapon )
  171. {
  172. const FileWeaponInfo_t *pInfo = &pWeapon->GetWpnData();
  173. return pInfo->m_bAllowFlipping && pInfo->m_bBuiltRightHanded != cl_righthand.GetBool();
  174. }
  175. #endif
  176. #ifdef TF_CLIENT_DLL
  177. CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
  178. if ( pWeapon )
  179. {
  180. return pWeapon->m_bFlipViewModel != cl_flipviewmodels.GetBool();
  181. }
  182. #endif
  183. return false;
  184. }
  185. void C_BaseViewModel::ApplyBoneMatrixTransform( matrix3x4_t& transform )
  186. {
  187. if ( ShouldFlipViewModel() )
  188. {
  189. matrix3x4_t viewMatrix, viewMatrixInverse;
  190. // We could get MATERIAL_VIEW here, but this is called sometimes before the renderer
  191. // has set that matrix. Luckily, this is called AFTER the CViewSetup has been initialized.
  192. const CViewSetup *pSetup = view->GetPlayerViewSetup();
  193. AngleMatrix( pSetup->angles, pSetup->origin, viewMatrixInverse );
  194. MatrixInvert( viewMatrixInverse, viewMatrix );
  195. // Transform into view space.
  196. matrix3x4_t temp, temp2;
  197. ConcatTransforms( viewMatrix, transform, temp );
  198. // Flip it along X.
  199. // (This is the slower way to do it, and it equates to negating the top row).
  200. //matrix3x4_t mScale;
  201. //SetIdentityMatrix( mScale );
  202. //mScale[0][0] = 1;
  203. //mScale[1][1] = -1;
  204. //mScale[2][2] = 1;
  205. //ConcatTransforms( mScale, temp, temp2 );
  206. temp[1][0] = -temp[1][0];
  207. temp[1][1] = -temp[1][1];
  208. temp[1][2] = -temp[1][2];
  209. temp[1][3] = -temp[1][3];
  210. // Transform back out of view space.
  211. ConcatTransforms( viewMatrixInverse, temp, transform );
  212. }
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: check if weapon viewmodel should be drawn
  216. //-----------------------------------------------------------------------------
  217. bool C_BaseViewModel::ShouldDraw()
  218. {
  219. if ( engine->IsHLTV() )
  220. {
  221. return ( HLTVCamera()->GetMode() == OBS_MODE_IN_EYE &&
  222. HLTVCamera()->GetPrimaryTarget() == GetOwner() );
  223. }
  224. #if defined( REPLAY_ENABLED )
  225. else if ( g_pEngineClientReplay->IsPlayingReplayDemo() )
  226. {
  227. return ( ReplayCamera()->GetMode() == OBS_MODE_IN_EYE &&
  228. ReplayCamera()->GetPrimaryTarget() == GetOwner() );
  229. }
  230. #endif
  231. else
  232. {
  233. return BaseClass::ShouldDraw();
  234. }
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried
  238. // by this player, otherwise draw the worldmodel.
  239. //-----------------------------------------------------------------------------
  240. int C_BaseViewModel::DrawModel( int flags )
  241. {
  242. if ( !m_bReadyToDraw )
  243. return 0;
  244. if ( flags & STUDIO_RENDER )
  245. {
  246. // Determine blending amount and tell engine
  247. float blend = (float)( GetFxBlend() / 255.0f );
  248. // Totally gone
  249. if ( blend <= 0.0f )
  250. return 0;
  251. // Tell engine
  252. render->SetBlend( blend );
  253. float color[3];
  254. GetColorModulation( color );
  255. render->SetColorModulation( color );
  256. }
  257. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  258. C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
  259. int ret;
  260. // If the local player's overriding the viewmodel rendering, let him do it
  261. if ( pPlayer && pPlayer->IsOverridingViewmodel() )
  262. {
  263. ret = pPlayer->DrawOverriddenViewmodel( this, flags );
  264. }
  265. else if ( pWeapon && pWeapon->IsOverridingViewmodel() )
  266. {
  267. ret = pWeapon->DrawOverriddenViewmodel( this, flags );
  268. }
  269. else
  270. {
  271. ret = BaseClass::DrawModel( flags );
  272. }
  273. // Now that we've rendered, reset the animation restart flag
  274. if ( flags & STUDIO_RENDER )
  275. {
  276. if ( m_nOldAnimationParity != m_nAnimationParity )
  277. {
  278. m_nOldAnimationParity = m_nAnimationParity;
  279. }
  280. // Tell the weapon itself that we've rendered, in case it wants to do something
  281. if ( pWeapon )
  282. {
  283. pWeapon->ViewModelDrawn( this );
  284. }
  285. }
  286. #ifdef TF_CLIENT_DLL
  287. CTFWeaponBase* pTFWeapon = dynamic_cast<CTFWeaponBase*>( pWeapon );
  288. if ( ( flags & STUDIO_RENDER ) && pTFWeapon && pTFWeapon->m_viewmodelStatTrakAddon )
  289. {
  290. pTFWeapon->m_viewmodelStatTrakAddon->RemoveEffects( EF_NODRAW );
  291. pTFWeapon->m_viewmodelStatTrakAddon->DrawModel( flags );
  292. pTFWeapon->m_viewmodelStatTrakAddon->AddEffects( EF_NODRAW );
  293. }
  294. #endif
  295. return ret;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose:
  299. //-----------------------------------------------------------------------------
  300. int C_BaseViewModel::InternalDrawModel( int flags )
  301. {
  302. CMatRenderContextPtr pRenderContext( materials );
  303. if ( ShouldFlipViewModel() )
  304. pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
  305. int ret = BaseClass::InternalDrawModel( flags );
  306. pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
  307. return ret;
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Purpose: Called by the player when the player's overriding the viewmodel drawing. Avoids infinite recursion.
  311. //-----------------------------------------------------------------------------
  312. int C_BaseViewModel::DrawOverriddenViewmodel( int flags )
  313. {
  314. return BaseClass::DrawModel( flags );
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose:
  318. // Output : int
  319. //-----------------------------------------------------------------------------
  320. int C_BaseViewModel::GetFxBlend( void )
  321. {
  322. // See if the local player wants to override the viewmodel's rendering
  323. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  324. if ( pPlayer && pPlayer->IsOverridingViewmodel() )
  325. {
  326. pPlayer->ComputeFxBlend();
  327. return pPlayer->GetFxBlend();
  328. }
  329. C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
  330. if ( pWeapon && pWeapon->IsOverridingViewmodel() )
  331. {
  332. pWeapon->ComputeFxBlend();
  333. return pWeapon->GetFxBlend();
  334. }
  335. return BaseClass::GetFxBlend();
  336. }
  337. //-----------------------------------------------------------------------------
  338. // Purpose:
  339. // Output : Returns true on success, false on failure.
  340. //-----------------------------------------------------------------------------
  341. bool C_BaseViewModel::IsTransparent( void )
  342. {
  343. // See if the local player wants to override the viewmodel's rendering
  344. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  345. if ( pPlayer && pPlayer->IsOverridingViewmodel() )
  346. {
  347. return pPlayer->ViewModel_IsTransparent();
  348. }
  349. C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
  350. if ( pWeapon && pWeapon->IsOverridingViewmodel() )
  351. return pWeapon->ViewModel_IsTransparent();
  352. return BaseClass::IsTransparent();
  353. }
  354. //-----------------------------------------------------------------------------
  355. // Purpose:
  356. //-----------------------------------------------------------------------------
  357. bool C_BaseViewModel::UsesPowerOfTwoFrameBufferTexture( void )
  358. {
  359. // See if the local player wants to override the viewmodel's rendering
  360. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  361. if ( pPlayer && pPlayer->IsOverridingViewmodel() )
  362. {
  363. return pPlayer->ViewModel_IsUsingFBTexture();
  364. }
  365. C_BaseCombatWeapon *pWeapon = GetOwningWeapon();
  366. if ( pWeapon && pWeapon->IsOverridingViewmodel() )
  367. {
  368. return pWeapon->ViewModel_IsUsingFBTexture();
  369. }
  370. return BaseClass::UsesPowerOfTwoFrameBufferTexture();
  371. }
  372. //-----------------------------------------------------------------------------
  373. // Purpose: If the animation parity of the weapon has changed, we reset cycle to avoid popping
  374. //-----------------------------------------------------------------------------
  375. void C_BaseViewModel::UpdateAnimationParity( void )
  376. {
  377. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  378. // If we're predicting, then we don't use animation parity because we change the animations on the clientside
  379. // while predicting. When not predicting, only the server changes the animations, so a parity mismatch
  380. // tells us if we need to reset the animation.
  381. if ( m_nOldAnimationParity != m_nAnimationParity && !GetPredictable() )
  382. {
  383. float curtime = (pPlayer && IsIntermediateDataAllocated()) ? pPlayer->GetFinalPredictedTime() : gpGlobals->curtime;
  384. // FIXME: this is bad
  385. // Simulate a networked m_flAnimTime and m_flCycle
  386. // FIXME: Do we need the magic 0.1?
  387. SetCycle( 0.0f ); // GetSequenceCycleRate( GetSequence() ) * 0.1;
  388. m_flAnimTime = curtime;
  389. }
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose: Update global map state based on data received
  393. // Input : bnewentity -
  394. //-----------------------------------------------------------------------------
  395. void C_BaseViewModel::OnDataChanged( DataUpdateType_t updateType )
  396. {
  397. SetPredictionEligible( true );
  398. BaseClass::OnDataChanged(updateType);
  399. }
  400. void C_BaseViewModel::PostDataUpdate( DataUpdateType_t updateType )
  401. {
  402. BaseClass::PostDataUpdate(updateType);
  403. OnLatchInterpolatedVariables( LATCH_ANIMATION_VAR );
  404. }
  405. //-----------------------------------------------------------------------------
  406. // Purpose: Add entity to visible view models list
  407. //-----------------------------------------------------------------------------
  408. void C_BaseViewModel::AddEntity( void )
  409. {
  410. // Server says don't interpolate this frame, so set previous info to new info.
  411. if ( IsNoInterpolationFrame() )
  412. {
  413. ResetLatched();
  414. }
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose:
  418. //-----------------------------------------------------------------------------
  419. void C_BaseViewModel::GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS])
  420. {
  421. BaseClass::GetBoneControllers( controllers );
  422. // Tell the weapon itself that we've rendered, in case it wants to do something
  423. C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
  424. if ( pWeapon )
  425. {
  426. pWeapon->GetViewmodelBoneControllers( this, controllers );
  427. }
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Purpose:
  431. // Output : RenderGroup_t
  432. //-----------------------------------------------------------------------------
  433. RenderGroup_t C_BaseViewModel::GetRenderGroup()
  434. {
  435. return RENDER_GROUP_VIEW_MODEL_OPAQUE;
  436. }