//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "C_PortalGhostRenderable.h" #include "PortalRender.h" #include "c_portal_player.h" #include "model_types.h" C_PortalGhostRenderable::C_PortalGhostRenderable( C_Prop_Portal *pOwningPortal, C_BaseEntity *pGhostSource, RenderGroup_t sourceRenderGroup, const VMatrix &matGhostTransform, float *pSharedRenderClipPlane, bool bLocalPlayer ) : m_pGhostedRenderable( pGhostSource ), m_matGhostTransform( matGhostTransform ), m_pSharedRenderClipPlane( pSharedRenderClipPlane ), m_bLocalPlayer( bLocalPlayer ), m_pOwningPortal( pOwningPortal ) { m_bSourceIsBaseAnimating = (dynamic_cast(pGhostSource) != NULL); cl_entitylist->AddNonNetworkableEntity( GetIClientUnknown() ); g_pClientLeafSystem->AddRenderable( this, sourceRenderGroup ); } C_PortalGhostRenderable::~C_PortalGhostRenderable( void ) { m_pGhostedRenderable = NULL; g_pClientLeafSystem->RemoveRenderable( RenderHandle() ); cl_entitylist->RemoveEntity( GetIClientUnknown()->GetRefEHandle() ); DestroyModelInstance(); } void C_PortalGhostRenderable::PerFrameUpdate( void ) { if( m_pGhostedRenderable ) { SetModelName( m_pGhostedRenderable->GetModelName() ); SetModelIndex( m_pGhostedRenderable->GetModelIndex() ); SetEffects( m_pGhostedRenderable->GetEffects() | EF_NOINTERP ); m_flAnimTime = m_pGhostedRenderable->m_flAnimTime; if( m_bSourceIsBaseAnimating ) { C_BaseAnimating *pSource = (C_BaseAnimating *)m_pGhostedRenderable; SetCycle( pSource->GetCycle() ); SetSequence( pSource->GetSequence() ); m_nBody = pSource->m_nBody; m_nSkin = pSource->m_nSkin; } } // Set position and angles relative to the object it's ghosting Vector ptNewOrigin = m_matGhostTransform * m_pGhostedRenderable->GetAbsOrigin(); QAngle qNewAngles = TransformAnglesToWorldSpace( m_pGhostedRenderable->GetAbsAngles(), m_matGhostTransform.As3x4() ); SetAbsOrigin( ptNewOrigin ); SetAbsAngles( qNewAngles ); AddEffects( EF_NOINTERP ); RemoveFromInterpolationList(); g_pClientLeafSystem->RenderableChanged( RenderHandle() ); } Vector const& C_PortalGhostRenderable::GetRenderOrigin( void ) { if( m_pGhostedRenderable == NULL ) return m_ReferencedReturns.vRenderOrigin; m_ReferencedReturns.vRenderOrigin = m_matGhostTransform * m_pGhostedRenderable->GetRenderOrigin(); return m_ReferencedReturns.vRenderOrigin; } QAngle const& C_PortalGhostRenderable::GetRenderAngles( void ) { if( m_pGhostedRenderable == NULL ) return m_ReferencedReturns.qRenderAngle; m_ReferencedReturns.qRenderAngle = TransformAnglesToWorldSpace( m_pGhostedRenderable->GetRenderAngles(), m_matGhostTransform.As3x4() ); return m_ReferencedReturns.qRenderAngle; } bool C_PortalGhostRenderable::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime ) { if( m_pGhostedRenderable == NULL ) return false; int nModelIndex = 0; CBaseCombatWeapon *pParent = dynamic_cast( m_pGhostedRenderable ); if ( pParent ) { nModelIndex = pParent->GetModelIndex(); pParent->SetModelIndex( pParent->GetWorldModelIndex() ); } if( m_pGhostedRenderable->SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ) ) { if( pBoneToWorldOut ) { for( int i = 0; i != nMaxBones; ++i ) //FIXME: nMaxBones is most definitely greater than the actual number of bone transforms actually used, find the subset somehow { pBoneToWorldOut[i] = (m_matGhostTransform * pBoneToWorldOut[i]).As3x4(); } } return true; } if ( pParent ) { pParent->SetModelIndex( nModelIndex ); } return false; } void C_PortalGhostRenderable::GetRenderBounds( Vector& mins, Vector& maxs ) { if( m_pGhostedRenderable == NULL ) { mins = maxs = vec3_origin; return; } m_pGhostedRenderable->GetRenderBounds( mins, maxs ); } void C_PortalGhostRenderable::GetRenderBoundsWorldspace( Vector& mins, Vector& maxs ) { if( m_pGhostedRenderable == NULL ) { mins = maxs = vec3_origin; return; } m_pGhostedRenderable->GetRenderBoundsWorldspace( mins, maxs ); TransformAABB( m_matGhostTransform.As3x4(), mins, maxs, mins, maxs ); } void C_PortalGhostRenderable::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType ) { m_pGhostedRenderable->GetShadowRenderBounds( mins, maxs, shadowType ); TransformAABB( m_matGhostTransform.As3x4(), mins, maxs, mins, maxs ); } /*bool C_PortalGhostRenderable::GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const { if( m_pGhostedRenderable == NULL ) return false; return m_pGhostedRenderable->GetShadowCastDistance( pDist, shadowType ); } bool C_PortalGhostRenderable::GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const { if( m_pGhostedRenderable == NULL ) return false; if( m_pGhostedRenderable->GetShadowCastDirection( pDirection, shadowType ) ) { if( pDirection ) *pDirection = m_matGhostTransform.ApplyRotation( *pDirection ); return true; } return false; }*/ const matrix3x4_t & C_PortalGhostRenderable::RenderableToWorldTransform() { if( m_pGhostedRenderable == NULL ) return m_ReferencedReturns.matRenderableToWorldTransform; ConcatTransforms( m_matGhostTransform.As3x4(), m_pGhostedRenderable->RenderableToWorldTransform(), m_ReferencedReturns.matRenderableToWorldTransform ); return m_ReferencedReturns.matRenderableToWorldTransform; } bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin, QAngle &angles ) { if( m_pGhostedRenderable == NULL ) return false; if( m_pGhostedRenderable->GetAttachment( number, origin, angles ) ) { origin = m_matGhostTransform * origin; angles = TransformAnglesToWorldSpace( angles, m_matGhostTransform.As3x4() ); return true; } return false; } bool C_PortalGhostRenderable::GetAttachment( int number, matrix3x4_t &matrix ) { if( m_pGhostedRenderable == NULL ) return false; if( m_pGhostedRenderable->GetAttachment( number, matrix ) ) { ConcatTransforms( m_matGhostTransform.As3x4(), matrix, matrix ); return true; } return false; } bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin ) { if( m_pGhostedRenderable == NULL ) return false; if( m_pGhostedRenderable->GetAttachment( number, origin ) ) { origin = m_matGhostTransform * origin; return true; } return false; } bool C_PortalGhostRenderable::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel ) { if( m_pGhostedRenderable == NULL ) return false; Vector ghostVel; if( m_pGhostedRenderable->GetAttachmentVelocity( number, ghostVel, angleVel ) ) { Vector3DMultiply( m_matGhostTransform, ghostVel, originVel ); Vector3DMultiply( m_matGhostTransform, *(Vector*)( &angleVel ), *(Vector*)( &angleVel ) ); return true; } return false; } int C_PortalGhostRenderable::DrawModel( int flags ) { if( m_bSourceIsBaseAnimating ) { if( m_bLocalPlayer ) { C_Portal_Player *pPlayer = C_Portal_Player::GetLocalPlayer(); if ( !pPlayer->IsAlive() ) { // Dead player uses a ragdoll to draw, so don't ghost the dead entity return 0; } else if( g_pPortalRender->GetViewRecursionLevel() == 0 ) { if( pPlayer->m_bEyePositionIsTransformedByPortal ) return 0; } else if( g_pPortalRender->GetViewRecursionLevel() == 1 ) { if( !pPlayer->m_bEyePositionIsTransformedByPortal ) return 0; } } return C_BaseAnimating::DrawModel( flags ); } else { DrawBrushModelMode_t mode = DBM_DRAW_ALL; if ( flags & STUDIO_TWOPASS ) { mode = ( flags & STUDIO_TRANSPARENCY ) ? DBM_DRAW_TRANSLUCENT_ONLY : DBM_DRAW_OPAQUE_ONLY; } render->DrawBrushModelEx( m_pGhostedRenderable, (model_t *)m_pGhostedRenderable->GetModel(), GetRenderOrigin(), GetRenderAngles(), mode ); return 1; } return 0; } ModelInstanceHandle_t C_PortalGhostRenderable::GetModelInstance() { if ( m_pGhostedRenderable ) return m_pGhostedRenderable->GetModelInstance(); return BaseClass::GetModelInstance(); } bool C_PortalGhostRenderable::IsTransparent( void ) { if( m_pGhostedRenderable == NULL ) return false; return m_pGhostedRenderable->IsTransparent(); } bool C_PortalGhostRenderable::UsesPowerOfTwoFrameBufferTexture() { if( m_pGhostedRenderable == NULL ) return false; return m_pGhostedRenderable->UsesPowerOfTwoFrameBufferTexture(); } /*const model_t* C_PortalGhostRenderable::GetModel( ) const { if( m_pGhostedRenderable == NULL ) return NULL; return m_pGhostedRenderable->GetModel(); } int C_PortalGhostRenderable::GetBody() { if( m_pGhostedRenderable == NULL ) return 0; return m_pGhostedRenderable->GetBody(); }*/ void C_PortalGhostRenderable::GetColorModulation( float* color ) { if( m_pGhostedRenderable == NULL ) return; return m_pGhostedRenderable->GetColorModulation( color ); } /*ShadowType_t C_PortalGhostRenderable::ShadowCastType() { if( m_pGhostedRenderable == NULL ) return SHADOWS_NONE; return m_pGhostedRenderable->ShadowCastType(); }*/ int C_PortalGhostRenderable::LookupAttachment( const char *pAttachmentName ) { if( m_pGhostedRenderable == NULL ) return -1; return m_pGhostedRenderable->LookupAttachment( pAttachmentName ); } /*int C_PortalGhostRenderable::GetSkin() { if( m_pGhostedRenderable == NULL ) return -1; return m_pGhostedRenderable->GetSkin(); } bool C_PortalGhostRenderable::IsTwoPass( void ) { if( m_pGhostedRenderable == NULL ) return false; return m_pGhostedRenderable->IsTwoPass(); }*/