source-engine/game/client/portal/c_func_liquidportal.cpp
2022-04-16 12:05:19 +03:00

631 lines
22 KiB
C++

//========= 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 );
}
}