aboutsummaryrefslogtreecommitdiff
path: root/mp/src/utils/vrad/vraddisps.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/utils/vrad/vraddisps.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/utils/vrad/vraddisps.cpp')
-rw-r--r--mp/src/utils/vrad/vraddisps.cpp3518
1 files changed, 1759 insertions, 1759 deletions
diff --git a/mp/src/utils/vrad/vraddisps.cpp b/mp/src/utils/vrad/vraddisps.cpp
index 0bbafd40..d6bc6f7a 100644
--- a/mp/src/utils/vrad/vraddisps.cpp
+++ b/mp/src/utils/vrad/vraddisps.cpp
@@ -1,1759 +1,1759 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-#include "vrad.h"
-#include "utlvector.h"
-#include "cmodel.h"
-#include "BSPTreeData.h"
-#include "VRAD_DispColl.h"
-#include "CollisionUtils.h"
-#include "lightmap.h"
-#include "Radial.h"
-#include "CollisionUtils.h"
-#include "mathlib/bumpvects.h"
-#include "utlrbtree.h"
-#include "tier0/fasttimer.h"
-#include "disp_vrad.h"
-
-class CBSPDispRayDistanceEnumerator;
-
-//=============================================================================
-//
-// Displacement/Face List
-//
-class CBSPDispFaceListEnumerator : public ISpatialLeafEnumerator, public IBSPTreeDataEnumerator
-{
-public:
-
- //=========================================================================
- //
- // Construction/Deconstruction
- //
- CBSPDispFaceListEnumerator() {};
- virtual ~CBSPDispFaceListEnumerator()
- {
- m_DispList.Purge();
- m_FaceList.Purge();
- }
-
- // ISpatialLeafEnumerator
- bool EnumerateLeaf( int ndxLeaf, int context );
-
- // IBSPTreeDataEnumerator
- bool FASTCALL EnumerateElement( int userId, int context );
-
-public:
-
- CUtlVector<CVRADDispColl*> m_DispList;
- CUtlVector<int> m_FaceList;
-};
-
-
-//=============================================================================
-//
-// RayEnumerator
-//
-class CBSPDispRayEnumerator : public ISpatialLeafEnumerator, public IBSPTreeDataEnumerator
-{
-public:
- // ISpatialLeafEnumerator
- bool EnumerateLeaf( int ndxLeaf, int context );
-
- // IBSPTreeDataEnumerator
- bool FASTCALL EnumerateElement( int userId, int context );
-};
-
-//=============================================================================
-//
-// VRad Displacement Manager
-//
-class CVRadDispMgr : public IVRadDispMgr
-{
-public:
-
- //=========================================================================
- //
- // Construction/Deconstruction
- //
- CVRadDispMgr();
- virtual ~CVRadDispMgr();
-
- // creation/destruction
- void Init( void );
- void Shutdown( void );
-
- // "CalcPoints"
- bool BuildDispSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
- bool BuildDispLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
- bool BuildDispSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
-
- // patching functions
- void MakePatches( void );
- void SubdividePatch( int iPatch );
-
- // pre "FinalLightFace"
- void InsertSamplesDataIntoHashTable( void );
- void InsertPatchSampleDataIntoHashTable( void );
-
- // "FinalLightFace"
- radial_t *BuildLuxelRadial( int ndxFace, int ndxStyle, bool bBump );
- bool SampleRadial( int ndxFace, radial_t *pRadial, Vector const &vPos, int ndxLxl, LightingValue_t *pLightSample, int sampleCount, bool bPatch );
- radial_t *BuildPatchRadial( int ndxFace, bool bBump );
-
- // utility
- void GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal, bool bInside );
- void GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree );
-
- // bsp tree functions
- bool ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray );
- bool ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray, int ndxLeaf );
- void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray, int ndxLeaf,
- float& dist, dface_t*& pFace, Vector2D& luxelCoord );
- void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
- int ndxLeaf, float& dist, Vector *pNormal );
-
- void StartRayTest( DispTested_t &dispTested );
- void AddPolysForRayTrace( void );
-
- // general timing -- should be moved!!
- void StartTimer( const char *name );
- void EndTimer( void );
-
- //=========================================================================
- //
- // Enumeration Methods
- //
- bool DispRay_EnumerateLeaf( int ndxLeaf, int context );
- bool DispRay_EnumerateElement( int userId, int context );
- bool DispRayDistance_EnumerateElement( int userId, CBSPDispRayDistanceEnumerator* pEnum );
-
- bool DispFaceList_EnumerateLeaf( int ndxLeaf, int context );
- bool DispFaceList_EnumerateElement( int userId, int context );
-
-private:
-
- //=========================================================================
- //
- // BSP Tree Helpers
- //
- void InsertDispIntoTree( int ndxDisp );
- void RemoveDispFromTree( int ndxDisp );
-
- //=========================================================================
- //
- // Displacement Data Loader (from .bsp)
- //
- void UnserializeDisps( void );
- void DispBuilderInit( CCoreDispInfo *pBuilderDisp, dface_t *pFace, int ndxFace );
-
- //=========================================================================
- //
- // Sampling Helpers
- //
- void RadialLuxelBuild( CVRADDispColl *pDispTree, radial_t *pRadial, int ndxStyle, bool bBump );
- void RadialLuxelAddSamples( int ndxFace, Vector const &luxelPt, Vector const &luxelNormal, float radius,
- radial_t *pRadial, int ndxRadial, bool bBump, int lightStyle );
-
- void RadialPatchBuild( CVRADDispColl *pDispTree, radial_t *pRadial, bool bBump );
- void RadialLuxelAddPatch( int ndxFace, Vector const &luxelPt,
- Vector const &luxelNormal, float radius,
- radial_t *pRadial, int ndxRadial, bool bBump,
- CUtlVector<CPatch*> &interestingPatches );
-
- bool IsNeighbor( int iDispFace, int iNeighborFace );
-
- void GetInterestingPatchesForLuxels(
- int ndxFace,
- CUtlVector<CPatch*> &interestingPatches,
- float patchSampleRadius );
-
-private:
-
- struct DispCollTree_t
- {
- CVRADDispColl *m_pDispTree;
- BSPTreeDataHandle_t m_Handle;
- };
-
- struct EnumContext_t
- {
- DispTested_t *m_pDispTested;
- Ray_t const *m_pRay;
- };
-
- CUtlVector<DispCollTree_t> m_DispTrees;
-
- IBSPTreeData *m_pBSPTreeData;
-
- CBSPDispRayEnumerator m_EnumDispRay;
- CBSPDispFaceListEnumerator m_EnumDispFaceList;
-
- int sampleCount;
- Vector *m_pSamplePos;
-
- CFastTimer m_Timer;
-};
-
-//-----------------------------------------------------------------------------
-// Purpose: expose IVRadDispMgr to vrad
-//-----------------------------------------------------------------------------
-
-static CVRadDispMgr s_DispMgr;
-
-IVRadDispMgr *StaticDispMgr( void )
-{
- return &s_DispMgr;
-}
-
-
-//=============================================================================
-//
-// Displacement/Face List
-//
-// ISpatialLeafEnumerator
-bool CBSPDispFaceListEnumerator::EnumerateLeaf( int ndxLeaf, int context )
-{
- return s_DispMgr.DispFaceList_EnumerateLeaf( ndxLeaf, context );
-}
-
-// IBSPTreeDataEnumerator
-bool FASTCALL CBSPDispFaceListEnumerator::EnumerateElement( int userId, int context )
-{
- return s_DispMgr.DispFaceList_EnumerateElement( userId, context );
-}
-
-
-//=============================================================================
-//
-// RayEnumerator
-//
-bool CBSPDispRayEnumerator::EnumerateLeaf( int ndxLeaf, int context )
-{
- return s_DispMgr.DispRay_EnumerateLeaf( ndxLeaf, context );
-}
-
-bool FASTCALL CBSPDispRayEnumerator::EnumerateElement( int userId, int context )
-{
- return s_DispMgr.DispRay_EnumerateElement( userId, context );
-}
-
-
-//-----------------------------------------------------------------------------
-// Here's an enumerator that we use for testing against disps in a leaf...
-//-----------------------------------------------------------------------------
-
-class CBSPDispRayDistanceEnumerator : public IBSPTreeDataEnumerator
-{
-public:
- CBSPDispRayDistanceEnumerator() : m_Distance(1.0f), m_pSurface(0) {}
-
- // IBSPTreeDataEnumerator
- bool FASTCALL EnumerateElement( int userId, int context )
- {
- return s_DispMgr.DispRayDistance_EnumerateElement( userId, this );
- }
-
- float m_Distance;
- dface_t* m_pSurface;
- DispTested_t *m_pDispTested;
- Ray_t const *m_pRay;
- Vector2D m_LuxelCoord;
- Vector m_Normal;
-};
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CVRadDispMgr::CVRadDispMgr()
-{
- m_pBSPTreeData = CreateBSPTreeData();
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CVRadDispMgr::~CVRadDispMgr()
-{
- DestroyBSPTreeData( m_pBSPTreeData );
-}
-
-
-//-----------------------------------------------------------------------------
-// Insert a displacement into the tree for collision
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::InsertDispIntoTree( int ndxDisp )
-{
- DispCollTree_t &dispTree = m_DispTrees[ndxDisp];
- CDispCollTree *pDispTree = dispTree.m_pDispTree;
-
- // get the bounding box of the tree
- Vector boxMin, boxMax;
- pDispTree->GetBounds( boxMin, boxMax );
-
- // add the displacement to the tree so we will collide against it
- dispTree.m_Handle = m_pBSPTreeData->Insert( ndxDisp, boxMin, boxMax );
-}
-
-
-//-----------------------------------------------------------------------------
-// Remove a displacement from the tree for collision
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::RemoveDispFromTree( int ndxDisp )
-{
- // release the tree handle
- if( m_DispTrees[ndxDisp].m_Handle != TREEDATA_INVALID_HANDLE )
- {
- m_pBSPTreeData->Remove( m_DispTrees[ndxDisp].m_Handle );
- m_DispTrees[ndxDisp].m_Handle = TREEDATA_INVALID_HANDLE;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::Init( void )
-{
- // initialize the bsp tree
- m_pBSPTreeData->Init( ToolBSPTree() );
-
- // read in displacements that have been compiled into the bsp file
- UnserializeDisps();
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::Shutdown( void )
-{
- // remove all displacements from the tree
- for( int ndxDisp = m_DispTrees.Size(); ndxDisp >= 0; ndxDisp-- )
- {
- RemoveDispFromTree( ndxDisp );
- }
-
- // shutdown the bsp tree
- m_pBSPTreeData->Shutdown();
-
- // purge the displacement collision tree list
- m_DispTrees.Purge();
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::DispBuilderInit( CCoreDispInfo *pBuilderDisp, dface_t *pFace, int ndxFace )
-{
- // get the .bsp displacement
- ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo];
- if( !pDisp )
- return;
-
- //
- // initlialize the displacement base surface
- //
- CCoreDispSurface *pSurf = pBuilderDisp->GetSurface();
- pSurf->SetPointCount( 4 );
- pSurf->SetHandle( ndxFace );
- pSurf->SetContents( pDisp->contents );
-
- Vector pt[4];
- int ndxPt;
- for( ndxPt = 0; ndxPt < 4; ndxPt++ )
- {
- int eIndex = dsurfedges[pFace->firstedge+ndxPt];
- if( eIndex < 0 )
- {
- pSurf->SetPoint( ndxPt, dvertexes[dedges[-eIndex].v[1]].point );
- }
- else
- {
- pSurf->SetPoint( ndxPt, dvertexes[dedges[eIndex].v[0]].point );
- }
-
- VectorCopy( pSurf->GetPoint(ndxPt), pt[ndxPt] );
- }
-
- //
- // calculate the displacement surface normal
- //
- Vector vFaceNormal;
- pSurf->GetNormal( vFaceNormal );
- for( ndxPt = 0; ndxPt < 4; ndxPt++ )
- {
- pSurf->SetPointNormal( ndxPt, vFaceNormal );
- }
-
- // set the surface initial point info
- pSurf->SetPointStart( pDisp->startPosition );
- pSurf->FindSurfPointStartIndex();
- pSurf->AdjustSurfPointData();
-
- Vector vecTmp( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][0],
- texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][1],
- texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][2] );
- int nLuxelsPerWorldUnit = static_cast<int>( 1.0f / VectorLength( vecTmp ) );
- Vector vecU( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][0],
- texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][1],
- texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][2] );
- Vector vecV( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][0],
- texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][1],
- texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][2] );
- pSurf->CalcLuxelCoords( nLuxelsPerWorldUnit, false, vecU, vecV );
-
- pBuilderDisp->SetNeighborData( pDisp->m_EdgeNeighbors, pDisp->m_CornerNeighbors );
-
- CDispVert *pVerts = &g_DispVerts[ pDisp->m_iDispVertStart ];
- CDispTri *pTris = &g_DispTris[pDisp->m_iDispTriStart];
-
- //
- // initialize the displacement data
- //
- pBuilderDisp->InitDispInfo(
- pDisp->power,
- pDisp->minTess,
- pDisp->smoothingAngle,
- pVerts,
- pTris );
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::UnserializeDisps( void )
-{
- // temporarily create the "builder" displacements
- CUtlVector<CCoreDispInfo*> builderDisps;
- for ( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
- {
- CCoreDispInfo *pDisp = new CCoreDispInfo;
- if ( !pDisp )
- {
- builderDisps.Purge();
- return;
- }
-
- int nIndex = builderDisps.AddToTail();
- pDisp->SetListIndex( nIndex );
- builderDisps[nIndex] = pDisp;
- }
-
- // Set them up as CDispUtilsHelpers.
- for ( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
- {
- builderDisps[iDisp]->SetDispUtilsHelperInfo( builderDisps.Base(), g_dispinfo.Count() );
- }
-
- //
- // find all faces with displacement data and initialize
- //
- for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
- {
- dface_t *pFace = &g_pFaces[ndxFace];
- if( ValidDispFace( pFace ) )
- {
- DispBuilderInit( builderDisps[pFace->dispinfo], pFace, ndxFace );
- }
- }
-
- // generate the displacement surfaces
- for( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
- {
- builderDisps[iDisp]->Create();
- }
-
- // smooth edge normals
- SmoothNeighboringDispSurfNormals( builderDisps.Base(), g_dispinfo.Count() );
-
- //
- // create the displacement collision tree and add it to the bsp tree
- //
- CVRADDispColl *pDispTrees = new CVRADDispColl[g_dispinfo.Count()];
- if( !pDispTrees )
- return;
-
- m_DispTrees.AddMultipleToTail( g_dispinfo.Count() );
-
- for( int iDisp = 0; iDisp < g_dispinfo.Count(); iDisp++ )
- {
- pDispTrees[iDisp].Create( builderDisps[iDisp] );
-
- m_DispTrees[iDisp].m_pDispTree = &pDispTrees[iDisp];
- m_DispTrees[iDisp].m_Handle = TREEDATA_INVALID_HANDLE;
-
- InsertDispIntoTree( iDisp );
- }
-
- // free "builder" disps
- builderDisps.Purge();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: create a set of patches for each displacement surface to transfer
-// bounced light around with
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::MakePatches( void )
-{
- // Collect stats - keep track of the total displacement surface area.
- float flTotalArea = 0.0f;
-
- // Create patches for all of the displacements.
- int nTreeCount = m_DispTrees.Size();
- for( int iTree = 0; iTree < nTreeCount; ++iTree )
- {
- // Get the current displacement collision tree.
- CVRADDispColl *pDispTree = m_DispTrees[iTree].m_pDispTree;
- if( !pDispTree )
- continue;
-
- flTotalArea += pDispTree->CreateParentPatches();
- }
-
- // Print stats.
- qprintf( "%i Displacements\n", nTreeCount );
- qprintf( "%i Square Feet [%.2f Square Inches]\n", ( int )( flTotalArea / 144.0f ), flTotalArea );
-}
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::SubdividePatch( int iPatch )
-{
- // Get the current patch to subdivide.
- CPatch *pPatch = &g_Patches[iPatch];
- if ( !pPatch )
- return;
-
- // Create children patches.
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[pPatch->faceNumber].dispinfo];
- CVRADDispColl *pTree = dispTree.m_pDispTree;
- if( pTree )
- {
- pTree->CreateChildPatches( iPatch, 0 );
- }
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::StartRayTest( DispTested_t &dispTested )
-{
- if( m_DispTrees.Size() > 0 )
- {
- if( dispTested.m_pTested == 0 )
- {
- dispTested.m_pTested = new int[m_DispTrees.Size()];
- memset( dispTested.m_pTested, 0, m_DispTrees.Size() * sizeof( int ) );
- dispTested.m_Enum = 0;
- }
- ++dispTested.m_Enum;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray )
-{
- StartRayTest( dispTested );
-
- EnumContext_t ctx;
- ctx.m_pRay = &ray;
- ctx.m_pDispTested = &dispTested;
-
- // If it got through without a hit, it returns true
- return !m_pBSPTreeData->EnumerateLeavesAlongRay( ray, &m_EnumDispRay, ( int )&ctx );
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
- int ndxLeaf )
-{
- EnumContext_t ctx;
- ctx.m_pRay = &ray;
- ctx.m_pDispTested = &dispTested;
-
- return !m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, ( int )&ctx );
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
- int ndxLeaf, float& dist, dface_t*& pFace, Vector2D& luxelCoord )
-{
- CBSPDispRayDistanceEnumerator rayTestEnum;
- rayTestEnum.m_pRay = &ray;
- rayTestEnum.m_pDispTested = &dispTested;
-
- m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &rayTestEnum, 0 );
-
- dist = rayTestEnum.m_Distance;
- pFace = rayTestEnum.m_pSurface;
- if (pFace)
- {
- Vector2DCopy( rayTestEnum.m_LuxelCoord, luxelCoord );
- }
-}
-
-void CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
- int ndxLeaf, float& dist, Vector *pNormal )
-{
- CBSPDispRayDistanceEnumerator rayTestEnum;
- rayTestEnum.m_pRay = &ray;
- rayTestEnum.m_pDispTested = &dispTested;
-
- m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &rayTestEnum, 0 );
- dist = rayTestEnum.m_Distance;
- if ( rayTestEnum.m_pSurface )
- {
- *pNormal = rayTestEnum.m_Normal;
- }
-}
-
-void CVRadDispMgr::AddPolysForRayTrace( void )
-{
- int nTreeCount = m_DispTrees.Size();
- for( int iTree = 0; iTree < nTreeCount; ++iTree )
- {
- // Get the current displacement collision tree.
- CVRADDispColl *pDispTree = m_DispTrees[iTree].m_pDispTree;
-
- // Add the triangles of the tree to the RT environment
- pDispTree->AddPolysForRayTrace();
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal,
- bool bInside )
-{
- // get the displacement surface data
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
- CVRADDispColl *pDispTree = dispTree.m_pDispTree;
-
- // find the parameterized displacement indices
- Vector2D uv;
- pDispTree->BaseFacePlaneToDispUV( pt, uv );
-
- if( bInside )
- {
- if( uv[0] < 0.0f || uv[0] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[0] ); }
- if( uv[1] < 0.0f || uv[1] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[1] ); }
- }
-
- if( uv[0] < 0.0f ) { uv[0] = 0.0f; }
- if( uv[0] > 1.0f ) { uv[0] = 1.0f; }
- if( uv[1] < 0.0f ) { uv[1] = 0.0f; }
- if( uv[1] > 1.0f ) { uv[1] = 1.0f; }
-
- // get the normal at "pt"
- pDispTree->DispUVToSurfNormal( uv, ptNormal );
-
- // get the new "pt"
- pDispTree->DispUVToSurfPoint( uv, pt, 1.0f );
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree )
-{
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
- *ppDispTree = dispTree.m_pDispTree;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::DispRay_EnumerateLeaf( int ndxLeaf, int context )
-{
- return m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, context );
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::DispRay_EnumerateElement( int userId, int context )
-{
- DispCollTree_t &dispTree = m_DispTrees[userId];
- EnumContext_t *pCtx = ( EnumContext_t* )context;
-
- // don't test twice (check tested value)
- if( pCtx->m_pDispTested->m_pTested[userId] == pCtx->m_pDispTested->m_Enum )
- return true;
-
- // set the tested value
- pCtx->m_pDispTested->m_pTested[userId] = pCtx->m_pDispTested->m_Enum;
-
- // false mean stop iterating -- return false if we hit! (NOTE: opposite return
- // result of the collision tree's ray test, thus the !)
- CBaseTrace trace;
- trace.fraction = 1.0f;
- return ( !dispTree.m_pDispTree->AABBTree_Ray( *pCtx->m_pRay, pCtx->m_pRay->InvDelta(), &trace, true ) );
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-bool CVRadDispMgr::DispRayDistance_EnumerateElement( int userId, CBSPDispRayDistanceEnumerator* pCtx )
-{
- DispCollTree_t &dispTree = m_DispTrees[userId];
-
- // don't test twice (check tested value)
- if( pCtx->m_pDispTested->m_pTested[userId] == pCtx->m_pDispTested->m_Enum )
- return true;
-
- // set the tested value
- pCtx->m_pDispTested->m_pTested[userId] = pCtx->m_pDispTested->m_Enum;
-
- // Test the ray, if it's closer than previous tests, use it!
- RayDispOutput_t output;
- output.ndxVerts[0] = -1;
- output.ndxVerts[1] = -1;
- output.ndxVerts[2] = -1;
- output.ndxVerts[3] = -1;
- output.u = -1.0f;
- output.v = -1.0f;
- output.dist = FLT_MAX;
-
- if (dispTree.m_pDispTree->AABBTree_Ray( *pCtx->m_pRay, output ))
- {
- if (output.dist < pCtx->m_Distance)
- {
- pCtx->m_Distance = output.dist;
- pCtx->m_pSurface = &g_pFaces[dispTree.m_pDispTree->GetParentIndex()];
-
- // Get the luxel coordinate
- ComputePointFromBarycentric(
- dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[0]),
- dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[1]),
- dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[2]),
- output.u, output.v, pCtx->m_LuxelCoord );
-
- Vector v0,v1,v2;
- dispTree.m_pDispTree->GetVert( output.ndxVerts[0], v0 );
- dispTree.m_pDispTree->GetVert( output.ndxVerts[1], v1 );
- dispTree.m_pDispTree->GetVert( output.ndxVerts[2], v2 );
- Vector e0 = v1-v0;
- Vector e1 = v2-v0;
- pCtx->m_Normal = CrossProduct( e0, e1 );
- VectorNormalize(pCtx->m_Normal);
- }
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Test a ray against a particular dispinfo
-//-----------------------------------------------------------------------------
-
-/*
-float CVRadDispMgr::ClipRayToDisp( Ray_t const &ray, int dispinfo )
-{
- assert( m_DispTrees.IsValidIndex(dispinfo) );
-
- RayDispOutput_t output;
- if (!m_DispTrees[dispinfo].m_pDispTree->AABBTree_Ray( ray, output ))
- return 1.0f;
- return output.dist;
-}
-*/
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::DispFaceList_EnumerateLeaf( int ndxLeaf, int context )
-{
- //
- // add the faces found in this leaf to the face list
- //
- dleaf_t *pLeaf = &dleafs[ndxLeaf];
- for( int ndxFace = 0; ndxFace < pLeaf->numleaffaces; ndxFace++ )
- {
- // get the current face index
- int ndxLeafFace = pLeaf->firstleafface + ndxFace;
-
- // check to see if the face already lives in the list
- int ndx;
- int size = m_EnumDispFaceList.m_FaceList.Size();
- for( ndx = 0; ndx < size; ndx++ )
- {
- if( m_EnumDispFaceList.m_FaceList[ndx] == ndxLeafFace )
- break;
- }
-
- if( ndx == size )
- {
- int ndxList = m_EnumDispFaceList.m_FaceList.AddToTail();
- m_EnumDispFaceList.m_FaceList[ndxList] = ndxLeafFace;
- }
- }
-
- return m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispFaceList, context );
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::DispFaceList_EnumerateElement( int userId, int context )
-{
- DispCollTree_t &dispTree = m_DispTrees[userId];
- CVRADDispColl *pDispTree = dispTree.m_pDispTree;
- if( !pDispTree )
- return false;
-
- // check to see if the displacement already lives in the list
- int ndx;
- int size = m_EnumDispFaceList.m_DispList.Size();
- for( ndx = 0; ndx < size; ndx++ )
- {
- if( m_EnumDispFaceList.m_DispList[ndx] == pDispTree )
- break;
- }
-
- if( ndx == size )
- {
- int ndxList = m_EnumDispFaceList.m_DispList.AddToTail();
- m_EnumDispFaceList.m_DispList[ndxList] = pDispTree;
- }
-
- return true;
-}
-
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-inline void GetSampleLight( facelight_t *pFaceLight, int ndxStyle, bool bBumped,
- int ndxSample, LightingValue_t *pSampleLight )
-{
-// SampleLight[0].Init( 20.0f, 10.0f, 10.0f );
-// return;
-
- // get sample from bumped lighting data
- if( bBumped )
- {
- for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
- {
- pSampleLight[ndxBump] = pFaceLight->light[ndxStyle][ndxBump][ndxSample];
- }
- }
- // just a generally lit surface
- else
- {
- pSampleLight[0] = pFaceLight->light[ndxStyle][0][ndxSample];
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void AddSampleLightToRadial( Vector const &samplePos, Vector const &sampleNormal,
- LightingValue_t *pSampleLight, float sampleRadius2,
- Vector const &luxelPos, Vector const &luxelNormal,
- radial_t *pRadial, int ndxRadial, bool bBumped,
- bool bNeighborBumped )
-{
- // check normals to see if sample contributes any light at all
- float angle = sampleNormal.Dot( luxelNormal );
- if ( angle < 0.15f )
- return;
-
- // calculate the light vector
- Vector vSegment = samplePos - luxelPos;
-
- // get the distance to the light
- float dist = vSegment.Length();
- float dist2 = dist * dist;
-
- // Check to see if the light is within the influence.
- float influence = 1.0f - ( dist2 / ( sampleRadius2 ) );
- if( influence <= 0.0f )
- return;
-
- influence *= angle;
-
- if( bBumped )
- {
- if( bNeighborBumped )
- {
- for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
- {
- pRadial->light[ndxBump][ndxRadial].AddWeighted( pSampleLight[ndxBump], influence );
- }
- pRadial->weight[ndxRadial] += influence;
- }
- else
- {
- influence *= 0.05f;
- for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
- {
- pRadial->light[ndxBump][ndxRadial].AddWeighted( pSampleLight[0], influence );
- }
- pRadial->weight[ndxRadial] += influence;
- }
- }
- else
- {
- pRadial->light[0][ndxRadial].AddWeighted( pSampleLight[0], influence );
- pRadial->weight[ndxRadial] += influence;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::IsNeighbor( int iFace, int iNeighborFace )
-{
- if ( iFace == iNeighborFace )
- return true;
-
- faceneighbor_t *pFaceNeighbor = &faceneighbor[iFace];
- for ( int iNeighbor = 0; iNeighbor < pFaceNeighbor->numneighbors; iNeighbor++ )
- {
- if ( pFaceNeighbor->neighbor[iNeighbor] == iNeighborFace )
- return true;
- }
-
- return false;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::RadialLuxelAddSamples( int ndxFace, Vector const &luxelPt, Vector const &luxelNormal, float radius,
- radial_t *pRadial, int ndxRadial, bool bBump, int lightStyle )
-{
- // calculate one over the voxel size
- float ooVoxelSize = 1.0f / SAMPLEHASH_VOXEL_SIZE;
-
- //
- // find voxel info
- //
- int voxelMin[3], voxelMax[3];
- for( int axis = 0; axis < 3; axis++ )
- {
- voxelMin[axis] = ( int )( ( luxelPt[axis] - radius ) * ooVoxelSize );
- voxelMax[axis] = ( int )( ( luxelPt[axis] + radius ) * ooVoxelSize ) + 1;
- }
-
- SampleData_t sampleData;
- for( int ndxZ = voxelMin[2]; ndxZ < voxelMax[2] + 1; ndxZ++ )
- {
- for( int ndxY = voxelMin[1]; ndxY < voxelMax[1] + 1; ndxY++ )
- {
- for( int ndxX = voxelMin[0]; ndxX < voxelMax[0] + 1; ndxX++ )
- {
- sampleData.x = ndxX * 100;
- sampleData.y = ndxY * 10;
- sampleData.z = ndxZ;
-
- UtlHashHandle_t handle = g_SampleHashTable.Find( sampleData );
- if( handle != g_SampleHashTable.InvalidHandle() )
- {
- SampleData_t *pSampleData = &g_SampleHashTable.Element( handle );
- int count = pSampleData->m_Samples.Count();
- for( int ndx = 0; ndx < count; ndx++ )
- {
- SampleHandle_t sampleHandle = pSampleData->m_Samples.Element( ndx );
- int ndxSample = ( sampleHandle & 0x0000ffff );
- int ndxFaceLight = ( ( sampleHandle >> 16 ) & 0x0000ffff );
-
- facelight_t *pFaceLight = &facelight[ndxFaceLight];
- if( pFaceLight && IsNeighbor( ndxFace, ndxFaceLight ) )
- {
- //
- // check for similar lightstyles
- //
- dface_t *pFace = &g_pFaces[ndxFaceLight];
- if( pFace )
- {
- int ndxNeighborStyle = -1;
- for( int ndxLightStyle = 0; ndxLightStyle < MAXLIGHTMAPS; ndxLightStyle++ )
- {
- if( pFace->styles[ndxLightStyle] == lightStyle )
- {
- ndxNeighborStyle = ndxLightStyle;
- break;
- }
- }
- if( ndxNeighborStyle == -1 )
- continue;
-
- // is this surface bumped???
- bool bNeighborBump = texinfo[pFace->texinfo].flags & SURF_BUMPLIGHT ? true : false;
-
- LightingValue_t sampleLight[NUM_BUMP_VECTS+1];
- GetSampleLight( pFaceLight, ndxNeighborStyle, bNeighborBump, ndxSample, sampleLight );
- AddSampleLightToRadial( pFaceLight->sample[ndxSample].pos, pFaceLight->sample[ndxSample].normal,
- sampleLight, radius*radius, luxelPt, luxelNormal, pRadial, ndxRadial,
- bBump, bNeighborBump );
- }
- }
- }
- }
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::RadialLuxelBuild( CVRADDispColl *pDispTree, radial_t *pRadial,
- int ndxStyle, bool bBump )
-{
- //
- // get data lighting data
- //
- int ndxFace = pDispTree->GetParentIndex();
-
- dface_t *pFace = &g_pFaces[ndxFace];
- facelight_t *pFaceLight = &facelight[ndxFace];
-
- // get the influence radius
- float radius2 = pDispTree->GetSampleRadius2();
- float radius = ( float )sqrt( radius2 );
-
- int radialSize = pRadial->w * pRadial->h;
- for( int ndxRadial = 0; ndxRadial < radialSize; ndxRadial++ )
- {
- RadialLuxelAddSamples( ndxFace, pFaceLight->luxel[ndxRadial], pFaceLight->luxelNormals[ndxRadial],
- radius, pRadial, ndxRadial, bBump, pFace->styles[ndxStyle] );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-radial_t *CVRadDispMgr::BuildLuxelRadial( int ndxFace, int ndxStyle, bool bBump )
-{
- // allocate the radial
- radial_t *pRadial = AllocateRadial( ndxFace );
- if( !pRadial )
- return NULL;
-
- //
- // step 1: get the displacement surface to be lit
- //
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
- CVRADDispColl *pDispTree = dispTree.m_pDispTree;
- if( !pDispTree )
- return NULL;
-
- // step 2: build radial luxels
- RadialLuxelBuild( pDispTree, pRadial, ndxStyle, bBump );
-
- // step 3: return the built radial
- return pRadial;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::SampleRadial( int ndxFace, radial_t *pRadial, Vector const &vPos, int ndxLxl,
- LightingValue_t *pLightSample, int sampleCount, bool bPatch )
-{
- bool bGoodSample = true;
- for ( int count = 0; count < sampleCount; count++ )
- {
- pLightSample[count].Zero();
-
- if ( pRadial->weight[ndxLxl] > 0.0f )
- {
- pLightSample[count].AddWeighted( pRadial->light[count][ndxLxl], ( 1.0f / pRadial->weight[ndxLxl] ) );
- }
- else
- {
- // error, luxel has no samples (not for patches)
- if ( !bPatch )
- {
- // Yes, 2550 is correct!
- // pLightSample[count].Init( 2550.0f, 0.0f, 2550.0f );
- if( count == 0 )
- bGoodSample = false;
- }
- }
- }
-
- return bGoodSample;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void GetPatchLight( CPatch *pPatch, bool bBump, Vector *pPatchLight )
-{
- VectorCopy( pPatch->totallight.light[0], pPatchLight[0] );
-
- if( bBump )
- {
- for( int ndxBump = 1; ndxBump < ( NUM_BUMP_VECTS + 1 ); ndxBump++ )
- {
- VectorCopy( pPatch->totallight.light[ndxBump], pPatchLight[ndxBump] );
- }
- }
-}
-
-extern void GetBumpNormals( const float* sVect, const float* tVect, const Vector& flatNormal,
- const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] );
-extern void PreGetBumpNormalsForDisp( texinfo_t *pTexinfo, Vector &vecU, Vector &vecV, Vector &vecNormal );
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal,
- Vector *pPatchLight, float patchRadius2,
- Vector const &luxelPos, Vector const &luxelNormal,
- radial_t *pRadial, int ndxRadial, bool bBump,
- bool bNeighborBump )
-{
- // calculate the light vector
- Vector vSegment = patchOrigin - luxelPos;
-
- // get the distance to the light
- float dist = vSegment.Length();
- float dist2 = dist * dist;
-
- // Check to see if the light is within the sample influence.
- float influence = 1.0f - ( dist2 / ( patchRadius2 ) );
- if ( influence <= 0.0f )
- return;
-
- if( bBump )
- {
- Vector normals[NUM_BUMP_VECTS+1];
- normals[0] = luxelNormal;
- texinfo_t *pTexinfo = &texinfo[g_pFaces[pRadial->facenum].texinfo];
- Vector vecTexU, vecTexV;
- PreGetBumpNormalsForDisp( pTexinfo, vecTexU, vecTexV, normals[0] );
- GetBumpNormals( vecTexU, vecTexV, normals[0], normals[0], &normals[1] );
-
- if( bNeighborBump )
- {
- float flScale = patchNormal.Dot( normals[0] );
- flScale = max( 0.0f, flScale );
- float flBumpInfluence = influence * flScale;
-
- for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
- {
- pRadial->light[ndxBump][ndxRadial].AddWeighted( pPatchLight[ndxBump], flBumpInfluence );
- }
-
- pRadial->weight[ndxRadial] += flBumpInfluence;
- }
- else
- {
- float flScale = patchNormal.Dot( normals[0] );
- flScale = max( 0.0f, flScale );
- float flBumpInfluence = influence * flScale * 0.05f;
-
- for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
- {
- pRadial->light[ndxBump][ndxRadial].AddWeighted( pPatchLight[0], flBumpInfluence );
- }
-
- pRadial->weight[ndxRadial] += flBumpInfluence;
- }
- }
- else
- {
- float flScale = patchNormal.Dot( luxelNormal );
- flScale = max( 0.0f, flScale );
- influence *= flScale;
- pRadial->light[0][ndxRadial].AddWeighted( pPatchLight[0], influence );
-
- // add the weight value
- pRadial->weight[ndxRadial] += influence;
- }
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::RadialLuxelAddPatch( int ndxFace, Vector const &luxelPt,
- Vector const &luxelNormal, float radius,
- radial_t *pRadial, int ndxRadial, bool bBump,
- CUtlVector<CPatch*> &interestingPatches )
-{
-#ifdef SAMPLEHASH_QUERY_ONCE
- for ( int i=0; i < interestingPatches.Count(); i++ )
- {
- CPatch *pPatch = interestingPatches[i];
- bool bNeighborBump = texinfo[g_pFaces[pPatch->faceNumber].texinfo].flags & SURF_BUMPLIGHT ? true : false;
-
- Vector patchLight[NUM_BUMP_VECTS+1];
- GetPatchLight( pPatch, bBump, patchLight );
- AddPatchLightToRadial( pPatch->origin, pPatch->normal, patchLight, radius*radius,
- luxelPt, luxelNormal, pRadial, ndxRadial, bBump, bNeighborBump );
- }
-#else
- // calculate one over the voxel size
- float ooVoxelSize = 1.0f / SAMPLEHASH_VOXEL_SIZE;
-
- //
- // find voxel info
- //
- int voxelMin[3], voxelMax[3];
- for ( int axis = 0; axis < 3; axis++ )
- {
- voxelMin[axis] = ( int )( ( luxelPt[axis] - radius ) * ooVoxelSize );
- voxelMax[axis] = ( int )( ( luxelPt[axis] + radius ) * ooVoxelSize ) + 1;
- }
-
- unsigned short curIterationKey = IncrementPatchIterationKey();
- PatchSampleData_t patchData;
- for ( int ndxZ = voxelMin[2]; ndxZ < voxelMax[2] + 1; ndxZ++ )
- {
- for ( int ndxY = voxelMin[1]; ndxY < voxelMax[1] + 1; ndxY++ )
- {
- for ( int ndxX = voxelMin[0]; ndxX < voxelMax[0] + 1; ndxX++ )
- {
- patchData.x = ndxX * 100;
- patchData.y = ndxY * 10;
- patchData.z = ndxZ;
-
- UtlHashHandle_t handle = g_PatchSampleHashTable.Find( patchData );
- if ( handle != g_PatchSampleHashTable.InvalidHandle() )
- {
- PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
- int count = pPatchData->m_ndxPatches.Count();
- for ( int ndx = 0; ndx < count; ndx++ )
- {
- int ndxPatch = pPatchData->m_ndxPatches.Element( ndx );
- CPatch *pPatch = &g_Patches.Element( ndxPatch );
- if ( pPatch && pPatch->m_IterationKey != curIterationKey )
- {
- pPatch->m_IterationKey = curIterationKey;
-
- if ( IsNeighbor( ndxFace, pPatch->faceNumber ) )
- {
- bool bNeighborBump = texinfo[g_pFaces[pPatch->faceNumber].texinfo].flags & SURF_BUMPLIGHT ? true : false;
-
- Vector patchLight[NUM_BUMP_VECTS+1];
- GetPatchLight( pPatch, bBump, patchLight );
- AddPatchLightToRadial( pPatch->origin, pPatch->normal, patchLight, radius*radius,
- luxelPt, luxelNormal, pRadial, ndxRadial, bBump, bNeighborBump );
- }
- }
- }
- }
- }
- }
- }
-#endif
-}
-
-
-void CVRadDispMgr::GetInterestingPatchesForLuxels(
- int ndxFace,
- CUtlVector<CPatch*> &interestingPatches,
- float patchSampleRadius )
-{
- facelight_t *pFaceLight = &facelight[ndxFace];
-
- // Get the max bounds of all voxels that these luxels touch.
- Vector vLuxelMin( FLT_MAX, FLT_MAX, FLT_MAX );
- Vector vLuxelMax( -FLT_MAX, -FLT_MAX, -FLT_MAX );
- for ( int i=0; i < pFaceLight->numluxels; i++ )
- {
- VectorMin( pFaceLight->luxel[i], vLuxelMin, vLuxelMin );
- VectorMax( pFaceLight->luxel[i], vLuxelMax, vLuxelMax );
- }
-
- int allVoxelMin[3], allVoxelMax[3];
- for ( int axis = 0; axis < 3; axis++ )
- {
- allVoxelMin[axis] = ( int )( ( vLuxelMin[axis] - patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE );
- allVoxelMax[axis] = ( int )( ( vLuxelMax[axis] + patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE ) + 1;
- }
- int allVoxelSize[3] = { allVoxelMax[0] - allVoxelMin[0], allVoxelMax[1] - allVoxelMin[1], allVoxelMax[2] - allVoxelMin[2] };
-
-
- // Now figure out exactly which voxels these luxels touch.
- CUtlVector<unsigned char> voxelBits;
- voxelBits.SetSize( ((allVoxelSize[0] * allVoxelSize[1] * allVoxelSize[2]) + 7) / 8 );
- memset( voxelBits.Base(), 0, voxelBits.Count() );
-
- for ( int i=0; i < pFaceLight->numluxels; i++ )
- {
- int voxelMin[3], voxelMax[3];
- for ( int axis=0; axis < 3; axis++ )
- {
- voxelMin[axis] = ( int )( ( pFaceLight->luxel[i][axis] - patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE );
- voxelMax[axis] = ( int )( ( pFaceLight->luxel[i][axis] + patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE ) + 1;
- }
-
- for ( int x=voxelMin[0]; x < voxelMax[0]; x++ )
- {
- for ( int y=voxelMin[1]; y < voxelMax[1]; y++ )
- {
- for ( int z=voxelMin[2]; z < voxelMax[2]; z++ )
- {
- int iBit = (z - allVoxelMin[2])*(allVoxelSize[0]*allVoxelSize[1]) +
- (y-allVoxelMin[1])*allVoxelSize[0] +
- (x-allVoxelMin[0]);
- voxelBits[iBit>>3] |= (1 << (iBit & 7));
- }
- }
- }
- }
-
-
- // Now get the list of patches that touch those voxels.
- unsigned short curIterationKey = IncrementPatchIterationKey();
-
- for ( int x=0; x < allVoxelSize[0]; x++ )
- {
- for ( int y=0; y < allVoxelSize[1]; y++ )
- {
- for ( int z=0; z < allVoxelSize[2]; z++ )
- {
- // Make sure this voxel has any luxels that care about it.
- int iBit = z*(allVoxelSize[0]*allVoxelSize[1]) + y*allVoxelSize[0] + x;
- unsigned char val = voxelBits[iBit>>3] & (1 << (iBit & 7));
- if ( !val )
- continue;
-
- PatchSampleData_t patchData;
- patchData.x = (x + allVoxelMin[0]) * 100;
- patchData.y = (y + allVoxelMin[1]) * 10;
- patchData.z = (z + allVoxelMin[2]);
-
- UtlHashHandle_t handle = g_PatchSampleHashTable.Find( patchData );
- if ( handle != g_PatchSampleHashTable.InvalidHandle() )
- {
- PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
-
- // For all patches that touch this hash table element..
- for ( int ndx = 0; ndx < pPatchData->m_ndxPatches.Count(); ndx++ )
- {
- int ndxPatch = pPatchData->m_ndxPatches.Element( ndx );
- CPatch *pPatch = &g_Patches.Element( ndxPatch );
-
- // If we haven't touched the patch already and it's a valid neighbor, then we want to use it.
- if ( pPatch && pPatch->m_IterationKey != curIterationKey )
- {
- pPatch->m_IterationKey = curIterationKey;
-
- if ( IsNeighbor( ndxFace, pPatch->faceNumber ) )
- {
- interestingPatches.AddToTail( pPatch );
- }
- }
- }
- }
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::RadialPatchBuild( CVRADDispColl *pDispTree, radial_t *pRadial,
- bool bBump )
-{
- //
- // get data lighting data
- //
- int ndxFace = pDispTree->GetParentIndex();
- facelight_t *pFaceLight = &facelight[ndxFace];
-
- // get the influence radius
- float radius2 = pDispTree->GetPatchSampleRadius2();
- float radius = ( float )sqrt( radius2 );
-
- CUtlVector<CPatch*> interestingPatches;
-#ifdef SAMPLEHASH_QUERY_ONCE
- GetInterestingPatchesForLuxels( ndxFace, interestingPatches, radius );
-#endif
-
- int radialSize = pRadial->w * pRadial->h;
- for( int ndxRadial = 0; ndxRadial < radialSize; ndxRadial++ )
- {
- RadialLuxelAddPatch(
- ndxFace,
- pFaceLight->luxel[ndxRadial],
- pFaceLight->luxelNormals[ndxRadial],
- radius,
- pRadial,
- ndxRadial,
- bBump,
- interestingPatches );
- }
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-radial_t *CVRadDispMgr::BuildPatchRadial( int ndxFace, bool bBump )
-{
- // allocate the radial
- radial_t *pRadial = AllocateRadial( ndxFace );
- if( !pRadial )
- return NULL;
-
- //
- // step 1: get the displacement surface to be lit
- //
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
- CVRADDispColl *pDispTree = dispTree.m_pDispTree;
- if( !pDispTree )
- return NULL;
-
- // step 2: build radial of patch light
- RadialPatchBuild( pDispTree, pRadial, bBump );
-
- // step 3: return the built radial
- return pRadial;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool SampleInSolid( sample_t *pSample )
-{
- int ndxLeaf = PointLeafnum( pSample->pos );
- return ( dleafs[ndxLeaf].contents == CONTENTS_SOLID );
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::InsertSamplesDataIntoHashTable( void )
-{
- int totalSamples = 0;
-#if 0
- int totalSamplesInSolid = 0;
-#endif
-
- for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
- {
- dface_t *pFace = &g_pFaces[ndxFace];
- facelight_t *pFaceLight = &facelight[ndxFace];
- if( !pFace || !pFaceLight )
- continue;
-
- if( texinfo[pFace->texinfo].flags & TEX_SPECIAL )
- continue;
-
-#if 0
- bool bDisp = ( pFace->dispinfo != -1 );
-#endif
- //
- // for each sample
- //
- for( int ndxSample = 0; ndxSample < pFaceLight->numsamples; ndxSample++ )
- {
- sample_t *pSample = &pFaceLight->sample[ndxSample];
- if( pSample )
- {
-#if 0
- if( bDisp )
- {
- // test sample to see if the displacement samples resides in solid
- if( SampleInSolid( pSample ) )
- {
- totalSamplesInSolid++;
- continue;
- }
- }
-#endif
-
- // create the sample handle
- SampleHandle_t sampleHandle = ndxSample;
- sampleHandle |= ( ndxFace << 16 );
-
- SampleData_AddSample( pSample, sampleHandle );
- }
-
- }
-
- totalSamples += pFaceLight->numsamples;
- }
-
-#if 0
- // not implemented yet!!!
- Msg( "%d samples in solid\n", totalSamplesInSolid );
-#endif
-
- // log the distribution
- SampleData_Log();
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::InsertPatchSampleDataIntoHashTable( void )
-{
- // don't insert patch samples if we are not bouncing light
- if( numbounce <= 0 )
- return;
-
- int totalPatchSamples = 0;
-
- for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
- {
- dface_t *pFace = &g_pFaces[ndxFace];
- facelight_t *pFaceLight = &facelight[ndxFace];
- if( !pFace || !pFaceLight )
- continue;
-
- if( texinfo[pFace->texinfo].flags & TEX_SPECIAL )
- continue;
-
- //
- // for each patch
- //
- CPatch *pNextPatch = NULL;
- if( g_FacePatches.Element( ndxFace ) != g_FacePatches.InvalidIndex() )
- {
- for( CPatch *pPatch = &g_Patches.Element( g_FacePatches.Element( ndxFace ) ); pPatch; pPatch = pNextPatch )
- {
- // next patch
- pNextPatch = NULL;
- if( pPatch->ndxNext != g_Patches.InvalidIndex() )
- {
- pNextPatch = &g_Patches.Element( pPatch->ndxNext );
- }
-
- // skip patches with children
- if( pPatch->child1 != g_Patches.InvalidIndex() )
- continue;
-
- int ndxPatch = pPatch - g_Patches.Base();
- PatchSampleData_AddSample( pPatch, ndxPatch );
-
- totalPatchSamples++;
- }
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::StartTimer( const char *name )
-{
- Msg( name );
- m_Timer.Start();
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CVRadDispMgr::EndTimer( void )
-{
- m_Timer.End();
- CCycleCount duration = m_Timer.GetDuration();
- double seconds = duration.GetSeconds();
-
- Msg( "Done<%1.4lf sec>\n", seconds );
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::BuildDispSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
-{
- // get the tree assosciated with the face
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
- CVRADDispColl *pDispTree = dispTree.m_pDispTree;
- if( !pDispTree )
- return false;
-
- // lightmap size
- int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
- int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
-
- // calculate the steps in uv space
- float stepU = 1.0f / ( float )width;
- float stepV = 1.0f / ( float )height;
- float halfStepU = stepU * 0.5f;
- float halfStepV = stepV * 0.5f;
-
- //
- // build the winding points (used to generate world space winding and
- // calculate the area of the "sample")
- //
- int ndxU, ndxV;
-
- CUtlVector<sample_t> samples;
- samples.SetCount( SINGLEMAP );
- sample_t *pSamples = samples.Base();
-
- CUtlVector<Vector> worldPoints;
- worldPoints.SetCount( SINGLEMAP );
- Vector *pWorldPoints = worldPoints.Base();
-
- for( ndxV = 0; ndxV < ( height + 1 ); ndxV++ )
- {
- for( ndxU = 0; ndxU < ( width + 1 ); ndxU++ )
- {
- int ndx = ( ndxV * ( width + 1 ) ) + ndxU;
-
- Vector2D uv( ndxU * stepU, ndxV * stepV );
- pDispTree->DispUVToSurfPoint( uv, pWorldPoints[ndx], 0.0f );
- }
- }
-
- for( ndxV = 0; ndxV < height; ndxV++ )
- {
- for( ndxU = 0; ndxU < width; ndxU++ )
- {
- // build the winding
- winding_t *pWinding = AllocWinding( 4 );
- if( pWinding )
- {
- pWinding->numpoints = 4;
- pWinding->p[0] = pWorldPoints[(ndxV*(width+1))+ndxU];
- pWinding->p[1] = pWorldPoints[((ndxV+1)*(width+1))+ndxU];
- pWinding->p[2] = pWorldPoints[((ndxV+1)*(width+1))+(ndxU+1)];
- pWinding->p[3] = pWorldPoints[(ndxV*(width+1))+(ndxU+1)];
-
- // calculate the area
- float area = WindingArea( pWinding );
-
- int ndxSample = ( ndxV * width ) + ndxU;
- pSamples[ndxSample].w = pWinding;
- pSamples[ndxSample].area = area;
- }
- else
- {
- Msg( "BuildDispSamples: WARNING - failed winding allocation\n" );
- }
- }
- }
-
- //
- // build the samples points (based on s, t and sampleoffset (center of samples);
- // generates world space position and normal)
- //
- for( ndxV = 0; ndxV < height; ndxV++ )
- {
- for( ndxU = 0; ndxU < width; ndxU++ )
- {
- int ndxSample = ( ndxV * width ) + ndxU;
- pSamples[ndxSample].s = ndxU;
- pSamples[ndxSample].t = ndxV;
- pSamples[ndxSample].coord[0] = ( ndxU * stepU ) + halfStepU;
- pSamples[ndxSample].coord[1] = ( ndxV * stepV ) + halfStepV;
- pDispTree->DispUVToSurfPoint( pSamples[ndxSample].coord, pSamples[ndxSample].pos, 1.0f );
- pDispTree->DispUVToSurfNormal( pSamples[ndxSample].coord, pSamples[ndxSample].normal );
- }
- }
-
- //
- // copy over samples
- //
- pFaceLight->numsamples = width * height;
- pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
- if( !pFaceLight->sample )
- return false;
-
- memcpy( pFaceLight->sample, pSamples, pFaceLight->numsamples * sizeof( *pFaceLight->sample ) );
-
- // statistics - warning?!
- if( pFaceLight->numsamples == 0 )
- {
- Msg( "BuildDispSamples: WARNING - no samples %d\n", pLightInfo->face - g_pFaces );
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::BuildDispLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
-{
- // get the tree assosciated with the face
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
- CVRADDispColl *pDispTree = dispTree.m_pDispTree;
- if( !pDispTree )
- return false;
-
- // lightmap size
- int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
- int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
-
- // calcuate actual luxel points
- pFaceLight->numluxels = width * height;
- pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
- pFaceLight->luxelNormals = ( Vector* )calloc( pFaceLight->numluxels, sizeof( Vector ) );
- if( !pFaceLight->luxel || !pFaceLight->luxelNormals )
- return false;
-
- float stepU = 1.0f / ( float )( width - 1 );
- float stepV = 1.0f / ( float )( height - 1 );
-
- for( int ndxV = 0; ndxV < height; ndxV++ )
- {
- for( int ndxU = 0; ndxU < width; ndxU++ )
- {
- int ndxLuxel = ( ndxV * width ) + ndxU;
-
- Vector2D uv( ndxU * stepU, ndxV * stepV );
- pDispTree->DispUVToSurfPoint( uv, pFaceLight->luxel[ndxLuxel], 1.0f );
- pDispTree->DispUVToSurfNormal( uv, pFaceLight->luxelNormals[ndxLuxel] );
- }
- }
-
- return true;
-}
-
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CVRadDispMgr::BuildDispSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
-{
- // get the tree assosciated with the face
- DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
- CVRADDispColl *pDispTree = dispTree.m_pDispTree;
- if( !pDispTree )
- return false;
-
- // lightmap size
- int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
- int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
-
- // calcuate actual luxel points
- pFaceLight->numsamples = width * height;
- pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
- if( !pFaceLight->sample )
- return false;
-
- pFaceLight->numluxels = width * height;
- pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
- pFaceLight->luxelNormals = ( Vector* )calloc( pFaceLight->numluxels, sizeof( Vector ) );
- if( !pFaceLight->luxel || !pFaceLight->luxelNormals )
- return false;
-
- float stepU = 1.0f / ( float )( width - 1 );
- float stepV = 1.0f / ( float )( height - 1 );
- float halfStepU = stepU * 0.5f;
- float halfStepV = stepV * 0.5f;
-
- for( int ndxV = 0; ndxV < height; ndxV++ )
- {
- for( int ndxU = 0; ndxU < width; ndxU++ )
- {
- int ndx = ( ndxV * width ) + ndxU;
-
- pFaceLight->sample[ndx].s = ndxU;
- pFaceLight->sample[ndx].t = ndxV;
- pFaceLight->sample[ndx].coord[0] = ( ndxU * stepU ) + halfStepU;
- pFaceLight->sample[ndx].coord[1] = ( ndxV * stepV ) + halfStepV;
-
- pDispTree->DispUVToSurfPoint( pFaceLight->sample[ndx].coord, pFaceLight->sample[ndx].pos, 1.0f );
- pDispTree->DispUVToSurfNormal( pFaceLight->sample[ndx].coord, pFaceLight->sample[ndx].normal );
-
- pFaceLight->luxel[ndx] = pFaceLight->sample[ndx].pos;
- pFaceLight->luxelNormals[ndx] = pFaceLight->sample[ndx].normal;
- }
- }
-
- return true;
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "vrad.h"
+#include "utlvector.h"
+#include "cmodel.h"
+#include "BSPTreeData.h"
+#include "VRAD_DispColl.h"
+#include "CollisionUtils.h"
+#include "lightmap.h"
+#include "Radial.h"
+#include "CollisionUtils.h"
+#include "mathlib/bumpvects.h"
+#include "utlrbtree.h"
+#include "tier0/fasttimer.h"
+#include "disp_vrad.h"
+
+class CBSPDispRayDistanceEnumerator;
+
+//=============================================================================
+//
+// Displacement/Face List
+//
+class CBSPDispFaceListEnumerator : public ISpatialLeafEnumerator, public IBSPTreeDataEnumerator
+{
+public:
+
+ //=========================================================================
+ //
+ // Construction/Deconstruction
+ //
+ CBSPDispFaceListEnumerator() {};
+ virtual ~CBSPDispFaceListEnumerator()
+ {
+ m_DispList.Purge();
+ m_FaceList.Purge();
+ }
+
+ // ISpatialLeafEnumerator
+ bool EnumerateLeaf( int ndxLeaf, int context );
+
+ // IBSPTreeDataEnumerator
+ bool FASTCALL EnumerateElement( int userId, int context );
+
+public:
+
+ CUtlVector<CVRADDispColl*> m_DispList;
+ CUtlVector<int> m_FaceList;
+};
+
+
+//=============================================================================
+//
+// RayEnumerator
+//
+class CBSPDispRayEnumerator : public ISpatialLeafEnumerator, public IBSPTreeDataEnumerator
+{
+public:
+ // ISpatialLeafEnumerator
+ bool EnumerateLeaf( int ndxLeaf, int context );
+
+ // IBSPTreeDataEnumerator
+ bool FASTCALL EnumerateElement( int userId, int context );
+};
+
+//=============================================================================
+//
+// VRad Displacement Manager
+//
+class CVRadDispMgr : public IVRadDispMgr
+{
+public:
+
+ //=========================================================================
+ //
+ // Construction/Deconstruction
+ //
+ CVRadDispMgr();
+ virtual ~CVRadDispMgr();
+
+ // creation/destruction
+ void Init( void );
+ void Shutdown( void );
+
+ // "CalcPoints"
+ bool BuildDispSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
+ bool BuildDispLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
+ bool BuildDispSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace );
+
+ // patching functions
+ void MakePatches( void );
+ void SubdividePatch( int iPatch );
+
+ // pre "FinalLightFace"
+ void InsertSamplesDataIntoHashTable( void );
+ void InsertPatchSampleDataIntoHashTable( void );
+
+ // "FinalLightFace"
+ radial_t *BuildLuxelRadial( int ndxFace, int ndxStyle, bool bBump );
+ bool SampleRadial( int ndxFace, radial_t *pRadial, Vector const &vPos, int ndxLxl, LightingValue_t *pLightSample, int sampleCount, bool bPatch );
+ radial_t *BuildPatchRadial( int ndxFace, bool bBump );
+
+ // utility
+ void GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal, bool bInside );
+ void GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree );
+
+ // bsp tree functions
+ bool ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray );
+ bool ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray, int ndxLeaf );
+ void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray, int ndxLeaf,
+ float& dist, dface_t*& pFace, Vector2D& luxelCoord );
+ void ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
+ int ndxLeaf, float& dist, Vector *pNormal );
+
+ void StartRayTest( DispTested_t &dispTested );
+ void AddPolysForRayTrace( void );
+
+ // general timing -- should be moved!!
+ void StartTimer( const char *name );
+ void EndTimer( void );
+
+ //=========================================================================
+ //
+ // Enumeration Methods
+ //
+ bool DispRay_EnumerateLeaf( int ndxLeaf, int context );
+ bool DispRay_EnumerateElement( int userId, int context );
+ bool DispRayDistance_EnumerateElement( int userId, CBSPDispRayDistanceEnumerator* pEnum );
+
+ bool DispFaceList_EnumerateLeaf( int ndxLeaf, int context );
+ bool DispFaceList_EnumerateElement( int userId, int context );
+
+private:
+
+ //=========================================================================
+ //
+ // BSP Tree Helpers
+ //
+ void InsertDispIntoTree( int ndxDisp );
+ void RemoveDispFromTree( int ndxDisp );
+
+ //=========================================================================
+ //
+ // Displacement Data Loader (from .bsp)
+ //
+ void UnserializeDisps( void );
+ void DispBuilderInit( CCoreDispInfo *pBuilderDisp, dface_t *pFace, int ndxFace );
+
+ //=========================================================================
+ //
+ // Sampling Helpers
+ //
+ void RadialLuxelBuild( CVRADDispColl *pDispTree, radial_t *pRadial, int ndxStyle, bool bBump );
+ void RadialLuxelAddSamples( int ndxFace, Vector const &luxelPt, Vector const &luxelNormal, float radius,
+ radial_t *pRadial, int ndxRadial, bool bBump, int lightStyle );
+
+ void RadialPatchBuild( CVRADDispColl *pDispTree, radial_t *pRadial, bool bBump );
+ void RadialLuxelAddPatch( int ndxFace, Vector const &luxelPt,
+ Vector const &luxelNormal, float radius,
+ radial_t *pRadial, int ndxRadial, bool bBump,
+ CUtlVector<CPatch*> &interestingPatches );
+
+ bool IsNeighbor( int iDispFace, int iNeighborFace );
+
+ void GetInterestingPatchesForLuxels(
+ int ndxFace,
+ CUtlVector<CPatch*> &interestingPatches,
+ float patchSampleRadius );
+
+private:
+
+ struct DispCollTree_t
+ {
+ CVRADDispColl *m_pDispTree;
+ BSPTreeDataHandle_t m_Handle;
+ };
+
+ struct EnumContext_t
+ {
+ DispTested_t *m_pDispTested;
+ Ray_t const *m_pRay;
+ };
+
+ CUtlVector<DispCollTree_t> m_DispTrees;
+
+ IBSPTreeData *m_pBSPTreeData;
+
+ CBSPDispRayEnumerator m_EnumDispRay;
+ CBSPDispFaceListEnumerator m_EnumDispFaceList;
+
+ int sampleCount;
+ Vector *m_pSamplePos;
+
+ CFastTimer m_Timer;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: expose IVRadDispMgr to vrad
+//-----------------------------------------------------------------------------
+
+static CVRadDispMgr s_DispMgr;
+
+IVRadDispMgr *StaticDispMgr( void )
+{
+ return &s_DispMgr;
+}
+
+
+//=============================================================================
+//
+// Displacement/Face List
+//
+// ISpatialLeafEnumerator
+bool CBSPDispFaceListEnumerator::EnumerateLeaf( int ndxLeaf, int context )
+{
+ return s_DispMgr.DispFaceList_EnumerateLeaf( ndxLeaf, context );
+}
+
+// IBSPTreeDataEnumerator
+bool FASTCALL CBSPDispFaceListEnumerator::EnumerateElement( int userId, int context )
+{
+ return s_DispMgr.DispFaceList_EnumerateElement( userId, context );
+}
+
+
+//=============================================================================
+//
+// RayEnumerator
+//
+bool CBSPDispRayEnumerator::EnumerateLeaf( int ndxLeaf, int context )
+{
+ return s_DispMgr.DispRay_EnumerateLeaf( ndxLeaf, context );
+}
+
+bool FASTCALL CBSPDispRayEnumerator::EnumerateElement( int userId, int context )
+{
+ return s_DispMgr.DispRay_EnumerateElement( userId, context );
+}
+
+
+//-----------------------------------------------------------------------------
+// Here's an enumerator that we use for testing against disps in a leaf...
+//-----------------------------------------------------------------------------
+
+class CBSPDispRayDistanceEnumerator : public IBSPTreeDataEnumerator
+{
+public:
+ CBSPDispRayDistanceEnumerator() : m_Distance(1.0f), m_pSurface(0) {}
+
+ // IBSPTreeDataEnumerator
+ bool FASTCALL EnumerateElement( int userId, int context )
+ {
+ return s_DispMgr.DispRayDistance_EnumerateElement( userId, this );
+ }
+
+ float m_Distance;
+ dface_t* m_pSurface;
+ DispTested_t *m_pDispTested;
+ Ray_t const *m_pRay;
+ Vector2D m_LuxelCoord;
+ Vector m_Normal;
+};
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CVRadDispMgr::CVRadDispMgr()
+{
+ m_pBSPTreeData = CreateBSPTreeData();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CVRadDispMgr::~CVRadDispMgr()
+{
+ DestroyBSPTreeData( m_pBSPTreeData );
+}
+
+
+//-----------------------------------------------------------------------------
+// Insert a displacement into the tree for collision
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::InsertDispIntoTree( int ndxDisp )
+{
+ DispCollTree_t &dispTree = m_DispTrees[ndxDisp];
+ CDispCollTree *pDispTree = dispTree.m_pDispTree;
+
+ // get the bounding box of the tree
+ Vector boxMin, boxMax;
+ pDispTree->GetBounds( boxMin, boxMax );
+
+ // add the displacement to the tree so we will collide against it
+ dispTree.m_Handle = m_pBSPTreeData->Insert( ndxDisp, boxMin, boxMax );
+}
+
+
+//-----------------------------------------------------------------------------
+// Remove a displacement from the tree for collision
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::RemoveDispFromTree( int ndxDisp )
+{
+ // release the tree handle
+ if( m_DispTrees[ndxDisp].m_Handle != TREEDATA_INVALID_HANDLE )
+ {
+ m_pBSPTreeData->Remove( m_DispTrees[ndxDisp].m_Handle );
+ m_DispTrees[ndxDisp].m_Handle = TREEDATA_INVALID_HANDLE;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::Init( void )
+{
+ // initialize the bsp tree
+ m_pBSPTreeData->Init( ToolBSPTree() );
+
+ // read in displacements that have been compiled into the bsp file
+ UnserializeDisps();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::Shutdown( void )
+{
+ // remove all displacements from the tree
+ for( int ndxDisp = m_DispTrees.Size(); ndxDisp >= 0; ndxDisp-- )
+ {
+ RemoveDispFromTree( ndxDisp );
+ }
+
+ // shutdown the bsp tree
+ m_pBSPTreeData->Shutdown();
+
+ // purge the displacement collision tree list
+ m_DispTrees.Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::DispBuilderInit( CCoreDispInfo *pBuilderDisp, dface_t *pFace, int ndxFace )
+{
+ // get the .bsp displacement
+ ddispinfo_t *pDisp = &g_dispinfo[pFace->dispinfo];
+ if( !pDisp )
+ return;
+
+ //
+ // initlialize the displacement base surface
+ //
+ CCoreDispSurface *pSurf = pBuilderDisp->GetSurface();
+ pSurf->SetPointCount( 4 );
+ pSurf->SetHandle( ndxFace );
+ pSurf->SetContents( pDisp->contents );
+
+ Vector pt[4];
+ int ndxPt;
+ for( ndxPt = 0; ndxPt < 4; ndxPt++ )
+ {
+ int eIndex = dsurfedges[pFace->firstedge+ndxPt];
+ if( eIndex < 0 )
+ {
+ pSurf->SetPoint( ndxPt, dvertexes[dedges[-eIndex].v[1]].point );
+ }
+ else
+ {
+ pSurf->SetPoint( ndxPt, dvertexes[dedges[eIndex].v[0]].point );
+ }
+
+ VectorCopy( pSurf->GetPoint(ndxPt), pt[ndxPt] );
+ }
+
+ //
+ // calculate the displacement surface normal
+ //
+ Vector vFaceNormal;
+ pSurf->GetNormal( vFaceNormal );
+ for( ndxPt = 0; ndxPt < 4; ndxPt++ )
+ {
+ pSurf->SetPointNormal( ndxPt, vFaceNormal );
+ }
+
+ // set the surface initial point info
+ pSurf->SetPointStart( pDisp->startPosition );
+ pSurf->FindSurfPointStartIndex();
+ pSurf->AdjustSurfPointData();
+
+ Vector vecTmp( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][0],
+ texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][1],
+ texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][2] );
+ int nLuxelsPerWorldUnit = static_cast<int>( 1.0f / VectorLength( vecTmp ) );
+ Vector vecU( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][0],
+ texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][1],
+ texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[0][2] );
+ Vector vecV( texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][0],
+ texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][1],
+ texinfo[pFace->texinfo].lightmapVecsLuxelsPerWorldUnits[1][2] );
+ pSurf->CalcLuxelCoords( nLuxelsPerWorldUnit, false, vecU, vecV );
+
+ pBuilderDisp->SetNeighborData( pDisp->m_EdgeNeighbors, pDisp->m_CornerNeighbors );
+
+ CDispVert *pVerts = &g_DispVerts[ pDisp->m_iDispVertStart ];
+ CDispTri *pTris = &g_DispTris[pDisp->m_iDispTriStart];
+
+ //
+ // initialize the displacement data
+ //
+ pBuilderDisp->InitDispInfo(
+ pDisp->power,
+ pDisp->minTess,
+ pDisp->smoothingAngle,
+ pVerts,
+ pTris );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::UnserializeDisps( void )
+{
+ // temporarily create the "builder" displacements
+ CUtlVector<CCoreDispInfo*> builderDisps;
+ for ( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
+ {
+ CCoreDispInfo *pDisp = new CCoreDispInfo;
+ if ( !pDisp )
+ {
+ builderDisps.Purge();
+ return;
+ }
+
+ int nIndex = builderDisps.AddToTail();
+ pDisp->SetListIndex( nIndex );
+ builderDisps[nIndex] = pDisp;
+ }
+
+ // Set them up as CDispUtilsHelpers.
+ for ( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
+ {
+ builderDisps[iDisp]->SetDispUtilsHelperInfo( builderDisps.Base(), g_dispinfo.Count() );
+ }
+
+ //
+ // find all faces with displacement data and initialize
+ //
+ for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
+ {
+ dface_t *pFace = &g_pFaces[ndxFace];
+ if( ValidDispFace( pFace ) )
+ {
+ DispBuilderInit( builderDisps[pFace->dispinfo], pFace, ndxFace );
+ }
+ }
+
+ // generate the displacement surfaces
+ for( int iDisp = 0; iDisp < g_dispinfo.Count(); ++iDisp )
+ {
+ builderDisps[iDisp]->Create();
+ }
+
+ // smooth edge normals
+ SmoothNeighboringDispSurfNormals( builderDisps.Base(), g_dispinfo.Count() );
+
+ //
+ // create the displacement collision tree and add it to the bsp tree
+ //
+ CVRADDispColl *pDispTrees = new CVRADDispColl[g_dispinfo.Count()];
+ if( !pDispTrees )
+ return;
+
+ m_DispTrees.AddMultipleToTail( g_dispinfo.Count() );
+
+ for( int iDisp = 0; iDisp < g_dispinfo.Count(); iDisp++ )
+ {
+ pDispTrees[iDisp].Create( builderDisps[iDisp] );
+
+ m_DispTrees[iDisp].m_pDispTree = &pDispTrees[iDisp];
+ m_DispTrees[iDisp].m_Handle = TREEDATA_INVALID_HANDLE;
+
+ InsertDispIntoTree( iDisp );
+ }
+
+ // free "builder" disps
+ builderDisps.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: create a set of patches for each displacement surface to transfer
+// bounced light around with
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::MakePatches( void )
+{
+ // Collect stats - keep track of the total displacement surface area.
+ float flTotalArea = 0.0f;
+
+ // Create patches for all of the displacements.
+ int nTreeCount = m_DispTrees.Size();
+ for( int iTree = 0; iTree < nTreeCount; ++iTree )
+ {
+ // Get the current displacement collision tree.
+ CVRADDispColl *pDispTree = m_DispTrees[iTree].m_pDispTree;
+ if( !pDispTree )
+ continue;
+
+ flTotalArea += pDispTree->CreateParentPatches();
+ }
+
+ // Print stats.
+ qprintf( "%i Displacements\n", nTreeCount );
+ qprintf( "%i Square Feet [%.2f Square Inches]\n", ( int )( flTotalArea / 144.0f ), flTotalArea );
+}
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::SubdividePatch( int iPatch )
+{
+ // Get the current patch to subdivide.
+ CPatch *pPatch = &g_Patches[iPatch];
+ if ( !pPatch )
+ return;
+
+ // Create children patches.
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[pPatch->faceNumber].dispinfo];
+ CVRADDispColl *pTree = dispTree.m_pDispTree;
+ if( pTree )
+ {
+ pTree->CreateChildPatches( iPatch, 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::StartRayTest( DispTested_t &dispTested )
+{
+ if( m_DispTrees.Size() > 0 )
+ {
+ if( dispTested.m_pTested == 0 )
+ {
+ dispTested.m_pTested = new int[m_DispTrees.Size()];
+ memset( dispTested.m_pTested, 0, m_DispTrees.Size() * sizeof( int ) );
+ dispTested.m_Enum = 0;
+ }
+ ++dispTested.m_Enum;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::ClipRayToDisp( DispTested_t &dispTested, Ray_t const &ray )
+{
+ StartRayTest( dispTested );
+
+ EnumContext_t ctx;
+ ctx.m_pRay = &ray;
+ ctx.m_pDispTested = &dispTested;
+
+ // If it got through without a hit, it returns true
+ return !m_pBSPTreeData->EnumerateLeavesAlongRay( ray, &m_EnumDispRay, ( int )&ctx );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
+ int ndxLeaf )
+{
+ EnumContext_t ctx;
+ ctx.m_pRay = &ray;
+ ctx.m_pDispTested = &dispTested;
+
+ return !m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, ( int )&ctx );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
+ int ndxLeaf, float& dist, dface_t*& pFace, Vector2D& luxelCoord )
+{
+ CBSPDispRayDistanceEnumerator rayTestEnum;
+ rayTestEnum.m_pRay = &ray;
+ rayTestEnum.m_pDispTested = &dispTested;
+
+ m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &rayTestEnum, 0 );
+
+ dist = rayTestEnum.m_Distance;
+ pFace = rayTestEnum.m_pSurface;
+ if (pFace)
+ {
+ Vector2DCopy( rayTestEnum.m_LuxelCoord, luxelCoord );
+ }
+}
+
+void CVRadDispMgr::ClipRayToDispInLeaf( DispTested_t &dispTested, Ray_t const &ray,
+ int ndxLeaf, float& dist, Vector *pNormal )
+{
+ CBSPDispRayDistanceEnumerator rayTestEnum;
+ rayTestEnum.m_pRay = &ray;
+ rayTestEnum.m_pDispTested = &dispTested;
+
+ m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &rayTestEnum, 0 );
+ dist = rayTestEnum.m_Distance;
+ if ( rayTestEnum.m_pSurface )
+ {
+ *pNormal = rayTestEnum.m_Normal;
+ }
+}
+
+void CVRadDispMgr::AddPolysForRayTrace( void )
+{
+ int nTreeCount = m_DispTrees.Size();
+ for( int iTree = 0; iTree < nTreeCount; ++iTree )
+ {
+ // Get the current displacement collision tree.
+ CVRADDispColl *pDispTree = m_DispTrees[iTree].m_pDispTree;
+
+ // Add the triangles of the tree to the RT environment
+ pDispTree->AddPolysForRayTrace();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::GetDispSurfNormal( int ndxFace, Vector &pt, Vector &ptNormal,
+ bool bInside )
+{
+ // get the displacement surface data
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
+ CVRADDispColl *pDispTree = dispTree.m_pDispTree;
+
+ // find the parameterized displacement indices
+ Vector2D uv;
+ pDispTree->BaseFacePlaneToDispUV( pt, uv );
+
+ if( bInside )
+ {
+ if( uv[0] < 0.0f || uv[0] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[0] ); }
+ if( uv[1] < 0.0f || uv[1] > 1.0f ) { Msg( "Disp UV (%f) outside bounds!\n", uv[1] ); }
+ }
+
+ if( uv[0] < 0.0f ) { uv[0] = 0.0f; }
+ if( uv[0] > 1.0f ) { uv[0] = 1.0f; }
+ if( uv[1] < 0.0f ) { uv[1] = 0.0f; }
+ if( uv[1] > 1.0f ) { uv[1] = 1.0f; }
+
+ // get the normal at "pt"
+ pDispTree->DispUVToSurfNormal( uv, ptNormal );
+
+ // get the new "pt"
+ pDispTree->DispUVToSurfPoint( uv, pt, 1.0f );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::GetDispSurf( int ndxFace, CVRADDispColl **ppDispTree )
+{
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
+ *ppDispTree = dispTree.m_pDispTree;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::DispRay_EnumerateLeaf( int ndxLeaf, int context )
+{
+ return m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispRay, context );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::DispRay_EnumerateElement( int userId, int context )
+{
+ DispCollTree_t &dispTree = m_DispTrees[userId];
+ EnumContext_t *pCtx = ( EnumContext_t* )context;
+
+ // don't test twice (check tested value)
+ if( pCtx->m_pDispTested->m_pTested[userId] == pCtx->m_pDispTested->m_Enum )
+ return true;
+
+ // set the tested value
+ pCtx->m_pDispTested->m_pTested[userId] = pCtx->m_pDispTested->m_Enum;
+
+ // false mean stop iterating -- return false if we hit! (NOTE: opposite return
+ // result of the collision tree's ray test, thus the !)
+ CBaseTrace trace;
+ trace.fraction = 1.0f;
+ return ( !dispTree.m_pDispTree->AABBTree_Ray( *pCtx->m_pRay, pCtx->m_pRay->InvDelta(), &trace, true ) );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+bool CVRadDispMgr::DispRayDistance_EnumerateElement( int userId, CBSPDispRayDistanceEnumerator* pCtx )
+{
+ DispCollTree_t &dispTree = m_DispTrees[userId];
+
+ // don't test twice (check tested value)
+ if( pCtx->m_pDispTested->m_pTested[userId] == pCtx->m_pDispTested->m_Enum )
+ return true;
+
+ // set the tested value
+ pCtx->m_pDispTested->m_pTested[userId] = pCtx->m_pDispTested->m_Enum;
+
+ // Test the ray, if it's closer than previous tests, use it!
+ RayDispOutput_t output;
+ output.ndxVerts[0] = -1;
+ output.ndxVerts[1] = -1;
+ output.ndxVerts[2] = -1;
+ output.ndxVerts[3] = -1;
+ output.u = -1.0f;
+ output.v = -1.0f;
+ output.dist = FLT_MAX;
+
+ if (dispTree.m_pDispTree->AABBTree_Ray( *pCtx->m_pRay, output ))
+ {
+ if (output.dist < pCtx->m_Distance)
+ {
+ pCtx->m_Distance = output.dist;
+ pCtx->m_pSurface = &g_pFaces[dispTree.m_pDispTree->GetParentIndex()];
+
+ // Get the luxel coordinate
+ ComputePointFromBarycentric(
+ dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[0]),
+ dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[1]),
+ dispTree.m_pDispTree->GetLuxelCoord(output.ndxVerts[2]),
+ output.u, output.v, pCtx->m_LuxelCoord );
+
+ Vector v0,v1,v2;
+ dispTree.m_pDispTree->GetVert( output.ndxVerts[0], v0 );
+ dispTree.m_pDispTree->GetVert( output.ndxVerts[1], v1 );
+ dispTree.m_pDispTree->GetVert( output.ndxVerts[2], v2 );
+ Vector e0 = v1-v0;
+ Vector e1 = v2-v0;
+ pCtx->m_Normal = CrossProduct( e0, e1 );
+ VectorNormalize(pCtx->m_Normal);
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Test a ray against a particular dispinfo
+//-----------------------------------------------------------------------------
+
+/*
+float CVRadDispMgr::ClipRayToDisp( Ray_t const &ray, int dispinfo )
+{
+ assert( m_DispTrees.IsValidIndex(dispinfo) );
+
+ RayDispOutput_t output;
+ if (!m_DispTrees[dispinfo].m_pDispTree->AABBTree_Ray( ray, output ))
+ return 1.0f;
+ return output.dist;
+}
+*/
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::DispFaceList_EnumerateLeaf( int ndxLeaf, int context )
+{
+ //
+ // add the faces found in this leaf to the face list
+ //
+ dleaf_t *pLeaf = &dleafs[ndxLeaf];
+ for( int ndxFace = 0; ndxFace < pLeaf->numleaffaces; ndxFace++ )
+ {
+ // get the current face index
+ int ndxLeafFace = pLeaf->firstleafface + ndxFace;
+
+ // check to see if the face already lives in the list
+ int ndx;
+ int size = m_EnumDispFaceList.m_FaceList.Size();
+ for( ndx = 0; ndx < size; ndx++ )
+ {
+ if( m_EnumDispFaceList.m_FaceList[ndx] == ndxLeafFace )
+ break;
+ }
+
+ if( ndx == size )
+ {
+ int ndxList = m_EnumDispFaceList.m_FaceList.AddToTail();
+ m_EnumDispFaceList.m_FaceList[ndxList] = ndxLeafFace;
+ }
+ }
+
+ return m_pBSPTreeData->EnumerateElementsInLeaf( ndxLeaf, &m_EnumDispFaceList, context );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::DispFaceList_EnumerateElement( int userId, int context )
+{
+ DispCollTree_t &dispTree = m_DispTrees[userId];
+ CVRADDispColl *pDispTree = dispTree.m_pDispTree;
+ if( !pDispTree )
+ return false;
+
+ // check to see if the displacement already lives in the list
+ int ndx;
+ int size = m_EnumDispFaceList.m_DispList.Size();
+ for( ndx = 0; ndx < size; ndx++ )
+ {
+ if( m_EnumDispFaceList.m_DispList[ndx] == pDispTree )
+ break;
+ }
+
+ if( ndx == size )
+ {
+ int ndxList = m_EnumDispFaceList.m_DispList.AddToTail();
+ m_EnumDispFaceList.m_DispList[ndxList] = pDispTree;
+ }
+
+ return true;
+}
+
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+inline void GetSampleLight( facelight_t *pFaceLight, int ndxStyle, bool bBumped,
+ int ndxSample, LightingValue_t *pSampleLight )
+{
+// SampleLight[0].Init( 20.0f, 10.0f, 10.0f );
+// return;
+
+ // get sample from bumped lighting data
+ if( bBumped )
+ {
+ for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
+ {
+ pSampleLight[ndxBump] = pFaceLight->light[ndxStyle][ndxBump][ndxSample];
+ }
+ }
+ // just a generally lit surface
+ else
+ {
+ pSampleLight[0] = pFaceLight->light[ndxStyle][0][ndxSample];
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void AddSampleLightToRadial( Vector const &samplePos, Vector const &sampleNormal,
+ LightingValue_t *pSampleLight, float sampleRadius2,
+ Vector const &luxelPos, Vector const &luxelNormal,
+ radial_t *pRadial, int ndxRadial, bool bBumped,
+ bool bNeighborBumped )
+{
+ // check normals to see if sample contributes any light at all
+ float angle = sampleNormal.Dot( luxelNormal );
+ if ( angle < 0.15f )
+ return;
+
+ // calculate the light vector
+ Vector vSegment = samplePos - luxelPos;
+
+ // get the distance to the light
+ float dist = vSegment.Length();
+ float dist2 = dist * dist;
+
+ // Check to see if the light is within the influence.
+ float influence = 1.0f - ( dist2 / ( sampleRadius2 ) );
+ if( influence <= 0.0f )
+ return;
+
+ influence *= angle;
+
+ if( bBumped )
+ {
+ if( bNeighborBumped )
+ {
+ for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
+ {
+ pRadial->light[ndxBump][ndxRadial].AddWeighted( pSampleLight[ndxBump], influence );
+ }
+ pRadial->weight[ndxRadial] += influence;
+ }
+ else
+ {
+ influence *= 0.05f;
+ for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
+ {
+ pRadial->light[ndxBump][ndxRadial].AddWeighted( pSampleLight[0], influence );
+ }
+ pRadial->weight[ndxRadial] += influence;
+ }
+ }
+ else
+ {
+ pRadial->light[0][ndxRadial].AddWeighted( pSampleLight[0], influence );
+ pRadial->weight[ndxRadial] += influence;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::IsNeighbor( int iFace, int iNeighborFace )
+{
+ if ( iFace == iNeighborFace )
+ return true;
+
+ faceneighbor_t *pFaceNeighbor = &faceneighbor[iFace];
+ for ( int iNeighbor = 0; iNeighbor < pFaceNeighbor->numneighbors; iNeighbor++ )
+ {
+ if ( pFaceNeighbor->neighbor[iNeighbor] == iNeighborFace )
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::RadialLuxelAddSamples( int ndxFace, Vector const &luxelPt, Vector const &luxelNormal, float radius,
+ radial_t *pRadial, int ndxRadial, bool bBump, int lightStyle )
+{
+ // calculate one over the voxel size
+ float ooVoxelSize = 1.0f / SAMPLEHASH_VOXEL_SIZE;
+
+ //
+ // find voxel info
+ //
+ int voxelMin[3], voxelMax[3];
+ for( int axis = 0; axis < 3; axis++ )
+ {
+ voxelMin[axis] = ( int )( ( luxelPt[axis] - radius ) * ooVoxelSize );
+ voxelMax[axis] = ( int )( ( luxelPt[axis] + radius ) * ooVoxelSize ) + 1;
+ }
+
+ SampleData_t sampleData;
+ for( int ndxZ = voxelMin[2]; ndxZ < voxelMax[2] + 1; ndxZ++ )
+ {
+ for( int ndxY = voxelMin[1]; ndxY < voxelMax[1] + 1; ndxY++ )
+ {
+ for( int ndxX = voxelMin[0]; ndxX < voxelMax[0] + 1; ndxX++ )
+ {
+ sampleData.x = ndxX * 100;
+ sampleData.y = ndxY * 10;
+ sampleData.z = ndxZ;
+
+ UtlHashHandle_t handle = g_SampleHashTable.Find( sampleData );
+ if( handle != g_SampleHashTable.InvalidHandle() )
+ {
+ SampleData_t *pSampleData = &g_SampleHashTable.Element( handle );
+ int count = pSampleData->m_Samples.Count();
+ for( int ndx = 0; ndx < count; ndx++ )
+ {
+ SampleHandle_t sampleHandle = pSampleData->m_Samples.Element( ndx );
+ int ndxSample = ( sampleHandle & 0x0000ffff );
+ int ndxFaceLight = ( ( sampleHandle >> 16 ) & 0x0000ffff );
+
+ facelight_t *pFaceLight = &facelight[ndxFaceLight];
+ if( pFaceLight && IsNeighbor( ndxFace, ndxFaceLight ) )
+ {
+ //
+ // check for similar lightstyles
+ //
+ dface_t *pFace = &g_pFaces[ndxFaceLight];
+ if( pFace )
+ {
+ int ndxNeighborStyle = -1;
+ for( int ndxLightStyle = 0; ndxLightStyle < MAXLIGHTMAPS; ndxLightStyle++ )
+ {
+ if( pFace->styles[ndxLightStyle] == lightStyle )
+ {
+ ndxNeighborStyle = ndxLightStyle;
+ break;
+ }
+ }
+ if( ndxNeighborStyle == -1 )
+ continue;
+
+ // is this surface bumped???
+ bool bNeighborBump = texinfo[pFace->texinfo].flags & SURF_BUMPLIGHT ? true : false;
+
+ LightingValue_t sampleLight[NUM_BUMP_VECTS+1];
+ GetSampleLight( pFaceLight, ndxNeighborStyle, bNeighborBump, ndxSample, sampleLight );
+ AddSampleLightToRadial( pFaceLight->sample[ndxSample].pos, pFaceLight->sample[ndxSample].normal,
+ sampleLight, radius*radius, luxelPt, luxelNormal, pRadial, ndxRadial,
+ bBump, bNeighborBump );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::RadialLuxelBuild( CVRADDispColl *pDispTree, radial_t *pRadial,
+ int ndxStyle, bool bBump )
+{
+ //
+ // get data lighting data
+ //
+ int ndxFace = pDispTree->GetParentIndex();
+
+ dface_t *pFace = &g_pFaces[ndxFace];
+ facelight_t *pFaceLight = &facelight[ndxFace];
+
+ // get the influence radius
+ float radius2 = pDispTree->GetSampleRadius2();
+ float radius = ( float )sqrt( radius2 );
+
+ int radialSize = pRadial->w * pRadial->h;
+ for( int ndxRadial = 0; ndxRadial < radialSize; ndxRadial++ )
+ {
+ RadialLuxelAddSamples( ndxFace, pFaceLight->luxel[ndxRadial], pFaceLight->luxelNormals[ndxRadial],
+ radius, pRadial, ndxRadial, bBump, pFace->styles[ndxStyle] );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+radial_t *CVRadDispMgr::BuildLuxelRadial( int ndxFace, int ndxStyle, bool bBump )
+{
+ // allocate the radial
+ radial_t *pRadial = AllocateRadial( ndxFace );
+ if( !pRadial )
+ return NULL;
+
+ //
+ // step 1: get the displacement surface to be lit
+ //
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
+ CVRADDispColl *pDispTree = dispTree.m_pDispTree;
+ if( !pDispTree )
+ return NULL;
+
+ // step 2: build radial luxels
+ RadialLuxelBuild( pDispTree, pRadial, ndxStyle, bBump );
+
+ // step 3: return the built radial
+ return pRadial;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::SampleRadial( int ndxFace, radial_t *pRadial, Vector const &vPos, int ndxLxl,
+ LightingValue_t *pLightSample, int sampleCount, bool bPatch )
+{
+ bool bGoodSample = true;
+ for ( int count = 0; count < sampleCount; count++ )
+ {
+ pLightSample[count].Zero();
+
+ if ( pRadial->weight[ndxLxl] > 0.0f )
+ {
+ pLightSample[count].AddWeighted( pRadial->light[count][ndxLxl], ( 1.0f / pRadial->weight[ndxLxl] ) );
+ }
+ else
+ {
+ // error, luxel has no samples (not for patches)
+ if ( !bPatch )
+ {
+ // Yes, 2550 is correct!
+ // pLightSample[count].Init( 2550.0f, 0.0f, 2550.0f );
+ if( count == 0 )
+ bGoodSample = false;
+ }
+ }
+ }
+
+ return bGoodSample;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void GetPatchLight( CPatch *pPatch, bool bBump, Vector *pPatchLight )
+{
+ VectorCopy( pPatch->totallight.light[0], pPatchLight[0] );
+
+ if( bBump )
+ {
+ for( int ndxBump = 1; ndxBump < ( NUM_BUMP_VECTS + 1 ); ndxBump++ )
+ {
+ VectorCopy( pPatch->totallight.light[ndxBump], pPatchLight[ndxBump] );
+ }
+ }
+}
+
+extern void GetBumpNormals( const float* sVect, const float* tVect, const Vector& flatNormal,
+ const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] );
+extern void PreGetBumpNormalsForDisp( texinfo_t *pTexinfo, Vector &vecU, Vector &vecV, Vector &vecNormal );
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void AddPatchLightToRadial( Vector const &patchOrigin, Vector const &patchNormal,
+ Vector *pPatchLight, float patchRadius2,
+ Vector const &luxelPos, Vector const &luxelNormal,
+ radial_t *pRadial, int ndxRadial, bool bBump,
+ bool bNeighborBump )
+{
+ // calculate the light vector
+ Vector vSegment = patchOrigin - luxelPos;
+
+ // get the distance to the light
+ float dist = vSegment.Length();
+ float dist2 = dist * dist;
+
+ // Check to see if the light is within the sample influence.
+ float influence = 1.0f - ( dist2 / ( patchRadius2 ) );
+ if ( influence <= 0.0f )
+ return;
+
+ if( bBump )
+ {
+ Vector normals[NUM_BUMP_VECTS+1];
+ normals[0] = luxelNormal;
+ texinfo_t *pTexinfo = &texinfo[g_pFaces[pRadial->facenum].texinfo];
+ Vector vecTexU, vecTexV;
+ PreGetBumpNormalsForDisp( pTexinfo, vecTexU, vecTexV, normals[0] );
+ GetBumpNormals( vecTexU, vecTexV, normals[0], normals[0], &normals[1] );
+
+ if( bNeighborBump )
+ {
+ float flScale = patchNormal.Dot( normals[0] );
+ flScale = max( 0.0f, flScale );
+ float flBumpInfluence = influence * flScale;
+
+ for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
+ {
+ pRadial->light[ndxBump][ndxRadial].AddWeighted( pPatchLight[ndxBump], flBumpInfluence );
+ }
+
+ pRadial->weight[ndxRadial] += flBumpInfluence;
+ }
+ else
+ {
+ float flScale = patchNormal.Dot( normals[0] );
+ flScale = max( 0.0f, flScale );
+ float flBumpInfluence = influence * flScale * 0.05f;
+
+ for( int ndxBump = 0; ndxBump < ( NUM_BUMP_VECTS+1 ); ndxBump++ )
+ {
+ pRadial->light[ndxBump][ndxRadial].AddWeighted( pPatchLight[0], flBumpInfluence );
+ }
+
+ pRadial->weight[ndxRadial] += flBumpInfluence;
+ }
+ }
+ else
+ {
+ float flScale = patchNormal.Dot( luxelNormal );
+ flScale = max( 0.0f, flScale );
+ influence *= flScale;
+ pRadial->light[0][ndxRadial].AddWeighted( pPatchLight[0], influence );
+
+ // add the weight value
+ pRadial->weight[ndxRadial] += influence;
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::RadialLuxelAddPatch( int ndxFace, Vector const &luxelPt,
+ Vector const &luxelNormal, float radius,
+ radial_t *pRadial, int ndxRadial, bool bBump,
+ CUtlVector<CPatch*> &interestingPatches )
+{
+#ifdef SAMPLEHASH_QUERY_ONCE
+ for ( int i=0; i < interestingPatches.Count(); i++ )
+ {
+ CPatch *pPatch = interestingPatches[i];
+ bool bNeighborBump = texinfo[g_pFaces[pPatch->faceNumber].texinfo].flags & SURF_BUMPLIGHT ? true : false;
+
+ Vector patchLight[NUM_BUMP_VECTS+1];
+ GetPatchLight( pPatch, bBump, patchLight );
+ AddPatchLightToRadial( pPatch->origin, pPatch->normal, patchLight, radius*radius,
+ luxelPt, luxelNormal, pRadial, ndxRadial, bBump, bNeighborBump );
+ }
+#else
+ // calculate one over the voxel size
+ float ooVoxelSize = 1.0f / SAMPLEHASH_VOXEL_SIZE;
+
+ //
+ // find voxel info
+ //
+ int voxelMin[3], voxelMax[3];
+ for ( int axis = 0; axis < 3; axis++ )
+ {
+ voxelMin[axis] = ( int )( ( luxelPt[axis] - radius ) * ooVoxelSize );
+ voxelMax[axis] = ( int )( ( luxelPt[axis] + radius ) * ooVoxelSize ) + 1;
+ }
+
+ unsigned short curIterationKey = IncrementPatchIterationKey();
+ PatchSampleData_t patchData;
+ for ( int ndxZ = voxelMin[2]; ndxZ < voxelMax[2] + 1; ndxZ++ )
+ {
+ for ( int ndxY = voxelMin[1]; ndxY < voxelMax[1] + 1; ndxY++ )
+ {
+ for ( int ndxX = voxelMin[0]; ndxX < voxelMax[0] + 1; ndxX++ )
+ {
+ patchData.x = ndxX * 100;
+ patchData.y = ndxY * 10;
+ patchData.z = ndxZ;
+
+ UtlHashHandle_t handle = g_PatchSampleHashTable.Find( patchData );
+ if ( handle != g_PatchSampleHashTable.InvalidHandle() )
+ {
+ PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
+ int count = pPatchData->m_ndxPatches.Count();
+ for ( int ndx = 0; ndx < count; ndx++ )
+ {
+ int ndxPatch = pPatchData->m_ndxPatches.Element( ndx );
+ CPatch *pPatch = &g_Patches.Element( ndxPatch );
+ if ( pPatch && pPatch->m_IterationKey != curIterationKey )
+ {
+ pPatch->m_IterationKey = curIterationKey;
+
+ if ( IsNeighbor( ndxFace, pPatch->faceNumber ) )
+ {
+ bool bNeighborBump = texinfo[g_pFaces[pPatch->faceNumber].texinfo].flags & SURF_BUMPLIGHT ? true : false;
+
+ Vector patchLight[NUM_BUMP_VECTS+1];
+ GetPatchLight( pPatch, bBump, patchLight );
+ AddPatchLightToRadial( pPatch->origin, pPatch->normal, patchLight, radius*radius,
+ luxelPt, luxelNormal, pRadial, ndxRadial, bBump, bNeighborBump );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif
+}
+
+
+void CVRadDispMgr::GetInterestingPatchesForLuxels(
+ int ndxFace,
+ CUtlVector<CPatch*> &interestingPatches,
+ float patchSampleRadius )
+{
+ facelight_t *pFaceLight = &facelight[ndxFace];
+
+ // Get the max bounds of all voxels that these luxels touch.
+ Vector vLuxelMin( FLT_MAX, FLT_MAX, FLT_MAX );
+ Vector vLuxelMax( -FLT_MAX, -FLT_MAX, -FLT_MAX );
+ for ( int i=0; i < pFaceLight->numluxels; i++ )
+ {
+ VectorMin( pFaceLight->luxel[i], vLuxelMin, vLuxelMin );
+ VectorMax( pFaceLight->luxel[i], vLuxelMax, vLuxelMax );
+ }
+
+ int allVoxelMin[3], allVoxelMax[3];
+ for ( int axis = 0; axis < 3; axis++ )
+ {
+ allVoxelMin[axis] = ( int )( ( vLuxelMin[axis] - patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE );
+ allVoxelMax[axis] = ( int )( ( vLuxelMax[axis] + patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE ) + 1;
+ }
+ int allVoxelSize[3] = { allVoxelMax[0] - allVoxelMin[0], allVoxelMax[1] - allVoxelMin[1], allVoxelMax[2] - allVoxelMin[2] };
+
+
+ // Now figure out exactly which voxels these luxels touch.
+ CUtlVector<unsigned char> voxelBits;
+ voxelBits.SetSize( ((allVoxelSize[0] * allVoxelSize[1] * allVoxelSize[2]) + 7) / 8 );
+ memset( voxelBits.Base(), 0, voxelBits.Count() );
+
+ for ( int i=0; i < pFaceLight->numluxels; i++ )
+ {
+ int voxelMin[3], voxelMax[3];
+ for ( int axis=0; axis < 3; axis++ )
+ {
+ voxelMin[axis] = ( int )( ( pFaceLight->luxel[i][axis] - patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE );
+ voxelMax[axis] = ( int )( ( pFaceLight->luxel[i][axis] + patchSampleRadius ) / SAMPLEHASH_VOXEL_SIZE ) + 1;
+ }
+
+ for ( int x=voxelMin[0]; x < voxelMax[0]; x++ )
+ {
+ for ( int y=voxelMin[1]; y < voxelMax[1]; y++ )
+ {
+ for ( int z=voxelMin[2]; z < voxelMax[2]; z++ )
+ {
+ int iBit = (z - allVoxelMin[2])*(allVoxelSize[0]*allVoxelSize[1]) +
+ (y-allVoxelMin[1])*allVoxelSize[0] +
+ (x-allVoxelMin[0]);
+ voxelBits[iBit>>3] |= (1 << (iBit & 7));
+ }
+ }
+ }
+ }
+
+
+ // Now get the list of patches that touch those voxels.
+ unsigned short curIterationKey = IncrementPatchIterationKey();
+
+ for ( int x=0; x < allVoxelSize[0]; x++ )
+ {
+ for ( int y=0; y < allVoxelSize[1]; y++ )
+ {
+ for ( int z=0; z < allVoxelSize[2]; z++ )
+ {
+ // Make sure this voxel has any luxels that care about it.
+ int iBit = z*(allVoxelSize[0]*allVoxelSize[1]) + y*allVoxelSize[0] + x;
+ unsigned char val = voxelBits[iBit>>3] & (1 << (iBit & 7));
+ if ( !val )
+ continue;
+
+ PatchSampleData_t patchData;
+ patchData.x = (x + allVoxelMin[0]) * 100;
+ patchData.y = (y + allVoxelMin[1]) * 10;
+ patchData.z = (z + allVoxelMin[2]);
+
+ UtlHashHandle_t handle = g_PatchSampleHashTable.Find( patchData );
+ if ( handle != g_PatchSampleHashTable.InvalidHandle() )
+ {
+ PatchSampleData_t *pPatchData = &g_PatchSampleHashTable.Element( handle );
+
+ // For all patches that touch this hash table element..
+ for ( int ndx = 0; ndx < pPatchData->m_ndxPatches.Count(); ndx++ )
+ {
+ int ndxPatch = pPatchData->m_ndxPatches.Element( ndx );
+ CPatch *pPatch = &g_Patches.Element( ndxPatch );
+
+ // If we haven't touched the patch already and it's a valid neighbor, then we want to use it.
+ if ( pPatch && pPatch->m_IterationKey != curIterationKey )
+ {
+ pPatch->m_IterationKey = curIterationKey;
+
+ if ( IsNeighbor( ndxFace, pPatch->faceNumber ) )
+ {
+ interestingPatches.AddToTail( pPatch );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::RadialPatchBuild( CVRADDispColl *pDispTree, radial_t *pRadial,
+ bool bBump )
+{
+ //
+ // get data lighting data
+ //
+ int ndxFace = pDispTree->GetParentIndex();
+ facelight_t *pFaceLight = &facelight[ndxFace];
+
+ // get the influence radius
+ float radius2 = pDispTree->GetPatchSampleRadius2();
+ float radius = ( float )sqrt( radius2 );
+
+ CUtlVector<CPatch*> interestingPatches;
+#ifdef SAMPLEHASH_QUERY_ONCE
+ GetInterestingPatchesForLuxels( ndxFace, interestingPatches, radius );
+#endif
+
+ int radialSize = pRadial->w * pRadial->h;
+ for( int ndxRadial = 0; ndxRadial < radialSize; ndxRadial++ )
+ {
+ RadialLuxelAddPatch(
+ ndxFace,
+ pFaceLight->luxel[ndxRadial],
+ pFaceLight->luxelNormals[ndxRadial],
+ radius,
+ pRadial,
+ ndxRadial,
+ bBump,
+ interestingPatches );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+radial_t *CVRadDispMgr::BuildPatchRadial( int ndxFace, bool bBump )
+{
+ // allocate the radial
+ radial_t *pRadial = AllocateRadial( ndxFace );
+ if( !pRadial )
+ return NULL;
+
+ //
+ // step 1: get the displacement surface to be lit
+ //
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
+ CVRADDispColl *pDispTree = dispTree.m_pDispTree;
+ if( !pDispTree )
+ return NULL;
+
+ // step 2: build radial of patch light
+ RadialPatchBuild( pDispTree, pRadial, bBump );
+
+ // step 3: return the built radial
+ return pRadial;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool SampleInSolid( sample_t *pSample )
+{
+ int ndxLeaf = PointLeafnum( pSample->pos );
+ return ( dleafs[ndxLeaf].contents == CONTENTS_SOLID );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::InsertSamplesDataIntoHashTable( void )
+{
+ int totalSamples = 0;
+#if 0
+ int totalSamplesInSolid = 0;
+#endif
+
+ for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
+ {
+ dface_t *pFace = &g_pFaces[ndxFace];
+ facelight_t *pFaceLight = &facelight[ndxFace];
+ if( !pFace || !pFaceLight )
+ continue;
+
+ if( texinfo[pFace->texinfo].flags & TEX_SPECIAL )
+ continue;
+
+#if 0
+ bool bDisp = ( pFace->dispinfo != -1 );
+#endif
+ //
+ // for each sample
+ //
+ for( int ndxSample = 0; ndxSample < pFaceLight->numsamples; ndxSample++ )
+ {
+ sample_t *pSample = &pFaceLight->sample[ndxSample];
+ if( pSample )
+ {
+#if 0
+ if( bDisp )
+ {
+ // test sample to see if the displacement samples resides in solid
+ if( SampleInSolid( pSample ) )
+ {
+ totalSamplesInSolid++;
+ continue;
+ }
+ }
+#endif
+
+ // create the sample handle
+ SampleHandle_t sampleHandle = ndxSample;
+ sampleHandle |= ( ndxFace << 16 );
+
+ SampleData_AddSample( pSample, sampleHandle );
+ }
+
+ }
+
+ totalSamples += pFaceLight->numsamples;
+ }
+
+#if 0
+ // not implemented yet!!!
+ Msg( "%d samples in solid\n", totalSamplesInSolid );
+#endif
+
+ // log the distribution
+ SampleData_Log();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::InsertPatchSampleDataIntoHashTable( void )
+{
+ // don't insert patch samples if we are not bouncing light
+ if( numbounce <= 0 )
+ return;
+
+ int totalPatchSamples = 0;
+
+ for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ )
+ {
+ dface_t *pFace = &g_pFaces[ndxFace];
+ facelight_t *pFaceLight = &facelight[ndxFace];
+ if( !pFace || !pFaceLight )
+ continue;
+
+ if( texinfo[pFace->texinfo].flags & TEX_SPECIAL )
+ continue;
+
+ //
+ // for each patch
+ //
+ CPatch *pNextPatch = NULL;
+ if( g_FacePatches.Element( ndxFace ) != g_FacePatches.InvalidIndex() )
+ {
+ for( CPatch *pPatch = &g_Patches.Element( g_FacePatches.Element( ndxFace ) ); pPatch; pPatch = pNextPatch )
+ {
+ // next patch
+ pNextPatch = NULL;
+ if( pPatch->ndxNext != g_Patches.InvalidIndex() )
+ {
+ pNextPatch = &g_Patches.Element( pPatch->ndxNext );
+ }
+
+ // skip patches with children
+ if( pPatch->child1 != g_Patches.InvalidIndex() )
+ continue;
+
+ int ndxPatch = pPatch - g_Patches.Base();
+ PatchSampleData_AddSample( pPatch, ndxPatch );
+
+ totalPatchSamples++;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::StartTimer( const char *name )
+{
+ Msg( name );
+ m_Timer.Start();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CVRadDispMgr::EndTimer( void )
+{
+ m_Timer.End();
+ CCycleCount duration = m_Timer.GetDuration();
+ double seconds = duration.GetSeconds();
+
+ Msg( "Done<%1.4lf sec>\n", seconds );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::BuildDispSamples( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
+{
+ // get the tree assosciated with the face
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
+ CVRADDispColl *pDispTree = dispTree.m_pDispTree;
+ if( !pDispTree )
+ return false;
+
+ // lightmap size
+ int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
+ int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
+
+ // calculate the steps in uv space
+ float stepU = 1.0f / ( float )width;
+ float stepV = 1.0f / ( float )height;
+ float halfStepU = stepU * 0.5f;
+ float halfStepV = stepV * 0.5f;
+
+ //
+ // build the winding points (used to generate world space winding and
+ // calculate the area of the "sample")
+ //
+ int ndxU, ndxV;
+
+ CUtlVector<sample_t> samples;
+ samples.SetCount( SINGLEMAP );
+ sample_t *pSamples = samples.Base();
+
+ CUtlVector<Vector> worldPoints;
+ worldPoints.SetCount( SINGLEMAP );
+ Vector *pWorldPoints = worldPoints.Base();
+
+ for( ndxV = 0; ndxV < ( height + 1 ); ndxV++ )
+ {
+ for( ndxU = 0; ndxU < ( width + 1 ); ndxU++ )
+ {
+ int ndx = ( ndxV * ( width + 1 ) ) + ndxU;
+
+ Vector2D uv( ndxU * stepU, ndxV * stepV );
+ pDispTree->DispUVToSurfPoint( uv, pWorldPoints[ndx], 0.0f );
+ }
+ }
+
+ for( ndxV = 0; ndxV < height; ndxV++ )
+ {
+ for( ndxU = 0; ndxU < width; ndxU++ )
+ {
+ // build the winding
+ winding_t *pWinding = AllocWinding( 4 );
+ if( pWinding )
+ {
+ pWinding->numpoints = 4;
+ pWinding->p[0] = pWorldPoints[(ndxV*(width+1))+ndxU];
+ pWinding->p[1] = pWorldPoints[((ndxV+1)*(width+1))+ndxU];
+ pWinding->p[2] = pWorldPoints[((ndxV+1)*(width+1))+(ndxU+1)];
+ pWinding->p[3] = pWorldPoints[(ndxV*(width+1))+(ndxU+1)];
+
+ // calculate the area
+ float area = WindingArea( pWinding );
+
+ int ndxSample = ( ndxV * width ) + ndxU;
+ pSamples[ndxSample].w = pWinding;
+ pSamples[ndxSample].area = area;
+ }
+ else
+ {
+ Msg( "BuildDispSamples: WARNING - failed winding allocation\n" );
+ }
+ }
+ }
+
+ //
+ // build the samples points (based on s, t and sampleoffset (center of samples);
+ // generates world space position and normal)
+ //
+ for( ndxV = 0; ndxV < height; ndxV++ )
+ {
+ for( ndxU = 0; ndxU < width; ndxU++ )
+ {
+ int ndxSample = ( ndxV * width ) + ndxU;
+ pSamples[ndxSample].s = ndxU;
+ pSamples[ndxSample].t = ndxV;
+ pSamples[ndxSample].coord[0] = ( ndxU * stepU ) + halfStepU;
+ pSamples[ndxSample].coord[1] = ( ndxV * stepV ) + halfStepV;
+ pDispTree->DispUVToSurfPoint( pSamples[ndxSample].coord, pSamples[ndxSample].pos, 1.0f );
+ pDispTree->DispUVToSurfNormal( pSamples[ndxSample].coord, pSamples[ndxSample].normal );
+ }
+ }
+
+ //
+ // copy over samples
+ //
+ pFaceLight->numsamples = width * height;
+ pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
+ if( !pFaceLight->sample )
+ return false;
+
+ memcpy( pFaceLight->sample, pSamples, pFaceLight->numsamples * sizeof( *pFaceLight->sample ) );
+
+ // statistics - warning?!
+ if( pFaceLight->numsamples == 0 )
+ {
+ Msg( "BuildDispSamples: WARNING - no samples %d\n", pLightInfo->face - g_pFaces );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::BuildDispLuxels( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
+{
+ // get the tree assosciated with the face
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
+ CVRADDispColl *pDispTree = dispTree.m_pDispTree;
+ if( !pDispTree )
+ return false;
+
+ // lightmap size
+ int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
+ int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
+
+ // calcuate actual luxel points
+ pFaceLight->numluxels = width * height;
+ pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
+ pFaceLight->luxelNormals = ( Vector* )calloc( pFaceLight->numluxels, sizeof( Vector ) );
+ if( !pFaceLight->luxel || !pFaceLight->luxelNormals )
+ return false;
+
+ float stepU = 1.0f / ( float )( width - 1 );
+ float stepV = 1.0f / ( float )( height - 1 );
+
+ for( int ndxV = 0; ndxV < height; ndxV++ )
+ {
+ for( int ndxU = 0; ndxU < width; ndxU++ )
+ {
+ int ndxLuxel = ( ndxV * width ) + ndxU;
+
+ Vector2D uv( ndxU * stepU, ndxV * stepV );
+ pDispTree->DispUVToSurfPoint( uv, pFaceLight->luxel[ndxLuxel], 1.0f );
+ pDispTree->DispUVToSurfNormal( uv, pFaceLight->luxelNormals[ndxLuxel] );
+ }
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CVRadDispMgr::BuildDispSamplesAndLuxels_DoFast( lightinfo_t *pLightInfo, facelight_t *pFaceLight, int ndxFace )
+{
+ // get the tree assosciated with the face
+ DispCollTree_t &dispTree = m_DispTrees[g_pFaces[ndxFace].dispinfo];
+ CVRADDispColl *pDispTree = dispTree.m_pDispTree;
+ if( !pDispTree )
+ return false;
+
+ // lightmap size
+ int width = pLightInfo->face->m_LightmapTextureSizeInLuxels[0]+1;
+ int height = pLightInfo->face->m_LightmapTextureSizeInLuxels[1]+1;
+
+ // calcuate actual luxel points
+ pFaceLight->numsamples = width * height;
+ pFaceLight->sample = ( sample_t* )calloc( pFaceLight->numsamples, sizeof( *pFaceLight->sample ) );
+ if( !pFaceLight->sample )
+ return false;
+
+ pFaceLight->numluxels = width * height;
+ pFaceLight->luxel = ( Vector* )calloc( pFaceLight->numluxels, sizeof( *pFaceLight->luxel ) );
+ pFaceLight->luxelNormals = ( Vector* )calloc( pFaceLight->numluxels, sizeof( Vector ) );
+ if( !pFaceLight->luxel || !pFaceLight->luxelNormals )
+ return false;
+
+ float stepU = 1.0f / ( float )( width - 1 );
+ float stepV = 1.0f / ( float )( height - 1 );
+ float halfStepU = stepU * 0.5f;
+ float halfStepV = stepV * 0.5f;
+
+ for( int ndxV = 0; ndxV < height; ndxV++ )
+ {
+ for( int ndxU = 0; ndxU < width; ndxU++ )
+ {
+ int ndx = ( ndxV * width ) + ndxU;
+
+ pFaceLight->sample[ndx].s = ndxU;
+ pFaceLight->sample[ndx].t = ndxV;
+ pFaceLight->sample[ndx].coord[0] = ( ndxU * stepU ) + halfStepU;
+ pFaceLight->sample[ndx].coord[1] = ( ndxV * stepV ) + halfStepV;
+
+ pDispTree->DispUVToSurfPoint( pFaceLight->sample[ndx].coord, pFaceLight->sample[ndx].pos, 1.0f );
+ pDispTree->DispUVToSurfNormal( pFaceLight->sample[ndx].coord, pFaceLight->sample[ndx].normal );
+
+ pFaceLight->luxel[ndx] = pFaceLight->sample[ndx].pos;
+ pFaceLight->luxelNormals[ndx] = pFaceLight->sample[ndx].normal;
+ }
+ }
+
+ return true;
+}