summaryrefslogtreecommitdiff
path: root/game/client/portal/portalrenderable_flatbasic.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/portal/portalrenderable_flatbasic.cpp')
-rw-r--r--game/client/portal/portalrenderable_flatbasic.cpp1304
1 files changed, 1304 insertions, 0 deletions
diff --git a/game/client/portal/portalrenderable_flatbasic.cpp b/game/client/portal/portalrenderable_flatbasic.cpp
new file mode 100644
index 0000000..35bfef8
--- /dev/null
+++ b/game/client/portal/portalrenderable_flatbasic.cpp
@@ -0,0 +1,1304 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include "cbase.h"
+#include "portalrenderable_flatbasic.h"
+#include "clienteffectprecachesystem.h"
+#include "Portal_DynamicMeshRenderingUtils.h"
+#include "portal_shareddefs.h"
+#include "view.h"
+#include "c_pixel_visibility.h"
+#include "glow_overlay.h"
+#include "portal_render_targets.h"
+#include "materialsystem/itexture.h"
+#include "toolframework/itoolframework.h"
+#include "toolframework_client.h"
+#include "tier1/KeyValues.h"
+#include "prop_portal_shared.h"
+#include "view_scene.h"
+#include "materialsystem/imaterialvar.h"
+#include "tier0/vprof.h"
+
+
+#define PORTALRENDERABLE_FLATBASIC_MINPIXELVIS 0.0f
+
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheFlatBasicPortalDrawingMaterials )
+#if !defined( _X360 ) //XBox 360 is guaranteed to use stencil mode, and therefore doesn't need texture mode materials
+CLIENTEFFECT_MATERIAL( "models/portals/portal_1_dynamicmesh" )
+CLIENTEFFECT_MATERIAL( "models/portals/portal_2_dynamicmesh" )
+CLIENTEFFECT_MATERIAL( "models/portals/portal_1_renderfix_dynamicmesh" )
+CLIENTEFFECT_MATERIAL( "models/portals/portal_2_renderfix_dynamicmesh" )
+#endif
+CLIENTEFFECT_MATERIAL( "models/portals/portal_depthdoubler" )
+CLIENTEFFECT_MATERIAL( "models/portals/portalstaticoverlay_1" )
+CLIENTEFFECT_MATERIAL( "models/portals/portalstaticoverlay_2" )
+CLIENTEFFECT_MATERIAL( "models/portals/portal_stencil_hole" )
+CLIENTEFFECT_MATERIAL( "models/portals/portal_refract_1" )
+CLIENTEFFECT_MATERIAL( "models/portals/portal_refract_2" )
+//CLIENTEFFECT_MATERIAL( "effects/flashlight001" ) //light transfers disabled indefinitely
+CLIENTEFFECT_REGISTER_END()
+
+class CAutoInitFlatBasicPortalDrawingMaterials : public CAutoGameSystem
+{
+public:
+ FlatBasicPortalRenderingMaterials_t m_Materials;
+ void LevelInitPreEntity()
+ {
+ m_Materials.m_PortalMaterials[0].Init( "models/portals/portal_1_dynamicmesh", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_PortalMaterials[1].Init( "models/portals/portal_2_dynamicmesh", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_PortalRenderFixMaterials[0].Init( "models/portals/portal_1_renderfix_dynamicmesh", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_PortalRenderFixMaterials[1].Init( "models/portals/portal_2_renderfix_dynamicmesh", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_PortalDepthDoubler.Init( "models/portals/portal_depthdoubler", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_PortalStaticOverlay[0].Init( "models/portals/portalstaticoverlay_1", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_PortalStaticOverlay[1].Init( "models/portals/portalstaticoverlay_2", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_Portal_Stencil_Hole.Init( "models/portals/portal_stencil_hole", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_Portal_Refract[0].Init( "models/portals/portal_refract_1", TEXTURE_GROUP_CLIENT_EFFECTS );
+ m_Materials.m_Portal_Refract[1].Init( "models/portals/portal_refract_2", TEXTURE_GROUP_CLIENT_EFFECTS );
+ //m_Materials.m_PortalLightTransfer_ShadowTexture.Init( "effects/flashlight001", TEXTURE_GROUP_OTHER ); //light transfers disabled indefinitely
+
+ m_Materials.m_pDepthDoubleViewMatrixVar = m_Materials.m_PortalDepthDoubler->FindVar( "$alternateviewmatrix", NULL, false );
+ Assert( m_Materials.m_pDepthDoubleViewMatrixVar != NULL );
+ }
+};
+static CAutoInitFlatBasicPortalDrawingMaterials s_FlatBasicPortalDrawingMaterials;
+
+const FlatBasicPortalRenderingMaterials_t& CPortalRenderable_FlatBasic::m_Materials = s_FlatBasicPortalDrawingMaterials.m_Materials;
+
+
+LINK_ENTITY_TO_CLASS( prop_portal_flatbasic, CPortalRenderable_FlatBasic );
+
+
+CPortalRenderable_FlatBasic::CPortalRenderable_FlatBasic( void )
+: m_pLinkedPortal( NULL ),
+ m_ptOrigin( 0.0f, 0.0f, 0.0f ),
+ m_vForward( 1.0f, 0.0f, 0.0f ),
+ m_vUp( 0.0f, 0.0f, 1.0f ),
+ m_vRight( 0.0f, 1.0f, 0.0f ),
+ m_fStaticAmount( 0.0f ),
+ m_fSecondaryStaticAmount( 0.0f ),
+ m_fOpenAmount( 0.0f ),
+ m_bIsPortal2( false )
+{
+ m_InternallyMaintainedData.m_VisData.m_fDistToAreaPortalTolerance = 64.0f;
+ m_InternallyMaintainedData.m_VisData.m_vecVisOrigin = Vector(0,0,0);
+ m_InternallyMaintainedData.m_iViewLeaf = -1;
+
+ m_InternallyMaintainedData.m_DepthDoublerTextureView.Identity();
+ m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration = false;
+ m_InternallyMaintainedData.m_nSkyboxVisibleFromCorners = SKYBOX_NOT_VISIBLE;
+
+ m_InternallyMaintainedData.m_ptForwardOrigin.Init( 1.0f, 0.0f, 0.0f );
+ m_InternallyMaintainedData.m_ptCorners[0] =
+ m_InternallyMaintainedData.m_ptCorners[1] =
+ m_InternallyMaintainedData.m_ptCorners[2] =
+ m_InternallyMaintainedData.m_ptCorners[3] =
+ Vector( 0.0f, 0.0f, 0.0f );
+}
+
+void CPortalRenderable_FlatBasic::GetToolRecordingState( bool bActive, KeyValues *msg )
+{
+ if ( !ToolsEnabled() )
+ return;
+
+ VPROF_BUDGET( "CPortalRenderable_FlatBasic::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
+
+ BaseClass::GetToolRecordingState( msg );
+ CPortalRenderable::GetToolRecordingState( bActive, msg );
+
+ C_Prop_Portal *pLinkedPortal = static_cast<C_Prop_Portal*>( m_pLinkedPortal );
+
+ static PortalRecordingState_t state;
+ state.m_nPortalId = static_cast<C_Prop_Portal*>( this )->index;
+ state.m_nLinkedPortalId = pLinkedPortal ? pLinkedPortal->index : -1;
+ state.m_fStaticAmount = m_fStaticAmount;
+ state.m_fSecondaryStaticAmount = m_fSecondaryStaticAmount;
+ state.m_fOpenAmount = m_fOpenAmount;
+ state.m_bIsPortal2 = m_bIsPortal2;
+ msg->SetPtr( "portal", &state );
+}
+
+void CPortalRenderable_FlatBasic::PortalMoved( void )
+{
+ m_InternallyMaintainedData.m_ptForwardOrigin = m_ptOrigin + m_vForward;
+ m_InternallyMaintainedData.m_fPlaneDist = m_vForward.Dot( m_ptOrigin );
+
+ // Update the points on the portal which we add to PVS
+ {
+ Vector vScaledRight = m_vRight * PORTAL_HALF_WIDTH;
+ Vector vScaledUp = m_vUp * PORTAL_HALF_HEIGHT;
+
+ m_InternallyMaintainedData.m_ptCorners[0] = (m_InternallyMaintainedData.m_ptForwardOrigin + vScaledRight) + vScaledUp;
+ m_InternallyMaintainedData.m_ptCorners[1] = (m_InternallyMaintainedData.m_ptForwardOrigin - vScaledRight) + vScaledUp;
+ m_InternallyMaintainedData.m_ptCorners[2] = (m_InternallyMaintainedData.m_ptForwardOrigin - vScaledRight) - vScaledUp;
+ m_InternallyMaintainedData.m_ptCorners[3] = (m_InternallyMaintainedData.m_ptForwardOrigin + vScaledRight) - vScaledUp;
+
+
+ m_InternallyMaintainedData.m_VisData.m_vecVisOrigin = m_InternallyMaintainedData.m_ptForwardOrigin;
+ m_InternallyMaintainedData.m_VisData.m_fDistToAreaPortalTolerance = 64.0f;
+ m_InternallyMaintainedData.m_iViewLeaf = enginetrace->GetLeafContainingPoint( m_InternallyMaintainedData.m_ptForwardOrigin );
+ }
+
+ m_InternallyMaintainedData.m_nSkyboxVisibleFromCorners = engine->IsSkyboxVisibleFromPoint( m_InternallyMaintainedData.m_ptForwardOrigin );
+ for( int i = 0; i < 4 && ( m_InternallyMaintainedData.m_nSkyboxVisibleFromCorners != SKYBOX_3DSKYBOX_VISIBLE ); ++i )
+ {
+ SkyboxVisibility_t nCornerVis = engine->IsSkyboxVisibleFromPoint( m_InternallyMaintainedData.m_ptCorners[i] );
+ if ( ( m_InternallyMaintainedData.m_nSkyboxVisibleFromCorners == SKYBOX_NOT_VISIBLE ) || ( nCornerVis != SKYBOX_NOT_VISIBLE ) )
+ {
+ m_InternallyMaintainedData.m_nSkyboxVisibleFromCorners = nCornerVis;
+ }
+ }
+
+ //render fix bounding planes
+ {
+ for( int i = 0; i != PORTALRENDERFIXMESH_OUTERBOUNDPLANES; ++i )
+ {
+ float fCirclePos = ((float)(i)) * ((M_PI * 2.0f) / (float)PORTALRENDERFIXMESH_OUTERBOUNDPLANES);
+ float fUpBlend = cosf( fCirclePos );
+ float fRightBlend = sinf( fCirclePos );
+
+ Vector vNormal = -fUpBlend * m_vUp - fRightBlend * m_vRight;
+ Vector ptOnPlane = m_ptOrigin + (m_vUp * (fUpBlend * PORTAL_HALF_HEIGHT * 1.1f)) + (m_vRight * (fRightBlend * PORTAL_HALF_WIDTH * 1.1f));
+
+ m_InternallyMaintainedData.m_BoundingPlanes[i].Init( vNormal, vNormal.Dot( ptOnPlane ) );
+ }
+
+ m_InternallyMaintainedData.m_BoundingPlanes[PORTALRENDERFIXMESH_OUTERBOUNDPLANES].Init( -m_vForward, (-m_vForward).Dot( m_ptOrigin ) );
+ m_InternallyMaintainedData.m_BoundingPlanes[PORTALRENDERFIXMESH_OUTERBOUNDPLANES + 1].Init( m_vForward, m_vForward.Dot( m_ptOrigin - (m_vForward * 5.0f) ) );
+ }
+
+ //update depth doubler usability flag
+ m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration =
+ ( m_pLinkedPortal && //linked to another portal
+ ( m_vForward.Dot( m_pLinkedPortal->m_ptOrigin - m_ptOrigin ) > 0.0f ) && //this portal looking in the general direction of the other portal
+ ( m_vForward.Dot( m_pLinkedPortal->m_vForward ) < -0.7071f ) ); //within 45 degrees of facing directly at each other
+
+ if( m_pLinkedPortal )
+ m_pLinkedPortal->m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration = true;
+
+
+
+ //lastly, update link matrix
+ if ( m_pLinkedPortal != NULL )
+ {
+ matrix3x4_t localToWorld( m_vForward, -m_vRight, m_vUp, m_ptOrigin );
+ matrix3x4_t remoteToWorld( m_pLinkedPortal->m_vForward, -m_pLinkedPortal->m_vRight, m_pLinkedPortal->m_vUp, m_pLinkedPortal->m_ptOrigin );
+ CProp_Portal_Shared::UpdatePortalTransformationMatrix( localToWorld, remoteToWorld, &m_matrixThisToLinked );
+
+ // update the remote portal
+ MatrixInverseTR( m_matrixThisToLinked, m_pLinkedPortal->m_matrixThisToLinked );
+ }
+ else
+ {
+ m_matrixThisToLinked.Identity(); // don't accidentally teleport objects to zero space
+ }
+}
+
+
+
+
+bool CPortalRenderable_FlatBasic::WillUseDepthDoublerThisDraw( void ) const
+{
+ return g_pPortalRender->ShouldUseStencilsToRenderPortals() &&
+ m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration &&
+ (g_pPortalRender->GetRemainingPortalViewDepth() == 0) &&
+ (g_pPortalRender->GetViewRecursionLevel() > 1) &&
+ (g_pPortalRender->GetCurrentViewExitPortal() != this);
+}
+
+
+
+ConVar r_portal_use_complex_frustums( "r_portal_use_complex_frustums", "1", FCVAR_CLIENTDLL, "View optimization, turn this off if you get odd visual bugs." );
+
+bool CPortalRenderable_FlatBasic::CalcFrustumThroughPortal( const Vector &ptCurrentViewOrigin, Frustum OutputFrustum )
+{
+ if( r_portal_use_complex_frustums.GetBool() == false )
+ return false;
+
+ int i;
+
+ int iViewRecursionLevel = g_pPortalRender->GetViewRecursionLevel();
+ int iNextViewRecursionLevel = iViewRecursionLevel + 1;
+
+ if( (iViewRecursionLevel == 0) &&
+ ( (ptCurrentViewOrigin - m_ptOrigin).LengthSqr() < (PORTAL_HALF_HEIGHT * PORTAL_HALF_HEIGHT) ) )//FIXME: Player closeness check might need reimplementation
+ {
+ //calculations are most likely going to be completely useless, return nothing
+ return false;
+ }
+
+ if( m_pLinkedPortal == NULL )
+ return false;
+
+ if( m_vForward.Dot( ptCurrentViewOrigin ) <= m_InternallyMaintainedData.m_fPlaneDist )
+ return false; //looking at portal backface
+
+ //VPlane *pInputFrustum = view->GetFrustum(); //g_pPortalRender->m_RecursiveViewComplexFrustums[iViewRecursionLevel].Base();
+ //int iInputFrustumPlaneCount = 6; //g_pPortalRender->m_RecursiveViewComplexFrustums[iViewRecursionLevel].Count();
+ VPlane *pInputFrustum = g_pPortalRender->m_RecursiveViewComplexFrustums[iViewRecursionLevel].Base();
+ int iInputFrustumPlaneCount = g_pPortalRender->m_RecursiveViewComplexFrustums[iViewRecursionLevel].Count();
+ Assert( iInputFrustumPlaneCount > 0 );
+
+ Vector ptTempWork[2];
+ int iAllocSize = 4 + iInputFrustumPlaneCount;
+
+ Vector *pInVerts = (Vector *)stackalloc( sizeof( Vector ) * iAllocSize * 2 ); //possible to add 1 point per cut, 4 starting points, iInputFrustumPlaneCount cuts
+ Vector *pOutVerts = pInVerts + iAllocSize;
+ Vector *pTempVerts;
+
+ //clip by first plane and put output into pInVerts
+ int iVertCount = ClipPolyToPlane( m_InternallyMaintainedData.m_ptCorners, 4, pInVerts, pInputFrustum[0].m_Normal, pInputFrustum[0].m_Dist, 0.01f );
+
+ //clip by other planes and flipflop in and out pointers
+ for( i = 1; i != iInputFrustumPlaneCount; ++i )
+ {
+ if( iVertCount < 3 )
+ return false; //nothing left in the frustum
+
+ iVertCount = ClipPolyToPlane( pInVerts, iVertCount, pOutVerts, pInputFrustum[i].m_Normal, pInputFrustum[i].m_Dist, 0.01f );
+ pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
+ }
+
+ if( iVertCount < 3 )
+ return false; //nothing left in the frustum
+
+ g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].SetCount( iVertCount + 2 ); //+2 for near and far z planes
+
+ Vector ptTransformedCamera = m_matrixThisToLinked * ptCurrentViewOrigin;
+
+ //generate planes defined by each line around the convex and the camera origin
+ for( i = 0; i != iVertCount; ++i )
+ {
+ Vector *p1, *p2;
+ p1 = &pInVerts[i];
+ p2 = &pInVerts[(i+1)%iVertCount];
+
+ Vector vLine1 = *p1 - ptCurrentViewOrigin;
+ Vector vLine2 = *p2 - ptCurrentViewOrigin;
+ Vector vNormal = vLine1.Cross( vLine2 );
+ vNormal.NormalizeInPlace();
+
+ vNormal = m_matrixThisToLinked.ApplyRotation( vNormal );
+ g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Element(i).Init( vNormal, vNormal.Dot( ptTransformedCamera ) );
+ }
+
+ //Near Z
+ g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Element(i).Init( m_pLinkedPortal->m_vForward, m_pLinkedPortal->m_InternallyMaintainedData.m_fPlaneDist );
+
+ //Far Z
+ ++i;
+ {
+ Vector vNormal = m_matrixThisToLinked.ApplyRotation( pInputFrustum[iInputFrustumPlaneCount - 1].m_Normal );
+ Vector ptOnPlane = pInputFrustum[iInputFrustumPlaneCount - 1].m_Dist * pInputFrustum[iInputFrustumPlaneCount - 1].m_Normal;
+ g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Element(i).Init( vNormal, vNormal.Dot( m_matrixThisToLinked * ptOnPlane ) );
+ }
+
+
+
+
+ if( iVertCount > 4 )
+ {
+ float *fLineLengthSqr = (float *)stackalloc( sizeof( float ) * iVertCount );
+ VPlane *Planes = (VPlane *)stackalloc( sizeof( VPlane ) * iVertCount );
+
+ memcpy( Planes, g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Base(), sizeof( VPlane ) * iVertCount );
+
+ for( i = 0; i != (iVertCount - 1); ++i )
+ {
+ fLineLengthSqr[i] = (pInVerts[i + 1] - pInVerts[i]).LengthSqr();
+ }
+ fLineLengthSqr[i] = (pInVerts[0] - pInVerts[i]).LengthSqr(); //wrap around
+
+
+ while( iVertCount > 4 )
+ {
+ //we have too many verts to represent this accurately as a frustum,
+ //so, we're going to eliminate the smallest sides and bridge the surrounding sides until we're down to 4
+
+ float fMinSide = fLineLengthSqr[0];
+ int iMinSideFirstPoint = 0;
+ int iOldVertCount = iVertCount;
+ --iVertCount; //we're going to decrement this sometime in this block, it makes math easier to do it now
+
+ for( i = 1; i != iOldVertCount; ++i )
+ {
+ if( fLineLengthSqr[i] < fMinSide )
+ {
+ fMinSide = fLineLengthSqr[i];
+ iMinSideFirstPoint = i;
+ }
+ }
+
+ int i1, i2, i3, i4;
+ i1 = (iMinSideFirstPoint + iVertCount)%(iOldVertCount);
+ i2 = iMinSideFirstPoint;
+ i3 = (iMinSideFirstPoint + 1)%(iOldVertCount);
+ i4 = (iMinSideFirstPoint + 2)%(iOldVertCount);
+
+ Vector *p1, *p2, *p3, *p4;
+ p1 = &pInVerts[i1];
+ p2 = &pInVerts[i2];
+ p3 = &pInVerts[i3];
+ p4 = &pInVerts[i4];
+
+
+ //now we know the two points that we have to merge to one, project and make a merged point from the surrounding lines
+ if( fMinSide >= 0.1f ) //only worth doing the math if it's actually going to be accurate and make a difference
+ {
+ Vector vLine1 = *p2 - *p1;
+ Vector vLine2 = *p3 - *p4;
+
+ Vector vLine1Normal = vLine1.Cross( m_vForward );
+ vLine1Normal.NormalizeInPlace();
+
+ float fNormalDot = vLine1Normal.Dot( vLine2 );
+
+ AssertMsgOnce( fNormalDot != 0.0f, "Tell Dave Kircher if this pops up. It won't interfere with gameplay though" );
+ if( fNormalDot == 0.0f )
+ {
+ return false; //something went horribly wrong, bail and just suffer a slight framerate penalty for now
+ }
+
+ float fDist = vLine1Normal.Dot(*p1 - *p4);
+ *p2 = *p4 + (vLine2 * (fDist/fNormalDot));
+ }
+
+ fLineLengthSqr[i1] = (*p2 - *p1).LengthSqr();
+ fLineLengthSqr[i2] = (*p4 - *p2).LengthSqr(); //must do this BEFORE possibly shifting points p4+ left
+
+ if( i2 < i3 )
+ {
+ VPlane *v2 = &Planes[iMinSideFirstPoint];
+ memcpy( v2, v2 + 1, sizeof( VPlane ) * (iVertCount - iMinSideFirstPoint) );
+ }
+
+ if( i3 < i4 ) //not the last point in the array
+ {
+ int iElementShift = (iOldVertCount - i4);
+
+ //eliminate p3, we merged p2+p3 and already stored the result in p2
+ memcpy( p3, p3 + 1, sizeof( Vector ) * iElementShift );
+
+ float *l3 = &fLineLengthSqr[i3];
+ memcpy( l3, l3 + 1, sizeof( float ) * iElementShift );
+ }
+ }
+
+ for( i = 0; i != 4; ++i )
+ {
+ OutputFrustum[i] = Planes[i];
+ }
+ }
+ else
+ {
+ for( i = 0; i != iVertCount; ++i )
+ {
+ OutputFrustum[i] = g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Element(i);
+ }
+
+ for( ; i != 4; ++i )
+ {
+ //we had less than 4 planes for the sides, just copy from the last valid plane
+ OutputFrustum[i] = OutputFrustum[iVertCount-1];
+ }
+ }
+
+ //copy near/far planes
+ int iComplexCount = g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Count();
+ OutputFrustum[FRUSTUM_NEARZ] = g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Element(iComplexCount-2);
+ OutputFrustum[FRUSTUM_FARZ] = g_pPortalRender->m_RecursiveViewComplexFrustums[iNextViewRecursionLevel].Element(iComplexCount-1);
+
+ return true;
+}
+
+
+
+void CPortalRenderable_FlatBasic::RenderPortalViewToBackBuffer( CViewRender *pViewRender, const CViewSetup &cameraView )
+{
+ VPROF( "CPortalRenderable_FlatBasic::RenderPortalViewToBackBuffer" );
+
+ if( m_fStaticAmount == 1.0f )
+ return; //not going to see anything anyways
+
+ if( m_pLinkedPortal == NULL ) //not linked to any portal, so we'll be all static anyways
+ return;
+
+ Frustum FrustumBackup;
+ memcpy( FrustumBackup, pViewRender->GetFrustum(), sizeof( Frustum ) );
+
+ Frustum seeThroughFrustum;
+ bool bUseSeeThroughFrustum;
+
+ bUseSeeThroughFrustum = CalcFrustumThroughPortal( cameraView.origin, seeThroughFrustum );
+
+ Vector vCameraForward;
+ AngleVectors( cameraView.angles, &vCameraForward, NULL, NULL );
+
+ // Setup fog state for the camera.
+ Vector ptPOVOrigin = m_matrixThisToLinked * cameraView.origin;
+ Vector vPOVForward = m_matrixThisToLinked.ApplyRotation( vCameraForward );
+
+ Vector ptRemotePortalPosition = m_pLinkedPortal->m_ptOrigin;
+ Vector vRemotePortalForward = m_pLinkedPortal->m_vForward;
+
+ CViewSetup portalView = cameraView;
+
+ if( portalView.zNear < 1.0f )
+ portalView.zNear = 1.0f;
+
+ QAngle qPOVAngles = TransformAnglesToWorldSpace( cameraView.angles, m_matrixThisToLinked.As3x4() );
+
+ portalView.width = cameraView.width;
+ portalView.height = cameraView.height;
+ portalView.x = cameraView.x;
+ portalView.y = cameraView.y;
+ portalView.origin = ptPOVOrigin;
+ portalView.angles = qPOVAngles;
+ portalView.fov = cameraView.fov;
+ portalView.m_bOrtho = false;
+ portalView.m_flAspectRatio = cameraView.m_flAspectRatio;
+
+ CopyToCurrentView( pViewRender, portalView );
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ {
+ float fCustomClipPlane[4];
+ fCustomClipPlane[0] = vRemotePortalForward.x;
+ fCustomClipPlane[1] = vRemotePortalForward.y;
+ fCustomClipPlane[2] = vRemotePortalForward.z;
+ fCustomClipPlane[3] = vRemotePortalForward.Dot( ptRemotePortalPosition - (vRemotePortalForward * 0.5f) ); //moving it back a smidge to eliminate visual artifacts for half-in objects
+
+ pRenderContext->PushCustomClipPlane( fCustomClipPlane ); //this is technically the same plane within recursive views, but pushing it anyway in-case something else has been added to the stack
+ }
+
+
+ {
+ 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 );
+
+ if( m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration && (g_pPortalRender->GetRemainingPortalViewDepth() == 1) )
+ {
+ //save the view matrix for usage with the depth doubler.
+ //It's important that we do this AFTER using the depth doubler this frame to compensate for the fact that the front buffer is 1 frame behind the current view matrix
+ //otherwise we get a lag effect when the player changes their viewing angles
+ pRenderContext->GetMatrix( MATERIAL_VIEW, &m_InternallyMaintainedData.m_DepthDoublerTextureView );
+ }
+
+ SetViewRecursionLevel( g_pPortalRender->GetViewRecursionLevel() - 1 );
+ }
+ render->PopView( pViewRender->GetFrustum() );
+
+ //restore old frustum
+ memcpy( pViewRender->GetFrustum(), FrustumBackup, sizeof( Frustum ) );
+ render->OverrideViewFrustum( FrustumBackup );
+ }
+
+ pRenderContext->PopCustomClipPlane();
+
+ //restore old vis data
+ CopyToCurrentView( pViewRender, cameraView );
+}
+
+
+void CPortalRenderable_FlatBasic::RenderPortalViewToTexture( CViewRender *pViewRender, const CViewSetup &cameraView )
+{
+ if( m_fStaticAmount == 1.0f )
+ return; //not going to see anything anyways
+
+ if( m_pLinkedPortal == NULL ) //not linked to any portal, so we'll be all static anyways
+ return;
+
+ float fPixelVisibilty = g_pPortalRender->GetPixelVisilityForPortalSurface( this );
+ if( (fPixelVisibilty >= 0.0f) && (fPixelVisibilty <= PORTALRENDERABLE_FLATBASIC_MINPIXELVIS) )
+ return;
+
+ ITexture *pRenderTarget;
+ if( m_bIsPortal2 )
+ pRenderTarget = portalrendertargets->GetPortal2Texture();
+ else
+ pRenderTarget = portalrendertargets->GetPortal1Texture();
+
+ // Require that we have render textures for drawing
+ AssertMsg( pRenderTarget, "Portal render targets not initialized properly" );
+
+ // We're about to dereference this, so just bail if we can't
+ if ( !pRenderTarget )
+ return;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ Vector vCameraForward;
+ AngleVectors( cameraView.angles, &vCameraForward, NULL, NULL );
+
+ Frustum seeThroughFrustum;
+ bool bUseSeeThroughFrustum = CalcFrustumThroughPortal( cameraView.origin, seeThroughFrustum );
+
+ // Setup fog state for the camera.
+ Vector ptPOVOrigin = m_matrixThisToLinked * cameraView.origin;
+ Vector vPOVForward = m_matrixThisToLinked.ApplyRotation( vCameraForward );
+
+ Vector vCameraToPortal = m_ptOrigin - cameraView.origin;
+
+ CViewSetup portalView = cameraView;
+ Frustum frustumBackup;
+ memcpy( frustumBackup, pViewRender->GetFrustum(), sizeof( Frustum ) );
+
+ QAngle qPOVAngles = TransformAnglesToWorldSpace( cameraView.angles, m_matrixThisToLinked.As3x4() );
+
+ portalView.width = pRenderTarget->GetActualWidth();
+ portalView.height = pRenderTarget->GetActualHeight();
+ portalView.x = 0;
+ portalView.y = 0;
+ portalView.origin = ptPOVOrigin;
+ portalView.angles = qPOVAngles;
+ portalView.fov = cameraView.fov;
+ portalView.m_bOrtho = false;
+ portalView.m_flAspectRatio = (float)cameraView.width / (float)cameraView.height; //use the screen aspect ratio, 0.0f doesn't work as advertised
+
+ //pRenderContext->Flush( false );
+
+ float fCustomClipPlane[4];
+ fCustomClipPlane[0] = m_pLinkedPortal->m_vForward.x;
+ fCustomClipPlane[1] = m_pLinkedPortal->m_vForward.y;
+ fCustomClipPlane[2] = m_pLinkedPortal->m_vForward.z;
+ fCustomClipPlane[3] = m_pLinkedPortal->m_vForward.Dot( m_pLinkedPortal->m_ptOrigin - (m_pLinkedPortal->m_vForward * 0.5f) ); //moving it back a smidge to eliminate visual artifacts for half-in objects
+
+ pRenderContext->PushCustomClipPlane( fCustomClipPlane );
+
+ {
+ render->Push3DView( portalView, VIEW_CLEAR_DEPTH, pRenderTarget, pViewRender->GetFrustum() );
+
+ {
+ ViewCustomVisibility_t customVisibility;
+ m_pLinkedPortal->AddToVisAsExitPortal( &customVisibility );
+
+ SetRemainingViewDepth( 0 );
+ SetViewRecursionLevel( 1 );
+
+ CPortalRenderable *pRenderingViewForPortalBackup = g_pPortalRender->GetCurrentViewEntryPortal();
+ CPortalRenderable *pRenderingViewExitPortalBackup = g_pPortalRender->GetCurrentViewExitPortal();
+ SetViewEntranceAndExitPortals( this, m_pLinkedPortal );
+
+ bool bDrew3dSkybox = false;
+ SkyboxVisibility_t nSkyboxVisible = SKYBOX_NOT_VISIBLE;
+
+ // if the 3d skybox world is drawn, then don't draw the normal skybox
+ int nClearFlags = 0;
+ Draw3dSkyboxworld_Portal( pViewRender, portalView, nClearFlags, bDrew3dSkybox, nSkyboxVisible, pRenderTarget );
+
+ if( bUseSeeThroughFrustum )
+ {
+ memcpy( pViewRender->GetFrustum(), seeThroughFrustum, sizeof( Frustum ) );
+ }
+
+ render->OverrideViewFrustum( pViewRender->GetFrustum() );
+
+ pRenderContext->EnableUserClipTransformOverride( false );
+
+ ViewDrawScene( pViewRender, bDrew3dSkybox, nSkyboxVisible, portalView, nClearFlags, (view_id_t)g_pPortalRender->GetCurrentViewId(), false, 0, &customVisibility );
+
+ SetViewEntranceAndExitPortals( pRenderingViewForPortalBackup, pRenderingViewExitPortalBackup );
+
+ SetRemainingViewDepth( 1 );
+ SetViewRecursionLevel( 0 );
+
+ memcpy( pViewRender->GetFrustum(), frustumBackup, sizeof( Frustum ) );
+ render->OverrideViewFrustum( pViewRender->GetFrustum() );
+ }
+
+ render->PopView( pViewRender->GetFrustum() );
+ }
+
+ pRenderContext->PopCustomClipPlane();
+
+ //pRenderContext->Flush( false );
+
+ CopyToCurrentView( pViewRender, cameraView );
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// AddToVisAsExitPortal
+// input - pViewRender: pointer to the CViewRender class used to render this scene.
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void CPortalRenderable_FlatBasic::AddToVisAsExitPortal( ViewCustomVisibility_t *pCustomVisibility )
+{
+ if ( !pCustomVisibility )
+ return;
+
+ // Add four corners of the portal to the renderer as visibility origins
+ for ( int i = 0; i < 4; ++i )
+ {
+ if( enginetrace->GetLeafContainingPoint( m_InternallyMaintainedData.m_ptCorners[i] ) != -1 )
+ pCustomVisibility->AddVisOrigin( m_InternallyMaintainedData.m_ptCorners[i] );
+ }
+
+ // Specify which leaf to use for area portal culling
+ pCustomVisibility->ForceVisOverride( m_InternallyMaintainedData.m_VisData );
+ pCustomVisibility->ForceViewLeaf( m_InternallyMaintainedData.m_iViewLeaf );
+}
+
+void CPortalRenderable_FlatBasic::DrawPreStencilMask( void )
+{
+ if ( ( m_fOpenAmount > 0.0f ) && ( m_fOpenAmount < 1.0f ) )
+ {
+ DrawSimplePortalMesh( m_Materials.m_Portal_Refract[ ( ( m_bIsPortal2 ) ? ( 1 ) : ( 0 ) ) ] );
+ }
+}
+
+void CPortalRenderable_FlatBasic::DrawStencilMask( void )
+{
+ DrawSimplePortalMesh( m_Materials.m_Portal_Stencil_Hole );
+ DrawRenderFixMesh( g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
+}
+
+void CPortalRenderable_FlatBasic::DrawPostStencilFixes( void )
+{
+ CMatRenderContextPtr pRenderContext( materials );
+
+ //fast clipping may have hosed depth, reset it
+ pRenderContext->ClearBuffersObeyStencil( false, true );
+
+ //replace the fog we overwrote
+ RenderFogQuad();
+
+ //replace depth
+ DrawSimplePortalMesh( g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model, 0.0f );
+ DrawRenderFixMesh( g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model, 0.0f );
+}
+
+bool CPortalRenderable_FlatBasic::ShouldUpdateDepthDoublerTexture( const CViewSetup &viewSetup )
+{
+ return ( (m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration) &&
+ (m_pLinkedPortal != NULL) &&
+ (m_fStaticAmount < 1.0f) );
+}
+
+void CPortalRenderable_FlatBasic::HandlePortalPlaybackMessage( KeyValues *pKeyValues )
+{
+ int nLinkedPortalId = pKeyValues->GetInt( "linkedPortalId" );
+ m_fOpenAmount = pKeyValues->GetFloat( "openAmount" );
+ m_fStaticAmount = pKeyValues->GetFloat( "staticAmount" );
+ m_fSecondaryStaticAmount = pKeyValues->GetFloat( "secondaryStaticAmount" );
+ m_bIsPortal2 = pKeyValues->GetInt( "isPortal2" ) != 0;
+ m_pLinkedPortal = nLinkedPortalId >= 0 ? (CPortalRenderable_FlatBasic *)FindRecordedPortal( nLinkedPortalId ) : NULL;
+ matrix3x4_t *pMat = (matrix3x4_t*)pKeyValues->GetPtr( "portalToWorld" );
+
+ MatrixGetColumn( *pMat, 3, m_ptOrigin );
+ MatrixGetColumn( *pMat, 0, m_vForward );
+ MatrixGetColumn( *pMat, 1, m_vRight );
+ MatrixGetColumn( *pMat, 2, m_vUp );
+ m_vRight *= -1.0f;
+
+ PortalMoved();
+}
+
+extern ConVar mat_wireframe;
+static void DrawComplexPortalMesh_SubQuad( Vector &ptBottomLeft, Vector &vUp, Vector &vRight, float *fSubQuadRect, void *pBindEnt, const IMaterial *pMaterial, const VMatrix *pReplacementViewMatrixForTexCoords = NULL )
+{
+ PortalMeshPoint_t Vertices[4];
+
+ Vertices[0].vWorldSpacePosition = ptBottomLeft + (vRight * fSubQuadRect[2]) + (vUp * fSubQuadRect[3]);
+ Vertices[0].texCoord.x = fSubQuadRect[2];
+ Vertices[0].texCoord.y = fSubQuadRect[3];
+
+ Vertices[1].vWorldSpacePosition = ptBottomLeft + (vRight * fSubQuadRect[2]) + (vUp * fSubQuadRect[1]);
+ Vertices[1].texCoord.x = fSubQuadRect[2];
+ Vertices[1].texCoord.y = fSubQuadRect[1];
+
+ Vertices[2].vWorldSpacePosition = ptBottomLeft + (vRight * fSubQuadRect[0]) + (vUp * fSubQuadRect[1]);
+ Vertices[2].texCoord.x = fSubQuadRect[0];
+ Vertices[2].texCoord.y = fSubQuadRect[1];
+
+ Vertices[3].vWorldSpacePosition = ptBottomLeft + (vRight * fSubQuadRect[0]) + (vUp * fSubQuadRect[3]);
+ Vertices[3].texCoord.x = fSubQuadRect[0];
+ Vertices[3].texCoord.y = fSubQuadRect[3];
+
+ Clip_And_Render_Convex_Polygon( Vertices, 4, pMaterial, pBindEnt );
+}
+
+#define PORTAL_PROJECTION_MESH_SUBDIVIDE_HEIGHTCHUNKS 8
+#define PORTAL_PROJECTION_MESH_SUBDIVIDE_WIDTHCHUNKS 6
+
+void CPortalRenderable_FlatBasic::DrawComplexPortalMesh( const IMaterial *pMaterialOverride, float fForwardOffsetModifier ) //generates and draws the portal mesh (Needed for compatibility with fixed function rendering)
+{
+ PortalMeshPoint_t BaseVertices[4];
+
+ Vector ptBottomLeft = m_ptOrigin + (m_vForward * (fForwardOffsetModifier)) - (m_vRight * PORTAL_HALF_WIDTH) - (m_vUp * PORTAL_HALF_HEIGHT);
+ Vector vScaledUp = m_vUp * (2.0f * PORTAL_HALF_HEIGHT);
+ Vector vScaledRight = m_vRight * (2.0f * PORTAL_HALF_WIDTH);
+
+ CMatRenderContextPtr pRenderContext( materials );
+ VMatrix matView;
+ pRenderContext->GetMatrix( MATERIAL_VIEW, &matView );
+
+ const IMaterial *pMaterial;
+ if( pMaterialOverride )
+ {
+ pMaterial = pMaterialOverride;
+ }
+ else
+ {
+ pMaterial = m_Materials.m_PortalMaterials[(m_bIsPortal2)?1:0];
+ }
+
+
+ float fSubQuadRect[4] = { 0.0f, 0.0f, 1.0f, 1.0f };
+
+ float fHeightBegin = 0.0f;
+ for( int i = 0; i != PORTAL_PROJECTION_MESH_SUBDIVIDE_HEIGHTCHUNKS; ++i )
+ {
+ float fHeightEnd = fHeightBegin + (1.0f / ((float)PORTAL_PROJECTION_MESH_SUBDIVIDE_HEIGHTCHUNKS));
+
+ fSubQuadRect[1] = fHeightBegin;
+ fSubQuadRect[3] = fHeightEnd;
+
+ float fWidthBegin = 0.0f;
+ for( int j = 0; j != PORTAL_PROJECTION_MESH_SUBDIVIDE_WIDTHCHUNKS; ++j )
+ {
+ float fWidthEnd = fWidthBegin + (1.0f / ((float)PORTAL_PROJECTION_MESH_SUBDIVIDE_WIDTHCHUNKS));
+
+ fSubQuadRect[0] = fWidthBegin;
+ fSubQuadRect[2] = fWidthEnd;
+
+ DrawComplexPortalMesh_SubQuad( ptBottomLeft, vScaledUp, vScaledRight, fSubQuadRect, GetClientRenderable(), pMaterial );
+
+ fWidthBegin = fWidthEnd;
+ }
+ fHeightBegin = fHeightEnd;
+ }
+
+ //pRenderContext->Flush( false );
+}
+
+void CPortalRenderable_FlatBasic::DrawDepthDoublerMesh( float fForwardOffsetModifier )
+{
+ IMaterialVar *pDepthDoubleViewMatrixVar = s_FlatBasicPortalDrawingMaterials.m_Materials.m_PortalDepthDoubler->FindVar( "$alternateviewmatrix", NULL, false );
+ if ( pDepthDoubleViewMatrixVar )
+ pDepthDoubleViewMatrixVar->SetMatrixValue( m_InternallyMaintainedData.m_DepthDoublerTextureView );
+ DrawSimplePortalMesh( m_Materials.m_PortalDepthDoubler, fForwardOffsetModifier );
+}
+
+
+
+void CPortalRenderable_FlatBasic::DrawSimplePortalMesh( const IMaterial *pMaterialOverride, float fForwardOffsetModifier )
+{
+ const IMaterial *pMaterial;
+ if( pMaterialOverride )
+ pMaterial = pMaterialOverride;
+ else
+ pMaterial = m_Materials.m_PortalMaterials[m_bIsPortal2?1:0];
+
+ CMatRenderContextPtr pRenderContext( materials );
+ pRenderContext->Bind( (IMaterial *)pMaterial, GetClientRenderable() );
+
+ // This can depend on the Bind command above, so keep this after!
+ UpdateFrontBufferTexturesForMaterial( (IMaterial *)pMaterial );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL ); //just in case
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ Vector ptCenter = m_ptOrigin + (m_vForward * fForwardOffsetModifier);
+
+ Vector verts[4];
+ verts[0] = ptCenter + (m_vRight * PORTAL_HALF_WIDTH) - (m_vUp * PORTAL_HALF_HEIGHT);
+ verts[1] = ptCenter + (m_vRight * PORTAL_HALF_WIDTH) + (m_vUp * PORTAL_HALF_HEIGHT);
+ verts[2] = ptCenter - (m_vRight * PORTAL_HALF_WIDTH) - (m_vUp * PORTAL_HALF_HEIGHT);
+ verts[3] = ptCenter - (m_vRight * PORTAL_HALF_WIDTH) + (m_vUp * PORTAL_HALF_HEIGHT);
+
+ float vTangent[4] = { -m_vRight.x, -m_vRight.y, -m_vRight.z, 1.0f };
+
+ CMeshBuilder meshBuilder;
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( false );
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 );
+
+ meshBuilder.Position3fv( &verts[0].x );
+ meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
+ meshBuilder.TexCoord2f( 1, 0.0f, 1.0f );
+ meshBuilder.Normal3f( m_vForward.x, m_vForward.y, m_vForward.z );
+ meshBuilder.UserData( vTangent );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( &verts[1].x );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.TexCoord2f( 1, 0.0f, 0.0f );
+ meshBuilder.Normal3f( m_vForward.x, m_vForward.y, m_vForward.z );
+ meshBuilder.UserData( vTangent );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( &verts[2].x );
+ meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
+ meshBuilder.TexCoord2f( 1, 1.0f, 1.0f );
+ meshBuilder.Normal3f( m_vForward.x, m_vForward.y, m_vForward.z );
+ meshBuilder.UserData( vTangent );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( &verts[3].x );
+ meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
+ meshBuilder.TexCoord2f( 1, 1.0f, 0.0f );
+ meshBuilder.Normal3f( m_vForward.x, m_vForward.y, m_vForward.z );
+ meshBuilder.UserData( vTangent );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ if( mat_wireframe.GetBool() )
+ {
+ pRenderContext->Bind( (IMaterial *)(const IMaterial *)g_pPortalRender->m_MaterialsAccess.m_Wireframe, (CPortalRenderable*)this );
+
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( false );
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 );
+
+ meshBuilder.Position3fv( &verts[0].x );
+ meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
+ meshBuilder.TexCoord2f( 1, 0.0f, 1.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( &verts[1].x );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.TexCoord2f( 1, 0.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( &verts[2].x );
+ meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
+ meshBuilder.TexCoord2f( 1, 1.0f, 1.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( &verts[3].x );
+ meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
+ meshBuilder.TexCoord2f( 1, 1.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+ }
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+}
+
+
+
+void CPortalRenderable_FlatBasic::DrawRenderFixMesh( const IMaterial *pMaterialOverride, float fFrontClipDistance )
+{
+ const IMaterial *pMaterial;
+ if( pMaterialOverride )
+ pMaterial = pMaterialOverride;
+ else
+ pMaterial = m_Materials.m_PortalRenderFixMaterials[(m_bIsPortal2)?1:0];
+
+ if( g_pPortalRender->GetViewRecursionLevel() != 0 )
+ return; //a render fix should only ever be necessary in the primary view
+
+ Vector ptCameraOrigin = CurrentViewOrigin();
+
+ Vector vPortalCenterToCamera = ptCameraOrigin - m_ptOrigin;
+ if( (vPortalCenterToCamera.Dot( m_vForward ) < -1.0f) ) //camera coplanar (to 1.0 units) or in front of portal plane
+ return;
+
+ if( vPortalCenterToCamera.LengthSqr() < (PORTAL_HALF_HEIGHT * PORTAL_HALF_HEIGHT) ) //FIXME: Player closeness check might need reimplementation
+ {
+ //if the player is this close to the portal, immediately get rid of any static it has as well as draw the fix
+ m_fStaticAmount = 0.0f;
+ //m_fSecondaryStaticAmount = 0.0f;
+
+ float fOldDist = m_InternallyMaintainedData.m_BoundingPlanes[PORTALRENDERFIXMESH_OUTERBOUNDPLANES].m_Dist;
+
+
+ float fCameraDist = m_vForward.Dot(ptCameraOrigin - m_ptOrigin);
+
+ if( fFrontClipDistance > fCameraDist ) //never clip further out than the camera, we can see into the garbage space of the portal view's texture
+ fFrontClipDistance = fCameraDist;
+
+ m_InternallyMaintainedData.m_BoundingPlanes[PORTALRENDERFIXMESH_OUTERBOUNDPLANES].m_Dist -= fFrontClipDistance;
+ Internal_DrawRenderFixMesh( pMaterial );
+ m_InternallyMaintainedData.m_BoundingPlanes[PORTALRENDERFIXMESH_OUTERBOUNDPLANES].m_Dist = fOldDist;
+ }
+
+
+}
+
+void CPortalRenderable_FlatBasic::Internal_DrawRenderFixMesh( const IMaterial *pMaterial )
+{
+ PortalMeshPoint_t WorkVertices[4];
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL ); //just in case
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+
+ //view->GetViewSetup()->zNear;
+ Vector vForward, vUp, vRight, vOrigin;
+ vForward = CurrentViewForward();
+ vUp = CurrentViewUp();
+ vRight = CurrentViewRight();
+
+ vOrigin = CurrentViewOrigin() + vForward * (view->GetViewSetup()->zNear + 0.05f);
+
+ for( int i = 0; i != 4; ++i )
+ {
+ WorkVertices[i].texCoord.x = WorkVertices[i].texCoord.y = 0.0f;
+ }
+
+ 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);
+
+ ClipFixToBoundingAreaAndDraw( WorkVertices, pMaterial);
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+}
+
+void CPortalRenderable_FlatBasic::ClipFixToBoundingAreaAndDraw( PortalMeshPoint_t *pVerts, const IMaterial *pMaterial )
+{
+ PortalMeshPoint_t *pInVerts = (PortalMeshPoint_t *)stackalloc( 4 * (PORTALRENDERFIXMESH_OUTERBOUNDPLANES + 2) * 16 * sizeof( PortalMeshPoint_t ) ); //really only should need 4x points, but I'm paranoid
+ PortalMeshPoint_t *pOutVerts = (PortalMeshPoint_t *)stackalloc( 4 * (PORTALRENDERFIXMESH_OUTERBOUNDPLANES + 2) * 16 * sizeof( PortalMeshPoint_t ) );
+ PortalMeshPoint_t *pTempVerts;
+
+ memcpy( pInVerts, pVerts, sizeof( PortalMeshPoint_t ) * 4 );
+ int iVertCount = 4;
+
+ //clip by bounding area planes
+ {
+ for( int i = 0; i != (PORTALRENDERFIXMESH_OUTERBOUNDPLANES + 1); ++i )
+ {
+ if( iVertCount < 3 )
+ return; //nothing to draw
+
+ iVertCount = ClipPolyToPlane_LerpTexCoords( pInVerts, iVertCount, pOutVerts, m_InternallyMaintainedData.m_BoundingPlanes[i].m_Normal, m_InternallyMaintainedData.m_BoundingPlanes[i].m_Dist, 0.01f );
+ pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
+ }
+
+ if( iVertCount < 3 )
+ return; //nothing to draw
+ }
+
+
+ //clip by the viewing frustum
+ {
+ VPlane *pFrustum = view->GetFrustum();
+
+ for( int i = 0; 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 );
+
+ //project the points so we can fudge the numbers a bit and move them to exactly 0.0f depth
+ {
+ VMatrix matProj, matView, matViewProj;
+ pRenderContext->GetMatrix( MATERIAL_PROJECTION, &matProj );
+ pRenderContext->GetMatrix( MATERIAL_VIEW, &matView );
+ MatrixMultiply( matProj, matView, matViewProj );
+
+ for( int i = 0; i != iVertCount; ++i )
+ {
+ float W, inverseW;
+
+ W = matViewProj.m[3][0] * pInVerts[i].vWorldSpacePosition.x;
+ W += matViewProj.m[3][1] * pInVerts[i].vWorldSpacePosition.y;
+ W += matViewProj.m[3][2] * pInVerts[i].vWorldSpacePosition.z;
+ W += matViewProj.m[3][3];
+
+ inverseW = 1.0f / W;
+
+
+ pInVerts[i].vWorldSpacePosition = matViewProj * pInVerts[i].vWorldSpacePosition;
+ pInVerts[i].vWorldSpacePosition *= inverseW;
+ pInVerts[i].vWorldSpacePosition.z = 0.00001f; //the primary reason we're projecting on the CPU to begin with
+ }
+ }
+
+ //render with identity transforms and clipping disabled
+ {
+ bool bClippingEnabled = pRenderContext->EnableClipping( false );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ RenderPortalMeshConvexPolygon( pInVerts, iVertCount, pMaterial, this );
+ if( mat_wireframe.GetBool() )
+ RenderPortalMeshConvexPolygon( pInVerts, iVertCount, materials->FindMaterial( "shadertest/wireframe", TEXTURE_GROUP_CLIENT_EFFECTS, false ), this );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->EnableClipping( bClippingEnabled );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// renders a quad that simulates fog as an overlay for something else (most notably the hole we create for stencil mode portals)
+//-----------------------------------------------------------------------------
+void CPortalRenderable_FlatBasic::RenderFogQuad( void )
+{
+ CMatRenderContextPtr pRenderContext( materials );
+ if( pRenderContext->GetFogMode() == MATERIAL_FOG_NONE )
+ return;
+
+ float fFogStart, fFogEnd;
+ pRenderContext->GetFogDistances( &fFogStart, &fFogEnd, NULL );
+ float vertexColor[4];
+ unsigned char fogColor[3];
+ pRenderContext->GetFogColor( fogColor );
+
+ /*float fColorScale = LinearToGammaFullRange( pRenderContext->GetToneMappingScaleLinear().x );
+
+ fogColor[0] *= fColorScale;
+ fogColor[1] *= fColorScale;
+ fogColor[2] *= fColorScale;*/
+
+ vertexColor[0] = fogColor[0] * (1.0f / 255.0f);
+ vertexColor[1] = fogColor[1] * (1.0f / 255.0f);
+ vertexColor[2] = fogColor[2] * (1.0f / 255.0f);
+
+ float ooFogRange = 1.0f;
+ if ( fFogEnd != fFogStart )
+ {
+ ooFogRange = 1.0f / (fFogEnd - fFogStart);
+ }
+
+ float FogEndOverFogRange = ooFogRange * fFogEnd;
+
+ VMatrix matView, matViewProj, matProj;
+ pRenderContext->GetMatrix( MATERIAL_VIEW, &matView );
+ pRenderContext->GetMatrix( MATERIAL_PROJECTION, &matProj );
+ MatrixMultiply( matProj, matView, matViewProj );
+
+ Vector vUp = m_vUp * (PORTAL_HALF_HEIGHT * 2.0f);
+ Vector vRight = m_vRight * (PORTAL_HALF_WIDTH * 2.0f);
+
+ Vector ptCorners[4];
+ ptCorners[0] = (m_ptOrigin + vUp) + vRight;
+ ptCorners[1] = (m_ptOrigin + vUp) - vRight;
+ ptCorners[2] = (m_ptOrigin - vUp) + vRight;
+ ptCorners[3] = (m_ptOrigin - vUp) - vRight;
+
+
+ pRenderContext->Bind( (IMaterial *)(const IMaterial *)g_pPortalRender->m_MaterialsAccess.m_TranslucentVertexColor );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 2 );
+
+ for( int i = 0; i != 4; ++i )
+ {
+ float projZ;
+ projZ = matViewProj.m[2][0] * ptCorners[i].x;
+ projZ += matViewProj.m[2][1] * ptCorners[i].y;
+ projZ += matViewProj.m[2][2] * ptCorners[i].z;
+ projZ += matViewProj.m[2][3];
+
+ float fFogAmount = ((-projZ * ooFogRange) + FogEndOverFogRange); //projZ should be negative
+
+ //range fix
+ if( fFogAmount >= 1.0f )
+ fFogAmount = 1.0f;
+
+ if( fFogAmount <= 0.0f )
+ fFogAmount = 0.0f;
+
+ vertexColor[3] = 1.0f - fFogAmount; //alpha is inverse fog
+
+ meshBuilder.Position3fv( &ptCorners[i].x );
+ meshBuilder.Color4fv( vertexColor );
+ meshBuilder.AdvanceVertex();
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+void CPortalRenderable_FlatBasic::DrawPortal( void )
+{
+ if( (view->GetDrawFlags() & DF_RENDER_REFLECTION) != 0 )
+ return;
+
+ if ( g_pPortalRender->ShouldUseStencilsToRenderPortals() )
+ {
+ //stencil-based rendering
+ if( g_pPortalRender->IsRenderingPortal() == false ) //main view
+ {
+ if( m_pLinkedPortal == NULL ) //didn't pass through pre-stencil mask
+ {
+ if ( ( m_fOpenAmount > 0.0f ) && ( m_fOpenAmount < 1.0f ) )
+ {
+ DrawSimplePortalMesh( m_Materials.m_Portal_Refract[ ( ( m_bIsPortal2 ) ? ( 1 ) : ( 0 ) ) ] );
+ }
+ }
+
+ DrawSimplePortalMesh( m_Materials.m_PortalStaticOverlay[((m_bIsPortal2)?(1):(0))] );
+ DrawRenderFixMesh( g_pPortalRender->m_MaterialsAccess.m_WriteZ_Model );
+ }
+ else if( g_pPortalRender->GetCurrentViewExitPortal() != this )
+ {
+ if( m_pLinkedPortal == NULL ) //didn't pass through pre-stencil mask
+ {
+ if ( ( m_fOpenAmount > 0.0f ) && ( m_fOpenAmount < 1.0f ) )
+ {
+ DrawSimplePortalMesh( m_Materials.m_Portal_Refract[ ( ( m_bIsPortal2 ) ? ( 1 ) : ( 0 ) ) ] );
+ }
+ }
+
+ if( (m_InternallyMaintainedData.m_bUsableDepthDoublerConfiguration)
+ && (g_pPortalRender->GetRemainingPortalViewDepth() == 0)
+ && (g_pPortalRender->GetViewRecursionLevel() > 1) )
+ {
+ DrawDepthDoublerMesh();
+ }
+ else
+ {
+ DrawSimplePortalMesh( m_Materials.m_PortalStaticOverlay[((m_bIsPortal2)?(1):(0))] );
+ }
+ }
+ }
+ else
+ {
+ BeginPortalPixelVisibilityQuery();
+
+ //texture-based rendering
+ if( g_pPortalRender->IsRenderingPortal() == false )
+ {
+ if ( ( m_fOpenAmount > 0.0f ) && ( m_fOpenAmount < 1.0f ) )
+ {
+ DrawSimplePortalMesh( m_Materials.m_Portal_Refract[ ( ( m_bIsPortal2 ) ? ( 1 ) : ( 0 ) ) ] );
+ }
+
+ DrawComplexPortalMesh();
+ DrawRenderFixMesh();
+ }
+ else if( g_pPortalRender->GetCurrentViewExitPortal() != this ) //don't render portals that our view is exiting from
+ {
+ if ( ( m_fOpenAmount > 0.0f ) && ( m_fOpenAmount < 1.0f ) )
+ {
+ DrawSimplePortalMesh( m_Materials.m_Portal_Refract[ ( ( m_bIsPortal2 ) ? ( 1 ) : ( 0 ) ) ] );
+ }
+ DrawSimplePortalMesh( m_Materials.m_PortalStaticOverlay[((m_bIsPortal2)?(1):(0))] ); //FIXME: find out why the projection mesh screws up at the second level of rendering in -nouserclip situations
+ }
+
+ EndPortalPixelVisibilityQuery();
+ }
+}
+
+bool CPortalRenderable_FlatBasic::DoesExitViewIntersectWaterPlane( float waterZ, int leafWaterDataID ) const
+{
+ bool bAboveWater = false, bBelowWater = false;
+ for( int i = 0; i != 4; ++i )
+ {
+ bAboveWater |= (m_InternallyMaintainedData.m_ptCorners[i].z >= waterZ);
+ bBelowWater |= (m_InternallyMaintainedData.m_ptCorners[i].z <= waterZ);
+ }
+
+ return (bAboveWater && bBelowWater);
+}
+
+bool CPortalRenderable_FlatBasic::ShouldUpdatePortalView_BasedOnView( const CViewSetup &currentView, CUtlVector<VPlane> &currentComplexFrustum )
+{
+ if( m_pLinkedPortal == NULL )
+ return false;
+
+ if( m_fStaticAmount == 1.0f )
+ return false;
+
+ Vector vCameraPos = currentView.origin;
+
+ if( (g_pPortalRender->GetViewRecursionLevel() == 0) &&
+ ((m_ptOrigin - vCameraPos).LengthSqr() < (PORTAL_HALF_HEIGHT * PORTAL_HALF_HEIGHT)) ) //FIXME: Player closeness check might need reimplementation
+ {
+ return true; //fudgery time. The player might not be able to see the surface, but they can probably see the render fix
+ }
+
+ if( m_vForward.Dot( vCameraPos ) <= m_InternallyMaintainedData.m_fPlaneDist )
+ return false; //looking at portal backface
+
+ VPlane *currentFrustum = currentComplexFrustum.Base();
+ int iCurrentFrustmPlanes = currentComplexFrustum.Count();
+
+ //now slice up the portal quad and see if any is visible within the frustum
+ int allocSize = (6 + currentComplexFrustum.Count()); //possible to add 1 point per cut, 4 starting points, N plane cuts, 2 extra because I'm paranoid
+ Vector *pInVerts = (Vector *)stackalloc( sizeof( Vector ) * allocSize * 2 );
+ Vector *pOutVerts = pInVerts + allocSize;
+ Vector *pTempVerts;
+
+ //clip by first plane and put output into pInVerts
+ int iVertCount = ClipPolyToPlane( m_InternallyMaintainedData.m_ptCorners, 4, pInVerts, currentFrustum[0].m_Normal, currentFrustum[0].m_Dist, 0.01f );
+
+ //clip by other planes and flipflop in and out pointers
+ for( int i = 1; i != iCurrentFrustmPlanes; ++i )
+ {
+ if( iVertCount < 3 )
+ return false; //nothing left in the frustum
+
+ iVertCount = ClipPolyToPlane( pInVerts, iVertCount, pOutVerts, currentFrustum[i].m_Normal, currentFrustum[i].m_Dist, 0.01f );
+ pTempVerts = pInVerts; pInVerts = pOutVerts; pOutVerts = pTempVerts; //swap vertex pointers
+ }
+
+ if( iVertCount < 3 )
+ return false; //nothing left in the frustum
+
+ return true;
+}
+
+bool CPortalRenderable_FlatBasic::ShouldUpdatePortalView_BasedOnPixelVisibility( float fScreenFilledByStencilMaskLastFrame_Normalized )
+{
+ return (fScreenFilledByStencilMaskLastFrame_Normalized < 0.0f) || // < 0 is an error value
+ (fScreenFilledByStencilMaskLastFrame_Normalized > PORTALRENDERABLE_FLATBASIC_MINPIXELVIS );
+}
+
+CPortalRenderable *CreatePortal_FlatBasic_Fn( void )
+{
+ return new CPortalRenderable_FlatBasic;
+}
+
+static CPortalRenderableCreator CreatePortal_FlatBasic( "flatBasic", CreatePortal_FlatBasic_Fn );