aboutsummaryrefslogtreecommitdiff
path: root/mp/src/public/disp_common.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/public/disp_common.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/public/disp_common.cpp')
-rw-r--r--mp/src/public/disp_common.cpp2592
1 files changed, 1296 insertions, 1296 deletions
diff --git a/mp/src/public/disp_common.cpp b/mp/src/public/disp_common.cpp
index 2b9fb3d7..0c2ac51b 100644
--- a/mp/src/public/disp_common.cpp
+++ b/mp/src/public/disp_common.cpp
@@ -1,1296 +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 );
-}
+//========= 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 );
+}