add hl1,portal,dod source code

This commit is contained in:
nillerusr
2022-04-16 12:05:19 +03:00
parent bc6873014e
commit 23a370d9bb
524 changed files with 174173 additions and 0 deletions
@@ -0,0 +1,377 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "C_PortalGhostRenderable.h"
#include "PortalRender.h"
#include "c_portal_player.h"
#include "model_types.h"
C_PortalGhostRenderable::C_PortalGhostRenderable( C_Prop_Portal *pOwningPortal, C_BaseEntity *pGhostSource, RenderGroup_t sourceRenderGroup, const VMatrix &matGhostTransform, float *pSharedRenderClipPlane, bool bLocalPlayer )
: m_pGhostedRenderable( pGhostSource ),
m_matGhostTransform( matGhostTransform ),
m_pSharedRenderClipPlane( pSharedRenderClipPlane ),
m_bLocalPlayer( bLocalPlayer ),
m_pOwningPortal( pOwningPortal )
{
m_bSourceIsBaseAnimating = (dynamic_cast<C_BaseAnimating *>(pGhostSource) != NULL);
cl_entitylist->AddNonNetworkableEntity( GetIClientUnknown() );
g_pClientLeafSystem->AddRenderable( this, sourceRenderGroup );
}
C_PortalGhostRenderable::~C_PortalGhostRenderable( void )
{
m_pGhostedRenderable = NULL;
g_pClientLeafSystem->RemoveRenderable( RenderHandle() );
cl_entitylist->RemoveEntity( GetIClientUnknown()->GetRefEHandle() );
DestroyModelInstance();
}
void C_PortalGhostRenderable::PerFrameUpdate( void )
{
if( m_pGhostedRenderable )
{
SetModelName( m_pGhostedRenderable->GetModelName() );
SetModelIndex( m_pGhostedRenderable->GetModelIndex() );
SetEffects( m_pGhostedRenderable->GetEffects() | EF_NOINTERP );
m_flAnimTime = m_pGhostedRenderable->m_flAnimTime;
if( m_bSourceIsBaseAnimating )
{
C_BaseAnimating *pSource = (C_BaseAnimating *)m_pGhostedRenderable;
SetCycle( pSource->GetCycle() );
SetSequence( pSource->GetSequence() );
m_nBody = pSource->m_nBody;
m_nSkin = pSource->m_nSkin;
}
}
// Set position and angles relative to the object it's ghosting
Vector ptNewOrigin = m_matGhostTransform * m_pGhostedRenderable->GetAbsOrigin();
QAngle qNewAngles = TransformAnglesToWorldSpace( m_pGhostedRenderable->GetAbsAngles(), m_matGhostTransform.As3x4() );
SetAbsOrigin( ptNewOrigin );
SetAbsAngles( qNewAngles );
AddEffects( EF_NOINTERP );
RemoveFromInterpolationList();
g_pClientLeafSystem->RenderableChanged( RenderHandle() );
}
Vector const& C_PortalGhostRenderable::GetRenderOrigin( void )
{
if( m_pGhostedRenderable == NULL )
return m_ReferencedReturns.vRenderOrigin;
m_ReferencedReturns.vRenderOrigin = m_matGhostTransform * m_pGhostedRenderable->GetRenderOrigin();
return m_ReferencedReturns.vRenderOrigin;
}
QAngle const& C_PortalGhostRenderable::GetRenderAngles( void )
{
if( m_pGhostedRenderable == NULL )
return m_ReferencedReturns.qRenderAngle;
m_ReferencedReturns.qRenderAngle = TransformAnglesToWorldSpace( m_pGhostedRenderable->GetRenderAngles(), m_matGhostTransform.As3x4() );
return m_ReferencedReturns.qRenderAngle;
}
bool C_PortalGhostRenderable::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
{
if( m_pGhostedRenderable == NULL )
return false;
int nModelIndex = 0;
CBaseCombatWeapon *pParent = dynamic_cast<CBaseCombatWeapon*>( m_pGhostedRenderable );
if ( pParent )
{
nModelIndex = pParent->GetModelIndex();
pParent->SetModelIndex( pParent->GetWorldModelIndex() );
}
if( m_pGhostedRenderable->SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime ) )
{
if( pBoneToWorldOut )
{
for( int i = 0; i != nMaxBones; ++i ) //FIXME: nMaxBones is most definitely greater than the actual number of bone transforms actually used, find the subset somehow
{
pBoneToWorldOut[i] = (m_matGhostTransform * pBoneToWorldOut[i]).As3x4();
}
}
return true;
}
if ( pParent )
{
pParent->SetModelIndex( nModelIndex );
}
return false;
}
void C_PortalGhostRenderable::GetRenderBounds( Vector& mins, Vector& maxs )
{
if( m_pGhostedRenderable == NULL )
{
mins = maxs = vec3_origin;
return;
}
m_pGhostedRenderable->GetRenderBounds( mins, maxs );
}
void C_PortalGhostRenderable::GetRenderBoundsWorldspace( Vector& mins, Vector& maxs )
{
if( m_pGhostedRenderable == NULL )
{
mins = maxs = vec3_origin;
return;
}
m_pGhostedRenderable->GetRenderBoundsWorldspace( mins, maxs );
TransformAABB( m_matGhostTransform.As3x4(), mins, maxs, mins, maxs );
}
void C_PortalGhostRenderable::GetShadowRenderBounds( Vector &mins, Vector &maxs, ShadowType_t shadowType )
{
m_pGhostedRenderable->GetShadowRenderBounds( mins, maxs, shadowType );
TransformAABB( m_matGhostTransform.As3x4(), mins, maxs, mins, maxs );
}
/*bool C_PortalGhostRenderable::GetShadowCastDistance( float *pDist, ShadowType_t shadowType ) const
{
if( m_pGhostedRenderable == NULL )
return false;
return m_pGhostedRenderable->GetShadowCastDistance( pDist, shadowType );
}
bool C_PortalGhostRenderable::GetShadowCastDirection( Vector *pDirection, ShadowType_t shadowType ) const
{
if( m_pGhostedRenderable == NULL )
return false;
if( m_pGhostedRenderable->GetShadowCastDirection( pDirection, shadowType ) )
{
if( pDirection )
*pDirection = m_matGhostTransform.ApplyRotation( *pDirection );
return true;
}
return false;
}*/
const matrix3x4_t & C_PortalGhostRenderable::RenderableToWorldTransform()
{
if( m_pGhostedRenderable == NULL )
return m_ReferencedReturns.matRenderableToWorldTransform;
ConcatTransforms( m_matGhostTransform.As3x4(), m_pGhostedRenderable->RenderableToWorldTransform(), m_ReferencedReturns.matRenderableToWorldTransform );
return m_ReferencedReturns.matRenderableToWorldTransform;
}
bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin, QAngle &angles )
{
if( m_pGhostedRenderable == NULL )
return false;
if( m_pGhostedRenderable->GetAttachment( number, origin, angles ) )
{
origin = m_matGhostTransform * origin;
angles = TransformAnglesToWorldSpace( angles, m_matGhostTransform.As3x4() );
return true;
}
return false;
}
bool C_PortalGhostRenderable::GetAttachment( int number, matrix3x4_t &matrix )
{
if( m_pGhostedRenderable == NULL )
return false;
if( m_pGhostedRenderable->GetAttachment( number, matrix ) )
{
ConcatTransforms( m_matGhostTransform.As3x4(), matrix, matrix );
return true;
}
return false;
}
bool C_PortalGhostRenderable::GetAttachment( int number, Vector &origin )
{
if( m_pGhostedRenderable == NULL )
return false;
if( m_pGhostedRenderable->GetAttachment( number, origin ) )
{
origin = m_matGhostTransform * origin;
return true;
}
return false;
}
bool C_PortalGhostRenderable::GetAttachmentVelocity( int number, Vector &originVel, Quaternion &angleVel )
{
if( m_pGhostedRenderable == NULL )
return false;
Vector ghostVel;
if( m_pGhostedRenderable->GetAttachmentVelocity( number, ghostVel, angleVel ) )
{
Vector3DMultiply( m_matGhostTransform, ghostVel, originVel );
Vector3DMultiply( m_matGhostTransform, *(Vector*)( &angleVel ), *(Vector*)( &angleVel ) );
return true;
}
return false;
}
int C_PortalGhostRenderable::DrawModel( int flags )
{
if( m_bSourceIsBaseAnimating )
{
if( m_bLocalPlayer )
{
C_Portal_Player *pPlayer = C_Portal_Player::GetLocalPlayer();
if ( !pPlayer->IsAlive() )
{
// Dead player uses a ragdoll to draw, so don't ghost the dead entity
return 0;
}
else if( g_pPortalRender->GetViewRecursionLevel() == 0 )
{
if( pPlayer->m_bEyePositionIsTransformedByPortal )
return 0;
}
else if( g_pPortalRender->GetViewRecursionLevel() == 1 )
{
if( !pPlayer->m_bEyePositionIsTransformedByPortal )
return 0;
}
}
return C_BaseAnimating::DrawModel( flags );
}
else
{
DrawBrushModelMode_t mode = DBM_DRAW_ALL;
if ( flags & STUDIO_TWOPASS )
{
mode = ( flags & STUDIO_TRANSPARENCY ) ? DBM_DRAW_TRANSLUCENT_ONLY : DBM_DRAW_OPAQUE_ONLY;
}
render->DrawBrushModelEx( m_pGhostedRenderable,
(model_t *)m_pGhostedRenderable->GetModel(),
GetRenderOrigin(),
GetRenderAngles(),
mode );
return 1;
}
return 0;
}
ModelInstanceHandle_t C_PortalGhostRenderable::GetModelInstance()
{
if ( m_pGhostedRenderable )
return m_pGhostedRenderable->GetModelInstance();
return BaseClass::GetModelInstance();
}
bool C_PortalGhostRenderable::IsTransparent( void )
{
if( m_pGhostedRenderable == NULL )
return false;
return m_pGhostedRenderable->IsTransparent();
}
bool C_PortalGhostRenderable::UsesPowerOfTwoFrameBufferTexture()
{
if( m_pGhostedRenderable == NULL )
return false;
return m_pGhostedRenderable->UsesPowerOfTwoFrameBufferTexture();
}
/*const model_t* C_PortalGhostRenderable::GetModel( ) const
{
if( m_pGhostedRenderable == NULL )
return NULL;
return m_pGhostedRenderable->GetModel();
}
int C_PortalGhostRenderable::GetBody()
{
if( m_pGhostedRenderable == NULL )
return 0;
return m_pGhostedRenderable->GetBody();
}*/
void C_PortalGhostRenderable::GetColorModulation( float* color )
{
if( m_pGhostedRenderable == NULL )
return;
return m_pGhostedRenderable->GetColorModulation( color );
}
/*ShadowType_t C_PortalGhostRenderable::ShadowCastType()
{
if( m_pGhostedRenderable == NULL )
return SHADOWS_NONE;
return m_pGhostedRenderable->ShadowCastType();
}*/
int C_PortalGhostRenderable::LookupAttachment( const char *pAttachmentName )
{
if( m_pGhostedRenderable == NULL )
return -1;
return m_pGhostedRenderable->LookupAttachment( pAttachmentName );
}
/*int C_PortalGhostRenderable::GetSkin()
{
if( m_pGhostedRenderable == NULL )
return -1;
return m_pGhostedRenderable->GetSkin();
}
bool C_PortalGhostRenderable::IsTwoPass( void )
{
if( m_pGhostedRenderable == NULL )
return false;
return m_pGhostedRenderable->IsTwoPass();
}*/
@@ -0,0 +1,128 @@
//========= Copyright 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"
class C_PortalGhostRenderable : public C_BaseAnimating//IClientRenderable, public IClientUnknown
{
public:
C_BaseEntity *m_pGhostedRenderable; //the renderable we're transforming and re-rendering
VMatrix m_matGhostTransform;
float *m_pSharedRenderClipPlane; //shared by all portal ghost renderables within the same portal
bool m_bLocalPlayer; //special draw rules for the local player
bool m_bSourceIsBaseAnimating;
C_Prop_Portal *m_pOwningPortal;
struct
{
Vector vRenderOrigin;
QAngle qRenderAngle;
matrix3x4_t matRenderableToWorldTransform;
} m_ReferencedReturns; //when returning a reference, it has to actually exist somewhere
C_PortalGhostRenderable( C_Prop_Portal *pOwningPortal, C_BaseEntity *pGhostSource, RenderGroup_t sourceRenderGroup, const VMatrix &matGhostTransform, float *pSharedRenderClipPlane, bool bLocalPlayer );
virtual ~C_PortalGhostRenderable( 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 true; }
// 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( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime );
// 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 ) { return m_pSharedRenderClipPlane; };
virtual int DrawModel( int flags );
// Get the model instance of the ghosted model so that decals will properly draw across portals
virtual ModelInstanceHandle_t GetModelInstance();
//------------------------------------------
//IClientRenderable - Trivial or redirection
//------------------------------------------
virtual IClientUnknown* GetIClientUnknown() { return this; };
virtual bool IsTransparent( void );
virtual bool UsesPowerOfTwoFrameBufferTexture();
//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; };
//IClientUnknown
virtual ICollideable* GetCollideable() { return NULL; };
virtual IClientNetworkable* GetClientNetworkable() { return NULL; };
virtual IClientRenderable* GetClientRenderable() { return this; };
virtual IClientEntity* GetIClientEntity() { return NULL; };
virtual C_BaseEntity* GetBaseEntity() { return NULL; };
virtual IClientThinkable* GetClientThinkable() { return NULL; };
};
#endif //#ifndef C_PORTALGHOSTRENDERABLE_H
@@ -0,0 +1,127 @@
//========= Copyright 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 "toolframework_client.h"
#include "portalrenderable_flatbasic.h"
#include <KeyValues.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 );
CPortalRenderable_FlatBasic *pFlatBasic = dynamic_cast<CPortalRenderable_FlatBasic*>( 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() );
}
if ( ToolsEnabled() )
{
ToolFramework_RecordMaterialParams( GetMaterial() );
}
}
EXPOSE_INTERFACE( CPortalPickAlphaMaskProxy, IMaterialProxy, "PortalPickAlphaMask" IMATERIAL_PROXY_INTERFACE_VERSION );
File diff suppressed because it is too large Load Diff
+333
View File
@@ -0,0 +1,333 @@
//========= Copyright 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"
#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 CPortalRenderable
{
public:
CPortalRenderable( void );
virtual ~CPortalRenderable( void );
//----------------------------------------------------------------------------
//Stencil-based drawing helpers, these are ONLY used in stencil drawing mode
//----------------------------------------------------------------------------
virtual void DrawPreStencilMask( void ) { }; //Do whatever drawing you need before cutting the stencil hole
virtual void DrawStencilMask( void ) { }; //Draw to wherever you should see through the portal. The mask will later be filled with the portal view.
virtual void DrawPostStencilFixes( void ) { }; //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;
//-----------------------------------------------------------------------------
//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 &currentView, CUtlVector<VPlane> &currentComplexFrustum ) { 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( void ) { }; //sort of like what you'd expect to happen in C_BaseAnimating::DrawModel() if portals were fully compatible with models
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
//-----------------------------------------------------------------------------
//SFM related
//-----------------------------------------------------------------------------
bool m_bIsPlaybackPortal;
virtual void GetToolRecordingState( bool bActive, KeyValues *msg ) { };
virtual void HandlePortalPlaybackMessage( KeyValues *pKeyValues ) { };
protected:
//-----------------------------------------------------------------------------
// Wrap the draw of the surface that makes use of your portal render targets with these. Only required for texture mode, but won't hurt stencil mode.
// Using these will allow you to know whether it's worth drawing the other side of a portal next frame.
//-----------------------------------------------------------------------------
void BeginPortalPixelVisibilityQuery( void );
void EndPortalPixelVisibilityQuery( void );
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 );
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
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;
};
typedef CPortalRenderable *(*PortalRenderableCreationFunc)( void );
struct PortalRenderableCreationFunction_t
{
CUtlString portalType;
PortalRenderableCreationFunc creationFunc;
};
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;
};
//-----------------------------------------------------------------------------
// Portal rendering management class
//-----------------------------------------------------------------------------
class CPortalRender : public CAutoGameSystem
{
public:
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
// true if the rendering path for portals uses stencils instead of textures
bool ShouldUseStencilsToRenderPortals() const;
//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;
//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 );
void DrawPortalsToTextures( CViewRender *pViewRender, const CViewSetup &cameraView ); //updates portal textures
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
void EnteredPortal( 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;
const Vector &GetExitPortalFogOrigin() const;
SkyboxVisibility_t IsSkyboxVisibleFromExitPortal() const;
bool DoesExitPortalViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const;
void HandlePortalPlaybackMessage( KeyValues *pKeyValues );
CPortalRenderable* FindRecordedPortal( IClientRenderable *pRenderable );
void AddPortalCreationFunc( const char *szPortalType, PortalRenderableCreationFunc creationFunc );
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 );
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 );
CUtlVector<PortalRenderableCreationFunction_t> m_PortalRenderableCreators; //for SFM compatibility
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
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;
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
CUtlVector<VPlane> m_RecursiveViewComplexFrustums[MAX_PORTAL_RECURSIVE_VIEWS];
const 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 );
}
class CPortalRenderableCreator //create one of these as a global and ensure you register exactly once
{
public:
CPortalRenderableCreator( const char *szPortalType, PortalRenderableCreationFunc creationFunction )
{
g_pPortalRender->AddPortalCreationFunc( szPortalType, creationFunction );
}
};
//-----------------------------------------------------------------------------
// 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
@@ -0,0 +1,183 @@
//========= Copyright 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;
}
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 );
}
@@ -0,0 +1,32 @@
//========= Copyright 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 );
#endif //#ifndef PORTAL_DYNAMICMESHRENDERINGUTILS_H
@@ -0,0 +1,499 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "particles_simple.h"
#include "env_lightrail_endpoint_shared.h"
#include "particles_attractor.h"
#include "fx_quad.h"
class C_Env_Lightrail_Endpoint : public C_BaseEntity
{
DECLARE_CLASS( C_Env_Lightrail_Endpoint, C_BaseEntity );
DECLARE_CLIENTCLASS();
public:
void OnDataChanged( DataUpdateType_t updateType );
RenderGroup_t GetRenderGroup( void );
void ClientThink( void );
void NotifyShouldTransmit( ShouldTransmitState_t state );
void UpdateIdle( float percentage );
void UpdateCharging( float percentage ); //Update the charging state
void UpdateLargeFX( void ); //Update Discharging Large FX
void UpdateSmallFX( void ); //Update Discharging Small FX
private:
bool SetupEmitters( void );
inline float GetStateDurationPercentage( void );
float m_flSmallScale;
float m_flLargeScale;
int m_nState;
float m_flDuration;
float m_flStartTime;
int m_spawnflags;
CSmartPtr<CSimpleEmitter> m_pSimpleEmitter;
CSmartPtr<CParticleAttractor> m_pAttractorEmitter;
};
IMPLEMENT_CLIENTCLASS_DT( C_Env_Lightrail_Endpoint, DT_Env_Lightrail_Endpoint, CEnv_Lightrail_Endpoint )
RecvPropFloat( RECVINFO(m_flSmallScale) ),
RecvPropFloat( RECVINFO(m_flLargeScale) ),
RecvPropInt( RECVINFO(m_nState) ),
RecvPropFloat( RECVINFO(m_flDuration) ),
RecvPropFloat( RECVINFO(m_flStartTime) ),
RecvPropInt( RECVINFO(m_spawnflags) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
// Output : RenderGroup_t
//-----------------------------------------------------------------------------
RenderGroup_t C_Env_Lightrail_Endpoint::GetRenderGroup( void )
{
return RENDER_GROUP_TRANSLUCENT_ENTITY;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_Env_Lightrail_Endpoint::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
SetupEmitters();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_Env_Lightrail_Endpoint::SetupEmitters( void )
{
// Setup the basic core emitter
if ( m_pSimpleEmitter.IsValid() == false )
{
m_pSimpleEmitter = CSimpleEmitter::Create( "energycore" );
if ( m_pSimpleEmitter.IsValid() == false )
return false;
}
// Setup the attractor emitter
if ( m_pAttractorEmitter.IsValid() == false )
{
m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "energyattractor" );
if ( m_pAttractorEmitter.IsValid() == false )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_Env_Lightrail_Endpoint::UpdateIdle( float percentage )
{
// Only do these particles if required
//if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES )
// return;
// Must be active
if ( percentage >= 1.0f )
return;
// Emitters must be valid
if ( SetupEmitters() == false )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
SimpleParticle *sParticle;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
Vector offset;
float dist;
int numParticles = floor( 4.0f * percentage );
for ( int i = 0; i < numParticles; i++ )
{
dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f );
offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/strider_muzzle" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,8);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255 * percentage;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_Env_Lightrail_Endpoint::UpdateCharging( float percentage )
{
// Emitters must be valid
if ( SetupEmitters() == false )
return;
if ( percentage <= 0.0f )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
float flLargeScale = 4.0f * m_flLargeScale * percentage;
//float flSmallScale = 4.0f * m_flSmallScale * percentage;
SimpleParticle *sParticle;
// Do the core effects
for ( int i = 0; i < 2; i++ )
{
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.1f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
if ( i < 2 )
{
sParticle->m_uchStartSize = flLargeScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
else
{
if ( random->RandomInt( 0, 20 ) == 0 )
{
sParticle->m_uchStartSize = flLargeScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f;
sParticle->m_flDieTime = 0.25f;
}
else
{
sParticle->m_uchStartSize = flLargeScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
}
}
// Only do these particles if required
//if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES )
// return;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
Vector offset;
float dist;
int numParticles = floor( 4.0f * percentage );
for ( int i = 0; i < numParticles; i++ )
{
dist = random->RandomFloat( 4.0f * percentage, 64.0f * percentage );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * percentage, 64.0f * percentage, 6.0f, 1.0f );
offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/strider_muzzle" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,8);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255 * percentage;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_Env_Lightrail_Endpoint::UpdateSmallFX( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : percentage -
//-----------------------------------------------------------------------------
void C_Env_Lightrail_Endpoint::UpdateLargeFX( void )
{
// Emitters must be valid
if ( SetupEmitters() == false )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
float flLargeScale = 8.0f * m_flLargeScale;
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
SimpleParticle *sParticle;
// Base of the core effect
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = forward * 32.0f;
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 128;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = flLargeScale * 2.0f;
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
// Make sure we encompass the complete particle here!
m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize );
// Do the core effects
for ( int i = 0; i < 2; i++ )
{
sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/combinemuzzle2" ), GetAbsOrigin() );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = forward * ( 32.0f * (i+1) );
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 100;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
if ( i < 1 )
{
sParticle->m_uchStartSize = flLargeScale * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
else
{
if ( random->RandomInt( 0, 20 ) == 0 )
{
sParticle->m_uchStartSize = flLargeScale * (i+1);
sParticle->m_uchEndSize = 0.0f;
sParticle->m_flDieTime = 0.25f;
}
else
{
sParticle->m_uchStartSize = flLargeScale * (i+1);
sParticle->m_uchEndSize = 0.0f;
}
}
}
// Only do these particles if required
//if ( m_spawnflags & SF_ENERGYCORE_NO_PARTICLES )
// return;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector offset;
float dist;
for ( int i = 0; i < 4; i++ )
{
dist = random->RandomFloat( 4.0f * m_flLargeScale, 64.0f * m_flLargeScale );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f * m_flLargeScale, 64.0f * m_flLargeScale, 6.0f, 1.0f );
offset += right * random->RandomFloat( -2.0f * dist * m_flLargeScale, 2.0f * dist * m_flLargeScale );
offset += up * random->RandomFloat( -2.0f * dist * m_flLargeScale, 2.0f * dist * m_flLargeScale );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/combinemuzzle2_dark" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,2);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 1;
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : inline float
//-----------------------------------------------------------------------------
inline float C_Env_Lightrail_Endpoint::GetStateDurationPercentage( void )
{
if ( m_flDuration == 0 )
return 0.0f;
return RemapValClamped( ( gpGlobals->curtime - m_flStartTime ), 0, m_flDuration, 0, 1.0f );;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_Env_Lightrail_Endpoint::NotifyShouldTransmit( ShouldTransmitState_t state )
{
BaseClass::NotifyShouldTransmit( state );
// Turn off
if ( state == SHOULDTRANSMIT_END )
{
SetNextClientThink( CLIENT_THINK_NEVER );
}
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_Env_Lightrail_Endpoint::ClientThink( void )
{
if ( gpGlobals->frametime <= 0.0f )
return;
float flDuration = GetStateDurationPercentage();
switch( m_nState )
{
case ENDPOINT_STATE_OFF:
UpdateIdle( 1.0f - flDuration );
break;
case ENDPOINT_STATE_CHARGING:
UpdateCharging( flDuration );
break;
case ENDPOINT_STATE_SMALLFX:
UpdateSmallFX( );
break;
case ENDPOINT_STATE_LARGEFX:
UpdateLargeFX( );
break;
}
}
@@ -0,0 +1,203 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Client Side Effects for the env_portal_path_track.
//
//=============================================================================//
#include "cbase.h"
#include "env_portal_path_track_shared.h"
#include "particles_simple.h"
#include "particles_attractor.h"
class C_EnvPortalPathTrack : public C_BaseEntity
{
DECLARE_CLASS( C_EnvPortalPathTrack, C_BaseEntity );
DECLARE_CLIENTCLASS();
public:
void OnDataChanged( DataUpdateType_t updateType );
RenderGroup_t GetRenderGroup( void );
void ClientThink( void );
void NotifyShouldTransmit( ShouldTransmitState_t state );
void UpdateParticles_Inactive( void );
void UpdateParticles_Active( void );
private:
float m_flScale;
int m_nState;
float m_flDuration;
float m_flStartTime;
bool m_bTrackActive;
bool m_bEndpointActive;
bool SetupEmitters( void ); // Init our particle emitters
CSmartPtr<CSimpleEmitter> m_pSimpleEmitter; // particle system, emits particles
CSmartPtr<CParticleAttractor> m_pAttractorEmitter; // particle system, attracts particles
};
IMPLEMENT_CLIENTCLASS_DT( C_EnvPortalPathTrack, DT_EnvPortalPathTrack, CEnvPortalPathTrack )
RecvPropBool( RECVINFO(m_bTrackActive) ),
RecvPropBool( RECVINFO(m_bEndpointActive) ),
RecvPropInt( RECVINFO(m_nState) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Purpose:
// Output : RenderGroup_t
//-----------------------------------------------------------------------------
RenderGroup_t C_EnvPortalPathTrack::GetRenderGroup( void )
{
return RENDER_GROUP_TRANSLUCENT_ENTITY;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : updateType -
//-----------------------------------------------------------------------------
void C_EnvPortalPathTrack::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_CREATED )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool C_EnvPortalPathTrack::SetupEmitters( void )
{
// Setup the basic core emitter
if ( m_pSimpleEmitter.IsValid() == false )
{
m_pSimpleEmitter = CSimpleEmitter::Create( "portaltracktrainendpoint" );
if ( m_pSimpleEmitter.IsValid() == false )
return false;
}
// Setup the attractor emitter
if ( m_pAttractorEmitter.IsValid() == false )
{
m_pAttractorEmitter = CParticleAttractor::Create( GetAbsOrigin(), "portaltracktrainendpointattractor" );
if ( m_pAttractorEmitter.IsValid() == false )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EnvPortalPathTrack::ClientThink( void )
{
if ( gpGlobals->frametime <= 0.0f )
return;
switch( m_nState )
{
case PORTAL_PATH_TRACK_STATE_OFF:
break;
case PORTAL_PATH_TRACK_STATE_INACTIVE:
UpdateParticles_Inactive();
break;
case PORTAL_PATH_TRACK_STATE_ACTIVE:
UpdateParticles_Active();
break;
}
}
void C_EnvPortalPathTrack::UpdateParticles_Inactive( void )
{
}
void C_EnvPortalPathTrack::UpdateParticles_Active ( void )
{
// Emitters must be valid
if ( SetupEmitters() == false )
return;
// Reset our sort origin
m_pSimpleEmitter->SetSortOrigin( GetAbsOrigin() );
SimpleParticle *sParticle;
// Do the charging particles
m_pAttractorEmitter->SetAttractorOrigin( GetAbsOrigin() );
Vector forward, right, up;
AngleVectors( GetAbsAngles(), &forward, &right, &up );
Vector offset;
float dist;
int numParticles = floor( 4.0f );
for ( int i = 0; i < numParticles; i++ )
{
dist = random->RandomFloat( 4.0f, 64.0f );
offset = forward * dist;
dist = RemapValClamped( dist, 4.0f, 64.0f, 6.0f, 1.0f );
offset += right * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += up * random->RandomFloat( -4.0f * dist, 4.0f * dist );
offset += GetAbsOrigin();
sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), m_pAttractorEmitter->GetPMaterial( "effects/strider_muzzle" ), offset );
if ( sParticle == NULL )
return;
sParticle->m_vecVelocity = Vector(0,0,8);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void C_EnvPortalPathTrack::NotifyShouldTransmit( ShouldTransmitState_t state )
{
BaseClass::NotifyShouldTransmit( state );
// Turn off
if ( state == SHOULDTRANSMIT_END )
{
SetNextClientThink( CLIENT_THINK_NEVER );
}
// Turn on
if ( state == SHOULDTRANSMIT_START )
{
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
}
+630
View File
@@ -0,0 +1,630 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Rising liquid that acts as a one-way portal
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_func_liquidportal.h"
#include "debugoverlay_shared.h"
#include "view_scene.h"
#include "view.h"
#include "ScreenSpaceEffects.h"
#include "materialsystem/imaterialvar.h"
LINK_ENTITY_TO_CLASS( func_liquidportal, C_Func_LiquidPortal );
IMPLEMENT_CLIENTCLASS_DT( C_Func_LiquidPortal, DT_Func_LiquidPortal, CFunc_LiquidPortal )
RecvPropEHandle( RECVINFO(m_hLinkedPortal) ),
RecvPropFloat( RECVINFO(m_fFillStartTime) ),
RecvPropFloat( RECVINFO(m_fFillEndTime) ),
END_RECV_TABLE()
#define LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( vertnum, xtexbase, xtexscale, ytexbase, ytexscale )\
meshBuilder.Position3fv( &vVertices[vertnum].x );\
meshBuilder.TexCoord2f( 0, vVertices[vertnum].xtexbase * xtexscale, vVertices[vertnum].ytexbase * ytexscale );\
meshBuilder.AdvanceVertex();
C_Func_LiquidPortal::C_Func_LiquidPortal( void )
{
g_pPortalRender->AddPortal( this );
}
C_Func_LiquidPortal::~C_Func_LiquidPortal( void )
{
g_pPortalRender->RemovePortal( this );
}
int C_Func_LiquidPortal::DrawModel( int flags )
{
if( IsFillingNow() )
{
DrawPortal();
return 1;
}
return 0;
}
void C_Func_LiquidPortal::OnDataChanged( DataUpdateType_t updateType )
{
GetRenderBoundsWorldspace( m_vAABBMins, m_vAABBMaxs );
m_pLinkedPortal = m_hLinkedPortal.Get();
ComputeLinkMatrix();
UpdateBoundingPlanes();
}
void C_Func_LiquidPortal::ComputeLinkMatrix( void )
{
C_Func_LiquidPortal *pLinkedPortal = m_hLinkedPortal.Get();
if( pLinkedPortal )
{
VMatrix matLocalToWorld, matLocalToWorldInv, matRemoteToWorld;
//matLocalToWorld.Identity();
//matLocalToWorld.SetTranslation( CollisionProp()->WorldSpaceCenter() );
matLocalToWorld = EntityToWorldTransform();
//matRemoteToWorld.Identity();
//matRemoteToWorld.SetTranslation( pLinkedPortal->CollisionProp()->WorldSpaceCenter() );
matRemoteToWorld = pLinkedPortal->EntityToWorldTransform();
MatrixInverseTR( matLocalToWorld, matLocalToWorldInv );
m_matrixThisToLinked = matRemoteToWorld * matLocalToWorldInv;
MatrixInverseTR( m_matrixThisToLinked, pLinkedPortal->m_matrixThisToLinked );
}
else
{
m_matrixThisToLinked.Identity();
}
}
void CPortalRenderable_Func_LiquidPortal::UpdateBoundingPlanes( void )
{
//x min
m_fBoundingPlanes[0][0] = 1.0f;
m_fBoundingPlanes[0][1] = 0.0f;
m_fBoundingPlanes[0][2] = 0.0f;
m_fBoundingPlanes[0][3] = m_vAABBMins.x;
//x max
m_fBoundingPlanes[1][0] = -1.0f;
m_fBoundingPlanes[1][1] = 0.0f;
m_fBoundingPlanes[1][2] = 0.0f;
m_fBoundingPlanes[1][3] = -m_vAABBMaxs.x;
//y min
m_fBoundingPlanes[2][0] = 0.0f;
m_fBoundingPlanes[2][1] = 1.0f;
m_fBoundingPlanes[2][2] = 0.0f;
m_fBoundingPlanes[2][3] = m_vAABBMins.y;
//y max
m_fBoundingPlanes[3][0] = 0.0f;
m_fBoundingPlanes[3][1] = -1.0f;
m_fBoundingPlanes[3][2] = 0.0f;
m_fBoundingPlanes[3][3] = -m_vAABBMaxs.y;
//z min
m_fBoundingPlanes[4][0] = 0.0f;
m_fBoundingPlanes[4][1] = 0.0f;
m_fBoundingPlanes[4][2] = 1.0f;
m_fBoundingPlanes[4][3] = m_vAABBMins.z;
//z max is too variable to store
}
void CPortalRenderable_Func_LiquidPortal::DrawPreStencilMask( void )
{
// Should we do something here like flatbasic?
}
void CPortalRenderable_Func_LiquidPortal::DrawStencilMask( void )
{
DrawOutwardBox( g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
DrawInnerLiquid( true, 1.0f, g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
}
void CPortalRenderable_Func_LiquidPortal::DrawPostStencilFixes( void )
{
DrawOutwardBox( g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
DrawInnerLiquid( true, 1.0f, g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
}
void CPortalRenderable_Func_LiquidPortal::RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView )
{
if( m_pLinkedPortal == NULL ) //not linked to any portal
return;
Frustum FrustumBackup;
memcpy( FrustumBackup, pViewRender->GetFrustum(), sizeof( Frustum ) );
Frustum seeThroughFrustum;
bool bUseSeeThroughFrustum;
if ( g_pPortalRender->GetViewRecursionLevel() == 0 )
{
bUseSeeThroughFrustum = CalcFrustumThroughPortal( cameraView.origin, seeThroughFrustum, pViewRender->GetFrustum(), FRUSTUM_NUMPLANES );
}
else
{
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;
QAngle qPOVAngles = TransformAnglesToWorldSpace( cameraView.angles, m_matrixThisToLinked.As3x4() );
portalView.width = cameraView.width;
portalView.height = cameraView.height;
portalView.x = 0;
portalView.y = 0;
portalView.origin = ptPOVOrigin;
portalView.angles = qPOVAngles;
portalView.fov = cameraView.fov;
portalView.m_bOrtho = false;
portalView.m_flAspectRatio = cameraView.m_flAspectRatio; //use the screen aspect ratio, 0.0f doesn't work as advertised
CopyToCurrentView( pViewRender, portalView );
CMatRenderContextPtr pRenderContext( materials );
{
ViewCustomVisibility_t customVisibility;
m_pLinkedPortal->AddToVisAsExitPortal( &customVisibility );
render->Push3DView( 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 );
SetViewRecursionLevel( g_pPortalRender->GetViewRecursionLevel() - 1 );
}
render->PopView( pViewRender->GetFrustum() );
//restore old frustum
memcpy( pViewRender->GetFrustum(), FrustumBackup, sizeof( Frustum ) );
render->OverrideViewFrustum( FrustumBackup );
}
//restore old vis data
CopyToCurrentView( pViewRender, cameraView );
}
void CPortalRenderable_Func_LiquidPortal::RenderPortalViewToTexture( CViewRender *pViewRender, const CViewSetup &cameraView )
{
}
void CPortalRenderable_Func_LiquidPortal::AddToVisAsExitPortal( ViewCustomVisibility_t *pCustomVisibility )
{
if ( !pCustomVisibility )
return;
VisOverrideData_t visOverride;
Vector vOrigin = (m_vAABBMins + m_vAABBMaxs) * 0.5f;
visOverride.m_vecVisOrigin = vOrigin;
visOverride.m_fDistToAreaPortalTolerance = 64.0f;
// Specify which leaf to use for area portal culling
pCustomVisibility->ForceVisOverride( visOverride );
pCustomVisibility->ForceViewLeaf( enginetrace->GetLeafContainingPoint( vOrigin ) );
pCustomVisibility->AddVisOrigin( vOrigin );
}
bool CPortalRenderable_Func_LiquidPortal::DoesExitViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const
{
return ((m_vAABBMins.z < waterZ) && (m_vAABBMaxs.z > waterZ));
}
SkyboxVisibility_t CPortalRenderable_Func_LiquidPortal::SkyBoxVisibleFromPortal( void )
{
return SKYBOX_NOT_VISIBLE;
}
bool CPortalRenderable_Func_LiquidPortal::CalcFrustumThroughPortal( const Vector &ptCurrentViewOrigin, Frustum OutputFrustum, const VPlane *pInputFrustum, int iInputFrustumPlaneCount )
{
return false;
}
const Vector& CPortalRenderable_Func_LiquidPortal::GetFogOrigin( void ) const
{
return vec3_origin;
}
void CPortalRenderable_Func_LiquidPortal::ShiftFogForExitPortalView() const
{
}
bool CPortalRenderable_Func_LiquidPortal::ShouldUpdatePortalView_BasedOnView( const CViewSetup &currentView, Frustum currentFrustum )
{
//return false;
return IsFillingNow();
}
CPortalRenderable* CPortalRenderable_Func_LiquidPortal::GetLinkedPortal() const
{
return m_pLinkedPortal;
}
bool CPortalRenderable_Func_LiquidPortal::ShouldUpdateDepthDoublerTexture( const CViewSetup &viewSetup )
{
return false;
}
void CPortalRenderable_Func_LiquidPortal::DrawPortal( void )
{
if( IsFillingNow() )
{
//"shadertest/gooinglass"
//"glass/glasswindow_refract01"
//IMaterial *pMaterial = materials->FindMaterial( "glass/glasswindow_refract01", TEXTURE_GROUP_OTHER );
//UpdateFrontBufferTexturesForMaterial( (IMaterial *)pMaterial );
DrawOutwardBox();
//DrawInnerLiquid( pMaterial );
//DrawInwardBox( pMaterial );
}
}
void CPortalRenderable_Func_LiquidPortal::GetToolRecordingState( bool bActive, KeyValues *msg )
{
}
void CPortalRenderable_Func_LiquidPortal::HandlePortalPlaybackMessage( KeyValues *pKeyValues )
{
}
void CPortalRenderable_Func_LiquidPortal::DrawOutwardBox( const IMaterial *pMaterial )
{
if( pMaterial == NULL )
pMaterial = materials->FindMaterial( "glass/glasswindow_refract01", TEXTURE_GROUP_OTHER );
const float fVerticalTextureScale = 1.0f / 100.0f;
const float fHorizontalTextureScale = 1.0f / 100.0f;
float fMaxZ = m_vAABBMins.z + ((m_vAABBMaxs.z - m_vAABBMins.z) * GetFillInterpolationAmount());
Vector vVertices[8];
for( int i = 0; i != 8; ++i )
{
vVertices[i].x = (i&(1<<0)) ? m_vAABBMaxs.x : m_vAABBMins.x;
vVertices[i].y = (i&(1<<1)) ? m_vAABBMaxs.y : m_vAABBMins.y;
vVertices[i].z = (i&(1<<2)) ? fMaxZ : m_vAABBMins.z;
}
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( (IMaterial *)pMaterial, (CPortalRenderable_Func_LiquidPortal*)this );
CMeshBuilder meshBuilder;
IMesh* pMesh = pRenderContext->GetDynamicMesh( false );
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 6 );
//x min
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 2, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 6, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 4, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 0, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
//x max
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 1, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 5, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 7, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 3, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
//y min
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 0, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 4, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 5, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 1, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
//y max
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 3, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 7, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 6, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 2, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
//z min
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 1, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 3, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 2, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 0, x, fHorizontalTextureScale, y, fVerticalTextureScale );
//z max
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 4, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 6, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 7, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 5, x, fHorizontalTextureScale, y, fVerticalTextureScale );
meshBuilder.End();
pMesh->Draw();
pRenderContext->Flush( false );
}
void CPortalRenderable_Func_LiquidPortal::DrawInwardBox( const IMaterial *pMaterial )
{
if( pMaterial == NULL )
pMaterial = materials->FindMaterial( "glass/glasswindow_refract01", TEXTURE_GROUP_OTHER );
const float fVerticalTextureScale = 1.0f / 100.0f;
const float fHorizontalTextureScale = 1.0f / 100.0f;
float fMaxZ = m_vAABBMins.z + ((m_vAABBMaxs.z - m_vAABBMins.z) * GetFillInterpolationAmount());
Vector vVertices[8];
for( int i = 0; i != 8; ++i )
{
vVertices[i].x = (i&(1<<0)) ? m_vAABBMaxs.x : m_vAABBMins.x;
vVertices[i].y = (i&(1<<1)) ? m_vAABBMaxs.y : m_vAABBMins.y;
vVertices[i].z = (i&(1<<2)) ? fMaxZ : m_vAABBMins.z;
}
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( (IMaterial *)pMaterial, (CPortalRenderable_Func_LiquidPortal*)this );
CMeshBuilder meshBuilder;
IMesh* pMesh = pRenderContext->GetDynamicMesh( false );
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 6 );
//x min
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 0, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 4, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 6, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 2, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
//x max
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 3, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 7, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 5, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 1, y, fHorizontalTextureScale, z, -fVerticalTextureScale );
//y min
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 1, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 5, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 4, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 0, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
//y max
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 2, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 6, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 7, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 3, x, fHorizontalTextureScale, z, -fVerticalTextureScale );
//z min
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 0, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 2, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 3, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 1, x, fHorizontalTextureScale, y, fVerticalTextureScale );
//z max
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 5, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 7, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 6, x, fHorizontalTextureScale, y, fVerticalTextureScale );
LIQUIDPORTAL_DYNAMICMESH_BOX_ADDVERTEX( 4, x, fHorizontalTextureScale, y, fVerticalTextureScale );
meshBuilder.End();
pMesh->Draw();
pRenderContext->Flush( false );
}
void CPortalRenderable_Func_LiquidPortal::DrawInnerLiquid( bool bClipToBounds, float fOpacity, const IMaterial *pMaterial ) //quads in front of camera clipped to box dimensions
{
if( !IsFillingNow() && bClipToBounds )
return;
PortalMeshPoint_t WorkVertices[4];
//view->GetViewSetup()->zNear;
Vector vForward, vUp, vRight, vOrigin;
vForward = CurrentViewForward();
vUp = CurrentViewUp();
vRight = CurrentViewRight();
//vOrigin = CurrentViewOrigin() + vForward * (view->GetViewSetup()->zNear + 0.011f); //experimentation has shown this to be the optimal distance on the Nvidia 6800 cards we develop on
vOrigin = CurrentViewOrigin() + vForward * (view->GetViewSetup()->zNear + 1.0f );
const float fScalingAmount = 5.0f;
WorkVertices[0].texCoord.x = fScalingAmount;
WorkVertices[0].texCoord.y = fScalingAmount;
WorkVertices[1].texCoord.x = fScalingAmount;
WorkVertices[1].texCoord.y = 0.0f;
WorkVertices[2].texCoord.x = 0.0f;
WorkVertices[2].texCoord.y = 0.0f;
WorkVertices[3].texCoord.x = 0.0f;
WorkVertices[3].texCoord.y = fScalingAmount;
WorkVertices[0].vWorldSpacePosition = vOrigin + (vRight * 40.0f) + (vUp * -40.0f);
WorkVertices[1].vWorldSpacePosition = vOrigin + (vRight * 40.0f) + (vUp * 40.0f);
WorkVertices[2].vWorldSpacePosition = vOrigin + (vRight * -40.0f) + (vUp * 40.0f);
WorkVertices[3].vWorldSpacePosition = vOrigin + (vRight * -40.0f) + (vUp * -40.0f);
PortalMeshPoint_t *pInVerts = (PortalMeshPoint_t *)stackalloc( 4 * (6) * 2 * sizeof( PortalMeshPoint_t ) ); //really only should need 2x points, but I'm paranoid
PortalMeshPoint_t *pOutVerts = (PortalMeshPoint_t *)stackalloc( 4 * (6) * 2 * sizeof( PortalMeshPoint_t ) );
PortalMeshPoint_t *pFinalVerts;
int iVertCount;
if( bClipToBounds )
{
PortalMeshPoint_t *pTempVerts;
//clip by first plane and put output into pInVerts
iVertCount = ClipPolyToPlane_LerpTexCoords( WorkVertices, 4, pInVerts, Vector( 0.0f, 0.0f, -1.0f ), -(m_vAABBMins.z + ((m_vAABBMaxs.z - m_vAABBMins.z) * GetFillInterpolationAmount())), 0.01f );
//clip by other planes and flipflop in and out pointers
for( int i = 0; i != 5; ++i )
{
if( iVertCount < 3 )
return; //nothing to draw
iVertCount = ClipPolyToPlane_LerpTexCoords( pInVerts, iVertCount, pOutVerts, *(Vector *)m_fBoundingPlanes[i], m_fBoundingPlanes[i][3], 0.01f );
pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
}
if( iVertCount < 3 )
return; //nothing to draw
pFinalVerts = pInVerts;
}
else
{
pFinalVerts = WorkVertices;
iVertCount = 4;
}
bool bInterpOpacity = false;
if( pMaterial == NULL )
{
pMaterial = materials->FindMaterial( "glass/glasswindow_refract01", TEXTURE_GROUP_OTHER );
bInterpOpacity = ( fOpacity != 1.0f );
}
if( bInterpOpacity )
{
IMaterial *pEditMaterial = (IMaterial *)pMaterial; //we'll be making changes, then changing it back
IMaterialVar *pRefractAmount = pEditMaterial->FindVar( "$refractamount", NULL );
IMaterialVar *pBlurAmount = pEditMaterial->FindVar( "$bluramount", NULL );
IMaterialVar *pTint = pEditMaterial->FindVar( "$refracttint", NULL );
float fOriginalRefractAmount = pRefractAmount->GetFloatValue();
float fOriginalBlurAmount = pBlurAmount->GetFloatValue();
Vector4D vOriginalTint;
pTint->GetVecValue( &vOriginalTint.x, 4 );
Vector4D vModdedTint = vOriginalTint;
pRefractAmount->SetFloatValue( fOriginalRefractAmount * fOpacity );
pBlurAmount->SetFloatValue( fOriginalBlurAmount * fOpacity );
vModdedTint.x = 1.0f - ((1.0f - vOriginalTint.x) * fOpacity);
vModdedTint.y = 1.0f - ((1.0f - vOriginalTint.y) * fOpacity);
vModdedTint.z = 1.0f - ((1.0f - vOriginalTint.z) * fOpacity);
pTint->SetVecValue( &vModdedTint.x, 4 );
Clip_And_Render_Convex_Polygon( pFinalVerts, iVertCount, pEditMaterial, this );
materials->Flush();
pRefractAmount->SetFloatValue( fOriginalRefractAmount );
pBlurAmount->SetFloatValue( fOriginalBlurAmount );
pTint->SetVecValue( &vOriginalTint.x, 4 );
}
else
{
Clip_And_Render_Convex_Polygon( pFinalVerts, iVertCount, pMaterial, this );
}
}
ADD_SCREENSPACE_EFFECT( CLiquidPortal_InnerLiquidEffect, LiquidPortal_InnerLiquid );
const float CLiquidPortal_InnerLiquidEffect::s_fFadeBackEffectTime = 5.0f;
CLiquidPortal_InnerLiquidEffect::CLiquidPortal_InnerLiquidEffect( void )
: m_bEnable(true),
m_pImmersionPortal(NULL),
m_bFadeBackToReality(false),
m_fFadeBackTimeLeft(0.0f)
{
}
void CLiquidPortal_InnerLiquidEffect::SetParameters( KeyValues *params )
{
/*KeyValues *pImmersionPortal = params->FindKey( "immersion_portal" );
if( pImmersionPortal )
m_pImmersionPortal = (C_Func_LiquidPortal *)pImmersionPortal->GetPtr();*/
}
void CLiquidPortal_InnerLiquidEffect::Render( int x, int y, int w, int h )
{
if( !m_pImmersionPortal || !m_bEnable )
return;
if( m_bFadeBackToReality )
{
//effect should cover whole screen and have a alpha-like fade back to normal view
m_fFadeBackTimeLeft -= gpGlobals->absoluteframetime;
if( m_fFadeBackTimeLeft > 0.0f )
{
float fInterp = m_fFadeBackTimeLeft/s_fFadeBackEffectTime;
//clear depth buffer so we can be all warpy on the view model too
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->ClearBuffers( false, true, false );
pRenderContext->OverrideDepthEnable( true, false );
m_pImmersionPortal->DrawInnerLiquid( false, fInterp );
pRenderContext->OverrideDepthEnable( false, true );
}
else
{
m_bFadeBackToReality = false;
m_pImmersionPortal = NULL;
}
}
else
{
//effect should only cover a portion of the screen and be in full warpiness
//clear depth buffer so we can be all warpy on the view model too
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->ClearBuffers( false, true, false );
pRenderContext->OverrideDepthEnable( true, false );
m_pImmersionPortal->DrawInnerLiquid();
pRenderContext->OverrideDepthEnable( false, true );
}
}
+131
View File
@@ -0,0 +1,131 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#ifndef C_FUNC_LIQUIDPORTAL_H
#define C_FUNC_LIQUIDPORTAL_H
#ifdef _WIN32
#pragma once
#endif
#include "c_baseentity.h"
#include "PortalRender.h"
#include "Portal_DynamicMeshRenderingUtils.h"
#include "ScreenSpaceEffects.h"
class CPortalRenderable_Func_LiquidPortal : public CPortalRenderable
{
public:
virtual void DrawPreStencilMask( void );
virtual void DrawStencilMask( void );
virtual void DrawPostStencilFixes( void );
virtual void RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView );
virtual void RenderPortalViewToTexture( CViewRender *pViewRender, const CViewSetup &cameraView );
void AddToVisAsExitPortal( ViewCustomVisibility_t *pCustomVisibility );
virtual bool DoesExitViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const;
virtual SkyboxVisibility_t SkyBoxVisibleFromPortal( void );
bool CalcFrustumThroughPortal( const Vector &ptCurrentViewOrigin, Frustum OutputFrustum, const VPlane *pInputFrustum = NULL, int iInputFrustumPlaneCount = 0 );
virtual const Vector& GetFogOrigin( void ) const;
virtual void ShiftFogForExitPortalView() const;
virtual bool ShouldUpdatePortalView_BasedOnView( const CViewSetup &currentView, Frustum currentFrustum ); //portal is both visible, and will display at least some portion of a remote view
virtual CPortalRenderable* GetLinkedPortal() const;
virtual bool ShouldUpdateDepthDoublerTexture( const CViewSetup &viewSetup );
virtual void DrawPortal( void ); //sort of like what you'd expect to happen in C_BaseAnimating::DrawModel() if portals were fully compatible with models
virtual void GetToolRecordingState( bool bActive, KeyValues *msg );
virtual void HandlePortalPlaybackMessage( KeyValues *pKeyValues );
void DrawOutwardBox( const IMaterial *pMaterial = NULL );
void DrawInwardBox( const IMaterial *pMaterial = NULL );
void DrawInnerLiquid( bool bClipToBounds = true, float fOpacity = 1.0f, const IMaterial *pMaterial = NULL ); //quads in front of camera clipped to box dimensions
float GetFillInterpolationAmount( void );
bool IsFillingNow( void );
void UpdateBoundingPlanes( void );
float m_fFillStartTime;
float m_fFillEndTime;
Vector m_vAABBMins;
Vector m_vAABBMaxs;
float m_fBoundingPlanes[5][4]; //top is highly variable and therefore not actually stored
CPortalRenderable_Func_LiquidPortal *m_pLinkedPortal;
};
inline float CPortalRenderable_Func_LiquidPortal::GetFillInterpolationAmount( void )
{
if( m_fFillEndTime < gpGlobals->curtime )
return 0.0f;
return ((gpGlobals->curtime - m_fFillStartTime) / (m_fFillEndTime - m_fFillStartTime));
}
inline bool CPortalRenderable_Func_LiquidPortal::IsFillingNow( void )
{
return ((m_fFillEndTime >= gpGlobals->curtime) && (m_fFillStartTime <= gpGlobals->curtime));
}
class C_Func_LiquidPortal : public C_BaseEntity, public CPortalRenderable_Func_LiquidPortal
{
public:
DECLARE_CLASS( C_Func_LiquidPortal, C_BaseEntity );
DECLARE_CLIENTCLASS();
C_Func_LiquidPortal( void );
~C_Func_LiquidPortal( void );
virtual bool IsTransparent( void ) { return true; };
virtual bool UsesPowerOfTwoFrameBufferTexture() { return true; };
virtual int DrawModel( int flags );
void ComputeLinkMatrix( void );
virtual void OnDataChanged( DataUpdateType_t updateType );
CHandle<C_Func_LiquidPortal> m_hLinkedPortal;
};
class CLiquidPortal_InnerLiquidEffect : public IScreenSpaceEffect
{
public:
CLiquidPortal_InnerLiquidEffect( void );
void Init( void ) { };
void Shutdown( void ) { };
void SetParameters( KeyValues *params );
void Render( int x, int y, int w, int h );
void Enable( bool bEnable ) { m_bEnable = bEnable; };
bool IsEnabled( void ) { return m_bEnable; };
private:
bool m_bEnable;
public:
C_Func_LiquidPortal* m_pImmersionPortal; //portal that did the filling + teleporting
bool m_bFadeBackToReality;
float m_fFadeBackTimeLeft;
static const float s_fFadeBackEffectTime; //how long the effect should take
};
#endif //#ifndef C_FUNC_LIQUIDPORTAL_H
@@ -0,0 +1,56 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "c_neurotoxin_countdown.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
CUtlVector< C_NeurotoxinCountdown* > g_NeurotoxinCountdowns;
IMPLEMENT_CLIENTCLASS_DT(C_NeurotoxinCountdown, DT_NeurotoxinCountdown, CNeurotoxinCountdown)
RecvPropBool( RECVINFO(m_bEnabled) ),
END_RECV_TABLE()
C_NeurotoxinCountdown::C_NeurotoxinCountdown()
{
g_NeurotoxinCountdowns.AddToTail( this );
}
C_NeurotoxinCountdown::~C_NeurotoxinCountdown()
{
g_NeurotoxinCountdowns.FindAndRemove( this );
}
int C_NeurotoxinCountdown::GetMinutes( void )
{
C_BasePlayer *player = UTIL_PlayerByIndex( 1 );
if ( player )
return player->GetBonusProgress() / 60;
return 0.0f;
}
int C_NeurotoxinCountdown::GetSeconds( void )
{
C_BasePlayer *player = UTIL_PlayerByIndex( 1 );
if ( player )
return player->GetBonusProgress() % 60;
return 0.0f;
}
int C_NeurotoxinCountdown::GetMilliseconds( void )
{
return static_cast<int>( gpGlobals->curtime * 100.0f ) % 100;;
}
@@ -0,0 +1,39 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef C_NEUROTOXIN_COUNTDOWN_H
#define C_NEUROTOXIN_COUNTDOWN_H
#include "cbase.h"
#include "utlvector.h"
class C_NeurotoxinCountdown : public C_BaseEntity
{
public:
DECLARE_CLASS( C_NeurotoxinCountdown, CBaseEntity );
DECLARE_CLIENTCLASS();
C_NeurotoxinCountdown();
virtual ~C_NeurotoxinCountdown();
bool IsEnabled( void ) { return m_bEnabled; }
int GetMinutes( void );
int GetSeconds( void );
int GetMilliseconds( void );
private:
bool m_bEnabled;
};
extern CUtlVector< C_NeurotoxinCountdown* > g_NeurotoxinCountdowns;
#endif //C_NEUROTOXIN_COUNTDOWN_H
@@ -0,0 +1,168 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "beam_shared.h"
#include "prop_portal_shared.h"
#define FLOOR_TURRET_PORTAL_EYE_ATTACHMENT 1
#define FLOOR_TURRET_PORTAL_LASER_ATTACHMENT 2
#define FLOOR_TURRET_PORTAL_LASER_RANGE 8192
#define FLOOR_TURRET_PORTAL_END_POINT_PULSE_SCALE 4.0f
class C_NPC_Portal_FloorTurret : public C_AI_BaseNPC
{
public:
DECLARE_CLASS( C_NPC_Portal_FloorTurret, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
virtual ~C_NPC_Portal_FloorTurret( void );
virtual void Spawn( void );
virtual void ClientThink( void );
bool IsLaserOn( void ) { return m_pBeam != NULL; }
void LaserOff( void );
void LaserOn( void );
float LaserEndPointSize( void );
private:
CBeam *m_pBeam;
bool m_bOutOfAmmo;
bool m_bLaserOn;
int m_sLaserHaloSprite;
float m_fPulseOffset;
float m_bBeamFlickerOff;
float m_fBeamFlickerTime;
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_Portal_FloorTurret, DT_NPC_Portal_FloorTurret, CNPC_Portal_FloorTurret )
RecvPropBool( RECVINFO( m_bOutOfAmmo ) ),
RecvPropBool( RECVINFO( m_bLaserOn ) ),
RecvPropInt( RECVINFO( m_sLaserHaloSprite ) ),
END_RECV_TABLE()
C_NPC_Portal_FloorTurret::~C_NPC_Portal_FloorTurret( void )
{
LaserOff();
if( m_pBeam )
m_pBeam->Remove();
}
void C_NPC_Portal_FloorTurret::Spawn( void )
{
SetThink( &C_NPC_Portal_FloorTurret::ClientThink );
SetNextClientThink( CLIENT_THINK_ALWAYS );
m_pBeam = NULL;
m_fPulseOffset = RandomFloat( 0.0f, 2.0f * M_PI );
m_bBeamFlickerOff = false;
m_fBeamFlickerTime = 0.0f;
BaseClass::Spawn();
}
void C_NPC_Portal_FloorTurret::ClientThink( void )
{
if ( m_bOutOfAmmo && m_fBeamFlickerTime < gpGlobals->curtime )
{
m_fBeamFlickerTime = gpGlobals->curtime + RandomFloat( 0.05f, 0.3f );
m_bBeamFlickerOff = !m_bBeamFlickerOff;
}
if ( m_bLaserOn && !m_bBeamFlickerOff )
LaserOn();
else
LaserOff();
}
void C_NPC_Portal_FloorTurret::LaserOff( void )
{
if( m_pBeam )
{
m_pBeam->AddEffects( EF_NODRAW );
}
}
void C_NPC_Portal_FloorTurret::LaserOn( void )
{
if ( !IsBoneAccessAllowed() )
{
LaserOff();
return;
}
Vector vecMuzzle;
QAngle angMuzzleDir;
GetAttachment( FLOOR_TURRET_PORTAL_LASER_ATTACHMENT, vecMuzzle, angMuzzleDir );
Vector vecEye;
QAngle angEyeDir;
GetAttachment( FLOOR_TURRET_PORTAL_EYE_ATTACHMENT, vecEye, angEyeDir );
Vector vecMuzzleDir;
AngleVectors( angEyeDir, &vecMuzzleDir );
if (!m_pBeam)
{
m_pBeam = CBeam::BeamCreate( "effects/redlaser1.vmt", 0.2 );
m_pBeam->SetColor( 255, 32, 32 );
m_pBeam->SetBrightness( 255 );
m_pBeam->SetNoise( 0 );
m_pBeam->SetWidth( IsX360() ? ( 1.5f ) : ( 0.75f ) ); // On low end TVs these lasers are very hard to see at a distance
m_pBeam->SetEndWidth( 0 );
m_pBeam->SetScrollRate( 0 );
m_pBeam->SetFadeLength( 0 );
m_pBeam->SetHaloTexture( m_sLaserHaloSprite );
m_pBeam->SetHaloScale( 4.0f );
m_pBeam->SetCollisionGroup( COLLISION_GROUP_NONE );
m_pBeam->PointsInit( vecMuzzle + vecMuzzleDir, vecMuzzle );
m_pBeam->SetBeamFlag( FBEAM_REVERSED );
m_pBeam->SetStartEntity( this );
}
else
{
m_pBeam->RemoveEffects( EF_NODRAW );
}
// Trace to find an endpoint
Vector vEndPoint;
float fEndFraction;
Ray_t rayPath;
rayPath.Init( vecMuzzle, vecMuzzle + vecMuzzleDir * FLOOR_TURRET_PORTAL_LASER_RANGE );
CTraceFilterSkipClassname traceFilter( this, "prop_energy_ball", COLLISION_GROUP_NONE );
if ( UTIL_Portal_TraceRay_Beam( rayPath, MASK_SHOT, &traceFilter, &fEndFraction ) )
vEndPoint = vecMuzzle + vecMuzzleDir * FLOOR_TURRET_PORTAL_LASER_RANGE; // Trace went through portal and endpoint is unknown
else
vEndPoint = vecMuzzle + vecMuzzleDir * FLOOR_TURRET_PORTAL_LASER_RANGE * fEndFraction; // Trace hit a wall
// The beam is backwards, sort of. The endpoint is the sniper. This is
// so that the beam can be tapered to very thin where it emits from the turret.
m_pBeam->PointsInit( vEndPoint, vecMuzzle );
m_pBeam->SetHaloScale( LaserEndPointSize() );
}
float C_NPC_Portal_FloorTurret::LaserEndPointSize( void )
{
return ( ( MAX( 0.0f, sinf( gpGlobals->curtime * M_PI + m_fPulseOffset ) ) ) * FLOOR_TURRET_PORTAL_END_POINT_PULSE_SCALE + 3.0f ) * ( IsX360() ? ( 3.0f ) : ( 1.5f ) );
}
+177
View File
@@ -0,0 +1,177 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "c_ai_basenpc.h"
#include "beam_shared.h"
#include "prop_portal_shared.h"
#define ROCKET_TURRET_LASER_ATTACHMENT 2
#define ROCKET_TURRET_LASER_RANGE 8192
#define ROCKET_TURRET_END_POINT_PULSE_SCALE 5.0f
class C_NPC_RocketTurret : public C_AI_BaseNPC
{
public:
DECLARE_CLASS( C_NPC_RocketTurret, C_AI_BaseNPC );
DECLARE_CLIENTCLASS();
C_NPC_RocketTurret( void );
virtual ~C_NPC_RocketTurret( void );
virtual void Spawn( void );
virtual void ClientThink( void );
virtual ITraceFilter* GetBeamTraceFilter( void );
void LaserOff( void );
void LaserOn( void );
float LaserEndPointSize( void );
private:
CBeam *m_pBeam;
int m_iLaserState;
int m_nSiteHalo;
float m_fPulseOffset;
QAngle m_vecCurrentAngles;
CTraceFilterSkipTwoEntities m_filterBeams;
};
IMPLEMENT_CLIENTCLASS_DT( C_NPC_RocketTurret, DT_NPC_RocketTurret, CNPC_RocketTurret )
RecvPropInt( RECVINFO( m_iLaserState ) ),
RecvPropInt( RECVINFO( m_nSiteHalo ) ),
RecvPropVector( RECVINFO( m_vecCurrentAngles ) ),
END_RECV_TABLE()
C_NPC_RocketTurret::C_NPC_RocketTurret( void )
: m_filterBeams( NULL, NULL, COLLISION_GROUP_DEBRIS )
{
m_filterBeams.SetPassEntity( this );
m_filterBeams.SetPassEntity2( UTIL_PlayerByIndex( 1 ) );
}
C_NPC_RocketTurret::~C_NPC_RocketTurret( void )
{
LaserOff();
if( m_pBeam )
m_pBeam->Remove();
}
void C_NPC_RocketTurret::Spawn( void )
{
SetThink( &C_NPC_RocketTurret::ClientThink );
SetNextClientThink( CLIENT_THINK_ALWAYS );
m_pBeam = NULL;
m_fPulseOffset = RandomFloat( 0.0f, 2.0f * M_PI );
BaseClass::Spawn();
}
void C_NPC_RocketTurret::ClientThink( void )
{
if ( m_iLaserState == 0 )
LaserOff();
else
LaserOn();
}
ITraceFilter* C_NPC_RocketTurret::GetBeamTraceFilter( void )
{
return &m_filterBeams;
}
void C_NPC_RocketTurret::LaserOff( void )
{
if( m_pBeam )
m_pBeam->AddEffects( EF_NODRAW );
}
void C_NPC_RocketTurret::LaserOn( void )
{
if ( !IsBoneAccessAllowed() )
{
LaserOff();
return;
}
Vector vecMuzzle;
QAngle angMuzzleDir;
GetAttachment( ROCKET_TURRET_LASER_ATTACHMENT, vecMuzzle, angMuzzleDir );
QAngle angAimDir = m_vecCurrentAngles;
Vector vecAimDir;
AngleVectors ( angAimDir, &vecAimDir );
if (!m_pBeam)
{
m_pBeam = CBeam::BeamCreate( "effects/bluelaser1.vmt", 0.1 );
m_pBeam->SetHaloTexture( m_nSiteHalo );
m_pBeam->SetColor( 100, 100, 255 );
m_pBeam->SetBrightness( 100 );
m_pBeam->SetNoise( 0 );
m_pBeam->SetWidth( 1 );
m_pBeam->SetEndWidth( 0 );
m_pBeam->SetScrollRate( 0 );
m_pBeam->SetFadeLength( 0 );
m_pBeam->SetHaloScale( 16.0f );
m_pBeam->SetCollisionGroup( COLLISION_GROUP_NONE );
m_pBeam->SetBeamFlag( FBEAM_REVERSED );
m_pBeam->PointsInit( vecMuzzle + vecAimDir, vecMuzzle );
m_pBeam->SetStartEntity( this );
}
else
{
m_pBeam->RemoveEffects( EF_NODRAW );
}
if ( m_iLaserState == 2 )
{
// Beam is freaking out
float fSize = RandomFloat( 0.5f, 5.0f );
int iRate = RandomInt( 4, 20 );
m_pBeam->SetWidth( fSize );
m_pBeam->SetScrollRate( iRate );
}
else
{
m_pBeam->SetWidth( 1 );
m_pBeam->SetScrollRate( 0 );
}
// Trace to find an endpoint (so the beam draws through portals)
Vector vEndPoint;
float fEndFraction;
Ray_t rayPath;
rayPath.Init( vecMuzzle, vecMuzzle + vecAimDir * ROCKET_TURRET_LASER_RANGE );
if ( UTIL_Portal_TraceRay_Beam( rayPath, MASK_SHOT, &m_filterBeams, &fEndFraction ) )
vEndPoint = vecMuzzle + vecAimDir * ROCKET_TURRET_LASER_RANGE; // Trace went through portal and endpoint is unknown
else
vEndPoint = vecMuzzle + vecAimDir * ROCKET_TURRET_LASER_RANGE * fEndFraction; // Trace hit a wall
m_pBeam->PointsInit( vEndPoint, vecMuzzle );
m_pBeam->SetHaloScale( LaserEndPointSize() );
}
float C_NPC_RocketTurret::LaserEndPointSize( void )
{
return ( MAX( 0.0f, sinf( gpGlobals->curtime * M_PI + m_fPulseOffset ) ) ) * ROCKET_TURRET_END_POINT_PULSE_SCALE + 1.0f;
}
File diff suppressed because it is too large Load Diff
+222
View File
@@ -0,0 +1,222 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef PORTAL_PLAYER_H
#define PORTAL_PLAYER_H
#pragma once
#include "portal_playeranimstate.h"
#include "c_basehlplayer.h"
#include "portal_player_shared.h"
#include "c_prop_portal.h"
#include "weapon_portalbase.h"
#include "c_func_liquidportal.h"
#include "colorcorrectionmgr.h"
//=============================================================================
// >> Portal_Player
//=============================================================================
class C_Portal_Player : public C_BaseHLPlayer
{
public:
DECLARE_CLASS( C_Portal_Player, C_BaseHLPlayer );
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
DECLARE_INTERPOLATION();
C_Portal_Player();
~C_Portal_Player( void );
void ClientThink( void );
void FixTeleportationRoll( void );
static inline C_Portal_Player* GetLocalPortalPlayer()
{
return (C_Portal_Player*)C_BasePlayer::GetLocalPlayer();
}
static inline C_Portal_Player* GetLocalPlayer()
{
return (C_Portal_Player*)C_BasePlayer::GetLocalPlayer();
}
virtual const QAngle& GetRenderAngles();
virtual void UpdateClientSideAnimation();
void DoAnimationEvent( PlayerAnimEvent_t event, int nData );
virtual int DrawModel( int flags );
virtual void AddEntity( void );
QAngle GetAnimEyeAngles( void ) { return m_angEyeAngles; }
Vector GetAttackSpread( CBaseCombatWeapon *pWeapon, CBaseEntity *pTarget = NULL );
// Used by prediction, sets the view angles for the player
virtual void SetLocalViewAngles( const QAngle &viewAngles );
virtual void SetViewAngles( const QAngle &ang );
// Should this object cast shadows?
virtual ShadowType_t ShadowCastType( void );
virtual C_BaseAnimating* BecomeRagdollOnClient();
virtual bool ShouldDraw( void );
virtual const QAngle& EyeAngles();
virtual void OnPreDataChanged( DataUpdateType_t type );
virtual void OnDataChanged( DataUpdateType_t type );
bool DetectAndHandlePortalTeleportation( void ); //detects if the player has portalled and fixes views
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 PostDataUpdate( DataUpdateType_t updateType );
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 Vector EyePosition();
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_Prop_Portal *pEnteredPortal );
virtual void CalcView( Vector &eyeOrigin, QAngle &eyeAngles, float &zNear, float &zFar, float &fov );
void CalcPortalView( Vector &eyeOrigin, QAngle &eyeAngles );
virtual void CalcViewModelView( const Vector& eyeOrigin, const QAngle& eyeAngles);
CBaseEntity* FindUseEntity( void );
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));
}
bool CanSprint( void );
void StartSprinting( void );
void StopSprinting( void );
void HandleSpeedChanges( void );
void UpdateLookAt( void );
void Initialize( void );
int GetIDTarget() const;
void UpdateIDTarget( void );
void ToggleHeldObjectOnOppositeSideOfPortal( void ) { m_bHeldObjectOnOppositeSideOfPortal = !m_bHeldObjectOnOppositeSideOfPortal; }
void SetHeldObjectOnOppositeSideOfPortal( bool p_bHeldObjectOnOppositeSideOfPortal ) { m_bHeldObjectOnOppositeSideOfPortal = p_bHeldObjectOnOppositeSideOfPortal; }
bool IsHeldObjectOnOppositeSideOfPortal( void ) { return m_bHeldObjectOnOppositeSideOfPortal; }
CProp_Portal *GetHeldObjectPortal( void ) { return m_pHeldObjectPortal; }
Activity TranslateActivity( Activity baseAct, bool *pRequired = NULL );
CWeaponPortalBase* GetActivePortalWeapon() const;
bool IsSuppressingCrosshair( void ) { return m_bSuppressingCrosshair; }
private:
C_Portal_Player( const C_Portal_Player & );
void UpdatePortalEyeInterpolation( void );
CPortalPlayerAnimState *m_PlayerAnimState;
QAngle m_angEyeAngles;
CInterpolatedVar< QAngle > m_iv_angEyeAngles;
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;
bool m_bSuppressingCrosshair;
bool m_isInit;
Vector m_vLookAtTarget;
float m_flLastBodyYaw;
float m_flCurrentHeadYaw;
float m_flCurrentHeadPitch;
float m_flStartLookTime;
int m_iIDEntIndex;
CountdownTimer m_blinkTimer;
int m_iSpawnInterpCounter;
int m_iSpawnInterpCounterCache;
int m_iPlayerSoundType;
bool m_bHeldObjectOnOppositeSideOfPortal;
CProp_Portal *m_pHeldObjectPortal;
int m_iForceNoDrawInPortalSurface; //only valid for one frame, used to temp disable drawing of the player model in a surface because of freaky artifacts
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_Prop_Portal> m_hPortalEnvironment;
CHandle<C_Func_LiquidPortal> m_hSurroundingLiquidPortal;
//Vector m_ptPlayerPosition;
QAngle m_qEyeAngles;
} PreDataChanged_Backup;
Vector m_ptEyePosition_LastCalcView;
QAngle m_qEyeAngles_LastCalcView; //we've got some VERY persistent single frame errors while teleporting, this will be updated every frame in CalcView() and will serve as a central source for fixed angles
C_Prop_Portal *m_pPortalEnvironment_LastCalcView;
ClientCCHandle_t m_CCDeathHandle; // handle to death cc effect
float m_flDeathCCWeight; // for fading in cc effect
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;
public:
bool m_bPitchReorientation;
float m_fReorientationRate;
bool m_bEyePositionIsTransformedByPortal; //when the eye and body positions are not on the same side of a portal
CHandle<C_Prop_Portal> m_hPortalEnvironment; //a portal whose environment the player is currently in, should be invalid most of the time
CHandle<C_Func_LiquidPortal> m_hSurroundingLiquidPortal; //a liquid portal whose volume the player is standing in
};
inline C_Portal_Player *ToPortalPlayer( CBaseEntity *pEntity )
{
if ( !pEntity || !pEntity->IsPlayer() )
return NULL;
return dynamic_cast<C_Portal_Player*>( pEntity );
}
inline C_Portal_Player *GetPortalPlayer( void )
{
return static_cast<C_Portal_Player*>( C_BasePlayer::GetLocalPlayer() );
}
#endif //Portal_PLAYER_H
+256
View File
@@ -0,0 +1,256 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//
//=====================================================================================//
#include "cbase.h"
#include "c_physicsprop.h"
#include "portal_gamerules.h"
#include "igameevents.h"
#include "soundenvelope.h"
#include "beamdraw.h"
//#define RADIO_DEBUG_CLIENT
class C_Dinosaur_Signal : public C_BaseEntity
{
public:
DECLARE_CLIENTCLASS();
DECLARE_CLASS( C_Dinosaur_Signal, C_BaseEntity );
char m_szSoundName[128];
float m_flInnerRadius;
float m_flOuterRadius;
int m_nSignalID;
};
IMPLEMENT_CLIENTCLASS_DT( C_Dinosaur_Signal, DT_DinosaurSignal, CDinosaurSignal )
RecvPropString( RECVINFO(m_szSoundName) ),
RecvPropFloat( RECVINFO(m_flOuterRadius) ),
RecvPropFloat( RECVINFO(m_flInnerRadius) ),
RecvPropInt( RECVINFO(m_nSignalID) ),
END_RECV_TABLE()
class C_Portal_Dinosaur : public C_PhysicsProp
{
public:
DECLARE_CLIENTCLASS();
DECLARE_CLASS( C_Portal_Dinosaur, C_PhysicsProp );
~C_Portal_Dinosaur( void );
virtual void Spawn();
virtual void Precache();
virtual void ClientThink();
virtual int DrawModel( int flags );
void ScanForSounds();
void SetupSounds();
CHandle<C_Dinosaur_Signal> m_hDinosaur_Signal;
float m_flOldBlend;
bool m_bAlreadyDiscovered;
bool m_bDinosaurExtinct;
// Sound envelopes
CSoundPatch *m_pNormalSound;
CSoundPatch *m_pStaticSound;
CSoundPatch *m_pSignalSound;
};
IMPLEMENT_CLIENTCLASS_DT( C_Portal_Dinosaur, DT_PropDinosaur, CPortal_Dinosaur )
RecvPropEHandle( RECVINFO( m_hDinosaur_Signal) ),
RecvPropBool( RECVINFO(m_bAlreadyDiscovered) ),
END_RECV_TABLE()
void C_Portal_Dinosaur::Spawn()
{
Precache();
m_flOldBlend = 0.0f;
BaseClass::Spawn();
SetThink( &C_Portal_Dinosaur::ClientThink );
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
C_Portal_Dinosaur::~C_Portal_Dinosaur( void )
{
if ( m_pNormalSound != NULL )
{
CSoundEnvelopeController::GetController().Shutdown( m_pNormalSound );
}
if ( m_pStaticSound != NULL )
{
CSoundEnvelopeController::GetController().Shutdown( m_pStaticSound );
}
if ( m_pSignalSound != NULL )
{
CSoundEnvelopeController::GetController().Shutdown( m_pSignalSound );
}
}
void C_Portal_Dinosaur::Precache( void )
{
PrecacheScriptSound( "Portal.room1_radio" );
PrecacheScriptSound( "UpdateItem.Static" );
PrecacheScriptSound( "UpdateItem.Dinosaur01" );
PrecacheScriptSound( "UpdateItem.Dinosaur02" );
PrecacheScriptSound( "UpdateItem.Dinosaur03" );
PrecacheScriptSound( "UpdateItem.Dinosaur04" );
PrecacheScriptSound( "UpdateItem.Dinosaur05" );
PrecacheScriptSound( "UpdateItem.Dinosaur06" );
PrecacheScriptSound( "UpdateItem.Dinosaur07" );
PrecacheScriptSound( "UpdateItem.Dinosaur08" );
PrecacheScriptSound( "UpdateItem.Dinosaur09" );
PrecacheScriptSound( "UpdateItem.Dinosaur10" );
PrecacheScriptSound( "UpdateItem.Dinosaur11" );
PrecacheScriptSound( "UpdateItem.Dinosaur12" );
PrecacheScriptSound( "UpdateItem.Dinosaur13" );
PrecacheScriptSound( "UpdateItem.Dinosaur14" );
PrecacheScriptSound( "UpdateItem.Dinosaur15" );
PrecacheScriptSound( "UpdateItem.Dinosaur16" );
PrecacheScriptSound( "UpdateItem.Dinosaur17" );
PrecacheScriptSound( "UpdateItem.Dinosaur18" );
PrecacheScriptSound( "UpdateItem.Dinosaur19" );
PrecacheScriptSound( "UpdateItem.Dinosaur20" );
PrecacheScriptSound( "UpdateItem.Dinosaur21" );
PrecacheScriptSound( "UpdateItem.Dinosaur22" );
PrecacheScriptSound( "UpdateItem.Dinosaur23" );
PrecacheScriptSound( "UpdateItem.Dinosaur24" );
PrecacheScriptSound( "UpdateItem.Dinosaur25" );
PrecacheScriptSound( "UpdateItem.Dinosaur26" );
}
void C_Portal_Dinosaur::SetupSounds()
{
CPASAttenuationFilter filter( this );
if ( m_pNormalSound == NULL )
{
m_pNormalSound = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "Portal.room1_radio" );
CSoundEnvelopeController::GetController().Play( m_pNormalSound, 0.0, PITCH_NORM );
}
if ( m_pStaticSound == NULL )
{
m_pStaticSound = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "UpdateItem.Static" );
CSoundEnvelopeController::GetController().Play( m_pStaticSound, 0.0, PITCH_NORM );
}
if ( m_pSignalSound == NULL && m_hDinosaur_Signal.Get() != NULL )
{
m_pSignalSound = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), m_hDinosaur_Signal->m_szSoundName );
//m_pSignalSound = CSoundEnvelopeController::GetController().SoundCreate( filter, entindex(), "UpdateItem.Signal" );
CSoundEnvelopeController::GetController().Play( m_pSignalSound, 0.0, PITCH_NORM );
}
}
void C_Portal_Dinosaur::ClientThink()
{
SetupSounds();
//if ( V_stristr( engine->GetLevelName(), "testchmb_a_00" ) != 0 )
if ( 0 )//m_hDinosaur_Signal.Get() && m_hDinosaur_Signal.Get()->m_nSignalID == 0 )
{
// TODO:Play either morse code or special sstv content based on
// game account client state given from gc.
}
else
{
// On any other map, we scan for the partnered Dinosaur_Signal signal
ScanForSounds();
}
if ( m_bDinosaurExtinct == false && m_bDinosaurExtinct != m_bAlreadyDiscovered )
m_bDinosaurExtinct = m_bAlreadyDiscovered;
}
void C_Portal_Dinosaur::ScanForSounds()
{
if ( m_hDinosaur_Signal.Get() == NULL )
{
AssertMsgOnce( 0, "Unpaired radio exists on this map." );
return;
}
// How much of the real signal to blend in
// 1.0 at > outerrad, 0.0 at < inner rad, blend when in between the two.
float flRadiusDelta = fabs( m_hDinosaur_Signal.Get()->m_flOuterRadius - m_hDinosaur_Signal.Get()->m_flInnerRadius );
float flDist = m_hDinosaur_Signal.Get()->GetAbsOrigin().DistTo( GetAbsOrigin() );
float flOuterBlend = RemapValClamped( flDist, m_hDinosaur_Signal.Get()->m_flOuterRadius, m_hDinosaur_Signal.Get()->m_flOuterRadius-(flRadiusDelta*0.5f), 1.0f, 0.0f );
float flInnerBlend = RemapValClamped( flDist, m_hDinosaur_Signal.Get()->m_flOuterRadius-(flRadiusDelta*0.5f), m_hDinosaur_Signal.Get()->m_flInnerRadius, 0.0f, 1.0f );
flInnerBlend = Bias( flInnerBlend, 0.1f );
if ( m_pNormalSound )
{
CSoundEnvelopeController::GetController().SoundChangeVolume( m_pNormalSound, flOuterBlend, 0.1f );
}
float flMidBlend = 0.0f;
if ( m_pStaticSound )
{
if ( flOuterBlend <= 0.0f )
{
flMidBlend = RemapValClamped( flDist, m_hDinosaur_Signal.Get()->m_flOuterRadius-(flRadiusDelta*0.5f), m_hDinosaur_Signal.Get()->m_flInnerRadius, 1.0f, 0.0f );
}
else
{
flMidBlend = RemapValClamped( flDist, m_hDinosaur_Signal.Get()->m_flOuterRadius, m_hDinosaur_Signal.Get()->m_flOuterRadius-(flRadiusDelta*0.5f), 0.0f, 1.0f );
flMidBlend = Bias( flMidBlend, 0.9f );
}
CSoundEnvelopeController::GetController().SoundChangeVolume( m_pStaticSound, flMidBlend, 0.1f );
}
if ( m_pSignalSound )
{
CSoundEnvelopeController::GetController().SoundChangeVolume( m_pSignalSound, flInnerBlend, 0.1f );
}
#if defined ( RADIO_DEBUG_CLIENT )
// Msg( "Dinosaur(%d) listening for signal... dist: %f, blend amt: %f\n", entindex(), flDist, flMidBlend );
#endif
// If we've fully heard this signal, mark the achievement
if ( flInnerBlend >= 1.0f && m_flOldBlend < 1.0f )
{
m_bDinosaurExtinct = true;
int id = m_hDinosaur_Signal.Get()->m_nSignalID;
IGameEvent *event = gameeventmanager->CreateEvent( "dinosaur_signal_found" );
if ( event )
{
event->SetInt( "id", id );
gameeventmanager->FireEvent( event );
}
}
m_flOldBlend = flInnerBlend;
}
int C_Portal_Dinosaur::DrawModel( int flags )
{
int nRet = BaseClass::DrawModel( flags );
CMaterialReference hMaterial;
hMaterial.Init( "sprites/grav_light", TEXTURE_GROUP_CLIENT_EFFECTS );
// Draw the sprite
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( hMaterial, this );
color32 color;
color.r = ( m_bDinosaurExtinct ) ? 0 : 255;
color.g = ( m_bDinosaurExtinct ) ? 255 : 0;
color.b = 0;
color.a = 128;
Vector vForward, vRight, vUp;
GetVectors( &vForward, &vRight, &vUp );
Vector vOffset = GetAbsOrigin() + ( vForward * 4.0f ) + ( vUp * 1.85f );
DrawSprite( vOffset, 6.0f, 6.0f, color );
return nRet;
}
+133
View File
@@ -0,0 +1,133 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// c_prop_energy_ball.cpp
//
// Purpose: Portal version of the combine ball. This client code is needed to provide a different
// look when the energy ball has infinite life and to have modified client effects.
//
//=====================================================================================//
#include "cbase.h" // precompiled headers
#include "c_prop_combine_ball.h" // Our parent class
#include "clienteffectprecachesystem.h" // To precache our new material
ConVar cl_energy_ball_start_fade_time ( "cl_energy_ball_start_fade_time", "8", FCVAR_CHEAT );
//-----------------------------------------------------------------------------
// Purpose: Portal version of a combine ball
//-----------------------------------------------------------------------------
class C_PropEnergyBall : public C_PropCombineBall
{
public:
DECLARE_CLASS( C_PropEnergyBall, C_PropCombineBall );
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
C_PropEnergyBall();
virtual void OnDataChanged( DataUpdateType_t updateType );
protected:
bool InitMaterials();
bool m_bIsInfiniteLife; // if this energy ball is an infinite life variety
float m_fTimeTillDeath; // If this is a finite life energy ball, the time remaining until detonation
float m_fCurAlpha; // The amount of alpha to apply at DrawModel, to simulate a decaying energy ball
};
LINK_ENTITY_TO_CLASS( prop_energy_ball, C_PropEnergyBall );
// precache our different materials for the infinite life energy balls
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectEnergyBall )
CLIENTEFFECT_MATERIAL( "effects/eball_infinite_life" )
CLIENTEFFECT_MATERIAL( "effects/eball_finite_life" )
CLIENTEFFECT_REGISTER_END()
IMPLEMENT_CLIENTCLASS_DT( C_PropEnergyBall, DT_PropEnergyBall, CPropEnergyBall )
RecvPropBool( RECVINFO( m_bIsInfiniteLife ) ),
RecvPropFloat( RECVINFO( m_fTimeTillDeath ) ),
END_RECV_TABLE()
BEGIN_PREDICTION_DATA( C_PropEnergyBall )
DEFINE_PRED_FIELD( m_bIsInfiniteLife, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_fTimeTillDeath, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
C_PropEnergyBall::C_PropEnergyBall(): m_bIsInfiniteLife(false), m_fTimeTillDeath(-1), m_fCurAlpha ( 1.0f )
{
}
//-----------------------------------------------------------------------------
// Purpose: Flag our data as new this frame
// Input : DataUpdateType_t, either created or updated
// Output : void
//-----------------------------------------------------------------------------
void C_PropEnergyBall::OnDataChanged(DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
// If our data changed this frame, then operate based on it next think
if ( updateType == DATA_UPDATE_DATATABLE_CHANGED )
{
float fStartFadeTime = cl_energy_ball_start_fade_time.GetFloat();
if ( fStartFadeTime < 1.0f )
{
fStartFadeTime = 1.0f;
}
// The last x seconds of life, fade
if ( (m_fTimeTillDeath > 0.0f) )
{
float fNewAlpha = m_fTimeTillDeath / fStartFadeTime;
clamp( fNewAlpha, 0.0f, 1.0f );
m_fCurAlpha = fNewAlpha;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Use our custom body materials for energy ball, but otherwise use the base class materials (base being C_PropCombineBall)
// Output : bool
//-----------------------------------------------------------------------------
bool C_PropEnergyBall::InitMaterials()
{
// Use the same materials as a combine ball
bool bRetVal = BaseClass::InitMaterials();
// If we're an infinite life combine ball, swap out the body material (and the base implementation didnt fail)
IMaterial* pBodyMat;
if ( m_bIsInfiniteLife )
{
pBodyMat = materials->FindMaterial( "effects/eball_infinite_life", NULL, false );
}
else
{
pBodyMat = materials->FindMaterial( "effects/eball_finite_life", NULL, false );
}
// If we can find our custom material, use it.
if ( pBodyMat == NULL )
{
bRetVal = false;
}
else
{
m_pBodyMaterial = pBodyMat;
m_pBodyMaterial->AlphaModulate( m_fCurAlpha );
}
return bRetVal;
}
+952
View File
@@ -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 );
}
+96
View File
@@ -0,0 +1,96 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef C_PROP_PORTAL_H
#define C_PROP_PORTAL_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"
struct dlight_t;
class C_DynamicLight;
class C_Prop_Portal : public CPortalRenderable_FlatBasic
{
public:
DECLARE_CLASS( C_Prop_Portal, CPortalRenderable_FlatBasic );
DECLARE_CLIENTCLASS();
C_Prop_Portal( void );
virtual ~C_Prop_Portal( void );
// Handle recording for the SFM
virtual void GetToolRecordingState( KeyValues *msg );
CHandle<C_Prop_Portal> m_hLinkedPortal; //the portal this portal is linked to
bool m_bActivated; //a portal can exist and not be active
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 void ClientThink( void );
virtual void Simulate();
virtual void UpdateOnRemove( void );
virtual void OnNewParticleEffect( const char *pszParticleName, CNewParticleEffect *pNewParticleEffect );
struct Portal_PreDataChanged
{
bool m_bActivated;
bool m_bIsPortal2;
Vector m_vOrigin;
QAngle m_qAngles;
EHANDLE m_hLinkedTo;
} PreDataChanged;
struct TransformedLightingData_t
{
ClientShadowHandle_t m_LightShadowHandle;
dlight_t *m_pEntityLight;
} TransformedLighting;
virtual void OnPreDataChanged( DataUpdateType_t updateType );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual int DrawModel( int flags );
void UpdateOriginPlane( void );
void UpdateGhostRenderables( void );
void SetIsPortal2( bool bValue );
bool IsActivedAndLinked( void ) const;
CPortalSimulator m_PortalSimulator;
virtual C_BaseEntity * PortalRenderable_GetPairedEntity( void ) { return this; };
private:
CUtlVector<EHANDLE> m_hGhostingEntities;
CUtlVector<C_PortalGhostRenderable *> m_GhostRenderables;
float m_fGhostRenderablesClip[4];
friend void __MsgFunc_EntityPortalled(bf_read &msg);
};
typedef C_Prop_Portal CProp_Portal;
#endif //#ifndef C_PROP_PORTAL_H
@@ -0,0 +1,341 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "c_prop_portal_stats_display.h"
#include "c_te_legacytempents.h"
#include "tempent.h"
#include "engine/IEngineSound.h"
#include "dlight.h"
#include "iefx.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include "point_bonusmaps_accessor.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern const ConVar *sv_cheats;
CUtlVector< C_PropPortalStatsDisplay* > g_PropPortalStatsDisplays;
IMPLEMENT_CLIENTCLASS_DT(C_PropPortalStatsDisplay, DT_PropPortalStatsDisplay, CPropPortalStatsDisplay)
RecvPropBool( RECVINFO(m_bEnabled) ),
RecvPropInt( RECVINFO(m_iNumPortalsPlaced) ),
RecvPropInt( RECVINFO(m_iNumStepsTaken) ),
RecvPropFloat( RECVINFO(m_fNumSecondsTaken) ),
RecvPropInt( RECVINFO(m_iBronzeObjective) ),
RecvPropInt( RECVINFO(m_iSilverObjective) ),
RecvPropInt( RECVINFO(m_iGoldObjective) ),
RecvPropString( RECVINFO( szChallengeFileName ) ),
RecvPropString( RECVINFO( szChallengeMapName ) ),
RecvPropString( RECVINFO( szChallengeName ) ),
RecvPropInt( RECVINFO(m_iDisplayObjective) ),
END_RECV_TABLE()
C_PropPortalStatsDisplay::C_PropPortalStatsDisplay()
{
g_PropPortalStatsDisplays.AddToTail( this );
m_fEnabledCounter = -2.0f;
}
C_PropPortalStatsDisplay::~C_PropPortalStatsDisplay()
{
g_PropPortalStatsDisplays.FindAndRemove( this );
}
void C_PropPortalStatsDisplay::Spawn( void )
{
BaseClass::Spawn();
m_bHasCheated = false;
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
void C_PropPortalStatsDisplay::OnPreDataChanged( DataUpdateType_t updateType )
{
// Remember the enable status from before the update
if ( updateType == DATA_UPDATE_DATATABLE_CHANGED )
m_bPrevEnabled = m_bEnabled;
BaseClass::OnPreDataChanged( updateType );
}
void C_PropPortalStatsDisplay::OnDataChanged( DataUpdateType_t updateType )
{
BaseClass::OnDataChanged( updateType );
if ( updateType == DATA_UPDATE_DATATABLE_CHANGED )
{
// Check if it was just enabled
if ( m_bEnabled && !m_bPrevEnabled )
{
ResetDisplayAnimation();
// Don't update if the player has cheated (and isn't at least developer level 2)
if ( !m_bHasCheated || developer.GetInt() >= 2 )
{
int iStat = 0;
if ( m_iDisplayObjective == 0 )
iStat = m_iNumPortalsPlaced;
else if ( m_iDisplayObjective == 1 )
iStat = m_iNumStepsTaken;
else if ( m_iDisplayObjective == 2 )
iStat = m_fNumSecondsTaken;
BonusMapChallengeUpdate( szChallengeFileName, szChallengeMapName, szChallengeName, iStat );
}
}
}
}
void C_PropPortalStatsDisplay::ClientThink( void )
{
BaseClass::ClientThink();
// Remembers if the player has cheated
// This doesn't persist across save/loads,
// this is only to prevent players from accidentally wiping their stats while no clipping through a map
if ( !sv_cheats )
{
sv_cheats = cvar->FindVar( "sv_cheats" );
}
if ( sv_cheats && sv_cheats->GetInt() != 0 )
m_bHasCheated = true;
if ( !m_bEnabled )
return;
// Check if the display needs to be initialized
if ( m_fEnabledCounter < -1.0f )
{
m_fEnabledCounter = -1.0f;
if ( m_iDisplayObjective == 0 )
m_fNumPlayerDisplay = m_iNumPortalsPlaced;
else if ( m_iDisplayObjective == 1 )
m_fNumPlayerDisplay = m_iNumStepsTaken;
else
m_fNumPlayerDisplay = m_fNumSecondsTaken;
SetDisplayMedals();
if ( m_iGoalLevelDisplay == 0 )
m_iGoalDisplay = m_iBronzeObjective;
else if ( m_iGoalLevelDisplay == 1 )
m_iGoalDisplay = m_iSilverObjective;
else
m_iGoalDisplay = m_iGoldObjective;
m_bGoalVisible = true;
m_iGoalSuccess = -1;
return;
}
//Check if the display is done animating
if ( m_fEnabledCounter < 0.0f )
return;
// Add up how much time has passed
m_fEnabledCounter += gpGlobals->frametime;
switch ( m_iCurrentDisplayStep )
{
// Count down to making objective visible
case 0:
if ( m_fEnabledCounter > 1.0f )
{
m_fEnabledCounter = 0.0f;
EmitSound( "Portal.stair_clack" );
m_bGoalVisible = true;
++m_iCurrentDisplayStep;
}
break;
// Count up how the player actually did
case 1:
switch ( m_iDisplayObjective )
{
case PORTAL_LEVEL_STAT_NUM_PORTALS:
if ( m_fEnabledCounter > 1.5f / static_cast<float>( m_iNumPortalsPlaced + 1 ) )
{
m_fEnabledCounter = 0.0f;
if ( m_fNumPlayerDisplay < m_iNumPortalsPlaced )
{
m_fNumPlayerDisplay += 1.0f;
if ( static_cast<int>( m_fNumPlayerDisplay ) % 2 == 0 )
EmitSound( "Weapon_Portalgun.fire_blue" );
else
EmitSound( "Weapon_Portalgun.fire_red" );
}
else
++m_iCurrentDisplayStep;
}
break;
case PORTAL_LEVEL_STAT_NUM_STEPS:
if ( m_fEnabledCounter > 1.5f / static_cast<float>( m_iNumStepsTaken + 1 ) )
{
int iNumStepsThisFrame = m_fEnabledCounter * static_cast<float>( m_iNumStepsTaken + 1 );
m_fEnabledCounter = 0.0f;
if ( m_fNumPlayerDisplay < m_iNumStepsTaken )
{
m_fNumPlayerDisplay += MIN( iNumStepsThisFrame, m_iNumStepsTaken - m_fNumPlayerDisplay );
int iStepsMod10 = static_cast<int>( m_fNumPlayerDisplay ) % 10;
if ( iStepsMod10 == 0 )
EmitSound( "NPC_Citizen.RunFootstepLeft" );
else if ( iStepsMod10 == 5 )
EmitSound( "NPC_Citizen.RunFootstepRight" );
}
else
++m_iCurrentDisplayStep;
}
break;
case PORTAL_LEVEL_STAT_NUM_SECONDS:
if ( m_fNumPlayerDisplay < m_fNumSecondsTaken )
{
if ( m_fEnabledCounter > 1.5f / ( m_fNumSecondsTaken + 1.0f ) )
{
m_fEnabledCounter = 0.0f;
EmitSound( "Portal.room1_Clock" );
}
m_fNumPlayerDisplay += gpGlobals->frametime * m_fNumSecondsTaken;
if ( m_fNumPlayerDisplay >= m_fNumSecondsTaken )
{
m_fNumPlayerDisplay = m_fNumSecondsTaken;
m_fEnabledCounter = 0.0f;
++m_iCurrentDisplayStep;
}
}
break;
}
break;
// Count down to reveal success or failure
case 2:
if ( m_fEnabledCounter > 1.5f )
{
m_fEnabledCounter = 0.0f;
int iCurretStat = -1;
switch ( m_iDisplayObjective )
{
case 0:
iCurretStat = m_iNumPortalsPlaced;
break;
case 1:
iCurretStat = m_iNumStepsTaken;
break;
case 2:
iCurretStat = static_cast<int>( m_fNumSecondsTaken );
break;
}
int (*(pObjectives[ 3 ])) = { &m_iBronzeObjective, &m_iSilverObjective, &m_iGoldObjective };
if ( iCurretStat <= (*(pObjectives[ m_iGoalLevelDisplay ])) )
{
m_bMedalCompleted[ m_iGoalLevelDisplay ] = true;
m_iGoalSuccess = 1;
EmitSound( "Portal.button_down" );
if ( m_iGoalLevelDisplay == 2 )
++m_iCurrentDisplayStep; // skip the next step
}
else
{
m_iGoalSuccess = 0;
EmitSound( "Portal.button_up" );
++m_iCurrentDisplayStep; // skip the next step
}
++m_iCurrentDisplayStep;
}
break;
// Count down to reveal new objective
case 3:
if ( m_fEnabledCounter > 1.5f )
{
m_fEnabledCounter = 0.0f;
++m_iGoalLevelDisplay;
int (*(pObjectives[ 3 ])) = { &m_iBronzeObjective, &m_iSilverObjective, &m_iGoldObjective };
m_iGoalDisplay = (*(pObjectives[ m_iGoalLevelDisplay ]));
m_iGoalSuccess = -1;
EmitSound( "Portal.stair_clack" );
--m_iCurrentDisplayStep; // go back to success or failure step
}
break;
// Short pause before going to next objective
case 4:
if ( m_fEnabledCounter > 1.5f )
{
m_fEnabledCounter = 0.0f;
m_iGoalSuccess = -1;
m_fEnabledCounter = -1.0f;
m_iCurrentDisplayStep = 0;
}
break;
}
}
void C_PropPortalStatsDisplay::ResetDisplayAnimation( void )
{
EmitSound( "Portal.elevator_ding" );
m_fEnabledCounter = 0.0f;
m_iCurrentDisplayStep = 0;
m_fNumPlayerDisplay = 0.0f;
SetDisplayMedals();
m_bGoalVisible = false;
}
void C_PropPortalStatsDisplay::SetDisplayMedals( void )
{
m_bMedalCompleted[ 0 ] = false;
m_bMedalCompleted[ 1 ] = false;
m_bMedalCompleted[ 2 ] = false;
m_iGoalDisplay = m_iBronzeObjective;
m_iGoalLevelDisplay = 0;
m_iGoalSuccess = -1;
}
@@ -0,0 +1,87 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef C_PROP_PORTAL_STATS_DISPLAY_H
#define C_PROP_PORTAL_STATS_DISPLAY_H
#include "cbase.h"
#include "c_portal_player.h"
#include "portal_shareddefs.h"
#include "utlvector.h"
class C_PropPortalStatsDisplay : public C_BaseAnimating
{
public:
DECLARE_CLASS( C_PropPortalStatsDisplay, CBaseAnimating );
DECLARE_CLIENTCLASS();
C_PropPortalStatsDisplay();
virtual ~C_PropPortalStatsDisplay();
void Spawn( void );
virtual void OnPreDataChanged( DataUpdateType_t updateType );
virtual void OnDataChanged( DataUpdateType_t updateType );
void ClientThink( void );
bool HasCheated( void ) { return m_bHasCheated; }
bool IsEnabled( void ) { return m_bEnabled; }
int GetDisplayObjective( void ) { return m_iDisplayObjective; }
float GetNumPlayerDisplay( void ) { return m_fNumPlayerDisplay; }
bool IsTime( void ) { return m_iDisplayObjective == PORTAL_LEVEL_STAT_NUM_SECONDS; }
bool GetGoalVisible( void ) { return m_bGoalVisible; }
int GetNumGoalDisplay( void ) { return m_iGoalDisplay; }
int GetGoalSuccess( void ) { return m_iGoalSuccess; }
int GetGoalLevelDisplay( void ) { return m_iGoalLevelDisplay; }
bool IsMedalCompleted( int iLevel ) { return m_bMedalCompleted[ iLevel ]; }
private:
void ResetDisplayAnimation( void );
void SetDisplayMedals( void );
private:
bool m_bPrevEnabled;
bool m_bHasCheated;
bool m_bEnabled;
int m_iNumPortalsPlaced;
int m_iNumStepsTaken;
float m_fNumSecondsTaken;
int m_iBronzeObjective;
int m_iSilverObjective;
int m_iGoldObjective;
char szChallengeFileName[128];
char szChallengeMapName[32];
char szChallengeName[32];
int m_iDisplayObjective;
int m_iCurrentDisplayStep;
float m_fEnabledCounter;
float m_fNumPlayerDisplay;
bool m_bGoalVisible;
int m_iGoalDisplay;
int m_iGoalSuccess;
int m_iGoalLevelDisplay;
bool m_bMedalCompleted[ 3 ];
};
extern CUtlVector< C_PropPortalStatsDisplay* > g_PropPortalStatsDisplays;
#endif //C_PROP_PORTAL_STATS_DISPLAY_H
+388
View File
@@ -0,0 +1,388 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_weapon__stubs.h"
#include "weapon_portalbasecombatweapon.h"
#include "fx.h"
#include "particles_localspace.h"
#include "view.h"
#include "particles_attractor.h"
class C_WeaponPhysCannon: public CBasePortalCombatWeapon
{
DECLARE_CLASS( C_WeaponPhysCannon, CBasePortalCombatWeapon );
public:
C_WeaponPhysCannon( void );
DECLARE_CLIENTCLASS();
DECLARE_PREDICTABLE();
virtual int DrawModel( int flags );
private:
bool SetupEmitter( void );
bool m_bIsCurrentlyUpgrading;
bool m_bWasUpgraded;
CSmartPtr<CLocalSpaceEmitter> m_pLocalEmitter;
CSmartPtr<CSimpleEmitter> m_pEmitter;
CSmartPtr<CParticleAttractor> m_pAttractor;
};
STUB_WEAPON_CLASS_IMPLEMENT( weapon_physcannon, C_WeaponPhysCannon );
IMPLEMENT_CLIENTCLASS_DT( C_WeaponPhysCannon, DT_WeaponPhysCannon, CWeaponPhysCannon )
RecvPropBool( RECVINFO( m_bIsCurrentlyUpgrading ) ),
END_RECV_TABLE()
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
C_WeaponPhysCannon::C_WeaponPhysCannon( void )
{
m_bWasUpgraded = false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_WeaponPhysCannon::SetupEmitter( void )
{
if ( !m_pLocalEmitter.IsValid() )
{
m_pLocalEmitter = CLocalSpaceEmitter::Create( "physpowerup", GetRefEHandle(), LookupAttachment( "core" ) );
if ( m_pLocalEmitter.IsValid() == false )
return false;
}
if ( !m_pAttractor.IsValid() )
{
m_pAttractor = CParticleAttractor::Create( vec3_origin, "physpowerup_att" );
if ( m_pAttractor.IsValid() == false )
return false;
}
if ( !m_pEmitter.IsValid() )
{
m_pEmitter = CSimpleEmitter::Create( "physpowerup_glow" );
if ( m_pEmitter.IsValid() == false )
return false;
}
return true;
}
//-----------------------------------------------------------------------------
// Sorts the components of a vector
//-----------------------------------------------------------------------------
static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx )
{
Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
if (absVec[2] > absVec[maxIdx])
{
maxIdx = 2;
}
// always choose something right-handed....
switch( maxIdx )
{
case 0:
pVecIdx[0] = 1;
pVecIdx[1] = 2;
pVecIdx[2] = 0;
break;
case 1:
pVecIdx[0] = 2;
pVecIdx[1] = 0;
pVecIdx[2] = 1;
break;
case 2:
pVecIdx[0] = 0;
pVecIdx[1] = 1;
pVecIdx[2] = 2;
break;
}
}
//-----------------------------------------------------------------------------
// Compute the bounding box's center, size, and basis
//-----------------------------------------------------------------------------
void ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld,
Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec )
{
// Compute the center of the hitbox in worldspace
Vector vecHitboxCenter;
VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter );
vecHitboxCenter *= 0.5f;
VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin );
// Get the object's basis
Vector vec[3];
MatrixGetColumn( hitboxToWorld, 0, vec[0] );
MatrixGetColumn( hitboxToWorld, 1, vec[1] );
MatrixGetColumn( hitboxToWorld, 2, vec[2] );
// vec[1] *= -1.0f;
Vector vecViewDir;
VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir );
VectorNormalize( vecViewDir );
// Project the shadow casting direction into the space of the hitbox
Vector localViewDir;
localViewDir[0] = DotProduct( vec[0], vecViewDir );
localViewDir[1] = DotProduct( vec[1], vecViewDir );
localViewDir[2] = DotProduct( vec[2], vecViewDir );
// Figure out which vector has the largest component perpendicular
// to the view direction...
// Sort by how perpendicular it is
int vecIdx[3];
SortAbsVectorComponents( localViewDir, vecIdx );
// Here's our hitbox basis vectors; namely the ones that are
// most perpendicular to the view direction
*pXVec = vec[vecIdx[0]];
*pYVec = vec[vecIdx[1]];
// Project them into a plane perpendicular to the view direction
*pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec );
*pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec );
VectorNormalize( *pXVec );
VectorNormalize( *pYVec );
// Compute the hitbox size
Vector boxSize;
VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize );
// We project the two longest sides into the vectors perpendicular
// to the projection direction, then add in the projection of the perp direction
Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) );
size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) );
// Add the third component into x and y
size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) );
size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) );
// Bloat a bit, since the shadow wants to extend outside the model a bit
size *= 2.0f;
// Clamp the minimum size
Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
// Factor the size into the xvec + yvec
(*pXVec) *= size.x * 0.5f;
(*pYVec) *= size.y * 0.5f;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
// Output : int
//-----------------------------------------------------------------------------
int C_WeaponPhysCannon::DrawModel( int flags )
{
// If we're not ugrading, don't do anything special
if ( m_bIsCurrentlyUpgrading == false && m_bWasUpgraded == false )
return BaseClass::DrawModel( flags );
if ( gpGlobals->frametime == 0 )
return BaseClass::DrawModel( flags );
if ( !m_bReadyToDraw )
return 0;
m_bWasUpgraded = true;
// Create the particle emitter if it's not already
if ( SetupEmitter() )
{
// Add the power-up particles
// See if we should draw
if ( m_bReadyToDraw == false )
return 0;
C_BaseAnimating *pAnimating = GetBaseAnimating();
if (!pAnimating)
return 0;
matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
return 0;
studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
if (!pStudioHdr)
return false;
mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
if ( !set )
return false;
int i;
float fadePerc = 1.0f;
if ( m_bIsCurrentlyUpgrading )
{
Vector vecSkew = vec3_origin;
// Skew the particles in front or in back of their targets
vecSkew = CurrentViewForward() * 4.0f;
float spriteScale = 1.0f;
spriteScale = clamp( spriteScale, 0.75f, 1.0f );
SimpleParticle *sParticle;
for ( i = 0; i < set->numhitboxes; ++i )
{
Vector vecAbsOrigin, xvec, yvec;
mstudiobbox_t *pBox = set->pHitbox(i);
ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec );
Vector offset;
Vector xDir, yDir;
xDir = xvec;
float xScale = VectorNormalize( xDir ) * 0.75f;
yDir = yvec;
float yScale = VectorNormalize( yDir ) * 0.75f;
int numParticles = clamp( 4.0f * fadePerc, 1, 3 );
for ( int j = 0; j < numParticles; j++ )
{
offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f );
offset += vecSkew;
sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), m_pEmitter->GetPMaterial( "effects/combinemuzzle1" ), vecAbsOrigin + offset );
if ( sParticle == NULL )
return 1;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_uchStartSize = 16.0f * spriteScale;
sParticle->m_flDieTime = 0.2f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
float alpha = 40;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2;
}
}
}
}
int attachment = LookupAttachment( "core" );
Vector coreOrigin;
QAngle coreAngles;
GetAttachment( attachment, coreOrigin, coreAngles );
SimpleParticle *sParticle;
// Do the core effects
for ( int i = 0; i < 4; i++ )
{
sParticle = (SimpleParticle *) m_pLocalEmitter->AddParticle( sizeof(SimpleParticle), m_pLocalEmitter->GetPMaterial( "effects/strider_muzzle" ), vec3_origin );
if ( sParticle == NULL )
return 1;
sParticle->m_vecVelocity = vec3_origin;
sParticle->m_flDieTime = 0.1f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
if ( i < 2 )
{
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
else
{
if ( random->RandomInt( 0, 20 ) == 0 )
{
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 4.0f;
sParticle->m_flDieTime = 0.25f;
}
else
{
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 ) * (i+1);
sParticle->m_uchEndSize = sParticle->m_uchStartSize * 2.0f;
}
}
}
if ( m_bWasUpgraded && m_bIsCurrentlyUpgrading )
{
// Update our attractor point
m_pAttractor->SetAttractorOrigin( coreOrigin );
Vector offset;
for ( int i = 0; i < 4; i++ )
{
offset = coreOrigin + RandomVector( -32.0f, 32.0f );
sParticle = (SimpleParticle *) m_pAttractor->AddParticle( sizeof(SimpleParticle), m_pAttractor->GetPMaterial( "effects/strider_muzzle" ), offset );
if ( sParticle == NULL )
return 1;
sParticle->m_vecVelocity = Vector(0,0,8);
sParticle->m_flDieTime = 0.5f;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
sParticle->m_flRollDelta = 0.0f;
float alpha = 255;
sParticle->m_uchColor[0] = alpha;
sParticle->m_uchColor[1] = alpha;
sParticle->m_uchColor[2] = alpha;
sParticle->m_uchStartAlpha = alpha;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomFloat( 1, 2 );
sParticle->m_uchEndSize = 0;
}
}
return BaseClass::DrawModel( flags );
}
File diff suppressed because it is too large Load Diff
+278
View File
@@ -0,0 +1,278 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef C_WEAPON_PORTALGUN_H
#define C_WEAPON_PORTALGUN_H
#ifdef _WIN32
#pragma once
#endif
#include "weapon_portalbasecombatweapon.h"
#include "c_prop_portal.h"
#include "fx_interpvalue.h"
#include "beamdraw.h"
#include "iviewrender_beams.h"
//----------------------------------------------------------------------------------------------------------------------------------------------------------
// CPhysCannonEffect class
//----------------------------------------------------------------------------------------------------------------------------------------------------------
class CPortalgunEffect
{
public:
CPortalgunEffect( void )
: m_vecColor( 255, 255, 255 ),
m_bVisibleViewModel( true ),
m_bVisible3rdPerson( true ),
m_nAttachment( -1 )
{}
void SetAttachment( int attachment ) { m_nAttachment = attachment; }
int GetAttachment( void ) const { return m_nAttachment; }
void SetVisible( bool visible = true ) { m_bVisibleViewModel = visible; m_bVisible3rdPerson = visible; }
void SetVisibleViewModel( bool visible = true ) { m_bVisibleViewModel = visible; }
int IsVisibleViewModel( void ) const { return m_bVisibleViewModel; }
void SetVisible3rdPerson( bool visible = true ) { m_bVisible3rdPerson = visible; }
int IsVisible3rdPerson( void ) const { return m_bVisible3rdPerson; }
void SetColor( const Vector &color ) { m_vecColor = color; }
const Vector &GetColor( void ) const { return m_vecColor; }
bool SetMaterial( const char *materialName )
{
m_hMaterial.Init( materialName, TEXTURE_GROUP_CLIENT_EFFECTS );
return ( m_hMaterial != NULL );
}
CMaterialReference &GetMaterial( void ) { return m_hMaterial; }
CInterpolatedValue &GetAlpha( void ) { return m_Alpha; }
CInterpolatedValue &GetScale( void ) { return m_Scale; }
virtual PortalWeaponID GetWeaponID( void ) const { return WEAPON_PORTALGUN; }
private:
CInterpolatedValue m_Alpha;
CInterpolatedValue m_Scale;
Vector m_vecColor;
bool m_bVisibleViewModel;
bool m_bVisible3rdPerson;
int m_nAttachment;
CMaterialReference m_hMaterial;
};
class CPortalgunEffectBeam
{
public:
CPortalgunEffectBeam( void );;
~CPortalgunEffectBeam( void );
void Release( void );
void Init( int startAttachment, int endAttachment, CBaseEntity *pEntity, bool firstPerson );
void SetVisibleViewModel( bool visible = true );
int IsVisibleViewModel( void ) const;
void SetVisible3rdPerson( bool visible = true );
int SetVisible3rdPerson( void ) const;
void SetBrightness( float fBrightness );
void DrawBeam( void );
private:
Beam_t *m_pBeam;
float m_fBrightness;
};
class C_WeaponPortalgun : public CBasePortalCombatWeapon
{
public:
DECLARE_CLASS( C_WeaponPortalgun, CBasePortalCombatWeapon );
DECLARE_NETWORKCLASS();
DECLARE_PREDICTABLE();
private:
CNetworkVar( bool, m_bCanFirePortal1 ); // Is able to use primary fire
CNetworkVar( bool, m_bCanFirePortal2 ); // Is able to use secondary fire
CNetworkVar( int, m_iLastFiredPortal ); // Which portal was placed last
CNetworkVar( bool, m_bOpenProngs ); // Which portal was placed last
CNetworkVar( float, m_fCanPlacePortal1OnThisSurface ); // Tells the gun if it can place on the surface it's pointing at
CNetworkVar( float, m_fCanPlacePortal2OnThisSurface ); // Tells the gun if it can place on the surface it's pointing at
CNetworkVar( float, m_fEffectsMaxSize1 );
CNetworkVar( float, m_fEffectsMaxSize2 );
public:
virtual const Vector& GetBulletSpread( void )
{
static Vector cone = VECTOR_CONE_10DEGREES;
return cone;
}
void Precache ( void );
virtual void OnRestore( void );
virtual void UpdateOnRemove( void );
void Spawn( void );
void DoEffectCreate( Vector &vDir, Vector &ptStart, Vector &ptEnd, bool bPortal1, bool bPlayer );
virtual bool ShouldDrawCrosshair( void );
float GetPortal1Placablity( void ) { return m_fCanPlacePortal1OnThisSurface; }
float GetPortal2Placablity( void ) { return m_fCanPlacePortal2OnThisSurface; }
int GetLastFiredPortal( void ) { return m_iLastFiredPortal; }
bool IsHoldingObject( void ) { return m_bOpenProngs; }
bool Reload( void );
void FillClip( void );
void CheckHolsterReload( void );
void ItemHolsterFrame( void );
bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
bool Deploy( void );
void SetCanFirePortal1( bool bCanFire = true );
void SetCanFirePortal2( bool bCanFire = true );
float CanFirePortal1( void ) { return m_bCanFirePortal1; }
float CanFirePortal2( void ) { return m_bCanFirePortal2; }
void PrimaryAttack( void );
void SecondaryAttack( void );
void DelayAttack( float fDelay );
void DryFire( void );
virtual float GetFireRate( void ) { return 0.7; };
void WeaponIdle( void );
protected:
void StartEffects( void ); // Initialize all sprites and beams
void StopEffects( bool stopSound = true ); // Hide all effects temporarily
void DestroyEffects( void ); // Destroy all sprites and beams
// Portalgun effects
void DoEffect( int effectType, Vector *pos = NULL );
void DoEffectClosed( void );
void DoEffectReady( void );
void DoEffectHolding( void );
void DoEffectNone( void );
enum EffectType_t
{
PORTALGUN_GRAVLIGHT = 0,
PORTALGUN_GRAVLIGHT_WORLD,
PORTALGUN_PORTAL1LIGHT,
PORTALGUN_PORTAL1LIGHT_WORLD,
PORTALGUN_PORTAL2LIGHT,
PORTALGUN_PORTAL2LIGHT_WORLD,
PORTALGUN_GLOW1, // Must be in order!
PORTALGUN_GLOW2,
PORTALGUN_GLOW3,
PORTALGUN_GLOW4,
PORTALGUN_GLOW5,
PORTALGUN_GLOW6,
PORTALGUN_GLOW1_WORLD,
PORTALGUN_GLOW2_WORLD,
PORTALGUN_GLOW3_WORLD,
PORTALGUN_GLOW4_WORLD,
PORTALGUN_GLOW5_WORLD,
PORTALGUN_GLOW6_WORLD,
PORTALGUN_ENDCAP1, // Must be in order!
PORTALGUN_ENDCAP2,
PORTALGUN_ENDCAP3,
PORTALGUN_ENDCAP1_WORLD,
PORTALGUN_ENDCAP2_WORLD,
PORTALGUN_ENDCAP3_WORLD,
PORTALGUN_MUZZLE_GLOW,
PORTALGUN_MUZZLE_GLOW_WORLD,
PORTALGUN_TUBE_BEAM1,
PORTALGUN_TUBE_BEAM2,
PORTALGUN_TUBE_BEAM3,
PORTALGUN_TUBE_BEAM4,
PORTALGUN_TUBE_BEAM5,
PORTALGUN_TUBE_BEAM1_WORLD,
PORTALGUN_TUBE_BEAM2_WORLD,
PORTALGUN_TUBE_BEAM3_WORLD,
PORTALGUN_TUBE_BEAM4_WORLD,
PORTALGUN_TUBE_BEAM5_WORLD,
NUM_PORTALGUN_PARAMETERS // Must be last!
};
#define NUM_GLOW_SPRITES ((C_WeaponPortalgun::PORTALGUN_GLOW6-C_WeaponPortalgun::PORTALGUN_GLOW1)+1)
#define NUM_GLOW_SPRITES_WORLD ((C_WeaponPortalgun::PORTALGUN_GLOW6_WORLD-C_WeaponPortalgun::PORTALGUN_GLOW1_WORLD)+1)
#define NUM_ENDCAP_SPRITES ((C_WeaponPortalgun::PORTALGUN_ENDCAP3-C_WeaponPortalgun::PORTALGUN_ENDCAP1)+1)
#define NUM_ENDCAP_SPRITES_WORLD ((C_WeaponPortalgun::PORTALGUN_ENDCAP3_WORLD-C_WeaponPortalgun::PORTALGUN_ENDCAP1_WORLD)+1)
#define NUM_TUBE_BEAM_SPRITES ((C_WeaponPortalgun::PORTALGUN_TUBE_BEAM5-C_WeaponPortalgun::PORTALGUN_TUBE_BEAM1)+1)
#define NUM_TUBE_BEAM_SPRITES_WORLD ((C_WeaponPortalgun::PORTALGUN_TUBE_BEAM5_WORLD-C_WeaponPortalgun::PORTALGUN_TUBE_BEAM1_WORLD)+1)
#define NUM_PORTALGUN_BEAMS 6
void DrawEffects( bool b3rdPerson );
Vector GetEffectColor( int iPalletIndex );
void GetEffectParameters( EffectType_t effectID, color32 &color, float &scale, IMaterial **pMaterial, Vector &vecAttachment, bool b3rdPerson );
void DrawEffectSprite( EffectType_t effectID, bool b3rdPerson );
inline bool IsEffectVisible( EffectType_t effectID, bool b3rdPerson );
void UpdateElementPosition( void );
CPortalgunEffect m_Parameters[NUM_PORTALGUN_PARAMETERS]; // Interpolated parameters for the effects
CPortalgunEffectBeam m_Beams[NUM_PORTALGUN_BEAMS]; // Beams
int m_nOldEffectState; // Used for parity checks
bool m_bOldCanFirePortal1;
bool m_bOldCanFirePortal2;
bool m_bPulseUp;
float m_fPulse;
CNetworkVar( int, m_EffectState ); // Current state of the effects on the gun
public:
virtual int DrawModel( int flags );
virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel );
virtual void OnPreDataChanged( DataUpdateType_t updateType );
virtual void OnDataChanged( DataUpdateType_t updateType );
virtual void ClientThink( void );
void DoEffectIdle( void );
public:
DECLARE_ACTTABLE();
C_WeaponPortalgun(void);
private:
C_WeaponPortalgun( const C_WeaponPortalgun & );
};
#endif // C_WEAPON_PORTALGUN_H
@@ -0,0 +1,39 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "c_weapon__stubs.h"
#include "basehlcombatweapon_shared.h"
#include "c_basehlcombatweapon.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
STUB_WEAPON_CLASS( cycler_weapon, WeaponCycler, C_BaseCombatWeapon );
STUB_WEAPON_CLASS( weapon_binoculars, WeaponBinoculars, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_bugbait, WeaponBugBait, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_flaregun, Flaregun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_annabelle, WeaponAnnabelle, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_gauss, WeaponGaussGun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_cubemap, WeaponCubemap, C_BaseCombatWeapon );
STUB_WEAPON_CLASS( weapon_alyxgun, WeaponAlyxGun, C_HLSelectFireMachineGun );
STUB_WEAPON_CLASS( weapon_citizenpackage, WeaponCitizenPackage, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_citizensuitcase, WeaponCitizenSuitcase, C_WeaponCitizenPackage );
STUB_WEAPON_CLASS( weapon_ar2, WeaponAR2, C_HLMachineGun );
STUB_WEAPON_CLASS( weapon_frag, WeaponFrag, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_rpg, WeaponRPG, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_pistol, WeaponPistol, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_shotgun, WeaponShotgun, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_smg1, WeaponSMG1, C_HLSelectFireMachineGun );
STUB_WEAPON_CLASS( weapon_357, Weapon357, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_crossbow, WeaponCrossbow, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_slam, Weapon_SLAM, C_BaseHLCombatWeapon );
STUB_WEAPON_CLASS( weapon_crowbar, WeaponCrowbar, C_BaseHLBludgeonWeapon );
STUB_WEAPON_CLASS( weapon_hopwire, WeaponHopwire, C_BaseHLCombatWeapon );
+227
View File
@@ -0,0 +1,227 @@
//========= Copyright 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"
// 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 );
// The current client mode. Always ClientModeNormal in HL.
IClientMode *g_pClientMode = NULL;
//extern EHANDLE g_eKillTarget1;
//extern EHANDLE g_eKillTarget2;
vgui::HScheme g_hVGuiCombineScheme = 0;
#define SCREEN_FILE "scripts/vgui_screens.txt"
//void MsgFunc_KillCam(bf_read &msg)
//{
// C_Portal_Player *pPlayer = C_Portal_Player::GetLocalPortalPlayer();
//
// if ( !pPlayer )
// return;
//
// g_eKillTarget1 = 0;
// g_eKillTarget2 = 0;
// g_nKillCamTarget1 = 0;
// g_nKillCamTarget1 = 0;
//
// long iEncodedEHandle = msg.ReadLong();
//
// if( iEncodedEHandle == INVALID_NETWORKED_EHANDLE_VALUE )
// return;
//
// int iEntity = iEncodedEHandle & ((1 << MAX_EDICT_BITS) - 1);
// int iSerialNum = iEncodedEHandle >> MAX_EDICT_BITS;
//
// EHANDLE hEnt1( iEntity, iSerialNum );
//
// iEncodedEHandle = msg.ReadLong();
//
// if( iEncodedEHandle == INVALID_NETWORKED_EHANDLE_VALUE )
// return;
//
// iEntity = iEncodedEHandle & ((1 << MAX_EDICT_BITS) - 1);
// iSerialNum = iEncodedEHandle >> MAX_EDICT_BITS;
//
// EHANDLE hEnt2( iEntity, iSerialNum );
//
// g_eKillTarget1 = hEnt1;
// g_eKillTarget2 = hEnt2;
//
// if ( g_eKillTarget1.Get() )
// {
// g_nKillCamTarget1 = g_eKillTarget1.Get()->entindex();
// }
//
// if ( g_eKillTarget2.Get() )
// {
// g_nKillCamTarget2 = g_eKillTarget2.Get()->entindex();
// }
//}
//-----------------------------------------------------------------------------
// 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 );
gHUD.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 CHL2MPClientScoreBoardDialog( 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 )
{
g_pClientMode = 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 )
{
g_pClientMode->LevelInit( newmap );
if ( g_nKillCamMode > OBS_MODE_NONE )
{
g_bForceCLPredictOff = false;
}
g_nKillCamMode = OBS_MODE_NONE;
//g_nKillCamTarget1 = 0;
//g_nKillCamTarget2 = 0;
}
void CHLModeManager::LevelShutdown( void )
{
g_pClientMode->LevelShutdown();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
ClientModePortalNormal::ClientModePortalNormal()
{
}
//-----------------------------------------------------------------------------
// 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();
//usermessages->HookMessage( "KillCam", MsgFunc_KillCam );
}
void ClientModePortalNormal::InitViewport()
{
m_pViewport = new CHudViewport();
m_pViewport->Start( gameuifuncs, gameeventmanager );
}
ClientModePortalNormal g_ClientModeNormal;
IClientMode *GetClientModeNormal()
{
return &g_ClientModeNormal;
}
ClientModePortalNormal* GetClientModePortalNormal()
{
Assert( dynamic_cast< ClientModePortalNormal* >( GetClientModeNormal() ) );
return static_cast< ClientModePortalNormal* >( GetClientModeNormal() );
}
static CHLModeManager g_HLModeManager;
IVModeManager *modemanager = &g_HLModeManager;
+51
View File
@@ -0,0 +1,51 @@
//========= Copyright 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;
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();
private:
// void UpdateSpectatorMode( void );
};
extern IClientMode *GetClientModeNormal();
extern ClientModePortalNormal* GetClientModePortalNormal();
#endif // PORTAL_CLIENTMODE_H
+123
View File
@@ -0,0 +1,123 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Fizzle effects for portal.
//
//=============================================================================//
#include "cbase.h"
#include "clienteffectprecachesystem.h"
#include "fx.h"
#include "fx_sparks.h"
#include "iefx.h"
#include "c_te_effect_dispatch.h"
#include "particles_ez.h"
#include "decals.h"
#include "engine/IEngineSound.h"
#include "fx_quad.h"
#include "engine/ivdebugoverlay.h"
#include "shareddefs.h"
#include "portal_shareddefs.h"
#include "effect_color_tables.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
class C_PortalBlast : public C_BaseEntity
{
DECLARE_CLASS( C_PortalBlast, C_BaseAnimating );
public:
static void Create( bool bIsPortal2, PortalPlacedByType ePlacedBy, const Vector &vStart, const Vector &vEnd, const QAngle &qAngles, float fDeathTime );
void Init( bool bIsPortal2, PortalPlacedByType ePlacedBy, const Vector &vStart, const Vector &vEnd, const QAngle &qAngles, float fDeathTime );
virtual void ClientThink( void );
private:
Vector m_ptCreationPoint;
Vector m_ptDeathPoint;
Vector m_ptAimPoint;
float m_fCreationTime;
float m_fDeathTime;
};
void C_PortalBlast::Create( bool bIsPortal2, PortalPlacedByType ePlacedBy, const Vector &vStart, const Vector &vEnd, const QAngle &qAngles, float fDeathTime )
{
C_PortalBlast *pPortalBlast = new C_PortalBlast;
pPortalBlast->Init( bIsPortal2, ePlacedBy, vStart, vEnd, qAngles, fDeathTime );
}
void C_PortalBlast::Init( bool bIsPortal2, PortalPlacedByType ePlacedBy, const Vector &vStart, const Vector &vEnd, const QAngle &qAngles, float fDeathTime )
{
ClientEntityList().AddNonNetworkableEntity( this );
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS );
AddToLeafSystem( RENDER_GROUP_OPAQUE_ENTITY );
SetThink( &C_PortalBlast::ClientThink );
SetNextClientThink( CLIENT_THINK_ALWAYS );
m_ptCreationPoint = vStart;
m_ptDeathPoint = vEnd;
SetAbsOrigin( m_ptCreationPoint );
m_fCreationTime = gpGlobals->curtime;
m_fDeathTime = fDeathTime;
if ( m_fDeathTime - 0.1f < m_fCreationTime )
{
m_fDeathTime = m_fCreationTime + 0.1f;
}
Vector vForward;
AngleVectors( qAngles, &vForward );
m_ptAimPoint = m_ptCreationPoint + vForward * m_ptCreationPoint.DistTo( m_ptDeathPoint );
if ( ePlacedBy == PORTAL_PLACED_BY_PLAYER )
ParticleProp()->Create( ( ( bIsPortal2 ) ? ( "portal_2_projectile_stream" ) : ( "portal_1_projectile_stream" ) ), PATTACH_ABSORIGIN_FOLLOW );
else
ParticleProp()->Create( ( ( bIsPortal2 ) ? ( "portal_2_projectile_stream_pedestal" ) : ( "portal_1_projectile_stream_pedestal" ) ), PATTACH_ABSORIGIN_FOLLOW );
}
void C_PortalBlast::ClientThink( void )
{
if ( m_fCreationTime == 0.0f && m_fDeathTime == 0.0f )
{
// Die!
Remove();
return;
}
float fT = ( gpGlobals->curtime - m_fCreationTime ) / ( m_fDeathTime - m_fCreationTime );
if ( fT >= 1.0f )
{
// Ready to die! But we want one more frame in the final position
SetAbsOrigin( m_ptDeathPoint );
m_fCreationTime = 0.0f;
m_fDeathTime = 0.0f;
return;
}
// Set the interpolated position
Vector vTarget = m_ptAimPoint * ( 1.0f - fT ) + m_ptDeathPoint * fT;
SetAbsOrigin( m_ptCreationPoint * ( 1.0f - fT ) + vTarget * fT );
}
void PortalBlastCallback( const CEffectData & data )
{
C_PortalBlast::Create( ( data.m_nColor == 1 ) ? ( false ) : ( true ), (PortalPlacedByType)data.m_nDamageType, data.m_vOrigin, data.m_vStart, data.m_vAngles, data.m_flScale );
}
DECLARE_CLIENT_EFFECT( "PortalBlast", PortalBlastCallback );
+383
View File
@@ -0,0 +1,383 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "hudelement.h"
#include "iclientmode.h"
#include "engine/IEngineSound.h"
#include "vgui_controls/AnimationController.h"
#include "vgui_controls/Controls.h"
#include "vgui_controls/Panel.h"
#include "vgui/ISurface.h"
#include "c_portal_player.h"
#include "c_weapon_portalgun.h"
#include "IGameUIFuncs.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define HEALTH_WARNING_THRESHOLD 25
static ConVar hud_quickinfo( "hud_quickinfo", "1", FCVAR_ARCHIVE );
static ConVar hud_quickinfo_swap( "hud_quickinfo_swap", "0", FCVAR_ARCHIVE );
extern ConVar crosshair;
#define QUICKINFO_EVENT_DURATION 1.0f
#define QUICKINFO_BRIGHTNESS_FULL 255
#define QUICKINFO_BRIGHTNESS_DIM 64
#define QUICKINFO_FADE_IN_TIME 0.5f
#define QUICKINFO_FADE_OUT_TIME 2.0f
/*
==================================================
CHUDQuickInfo
==================================================
*/
using namespace vgui;
class CHUDQuickInfo : public CHudElement, public vgui::Panel
{
DECLARE_CLASS_SIMPLE( CHUDQuickInfo, vgui::Panel );
public:
CHUDQuickInfo( const char *pElementName );
void Init( void );
void VidInit( void );
bool ShouldDraw( void );
//virtual void OnThink();
virtual void Paint();
virtual void ApplySchemeSettings( IScheme *scheme );
private:
void DrawWarning( int x, int y, CHudTexture *icon, float &time );
void UpdateEventTime( void );
bool EventTimeElapsed( void );
float m_flLastEventTime;
float m_fLastPlacedAlpha[2];
bool m_bLastPlacedAlphaCountingUp[2];
CHudTexture *m_icon_c;
CHudTexture *m_icon_rbn; // right bracket
CHudTexture *m_icon_lbn; // left bracket
CHudTexture *m_icon_rb; // right bracket, full
CHudTexture *m_icon_lb; // left bracket, full
CHudTexture *m_icon_rbe; // right bracket, empty
CHudTexture *m_icon_lbe; // left bracket, empty
CHudTexture *m_icon_rbnone; // right bracket
CHudTexture *m_icon_lbnone; // left bracket
};
DECLARE_HUDELEMENT( CHUDQuickInfo );
CHUDQuickInfo::CHUDQuickInfo( const char *pElementName ) :
CHudElement( pElementName ), BaseClass( NULL, "HUDQuickInfo" )
{
vgui::Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
SetHiddenBits( HIDEHUD_CROSSHAIR );
m_fLastPlacedAlpha[0] = m_fLastPlacedAlpha[1] = 80;
m_bLastPlacedAlphaCountingUp[0] = m_bLastPlacedAlphaCountingUp[1] = true;
}
void CHUDQuickInfo::ApplySchemeSettings( IScheme *scheme )
{
BaseClass::ApplySchemeSettings( scheme );
SetPaintBackgroundEnabled( false );
}
void CHUDQuickInfo::Init( void )
{
m_flLastEventTime = 0.0f;
}
void CHUDQuickInfo::VidInit( void )
{
Init();
m_icon_c = gHUD.GetIcon( "crosshair" );
if ( IsX360() )
{
m_icon_rb = gHUD.GetIcon( "portal_crosshair_right_valid_x360" );
m_icon_lb = gHUD.GetIcon( "portal_crosshair_left_valid_x360" );
m_icon_rbe = gHUD.GetIcon( "portal_crosshair_last_placed_x360" );
m_icon_lbe = gHUD.GetIcon( "portal_crosshair_last_placed_x360" );
m_icon_rbn = gHUD.GetIcon( "portal_crosshair_right_invalid_x360" );
m_icon_lbn = gHUD.GetIcon( "portal_crosshair_left_invalid_x360" );
}
else
{
m_icon_rb = gHUD.GetIcon( "portal_crosshair_right_valid" );
m_icon_lb = gHUD.GetIcon( "portal_crosshair_left_valid" );
m_icon_rbe = gHUD.GetIcon( "portal_crosshair_last_placed" );
m_icon_lbe = gHUD.GetIcon( "portal_crosshair_last_placed" );
m_icon_rbn = gHUD.GetIcon( "portal_crosshair_right_invalid" );
m_icon_lbn = gHUD.GetIcon( "portal_crosshair_left_invalid" );
m_icon_rbnone = gHUD.GetIcon( "crosshair_right" );
m_icon_lbnone = gHUD.GetIcon( "crosshair_left" );
}
}
void CHUDQuickInfo::DrawWarning( int x, int y, CHudTexture *icon, float &time )
{
float scale = (int)( fabs(sin(gpGlobals->curtime*8.0f)) * 128.0);
// Only fade out at the low point of our blink
if ( time <= (gpGlobals->frametime * 200.0f) )
{
if ( scale < 40 )
{
time = 0.0f;
return;
}
else
{
// Counteract the offset below to survive another frame
time += (gpGlobals->frametime * 200.0f);
}
}
// Update our time
time -= (gpGlobals->frametime * 200.0f);
Color caution = gHUD.m_clrCaution;
caution[3] = scale * 255;
icon->DrawSelf( x, y, caution );
}
//-----------------------------------------------------------------------------
// Purpose: Save CPU cycles by letting the HUD system early cull
// costly traversal. Called per frame, return true if thinking and
// painting need to occur.
//-----------------------------------------------------------------------------
bool CHUDQuickInfo::ShouldDraw( void )
{
if ( !m_icon_c || !m_icon_rb || !m_icon_rbe || !m_icon_lb || !m_icon_lbe )
return false;
C_Portal_Player *player = ToPortalPlayer(C_BasePlayer::GetLocalPlayer());
if ( player == NULL )
return false;
if ( !crosshair.GetBool() )
return false;
if ( player->IsSuppressingCrosshair() )
return false;
return ( CHudElement::ShouldDraw() && !engine->IsDrawingLoadingImage() );
}
void CHUDQuickInfo::Paint()
{
C_Portal_Player *pPortalPlayer = (C_Portal_Player*)( C_BasePlayer::GetLocalPlayer() );
if ( pPortalPlayer == NULL )
return;
C_BaseCombatWeapon *pWeapon = GetActiveWeapon();
if ( pWeapon == NULL )
return;
int xCenter = ( ScreenWidth() - m_icon_c->Width() ) / 2;
int yCenter = ( ScreenHeight() - m_icon_c->Height() ) / 2;
Color clrNormal = gHUD.m_clrNormal;
clrNormal[3] = 255;
SetActive( true );
m_icon_c->DrawSelf( xCenter, yCenter, clrNormal );
// adjust center for the bigger crosshairs
xCenter = ScreenWidth() / 2;
yCenter = ( ScreenHeight() - m_icon_lb->Height() ) / 2;
C_WeaponPortalgun *pPortalgun = dynamic_cast<C_WeaponPortalgun*>( pWeapon );
bool bPortalPlacability[2];
if ( pPortalgun )
{
bPortalPlacability[0] = pPortalgun->GetPortal1Placablity() > 0.5f;
bPortalPlacability[1] = pPortalgun->GetPortal2Placablity() > 0.5f;
}
if ( !hud_quickinfo.GetInt() || !pPortalgun || ( !pPortalgun->CanFirePortal1() && !pPortalgun->CanFirePortal2() ) )
{
// no quickinfo or we can't fire either portal, just draw the small versions of the crosshairs
clrNormal[3] = 196;
m_icon_lbnone->DrawSelf(xCenter - (m_icon_lbnone->Width() * 2), yCenter, clrNormal);
m_icon_rbnone->DrawSelf(xCenter + m_icon_rbnone->Width(), yCenter, clrNormal);
return;
}
const unsigned char iAlphaStart = 150;
Color portal1Color = UTIL_Portal_Color( 1 );
Color portal2Color = UTIL_Portal_Color( 2 );
portal1Color[ 3 ] = iAlphaStart;
portal2Color[ 3 ] = iAlphaStart;
const int iBaseLastPlacedAlpha = 128;
Color lastPlaced1Color = Color( portal1Color[0], portal1Color[1], portal1Color[2], iBaseLastPlacedAlpha );
Color lastPlaced2Color = Color( portal2Color[0], portal2Color[1], portal2Color[2], iBaseLastPlacedAlpha );
const float fLastPlacedAlphaLerpSpeed = 300.0f;
float fLeftPlaceBarFill = 0.0f;
float fRightPlaceBarFill = 0.0f;
if ( pPortalgun->CanFirePortal1() && pPortalgun->CanFirePortal2() )
{
int iDrawLastPlaced = 0;
//do last placed indicator effects
if ( pPortalgun->GetLastFiredPortal() == 1 )
{
iDrawLastPlaced = 0;
fLeftPlaceBarFill = 1.0f;
}
else if ( pPortalgun->GetLastFiredPortal() == 2 )
{
iDrawLastPlaced = 1;
fRightPlaceBarFill = 1.0f;
}
if( m_bLastPlacedAlphaCountingUp[iDrawLastPlaced] )
{
m_fLastPlacedAlpha[iDrawLastPlaced] += gpGlobals->absoluteframetime * fLastPlacedAlphaLerpSpeed * 2.0f;
if( m_fLastPlacedAlpha[iDrawLastPlaced] > 255.0f )
{
m_bLastPlacedAlphaCountingUp[iDrawLastPlaced] = false;
m_fLastPlacedAlpha[iDrawLastPlaced] = 255.0f - (m_fLastPlacedAlpha[iDrawLastPlaced] - 255.0f);
}
}
else
{
m_fLastPlacedAlpha[iDrawLastPlaced] -= gpGlobals->absoluteframetime * fLastPlacedAlphaLerpSpeed;
if( m_fLastPlacedAlpha[iDrawLastPlaced] < (float)iBaseLastPlacedAlpha )
{
m_fLastPlacedAlpha[iDrawLastPlaced] = (float)iBaseLastPlacedAlpha;
}
}
//reset the last placed indicator on the other side
m_fLastPlacedAlpha[1 - iDrawLastPlaced] -= gpGlobals->absoluteframetime * fLastPlacedAlphaLerpSpeed;
if( m_fLastPlacedAlpha[1 - iDrawLastPlaced] < 0.0f )
{
m_fLastPlacedAlpha[1 - iDrawLastPlaced] = 0.0f;
}
m_bLastPlacedAlphaCountingUp[1 - iDrawLastPlaced] = true;
if ( pPortalgun->GetLastFiredPortal() != 0 )
{
lastPlaced1Color[3] = m_fLastPlacedAlpha[0];
lastPlaced2Color[3] = m_fLastPlacedAlpha[1];
}
else
{
lastPlaced1Color[3] = 0.0f;
lastPlaced2Color[3] = 0.0f;
}
}
//can't fire both portals, and we want the crosshair to remain somewhat symmetrical without being confusing
else if ( !pPortalgun->CanFirePortal1() )
{
// clone portal2 info to portal 1
portal1Color = portal2Color;
lastPlaced1Color[3] = 0.0f;
lastPlaced2Color[3] = 0.0f;
bPortalPlacability[0] = bPortalPlacability[1];
}
else if ( !pPortalgun->CanFirePortal2() )
{
// clone portal1 info to portal 2
portal2Color = portal1Color;
lastPlaced1Color[3] = 0.0f;
lastPlaced2Color[3] = 0.0f;
bPortalPlacability[1] = bPortalPlacability[0];
}
if ( pPortalgun->IsHoldingObject() )
{
// Change the middle to orange
portal1Color = portal2Color = UTIL_Portal_Color( 0 );
bPortalPlacability[0] = bPortalPlacability[1] = false;
}
if ( !hud_quickinfo_swap.GetBool() )
{
if ( bPortalPlacability[0] )
m_icon_lb->DrawSelf(xCenter - (m_icon_lb->Width() * 0.64f ), yCenter - ( m_icon_rb->Height() * 0.17f ), portal1Color);
else
m_icon_lbn->DrawSelf(xCenter - (m_icon_lbn->Width() * 0.64f ), yCenter - ( m_icon_rb->Height() * 0.17f ), portal1Color);
if ( bPortalPlacability[1] )
m_icon_rb->DrawSelf(xCenter + ( m_icon_rb->Width() * -0.35f ), yCenter + ( m_icon_rb->Height() * 0.17f ), portal2Color);
else
m_icon_rbn->DrawSelf(xCenter + ( m_icon_rbn->Width() * -0.35f ), yCenter + ( m_icon_rb->Height() * 0.17f ), portal2Color);
//last placed portal indicator
m_icon_lbe->DrawSelf( xCenter - (m_icon_lbe->Width() * 1.85f), yCenter, lastPlaced1Color );
m_icon_rbe->DrawSelf( xCenter + (m_icon_rbe->Width() * 0.75f), yCenter, lastPlaced2Color );
}
else
{
if ( bPortalPlacability[1] )
m_icon_lb->DrawSelf(xCenter - (m_icon_lb->Width() * 0.64f ), yCenter - ( m_icon_rb->Height() * 0.17f ), portal2Color);
else
m_icon_lbn->DrawSelf(xCenter - (m_icon_lbn->Width() * 0.64f ), yCenter - ( m_icon_rb->Height() * 0.17f ), portal2Color);
if ( bPortalPlacability[0] )
m_icon_rb->DrawSelf(xCenter + ( m_icon_rb->Width() * -0.35f ), yCenter + ( m_icon_rb->Height() * 0.17f ), portal1Color);
else
m_icon_rbn->DrawSelf(xCenter + ( m_icon_rbn->Width() * -0.35f ), yCenter + ( m_icon_rb->Height() * 0.17f ), portal1Color);
//last placed portal indicator
m_icon_lbe->DrawSelf( xCenter - (m_icon_lbe->Width() * 1.85f), yCenter, lastPlaced2Color );
m_icon_rbe->DrawSelf( xCenter + (m_icon_rbe->Width() * 0.75f), yCenter, lastPlaced1Color );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHUDQuickInfo::UpdateEventTime( void )
{
m_flLastEventTime = gpGlobals->curtime;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CHUDQuickInfo::EventTimeElapsed( void )
{
if (( gpGlobals->curtime - m_flLastEventTime ) > QUICKINFO_EVENT_DURATION )
return true;
return false;
}
@@ -0,0 +1,147 @@
//========= Copyright 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 "toolframework_client.h"
#include <KeyValues.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; }
float ComputeStaticAmount( CPortalRenderable_FlatBasic *pPortal );
};
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;
return true;
}
float CPortalStaticProxy::ComputeStaticAmount( CPortalRenderable_FlatBasic *pFlatBasic )
{
float flStaticAmount = pFlatBasic->m_fStaticAmount;
if ( !pFlatBasic->GetLinkedPortal() )
{
flStaticAmount = 1.0f;
}
if ( pFlatBasic->WillUseDepthDoublerThisDraw() )
{
flStaticAmount = 0.0f;
}
else if ( g_pPortalRender->GetRemainingPortalViewDepth() == 0 ) //end of the line, no more views
{
flStaticAmount = 1.0f;
}
else if ( (g_pPortalRender->GetRemainingPortalViewDepth() == 1) && (pFlatBasic->m_fSecondaryStaticAmount > flStaticAmount) ) //fading in from no views to another view (player just walked through it)
{
flStaticAmount = pFlatBasic->m_fSecondaryStaticAmount;
}
return flStaticAmount;
}
void CPortalStaticProxy::OnBind( void *pBind )
{
if ( pBind == NULL )
return;
float flStaticAmount;
IClientRenderable *pRenderable = (IClientRenderable*)pBind;
CPortalRenderable *pRecordedPortal = g_pPortalRender->FindRecordedPortal( pRenderable );
if ( pRecordedPortal )
{
CPortalRenderable_FlatBasic *pRecordedFlatBasic = dynamic_cast<CPortalRenderable_FlatBasic *>(pRecordedPortal);
if ( !pRecordedFlatBasic )
return;
flStaticAmount = ComputeStaticAmount( pRecordedFlatBasic );
}
else
{
CPortalRenderable_FlatBasic *pFlatBasic = dynamic_cast<CPortalRenderable_FlatBasic*>( pRenderable );
if ( !pFlatBasic )
return;
flStaticAmount = ComputeStaticAmount( pFlatBasic );
}
m_StaticOutput->SetFloatValue( flStaticAmount );
if ( ToolsEnabled() )
{
ToolFramework_RecordMaterialParams( GetMaterial() );
}
}
EXPOSE_INTERFACE( CPortalStaticProxy, IMaterialProxy, "PortalStaticModel" IMATERIAL_PROXY_INTERFACE_VERSION );
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 = ComputeStaticAmount( pPortal );
m_StaticOutput->SetFloatValue( flStaticAmount );
}
EXPOSE_INTERFACE( CPortalStaticPortalProxy, IMaterialProxy, "PortalStatic" IMATERIAL_PROXY_INTERFACE_VERSION );
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_INTERFACE( CPortalOpenAmountProxy, IMaterialProxy, "PortalOpenAmount" IMATERIAL_PROXY_INTERFACE_VERSION );
File diff suppressed because it is too large Load Diff
+150
View File
@@ -0,0 +1,150 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "portal_hud_crosshair.h"
#include "iclientmode.h"
#include "c_portal_player.h"
#include "view.h"
#include "weapon_portalbase.h"
#include "vgui_controls/Controls.h"
#include "vgui/ISurface.h"
#include "ivrenderview.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar crosshair;
extern ConVar cl_observercrosshair;
using namespace vgui;
int ScreenTransform( const Vector& point, Vector& screen );
DECLARE_HUDELEMENT( CHudPortalCrosshair );
CHudPortalCrosshair::CHudPortalCrosshair( const char *pElementName ) :
CHudElement( pElementName ), BaseClass( NULL, "HudPortalCrosshair" )
{
vgui::Panel *pParent = g_pClientMode->GetViewport();
SetParent( pParent );
m_pCrosshair = 0;
m_clrCrosshair = Color( 0, 0, 0, 0 );
m_vecCrossHairOffsetAngle.Init();
SetHiddenBits( HIDEHUD_PLAYERDEAD | HIDEHUD_CROSSHAIR );
}
void CHudPortalCrosshair::ApplySchemeSettings( IScheme *scheme )
{
BaseClass::ApplySchemeSettings( scheme );
m_pDefaultCrosshair = gHUD.GetIcon("crosshair_default");
SetPaintBackgroundEnabled( false );
}
//-----------------------------------------------------------------------------
// Purpose: Save CPU cycles by letting the HUD system early cull
// costly traversal. Called per frame, return true if thinking and
// painting need to occur.
//-----------------------------------------------------------------------------
bool CHudPortalCrosshair::ShouldDraw()
{
// NOTE: Portal crosshair should no longer be in use, but I'm leaving the code here until X360 lock down... we don't want to draw this ever. -Jeep
return false;
C_Portal_Player *pPlayer = C_Portal_Player::GetLocalPortalPlayer();
if ( !pPlayer )
return false;
CWeaponPortalBase *pWeapon = dynamic_cast<CWeaponPortalBase*>( pPlayer->GetActiveWeapon() );
if ( !pWeapon )
return false;
bool bNeedsDraw = m_pCrosshair &&
crosshair.GetInt() &&
!engine->IsDrawingLoadingImage() &&
!engine->IsPaused() &&
g_pClientMode->ShouldDrawCrosshair() &&
!( pPlayer->GetFlags() & FL_FROZEN ) &&
( pPlayer->entindex() == render->GetViewEntity() ) &&
!pPlayer->IsInVGuiInputMode() &&
( pPlayer->IsAlive() || ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) || ( cl_observercrosshair.GetBool() && pPlayer->GetObserverMode() == OBS_MODE_ROAMING ) );
return ( bNeedsDraw && CHudElement::ShouldDraw() );
}
void CHudPortalCrosshair::Paint( void )
{
if ( !m_pCrosshair )
return;
if ( !IsCurrentViewAccessAllowed() )
return;
m_curViewAngles = CurrentViewAngles();
m_curViewOrigin = CurrentViewOrigin();
float x, y;
x = ScreenWidth()/2;
y = ScreenHeight()/2;
// MattB - m_vecCrossHairOffsetAngle is the autoaim angle.
// if we're not using autoaim, just draw in the middle of the
// screen
if ( m_vecCrossHairOffsetAngle != vec3_angle )
{
QAngle angles;
Vector forward;
Vector point, screen;
// this code is wrong
angles = m_curViewAngles + m_vecCrossHairOffsetAngle;
AngleVectors( angles, &forward );
VectorAdd( m_curViewOrigin, forward, point );
ScreenTransform( point, screen );
x += 0.5f * screen[0] * ScreenWidth() + 0.5f;
y += 0.5f * screen[1] * ScreenHeight() + 0.5f;
}
m_pCrosshair->DrawSelf(
x - 0.5f * m_pCrosshair->Width(),
y - 0.5f * m_pCrosshair->Height(),
m_clrCrosshair );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudPortalCrosshair::SetCrosshairAngle( const QAngle& angle )
{
VectorCopy( angle, m_vecCrossHairOffsetAngle );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CHudPortalCrosshair::SetCrosshair( CHudTexture *texture, Color& clr )
{
m_pCrosshair = texture;
m_clrCrosshair = clr;
}
//-----------------------------------------------------------------------------
// Purpose: Resets the crosshair back to the default
//-----------------------------------------------------------------------------
void CHudPortalCrosshair::ResetCrosshair()
{
Color white(255, 255, 255, 255);
SetCrosshair( m_pDefaultCrosshair, white );
}
+58
View File
@@ -0,0 +1,58 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef HUD_PORTAL_CROSSHAIR_H
#define HUD_PORTAL_CROSSHAIR_H
#ifdef _WIN32
#pragma once
#endif
#include "hudelement.h"
#include <vgui_controls/Panel.h>
namespace vgui
{
class IScheme;
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
class CHudPortalCrosshair : public CHudElement, public vgui::Panel
{
DECLARE_CLASS_SIMPLE( CHudPortalCrosshair, vgui::Panel );
public:
CHudPortalCrosshair( const char *pElementName );
void SetCrosshairAngle( const QAngle& angle );
void SetCrosshair( CHudTexture *texture, Color& clr );
void ResetCrosshair();
void DrawCrosshair( void );
bool HasCrosshair( void ) { return ( m_pCrosshair != NULL ); }
bool ShouldDraw();
protected:
virtual void ApplySchemeSettings( vgui::IScheme *scheme );
virtual void Paint();
private:
// Crosshair sprite and colors
CHudTexture *m_pCrosshair;
CHudTexture *m_pDefaultCrosshair;
Color m_clrCrosshair;
QAngle m_vecCrossHairOffsetAngle;
QAngle m_curViewAngles;
Vector m_curViewOrigin;
};
// Enable/disable crosshair rendering.
extern ConVar crosshair;
#endif // HUD_PORTAL_CROSSHAIR_H
@@ -0,0 +1,229 @@
//========= Copyright 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 ( IsX360() )
{
// 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 ( IsX360() )
{
// 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",
512, 512, RT_SIZE_DEFAULT,
pMaterialSystem->GetBackBufferFormat(),
MATERIAL_RT_DEPTH_SHARED,
0,
CREATERENDERTARGETFLAGS_HDR );
}
ITexture* CPortalRenderTargets::GetDepthDoublerTexture()
{
return m_DepthDoublerTexture;
}
void CPortalRenderTargets::InitPortalWaterTextures( IMaterialSystem* pMaterialSystem )
{
if ( IsX360() )
{
return;
}
//Reflections
m_WaterReflectionTextures[0].Init(
pMaterialSystem->CreateNamedRenderTargetTextureEx2(
"_rt_PortalWaterReflection_Depth1",
512, 512, RT_SIZE_PICMIP,
pMaterialSystem->GetBackBufferFormat(),
MATERIAL_RT_DEPTH_SEPARATE,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
CREATERENDERTARGETFLAGS_HDR ) );
m_WaterReflectionTextures[1].Init(
pMaterialSystem->CreateNamedRenderTargetTextureEx2(
"_rt_PortalWaterReflection_Depth2",
256, 256, RT_SIZE_PICMIP,
pMaterialSystem->GetBackBufferFormat(),
MATERIAL_RT_DEPTH_SEPARATE,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
CREATERENDERTARGETFLAGS_HDR ) );
//Refractions
m_WaterRefractionTextures[0].Init(
pMaterialSystem->CreateNamedRenderTargetTextureEx2(
"_rt_PortalWaterRefraction_Depth1",
512, 512, RT_SIZE_PICMIP,
// This is different than reflection because it has to have alpha for fog factor.
IMAGE_FORMAT_RGBA8888,
MATERIAL_RT_DEPTH_SEPARATE,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
CREATERENDERTARGETFLAGS_HDR ) );
m_WaterRefractionTextures[1].Init(
pMaterialSystem->CreateNamedRenderTargetTextureEx2(
"_rt_PortalWaterRefraction_Depth2",
256, 256, RT_SIZE_PICMIP,
// This is different than reflection because it has to have alpha for fog factor.
IMAGE_FORMAT_RGBA8888,
MATERIAL_RT_DEPTH_SEPARATE,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
CREATERENDERTARGETFLAGS_HDR ) );
}
ITexture* CPortalRenderTargets::GetWaterReflectionTextureForStencilDepth( int iStencilDepth )
{
if ( IsX360() )
{
return NULL;
}
if ( iStencilDepth > 2 )
return NULL;
if ( iStencilDepth == 0 )
return m_WaterReflectionTexture; //from CBaseClientRenderTargets
return m_WaterReflectionTextures[ iStencilDepth - 1 ];
}
ITexture* CPortalRenderTargets::GetWaterRefractionTextureForStencilDepth( int iStencilDepth )
{
if ( IsX360() )
{
return NULL;
}
if ( iStencilDepth > 2 )
return NULL;
if ( iStencilDepth == 0 )
return m_WaterRefractionTexture; //from CBaseClientRenderTargets
return m_WaterRefractionTextures[ iStencilDepth - 1 ];
}
//-----------------------------------------------------------------------------
// 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 )
{
// 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() || !IsX360() )
{
m_Portal1Texture.Init( InitPortal1Texture( pMaterialSystem ) );
m_Portal2Texture.Init( InitPortal2Texture( pMaterialSystem ) );
}
m_DepthDoublerTexture.Init( InitDepthDoublerTexture( pMaterialSystem ) );
if ( IsPC() || !IsX360() )
{
InitPortalWaterTextures( pMaterialSystem );
}
// Water effects & camera from the base class (standard HL2 targets)
BaseClass::InitClientRenderTargets( pMaterialSystem, pHardwareConfig, 512, 256 );
}
//-----------------------------------------------------------------------------
// 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();
for ( int i = 0; i < 2; ++i )
{
m_WaterReflectionTextures[i].Shutdown();
m_WaterRefractionTextures[i].Shutdown();
}
// Clean up standard HL2 RTs (camera and water)
BaseClass::ShutdownClientRenderTargets();
}
static CPortalRenderTargets g_PortalRenderTargets;
EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CPortalRenderTargets, IClientRenderTargets, CLIENTRENDERTARGETS_INTERFACE_VERSION, g_PortalRenderTargets );
CPortalRenderTargets* portalrendertargets = &g_PortalRenderTargets;
@@ -0,0 +1,61 @@
//========= Copyright 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
ITexture* GetWaterReflectionTextureForStencilDepth( int iStencilDepth );
ITexture* GetWaterRefractionTextureForStencilDepth( int iStencilDepth );
private:
CTextureReference m_Portal1Texture;
CTextureReference m_Portal2Texture;
CTextureReference m_DepthDoublerTexture;
CTextureReference m_WaterRefractionTextures[2];
CTextureReference m_WaterReflectionTextures[2];
ITexture* InitPortal1Texture ( IMaterialSystem* pMaterialSystem );
ITexture* InitPortal2Texture ( IMaterialSystem* pMaterialSystem );
ITexture* InitDepthDoublerTexture ( IMaterialSystem* pMaterialSystem );
void InitPortalWaterTextures ( IMaterialSystem* pMaterialSystem );
};
extern CPortalRenderTargets* portalrendertargets;
#endif //PORTALRENDERTARGETS_H_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,121 @@
//========= Copyright 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
struct FlatBasicPortalRenderingMaterials_t
{
CMaterialReference m_PortalMaterials[2];
CMaterialReference m_PortalRenderFixMaterials[2];
CMaterialReference m_PortalDepthDoubler;
CMaterialReference m_PortalStaticOverlay[2];
CMaterialReference m_Portal_Stencil_Hole;
CMaterialReference m_Portal_Refract[2];
//CTextureReference m_PortalLightTransfer_ShadowTexture; //light transfers disabled indefinitely
IMaterialVar *m_pDepthDoubleViewMatrixVar;
};
//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( const IMaterial *pMaterialOverride = NULL, float fForwardOffsetModifier = 0.25f );
//generates a single quad
virtual void DrawSimplePortalMesh( const IMaterial *pMaterialOverride = NULL, float fForwardOffsetModifier = 0.25f );
//draws a screenspace mesh to replace missing pixels caused by the camera near plane intersecting the portal mesh
virtual void DrawRenderFixMesh( const IMaterial *pMaterialOverride = NULL, float fFrontClipDistance = 0.3f );
//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( float fForwardOffsetModifier = 0.25f );
virtual void DrawPortal( void );
virtual void DrawPreStencilMask( void ); //Draw to wherever you can see through the portal. The mask will later be filled with the portal view.
virtual void DrawStencilMask( void ); //Draw to wherever you can see through the portal. The mask will later be filled with the portal view.
virtual void DrawPostStencilFixes( void ); //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
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 &currentView, CUtlVector<VPlane> &currentComplexFrustum ); //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( bool bActive, 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;
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 );
protected:
void ClipFixToBoundingAreaAndDraw( PortalMeshPoint_t *pVerts, const IMaterial *pMaterial );
void Internal_DrawRenderFixMesh( 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
static const FlatBasicPortalRenderingMaterials_t& m_Materials;
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; //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;
float m_fStaticAmount;
float m_fSecondaryStaticAmount; // used to help kludge the end of our recursive rendering chain
float m_fOpenAmount;
bool m_bIsPortal2; //for any set of portals, one must be portal 1, and the other portal 2. Uses different render targets
};
#endif //#ifndef PORTALRENDERABLE_FLATBASIC_H
@@ -0,0 +1,186 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "c_vguiscreen.h"
#include "vgui_controls/Label.h"
#include "vgui_bitmappanel.h"
#include <vgui/IVGui.h>
#include "c_neurotoxin_countdown.h"
#include "ienginevgui.h"
#include "fmtstr.h"
#include "vgui_controls/ImagePanel.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Control screen
//-----------------------------------------------------------------------------
class CNeurotoxinCountdownScreen : public CVGuiScreenPanel
{
DECLARE_CLASS( CNeurotoxinCountdownScreen, CVGuiScreenPanel );
public:
CNeurotoxinCountdownScreen( vgui::Panel *parent, const char *panelName );
virtual void ApplySchemeSettings( IScheme *pScheme );
virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
virtual void OnTick();
private:
void Update( C_NeurotoxinCountdown *pNeurotoxinCountdown );
private:
vgui::Label *m_pDisplayTextLabel;
int iLastSlideIndex;
Color m_cDefault;
Color m_cInvisible;
bool bIsAlreadyVisible;
//ImagePanel *(m_pNumberImages[ 6 ][ 10 ]);
};
DECLARE_VGUI_SCREEN_FACTORY( CNeurotoxinCountdownScreen, "neurotoxin_countdown_screen" );
//-----------------------------------------------------------------------------
// Constructor:
//-----------------------------------------------------------------------------
CNeurotoxinCountdownScreen::CNeurotoxinCountdownScreen( vgui::Panel *parent, const char *panelName )
: BaseClass( parent, "CNeurotoxinCountdownScreen", vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/NeurotoxinCountdownScreen.res", "NeuroToxinScreen" ) )
{
m_pDisplayTextLabel = new vgui::Label( this, "NumberDisplay", "x" );
iLastSlideIndex = 0;
}
void CNeurotoxinCountdownScreen::ApplySchemeSettings( IScheme *pScheme )
{
assert( pScheme );
m_cDefault = pScheme->GetColor( "CNeurotoxinCountdownScreen_Default", GetFgColor() );
m_cInvisible = Color( 0, 0, 0, 0 );
m_pDisplayTextLabel->SetFgColor( m_cDefault );
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
bool CNeurotoxinCountdownScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
{
// Make sure we get ticked...
vgui::ivgui()->AddTickSignal( GetVPanel() );
if (!BaseClass::Init(pKeyValues, pInitData))
return false;
//for ( int iDigit = 0; iDigit < 6; ++iDigit )
//{
// for ( int iNumber = 0; iNumber < 6; ++iNumber )
// {
// m_pNumberImages[ iDigit ][ iNumber ] = SETUP_PANEL( new ImagePanel( this, "SlideshowImage" ) );
// m_pNumberImages[ iDigit ][ iNumber ]->SetImage( "" );
// m_pNumberImages[ iDigit ][ iNumber ]->SetZPos( -2 );
// m_pNumberImages[ iDigit ][ iNumber ]->SetVisible( false );
// }
//}
return true;
}
//-----------------------------------------------------------------------------
// Update the display string
//-----------------------------------------------------------------------------
void CNeurotoxinCountdownScreen::OnTick()
{
BaseClass::OnTick();
if ( g_NeurotoxinCountdowns.Count() <= 0 )
return;
C_NeurotoxinCountdown *pNeurotoxinCountdown = NULL;
for ( int iDisplayScreens = 0; iDisplayScreens < g_NeurotoxinCountdowns.Count(); ++iDisplayScreens )
{
C_NeurotoxinCountdown *pNeurotoxinCountdownTemp = g_NeurotoxinCountdowns[ iDisplayScreens ];
if ( pNeurotoxinCountdownTemp && pNeurotoxinCountdownTemp->IsEnabled() )
{
pNeurotoxinCountdown = pNeurotoxinCountdownTemp;
break;
}
}
if( !pNeurotoxinCountdown )
{
// All display screens are disabled
if ( bIsAlreadyVisible )
{
SetVisible( false );
bIsAlreadyVisible = false;
}
return;
}
if ( !bIsAlreadyVisible )
{
SetVisible( true );
bIsAlreadyVisible = true;
}
Update( pNeurotoxinCountdown );
}
void CNeurotoxinCountdownScreen::Update( C_NeurotoxinCountdown *pNeurotoxinCountdown )
{
char szBuff[ 256 ];
char szMinutesBuff[ 4 ];
char szSecondsBuff[ 4 ];
char szMillisecondsBuff[ 4 ];
int iMinutes = pNeurotoxinCountdown->GetMinutes();
int iSeconds = pNeurotoxinCountdown->GetSeconds();
int iMilliseconds;
if ( iMinutes <= 0 && iSeconds <= 0 )
{
iMinutes = 0;
iSeconds = 0;
iMilliseconds = 0;
// Blink!
m_pDisplayTextLabel->SetVisible( static_cast<int>( gpGlobals->curtime * 10.0f ) % 2 == 0 );
}
else
{
iMilliseconds = pNeurotoxinCountdown->GetMilliseconds();
m_pDisplayTextLabel->SetVisible( true );
}
if ( iMinutes < 10 )
sprintf( szMinutesBuff, "0%i", iMinutes );
else
sprintf( szMinutesBuff, "%i", iMinutes );
if ( iSeconds < 10 )
sprintf( szSecondsBuff, "0%i", iSeconds );
else
sprintf( szSecondsBuff, "%i", iSeconds );
if ( iMilliseconds < 10 )
sprintf( szMillisecondsBuff, "0%i", iMilliseconds );
else
sprintf( szMillisecondsBuff, "%i", iMilliseconds );
sprintf( szBuff, "%s:%s:%s", szMinutesBuff, szSecondsBuff, szMillisecondsBuff );
m_pDisplayTextLabel->SetText( szBuff );
}
@@ -0,0 +1,305 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "c_vguiscreen.h"
#include "vgui_controls/Label.h"
#include "vgui_bitmappanel.h"
#include <vgui/IVGui.h>
#include "c_prop_portal_stats_display.h"
#include "ienginevgui.h"
#include "fmtstr.h"
#include "portal_shareddefs.h"
using namespace vgui;
#define TESTCHAMBER_STATS_FIRST_MEDAL "MedalPortalGold"
#define TESTCHAMBER_STATS_FIRST_MEDAL_POINTER "MedalPointer00"
#define TESTCHAMBER_STATS_FIRST_SUBJECT_REACTION "SubjectReactionIdle"
//-----------------------------------------------------------------------------
// Control screen
//-----------------------------------------------------------------------------
class CPortalStatsDisplayScreen : public CVGuiScreenPanel
{
DECLARE_CLASS( CPortalStatsDisplayScreen, CVGuiScreenPanel );
public:
CPortalStatsDisplayScreen( vgui::Panel *parent, const char *panelName );
~CPortalStatsDisplayScreen();
virtual void ApplySchemeSettings( IScheme *pScheme );
virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
virtual void OnTick();
private:
void UpdateTextFields( C_PropPortalStatsDisplay *pPropPortalStatsDisplay );
void UpdateMedals( C_PropPortalStatsDisplay *pPropPortalStatsDisplay );
private:
vgui::Label *m_pNumPlayerLabel;
vgui::Label *m_pNumGoalLabel;
vgui::Label *m_pCheatedLabel;
float m_flNextDigitRandomizeTime; //next time to grab a new digit while scrolling random digits
//in un-decoded digits
int m_iLastRandomInt; //store the random digit between new rand calls
bool m_bInitLabelColor;
Color m_cPass;
Color m_cFail;
Color m_cUnknown;
Color m_cInvisible;
};
DECLARE_VGUI_SCREEN_FACTORY( CPortalStatsDisplayScreen, "portal_stats_display_screen" );
//-----------------------------------------------------------------------------
// Constructor:
//-----------------------------------------------------------------------------
CPortalStatsDisplayScreen::CPortalStatsDisplayScreen( vgui::Panel *parent, const char *panelName )
: BaseClass( parent, "CPortalStatsDisplayScreen", vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/PortalStatsDisplayScreen.res", "PortalStatsDisplayScreens" ) )
{
m_pNumPlayerLabel = new vgui::Label( this, "NumPlayer", "" );
m_pNumGoalLabel = new vgui::Label( this, "NumGoal", "" );
m_pCheatedLabel = new vgui::Label( this, "CheatedLabel", "" );
m_flNextDigitRandomizeTime = 0;
m_iLastRandomInt = 0;
m_bInitLabelColor = true;
}
CPortalStatsDisplayScreen::~CPortalStatsDisplayScreen()
{
}
void CPortalStatsDisplayScreen::ApplySchemeSettings( IScheme *pScheme )
{
assert( pScheme );
m_cPass = pScheme->GetColor( "CPortalStatsDisplayScreen_Pass", GetFgColor() );
m_cFail = pScheme->GetColor( "CPortalStatsDisplayScreen_Fail", GetFgColor() );
m_cUnknown = pScheme->GetColor( "CPortalStatsDisplayScreen_Unknown", GetFgColor() );
m_cInvisible = Color( 0, 0, 0, 0 );
if( m_bInitLabelColor )
{
m_pNumPlayerLabel->SetFgColor( m_cUnknown );
m_pNumGoalLabel->SetFgColor( m_cUnknown );
m_bInitLabelColor = false;
}
}
//-----------------------------------------------------------------------------
// Initialization
//-----------------------------------------------------------------------------
bool CPortalStatsDisplayScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
{
// Make sure we get ticked...
vgui::ivgui()->AddTickSignal( GetVPanel() );
if (!BaseClass::Init(pKeyValues, pInitData))
return false;
return true;
}
void MakeTimeString( CFmtStr &str, int iHours, int iMinutes, int iSeconds )
{
if ( iHours )
{
if ( iMinutes < 10 )
{
if ( iSeconds < 10 )
str.sprintf( "%d:0%d:0%d", iHours, iMinutes, iSeconds );
else
str.sprintf( "%d:0%d:%d", iHours, iMinutes, iSeconds );
}
else
{
if ( iSeconds < 10 )
str.sprintf( "%d:%d:0%d", iHours, iMinutes, iSeconds );
else
str.sprintf( "%d:%d:%d", iHours, iMinutes, iSeconds );
}
}
else
{
if ( iSeconds < 10 )
str.sprintf( "%d:0%d", iMinutes, iSeconds );
else
str.sprintf( "%d:%d", iMinutes, iSeconds );
}
}
//-----------------------------------------------------------------------------
// Update the display string
//-----------------------------------------------------------------------------
void CPortalStatsDisplayScreen::OnTick()
{
BaseClass::OnTick();
if ( g_PropPortalStatsDisplays.Count() <= 0 )
return;
C_PropPortalStatsDisplay *pPropPortalStatsDisplay = NULL;
for ( int iDisplayScreens = 0; iDisplayScreens < g_PropPortalStatsDisplays.Count(); ++iDisplayScreens )
{
C_PropPortalStatsDisplay *pPropPortalStatsDisplayTemp = g_PropPortalStatsDisplays[ iDisplayScreens ];
if ( pPropPortalStatsDisplayTemp && pPropPortalStatsDisplayTemp->IsEnabled() )
{
pPropPortalStatsDisplay = pPropPortalStatsDisplayTemp;
break;
}
}
if( !pPropPortalStatsDisplay )
{
// All display screens are disabled
SetVisible( false );
return;
}
SetVisible( true );
UpdateTextFields( pPropPortalStatsDisplay );
UpdateMedals( pPropPortalStatsDisplay );
}
void CPortalStatsDisplayScreen::UpdateTextFields( C_PropPortalStatsDisplay *pPropPortalStatsDisplay )
{
bool bIsTime = pPropPortalStatsDisplay->IsTime();
float fNumPlayer = pPropPortalStatsDisplay->GetNumPlayerDisplay();
float fNumGoal = pPropPortalStatsDisplay->GetNumGoalDisplay();
// Figure out colors
Color *( pColors[ 3 ] ) = { &m_cUnknown, &m_cFail, &m_cPass };
int iColor = pPropPortalStatsDisplay->GetGoalSuccess() + 1;
m_pNumPlayerLabel->SetFgColor( ( fNumPlayer != 0.0f ) ? ( *pColors[ iColor ] ) : ( m_cInvisible ) );
m_pNumGoalLabel->SetFgColor( ( pPropPortalStatsDisplay->GetGoalVisible() ) ? ( *pColors[ iColor ] ) : ( m_cInvisible ) );
// Fill in labels
CFmtStr str;
if ( !bIsTime )
{
str.sprintf( "%.0f", fNumPlayer );
m_pNumPlayerLabel->SetText( str );
str.sprintf( "%.0f", fNumGoal );
m_pNumGoalLabel->SetText( str );
}
else
{
// break seconds into mnutes and seconds
int iMinutes = static_cast<int>( fNumPlayer / 60.0f );
int iHours = iMinutes / 60;
iMinutes %= 60;
int iSeconds = static_cast<int>( fNumPlayer ) % 60;
MakeTimeString( str, iHours, iMinutes, iSeconds );
m_pNumPlayerLabel->SetText( str );
// break seconds into mnutes and seconds
iMinutes = static_cast<int>( fNumGoal / 60.0f );
iHours = iMinutes / 60;
iMinutes %= 60;
iSeconds = static_cast<int>( fNumGoal ) % 60;
MakeTimeString( str, iHours, iMinutes, iSeconds );
m_pNumGoalLabel->SetText( str );
}
// Draw cheated label when needed
m_pCheatedLabel->SetVisible( pPropPortalStatsDisplay->HasCheated() );
}
int GetMedalOffset( int iObjective, int iLevel )
{
return iObjective * 6 + ( 2 - iLevel ) * 2;
}
void CPortalStatsDisplayScreen::UpdateMedals( C_PropPortalStatsDisplay *pPropPortalStatsDisplay )
{
// Get the index of the first medal image
int iFirstChildIndex = FindChildIndexByName( TESTCHAMBER_STATS_FIRST_MEDAL );
CBitmapPanel *pBitmapPanel;
// Loop through all the goals
for ( int iGoal = 0; iGoal < PORTAL_LEVEL_STAT_TOTAL; ++iGoal )
{
int iMedalComplete = -1;
// Loop through bronze, silver, and gold
for ( int iLevel = 0; iLevel < 3; ++iLevel )
{
if ( pPropPortalStatsDisplay->IsMedalCompleted( iLevel ) )
iMedalComplete = iLevel;
}
// Loop through bronze, silver, and gold
for ( int iLevel = 0; iLevel < 3; ++iLevel )
{
int iMedalIndex = iFirstChildIndex + GetMedalOffset( iGoal, iLevel );
if ( iGoal != pPropPortalStatsDisplay->GetDisplayObjective() )
{
// Set both invisible
pBitmapPanel = dynamic_cast<CBitmapPanel*>( GetChild( iMedalIndex ) );
pBitmapPanel->SetVisible( false );
// Set if "no medal" is visible
pBitmapPanel = dynamic_cast<CBitmapPanel*>( GetChild( iMedalIndex + 1 ) );
pBitmapPanel->SetVisible( false );
}
else
{
// Set if medal is visible
pBitmapPanel = dynamic_cast<CBitmapPanel*>( GetChild( iMedalIndex ) );
pBitmapPanel->SetVisible( ( iLevel == iMedalComplete ) ? ( true ) : ( false ) );
// Set if "no medal" is visible
pBitmapPanel = dynamic_cast<CBitmapPanel*>( GetChild( iMedalIndex + 1 ) );
pBitmapPanel->SetVisible( ( iMedalComplete == -1 && iLevel == 0 ) ? ( true ) : ( false ) );
}
}
}
// Get the index of the first pointer
iFirstChildIndex = FindChildIndexByName( TESTCHAMBER_STATS_FIRST_MEDAL_POINTER );
// Loop through bronze, silver, and gold
for ( int iLevel = 0; iLevel < 3; ++iLevel )
{
pBitmapPanel = dynamic_cast<CBitmapPanel*>( GetChild( iFirstChildIndex + iLevel ) );
pBitmapPanel->SetVisible( ( iLevel == pPropPortalStatsDisplay->GetGoalLevelDisplay() ) ? ( true ) : ( false ) );
}
int iSubjectReaction = pPropPortalStatsDisplay->GetGoalSuccess() + 1;
// Get the index of the first subject reaction
iFirstChildIndex = FindChildIndexByName( TESTCHAMBER_STATS_FIRST_SUBJECT_REACTION );
// Loop through idle, happy, sad
for ( int iReaction = 0; iReaction < 3; ++iReaction )
{
pBitmapPanel = dynamic_cast<CBitmapPanel*>( GetChild( iFirstChildIndex + iReaction ) );
pBitmapPanel->SetVisible( ( iReaction == iSubjectReaction ) ? ( true ) : ( false ) );
}
}