//========= 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 ] ;
for ( int i = 0 ; i < ( iVertCount - iMinSideFirstPoint ) ; i + + )
v2 [ i ] = v2 [ i + 1 ] ;
}
if ( i3 < i4 ) //not the last point in the array
{
int iElementShift = ( iOldVertCount - i4 ) ;
float * l3 = & fLineLengthSqr [ i3 ] ;
//eliminate p3, we merged p2+p3 and already stored the result in p2
for ( int i = 0 ; i < iElementShift ; i + + )
{
p3 [ i ] = p3 [ i + 1 ] ;
l3 [ i ] = l3 [ i + 1 ] ;
}
}
}
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 ) ;