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.

980 lines
32 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "C_PortalGhostRenderable.h"
  9. #include "PortalRender.h"
  10. #include "c_portal_player.h"
  11. #include "model_types.h"
  12. #include "c_basecombatweapon.h"
  13. #include "c_combatweaponworldclone.h"
  14. #include "toolframework_client.h"
  15. ConVar portal_ghosts_disable( "portal_ghosts_disable", "0", 0, "Disables rendering of ghosted objects in portal environments" );
  16. inline float GhostedRenderableOriginTime( C_BaseEntity *pGhostedRenderable, float fCurTime )
  17. {
  18. return pGhostedRenderable->GetOriginInterpolator().GetInterpolatedTime( pGhostedRenderable->GetEffectiveInterpolationCurTime( fCurTime ) );
  19. }
  20. #define GHOST_RENDERABLE_TEN_TON_HAMMER 0
  21. #if (GHOST_RENDERABLE_TEN_TON_HAMMER == 1)
  22. void GhostResetEverything( C_PortalGhostRenderable *pGhost )
  23. {
  24. C_BaseEntity *pGhostedRenderable = pGhost->m_hGhostedRenderable;
  25. if( pGhostedRenderable )
  26. {
  27. pGhostedRenderable->MarkRenderHandleDirty();
  28. if( pGhost->m_bSourceIsBaseAnimating )
  29. {
  30. //((C_BaseAnimating *)pGhostedRenderable)->MarkForThreadedBoneSetup();
  31. ((C_BaseAnimating *)pGhostedRenderable)->InvalidateBoneCache();
  32. }
  33. pGhostedRenderable->CollisionProp()->MarkPartitionHandleDirty();
  34. pGhostedRenderable->CollisionProp()->MarkSurroundingBoundsDirty();
  35. pGhostedRenderable->AddEFlags( EFL_DIRTY_ABSTRANSFORM | EFL_DIRTY_SPATIAL_PARTITION );
  36. g_pClientLeafSystem->DisableCachedRenderBounds( pGhostedRenderable->RenderHandle(), true );
  37. g_pClientLeafSystem->RenderableChanged( pGhostedRenderable->RenderHandle() );
  38. if( C_BaseEntity::IsAbsQueriesValid() )
  39. {
  40. pGhostedRenderable->CollisionProp()->UpdatePartition();
  41. //pGhostedRenderable->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  42. }
  43. }
  44. pGhost->MarkRenderHandleDirty();
  45. //pGhost->MarkForThreadedBoneSetup();
  46. pGhost->InvalidateBoneCache();
  47. pGhost->CollisionProp()->MarkPartitionHandleDirty();
  48. pGhost->CollisionProp()->MarkSurroundingBoundsDirty();
  49. pGhost->AddEFlags( EFL_DIRTY_ABSTRANSFORM | EFL_DIRTY_SPATIAL_PARTITION );
  50. g_pClientLeafSystem->DisableCachedRenderBounds( pGhost->RenderHandle(), true );
  51. g_pClientLeafSystem->RenderableChanged( pGhost->RenderHandle() );
  52. if( C_BaseEntity::IsAbsQueriesValid() )
  53. {
  54. pGhost->CollisionProp()->UpdatePartition();
  55. //pGhost->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
  56. }
  57. }
  58. #endif //#if (GHOST_RENDERABLE_TEN_TON_HAMMER == 1)
  59. C_PortalGhostRenderable::C_PortalGhostRenderable( C_Portal_Base2D *pOwningPortal, C_BaseEntity *pGhostSource, const VMatrix &matGhostTransform, float *pSharedRenderClipPlane, C_BasePlayer *pPlayer ) :
  60. m_hGhostedRenderable( pGhostSource ),
  61. m_matGhostTransform( matGhostTransform ),
  62. m_pSharedRenderClipPlane( pSharedRenderClipPlane ),
  63. m_pPortalExitRenderClipPlane( NULL ),
  64. m_hHoldingPlayer( pPlayer ),
  65. m_pOwningPortal( pOwningPortal )
  66. {
  67. m_fRenderableRange[0] = -FLT_MAX;
  68. m_fRenderableRange[1] = FLT_MAX;
  69. m_fNoTransformBeforeTime = -FLT_MAX;
  70. m_fDisablePositionChecksUntilTime = -FLT_MAX;
  71. #if( DEBUG_GHOSTRENDERABLES == 1 )
  72. if( pOwningPortal->m_bIsPortal2 )
  73. {
  74. m_iDebugColor[0] = 255;
  75. m_iDebugColor[1] = 0;
  76. m_iDebugColor[2] = 0;
  77. }
  78. else
  79. {
  80. m_iDebugColor[0] = 0;
  81. m_iDebugColor[1] = 0;
  82. m_iDebugColor[2] = 255;
  83. }
  84. m_iDebugColor[3] = 16;
  85. #endif
  86. m_bSourceIsBaseAnimating = (dynamic_cast<C_BaseAnimating *>(pGhostSource) != NULL);
  87. RenderWithViewModels( pGhostSource->IsRenderingWithViewModels() );
  88. SetModelName( m_hGhostedRenderable->GetModelName() );
  89. m_bCombatWeapon = (dynamic_cast<C_BaseCombatWeapon *>(pGhostSource) != NULL);
  90. SetModelIndex( m_bCombatWeapon ? ((C_BaseCombatWeapon *)pGhostSource)->GetWorldModelIndex() : pGhostSource->GetModelIndex() );
  91. m_bCombatWeaponWorldClone = ( dynamic_cast< C_CombatWeaponClone* >( pGhostSource ) != NULL );
  92. m_bPlayerHeldClone = ( dynamic_cast< C_PlayerHeldObjectClone* >( pGhostSource ) != NULL );
  93. SetSize( pGhostSource->CollisionProp()->OBBMins(), pGhostSource->CollisionProp()->OBBMaxs() );
  94. Assert( m_hGhostedRenderable.Get() != NULL );
  95. }
  96. C_PortalGhostRenderable::~C_PortalGhostRenderable( void )
  97. {
  98. m_hGhostedRenderable = NULL;
  99. }
  100. void C_PortalGhostRenderable::UpdateOnRemove( void )
  101. {
  102. m_hGhostedRenderable = NULL;
  103. BaseClass::UpdateOnRemove();
  104. }
  105. void C_PortalGhostRenderable::PerFrameUpdate( void )
  106. {
  107. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  108. if( !pGhostedRenderable )
  109. return;
  110. SetModelName( pGhostedRenderable->GetModelName() );
  111. SetModelIndex( m_bCombatWeapon ? ((C_BaseCombatWeapon *)pGhostedRenderable)->GetWorldModelIndex() : pGhostedRenderable->GetModelIndex() );
  112. SetEffects( pGhostedRenderable->GetEffects() | EF_NOINTERP );
  113. m_flAnimTime = pGhostedRenderable->m_flAnimTime;
  114. if( m_bSourceIsBaseAnimating && !m_bCombatWeapon )
  115. {
  116. C_BaseAnimating *pSource = (C_BaseAnimating *)pGhostedRenderable;
  117. SetCycle( pSource->GetCycle() );
  118. SetSequence( pSource->GetSequence() );
  119. SetBody( pSource->GetBody() );
  120. SetSkin( pSource->GetSkin() );
  121. }
  122. SetSize( pGhostedRenderable->CollisionProp()->OBBMins(), pGhostedRenderable->CollisionProp()->OBBMaxs() );
  123. // Set position and angles relative to the object it's ghosting
  124. Vector ptNewOrigin;
  125. QAngle qNewAngles;
  126. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) >= m_fNoTransformBeforeTime )
  127. {
  128. ptNewOrigin = m_matGhostTransform * pGhostedRenderable->GetNetworkOrigin();
  129. qNewAngles = TransformAnglesToWorldSpace( pGhostedRenderable->GetNetworkAngles(), m_matGhostTransform.As3x4() );
  130. }
  131. else
  132. {
  133. ptNewOrigin = pGhostedRenderable->GetNetworkOrigin();
  134. qNewAngles = pGhostedRenderable->GetNetworkAngles();
  135. }
  136. SetNetworkOrigin( ptNewOrigin );
  137. SetLocalOrigin( ptNewOrigin );
  138. SetAbsOrigin( ptNewOrigin );
  139. SetNetworkAngles( qNewAngles );
  140. SetLocalAngles( qNewAngles );
  141. SetAbsAngles( qNewAngles );
  142. g_pClientLeafSystem->RenderableChanged( RenderHandle() );
  143. #if (GHOST_RENDERABLE_TEN_TON_HAMMER == 1)
  144. GhostResetEverything( this );
  145. #endif
  146. }
  147. Vector const& C_PortalGhostRenderable::GetRenderOrigin( void )
  148. {
  149. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  150. if( pGhostedRenderable == NULL )
  151. return m_ReferencedReturns.vRenderOrigin;
  152. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  153. {
  154. m_ReferencedReturns.vRenderOrigin = pGhostedRenderable->GetRenderOrigin();
  155. }
  156. else
  157. {
  158. m_ReferencedReturns.vRenderOrigin = m_matGhostTransform * pGhostedRenderable->GetRenderOrigin();
  159. }
  160. return m_ReferencedReturns.vRenderOrigin;
  161. }
  162. QAngle const& C_PortalGhostRenderable::GetRenderAngles( void )
  163. {
  164. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  165. if( pGhostedRenderable == NULL )
  166. return m_ReferencedReturns.qRenderAngle;
  167. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  168. {
  169. m_ReferencedReturns.qRenderAngle = pGhostedRenderable->GetRenderAngles();
  170. }
  171. else
  172. {
  173. m_ReferencedReturns.qRenderAngle = TransformAnglesToWorldSpace( pGhostedRenderable->GetRenderAngles(), m_matGhostTransform.As3x4() );
  174. }
  175. return m_ReferencedReturns.qRenderAngle;
  176. }
  177. bool C_PortalGhostRenderable::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  178. {
  179. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  180. if( pGhostedRenderable == NULL )
  181. return false;
  182. int iOldModelIndex = 0, iWorldModelIndex = 0;
  183. bool bChangeModelIndex = m_bCombatWeapon &&
  184. ((iOldModelIndex = ((C_BaseCombatWeapon *)pGhostedRenderable)->GetModelIndex()) != (iWorldModelIndex = ((C_BaseCombatWeapon *)pGhostedRenderable)->GetWorldModelIndex()));
  185. if( bChangeModelIndex )
  186. {
  187. ((C_BaseCombatWeapon *)pGhostedRenderable)->SetModelIndex( iWorldModelIndex );
  188. }
  189. if( pGhostedRenderable->SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ) )
  190. {
  191. if( pBoneToWorldOut && (GhostedRenderableOriginTime( pGhostedRenderable, currentTime ) >= m_fNoTransformBeforeTime) )
  192. {
  193. matrix3x4a_t matGhostTransform;
  194. matGhostTransform = m_matGhostTransform.As3x4();
  195. CStudioHdr *hdr = GetModelPtr();
  196. int nBoneCount = hdr->numbones();
  197. nBoneCount = MIN( nMaxBones, nBoneCount );
  198. for( int i = 0; i != nBoneCount; ++i )
  199. {
  200. ConcatTransforms_Aligned( matGhostTransform, pBoneToWorldOut[i], pBoneToWorldOut[i] );
  201. }
  202. }
  203. if( bChangeModelIndex )
  204. {
  205. ((C_BaseCombatWeapon *)pGhostedRenderable)->SetModelIndex( iOldModelIndex );
  206. }
  207. return true;
  208. }
  209. if( bChangeModelIndex )
  210. {
  211. ((C_BaseCombatWeapon *)pGhostedRenderable)->SetModelIndex( iOldModelIndex );
  212. }
  213. return false;
  214. }
  215. C_BaseAnimating *C_PortalGhostRenderable::GetBoneSetupDependancy( void )
  216. {
  217. return m_bSourceIsBaseAnimating ? (C_BaseAnimating *)(m_hGhostedRenderable.Get()) : NULL;
  218. }
  219. void C_PortalGhostRenderable::GetRenderBounds( Vector& mins, Vector& maxs )
  220. {
  221. if( m_hGhostedRenderable == NULL )
  222. {
  223. mins = maxs = vec3_origin;
  224. return;
  225. }
  226. m_hGhostedRenderable->GetRenderBounds( mins, maxs );
  227. }
  228. void C_PortalGhostRenderable::GetRenderBoundsWorldspace( Vector& mins, Vector& maxs )
  229. {
  230. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  231. if( pGhostedRenderable == NULL )
  232. {
  233. mins = maxs = vec3_origin;
  234. return;
  235. }
  236. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  237. return pGhostedRenderable->GetRenderBoundsWorldspace( mins, maxs );
  238. Vector vTempMins, vTempMaxs;
  239. pGhostedRenderable->GetRenderBoundsWorldspace( vTempMins, vTempMaxs );
  240. TransformAABB( m_matGhostTransform.As3x4(), vTempMins, vTempMaxs, mins, maxs );
  241. }
  242. bool C_PortalGhostRenderable::ShouldReceiveProjectedTextures( int flags )
  243. {
  244. return false;
  245. }
  246. void C_PortalGhostRenderable::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
  247. {
  248. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  249. if( pGhostedRenderable == NULL )
  250. {
  251. mins = maxs = vec3_origin;
  252. return;
  253. }
  254. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  255. return pGhostedRenderable->GetShadowRenderBounds( mins, maxs, shadowType );
  256. Vector vTempMins, vTempMaxs;
  257. pGhostedRenderable->GetShadowRenderBounds( vTempMins, vTempMaxs, shadowType );
  258. TransformAABB( m_matGhostTransform.As3x4(), vTempMins, vTempMaxs, mins, maxs );
  259. }
  260. /*bool C_PortalGhostRenderable::GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const
  261. {
  262. if( m_hGhostedRenderable == NULL )
  263. return false;
  264. return m_hGhostedRenderable->GetShadowCastDistance( pDist, shadowType );
  265. }
  266. bool C_PortalGhostRenderable::GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const
  267. {
  268. if( m_hGhostedRenderable == NULL )
  269. return false;
  270. if( m_hGhostedRenderable->GetShadowCastDirection( pDirection, shadowType ) )
  271. {
  272. if( pDirection )
  273. *pDirection = m_matGhostTransform.ApplyRotation( *pDirection );
  274. return true;
  275. }
  276. return false;
  277. }*/
  278. const matrix3x4_t & C_PortalGhostRenderable::RenderableToWorldTransform()
  279. {
  280. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  281. if( pGhostedRenderable == NULL )
  282. return m_ReferencedReturns.matRenderableToWorldTransform;
  283. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  284. {
  285. m_ReferencedReturns.matRenderableToWorldTransform = pGhostedRenderable->RenderableToWorldTransform();
  286. }
  287. else
  288. {
  289. ConcatTransforms( m_matGhostTransform.As3x4(), pGhostedRenderable->RenderableToWorldTransform(), m_ReferencedReturns.matRenderableToWorldTransform );
  290. }
  291. return m_ReferencedReturns.matRenderableToWorldTransform;
  292. }
  293. bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin, QAngle &angles )
  294. {
  295. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  296. if( pGhostedRenderable == NULL )
  297. return false;
  298. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  299. return pGhostedRenderable->GetAttachment( number, origin, angles );
  300. if( pGhostedRenderable->GetAttachment( number, origin, angles ) )
  301. {
  302. origin = m_matGhostTransform * origin;
  303. angles = TransformAnglesToWorldSpace( angles, m_matGhostTransform.As3x4() );
  304. return true;
  305. }
  306. return false;
  307. }
  308. bool C_PortalGhostRenderable::GetAttachment( int number, matrix3x4_t &matrix )
  309. {
  310. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  311. if( pGhostedRenderable == NULL )
  312. return false;
  313. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  314. return pGhostedRenderable->GetAttachment( number, matrix );
  315. if( pGhostedRenderable->GetAttachment( number, matrix ) )
  316. {
  317. ConcatTransforms( m_matGhostTransform.As3x4(), matrix, matrix );
  318. return true;
  319. }
  320. return false;
  321. }
  322. bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin )
  323. {
  324. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  325. if( pGhostedRenderable == NULL )
  326. return false;
  327. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  328. return pGhostedRenderable->GetAttachment( number, origin );
  329. if( pGhostedRenderable->GetAttachment( number, origin ) )
  330. {
  331. origin = m_matGhostTransform * origin;
  332. return true;
  333. }
  334. return false;
  335. }
  336. bool C_PortalGhostRenderable::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
  337. {
  338. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
  339. if( pGhostedRenderable == NULL )
  340. return false;
  341. if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
  342. return pGhostedRenderable->GetAttachmentVelocity( number, originVel, angleVel );
  343. Vector ghostVel;
  344. if( pGhostedRenderable->GetAttachmentVelocity( number, ghostVel, angleVel ) )
  345. {
  346. Vector3DMultiply( m_matGhostTransform, ghostVel, originVel );
  347. Vector3DMultiply( m_matGhostTransform, *(Vector*)( &angleVel ), *(Vector*)( &angleVel ) );
  348. return true;
  349. }
  350. return false;
  351. }
  352. bool C_PortalGhostRenderable::ShouldDrawForThisView( void )
  353. {
  354. if ( portal_ghosts_disable.GetBool() )
  355. return false;
  356. C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable.Get();
  357. if( pGhostedRenderable == NULL )
  358. {
  359. return false;
  360. }
  361. float fInterpTime = GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime );
  362. if( (fInterpTime < m_fRenderableRange[0]) ||
  363. (fInterpTime >= m_fRenderableRange[1]) )
  364. return false;
  365. if ( m_bSourceIsBaseAnimating )
  366. {
  367. C_Portal_Player *pViewPlayer = ToPortalPlayer( GetSplitScreenViewPlayer() );
  368. C_Portal_Player *pHoldingPlayer = ToPortalPlayer( m_hHoldingPlayer.Get() );
  369. if ( pHoldingPlayer && (pHoldingPlayer == pViewPlayer) && !pViewPlayer->ShouldDrawLocalPlayer() )
  370. {
  371. if ( !pHoldingPlayer->IsAlive() )
  372. {
  373. // Dead player uses a ragdoll to draw, so don't ghost the dead entity
  374. return false;
  375. }
  376. else if( g_pPortalRender->GetViewRecursionLevel() == 0 )
  377. {
  378. if ( pHoldingPlayer->m_bEyePositionIsTransformedByPortal )
  379. return false;
  380. C_PlayerHeldObjectClone *pClone = NULL;
  381. if ( m_bPlayerHeldClone )
  382. {
  383. pClone = assert_cast< C_PlayerHeldObjectClone* >( m_hGhostedRenderable.Get() );
  384. if( pClone && pClone->m_bOnOppositeSideOfPortal )
  385. return false;
  386. }
  387. }
  388. else if ( g_pPortalRender->GetViewRecursionLevel() == 1 )
  389. {
  390. C_PlayerHeldObjectClone *pClone = NULL;
  391. if ( m_bPlayerHeldClone )
  392. {
  393. pClone = assert_cast< C_PlayerHeldObjectClone* >( m_hGhostedRenderable.Get() );
  394. }
  395. if ( (!pHoldingPlayer->m_bEyePositionIsTransformedByPortal && (g_pPortalRender->GetCurrentViewEntryPortal() == m_pOwningPortal)) &&
  396. !( pClone && pClone->m_bOnOppositeSideOfPortal ) )
  397. return false;
  398. }
  399. }
  400. }
  401. return true;
  402. }
  403. int C_PortalGhostRenderable::DrawModel( int flags, const RenderableInstance_t &instance )
  404. {
  405. if( !ShouldDrawForThisView() )
  406. return 0;
  407. #if( DEBUG_GHOSTRENDERABLES == 1 )
  408. if( m_iDebugColor[3] != 0 )
  409. {
  410. //NDebugOverlay::BoxAngles( GetRenderOrigin(), m_hGhostedRenderable->CollisionProp()->OBBMins(), m_hGhostedRenderable->CollisionProp()->OBBMaxs(), GetRenderAngles(), m_iDebugColor[0], m_iDebugColor[1], m_iDebugColor[2], m_iDebugColor[3], 0.0f );
  411. NDebugOverlay::Sphere( GetNetworkOrigin(), 5.0f, m_iDebugColor[0], m_iDebugColor[1], m_iDebugColor[2], true, 0.0f );
  412. }
  413. #endif
  414. if ( m_bSourceIsBaseAnimating )
  415. {
  416. return C_BaseAnimating::DrawModel( flags, instance );
  417. }
  418. else
  419. {
  420. DrawBrushModelMode_t mode = DBM_DRAW_ALL;
  421. if ( flags & STUDIO_TWOPASS )
  422. {
  423. mode = ( flags & STUDIO_TRANSPARENCY ) ? DBM_DRAW_TRANSLUCENT_ONLY : DBM_DRAW_OPAQUE_ONLY;
  424. }
  425. render->DrawBrushModelEx( m_hGhostedRenderable,
  426. (model_t *)m_hGhostedRenderable->GetModel(),
  427. GetRenderOrigin(),
  428. GetRenderAngles(),
  429. mode );
  430. return 1;
  431. }
  432. return 0;
  433. }
  434. ModelInstanceHandle_t C_PortalGhostRenderable::GetModelInstance()
  435. {
  436. // HACK: This causes problems if the ghosted renderable is
  437. // has it's model instance destructed mid-render... this is currently
  438. // the case for the portalgun view model due to model switching
  439. // so we're not going to use the ghost's model instance for combat weapon ents.
  440. // This will only mean the decal state is wrong, the worldmodel doesn't get decals anyway.
  441. // Real fix would be to 'sync' the decal state between this and the ghosted ent, but
  442. // this will fix it for now.
  443. if ( m_hGhostedRenderable && (m_bCombatWeapon == false) && (m_bCombatWeaponWorldClone == false) )
  444. return m_hGhostedRenderable->GetModelInstance();
  445. return BaseClass::GetModelInstance();
  446. }
  447. RenderableTranslucencyType_t C_PortalGhostRenderable::ComputeTranslucencyType( void )
  448. {
  449. if ( m_hGhostedRenderable == NULL )
  450. return RENDERABLE_IS_OPAQUE;
  451. return m_hGhostedRenderable->ComputeTranslucencyType();
  452. }
  453. int C_PortalGhostRenderable::GetRenderFlags()
  454. {
  455. if( m_hGhostedRenderable == NULL )
  456. return false;
  457. return m_hGhostedRenderable->GetRenderFlags();
  458. }
  459. /*const model_t* C_PortalGhostRenderable::GetModel( ) const
  460. {
  461. if( m_hGhostedRenderable == NULL )
  462. return NULL;
  463. return m_hGhostedRenderable->GetModel();
  464. }
  465. int C_PortalGhostRenderable::GetBody()
  466. {
  467. if( m_hGhostedRenderable == NULL )
  468. return 0;
  469. return m_hGhostedRenderable->GetBody();
  470. }*/
  471. void C_PortalGhostRenderable::GetColorModulation( float* color )
  472. {
  473. if( m_hGhostedRenderable == NULL )
  474. return;
  475. #if(DEBUG_GHOSTRENDERABLES == 1)
  476. if( color[3] != 0 )
  477. {
  478. color[0] = m_iDebugColor[0] / 255.0f;
  479. color[1] = m_iDebugColor[1] / 255.0f;
  480. color[2] = m_iDebugColor[2] / 255.0f;
  481. return;
  482. }
  483. #endif
  484. return m_hGhostedRenderable->GetColorModulation( color );
  485. }
  486. /*ShadowType_t C_PortalGhostRenderable::ShadowCastType()
  487. {
  488. if( m_hGhostedRenderable == NULL )
  489. return SHADOWS_NONE;
  490. return m_hGhostedRenderable->ShadowCastType();
  491. }*/
  492. int C_PortalGhostRenderable::LookupAttachment( const char *pAttachmentName )
  493. {
  494. if( m_hGhostedRenderable == NULL )
  495. return -1;
  496. return m_hGhostedRenderable->LookupAttachment( pAttachmentName );
  497. }
  498. /*
  499. int C_PortalGhostRenderable::GetSkin()
  500. {
  501. if( m_hGhostedRenderable == NULL )
  502. return -1;
  503. return m_hGhostedRenderable->GetSkin();
  504. }
  505. */
  506. float *C_PortalGhostRenderable::GetRenderClipPlane( void )
  507. {
  508. if( !ShouldDrawForThisView() ) //Fix for systems that do not support clip planes. The occluding depth box should be avoided if it's not going to be useful
  509. return NULL;
  510. if( m_pPortalExitRenderClipPlane && //have an exit portal special clip plane
  511. g_pPortalRender->IsRenderingPortal() && //rendering through a portal
  512. (g_pPortalRender->GetCurrentViewEntryPortal() == m_pOwningPortal) ) //we're being drawn on the exit side
  513. {
  514. return m_pPortalExitRenderClipPlane;
  515. }
  516. return m_pSharedRenderClipPlane;
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Handle recording for the SFM
  520. //-----------------------------------------------------------------------------
  521. void C_PortalGhostRenderable::GetToolRecordingState( KeyValues *msg )
  522. {
  523. VPROF_BUDGET( "C_PortalGhostRenderable::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
  524. BaseClass::GetToolRecordingState( msg );
  525. C_Portal_Player *pViewPlayer = ToPortalPlayer( GetSplitScreenViewPlayer() );
  526. if ( m_hHoldingPlayer.Get() && m_hHoldingPlayer.Get() == pViewPlayer )
  527. {
  528. msg->SetInt( "worldmodel", 2 ); //world model that should only draw in third person
  529. }
  530. }
  531. bool C_PortalGhostRenderable::ShouldCloneEntity( C_BaseEntity *pEntity, C_Portal_Base2D *pPortal, bool bUsePositionChecks )
  532. {
  533. if( pEntity->IsEffectActive( EF_NODRAW ) )
  534. return false;
  535. bool bIsMovable = false;
  536. C_BaseEntity *pMoveEntity = pEntity;
  537. MoveType_t moveType = MOVETYPE_NONE;
  538. //unmoveables and doors can never get halfway in the portal
  539. while ( pMoveEntity )
  540. {
  541. moveType = pMoveEntity->GetMoveType();
  542. if ( !( moveType == MOVETYPE_NONE || moveType == MOVETYPE_PUSH ) )
  543. {
  544. bIsMovable = true;
  545. pMoveEntity = NULL;
  546. }
  547. else
  548. pMoveEntity = pMoveEntity->GetMoveParent();
  549. }
  550. if ( !bIsMovable )
  551. return false;
  552. if( (moveType == MOVETYPE_NOCLIP) && dynamic_cast<C_Portal_Base2D *>(pEntity) != NULL ) //potentially "mobile" portals in p2 can use MOVETYPE_NOCLIP
  553. return false;
  554. Assert( dynamic_cast<C_Portal_Base2D *>(pEntity) == NULL ); //should have been killed with (pEntity->GetMoveType() == MOVETYPE_NONE) check. Infinite recursion is infinitely bad.
  555. if( ToBaseViewModel(pEntity) )
  556. return false; //avoid ghosting view models
  557. if( pEntity->IsRenderingWithViewModels() )
  558. return false; //avoid ghosting anything that draws with viewmodels
  559. bool bActivePlayerWeapon = false;
  560. C_BaseCombatWeapon *pWeapon = ToBaseCombatWeapon( pEntity );
  561. if ( pWeapon )
  562. {
  563. C_Portal_Player *pPortalPlayer = ToPortalPlayer( pWeapon->GetOwner() );
  564. if ( pPortalPlayer )
  565. {
  566. if ( pWeapon->m_iState != WEAPON_IS_ACTIVE )
  567. {
  568. return false; // don't ghost player owned non active weapons
  569. }
  570. else
  571. {
  572. bActivePlayerWeapon = true;
  573. }
  574. }
  575. }
  576. // Weapon is not teleportable, and we don't want to make that function use a dynamic cast to test for it,
  577. // so do the simple thing and just ignore this check for player-held weapons
  578. if( !bActivePlayerWeapon && !CPortal_Base2D_Shared::IsEntityTeleportable( pEntity ) )
  579. return false;
  580. if( bUsePositionChecks )
  581. {
  582. Vector ptEntCenter = pEntity->WorldSpaceCenter();
  583. float fEntCenterDist = (pPortal->m_plane_Origin.normal.Dot( ptEntCenter ) - pPortal->m_plane_Origin.dist);
  584. if( fEntCenterDist < -5.0f )
  585. {
  586. //view model held objects don't actually teleport to the other side of a portal when their center crosses the plane.
  587. //Alternate test is to ensure that a line drawn from the player center to the clone intersects the portal
  588. C_Portal_Player *pHoldingPlayer = (C_Portal_Player *)GetPlayerHoldingEntity( pEntity );
  589. if( (pHoldingPlayer == NULL) || //not held
  590. !pHoldingPlayer->IsUsingVMGrab() || //not in ViewModel grab mode
  591. dynamic_cast<C_PlayerHeldObjectClone *>(pEntity) ) //clones actually handle the teleportation correctly on the client.
  592. {
  593. return false; //entity is behind the portal, most likely behind the wall the portal is placed on
  594. }
  595. else
  596. {
  597. Vector vPlayerCenter = pHoldingPlayer->WorldSpaceCenter();
  598. float fPlayerCenterDist = (pPortal->m_plane_Origin.normal.Dot( vPlayerCenter ) - pPortal->m_plane_Origin.dist);
  599. if( fPlayerCenterDist < 0.0f )
  600. return false;
  601. float fTotalDist = fPlayerCenterDist - fEntCenterDist;
  602. if( fTotalDist == 0.0f ) //should be >= 5.0 at all times, but I've been bitten too many times by impossibly 0 cases
  603. return false;
  604. Vector vPlaneIntersect = (ptEntCenter * (fPlayerCenterDist/fTotalDist)) - (vPlayerCenter * (fEntCenterDist/fTotalDist));
  605. Vector vPortalCenterToIntersect = vPlaneIntersect - pPortal->m_ptOrigin;
  606. if( (fabs( vPortalCenterToIntersect.Dot( pPortal->m_vRight ) ) > pPortal->GetHalfWidth()) ||
  607. (fabs( vPortalCenterToIntersect.Dot( pPortal->m_vUp ) ) > pPortal->GetHalfHeight()) )
  608. {
  609. return false;
  610. }
  611. //else intersects on the portal quad and the test passes
  612. }
  613. }
  614. if ( bActivePlayerWeapon )
  615. {
  616. // Both the player AND the weapon must be in the portal hole.
  617. //
  618. // We test the player's collision AABB against the portal hole because it's guaranteed not to intersect
  619. // multiple adjacent portal holes at the same time in a degenerate case.
  620. //
  621. // We test the player's weapon hitbox against the portal hole because it doesn't have a good collision AABB
  622. // and because we'll only bother to even do this test if the player's AABB is acutally inside the portal hole.
  623. //
  624. // If we only test the weapon, we get false positives (phantom renderables) when its bounds span multiple adjacent
  625. // portal holes.
  626. if( !pPortal->m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( pWeapon->GetOwner(), true /* bUseCollisionAABB */ ) ||
  627. !pPortal->m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( (C_BaseAnimating*)pEntity, false /* bUseCollisionAABB */ ) )
  628. return false;
  629. }
  630. else if( pEntity->IsPlayer() )
  631. {
  632. if( !pPortal->m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( (C_BaseAnimating*)pEntity, true /* bUseCollisionAABB */ ) )
  633. return false;
  634. }
  635. else
  636. {
  637. if( !pPortal->m_PortalSimulator.EntityIsInPortalHole( pEntity ) )
  638. return false;
  639. }
  640. }
  641. return true;
  642. }
  643. C_PortalGhostRenderable *C_PortalGhostRenderable::CreateGhostRenderable( C_BaseEntity *pEntity, C_Portal_Base2D *pPortal )
  644. {
  645. Assert( ShouldCloneEntity( pEntity, pPortal, false ) );
  646. C_BasePlayer *pPlayerOwner = NULL;
  647. bool bRenderableIsPlayer = pEntity->IsPlayer();
  648. if ( bRenderableIsPlayer )
  649. {
  650. pPlayerOwner = ToBasePlayer( pEntity );
  651. }
  652. else
  653. {
  654. C_BaseCombatWeapon *pWeapon = ToBaseCombatWeapon( pEntity );
  655. if ( pWeapon )
  656. {
  657. C_Portal_Player *pOwningPlayer = ToPortalPlayer( pWeapon->GetOwner() );
  658. if ( pOwningPlayer )
  659. {
  660. pPlayerOwner = pOwningPlayer;
  661. }
  662. }
  663. else
  664. {
  665. C_PlayerHeldObjectClone *pClone = dynamic_cast< C_PlayerHeldObjectClone* >( pEntity );
  666. if ( pClone )
  667. {
  668. C_Portal_Player *pOwningPlayer = ToPortalPlayer( pClone->m_hPlayer );
  669. if ( pOwningPlayer )
  670. {
  671. pPlayerOwner = pOwningPlayer;
  672. }
  673. }
  674. }
  675. }
  676. #if( DEBUG_GHOSTRENDERABLES == 1 )
  677. {
  678. Vector vTransformedOrigin;
  679. QAngle qTransformedAngles;
  680. VectorTransform( pEntity->GetRenderOrigin(), pPortal->m_matrixThisToLinked.As3x4(), vTransformedOrigin );
  681. qTransformedAngles = TransformAnglesToWorldSpace( pEntity->GetRenderAngles(), pPortal->m_matrixThisToLinked.As3x4() );
  682. NDebugOverlay::BoxAngles( vTransformedOrigin, pEntity->CollisionProp()->OBBMins(), pEntity->CollisionProp()->OBBMaxs(), qTransformedAngles, 0, 255, 0, 16, 0.0f );
  683. }
  684. #endif
  685. C_PortalGhostRenderable *pNewGhost = new C_PortalGhostRenderable( pPortal,
  686. pEntity,
  687. pPortal->m_matrixThisToLinked,
  688. bRenderableIsPlayer ? pPortal->m_fGhostRenderablesClipForPlayer : pPortal->m_fGhostRenderablesClip,
  689. pPlayerOwner );
  690. if( !pNewGhost->InitializeAsClientEntity( pEntity->GetModelName(), false ) )
  691. {
  692. pNewGhost->Release();
  693. return NULL;
  694. }
  695. Assert( pNewGhost );
  696. if( pPlayerOwner )
  697. {
  698. pNewGhost->SetOwnerEntity( pPlayerOwner );
  699. }
  700. if( pNewGhost->m_pSharedRenderClipPlane == pPortal->m_fGhostRenderablesClipForPlayer )
  701. {
  702. pNewGhost->m_pPortalExitRenderClipPlane = pPortal->m_fGhostRenderablesClip;
  703. }
  704. pPortal->m_GhostRenderables.AddToTail( pNewGhost );
  705. {
  706. // HACK - I just copied the CClientTools::OnEntityCreated code here,
  707. // since the ghosts aren't really entities - they don't have an entindex,
  708. // they're not in the entitylist, and they get created during Simulate(),
  709. // which isn't valid for real entities, since it changes the simulate list
  710. // -jd
  711. if ( ToolsEnabled() && clienttools->IsInRecordingMode() )
  712. {
  713. // Send deletion message to tool interface
  714. KeyValues *kv = new KeyValues( "created" );
  715. HTOOLHANDLE h = clienttools->AttachToEntity( pNewGhost );
  716. ToolFramework_PostToolMessage( h, kv );
  717. kv->deleteThis();
  718. }
  719. }
  720. g_pClientLeafSystem->DisableCachedRenderBounds( pNewGhost->RenderHandle(), true );
  721. pNewGhost->PerFrameUpdate();
  722. return pNewGhost;
  723. }
  724. C_PortalGhostRenderable *C_PortalGhostRenderable::CreateInversion( C_PortalGhostRenderable *pSrc, C_Portal_Base2D *pSourcePortal, float fTime )
  725. {
  726. if( !(pSourcePortal && pSrc) )
  727. return NULL;
  728. C_Portal_Base2D *pRemotePortal = pSourcePortal->m_hLinkedPortal.Get();
  729. if( !pRemotePortal )
  730. return NULL;
  731. C_BaseEntity *pRootEntity = pSrc->m_hGhostedRenderable;
  732. if( !pRootEntity )
  733. return NULL;
  734. C_PortalGhostRenderable *pNewGhost = NULL;
  735. //use existing if we already have one
  736. for( int i = 0; i != pRemotePortal->m_GhostRenderables.Count(); ++i )
  737. {
  738. if( pRemotePortal->m_GhostRenderables[i]->m_hGhostedRenderable == pRootEntity )
  739. {
  740. pNewGhost = pRemotePortal->m_GhostRenderables[i];
  741. //reset time based variables
  742. pNewGhost->m_fRenderableRange[0] = -FLT_MAX;
  743. pNewGhost->m_fRenderableRange[1] = FLT_MAX;
  744. pNewGhost->m_fNoTransformBeforeTime = -FLT_MAX;
  745. break;
  746. }
  747. }
  748. if( pNewGhost == NULL )
  749. {
  750. pNewGhost = new C_PortalGhostRenderable( pRemotePortal, pSrc->m_hGhostedRenderable, pRemotePortal->m_matrixThisToLinked,
  751. pSrc->m_pSharedRenderClipPlane == pSourcePortal->m_fGhostRenderablesClipForPlayer ? pRemotePortal->m_fGhostRenderablesClipForPlayer : pRemotePortal->m_fGhostRenderablesClip, pSrc->m_hHoldingPlayer );
  752. if( !pNewGhost->InitializeAsClientEntity( pRootEntity->GetModelName(), false ) )
  753. {
  754. pNewGhost->Release();
  755. return NULL;
  756. }
  757. if( pSrc->m_hHoldingPlayer )
  758. {
  759. pNewGhost->SetOwnerEntity( pSrc->m_hHoldingPlayer );
  760. }
  761. if( pSrc->m_pPortalExitRenderClipPlane != NULL )
  762. {
  763. if( pSrc->m_pPortalExitRenderClipPlane == pSourcePortal->m_fGhostRenderablesClipForPlayer )
  764. {
  765. pNewGhost->m_pPortalExitRenderClipPlane = pRemotePortal->m_fGhostRenderablesClipForPlayer;
  766. }
  767. else if( pSrc->m_pPortalExitRenderClipPlane == pSourcePortal->m_fGhostRenderablesClip )
  768. {
  769. pNewGhost->m_pPortalExitRenderClipPlane = pRemotePortal->m_fGhostRenderablesClip;
  770. }
  771. else
  772. {
  773. Assert( false );
  774. }
  775. }
  776. pRemotePortal->m_GhostRenderables.AddToTail( pNewGhost );
  777. #if( DEBUG_GHOSTRENDERABLES == 1 )
  778. {
  779. Vector vTransformedOrigin;
  780. QAngle qTransformedAngles;
  781. VectorTransform( pSrc->m_hGhostedRenderable->GetNetworkOrigin(), pRemotePortal->m_matrixThisToLinked.As3x4(), vTransformedOrigin );
  782. qTransformedAngles = TransformAnglesToWorldSpace( pSrc->m_hGhostedRenderable->GetNetworkAngles(), pRemotePortal->m_matrixThisToLinked.As3x4() );
  783. NDebugOverlay::BoxAngles( vTransformedOrigin, pSrc->m_hGhostedRenderable->CollisionProp()->OBBMins(), pSrc->m_hGhostedRenderable->CollisionProp()->OBBMaxs(), qTransformedAngles, 0, 255, 0, 16, 0.0f );
  784. }
  785. #endif
  786. }
  787. //these times are in effective origin interpolator time m_hGhostedRenderable->GetOriginInterpolator().GetInterpolatedTime( m_hGhostedRenderable->GetEffectiveInterpolationCurTime() )
  788. pNewGhost->m_fRenderableRange[0] = fTime;
  789. pNewGhost->m_fRenderableRange[1] = FLT_MAX;
  790. pSrc->m_fRenderableRange[0] = -FLT_MAX;
  791. pSrc->m_fRenderableRange[1] = fTime;
  792. pNewGhost->m_fNoTransformBeforeTime = fTime;
  793. pSrc->m_fDisablePositionChecksUntilTime = fTime + (TICK_INTERVAL * 2.0f) + pSrc->m_hGhostedRenderable->GetOriginInterpolator().GetInterpolationAmount();
  794. pNewGhost->m_fDisablePositionChecksUntilTime = pSrc->m_fDisablePositionChecksUntilTime;
  795. g_pClientLeafSystem->DisableCachedRenderBounds( pNewGhost->RenderHandle(), true );
  796. pNewGhost->PerFrameUpdate();
  797. return pNewGhost;
  798. }