initial
This commit is contained in:
941
game/client/portal/c_portal_base2d.cpp
Normal file
941
game/client/portal/c_portal_base2d.cpp
Normal file
@@ -0,0 +1,941 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "c_portal_base2d.h"
|
||||
#include "portal_shareddefs.h"
|
||||
#include "clientsideeffects.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "materialsystem/ITexture.h"
|
||||
#include "hud_macros.h"
|
||||
#include "IGameSystem.h"
|
||||
#include "view.h" // For MainViewOrigin()
|
||||
#include "clientleafsystem.h" // For finding the leaves our portals are in
|
||||
#include "portal_render_targets.h" // Access to static references to Portal-specific render textures
|
||||
#include "toolframework/itoolframework.h"
|
||||
#include "toolframework_client.h"
|
||||
#include "tier1/keyvalues.h"
|
||||
#include "rendertexture.h"
|
||||
#include "portal_base2d_shared.h"
|
||||
#include "particles_new.h"
|
||||
#include "materialsystem/imaterialvar.h"
|
||||
#include "c_baseprojectedentity.h"
|
||||
#include "c_basetempentity.h"
|
||||
#include "c_combatweaponworldclone.h"
|
||||
#include "C_Portal_Player.h"
|
||||
#include "prediction.h"
|
||||
#include "tier1/callqueue.h"
|
||||
|
||||
#include "c_pixel_visibility.h"
|
||||
|
||||
#include "glow_overlay.h"
|
||||
|
||||
#include "dlight.h"
|
||||
#include "iefx.h"
|
||||
|
||||
#include "simple_keys.h"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "filesystem.h"
|
||||
#endif
|
||||
|
||||
#include "debugoverlay_shared.h"
|
||||
|
||||
// HACK: This define can really hose the following macro, so we need to undefine it for a moment while this sets up
|
||||
#undef CPortal_Base2D
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_Portal_Base2D, DT_Portal_Base2D, CPortal_Base2D )
|
||||
RecvPropVector( RECVINFO_NAME( m_vecNetworkOrigin, m_vecOrigin ) ),
|
||||
RecvPropVector( RECVINFO_NAME( m_angNetworkAngles, m_angRotation ) ),
|
||||
|
||||
RecvPropVector( RECVINFO( m_ptOrigin ) ),
|
||||
RecvPropVector( RECVINFO( m_qAbsAngle ) ),
|
||||
|
||||
RecvPropEHandle( RECVINFO(m_hLinkedPortal) ),
|
||||
RecvPropBool( RECVINFO(m_bActivated) ),
|
||||
RecvPropBool( RECVINFO(m_bOldActivatedState) ),
|
||||
RecvPropBool( RECVINFO(m_bIsPortal2) ),
|
||||
RecvPropFloat( RECVINFO( m_fNetworkHalfWidth ) ),
|
||||
RecvPropFloat( RECVINFO( m_fNetworkHalfHeight ) ),
|
||||
RecvPropBool( RECVINFO( m_bIsMobile ) ),
|
||||
|
||||
RecvPropDataTable( RECVINFO_DT( m_PortalSimulator ), 0, &REFERENCE_RECV_TABLE(DT_PortalSimulator) )
|
||||
END_RECV_TABLE()
|
||||
|
||||
// HACK: Now we can replace it
|
||||
#define CPortal_Base2D C_Portal_Base2D
|
||||
|
||||
BEGIN_PREDICTION_DATA( C_Portal_Base2D )
|
||||
DEFINE_PRED_FIELD( m_bActivated, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_bOldActivatedState, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_hLinkedPortal, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_ptOrigin, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
|
||||
DEFINE_PRED_FIELD( m_qAbsAngle, FIELD_VECTOR, FTYPEDESC_INSENDTABLE ),
|
||||
|
||||
//not actually networked fields. But we need them backed up and restored in the same way as the networked ones.
|
||||
DEFINE_FIELD( m_vForward, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( m_vRight, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( m_vUp, FIELD_VECTOR ),
|
||||
DEFINE_FIELD( m_plane_Origin, FIELD_VECTOR4D ),
|
||||
DEFINE_FIELD( m_matrixThisToLinked, FIELD_VMATRIX ),
|
||||
END_PREDICTION_DATA()
|
||||
|
||||
|
||||
|
||||
static ConVar portal_demohack( "portal_demohack", "0", FCVAR_ARCHIVE, "Do the demo_legacy_rollback setting to help during demo playback of going through portals." );
|
||||
static ConVar portal_ghost_use_network_origin( "portal_ghost_use_network_origin", "0", 0, "Use the network origin for determining bounds in which to ghost renderables, rather than the abs origin." );
|
||||
|
||||
class C_PortalInitHelper : public CAutoGameSystem
|
||||
{
|
||||
virtual bool Init()
|
||||
{
|
||||
if ( portal_demohack.GetBool() )
|
||||
{
|
||||
ConVarRef demo_legacy_rollback_ref( "demo_legacy_rollback" );
|
||||
demo_legacy_rollback_ref.SetValue( false ); //Portal demos are wrong if the eyes rollback as far as regular demos
|
||||
}
|
||||
// However, there are probably bugs with this when jump ducking, etc.
|
||||
return true;
|
||||
}
|
||||
};
|
||||
static C_PortalInitHelper s_PortalInitHelper;
|
||||
|
||||
|
||||
|
||||
C_Portal_Base2D::C_Portal_Base2D( void )
|
||||
{
|
||||
CPortal_Base2D_Shared::AllPortals.AddToTail( this );
|
||||
|
||||
m_PortalSimulator.SetPortalSimulatorCallbacks( this );
|
||||
}
|
||||
|
||||
C_Portal_Base2D::~C_Portal_Base2D( void )
|
||||
{
|
||||
CPortal_Base2D_Shared::AllPortals.FindAndRemove( this );
|
||||
g_pPortalRender->RemovePortal( this );
|
||||
|
||||
for( int i = m_GhostRenderables.Count(); --i >= 0; )
|
||||
{
|
||||
UTIL_Remove( m_GhostRenderables[i] );
|
||||
}
|
||||
m_GhostRenderables.RemoveAll();
|
||||
|
||||
if( m_pCollisionShape )
|
||||
{
|
||||
physcollision->DestroyCollide( m_pCollisionShape );
|
||||
m_pCollisionShape = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::Spawn( void )
|
||||
{
|
||||
// disable the fast path for these entities so our custom DrawModel() function gets called
|
||||
m_bCanUseFastPath = false;
|
||||
|
||||
m_matrixThisToLinked.Identity(); //don't accidentally teleport objects to zero space
|
||||
BaseClass::Spawn();
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::Activate( void )
|
||||
{
|
||||
BaseClass::Activate();
|
||||
}
|
||||
|
||||
ConVar cl_portal_ghost_use_render_bound("cl_portal_ghost_use_render_bound", "1");
|
||||
bool C_Portal_Base2D::Simulate()
|
||||
{
|
||||
BaseClass::Simulate();
|
||||
|
||||
//clear list of ghosted entities from last frame, and clear the clipping planes we put on them
|
||||
for( int i = m_hGhostingEntities.Count(); --i >= 0; )
|
||||
{
|
||||
C_BaseEntity *pEntity = m_hGhostingEntities[i].Get();
|
||||
|
||||
if( pEntity != NULL )
|
||||
{
|
||||
pEntity->m_bEnableRenderingClipPlane = false;
|
||||
}
|
||||
}
|
||||
m_hGhostingEntities.RemoveAll();
|
||||
|
||||
if( IsMobile() )
|
||||
{
|
||||
m_ptOrigin = GetAbsOrigin();
|
||||
AngleVectors( GetAbsAngles(), &m_vForward, &m_vRight, &m_vUp );
|
||||
PortalMoved(); //updates link matrix and internals
|
||||
|
||||
UpdateTeleportMatrix();
|
||||
OnPortalMoved();
|
||||
}
|
||||
|
||||
if( !IsActivedAndLinked() )
|
||||
{
|
||||
//remove all ghost renderables
|
||||
for( int i = m_GhostRenderables.Count(); --i >= 0; )
|
||||
{
|
||||
UTIL_Remove( m_GhostRenderables[i] );
|
||||
}
|
||||
|
||||
m_GhostRenderables.RemoveAll();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Portal doesn't support splits creen yet!!!
|
||||
//ACTIVE_SPLITSCREEN_PLAYER_GUARD( 0 );
|
||||
|
||||
//Find objects that are intersecting the portal and mark them for later replication on the remote portal's side
|
||||
//C_Portal_Player *pLocalPlayer = C_Portal_Player::GetLocalPlayer();
|
||||
//C_BaseViewModel *pLocalPlayerViewModel = pLocalPlayer->GetViewModel();
|
||||
|
||||
CBaseEntity *pEntsNearPortal[1024];
|
||||
|
||||
Vector vExtents = MAX( GetHalfHeight(), GetHalfWidth() ) * Vector(1,1,1);
|
||||
Vector vOrigin = portal_ghost_use_network_origin.GetBool() ? GetNetworkOrigin() : GetAbsOrigin();
|
||||
int iEntsNearPortal = ( cl_portal_ghost_use_render_bound.GetBool() ) ? UTIL_RenderablesInBox( pEntsNearPortal, 1024, vOrigin - vExtents, vOrigin + vExtents ) : UTIL_EntitiesInSphere( pEntsNearPortal, 1024, vOrigin, MAX( GetHalfHeight(), GetHalfWidth() ), 0, PARTITION_CLIENT_NON_STATIC_EDICTS );
|
||||
|
||||
if( iEntsNearPortal != 0 )
|
||||
{
|
||||
float fClipPlane[4];
|
||||
fClipPlane[0] = m_plane_Origin.normal.x;
|
||||
fClipPlane[1] = m_plane_Origin.normal.y;
|
||||
fClipPlane[2] = m_plane_Origin.normal.z;
|
||||
fClipPlane[3] = m_plane_Origin.dist - 2.0f;
|
||||
|
||||
for( int i = 0; i != iEntsNearPortal; ++i )
|
||||
{
|
||||
CBaseEntity *pEntity = pEntsNearPortal[i];
|
||||
Assert( pEntity != NULL );
|
||||
|
||||
if( C_PortalGhostRenderable::ShouldCloneEntity( pEntity, this, true ) )
|
||||
{
|
||||
pEntity->m_bEnableRenderingClipPlane = true;
|
||||
memcpy( pEntity->m_fRenderingClipPlane, fClipPlane, sizeof( float ) * 4 );
|
||||
|
||||
EHANDLE hEnt = pEntity;
|
||||
m_hGhostingEntities.AddToTail( hEnt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//now, fix up our list of ghosted renderables.
|
||||
{
|
||||
bool *bStillInUse = (bool *)stackalloc( sizeof( bool ) * (m_GhostRenderables.Count() + m_hGhostingEntities.Count()) );
|
||||
memset( bStillInUse, 0, sizeof( bool ) * (m_GhostRenderables.Count() + m_hGhostingEntities.Count()) );
|
||||
|
||||
for( int i = m_hGhostingEntities.Count(); --i >= 0; )
|
||||
{
|
||||
C_BaseEntity *pRenderable = m_hGhostingEntities[i].Get();
|
||||
|
||||
int j;
|
||||
for( j = m_GhostRenderables.Count(); --j >= 0; )
|
||||
{
|
||||
if ( pRenderable == m_GhostRenderables[j]->m_hGhostedRenderable )
|
||||
{
|
||||
bStillInUse[j] = true;
|
||||
m_GhostRenderables[j]->PerFrameUpdate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( j >= 0 )
|
||||
continue;
|
||||
|
||||
GetSimulateCallQueue()->QueueCall( C_PortalGhostRenderable::CreateGhostRenderable, pRenderable, this );
|
||||
}
|
||||
|
||||
for( int i = m_GhostRenderables.Count(); --i >= 0; )
|
||||
{
|
||||
if( !bStillInUse[i] &&
|
||||
((m_GhostRenderables[i]->m_fDisablePositionChecksUntilTime > gpGlobals->curtime) &&
|
||||
(m_GhostRenderables[i]->m_hGhostedRenderable.Get() != NULL) &&
|
||||
C_PortalGhostRenderable::ShouldCloneEntity( m_GhostRenderables[i]->m_hGhostedRenderable, this, false )) )
|
||||
{
|
||||
//this ghost is in a transitional state and gets a temporary reprieve from any position requirements to its ghosting
|
||||
bStillInUse[i] = true;
|
||||
m_GhostRenderables[i]->PerFrameUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
//remove unused ghosts
|
||||
for ( int i = m_GhostRenderables.Count(); --i >= 0; )
|
||||
{
|
||||
if ( bStillInUse[i] )
|
||||
continue;
|
||||
|
||||
// HACK - I just copied the CClientTools::OnEntityDeleted code here,
|
||||
// since the ghosts aren't really entities - they don't have an entindex,
|
||||
// they're not in the entitylist, and they get created during Simulate(),
|
||||
// which isn't valid for real entities, since it changes the simulate list
|
||||
// -jd
|
||||
C_PortalGhostRenderable *pGhost = m_GhostRenderables[i];
|
||||
|
||||
#if( DEBUG_GHOSTRENDERABLES == 1 )
|
||||
C_BaseEntity *pRenderable = pGhost->m_hGhostedRenderable;
|
||||
if( pRenderable )
|
||||
{
|
||||
Vector vTransformedOrigin;
|
||||
QAngle qTransformedAngles;
|
||||
VectorTransform( pRenderable->GetRenderOrigin(), m_matrixThisToLinked.As3x4(), vTransformedOrigin );
|
||||
qTransformedAngles = TransformAnglesToWorldSpace( pRenderable->GetRenderAngles(), m_matrixThisToLinked.As3x4() );
|
||||
NDebugOverlay::BoxAngles( vTransformedOrigin, pRenderable->CollisionProp()->OBBMins(), pRenderable->CollisionProp()->OBBMaxs(), qTransformedAngles, 255, 0, 0, 16, 0.0f );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( ToolsEnabled() )
|
||||
{
|
||||
HTOOLHANDLE handle = pGhost ? pGhost->GetToolHandle() : (HTOOLHANDLE)0;
|
||||
if ( handle != (HTOOLHANDLE)0 )
|
||||
{
|
||||
if ( clienttools->IsInRecordingMode() )
|
||||
{
|
||||
// Send deletion message to tool interface
|
||||
KeyValues *kv = new KeyValues( "deleted" );
|
||||
ToolFramework_PostToolMessage( handle, kv );
|
||||
kv->deleteThis();
|
||||
}
|
||||
|
||||
clienttools->DetachFromEntity( pGhost );
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_Remove( pGhost );
|
||||
m_GhostRenderables.FastRemove( i );
|
||||
}
|
||||
}
|
||||
|
||||
//ensure the shared clip plane is up to date
|
||||
C_Portal_Base2D *pLinkedPortal = m_hLinkedPortal.Get();
|
||||
|
||||
// When the portal is flat on the ground or on a ceiling, tweak the clip plane offset to hide the player feet sticking
|
||||
// through the floor. We can't use this offset in other configurations -- it visibly would cut of parts of the model.
|
||||
float flTmp = fabsf( DotProduct( pLinkedPortal->m_plane_Origin.normal, Vector( 0, 0, 1 ) ) );
|
||||
flTmp = fabsf( flTmp - 1.0f );
|
||||
float flClipPlaneFudgeOffset = ( flTmp < 0.01f ) ? 2.0f : -2.0f;
|
||||
|
||||
m_fGhostRenderablesClip[0] = pLinkedPortal->m_plane_Origin.normal.x;
|
||||
m_fGhostRenderablesClip[1] = pLinkedPortal->m_plane_Origin.normal.y;
|
||||
m_fGhostRenderablesClip[2] = pLinkedPortal->m_plane_Origin.normal.z;
|
||||
m_fGhostRenderablesClip[3] = pLinkedPortal->m_plane_Origin.dist - 2.0f;
|
||||
|
||||
m_fGhostRenderablesClipForPlayer[0] = pLinkedPortal->m_plane_Origin.normal.x;
|
||||
m_fGhostRenderablesClipForPlayer[1] = pLinkedPortal->m_plane_Origin.normal.y;
|
||||
m_fGhostRenderablesClipForPlayer[2] = pLinkedPortal->m_plane_Origin.normal.z;
|
||||
m_fGhostRenderablesClipForPlayer[3] = pLinkedPortal->m_plane_Origin.dist + flClipPlaneFudgeOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
C_PortalGhostRenderable *C_Portal_Base2D::GetGhostRenderableForEntity( C_BaseEntity *pEntity )
|
||||
{
|
||||
for( int i = 0; i != m_GhostRenderables.Count(); ++i )
|
||||
{
|
||||
if( m_GhostRenderables[i]->m_hGhostedRenderable == pEntity )
|
||||
return m_GhostRenderables[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::UpdateOnRemove( void )
|
||||
{
|
||||
g_pPortalRender->RemovePortal( this );
|
||||
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect )
|
||||
{
|
||||
if ( Q_stricmp( pszParticleName, "portal_1_overlap" ) == 0 || Q_stricmp( pszParticleName, "portal_2_overlap" ) == 0 )
|
||||
{
|
||||
float fClosestDistanceSqr = -1.0f;
|
||||
Vector vClosestPosition;
|
||||
|
||||
int iPortalCount = CPortal_Base2D_Shared::AllPortals.Count();
|
||||
if( iPortalCount != 0 )
|
||||
{
|
||||
C_Portal_Base2D **pPortals = CPortal_Base2D_Shared::AllPortals.Base();
|
||||
for( int i = 0; i != iPortalCount; ++i )
|
||||
{
|
||||
C_Portal_Base2D *pTempPortal = pPortals[i];
|
||||
if ( pTempPortal != this && pTempPortal->IsActive() )
|
||||
{
|
||||
Vector vPosition = pTempPortal->GetAbsOrigin();
|
||||
|
||||
float fDistanceSqr = pNewParticleEffect->GetRenderOrigin().DistToSqr( vPosition );
|
||||
|
||||
if ( fClosestDistanceSqr == -1.0f || fClosestDistanceSqr > fDistanceSqr )
|
||||
{
|
||||
fClosestDistanceSqr = fDistanceSqr;
|
||||
vClosestPosition = vPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( fClosestDistanceSqr != -1.0f )
|
||||
{
|
||||
pNewParticleEffect->SetControlPoint( 1, vClosestPosition );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::OnPreDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
//PreDataChanged.m_matrixThisToLinked = m_matrixThisToLinked;
|
||||
PreDataChanged.m_bIsPortal2 = m_bIsPortal2;
|
||||
PreDataChanged.m_bActivated = m_bActivated;
|
||||
PreDataChanged.m_bOldActivatedState = m_bOldActivatedState;
|
||||
PreDataChanged.m_hLinkedTo = m_hLinkedPortal.Get();
|
||||
PreDataChanged.m_bIsMobile = m_bIsMobile;
|
||||
PreDataChanged.m_vOrigin = m_ptOrigin;
|
||||
PreDataChanged.m_qAngles = m_qAbsAngle;
|
||||
|
||||
BaseClass::OnPreDataChanged( updateType );
|
||||
}
|
||||
|
||||
//ConVar r_portal_light_innerangle( "r_portal_light_innerangle", "90.0", FCVAR_CLIENTDLL );
|
||||
//ConVar r_portal_light_outerangle( "r_portal_light_outerangle", "90.0", FCVAR_CLIENTDLL );
|
||||
//ConVar r_portal_light_forward( "r_portal_light_forward", "0.0", FCVAR_CLIENTDLL );
|
||||
|
||||
void C_Portal_Base2D::HandleNetworkChanges( void )
|
||||
{
|
||||
C_Portal_Base2D *pRemote = m_hLinkedPortal;
|
||||
m_pLinkedPortal = pRemote;
|
||||
|
||||
//get absolute origin and angles, but cut out interpolation, use the network position and angles as transformed by any move parent
|
||||
{
|
||||
ALIGN16 matrix3x4_t finalMatrix;
|
||||
AngleMatrix( m_qAbsAngle, finalMatrix );
|
||||
|
||||
MatrixGetColumn( finalMatrix, 0, m_vForward );
|
||||
MatrixGetColumn( finalMatrix, 1, m_vRight );
|
||||
MatrixGetColumn( finalMatrix, 2, m_vUp );
|
||||
m_vRight = -m_vRight;
|
||||
}
|
||||
SetHalfSizes( m_fNetworkHalfWidth, m_fNetworkHalfHeight );
|
||||
|
||||
const PS_PlacementData_t &placement = m_PortalSimulator.GetInternalData().Placement;
|
||||
|
||||
bool bActivityChanged = PreDataChanged.m_bActivated != IsActive();
|
||||
bool bPortalMoved = ((/*(m_ptOrigin != PreDataChanged.m_vOrigin) &&*/ (m_ptOrigin != placement.ptCenter)) || //moved
|
||||
(/*(m_qAbsAngle != PreDataChanged.m_qAngles) &&*/ (m_qAbsAngle != placement.qAngles)) || //rotated
|
||||
(placement.fHalfWidth != m_fNetworkHalfWidth) || //resized
|
||||
(placement.fHalfHeight != m_fNetworkHalfHeight) || //resized
|
||||
(PreDataChanged.m_bIsPortal2 != m_bIsPortal2) ) || //swapped portal id
|
||||
((PreDataChanged.m_bIsMobile == true) && (m_bIsMobile == false)); //count an end of nudging as a move
|
||||
bool bNewLinkage = ( (PreDataChanged.m_hLinkedTo.Get() != m_hLinkedPortal.Get()) );
|
||||
|
||||
if( bNewLinkage || IsMobile() )
|
||||
m_PortalSimulator.DetachFromLinked(); //detach now so moves are theoretically faster
|
||||
|
||||
if( IsActive() )
|
||||
{
|
||||
//generic stuff we'll need
|
||||
g_pPortalRender->AddPortal( this ); //will know if we're already added and avoid adding twice
|
||||
|
||||
if( bPortalMoved || bActivityChanged )
|
||||
{
|
||||
if( !IsMobile() )
|
||||
{
|
||||
m_PortalSimulator.SetSize( GetHalfWidth(), GetHalfHeight() );
|
||||
m_PortalSimulator.MoveTo( m_ptOrigin, m_qAbsAngle );
|
||||
}
|
||||
}
|
||||
|
||||
if( pRemote && !IsMobile() )
|
||||
m_PortalSimulator.AttachTo( &pRemote->m_PortalSimulator );
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pPortalRender->RemovePortal( this );
|
||||
m_PortalSimulator.DetachFromLinked();
|
||||
|
||||
if( bPortalMoved || bActivityChanged )
|
||||
{
|
||||
if( !IsMobile() )
|
||||
{
|
||||
m_PortalSimulator.SetSize( GetHalfWidth(), GetHalfHeight() );
|
||||
m_PortalSimulator.MoveTo( m_ptOrigin, m_qAbsAngle );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( bNewLinkage || bPortalMoved || bActivityChanged )
|
||||
{
|
||||
//Warning_SpewCallStack( 10, "C_Portal_Base2D::HandleNetworkChanges( %.2f )\n", gpGlobals->curtime );
|
||||
PortalMoved(); //updates link matrix and internals
|
||||
UpdateTeleportMatrix();
|
||||
|
||||
if ( bPortalMoved )
|
||||
{
|
||||
OnPortalMoved();
|
||||
}
|
||||
|
||||
if( bActivityChanged )
|
||||
{
|
||||
OnActiveStateChanged();
|
||||
}
|
||||
|
||||
if( bNewLinkage )
|
||||
{
|
||||
OnLinkageChanged( PreDataChanged.m_hLinkedTo.Get() );
|
||||
}
|
||||
|
||||
UpdateGhostRenderables();
|
||||
if( pRemote )
|
||||
pRemote->UpdateGhostRenderables();
|
||||
}
|
||||
|
||||
m_PortalSimulator.SetCarvedParent( GetMoveParent() );
|
||||
|
||||
if( m_bIsPortal2 )
|
||||
{
|
||||
m_PortalSimulator.EditDebuggingData().overlayColor.SetColor( 255, 0, 0, 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PortalSimulator.EditDebuggingData().overlayColor.SetColor( 0, 0, 255, 255 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void C_Portal_Base2D::OnDataChanged( DataUpdateType_t updateType )
|
||||
{
|
||||
BaseClass::OnDataChanged( updateType );
|
||||
|
||||
bool bActivityChanged = PreDataChanged.m_bActivated != IsActive();
|
||||
|
||||
HandleNetworkChanges();
|
||||
|
||||
if ( bActivityChanged )
|
||||
{
|
||||
UpdateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::HandlePredictionError( bool bErrorInThisEntity )
|
||||
{
|
||||
if( bErrorInThisEntity )
|
||||
{
|
||||
HandleNetworkChanges();
|
||||
}
|
||||
|
||||
BaseClass::HandlePredictionError( bErrorInThisEntity );
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::UpdateGhostRenderables( void )
|
||||
{
|
||||
//lastly, update all ghost renderables
|
||||
for( int i = m_GhostRenderables.Count(); --i >= 0; )
|
||||
{
|
||||
m_GhostRenderables[i]->m_matGhostTransform = m_matrixThisToLinked;
|
||||
m_GhostRenderables[i]->m_fDisablePositionChecksUntilTime = -FLT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
extern ConVar building_cubemaps;
|
||||
|
||||
bool C_Portal_Base2D::ShouldDraw()
|
||||
{
|
||||
if ( !BaseClass::ShouldDraw() )
|
||||
return false;
|
||||
|
||||
if ( !IsActive() || building_cubemaps.GetBool() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::StartTouch( C_BaseEntity *pOther )
|
||||
{
|
||||
if( pOther->IsPlayer() )
|
||||
return;
|
||||
|
||||
//Warning( "C_Portal_Base2D::StartTouch(%s)\n", pOther->GetClassname() );
|
||||
BaseClass::StartTouch( pOther );
|
||||
|
||||
// Since prop_portal is a trigger it doesn't send back start touch, so I'm forcing it
|
||||
pOther->StartTouch( this );
|
||||
|
||||
if( (m_hLinkedPortal == NULL) || (IsActive() == false) || IsMobile() || m_hLinkedPortal->IsMobile() )
|
||||
return;
|
||||
|
||||
if( CPortal_Base2D_Shared::IsEntityTeleportable( pOther ) )
|
||||
{
|
||||
CCollisionProperty *pOtherCollision = pOther->CollisionProp();
|
||||
Vector vWorldMins, vWorldMaxs;
|
||||
pOtherCollision->WorldSpaceAABB( &vWorldMins, &vWorldMaxs );
|
||||
Vector ptOtherCenter = (vWorldMins + vWorldMaxs) / 2.0f;
|
||||
|
||||
if( m_plane_Origin.normal.Dot( ptOtherCenter ) > m_plane_Origin.dist )
|
||||
{
|
||||
//we should be interacting with this object, add it to our environment
|
||||
if( true )//SharedEnvironmentCheck( pOther ) )
|
||||
{
|
||||
Assert( IsMobile() || m_hLinkedPortal->IsMobile() || ((m_PortalSimulator.GetLinkedPortalSimulator() == NULL) && (m_hLinkedPortal.Get() == NULL)) ||
|
||||
(m_PortalSimulator.GetLinkedPortalSimulator() == &m_hLinkedPortal->m_PortalSimulator) ); //make sure this entity is linked to the same portal as our simulator
|
||||
|
||||
CPortalSimulator *pOwningSimulator = CPortalSimulator::GetSimulatorThatOwnsEntity( pOther );
|
||||
if( pOwningSimulator && (pOwningSimulator != &m_PortalSimulator) )
|
||||
pOwningSimulator->ReleaseOwnershipOfEntity( pOther );
|
||||
|
||||
m_PortalSimulator.TakeOwnershipOfEntity( pOther );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::Touch( C_BaseEntity *pOther )
|
||||
{
|
||||
if( pOther->IsPlayer() )
|
||||
return;
|
||||
|
||||
return BaseClass::Touch( pOther );
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::EndTouch( C_BaseEntity *pOther )
|
||||
{
|
||||
if( pOther->IsPlayer() )
|
||||
return;
|
||||
|
||||
//Warning( "C_Portal_Base2D::EndTouch(%s)\n", pOther->GetClassname() );
|
||||
BaseClass::EndTouch( pOther );
|
||||
|
||||
// Since prop_portal is a trigger it doesn't send back end touch, so I'm forcing it
|
||||
pOther->EndTouch( this );
|
||||
|
||||
// Don't do anything on end touch if it's not active
|
||||
if( !IsActive() || IsMobile() || ((m_hLinkedPortal.Get() != NULL) && m_hLinkedPortal->IsMobile()) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( ShouldTeleportTouchingEntity( pOther ) ) //an object passed through the plane and all the way out of the touch box
|
||||
{
|
||||
TeleportTouchingEntity( pOther );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PortalSimulator.ReleaseOwnershipOfEntity( pOther );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Handle recording for the SFM
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_Portal_Base2D::GetToolRecordingState( KeyValues *msg )
|
||||
{
|
||||
if ( !ToolsEnabled() )
|
||||
return;
|
||||
|
||||
VPROF_BUDGET( "C_Portal_Base2D::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
|
||||
BaseClass::GetToolRecordingState( msg );
|
||||
|
||||
if ( !IsActive() )
|
||||
{
|
||||
BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
|
||||
pBaseEntity->m_bVisible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::UpdateTeleportMatrix( void )
|
||||
{
|
||||
//setup our origin plane
|
||||
m_plane_Origin.normal = m_vForward;
|
||||
m_plane_Origin.dist = m_plane_Origin.normal.Dot( m_ptOrigin );
|
||||
m_plane_Origin.signbits = SignbitsForPlane( &m_plane_Origin );
|
||||
|
||||
Vector vAbsNormal;
|
||||
vAbsNormal.x = fabs(m_plane_Origin.normal.x);
|
||||
vAbsNormal.y = fabs(m_plane_Origin.normal.y);
|
||||
vAbsNormal.z = fabs(m_plane_Origin.normal.z);
|
||||
|
||||
if( vAbsNormal.x > vAbsNormal.y )
|
||||
{
|
||||
if( vAbsNormal.x > vAbsNormal.z )
|
||||
{
|
||||
if( vAbsNormal.x > 0.999f )
|
||||
m_plane_Origin.type = PLANE_X;
|
||||
else
|
||||
m_plane_Origin.type = PLANE_ANYX;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( vAbsNormal.z > 0.999f )
|
||||
m_plane_Origin.type = PLANE_Z;
|
||||
else
|
||||
m_plane_Origin.type = PLANE_ANYZ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( vAbsNormal.y > vAbsNormal.z )
|
||||
{
|
||||
if( vAbsNormal.y > 0.999f )
|
||||
m_plane_Origin.type = PLANE_Y;
|
||||
else
|
||||
m_plane_Origin.type = PLANE_ANYY;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( vAbsNormal.z > 0.999f )
|
||||
m_plane_Origin.type = PLANE_Z;
|
||||
else
|
||||
m_plane_Origin.type = PLANE_ANYZ;
|
||||
}
|
||||
}
|
||||
|
||||
UTIL_Portal_ComputeMatrix( this, m_pLinkedPortal );
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::SetIsPortal2( bool bValue )
|
||||
{
|
||||
m_bIsPortal2 = bValue;
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::UpdatePartitionListEntry()
|
||||
{
|
||||
::partition->RemoveAndInsert(
|
||||
PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, // remove
|
||||
PARTITION_CLIENT_TRIGGER_ENTITIES, // add
|
||||
CollisionProp()->GetPartitionHandle() );
|
||||
}
|
||||
|
||||
bool C_Portal_Base2D::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
|
||||
{
|
||||
if ( !m_pCollisionShape )
|
||||
{
|
||||
//HACK: This is a last-gasp type fix for a crash caused by m_pCollisionShape not yet being set up
|
||||
// during a restore.
|
||||
UpdateCollisionShape();
|
||||
}
|
||||
|
||||
physcollision->TraceBox( ray, MASK_ALL, NULL, m_pCollisionShape, m_ptOrigin, m_qAbsAngle, &tr );
|
||||
return tr.DidHit();
|
||||
}
|
||||
|
||||
void C_Portal_Base2D::NewLocation( const Vector &vOrigin, const QAngle &qAngles )
|
||||
{
|
||||
//Warning( "C_Portal_Base2D::NewLocation(client) %f %.2f %.2f %.2f\n", gpGlobals->curtime, XYZ( vOrigin ) );
|
||||
|
||||
//get absolute origin and angles, but cut out interpolation, use the network position and angles as transformed by any move parent
|
||||
{
|
||||
ALIGN16 matrix3x4_t finalMatrix;
|
||||
AngleMatrix( qAngles, finalMatrix );
|
||||
|
||||
MatrixGetColumn( finalMatrix, 0, m_vForward );
|
||||
MatrixGetColumn( finalMatrix, 1, m_vRight );
|
||||
MatrixGetColumn( finalMatrix, 2, m_vUp );
|
||||
m_vRight = -m_vRight;
|
||||
|
||||
m_ptOrigin = vOrigin;
|
||||
m_qAbsAngle = qAngles;
|
||||
}
|
||||
|
||||
AddEffects( EF_NOINTERP );
|
||||
//PredictClearNoInterpEffect();
|
||||
if( GetMoveParent() )
|
||||
{
|
||||
SetAbsOrigin( vOrigin );
|
||||
SetAbsAngles( qAngles );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNetworkOrigin( vOrigin );
|
||||
SetNetworkAngles( qAngles );
|
||||
}
|
||||
GetOriginInterpolator().ClearHistory();
|
||||
GetRotationInterpolator().ClearHistory();
|
||||
|
||||
if( IsActive() == false )
|
||||
{
|
||||
SetActive( true );
|
||||
OnActiveStateChanged();
|
||||
}
|
||||
|
||||
m_PortalSimulator.MoveTo( m_ptOrigin, m_qAbsAngle );
|
||||
m_PortalSimulator.SetSize( GetHalfWidth(), GetHalfHeight() );
|
||||
|
||||
if( m_hLinkedPortal.Get() && !IsMobile() )
|
||||
m_PortalSimulator.AttachTo( &m_hLinkedPortal.Get()->m_PortalSimulator );
|
||||
|
||||
m_pLinkedPortal = m_hLinkedPortal;
|
||||
|
||||
|
||||
PortalMoved(); //updates link matrix and internals
|
||||
UpdateTeleportMatrix();
|
||||
|
||||
OnPortalMoved();
|
||||
UpdateGhostRenderables();
|
||||
|
||||
C_Portal_Base2D *pRemote = m_hLinkedPortal.Get();
|
||||
if( pRemote )
|
||||
pRemote->UpdateGhostRenderables();
|
||||
|
||||
g_pPortalRender->AddPortal( this ); //will know if we're already added and avoid adding twice
|
||||
}
|
||||
|
||||
PRECACHE_REGISTER_BEGIN( GLOBAL, PrecachePortalBased2DMaterials )
|
||||
PRECACHE( MATERIAL, "models/portals/portal_depthdoubler" )
|
||||
PRECACHE( MATERIAL, "models/portals/portal_stencil_hole" )
|
||||
PRECACHE_REGISTER_END()
|
||||
|
||||
class CAutoInitPortalDrawingMaterials : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
PortalDrawingMaterials m_Materials;
|
||||
void LevelInitPreEntity()
|
||||
{
|
||||
m_Materials.m_Portal_Stencil_Hole.Init( "decals/portalstencildecal", TEXTURE_GROUP_CLIENT_EFFECTS );
|
||||
}
|
||||
};
|
||||
static CAutoInitPortalDrawingMaterials s_FlatBasicPortalDrawingMaterials;
|
||||
|
||||
PortalDrawingMaterials& C_Portal_Base2D::m_Materials = s_FlatBasicPortalDrawingMaterials.m_Materials;
|
||||
|
||||
void C_Portal_Base2D::DrawStencilMask( IMatRenderContext *pRenderContext )
|
||||
{
|
||||
DrawSimplePortalMesh( pRenderContext, m_Materials.m_Portal_Stencil_Hole );
|
||||
DrawRenderFixMesh( pRenderContext, g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
|
||||
}
|
||||
|
||||
|
||||
ConVar cl_portal_teleportation_interpolation_fixup_method( "cl_portal_teleportation_interpolation_fixup_method", "1", 0, "0 = transform history only, 1 = insert discontinuity transform" );
|
||||
|
||||
void EntityPortalledMessageHandler( C_BaseEntity *pEntity, C_Portal_Base2D *pPortal, float fTime, bool bForcedDuck )
|
||||
{
|
||||
#if( PLAYERPORTALDEBUGSPEW == 1 )
|
||||
Warning( "EntityPortalledMessageHandler() %f -=- %f %i======================\n", fTime, engine->GetLastTimeStamp(), prediction->GetLastAcknowledgedCommandNumber() );
|
||||
#endif
|
||||
|
||||
C_PortalGhostRenderable *pGhost = pPortal->GetGhostRenderableForEntity( pEntity );
|
||||
if( !pGhost )
|
||||
{
|
||||
//high velocity edge case. Entity portalled before it ever created a clone. But will need one for the interpolated origin history
|
||||
if( C_PortalGhostRenderable::ShouldCloneEntity( pEntity, pPortal, false ) )
|
||||
{
|
||||
pGhost = C_PortalGhostRenderable::CreateGhostRenderable( pEntity, pPortal );
|
||||
if( pGhost )
|
||||
{
|
||||
Assert( !pPortal->m_hGhostingEntities.IsValidIndex( pPortal->m_hGhostingEntities.Find( pEntity ) ) );
|
||||
pPortal->m_hGhostingEntities.AddToTail( pEntity );
|
||||
Assert( pPortal->m_GhostRenderables.IsValidIndex( pPortal->m_GhostRenderables.Find( pGhost ) ) );
|
||||
pGhost->PerFrameUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( pGhost )
|
||||
{
|
||||
C_PortalGhostRenderable::CreateInversion( pGhost, pPortal, fTime );
|
||||
}
|
||||
|
||||
if( pEntity->IsPlayer() )
|
||||
{
|
||||
((C_Portal_Player *)pEntity)->PlayerPortalled( pPortal, fTime, bForcedDuck );
|
||||
return;
|
||||
}
|
||||
|
||||
pEntity->AddEFlags( EFL_DIRTY_ABSTRANSFORM );
|
||||
|
||||
VMatrix matTransform = pPortal->MatrixThisToLinked();
|
||||
|
||||
CDiscontinuousInterpolatedVar< QAngle > &rotInterp = pEntity->GetRotationInterpolator();
|
||||
CDiscontinuousInterpolatedVar< Vector > &posInterp = pEntity->GetOriginInterpolator();
|
||||
|
||||
|
||||
if( cl_portal_teleportation_interpolation_fixup_method.GetInt() == 0 )
|
||||
{
|
||||
UTIL_TransformInterpolatedAngle( rotInterp, matTransform.As3x4(), fTime );
|
||||
UTIL_TransformInterpolatedPosition( posInterp, matTransform, fTime );
|
||||
}
|
||||
else
|
||||
{
|
||||
rotInterp.InsertDiscontinuity( matTransform.As3x4(), fTime );
|
||||
posInterp.InsertDiscontinuity( matTransform.As3x4(), fTime );
|
||||
}
|
||||
|
||||
if ( pEntity->IsToolRecording() )
|
||||
{
|
||||
static EntityTeleportedRecordingState_t state;
|
||||
|
||||
KeyValues *msg = new KeyValues( "entity_teleported" );
|
||||
msg->SetPtr( "state", &state );
|
||||
state.m_bTeleported = true;
|
||||
state.m_bViewOverride = false;
|
||||
state.m_vecTo = pEntity->GetAbsOrigin();
|
||||
state.m_qaTo = pEntity->GetAbsAngles();
|
||||
state.m_teleportMatrix = matTransform.As3x4();
|
||||
|
||||
// Post a message back to all IToolSystems
|
||||
Assert( (int)pEntity->GetToolHandle() != 0 );
|
||||
ToolFramework_PostToolMessage( pEntity->GetToolHandle(), msg );
|
||||
|
||||
msg->deleteThis();
|
||||
}
|
||||
|
||||
C_Portal_Player* pPlayer = C_Portal_Player::GetLocalPortalPlayer( GET_ACTIVE_SPLITSCREEN_SLOT() );
|
||||
if ( pPlayer && pEntity == pPlayer->GetAttachedObject() )
|
||||
{
|
||||
C_BaseAnimating *pAnim = pEntity->GetBaseAnimating();
|
||||
if ( pAnim && pAnim->IsUsingRenderOriginOverride() )
|
||||
{
|
||||
pPlayer->ResetHeldObjectOutOfEyeTransitionDT();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct PortalTeleportationLogEntry_t
|
||||
{
|
||||
CHandle<C_BaseEntity> hEntity;
|
||||
CHandle<C_Portal_Base2D> hPortal;
|
||||
float fTeleportTime;
|
||||
bool bForcedDuck;
|
||||
};
|
||||
|
||||
static CThreadFastMutex s_PortalTeleportationLogMutex;
|
||||
static CUtlVector<PortalTeleportationLogEntry_t> s_PortalTeleportationLog;
|
||||
|
||||
void RecieveEntityPortalledMessage( CHandle<C_BaseEntity> hEntity, CHandle<C_Portal_Base2D> hPortal, float fTime, bool bForcedDuck )
|
||||
{
|
||||
PortalTeleportationLogEntry_t temp;
|
||||
temp.hEntity = hEntity;
|
||||
temp.hPortal = hPortal;
|
||||
temp.fTeleportTime = fTime;
|
||||
temp.bForcedDuck = bForcedDuck;
|
||||
|
||||
s_PortalTeleportationLogMutex.Lock();
|
||||
s_PortalTeleportationLog.AddToTail( temp );
|
||||
s_PortalTeleportationLogMutex.Unlock();
|
||||
}
|
||||
|
||||
|
||||
void ProcessPortalTeleportations( void )
|
||||
{
|
||||
s_PortalTeleportationLogMutex.Lock();
|
||||
for( int i = 0; i != s_PortalTeleportationLog.Count(); ++i )
|
||||
{
|
||||
PortalTeleportationLogEntry_t &entry = s_PortalTeleportationLog[i];
|
||||
|
||||
C_Portal_Base2D *pPortal = entry.hPortal;
|
||||
if( pPortal == NULL )
|
||||
continue;
|
||||
|
||||
//grab other entity's EHANDLE
|
||||
C_BaseEntity *pEntity = entry.hEntity;
|
||||
if( pEntity == NULL )
|
||||
continue;
|
||||
|
||||
EntityPortalledMessageHandler( pEntity, pPortal, entry.fTeleportTime, entry.bForcedDuck );
|
||||
}
|
||||
s_PortalTeleportationLog.RemoveAll();
|
||||
s_PortalTeleportationLogMutex.Unlock();
|
||||
}
|
||||
157
game/client/portal/c_portal_base2d.h
Normal file
157
game/client/portal/c_portal_base2d.h
Normal file
@@ -0,0 +1,157 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_PORTAL_BASE2D_H
|
||||
#define C_PORTAL_BASE2D_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "portalrenderable_flatbasic.h"
|
||||
#include "iviewrender.h"
|
||||
#include "view_shared.h"
|
||||
#include "viewrender.h"
|
||||
#include "PortalSimulation.h"
|
||||
#include "C_PortalGhostRenderable.h"
|
||||
#include "portal_base2d_shared.h"
|
||||
#include "portal_player_shared.h"
|
||||
|
||||
struct dlight_t;
|
||||
class C_DynamicLight;
|
||||
|
||||
struct PortalDrawingMaterials
|
||||
{
|
||||
CMaterialReference m_Portal_Stencil_Hole;
|
||||
};
|
||||
|
||||
class C_Portal_Base2D : public CPortalRenderable_FlatBasic, public CPortal_Base2D_Shared, public CPortalSimulatorEventCallbacks, public CSignifierTarget
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_Portal_Base2D, CPortalRenderable_FlatBasic );
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
C_Portal_Base2D( void );
|
||||
virtual ~C_Portal_Base2D( void );
|
||||
|
||||
// Handle recording for the SFM
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
|
||||
CHandle<C_Portal_Base2D> m_hLinkedPortal; //the portal this portal is linked to
|
||||
|
||||
bool m_bSharedEnvironmentConfiguration; //this will be set by an instance of CPortal_Environment when two environments are in close proximity
|
||||
|
||||
cplane_t m_plane_Origin; // The plane on which this portal is placed, normal facing outward (matching model forward vec)
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Activate( void );
|
||||
|
||||
virtual bool Simulate();
|
||||
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual bool IsActive( void ) const { return m_bActivated; }
|
||||
virtual bool GetOldActiveState( void ) const { return m_bOldActivatedState; }
|
||||
virtual void SetActive( bool bActive );
|
||||
|
||||
virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect );
|
||||
|
||||
virtual bool UseSelectionGlow( void ) { return false; }
|
||||
|
||||
struct Portal_PreDataChanged
|
||||
{
|
||||
bool m_bActivated;
|
||||
bool m_bOldActivatedState;
|
||||
bool m_bIsPortal2;
|
||||
Vector m_vOrigin;
|
||||
QAngle m_qAngles;
|
||||
CHandle<C_Portal_Base2D> m_hLinkedTo;
|
||||
bool m_bIsMobile;
|
||||
} PreDataChanged;
|
||||
|
||||
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
||||
void HandleNetworkChanges( void );
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
virtual void HandlePredictionError( bool bErrorInThisEntity );
|
||||
|
||||
//upgrade origin and angles to high precision to prevent prediction errors with projected walls.
|
||||
virtual bool ShouldRegenerateOriginFromCellBits() const {return false;}
|
||||
|
||||
virtual void OnPortalMoved( void ) { }; //this portal has moved
|
||||
virtual void OnActiveStateChanged( void ) { }; //this portal's active status has changed
|
||||
virtual void OnLinkageChanged( C_Portal_Base2D *pOldLinkage ) { };
|
||||
virtual bool ShouldDraw();
|
||||
virtual void StartTouch( C_BaseEntity *pOther );
|
||||
virtual void Touch( C_BaseEntity *pOther );
|
||||
virtual void EndTouch( C_BaseEntity *pOther );
|
||||
bool ShouldTeleportTouchingEntity( CBaseEntity *pOther ); //assuming the entity is or was just touching the portal, check for teleportation conditions
|
||||
void TeleportTouchingEntity( CBaseEntity *pOther );
|
||||
virtual void PreTeleportTouchingEntity( CBaseEntity *pOther ) {};
|
||||
virtual void PostTeleportTouchingEntity( CBaseEntity *pOther ) {};
|
||||
virtual void UpdatePartitionListEntry();
|
||||
virtual bool TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
|
||||
|
||||
virtual void PortalSimulator_TookOwnershipOfEntity( CBaseEntity *pEntity );
|
||||
virtual void PortalSimulator_ReleasedOwnershipOfEntity( CBaseEntity *pEntity );
|
||||
|
||||
//void UpdateOriginPlane( void );
|
||||
void UpdateTeleportMatrix( void );
|
||||
void UpdateGhostRenderables( void );
|
||||
|
||||
void SetIsPortal2( bool bValue );
|
||||
|
||||
bool IsActivedAndLinked( void ) const;
|
||||
|
||||
bool IsFloorPortal( float fThreshold = 0.8f ) const;
|
||||
bool IsCeilingPortal( float fThreshold = -0.8f ) const;
|
||||
|
||||
CPortalSimulator m_PortalSimulator;
|
||||
|
||||
virtual C_BaseEntity * PortalRenderable_GetPairedEntity( void ) { return this; };
|
||||
|
||||
inline bool IsMobile( void ) const { return m_bIsMobile; }
|
||||
|
||||
inline float GetHalfWidth( void ) const { return m_fNetworkHalfWidth; }
|
||||
inline float GetHalfHeight( void ) const { return m_fNetworkHalfHeight; }
|
||||
inline Vector GetLocalMins( void ) const { return Vector( 0.0f, -m_fNetworkHalfWidth, -m_fNetworkHalfHeight ); }
|
||||
inline Vector GetLocalMaxs( void ) const { return Vector( 64.0f, m_fNetworkHalfWidth, m_fNetworkHalfHeight ); }
|
||||
|
||||
void UpdateCollisionShape( void );
|
||||
|
||||
virtual void NewLocation( const Vector &vOrigin, const QAngle &qAngles );
|
||||
virtual void DrawStencilMask( IMatRenderContext *pRenderContext );
|
||||
|
||||
//it shouldn't matter, but the convention should be that we query the exit portal for these values
|
||||
virtual float GetMinimumExitSpeed( bool bPlayer, bool bEntranceOnFloor, bool bExitOnFloor, const Vector &vEntityCenterAtExit, CBaseEntity *pEntity ); //return -FLT_MAX for no minimum
|
||||
virtual float GetMaximumExitSpeed( bool bPlayer, bool bEntranceOnFloor, bool bExitOnFloor, const Vector &vEntityCenterAtExit, CBaseEntity *pEntity ); //return FLT_MAX for no maximum
|
||||
|
||||
//does all the gruntwork of figuring out flooriness and calling the two above
|
||||
static void GetExitSpeedRange( CPortal_Base2D *pEntrancePortal, bool bPlayer, float &fExitMinimum, float &fExitMaximum, const Vector &vEntityCenterAtExit, CBaseEntity *pEntity );
|
||||
|
||||
C_PortalGhostRenderable *GetGhostRenderableForEntity( C_BaseEntity *pEntity );
|
||||
|
||||
CUtlVector<EHANDLE> m_hGhostingEntities;
|
||||
CUtlVector<C_PortalGhostRenderable *> m_GhostRenderables;
|
||||
|
||||
float m_fGhostRenderablesClip[4];
|
||||
float m_fGhostRenderablesClipForPlayer[4];
|
||||
|
||||
static PortalDrawingMaterials& m_Materials;
|
||||
|
||||
protected:
|
||||
bool m_bActivated; //a portal can exist and not be active
|
||||
bool m_bOldActivatedState; //state the portal was in before it was created this instance
|
||||
|
||||
|
||||
|
||||
float m_fNetworkHalfWidth, m_fNetworkHalfHeight;
|
||||
bool m_bIsMobile;
|
||||
CPhysCollide *m_pCollisionShape;
|
||||
|
||||
};
|
||||
|
||||
#endif //#ifndef C_PORTAL_BASE2D_H
|
||||
4212
game/client/portal/c_portal_player.cpp
Normal file
4212
game/client/portal/c_portal_player.cpp
Normal file
File diff suppressed because it is too large
Load Diff
721
game/client/portal/c_portal_player.h
Normal file
721
game/client/portal/c_portal_player.h
Normal file
@@ -0,0 +1,721 @@
|
||||
//===== Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//===========================================================================//
|
||||
#ifndef PORTAL_PLAYER_H
|
||||
#define PORTAL_PLAYER_H
|
||||
#pragma once
|
||||
|
||||
#include "portal_playeranimstate.h"
|
||||
#include "c_baseplayer.h"
|
||||
#include "portal_player_shared.h"
|
||||
#include "c_portal_base2d.h"
|
||||
#include "weapon_portalbase.h"
|
||||
#include "colorcorrectionmgr.h"
|
||||
#include "c_portal_playerlocaldata.h"
|
||||
#include "iinput.h"
|
||||
#include "paint_power_user.h"
|
||||
#include "paintable_entity.h"
|
||||
#include "portal2/portal_grabcontroller_shared.h"
|
||||
#include "portal_shareddefs.h"
|
||||
|
||||
#if !defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
|
||||
#include "portal2_item_inventory.h"
|
||||
#endif
|
||||
|
||||
struct PaintPowerChoiceCriteria_t;
|
||||
|
||||
enum PortalScreenSpaceEffect
|
||||
{
|
||||
PAINT_SCREEN_SPACE_EFFECT,
|
||||
|
||||
PORTAL_SCREEN_SPACE_EFFECT_COUNT
|
||||
};
|
||||
|
||||
class C_EntityPortalledNetworkMessage : public CMemZeroOnNew
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS_NOBASE( C_EntityPortalledNetworkMessage );
|
||||
|
||||
CHandle<C_BaseEntity> m_hEntity;
|
||||
CHandle<CPortal_Base2D> m_hPortal;
|
||||
float m_fTime;
|
||||
bool m_bForcedDuck;
|
||||
uint32 m_iMessageCount;
|
||||
};
|
||||
|
||||
class CMoveData;
|
||||
|
||||
//=============================================================================
|
||||
// >> Portal_Player
|
||||
//=============================================================================
|
||||
class C_Portal_Player : public PaintPowerUser< CPaintableEntity< C_BasePlayer > >
|
||||
#if !defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
|
||||
, public IInventoryUpdateListener
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_Portal_Player, PaintPowerUser< CPaintableEntity< C_BasePlayer > > );
|
||||
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
DECLARE_INTERPOLATION();
|
||||
|
||||
|
||||
C_Portal_Player();
|
||||
~C_Portal_Player( void );
|
||||
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual void Precache( void );
|
||||
|
||||
virtual void PostThink();
|
||||
void ClientThink( void );
|
||||
|
||||
static inline C_Portal_Player* GetLocalPortalPlayer( int nSlot = -1 )
|
||||
{
|
||||
return static_cast< C_Portal_Player* >( C_BasePlayer::GetLocalPlayer( nSlot ) );
|
||||
}
|
||||
|
||||
static inline C_Portal_Player* GetLocalPlayer( int nSlot = -1 )
|
||||
{
|
||||
return static_cast< C_Portal_Player* >( C_BasePlayer::GetLocalPlayer( nSlot ) );
|
||||
}
|
||||
|
||||
virtual Vector GetThirdPersonViewPosition( void );
|
||||
virtual const Vector& GetRenderOrigin( void );
|
||||
virtual const QAngle& GetRenderAngles();
|
||||
|
||||
virtual void SetAnimation( PLAYER_ANIM playerAnim );
|
||||
|
||||
virtual void UpdateClientSideAnimation();
|
||||
void DoAnimationEvent( PlayerAnimEvent_t event, int nData );
|
||||
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
||||
|
||||
bool ShouldSkipRenderingViewpointPlayerForThisView( void );
|
||||
virtual const char *GetPlayerModelName( void );
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual bool Simulate( void );
|
||||
virtual IClientModelRenderable *GetClientModelRenderable();
|
||||
|
||||
QAngle GetAnimEyeAngles( void ) { return m_angEyeAngles; }
|
||||
Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL );
|
||||
|
||||
// Should this object cast shadows?
|
||||
virtual ShadowType_t ShadowCastType( void );
|
||||
virtual C_BaseAnimating* BecomeRagdollOnClient();
|
||||
virtual bool ShouldDraw( void );
|
||||
virtual bool ShouldSuppressForSplitScreenPlayer( int nSlot );
|
||||
virtual PlayerRenderMode_t GetPlayerRenderMode( int nSlot );
|
||||
virtual void GetRenderBoundsWorldspace( Vector& absMins, Vector& absMaxs );
|
||||
virtual const QAngle& EyeAngles();
|
||||
virtual void OnPreDataChanged( DataUpdateType_t type );
|
||||
virtual void PreDataUpdate( DataUpdateType_t updateType );
|
||||
virtual void OnDataChanged( DataUpdateType_t type );
|
||||
virtual void PostDataUpdate( DataUpdateType_t updateType );
|
||||
virtual float GetFOV( void );
|
||||
virtual CStudioHdr* OnNewModel( void );
|
||||
virtual void TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr );
|
||||
virtual void ItemPreFrame( void );
|
||||
virtual void ItemPostFrame( void );
|
||||
virtual float GetMinFOV() const { return 5.0f; }
|
||||
virtual Vector GetAutoaimVector( float flDelta );
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags );
|
||||
virtual void GetStepSoundVelocities( float *velwalk, float *velrun );
|
||||
virtual void PlayStepSound( Vector &vecOrigin, surfacedata_t *psurface, float fvol, bool force );
|
||||
virtual void PreThink( void );
|
||||
virtual void DoImpactEffect( trace_t &tr, int nDamageType );
|
||||
virtual bool CreateMove( float flInputSampleTime, CUserCmd *pCmd );
|
||||
virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const;
|
||||
virtual bool IsZoomed( void ) { return m_PortalLocal.m_bZoomedIn; }
|
||||
|
||||
virtual const Vector &WorldSpaceCenter() const;
|
||||
|
||||
virtual Vector EyePosition();
|
||||
virtual Vector EyeFootPosition( const QAngle &qEyeAngles );//interpolates between eyes and feet based on view angle roll
|
||||
inline Vector EyeFootPosition( void ) { return EyeFootPosition( EyeAngles() ); };
|
||||
void PlayerPortalled( C_Portal_Base2D *pEnteredPortal, float fTime, bool bForcedDuck );
|
||||
void CheckPlayerAboutToTouchPortal( void );
|
||||
|
||||
bool IsTaunting( void );
|
||||
int GetTeamTauntState( void ) const { return m_nTeamTauntState; }
|
||||
bool IsPingDisabled( void ) const { return m_bPingDisabled; }
|
||||
bool IsTauntDisabled( void ) const { return m_bTauntDisabled; }
|
||||
bool IsRemoteViewTaunt( void ) const { return m_bTauntRemoteView; }
|
||||
QAngle GetTeamTauntAngles( void ) { return m_vTauntAngles; }
|
||||
QAngle GetTrickFireAngles( void ) { return m_vPreTauntAngles; }
|
||||
bool IsTrickFiring( void ) const { return m_bTrickFire; }
|
||||
void ClearTrickFiring( void ) { m_bTrickFire = false; }
|
||||
bool IsInterpolatingTauntAngles( void ) const { return m_bTauntInterpolatingAngles; }
|
||||
float GetTauntCamTargetPitch( void ) const { return m_flTauntCamTargetPitch; }
|
||||
float GetTauntCamTargetYaw( void ) const { return m_flTauntCamTargetYaw; }
|
||||
void SetFaceTauntCameraEndAngles( bool bFaceTauntCameraEndAngles ) { m_bFaceTauntCameraEndAngles = bFaceTauntCameraEndAngles; }
|
||||
class C_Portal_Player* HasTauntPartnerInRange( void ) const { return m_hTauntPartnerInRange.Get(); }
|
||||
const char* GetTauntForceName( void ) const { return m_szTauntForce; }
|
||||
|
||||
void ResetHeldObjectOutOfEyeTransitionDT( void ) { m_flObjectOutOfEyeTransitionDT = 0.0f; }
|
||||
|
||||
C_BaseEntity *FindPlayerUseEntity( void );
|
||||
bool IsUseableEntity( CBaseEntity *pEntity, unsigned int requiredCaps );
|
||||
|
||||
virtual void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov );
|
||||
void CalcPortalView( Vector &eyeOrigin, QAngle &eyeAngles, float &fov );
|
||||
virtual void CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles);
|
||||
|
||||
bool IsInvalidHandoff( CBaseEntity *pObject );
|
||||
void PollForUseEntity( bool bBasicUse, CBaseEntity **ppUseEnt, CPortal_Base2D **ppUseThroughPortal );
|
||||
CBaseEntity* FindUseEntity( C_Portal_Base2D **pThroughPortal );
|
||||
CBaseEntity* FindUseEntityThroughPortal( void );
|
||||
|
||||
inline bool IsCloseToPortal( void ) //it's usually a good idea to turn on draw hacks when this is true
|
||||
{
|
||||
return ((PortalEyeInterpolation.m_bEyePositionIsInterpolating) || (m_hPortalEnvironment.Get() != NULL));
|
||||
}
|
||||
|
||||
// Gesturing
|
||||
virtual bool StartSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
|
||||
virtual bool StartGestureSceneEvent( CSceneEventInfo *info, CChoreoScene *scene, CChoreoEvent *event, CChoreoActor *actor, CBaseEntity *pTarget );
|
||||
|
||||
void SetAirControlSupressionTime( float flDuration ) { m_PortalLocal.m_flAirControlSupressionTime = flDuration; }
|
||||
bool IsSuppressingAirControl( void ) { return m_PortalLocal.m_flAirControlSupressionTime != 0.0f; }
|
||||
|
||||
void UpdateLookAt( void );
|
||||
void Initialize( void );
|
||||
|
||||
virtual const char * GetVOIPParticleEffectName( void ) const;
|
||||
virtual CNewParticleEffect *GetVOIPParticleEffect( void );
|
||||
|
||||
C_Portal_Base2D *GetHeldObjectPortal( void ) const { return m_hHeldObjectPortal.Get(); }
|
||||
|
||||
Activity TranslateActivity( Activity baseAct, bool *pRequired = NULL );
|
||||
CWeaponPortalBase* GetActivePortalWeapon() const;
|
||||
|
||||
#if USE_SLOWTIME
|
||||
bool IsSlowingTime( void ) { return m_PortalLocal.m_bSlowingTime; }
|
||||
#endif // USE_SLOWTIME
|
||||
bool IsShowingViewFinder( void ) { return m_PortalLocal.m_bShowingViewFinder; }
|
||||
|
||||
struct PredictedPortalTeleportation_t
|
||||
{
|
||||
float flTime;
|
||||
C_Portal_Base2D *pEnteredPortal;
|
||||
int iCommandNumber;
|
||||
float fDeleteServerTimeStamp;
|
||||
bool bDuckForced;
|
||||
VMatrix matUnroll; //sometimes the portals move/fizzle between an apply and an unroll. Store the undo matrix ahead of time
|
||||
};
|
||||
CUtlVector<PredictedPortalTeleportation_t> m_PredictedPortalTeleportations;
|
||||
|
||||
void FinishMove( CMoveData *move );
|
||||
|
||||
bool IsHoldingSomething( void ) const { return m_bIsHoldingSomething; }
|
||||
|
||||
virtual void ApplyTransformToInterpolators( const VMatrix &matTransform, float fUpToTime, bool bIsRevertingPreviousTransform, bool bDuckForced );
|
||||
|
||||
//single player doesn't predict portal teleportations. This is the call you'll receive when we determine the server portalled us.
|
||||
virtual void ApplyUnpredictedPortalTeleportation( const C_Portal_Base2D *pEnteredPortal, float flTeleportationTime, bool bForcedDuck );
|
||||
|
||||
//WARNING: predicted teleportations WILL need to be undone A LOT. Prediction rolls time forward and backward like mad. Optimally an apply then undo should revert to the starting state. But an easier and somewhat acceptable solution is to have an undo then (assumed) re-apply be a NOP.
|
||||
virtual void ApplyPredictedPortalTeleportation( C_Portal_Base2D *pEnteredPortal, CMoveData *pMove, bool bForcedDuck );
|
||||
virtual void UndoPredictedPortalTeleportation( const C_Portal_Base2D *pEnteredPortal, float fOriginallyAppliedTime, const VMatrix &matUndo, bool bDuckForced ); //fOriginallyAppliedTime is the value of gpGlobals->curtime when ApplyPredictedPortalTeleportation was called. Which will be in the future when this gets called
|
||||
|
||||
void UnrollPredictedTeleportations( int iCommandNumber ); //unroll all predicted teleportations at or after the target tick
|
||||
|
||||
virtual bool TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr );
|
||||
|
||||
float GetImplicitVerticalStepSpeed() const;
|
||||
void SetImplicitVerticalStepSpeed( float speed );
|
||||
|
||||
virtual void ForceDuckThisFrame( void );
|
||||
|
||||
const C_PortalPlayerLocalData& GetPortalPlayerLocalData() const;
|
||||
|
||||
bool m_bPitchReorientation;
|
||||
float m_fReorientationRate;
|
||||
bool m_bEyePositionIsTransformedByPortal; //when the eye and body positions are not on the same side of a portal
|
||||
C_Portal_Base2D *m_pNoDrawForRecursionLevelOne; //if your eye is transformed by a portal, your body is directly on the other side of this portal
|
||||
|
||||
CHandle<C_Portal_Base2D> m_hPortalEnvironment; //a portal whose environment the player is currently in, should be invalid most of the time
|
||||
void FixPortalEnvironmentOwnership( void ); //if we run prediction, there are multiple cases where m_hPortalEnvironment != CPortalSimulator::GetSimulatorThatOwnsEntity( this ), and that's bad
|
||||
|
||||
CGrabController &GetGrabController()
|
||||
{
|
||||
return m_GrabController;
|
||||
}
|
||||
|
||||
void ToggleHeldObjectOnOppositeSideOfPortal( void ) { m_bHeldObjectOnOppositeSideOfPortal = !m_bHeldObjectOnOppositeSideOfPortal; }
|
||||
void SetHeldObjectOnOppositeSideOfPortal( bool p_bHeldObjectOnOppositeSideOfPortal ) { m_bHeldObjectOnOppositeSideOfPortal = p_bHeldObjectOnOppositeSideOfPortal; }
|
||||
bool IsHeldObjectOnOppositeSideOfPortal( void )
|
||||
{
|
||||
return m_bHeldObjectOnOppositeSideOfPortal;
|
||||
}
|
||||
void SetHeldObjectPortal( CPortal_Base2D *pPortal ) { m_hHeldObjectPortal = pPortal; }
|
||||
void SetUsingVMGrabState( bool bState ) { m_bUsingVMGrabState = bState; }
|
||||
bool IsUsingVMGrab( void );
|
||||
bool WantsVMGrab( void );
|
||||
bool IsForcingDrop( void ) { return m_bForcingDrop; }
|
||||
|
||||
EHANDLE m_hGrabbedEntity;
|
||||
EHANDLE m_hPortalThroughWhichGrabOccured;
|
||||
bool m_bSilentDropAndPickup;
|
||||
void ForceDropOfCarriedPhysObjects( CBaseEntity *pOnlyIfHoldingThis );
|
||||
void PickupObject(CBaseEntity *pObject, bool bLimitMassAndSize );
|
||||
|
||||
void SetInTractorBeam( CTrigger_TractorBeam *pTractorBeam );
|
||||
void SetLeaveTractorBeam( CTrigger_TractorBeam *pTractorBeam, bool bKeepFloating );
|
||||
C_Trigger_TractorBeam* GetTractorBeam( void ) const { return m_PortalLocal.m_hTractorBeam.Get(); }
|
||||
|
||||
bool m_bForceFireNextPortal;
|
||||
|
||||
void PreventCrouchJump( CUserCmd* ucmd );
|
||||
|
||||
void BridgeRemovedFromUnder( void );
|
||||
|
||||
float GetMotionBlurAmount( void ) { return m_flMotionBlurAmount; }
|
||||
|
||||
friend class CPortalGameMovement;
|
||||
|
||||
virtual int GetDefaultFOV( void ) const;
|
||||
|
||||
void PlayCoopStepSound( const Vector& origin, int side, float volume );
|
||||
|
||||
protected:
|
||||
C_PortalPlayerLocalData m_PortalLocal;
|
||||
|
||||
mutable Vector m_vWorldSpaceCenterHolder; //WorldSpaceCenter() returns a reference, need an actual value somewhere
|
||||
|
||||
bool PortalledMessageIsPending() const;
|
||||
|
||||
private:
|
||||
|
||||
void AvoidPlayers( CUserCmd *pCmd );
|
||||
|
||||
void ClientPlayerRespawn();
|
||||
|
||||
// Taunting
|
||||
void TurnOnTauntCam( void );
|
||||
void TurnOffTauntCam( void );
|
||||
void TurnOffTauntCam_Finish();
|
||||
void TauntCamInterpolation();
|
||||
void HandleTaunting( void );
|
||||
|
||||
bool m_bFaceTauntCameraEndAngles;
|
||||
bool m_bTauntInterpolating;
|
||||
bool m_bTauntInterpolatingAngles;
|
||||
float m_flTauntCamCurrentDist;
|
||||
float m_flTauntCamTargetDist;
|
||||
float m_flTauntCamTargetPitch;
|
||||
float m_flTauntCamTargetYaw;
|
||||
bool m_bFinishingTaunt;
|
||||
|
||||
float m_flMotionBlurAmount;
|
||||
float m_flObjectOutOfEyeTransitionDT;
|
||||
|
||||
C_Portal_Player( const C_Portal_Player & );
|
||||
|
||||
void UpdatePortalEyeInterpolation( void );
|
||||
|
||||
CPortalPlayerAnimState *m_PlayerAnimState;
|
||||
|
||||
QAngle m_angEyeAngles;
|
||||
CDiscontinuousInterpolatedVar< QAngle > m_iv_angEyeAngles;
|
||||
|
||||
// we need to interpolate hull height to maintain the world space center
|
||||
float m_flHullHeight;
|
||||
CInterpolatedVar< float > m_iv_flHullHeight;
|
||||
|
||||
CDiscontinuousInterpolatedVar< Vector > m_iv_vEyeOffset;
|
||||
|
||||
virtual IRagdoll *GetRepresentativeRagdoll() const;
|
||||
EHANDLE m_hRagdoll;
|
||||
|
||||
int m_headYawPoseParam;
|
||||
int m_headPitchPoseParam;
|
||||
float m_headYawMin;
|
||||
float m_headYawMax;
|
||||
float m_headPitchMin;
|
||||
float m_headPitchMax;
|
||||
|
||||
float m_flPitchFixup; // We always flip over 180, but we if we were already looking down then we don't need to go as far.
|
||||
float m_flUprightRotDist; // how far we need to flip over to get our feet back on the ground.
|
||||
|
||||
bool m_isInit;
|
||||
Vector m_vLookAtTarget;
|
||||
|
||||
float m_flLastBodyYaw;
|
||||
float m_flCurrentHeadYaw;
|
||||
float m_flCurrentHeadPitch;
|
||||
float m_flStartLookTime;
|
||||
|
||||
CountdownTimer m_blinkTimer;
|
||||
|
||||
int m_iSpawnInterpCounter;
|
||||
int m_iSpawnInterpCounterCache;
|
||||
|
||||
int m_iPlayerSoundType;
|
||||
|
||||
bool m_bHeldObjectOnOppositeSideOfPortal;
|
||||
CHandle< C_Portal_Base2D > m_hHeldObjectPortal;
|
||||
|
||||
struct PortalEyeInterpolation_t
|
||||
{
|
||||
bool m_bEyePositionIsInterpolating; //flagged when the eye position would have popped between two distinct positions and we're smoothing it over
|
||||
Vector m_vEyePosition_Interpolated; //we'll be giving the interpolation a certain amount of instant movement per frame based on how much an uninterpolated eye would have moved
|
||||
Vector m_vEyePosition_Uninterpolated; //can't have smooth movement without tracking where we just were
|
||||
//bool m_bNeedToUpdateEyePosition;
|
||||
//int m_iFrameLastUpdated;
|
||||
|
||||
int m_iTickLastUpdated;
|
||||
float m_fTickInterpolationAmountLastUpdated;
|
||||
bool m_bDisableFreeMovement; //used for one frame usually when error in free movement is likely to be high
|
||||
bool m_bUpdatePosition_FreeMove;
|
||||
|
||||
PortalEyeInterpolation_t( void ) : m_iTickLastUpdated(0), m_fTickInterpolationAmountLastUpdated(0.0f), m_bDisableFreeMovement(false), m_bUpdatePosition_FreeMove(false) { };
|
||||
} PortalEyeInterpolation;
|
||||
|
||||
struct PreDataChanged_Backup_t
|
||||
{
|
||||
CHandle<C_Portal_Base2D> m_hPortalEnvironment;
|
||||
//Vector m_ptPlayerPosition;
|
||||
QAngle m_qEyeAngles;
|
||||
uint32 m_iEntityPortalledNetworkMessageCount;
|
||||
} PreDataChanged_Backup;
|
||||
|
||||
bool m_bPortalledMessagePending; //Player portalled. It's easier to wait until we get a OnDataChanged() event or a CalcView() before we do anything about it. Otherwise bits and pieces can get undone
|
||||
VMatrix m_PendingPortalMatrix;
|
||||
|
||||
bool m_bIsHoldingSomething;
|
||||
|
||||
bool m_bWasTaunting;
|
||||
bool m_bGibbed;
|
||||
CameraThirdData_t m_TauntCameraData;
|
||||
|
||||
bool m_bPingDisabled;
|
||||
bool m_bTauntDisabled;
|
||||
bool m_bTauntRemoteView;
|
||||
Vector m_vecRemoteViewOrigin;
|
||||
QAngle m_vecRemoteViewAngles;
|
||||
float m_fTauntCameraDistance;
|
||||
|
||||
float m_fTeamTauntStartTime;
|
||||
int m_nOldTeamTauntState;
|
||||
int m_nTeamTauntState;
|
||||
Vector m_vTauntPosition;
|
||||
QAngle m_vTauntAngles;
|
||||
QAngle m_vPreTauntAngles;
|
||||
bool m_bTrickFire;
|
||||
CHandle<C_Portal_Player> m_hTauntPartnerInRange;
|
||||
char m_szTauntForce[ PORTAL2_MP_TEAM_TAUNT_FORCE_LENGTH ];
|
||||
|
||||
QAngle m_angTauntPredViewAngles;
|
||||
QAngle m_angTauntEngViewAngles;
|
||||
|
||||
int m_nLastFrameDrawn;
|
||||
int m_nLastDrawnStudioFlags;
|
||||
|
||||
float m_flUseKeyStartTime; // for long duration uses, record the initial keypress start time
|
||||
int m_nUseKeyEntFoundCommandNum; // Kind of a hack... if we find a use ent, keep it around until it sends off to the server then clear
|
||||
int m_nUseKeyEntClearCommandNum;
|
||||
int m_nLastRecivedCommandNum;
|
||||
EHANDLE m_hUseEntToSend; // if we find a use ent during the extended polling, keep the handle
|
||||
float m_flAutoGrabLockOutTime;
|
||||
|
||||
bool m_bForcingDrop;
|
||||
bool m_bUseVMGrab;
|
||||
bool m_bUsingVMGrabState;
|
||||
|
||||
EHANDLE m_hAttachedObject;
|
||||
EHANDLE m_hOldAttachedObject;
|
||||
|
||||
EHANDLE m_hPreDataChangedAttachedObject; // Ok, I just want to know if our attached object went null on this network update for some cleanup
|
||||
// but the 'OldAttachedObject' above somehow got intertwined in some VM mode toggle logic I don't want to unravel.
|
||||
// Adding yet another ehandle to the same entity so I can cleanly detect when the server has cleared our held
|
||||
// object irrespective of what held mode we are in.
|
||||
|
||||
|
||||
CGrabController m_GrabController;
|
||||
|
||||
public:
|
||||
QAngle m_vecCarriedObjectAngles;
|
||||
C_PlayerHeldObjectClone *m_pHeldEntityClone;
|
||||
C_PlayerHeldObjectClone *m_pHeldEntityThirdpersonClone;
|
||||
|
||||
Vector m_vecCarriedObject_CurPosToTargetPos;
|
||||
QAngle m_vecCarriedObject_CurAngToTargetAng;
|
||||
|
||||
//this is where we'll ease into the networked value over time and avoid applying newly networked data to previously predicted frames
|
||||
Vector m_vecCarriedObject_CurPosToTargetPos_Interpolated;
|
||||
QAngle m_vecCarriedObject_CurAngToTargetAng_Interpolated;
|
||||
private:
|
||||
CInterpolatedVar<Vector> m_iv_vecCarriedObject_CurPosToTargetPos_Interpolator;
|
||||
CInterpolatedVar<QAngle> m_iv_vecCarriedObject_CurAngToTargetAng_Interpolator;
|
||||
|
||||
EHANDLE m_hUseEntThroughPortal;
|
||||
bool m_bUseWasDown;
|
||||
void PollForUseEntity( CUserCmd *pCmd );
|
||||
|
||||
float m_flImplicitVerticalStepSpeed; // When moving with step code, the player has an implicit vertical
|
||||
// velocity that keeps her on ramps, steps, etc. We need this to
|
||||
// correctly transform her velocity when she teleports.
|
||||
|
||||
Vector m_vRenderOrigin;
|
||||
|
||||
Vector m_vTempRenderOrigin;
|
||||
QAngle m_TempRenderAngles;
|
||||
|
||||
bool m_iSpawnCounter;
|
||||
bool m_iOldSpawnCounter;
|
||||
|
||||
float m_fLatestServerTeleport;
|
||||
VMatrix m_matLatestServerTeleportationInverseMatrix;
|
||||
|
||||
public: // PAINT SPECIFIC
|
||||
static bool RenderLocalScreenSpaceEffect( PortalScreenSpaceEffect effect, IMatRenderContext *pRenderContext, int x, int y, int w, int h );
|
||||
|
||||
virtual void SharedSpawn();
|
||||
virtual void Touch( CBaseEntity *pOther );
|
||||
|
||||
virtual Vector Weapon_ShootPosition();
|
||||
|
||||
virtual CBaseCombatWeapon* Weapon_OwnsThisType( const char *pszWeapon, int iSubType = 0 ) const; // True if already owns a weapon of this class
|
||||
void SelectItem( const char *pstr, int iSubType );
|
||||
|
||||
bool IsPressingJumpKey() const;
|
||||
bool IsHoldingJumpKey() const;
|
||||
bool IsTryingToSuperJump( const PaintPowerInfo_t* pInfo = NULL ) const;
|
||||
void SetJumpedThisFrame( bool jumped );
|
||||
bool JumpedThisFrame() const;
|
||||
void SetBouncedThisFrame( bool bounced );
|
||||
bool BouncedThisFrame() const;
|
||||
InAirState GetInAirState() const;
|
||||
|
||||
bool WantsToSwapGuns( void );
|
||||
|
||||
bool IsPotatosOn( void );
|
||||
|
||||
bool IsUsingPostTeleportationBox() const;
|
||||
|
||||
const Vector& GetInputVector() const;
|
||||
void SetInputVector( const Vector& vInput );
|
||||
|
||||
const Vector& GetPrevGroundNormal() const;
|
||||
void SetPrevGroundNormal( const Vector& vPrevNormal );
|
||||
|
||||
Vector GetPaintGunShootPosition();
|
||||
|
||||
EHANDLE GetAttachedObject ( void ) { return m_hAttachedObject; }
|
||||
|
||||
virtual PaintPowerType GetPaintPowerAtPoint( const Vector& worldContactPt ) const;
|
||||
virtual void Paint( PaintPowerType type, const Vector& worldContactPt );
|
||||
virtual void CleansePaint();
|
||||
|
||||
virtual bool RenderScreenSpaceEffect( PortalScreenSpaceEffect effect, IMatRenderContext *pRenderContext, int x, int y, int w, int h );
|
||||
|
||||
bool ScreenSpacePaintEffectIsActive() const;
|
||||
void SetScreenSpacePaintEffectColors( IMaterialVar* pColor1, IMaterialVar* pColor2 ) const;
|
||||
|
||||
void Reorient( QAngle& viewAngles );
|
||||
float GetReorientationProgress() const;
|
||||
bool IsDoneReorienting() const;
|
||||
|
||||
virtual void UpdateCollisionBounds();
|
||||
|
||||
virtual const Vector GetPlayerMins() const;
|
||||
virtual const Vector GetPlayerMaxs() const;
|
||||
const Vector& GetHullMins() const;
|
||||
const Vector& GetHullMaxs() const;
|
||||
const Vector& GetStandHullMins() const;
|
||||
const Vector& GetStandHullMaxs() const;
|
||||
const Vector& GetDuckHullMins() const;
|
||||
const Vector& GetDuckHullMaxs() const;
|
||||
|
||||
float GetHullHeight() const;
|
||||
float GetHullWidth() const;
|
||||
float GetStandHullHeight() const;
|
||||
float GetStandHullWidth() const;
|
||||
float GetDuckHullHeight() const;
|
||||
float GetDuckHullWidth() const;
|
||||
|
||||
void SetAirDuck( bool bDuckedInAir );
|
||||
void UnDuck();
|
||||
|
||||
StickCameraState GetStickCameraState() const;
|
||||
|
||||
void SetQuaternionPunch( const Quaternion& qPunch );
|
||||
void DecayQuaternionPunch();
|
||||
|
||||
using BaseClass::AddSurfacePaintPowerInfo;
|
||||
void AddSurfacePaintPowerInfo( const BrushContact& contact, char const* context = 0 );
|
||||
void AddSurfacePaintPowerInfo( const trace_t& trace, char const* context = 0 );
|
||||
|
||||
void SetEyeOffset( const Vector& vOldOrigin, const Vector& vNewOrigin );
|
||||
|
||||
bool IsInTeamTauntIdle( void );
|
||||
|
||||
void SetHullHeight( float flHeight );
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
|
||||
float PredictedAirTimeEnd( void ); // Uses the current velocity
|
||||
float PredictedBounce( void ); // Uses the current velocity
|
||||
void OnBounced( float fTimeOffset = 0.0f );
|
||||
|
||||
virtual void ChooseActivePaintPowers( PaintPowerInfoVector& activePowers );
|
||||
|
||||
private: // PAINT SPECIFIC
|
||||
void DecayEyeOffset();
|
||||
|
||||
// Find all the contacts
|
||||
void DeterminePaintContacts();
|
||||
void PredictPaintContacts( const Vector& contactBoxMin,
|
||||
const Vector& contactBoxMax,
|
||||
const Vector& traceBoxMin,
|
||||
const Vector& traceBoxMax,
|
||||
float lookAheadTime,
|
||||
char const* context );
|
||||
void ChooseBestPaintPowersInRange( PaintPowerChoiceResultArray& bestPowers,
|
||||
PaintPowerConstIter begin,
|
||||
PaintPowerConstIter end,
|
||||
const PaintPowerChoiceCriteria_t& info ) const;
|
||||
|
||||
// Paint Power User Implementation
|
||||
virtual PaintPowerState ActivateSpeedPower( PaintPowerInfo_t& powerInfo );
|
||||
virtual PaintPowerState UseSpeedPower( PaintPowerInfo_t& powerInfo );
|
||||
virtual PaintPowerState DeactivateSpeedPower( PaintPowerInfo_t& powerInfo );
|
||||
|
||||
virtual PaintPowerState ActivateBouncePower( PaintPowerInfo_t& powerInfo );
|
||||
virtual PaintPowerState UseBouncePower( PaintPowerInfo_t& powerInfo );
|
||||
virtual PaintPowerState DeactivateBouncePower( PaintPowerInfo_t& powerInfo );
|
||||
|
||||
void PlayPaintSounds( const PaintPowerChoiceResultArray& touchedPowers );
|
||||
void UpdatePaintedPower();
|
||||
void UpdateAirInputScaleFadeIn();
|
||||
void UpdateInAirState();
|
||||
void CachePaintPowerChoiceResults( const PaintPowerChoiceResultArray& choiceInfo );
|
||||
bool LateSuperJumpIsValid() const;
|
||||
void RecomputeBoundsForOrientation();
|
||||
void TryToChangeCollisionBounds( const Vector& newStandHullMin,
|
||||
const Vector& newStandHullMax,
|
||||
const Vector& newDuckHullMin,
|
||||
const Vector& newDuckHullMax );
|
||||
|
||||
float SpeedPaintAcceleration( float flDefaultMaxSpeed,
|
||||
float flSpeed,
|
||||
float flWishCos,
|
||||
float flWishDirSpeed ) const;
|
||||
|
||||
bool RenderScreenSpacePaintEffect( IMatRenderContext *pRenderContext );
|
||||
void InvalidatePaintEffects();
|
||||
|
||||
bool CheckToUseBouncePower( PaintPowerInfo_t& info );
|
||||
|
||||
// stick camera
|
||||
void RotateUpVector( Vector& vForward, Vector& vUp );
|
||||
void SnapCamera( StickCameraState nCameraState, bool bLookingInBadDirection );
|
||||
void PostTeleportationCameraFixup( const CPortal_Base2D *pEnteredPortal );
|
||||
|
||||
// Paint power debug
|
||||
void DrawJumpHelperDebug( PaintPowerConstIter begin, PaintPowerConstIter end, float duration, bool noDepthTest, const PaintPowerInfo_t* pSelected ) const;
|
||||
void ManageHeldObject();
|
||||
|
||||
void MoveHeldObjectOutOfPlayerEyes( void );
|
||||
|
||||
// PAINT POWER STATE
|
||||
PaintPowerInfo_t m_CachedJumpPower;
|
||||
CUtlReference< CNewParticleEffect > m_PaintScreenSpaceEffect;
|
||||
// commenting out the 3rd person drop effect
|
||||
//CUtlReference< CNewParticleEffect > m_PaintDripEffect;
|
||||
CountdownTimer m_PaintScreenEffectCooldownTimer;
|
||||
Vector m_vInputVector;
|
||||
float m_flCachedJumpPowerTime;
|
||||
float m_flUsePostTeleportationBoxTime;
|
||||
float m_flSpeedDecelerationTime;
|
||||
float m_flPredictedJumpTime;
|
||||
bool m_bDoneStickInterp;
|
||||
bool m_bDoneCorrectPitch;
|
||||
bool m_bJumpWasPressedWhenForced; // The jump button was actually pressed when ForceDuckThisFrame() was called
|
||||
|
||||
float m_flTimeSinceLastTouchedPower[3];
|
||||
|
||||
bool m_bDoneAirTauntHint;
|
||||
|
||||
bool m_bWantsToSwapGuns;
|
||||
|
||||
bool m_bPotatos;
|
||||
bool m_bIsBendy;
|
||||
|
||||
Vector m_vPrevGroundNormal; // Our ground normal from the previous frame
|
||||
|
||||
bool m_bToolMode_EyeHasPortalled_LastRecord; //when recording, keep track of whether we teleported the camera position last capture or not. Need to avoid interpolating when switching
|
||||
|
||||
public:
|
||||
CPortalPlayerShared m_Shared;
|
||||
|
||||
// Coop effects
|
||||
void CreatePingPointer( Vector vecDestintaion );
|
||||
void DestroyPingPointer( void );
|
||||
CUtlReference< CNewParticleEffect > m_FlingTrailEffect; // the particle trail effect that shows behind bots in coop when they fling
|
||||
CUtlReference< CNewParticleEffect > m_PointLaser; // the pointer that point for when the player does some pointing
|
||||
bool m_bFlingTrailActive;
|
||||
bool m_bFlingTrailJustPortalled;
|
||||
bool m_bFlingTrailPrePortalled;
|
||||
|
||||
PortalPlayerStatistics_t m_StatsThisLevel;
|
||||
|
||||
private:
|
||||
CUtlVector<C_EntityPortalledNetworkMessage> m_EntityPortalledNetworkMessages;
|
||||
enum
|
||||
{
|
||||
MAX_ENTITY_PORTALLED_NETWORK_MESSAGES = 32,
|
||||
};
|
||||
uint32 m_iEntityPortalledNetworkMessageCount;
|
||||
|
||||
friend class CPortalPlayerShared;
|
||||
friend class CMultiPlayerAnimState;
|
||||
|
||||
#if !defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
|
||||
|
||||
//----------------------------
|
||||
// INVENTORY MANAGEMENT
|
||||
public:
|
||||
// IInventoryUpdateListener
|
||||
virtual void InventoryUpdated( CPlayerInventory *pInventory );
|
||||
virtual void SOCacheUnsubscribed( const CSteamID & steamIDOwner ) { m_Shared.SetLoadoutUnavailable( true ); }
|
||||
void UpdateInventory( void );
|
||||
|
||||
// Inventory access
|
||||
CPortalPlayerInventory *Inventory( void ) { return &m_Inventory; }
|
||||
CEconItemView *GetItemInLoadoutSlot( int iLoadoutSlot ){ return m_Inventory.GetInventoryItemByItemID( m_EquippedLoadoutItemIndices[iLoadoutSlot] ); }
|
||||
|
||||
private:
|
||||
void UpdateClientsideWearables( void );
|
||||
void RemoveClientsideWearables( void );
|
||||
bool ItemsMatch( CEconItemView *pCurItem, CEconItemView *pNewItem );
|
||||
|
||||
private:
|
||||
CPortalPlayerInventory m_Inventory;
|
||||
bool m_bInventoryReceived;
|
||||
|
||||
// Items that have been equipped on this player instance (the inventory loadout may have changed)
|
||||
itemid_t m_EquippedLoadoutItemIndices[LOADOUT_POSITION_COUNT];
|
||||
|
||||
#endif //!defined( NO_STEAM ) && !defined( NO_STEAM_GAMECOORDINATOR )
|
||||
|
||||
bool m_bWasAlivePreUpdate;
|
||||
|
||||
};
|
||||
|
||||
inline C_Portal_Player *ToPortalPlayer( CBaseEntity *pEntity )
|
||||
{
|
||||
C_BasePlayer *pPlayer = ToBasePlayer( pEntity );
|
||||
return assert_cast<C_Portal_Player *>( pPlayer );
|
||||
}
|
||||
|
||||
inline C_Portal_Player *GetPortalPlayer( void )
|
||||
{
|
||||
return static_cast<C_Portal_Player*>( C_BasePlayer::GetLocalPlayer() );
|
||||
}
|
||||
|
||||
#endif //Portal_PLAYER_H
|
||||
980
game/client/portal/c_portalghostrenderable.cpp
Normal file
980
game/client/portal/c_portalghostrenderable.cpp
Normal file
@@ -0,0 +1,980 @@
|
||||
//===== Copyright © 1996-2005, 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"
|
||||
#include "c_basecombatweapon.h"
|
||||
#include "c_combatweaponworldclone.h"
|
||||
#include "toolframework_client.h"
|
||||
|
||||
ConVar portal_ghosts_disable( "portal_ghosts_disable", "0", 0, "Disables rendering of ghosted objects in portal environments" );
|
||||
|
||||
inline float GhostedRenderableOriginTime( C_BaseEntity *pGhostedRenderable, float fCurTime )
|
||||
{
|
||||
return pGhostedRenderable->GetOriginInterpolator().GetInterpolatedTime( pGhostedRenderable->GetEffectiveInterpolationCurTime( fCurTime ) );
|
||||
}
|
||||
|
||||
#define GHOST_RENDERABLE_TEN_TON_HAMMER 0
|
||||
|
||||
#if (GHOST_RENDERABLE_TEN_TON_HAMMER == 1)
|
||||
void GhostResetEverything( C_PortalGhostRenderable *pGhost )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = pGhost->m_hGhostedRenderable;
|
||||
if( pGhostedRenderable )
|
||||
{
|
||||
pGhostedRenderable->MarkRenderHandleDirty();
|
||||
if( pGhost->m_bSourceIsBaseAnimating )
|
||||
{
|
||||
//((C_BaseAnimating *)pGhostedRenderable)->MarkForThreadedBoneSetup();
|
||||
((C_BaseAnimating *)pGhostedRenderable)->InvalidateBoneCache();
|
||||
}
|
||||
pGhostedRenderable->CollisionProp()->MarkPartitionHandleDirty();
|
||||
pGhostedRenderable->CollisionProp()->MarkSurroundingBoundsDirty();
|
||||
pGhostedRenderable->AddEFlags( EFL_DIRTY_ABSTRANSFORM | EFL_DIRTY_SPATIAL_PARTITION );
|
||||
|
||||
g_pClientLeafSystem->DisableCachedRenderBounds( pGhostedRenderable->RenderHandle(), true );
|
||||
g_pClientLeafSystem->RenderableChanged( pGhostedRenderable->RenderHandle() );
|
||||
|
||||
if( C_BaseEntity::IsAbsQueriesValid() )
|
||||
{
|
||||
pGhostedRenderable->CollisionProp()->UpdatePartition();
|
||||
//pGhostedRenderable->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
|
||||
}
|
||||
}
|
||||
|
||||
pGhost->MarkRenderHandleDirty();
|
||||
//pGhost->MarkForThreadedBoneSetup();
|
||||
pGhost->InvalidateBoneCache();
|
||||
pGhost->CollisionProp()->MarkPartitionHandleDirty();
|
||||
pGhost->CollisionProp()->MarkSurroundingBoundsDirty();
|
||||
pGhost->AddEFlags( EFL_DIRTY_ABSTRANSFORM | EFL_DIRTY_SPATIAL_PARTITION );
|
||||
|
||||
g_pClientLeafSystem->DisableCachedRenderBounds( pGhost->RenderHandle(), true );
|
||||
g_pClientLeafSystem->RenderableChanged( pGhost->RenderHandle() );
|
||||
|
||||
if( C_BaseEntity::IsAbsQueriesValid() )
|
||||
{
|
||||
pGhost->CollisionProp()->UpdatePartition();
|
||||
//pGhost->SetupBones( NULL, -1, BONE_USED_BY_ANYTHING, gpGlobals->curtime );
|
||||
}
|
||||
}
|
||||
#endif //#if (GHOST_RENDERABLE_TEN_TON_HAMMER == 1)
|
||||
|
||||
|
||||
C_PortalGhostRenderable::C_PortalGhostRenderable( C_Portal_Base2D *pOwningPortal, C_BaseEntity *pGhostSource, const VMatrix &matGhostTransform, float *pSharedRenderClipPlane, C_BasePlayer *pPlayer ) :
|
||||
m_hGhostedRenderable( pGhostSource ),
|
||||
m_matGhostTransform( matGhostTransform ),
|
||||
m_pSharedRenderClipPlane( pSharedRenderClipPlane ),
|
||||
m_pPortalExitRenderClipPlane( NULL ),
|
||||
m_hHoldingPlayer( pPlayer ),
|
||||
m_pOwningPortal( pOwningPortal )
|
||||
{
|
||||
m_fRenderableRange[0] = -FLT_MAX;
|
||||
m_fRenderableRange[1] = FLT_MAX;
|
||||
m_fNoTransformBeforeTime = -FLT_MAX;
|
||||
m_fDisablePositionChecksUntilTime = -FLT_MAX;
|
||||
|
||||
#if( DEBUG_GHOSTRENDERABLES == 1 )
|
||||
if( pOwningPortal->m_bIsPortal2 )
|
||||
{
|
||||
m_iDebugColor[0] = 255;
|
||||
m_iDebugColor[1] = 0;
|
||||
m_iDebugColor[2] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_iDebugColor[0] = 0;
|
||||
m_iDebugColor[1] = 0;
|
||||
m_iDebugColor[2] = 255;
|
||||
}
|
||||
m_iDebugColor[3] = 16;
|
||||
#endif
|
||||
|
||||
m_bSourceIsBaseAnimating = (dynamic_cast<C_BaseAnimating *>(pGhostSource) != NULL);
|
||||
|
||||
RenderWithViewModels( pGhostSource->IsRenderingWithViewModels() );
|
||||
SetModelName( m_hGhostedRenderable->GetModelName() );
|
||||
|
||||
m_bCombatWeapon = (dynamic_cast<C_BaseCombatWeapon *>(pGhostSource) != NULL);
|
||||
SetModelIndex( m_bCombatWeapon ? ((C_BaseCombatWeapon *)pGhostSource)->GetWorldModelIndex() : pGhostSource->GetModelIndex() );
|
||||
|
||||
m_bCombatWeaponWorldClone = ( dynamic_cast< C_CombatWeaponClone* >( pGhostSource ) != NULL );
|
||||
|
||||
m_bPlayerHeldClone = ( dynamic_cast< C_PlayerHeldObjectClone* >( pGhostSource ) != NULL );
|
||||
|
||||
SetSize( pGhostSource->CollisionProp()->OBBMins(), pGhostSource->CollisionProp()->OBBMaxs() );
|
||||
|
||||
Assert( m_hGhostedRenderable.Get() != NULL );
|
||||
}
|
||||
|
||||
C_PortalGhostRenderable::~C_PortalGhostRenderable( void )
|
||||
{
|
||||
m_hGhostedRenderable = NULL;
|
||||
}
|
||||
|
||||
void C_PortalGhostRenderable::UpdateOnRemove( void )
|
||||
{
|
||||
m_hGhostedRenderable = NULL;
|
||||
BaseClass::UpdateOnRemove();
|
||||
}
|
||||
|
||||
void C_PortalGhostRenderable::PerFrameUpdate( void )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
|
||||
if( !pGhostedRenderable )
|
||||
return;
|
||||
|
||||
SetModelName( pGhostedRenderable->GetModelName() );
|
||||
|
||||
SetModelIndex( m_bCombatWeapon ? ((C_BaseCombatWeapon *)pGhostedRenderable)->GetWorldModelIndex() : pGhostedRenderable->GetModelIndex() );
|
||||
SetEffects( pGhostedRenderable->GetEffects() | EF_NOINTERP );
|
||||
m_flAnimTime = pGhostedRenderable->m_flAnimTime;
|
||||
|
||||
if( m_bSourceIsBaseAnimating && !m_bCombatWeapon )
|
||||
{
|
||||
C_BaseAnimating *pSource = (C_BaseAnimating *)pGhostedRenderable;
|
||||
SetCycle( pSource->GetCycle() );
|
||||
SetSequence( pSource->GetSequence() );
|
||||
SetBody( pSource->GetBody() );
|
||||
SetSkin( pSource->GetSkin() );
|
||||
}
|
||||
|
||||
SetSize( pGhostedRenderable->CollisionProp()->OBBMins(), pGhostedRenderable->CollisionProp()->OBBMaxs() );
|
||||
|
||||
// Set position and angles relative to the object it's ghosting
|
||||
Vector ptNewOrigin;
|
||||
QAngle qNewAngles;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) >= m_fNoTransformBeforeTime )
|
||||
{
|
||||
ptNewOrigin = m_matGhostTransform * pGhostedRenderable->GetNetworkOrigin();
|
||||
qNewAngles = TransformAnglesToWorldSpace( pGhostedRenderable->GetNetworkAngles(), m_matGhostTransform.As3x4() );
|
||||
}
|
||||
else
|
||||
{
|
||||
ptNewOrigin = pGhostedRenderable->GetNetworkOrigin();
|
||||
qNewAngles = pGhostedRenderable->GetNetworkAngles();
|
||||
}
|
||||
|
||||
SetNetworkOrigin( ptNewOrigin );
|
||||
SetLocalOrigin( ptNewOrigin );
|
||||
SetAbsOrigin( ptNewOrigin );
|
||||
SetNetworkAngles( qNewAngles );
|
||||
SetLocalAngles( qNewAngles );
|
||||
SetAbsAngles( qNewAngles );
|
||||
|
||||
g_pClientLeafSystem->RenderableChanged( RenderHandle() );
|
||||
|
||||
#if (GHOST_RENDERABLE_TEN_TON_HAMMER == 1)
|
||||
GhostResetEverything( this );
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector const& C_PortalGhostRenderable::GetRenderOrigin( void )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return m_ReferencedReturns.vRenderOrigin;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
{
|
||||
m_ReferencedReturns.vRenderOrigin = pGhostedRenderable->GetRenderOrigin();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ReferencedReturns.vRenderOrigin = m_matGhostTransform * pGhostedRenderable->GetRenderOrigin();
|
||||
}
|
||||
|
||||
return m_ReferencedReturns.vRenderOrigin;
|
||||
}
|
||||
|
||||
QAngle const& C_PortalGhostRenderable::GetRenderAngles( void )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return m_ReferencedReturns.qRenderAngle;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
{
|
||||
m_ReferencedReturns.qRenderAngle = pGhostedRenderable->GetRenderAngles();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ReferencedReturns.qRenderAngle = TransformAnglesToWorldSpace( pGhostedRenderable->GetRenderAngles(), m_matGhostTransform.As3x4() );
|
||||
}
|
||||
|
||||
return m_ReferencedReturns.qRenderAngle;
|
||||
}
|
||||
|
||||
bool C_PortalGhostRenderable::SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
int iOldModelIndex = 0, iWorldModelIndex = 0;
|
||||
bool bChangeModelIndex = m_bCombatWeapon &&
|
||||
((iOldModelIndex = ((C_BaseCombatWeapon *)pGhostedRenderable)->GetModelIndex()) != (iWorldModelIndex = ((C_BaseCombatWeapon *)pGhostedRenderable)->GetWorldModelIndex()));
|
||||
|
||||
if( bChangeModelIndex )
|
||||
{
|
||||
((C_BaseCombatWeapon *)pGhostedRenderable)->SetModelIndex( iWorldModelIndex );
|
||||
}
|
||||
|
||||
if( pGhostedRenderable->SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ) )
|
||||
{
|
||||
if( pBoneToWorldOut && (GhostedRenderableOriginTime( pGhostedRenderable, currentTime ) >= m_fNoTransformBeforeTime) )
|
||||
{
|
||||
matrix3x4a_t matGhostTransform;
|
||||
matGhostTransform = m_matGhostTransform.As3x4();
|
||||
CStudioHdr *hdr = GetModelPtr();
|
||||
int nBoneCount = hdr->numbones();
|
||||
nBoneCount = MIN( nMaxBones, nBoneCount );
|
||||
for( int i = 0; i != nBoneCount; ++i )
|
||||
{
|
||||
ConcatTransforms_Aligned( matGhostTransform, pBoneToWorldOut[i], pBoneToWorldOut[i] );
|
||||
}
|
||||
}
|
||||
|
||||
if( bChangeModelIndex )
|
||||
{
|
||||
((C_BaseCombatWeapon *)pGhostedRenderable)->SetModelIndex( iOldModelIndex );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if( bChangeModelIndex )
|
||||
{
|
||||
((C_BaseCombatWeapon *)pGhostedRenderable)->SetModelIndex( iOldModelIndex );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
C_BaseAnimating *C_PortalGhostRenderable::GetBoneSetupDependancy( void )
|
||||
{
|
||||
return m_bSourceIsBaseAnimating ? (C_BaseAnimating *)(m_hGhostedRenderable.Get()) : NULL;
|
||||
}
|
||||
|
||||
void C_PortalGhostRenderable::GetRenderBounds( Vector& mins, Vector& maxs )
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
{
|
||||
mins = maxs = vec3_origin;
|
||||
return;
|
||||
}
|
||||
|
||||
m_hGhostedRenderable->GetRenderBounds( mins, maxs );
|
||||
}
|
||||
|
||||
void C_PortalGhostRenderable::GetRenderBoundsWorldspace( Vector& mins, Vector& maxs )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
{
|
||||
mins = maxs = vec3_origin;
|
||||
return;
|
||||
}
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
return pGhostedRenderable->GetRenderBoundsWorldspace( mins, maxs );
|
||||
|
||||
Vector vTempMins, vTempMaxs;
|
||||
pGhostedRenderable->GetRenderBoundsWorldspace( vTempMins, vTempMaxs );
|
||||
TransformAABB( m_matGhostTransform.As3x4(), vTempMins, vTempMaxs, mins, maxs );
|
||||
}
|
||||
|
||||
bool C_PortalGhostRenderable::ShouldReceiveProjectedTextures( int flags )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void C_PortalGhostRenderable::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
{
|
||||
mins = maxs = vec3_origin;
|
||||
return;
|
||||
}
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
return pGhostedRenderable->GetShadowRenderBounds( mins, maxs, shadowType );
|
||||
|
||||
Vector vTempMins, vTempMaxs;
|
||||
pGhostedRenderable->GetShadowRenderBounds( vTempMins, vTempMaxs, shadowType );
|
||||
TransformAABB( m_matGhostTransform.As3x4(), vTempMins, vTempMaxs, mins, maxs );
|
||||
}
|
||||
|
||||
/*bool C_PortalGhostRenderable::GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
return m_hGhostedRenderable->GetShadowCastDistance( pDist, shadowType );
|
||||
}
|
||||
|
||||
bool C_PortalGhostRenderable::GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
if( m_hGhostedRenderable->GetShadowCastDirection( pDirection, shadowType ) )
|
||||
{
|
||||
if( pDirection )
|
||||
*pDirection = m_matGhostTransform.ApplyRotation( *pDirection );
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}*/
|
||||
|
||||
const matrix3x4_t & C_PortalGhostRenderable::RenderableToWorldTransform()
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return m_ReferencedReturns.matRenderableToWorldTransform;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
{
|
||||
m_ReferencedReturns.matRenderableToWorldTransform = pGhostedRenderable->RenderableToWorldTransform();
|
||||
}
|
||||
else
|
||||
{
|
||||
ConcatTransforms( m_matGhostTransform.As3x4(), pGhostedRenderable->RenderableToWorldTransform(), m_ReferencedReturns.matRenderableToWorldTransform );
|
||||
}
|
||||
|
||||
return m_ReferencedReturns.matRenderableToWorldTransform;
|
||||
}
|
||||
|
||||
bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin, QAngle &angles )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
return pGhostedRenderable->GetAttachment( number, origin, angles );
|
||||
|
||||
if( 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 )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
return pGhostedRenderable->GetAttachment( number, matrix );
|
||||
|
||||
if( pGhostedRenderable->GetAttachment( number, matrix ) )
|
||||
{
|
||||
ConcatTransforms( m_matGhostTransform.As3x4(), matrix, matrix );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
return pGhostedRenderable->GetAttachment( number, origin );
|
||||
|
||||
if( pGhostedRenderable->GetAttachment( number, origin ) )
|
||||
{
|
||||
origin = m_matGhostTransform * origin;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool C_PortalGhostRenderable::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
|
||||
{
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable;
|
||||
if( pGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
if( GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime ) < m_fNoTransformBeforeTime )
|
||||
return pGhostedRenderable->GetAttachmentVelocity( number, originVel, angleVel );
|
||||
|
||||
Vector ghostVel;
|
||||
if( pGhostedRenderable->GetAttachmentVelocity( number, ghostVel, angleVel ) )
|
||||
{
|
||||
Vector3DMultiply( m_matGhostTransform, ghostVel, originVel );
|
||||
Vector3DMultiply( m_matGhostTransform, *(Vector*)( &angleVel ), *(Vector*)( &angleVel ) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool C_PortalGhostRenderable::ShouldDrawForThisView( void )
|
||||
{
|
||||
if ( portal_ghosts_disable.GetBool() )
|
||||
return false;
|
||||
|
||||
C_BaseEntity *pGhostedRenderable = m_hGhostedRenderable.Get();
|
||||
if( pGhostedRenderable == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float fInterpTime = GhostedRenderableOriginTime( pGhostedRenderable, gpGlobals->curtime );
|
||||
|
||||
if( (fInterpTime < m_fRenderableRange[0]) ||
|
||||
(fInterpTime >= m_fRenderableRange[1]) )
|
||||
return false;
|
||||
|
||||
|
||||
if ( m_bSourceIsBaseAnimating )
|
||||
{
|
||||
C_Portal_Player *pViewPlayer = ToPortalPlayer( GetSplitScreenViewPlayer() );
|
||||
C_Portal_Player *pHoldingPlayer = ToPortalPlayer( m_hHoldingPlayer.Get() );
|
||||
|
||||
if ( pHoldingPlayer && (pHoldingPlayer == pViewPlayer) && !pViewPlayer->ShouldDrawLocalPlayer() )
|
||||
{
|
||||
if ( !pHoldingPlayer->IsAlive() )
|
||||
{
|
||||
// Dead player uses a ragdoll to draw, so don't ghost the dead entity
|
||||
return false;
|
||||
}
|
||||
else if( g_pPortalRender->GetViewRecursionLevel() == 0 )
|
||||
{
|
||||
if ( pHoldingPlayer->m_bEyePositionIsTransformedByPortal )
|
||||
return false;
|
||||
|
||||
C_PlayerHeldObjectClone *pClone = NULL;
|
||||
if ( m_bPlayerHeldClone )
|
||||
{
|
||||
pClone = assert_cast< C_PlayerHeldObjectClone* >( m_hGhostedRenderable.Get() );
|
||||
if( pClone && pClone->m_bOnOppositeSideOfPortal )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( g_pPortalRender->GetViewRecursionLevel() == 1 )
|
||||
{
|
||||
C_PlayerHeldObjectClone *pClone = NULL;
|
||||
if ( m_bPlayerHeldClone )
|
||||
{
|
||||
pClone = assert_cast< C_PlayerHeldObjectClone* >( m_hGhostedRenderable.Get() );
|
||||
}
|
||||
|
||||
if ( (!pHoldingPlayer->m_bEyePositionIsTransformedByPortal && (g_pPortalRender->GetCurrentViewEntryPortal() == m_pOwningPortal)) &&
|
||||
!( pClone && pClone->m_bOnOppositeSideOfPortal ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int C_PortalGhostRenderable::DrawModel( int flags, const RenderableInstance_t &instance )
|
||||
{
|
||||
if( !ShouldDrawForThisView() )
|
||||
return 0;
|
||||
|
||||
|
||||
#if( DEBUG_GHOSTRENDERABLES == 1 )
|
||||
if( m_iDebugColor[3] != 0 )
|
||||
{
|
||||
//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 );
|
||||
NDebugOverlay::Sphere( GetNetworkOrigin(), 5.0f, m_iDebugColor[0], m_iDebugColor[1], m_iDebugColor[2], true, 0.0f );
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( m_bSourceIsBaseAnimating )
|
||||
{
|
||||
return C_BaseAnimating::DrawModel( flags, instance );
|
||||
}
|
||||
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_hGhostedRenderable,
|
||||
(model_t *)m_hGhostedRenderable->GetModel(),
|
||||
GetRenderOrigin(),
|
||||
GetRenderAngles(),
|
||||
mode );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ModelInstanceHandle_t C_PortalGhostRenderable::GetModelInstance()
|
||||
{
|
||||
// HACK: This causes problems if the ghosted renderable is
|
||||
// has it's model instance destructed mid-render... this is currently
|
||||
// the case for the portalgun view model due to model switching
|
||||
// so we're not going to use the ghost's model instance for combat weapon ents.
|
||||
// This will only mean the decal state is wrong, the worldmodel doesn't get decals anyway.
|
||||
// Real fix would be to 'sync' the decal state between this and the ghosted ent, but
|
||||
// this will fix it for now.
|
||||
if ( m_hGhostedRenderable && (m_bCombatWeapon == false) && (m_bCombatWeaponWorldClone == false) )
|
||||
return m_hGhostedRenderable->GetModelInstance();
|
||||
|
||||
return BaseClass::GetModelInstance();
|
||||
}
|
||||
|
||||
|
||||
|
||||
RenderableTranslucencyType_t C_PortalGhostRenderable::ComputeTranslucencyType( void )
|
||||
{
|
||||
if ( m_hGhostedRenderable == NULL )
|
||||
return RENDERABLE_IS_OPAQUE;
|
||||
|
||||
return m_hGhostedRenderable->ComputeTranslucencyType();
|
||||
}
|
||||
|
||||
int C_PortalGhostRenderable::GetRenderFlags()
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return false;
|
||||
|
||||
return m_hGhostedRenderable->GetRenderFlags();
|
||||
}
|
||||
|
||||
/*const model_t* C_PortalGhostRenderable::GetModel( ) const
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return NULL;
|
||||
|
||||
return m_hGhostedRenderable->GetModel();
|
||||
}
|
||||
|
||||
int C_PortalGhostRenderable::GetBody()
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return 0;
|
||||
|
||||
return m_hGhostedRenderable->GetBody();
|
||||
}*/
|
||||
|
||||
void C_PortalGhostRenderable::GetColorModulation( float* color )
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return;
|
||||
|
||||
#if(DEBUG_GHOSTRENDERABLES == 1)
|
||||
if( color[3] != 0 )
|
||||
{
|
||||
color[0] = m_iDebugColor[0] / 255.0f;
|
||||
color[1] = m_iDebugColor[1] / 255.0f;
|
||||
color[2] = m_iDebugColor[2] / 255.0f;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_hGhostedRenderable->GetColorModulation( color );
|
||||
}
|
||||
|
||||
/*ShadowType_t C_PortalGhostRenderable::ShadowCastType()
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return SHADOWS_NONE;
|
||||
|
||||
return m_hGhostedRenderable->ShadowCastType();
|
||||
}*/
|
||||
|
||||
int C_PortalGhostRenderable::LookupAttachment( const char *pAttachmentName )
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return -1;
|
||||
|
||||
|
||||
return m_hGhostedRenderable->LookupAttachment( pAttachmentName );
|
||||
}
|
||||
|
||||
/*
|
||||
int C_PortalGhostRenderable::GetSkin()
|
||||
{
|
||||
if( m_hGhostedRenderable == NULL )
|
||||
return -1;
|
||||
|
||||
|
||||
return m_hGhostedRenderable->GetSkin();
|
||||
}
|
||||
*/
|
||||
|
||||
float *C_PortalGhostRenderable::GetRenderClipPlane( void )
|
||||
{
|
||||
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
|
||||
return NULL;
|
||||
|
||||
if( m_pPortalExitRenderClipPlane && //have an exit portal special clip plane
|
||||
g_pPortalRender->IsRenderingPortal() && //rendering through a portal
|
||||
(g_pPortalRender->GetCurrentViewEntryPortal() == m_pOwningPortal) ) //we're being drawn on the exit side
|
||||
{
|
||||
return m_pPortalExitRenderClipPlane;
|
||||
}
|
||||
|
||||
return m_pSharedRenderClipPlane;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Handle recording for the SFM
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_PortalGhostRenderable::GetToolRecordingState( KeyValues *msg )
|
||||
{
|
||||
VPROF_BUDGET( "C_PortalGhostRenderable::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
|
||||
BaseClass::GetToolRecordingState( msg );
|
||||
|
||||
C_Portal_Player *pViewPlayer = ToPortalPlayer( GetSplitScreenViewPlayer() );
|
||||
|
||||
if ( m_hHoldingPlayer.Get() && m_hHoldingPlayer.Get() == pViewPlayer )
|
||||
{
|
||||
msg->SetInt( "worldmodel", 2 ); //world model that should only draw in third person
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool C_PortalGhostRenderable::ShouldCloneEntity( C_BaseEntity *pEntity, C_Portal_Base2D *pPortal, bool bUsePositionChecks )
|
||||
{
|
||||
if( pEntity->IsEffectActive( EF_NODRAW ) )
|
||||
return false;
|
||||
|
||||
bool bIsMovable = false;
|
||||
|
||||
C_BaseEntity *pMoveEntity = pEntity;
|
||||
MoveType_t moveType = MOVETYPE_NONE;
|
||||
|
||||
//unmoveables and doors can never get halfway in the portal
|
||||
while ( pMoveEntity )
|
||||
{
|
||||
moveType = pMoveEntity->GetMoveType();
|
||||
|
||||
if ( !( moveType == MOVETYPE_NONE || moveType == MOVETYPE_PUSH ) )
|
||||
{
|
||||
bIsMovable = true;
|
||||
pMoveEntity = NULL;
|
||||
}
|
||||
else
|
||||
pMoveEntity = pMoveEntity->GetMoveParent();
|
||||
}
|
||||
|
||||
if ( !bIsMovable )
|
||||
return false;
|
||||
|
||||
if( (moveType == MOVETYPE_NOCLIP) && dynamic_cast<C_Portal_Base2D *>(pEntity) != NULL ) //potentially "mobile" portals in p2 can use MOVETYPE_NOCLIP
|
||||
return false;
|
||||
|
||||
Assert( dynamic_cast<C_Portal_Base2D *>(pEntity) == NULL ); //should have been killed with (pEntity->GetMoveType() == MOVETYPE_NONE) check. Infinite recursion is infinitely bad.
|
||||
|
||||
if( ToBaseViewModel(pEntity) )
|
||||
return false; //avoid ghosting view models
|
||||
|
||||
if( pEntity->IsRenderingWithViewModels() )
|
||||
return false; //avoid ghosting anything that draws with viewmodels
|
||||
|
||||
bool bActivePlayerWeapon = false;
|
||||
|
||||
C_BaseCombatWeapon *pWeapon = ToBaseCombatWeapon( pEntity );
|
||||
if ( pWeapon )
|
||||
{
|
||||
C_Portal_Player *pPortalPlayer = ToPortalPlayer( pWeapon->GetOwner() );
|
||||
if ( pPortalPlayer )
|
||||
{
|
||||
if ( pWeapon->m_iState != WEAPON_IS_ACTIVE )
|
||||
{
|
||||
return false; // don't ghost player owned non active weapons
|
||||
}
|
||||
else
|
||||
{
|
||||
bActivePlayerWeapon = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Weapon is not teleportable, and we don't want to make that function use a dynamic cast to test for it,
|
||||
// so do the simple thing and just ignore this check for player-held weapons
|
||||
if( !bActivePlayerWeapon && !CPortal_Base2D_Shared::IsEntityTeleportable( pEntity ) )
|
||||
return false;
|
||||
|
||||
if( bUsePositionChecks )
|
||||
{
|
||||
Vector ptEntCenter = pEntity->WorldSpaceCenter();
|
||||
float fEntCenterDist = (pPortal->m_plane_Origin.normal.Dot( ptEntCenter ) - pPortal->m_plane_Origin.dist);
|
||||
|
||||
if( fEntCenterDist < -5.0f )
|
||||
{
|
||||
//view model held objects don't actually teleport to the other side of a portal when their center crosses the plane.
|
||||
//Alternate test is to ensure that a line drawn from the player center to the clone intersects the portal
|
||||
C_Portal_Player *pHoldingPlayer = (C_Portal_Player *)GetPlayerHoldingEntity( pEntity );
|
||||
|
||||
if( (pHoldingPlayer == NULL) || //not held
|
||||
!pHoldingPlayer->IsUsingVMGrab() || //not in ViewModel grab mode
|
||||
dynamic_cast<C_PlayerHeldObjectClone *>(pEntity) ) //clones actually handle the teleportation correctly on the client.
|
||||
{
|
||||
return false; //entity is behind the portal, most likely behind the wall the portal is placed on
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector vPlayerCenter = pHoldingPlayer->WorldSpaceCenter();
|
||||
float fPlayerCenterDist = (pPortal->m_plane_Origin.normal.Dot( vPlayerCenter ) - pPortal->m_plane_Origin.dist);
|
||||
|
||||
if( fPlayerCenterDist < 0.0f )
|
||||
return false;
|
||||
|
||||
float fTotalDist = fPlayerCenterDist - fEntCenterDist;
|
||||
if( fTotalDist == 0.0f ) //should be >= 5.0 at all times, but I've been bitten too many times by impossibly 0 cases
|
||||
return false;
|
||||
|
||||
Vector vPlaneIntersect = (ptEntCenter * (fPlayerCenterDist/fTotalDist)) - (vPlayerCenter * (fEntCenterDist/fTotalDist));
|
||||
Vector vPortalCenterToIntersect = vPlaneIntersect - pPortal->m_ptOrigin;
|
||||
|
||||
if( (fabs( vPortalCenterToIntersect.Dot( pPortal->m_vRight ) ) > pPortal->GetHalfWidth()) ||
|
||||
(fabs( vPortalCenterToIntersect.Dot( pPortal->m_vUp ) ) > pPortal->GetHalfHeight()) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//else intersects on the portal quad and the test passes
|
||||
}
|
||||
}
|
||||
|
||||
if ( bActivePlayerWeapon )
|
||||
{
|
||||
// Both the player AND the weapon must be in the portal hole.
|
||||
//
|
||||
// We test the player's collision AABB against the portal hole because it's guaranteed not to intersect
|
||||
// multiple adjacent portal holes at the same time in a degenerate case.
|
||||
//
|
||||
// We test the player's weapon hitbox against the portal hole because it doesn't have a good collision AABB
|
||||
// and because we'll only bother to even do this test if the player's AABB is acutally inside the portal hole.
|
||||
//
|
||||
// If we only test the weapon, we get false positives (phantom renderables) when its bounds span multiple adjacent
|
||||
// portal holes.
|
||||
if( !pPortal->m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( pWeapon->GetOwner(), true /* bUseCollisionAABB */ ) ||
|
||||
!pPortal->m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( (C_BaseAnimating*)pEntity, false /* bUseCollisionAABB */ ) )
|
||||
return false;
|
||||
}
|
||||
else if( pEntity->IsPlayer() )
|
||||
{
|
||||
if( !pPortal->m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( (C_BaseAnimating*)pEntity, true /* bUseCollisionAABB */ ) )
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !pPortal->m_PortalSimulator.EntityIsInPortalHole( pEntity ) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
C_PortalGhostRenderable *C_PortalGhostRenderable::CreateGhostRenderable( C_BaseEntity *pEntity, C_Portal_Base2D *pPortal )
|
||||
{
|
||||
Assert( ShouldCloneEntity( pEntity, pPortal, false ) );
|
||||
|
||||
C_BasePlayer *pPlayerOwner = NULL;
|
||||
bool bRenderableIsPlayer = pEntity->IsPlayer();
|
||||
if ( bRenderableIsPlayer )
|
||||
{
|
||||
pPlayerOwner = ToBasePlayer( pEntity );
|
||||
}
|
||||
else
|
||||
{
|
||||
C_BaseCombatWeapon *pWeapon = ToBaseCombatWeapon( pEntity );
|
||||
if ( pWeapon )
|
||||
{
|
||||
C_Portal_Player *pOwningPlayer = ToPortalPlayer( pWeapon->GetOwner() );
|
||||
if ( pOwningPlayer )
|
||||
{
|
||||
pPlayerOwner = pOwningPlayer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
C_PlayerHeldObjectClone *pClone = dynamic_cast< C_PlayerHeldObjectClone* >( pEntity );
|
||||
if ( pClone )
|
||||
{
|
||||
C_Portal_Player *pOwningPlayer = ToPortalPlayer( pClone->m_hPlayer );
|
||||
if ( pOwningPlayer )
|
||||
{
|
||||
pPlayerOwner = pOwningPlayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if( DEBUG_GHOSTRENDERABLES == 1 )
|
||||
{
|
||||
Vector vTransformedOrigin;
|
||||
QAngle qTransformedAngles;
|
||||
VectorTransform( pEntity->GetRenderOrigin(), pPortal->m_matrixThisToLinked.As3x4(), vTransformedOrigin );
|
||||
qTransformedAngles = TransformAnglesToWorldSpace( pEntity->GetRenderAngles(), pPortal->m_matrixThisToLinked.As3x4() );
|
||||
NDebugOverlay::BoxAngles( vTransformedOrigin, pEntity->CollisionProp()->OBBMins(), pEntity->CollisionProp()->OBBMaxs(), qTransformedAngles, 0, 255, 0, 16, 0.0f );
|
||||
}
|
||||
#endif
|
||||
|
||||
C_PortalGhostRenderable *pNewGhost = new C_PortalGhostRenderable( pPortal,
|
||||
pEntity,
|
||||
pPortal->m_matrixThisToLinked,
|
||||
bRenderableIsPlayer ? pPortal->m_fGhostRenderablesClipForPlayer : pPortal->m_fGhostRenderablesClip,
|
||||
pPlayerOwner );
|
||||
|
||||
if( !pNewGhost->InitializeAsClientEntity( pEntity->GetModelName(), false ) )
|
||||
{
|
||||
pNewGhost->Release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Assert( pNewGhost );
|
||||
if( pPlayerOwner )
|
||||
{
|
||||
pNewGhost->SetOwnerEntity( pPlayerOwner );
|
||||
}
|
||||
|
||||
if( pNewGhost->m_pSharedRenderClipPlane == pPortal->m_fGhostRenderablesClipForPlayer )
|
||||
{
|
||||
pNewGhost->m_pPortalExitRenderClipPlane = pPortal->m_fGhostRenderablesClip;
|
||||
}
|
||||
|
||||
pPortal->m_GhostRenderables.AddToTail( pNewGhost );
|
||||
|
||||
{
|
||||
// HACK - I just copied the CClientTools::OnEntityCreated code here,
|
||||
// since the ghosts aren't really entities - they don't have an entindex,
|
||||
// they're not in the entitylist, and they get created during Simulate(),
|
||||
// which isn't valid for real entities, since it changes the simulate list
|
||||
// -jd
|
||||
if ( ToolsEnabled() && clienttools->IsInRecordingMode() )
|
||||
{
|
||||
// Send deletion message to tool interface
|
||||
KeyValues *kv = new KeyValues( "created" );
|
||||
HTOOLHANDLE h = clienttools->AttachToEntity( pNewGhost );
|
||||
ToolFramework_PostToolMessage( h, kv );
|
||||
|
||||
kv->deleteThis();
|
||||
}
|
||||
}
|
||||
|
||||
g_pClientLeafSystem->DisableCachedRenderBounds( pNewGhost->RenderHandle(), true );
|
||||
pNewGhost->PerFrameUpdate();
|
||||
|
||||
return pNewGhost;
|
||||
}
|
||||
|
||||
C_PortalGhostRenderable *C_PortalGhostRenderable::CreateInversion( C_PortalGhostRenderable *pSrc, C_Portal_Base2D *pSourcePortal, float fTime )
|
||||
{
|
||||
if( !(pSourcePortal && pSrc) )
|
||||
return NULL;
|
||||
|
||||
C_Portal_Base2D *pRemotePortal = pSourcePortal->m_hLinkedPortal.Get();
|
||||
if( !pRemotePortal )
|
||||
return NULL;
|
||||
|
||||
C_BaseEntity *pRootEntity = pSrc->m_hGhostedRenderable;
|
||||
if( !pRootEntity )
|
||||
return NULL;
|
||||
|
||||
C_PortalGhostRenderable *pNewGhost = NULL;
|
||||
|
||||
//use existing if we already have one
|
||||
for( int i = 0; i != pRemotePortal->m_GhostRenderables.Count(); ++i )
|
||||
{
|
||||
if( pRemotePortal->m_GhostRenderables[i]->m_hGhostedRenderable == pRootEntity )
|
||||
{
|
||||
pNewGhost = pRemotePortal->m_GhostRenderables[i];
|
||||
|
||||
//reset time based variables
|
||||
pNewGhost->m_fRenderableRange[0] = -FLT_MAX;
|
||||
pNewGhost->m_fRenderableRange[1] = FLT_MAX;
|
||||
pNewGhost->m_fNoTransformBeforeTime = -FLT_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( pNewGhost == NULL )
|
||||
{
|
||||
pNewGhost = new C_PortalGhostRenderable( pRemotePortal, pSrc->m_hGhostedRenderable, pRemotePortal->m_matrixThisToLinked,
|
||||
pSrc->m_pSharedRenderClipPlane == pSourcePortal->m_fGhostRenderablesClipForPlayer ? pRemotePortal->m_fGhostRenderablesClipForPlayer : pRemotePortal->m_fGhostRenderablesClip, pSrc->m_hHoldingPlayer );
|
||||
|
||||
if( !pNewGhost->InitializeAsClientEntity( pRootEntity->GetModelName(), false ) )
|
||||
{
|
||||
pNewGhost->Release();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( pSrc->m_hHoldingPlayer )
|
||||
{
|
||||
pNewGhost->SetOwnerEntity( pSrc->m_hHoldingPlayer );
|
||||
}
|
||||
|
||||
if( pSrc->m_pPortalExitRenderClipPlane != NULL )
|
||||
{
|
||||
if( pSrc->m_pPortalExitRenderClipPlane == pSourcePortal->m_fGhostRenderablesClipForPlayer )
|
||||
{
|
||||
pNewGhost->m_pPortalExitRenderClipPlane = pRemotePortal->m_fGhostRenderablesClipForPlayer;
|
||||
}
|
||||
else if( pSrc->m_pPortalExitRenderClipPlane == pSourcePortal->m_fGhostRenderablesClip )
|
||||
{
|
||||
pNewGhost->m_pPortalExitRenderClipPlane = pRemotePortal->m_fGhostRenderablesClip;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( false );
|
||||
}
|
||||
}
|
||||
|
||||
pRemotePortal->m_GhostRenderables.AddToTail( pNewGhost );
|
||||
|
||||
#if( DEBUG_GHOSTRENDERABLES == 1 )
|
||||
{
|
||||
Vector vTransformedOrigin;
|
||||
QAngle qTransformedAngles;
|
||||
VectorTransform( pSrc->m_hGhostedRenderable->GetNetworkOrigin(), pRemotePortal->m_matrixThisToLinked.As3x4(), vTransformedOrigin );
|
||||
qTransformedAngles = TransformAnglesToWorldSpace( pSrc->m_hGhostedRenderable->GetNetworkAngles(), pRemotePortal->m_matrixThisToLinked.As3x4() );
|
||||
NDebugOverlay::BoxAngles( vTransformedOrigin, pSrc->m_hGhostedRenderable->CollisionProp()->OBBMins(), pSrc->m_hGhostedRenderable->CollisionProp()->OBBMaxs(), qTransformedAngles, 0, 255, 0, 16, 0.0f );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//these times are in effective origin interpolator time m_hGhostedRenderable->GetOriginInterpolator().GetInterpolatedTime( m_hGhostedRenderable->GetEffectiveInterpolationCurTime() )
|
||||
pNewGhost->m_fRenderableRange[0] = fTime;
|
||||
pNewGhost->m_fRenderableRange[1] = FLT_MAX;
|
||||
pSrc->m_fRenderableRange[0] = -FLT_MAX;
|
||||
pSrc->m_fRenderableRange[1] = fTime;
|
||||
pNewGhost->m_fNoTransformBeforeTime = fTime;
|
||||
|
||||
pSrc->m_fDisablePositionChecksUntilTime = fTime + (TICK_INTERVAL * 2.0f) + pSrc->m_hGhostedRenderable->GetOriginInterpolator().GetInterpolationAmount();
|
||||
pNewGhost->m_fDisablePositionChecksUntilTime = pSrc->m_fDisablePositionChecksUntilTime;
|
||||
|
||||
g_pClientLeafSystem->DisableCachedRenderBounds( pNewGhost->RenderHandle(), true );
|
||||
pNewGhost->PerFrameUpdate();
|
||||
|
||||
return pNewGhost;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
147
game/client/portal/c_portalghostrenderable.h
Normal file
147
game/client/portal/c_portalghostrenderable.h
Normal file
@@ -0,0 +1,147 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_PORTALGHOSTRENDERABLE_H
|
||||
#define C_PORTALGHOSTRENDERABLE_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
//#include "iclientrenderable.h"
|
||||
#include "c_baseanimating.h"
|
||||
|
||||
#define DEBUG_GHOSTRENDERABLES 0
|
||||
|
||||
class C_PortalGhostRenderable : public C_BaseAnimating//IClientRenderable, public IClientUnknown
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_PortalGhostRenderable, C_BaseAnimating );
|
||||
CHandle<C_BaseEntity> m_hGhostedRenderable; //the renderable we're transforming and re-rendering
|
||||
|
||||
VMatrix m_matGhostTransform;
|
||||
float *m_pSharedRenderClipPlane; //shared by all portal ghost renderables within the same portal
|
||||
float *m_pPortalExitRenderClipPlane; //special clip plane to use if the current view entrance is our owner portal (we're on the exit side)
|
||||
CHandle< C_BasePlayer > m_hHoldingPlayer; //special draw rules for the local player
|
||||
bool m_bPlayerHeldClone;
|
||||
bool m_bSourceIsBaseAnimating;
|
||||
bool m_bCombatWeapon;
|
||||
bool m_bCombatWeaponWorldClone; //not actually derived from C_BaseCombatWeapon, but shares some of the same hacks
|
||||
C_Portal_Base2D *m_pOwningPortal;
|
||||
|
||||
float m_fRenderableRange[2];
|
||||
float m_fNoTransformBeforeTime;
|
||||
float m_fDisablePositionChecksUntilTime;
|
||||
|
||||
#if( DEBUG_GHOSTRENDERABLES == 1 )
|
||||
int m_iDebugColor[4];
|
||||
#endif
|
||||
|
||||
static bool ShouldCloneEntity( C_BaseEntity *pEntity, C_Portal_Base2D *pPortal, bool bUsePositionChecks );
|
||||
static C_PortalGhostRenderable *CreateGhostRenderable( C_BaseEntity *pEntity, C_Portal_Base2D *pPortal );
|
||||
static C_PortalGhostRenderable *CreateInversion( C_PortalGhostRenderable *pSrc, C_Portal_Base2D *pSourcePortal, float fTime );
|
||||
|
||||
struct
|
||||
{
|
||||
Vector vRenderOrigin;
|
||||
QAngle qRenderAngle;
|
||||
matrix3x4_t matRenderableToWorldTransform;
|
||||
} m_ReferencedReturns; //when returning a reference, it has to actually exist somewhere
|
||||
|
||||
C_PortalGhostRenderable( C_Portal_Base2D *pOwningPortal, C_BaseEntity *pGhostSource, const VMatrix &matGhostTransform, float *pSharedRenderClipPlane, C_BasePlayer *pPlayer );
|
||||
virtual ~C_PortalGhostRenderable( void );
|
||||
virtual void UpdateOnRemove( void );
|
||||
|
||||
void PerFrameUpdate( void ); //called once per frame for misc updating
|
||||
|
||||
// Data accessors
|
||||
virtual Vector const& GetRenderOrigin( void );
|
||||
virtual QAngle const& GetRenderAngles( void );
|
||||
virtual bool ShouldDraw( void ) { return !IsEffectActive( EF_NODRAW ); }
|
||||
|
||||
bool ShouldDrawForThisView( void );
|
||||
|
||||
// Call this to get the current bone transforms for the model.
|
||||
// currentTime parameter will affect interpolation
|
||||
// nMaxBones specifies how many matrices pBoneToWorldOut can hold. (Should be greater than or
|
||||
// equal to studiohdr_t::numbones. Use MAXSTUDIOBONES to be safe.)
|
||||
virtual bool SetupBones( matrix3x4a_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
|
||||
|
||||
virtual C_BaseAnimating *GetBoneSetupDependancy( void );
|
||||
|
||||
// Returns the bounds relative to the origin (render bounds)
|
||||
virtual void GetRenderBounds( Vector& mins, Vector& maxs );
|
||||
|
||||
// returns the bounds as an AABB in worldspace
|
||||
virtual void GetRenderBoundsWorldspace( Vector& mins, Vector& maxs );
|
||||
|
||||
// These normally call through to GetRenderAngles/GetRenderBounds, but some entities custom implement them.
|
||||
virtual void GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType );
|
||||
|
||||
// These methods return true if we want a per-renderable shadow cast direction + distance
|
||||
//virtual bool GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const;
|
||||
//virtual bool GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const;
|
||||
|
||||
// Returns the transform from RenderOrigin/RenderAngles to world
|
||||
virtual const matrix3x4_t &RenderableToWorldTransform();
|
||||
|
||||
// Attachments
|
||||
virtual bool GetAttachment( int number, Vector &origin, QAngle &angles );
|
||||
virtual bool GetAttachment( int number, matrix3x4_t &matrix );
|
||||
virtual bool GetAttachment( int number, Vector &origin );
|
||||
virtual bool GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel );
|
||||
|
||||
// Rendering clip plane, should be 4 floats, return value of NULL indicates a disabled render clip plane
|
||||
virtual float *GetRenderClipPlane( void );
|
||||
|
||||
virtual IClientModelRenderable* GetClientModelRenderable() { return NULL; }
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
|
||||
// Get the model instance of the ghosted model so that decals will properly draw across portals
|
||||
virtual ModelInstanceHandle_t GetModelInstance();
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
|
||||
|
||||
|
||||
//------------------------------------------
|
||||
//IClientRenderable - Trivial or redirection
|
||||
//------------------------------------------
|
||||
virtual IClientUnknown* GetIClientUnknown() { return this; };
|
||||
virtual RenderableTranslucencyType_t ComputeTranslucencyType( void );
|
||||
virtual int GetRenderFlags();
|
||||
//virtual ClientShadowHandle_t GetShadowHandle() const { return m_hShadowHandle; };
|
||||
//virtual ClientRenderHandle_t& RenderHandle() { return m_hRenderHandle; };
|
||||
//virtual const model_t* GetModel( ) const;
|
||||
//virtual int GetBody();
|
||||
//virtual void ComputeFxBlend( ) { return m_pGhostedRenderable->ComputeFxBlend(); };
|
||||
//virtual int GetFxBlend( void ) { return m_pGhostedRenderable->GetFxBlend(); };
|
||||
virtual void GetColorModulation( float* color );
|
||||
//virtual bool LODTest() { return true; };
|
||||
//virtual void SetupWeights( void ) { NULL; };
|
||||
//virtual void DoAnimationEvents( void ) { NULL; }; //TODO: find out if there's something we should be doing with this
|
||||
//virtual IPVSNotify* GetPVSNotifyInterface() { return NULL; };
|
||||
virtual bool ShouldReceiveProjectedTextures( int flags );// { return false; };//{ return m_pGhostedRenderable->ShouldReceiveProjectedTextures( flags ); };
|
||||
//virtual bool IsShadowDirty( ) { return m_bDirtyShadow; };
|
||||
//virtual void MarkShadowDirty( bool bDirty ) { m_bDirtyShadow = bDirty; };
|
||||
//virtual IClientRenderable * GetShadowParent() { return NULL; };
|
||||
//virtual IClientRenderable * FirstShadowChild() { return NULL; };
|
||||
//virtual IClientRenderable * NextShadowPeer() { return NULL; };
|
||||
//virtual ShadowType_t ShadowCastType();
|
||||
//virtual void CreateModelInstance() { NULL; };
|
||||
//virtual ModelInstanceHandle_t GetModelInstance() { return m_pGhostedRenderable->GetModelInstance(); }; //TODO: find out if sharing an instance causes bugs
|
||||
virtual int LookupAttachment( const char *pAttachmentName );
|
||||
//virtual int GetSkin();
|
||||
//virtual bool IsTwoPass( void );
|
||||
//virtual void OnThreadedDrawSetup() { NULL; };
|
||||
|
||||
//IHandleEntity
|
||||
//virtual void SetRefEHandle( const CBaseHandle &handle ) { m_RefEHandle = handle; };
|
||||
//virtual const CBaseHandle& GetRefEHandle() const { return m_RefEHandle; };
|
||||
};
|
||||
|
||||
#endif //#ifndef C_PORTALGHOSTRENDERABLE_H
|
||||
672
game/client/portal/c_prop_mirror.cpp
Normal file
672
game/client/portal/c_prop_mirror.cpp
Normal file
@@ -0,0 +1,672 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
//NOTE: Mirrors with models require an attachment named "MirrorSurface_Attach" with x facing out of the mirror plane.
|
||||
//They also require that the mirror surface be in a bodygroup by itself named "MirrorSurface" with the first index being the mirror, second being empty.
|
||||
//Lastly, they require that all non-mirror geometry be in bodygroups that have the second entry as empty.
|
||||
//It's a good idea to put a cubemap on the mirror surface material because they're not infinitely recursive
|
||||
|
||||
#include "cbase.h"
|
||||
#include "portalrenderable_flatbasic.h"
|
||||
#include "tier0/vprof.h"
|
||||
#include "model_types.h"
|
||||
#include "debugoverlay_shared.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class C_Prop_Mirror : public CPortalRenderable_FlatBasic
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_Prop_Mirror, CPortalRenderable_FlatBasic );
|
||||
DECLARE_CLIENTCLASS();
|
||||
|
||||
C_Prop_Mirror( void );
|
||||
virtual void Spawn( void );
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual void OnDataChanged( DataUpdateType_t type );
|
||||
virtual bool ShouldDraw( void ) { return true; }
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance );
|
||||
virtual CStudioHdr *OnNewModel( void );
|
||||
virtual void ClientThink( void );
|
||||
virtual bool ShouldUpdatePortalView_BasedOnView( const CViewSetup ¤tView, const CUtlVector<VPlane> ¤tComplexFrustum );
|
||||
virtual bool ShouldUpdatePortalView_BasedOnPixelVisibility( float fScreenFilledByStencilMaskLastFrame_Normalized ) { return true; }
|
||||
void UpdateReflectionPlane( void );
|
||||
void UpdateReflectionPolygon( void ); //call this before accessing m_LocalSpaceReflectionPolygonVerts, it'll detect if an update is necessary and do it
|
||||
|
||||
virtual void DrawStencilMask( IMatRenderContext *pRenderContext );
|
||||
virtual void DrawPostStencilFixes( IMatRenderContext *pRenderContext );
|
||||
virtual void RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView );
|
||||
bool CalcFrustumThroughPortal( const Vector &ptCurrentViewOrigin, Frustum OutputFrustum );
|
||||
|
||||
static CMaterialReference sm_Mirror_Stencil;
|
||||
float m_fWidth;
|
||||
float m_fHeight;
|
||||
int m_iMirrorSurfaceBodyGroup;
|
||||
int m_iMirrorFaceAttachment;
|
||||
bool m_bModel;
|
||||
Vector m_LocalSpaceReflectionPolygonVerts[10]; //best guess at the reflection polygon by intersecting the reflection plane with the local space rendering OBB
|
||||
int m_LocalSpaceReflectionPolygonVertCount;
|
||||
|
||||
struct ReflectPlaneCachedData_t
|
||||
{
|
||||
//Vector vAttachmentOrigin; //handled by m_ptOrigin
|
||||
QAngle qAttachmentAngle;
|
||||
|
||||
bool bModel;
|
||||
Vector vLocalSpaceAttachmentOrigin;
|
||||
QAngle qLocalSpaceAttachmentAngles;
|
||||
Vector vRenderOBB_Mins;
|
||||
Vector vRenderOBB_Maxs;
|
||||
};
|
||||
ReflectPlaneCachedData_t m_CachedReflectedData;
|
||||
};
|
||||
|
||||
CMaterialReference C_Prop_Mirror::sm_Mirror_Stencil;
|
||||
|
||||
IMPLEMENT_CLIENTCLASS_DT( C_Prop_Mirror, DT_Prop_Mirror, CProp_Mirror )
|
||||
RecvPropFloat( RECVINFO(m_fWidth) ),
|
||||
RecvPropFloat( RECVINFO(m_fHeight) ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
C_Prop_Mirror::C_Prop_Mirror( void )
|
||||
{
|
||||
m_ptOrigin.Invalidate();
|
||||
m_CachedReflectedData.qAttachmentAngle.Invalidate();
|
||||
m_CachedReflectedData.vLocalSpaceAttachmentOrigin.Invalidate();
|
||||
m_CachedReflectedData.qLocalSpaceAttachmentAngles.Invalidate();
|
||||
m_CachedReflectedData.vRenderOBB_Maxs.Invalidate();
|
||||
|
||||
m_matrixThisToLinked.m[3][0] = 0.0f;
|
||||
m_matrixThisToLinked.m[3][1] = 0.0f;
|
||||
m_matrixThisToLinked.m[3][2] = 0.0f;
|
||||
m_matrixThisToLinked.m[3][3] = 1.0f;
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::Spawn( void )
|
||||
{
|
||||
BaseClass::Spawn();
|
||||
if( !sm_Mirror_Stencil.IsValid() )
|
||||
{
|
||||
sm_Mirror_Stencil.Init( "decals/portalstencildecal", TEXTURE_GROUP_CLIENT_EFFECTS );
|
||||
}
|
||||
|
||||
m_pLinkedPortal = this;
|
||||
g_pPortalRender->AddPortal( this ); //will know if we're already added and avoid adding twice
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::UpdateOnRemove( void )
|
||||
{
|
||||
BaseClass::UpdateOnRemove();
|
||||
g_pPortalRender->RemovePortal( this );
|
||||
}
|
||||
|
||||
CStudioHdr *C_Prop_Mirror::OnNewModel( void )
|
||||
{
|
||||
CStudioHdr *pRetVal = BaseClass::OnNewModel();
|
||||
|
||||
if( (GetModel() != NULL) )
|
||||
{
|
||||
m_iMirrorSurfaceBodyGroup = FindBodygroupByName( "MirrorSurface" );
|
||||
m_iMirrorFaceAttachment = LookupAttachment( "MirrorSurface_Attach" );
|
||||
if( (m_iMirrorSurfaceBodyGroup >= 0) && (m_iMirrorFaceAttachment >= 0) )
|
||||
{
|
||||
m_bModel = true;
|
||||
SetBodygroup( m_iMirrorSurfaceBodyGroup, 1 ); //by default the mirror surface is hidden
|
||||
}
|
||||
else
|
||||
{
|
||||
Warning( "Prop_Mirror model missing vital data %s\n", (m_iMirrorFaceAttachment < 0) ?
|
||||
((m_iMirrorSurfaceBodyGroup < 0) ? "MirrorSurface bodygroup and MirrorSurface_Attach attachment point" : "MirrorSurface_Attach attachment point") :
|
||||
"MirrorSurface bodygroup" );
|
||||
|
||||
m_bModel = false;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_bModel )
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||||
}
|
||||
else
|
||||
{
|
||||
SetNextClientThink( CLIENT_THINK_NEVER );
|
||||
}
|
||||
|
||||
return pRetVal;
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::UpdateReflectionPlane( void )
|
||||
{
|
||||
PortalMoved();
|
||||
Vector vToOrigin( m_ptOrigin.Dot( m_vForward ), m_ptOrigin.Dot( m_vRight ), -m_ptOrigin.Dot( m_vUp ) );
|
||||
|
||||
//generate mirroring matrix. Move mirror to origin using base vectors, flip on forward axis, move back to position and orientation
|
||||
{
|
||||
m_matrixThisToLinked.m[0][0] = (-m_vForward.x * m_vForward.x) + (m_vRight.x * m_vRight.x) + (m_vUp.x * m_vUp.x);
|
||||
m_matrixThisToLinked.m[0][1] = (-m_vForward.x * m_vForward.y) + (m_vRight.x * m_vRight.y) + (m_vUp.x * m_vUp.y);
|
||||
m_matrixThisToLinked.m[0][2] = (-m_vForward.x * m_vForward.z) + (m_vRight.x * m_vRight.z) + (m_vUp.x * m_vUp.z);
|
||||
m_matrixThisToLinked.m[0][3] = (vToOrigin.x * m_vForward.x) - (vToOrigin.y * m_vRight.x) + (vToOrigin.z * m_vUp.x) + m_ptOrigin.x;
|
||||
m_matrixThisToLinked.m[1][0] = m_matrixThisToLinked.m[0][1]; //rotation portion of the matrix is equal to it's own transpose
|
||||
m_matrixThisToLinked.m[1][1] = (-m_vForward.y * m_vForward.y) + (m_vRight.y * m_vRight.y) + (m_vUp.y * m_vUp.y);
|
||||
m_matrixThisToLinked.m[1][2] = (-m_vForward.y * m_vForward.z) + (m_vRight.y * m_vRight.z) + (m_vUp.y * m_vUp.z);
|
||||
m_matrixThisToLinked.m[1][3] = (vToOrigin.x * m_vForward.y) - (vToOrigin.y * m_vRight.y) + (vToOrigin.z * m_vUp.y) + m_ptOrigin.y;
|
||||
m_matrixThisToLinked.m[2][0] = m_matrixThisToLinked.m[0][2]; //rotation portion of the matrix is equal to it's own transpose
|
||||
m_matrixThisToLinked.m[2][1] = m_matrixThisToLinked.m[1][2]; //rotation portion of the matrix is equal to it's own transpose
|
||||
m_matrixThisToLinked.m[2][2] = (-m_vForward.z * m_vForward.z) + (m_vRight.z * m_vRight.z) + (m_vUp.z * m_vUp.z);
|
||||
m_matrixThisToLinked.m[2][3] = (vToOrigin.x * m_vForward.z) - (vToOrigin.y * m_vRight.z) + (vToOrigin.z * m_vUp.z) + m_ptOrigin.z;
|
||||
}
|
||||
|
||||
UpdateReflectionPolygon();
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::UpdateReflectionPolygon( void )
|
||||
{
|
||||
if( m_bModel != m_CachedReflectedData.bModel )
|
||||
{
|
||||
m_CachedReflectedData.qAttachmentAngle.Invalidate();
|
||||
m_CachedReflectedData.vLocalSpaceAttachmentOrigin.Invalidate();
|
||||
m_CachedReflectedData.qLocalSpaceAttachmentAngles.Invalidate();
|
||||
m_CachedReflectedData.vRenderOBB_Maxs.Invalidate();
|
||||
m_CachedReflectedData.bModel = m_bModel;
|
||||
}
|
||||
|
||||
if( m_bModel )
|
||||
{
|
||||
Vector vMins, vMaxs;
|
||||
GetRenderBounds( vMins, vMaxs );
|
||||
|
||||
Vector vLocalAttachmentOrigin;
|
||||
QAngle qLocalAttachmentAngles;
|
||||
GetAttachmentLocal( m_iMirrorFaceAttachment, vLocalAttachmentOrigin, qLocalAttachmentAngles );
|
||||
|
||||
if( (vMins == m_CachedReflectedData.vRenderOBB_Mins) && (vMaxs == m_CachedReflectedData.vRenderOBB_Maxs) &&
|
||||
(vLocalAttachmentOrigin == m_CachedReflectedData.vLocalSpaceAttachmentOrigin) && (qLocalAttachmentAngles == m_CachedReflectedData.qLocalSpaceAttachmentAngles) )
|
||||
{
|
||||
return; //nothing to update
|
||||
}
|
||||
|
||||
m_CachedReflectedData.vRenderOBB_Mins = vMins;
|
||||
m_CachedReflectedData.vRenderOBB_Maxs = vMaxs;
|
||||
m_CachedReflectedData.vLocalSpaceAttachmentOrigin = vLocalAttachmentOrigin;
|
||||
m_CachedReflectedData.qLocalSpaceAttachmentAngles = qLocalAttachmentAngles;
|
||||
|
||||
Vector vAttachmentVectors[3];
|
||||
AngleVectors( qLocalAttachmentAngles, &vAttachmentVectors[0], &vAttachmentVectors[1], &vAttachmentVectors[2] );
|
||||
float fLargestOBBDiff = vMaxs.x - vMins.x;
|
||||
for( int i = 1; i != 3; ++i )
|
||||
{
|
||||
float fDiff = vMaxs[i] - vMins[i];
|
||||
if( fDiff > fLargestOBBDiff )
|
||||
{
|
||||
fLargestOBBDiff = fDiff;
|
||||
}
|
||||
}
|
||||
fLargestOBBDiff *= 4.0f; //to easily cover diagonal intersection and then some
|
||||
|
||||
Vector vClipBuffers[2][10]; //4 starting points, possible to create 1 extra point per cut, 6 cuts
|
||||
vClipBuffers[0][0] = vLocalAttachmentOrigin + (vAttachmentVectors[1] * fLargestOBBDiff) + (vAttachmentVectors[2] * fLargestOBBDiff);
|
||||
vClipBuffers[0][1] = vLocalAttachmentOrigin - (vAttachmentVectors[1] * fLargestOBBDiff) + (vAttachmentVectors[2] * fLargestOBBDiff);
|
||||
vClipBuffers[0][2] = vLocalAttachmentOrigin - (vAttachmentVectors[1] * fLargestOBBDiff) - (vAttachmentVectors[2] * fLargestOBBDiff);
|
||||
vClipBuffers[0][3] = vLocalAttachmentOrigin + (vAttachmentVectors[1] * fLargestOBBDiff) - (vAttachmentVectors[2] * fLargestOBBDiff);
|
||||
int iVertCount = 4;
|
||||
|
||||
VPlane vClipPlanes[6];
|
||||
vClipPlanes[0].Init( Vector( 1.0f, 0.0f, 0.0f ), vMins.x );
|
||||
vClipPlanes[1].Init( Vector( -1.0f, 0.0f, 0.0f ), -vMaxs.x );
|
||||
vClipPlanes[2].Init( Vector( 0.0f, 1.0f, 0.0f ), vMins.y );
|
||||
vClipPlanes[3].Init( Vector( 0.0f, -1.0f, 0.0f ), -vMaxs.y );
|
||||
vClipPlanes[4].Init( Vector( 0.0f, 0.0f, 1.0f ), vMins.z );
|
||||
vClipPlanes[5].Init( Vector( 0.0f, 0.0f, -1.0f ), -vMaxs.z );
|
||||
|
||||
for( int i = 0; i != 6; ++i )
|
||||
{
|
||||
iVertCount = ClipPolyToPlane( vClipBuffers[i & 1], iVertCount, vClipBuffers[(i & 1) ^ 1], vClipPlanes[i].m_Normal, vClipPlanes[i].m_Dist, 0.01f );
|
||||
}
|
||||
Assert( iVertCount >= 3 );
|
||||
|
||||
m_LocalSpaceReflectionPolygonVertCount = iVertCount;
|
||||
memcpy( m_LocalSpaceReflectionPolygonVerts, vClipBuffers[0], sizeof( Vector ) * iVertCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (m_CachedReflectedData.vRenderOBB_Maxs.x == m_fWidth) && (m_CachedReflectedData.vRenderOBB_Maxs.y == m_fHeight) )
|
||||
return;
|
||||
|
||||
m_LocalSpaceReflectionPolygonVertCount = 4;
|
||||
float fHalfWidth = GetHalfWidth();
|
||||
float fHalfHeight = GetHalfHeight();
|
||||
m_LocalSpaceReflectionPolygonVerts[0].Init( 0.0f, fHalfWidth, fHalfHeight );
|
||||
m_LocalSpaceReflectionPolygonVerts[1].Init( 0.0f, -fHalfWidth, fHalfHeight );
|
||||
m_LocalSpaceReflectionPolygonVerts[2].Init( 0.0f, -fHalfWidth, -fHalfHeight );
|
||||
m_LocalSpaceReflectionPolygonVerts[3].Init( 0.0f, fHalfWidth, -fHalfHeight );
|
||||
}
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::OnDataChanged( DataUpdateType_t type )
|
||||
{
|
||||
BaseClass::OnDataChanged( type );
|
||||
SetHalfSizes( m_fWidth / 2.0f, m_fHeight / 2.0f );
|
||||
|
||||
if( m_bModel )
|
||||
{
|
||||
Vector vMirrorAttachmentOrigin;
|
||||
QAngle qMirrorAttachmentAngles;
|
||||
GetAttachment( m_iMirrorFaceAttachment, vMirrorAttachmentOrigin, qMirrorAttachmentAngles );
|
||||
|
||||
if( (m_ptOrigin != vMirrorAttachmentOrigin) || (m_CachedReflectedData.qAttachmentAngle != qMirrorAttachmentAngles) )
|
||||
{
|
||||
m_ptOrigin = vMirrorAttachmentOrigin;
|
||||
m_CachedReflectedData.qAttachmentAngle = qMirrorAttachmentAngles;
|
||||
AngleVectors( qMirrorAttachmentAngles, &m_vForward, &m_vRight, &m_vUp );
|
||||
UpdateReflectionPlane();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (m_ptOrigin != GetRenderOrigin()) || (m_CachedReflectedData.qAttachmentAngle != GetRenderAngles()) )
|
||||
{
|
||||
m_ptOrigin = GetRenderOrigin();
|
||||
m_CachedReflectedData.qAttachmentAngle = GetRenderAngles();
|
||||
AngleVectors( GetRenderAngles(), &m_vForward, &m_vRight, &m_vUp );
|
||||
UpdateReflectionPlane();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void C_Prop_Mirror::ClientThink( void )
|
||||
{
|
||||
BaseClass::ClientThink();
|
||||
|
||||
if( m_bModel )
|
||||
{
|
||||
Vector vMirrorAttachmentOrigin;
|
||||
QAngle qMirrorAttachmentAngles;
|
||||
GetAttachment( m_iMirrorFaceAttachment, vMirrorAttachmentOrigin, qMirrorAttachmentAngles );
|
||||
|
||||
if( (m_ptOrigin != vMirrorAttachmentOrigin) || (m_CachedReflectedData.qAttachmentAngle != qMirrorAttachmentAngles) )
|
||||
{
|
||||
m_ptOrigin = vMirrorAttachmentOrigin;
|
||||
AngleVectors( qMirrorAttachmentAngles, &m_vForward, &m_vRight, &m_vUp );
|
||||
UpdateReflectionPlane();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::DrawStencilMask( IMatRenderContext *pRenderContext )
|
||||
{
|
||||
if( m_bModel )
|
||||
{
|
||||
int iNumBodyGroups = GetNumBodyGroups();
|
||||
int *pOldBodyGroups = (int *)stackalloc( sizeof( int ) * iNumBodyGroups );
|
||||
for( int i = 0; i != iNumBodyGroups; ++i )
|
||||
{
|
||||
pOldBodyGroups[i] = GetBodygroup( i );
|
||||
SetBodygroup( i, 1 );
|
||||
}
|
||||
pOldBodyGroups[m_iMirrorSurfaceBodyGroup] = 1;
|
||||
SetBodygroup( m_iMirrorSurfaceBodyGroup, 0 );
|
||||
|
||||
RenderableInstance_t tempInstance;
|
||||
tempInstance.m_nAlpha = 255;
|
||||
modelrender->ForcedMaterialOverride( (IMaterial *)(const IMaterial *)g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
|
||||
DrawModel( STUDIO_RENDER, tempInstance );
|
||||
modelrender->ForcedMaterialOverride( NULL );
|
||||
|
||||
for( int i = 0; i != iNumBodyGroups; ++i )
|
||||
{
|
||||
SetBodygroup( i, pOldBodyGroups[i] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSimplePortalMesh( pRenderContext, g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
|
||||
}
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::DrawPostStencilFixes( IMatRenderContext *pRenderContext )
|
||||
{
|
||||
if( m_bModel )
|
||||
{
|
||||
int iNumBodyGroups = GetNumBodyGroups();
|
||||
int *pOldBodyGroups = (int *)stackalloc( sizeof( int ) * iNumBodyGroups );
|
||||
for( int i = 0; i != iNumBodyGroups; ++i )
|
||||
{
|
||||
pOldBodyGroups[i] = GetBodygroup( i );
|
||||
SetBodygroup( i, 1 );
|
||||
}
|
||||
pOldBodyGroups[m_iMirrorSurfaceBodyGroup] = 1;
|
||||
SetBodygroup( m_iMirrorSurfaceBodyGroup, 0 );
|
||||
|
||||
RenderableInstance_t tempInstance;
|
||||
tempInstance.m_nAlpha = 255;
|
||||
modelrender->ForcedMaterialOverride( (IMaterial *)(const IMaterial *)g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
|
||||
DrawModel( STUDIO_RENDER, tempInstance );
|
||||
modelrender->ForcedMaterialOverride( NULL );
|
||||
|
||||
for( int i = 0; i != iNumBodyGroups; ++i )
|
||||
{
|
||||
SetBodygroup( i, pOldBodyGroups[i] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawSimplePortalMesh( pRenderContext, g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
|
||||
}
|
||||
}
|
||||
|
||||
bool C_Prop_Mirror::ShouldUpdatePortalView_BasedOnView( const CViewSetup ¤tView, const CUtlVector<VPlane> ¤tComplexFrustum )
|
||||
{
|
||||
if( m_vForward.Dot( currentView.origin ) <= m_vForward.Dot( m_ptOrigin ) )
|
||||
return false; //camera is behind the mirror plane
|
||||
|
||||
UpdateReflectionPolygon();
|
||||
matrix3x4_t matRenderTransform;
|
||||
AngleMatrix( GetRenderAngles(), GetRenderOrigin(), matRenderTransform );
|
||||
|
||||
Vector *pClipBuffers[2];
|
||||
int clipAllocSize = (m_LocalSpaceReflectionPolygonVertCount + currentComplexFrustum.Count() + 2); //possible to add 1 point per cut, m_LocalSpaceReflectionPolygonVertCount starting points, currentComplexFrustum.Count() plane cuts, 2 extra because I'm paranoid
|
||||
pClipBuffers[0] = (Vector *)stackalloc( sizeof( Vector ) * clipAllocSize * 2 );
|
||||
pClipBuffers[1] = pClipBuffers[0] + clipAllocSize;
|
||||
|
||||
for( int i = 0; i != m_LocalSpaceReflectionPolygonVertCount; ++i )
|
||||
{
|
||||
VectorTransform( m_LocalSpaceReflectionPolygonVerts[i], matRenderTransform, pClipBuffers[0][i] );
|
||||
}
|
||||
|
||||
const VPlane *currentFrustum = currentComplexFrustum.Base();
|
||||
int iCurrentFrustumPlanes = currentComplexFrustum.Count();
|
||||
|
||||
//clip by first plane and put output into pInVerts
|
||||
int iVertCount = ClipPolyToPlane( pClipBuffers[0], m_LocalSpaceReflectionPolygonVertCount, pClipBuffers[1], currentFrustum[0].m_Normal, currentFrustum[0].m_Dist, 0.01f );
|
||||
|
||||
for( int i = 1; i != iCurrentFrustumPlanes; ++i )
|
||||
{
|
||||
if( iVertCount < 3 )
|
||||
return false; //nothing left in the frustum
|
||||
|
||||
iVertCount = ClipPolyToPlane( pClipBuffers[i&1], iVertCount, pClipBuffers[(i&1)^1], currentFrustum[i].m_Normal, currentFrustum[i].m_Dist, 0.01f );
|
||||
}
|
||||
|
||||
#if 0 //for visibility culling debugging
|
||||
int iFinalBuffer = (iCurrentFrustumPlanes & 1) ^ 1;
|
||||
if( g_pPortalRender->GetViewRecursionLevel() == 0 )
|
||||
{
|
||||
NDebugOverlay::Line( pClipBuffers[iFinalBuffer][iVertCount - 1], pClipBuffers[iFinalBuffer][0], 255, 0, 0, false, 0.0f );
|
||||
for( int j = 0; j != iVertCount - 1; ++j )
|
||||
{
|
||||
NDebugOverlay::Line( pClipBuffers[iFinalBuffer][j], pClipBuffers[iFinalBuffer][j+1], 255, 0, 0, false, 0.0f );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return (iVertCount >= 3);
|
||||
|
||||
|
||||
#if 0
|
||||
if( m_bModel )
|
||||
{
|
||||
//it would be complicated to get the exact shape of the mirror surface and cut it up, so we'll just use the model's oriented bounding box.
|
||||
//which can provide up to 3 visible quads, if any 1 of them passes the test then the entire thing is visible.
|
||||
|
||||
if( m_vForward.Dot( currentView.origin ) <= m_vForward.Dot( m_ptOrigin ) )
|
||||
return false; //camera is behind the mirror plane
|
||||
|
||||
Vector vMins, vMaxs;
|
||||
GetRenderBounds( vMins, vMaxs );
|
||||
|
||||
Vector vRenderOrigin = GetRenderOrigin();
|
||||
Vector vOBBVectors[3];
|
||||
#if 1
|
||||
AngleVectors( GetRenderAngles(), &vOBBVectors[0], &vOBBVectors[1], &vOBBVectors[2] );
|
||||
vOBBVectors[1] = -vOBBVectors[1];
|
||||
#else
|
||||
{
|
||||
matrix3x4_t fRotateMatrix;
|
||||
AngleMatrix( GetRenderAngles(), fRotateMatrix );
|
||||
VectorRotate( Vector( 1.0f, 0.0f, 0.0f ), fRotateMatrix, vOBBVectors[0] );
|
||||
VectorRotate( Vector( 0.0f, 1.0f, 0.0f ), fRotateMatrix, vOBBVectors[1] );
|
||||
VectorRotate( Vector( 0.0f, 0.0f, 1.0f ), fRotateMatrix, vOBBVectors[2] );
|
||||
}
|
||||
#endif
|
||||
|
||||
Vector vRenderOriginToCamera = currentView.origin - vRenderOrigin;
|
||||
|
||||
Vector *pClipBuffers[2];
|
||||
int clipAllocSize = (6 + currentComplexFrustum.Count()); //possible to add 1 point per cut, 4 starting points, N plane cuts, 2 extra because I'm paranoid
|
||||
pClipBuffers[0] = (Vector *)stackalloc( sizeof( Vector ) * clipAllocSize * 2 );
|
||||
pClipBuffers[1] = pClipBuffers[0] + clipAllocSize;
|
||||
|
||||
VPlane *currentFrustum = currentComplexFrustum.Base();
|
||||
int iCurrentFrustumPlanes = currentComplexFrustum.Count();
|
||||
|
||||
for( int i = 0; i != 3; ++i )
|
||||
{
|
||||
Vector vPolyStartPoint;
|
||||
|
||||
float fDot = vRenderOriginToCamera.Dot( vOBBVectors[i] );
|
||||
|
||||
if( fDot > vMaxs[i] )
|
||||
{
|
||||
//on the positive side of this axis
|
||||
vPolyStartPoint = vRenderOrigin + (vOBBVectors[i] * vMaxs[i]);
|
||||
}
|
||||
else if( fDot < vMins[i] )
|
||||
{
|
||||
//on the negative side of this axis
|
||||
vPolyStartPoint = vRenderOrigin + (vOBBVectors[i] * vMins[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
//can't see the outside of the face
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
int iBasis[2];
|
||||
iBasis[0] = (i&1) ^ 1;
|
||||
iBasis[1] = (i&2) ^ 2;
|
||||
|
||||
pClipBuffers[0][0] = vPolyStartPoint + (vOBBVectors[iBasis[0]] * vMins[iBasis[0]]) + (vOBBVectors[iBasis[1]] * vMaxs[iBasis[1]]);
|
||||
pClipBuffers[0][1] = vPolyStartPoint + (vOBBVectors[iBasis[0]] * vMaxs[iBasis[0]]) + (vOBBVectors[iBasis[1]] * vMaxs[iBasis[1]]);
|
||||
pClipBuffers[0][2] = vPolyStartPoint + (vOBBVectors[iBasis[0]] * vMaxs[iBasis[0]]) + (vOBBVectors[iBasis[1]] * vMins[iBasis[1]]);
|
||||
pClipBuffers[0][3] = vPolyStartPoint + (vOBBVectors[iBasis[0]] * vMins[iBasis[0]]) + (vOBBVectors[iBasis[1]] * vMins[iBasis[1]]);
|
||||
|
||||
//clip by first plane and put output into pInVerts
|
||||
int iVertCount = ClipPolyToPlane( pClipBuffers[0], 4, pClipBuffers[1], currentFrustum[0].m_Normal, currentFrustum[0].m_Dist, 0.01f );
|
||||
|
||||
for( int j = 1; j != iCurrentFrustumPlanes; ++j )
|
||||
{
|
||||
if( iVertCount < 3 )
|
||||
break; //nothing left in the frustum
|
||||
|
||||
iVertCount = ClipPolyToPlane( pClipBuffers[j&1], iVertCount, pClipBuffers[(j&1)^1], currentFrustum[j].m_Normal, currentFrustum[j].m_Dist, 0.01f );
|
||||
}
|
||||
|
||||
if( iVertCount >= 3 )
|
||||
{
|
||||
return true; //this polygon is visible, we're done
|
||||
}
|
||||
}
|
||||
|
||||
return false; //none of the polygons are visible
|
||||
}
|
||||
else
|
||||
{
|
||||
//rely on flatbasic's technique since we're just using a quad
|
||||
return BaseClass::ShouldUpdatePortalView_BasedOnView( currentView, currentComplexFrustum );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
extern ConVar r_portal_use_complex_frustums;
|
||||
bool C_Prop_Mirror::CalcFrustumThroughPortal( const Vector &ptCurrentViewOrigin, Frustum OutputFrustum )
|
||||
{
|
||||
if( r_portal_use_complex_frustums.GetBool() == false )
|
||||
return false;
|
||||
|
||||
if( m_vForward.Dot( ptCurrentViewOrigin ) <= m_vForward.Dot( m_ptOrigin ) )
|
||||
return false; //looking at portal backface
|
||||
|
||||
Vector pTransformedVerts[10];
|
||||
const matrix3x4_t &matLocalToWorld = EntityToWorldTransform();
|
||||
for( int i = 0; i != m_LocalSpaceReflectionPolygonVertCount; ++i )
|
||||
{
|
||||
VectorTransform( &m_LocalSpaceReflectionPolygonVerts[i].x, matLocalToWorld, &pTransformedVerts[i].x );
|
||||
}
|
||||
|
||||
return CalcFrustumThroughPolygon( pTransformedVerts, m_LocalSpaceReflectionPolygonVertCount, ptCurrentViewOrigin, OutputFrustum );
|
||||
}
|
||||
|
||||
void C_Prop_Mirror::RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView )
|
||||
{
|
||||
VPROF( "C_Prop_Mirror::RenderPortalViewToBackBuffer" );
|
||||
|
||||
Frustum FrustumBackup;
|
||||
memcpy( FrustumBackup, pViewRender->GetFrustum(), sizeof( Frustum ) );
|
||||
|
||||
Frustum seeThroughFrustum;
|
||||
bool bUseSeeThroughFrustum;
|
||||
|
||||
bUseSeeThroughFrustum = CalcFrustumThroughPortal( cameraView.origin, seeThroughFrustum );
|
||||
|
||||
Vector vCameraForward;
|
||||
AngleVectors( cameraView.angles, &vCameraForward, NULL, NULL );
|
||||
|
||||
// Setup fog state for the camera.
|
||||
Vector ptPOVOrigin = m_matrixThisToLinked * cameraView.origin;
|
||||
Vector vPOVForward = m_matrixThisToLinked.ApplyRotation( vCameraForward );
|
||||
|
||||
CViewSetup portalView = cameraView;
|
||||
|
||||
if( portalView.zNear < 1.0f )
|
||||
portalView.zNear = 1.0f;
|
||||
|
||||
QAngle qPOVAngles = TransformAnglesToWorldSpace( cameraView.angles, m_matrixThisToLinked.As3x4() );
|
||||
|
||||
portalView.origin = ptPOVOrigin;
|
||||
portalView.angles = qPOVAngles;
|
||||
|
||||
VMatrix matCurrentView;
|
||||
if( cameraView.m_bCustomViewMatrix )
|
||||
{
|
||||
matCurrentView.CopyFrom3x4( cameraView.m_matCustomViewMatrix );
|
||||
}
|
||||
else
|
||||
{
|
||||
matCurrentView.Identity();
|
||||
|
||||
//generate the view matrix for the existing position and angle, then wedge our mirror matrix onto it as a world transformation that prepends the view
|
||||
MatrixRotate( matCurrentView, Vector( 1, 0, 0 ), -cameraView.angles[2] );
|
||||
MatrixRotate( matCurrentView, Vector( 0, 1, 0 ), -cameraView.angles[0] );
|
||||
MatrixRotate( matCurrentView, Vector( 0, 0, 1 ), -cameraView.angles[1] );
|
||||
MatrixTranslate( matCurrentView, -cameraView.origin );
|
||||
}
|
||||
|
||||
VMatrix matTemp = matCurrentView * m_matrixThisToLinked; //technically we should be using the inverse of m_matrixThisToLinked, but it's the same matrix!
|
||||
portalView.m_matCustomViewMatrix = matTemp.As3x4();
|
||||
portalView.m_bCustomViewMatrix = true;
|
||||
|
||||
CopyToCurrentView( pViewRender, portalView );
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
|
||||
pRenderContext->FlipCullMode(); //mirroring the world requires a flip in cull mode or we'll draw everything bass ackwards
|
||||
|
||||
//if we look through multiple unique pairs of portals, we have to take care not to clip too much
|
||||
bool bReplaceOldPortalClipPlane = (g_pPortalRender->GetViewRecursionLevel() != 0) && (dynamic_cast<CPortalRenderable_FlatBasic *>(g_pPortalRender->GetCurrentViewExitPortal()) != NULL);
|
||||
|
||||
{
|
||||
float fCustomClipPlane[4];
|
||||
fCustomClipPlane[0] = m_vForward.x;
|
||||
fCustomClipPlane[1] = m_vForward.y;
|
||||
fCustomClipPlane[2] = m_vForward.z;
|
||||
fCustomClipPlane[3] = m_vForward.Dot( m_ptOrigin );
|
||||
|
||||
if( bReplaceOldPortalClipPlane )
|
||||
pRenderContext->PopCustomClipPlane(); //HACKHACK: We really only want to remove the clip plane of the current portal view. This assumes we're the only ones leaving clip planes on the stack
|
||||
|
||||
pRenderContext->PushCustomClipPlane( fCustomClipPlane );
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
ViewCustomVisibility_t customVisibility;
|
||||
m_pLinkedPortal->AddToVisAsExitPortal( &customVisibility );
|
||||
render->Push3DView( pRenderContext, portalView, 0, NULL, pViewRender->GetFrustum() );
|
||||
{
|
||||
if( bUseSeeThroughFrustum)
|
||||
memcpy( pViewRender->GetFrustum(), seeThroughFrustum, sizeof( Frustum ) );
|
||||
|
||||
render->OverrideViewFrustum( pViewRender->GetFrustum() );
|
||||
SetViewRecursionLevel( g_pPortalRender->GetViewRecursionLevel() + 1 );
|
||||
|
||||
CPortalRenderable *pRenderingViewForPortalBackup = g_pPortalRender->GetCurrentViewEntryPortal();
|
||||
CPortalRenderable *pRenderingViewExitPortalBackup = g_pPortalRender->GetCurrentViewExitPortal();
|
||||
SetViewEntranceAndExitPortals( this, m_pLinkedPortal );
|
||||
|
||||
//DRAW!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
ViewDrawScene_PortalStencil( pViewRender, portalView, &customVisibility );
|
||||
|
||||
SetViewEntranceAndExitPortals( pRenderingViewForPortalBackup, pRenderingViewExitPortalBackup );
|
||||
|
||||
if( m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration && (g_pPortalRender->GetRemainingPortalViewDepth() == 1) )
|
||||
{
|
||||
//save the view matrix for usage with the depth doubler.
|
||||
//It's important that we do this AFTER using the depth doubler this frame to compensate for the fact that the front buffer is 1 frame behind the current view matrix
|
||||
//otherwise we get a lag effect when the player changes their viewing angles
|
||||
pRenderContext->GetMatrix( MATERIAL_VIEW, &m_InternallyMaintainedData.m_DepthDoublerTextureView[GET_ACTIVE_SPLITSCREEN_SLOT()] );
|
||||
}
|
||||
|
||||
SetViewRecursionLevel( g_pPortalRender->GetViewRecursionLevel() - 1 );
|
||||
}
|
||||
render->PopView( pRenderContext, pViewRender->GetFrustum() );
|
||||
|
||||
//restore old frustum
|
||||
memcpy( pViewRender->GetFrustum(), FrustumBackup, sizeof( Frustum ) );
|
||||
render->OverrideViewFrustum( FrustumBackup );
|
||||
}
|
||||
|
||||
pRenderContext->FlipCullMode(); //flip the cull mode again to restore it to it's original setting
|
||||
|
||||
pRenderContext->PopCustomClipPlane();
|
||||
|
||||
if( bReplaceOldPortalClipPlane )
|
||||
{
|
||||
CPortalRenderable_FlatBasic *pCurrentExitPortal = (CPortalRenderable_FlatBasic *)g_pPortalRender->GetCurrentViewExitPortal();
|
||||
|
||||
float fCustomClipPlane[4];
|
||||
fCustomClipPlane[0] = pCurrentExitPortal->m_vForward.x;
|
||||
fCustomClipPlane[1] = pCurrentExitPortal->m_vForward.y;
|
||||
fCustomClipPlane[2] = pCurrentExitPortal->m_vForward.z;
|
||||
fCustomClipPlane[3] = pCurrentExitPortal->m_vForward.Dot( pCurrentExitPortal->m_ptOrigin - (pCurrentExitPortal->m_vForward * 0.5f) ); //moving it back a smidge to eliminate visual artifacts for half-in objects
|
||||
|
||||
pRenderContext->PushCustomClipPlane( fCustomClipPlane );
|
||||
}
|
||||
|
||||
//restore old vis data
|
||||
CopyToCurrentView( pViewRender, cameraView );
|
||||
}
|
||||
|
||||
int C_Prop_Mirror::DrawModel( int flags, const RenderableInstance_t &instance )
|
||||
{
|
||||
if( g_pPortalRender->GetRemainingPortalViewDepth() == 0 )
|
||||
{
|
||||
SetBodygroup( m_iMirrorSurfaceBodyGroup, 0 );
|
||||
}
|
||||
|
||||
int iRetVal = BaseClass::DrawModel( flags, instance );
|
||||
|
||||
if( g_pPortalRender->GetRemainingPortalViewDepth() == 0 )
|
||||
{
|
||||
SetBodygroup( m_iMirrorSurfaceBodyGroup, 1 );
|
||||
}
|
||||
|
||||
return iRetVal;
|
||||
}
|
||||
1372
game/client/portal/c_prop_portal.cpp
Normal file
1372
game/client/portal/c_prop_portal.cpp
Normal file
File diff suppressed because it is too large
Load Diff
135
game/client/portal/c_prop_portal.h
Normal file
135
game/client/portal/c_prop_portal.h
Normal file
@@ -0,0 +1,135 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef C_PROP_PORTAL_H
|
||||
#define C_PROP_PORTAL_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "c_portal_base2d.h"
|
||||
#include "portal_shareddefs.h"
|
||||
|
||||
struct dlight_t;
|
||||
class C_DynamicLight;
|
||||
|
||||
struct PropPortalRenderingMaterials_t
|
||||
{
|
||||
CMaterialReference m_PortalMaterials[2];
|
||||
CMaterialReference m_PortalRenderFixMaterials[2];
|
||||
CMaterialReference m_PortalDepthDoubler;
|
||||
CMaterialReference m_PortalStaticOverlay[2];
|
||||
CMaterialReference m_PortalStaticOverlay_Tinted;
|
||||
CMaterialReference m_PortalStaticGhostedOverlay[2];
|
||||
CMaterialReference m_PortalStaticGhostedOverlay_Tinted;
|
||||
CMaterialReference m_Portal_Stencil_Hole;
|
||||
CMaterialReference m_Portal_Refract;
|
||||
|
||||
unsigned int m_nDepthDoubleViewMatrixVarCache;
|
||||
unsigned int m_nStaticOverlayTintedColorGradientLightVarCache;
|
||||
|
||||
Vector m_coopPlayerPortalColors[2][2];
|
||||
Vector m_singlePlayerPortalColors[2];
|
||||
};
|
||||
|
||||
class C_Prop_Portal : public C_Portal_Base2D
|
||||
{
|
||||
public:
|
||||
DECLARE_CLASS( C_Prop_Portal, C_Portal_Base2D );
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_PREDICTABLE();
|
||||
|
||||
C_Prop_Portal( void );
|
||||
virtual ~C_Prop_Portal( void );
|
||||
|
||||
virtual void Spawn( void );
|
||||
virtual void Activate( void );
|
||||
virtual void ClientThink( void );
|
||||
virtual void UpdateOnRemove( void );
|
||||
virtual void OnRestore( void );
|
||||
|
||||
virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect );
|
||||
virtual void OnPortalMoved( void );
|
||||
virtual void OnActiveStateChanged( void );
|
||||
virtual void OnLinkageChanged( C_Portal_Base2D *pOldLinkage );
|
||||
virtual void DrawPortal( IMatRenderContext *pRenderContext );
|
||||
virtual int BindPortalMaterial( IMatRenderContext *pRenderContext, int nPassIndex, bool *pAllowRingMeshOptimizationOut );
|
||||
|
||||
virtual void DrawPreStencilMask( IMatRenderContext *pRenderContext );
|
||||
virtual void DrawStencilMask( IMatRenderContext *pRenderContext );
|
||||
virtual float GetPortalGhostAlpha( void ) const;
|
||||
|
||||
//When we're in a configuration that sees through recursive portal views to a depth of 2, we should be able to cheaply approximate even further depth using pixels from previous frames
|
||||
void DrawDepthDoublerMesh( IMatRenderContext *pRenderContext, float fForwardOffsetModifier = 0.25f );
|
||||
|
||||
void CreateAttachedParticles( Color *pColors = NULL );
|
||||
void DestroyAttachedParticles( void );
|
||||
void UpdateTransformedLighting( void );
|
||||
|
||||
void DoFizzleEffect( int iEffect, bool bDelayedPos = true ); //display cool visual effect
|
||||
void Fizzle( void );
|
||||
void PlacePortal( const Vector &vOrigin, const QAngle &qAngles, PortalPlacementResult_t eResult, bool bDelay = false );
|
||||
void DelayedPlacementThink( void );
|
||||
void SetFiredByPlayer( CBasePlayer *pPlayer );
|
||||
inline CBasePlayer *GetFiredByPlayer( void ) const { return (CBasePlayer *)m_hFiredByPlayer.Get(); }
|
||||
|
||||
void CreateFizzleEffect( C_BaseEntity *pOwner, int iEffect, Vector vecOrigin, QAngle qAngles, int nTeam, int nPortalNum );
|
||||
|
||||
struct TransformedLightingData_t
|
||||
{
|
||||
ClientShadowHandle_t m_LightShadowHandle;
|
||||
dlight_t *m_pEntityLight;
|
||||
} TransformedLighting;
|
||||
|
||||
float m_fStaticAmount;
|
||||
float m_fSecondaryStaticAmount; // used to help kludge the end of our recursive rendering chain
|
||||
float m_fOpenAmount;
|
||||
|
||||
EHANDLE m_hFiredByPlayer; //needed for multiplayer portal coloration
|
||||
CUtlReference<CNewParticleEffect> m_hEffect; // the particles effect that attaches to an active portal
|
||||
|
||||
Vector m_vDelayedPosition;
|
||||
QAngle m_qDelayedAngles;
|
||||
int m_iDelayedFailure;
|
||||
|
||||
static bool ms_DefaultPortalSizeInitialized; // for CEG protection
|
||||
static float ms_DefaultPortalHalfWidth;
|
||||
static float ms_DefaultPortalHalfHeight;
|
||||
|
||||
//NULL portal will return default width/height
|
||||
static void GetPortalSize( float &fHalfWidth, float &fHalfHeight, C_Prop_Portal *pPortal = NULL );
|
||||
|
||||
|
||||
static PropPortalRenderingMaterials_t& m_Materials;
|
||||
static void DrawPortalGhostLocations( IMatRenderContext *pRenderContext ); //the outlines of prop_portals we can see through walls to keep track of them
|
||||
|
||||
virtual bool ShouldPredict( void );
|
||||
virtual C_BasePlayer *GetPredictionOwner( void );
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
virtual void HandlePortalPlaybackMessage( KeyValues *pKeyValues );
|
||||
|
||||
virtual float GetMinimumExitSpeed( bool bPlayer, bool bEntranceOnFloor, bool bExitOnFloor, const Vector &vEntityCenterAtExit, CBaseEntity *pEntity ); //return -FLT_MAX for no minimum
|
||||
virtual float GetMaximumExitSpeed( bool bPlayer, bool bEntranceOnFloor, bool bExitOnFloor, const Vector &vEntityCenterAtExit, CBaseEntity *pEntity ); //return FLT_MAX for no maximum
|
||||
|
||||
inline bool IsPortalOpening() const { return ( m_fOpenAmount > 0.0f ) && ( m_fOpenAmount < 1.0f ); }
|
||||
float ComputeStaticAmountForRendering() const;
|
||||
|
||||
virtual void HandlePredictionError( bool bErrorInThisEntity );
|
||||
|
||||
private:
|
||||
friend class CPortalRender;
|
||||
static void BuildPortalGhostRenderInfo( const CUtlVector< CPortalRenderable* > &allPortals, CUtlVector< GhostPortalRenderInfo_t > &ghostPortalRenderInfosOut );
|
||||
|
||||
public:
|
||||
int m_nPlacementAttemptParity;
|
||||
};
|
||||
|
||||
typedef C_Prop_Portal CProp_Portal;
|
||||
|
||||
#endif //#ifndef C_PROP_PORTAL_H
|
||||
487
game/client/portal/clientmode_portal.cpp
Normal file
487
game/client/portal/clientmode_portal.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "ivmodemanager.h"
|
||||
#include "clientmode_hlnormal.h"
|
||||
#include "panelmetaclassmgr.h"
|
||||
#include "c_playerresource.h"
|
||||
#include "c_portal_player.h"
|
||||
#include "clientmode_portal.h"
|
||||
#include "usermessages.h"
|
||||
#include "prediction.h"
|
||||
#include "portal2/vgui/portalclientscoreboard.h"
|
||||
#include "portal2/vgui/surveypanel.h"
|
||||
#include "hud_macros.h"
|
||||
#include "radialmenu.h"
|
||||
#include "glow_outline_effect.h"
|
||||
#include "portal2/portal_grabcontroller_shared.h"
|
||||
#include "viewpostprocess.h"
|
||||
#include "radialmenu.h"
|
||||
#include "fmtstr.h"
|
||||
#include "ivieweffects.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
// default FOV for HL2
|
||||
ConVar default_fov( "default_fov", "75", FCVAR_CHEAT );
|
||||
ConVar fov_desired( "fov_desired", "75", FCVAR_ARCHIVE | FCVAR_USERINFO, "Sets the base field-of-view.", true, 75.0, true, 90.0 );
|
||||
extern ConVar hide_gun_when_holding;
|
||||
extern ConVar v_viewmodel_fov;
|
||||
|
||||
ConVar cl_viewmodelfov( "cl_viewmodelfov", "50", FCVAR_DEVELOPMENTONLY );
|
||||
|
||||
ConVar cl_finale_completed( "cl_finale_completed", "0", FCVAR_HIDDEN );
|
||||
|
||||
#define DEATH_CC_LOOKUP_FILENAME "materials/correction/cc_death.raw"
|
||||
#define DEATH_CC_FADE_SPEED 0.05f
|
||||
|
||||
|
||||
// The current client mode. Always ClientModeNormal in HL.
|
||||
static IClientMode *g_pClientMode[ MAX_SPLITSCREEN_PLAYERS ];
|
||||
IClientMode *GetClientMode()
|
||||
{
|
||||
ASSERT_LOCAL_PLAYER_RESOLVABLE();
|
||||
return g_pClientMode[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
|
||||
}
|
||||
//extern EHANDLE g_eKillTarget1;
|
||||
//extern EHANDLE g_eKillTarget2;
|
||||
|
||||
vgui::HScheme g_hVGuiCombineScheme = 0;
|
||||
|
||||
#define SCREEN_FILE "scripts/vgui_screens.txt"
|
||||
|
||||
// Voice data
|
||||
void VoxCallback( IConVar *var, const char *oldString, float oldFloat )
|
||||
{
|
||||
if ( engine && engine->IsConnected() )
|
||||
{
|
||||
ConVarRef voice_vox( var->GetName() );
|
||||
if ( voice_vox.GetBool() /*&& voice_modenable.GetBool()*/ )
|
||||
{
|
||||
engine->ClientCmd( "voicerecord_toggle on\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->ClientCmd( "voicerecord_toggle off\n" );
|
||||
}
|
||||
}
|
||||
}
|
||||
ConVar voice_vox( "voice_vox", "1", FCVAR_ARCHIVE, "Voice chat uses a vox-style always on", false, 0, true, 1, VoxCallback );
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
class CVoxManager : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CVoxManager() : CAutoGameSystem( "VoxManager" ) { }
|
||||
|
||||
virtual void LevelInitPostEntity( void )
|
||||
{
|
||||
if ( voice_vox.GetBool() /*&& voice_modenable.GetBool()*/ )
|
||||
{
|
||||
engine->ClientCmd( "voicerecord_toggle on\n" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void LevelShutdownPreEntity( void )
|
||||
{
|
||||
if ( voice_vox.GetBool() )
|
||||
{
|
||||
engine->ClientCmd( "voicerecord_toggle off\n" );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
static CVoxManager s_VoxManager;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: this is the viewport that contains all the hud elements
|
||||
//-----------------------------------------------------------------------------
|
||||
class CHudViewport : public CBaseViewport
|
||||
{
|
||||
private:
|
||||
DECLARE_CLASS_SIMPLE( CHudViewport, CBaseViewport );
|
||||
|
||||
protected:
|
||||
virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
|
||||
{
|
||||
BaseClass::ApplySchemeSettings( pScheme );
|
||||
|
||||
GetHud().InitColors( pScheme );
|
||||
|
||||
SetPaintBackgroundEnabled( false );
|
||||
}
|
||||
|
||||
virtual IViewPortPanel *CreatePanelByName( const char *szPanelName );
|
||||
};
|
||||
|
||||
IViewPortPanel* CHudViewport::CreatePanelByName( const char *szPanelName )
|
||||
{
|
||||
IViewPortPanel* newpanel = NULL;
|
||||
|
||||
if ( Q_strcmp( PANEL_SCOREBOARD, szPanelName) == 0 )
|
||||
{
|
||||
newpanel = new CPortalClientScoreBoardDialog( this );
|
||||
return newpanel;
|
||||
}
|
||||
else if ( Q_strcmp( PANEL_SURVEY, szPanelName) == 0 )
|
||||
{
|
||||
newpanel = new CSurveyPanel( this );
|
||||
return newpanel;
|
||||
}
|
||||
/*else if ( Q_strcmp(PANEL_INFO, szPanelName) == 0 )
|
||||
{
|
||||
newpanel = new CHL2MPTextWindow( this );
|
||||
return newpanel;
|
||||
}*/
|
||||
|
||||
return BaseClass::CreatePanelByName( szPanelName );
|
||||
}
|
||||
|
||||
|
||||
class CHLModeManager : public IVModeManager
|
||||
{
|
||||
public:
|
||||
CHLModeManager( void );
|
||||
virtual ~CHLModeManager( void );
|
||||
|
||||
virtual void Init( void );
|
||||
virtual void SwitchMode( bool commander, bool force );
|
||||
virtual void OverrideView( CViewSetup *pSetup );
|
||||
virtual void CreateMove( float flInputSampleTime, CUserCmd *cmd );
|
||||
virtual void LevelInit( const char *newmap );
|
||||
virtual void LevelShutdown( void );
|
||||
};
|
||||
|
||||
CHLModeManager::CHLModeManager( void )
|
||||
{
|
||||
}
|
||||
|
||||
CHLModeManager::~CHLModeManager( void )
|
||||
{
|
||||
}
|
||||
|
||||
void CHLModeManager::Init( void )
|
||||
{
|
||||
for( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
|
||||
{
|
||||
ACTIVE_SPLITSCREEN_PLAYER_GUARD( i );
|
||||
g_pClientMode[ i ] = GetClientModeNormal();
|
||||
}
|
||||
PanelMetaClassMgr()->LoadMetaClassDefinitionFile( SCREEN_FILE );
|
||||
}
|
||||
|
||||
void CHLModeManager::SwitchMode( bool commander, bool force )
|
||||
{
|
||||
}
|
||||
|
||||
void CHLModeManager::OverrideView( CViewSetup *pSetup )
|
||||
{
|
||||
}
|
||||
|
||||
void CHLModeManager::CreateMove( float flInputSampleTime, CUserCmd *cmd )
|
||||
{
|
||||
}
|
||||
|
||||
void CHLModeManager::LevelInit( const char *newmap )
|
||||
{
|
||||
for( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
|
||||
{
|
||||
ACTIVE_SPLITSCREEN_PLAYER_GUARD( i );
|
||||
GetClientMode()->LevelInit( newmap );
|
||||
}
|
||||
|
||||
if ( g_nKillCamMode > OBS_MODE_NONE )
|
||||
{
|
||||
g_bForceCLPredictOff = false;
|
||||
}
|
||||
|
||||
g_nKillCamMode = OBS_MODE_NONE;
|
||||
}
|
||||
|
||||
void CHLModeManager::LevelShutdown( void )
|
||||
{
|
||||
for( int i = 0; i < MAX_SPLITSCREEN_PLAYERS; ++i )
|
||||
{
|
||||
ACTIVE_SPLITSCREEN_PLAYER_GUARD( i );
|
||||
GetClientMode()->LevelShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
static void __MsgFunc_TransitionFade( bf_read &msg )
|
||||
{
|
||||
float flFadeTime = msg.ReadFloat();
|
||||
GetClientModePortalNormal()->StartTransitionFade( flFadeTime );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
ClientModePortalNormal::ClientModePortalNormal()
|
||||
{
|
||||
m_BlurFadeScale = 0;
|
||||
m_pRadialMenu = NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: If you don't know what a destructor is by now, you are probably going to get fired
|
||||
//-----------------------------------------------------------------------------
|
||||
ClientModePortalNormal::~ClientModePortalNormal()
|
||||
{
|
||||
}
|
||||
|
||||
void ClientModePortalNormal::Init()
|
||||
{
|
||||
BaseClass::Init();
|
||||
|
||||
HOOK_MESSAGE( TransitionFade );
|
||||
|
||||
InitRadialMenuHudElement();
|
||||
}
|
||||
|
||||
void ClientModePortalNormal::InitViewport()
|
||||
{
|
||||
m_pViewport = new CHudViewport();
|
||||
m_pViewport->Start( gameuifuncs, gameeventmanager );
|
||||
}
|
||||
|
||||
CEG_NOINLINE void ClientModePortalNormal::LevelInit( const char *newmap )
|
||||
{
|
||||
CEG_PROTECT_VIRTUAL_FUNCTION( ClientModePortalNormal_LevelInit );
|
||||
|
||||
// Load color correction lookup for the death effect
|
||||
/*
|
||||
m_CCDeathHandle = g_pColorCorrectionMgr->AddColorCorrection( DEATH_CC_LOOKUP_FILENAME );
|
||||
if ( m_CCDeathHandle != INVALID_CLIENT_CCHANDLE )
|
||||
{
|
||||
g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCDeathHandle, 0.0f );
|
||||
}
|
||||
m_flDeathCCWeight = 0.0f;
|
||||
*/
|
||||
|
||||
m_hCurrentColorCorrection = NULL;
|
||||
|
||||
m_BlurFadeScale = 0;
|
||||
|
||||
return BaseClass::LevelInit( newmap );
|
||||
}
|
||||
|
||||
void ClientModePortalNormal::LevelShutdown( void )
|
||||
{
|
||||
// g_pColorCorrectionMgr->RemoveColorCorrection( m_CCDeathHandle );
|
||||
// m_CCDeathHandle = INVALID_CLIENT_CCHANDLE;
|
||||
return BaseClass::LevelShutdown();
|
||||
}
|
||||
|
||||
void ClientModePortalNormal::OnColorCorrectionWeightsReset( void )
|
||||
{
|
||||
BaseClass::OnColorCorrectionWeightsReset();
|
||||
|
||||
C_Portal_Player *pPlayer = C_Portal_Player::GetLocalPortalPlayer();
|
||||
|
||||
/*
|
||||
// if the player is dead, fade in the death color correction
|
||||
if ( m_CCDeathHandle != INVALID_CLIENT_CCHANDLE && ( pPlayer != NULL ) )
|
||||
{
|
||||
if ( pPlayer->m_lifeState != LIFE_ALIVE )
|
||||
{
|
||||
if ( m_flDeathCCWeight < 1.0f )
|
||||
{
|
||||
m_flDeathCCWeight += DEATH_CC_FADE_SPEED;
|
||||
clamp( m_flDeathCCWeight, 0.0f, 1.0f );
|
||||
}
|
||||
|
||||
// Player is dead, fade out the environmental color correction
|
||||
if ( m_hCurrentColorCorrection )
|
||||
{
|
||||
m_hCurrentColorCorrection->EnableOnClient( false );
|
||||
m_hCurrentColorCorrection = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_flDeathCCWeight = 0.0f;
|
||||
}
|
||||
|
||||
g_pColorCorrectionMgr->SetColorCorrectionWeight( m_CCDeathHandle, m_flDeathCCWeight );
|
||||
}
|
||||
|
||||
// Only blend between environmental color corrections if there is no death-induced color correction
|
||||
if ( m_flDeathCCWeight == 0.0f )
|
||||
*/
|
||||
{
|
||||
C_ColorCorrection *pNewColorCorrection = pPlayer ? pPlayer->GetActiveColorCorrection() : NULL;
|
||||
C_ColorCorrection *pOldColorCorrection = m_hCurrentColorCorrection;
|
||||
|
||||
if ( pNewColorCorrection != pOldColorCorrection )
|
||||
{
|
||||
if ( pOldColorCorrection )
|
||||
{
|
||||
pOldColorCorrection->EnableOnClient( false );
|
||||
}
|
||||
if ( pNewColorCorrection )
|
||||
{
|
||||
pNewColorCorrection->EnableOnClient( true, pOldColorCorrection == NULL );
|
||||
}
|
||||
m_hCurrentColorCorrection = pNewColorCorrection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ClientModePortalNormal::ShouldDrawCrosshair( void )
|
||||
{
|
||||
// If we're using the radial menu, don't show the crosshair
|
||||
// if ( IsRadialMenuOpen() )
|
||||
// return false;
|
||||
|
||||
// See if a player is holding
|
||||
C_Portal_Player *pPlayer = C_Portal_Player::GetLocalPortalPlayer();
|
||||
if ( pPlayer && pPlayer->IsHoldingSomething() )
|
||||
return false;
|
||||
|
||||
return BaseClass::ShouldDrawCrosshair();
|
||||
}
|
||||
|
||||
void ClientModePortalNormal::SetBlurFade( float scale )
|
||||
{
|
||||
m_BlurFadeScale = scale;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
void ClientModePortalNormal::StartTransitionFade( float flFadeTime )
|
||||
{
|
||||
STEAMWORKS_SELFCHECK();
|
||||
|
||||
// Screen fade to black
|
||||
ScreenFade_t sf;
|
||||
memset( &sf, 0, sizeof( sf ) );
|
||||
sf.a = 255;
|
||||
sf.r = 0;
|
||||
sf.g = 0;
|
||||
sf.b = 0;
|
||||
sf.duration = (float)(1<<SCREENFADE_FRACBITS) * flFadeTime;
|
||||
sf.holdTime = 0.f;
|
||||
sf.fadeFlags = FFADE_OUT|FFADE_STAYOUT;
|
||||
GetViewEffects()->Fade( sf );
|
||||
|
||||
// Sound fade to zero
|
||||
engine->ClientCmd( CFmtStr( "soundfade 100 5 %f %f\n", flFadeTime, flFadeTime ) );
|
||||
}
|
||||
|
||||
extern ConVar building_cubemaps;
|
||||
void ClientModePortalNormal::DoPostScreenSpaceEffects( const CViewSetup *pSetup )
|
||||
{
|
||||
if ( building_cubemaps.GetBool() )
|
||||
return;
|
||||
|
||||
MDLCACHE_CRITICAL_SECTION();
|
||||
|
||||
g_GlowObjectManager.RenderGlowEffects( pSetup, GetSplitScreenPlayerSlot() );
|
||||
|
||||
if ( m_BlurFadeScale )
|
||||
{
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
|
||||
int xl, yl, dest_width, dest_height;
|
||||
pRenderContext->GetViewport( xl, yl, dest_width, dest_height );
|
||||
|
||||
DoBlurFade( m_BlurFadeScale, 1.0f, xl, yl, dest_width, dest_height );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ClientModePortalNormal::InitRadialMenuHudElement( void )
|
||||
{
|
||||
m_pRadialMenu = GET_HUDELEMENT( CRadialMenu );
|
||||
Assert( m_pRadialMenu );
|
||||
}
|
||||
|
||||
|
||||
int ClientModePortalNormal::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding )
|
||||
{
|
||||
/*if ( GetFullscreenClientMode() && GetFullscreenClientMode() != this &&
|
||||
!GetFullscreenClientMode()->HudElementKeyInput( down, keynum, pszCurrentBinding ) )
|
||||
return 0;*/
|
||||
|
||||
if ( m_pRadialMenu )
|
||||
{
|
||||
if ( !m_pRadialMenu->KeyInput( down, keynum, pszCurrentBinding ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Override the viewmodelfov for splitscreen support. This variable is set via the splitscreen_config.txt file.
|
||||
// FIXME: Use this method for all games? Are there other features that we need to support to use this?
|
||||
float ClientModePortalNormal::GetViewModelFOV( void )
|
||||
{
|
||||
return cl_viewmodelfov.GetFloat();
|
||||
}
|
||||
|
||||
ClientModePortalNormal g_ClientModeNormal[ MAX_SPLITSCREEN_PLAYERS ];
|
||||
|
||||
IClientMode *GetClientModeNormal()
|
||||
{
|
||||
ASSERT_LOCAL_PLAYER_RESOLVABLE();
|
||||
return &g_ClientModeNormal[ GET_ACTIVE_SPLITSCREEN_SLOT() ];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
class FullscreenPortalViewport : public CHudViewport
|
||||
{
|
||||
private:
|
||||
DECLARE_CLASS_SIMPLE( FullscreenPortalViewport, CHudViewport );
|
||||
|
||||
private:
|
||||
virtual void InitViewportSingletons( void )
|
||||
{
|
||||
SetAsFullscreenViewportInterface();
|
||||
}
|
||||
};
|
||||
|
||||
class ClientModePortalNormalFullscreen : public ClientModePortalNormal
|
||||
{
|
||||
DECLARE_CLASS_SIMPLE( ClientModePortalNormalFullscreen, ClientModePortalNormal );
|
||||
public:
|
||||
virtual void InitViewport()
|
||||
{
|
||||
// Skip over BaseClass!!!
|
||||
BaseClass::ClientModeShared::InitViewport();
|
||||
m_pViewport = new FullscreenPortalViewport();
|
||||
m_pViewport->Start( gameuifuncs, gameeventmanager );
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------------------------
|
||||
static ClientModePortalNormalFullscreen g_FullscreenClientMode;
|
||||
IClientMode *GetFullscreenClientMode( void )
|
||||
{
|
||||
return &g_FullscreenClientMode;
|
||||
}
|
||||
|
||||
ClientModePortalNormal* GetClientModePortalNormal()
|
||||
{
|
||||
Assert( dynamic_cast< ClientModePortalNormal* >( GetClientModeNormal() ) );
|
||||
|
||||
return static_cast< ClientModePortalNormal* >( GetClientModeNormal() );
|
||||
}
|
||||
|
||||
|
||||
static CHLModeManager g_HLModeManager;
|
||||
IVModeManager *modemanager = &g_HLModeManager;
|
||||
|
||||
73
game/client/portal/clientmode_portal.h
Normal file
73
game/client/portal/clientmode_portal.h
Normal file
@@ -0,0 +1,73 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef PORTAL_CLIENTMODE_H
|
||||
#define PORTAL_CLIENTMODE_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "clientmode_shared.h"
|
||||
#include <vgui_controls/EditablePanel.h>
|
||||
#include <vgui/Cursor.h>
|
||||
|
||||
class CHudViewport;
|
||||
class CRadialMenu;
|
||||
|
||||
namespace vgui
|
||||
{
|
||||
typedef unsigned long HScheme;
|
||||
}
|
||||
|
||||
class ClientModePortalNormal : public ClientModeShared
|
||||
{
|
||||
DECLARE_CLASS( ClientModePortalNormal, ClientModeShared );
|
||||
|
||||
private:
|
||||
|
||||
// IClientMode overrides.
|
||||
public:
|
||||
|
||||
ClientModePortalNormal();
|
||||
virtual ~ClientModePortalNormal();
|
||||
|
||||
virtual void Init();
|
||||
virtual void InitViewport();
|
||||
virtual void LevelInit( const char *newmap );
|
||||
virtual void LevelShutdown( void );
|
||||
virtual void SetBlurFade( float scale );
|
||||
virtual float GetBlurFade( void ) { return m_BlurFadeScale; }
|
||||
virtual void OnColorCorrectionWeightsReset( void );
|
||||
virtual float GetColorCorrectionScale( void ) const { return 1.0f; }
|
||||
virtual void InitWeaponSelectionHudElement( void ) { return; } // don't init this hud
|
||||
virtual bool ShouldDrawCrosshair( void );
|
||||
virtual void DoPostScreenSpaceEffects( const CViewSetup *pSetup );
|
||||
|
||||
virtual int HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding );
|
||||
void InitRadialMenuHudElement( void );
|
||||
|
||||
virtual float GetViewModelFOV( void );
|
||||
|
||||
void StartTransitionFade( float flFadeTime );
|
||||
private:
|
||||
|
||||
// void UpdateSpectatorMode( void );
|
||||
// ClientCCHandle_t m_CCDeathHandle; // handle to death cc effect
|
||||
// float m_flDeathCCWeight; // for fading in cc effect
|
||||
|
||||
CHandle<C_ColorCorrection> m_hCurrentColorCorrection;
|
||||
|
||||
float m_BlurFadeScale;
|
||||
|
||||
CRadialMenu *m_pRadialMenu;
|
||||
};
|
||||
|
||||
|
||||
extern IClientMode *GetClientModeNormal();
|
||||
extern ClientModePortalNormal* GetClientModePortalNormal();
|
||||
|
||||
|
||||
#endif // PORTAL_CLIENTMODE_H
|
||||
122
game/client/portal/materialproxy_portal_pickalphamask.cpp
Normal file
122
game/client/portal/materialproxy_portal_pickalphamask.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "materialsystem/IMaterialProxy.h"
|
||||
#include "materialsystem/IMaterialVar.h"
|
||||
#include "materialsystem/IMaterial.h"
|
||||
#include "materialsystem/ITexture.h"
|
||||
#include "c_prop_portal.h"
|
||||
#include <KeyValues.h>
|
||||
|
||||
#include "imaterialproxydict.h"
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class CPortalPickAlphaMaskProxy : public IMaterialProxy
|
||||
{
|
||||
private:
|
||||
IMaterialVar *m_AlphaMaskTextureOutput;
|
||||
IMaterialVar *m_AlphaMaskTextureFrame;
|
||||
ITexture *m_pOpeningTexture;
|
||||
ITexture *m_pIdleTexture;
|
||||
|
||||
public:
|
||||
CPortalPickAlphaMaskProxy( void );
|
||||
~CPortalPickAlphaMaskProxy( void );
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pBind );
|
||||
virtual void Release( void ) { delete this; }
|
||||
virtual IMaterial * GetMaterial()
|
||||
{
|
||||
if ( m_AlphaMaskTextureOutput )
|
||||
return m_AlphaMaskTextureOutput->GetOwningMaterial();
|
||||
if ( m_AlphaMaskTextureFrame )
|
||||
return m_AlphaMaskTextureFrame->GetOwningMaterial();
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
CPortalPickAlphaMaskProxy::CPortalPickAlphaMaskProxy( void )
|
||||
: m_pOpeningTexture( NULL ), m_pIdleTexture( NULL )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CPortalPickAlphaMaskProxy::~CPortalPickAlphaMaskProxy( void )
|
||||
{
|
||||
if( m_pOpeningTexture )
|
||||
{
|
||||
m_pOpeningTexture->DecrementReferenceCount();
|
||||
m_pOpeningTexture = NULL;
|
||||
}
|
||||
|
||||
if( m_pIdleTexture )
|
||||
{
|
||||
m_pIdleTexture->DecrementReferenceCount();
|
||||
m_pIdleTexture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CPortalPickAlphaMaskProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
char const* pszResultVar = pKeyValues->GetString( "maskTextureVar" );
|
||||
if( !pszResultVar )
|
||||
return false;
|
||||
|
||||
char const* pszFrameVar = pKeyValues->GetString( "maskFrameVar" );
|
||||
if( !pszFrameVar )
|
||||
return false;
|
||||
|
||||
char const* pszOpeningTextureInput = pKeyValues->GetString( "openingTexture" );
|
||||
if( !pszOpeningTextureInput )
|
||||
return false;
|
||||
|
||||
char const* pszIdleTextureInput = pKeyValues->GetString( "idleTexture" );
|
||||
if( !pszIdleTextureInput )
|
||||
return false;
|
||||
|
||||
bool foundVar;
|
||||
m_AlphaMaskTextureOutput = pMaterial->FindVar( pszResultVar, &foundVar, false );
|
||||
if( !foundVar )
|
||||
return false;
|
||||
|
||||
m_AlphaMaskTextureFrame = pMaterial->FindVar( pszFrameVar, &foundVar, false );
|
||||
if( !foundVar )
|
||||
return false;
|
||||
|
||||
|
||||
m_pOpeningTexture = materials->FindTexture( pszOpeningTextureInput, TEXTURE_GROUP_CLIENT_EFFECTS );
|
||||
m_pOpeningTexture->IncrementReferenceCount();
|
||||
m_pIdleTexture = materials->FindTexture( pszIdleTextureInput, TEXTURE_GROUP_CLIENT_EFFECTS );
|
||||
m_pIdleTexture->IncrementReferenceCount();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPortalPickAlphaMaskProxy::OnBind( void *pBind )
|
||||
{
|
||||
if( pBind == NULL )
|
||||
return;
|
||||
|
||||
IClientRenderable *pRenderable = (IClientRenderable*)( pBind );
|
||||
|
||||
C_Prop_Portal *pFlatBasic = dynamic_cast<C_Prop_Portal*>( pRenderable );
|
||||
|
||||
if ( !pFlatBasic )
|
||||
return;
|
||||
|
||||
if( pFlatBasic->m_fOpenAmount == 1.0f )
|
||||
{
|
||||
m_AlphaMaskTextureOutput->SetTextureValue( m_pIdleTexture );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_AlphaMaskTextureOutput->SetTextureValue( m_pOpeningTexture );
|
||||
m_AlphaMaskTextureFrame->SetIntValue( pFlatBasic->m_fOpenAmount * m_pOpeningTexture->GetNumAnimationFrames() );
|
||||
}
|
||||
}
|
||||
|
||||
EXPOSE_MATERIAL_PROXY( CPortalPickAlphaMaskProxy, PortalPickAlphaMask );
|
||||
122
game/client/portal/materialproxy_portalstatic.cpp
Normal file
122
game/client/portal/materialproxy_portalstatic.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
#include "cbase.h"
|
||||
#include "materialsystem/IMaterialProxy.h"
|
||||
#include "materialsystem/IMaterialVar.h"
|
||||
#include "materialsystem/IMaterial.h"
|
||||
#include "portalrenderable_flatbasic.h"
|
||||
#include "c_prop_portal.h"
|
||||
#include <KeyValues.h>
|
||||
|
||||
#include "imaterialproxydict.h"
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
class CPortalStaticProxy : public IMaterialProxy
|
||||
{
|
||||
protected:
|
||||
IMaterialVar *m_StaticOutput;
|
||||
public:
|
||||
virtual bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||||
virtual void OnBind( void *pBind );
|
||||
virtual void Release( void ) { delete this; }
|
||||
|
||||
virtual IMaterial * GetMaterial() { return ( m_StaticOutput ) ? m_StaticOutput->GetOwningMaterial() : NULL; }
|
||||
};
|
||||
|
||||
bool CPortalStaticProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||||
{
|
||||
char const* pszResultVar = pKeyValues->GetString( "resultVar" );
|
||||
if( !pszResultVar )
|
||||
return false;
|
||||
|
||||
bool foundVar;
|
||||
m_StaticOutput = pMaterial->FindVar( pszResultVar, &foundVar, false );
|
||||
if( !foundVar )
|
||||
return false;
|
||||
|
||||
if ( !Q_stricmp( pszResultVar, "$alpha" ) )
|
||||
{
|
||||
pMaterial->SetMaterialVarFlag( MATERIAL_VAR_ALPHA_MODIFIED_BY_PROXY, true );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPortalStaticProxy::OnBind( void *pBind )
|
||||
{
|
||||
if ( pBind == NULL )
|
||||
return;
|
||||
|
||||
float flStaticAmount;
|
||||
IClientRenderable *pRenderable = (IClientRenderable*)pBind;
|
||||
CPortalRenderable *pRecordedPortal = g_pPortalRender->FindRecordedPortal( pRenderable );
|
||||
|
||||
if ( pRecordedPortal )
|
||||
{
|
||||
C_Prop_Portal *pRecordedFlatBasic = dynamic_cast<C_Prop_Portal *>(pRecordedPortal);
|
||||
if ( !pRecordedFlatBasic )
|
||||
return;
|
||||
|
||||
flStaticAmount = pRecordedFlatBasic->ComputeStaticAmountForRendering();
|
||||
}
|
||||
else
|
||||
{
|
||||
C_Prop_Portal *pFlatBasic = dynamic_cast<C_Prop_Portal*>( pRenderable );
|
||||
if ( !pFlatBasic )
|
||||
return;
|
||||
|
||||
flStaticAmount = pFlatBasic->ComputeStaticAmountForRendering();
|
||||
}
|
||||
|
||||
m_StaticOutput->SetFloatValue( flStaticAmount );
|
||||
}
|
||||
|
||||
EXPOSE_MATERIAL_PROXY( CPortalStaticProxy, PortalStaticModel );
|
||||
|
||||
|
||||
class CPortalStaticPortalProxy : public CPortalStaticProxy
|
||||
{
|
||||
public:
|
||||
virtual void OnBind( void *pBind );
|
||||
};
|
||||
|
||||
void CPortalStaticPortalProxy::OnBind( void *pBind )
|
||||
{
|
||||
if ( pBind == NULL )
|
||||
return;
|
||||
|
||||
IClientRenderable *pRenderable = (IClientRenderable*)( pBind );
|
||||
C_Prop_Portal *pPortal = (C_Prop_Portal *)pRenderable;
|
||||
|
||||
float flStaticAmount = pPortal->ComputeStaticAmountForRendering();
|
||||
m_StaticOutput->SetFloatValue( flStaticAmount );
|
||||
}
|
||||
|
||||
EXPOSE_MATERIAL_PROXY( CPortalStaticPortalProxy, PortalStatic );
|
||||
|
||||
|
||||
class CPortalOpenAmountProxy : public CPortalStaticProxy
|
||||
{
|
||||
public:
|
||||
virtual void OnBind( void *pBind );
|
||||
};
|
||||
|
||||
void CPortalOpenAmountProxy::OnBind( void *pBind )
|
||||
{
|
||||
if ( pBind == NULL )
|
||||
return;
|
||||
|
||||
IClientRenderable *pRenderable = (IClientRenderable*)( pBind );
|
||||
C_Prop_Portal *pPortal = (C_Prop_Portal *)pRenderable;
|
||||
|
||||
m_StaticOutput->SetFloatValue( pPortal->m_fOpenAmount );
|
||||
}
|
||||
|
||||
EXPOSE_MATERIAL_PROXY( CPortalOpenAmountProxy, PortalOpenAmount );
|
||||
|
||||
|
||||
279
game/client/portal/portal_dynamicmeshrenderingutils.cpp
Normal file
279
game/client/portal/portal_dynamicmeshrenderingutils.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "Portal_DynamicMeshRenderingUtils.h"
|
||||
#include "iviewrender.h"
|
||||
|
||||
extern ConVar mat_wireframe;
|
||||
|
||||
|
||||
int ClipPolyToPlane_LerpTexCoords( PortalMeshPoint_t *inVerts, int vertCount, PortalMeshPoint_t *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon )
|
||||
{
|
||||
vec_t *dists = (vec_t *)stackalloc( sizeof(vec_t) * vertCount * 4 ); //4x vertcount should cover all cases
|
||||
int *sides = (int *)stackalloc( sizeof(int) * vertCount * 4 );
|
||||
int counts[3];
|
||||
vec_t dot;
|
||||
int i, j;
|
||||
Vector mid = vec3_origin;
|
||||
int outCount;
|
||||
|
||||
counts[0] = counts[1] = counts[2] = 0;
|
||||
|
||||
// determine sides for each point
|
||||
for ( i = 0; i < vertCount; i++ )
|
||||
{
|
||||
dot = DotProduct( inVerts[i].vWorldSpacePosition, normal) - dist;
|
||||
dists[i] = dot;
|
||||
if ( dot > fOnPlaneEpsilon )
|
||||
sides[i] = SIDE_FRONT;
|
||||
else if ( dot < -fOnPlaneEpsilon )
|
||||
sides[i] = SIDE_BACK;
|
||||
else
|
||||
sides[i] = SIDE_ON;
|
||||
counts[sides[i]]++;
|
||||
}
|
||||
sides[i] = sides[0];
|
||||
dists[i] = dists[0];
|
||||
|
||||
if (!counts[0])
|
||||
return 0;
|
||||
|
||||
if (!counts[1])
|
||||
{
|
||||
// Copy to output verts
|
||||
//for ( i = 0; i < vertCount; i++ )
|
||||
memcpy( outVerts, inVerts, sizeof( PortalMeshPoint_t ) * vertCount );
|
||||
return vertCount;
|
||||
}
|
||||
|
||||
outCount = 0;
|
||||
for ( i = 0; i < vertCount; i++ )
|
||||
{
|
||||
if (sides[i] == SIDE_ON)
|
||||
{
|
||||
memcpy( &outVerts[outCount], &inVerts[i], sizeof( PortalMeshPoint_t ) );
|
||||
++outCount;
|
||||
continue;
|
||||
}
|
||||
if (sides[i] == SIDE_FRONT)
|
||||
{
|
||||
memcpy( &outVerts[outCount], &inVerts[i], sizeof( PortalMeshPoint_t ) );
|
||||
++outCount;
|
||||
}
|
||||
if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
|
||||
continue;
|
||||
|
||||
Vector& p1 = inVerts[i].vWorldSpacePosition;
|
||||
|
||||
|
||||
// generate a split point
|
||||
int i2 = (i+1)%vertCount;
|
||||
Vector& p2 = inVerts[i2].vWorldSpacePosition;
|
||||
|
||||
dot = dists[i] / (dists[i]-dists[i+1]);
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
mid[j] = p1[j] + dot*(p2[j]-p1[j]);
|
||||
}
|
||||
|
||||
VectorCopy (mid, outVerts[outCount].vWorldSpacePosition);
|
||||
|
||||
outVerts[outCount].texCoord.x = inVerts[i].texCoord.x + dot*(inVerts[i2].texCoord.x - inVerts[i].texCoord.x);
|
||||
outVerts[outCount].texCoord.y = inVerts[i].texCoord.y + dot*(inVerts[i2].texCoord.y - inVerts[i].texCoord.y);
|
||||
|
||||
++outCount;
|
||||
}
|
||||
|
||||
return outCount;
|
||||
}
|
||||
|
||||
// Returns true if clipping took place.
|
||||
// Outputs two polygons: One for each side of the plane
|
||||
void ProjectPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
|
||||
const Vector& normal, float flDist, const Vector &vCameraPos )
|
||||
{
|
||||
for ( int i = 0; i < nVertCount; i++ )
|
||||
{
|
||||
// project point onto plane
|
||||
Vector vDir( pInVerts[i].vWorldSpacePosition - vCameraPos );
|
||||
float flT = ( flDist - DotProduct( vCameraPos, normal ) ) / DotProduct( vDir, normal );
|
||||
pInVerts[i].vWorldSpacePosition = vCameraPos + flT * vDir;
|
||||
|
||||
/*
|
||||
double dirx, diry, dirz;
|
||||
dirx = pInVerts[i].vWorldSpacePosition.x - vCameraPos.x;
|
||||
diry = pInVerts[i].vWorldSpacePosition.y - vCameraPos.y;
|
||||
dirz = pInVerts[i].vWorldSpacePosition.z - vCameraPos.z;
|
||||
double dot1 = vCameraPos.x * normal.x + vCameraPos.y * normal.y + vCameraPos.z * normal.z;
|
||||
double dot2 = dirx * normal.x + diry * normal.y + dirz * normal.z;
|
||||
double flT2 = ( double( flDist ) - dot1 ) / dot2;
|
||||
pInVerts[i].vWorldSpacePosition.x = double( vCameraPos.x ) + flT2 * dirx;
|
||||
pInVerts[i].vWorldSpacePosition.y = double( vCameraPos.y ) + flT2 * diry;
|
||||
pInVerts[i].vWorldSpacePosition.z = double( vCameraPos.z ) + flT2 * dirz;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// Clips a convex poly to a single plane
|
||||
bool ClipPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
|
||||
PortalMeshPoint_t *pFrontVerts, int *pFrontVertCount,
|
||||
const Vector& normal, float flDist )
|
||||
{
|
||||
if ( nVertCount < 3 )
|
||||
{
|
||||
*pFrontVertCount = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
float *dists = (float *)stackalloc( sizeof(float) * nVertCount );
|
||||
int *sides = (int *)stackalloc( sizeof(int) * nVertCount );
|
||||
int count[2] = { 0, 0 };
|
||||
|
||||
// determine sides for each point
|
||||
for ( int i = 0; i < nVertCount; i++ )
|
||||
{
|
||||
float dot = DotProduct( pInVerts[i].vWorldSpacePosition, normal) - flDist;
|
||||
dists[i] = dot;
|
||||
sides[i] = ( dot >= 0.0f ) ? SIDE_FRONT : SIDE_BACK;
|
||||
count[ sides[i] ]++;
|
||||
}
|
||||
|
||||
// no need to clip anything
|
||||
if ( count[0] == 0 )
|
||||
{
|
||||
*pFrontVertCount = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int outCount1 = 0;
|
||||
for ( int i = 0; i < nVertCount; i++ )
|
||||
{
|
||||
int i2 = ( i + 1 ) % nVertCount;
|
||||
|
||||
if ( sides[i] == SIDE_FRONT )
|
||||
{
|
||||
memcpy( &pFrontVerts[outCount1], &pInVerts[i], sizeof( PortalMeshPoint_t ) );
|
||||
++outCount1;
|
||||
|
||||
}
|
||||
if ( sides[i2] == sides[i] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// generate a split point
|
||||
float dot = dists[i] / ( dists[i] - dists[i2] );
|
||||
|
||||
Vector& p1 = pInVerts[i].vWorldSpacePosition;
|
||||
Vector& p2 = pInVerts[i2].vWorldSpacePosition;
|
||||
Vector midPt = p1 + dot * ( p2 - p1 );
|
||||
|
||||
Vector2D& uv1 = pInVerts[i].texCoord;
|
||||
Vector2D& uv2 = pInVerts[i2].texCoord;
|
||||
Vector2D midUv = uv1 + dot * ( uv2 - uv1 );
|
||||
|
||||
VectorCopy( midPt, pFrontVerts[outCount1].vWorldSpacePosition );
|
||||
pFrontVerts[outCount1].texCoord = midUv;
|
||||
|
||||
++outCount1;
|
||||
}
|
||||
|
||||
*pFrontVertCount = outCount1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RenderPortalMeshConvexPolygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind )
|
||||
{
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
pRenderContext->Bind( (IMaterial *)pMaterial, pBind );
|
||||
|
||||
//PortalMeshPoint_t *pMidVerts = (PortalMeshPoint_t *)stackalloc( sizeof( PortalMeshPoint_t ) * iVertCount );
|
||||
|
||||
CMeshBuilder meshBuilder;
|
||||
IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
|
||||
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, iVertCount - 2 );
|
||||
|
||||
//any convex polygon can be rendered with a triangle strip by starting at a vertex and alternating vertices from each side
|
||||
int iForwardCounter = 0;
|
||||
int iReverseCounter = iVertCount - 1; //guaranteed to be >= 2 to start
|
||||
|
||||
do
|
||||
{
|
||||
PortalMeshPoint_t *pVertex = &pVerts[iForwardCounter];
|
||||
meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x );
|
||||
meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x );
|
||||
meshBuilder.AdvanceVertex();
|
||||
++iForwardCounter;
|
||||
|
||||
if( iForwardCounter > iReverseCounter )
|
||||
break;
|
||||
|
||||
pVertex = &pVerts[iReverseCounter];
|
||||
meshBuilder.Position3fv( &pVertex->vWorldSpacePosition.x );
|
||||
meshBuilder.TexCoord2fv( 0, &pVertex->texCoord.x );
|
||||
meshBuilder.AdvanceVertex();
|
||||
--iReverseCounter;
|
||||
} while( iForwardCounter <= iReverseCounter );
|
||||
|
||||
meshBuilder.End();
|
||||
pMesh->Draw();
|
||||
}
|
||||
|
||||
|
||||
void Clip_And_Render_Convex_Polygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind )
|
||||
{
|
||||
PortalMeshPoint_t *pInVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) ); //really only should need 2x points, but I'm paranoid
|
||||
PortalMeshPoint_t *pOutVerts = (PortalMeshPoint_t *)stackalloc( iVertCount * 4 * sizeof( PortalMeshPoint_t ) );
|
||||
PortalMeshPoint_t *pTempVerts;
|
||||
|
||||
|
||||
//clip by the viewing frustum
|
||||
{
|
||||
VPlane *pFrustum = view->GetFrustum();
|
||||
|
||||
//clip by first plane and put output into pInVerts
|
||||
iVertCount = ClipPolyToPlane_LerpTexCoords( pVerts, iVertCount, pInVerts, pFrustum[0].m_Normal, pFrustum[0].m_Dist, 0.01f );
|
||||
|
||||
//clip by other planes and flipflop in and out pointers
|
||||
for( int i = 1; i != FRUSTUM_NUMPLANES; ++i )
|
||||
{
|
||||
if( iVertCount < 3 )
|
||||
return; //nothing to draw
|
||||
|
||||
iVertCount = ClipPolyToPlane_LerpTexCoords( pInVerts, iVertCount, pOutVerts, pFrustum[i].m_Normal, pFrustum[i].m_Dist, 0.01f );
|
||||
pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
|
||||
}
|
||||
|
||||
if( iVertCount < 3 )
|
||||
return; //nothing to draw
|
||||
}
|
||||
|
||||
CMatRenderContextPtr pRenderContext( materials );
|
||||
|
||||
RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, pMaterial, pBind );
|
||||
if( mat_wireframe.GetBool() )
|
||||
RenderPortalMeshConvexPolygon( pOutVerts, iVertCount, materials->FindMaterial( "shadertest/wireframe", TEXTURE_GROUP_CLIENT_EFFECTS, false ), pBind );
|
||||
|
||||
stackfree( pOutVerts );
|
||||
stackfree( pInVerts );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
38
game/client/portal/portal_dynamicmeshrenderingutils.h
Normal file
38
game/client/portal/portal_dynamicmeshrenderingutils.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef PORTAL_DYNAMICMESHRENDERINGUTILS_H
|
||||
#define PORTAL_DYNAMICMESHRENDERINGUTILS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "materialsystem/IMaterial.h"
|
||||
#include "mathlib/mathlib.h"
|
||||
#include "portalrender.h"
|
||||
|
||||
struct PortalMeshPoint_t
|
||||
{
|
||||
Vector vWorldSpacePosition;
|
||||
Vector2D texCoord;
|
||||
};
|
||||
|
||||
int ClipPolyToPlane_LerpTexCoords( PortalMeshPoint_t *inVerts, int vertCount, PortalMeshPoint_t *outVerts, const Vector& normal, float dist, float fOnPlaneEpsilon );
|
||||
void RenderPortalMeshConvexPolygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind );
|
||||
|
||||
void Clip_And_Render_Convex_Polygon( PortalMeshPoint_t *pVerts, int iVertCount, const IMaterial *pMaterial, void *pBind );
|
||||
|
||||
bool ClipPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
|
||||
PortalMeshPoint_t *pFrontVerts, int *pFrontVertCount,
|
||||
const Vector& normal, float flDist );
|
||||
|
||||
void ProjectPortalPolyToPlane( PortalMeshPoint_t *pInVerts, int nVertCount,
|
||||
const Vector& normal, float flDist, const Vector &vCameraPos );
|
||||
|
||||
#endif //#ifndef PORTAL_DYNAMICMESHRENDERINGUTILS_H
|
||||
|
||||
190
game/client/portal/portal_render_targets.cpp
Normal file
190
game/client/portal/portal_render_targets.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
//========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Portal mod render targets are specified by and accessable through this singleton
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "portal_render_targets.h"
|
||||
#include "materialsystem/imaterialsystem.h"
|
||||
#include "rendertexture.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called in CClientRenderTargets::InitClientRenderTargets, used to set
|
||||
// the CTextureReference member
|
||||
// Input : pMaterialSystem - material system passed in from the engine
|
||||
// Output : ITexture* - the created texture
|
||||
//-----------------------------------------------------------------------------
|
||||
ITexture* CPortalRenderTargets::InitPortal1Texture( IMaterialSystem* pMaterialSystem )
|
||||
{
|
||||
if ( IsGameConsole() )
|
||||
{
|
||||
// shouldn't be using
|
||||
Assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pMaterialSystem->CreateNamedRenderTargetTextureEx2(
|
||||
"_rt_Portal1",
|
||||
1, 1, RT_SIZE_FULL_FRAME_BUFFER,
|
||||
pMaterialSystem->GetBackBufferFormat(),
|
||||
MATERIAL_RT_DEPTH_SHARED,
|
||||
0,
|
||||
CREATERENDERTARGETFLAGS_HDR );
|
||||
}
|
||||
|
||||
ITexture* CPortalRenderTargets::GetPortal1Texture()
|
||||
{
|
||||
return m_Portal1Texture;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called in CClientRenderTargets::InitClientRenderTargets, used to set
|
||||
// the CTextureReference member
|
||||
// Input : pMaterialSystem - material system passed in from the engine
|
||||
// Output : ITexture* - the created texture
|
||||
//-----------------------------------------------------------------------------
|
||||
ITexture* CPortalRenderTargets::InitPortal2Texture( IMaterialSystem* pMaterialSystem )
|
||||
{
|
||||
if ( IsGameConsole() )
|
||||
{
|
||||
// shouldn't be using
|
||||
Assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pMaterialSystem->CreateNamedRenderTargetTextureEx2(
|
||||
"_rt_Portal2",
|
||||
1, 1, RT_SIZE_FULL_FRAME_BUFFER,
|
||||
pMaterialSystem->GetBackBufferFormat(),
|
||||
MATERIAL_RT_DEPTH_SHARED,
|
||||
0,
|
||||
CREATERENDERTARGETFLAGS_HDR );
|
||||
}
|
||||
|
||||
ITexture* CPortalRenderTargets::GetPortal2Texture()
|
||||
{
|
||||
return m_Portal2Texture;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called in CClientRenderTargets::InitClientRenderTargets, used to set
|
||||
// the CTextureReference member
|
||||
// Input : pMaterialSystem - material system passed in from the engine
|
||||
// Output : ITexture* - the created texture
|
||||
//-----------------------------------------------------------------------------
|
||||
ITexture* CPortalRenderTargets::InitDepthDoublerTexture( IMaterialSystem* pMaterialSystem )
|
||||
{
|
||||
return pMaterialSystem->CreateNamedRenderTargetTextureEx2(
|
||||
"_rt_DepthDoubler",
|
||||
1, 1, RT_SIZE_FULL_FRAME_BUFFER,
|
||||
pMaterialSystem->GetBackBufferFormat(),
|
||||
MATERIAL_RT_DEPTH_SHARED,
|
||||
0,
|
||||
CREATERENDERTARGETFLAGS_HDR | (IsX360() ? CREATERENDERTARGETFLAGS_NOEDRAM : 0) );
|
||||
}
|
||||
|
||||
ITexture* CPortalRenderTargets::GetDepthDoublerTexture()
|
||||
{
|
||||
return m_DepthDoublerTexture;
|
||||
}
|
||||
|
||||
|
||||
void CPortalRenderTargets::InitPortalWaterTextures( IMaterialSystem* pMaterialSystem )
|
||||
{
|
||||
// This code does not work on ATI or newer nVidia chips (probably an issue with mismatched depth buffer configuration?) -- disabling it for now
|
||||
// since we probably don't need it to ship either (first 2 levels use full res buffer, 3rd level uses cheap water, low end PC will just
|
||||
// use cheap water everywhere)
|
||||
#if 0
|
||||
if( !IsGameConsole() )
|
||||
{
|
||||
//Reflections
|
||||
GetWaterReflectionTexture()->AddDownsizedSubTarget( GetSubTargetNameForPortalRecursionLevel( 1 ), 2, MATERIAL_RT_DEPTH_SEPARATE );
|
||||
GetWaterReflectionTexture()->AddDownsizedSubTarget( GetSubTargetNameForPortalRecursionLevel( 2 ), 4, MATERIAL_RT_DEPTH_SEPARATE );
|
||||
|
||||
//Refractions
|
||||
GetWaterRefractionTexture()->AddDownsizedSubTarget( GetSubTargetNameForPortalRecursionLevel( 1 ), 2, MATERIAL_RT_DEPTH_SEPARATE );
|
||||
GetWaterRefractionTexture()->AddDownsizedSubTarget( GetSubTargetNameForPortalRecursionLevel( 2 ), 4, MATERIAL_RT_DEPTH_SEPARATE );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: InitClientRenderTargets, interface called by the engine at material system init in the engine
|
||||
// Input : pMaterialSystem - the interface to the material system from the engine (our singleton hasn't been set up yet)
|
||||
// pHardwareConfig - the user's hardware config, useful for conditional render targets setup
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPortalRenderTargets::InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig )
|
||||
{
|
||||
static ConVarRef gpu_level( "gpu_level" );
|
||||
int nWaterRenderTargetResolution = 512;
|
||||
|
||||
// If we're at a decent GPU level, check back buffer dimensions and increase water texture resolution accordingly
|
||||
if ( !IsGameConsole() && ( gpu_level.GetInt() > 1 ) )
|
||||
{
|
||||
int nWidth, nHeight;
|
||||
pMaterialSystem->GetBackBufferDimensions( nWidth, nHeight );
|
||||
|
||||
if ( nHeight >= 1024 )
|
||||
{
|
||||
nWaterRenderTargetResolution = 1024;
|
||||
}
|
||||
}
|
||||
|
||||
// Water effects & camera from the base class (standard HL2 targets)
|
||||
BaseClass::SetupClientRenderTargets( pMaterialSystem, pHardwareConfig, nWaterRenderTargetResolution, 256 );
|
||||
|
||||
// If they don't support stencils, allocate render targets for drawing portals.
|
||||
// TODO: When stencils are default, do the below check before bothering to allocate the RTs
|
||||
// and make sure that switching from Stencil<->RT mode reinits the material system.
|
||||
// if ( materials->StencilBufferBits() == 0 )
|
||||
if ( IsPC() || !IsGameConsole() )
|
||||
{
|
||||
m_Portal1Texture.Init( InitPortal1Texture( pMaterialSystem ) );
|
||||
m_Portal2Texture.Init( InitPortal2Texture( pMaterialSystem ) );
|
||||
}
|
||||
|
||||
m_DepthDoublerTexture.Init( InitDepthDoublerTexture( pMaterialSystem ) );
|
||||
|
||||
//if ( IsPC() || !IsGameConsole() )
|
||||
{
|
||||
InitPortalWaterTextures( pMaterialSystem );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Shutdown client render targets. This gets called during shutdown in the engine
|
||||
// Input : -
|
||||
//-----------------------------------------------------------------------------
|
||||
void CPortalRenderTargets::ShutdownClientRenderTargets()
|
||||
{
|
||||
m_Portal1Texture.Shutdown();
|
||||
m_Portal2Texture.Shutdown();
|
||||
m_DepthDoublerTexture.Shutdown();
|
||||
|
||||
|
||||
// Clean up standard HL2 RTs (camera and water)
|
||||
BaseClass::ShutdownClientRenderTargets();
|
||||
}
|
||||
|
||||
const char *GetSubTargetNameForPortalRecursionLevel( int iRecursionLevel )
|
||||
{
|
||||
switch( iRecursionLevel )
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
return NULL;
|
||||
case 1:
|
||||
return "Depth_1";
|
||||
case 2:
|
||||
return "Depth_2";
|
||||
}
|
||||
}
|
||||
|
||||
static CPortalRenderTargets g_PortalRenderTargets;
|
||||
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CPortalRenderTargets, IClientRenderTargets, CLIENTRENDERTARGETS_INTERFACE_VERSION, g_PortalRenderTargets );
|
||||
CPortalRenderTargets* portalrendertargets = &g_PortalRenderTargets;
|
||||
58
game/client/portal/portal_render_targets.h
Normal file
58
game/client/portal/portal_render_targets.h
Normal file
@@ -0,0 +1,58 @@
|
||||
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Portal mod render targets are specified by and accessable through this singleton
|
||||
//
|
||||
//
|
||||
// $Workfile: $
|
||||
// $Date: $
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#ifndef PORTALRENDERTARGETS_H_
|
||||
#define PORTALRENDERTARGETS_H_
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "baseclientrendertargets.h" // Base class, with interfaces called by engine and inherited members to init common render targets
|
||||
|
||||
#ifndef PORTAL
|
||||
#pragma message ( "This file should only be built with portal builds" )
|
||||
#endif
|
||||
|
||||
// externs
|
||||
class IMaterialSystem;
|
||||
class IMaterialSystemHardwareConfig;
|
||||
|
||||
class CPortalRenderTargets : public CBaseClientRenderTargets
|
||||
{
|
||||
// no networked vars
|
||||
DECLARE_CLASS_GAMEROOT( CPortalRenderTargets, CBaseClientRenderTargets );
|
||||
public:
|
||||
virtual void InitClientRenderTargets( IMaterialSystem* pMaterialSystem, IMaterialSystemHardwareConfig* pHardwareConfig );
|
||||
virtual void ShutdownClientRenderTargets();
|
||||
|
||||
ITexture* GetPortal1Texture( void );
|
||||
ITexture* GetPortal2Texture( void );
|
||||
ITexture* GetDepthDoublerTexture( void );
|
||||
|
||||
//recursive views require different water textures
|
||||
|
||||
private:
|
||||
CTextureReference m_Portal1Texture;
|
||||
CTextureReference m_Portal2Texture;
|
||||
CTextureReference m_DepthDoublerTexture;
|
||||
|
||||
|
||||
ITexture* InitPortal1Texture ( IMaterialSystem* pMaterialSystem );
|
||||
ITexture* InitPortal2Texture ( IMaterialSystem* pMaterialSystem );
|
||||
ITexture* InitDepthDoublerTexture ( IMaterialSystem* pMaterialSystem );
|
||||
|
||||
void InitPortalWaterTextures ( IMaterialSystem* pMaterialSystem );
|
||||
|
||||
};
|
||||
|
||||
extern CPortalRenderTargets* portalrendertargets;
|
||||
|
||||
const char *GetSubTargetNameForPortalRecursionLevel( int iRecursionLevel );
|
||||
|
||||
#endif //PORTALRENDERTARGETS_H_
|
||||
2113
game/client/portal/portalrender.cpp
Normal file
2113
game/client/portal/portalrender.cpp
Normal file
File diff suppressed because it is too large
Load Diff
375
game/client/portal/portalrender.h
Normal file
375
game/client/portal/portalrender.h
Normal file
@@ -0,0 +1,375 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef PORTALRENDER_H
|
||||
#define PORTALRENDER_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "iviewrender.h"
|
||||
#include "view_shared.h"
|
||||
#include "viewrender.h"
|
||||
#include "shaderapi/ishaderapi.h"
|
||||
|
||||
#define MAX_PORTAL_RECURSIVE_VIEWS 11 //maximum number of recursions we allow when drawing views through portals. Seeing as how 5 is extremely choppy under best conditions and is barely visible, 10 is a safe limit. Adding one because 0 tends to be the primary view in most arrays of this size
|
||||
|
||||
class C_Prop_Portal;
|
||||
|
||||
class CPortalRenderable
|
||||
{
|
||||
public:
|
||||
CPortalRenderable( void );
|
||||
virtual ~CPortalRenderable( void );
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//Stencil-based drawing helpers, these are ONLY used in stencil drawing mode
|
||||
//----------------------------------------------------------------------------
|
||||
virtual void DrawPreStencilMask( IMatRenderContext *pRenderContext ) { }; //Do whatever drawing you need before cutting the stencil hole
|
||||
virtual void DrawStencilMask( IMatRenderContext *pRenderContext ) { }; //Draw to wherever you should see through the portal. The mask will later be filled with the portal view.
|
||||
virtual void DrawPostStencilFixes( IMatRenderContext *pRenderContext ) { }; //After done drawing to the portal mask, we need to fix the depth buffer as well as fog. So draw your mesh again, writing to z and with the fog color alpha'd in by distance
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//Rendering of views beyond the portal
|
||||
//----------------------------------------------------------------------------
|
||||
virtual void RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView ) { };
|
||||
virtual void RenderPortalViewToTexture( CViewRender *pViewRender, const CViewSetup &cameraView ) { };
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//Visibility through portals
|
||||
//----------------------------------------------------------------------------
|
||||
virtual bool DoesExitViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const { return false; };
|
||||
virtual SkyboxVisibility_t SkyBoxVisibleFromPortal( void ) { return SKYBOX_NOT_VISIBLE; };
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//Fog workarounds
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual const Vector& GetFogOrigin( void ) const { return vec3_origin; };
|
||||
virtual void ShiftFogForExitPortalView() const;
|
||||
virtual float GetPortalDistanceBias() const { return 0.0f; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//Portal visibility testing
|
||||
//-----------------------------------------------------------------------------
|
||||
//Based on view, will the camera be able to see through the portal this frame? This will allow the stencil mask to start being tested for pixel visibility.
|
||||
virtual bool ShouldUpdatePortalView_BasedOnView( const CViewSetup ¤tView, const CUtlVector<VPlane> ¤tComplexFrustum ) { return false; };
|
||||
|
||||
//Stencil mode only: You stated the portal was visible based on view, and this is how much of the screen your stencil mask took up last frame. Still want to draw this frame? Values less than zero indicate a lack of data from last frame
|
||||
virtual bool ShouldUpdatePortalView_BasedOnPixelVisibility( float fScreenFilledByStencilMaskLastFrame_Normalized ) { return (fScreenFilledByStencilMaskLastFrame_Normalized != 0.0f); }; // < 0 is unknown visibility, > 0 is known to be partially visible
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Misc
|
||||
//-----------------------------------------------------------------------------
|
||||
virtual CPortalRenderable* GetLinkedPortal() const { return NULL; };
|
||||
const VMatrix& MatrixThisToLinked() const;
|
||||
virtual bool ShouldUpdateDepthDoublerTexture( const CViewSetup &viewSetup ) { return false; };
|
||||
virtual void DrawPortal( IMatRenderContext *pRenderContext ) { }; //sort of like what you'd expect to happen in C_BaseAnimating::DrawModel() if portals were fully compatible with models
|
||||
virtual int BindPortalMaterial( IMatRenderContext *pRenderContext, int nPassIndex, bool *pAllowRingMeshOptimizationOut ) { Assert( 0 ); return 0; }
|
||||
|
||||
virtual C_BaseEntity *PortalRenderable_GetPairedEntity( void ) { return NULL; }; //Pairing a portal with an entity is common but not required. Accessing that entity allows the CPortalRender system to better optimize.
|
||||
VMatrix m_matrixThisToLinked; //Always going to need a matrix
|
||||
|
||||
// Poor man's RTTI
|
||||
FORCEINLINE bool IsPropPortal() const { return m_bIsPropPortal; }
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//SFM related
|
||||
//-----------------------------------------------------------------------------
|
||||
bool m_bIsPlaybackPortal;
|
||||
virtual void HandlePortalPlaybackMessage( KeyValues *pKeyValues ) { };
|
||||
|
||||
protected:
|
||||
|
||||
CPortalRenderable *FindRecordedPortal( int nPortalId ); //routed through here to get friend access to CPortalRender
|
||||
|
||||
//routed through here to get friend access to CViewRender
|
||||
void CopyToCurrentView( CViewRender *pViewRender, const CViewSetup &viewSetup );
|
||||
void ViewDrawScene_PortalStencil( CViewRender *pViewRender, const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility );
|
||||
void Draw3dSkyboxworld_Portal( CViewRender *pViewRender, const CViewSetup &viewIn, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget = NULL );
|
||||
void ViewDrawScene( CViewRender *pViewRender, bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &viewIn, int nClearFlags, view_id_t viewID, bool bDrawViewModel = false, int baseDrawFlags = 0, ViewCustomVisibility_t *pCustomVisibility = NULL );
|
||||
void SetViewRecursionLevel( int iViewRecursionLevel );
|
||||
void SetRemainingViewDepth( int iRemainingViewDepth );
|
||||
void SetViewEntranceAndExitPortals( CPortalRenderable *pEntryPortal, CPortalRenderable *pExitPortal );
|
||||
|
||||
bool m_bIsPropPortal;
|
||||
|
||||
private:
|
||||
int m_iPortalViewIDNodeIndex; //each PortalViewIDNode_t has a child node link for each CPortalRenderable in CPortalRender::m_ActivePortals. This portal follows the same indexed link from each node
|
||||
// m_iPortalViewIDNodeIndex is the index into CPortalRender::m_AllPortals
|
||||
friend class CPortalRender;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// inline state querying methods
|
||||
//-----------------------------------------------------------------------------
|
||||
inline const VMatrix& CPortalRenderable::MatrixThisToLinked() const
|
||||
{
|
||||
return m_matrixThisToLinked;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Portal rendering materials
|
||||
//-----------------------------------------------------------------------------
|
||||
struct PortalRenderingMaterials_t
|
||||
{
|
||||
CMaterialReference m_Wireframe;
|
||||
CMaterialReference m_WriteZ_Model;
|
||||
CMaterialReference m_TranslucentVertexColor;
|
||||
CMaterialReference m_PortalDepthDoubler;
|
||||
unsigned int m_nDepthDoubleViewMatrixVarCache;
|
||||
};
|
||||
|
||||
struct PortalViewIDNode_t
|
||||
{
|
||||
CUtlVector<PortalViewIDNode_t *> ChildNodes; //links will only be non-null if they're useful (can see through the portal at that depth and view setup)
|
||||
int iPrimaryViewID;
|
||||
//skybox view id is always primary + 1
|
||||
|
||||
//In stencil mode this wraps CPortalRenderable::DrawStencilMask() and gives previous frames' results to CPortalRenderable::RenderPortalViewToBackBuffer()
|
||||
//In texture mode there's no good spot to auto-wrap occlusion tests. So you'll need to wrap it yourself for that.
|
||||
OcclusionQueryObjectHandle_t occlusionQueryHandle;
|
||||
int iWindowPixelsAtQueryTime;
|
||||
int iOcclusionQueryPixelsRendered;
|
||||
float fScreenFilledByPortalSurfaceLastFrame_Normalized;
|
||||
};
|
||||
|
||||
struct GhostPortalRenderInfo_t
|
||||
{
|
||||
C_Prop_Portal *m_pPortal;
|
||||
int m_nGhostPortalQuadIndex;
|
||||
IMaterial *m_pGhostMaterial;
|
||||
};
|
||||
|
||||
struct ClampedPortalMeshRenderInfo_t
|
||||
{
|
||||
int nStartIndex;
|
||||
int nIndexCount;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Portal rendering management class
|
||||
//-----------------------------------------------------------------------------
|
||||
class CPortalRender : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CPortalRender();
|
||||
~CPortalRender();
|
||||
|
||||
// Inherited from IGameSystem
|
||||
virtual void LevelInitPreEntity();
|
||||
virtual void LevelShutdownPreEntity();
|
||||
|
||||
// Are we currently rendering a portal?
|
||||
bool IsRenderingPortal() const;
|
||||
|
||||
// Returns the current View IDs. Portal View IDs will change often (especially with recursive views) and should not be cached
|
||||
int GetCurrentViewId() const;
|
||||
int GetCurrentSkyboxViewId() const;
|
||||
|
||||
// Returns view recursion level
|
||||
int GetViewRecursionLevel() const;
|
||||
|
||||
float GetPixelVisilityForPortalSurface( const CPortalRenderable *pPortal ) const; //normalized for how many of the screen's possible pixels it takes up, less than zero indicates a lack of data from last frame
|
||||
|
||||
// Returns the remaining number of portals to render within other portals
|
||||
// lets portals know that they should do "end of the line" kludges to cover up that portals don't go infinitely recursive
|
||||
int GetRemainingPortalViewDepth() const;
|
||||
|
||||
inline CPortalRenderable *GetCurrentViewEntryPortal( void ) const { return m_pRenderingViewForPortal; }; //if rendering a portal view, this is the portal the current view enters into
|
||||
inline CPortalRenderable *GetCurrentViewExitPortal( void ) const { return m_pRenderingViewExitPortal; }; //if rendering a portal view, this is the portal the current view exits from
|
||||
|
||||
//it's a good idea to force cheaper water when the ratio of performance gain to noticability is high
|
||||
//0 = force no reflection/refraction
|
||||
//1/2 = downgrade to simple/world reflections as seen in advanced video options
|
||||
//3 = no downgrade
|
||||
int ShouldForceCheaperWaterLevel() const;
|
||||
|
||||
bool ShouldObeyStencilForClears() const;
|
||||
|
||||
#ifdef _PS3
|
||||
void ReloadZcullMemory();
|
||||
#endif // _PS3
|
||||
|
||||
//sometimes we have to tweak some systems to render water properly with portals
|
||||
void WaterRenderingHandler_PreReflection() const;
|
||||
void WaterRenderingHandler_PostReflection() const;
|
||||
void WaterRenderingHandler_PreRefraction() const;
|
||||
void WaterRenderingHandler_PostRefraction() const;
|
||||
|
||||
// return value indicates that something was done, and render lists should be rebuilt afterwards
|
||||
bool DrawPortalsUsingStencils( CViewRender *pViewRender );
|
||||
bool DrawPortalsUsingStencils_Old( CViewRender *pViewRender );
|
||||
|
||||
void OverlayPortalRenderTargets( float w, float h );
|
||||
|
||||
void UpdateDepthDoublerTexture( const CViewSetup &viewSetup ); //our chance to update all depth doubler texture before the view model is added to the back buffer
|
||||
static bool DepthDoublerPIPDisableCheck( void ); //the depth doubler texture is unusable for a picture-in-picture view. Rather than sort out that ugly mess, just disable it for that case.
|
||||
|
||||
void EnteredPortal( int nPlayerSlot, CPortalRenderable *pEnteredPortal ); //does a bit of internal maintenance whenever the player/camera has logically passed the portal threshold
|
||||
|
||||
// adds, removes a portal to the set of renderable portals
|
||||
void AddPortal( CPortalRenderable *pPortal );
|
||||
void RemovePortal( CPortalRenderable *pPortal );
|
||||
|
||||
// Methods to query about the exit portal associated with the currently rendering portal
|
||||
void ShiftFogForExitPortalView() const;
|
||||
float GetCurrentPortalDistanceBias() const;
|
||||
const Vector &GetExitPortalFogOrigin() const;
|
||||
SkyboxVisibility_t IsSkyboxVisibleFromExitPortal() const;
|
||||
bool DoesExitPortalViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const;
|
||||
|
||||
void HandlePortalPlaybackMessage( KeyValues *pKeyValues );
|
||||
|
||||
CPortalRenderable* FindRecordedPortal( IClientRenderable *pRenderable );
|
||||
|
||||
CViewSetup m_RecursiveViewSetups[MAX_PORTAL_RECURSIVE_VIEWS]; //before we recurse into a view, we backup the view setup here for reference
|
||||
|
||||
// tests if the parameter ID is being used by portal pixel vis queries
|
||||
bool IsPortalViewID( view_id_t id );
|
||||
|
||||
inline CUtlVector<VPlane> &GetRecursiveViewComplexFrustums( int nIdx ) { return m_RecursiveViewComplexFrustums[ nIdx ]; }
|
||||
|
||||
void DrawEarlyZPortals( CViewRender *pViewRender );
|
||||
|
||||
private:
|
||||
struct RecordedPortalInfo_t
|
||||
{
|
||||
CPortalRenderable *m_pActivePortal;
|
||||
int m_nPortalId;
|
||||
IClientRenderable *m_pPlaybackRenderable;
|
||||
};
|
||||
|
||||
PortalViewIDNode_t m_HeadPortalViewIDNode; //pseudo node. Primary view id will be VIEW_MAIN. The child links are what we really care about
|
||||
PortalViewIDNode_t* m_PortalViewIDNodeChain[MAX_PORTAL_RECURSIVE_VIEWS]; //the view id node chain we're following, 0 always being &m_HeadPortalViewIDNode (offsetting by 1 seems like it'd cause bugs in the long run)
|
||||
|
||||
void UpdatePortalPixelVisibility( void ); //updates pixel visibility for portal surfaces
|
||||
|
||||
// Handles a portal update message
|
||||
void HandlePortalUpdateMessage( KeyValues *pKeyValues );
|
||||
|
||||
// Finds a recorded portal
|
||||
int FindRecordedPortalIndex( int nPortalId );
|
||||
CPortalRenderable* FindRecordedPortal( int nPortalId );
|
||||
|
||||
void DrawPortalGhostLocations( IMatRenderContext *pRenderContext, IMesh *pPortalQuadMesh, const GhostPortalRenderInfo_t *pGhostPortalRenderInfos, int nPortalCount ) const;
|
||||
void RenderPortalEffects( IMatRenderContext *pRenderContext, IMesh *pPortalQuadMesh, const CUtlVector< CPortalRenderable* > &actualActivePortals,
|
||||
const CUtlVector< int > &actualActivePortalQuadVBIndex ) const;
|
||||
|
||||
private:
|
||||
|
||||
PortalRenderingMaterials_t m_Materials;
|
||||
int m_iViewRecursionLevel;
|
||||
int m_iRemainingPortalViewDepth; //let's portals know that they should do "end of the line" kludges to cover up that portals don't go infinitely recursive
|
||||
|
||||
// Data that's only valid while inside DrawPortalsUsingStencil()
|
||||
CUtlStack<int> m_stencilValueStack;
|
||||
CUtlStack<int> m_parentPortalIdStack;
|
||||
ICachedPerFrameMeshData *m_pCachedPortalQuadMeshData;
|
||||
VertexFormat_t m_portalQuadMeshVertexFmt;
|
||||
CUtlVector< ClampedPortalMeshRenderInfo_t > m_clampedPortalMeshRenderInfos;
|
||||
CUtlVector< bool > m_portalIsOpening;
|
||||
|
||||
CPortalRenderable *m_pRenderingViewForPortal; //the specific pointer for the portal that we're rending a view for
|
||||
CPortalRenderable *m_pRenderingViewExitPortal; //the specific pointer for the portal that our view exits from
|
||||
|
||||
CUtlVector<CPortalRenderable *> m_AllPortals; //All portals currently in memory, active or not
|
||||
CUtlVector<CPortalRenderable *> m_ActivePortals;
|
||||
CUtlVector< RecordedPortalInfo_t > m_RecordedPortals;
|
||||
|
||||
ShaderStencilState_t m_StencilState;
|
||||
|
||||
CUtlVector<VPlane> m_RecursiveViewComplexFrustums[MAX_PORTAL_RECURSIVE_VIEWS];
|
||||
|
||||
CUtlVector< GhostPortalRenderInfo_t > m_portalGhostRenderInfos;
|
||||
|
||||
public:
|
||||
//frustums with more (or less) than 6 planes. Store each recursion level's custom frustum here so further recursions can be better optimized.
|
||||
//When going into further recursions, if you've failed to fill in a complex frustum, the standard frustum will be copied in.
|
||||
//So all parent levels are guaranteed to contain valid data
|
||||
PortalRenderingMaterials_t& m_MaterialsAccess;
|
||||
|
||||
friend class CPortalRenderable;
|
||||
friend void OnRenderStart();
|
||||
};
|
||||
|
||||
extern CPortalRender* g_pPortalRender;
|
||||
|
||||
|
||||
inline CPortalRenderable *CPortalRenderable::FindRecordedPortal( int nPortalId )
|
||||
{
|
||||
return g_pPortalRender->FindRecordedPortal( nPortalId );
|
||||
}
|
||||
|
||||
|
||||
typedef CPortalRenderable *(*PortalRenderableCreationFunc)( void );
|
||||
|
||||
//only ever create global/static instances of this
|
||||
class CPortalRenderableCreator_AutoRegister
|
||||
{
|
||||
public:
|
||||
CPortalRenderableCreator_AutoRegister( const char *szType, PortalRenderableCreationFunc creationFunc )
|
||||
: m_szPortalType( szType ), m_creationFunc( creationFunc )
|
||||
{
|
||||
m_pNext = s_pRegisteredTypes;
|
||||
s_pRegisteredTypes = this;
|
||||
}
|
||||
private:
|
||||
const char *m_szPortalType;
|
||||
PortalRenderableCreationFunc m_creationFunc;
|
||||
const CPortalRenderableCreator_AutoRegister *m_pNext;
|
||||
static CPortalRenderableCreator_AutoRegister *s_pRegisteredTypes;
|
||||
friend class CPortalRender;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// inline friend access redirects
|
||||
//-----------------------------------------------------------------------------
|
||||
inline void CPortalRenderable::CopyToCurrentView( CViewRender *pViewRender, const CViewSetup &viewSetup )
|
||||
{
|
||||
pViewRender->m_CurrentView = viewSetup;
|
||||
}
|
||||
|
||||
inline void CPortalRenderable::ViewDrawScene_PortalStencil( CViewRender *pViewRender, const CViewSetup &viewIn, ViewCustomVisibility_t *pCustomVisibility )
|
||||
{
|
||||
pViewRender->ViewDrawScene_PortalStencil( viewIn, pCustomVisibility );
|
||||
}
|
||||
|
||||
inline void CPortalRenderable::Draw3dSkyboxworld_Portal( CViewRender *pViewRender, const CViewSetup &viewIn, int &nClearFlags, bool &bDrew3dSkybox, SkyboxVisibility_t &nSkyboxVisible, ITexture *pRenderTarget )
|
||||
{
|
||||
pViewRender->Draw3dSkyboxworld_Portal( viewIn, nClearFlags, bDrew3dSkybox, nSkyboxVisible, pRenderTarget );
|
||||
}
|
||||
|
||||
inline void CPortalRenderable::ViewDrawScene( CViewRender *pViewRender, bool bDrew3dSkybox, SkyboxVisibility_t nSkyboxVisible, const CViewSetup &viewIn, int nClearFlags, view_id_t viewID, bool bDrawViewModel, int baseDrawFlags, ViewCustomVisibility_t *pCustomVisibility )
|
||||
{
|
||||
pViewRender->ViewDrawScene( bDrew3dSkybox, nSkyboxVisible, viewIn, nClearFlags, viewID, bDrawViewModel, baseDrawFlags, pCustomVisibility );
|
||||
}
|
||||
|
||||
inline void CPortalRenderable::SetViewRecursionLevel( int iViewRecursionLevel )
|
||||
{
|
||||
g_pPortalRender->m_iViewRecursionLevel = iViewRecursionLevel;
|
||||
}
|
||||
|
||||
inline void CPortalRenderable::SetRemainingViewDepth( int iRemainingViewDepth )
|
||||
{
|
||||
g_pPortalRender->m_iRemainingPortalViewDepth = iRemainingViewDepth;
|
||||
}
|
||||
|
||||
inline void CPortalRenderable::SetViewEntranceAndExitPortals( CPortalRenderable *pEntryPortal, CPortalRenderable *pExitPortal )
|
||||
{
|
||||
g_pPortalRender->m_pRenderingViewForPortal = pEntryPortal;
|
||||
g_pPortalRender->m_pRenderingViewExitPortal = pExitPortal;
|
||||
}
|
||||
|
||||
#endif //#ifndef PORTALRENDER_H
|
||||
|
||||
1747
game/client/portal/portalrenderable_flatbasic.cpp
Normal file
1747
game/client/portal/portalrenderable_flatbasic.cpp
Normal file
File diff suppressed because it is too large
Load Diff
132
game/client/portal/portalrenderable_flatbasic.h
Normal file
132
game/client/portal/portalrenderable_flatbasic.h
Normal file
@@ -0,0 +1,132 @@
|
||||
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef PORTALRENDERABLE_FLATBASIC_H
|
||||
#define PORTALRENDERABLE_FLATBASIC_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "PortalRender.h"
|
||||
|
||||
struct PortalMeshPoint_t;
|
||||
#define PORTALRENDERFIXMESH_OUTERBOUNDPLANES 12
|
||||
|
||||
|
||||
//As seen in "Portal"
|
||||
class CPortalRenderable_FlatBasic : public C_BaseAnimating, public CPortalRenderable
|
||||
{
|
||||
DECLARE_CLASS( CPortalRenderable_FlatBasic, C_BaseAnimating );
|
||||
|
||||
public:
|
||||
CPortalRenderable_FlatBasic( void );
|
||||
|
||||
//generates a 8x6 tiled set of quads, each clipped to the view frustum. Helps vs11/ps11 portal shaders interpolate correctly. Not necessary for vs20/ps20 portal shaders or stencil mode.
|
||||
virtual void DrawComplexPortalMesh( IMatRenderContext *pRenderContext, const IMaterial *pMaterial, float fForwardOffsetModifier = 0.0f );
|
||||
|
||||
//generates a single quad
|
||||
virtual void DrawSimplePortalMesh( IMatRenderContext *pRenderContext, const IMaterial *pMaterial, float fForwardOffsetModifier = 0.0f, float flAlpha = 1.0f, const Vector *pVertexColor = NULL );
|
||||
|
||||
//draws a screenspace mesh to replace missing pixels caused by the camera near plane intersecting the portal mesh
|
||||
virtual void DrawRenderFixMesh( IMatRenderContext *pRenderContext, const IMaterial *pMaterialOverride = NULL, float fFrontClipDistance = 0.3f );
|
||||
|
||||
virtual void DrawPortal( IMatRenderContext *pRenderContext );
|
||||
virtual int BindPortalMaterial( IMatRenderContext *pRenderContext, int nPassIndex, bool *pAllowRingMeshOptimizationOut );
|
||||
|
||||
virtual void DrawStencilMask( IMatRenderContext *pRenderContext ); //Draw to wherever you can see through the portal. The mask will later be filled with the portal view.
|
||||
virtual void DrawPostStencilFixes( IMatRenderContext *pRenderContext ); //After done drawing to the portal mask, we need to fix the depth buffer as well as fog. So draw your mesh again, writing to z and with the fog color alpha'd in by distance
|
||||
|
||||
//When we're in a configuration that sees through recursive portal views to a depth of 2, we should be able to cheaply approximate even further depth using pixels from previous frames
|
||||
virtual void DrawDepthDoublerMesh( IMatRenderContext *pRenderContext, float fForwardOffsetModifier = 0.25f );
|
||||
|
||||
virtual void RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView );
|
||||
virtual void RenderPortalViewToTexture( CViewRender *pViewRender, const CViewSetup &cameraView );
|
||||
|
||||
void AddToVisAsExitPortal( ViewCustomVisibility_t *pCustomVisibility );
|
||||
|
||||
virtual bool ShouldUpdatePortalView_BasedOnView( const CViewSetup ¤tView, const CUtlVector<VPlane> ¤tComplexFrustum ); //portal is both visible, and will display at least some portion of a remote view
|
||||
virtual bool ShouldUpdatePortalView_BasedOnPixelVisibility( float fScreenFilledByStencilMaskLastFrame_Normalized );
|
||||
virtual bool ShouldUpdateDepthDoublerTexture( const CViewSetup &viewSetup );
|
||||
|
||||
virtual void GetToolRecordingState( KeyValues *msg );
|
||||
virtual void HandlePortalPlaybackMessage( KeyValues *pKeyValues );
|
||||
|
||||
virtual const Vector &GetFogOrigin( void ) const { return m_ptOrigin; };
|
||||
virtual SkyboxVisibility_t SkyBoxVisibleFromPortal( void ) { return m_InternallyMaintainedData.m_nSkyboxVisibleFromCorners; };
|
||||
virtual bool DoesExitViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const;
|
||||
virtual float GetPortalDistanceBias() const;
|
||||
|
||||
bool WillUseDepthDoublerThisDraw( void ) const; //returns true if the DrawPortal() would draw a depth doubler mesh if you were to call it right now
|
||||
|
||||
virtual CPortalRenderable *GetLinkedPortal() const { return m_pLinkedPortal; };
|
||||
bool CalcFrustumThroughPortal( const Vector &ptCurrentViewOrigin, Frustum OutputFrustum );
|
||||
bool CalcFrustumThroughPolygon( const Vector *pPolyVertices, int iPolyVertCount, const Vector &ptCurrentViewOrigin, Frustum OutputFrustum );
|
||||
|
||||
virtual float GetPortalGhostAlpha( void ) const { return 1.0; }
|
||||
|
||||
static IMesh *CreateMeshForPortals( IMatRenderContext *pRenderContext, int nPortalCount, CPortalRenderable **ppPortals, CUtlVector< ClampedPortalMeshRenderInfo_t > &clampedPortalMeshRenderInfos );
|
||||
|
||||
virtual int DrawModel( int flags, const RenderableInstance_t &instance ) { return 0; } // Prevent the model from rendering as a normal model
|
||||
virtual IClientModelRenderable* GetClientModelRenderable() { return NULL; }
|
||||
|
||||
bool ComputeClipSpacePortalCorners( Vector4D *pClipSpacePortalCornersOut, const VMatrix &matViewProj ) const;
|
||||
|
||||
protected:
|
||||
void ClipFixToBoundingAreaAndDraw( PortalMeshPoint_t *pVerts, const IMaterial *pMaterial );
|
||||
void Internal_DrawRenderFixMesh( IMatRenderContext *pRenderContext, const IMaterial *pMaterial );
|
||||
|
||||
// renders a quad that simulates fog as an overlay for something else (most notably the hole we create for stencil mode portals)
|
||||
void RenderFogQuad( void );
|
||||
|
||||
void PortalMoved( void ); // call this if you've moved the portal around so we can update internally maintained data
|
||||
|
||||
struct FlatBasicPortal_InternalData_t
|
||||
{
|
||||
VPlane m_BoundingPlanes[PORTALRENDERFIXMESH_OUTERBOUNDPLANES + 2]; // +2 for front and back
|
||||
|
||||
VisOverrideData_t m_VisData; // a data to use for visibility calculations (to override area portal culling)
|
||||
int m_iViewLeaf; // leaf to start in for area portal flowing through calculations
|
||||
|
||||
VMatrix m_DepthDoublerTextureView[MAX_SPLITSCREEN_CLIENTS]; //cached version of view matrix at depth 1 for use when drawing the depth doubler mesh
|
||||
bool m_bUsableDepthDoublerConfiguration; //every time a portal moves we re-evaluate whether the depth doubler will reasonably approximate more views
|
||||
SkyboxVisibility_t m_nSkyboxVisibleFromCorners;
|
||||
|
||||
Vector m_ptForwardOrigin;
|
||||
Vector m_ptCorners[4];
|
||||
|
||||
float m_fPlaneDist; //combines with m_vForward to make a plane
|
||||
};
|
||||
|
||||
FlatBasicPortal_InternalData_t m_InternallyMaintainedData;
|
||||
|
||||
public:
|
||||
CPortalRenderable_FlatBasic *m_pLinkedPortal;
|
||||
Vector m_ptOrigin;
|
||||
Vector m_vForward, m_vUp, m_vRight;
|
||||
QAngle m_qAbsAngle;
|
||||
bool m_bIsPortal2; //for any set of portals, one must be portal 1, and the other portal 2. Uses different render targets
|
||||
|
||||
#if 0
|
||||
//SFM stuff
|
||||
Vector m_ptLastRecordedOrigin;
|
||||
QAngle m_qLastRecordedAngle;
|
||||
#endif
|
||||
|
||||
private:
|
||||
float m_fHalfWidth, m_fHalfHeight;
|
||||
static CUtlStack<Vector4D> ms_clipPlaneStack;
|
||||
|
||||
public:
|
||||
inline float GetHalfWidth( void ) const { return m_fHalfWidth; }
|
||||
inline float GetHalfHeight( void ) const { return m_fHalfHeight; }
|
||||
inline Vector GetLocalMins( void ) const { return Vector( 0.0f, -m_fHalfWidth, -m_fHalfHeight ); }
|
||||
inline Vector GetLocalMaxs( void ) const { return Vector( 64.0f, m_fHalfWidth, m_fHalfHeight ); }
|
||||
inline void SetHalfSizes( float fHalfWidth, float fHalfHeight ) { m_fHalfWidth = fHalfWidth; m_fHalfHeight = fHalfHeight; }
|
||||
};
|
||||
|
||||
#endif //#ifndef PORTALRENDERABLE_FLATBASIC_H
|
||||
Reference in New Issue
Block a user