diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/public/disp_common.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/public/disp_common.cpp')
| -rw-r--r-- | mp/src/public/disp_common.cpp | 1296 |
1 files changed, 1296 insertions, 0 deletions
diff --git a/mp/src/public/disp_common.cpp b/mp/src/public/disp_common.cpp new file mode 100644 index 00000000..2b9fb3d7 --- /dev/null +++ b/mp/src/public/disp_common.cpp @@ -0,0 +1,1296 @@ +//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "disp_common.h"
+#include "disp_powerinfo.h"
+#include "builddisp.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+class CNodeVert
+{
+public:
+ CNodeVert() {}
+ CNodeVert( int ix, int iy ) {x=ix; y=iy;}
+
+ inline int& operator[]( int i ) {return ((int*)this)[i];}
+ inline int const& operator[]( int i ) const {return ((int*)this)[i];}
+
+ int x, y;
+};
+
+static CNodeVert const g_NodeChildLookup[4][2] =
+{
+ {CNodeVert(0,0), CNodeVert(1,1)},
+ {CNodeVert(1,0), CNodeVert(2,1)},
+ {CNodeVert(0,1), CNodeVert(1,2)},
+ {CNodeVert(1,1), CNodeVert(2,2)}
+};
+
+static CNodeVert const g_NodeTriWinding[9] =
+{
+ CNodeVert(0, 1),
+ CNodeVert(0, 0),
+ CNodeVert(1, 0),
+ CNodeVert(2, 0),
+ CNodeVert(2, 1),
+ CNodeVert(2, 2),
+ CNodeVert(1, 2),
+ CNodeVert(0, 2),
+ CNodeVert(0, 1)
+};
+
+// Indexed by CORNER_. These store NEIGHBOREDGE_ defines and tell which edges butt up against the corner.
+static int g_CornerEdges[4][2] =
+{
+ { NEIGHBOREDGE_BOTTOM, NEIGHBOREDGE_LEFT }, // CORNER_LOWER_LEFT
+ { NEIGHBOREDGE_TOP, NEIGHBOREDGE_LEFT }, // CORNER_UPPER_LEFT
+ { NEIGHBOREDGE_TOP, NEIGHBOREDGE_RIGHT }, // CORNER_UPPER_RIGHT
+ { NEIGHBOREDGE_BOTTOM, NEIGHBOREDGE_RIGHT } // CORNER_LOWER_RIGHT
+};
+
+int g_EdgeDims[4] =
+{
+ 0, // NEIGHBOREDGE_LEFT = X
+ 1, // NEIGHBOREDGE_TOP = Y
+ 0, // NEIGHBOREDGE_RIGHT = X
+ 1 // NEIGHBOREDGE_BOTTOM = Y
+};
+
+CShiftInfo g_ShiftInfos[3][3] =
+{
+ {
+ {0, 0, true}, // CORNER_TO_CORNER -> CORNER_TO_CORNER
+ {0, -1, true}, // CORNER_TO_CORNER -> CORNER_TO_MIDPOINT
+ {2, -1, true} // CORNER_TO_CORNER -> MIDPOINT_TO_CORNER
+ },
+
+ {
+ {0, 1, true}, // CORNER_TO_MIDPOINT -> CORNER_TO_CORNER
+ {0, 0, false}, // CORNER_TO_MIDPOINT -> CORNER_TO_MIDPOINT (invalid)
+ {0, 0, false} // CORNER_TO_MIDPOINT -> MIDPOINT_TO_CORNER (invalid)
+ },
+
+ {
+ {-1, 1, true}, // MIDPOINT_TO_CORNER -> CORNER_TO_CORNER
+ {0, 0, false}, // MIDPOINT_TO_CORNER -> CORNER_TO_MIDPOINT (invalid)
+ {0, 0, false} // MIDPOINT_TO_CORNER -> MIDPOINT_TO_CORNER (invalid)
+ }
+};
+
+int g_EdgeSideLenMul[4] =
+{
+ 0,
+ 1,
+ 1,
+ 0
+};
+
+
+// --------------------------------------------------------------------------------- //
+// Helper functions.
+// --------------------------------------------------------------------------------- //
+
+inline int SignedBitShift( int val, int shift )
+{
+ if( shift > 0 )
+ return val << shift;
+ else
+ return val >> -shift;
+}
+
+static inline void RotateVertIndex(
+ NeighborOrientation neighor,
+ int sideLengthMinus1,
+ CVertIndex const &in,
+ CVertIndex &out )
+{
+ if( neighor == ORIENTATION_CCW_0 )
+ {
+ out = in;
+ }
+ else if( neighor == ORIENTATION_CCW_90 )
+ {
+ out.x = in.y;
+ out.y = sideLengthMinus1 - in.x;
+ }
+ else if( neighor == ORIENTATION_CCW_180 )
+ {
+ out.x = sideLengthMinus1 - in.x;
+ out.y = sideLengthMinus1 - in.y;
+ }
+ else
+ {
+ out.x = sideLengthMinus1 - in.y;
+ out.y = in.x;
+ }
+}
+
+static inline void RotateVertIncrement(
+ NeighborOrientation neighor,
+ CVertIndex const &in,
+ CVertIndex &out )
+{
+ if( neighor == ORIENTATION_CCW_0 )
+ {
+ out = in;
+ }
+ else if( neighor == ORIENTATION_CCW_90 )
+ {
+ out.x = in.y;
+ out.y = -in.x;
+ }
+ else if( neighor == ORIENTATION_CCW_180 )
+ {
+ out.x = -in.x;
+ out.y = -in.y;
+ }
+ else
+ {
+ out.x = -in.y;
+ out.y = in.x;
+ }
+}
+
+
+// --------------------------------------------------------------------------------- //
+// CDispHelper functions.
+// --------------------------------------------------------------------------------- //
+
+int GetEdgeIndexFromPoint( CVertIndex const &index, int iMaxPower )
+{
+ int sideLengthMinus1 = 1 << iMaxPower;
+
+ if( index.x == 0 )
+ return NEIGHBOREDGE_LEFT;
+ else if( index.y == sideLengthMinus1 )
+ return NEIGHBOREDGE_TOP;
+ else if( index.x == sideLengthMinus1 )
+ return NEIGHBOREDGE_RIGHT;
+ else if( index.y == 0 )
+ return NEIGHBOREDGE_BOTTOM;
+ else
+ return -1;
+}
+
+
+int GetCornerIndexFromPoint( CVertIndex const &index, int iPower )
+{
+ int sideLengthMinus1 = 1 << iPower;
+
+ if( index.x == 0 && index.y == 0 )
+ return CORNER_LOWER_LEFT;
+
+ else if( index.x == 0 && index.y == sideLengthMinus1 )
+ return CORNER_UPPER_LEFT;
+
+ else if( index.x == sideLengthMinus1 && index.y == sideLengthMinus1 )
+ return CORNER_UPPER_RIGHT;
+
+ else if( index.x == sideLengthMinus1 && index.y == 0 )
+ return CORNER_LOWER_RIGHT;
+
+ else
+ return -1;
+}
+
+
+int GetNeighborEdgePower( CDispUtilsHelper *pDisp, int iEdge, int iSub )
+{
+ CDispNeighbor *pEdge = pDisp->GetEdgeNeighbor( iEdge );
+ CDispSubNeighbor *pSub = &pEdge->m_SubNeighbors[iSub];
+ if ( !pSub->IsValid() )
+ return -1;
+
+ CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->GetNeighborIndex() );
+
+ CShiftInfo *pInfo = &g_ShiftInfos[pSub->m_Span][pSub->m_NeighborSpan];
+ Assert( pInfo->m_bValid );
+
+ return pNeighbor->GetPower() + pInfo->m_PowerShiftAdd;
+}
+
+
+CDispUtilsHelper* SetupEdgeIncrements(
+ CDispUtilsHelper *pDisp,
+ int iEdge,
+ int iSub,
+ CVertIndex &myIndex,
+ CVertIndex &myInc,
+ CVertIndex &nbIndex,
+ CVertIndex &nbInc,
+ int &myEnd,
+ int &iFreeDim )
+{
+ int iEdgeDim = g_EdgeDims[iEdge];
+ iFreeDim = !iEdgeDim;
+
+ CDispNeighbor *pSide = pDisp->GetEdgeNeighbor( iEdge );
+ CDispSubNeighbor *pSub = &pSide->m_SubNeighbors[iSub];
+ if ( !pSub->IsValid() )
+ return NULL;
+
+ CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->m_iNeighbor );
+
+ CShiftInfo *pShiftInfo = &g_ShiftInfos[pSub->m_Span][pSub->m_NeighborSpan];
+ Assert( pShiftInfo->m_bValid );
+
+ // Setup a start point and edge increment (NOTE: just precalculate these
+ // and store them in the CDispSubNeighbors).
+ CVertIndex tempInc;
+
+ const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo();
+ myIndex[iEdgeDim] = g_EdgeSideLenMul[iEdge] * pPowerInfo->m_SideLengthM1;
+ myIndex[iFreeDim] = pPowerInfo->m_MidPoint * iSub;
+ TransformIntoSubNeighbor( pDisp, iEdge, iSub, myIndex, nbIndex );
+
+ int myPower = pDisp->GetPowerInfo()->m_Power;
+ int nbPower = pNeighbor->GetPowerInfo()->m_Power + pShiftInfo->m_PowerShiftAdd;
+
+ myInc[iEdgeDim] = tempInc[iEdgeDim] = 0;
+ if( nbPower > myPower )
+ {
+ myInc[iFreeDim] = 1;
+ tempInc[iFreeDim] = 1 << (nbPower - myPower);
+ }
+ else
+ {
+ myInc[iFreeDim] = 1 << (myPower - nbPower);
+ tempInc[iFreeDim] = 1;
+ }
+ RotateVertIncrement( pSub->GetNeighborOrientation(), tempInc, nbInc );
+
+ // Walk along the edge.
+ if( pSub->m_Span == CORNER_TO_MIDPOINT )
+ myEnd = pDisp->GetPowerInfo()->m_SideLength >> 1;
+ else
+ myEnd = pDisp->GetPowerInfo()->m_SideLength - 1;
+
+ return pNeighbor;
+}
+
+
+int GetSubNeighborIndex(
+ CDispUtilsHelper *pDisp,
+ int iEdge,
+ CVertIndex const &nodeIndex )
+{
+ const CPowerInfo *pPowerInfo = pDisp->GetPowerInfo();
+ const CDispNeighbor *pSide = pDisp->GetEdgeNeighbor( iEdge );
+
+ // Figure out if this is a vertical or horizontal edge.
+ int iEdgeDim = g_EdgeDims[iEdge];
+ int iFreeDim = !iEdgeDim;
+
+ int iFreeIndex = nodeIndex[iFreeDim];
+
+ // Figure out which of the (up to two) neighbors it lies in.
+ int iSub = 0;
+ if( iFreeIndex == pPowerInfo->m_MidPoint )
+ {
+ // If it's in the middle, we only are interested if there's one neighbor
+ // next to us (so we can enable its middle vert). If there are any neighbors
+ // that touch the midpoint, then we have no need to return them because it would
+ // touch their corner verts which are always active.
+ if( pSide->m_SubNeighbors[0].m_Span != CORNER_TO_CORNER )
+ return -1;
+ }
+ else if ( iFreeIndex > pPowerInfo->m_MidPoint )
+ {
+ iSub = 1;
+ }
+
+ // Make sure we get a valid neighbor.
+ if( !pSide->m_SubNeighbors[iSub].IsValid() )
+ {
+ if( iSub == 1 &&
+ pSide->m_SubNeighbors[0].IsValid() &&
+ pSide->m_SubNeighbors[0].m_Span == CORNER_TO_CORNER )
+ {
+ iSub = 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ return iSub;
+}
+
+
+void SetupSpan( int iPower, int iEdge, NeighborSpan span, CVertIndex &viStart, CVertIndex &viEnd )
+{
+ int iFreeDim = !g_EdgeDims[iEdge];
+ const CPowerInfo *pPowerInfo = GetPowerInfo( iPower );
+
+ viStart = pPowerInfo->GetCornerPointIndex( iEdge );
+ viEnd = pPowerInfo->GetCornerPointIndex( (iEdge+1) & 3 );;
+
+ if ( iEdge == NEIGHBOREDGE_RIGHT || iEdge == NEIGHBOREDGE_BOTTOM )
+ {
+ // CORNER_TO_MIDPOINT and MIDPOINT_CORNER are defined where the edge moves up or right,
+ // but pPowerInfo->GetCornerPointIndex walks around the edges clockwise, so on the
+ // bottom and right edges (where GetCornerPointIndex has us moving down and left) we need to
+ // reverse the sense here to make sure we return the right span.
+ if ( span == CORNER_TO_MIDPOINT )
+ viStart[iFreeDim] = pPowerInfo->GetMidPoint();
+ else if ( span == MIDPOINT_TO_CORNER )
+ viEnd[iFreeDim] = pPowerInfo->GetMidPoint();
+ }
+ else
+ {
+ if ( span == CORNER_TO_MIDPOINT )
+ viEnd[iFreeDim] = pPowerInfo->GetMidPoint();
+ else if ( span == MIDPOINT_TO_CORNER )
+ viStart[iFreeDim] = pPowerInfo->GetMidPoint();
+ }
+}
+
+
+CDispUtilsHelper* TransformIntoSubNeighbor(
+ CDispUtilsHelper *pDisp,
+ int iEdge,
+ int iSub,
+ CVertIndex const &nodeIndex,
+ CVertIndex &out
+ )
+{
+ const CDispSubNeighbor *pSub = &pDisp->GetEdgeNeighbor( iEdge )->m_SubNeighbors[iSub];
+
+ // Find the part of pDisp's edge that this neighbor covers.
+ CVertIndex viSrcStart, viSrcEnd;
+ SetupSpan( pDisp->GetPower(), iEdge, pSub->GetSpan(), viSrcStart, viSrcEnd );
+
+ // Find the corresponding parts on the neighbor.
+ CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->GetNeighborIndex() );
+ int iNBEdge = (iEdge + 2 + pSub->GetNeighborOrientation()) & 3;
+
+ CVertIndex viDestStart, viDestEnd;
+ SetupSpan( pNeighbor->GetPower(), iNBEdge, pSub->GetNeighborSpan(), viDestEnd, viDestStart );
+
+
+ // Now map the one into the other.
+ int iFreeDim = !g_EdgeDims[iEdge];
+ int fixedPercent = ((nodeIndex[iFreeDim] - viSrcStart[iFreeDim]) * (1<<16)) / (viSrcEnd[iFreeDim] - viSrcStart[iFreeDim]);
+ Assert( fixedPercent >= 0 && fixedPercent <= (1<<16) );
+
+ int nbDim = g_EdgeDims[iNBEdge];
+ out[nbDim] = viDestStart[nbDim];
+ out[!nbDim] = viDestStart[!nbDim] + ((viDestEnd[!nbDim] - viDestStart[!nbDim]) * fixedPercent) / (1<<16);
+
+ Assert( out.x >= 0 && out.x < pNeighbor->GetSideLength() );
+ Assert( out.y >= 0 && out.y < pNeighbor->GetSideLength() );
+
+ return pNeighbor;
+}
+
+
+CDispUtilsHelper* TransformIntoNeighbor(
+ CDispUtilsHelper *pDisp,
+ int iEdge,
+ CVertIndex const &nodeIndex,
+ CVertIndex &out
+ )
+{
+ if ( iEdge == -1 )
+ iEdge = GetEdgeIndexFromPoint( nodeIndex, pDisp->GetPower() );
+
+ int iSub = GetSubNeighborIndex( pDisp, iEdge, nodeIndex );
+ if ( iSub == -1 )
+ return NULL;
+
+ CDispUtilsHelper *pRet = TransformIntoSubNeighbor( pDisp, iEdge, iSub, nodeIndex, out );
+
+#if 0
+ // Debug check.. make sure it comes back to the same point from the other side.
+ #if defined( _DEBUG )
+ static bool bTesting = false;
+ if ( pRet && !bTesting )
+ {
+ bTesting = true;
+
+ // We could let TransformIntoNeighbor figure out the index but if this is a corner vert, then
+ // it may pick the wrong edge and we'd get a benign assert.
+ int nbOrientation = pDisp->GetEdgeNeighbor( iEdge )->m_SubNeighbors[iSub].GetNeighborOrientation();
+ int iNeighborEdge = (iEdge + 2 + nbOrientation) & 3;
+
+ CVertIndex testIndex;
+ CDispUtilsHelper *pTest = TransformIntoNeighbor( pRet, iNeighborEdge, out, testIndex );
+ Assert( pTest == pDisp );
+ Assert( testIndex == nodeIndex );
+
+ bTesting = false;
+ }
+ #endif
+#endif
+
+ return pRet;
+}
+
+
+bool DoesPointHaveAnyNeighbors(
+ CDispUtilsHelper *pDisp,
+ const CVertIndex &index )
+{
+ // See if it connects to a neighbor on the edge.
+ CVertIndex dummy;
+ if ( TransformIntoNeighbor( pDisp, -1, index, dummy ) )
+ return true;
+
+ // See if it connects to a neighbor on a corner.
+ int iCorner = GetCornerIndexFromPoint( index, pDisp->GetPower() );
+ if ( iCorner == -1 )
+ return false;
+
+ // If there are any neighbors on the specified corner, then the point has neighbors.
+ if ( pDisp->GetCornerNeighbors( iCorner )->m_nNeighbors > 0 )
+ return true;
+
+ // Since points on corners touch two edges, we actually want to test two edges to see
+ // if the point has a neighbor on either edge.
+ for ( int i=0; i < 2; i++ )
+ {
+ if ( TransformIntoNeighbor( pDisp, g_CornerEdges[iCorner][i], index, dummy ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+// ------------------------------------------------------------------------------------ //
+// CDispSubEdgeIterator.
+// ------------------------------------------------------------------------------------ //
+
+CDispSubEdgeIterator::CDispSubEdgeIterator()
+{
+ m_pNeighbor = 0;
+ m_FreeDim = m_Index.x = m_Inc.x = m_End = 0; // Setup so Next returns false.
+}
+
+
+void CDispSubEdgeIterator::Start( CDispUtilsHelper *pDisp, int iEdge, int iSub, bool bTouchCorners )
+{
+ m_pNeighbor = SetupEdgeIncrements( pDisp, iEdge, iSub, m_Index, m_Inc, m_NBIndex, m_NBInc, m_End, m_FreeDim );
+ if ( m_pNeighbor )
+ {
+ if ( bTouchCorners )
+ {
+ // Back up our current position by 1 so we hit the corner first, and extend the endpoint
+ // so we hit the other corner too.
+ m_Index -= m_Inc;
+ m_NBIndex -= m_NBInc;
+
+ m_End += m_Inc[m_FreeDim];
+ }
+ }
+ else
+ {
+ m_FreeDim = m_Index.x = m_Inc.x = m_End = 0; // Setup so Next returns false.
+ }
+}
+
+
+bool CDispSubEdgeIterator::Next()
+{
+ m_Index += m_Inc;
+ m_NBIndex += m_NBInc;
+
+ // Were we just at the last point on the edge?
+ return m_Index[m_FreeDim] < m_End;
+}
+
+
+bool CDispSubEdgeIterator::IsLastVert() const
+{
+ return (m_Index[m_FreeDim] + m_Inc[m_FreeDim]) >= m_End;
+}
+
+
+// ------------------------------------------------------------------------------------ //
+// CDispEdgeIterator.
+// ------------------------------------------------------------------------------------ //
+
+CDispEdgeIterator::CDispEdgeIterator( CDispUtilsHelper *pDisp, int iEdge )
+{
+ m_pDisp = pDisp;
+ m_iEdge = iEdge;
+ m_iCurSub = -1;
+}
+
+
+bool CDispEdgeIterator::Next()
+{
+ while ( !m_It.Next() )
+ {
+ // Ok, move up to the next sub.
+ if ( m_iCurSub == 1 )
+ return false;
+
+ ++m_iCurSub;
+ m_It.Start( m_pDisp, m_iEdge, m_iCurSub );
+ }
+ return true;
+}
+
+
+// ------------------------------------------------------------------------------------ //
+// CDispCircumferenceIterator.
+// ------------------------------------------------------------------------------------ //
+
+CDispCircumferenceIterator::CDispCircumferenceIterator( int sideLength )
+{
+ m_iCurEdge = -1;
+ m_SideLengthM1 = sideLength - 1;
+}
+
+
+bool CDispCircumferenceIterator::Next()
+{
+ switch ( m_iCurEdge )
+ {
+ case -1:
+ {
+ m_iCurEdge = NEIGHBOREDGE_LEFT;
+ m_VertIndex.Init( 0, 0 );
+ }
+ break;
+
+ case NEIGHBOREDGE_LEFT:
+ {
+ ++m_VertIndex.y;
+ if ( m_VertIndex.y == m_SideLengthM1 )
+ m_iCurEdge = NEIGHBOREDGE_TOP;
+ }
+ break;
+
+ case NEIGHBOREDGE_TOP:
+ {
+ ++m_VertIndex.x;
+ if ( m_VertIndex.x == m_SideLengthM1 )
+ m_iCurEdge = NEIGHBOREDGE_RIGHT;
+ }
+ break;
+
+ case NEIGHBOREDGE_RIGHT:
+ {
+ --m_VertIndex.y;
+ if ( m_VertIndex.y == 0 )
+ m_iCurEdge = NEIGHBOREDGE_BOTTOM;
+ }
+ break;
+
+ case NEIGHBOREDGE_BOTTOM:
+ {
+ --m_VertIndex.x;
+ if ( m_VertIndex.x == 0 )
+ return false; // Done!
+ }
+ break;
+ }
+
+ return true;
+}
+
+
+
+// Helper function to setup an index either on the edges or the center
+// of the box defined by [bottomleft,topRight].
+static inline void SetupCoordXY( CNodeVert &out, CNodeVert const &bottomLeft, CNodeVert const &topRight, CNodeVert const &info )
+{
+ for( int i=0; i < 2; i++ )
+ {
+ if( info[i] == 0 )
+ out[i] = bottomLeft[i];
+ else if( info[i] == 1 )
+ out[i] = (bottomLeft[i] + topRight[i]) >> 1;
+ else
+ out[i] = topRight[i];
+ }
+}
+
+
+static unsigned short* DispCommon_GenerateTriIndices_R(
+ CNodeVert const &bottomLeft,
+ CNodeVert const &topRight,
+ unsigned short *indices,
+ int power,
+ int sideLength )
+{
+ if( power == 1 )
+ {
+ // Ok, add triangles. All we do here is follow a list of verts (g_NodeTriWinding)
+ // around the center vert of this node and make triangles.
+ int iCurTri = 0;
+ CNodeVert verts[3];
+
+ // verts[0] is always the center vert.
+ SetupCoordXY( verts[0], bottomLeft, topRight, CNodeVert(1,1) );
+ int iCurVert = 1;
+
+ for( int i=0; i < 9; i++ )
+ {
+ SetupCoordXY( verts[iCurVert], bottomLeft, topRight, g_NodeTriWinding[i] );
+ ++iCurVert;
+
+ if( iCurVert == 3 )
+ {
+ for( int iTriVert=2; iTriVert >= 0; iTriVert-- )
+ {
+ int index = verts[iTriVert].y * sideLength + verts[iTriVert].x;
+ *indices = index;
+ ++indices;
+ }
+
+ // Setup for the next triangle.
+ verts[1] = verts[2];
+ iCurVert = 2;
+ iCurTri++;
+ }
+ }
+ }
+ else
+ {
+ // Recurse into the children.
+ for( int i=0; i < 4; i++ )
+ {
+ CNodeVert childBottomLeft, childTopRight;
+ SetupCoordXY( childBottomLeft, bottomLeft, topRight, g_NodeChildLookup[i][0] );
+ SetupCoordXY( childTopRight, bottomLeft, topRight, g_NodeChildLookup[i][1] );
+
+ indices = DispCommon_GenerateTriIndices_R( childBottomLeft, childTopRight, indices, power-1, sideLength );
+ }
+ }
+
+ return indices;
+}
+
+
+// ------------------------------------------------------------------------------------------- //
+// CDispUtilsHelper functions.
+// ------------------------------------------------------------------------------------------- //
+
+int CDispUtilsHelper::GetPower() const
+{
+ return GetPowerInfo()->GetPower();
+}
+
+int CDispUtilsHelper::GetSideLength() const
+{
+ return GetPowerInfo()->GetSideLength();
+}
+
+const CVertIndex& CDispUtilsHelper::GetCornerPointIndex( int iCorner ) const
+{
+ return GetPowerInfo()->GetCornerPointIndex( iCorner );
+}
+
+int CDispUtilsHelper::VertIndexToInt( const CVertIndex &i ) const
+{
+ Assert( i.x >= 0 && i.x < GetSideLength() && i.y >= 0 && i.y < GetSideLength() );
+ return i.y * GetSideLength() + i.x;
+}
+
+CVertIndex CDispUtilsHelper::GetEdgeMidPoint( int iEdge ) const
+{
+ int end = GetSideLength() - 1;
+ int mid = GetPowerInfo()->GetMidPoint();
+
+ if ( iEdge == NEIGHBOREDGE_LEFT )
+ return CVertIndex( 0, mid );
+
+ else if ( iEdge == NEIGHBOREDGE_TOP )
+ return CVertIndex( mid, end );
+
+ else if ( iEdge == NEIGHBOREDGE_RIGHT )
+ return CVertIndex( end, mid );
+
+ else if ( iEdge == NEIGHBOREDGE_BOTTOM )
+ return CVertIndex( mid, 0 );
+
+ Assert( false );
+ return CVertIndex( 0, 0 );
+}
+
+int DispCommon_GetNumTriIndices( int power )
+{
+ return (1<<power) * (1<<power) * 2 * 3;
+}
+
+
+void DispCommon_GenerateTriIndices( int power, unsigned short *indices )
+{
+ int sideLength = 1 << power;
+ DispCommon_GenerateTriIndices_R(
+ CNodeVert( 0, 0 ),
+ CNodeVert( sideLength, sideLength ),
+ indices,
+ power,
+ sideLength+1 );
+}
+
+//=============================================================================
+//
+// Finding neighbors.
+//
+
+// This table swaps MIDPOINT_TO_CORNER and CORNER_TO_MIDPOINT.
+static NeighborSpan g_SpanFlip[3] = {CORNER_TO_CORNER, MIDPOINT_TO_CORNER, CORNER_TO_MIDPOINT};
+static bool g_bEdgeNeighborFlip[4] = {false, false, true, true};
+
+// These map CCoreDispSurface neighbor orientations (which are actually edge indices)
+// into our 'degrees of rotation' representation.
+static int g_CoreDispNeighborOrientationMap[4][4] =
+{
+ {ORIENTATION_CCW_180, ORIENTATION_CCW_270, ORIENTATION_CCW_0, ORIENTATION_CCW_90},
+ {ORIENTATION_CCW_90, ORIENTATION_CCW_180, ORIENTATION_CCW_270, ORIENTATION_CCW_0},
+ {ORIENTATION_CCW_0, ORIENTATION_CCW_90, ORIENTATION_CCW_180, ORIENTATION_CCW_270},
+ {ORIENTATION_CCW_270, ORIENTATION_CCW_0, ORIENTATION_CCW_90, ORIENTATION_CCW_180}
+};
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void ClearNeighborData( CCoreDispInfo *pDisp )
+{
+ for ( int i=0; i < 4; i++ )
+ {
+ pDisp->GetEdgeNeighbor( i )->SetInvalid();
+ pDisp->GetCornerNeighbors( i )->SetInvalid();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void GetDispBox( CCoreDispInfo *pDisp, CDispBox &box )
+{
+ // Calculate the bbox for this displacement.
+ Vector vMin( 1e24, 1e24, 1e24 );
+ Vector vMax( -1e24, -1e24, -1e24 );
+
+ for ( int iVert = 0; iVert < 4; ++iVert )
+ {
+ const Vector &vTest = pDisp->GetSurface()->GetPoint( iVert );
+ VectorMin( vTest, vMin, vMin );
+ VectorMax( vTest, vMax, vMax );
+ }
+
+ // Puff the box out a little.
+ static float flPuff = 0.1f;
+ vMin -= Vector( flPuff, flPuff, flPuff );
+ vMax += Vector( flPuff, flPuff, flPuff );
+
+ box.m_Min = vMin;
+ box.m_Max = vMax;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void SetupDispBoxes( CCoreDispInfo **ppListBase, int nListSize, CUtlVector<CDispBox> &out )
+{
+ out.SetSize( nListSize );
+ for ( int iDisp = 0; iDisp < nListSize; ++iDisp )
+ {
+ CCoreDispInfo *pDisp = ppListBase[iDisp];
+ GetDispBox( pDisp, out[iDisp] );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+inline bool DoBBoxesTouch( const CDispBox &a, const CDispBox &b )
+{
+ for ( int i=0; i < 3; i++ )
+ {
+ if ( a.m_Max[i] < b.m_Min[i] )
+ return false;
+
+ if ( a.m_Min[i] > b.m_Max[i] )
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool FindEdge( CCoreDispInfo *pInfo, Vector const &vPoint1, Vector const &vPoint2, int &iEdge )
+{
+ CCoreDispSurface *pSurface = pInfo->GetSurface();
+
+ for( iEdge=0; iEdge < 4; iEdge++ )
+ {
+ if( VectorsAreEqual( vPoint1, pSurface->GetPoint( iEdge ), 0.01f ) &&
+ VectorsAreEqual( vPoint2, pSurface->GetPoint( (iEdge+1) & 3), 0.01f ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+NeighborSpan NeighborSpanFlip( int iEdge, NeighborSpan span )
+{
+ if ( g_bEdgeNeighborFlip[iEdge] )
+ return g_SpanFlip[span];
+ else
+ return span;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void AddNeighbor( CCoreDispInfo *pMain,
+ int iEdge, // Which of pMain's sides this is on.
+ int iSub, // Which sub neighbor this takes up in pSide.
+ NeighborSpan span, // What span this fills in pMain.
+ CCoreDispInfo *pOther, int iNeighborEdge, NeighborSpan nbSpan )
+{
+ // The edge iteration before coming in here goes 0-1, 1-2, 2-3, 3-4.
+ // This flips the sense of CORNER_TO_MIDPOINT/MIDPOINT_TO_CORNER on the right and
+ // bottom edges and is undone here.
+ span = NeighborSpanFlip( iEdge, span );
+ nbSpan = NeighborSpanFlip( iNeighborEdge, nbSpan );
+
+ // Get the subspan this fills on our displacement.
+ CDispSubNeighbor *pSub = &pMain->GetEdgeNeighbor(iEdge)->m_SubNeighbors[iSub];
+
+ // Which subspan does this use in the neighbor?
+ CDispSubNeighbor *pNeighborSub;
+ if ( nbSpan == MIDPOINT_TO_CORNER )
+ {
+ pNeighborSub = &pOther->GetEdgeNeighbor(iNeighborEdge)->m_SubNeighbors[1];
+ }
+ else
+ {
+ pNeighborSub = &pOther->GetEdgeNeighbor(iNeighborEdge)->m_SubNeighbors[0];
+ }
+
+ // Make sure this slot isn't used on either displacement.
+ if ( pSub->IsValid() || pNeighborSub->IsValid() )
+ {
+ ExecuteOnce( Warning( "Found a displacement edge abutting multiple other edges.\n" ) );
+ return;
+ }
+
+ // Now just copy the data into each displacement.
+ pSub->m_iNeighbor = pOther->GetListIndex();
+ pSub->m_NeighborOrientation = g_CoreDispNeighborOrientationMap[iEdge][iNeighborEdge];
+ pSub->m_Span = span;
+ pSub->m_NeighborSpan = nbSpan;
+
+ pNeighborSub->m_iNeighbor = pMain->GetListIndex();
+ pNeighborSub->m_NeighborOrientation = g_CoreDispNeighborOrientationMap[iNeighborEdge][iEdge];
+ pNeighborSub->m_Span = nbSpan;
+ pNeighborSub->m_NeighborSpan = span;
+
+#if defined( _DEBUG )
+ // Walk an iterator over the new connection to make sure it works.
+ CDispSubEdgeIterator it;
+ it.Start( pMain, iEdge, iSub );
+ while ( it.Next() )
+ {
+ CVertIndex nbIndex;
+ TransformIntoNeighbor( pMain, iEdge, it.GetVertIndex(), nbIndex );
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// This function is symmetric wrt pMain and pOther. It sets up valid neighboring data for
+// the relationship between both of them.
+//-----------------------------------------------------------------------------
+void SetupEdgeNeighbors( CCoreDispInfo *pMain, CCoreDispInfo *pOther )
+{
+ // Initialize..
+ for( int iEdge=0; iEdge < 4; iEdge++ )
+ {
+ // Setup the edge points and the midpoint.
+ Vector pt[2], mid;
+ pMain->GetSurface()->GetPoint( iEdge, pt[0] );
+ pMain->GetSurface()->GetPoint( (iEdge + 1) & 3, pt[1] );
+ mid = (pt[0] + pt[1]) * 0.5f;
+
+ // Find neighbors.
+ int iNBEdge;
+ if( FindEdge( pOther, pt[1], pt[0], iNBEdge ) )
+ {
+ AddNeighbor( pMain, iEdge, 0, CORNER_TO_CORNER, pOther, iNBEdge, CORNER_TO_CORNER );
+ }
+ else
+ {
+ // Look for one that takes up our whole side.
+ if( FindEdge( pOther, pt[1], pt[0]*2 - pt[1], iNBEdge ) )
+ {
+ AddNeighbor( pMain, iEdge, 0, CORNER_TO_CORNER, pOther, iNBEdge, CORNER_TO_MIDPOINT );
+ }
+ else if( FindEdge( pOther, pt[1]*2 - pt[0], pt[0], iNBEdge ) )
+ {
+ AddNeighbor( pMain, iEdge, 0, CORNER_TO_CORNER, pOther, iNBEdge, MIDPOINT_TO_CORNER );
+ }
+ else
+ {
+ // Ok, look for 1 or two that abut this side.
+ if( FindEdge( pOther, mid, pt[0], iNBEdge ) )
+ {
+ AddNeighbor( pMain, iEdge, g_bEdgeNeighborFlip[iEdge], CORNER_TO_MIDPOINT, pOther, iNBEdge, CORNER_TO_CORNER );
+ }
+
+ if( FindEdge( pOther, pt[1], mid, iNBEdge ) )
+ {
+ AddNeighbor( pMain, iEdge, !g_bEdgeNeighborFlip[iEdge], MIDPOINT_TO_CORNER, pOther, iNBEdge, CORNER_TO_CORNER );
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Returns true if the displacement has an edge neighbor with the given index.
+//-----------------------------------------------------------------------------
+bool HasEdgeNeighbor( const CCoreDispInfo *pMain, int iNeighbor )
+{
+ for ( int i=0; i < 4; i++ )
+ {
+ const CDispCornerNeighbors *pCorner = pMain->GetCornerNeighbors( i );
+ for ( int iNB=0; iNB < pCorner->m_nNeighbors; iNB++ )
+ if ( pCorner->m_Neighbors[iNB] == iNeighbor )
+ return true;
+
+ const CDispNeighbor *pEdge = pMain->GetEdgeNeighbor( i );
+ if ( pEdge->m_SubNeighbors[0].GetNeighborIndex() == iNeighbor ||
+ pEdge->m_SubNeighbors[1].GetNeighborIndex() == iNeighbor )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void SetupCornerNeighbors( CCoreDispInfo *pMain, CCoreDispInfo *pOther, int *nOverflows )
+{
+ if ( HasEdgeNeighbor( pMain, pOther->GetListIndex() ) )
+ return;
+
+ // Do these two share a vertex?
+ int nShared = 0;
+ int iMainSharedCorner = -1;
+ int iOtherSharedCorner = -1;
+
+ for ( int iMainCorner=0; iMainCorner < 4; iMainCorner++ )
+ {
+ Vector const &vMainCorner = pMain->GetCornerPoint( iMainCorner );
+
+ for ( int iOtherCorner=0; iOtherCorner < 4; iOtherCorner++ )
+ {
+ Vector const &vOtherCorner = pOther->GetCornerPoint( iOtherCorner );
+
+ if ( VectorsAreEqual( vMainCorner, vOtherCorner, 0.001f ) )
+ {
+ iMainSharedCorner = iMainCorner;
+ iOtherSharedCorner = iOtherCorner;
+ ++nShared;
+ }
+ }
+ }
+
+ if ( nShared == 1 )
+ {
+ CDispCornerNeighbors *pMainCorner = pMain->GetCornerNeighbors( iMainSharedCorner );
+ CDispCornerNeighbors *pOtherCorner = pOther->GetCornerNeighbors( iOtherSharedCorner );
+
+ if ( pMainCorner->m_nNeighbors < MAX_DISP_CORNER_NEIGHBORS &&
+ pOtherCorner->m_nNeighbors < MAX_DISP_CORNER_NEIGHBORS )
+ {
+ pMainCorner->m_Neighbors[pMainCorner->m_nNeighbors++] = pOther->GetListIndex();
+ pOtherCorner->m_Neighbors[pOtherCorner->m_nNeighbors++] = pMain->GetListIndex();
+ }
+ else
+ {
+ ++(*nOverflows);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool VerifyNeighborVertConnection( CDispUtilsHelper *pDisp, const CVertIndex &nodeIndex,
+ const CDispUtilsHelper *pTestNeighbor, const CVertIndex &testNeighborIndex,
+ int mySide )
+{
+ CVertIndex nbIndex( -1, -1 );
+ CDispUtilsHelper *pNeighbor = NULL;
+ if( (pNeighbor = TransformIntoNeighbor( pDisp, mySide, nodeIndex, nbIndex ) ) != NULL )
+ {
+ if ( pTestNeighbor != pNeighbor || nbIndex != testNeighborIndex )
+ return false;
+
+ CVertIndex testIndex( -1, -1 );
+ int iSide = GetEdgeIndexFromPoint( nbIndex, pNeighbor->GetPowerInfo()->m_Power );
+ if ( iSide == -1 )
+ {
+ return false;
+ }
+
+ CDispUtilsHelper *pTest = TransformIntoNeighbor( pNeighbor, iSide, nbIndex, testIndex );
+
+ if( pTest != pDisp || nodeIndex != testIndex )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void VerifyNeighborConnections( CCoreDispInfo **ppListBase, int nDisps )
+{
+ while ( 1 )
+ {
+ bool bHappy = true;
+
+ int iDisp;
+ for ( iDisp = 0; iDisp < nDisps; ++iDisp )
+ {
+ CCoreDispInfo *pDisp = ppListBase[iDisp];
+ CDispUtilsHelper *pHelper = pDisp;
+
+ for ( int iEdge=0; iEdge < 4; iEdge++ )
+ {
+ CDispEdgeIterator it( pHelper, iEdge );
+ while ( it.Next() )
+ {
+ if ( !VerifyNeighborVertConnection( pHelper, it.GetVertIndex(), it.GetCurrentNeighbor(), it.GetNBVertIndex(), iEdge ) )
+ {
+ pDisp->GetEdgeNeighbor( iEdge )->SetInvalid();
+ Warning( "Warning: invalid neighbor connection on displacement near (%.2f %.2f %.2f)\n", VectorExpand( pDisp->GetCornerPoint(0) ) );
+ bHappy = false;
+ }
+ }
+ }
+ }
+
+ if ( bHappy )
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void FindNeighboringDispSurfs( CCoreDispInfo **ppListBase, int nListSize )
+{
+ // First, clear all neighboring data.
+ int iDisp;
+ for ( iDisp = 0; iDisp < nListSize; ++iDisp )
+ {
+ ClearNeighborData( ppListBase[iDisp] );
+ }
+
+ CUtlVector<CDispBox> boxes;
+ SetupDispBoxes( ppListBase, nListSize, boxes );
+
+ int nCornerOverflows = 0;
+
+ // Now test all pairs of displacements and setup neighboring relations between them.
+ for( iDisp = 0; iDisp < nListSize; ++iDisp )
+ {
+ CCoreDispInfo *pMain = ppListBase[iDisp];
+
+ for ( int iDisp2 = iDisp+1; iDisp2 < nListSize; ++iDisp2 )
+ {
+ CCoreDispInfo *pOther = ppListBase[iDisp2];
+
+ // Trivial reject.
+ if ( !DoBBoxesTouch( boxes[iDisp], boxes[iDisp2] ) )
+ continue;
+
+ SetupEdgeNeighbors( pMain, pOther );
+
+ // NOTE: this must come after SetupEdgeNeighbors because it makes sure not to add
+ // corner neighbors for disps that are already edge neighbors.
+ SetupCornerNeighbors( pMain, pOther, &nCornerOverflows );
+ }
+ }
+
+ if ( nCornerOverflows )
+ {
+ Warning( "Warning: overflowed %d displacement corner-neighbor lists.", nCornerOverflows );
+ }
+
+ // Debug check.. make sure the neighbor connections are intact (make sure that any
+ // edge vert that gets mapped into a neighbor gets mapped back the same way).
+ VerifyNeighborConnections( ppListBase, nListSize );
+}
+
+//=============================================================================
+//
+// Allowable verts.
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int IsCorner( CVertIndex const &index, int sideLength )
+{
+ if ( index.x == 0 )
+ {
+ if ( index.y == 0 )
+ return true;
+ else if ( index.y == sideLength-1 )
+ return true;
+ }
+ else if ( index.x == sideLength-1 )
+ {
+ if ( index.y == 0 )
+ return true;
+ else if ( index.y == sideLength-1 )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool IsVertAllowed( CDispUtilsHelper *pDisp, CVertIndex const &sideVert, int iLevel )
+{
+ if ( IsCorner( sideVert, pDisp->GetPowerInfo()->GetSideLength() ) )
+ return true;
+
+ int iSide = GetEdgeIndexFromPoint( sideVert, pDisp->GetPowerInfo()->GetPower() );
+ if ( iSide == -1 )
+ return true;
+
+ int iSub = GetSubNeighborIndex( pDisp, iSide, sideVert );
+ if ( iSub == -1 )
+ return true;
+
+ CDispSubNeighbor *pSub = &pDisp->GetEdgeNeighbor( iSide )->m_SubNeighbors[iSub];
+ CDispUtilsHelper *pNeighbor = pDisp->GetDispUtilsByIndex( pSub->m_iNeighbor );
+ Assert( pNeighbor );
+
+ // Ok, there is a neighbor.. see if this vertex exists in the neighbor.
+ CShiftInfo *pShiftInfo = &g_ShiftInfos[pSub->m_Span][pSub->m_NeighborSpan];
+ Assert( pShiftInfo->m_bValid );
+
+ if ( ( pNeighbor->GetPowerInfo()->GetPower() + pShiftInfo->m_PowerShiftAdd ) < ( iLevel+1 ) )
+ {
+ return false;
+ }
+
+ // Ok, it exists. Make sure the neighbor hasn't disallowed it.
+ CVertIndex nbIndex;
+ TransformIntoSubNeighbor( pDisp, iSide, iSub, sideVert, nbIndex );
+
+ CBitVec<MAX_DISPVERTS> &allowedVerts = CCoreDispInfo::FromDispUtils( pNeighbor )->GetAllowedVerts();
+ return !!allowedVerts.Get( pNeighbor->VertIndexToInt( nbIndex ) );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void UnallowVerts_R( CDispUtilsHelper *pDisp, CVertIndex const &nodeIndex, int &nUnallowed )
+{
+ int iNodeIndex = pDisp->VertIndexToInt( nodeIndex );
+
+ CCoreDispInfo *pCoreDisp = CCoreDispInfo::FromDispUtils( pDisp );
+ if ( !pCoreDisp->GetAllowedVerts().Get( iNodeIndex ) )
+ return;
+
+ nUnallowed++;
+ pCoreDisp->GetAllowedVerts().Clear( iNodeIndex );
+
+ for ( int iDep=0; iDep < CVertInfo::NUM_REVERSE_DEPENDENCIES; iDep++ )
+ {
+ CVertDependency &dep = pDisp->GetPowerInfo()->m_pVertInfo[iNodeIndex].m_ReverseDependencies[iDep];
+
+ if( dep.m_iVert.x != -1 && dep.m_iNeighbor == -1 )
+ {
+ UnallowVerts_R( pDisp, dep.m_iVert, nUnallowed );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void DisableUnallowedVerts_R( CDispUtilsHelper *pDisp, CVertIndex const &nodeIndex, int iLevel, int &nUnallowed )
+{
+ int iNodeIndex = pDisp->VertIndexToInt( nodeIndex );
+
+ // This vertex is not allowed if it is on an edge with a neighbor
+ // that does not have this vertex.
+
+ // Test side verts.
+ for( int iSide=0; iSide < 4; iSide++ )
+ {
+ CVertIndex const &sideVert = pDisp->GetPowerInfo()->m_pSideVerts[iNodeIndex].m_Verts[iSide];
+
+ if( !IsVertAllowed( pDisp, sideVert, iLevel ) )
+ {
+ // This vert (and its dependencies) can't exist.
+ UnallowVerts_R( pDisp, sideVert, nUnallowed );
+ }
+ }
+
+#if 0
+ // Test dependencies.
+ for( int iDep=0; iDep < 2; iDep++ )
+ {
+ CVertDependency const &dep = pDisp->GetPowerInfo()->m_pVertInfo[iNodeIndex].m_Dependencies[iDep];
+
+ if( dep.m_iNeighbor == -1 && !IsVertAllowed( pDisp, dep.m_iVert, iLevel ) )
+ {
+ UnallowVerts_R( pDisp, nodeIndex, nUnallowed );
+ }
+ }
+#endif
+
+ // Recurse.
+ if( iLevel+1 < pDisp->GetPower() )
+ {
+ for( int iChild=0; iChild < 4; iChild++ )
+ {
+ DisableUnallowedVerts_R( pDisp, pDisp->GetPowerInfo()->m_pChildVerts[iNodeIndex].m_Verts[iChild], iLevel+1, nUnallowed );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void SetupAllowedVerts( CCoreDispInfo **ppListBase, int nListSize )
+{
+ // Set all verts to allowed to start with.
+ int iDisp;
+ for ( iDisp = 0; iDisp < nListSize; ++iDisp )
+ {
+ ppListBase[iDisp]->GetAllowedVerts().SetAll();
+ }
+
+ // Disable verts that need to be disabled so higher-powered displacements remove
+ // the necessary triangles when bordering lower-powered displacements.
+ // It is necessary to loop around here because disabling verts can accumulate into
+ // neighbors.
+ bool bContinue;
+ do
+ {
+ bContinue = false;
+ for( iDisp = 0; iDisp < nListSize; ++iDisp )
+ {
+ CDispUtilsHelper *pDisp = ppListBase[iDisp];
+
+ int nUnallowed = 0;
+ DisableUnallowedVerts_R( pDisp, pDisp->GetPowerInfo()->m_RootNode, 0, nUnallowed );
+ if ( nUnallowed )
+ bContinue = true;
+ }
+ } while( bContinue );
+}
|