summaryrefslogtreecommitdiff
path: root/hammer/subdiv.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/subdiv.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/subdiv.cpp')
-rw-r--r--hammer/subdiv.cpp1253
1 files changed, 1253 insertions, 0 deletions
diff --git a/hammer/subdiv.cpp b/hammer/subdiv.cpp
new file mode 100644
index 0000000..aee7926
--- /dev/null
+++ b/hammer/subdiv.cpp
@@ -0,0 +1,1253 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdafx.h>
+#include "MainFrm.h"
+#include "MapDoc.h"
+#include "GlobalFunctions.h"
+#include "Subdiv.h"
+#include "History.h"
+
+//=============================================================================
+//
+// Subdivision Point Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivPoint::Clear( void )
+{
+ VectorClear( m_Point );
+ VectorClear( m_NewPoint );
+ VectorClear( m_Normal );
+ VectorClear( m_NewNormal );
+
+ m_Type = -1;
+ m_Valence = 0;
+
+ for( int i = 0; i < NUM_SUBDIV_EDGES; i++ )
+ {
+ m_pEdges[i] = NULL;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivPoint::Copy( const CSubdivPoint *pFrom )
+{
+ m_Point = pFrom->m_Point;
+ m_NewPoint = pFrom->m_NewPoint;
+ m_Normal = pFrom->m_Normal;
+ m_NewNormal = pFrom->m_NewNormal;
+
+ m_Type = pFrom->m_Type;
+ m_Valence = pFrom->m_Valence;
+
+ for( int i = 0; i < NUM_SUBDIV_EDGES; i++ )
+ {
+ m_pEdges[i] = pFrom->m_pEdges[i];
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivPoint::CalcNewVertexNormal( void )
+{
+ switch( m_Type )
+ {
+ case POINT_CORNER:
+ {
+ m_NewNormal = m_Normal;
+ break;
+ }
+ case POINT_CREASE:
+ {
+ Vector edgeAccum;
+ VectorClear( edgeAccum );
+ for( int i = 0; i < m_Valence; i++ )
+ {
+ if( m_pEdges[i]->m_Sharpness > 0.0f )
+ {
+ VectorAdd( edgeAccum, m_pEdges[i]->m_NewEdgeNormal, edgeAccum );
+ }
+ }
+
+ //
+ // normal
+ //
+ VectorScale( m_Normal, 6.0f, m_NewNormal );
+ VectorAdd( m_NewNormal, edgeAccum, m_NewNormal );
+ VectorScale( m_NewNormal, 0.125f, m_NewNormal );
+
+ break;
+ }
+ case POINT_ORDINARY:
+ {
+ //
+ // accumulate edge data and multiply by valence ratio
+ //
+ Vector edgeAccum;
+ VectorClear( edgeAccum );
+ for( int i = 0; i < m_Valence; i++ )
+ {
+ VectorAdd( edgeAccum, m_pEdges[i]->m_NewEdgeNormal, edgeAccum );
+ }
+ float ratio = ( 1.0f / ( float )( m_Valence * m_Valence ) );
+ VectorScale( edgeAccum, ratio, edgeAccum );
+
+ //
+ // accumulate centroid data and multiply by valence ratio
+ //
+ int quadCount = 0;
+ CSubdivQuad *quadList[16];
+ for( i = 0; i < m_Valence; i++ )
+ {
+ for( int j = 0; j < 2; j++ )
+ {
+ if( m_pEdges[i]->m_pQuads[j] )
+ {
+ for( int k = 0; k < quadCount; k++ )
+ {
+ if( m_pEdges[i]->m_pQuads[j] == quadList[k] )
+ break;
+ }
+
+ if( k != quadCount )
+ continue;
+
+ quadList[quadCount] = m_pEdges[i]->m_pQuads[j];
+ quadCount++;
+ }
+ }
+ }
+
+ Vector centroidAccum;
+ VectorClear( centroidAccum );
+ for( i = 0; i < quadCount; i++ )
+ {
+ Vector centroid;
+ quadList[i]->GetNormal( centroid );
+ VectorAdd( centroidAccum, centroid, centroidAccum );
+ }
+ VectorScale( centroidAccum, ratio, centroidAccum );
+
+ //
+ // normal
+ //
+ VectorScale( m_Normal, ratio, m_NewNormal );
+ VectorAdd( m_NewNormal, edgeAccum, m_NewNormal );
+ VectorAdd( m_NewNormal, centroidAccum, m_NewNormal );
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivPoint::CalcNewVertexPoint( void )
+{
+ switch( m_Type )
+ {
+ case POINT_CORNER:
+ {
+ m_NewPoint = m_Point;
+ break;
+ }
+ case POINT_CREASE:
+ {
+ Vector edgeAccum;
+ VectorClear( edgeAccum );
+ for( int i = 0; i < m_Valence; i++ )
+ {
+ if( m_pEdges[i]->m_Sharpness > 0.0f )
+ {
+ VectorAdd( edgeAccum, m_pEdges[i]->m_NewEdgePoint, edgeAccum );
+ }
+ }
+
+ //
+ // point
+ //
+ VectorScale( m_Point, 6.0f, m_NewPoint );
+ VectorAdd( m_NewPoint, edgeAccum, m_NewPoint );
+ VectorScale( m_NewPoint, 0.125f, m_NewPoint );
+
+ break;
+ }
+ case POINT_ORDINARY:
+ {
+ //
+ // accumulate edge data and multiply by valence ratio
+ //
+ Vector edgeAccum;
+ VectorClear( edgeAccum );
+ for( int i = 0; i < m_Valence; i++ )
+ {
+ VectorAdd( edgeAccum, m_pEdges[i]->m_NewEdgePoint, edgeAccum );
+ }
+ float ratio = ( 1.0f / ( float )( m_Valence * m_Valence ) );
+ VectorScale( edgeAccum, ratio, edgeAccum );
+
+ //
+ // accumulate centroid data and multiply by valence ratio
+ //
+ int quadCount = 0;
+ CSubdivQuad *quadList[16];
+ for( i = 0; i < m_Valence; i++ )
+ {
+ for( int j = 0; j < 2; j++ )
+ {
+ if( m_pEdges[i]->m_pQuads[j] )
+ {
+ for( int k = 0; k < quadCount; k++ )
+ {
+ if( m_pEdges[i]->m_pQuads[j] == quadList[k] )
+ break;
+ }
+
+ if( k != quadCount )
+ continue;
+
+ quadList[quadCount] = m_pEdges[i]->m_pQuads[j];
+ quadCount++;
+ }
+ }
+ }
+
+ Vector centroidAccum;
+ VectorClear( centroidAccum );
+ for( i = 0; i < quadCount; i++ )
+ {
+ Vector centroid;
+ quadList[i]->GetCentroid( centroid );
+ VectorAdd( centroidAccum, centroid, centroidAccum );
+ }
+ VectorScale( centroidAccum, ratio, centroidAccum );
+
+ //
+ // point contribution to eqtn.
+ //
+ ratio = ( ( float )m_Valence - 2.0f ) / ( float )m_Valence;
+ VectorScale( m_Point, ratio, m_NewPoint );
+
+ VectorAdd( m_NewPoint, edgeAccum, m_NewPoint );
+ VectorAdd( m_NewPoint, centroidAccum, m_NewPoint );
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CompareSubdivPoints( const CSubdivPoint *pPoint1, const CSubdivPoint *pPoint2, float tolerance )
+{
+ for( int i = 0 ; i < 3 ; i++ )
+ {
+ if( fabs( pPoint1->m_Point[i] - pPoint2->m_Point[i] ) > tolerance )
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CompareSubdivPointToPoint( const CSubdivPoint *pSubdivPoint, const Vector& point, float tolerance )
+{
+ for( int i = 0 ; i < 3 ; i++ )
+ {
+ if( fabs( pSubdivPoint->m_Point[i] - point[i] ) > tolerance )
+ return false;
+ }
+
+ return true;
+}
+
+
+//=============================================================================
+//
+// Subdivision Edge Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivEdge::Clear( void )
+{
+ for( int i = 0; i < 2; i++ )
+ {
+ m_ndxPoint[i] = -1;
+ m_pQuads[i] = NULL;
+ m_ndxQuadEdge[i] = -1;
+ }
+
+ m_Sharpness = 1.0f;
+ VectorClear( m_NewEdgePoint );
+ m_Active = false;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivEdge::Copy( const CSubdivEdge *pFrom )
+{
+ for( int i = 0; i < 2; i++ )
+ {
+ m_ndxPoint[i] = pFrom->m_ndxPoint[i];
+ m_pQuads[i] = pFrom->m_pQuads[i];
+ m_ndxQuadEdge[i] = pFrom->m_ndxQuadEdge[i];
+ }
+
+ m_Sharpness = pFrom->m_Sharpness;
+ m_NewEdgePoint = pFrom->m_NewEdgePoint;
+ m_Active = pFrom->m_Active;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivEdge::CalcNewEdgeNormal( void )
+{
+ if( !m_Active )
+ return;
+
+ //
+ // get the subdivision mesh
+ //
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return;
+
+ CSubdivMesh *pMesh = pDoc->GetSubdivMesh();
+
+ //
+ // get the edge data
+ //
+ Vector normal0, normal1;
+ pMesh->GetNormal( m_ndxPoint[0], normal0 );
+ pMesh->GetNormal( m_ndxPoint[1], normal1 );
+
+ //
+ // calculate the "sharp" new edge point
+ //
+ Vector vSharp;
+ VectorClear( vSharp );
+ VectorAdd( normal0, normal1, vSharp );
+ VectorScale( vSharp, 0.5f, vSharp );
+
+ //
+ // calculate the "smooth" new edge point if necessary
+ //
+ Vector vSmooth;
+ VectorClear( vSmooth );
+ if( m_pQuads[1] && ( m_Sharpness != 1.0f ) )
+ {
+ Vector quadNormals[2];
+ m_pQuads[0]->GetNormal( quadNormals[0] );
+ m_pQuads[1]->GetNormal( quadNormals[1] );
+ VectorAdd( normal0, normal1, vSmooth );
+ VectorAdd( vSmooth, quadNormals[0], vSmooth );
+ VectorAdd( vSmooth, quadNormals[1], vSmooth );
+ VectorScale( vSmooth, 0.25f, vSmooth );
+ }
+ else
+ {
+ // make sure -- if here because of no neighboring quad
+ m_Sharpness = 1.0f;
+ m_pQuads[0]->CalcNormal();
+ }
+
+ //
+ // calculate the new edge point
+ //
+ // ( 1 - edge(sharpness) ) * vSmooth + edge(sharpness) * vSharp
+ //
+ VectorScale( vSmooth, ( 1.0f - m_Sharpness ), vSmooth );
+ VectorScale( vSharp, m_Sharpness, vSharp );
+ VectorAdd( vSmooth, vSharp, m_NewEdgeNormal );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivEdge::CalcNewEdgePoint( void )
+{
+ if( !m_Active )
+ return;
+
+ //
+ // get the subdivision mesh
+ //
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return;
+
+ CSubdivMesh *pMesh = pDoc->GetSubdivMesh();
+
+ //
+ // get the edge data
+ //
+ Vector edgePt0, edgePt1;
+ pMesh->GetPoint( m_ndxPoint[0], edgePt0 );
+ pMesh->GetPoint( m_ndxPoint[1], edgePt1 );
+
+ //
+ // calculate the "sharp" new edge point
+ //
+ Vector vSharp;
+ VectorClear( vSharp );
+ VectorAdd( edgePt0, edgePt1, vSharp );
+ VectorScale( vSharp, 0.5f, vSharp );
+
+ //
+ // calculate the "smooth" new edge point if necessary
+ //
+ Vector vSmooth;
+ VectorClear( vSmooth );
+ if( m_pQuads[1] && ( m_Sharpness != 1.0f ) )
+ {
+ Vector centroids[2];
+ m_pQuads[0]->GetCentroid( centroids[0] );
+ m_pQuads[1]->GetCentroid( centroids[1] );
+ VectorAdd( edgePt0, edgePt1, vSmooth );
+ VectorAdd( vSmooth, centroids[0], vSmooth );
+ VectorAdd( vSmooth, centroids[1], vSmooth );
+ VectorScale( vSmooth, 0.25f, vSmooth );
+ }
+ else
+ {
+ // make sure -- if here because of no neighboring quad
+ m_Sharpness = 1.0f;
+ m_pQuads[0]->CalcCentroid();
+ }
+
+ //
+ // calculate the new edge point
+ //
+ // ( 1 - edge(sharpness) ) * vSmooth + edge(sharpness) * vSharp
+ //
+ VectorScale( vSmooth, ( 1.0f - m_Sharpness ), vSmooth );
+ VectorScale( vSharp, m_Sharpness, vSharp );
+ VectorAdd( vSmooth, vSharp, m_NewEdgePoint );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CompareSubdivEdges( const CSubdivEdge *pEdge1, const CSubdivEdge *pEdge2 )
+{
+ if( ( ( pEdge1->m_ndxPoint[0] == pEdge2->m_ndxPoint[0] ) && ( pEdge1->m_ndxPoint[1] == pEdge2->m_ndxPoint[1] ) ) ||
+ ( ( pEdge1->m_ndxPoint[0] == pEdge2->m_ndxPoint[1] ) && ( pEdge1->m_ndxPoint[1] == pEdge2->m_ndxPoint[0] ) ) )
+ return true;
+
+ return false;
+}
+
+
+//=============================================================================
+//
+// Subdivision Quad Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivQuad::GetCentroid( Vector& centroid )
+{
+ // get the subdivision mesh
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return;
+
+ CSubdivMesh *pMesh = pDoc->GetSubdivMesh();
+
+ VectorClear( centroid );
+ for( int i = 0; i < 4; i++ )
+ {
+ Vector point;
+ pMesh->GetPoint( m_ndxVert[i], point );
+ VectorAdd( centroid, point, centroid );
+ }
+
+ VectorScale( centroid, 0.25f, centroid );
+
+ // keep to surface creation
+ m_Centroid = centroid;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivQuad::CalcCentroid( void )
+{
+ // get the subdivision mesh
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return;
+
+ CSubdivMesh *pMesh = pDoc->GetSubdivMesh();
+
+ VectorClear( m_Centroid );
+ for( int i = 0; i < 4; i++ )
+ {
+ Vector point;
+ pMesh->GetPoint( m_ndxVert[i], point );
+ VectorAdd( m_Centroid, point, m_Centroid );
+ }
+
+ VectorScale( m_Centroid, 0.25f, m_Centroid );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivQuad::GetNormal( Vector& normal )
+{
+ // get the subdivision mesh
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return;
+
+ CSubdivMesh *pMesh = pDoc->GetSubdivMesh();
+
+ Vector points[3];
+ Vector segs[2];
+
+ pMesh->GetPoint( m_ndxVert[0], points[0] );
+ pMesh->GetPoint( m_ndxVert[1], points[1] );
+ pMesh->GetPoint( m_ndxVert[2], points[2] );
+
+ VectorSubtract( points[1], points[0], segs[0] );
+ VectorSubtract( points[2], points[0], segs[1] );
+
+ CrossProduct( segs[1], segs[0], normal );
+ VectorNormalize( normal );
+
+ m_Normal = normal;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivQuad::CalcNormal( void )
+{
+ // get the subdivision mesh
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return;
+
+ CSubdivMesh *pMesh = pDoc->GetSubdivMesh();
+
+ Vector points[3];
+ Vector segs[2];
+
+ pMesh->GetPoint( m_ndxVert[0], points[0] );
+ pMesh->GetPoint( m_ndxVert[1], points[1] );
+ pMesh->GetPoint( m_ndxVert[2], points[2] );
+
+ VectorSubtract( points[1], points[0], segs[0] );
+ VectorSubtract( points[2], points[0], segs[1] );
+
+ CrossProduct( segs[1], segs[0], m_Normal );
+ VectorNormalize( m_Normal );
+}
+
+
+//=============================================================================
+//
+// Subdivision Mesh Functions
+//
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CSubdivMesh::CSubdivMesh()
+{
+ Clear();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CSubdivMesh::~CSubdivMesh()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CSubdivMesh::AddPoint( const Vector& point, const Vector& normal )
+{
+ //
+ // check for existing point within CSubdivPoints
+ //
+ for( int i = 0; i < m_PointCount; i++ )
+ {
+ if( CompareSubdivPointToPoint( &m_pPoints[i], point, 0.01f ) )
+ return i;
+ }
+
+ if( m_PointCount >= m_MaxPointCount )
+ {
+ // error message!
+ return -1;
+ }
+
+ m_pPoints[m_PointCount].m_Point = point;
+ m_pPoints[m_PointCount].m_Normal = normal;
+ m_PointCount++;
+
+ return ( m_PointCount - 1 );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::RemovePoint( Vector& point )
+{
+ //
+ // find point in list (and remove it)
+ //
+ for( int i = 0; i < m_PointCount; i++ )
+ {
+ if( !CompareSubdivPointToPoint( &m_pPoints[i], point, 0.01f ) )
+ continue;
+
+ if( i == ( m_PointCount - 1 ) )
+ {
+ m_pPoints[i].Clear();
+ }
+ else
+ {
+ m_pPoints[i].Copy( &m_pPoints[m_PointCount-1] );
+ m_pPoints[m_PointCount-1].Clear();
+ }
+
+ m_PointCount--;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CSubdivMesh::AddEdge( CSubdivEdge *edge )
+{
+ //
+ // check for existing edge
+ //
+ for( int i = 0; i < m_EdgeCount; i++ )
+ {
+ if( CompareSubdivEdges( edge, &m_pEdges[i] ) )
+ {
+ //
+ // check for "quads" on both sides of edge (add if necessary)
+ //
+ if( ( !m_pEdges[i].m_pQuads[1] ) && ( edge->m_pQuads[0] != m_pEdges[i].m_pQuads[0] ) )
+ {
+ m_pEdges[i].m_pQuads[1] = edge->m_pQuads[0];
+ m_pEdges[i].m_ndxQuadEdge[1] = edge->m_ndxQuadEdge[0];
+ m_pEdges[i].m_Sharpness = 0.0f;
+ }
+
+ return i;
+ }
+ }
+
+ if( m_EdgeCount >= m_MaxEdgeCount )
+ {
+ // error message!
+ return -1;
+ }
+
+ m_pEdges[m_EdgeCount].Copy( edge );
+ m_pEdges[m_EdgeCount].m_Active = true;
+ m_EdgeCount++;
+
+ return ( m_EdgeCount - 1 );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::RemoveEdge( CSubdivEdge *edge )
+{
+ return;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::CatmullClarkSubdivide( void )
+{
+ //
+ // calculate the "new edge points"
+ //
+ for( int i = 0; i < m_EdgeCount; i++ )
+ {
+ m_pEdges[i].CalcNewEdgePoint();
+ m_pEdges[i].CalcNewEdgeNormal();
+ }
+
+ //
+ // if point index if part of edge, add to point edge list and increment valence
+ //
+ for( i = 0; i < m_PointCount; i++ )
+ {
+ for( int j = 0; j < m_EdgeCount; j++ )
+ {
+ if( !m_pEdges[j].m_Active )
+ continue;
+
+ if( ( i == m_pEdges[j].m_ndxPoint[0] ) || ( i == m_pEdges[j].m_ndxPoint[1] ) )
+ {
+ m_pPoints[i].m_pEdges[m_pPoints[i].m_Valence] = &m_pEdges[j];
+ m_pPoints[i].m_Valence++;
+ }
+ }
+ }
+
+ //
+ // determine the point's "type"
+ //
+ for( i = 0; i < m_PointCount; i++ )
+ {
+ //
+ // get the number of sharp incident edges and neighbor data
+ //
+ int sharpnessCount = 0;
+ int sharpnessThreshold = m_pPoints[i].m_Valence - 1;
+ bool bHasNeighbors = false;
+
+ for( int j = 0; j < m_pPoints[i].m_Valence; j++ )
+ {
+ if( m_pPoints[i].m_pEdges[j]->m_Sharpness > 0.0f )
+ {
+ sharpnessCount++;
+ }
+
+ if( m_pPoints[i].m_pEdges[j]->m_pQuads[1] )
+ {
+ bHasNeighbors = true;
+ }
+ }
+
+ //
+ // determine point type
+ //
+ if( ( sharpnessCount >= sharpnessThreshold ) || !bHasNeighbors )
+// if( ( sharpnessCount > 2 ) || !bHasNeighbors )
+ {
+ m_pPoints[i].m_Type = CSubdivPoint::POINT_CORNER;
+ continue;
+ }
+
+ if( sharpnessCount > 1 )
+// if( sharpnessCount == 2 )
+ {
+ m_pPoints[i].m_Type = CSubdivPoint::POINT_CREASE;
+ continue;
+ }
+
+ m_pPoints[i].m_Type = CSubdivPoint::POINT_ORDINARY;
+ }
+
+ //
+ // calculate the new vertex point
+ //
+ for( i = 0; i < m_PointCount; i++ )
+ {
+ m_pPoints[i].CalcNewVertexPoint();
+ m_pPoints[i].CalcNewVertexNormal();
+ }
+
+ //
+ // move all new points to points
+ //
+ for( i = 0; i < m_PointCount; i++ )
+ {
+ m_pPoints[i].m_Point = m_pPoints[i].m_NewPoint;
+ m_pPoints[i].m_Normal = m_pPoints[i].m_NewNormal;
+ VectorClear( m_pPoints[i].m_NewPoint );
+ VectorClear( m_pPoints[i].m_NewNormal );
+ m_pPoints[i].m_Valence = 0;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CSubdivMesh::AddTree( CSubdivQuad *pTree )
+{
+ //
+ // check to see if tree already exists in list
+ //
+ for( int i = 0; i < m_TreeCount; i++ )
+ {
+ if( pTree == m_ppTrees[i] )
+ return i;
+ }
+
+ //
+ // check tree count
+ //
+ if( m_TreeCount >= m_MaxTreeCount )
+ {
+ // error message
+ _asm int 3;
+ return -1;
+ }
+
+ //
+ // add tree to list
+ //
+ m_ppTrees[m_TreeCount] = pTree;
+ m_TreeCount++;
+
+ return ( m_TreeCount - 1 );
+}
+
+static HCURSOR preSubdivCursor;
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CSubdivMesh::PreSubdivide( void )
+{
+ // change the mouse to hourglass -- so level designers know something is
+ // happening
+ preSubdivCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
+
+ // clear the mesh
+ Clear();
+
+ //
+ // get the selection set
+ //
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return false;
+
+ CDispManager *pDispManager = pDoc->GetDispManager();
+ if( !pDispManager )
+ return false;
+
+ // get number of displacements in selection
+ int selectionCount = pDispManager->GetSelectionListCount();
+
+ // allocate memory
+ if( !AllocCache( selectionCount ) )
+ return false;
+
+ // mark the subdivision undo
+ GetHistory()->MarkUndoPosition( NULL, "Subdivision" );
+
+ //
+ // add all surfaces to mesh to subdivide
+ //
+ for( int i = 0; i < selectionCount; i++ )
+ {
+ // get the current displacement surface
+ CMapDisp *pDisp = pDispManager->GetFromSelectionList( i );
+ if( !pDisp )
+ continue;
+
+ //
+ // setup for undo
+ //
+ CMapFace *pFace = ( CMapFace* )pDisp->GetParent();
+ CMapSolid *pSolid = ( CMapSolid* )pFace->GetParent();
+ GetHistory()->Keep( ( CMapClass* )pSolid );
+
+ //
+ // add displacement's subdivision tree to mesh list
+ //
+ if( AddTree( pDisp->PreSubdivide( this ) ) == -1 )
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::SetEdgeData( CSubdivQuad *pRoot, int index, int parentIndex, int subdivIndex )
+{
+ for( int i = 0; i < 4; i++ )
+ {
+ CSubdivEdge edge;
+
+ //
+ // add vert indices
+ //
+ edge.m_ndxPoint[0] = pRoot[index].m_ndxVert[i];
+ edge.m_ndxPoint[1] = pRoot[index].m_ndxVert[(i+1)%4];
+
+ //
+ // set initial quads and edges data
+ //
+ edge.m_pQuads[0] = &pRoot[index];
+ edge.m_pQuads[1] = NULL;
+
+ edge.m_ndxQuadEdge[0] = i;
+ edge.m_ndxQuadEdge[1] = -1;
+
+ //
+ // set edge sharpness
+ //
+ if( ( i == subdivIndex ) || ( i == ( (subdivIndex+3)%4 ) ) )
+ {
+ edge.m_Sharpness = m_pEdges[pRoot[parentIndex].m_ndxEdge[i]].m_Sharpness;
+ }
+ else
+ {
+ edge.m_Sharpness = 0.0f;
+ }
+
+ // add edge to global list
+ pRoot[index].m_ndxEdge[i] = AddEdge( &edge );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::CreateChildQuad4( CSubdivQuad *pRoot, int index, int parentIndex )
+{
+ //
+ // set quad indices -- displacement index values
+ //
+ pRoot[index].m_ndxQuad[0] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[3] ) / 2 );
+ pRoot[index].m_ndxQuad[1] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[2] ) / 2 );
+ pRoot[index].m_ndxQuad[2] = ( ( pRoot[parentIndex].m_ndxQuad[2] + pRoot[parentIndex].m_ndxQuad[3] ) / 2 );
+ pRoot[index].m_ndxQuad[3] = pRoot[parentIndex].m_ndxQuad[3];
+
+ //
+ // set vert indices
+ //
+ pRoot[index].m_ndxVert[0] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[3]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[3]].m_NewEdgeNormal );
+ pRoot[index].m_ndxVert[1] = AddPoint( pRoot[parentIndex].m_Centroid, pRoot[parentIndex].m_Normal );
+ pRoot[index].m_ndxVert[2] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[2]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[2]].m_NewEdgeNormal );
+ pRoot[index].m_ndxVert[3] = pRoot[parentIndex].m_ndxVert[3];
+
+ // set edge data
+ SetEdgeData( pRoot, index, parentIndex, 3 );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::CreateChildQuad3( CSubdivQuad *pRoot, int index, int parentIndex )
+{
+ //
+ // set quad indices -- displacement index values
+ //
+ pRoot[index].m_ndxQuad[0] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[2] ) / 2 );
+ pRoot[index].m_ndxQuad[1] = ( ( pRoot[parentIndex].m_ndxQuad[1] + pRoot[parentIndex].m_ndxQuad[2] ) / 2 );
+ pRoot[index].m_ndxQuad[2] = pRoot[parentIndex].m_ndxQuad[2];
+ pRoot[index].m_ndxQuad[3] = ( ( pRoot[parentIndex].m_ndxQuad[2] + pRoot[parentIndex].m_ndxQuad[3] ) / 2 );
+
+ //
+ // set vert indices
+ //
+ pRoot[index].m_ndxVert[0] = AddPoint( pRoot[parentIndex].m_Centroid, pRoot[parentIndex].m_Normal );
+ pRoot[index].m_ndxVert[1] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[1]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[1]].m_NewEdgeNormal );
+ pRoot[index].m_ndxVert[2] = pRoot[parentIndex].m_ndxVert[2];
+ pRoot[index].m_ndxVert[3] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[2]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[2]].m_NewEdgeNormal );
+
+ // set edge data
+ SetEdgeData( pRoot, index, parentIndex, 2 );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::CreateChildQuad2( CSubdivQuad *pRoot, int index, int parentIndex )
+{
+ //
+ // set quad indices -- displacement index values
+ //
+ pRoot[index].m_ndxQuad[0] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[1] ) / 2 );
+ pRoot[index].m_ndxQuad[1] = pRoot[parentIndex].m_ndxQuad[1];
+ pRoot[index].m_ndxQuad[2] = ( ( pRoot[parentIndex].m_ndxQuad[1] + pRoot[parentIndex].m_ndxQuad[2] ) / 2 );
+ pRoot[index].m_ndxQuad[3] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[2] ) / 2 );
+
+ //
+ // set vert indices
+ //
+ pRoot[index].m_ndxVert[0] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[0]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[0]].m_NewEdgeNormal );
+ pRoot[index].m_ndxVert[1] = pRoot[parentIndex].m_ndxVert[1];
+ pRoot[index].m_ndxVert[2] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[1]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[1]].m_NewEdgeNormal );
+ pRoot[index].m_ndxVert[3] = AddPoint( pRoot[parentIndex].m_Centroid, pRoot[parentIndex].m_Normal );
+
+ // set edge data
+ SetEdgeData( pRoot, index, parentIndex, 1 );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::CreateChildQuad1( CSubdivQuad *pRoot, int index, int parentIndex )
+{
+ //
+ // set quad indices -- displacement index values
+ //
+ pRoot[index].m_ndxQuad[0] = pRoot[parentIndex].m_ndxQuad[0];
+ pRoot[index].m_ndxQuad[1] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[1] ) / 2 );
+ pRoot[index].m_ndxQuad[2] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[2] ) / 2 );
+ pRoot[index].m_ndxQuad[3] = ( ( pRoot[parentIndex].m_ndxQuad[0] + pRoot[parentIndex].m_ndxQuad[3] ) / 2 );
+
+ //
+ // set vert indices
+ //
+ pRoot[index].m_ndxVert[0] = pRoot[parentIndex].m_ndxVert[0];
+ pRoot[index].m_ndxVert[1] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[0]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[0]].m_NewEdgeNormal );
+ pRoot[index].m_ndxVert[2] = AddPoint( pRoot[parentIndex].m_Centroid, pRoot[parentIndex].m_Normal );
+ pRoot[index].m_ndxVert[3] = AddPoint( m_pEdges[pRoot[parentIndex].m_ndxEdge[3]].m_NewEdgePoint,
+ m_pEdges[pRoot[parentIndex].m_ndxEdge[3]].m_NewEdgeNormal );
+
+ // set edge data
+ SetEdgeData( pRoot, index, parentIndex, 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::CreateChildQuads( CSubdivQuad *pRoot, int quadIndex )
+{
+ //
+ // create children
+ //
+ CreateChildQuad1( pRoot, ( ( quadIndex << 2 ) + 1 ), quadIndex );
+ CreateChildQuad2( pRoot, ( ( quadIndex << 2 ) + 2 ), quadIndex );
+ CreateChildQuad3( pRoot, ( ( quadIndex << 2 ) + 3 ), quadIndex );
+ CreateChildQuad4( pRoot, ( ( quadIndex << 2 ) + 4 ), quadIndex );
+
+ for( int i = 0; i < 4; i++ )
+ {
+ m_pEdges[pRoot[quadIndex].m_ndxEdge[i]].m_Active = false;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::AddQuadToMesh( CSubdivQuad *pQuad )
+{
+ return;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CSubdivMesh::GetEndIndexFromLevel( int levelIndex )
+{
+ switch( levelIndex )
+ {
+ case 0: { return 0; }
+ case 1: { return 4; }
+ case 2: { return 20; }
+ case 3: { return 84; }
+ default: { return 0; }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CSubdivMesh::GetStartIndexFromLevel( int levelIndex )
+{
+ switch( levelIndex )
+ {
+ case 0: { return 0; }
+ case 1: { return 1; }
+ case 2: { return 5; }
+ case 3: { return 21; }
+ default: { return 0; }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::Subdivide( void )
+{
+ //
+ // subdivide to four levels always (what the trees hold)
+ //
+ for( int subdivLevel = 0; subdivLevel < 4; subdivLevel++ )
+ {
+ int startIndex = GetStartIndexFromLevel( subdivLevel );
+ int endIndex = GetEndIndexFromLevel( subdivLevel );
+
+ // subdivide
+ CatmullClarkSubdivide();
+
+ //
+ // add subdivision data to subdivision tree
+ //
+ for( int treeIndex = 0; treeIndex < m_TreeCount; treeIndex++ )
+ {
+ //
+ // get the current tree
+ //
+ CSubdivQuad *pTree = m_ppTrees[treeIndex];
+ if( !pTree )
+ continue;
+
+ //
+ // for each quad in the tree (at the given level)
+ //
+ for( int index = startIndex; index <= endIndex; index++ )
+ {
+ CreateChildQuads( pTree, index );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::PostSubdivide( void )
+{
+ //
+ // get the selection set
+ //
+ CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
+ if( !pDoc )
+ return;
+
+ CDispManager *pDispManager = pDoc->GetDispManager();
+ if( !pDispManager )
+ return;
+
+ //
+ // add all surfaces to mesh to subdivide
+ //
+ int selectionCount = pDispManager->GetSelectionListCount();
+ for( int i = 0; i < selectionCount; i++ )
+ {
+ // get the current displacement surface
+ CMapDisp *pDisp = pDispManager->GetFromSelectionList( i );
+ if( !pDisp )
+ continue;
+
+ // post subdivide
+ pDisp->PostSubdivide( this );
+ }
+
+ // destroy cache!!!
+ FreeCache();
+
+ // set the cursor back to its previous state (before subdivision
+ SetCursor( preSubdivCursor );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::DoSubdivide( void )
+{
+ PreSubdivide();
+ Subdivide();
+ PostSubdivide();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CSubdivMesh::AllocCache( int dispCount )
+{
+#define POINTS_PER_DISP 512
+#define EDGES_PER_DISP 1024
+
+ m_MaxPointCount = POINTS_PER_DISP * dispCount;
+ m_MaxEdgeCount = EDGES_PER_DISP * dispCount;
+ m_MaxTreeCount = dispCount;
+
+ m_pPoints = new CSubdivPoint[m_MaxPointCount];
+ m_pEdges = new CSubdivEdge[m_MaxEdgeCount];
+ m_ppTrees = new CSubdivQuad*[m_MaxTreeCount];
+
+ if( !m_pPoints || !m_pEdges || !m_ppTrees )
+ {
+ FreeCache();
+ return false;
+ }
+
+ //
+ // clear cache
+ //
+ for( int i = 0; i < m_MaxPointCount; i++ )
+ {
+ m_pPoints[i].Clear();
+ }
+
+ for( i = 0; i < m_MaxEdgeCount; i++ )
+ {
+ m_pEdges[i].Clear();
+ }
+
+ //
+ // tell size of cache
+ //
+ int size = m_MaxPointCount * sizeof( CSubdivPoint );
+ size += m_MaxEdgeCount * sizeof( CSubdivEdge );
+ size += m_MaxTreeCount * sizeof( CSubdivQuad );
+
+ TRACE1( "Subdiv Cache: %d\n", size );
+
+ return true;
+
+#undef POINTS_PER_DISP
+#undef EDGES_PER_DISP
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CSubdivMesh::FreeCache( void )
+{
+ if( m_pPoints )
+ {
+ delete [] m_pPoints;
+ m_pPoints = NULL;
+ m_PointCount = 0;
+ }
+
+ if( m_pEdges )
+ {
+ delete [] m_pEdges;
+ m_pEdges = NULL;
+ m_EdgeCount = 0;
+ }
+
+ if( m_ppTrees )
+ {
+ delete [] m_ppTrees;
+ m_ppTrees = NULL;
+ m_TreeCount = 0;
+ }
+
+ // tell cache destroyed!!
+ TRACE0( "Subdiv Cache Destroyed!\n" );
+}