You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1253 lines
32 KiB
1253 lines
32 KiB
//========= 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" ); |
|
}
|
|
|