#include "fow.h" #include "fow_trisoup.h" #include "fow_lineoccluder.h" // memdbgon must be the last include file in a .cpp file!!! #include //----------------------------------------------------------------------------- // Purpose: constructor to init this collection with the id // Input : nID - unused //----------------------------------------------------------------------------- CFoW_TriSoupCollection::CFoW_TriSoupCollection( unsigned nID ) { } //----------------------------------------------------------------------------- // Purpose: destructor to dealloc the occluders //----------------------------------------------------------------------------- CFoW_TriSoupCollection::~CFoW_TriSoupCollection( void ) { Clear(); } //----------------------------------------------------------------------------- // Purpose: clears all entries from the collection ( useful for hammer editing only ) //----------------------------------------------------------------------------- void CFoW_TriSoupCollection::Clear( void ) { m_Occluders.PurgeAndDeleteElements(); } //----------------------------------------------------------------------------- // Purpose: adds a tri to the collection. this is immediately split up into the horizontal slices. very slow! // Input : pFoW - the main FoW object // vPointA - a point on the tri // vPointB - a point on the tri // vPointC - a point on the tri //----------------------------------------------------------------------------- void CFoW_TriSoupCollection::AddTri( CFoW *pFoW, Vector &vPointA, Vector &vPointB, Vector &vPointC ) { Vector vVerts[ 3 ], vOutVerts[ 8 ]; int nBottomZ; int nGridSize; int nGridUnits; Vector vNormal, vTestNormal; float flIntercept; float *pflVerticalLevels; vVerts[ 0 ] = vPointA; vVerts[ 1 ] = vPointB; vVerts[ 2 ] = vPointC; pFoW->GetVerticalGridInfo( nBottomZ, nGridSize, nGridUnits, &pflVerticalLevels ); ComputeTrianglePlane( vPointA, vPointB, vPointC, vNormal, flIntercept ); vTestNormal = vNormal; vTestNormal.z = 0.0f; vTestNormal.NormalizeInPlace(); Vector2D vTestNormal2( vTestNormal.x, vTestNormal.y ); for ( int i = 0; i < nGridUnits; i++ ) { nBottomZ = pflVerticalLevels[ i ] + 16.0f; int nCount = HorizontalSplitTri( vVerts, 3, vOutVerts, nBottomZ, 0.0f ); if ( nCount == 2 ) { CFoW_LineOccluder *pOccluder = new CFoW_LineOccluder( vOutVerts[ 0 ].x, vOutVerts[ 0 ].y, vOutVerts[ 1 ].x, vOutVerts[ 1 ].y, vTestNormal2, i ); m_Occluders.AddToTail( pOccluder ); pFoW->AddTriSoupOccluder( pOccluder, i ); } } } //----------------------------------------------------------------------------- // Purpose: adds all occluders back into the visibility tree // Input : pFoW - the main FoW object //----------------------------------------------------------------------------- void CFoW_TriSoupCollection::RepopulateOccluders( CFoW *pFoW ) { for ( int i = 0; i < m_Occluders.Count(); i++ ) { pFoW->AddTriSoupOccluder( m_Occluders[ i ], m_Occluders[ i ]->GetSliceNum() ); } } #if 0 void CFoW_TriSoupCollection::ObstructViewer( CFoW *FoW, CFoW_Viewer *Viewer ) { for ( int i = 0; i < m_Occluders.Count(); i++ ) { m_Occluders[ i ].ObstructViewer( FoW, Viewer ); } } #endif //----------------------------------------------------------------------------- // Purpose: clip a poly to the horizontal plane and return the poly on the front side of the plane // Input : *pInVerts - input polygon // nVertCount - # verts in input poly // *pOutVerts - destination poly // flDist - plane constant // flOnPlaneEpsilon - the fudge factor for determining if a point is within the plane edge // Output : int - # verts in output poly //----------------------------------------------------------------------------- int CFoW_TriSoupCollection::HorizontalSplitTri( Vector *pInVerts, int nVertCount, Vector *pOutVerts, float flDist, float flOnPlaneEpsilon ) { vec_t *pDists = ( vec_t * )stackalloc( sizeof( vec_t ) * nVertCount * 4 ); //4x vertcount should cover all cases int *pSides = ( int * )stackalloc( sizeof( vec_t ) * nVertCount * 4 ); int nCounts[ 3 ]; vec_t flDot; int i, j; Vector vMid = vec3_origin; int nOutCount; Vector vNormal( 0.0f, 0.0f, 1.0f ); nCounts[ 0 ] = nCounts[ 1 ] = nCounts[ 2 ] = 0; // determine sides for each point for ( i = 0; i < nVertCount; i++ ) { flDot = DotProduct( pInVerts[ i ], vNormal ) - flDist; pDists[ i ] = flDot; if ( flDot > flOnPlaneEpsilon ) { pSides[ i ] = SIDE_FRONT; } else if ( flDot < -flOnPlaneEpsilon ) { pSides[ i ] = SIDE_BACK; } else { pSides[ i ] = SIDE_ON; } nCounts[ pSides[ i ] ]++; } pSides[ i ] = pSides[ 0 ]; pDists[ i ] = pDists[ 0 ]; if ( !nCounts[ SIDE_FRONT ] ) { // if this has 2 sides that are side_on, then this should be a tri coming soon with the same two sides that are on, but with one on side_back return 0; } nOutCount = 0; for ( i = 0; i < nVertCount; i++ ) { int nCurrent = ( i + 0 ) % nVertCount; int nNext = ( i + 1 ) % nVertCount; Vector &p1 = pInVerts[ nCurrent ]; if ( pSides[ nCurrent ] == SIDE_ON ) { VectorCopy( p1, pOutVerts[ nOutCount ] ); nOutCount++; continue; } if ( pSides[ nCurrent ] == SIDE_FRONT ) { // VectorCopy( p1, outVerts[outCount]); // outCount++; } if ( pSides[ nNext ] == SIDE_ON || pSides[ nNext ] == pSides[ nCurrent ] ) { continue; } // generate a split point Vector &p2 = pInVerts[ nNext ]; flDot = pDists[ nCurrent ] / ( pDists[ nCurrent ] - pDists[ nNext ] ); for ( j = 0; j < 3; j++ ) { // avoid round off error when possible if ( vNormal[ j ] == 1 ) { vMid[ j ] = flDist; } else if ( vNormal[ j ] == -1 ) { vMid[ j ] = -flDist; } else { vMid[ j ] = p1[ j ] + flDot * ( p2[ j ] - p1[ j ] ); } } VectorCopy ( vMid, pOutVerts[ nOutCount ] ); nOutCount++; } return nOutCount; } #include