summaryrefslogtreecommitdiff
path: root/engine/disp_interface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/disp_interface.cpp')
-rw-r--r--engine/disp_interface.cpp1469
1 files changed, 1469 insertions, 0 deletions
diff --git a/engine/disp_interface.cpp b/engine/disp_interface.cpp
new file mode 100644
index 0000000..da6ea46
--- /dev/null
+++ b/engine/disp_interface.cpp
@@ -0,0 +1,1469 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=====================================================================================//
+
+#include "render_pch.h"
+#include "decal_private.h"
+#include "disp_defs.h"
+#include "disp.h"
+#include "gl_model_private.h"
+#include "gl_matsysiface.h"
+#include "gl_cvars.h"
+#include "gl_rsurf.h"
+#include "gl_lightmap.h"
+#include "con_nprint.h"
+#include "surfinfo.h"
+#include "Overlay.h"
+#include "cl_main.h"
+#include "r_decal.h"
+#include "materialsystem/materialsystem_config.h"
+
+#include "tier0/vprof.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// ----------------------------------------------------------------------------- //
+// Shadow decals + fragments
+// ----------------------------------------------------------------------------- //
+static CUtlLinkedList< CDispShadowDecal, DispShadowHandle_t, true > s_DispShadowDecals;
+static CUtlLinkedList< CDispShadowFragment, DispShadowFragmentHandle_t, true > s_DispShadowFragments;
+static CUtlLinkedList< CDispDecal, DispShadowHandle_t, true > s_DispDecals;
+static CUtlLinkedList< CDispDecalFragment, DispShadowFragmentHandle_t, true > s_DispDecalFragments;
+
+void CDispInfo::GetIntersectingSurfaces( GetIntersectingSurfaces_Struct *pStruct )
+{
+ if ( !m_Verts.Count() || !m_nIndices )
+ return;
+
+ // Walk through all of our triangles and add them one by one.
+ SurfInfo *pOut = &pStruct->m_pInfos[ pStruct->m_nSetInfos ];
+ for ( int iVert=0; iVert < m_MeshReader.NumIndices(); iVert += 3 )
+ {
+ // Is the list going to overflow?
+ if ( pStruct->m_nSetInfos >= pStruct->m_nMaxInfos )
+ break;
+
+ Vector const &a = m_MeshReader.Position( m_MeshReader.Index(iVert+0) - m_iVertOffset );
+ Vector const &b = m_MeshReader.Position( m_MeshReader.Index(iVert+1) - m_iVertOffset );
+ Vector const &c = m_MeshReader.Position( m_MeshReader.Index(iVert+2) - m_iVertOffset );
+
+ // Get the boundaries.
+ Vector vMin;
+ VectorMin( a, b, vMin );
+ VectorMin( c, vMin, vMin );
+
+ Vector vMax;
+ VectorMax( a, b, vMax );
+ VectorMax( c, vMax, vMax );
+
+ // See if it touches the sphere.
+ int iDim;
+ for ( iDim=0; iDim < 3; iDim++ )
+ {
+ if ( ((*pStruct->m_pCenter)[iDim]+pStruct->m_Radius) < vMin[iDim] ||
+ ((*pStruct->m_pCenter)[iDim]-pStruct->m_Radius) > vMax[iDim] )
+ {
+ break;
+ }
+ }
+
+ if ( iDim == 3 )
+ {
+ // Couldn't reject the sphere in the loop above, so add this surface.
+ pOut->m_nVerts = 3;
+ pOut->m_Verts[0] = a;
+ pOut->m_Verts[1] = b;
+ pOut->m_Verts[2] = c;
+ pOut->m_Plane.m_Normal = ( c - a ).Cross( b - a );
+ VectorNormalize( pOut->m_Plane.m_Normal );
+ pOut->m_Plane.m_Dist = pOut->m_Plane.m_Normal.Dot( a );
+
+ ++pStruct->m_nSetInfos;
+ ++pOut;
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------- //
+// CDispInfo implementation of IDispInfo.
+// ----------------------------------------------------------------------------- //
+void CDispInfo::RenderWireframeInLightmapPage( int pageId )
+{
+#ifndef SWDS
+ // render displacement as wireframe into lightmap pages
+ SurfaceHandle_t surfID = GetParent();
+
+ Assert( ( MSurf_MaterialSortID( surfID ) >= 0 ) && ( MSurf_MaterialSortID( surfID ) < g_WorldStaticMeshes.Count() ) );
+
+ if( materialSortInfoArray[MSurf_MaterialSortID( surfID ) ].lightmapPageID != pageId )
+ return;
+
+ Shader_DrawLightmapPageSurface( surfID, 0.0f, 0.0f, 1.0f );
+#endif
+}
+
+
+void CDispInfo::GetBoundingBox( Vector& bbMin, Vector& bbMax )
+{
+ bbMin = m_BBoxMin;
+ bbMax = m_BBoxMax;
+}
+
+
+void CDispInfo::SetParent( SurfaceHandle_t surfID )
+{
+ m_ParentSurfID = surfID;
+}
+
+
+// returns surfID
+SurfaceHandle_t CDispInfo::GetParent( void )
+{
+ return m_ParentSurfID;
+}
+
+
+unsigned int CDispInfo::ComputeDynamicLightMask( dlight_t *pLights )
+{
+ int lightMask = 0;
+
+#ifndef SWDS
+ if( !IS_SURF_VALID( m_ParentSurfID ) )
+ {
+ Assert( !"CDispInfo::ComputeDynamicLightMask: no parent surface" );
+ return 0;
+ }
+
+ for ( int lnum = 0, testBit = 1, mask = r_dlightactive; lnum < MAX_DLIGHTS && mask != 0; lnum++, mask >>= 1, testBit <<= 1 )
+ {
+ if ( mask & 1 )
+ {
+ // not lit by this light
+ if ( !(MSurf_DLightBits( m_ParentSurfID ) & testBit ) )
+ continue;
+
+ // This light doesn't affect the world
+ if ( pLights[lnum].flags & DLIGHT_NO_WORLD_ILLUMINATION)
+ continue;
+
+ // This is used to ensure a maximum number of dlights in a frame
+ if ( !R_CanUseVisibleDLight( lnum ) )
+ continue;
+
+ lightMask |= testBit;
+ }
+ }
+#endif
+ return lightMask;
+}
+
+void CDispInfo::AddDynamicLights( dlight_t *pLights, unsigned int mask )
+{
+#ifndef SWDS
+ if( !IS_SURF_VALID( m_ParentSurfID ) )
+ {
+ Assert( !"CDispInfo::AddDynamicLights: no parent surface" );
+ return;
+ }
+
+ for ( int lnum = 0; lnum < MAX_DLIGHTS && mask != 0; lnum++, mask >>= 1 )
+ {
+ if ( mask & 1 )
+ {
+ if ( (pLights[lnum].flags & DLIGHT_DISPLACEMENT_MASK) == 0)
+ {
+ if( NumLightMaps() == 1 )
+ {
+ AddSingleDynamicLight( pLights[lnum] );
+ }
+ else
+ {
+ AddSingleDynamicLightBumped( pLights[lnum] );
+ }
+ }
+ else
+ {
+ AddSingleDynamicAlphaLight( pLights[lnum]);
+ }
+ }
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Allocates fragments...
+//-----------------------------------------------------------------------------
+CDispDecalFragment* CDispInfo::AllocateDispDecalFragment( DispDecalHandle_t h, int nVerts )
+{
+ DispDecalFragmentHandle_t f = s_DispDecalFragments.Alloc(true);
+ s_DispDecalFragments.LinkBefore( s_DispDecals[h].m_FirstFragment, f );
+ s_DispDecals[h].m_FirstFragment = f;
+ CDispDecalFragment* pf = &s_DispDecalFragments[f];
+
+ // Initialize the vert count:
+ pf->m_nVerts = nVerts;
+ pf->m_pVerts = new CDecalVert[nVerts];
+
+ return pf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears decal fragment lists
+//-----------------------------------------------------------------------------
+void CDispInfo::ClearDecalFragments( DispDecalHandle_t h )
+{
+ // Iterate over all fragments associated with each shadow decal
+ CDispDecal& decal = s_DispDecals[h];
+ DispDecalFragmentHandle_t f = decal.m_FirstFragment;
+ DispDecalFragmentHandle_t next;
+
+ while( f != DISP_DECAL_FRAGMENT_HANDLE_INVALID )
+ {
+ next = s_DispDecalFragments.Next(f);
+ s_DispDecalFragments.Free(f); // Destructs the decal, freeing the memory.
+ f = next;
+ }
+
+ // Blat out the list
+ decal.m_FirstFragment = DISP_DECAL_FRAGMENT_HANDLE_INVALID;
+
+ // Mark is as not computed
+ decal.m_Flags &= ~CDispDecalBase::FRAGMENTS_COMPUTED;
+
+ // Update the number of triangles in the decal
+ decal.m_nTris = 0;
+ decal.m_nVerts = 0;
+}
+
+void CDispInfo::ClearAllDecalFragments()
+{
+ // Iterate over all shadow decals on the displacement
+ DispDecalHandle_t h = m_FirstDecal;
+ while( h != DISP_SHADOW_HANDLE_INVALID )
+ {
+ ClearDecalFragments( h );
+ h = s_DispDecals.Next(h);
+ }
+}
+
+// ----------------------------------------------------------------------------- //
+// Add/remove decals
+// ----------------------------------------------------------------------------- //
+DispDecalHandle_t CDispInfo::NotifyAddDecal( decal_t *pDecal, float flSize )
+{
+ // Create a new decal, link it in
+ DispDecalHandle_t h = s_DispDecals.Alloc( true );
+ if ( h != s_DispDecals.InvalidIndex() )
+ {
+ int nDecalCount = 0;
+ int iDecal = m_FirstDecal;
+ int iLastDecal = s_DispDecals.InvalidIndex();
+ while( iDecal != s_DispDecals.InvalidIndex() )
+ {
+ iLastDecal = iDecal;
+ iDecal = s_DispDecals.Next( iDecal );
+ ++nDecalCount;
+ }
+
+#ifndef SWDS
+ if ( nDecalCount >= MAX_DISP_DECALS )
+ {
+ R_DecalUnlink( s_DispDecals[iLastDecal].m_pDecal, host_state.worldbrush );
+ }
+#endif
+
+ s_DispDecals.LinkBefore( m_FirstDecal, h );
+ m_FirstDecal = h;
+
+ CDispDecal *pDispDecal = &s_DispDecals[h];
+ pDispDecal->m_pDecal = pDecal;
+ pDispDecal->m_FirstFragment = DISP_DECAL_FRAGMENT_HANDLE_INVALID;
+ pDispDecal->m_nVerts = 0;
+ pDispDecal->m_nTris = 0;
+ pDispDecal->m_flSize = flSize;
+
+ // Setup a basis for it.
+ CDecalVert *pOutVerts = NULL;
+ R_SetupDecalClip( pOutVerts, pDispDecal->m_pDecal, MSurf_Plane( m_ParentSurfID ).normal, pDispDecal->m_pDecal->material,
+ pDispDecal->m_TextureSpaceBasis, pDispDecal->m_DecalWorldScale );
+
+ // Recurse and precalculate which nodes this thing can touch.
+ SetupDecalNodeIntersect( m_pPowerInfo->m_RootNode, 0, pDispDecal, 0 );
+ }
+
+ return h;
+}
+
+void CDispInfo::NotifyRemoveDecal( DispDecalHandle_t h )
+{
+ // Any fragments we got we don't need
+ ClearDecalFragments(h);
+
+ // Reset the head of the list
+ if (m_FirstDecal == h)
+ m_FirstDecal = s_DispDecals.Next(h);
+
+ // Blow away the decal
+ s_DispDecals.Free( h );
+}
+
+
+//-----------------------------------------------------------------------------
+// Allocates fragments...
+//-----------------------------------------------------------------------------
+CDispShadowFragment* CDispInfo::AllocateShadowDecalFragment( DispShadowHandle_t h, int nCount )
+{
+ DispShadowFragmentHandle_t f = s_DispShadowFragments.Alloc(true);
+ s_DispShadowFragments.LinkBefore( s_DispShadowDecals[h].m_FirstFragment, f );
+ s_DispShadowDecals[h].m_FirstFragment = f;
+ CDispShadowFragment* pf = &s_DispShadowFragments[f];
+ pf->m_nVerts = nCount;
+ pf->m_ShadowVerts = new ShadowVertex_t[nCount];
+ return pf;
+}
+
+
+//-----------------------------------------------------------------------------
+// Clears shadow decal fragment lists
+//-----------------------------------------------------------------------------
+void CDispInfo::ClearShadowDecalFragments( DispShadowHandle_t h )
+{
+ // Iterate over all fragments associated with each shadow decal
+ CDispShadowDecal& decal = s_DispShadowDecals[h];
+ DispShadowFragmentHandle_t f = decal.m_FirstFragment;
+ DispShadowFragmentHandle_t next;
+ while( f != DISP_SHADOW_FRAGMENT_HANDLE_INVALID )
+ {
+ next = s_DispShadowFragments.Next(f);
+ s_DispShadowFragments.Free(f);
+ f = next;
+ }
+
+ // Blat out the list
+ decal.m_FirstFragment = DISP_SHADOW_FRAGMENT_HANDLE_INVALID;
+
+ // Mark is as not computed
+ decal.m_Flags &= ~CDispDecalBase::FRAGMENTS_COMPUTED;
+
+ // Update the number of triangles in the decal
+ decal.m_nTris = 0;
+ decal.m_nVerts = 0;
+}
+
+void CDispInfo::ClearAllShadowDecalFragments()
+{
+ // Iterate over all shadow decals on the displacement
+ DispShadowHandle_t h = m_FirstShadowDecal;
+ while( h != DISP_SHADOW_HANDLE_INVALID )
+ {
+ ClearShadowDecalFragments( h );
+ h = s_DispShadowDecals.Next(h);
+ }
+}
+
+
+// ----------------------------------------------------------------------------- //
+// Add/remove shadow decals
+// ----------------------------------------------------------------------------- //
+DispShadowHandle_t CDispInfo::AddShadowDecal( ShadowHandle_t shadowHandle )
+{
+ // Create a new shadow decal, link it in
+ DispShadowHandle_t h = s_DispShadowDecals.Alloc( true );
+ s_DispShadowDecals.LinkBefore( m_FirstShadowDecal, h );
+ m_FirstShadowDecal = h;
+
+ CDispShadowDecal* pShadowDecal = &s_DispShadowDecals[h];
+ pShadowDecal->m_nTris = 0;
+ pShadowDecal->m_nVerts = 0;
+ pShadowDecal->m_Shadow = shadowHandle;
+ pShadowDecal->m_FirstFragment = DISP_SHADOW_FRAGMENT_HANDLE_INVALID;
+
+ return h;
+}
+
+void CDispInfo::RemoveShadowDecal( DispShadowHandle_t h )
+{
+ // Any fragments we got we don't need
+ ClearShadowDecalFragments(h);
+
+ // Reset the head of the list
+ if (m_FirstShadowDecal == h)
+ m_FirstShadowDecal = s_DispShadowDecals.Next(h);
+
+ // Blow away the decal
+ s_DispShadowDecals.Free( h );
+}
+
+
+// ----------------------------------------------------------------------------- //
+// This little beastie generate decal fragments
+// ----------------------------------------------------------------------------- //
+void CDispInfo::GenerateDecalFragments_R( CVertIndex const &nodeIndex,
+ int iNodeBitIndex, unsigned short decalHandle, CDispDecalBase *pDispDecal, int iLevel )
+{
+ // Get the node info for this node...
+ Assert( iNodeBitIndex < m_pPowerInfo->m_NodeCount );
+ DispNodeInfo_t const& nodeInfo = m_pNodeInfo[iNodeBitIndex];
+
+ int iNodeIndex = VertIndex( nodeIndex );
+
+ // Don't bother adding decals if the node doesn't have decal info.
+ if( !pDispDecal->m_NodeIntersect.Get( iNodeBitIndex ) )
+ return;
+
+ // Recurse into child nodes, but only if they have triangles.
+ if ( ( iLevel+1 < m_Power ) && (nodeInfo.m_Flags & DispNodeInfo_t::CHILDREN_HAVE_TRIANGLES) )
+ {
+ int iChildNodeBit = iNodeBitIndex + 1;
+ for( int iChild=0; iChild < 4; iChild++ )
+ {
+ CVertIndex const &childNode = m_pPowerInfo->m_pChildVerts[iNodeIndex].m_Verts[iChild];
+
+ bool bActiveChild = m_ActiveVerts.Get( VertIndex( childNode ) ) != 0;
+ if ( bActiveChild )
+ GenerateDecalFragments_R( childNode, iChildNodeBit, decalHandle, pDispDecal, iLevel + 1
+ );
+ iChildNodeBit += m_pPowerInfo->m_NodeIndexIncrements[iLevel];
+ }
+ }
+
+ // Create the decal fragments on the node triangles
+ bool isShadow = (pDispDecal->m_Flags & CDispDecalBase::DECAL_SHADOW) != 0;
+
+ int index = nodeInfo.m_FirstTesselationIndex;
+ for ( int i = 0; i < nodeInfo.m_Count; i += 3 )
+ {
+ if (isShadow)
+ TestAddDecalTri( index + i, decalHandle, static_cast<CDispShadowDecal*>(pDispDecal)
+ );
+ else
+ TestAddDecalTri( index + i, decalHandle, static_cast<CDispDecal*>(pDispDecal) );
+ }
+}
+
+void CDispInfo::GenerateDecalFragments( CVertIndex const &nodeIndex,
+ int iNodeBitIndex, unsigned short decalHandle, CDispDecalBase *pDispDecal )
+{
+ GenerateDecalFragments_R( nodeIndex, iNodeBitIndex, decalHandle, pDispDecal, 0 );
+ pDispDecal->m_Flags |= CDispDecalBase::FRAGMENTS_COMPUTED;
+}
+
+
+
+// ----------------------------------------------------------------------------- //
+// Compute shadow fragments for a particular shadow
+// ----------------------------------------------------------------------------- //
+bool CDispInfo::ComputeShadowFragments( DispShadowHandle_t h, int& vertexCount, int& indexCount )
+{
+ CDispShadowDecal* pShadowDecal = &s_DispShadowDecals[h];
+
+ // If we already have fragments, that means the data's already cached.
+ if ((pShadowDecal->m_Flags & CDispDecalBase::FRAGMENTS_COMPUTED) != 0)
+ {
+ vertexCount = pShadowDecal->m_nVerts;
+ indexCount = 3 * pShadowDecal->m_nTris;
+ return true;
+ }
+
+ // Check to see if the bitfield wasn't computed. If so, compute it.
+ // This should happen whenever the shadow moves
+#ifndef SWDS
+ if ((pShadowDecal->m_Flags & CDispDecalBase::NODE_BITFIELD_COMPUTED ) == 0)
+ {
+ // First, determine the nodes that the shadow decal should affect
+ ShadowInfo_t const& info = g_pShadowMgr->GetInfo( pShadowDecal->m_Shadow );
+ SetupDecalNodeIntersect(
+ m_pPowerInfo->m_RootNode,
+ 0, // node bit index into CDispDecal::m_NodeIntersects
+ pShadowDecal,
+ &info
+ );
+ }
+#endif
+
+ // Check to see if there are any bits set in the bitfield, If not,
+ // this displacement should be taken out of the list of potential displacements
+ if (pShadowDecal->m_Flags & CDispDecalBase::NO_INTERSECTION)
+ return false;
+
+ // Now that we have the bitfield, compute the fragments
+ // It may happen that we have invalid fragments but valid bitfield.
+ // This can happen when a retesselation occurs
+ Assert( pShadowDecal->m_nTris == 0);
+ Assert( pShadowDecal->m_FirstFragment == DISP_SHADOW_FRAGMENT_HANDLE_INVALID);
+
+ GenerateDecalFragments( m_pPowerInfo->m_RootNode, 0, h, pShadowDecal );
+
+ // Compute the index + vertex counts
+ vertexCount = pShadowDecal->m_nVerts;
+ indexCount = 3 * pShadowDecal->m_nTris;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Generate vertex lists
+//-----------------------------------------------------------------------------
+
+bool CDispInfo::GetTag()
+{
+ return m_Tag == m_pDispArray->m_CurTag;
+}
+
+
+void CDispInfo::SetTag()
+{
+ m_Tag = m_pDispArray->m_CurTag;
+}
+
+//-----------------------------------------------------------------------------
+// Helpers for global functions.
+//-----------------------------------------------------------------------------
+
+// This function crashes in release without this pragma.
+#if !defined( _X360 )
+#pragma optimize( "g", off )
+#endif
+#pragma optimize( "", on )
+
+void DispInfo_BuildPrimLists( int nSortGroup, SurfaceHandle_t *pList, int listCount, bool bDepthOnly,
+ CDispInfo *visibleDisps[MAX_MAP_DISPINFO], int &nVisibleDisps )
+{
+ VPROF("DispInfo_BuildPrimLists");
+
+ nVisibleDisps = 0;
+ bool bDebugConvars = !bDepthOnly ? DispInfoRenderDebugModes() : false;
+ for( int i = 0; i < listCount; i++ )
+ {
+ CDispInfo *pDisp = static_cast<CDispInfo*>( pList[i]->pDispInfo );
+ if( !pDisp->Render( pDisp->m_pMesh, bDebugConvars ) )
+ continue;
+
+ // Add it to the list of visible displacements.
+ if( nVisibleDisps < MAX_MAP_DISPINFO )
+ {
+ visibleDisps[nVisibleDisps++] = pDisp;
+ }
+
+ if ( bDepthOnly )
+ continue;
+
+#ifndef SWDS
+ OverlayMgr()->AddFragmentListToRenderList( nSortGroup, MSurf_OverlayFragmentList( pList[i] ), true );
+#endif
+ }
+}
+
+ConVar disp_dynamic( "disp_dynamic", "0" );
+
+void DispInfo_DrawPrimLists( ERenderDepthMode DepthMode )
+{
+#ifndef SWDS
+ VPROF("DispInfo_DrawPrimLists");
+
+ int nDispGroupsSize = g_DispGroups.Size();
+
+ int nFullbright = g_pMaterialSystemConfig->nFullbright;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ for( int iGroup=0; iGroup < nDispGroupsSize; iGroup++ )
+ {
+ CDispGroup *pGroup = g_DispGroups[iGroup];
+ if( pGroup->m_nVisible == 0 )
+ continue;
+
+ if ( DepthMode != DEPTH_MODE_NORMAL )
+ {
+ // Select proper override material
+ int nAlphaTest = (int) pGroup->m_pMaterial->IsAlphaTested();
+ int nNoCull = (int) pGroup->m_pMaterial->IsTwoSided();
+ IMaterial *pDepthWriteMaterial;
+ if ( DepthMode == DEPTH_MODE_SHADOW )
+ {
+ pDepthWriteMaterial = g_pMaterialDepthWrite[nAlphaTest][nNoCull];
+ }
+ else
+ {
+ pDepthWriteMaterial = g_pMaterialSSAODepthWrite[nAlphaTest][nNoCull];
+ }
+
+ if ( nAlphaTest == 1 )
+ {
+ static unsigned int originalTextureVarCache = 0;
+ IMaterialVar *pOriginalTextureVar = pGroup->m_pMaterial->FindVarFast( "$basetexture", &originalTextureVarCache );
+ static unsigned int originalTextureFrameVarCache = 0;
+ IMaterialVar *pOriginalTextureFrameVar = pGroup->m_pMaterial->FindVarFast( "$frame", &originalTextureFrameVarCache );
+ static unsigned int originalAlphaRefCache = 0;
+ IMaterialVar *pOriginalAlphaRefVar = pGroup->m_pMaterial->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
+
+ static unsigned int textureVarCache = 0;
+ IMaterialVar *pTextureVar = pDepthWriteMaterial->FindVarFast( "$basetexture", &textureVarCache );
+ static unsigned int textureFrameVarCache = 0;
+ IMaterialVar *pTextureFrameVar = pDepthWriteMaterial->FindVarFast( "$frame", &textureFrameVarCache );
+ static unsigned int alphaRefCache = 0;
+ IMaterialVar *pAlphaRefVar = pDepthWriteMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
+
+ if( pTextureVar && pOriginalTextureVar )
+ {
+ pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
+ }
+
+ if( pTextureFrameVar && pOriginalTextureFrameVar )
+ {
+ pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
+ }
+
+ if( pAlphaRefVar && pOriginalAlphaRefVar )
+ {
+ pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
+ }
+ }
+
+ pRenderContext->Bind( pDepthWriteMaterial );
+ }
+ else
+ {
+ pRenderContext->Bind( pGroup->m_pMaterial );
+ }
+
+ if( nFullbright != 1 && DepthMode == DEPTH_MODE_NORMAL )
+ {
+ pRenderContext->BindLightmapPage( pGroup->m_LightmapPageID );
+ }
+ else
+ {
+ // If this code gets removed again, I'm chopping fingers off!
+ if( pGroup->m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS ) )
+ {
+ pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE_BUMP );
+ }
+ else
+ {
+ pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
+ }
+ }
+
+ int nMeshesSize = pGroup->m_Meshes.Size();
+
+ for( int iMesh=0; iMesh < nMeshesSize; iMesh++ )
+ {
+ CGroupMesh *pMesh = pGroup->m_Meshes[iMesh];
+ if( pMesh->m_nVisible == 0 )
+ continue;
+
+ if ( disp_dynamic.GetInt() )
+ {
+ for ( int iVisible=0; iVisible < pMesh->m_nVisible; iVisible++ )
+ {
+ pMesh->m_VisibleDisps[iVisible]->SpecifyDynamicMesh();
+ }
+ }
+ else
+ {
+ pMesh->m_pMesh->Draw( pMesh->m_Visible.Base(), pMesh->m_nVisible );
+ }
+
+ pMesh->m_nVisible = 0;
+ }
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void DecalDispSurfacesInit( void )
+{
+#ifndef SWDS
+ g_aDispDecalSortPool.RemoveAll();
+ ++g_nDispDecalSortCheckCount;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Batch up visible displacement decals and build them if necessary.
+//-----------------------------------------------------------------------------
+void DispInfo_BatchDecals( CDispInfo **pVisibleDisps, int nVisibleDisps )
+{
+#ifndef SWDS
+
+ // Performance analysis.
+ VPROF( "DispInfo_BatchDecals" );
+
+ // Increment the decal sort check count and clear the pool.
+ DecalDispSurfacesInit();
+
+ // Do we have any visible displacements?
+ if( !nVisibleDisps )
+ return;
+
+ for( int iDisp = 0; iDisp < nVisibleDisps; ++iDisp )
+ {
+ // Get the current visible displacement and see if it has any decals.
+ CDispInfo *pDisp = pVisibleDisps[iDisp];
+ if( pDisp->m_FirstDecal == DISP_DECAL_HANDLE_INVALID )
+ continue;
+
+ DispDecalHandle_t hDecal = pDisp->m_FirstDecal;
+ while ( hDecal != DISP_DECAL_HANDLE_INVALID )
+ {
+ CDispDecal &decal = s_DispDecals[hDecal];
+
+ // Create the displacement fragment if necessary.
+ if ( ( decal.m_Flags & CDispDecalBase::FRAGMENTS_COMPUTED ) == 0 )
+ {
+ pDisp->GenerateDecalFragments( pDisp->m_pPowerInfo->m_RootNode, 0, hDecal, &decal );
+ }
+
+ // Don't draw if there's no triangles.
+ if ( decal.m_nTris == 0 )
+ {
+ hDecal = s_DispDecals.Next( hDecal );
+ continue;
+ }
+
+ // Get the decal material.
+ IMaterial *pMaterial = decal.m_pDecal->material;
+ if ( !pMaterial )
+ {
+ DevMsg( "DispInfo_BatchDecals: material is NULL, decal %i.\n", hDecal );
+ hDecal = s_DispDecals.Next( hDecal );
+ continue;
+ }
+
+ // Lightmap decals.
+ int iTreeType = -1;
+ if ( pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP ) )
+ {
+ // Permanent lightmapped decals.
+ if ( decal.m_pDecal->flags & FDECAL_PERMANENT )
+ {
+ iTreeType = PERMANENT_LIGHTMAP;
+ }
+ // Non-permanent lightmapped decals.
+ else
+ {
+ iTreeType = LIGHTMAP;
+ }
+ }
+ // Non-lightmapped decals.
+ else
+ {
+ iTreeType = NONLIGHTMAP;
+ }
+
+ // There is only one group at a time.
+ int iGroup = 0;
+
+ int iPool = g_aDispDecalSortPool.Alloc( true );
+ g_aDispDecalSortPool[iPool] = decal.m_pDecal;
+
+ int iSortTree = decal.m_pDecal->m_iSortTree;
+ int iSortMaterial = decal.m_pDecal->m_iSortMaterial;
+
+ DecalMaterialBucket_t &materialBucket = g_aDispDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType].Element( iSortMaterial );
+ if ( materialBucket.m_nCheckCount == g_nDispDecalSortCheckCount )
+ {
+ int iHead = materialBucket.m_iHead;
+ g_aDispDecalSortPool.LinkBefore( iHead, iPool );
+ }
+
+ materialBucket.m_iHead = iPool;
+ materialBucket.m_nCheckCount = g_nDispDecalSortCheckCount;
+
+ hDecal = s_DispDecals.Next( hDecal );
+ }
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+inline void DispInfo_DrawDecalMeshList( DecalMeshList_t &meshList )
+{
+ CMatRenderContextPtr pRenderContext( materials );
+
+ bool bMatFullbright = ( g_pMaterialSystemConfig->nFullbright == 1 );
+
+ int nBatchCount = meshList.m_aBatches.Count();
+ for ( int iBatch = 0; iBatch < nBatchCount; ++iBatch )
+ {
+ const DecalBatchList_t &batch = meshList.m_aBatches[iBatch];
+
+ if ( !bMatFullbright )
+ {
+ pRenderContext->BindLightmapPage( batch.m_iLightmapPage );
+ }
+ else
+ {
+ pRenderContext->BindLightmapPage( MATERIAL_SYSTEM_LIGHTMAP_PAGE_WHITE );
+ }
+
+ pRenderContext->Bind( batch.m_pMaterial, batch.m_pProxy );
+ meshList.m_pMesh->Draw( batch.m_iStartIndex, batch.m_nIndexCount );
+ }
+}
+
+void DispInfo_DrawDecalsGroup( int iGroup, int iTreeType )
+{
+#ifndef SWDS
+ CMatRenderContextPtr pRenderContext( materials );
+
+ DecalMeshList_t meshList;
+ CMeshBuilder meshBuilder;
+
+ int nVertCount = 0;
+ int nIndexCount = 0;
+
+
+ int nDecalSortMaxVerts;
+ int nDecalSortMaxIndices;
+ R_DecalsGetMaxMesh( pRenderContext, nDecalSortMaxVerts, nDecalSortMaxIndices );
+
+ bool bMatWireframe = ShouldDrawInWireFrameMode();
+
+ int nSortTreeCount = g_aDispDecalSortTrees.Count();
+ for ( int iSortTree = 0; iSortTree < nSortTreeCount; ++iSortTree )
+ {
+ bool bMeshInit = true;
+
+ const CUtlVector<DecalMaterialBucket_t> &materialBucketList = g_aDispDecalSortTrees[iSortTree].m_aDecalSortBuckets[iGroup][iTreeType];
+ int nBucketCount = materialBucketList.Count();
+ for ( int iBucket = 0; iBucket < nBucketCount; ++iBucket )
+ {
+ if ( materialBucketList.Element( iBucket ).m_nCheckCount != g_nDispDecalSortCheckCount )
+ continue;
+
+ int iHead = materialBucketList.Element( iBucket ).m_iHead;
+ if ( !g_aDispDecalSortPool.IsValidIndex( iHead ) )
+ continue;
+
+ decal_t *pDecalHead = g_aDispDecalSortPool.Element( iHead );
+ Assert( pDecalHead->material );
+ if ( !pDecalHead->material )
+ continue;
+
+ // Vertex format.
+ VertexFormat_t vertexFormat = pDecalHead->material->GetVertexFormat();
+ if ( vertexFormat == 0 )
+ continue;
+
+ // New bucket = new batch.
+ DecalBatchList_t *pBatch = NULL;
+ bool bBatchInit = true;
+
+ int nCount;
+ int iElement = iHead;
+ while ( iElement != g_aDispDecalSortPool.InvalidIndex() )
+ {
+ decal_t *pDecal = g_aDispDecalSortPool.Element( iElement );
+ iElement = g_aDispDecalSortPool.Next( iElement );
+
+ CDispDecal &decal = s_DispDecals[pDecal->m_DispDecal];
+
+ // Now draw all the fragments with this material.
+ IMaterial* pMaterial = decal.m_pDecal->material;
+ if ( !pMaterial )
+ {
+ DevMsg( "DispInfo_DrawDecalsGroup: material is NULL decal %i.\n", pDecal->m_DispDecal );
+ continue;
+ }
+
+ DispDecalFragmentHandle_t hFrag = decal.m_FirstFragment;
+ while ( hFrag != DISP_DECAL_FRAGMENT_HANDLE_INVALID )
+ {
+ CDispDecalFragment &fragment = s_DispDecalFragments[hFrag];
+ hFrag = s_DispDecalFragments.Next( hFrag );
+ nCount = fragment.m_nVerts;
+
+ // Overflow - new mesh, batch.
+ if ( ( ( nVertCount + nCount ) >= nDecalSortMaxVerts ) || ( nIndexCount + ( nCount - 2 ) >= nDecalSortMaxIndices ) )
+ {
+ // Finish this batch.
+ if ( pBatch )
+ {
+ pBatch->m_nIndexCount = ( nIndexCount - pBatch->m_iStartIndex );
+ }
+
+ // End the mesh building phase and render.
+ meshBuilder.End();
+ DispInfo_DrawDecalMeshList( meshList );
+
+ // Reset.
+ bMeshInit = true;
+ pBatch = NULL;
+ bBatchInit = true;
+ }
+
+ // Create the mesh.
+ if ( bMeshInit )
+ {
+ // Reset the mesh list.
+ meshList.m_pMesh = NULL;
+ meshList.m_aBatches.RemoveAll();
+
+ if ( !bMatWireframe )
+ {
+ meshList.m_pMesh = pRenderContext->GetDynamicMesh( false, NULL, NULL, pDecalHead->material );
+ }
+ else
+ {
+ meshList.m_pMesh = pRenderContext->GetDynamicMesh( false, NULL, NULL, g_materialDecalWireframe );
+ }
+
+ meshBuilder.Begin( meshList.m_pMesh, MATERIAL_TRIANGLES, nDecalSortMaxVerts, nDecalSortMaxIndices );
+
+ nVertCount = 0;
+ nIndexCount = 0;
+
+ bMeshInit = false;
+ }
+
+ // Create the batch.
+ if ( bBatchInit )
+ {
+ // Create a batch for this bucket = material/lightmap pair.
+ int iBatchList = meshList.m_aBatches.AddToTail();
+ pBatch = &meshList.m_aBatches[iBatchList];
+ pBatch->m_iStartIndex = nIndexCount;
+
+ if ( !bMatWireframe )
+ {
+ pBatch->m_pMaterial = pDecalHead->material;
+ pBatch->m_pProxy = pDecalHead->userdata;
+ pBatch->m_iLightmapPage = materialSortInfoArray[MSurf_MaterialSortID( pDecalHead->surfID )].lightmapPageID;
+ }
+ else
+ {
+ pBatch->m_pMaterial = g_materialDecalWireframe;
+ }
+
+ bBatchInit = false;
+ }
+ Assert ( pBatch );
+
+ // Setup verts.
+ float flOffset = fragment.m_pDecal->lightmapOffset;
+ for ( int iVert = 0; iVert < fragment.m_nVerts; ++iVert )
+ {
+ const CDecalVert &vert = fragment.m_pVerts[iVert];
+
+ meshBuilder.Position3fv( vert.m_vPos.Base() );
+ // FIXME!! Really want the normal from the displacement, not from the base surface.
+ Vector &normal = MSurf_Plane( fragment.m_pDecal->surfID ).normal;
+ meshBuilder.Normal3fv( normal.Base() );
+ meshBuilder.Color4ub( fragment.m_pDecal->color.r, fragment.m_pDecal->color.g, fragment.m_pDecal->color.b, fragment.m_pDecal->color.a );
+ meshBuilder.TexCoord2f( 0, vert.m_ctCoords.x, vert.m_ctCoords.y );
+ meshBuilder.TexCoord2f( 1, vert.m_cLMCoords.x, vert.m_cLMCoords.y );
+ meshBuilder.TexCoord1f( 2, flOffset );
+ meshBuilder.AdvanceVertex();
+ }
+
+ // Setup indices.
+ int nTriCount = ( nCount - 2 );
+ CIndexBuilder &indexBuilder = meshBuilder;
+ indexBuilder.FastPolygon( nVertCount, nTriCount );
+
+ // Update counters.
+ nVertCount += nCount;
+ nIndexCount += ( nTriCount * 3 );
+ }
+
+ if ( pBatch )
+ {
+ pBatch->m_nIndexCount = ( nIndexCount - pBatch->m_iStartIndex );
+ }
+ }
+ }
+
+ if ( !bMeshInit )
+ {
+ meshBuilder.End();
+ DispInfo_DrawDecalMeshList( meshList );
+ }
+ }
+#endif
+}
+
+void DispInfo_DrawDecals( CDispInfo **visibleDisps, int nVisibleDisps )
+{
+#ifndef SWDS
+ VPROF( "DispInfo_DrawDecals" );
+
+ int iGroup = 0;
+
+ // Draw world decals.
+ DispInfo_DrawDecalsGroup( iGroup, PERMANENT_LIGHTMAP );
+
+ // Draw lightmapped non-world decals.
+ DispInfo_DrawDecalsGroup( iGroup, LIGHTMAP );
+
+ // Draw non-lit(mod2x) decals.
+ DispInfo_DrawDecalsGroup( iGroup, NONLIGHTMAP );
+#endif
+}
+
+void DispInfo_DrawDecals_Old( CDispInfo *visibleDisps[MAX_MAP_DISPINFO], int nVisibleDisps )
+{
+#ifndef SWDS
+// VPROF("DispInfo_DrawDecals");
+ if( !nVisibleDisps )
+ return;
+
+ int nTrisDrawn = 0;
+
+ CMatRenderContextPtr pRenderContext( materials );
+
+ // FIXME: We should bucket all decals (displacement + otherwise)
+ // and sort them by material enum id + lightmap
+ // To do this, we need to associate a sort index from 0-n for all
+ // decals we've seen this level. Then we add those decals to the
+ // appropriate search list, (sorted by lightmap id)?
+
+ for( int i=0; i < nVisibleDisps; i++ )
+ {
+ CDispInfo *pDisp = visibleDisps[i];
+
+ // Don't bother if there's no decals
+ if( pDisp->m_FirstDecal == DISP_DECAL_HANDLE_INVALID )
+ continue;
+
+ pRenderContext->BindLightmapPage( pDisp->m_pMesh->m_pGroup->m_LightmapPageID );
+
+ // At the moment, all decals in a single displacement are sorted by material
+ // so we get a little batching at least
+ DispDecalHandle_t d = pDisp->m_FirstDecal;
+ while( d != DISP_DECAL_HANDLE_INVALID )
+ {
+ CDispDecal& decal = s_DispDecals[d];
+
+ // Compute decal fragments if we haven't already....
+ if ((decal.m_Flags & CDispDecalBase::FRAGMENTS_COMPUTED) == 0)
+ {
+ pDisp->GenerateDecalFragments( pDisp->m_pPowerInfo->m_RootNode, 0, d, &decal );
+ }
+
+ // Don't draw if there's no triangles
+ if (decal.m_nTris == 0)
+ {
+ d = s_DispDecals.Next(d);
+ continue;
+ }
+
+ // Now draw all the fragments with this material.
+ IMaterial* pMaterial = decal.m_pDecal->material;
+
+ if ( !pMaterial )
+ {
+ DevMsg("DrawDecals: material is NULL fro decal %i.\n", d );
+ d = s_DispDecals.Next(d);
+ continue;
+ }
+
+ IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, pMaterial );
+
+ float matOffset[2], matScale[2];
+ pMaterial->GetMaterialOffset( matOffset );
+ pMaterial->GetMaterialScale( matScale );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, decal.m_nVerts, decal.m_nTris * 3 );
+
+ int baseIndex = 0;
+ DispDecalFragmentHandle_t f = decal.m_FirstFragment;
+ while (f != DISP_DECAL_FRAGMENT_HANDLE_INVALID)
+ {
+ CDispDecalFragment& fragment = s_DispDecalFragments[f];
+ int v;
+ for ( v = 0; v < fragment.m_nVerts - 2; ++v)
+ {
+ meshBuilder.Position3fv( fragment.m_pVerts[v].m_vPos.Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+
+ if ( pMaterial->InMaterialPage() )
+ {
+ meshBuilder.TexCoordSubRect2f( 0, fragment.m_pVerts[v].m_ctCoords.x, fragment.m_pVerts[v].m_ctCoords.y,
+ matOffset[0], matOffset[1], matScale[0], matScale[1] );
+ }
+ else
+ {
+ meshBuilder.TexCoord2f( 0, fragment.m_pVerts[v].m_ctCoords.x, fragment.m_pVerts[v].m_ctCoords.y );
+ }
+ meshBuilder.TexCoord2f( 1, fragment.m_pVerts[v].m_cLMCoords.x, fragment.m_pVerts[v].m_cLMCoords.y );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Index( baseIndex );
+ meshBuilder.AdvanceIndex();
+ meshBuilder.Index( v + baseIndex + 1 );
+ meshBuilder.AdvanceIndex();
+ meshBuilder.Index( v + baseIndex + 2 );
+ meshBuilder.AdvanceIndex();
+ }
+
+ meshBuilder.Position3fv( fragment.m_pVerts[v].m_vPos.Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ if ( pMaterial->InMaterialPage() )
+ {
+ meshBuilder.TexCoordSubRect2f( 0, fragment.m_pVerts[v].m_ctCoords.x, fragment.m_pVerts[v].m_ctCoords.y,
+ matOffset[0], matOffset[1], matScale[0], matScale[1] );
+ }
+ else
+ {
+ meshBuilder.TexCoord2f( 0, fragment.m_pVerts[v].m_ctCoords.x, fragment.m_pVerts[v].m_ctCoords.y );
+ }
+ meshBuilder.TexCoord2f( 1, fragment.m_pVerts[v].m_cLMCoords.x, fragment.m_pVerts[v].m_cLMCoords.y );
+ meshBuilder.AdvanceVertex();
+
+ ++v;
+ meshBuilder.Position3fv( fragment.m_pVerts[v].m_vPos.Base() );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ if ( pMaterial->InMaterialPage() )
+ {
+ meshBuilder.TexCoordSubRect2f( 0, fragment.m_pVerts[v].m_ctCoords.x, fragment.m_pVerts[v].m_ctCoords.y,
+ matOffset[0], matOffset[1], matScale[0], matScale[1] );
+ }
+ else
+ {
+ meshBuilder.TexCoord2f( 0, fragment.m_pVerts[v].m_ctCoords.x, fragment.m_pVerts[v].m_ctCoords.y );
+ }
+ meshBuilder.TexCoord2f( 1, fragment.m_pVerts[v].m_cLMCoords.x, fragment.m_pVerts[v].m_cLMCoords.y );
+ meshBuilder.AdvanceVertex();
+
+ baseIndex += fragment.m_nVerts;
+
+ f = s_DispDecalFragments.Next(f);
+ }
+ meshBuilder.End( false, true );
+
+ nTrisDrawn += decal.m_nTris * pMaterial->GetNumPasses();
+
+ d = s_DispDecals.Next(d);
+ }
+ }
+#endif
+}
+
+// ----------------------------------------------------------------------------- //
+// Adds shadow rendering data to a particular mesh builder
+// ----------------------------------------------------------------------------- //
+int DispInfo_AddShadowsToMeshBuilder( CMeshBuilder& meshBuilder, DispShadowHandle_t h, int baseIndex )
+{
+#ifdef SWDS
+ return 0;
+#else
+
+ ShadowDecalRenderInfo_t info;
+ CDispShadowDecal* pShadowDecal = &s_DispShadowDecals[h];
+ g_pShadowMgr->ComputeRenderInfo( &info, pShadowDecal->m_Shadow );
+
+ // It had better be computed by now...
+ Assert( pShadowDecal->m_Flags & CDispDecalBase::FRAGMENTS_COMPUTED );
+
+#ifdef _DEBUG
+ int triCount = 0;
+ int vertCount = 0;
+#endif
+
+ Vector2D texCoord;
+ unsigned char c;
+ DispShadowFragmentHandle_t f = pShadowDecal->m_FirstFragment;
+ while ( f != DISP_SHADOW_FRAGMENT_HANDLE_INVALID )
+ {
+ const CDispShadowFragment& fragment = s_DispShadowFragments[f];
+ const ShadowVertex_t *pShadowVert = fragment.m_ShadowVerts;
+
+ // Add in the vertices + indices, use two loops to minimize tests...
+ int i;
+ for ( i = 0; i < fragment.m_nVerts - 2; ++i, ++pShadowVert )
+ {
+ // Transform + offset the texture coords
+ Vector2DMultiply( pShadowVert->m_ShadowSpaceTexCoord.AsVector2D(), info.m_vTexSize, texCoord );
+ texCoord += info.m_vTexOrigin;
+ c = g_pShadowMgr->ComputeDarkness( pShadowVert->m_ShadowSpaceTexCoord.z, info );
+
+ meshBuilder.Position3fv( pShadowVert->m_Position.Base() );
+ meshBuilder.Color4ub( c, c, c, c );
+ meshBuilder.TexCoord2fv( 0, texCoord.Base() );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.FastIndex( baseIndex );
+ meshBuilder.FastIndex( i + baseIndex + 1 );
+ meshBuilder.FastIndex( i + baseIndex + 2 );
+ }
+
+ Vector2DMultiply( pShadowVert->m_ShadowSpaceTexCoord.AsVector2D(), info.m_vTexSize, texCoord );
+ texCoord += info.m_vTexOrigin;
+ c = g_pShadowMgr->ComputeDarkness( pShadowVert->m_ShadowSpaceTexCoord.z, info );
+ meshBuilder.Position3fv( pShadowVert->m_Position.Base() );
+ meshBuilder.Color4ub( c, c, c, c );
+ meshBuilder.TexCoord2fv( 0, texCoord.Base() );
+ meshBuilder.AdvanceVertex();
+ ++pShadowVert;
+
+ Vector2DMultiply( pShadowVert->m_ShadowSpaceTexCoord.AsVector2D(), info.m_vTexSize, texCoord );
+ texCoord += info.m_vTexOrigin;
+ c = g_pShadowMgr->ComputeDarkness( pShadowVert->m_ShadowSpaceTexCoord.z, info );
+ meshBuilder.Position3fv( pShadowVert->m_Position.Base() );
+ meshBuilder.Color4ub( c, c, c, c );
+ meshBuilder.TexCoord2fv( 0, texCoord.Base() );
+ meshBuilder.AdvanceVertex();
+
+ baseIndex += fragment.m_nVerts;
+ f = s_DispShadowFragments.Next(f);
+
+#ifdef _DEBUG
+ triCount += fragment.m_nVerts - 2;
+ vertCount += fragment.m_nVerts;
+#endif
+ }
+
+#ifdef _DEBUG
+ Assert( triCount == pShadowDecal->m_nTris );
+ Assert( vertCount == pShadowDecal->m_nVerts );
+#endif
+
+ return baseIndex;
+#endif
+}
+
+
+// ----------------------------------------------------------------------------- //
+// IDispInfo globals implementation.
+// ----------------------------------------------------------------------------- //
+
+void DispInfo_InitMaterialSystem()
+{
+}
+
+
+void DispInfo_ShutdownMaterialSystem()
+{
+}
+
+
+HDISPINFOARRAY DispInfo_CreateArray( int nElements )
+{
+ CDispArray *pRet = new CDispArray;
+
+ pRet->m_CurTag = 1;
+
+ pRet->m_nDispInfos = nElements;
+ if ( nElements )
+ {
+ pRet->m_pDispInfos = new CDispInfo[nElements];
+ }
+ else
+ {
+ pRet->m_pDispInfos = NULL;
+ }
+ for( int i=0; i < nElements; i++ )
+ pRet->m_pDispInfos[i].m_pDispArray = pRet;
+
+ return (HDISPINFOARRAY)pRet;
+}
+
+
+void DispInfo_DeleteArray( HDISPINFOARRAY hArray )
+{
+ CDispArray *pArray = static_cast<CDispArray*>( hArray );
+ if( !pArray )
+ return;
+
+ delete [] pArray->m_pDispInfos;
+ delete pArray;
+}
+
+
+IDispInfo* DispInfo_IndexArray( HDISPINFOARRAY hArray, int iElement )
+{
+ CDispArray *pArray = static_cast<CDispArray*>( hArray );
+ if( !pArray )
+ return NULL;
+
+ Assert( iElement >= 0 && iElement < pArray->m_nDispInfos );
+ return &pArray->m_pDispInfos[iElement];
+}
+
+int DispInfo_ComputeIndex( HDISPINFOARRAY hArray, IDispInfo* pInfo )
+{
+ CDispArray *pArray = static_cast<CDispArray*>( hArray );
+ if( !pArray )
+ return NULL;
+
+ int iElement = ((int)pInfo - (int)(pArray->m_pDispInfos)) / sizeof(CDispInfo);
+
+ Assert( iElement >= 0 && iElement < pArray->m_nDispInfos );
+ return iElement;
+}
+
+void DispInfo_ClearAllTags( HDISPINFOARRAY hArray )
+{
+ CDispArray *pArray = static_cast<CDispArray*>( hArray );
+ if( !pArray )
+ return;
+
+ ++pArray->m_CurTag;
+ if( pArray->m_CurTag == 0xFFFF )
+ {
+ // Reset all the tags.
+ pArray->m_CurTag = 1;
+ for( int i=0; i < pArray->m_nDispInfos; i++ )
+ pArray->m_pDispInfos[i].m_Tag = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Renders normals for the displacements
+//-----------------------------------------------------------------------------
+
+static void DispInfo_DrawChainNormals( SurfaceHandle_t *pList, int listCount )
+{
+#ifndef SWDS
+#ifdef _DEBUG
+ CMatRenderContextPtr pRenderContext( materials );
+
+ // Only do it in debug because we're only storing the info then
+ Vector p;
+
+ pRenderContext->Bind( g_pMaterialWireframeVertexColor );
+
+ for ( int i = 0; i < listCount; i++ )
+ {
+ CDispInfo *pDisp = static_cast<CDispInfo*>( pList[i]->pDispInfo );
+
+ int nVerts = pDisp->NumVerts();
+
+ IMesh *pMesh = pRenderContext->GetDynamicMesh( );
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, nVerts * 3 );
+
+ for( int iVert=0; iVert < nVerts; iVert++ )
+ {
+ CDispRenderVert* pVert = pDisp->GetVertex(iVert);
+ meshBuilder.Position3fv( pVert->m_vPos.Base() );
+ meshBuilder.Color3ub( 255, 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ VectorMA( pVert->m_vPos, 5.0f, pVert->m_vNormal, p );
+ meshBuilder.Position3fv( p.Base() );
+ meshBuilder.Color3ub( 255, 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pVert->m_vPos.Base() );
+ meshBuilder.Color3ub( 0, 255, 0 );
+ meshBuilder.AdvanceVertex();
+
+ VectorMA( pVert->m_vPos, 5.0f, pVert->m_vSVector, p );
+ meshBuilder.Position3fv( p.Base() );
+ meshBuilder.Color3ub( 0, 255, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3fv( pVert->m_vPos.Base() );
+ meshBuilder.Color3ub( 0, 0, 255 );
+ meshBuilder.AdvanceVertex();
+
+ VectorMA( pVert->m_vPos, 5.0f, pVert->m_vTVector, p );
+ meshBuilder.Position3fv( p.Base() );
+ meshBuilder.Color3ub( 0, 0, 255 );
+ meshBuilder.AdvanceVertex();
+ }
+
+ meshBuilder.End();
+ pMesh->Draw();
+ }
+#endif
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Renders debugging information for displacements
+//-----------------------------------------------------------------------------
+
+static void DispInfo_DrawDebugInformation( SurfaceHandle_t *pList, int listCount )
+{
+#ifndef SWDS
+ VPROF("DispInfo_DrawDebugInformation");
+ // Overlay with normals if we're in that mode
+ if( mat_normals.GetInt() )
+ {
+ DispInfo_DrawChainNormals(pList, listCount);
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Renders all displacements in sorted order
+//-----------------------------------------------------------------------------
+void DispInfo_RenderList( int nSortGroup, SurfaceHandle_t *pList, int listCount, bool bOrtho, unsigned long flags, ERenderDepthMode DepthMode )
+{
+#ifndef SWDS
+ if( !r_DrawDisp.GetInt() || !listCount )
+ return;
+
+ g_bDispOrthoRender = bOrtho;
+
+ // Build up the CPrimLists for all the displacements.
+ CDispInfo *visibleDisps[MAX_MAP_DISPINFO];
+ int nVisibleDisps;
+
+ DispInfo_BuildPrimLists( nSortGroup, pList, listCount, ( DepthMode != DEPTH_MODE_NORMAL ), visibleDisps, nVisibleDisps );
+
+ // Draw..
+ DispInfo_DrawPrimLists( DepthMode );
+
+ // Skip the rest if this is a shadow depth map pass
+ if ( ( DepthMode != DEPTH_MODE_NORMAL ) )
+ return;
+
+ // Add all displacements to the shadow render list
+ for ( int i = 0; i < listCount; i++ )
+ {
+ SurfaceHandle_t pCur = pList[i];
+ ShadowDecalHandle_t decalHandle = MSurf_ShadowDecals( pCur );
+ if (decalHandle != SHADOW_DECAL_HANDLE_INVALID)
+ {
+ g_pShadowMgr->AddShadowsOnSurfaceToRenderList( decalHandle );
+ }
+ }
+
+ bool bFlashlightMask = !( (flags & DRAWWORLDLISTS_DRAW_REFRACTION ) || (flags & DRAWWORLDLISTS_DRAW_REFLECTION ));
+
+ // Draw flashlight lighting for displacements
+ g_pShadowMgr->RenderFlashlights( bFlashlightMask );
+
+ // Draw overlays
+ OverlayMgr()->RenderOverlays( nSortGroup );
+
+ // Draw flashlight overlays
+ g_pShadowMgr->DrawFlashlightOverlays( nSortGroup, bFlashlightMask );
+ OverlayMgr()->ClearRenderLists( nSortGroup );
+
+ // Draw decals
+ DispInfo_BatchDecals( visibleDisps, nVisibleDisps );
+ DispInfo_DrawDecals( visibleDisps, nVisibleDisps );
+
+ // Draw flashlight decals
+ g_pShadowMgr->DrawFlashlightDecalsOnDisplacements( nSortGroup, visibleDisps, nVisibleDisps, bFlashlightMask );
+
+ // draw shadows
+ g_pShadowMgr->RenderShadows();
+ g_pShadowMgr->ClearShadowRenderList();
+
+ // Debugging rendering..
+ DispInfo_DrawDebugInformation( pList, listCount );
+#endif
+}
+