diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/vrad/vismat.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'utils/vrad/vismat.cpp')
| -rw-r--r-- | utils/vrad/vismat.cpp | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/utils/vrad/vismat.cpp b/utils/vrad/vismat.cpp new file mode 100644 index 0000000..ca9398e --- /dev/null +++ b/utils/vrad/vismat.cpp @@ -0,0 +1,483 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "vrad.h" +#include "vmpi.h" +#ifdef MPI +#include "messbuf.h" +static MessageBuffer mb; +#endif + +#define HALFBIT + +extern char source[MAX_PATH]; +extern char vismatfile[_MAX_PATH]; +extern char incrementfile[_MAX_PATH]; +extern qboolean incremental; + +/* +=================================================================== + +VISIBILITY MATRIX + +Determine which patches can see each other +Use the PVS to accelerate if available +=================================================================== +*/ + +#define TEST_EPSILON 0.1 +#define PLANE_TEST_EPSILON 0.01 // patch must be this much in front of the plane to be considered "in front" +#define PATCH_FACE_OFFSET 0.1 // push patch origins off from the face by this amount to avoid self collisions + +#define STREAM_SIZE 512 + +class CTransferMaker +{ +public: + + CTransferMaker( transfer_t *all_transfers ); + ~CTransferMaker(); + + FORCEINLINE void TestMakeTransfer( Vector start, Vector stop, int ndxShooter, int ndxReciever ) + { + g_RtEnv.AddToRayStream( m_RayStream, start, stop, &m_pResults[m_nTests] ); + m_pShooterPatches[m_nTests] = ndxShooter; + m_pRecieverPatches[m_nTests] = ndxReciever; + ++m_nTests; + } + + void Finish(); + +private: + + int m_nTests; + RayTracingSingleResult *m_pResults; + int *m_pShooterPatches; + int *m_pRecieverPatches; + RayStream m_RayStream; + transfer_t *m_AllTransfers; +}; + +CTransferMaker::CTransferMaker( transfer_t *all_transfers ) : + m_AllTransfers( all_transfers ), m_nTests( 0 ) +{ + m_pResults = (RayTracingSingleResult *)calloc( 1, MAX_PATCHES * sizeof ( RayTracingSingleResult ) ); + m_pShooterPatches = (int *)calloc( 1, MAX_PATCHES * sizeof( int ) ); + m_pRecieverPatches = (int *)calloc( 1, MAX_PATCHES * sizeof( int ) ); +} + +CTransferMaker::~CTransferMaker() +{ + free ( m_pResults ); + free ( m_pShooterPatches ); + free (m_pRecieverPatches ); +} + +void CTransferMaker::Finish() +{ + g_RtEnv.FinishRayStream( m_RayStream ); + for ( int i = 0; i < m_nTests; ++i ) + { + if ( m_pResults[i].HitID == -1 || m_pResults[i].HitDistance >= m_pResults[i].ray_length ) + { + MakeTransfer( m_pShooterPatches[i], m_pRecieverPatches[i], m_AllTransfers ); + } + } + m_nTests = 0; +} + + +dleaf_t* PointInLeaf (int iNode, Vector const& point) +{ + if ( iNode < 0 ) + return &dleafs[ (-1-iNode) ]; + + dnode_t *node = &dnodes[iNode]; + dplane_t *plane = &dplanes[ node->planenum ]; + + float dist = DotProduct (point, plane->normal) - plane->dist; + if ( dist > TEST_EPSILON ) + { + return PointInLeaf( node->children[0], point ); + } + else if ( dist < -TEST_EPSILON ) + { + return PointInLeaf( node->children[1], point ); + } + else + { + dleaf_t *pTest = PointInLeaf( node->children[0], point ); + if ( pTest->cluster != -1 ) + return pTest; + + return PointInLeaf( node->children[1], point ); + } +} + + +int ClusterFromPoint( Vector const& point ) +{ + dleaf_t *leaf = PointInLeaf( 0, point ); + + return leaf->cluster; +} + +void PvsForOrigin (Vector& org, byte *pvs) +{ + int visofs; + int cluster; + + if (!visdatasize) + { + memset (pvs, 255, (dvis->numclusters+7)/8 ); + return; + } + + cluster = ClusterFromPoint( org ); + if ( cluster < 0 ) + { + visofs = -1; + } + else + { + visofs = dvis->bitofs[ cluster ][DVIS_PVS]; + } + + if (visofs == -1) + Error ("visofs == -1"); + + DecompressVis (&dvisdata[visofs], pvs); +} + + +void TestPatchToPatch( int ndxPatch1, int ndxPatch2, int head, transfer_t *transfers, CTransferMaker &transferMaker, int iThread ) +{ + Vector tmp; + + // + // get patches + // + if( ndxPatch1 == g_Patches.InvalidIndex() || ndxPatch2 == g_Patches.InvalidIndex() ) + return; + + CPatch *patch = &g_Patches.Element( ndxPatch1 ); + CPatch *patch2 = &g_Patches.Element( ndxPatch2 ); + + if (patch2->child1 != g_Patches.InvalidIndex() ) + { + // check to see if we should use a child node instead + + VectorSubtract( patch->origin, patch2->origin, tmp ); + // SQRT( 1/4 ) + // FIXME: should be based on form-factor (ie. include visible angle, etc) + if ( DotProduct(tmp, tmp) * 0.0625 < patch2->area ) + { + TestPatchToPatch( ndxPatch1, patch2->child1, head, transfers, transferMaker, iThread ); + TestPatchToPatch( ndxPatch1, patch2->child2, head, transfers, transferMaker, iThread ); + return; + } + } + + // check vis between patch and patch2 + // if bit has not already been set + // && v2 is not behind light plane + // && v2 is visible from v1 + if ( DotProduct( patch2->origin, patch->normal ) > patch->planeDist + PLANE_TEST_EPSILON ) + { + // push out origins from face so that don't intersect their owners + Vector p1, p2; + VectorAdd( patch->origin, patch->normal, p1 ); + VectorAdd( patch2->origin, patch2->normal, p2 ); + transferMaker.TestMakeTransfer( p1, p2, ndxPatch1, ndxPatch2 ); + } +} + + +/* +============== +TestPatchToFace + +Sets vis bits for all patches in the face +============== +*/ +void TestPatchToFace (unsigned patchnum, int facenum, int head, transfer_t *transfers, CTransferMaker &transferMaker, int iThread ) +{ + if( faceParents.Element( facenum ) == g_Patches.InvalidIndex() || patchnum == g_Patches.InvalidIndex() ) + return; + + CPatch *patch = &g_Patches.Element( patchnum ); + CPatch *patch2 = &g_Patches.Element( faceParents.Element( facenum ) ); + + // if emitter is behind that face plane, skip all patches + + CPatch *pNextPatch; + + if ( patch2 && DotProduct(patch->origin, patch2->normal) > patch2->planeDist + PLANE_TEST_EPSILON ) + { + // we need to do a real test + for( ; patch2; patch2 = pNextPatch ) + { + // next patch + pNextPatch = NULL; + if( patch2->ndxNextParent != g_Patches.InvalidIndex() ) + { + pNextPatch = &g_Patches.Element( patch2->ndxNextParent ); + } + + /* + // skip patches too far away + VectorSubtract( patch->origin, patch2->origin, tmp ); + if (DotProduct( tmp, tmp ) > 512 * 512) + continue; + */ + + int ndxPatch2 = patch2 - g_Patches.Base(); + TestPatchToPatch( patchnum, ndxPatch2, head, transfers, transferMaker, iThread ); + } + } +} + + +struct ClusterDispList_t +{ + CUtlVector<int> dispFaces; +}; + +static CUtlVector<ClusterDispList_t> g_ClusterDispFaces; + +//----------------------------------------------------------------------------- +// Helps us find all displacements associated with a particular cluster +//----------------------------------------------------------------------------- +void AddDispsToClusterTable( void ) +{ + g_ClusterDispFaces.SetCount( g_ClusterLeaves.Count() ); + + // + // add displacement faces to the cluster table + // + for( int ndxFace = 0; ndxFace < numfaces; ndxFace++ ) + { + // search for displacement faces + if( g_pFaces[ndxFace].dispinfo == -1 ) + continue; + + // + // get the clusters associated with the face + // + if( g_FacePatches.Element( ndxFace ) != g_FacePatches.InvalidIndex() ) + { + CPatch *pNextPatch = NULL; + 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 ); + } + + if( pPatch->clusterNumber != g_Patches.InvalidIndex() ) + { + int ndxDisp = g_ClusterDispFaces[pPatch->clusterNumber].dispFaces.Find( ndxFace ); + if( ndxDisp == -1 ) + { + ndxDisp = g_ClusterDispFaces[pPatch->clusterNumber].dispFaces.AddToTail(); + g_ClusterDispFaces[pPatch->clusterNumber].dispFaces[ndxDisp] = ndxFace; + } + } + } + } + } +} + + +/* +============== +BuildVisRow + +Calc vis bits from a single patch +============== +*/ +void BuildVisRow (int patchnum, byte *pvs, int head, transfer_t *transfers, CTransferMaker &transferMaker, int iThread ) +{ + int j, k, l, leafIndex; + CPatch *patch; + dleaf_t *leaf; + byte face_tested[MAX_MAP_FACES]; + byte disp_tested[MAX_MAP_FACES]; + + patch = &g_Patches.Element( patchnum ); + + memset( face_tested, 0, numfaces ) ; + memset( disp_tested, 0, numfaces ); + + for (j=0; j<dvis->numclusters; j++) + { + if ( ! ( pvs[(j)>>3] & (1<<((j)&7)) ) ) + { + continue; // not in pvs + } + + for ( leafIndex = 0; leafIndex < g_ClusterLeaves[j].leafCount; leafIndex++ ) + { + leaf = dleafs + g_ClusterLeaves[j].leafs[leafIndex]; + + for (k=0 ; k<leaf->numleaffaces; k++) + { + l = dleaffaces[leaf->firstleafface + k]; + // faces can be marksurfed by multiple leaves, but + // don't bother testing again + if (face_tested[l]) + { + continue; + } + face_tested[l] = 1; + + // don't check patches on the same face + if (patch->faceNumber == l) + continue; + TestPatchToFace (patchnum, l, head, transfers, transferMaker, iThread ); + } + } + + int dispCount = g_ClusterDispFaces[j].dispFaces.Size(); + for( int ndxDisp = 0; ndxDisp < dispCount; ndxDisp++ ) + { + int ndxFace = g_ClusterDispFaces[j].dispFaces[ndxDisp]; + if( disp_tested[ndxFace] ) + continue; + + disp_tested[ndxFace] = 1; + + // don't check patches on the same face + if( patch->faceNumber == ndxFace ) + continue; + + TestPatchToFace( patchnum, ndxFace, head, transfers, transferMaker, iThread ); + } + } + + + // Msg("%d) Transfers: %5d\n", patchnum, patch->numtransfers); +} + + + +/* +=========== +BuildVisLeafs + + This is run by multiple threads +=========== +*/ + +transfer_t* BuildVisLeafs_Start() +{ + return (transfer_t *)calloc( 1, MAX_PATCHES * sizeof( transfer_t ) ); +} + + +// If PatchCB is non-null, it is called after each row is generated (used by MPI). +void BuildVisLeafs_Cluster( + int threadnum, + transfer_t *transfers, + int iCluster, + void (*PatchCB)(int iThread, int patchnum, CPatch *patch) + ) +{ + byte pvs[(MAX_MAP_CLUSTERS+7)/8]; + CPatch *patch; + int head; + unsigned patchnum; + + DecompressVis( &dvisdata[ dvis->bitofs[ iCluster ][DVIS_PVS] ], pvs); + head = 0; + + CTransferMaker transferMaker( transfers ); + + // light every patch in the cluster + if( clusterChildren.Element( iCluster ) != clusterChildren.InvalidIndex() ) + { + CPatch *pNextPatch; + for( patch = &g_Patches.Element( clusterChildren.Element( iCluster ) ); patch; patch = pNextPatch ) + { + // + // next patch + // + pNextPatch = NULL; + if( patch->ndxNextClusterChild != g_Patches.InvalidIndex() ) + { + pNextPatch = &g_Patches.Element( patch->ndxNextClusterChild ); + } + + patchnum = patch - g_Patches.Base(); + + // build to all other world clusters + BuildVisRow (patchnum, pvs, head, transfers, transferMaker, threadnum ); + transferMaker.Finish(); + + // do the transfers + MakeScales( patchnum, transfers ); + + // Let MPI aggregate the data if it's being used. + if ( PatchCB ) + PatchCB( threadnum, patchnum, patch ); + } + } +} + + +void BuildVisLeafs_End( transfer_t *transfers ) +{ + free( transfers ); +} + + +void BuildVisLeafs( int threadnum, void *pUserData ) +{ + transfer_t *transfers = BuildVisLeafs_Start(); + + while ( 1 ) + { + // + // build a minimal BSP tree that only + // covers areas relevent to the PVS + // + // JAY: Now this returns a cluster index + int iCluster = GetThreadWork(); + if ( iCluster == -1 ) + break; + + BuildVisLeafs_Cluster( threadnum, transfers, iCluster, NULL ); + } + + BuildVisLeafs_End( transfers ); +} + + +/* +============== +BuildVisMatrix +============== +*/ +void BuildVisMatrix (void) +{ + if ( g_bUseMPI ) + { + RunMPIBuildVisLeafs(); + } + else + { + RunThreadsOn (dvis->numclusters, true, BuildVisLeafs); + } +} + +void FreeVisMatrix (void) +{ + +} |