diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/portal/c_prop_portal.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/portal/c_prop_portal.cpp')
| -rw-r--r-- | game/client/portal/c_prop_portal.cpp | 952 |
1 files changed, 952 insertions, 0 deletions
diff --git a/game/client/portal/c_prop_portal.cpp b/game/client/portal/c_prop_portal.cpp new file mode 100644 index 0000000..7ca3812 --- /dev/null +++ b/game/client/portal/c_prop_portal.cpp @@ -0,0 +1,952 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// + +#include "cbase.h" +#include "c_prop_portal.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 "prop_portal_shared.h" +#include "particles_new.h" + +#include "c_portal_player.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" + + +LINK_ENTITY_TO_CLASS( prop_portal, C_Prop_Portal ); + +IMPLEMENT_CLIENTCLASS_DT( C_Prop_Portal, DT_Prop_Portal, CProp_Portal ) + RecvPropEHandle( RECVINFO(m_hLinkedPortal) ), + RecvPropBool( RECVINFO(m_bActivated) ), + RecvPropBool( RECVINFO(m_bIsPortal2) ), +END_RECV_TABLE() + + +void __MsgFunc_EntityPortalled(bf_read &msg) +{ + long iEncodedEHandle; + int iEntity, iSerialNum; + + + //grab portal EHANDLE + iEncodedEHandle = msg.ReadLong(); + + if( iEncodedEHandle == INVALID_NETWORKED_EHANDLE_VALUE ) + return; + + iEntity = iEncodedEHandle & ((1 << MAX_EDICT_BITS) - 1); + iSerialNum = iEncodedEHandle >> MAX_EDICT_BITS; + + EHANDLE hPortal( iEntity, iSerialNum ); + C_Prop_Portal *pPortal = ( C_Prop_Portal *)(hPortal.Get()); + + if( pPortal == NULL ) + return; + + + + //grab other entity's EHANDLE + + iEncodedEHandle = msg.ReadLong(); + + if( iEncodedEHandle == INVALID_NETWORKED_EHANDLE_VALUE ) + return; + + iEntity = iEncodedEHandle & ((1 << MAX_EDICT_BITS) - 1); + iSerialNum = iEncodedEHandle >> MAX_EDICT_BITS; + + EHANDLE hEntity( iEntity, iSerialNum ); + C_BaseEntity *pEntity = hEntity.Get(); + if( pEntity == NULL ) + return; + + + + bool bIsPlayer = pEntity->IsPlayer(); + + Vector ptNewPosition; + ptNewPosition.x = msg.ReadFloat(); + ptNewPosition.y = msg.ReadFloat(); + ptNewPosition.z = msg.ReadFloat(); + QAngle qNewAngles; + qNewAngles.x = msg.ReadFloat(); + qNewAngles.y = msg.ReadFloat(); + qNewAngles.z = msg.ReadFloat(); + + Vector vecOldInterpolatedPos; + QAngle qaOldInterpolatedRot; + if ( pEntity->IsToolRecording() ) + { + vecOldInterpolatedPos = pEntity->GetOriginInterpolator().GetCurrent(); + qaOldInterpolatedRot = pEntity->GetRotationInterpolator().GetCurrent(); + } + + pEntity->AddEFlags( EFL_DIRTY_ABSTRANSFORM ); + + VMatrix matTransform = pPortal->MatrixThisToLinked(); + //VMatrix matInvTransform = pPortal->m_hLinkedPortal->MatrixThisToLinked(); + + CInterpolatedVar< QAngle > &rotInterp = pEntity->GetRotationInterpolator(); + CInterpolatedVar< Vector > &posInterp = pEntity->GetOriginInterpolator(); + + Vector ptCurrentPosition = posInterp.GetCurrent(); + Vector ptInvCurrentPosition = matTransform * ptCurrentPosition; + bool bAlreadyTeleported = ((ptCurrentPosition - ptNewPosition).LengthSqr() < (ptInvCurrentPosition - ptNewPosition).LengthSqr()); //newest network update closer to destination than transformed to destination indicates it's already been transformed + + + UTIL_TransformInterpolatedAngle( rotInterp, matTransform.As3x4(), bAlreadyTeleported ); + + if( bIsPlayer ) //the player's origin != player's center, transforms are performed about centers + { + VMatrix matShiftOrigin; + matShiftOrigin.Identity(); + Vector vTranslate( 0.0f, 0.0f, 36.0f ); + matShiftOrigin.SetTranslation( vTranslate ); + matTransform = matTransform * matShiftOrigin; + vTranslate = -vTranslate; + matShiftOrigin.SetTranslation( vTranslate ); + matTransform = matShiftOrigin * matTransform; + } + + UTIL_TransformInterpolatedPosition( posInterp, matTransform, bAlreadyTeleported ); + + + if( bIsPlayer ) + ((C_Portal_Player *)pEntity)->PlayerPortalled( pPortal ); + + 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 = ptNewPosition; + state.m_qaTo = qNewAngles; + state.m_teleportMatrix = matTransform.As3x4(); + + // Post a message back to all IToolSystems + Assert( (int)pEntity->GetToolHandle() != 0 ); + ToolFramework_PostToolMessage( pEntity->GetToolHandle(), msg ); + + msg->deleteThis(); + } +} + +static ConVar portal_demohack( "portal_demohack", "0", FCVAR_ARCHIVE, "Do the demo_legacy_rollback setting to help during demo playback of going through portals." ); + +class C_PortalInitHelper : public CAutoGameSystem +{ + virtual bool Init() + { + //HOOK_MESSAGE( PlayerPortalled ); + HOOK_MESSAGE( EntityPortalled ); + 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_Prop_Portal::C_Prop_Portal( void ) +{ + TransformedLighting.m_LightShadowHandle = CLIENTSHADOW_INVALID_HANDLE; + CProp_Portal_Shared::AllPortals.AddToTail( this ); +} + +C_Prop_Portal::~C_Prop_Portal( void ) +{ + CProp_Portal_Shared::AllPortals.FindAndRemove( this ); + g_pPortalRender->RemovePortal( this ); + + for( int i = m_GhostRenderables.Count(); --i >= 0; ) + { + delete m_GhostRenderables[i]; + } + m_GhostRenderables.RemoveAll(); +} + +void C_Prop_Portal::Spawn( void ) +{ + SetThink( &C_Prop_Portal::ClientThink ); + SetNextClientThink( CLIENT_THINK_ALWAYS ); + + m_matrixThisToLinked.Identity(); //don't accidentally teleport objects to zero space + BaseClass::Spawn(); +} + +void C_Prop_Portal::Activate( void ) +{ + BaseClass::Activate(); +} + +void C_Prop_Portal::ClientThink( void ) +{ + bool bDidAnything = false; + if( m_fStaticAmount > 0.0f ) + { + m_fStaticAmount -= gpGlobals->absoluteframetime; + if( m_fStaticAmount < 0.0f ) + m_fStaticAmount = 0.0f; + + bDidAnything = true; + } + if( m_fSecondaryStaticAmount > 0.0f ) + { + m_fSecondaryStaticAmount -= gpGlobals->absoluteframetime; + if( m_fSecondaryStaticAmount < 0.0f ) + m_fSecondaryStaticAmount = 0.0f; + + bDidAnything = true; + } + + if( m_fOpenAmount < 1.0f ) + { + m_fOpenAmount += gpGlobals->absoluteframetime * 2.0f; + if( m_fOpenAmount > 1.0f ) + m_fOpenAmount = 1.0f; + + bDidAnything = true; + } + + if( bDidAnything == false ) + { + SetNextClientThink( CLIENT_THINK_NEVER ); + } +} + +void C_Prop_Portal::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( !IsActivedAndLinked() ) + { + //remove all ghost renderables + for( int i = m_GhostRenderables.Count(); --i >= 0; ) + { + delete m_GhostRenderables[i]; + } + + m_GhostRenderables.RemoveAll(); + + return; + } + + + + //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]; + int iEntsNearPortal = UTIL_EntitiesInSphere( pEntsNearPortal, 1024, GetNetworkOrigin(), PORTAL_HALF_HEIGHT, 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 - 0.3f; + + for( int i = 0; i != iEntsNearPortal; ++i ) + { + CBaseEntity *pEntity = pEntsNearPortal[i]; + Assert( pEntity != NULL ); + + 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 ) + continue; + + Assert( dynamic_cast<C_Prop_Portal *>(pEntity) == NULL ); //should have been killed with (pEntity->GetMoveType() == MOVETYPE_NONE) check. Infinite recursion is infinitely bad. + + if( pEntity == pLocalPlayerViewModel ) + continue; //avoid ghosting view models + + bool bActivePlayerWeapon = false; + + C_BaseCombatWeapon *pWeapon = dynamic_cast<C_BaseCombatWeapon*>( pEntity ); + if ( pWeapon ) + { + C_Portal_Player *pPortalPlayer = ToPortalPlayer( pWeapon->GetOwner() ); + if ( pPortalPlayer ) + { + if ( pPortalPlayer->GetActiveWeapon() != pWeapon ) + continue; // don't ghost player owned non selected weapons + else + bActivePlayerWeapon = true; + } + } + + Vector ptEntCenter = pEntity->WorldSpaceCenter(); + if( bActivePlayerWeapon ) + ptEntCenter = pWeapon->GetOwner()->WorldSpaceCenter(); + + if( (m_plane_Origin.normal.Dot( ptEntCenter ) - m_plane_Origin.dist) < -5.0f ) + continue; //entity is behind the portal, most likely behind the wall the portal is placed on + + if( !CProp_Portal_Shared::IsEntityTeleportable( pEntity ) ) + continue; + + if ( bActivePlayerWeapon ) + { + if( !m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( pWeapon->GetOwner() ) && + !m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( pWeapon ) ) + continue; + } + else if( pEntity->IsPlayer() ) + { + if( !m_PortalSimulator.EntityHitBoxExtentIsInPortalHole( (C_BaseAnimating*)pEntity ) ) + continue; + } + else + { + if( !m_PortalSimulator.EntityIsInPortalHole( pEntity ) ) + continue; + } + + 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_pGhostedRenderable ) + { + bStillInUse[j] = true; + m_GhostRenderables[j]->PerFrameUpdate(); + break; + } + } + + if ( j >= 0 ) + continue; + + //newly added + C_BaseEntity *pEntity = m_hGhostingEntities[i]; + + bool bIsHeldWeapon = false; + C_BaseCombatWeapon *pWeapon = dynamic_cast<C_BaseCombatWeapon*>( pEntity ); + if ( pWeapon && ToPortalPlayer( pWeapon->GetOwner() ) ) + bIsHeldWeapon = true; + + C_PortalGhostRenderable *pNewGhost = new C_PortalGhostRenderable( this, + pRenderable, + pEntity->GetRenderGroup(), + m_matrixThisToLinked, + m_fGhostRenderablesClip, + (pEntity == pLocalPlayer || bIsHeldWeapon) ); + Assert( pNewGhost ); + + bStillInUse[ m_GhostRenderables.AddToTail( pNewGhost ) ] = true; + pNewGhost->PerFrameUpdate(); + + // 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(); + } + } + + //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 ( 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 ); + } + } + + delete pGhost; + m_GhostRenderables.FastRemove( i ); + } + } + + //ensure the shared clip plane is up to date + C_Prop_Portal *pLinkedPortal = m_hLinkedPortal.Get(); + + 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 - 0.75f; +} + +void C_Prop_Portal::UpdateOnRemove( void ) +{ + if( TransformedLighting.m_LightShadowHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( TransformedLighting.m_LightShadowHandle ); + TransformedLighting.m_LightShadowHandle = CLIENTSHADOW_INVALID_HANDLE; + } + + g_pPortalRender->RemovePortal( this ); + + BaseClass::UpdateOnRemove(); +} + +void C_Prop_Portal::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 = CProp_Portal_Shared::AllPortals.Count(); + if( iPortalCount != 0 ) + { + CProp_Portal **pPortals = CProp_Portal_Shared::AllPortals.Base(); + for( int i = 0; i != iPortalCount; ++i ) + { + CProp_Portal *pTempPortal = pPortals[i]; + if ( pTempPortal != this && pTempPortal->m_bActivated ) + { + 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_Prop_Portal::OnPreDataChanged( DataUpdateType_t updateType ) +{ + //PreDataChanged.m_matrixThisToLinked = m_matrixThisToLinked; + PreDataChanged.m_bIsPortal2 = m_bIsPortal2; + PreDataChanged.m_bActivated = m_bActivated; + PreDataChanged.m_vOrigin = GetNetworkOrigin(); + PreDataChanged.m_qAngles = GetNetworkAngles(); + PreDataChanged.m_hLinkedTo = m_hLinkedPortal.Get(); + + 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_Prop_Portal::OnDataChanged( DataUpdateType_t updateType ) +{ + C_Prop_Portal *pRemote = m_hLinkedPortal; + m_pLinkedPortal = pRemote; + GetVectors( &m_vForward, &m_vRight, &m_vUp ); + m_ptOrigin = GetNetworkOrigin(); + + bool bPortalMoved = ( (PreDataChanged.m_vOrigin != m_ptOrigin ) || + (PreDataChanged.m_qAngles != GetNetworkAngles()) || + (PreDataChanged.m_bActivated == false) || + (PreDataChanged.m_bIsPortal2 != m_bIsPortal2) ); + + bool bNewLinkage = ( (PreDataChanged.m_hLinkedTo.Get() != m_hLinkedPortal.Get()) ); + if( bNewLinkage ) + m_PortalSimulator.DetachFromLinked(); //detach now so moves are theoretically faster + + if( m_bActivated ) + { + //generic stuff we'll need + Vector vRemoteUp, vRemoteRight, vRemoteForward, ptRemoteOrigin; + if( pRemote ) + { + pRemote->GetVectors( &vRemoteForward, &vRemoteRight, &vRemoteUp ); + ptRemoteOrigin = pRemote->GetNetworkOrigin(); + } + g_pPortalRender->AddPortal( this ); //will know if we're already added and avoid adding twice + + if( bPortalMoved ) + { + Vector ptForwardOrigin = m_ptOrigin + m_vForward;// * 3.0f; + Vector vScaledRight = m_vRight * (PORTAL_HALF_WIDTH * 0.95f); + Vector vScaledUp = m_vUp * (PORTAL_HALF_HEIGHT * 0.95f); + + m_PortalSimulator.MoveTo( GetNetworkOrigin(), GetNetworkAngles() ); + + //update our associated portal environment + //CPortal_PhysicsEnvironmentMgr::CreateEnvironment( this ); + + m_fOpenAmount = 0.0f; + //m_fStaticAmount = 1.0f; // This will cause the portal we are opening to show the static effect + SetNextClientThink( CLIENT_THINK_ALWAYS ); //we need this to help open up + + //add static to the remote + if( pRemote ) + { + pRemote->m_fStaticAmount = 1.0f; // This will cause the other portal to show the static effect + pRemote->SetNextClientThink( CLIENT_THINK_ALWAYS ); + } + + dlight_t *pFakeLight = NULL; + ClientShadowHandle_t ShadowHandle = CLIENTSHADOW_INVALID_HANDLE; + if( pRemote ) + { + pFakeLight = pRemote->TransformedLighting.m_pEntityLight; + ShadowHandle = pRemote->TransformedLighting.m_LightShadowHandle; + AssertMsg( (ShadowHandle == CLIENTSHADOW_INVALID_HANDLE) || (TransformedLighting.m_LightShadowHandle == CLIENTSHADOW_INVALID_HANDLE), "Two shadow handles found, should only have one shared handle" ); + AssertMsg( (pFakeLight == NULL) || (TransformedLighting.m_pEntityLight == NULL), "two lights found, should only have one shared light" ); + pRemote->TransformedLighting.m_pEntityLight = NULL; + pRemote->TransformedLighting.m_LightShadowHandle = CLIENTSHADOW_INVALID_HANDLE; + } + + if( TransformedLighting.m_pEntityLight ) + { + pFakeLight = TransformedLighting.m_pEntityLight; + TransformedLighting.m_pEntityLight = NULL; + } + + if( TransformedLighting.m_LightShadowHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + ShadowHandle = TransformedLighting.m_LightShadowHandle; + TransformedLighting.m_LightShadowHandle = CLIENTSHADOW_INVALID_HANDLE; + } + + + + + if( pFakeLight != NULL ) + { + //turn off the light so it doesn't interfere with absorbed light calculations + pFakeLight->color.r = 0; + pFakeLight->color.g = 0; + pFakeLight->color.b = 0; + pFakeLight->flags = DLIGHT_NO_WORLD_ILLUMINATION | DLIGHT_NO_MODEL_ILLUMINATION; + pFakeLight->radius = 0.0f; + render->TouchLight( pFakeLight ); + } + + if( pRemote ) //now, see if we need to fake light coming through a portal + { +#if 0 + Vector vLightAtRemotePortal( vec3_origin ), vLightAtLocalPortal( vec3_origin ); + + if( pRemote ) //get lighting at remote portal + { + engine->ComputeLighting( ptRemoteOrigin, NULL, false, vLightAtRemotePortal, NULL ); + } + + //now get lighting at the local portal + { + engine->ComputeLighting( ptOrigin, NULL, false, vLightAtLocalPortal, NULL ); + } + + //Vector vLightDiff = vLightAtLocalPortal - vLightAtRemotePortal; + //if( vLightDiff.Length() > 0.6f ) //a significant difference in lighting, remember that the light vectors are NOT normalized in length + { + //time to fake some light coming through the greater intensity portal to the lower intensity + + //are we transferring light from the local portal to the remote? + bool bLocalToRemote = (vLightAtLocalPortal.Length() > vLightAtRemotePortal.Length()); + + Vector ptLightOrigin, vLightForward, vColor, vClampedColor; + float fColorScale; + { + if( bLocalToRemote ) + { + vColor = vLightAtLocalPortal; + vLightForward = vRemoteForward; + ptLightOrigin = ptRemoteOrigin; + } + else + { + vColor = vLightAtRemotePortal; + vLightForward = vForward; + ptLightOrigin = ptOrigin; + } + + //clamp color values + fColorScale = vColor.x; + if( vColor.y > fColorScale ) + fColorScale = vColor.y; + if( vColor.z > fColorScale ) + fColorScale = vColor.z; + + if( fColorScale > 1.0f ) + vClampedColor = vColor * (1.0f / fColorScale); + else + vClampedColor = vColor; + + /*if( vColor.x < 0.0f ) + vColor.x = 0.0f; + if( vColor.x > 1.0f ) + vColor.x = 1.0f; + + if( vColor.y < 0.0f ) + vColor.y = 0.0f; + if( vColor.y > 1.0f ) + vColor.y = 1.0f; + + if( vColor.z < 0.0f ) + vColor.z = 0.0f; + if( vColor.z > 1.0f ) + vColor.z = 1.0f;*/ + } + + + if( pFakeLight == NULL ) + pFakeLight = effects->CL_AllocElight( 0 ); //is there a difference between DLight and ELight when only lighting ents? + + if( pFakeLight != NULL ) //be absolutely sure that light allocation hasn't failed + { + if( bLocalToRemote ) + { + //local light is greater, fake at remote portal + pRemote->TransformedLighting.m_pEntityLight = pFakeLight; + pFakeLight->key = pRemote->index; + } + else + { + //remote light is greater, fake at local portal + TransformedLighting.m_pEntityLight = pFakeLight; + pFakeLight->key = index; + } + + pFakeLight->die = gpGlobals->curtime + 1e10; + pFakeLight->flags = DLIGHT_NO_WORLD_ILLUMINATION; + pFakeLight->minlight = 0.0f; + pFakeLight->radius = 500.0f; + pFakeLight->m_InnerAngle = 0.0f; //r_portal_light_innerangle.GetFloat(); + pFakeLight->m_OuterAngle = 120.0f; //r_portal_light_outerangle.GetFloat(); + pFakeLight->style = 0; + + pFakeLight->origin = ptLightOrigin; + pFakeLight->m_Direction = vLightForward; + + pFakeLight->color.r = vClampedColor.x * 255; + pFakeLight->color.g = vClampedColor.y * 255; + pFakeLight->color.b = vClampedColor.z * 255; + pFakeLight->color.exponent = ((signed int)(((*((unsigned int *)(&fColorScale))) & 0x7F800000) >> 23)) - 125; //strip the exponent from our maximum color + //if( pFakeLight->color.exponent < 4 ) + // pFakeLight->color.exponent = 4; + + render->TouchLight( pFakeLight ); + } + + FlashlightState_t state; + { + state.m_NearZ = 4.0f; + state.m_FarZ = 500.0f; + state.m_nSpotlightTextureFrame = 0; + state.m_pSpotlightTexture = PortalDrawingMaterials::PortalLightTransfer_ShadowTexture; + state.m_fConstantAtten = 0.0f; + state.m_fLinearAtten = 500.0f; + state.m_fQuadraticAtten = 0.0f; + state.m_fHorizontalFOVDegrees = 120.0f; + state.m_fVerticalFOVDegrees = 120.0f; + + state.m_bEnableShadows = false; + state.m_vecLightOrigin = ptLightOrigin; + + Vector vLightRight, vLightUp( 0.0f, 0.0f, 1.0f ); + if( fabs( DotProduct( vLightUp, vLightForward ) ) > 0.99f ) + vLightUp.Init( 0.0f, 1.0f, 0.0f ); // Don't want vLightUp and vLightForward to be parallel + + CrossProduct( vLightUp, vLightForward, vLightRight ); + VectorNormalize( vLightRight ); + CrossProduct( vLightForward, vLightRight, vLightUp ); + VectorNormalize( vLightUp ); + + BasisToQuaternion( vLightForward, vLightRight, vLightUp, state.m_quatOrientation ); + + state.m_Color[0] = vColor.x * 0.35f; + state.m_Color[1] = vColor.y * 0.35f; + state.m_Color[2] = vColor.z * 0.35f; + state.m_Color[3] = 1.0f; + } + + if( ShadowHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->UpdateFlashlightState( ShadowHandle, state ); //simpler update for existing handle + g_pClientShadowMgr->UpdateProjectedTexture( ShadowHandle, true ); + } + + if( ShadowHandle == CLIENTSHADOW_INVALID_HANDLE ) + { + ShadowHandle = g_pClientShadowMgr->CreateFlashlight( state ); + if( ShadowHandle != CLIENTSHADOW_INVALID_HANDLE ) + g_pClientShadowMgr->UpdateProjectedTexture( ShadowHandle, true ); + } + + + if( bLocalToRemote ) + pRemote->TransformedLighting.m_LightShadowHandle = ShadowHandle; + else + TransformedLighting.m_LightShadowHandle = ShadowHandle; + } +#endif + } + } + } + else + { + g_pPortalRender->RemovePortal( this ); + + m_PortalSimulator.DetachFromLinked(); + + if( TransformedLighting.m_pEntityLight ) + { + TransformedLighting.m_pEntityLight->die = gpGlobals->curtime; + TransformedLighting.m_pEntityLight = NULL; + } + + if( TransformedLighting.m_LightShadowHandle != CLIENTSHADOW_INVALID_HANDLE ) + { + g_pClientShadowMgr->DestroyFlashlight( TransformedLighting.m_LightShadowHandle ); + TransformedLighting.m_LightShadowHandle = CLIENTSHADOW_INVALID_HANDLE; + } + } + + if( (PreDataChanged.m_hLinkedTo.Get() != m_hLinkedPortal.Get()) && m_hLinkedPortal.Get() ) + m_PortalSimulator.AttachTo( &m_hLinkedPortal.Get()->m_PortalSimulator ); + + + BaseClass::OnDataChanged( updateType ); + + if( bNewLinkage || bPortalMoved ) + { + PortalMoved(); //updates link matrix and internals + } + + if ( bPortalMoved ) + { + UpdateOriginPlane(); + } + + if( bPortalMoved || bNewLinkage ) + { + UpdateGhostRenderables(); + if( pRemote ) + pRemote->UpdateGhostRenderables(); + } +} + +void C_Prop_Portal::UpdateGhostRenderables( void ) +{ + //lastly, update all ghost renderables + for( int i = m_GhostRenderables.Count(); --i >= 0; ) + { + m_GhostRenderables[i]->m_matGhostTransform = m_matrixThisToLinked;; + } +} + +extern ConVar building_cubemaps; + +int C_Prop_Portal::DrawModel( int flags ) +{ + // Don't draw in cube maps because it makes an ugly colored splotch + if( m_bActivated == false || building_cubemaps.GetBool() ) + return 0; + + int iRetVal = 0; + + C_Prop_Portal *pLinkedPortal = m_hLinkedPortal.Get(); + + if ( pLinkedPortal == NULL ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); // we need this to help fade out + } + + if ( !g_pPortalRender->ShouldUseStencilsToRenderPortals() ) + { + DrawPortal(); + } + + if( WillUseDepthDoublerThisDraw() ) + m_fSecondaryStaticAmount = 0.0f; + + iRetVal = BaseClass::DrawModel( flags ); + + return iRetVal; +} + + +//----------------------------------------------------------------------------- +// Handle recording for the SFM +//----------------------------------------------------------------------------- +void C_Prop_Portal::GetToolRecordingState( KeyValues *msg ) +{ + if ( !ToolsEnabled() ) + return; + + VPROF_BUDGET( "C_Prop_Portal::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS ); + BaseClass::GetToolRecordingState( m_bActivated, msg ); + + if ( !m_bActivated ) + { + BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" ); + pBaseEntity->m_bVisible = false; + } +} + +void C_Prop_Portal::UpdateOriginPlane( void ) +{ + //setup our origin plane + GetVectors( &m_plane_Origin.normal, NULL, NULL ); + m_plane_Origin.dist = m_plane_Origin.normal.Dot( GetAbsOrigin() ); + 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; + } + } +} + +void C_Prop_Portal::SetIsPortal2( bool bValue ) +{ + m_bIsPortal2 = bValue; +} + +bool C_Prop_Portal::IsActivedAndLinked( void ) const +{ + return ( m_bActivated && m_hLinkedPortal.Get() != NULL ); +} |