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.
1128 lines
35 KiB
1128 lines
35 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
// |
|
//=============================================================================// |
|
|
|
#include <stdafx.h> |
|
#include "DispSubdiv.h" |
|
#include "MapDisp.h" |
|
#include "UtlLinkedList.h" |
|
#include "utlvector.h" |
|
#include "GlobalFunctions.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
//============================================================================= |
|
// |
|
// Editable Displacement Subdivision Mesh Implementation |
|
// |
|
class CEditDispSubdivMesh : public IEditDispSubdivMesh |
|
{ |
|
public: // functions |
|
|
|
void Init( void ); |
|
void Shutdown( void ); |
|
|
|
void AddDispTo( CMapDisp *pDisp ); |
|
void GetDispFrom( CMapDisp *pDisp ); |
|
|
|
void DoCatmullClarkSubdivision( void ); |
|
|
|
public: // typedefs, enums, structs |
|
|
|
enum { EDITDISP_QUADSIZE = 4 }; // should be in mapdisp (general define) |
|
|
|
private: // typedefs, enums, structs |
|
|
|
typedef int SubdivPointHandle_t; |
|
typedef int SubdivEdgeHandle_t; |
|
typedef int SubdivQuadHandle_t; |
|
|
|
enum { NUM_SUBDIV_LEVELS = 4 }; // number of subdivision levels |
|
|
|
enum |
|
{ |
|
SUBDIV_DISPPOINTS = 512, |
|
SUBDIV_DISPEDGES = 1024, |
|
SUBDIV_DISPQUADS = 512 |
|
}; |
|
|
|
enum |
|
{ |
|
SUBDIV_POINTORDINARY = 0, |
|
SUBDIV_POINTCORNER = 1, |
|
SUBDIV_POINTCREASE = 2 |
|
}; |
|
|
|
struct SubdivPoint_t |
|
{ |
|
Vector m_vPoint; |
|
Vector m_vNormal; |
|
Vector m_vNewPoint; |
|
Vector m_vNewNormal; |
|
unsigned short m_uType; |
|
unsigned short m_uValence; |
|
SubdivEdgeHandle_t m_EdgeHandles[EDITDISP_QUADSIZE*4]; |
|
}; |
|
|
|
struct SubdivEdge_t |
|
{ |
|
Vector m_vNewEdgePoint; |
|
Vector m_vNewEdgeNormal; |
|
SubdivPointHandle_t m_PointHandles[2]; |
|
SubdivQuadHandle_t m_QuadHandles[2]; |
|
float m_flSharpness; |
|
bool m_bActive; |
|
}; |
|
|
|
struct SubdivQuad_t |
|
{ |
|
// generated |
|
Vector m_vCentroid; // quad center |
|
Vector m_vNormal; // quad normal |
|
|
|
// linkage |
|
SubdivQuadHandle_t m_ndxParent; // parent quad index |
|
SubdivQuadHandle_t m_ndxChild[EDITDISP_QUADSIZE]; // chilren (4 of them) indices |
|
|
|
// quad data |
|
SubdivPointHandle_t m_PointHandles[EDITDISP_QUADSIZE]; // point indices - unique list |
|
SubdivEdgeHandle_t m_EdgeHandles[EDITDISP_QUADSIZE]; // edge indices - unique list |
|
|
|
// disp/quad mapping |
|
EditDispHandle_t m_EditDispHandle; |
|
short m_Level; // level of quad in the hierarchy (tree) |
|
short m_QuadIndices[EDITDISP_QUADSIZE]; // quad indices (in the X x X displacement surface) |
|
}; |
|
|
|
private: // functions |
|
|
|
SubdivPoint_t *GetPoint( SubdivPointHandle_t ptHandle ); |
|
SubdivEdge_t *GetEdge( SubdivEdgeHandle_t edgeHandle ); |
|
SubdivQuad_t *GetQuad( SubdivQuadHandle_t quadHandle ); |
|
|
|
void Point_Init( SubdivPointHandle_t ptHandle ); |
|
void Point_CalcNewPoint( SubdivPointHandle_t ptHandle ); |
|
void Point_PointOrdinary( SubdivPoint_t *pPoint ); |
|
void Point_PointCorner( SubdivPoint_t *pPoint ); |
|
void Point_PointCrease( SubdivPoint_t *pPoint ); |
|
|
|
void Edge_Init( SubdivEdgeHandle_t edgeHandle ); |
|
void Edge_CalcNewPoint( SubdivEdgeHandle_t edgeHandle ); |
|
|
|
void Quad_Init( SubdivQuadHandle_t quadHandle ); |
|
void Quad_CalcCentroid( SubdivQuadHandle_t quadHandle ); |
|
void Quad_CalcNormal( SubdivQuadHandle_t quadHandle ); |
|
|
|
bool CompareSubdivPoints( Vector const &pt1, Vector const &pt2, float flTolerance ); |
|
bool CompareSubdivEdges( SubdivPointHandle_t ptEdge0Handle0, SubdivPointHandle_t ptEdge0Handle1, |
|
SubdivPointHandle_t ptEdge1Handle0, SubdivPointHandle_t ptEdge1Handle1 ); |
|
|
|
SubdivPointHandle_t BuildSubdivPoint( Vector const &vPoint, Vector const &vNormal ); |
|
SubdivEdgeHandle_t BuildSubdivEdge( int ndxEdge, SubdivQuadHandle_t quadHandle, |
|
SubdivQuadHandle_t parentHandle, int ndxChild ); |
|
SubdivQuadHandle_t BuildSubdivQuad( int ndxChild, SubdivQuadHandle_t parentHandle ); |
|
|
|
void CatmullClarkSubdivision( void ); |
|
void UpdateSubdivisionHierarchy( int ndxLevel ); |
|
|
|
private: // variables |
|
|
|
CUtlLinkedList<SubdivPoint_t, SubdivPointHandle_t> m_Points; |
|
CUtlLinkedList<SubdivEdge_t, SubdivEdgeHandle_t> m_Edges; |
|
CUtlLinkedList<SubdivQuad_t, SubdivQuadHandle_t> m_Quads; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
IEditDispSubdivMesh *CreateEditDispSubdivMesh( void ) |
|
{ |
|
return new CEditDispSubdivMesh; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void DestroyEditDispSubdivMesh( IEditDispSubdivMesh **pSubdivMesh ) |
|
{ |
|
if ( *pSubdivMesh ) |
|
{ |
|
delete *pSubdivMesh; |
|
*pSubdivMesh = NULL; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CEditDispSubdivMesh::SubdivPoint_t *CEditDispSubdivMesh::GetPoint( SubdivPointHandle_t ptHandle ) |
|
{ |
|
if ( !m_Points.IsValidIndex( ptHandle ) ) |
|
return NULL; |
|
|
|
return &m_Points.Element( ptHandle ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CEditDispSubdivMesh::SubdivEdge_t *CEditDispSubdivMesh::GetEdge( SubdivEdgeHandle_t edgeHandle ) |
|
{ |
|
if ( !m_Edges.IsValidIndex( edgeHandle ) ) |
|
return NULL; |
|
|
|
return &m_Edges.Element( edgeHandle ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CEditDispSubdivMesh::SubdivQuad_t *CEditDispSubdivMesh::GetQuad( SubdivQuadHandle_t quadHandle ) |
|
{ |
|
if ( !m_Quads.IsValidIndex( quadHandle ) ) |
|
return NULL; |
|
|
|
return &m_Quads.Element( quadHandle ); |
|
} |
|
|
|
|
|
//============================================================================= |
|
// |
|
// Subdivision Edit Displacement Point Functions |
|
// |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Point_Init( SubdivPointHandle_t ptHandle ) |
|
{ |
|
SubdivPoint_t *pPoint = GetPoint( ptHandle ); |
|
if ( pPoint ) |
|
{ |
|
VectorClear( pPoint->m_vPoint ); |
|
VectorClear( pPoint->m_vNormal ); |
|
VectorClear( pPoint->m_vNewPoint ); |
|
VectorClear( pPoint->m_vNewNormal ); |
|
|
|
pPoint->m_uType = (unsigned short)-1; |
|
pPoint->m_uValence = 0; |
|
|
|
for ( int ndxEdge = 0; ndxEdge < ( EDITDISP_QUADSIZE*2 ); ndxEdge++ ) |
|
{ |
|
pPoint->m_EdgeHandles[ndxEdge] = m_Edges.InvalidIndex(); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Point_CalcNewPoint( SubdivPointHandle_t ptHandle ) |
|
{ |
|
// get the point to act on |
|
SubdivPoint_t *pPoint = GetPoint( ptHandle ); |
|
if ( !pPoint ) |
|
return; |
|
|
|
switch ( pPoint->m_uType ) |
|
{ |
|
case SUBDIV_POINTORDINARY: { Point_PointOrdinary( pPoint ); break; } |
|
case SUBDIV_POINTCORNER: { Point_PointCorner( pPoint ); break; } |
|
case SUBDIV_POINTCREASE: { Point_PointCrease( pPoint ); break; } |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Point_PointOrdinary( SubdivPoint_t *pPoint ) |
|
{ |
|
// |
|
// accumulate the edge data and multiply by the valence (coincident edge) |
|
// ratio (squared) |
|
// |
|
Vector edgeAccumPoint( 0.0f, 0.0f, 0.0f ); |
|
Vector edgeAccumNormal( 0.0f, 0.0f, 0.0f ); |
|
for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] ); |
|
if ( pEdge ) |
|
{ |
|
VectorAdd( edgeAccumPoint, pEdge->m_vNewEdgePoint, edgeAccumPoint ); |
|
VectorAdd( edgeAccumNormal, pEdge->m_vNewEdgeNormal, edgeAccumNormal ); |
|
} |
|
} |
|
|
|
float ratio = 1.0f / ( float )( pPoint->m_uValence * pPoint->m_uValence ); |
|
|
|
VectorScale( edgeAccumPoint, ratio, edgeAccumPoint ); |
|
VectorScale( edgeAccumNormal, ratio, edgeAccumNormal ); |
|
|
|
// |
|
// accumlate the centroid data from all neighboring quads and multiply by |
|
// the valence (coincident edge) ratio (squared) |
|
// |
|
int quadListCount = 0; |
|
SubdivQuadHandle_t quadList[32]; |
|
|
|
for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] ); |
|
if ( pEdge ) |
|
{ |
|
for ( int ndxQuad = 0; ndxQuad < 2; ndxQuad++ ) |
|
{ |
|
if ( pEdge->m_QuadHandles[ndxQuad] != m_Quads.InvalidIndex() ) |
|
{ |
|
int ndxList; |
|
for ( ndxList = 0; ndxList < quadListCount; ndxList++ ) |
|
{ |
|
if( pEdge->m_QuadHandles[ndxQuad] == quadList[ndxList] ) |
|
break; |
|
} |
|
|
|
if( ndxList == quadListCount ) |
|
{ |
|
quadList[quadListCount] = pEdge->m_QuadHandles[ndxQuad]; |
|
quadListCount++; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
Vector centroidAccum( 0.0f, 0.0f, 0.0f ); |
|
for ( int ndxQuad = 0; ndxQuad < quadListCount; ndxQuad++ ) |
|
{ |
|
SubdivQuadHandle_t quadHandle = quadList[ndxQuad]; |
|
Quad_CalcCentroid( quadHandle ); |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
VectorAdd( centroidAccum, pQuad->m_vCentroid, centroidAccum ); |
|
} |
|
|
|
VectorScale( centroidAccum, ratio, centroidAccum ); |
|
|
|
// |
|
// |
|
// |
|
ratio = ( ( float )pPoint->m_uValence - 2.0f ) / ( float )pPoint->m_uValence; |
|
|
|
VectorScale( pPoint->m_vPoint, ratio, pPoint->m_vNewPoint ); |
|
VectorAdd( pPoint->m_vNewPoint, edgeAccumPoint, pPoint->m_vNewPoint ); |
|
VectorAdd( pPoint->m_vNewPoint, centroidAccum, pPoint->m_vNewPoint ); |
|
|
|
VectorScale( pPoint->m_vNormal, ratio, pPoint->m_vNewNormal ); |
|
VectorAdd( pPoint->m_vNewNormal, edgeAccumNormal, pPoint->m_vNewNormal ); |
|
VectorAdd( pPoint->m_vNewNormal, centroidAccum, pPoint->m_vNewNormal ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Point_PointCorner( SubdivPoint_t *pPoint ) |
|
{ |
|
VectorCopy( pPoint->m_vPoint, pPoint->m_vNewPoint ); |
|
VectorCopy( pPoint->m_vNormal, pPoint->m_vNewNormal ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Point_PointCrease( SubdivPoint_t *pPoint ) |
|
{ |
|
// |
|
// accumulate the edge data and multiply by the valence (coincident edge) |
|
// ratio (squared) |
|
// |
|
Vector edgeAccumPoint( 0.0f, 0.0f, 0.0f ); |
|
Vector edgeAccumNormal( 0.0f, 0.0f, 0.0f ); |
|
for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] ); |
|
if ( pEdge && ( pEdge->m_flSharpness > 0.0f ) ) |
|
{ |
|
VectorAdd( edgeAccumPoint, pEdge->m_vNewEdgePoint, edgeAccumPoint ); |
|
VectorAdd( edgeAccumNormal, pEdge->m_vNewEdgeNormal, edgeAccumNormal ); |
|
} |
|
} |
|
|
|
// |
|
// |
|
// |
|
VectorScale( pPoint->m_vPoint, 6.0f, pPoint->m_vNewPoint ); |
|
VectorAdd( pPoint->m_vNewPoint, edgeAccumPoint, pPoint->m_vNewPoint ); |
|
VectorScale( pPoint->m_vNewPoint, 0.125f, pPoint->m_vNewPoint ); |
|
|
|
VectorScale( pPoint->m_vNormal, 6.0f, pPoint->m_vNewNormal ); |
|
VectorAdd( pPoint->m_vNewNormal, edgeAccumNormal, pPoint->m_vNewNormal ); |
|
VectorScale( pPoint->m_vNewNormal, 0.125f, pPoint->m_vNewNormal ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Edge_Init( SubdivEdgeHandle_t edgeHandle ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( edgeHandle ); |
|
if ( pEdge ) |
|
{ |
|
VectorClear( pEdge->m_vNewEdgePoint ); |
|
VectorClear( pEdge->m_vNewEdgeNormal ); |
|
|
|
pEdge->m_flSharpness = 1.0f; |
|
pEdge->m_bActive = false; |
|
|
|
for ( int ndx = 0; ndx < 2; ndx++ ) |
|
{ |
|
pEdge->m_PointHandles[ndx] = m_Points.InvalidIndex(); |
|
pEdge->m_QuadHandles[ndx] = m_Quads.InvalidIndex(); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Edge_CalcNewPoint( SubdivEdgeHandle_t edgeHandle ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( edgeHandle ); |
|
if ( !pEdge ) |
|
return; |
|
|
|
if ( !pEdge->m_bActive ) |
|
return; |
|
|
|
// |
|
// get edge points |
|
// |
|
SubdivPoint_t *pPoint0 = GetPoint( pEdge->m_PointHandles[0] ); |
|
SubdivPoint_t *pPoint1 = GetPoint( pEdge->m_PointHandles[1] ); |
|
if ( !pPoint0 || !pPoint1 ) |
|
return; |
|
|
|
// |
|
// calculate the "sharp" new edge point |
|
// |
|
Vector vSharpPoint( 0.0f, 0.0f, 0.0f ); |
|
VectorAdd( pPoint0->m_vPoint, pPoint1->m_vPoint, vSharpPoint ); |
|
VectorScale( vSharpPoint, 0.5f, vSharpPoint ); |
|
|
|
Vector vSharpNormal( 0.0f, 0.0f, 0.0f ); |
|
VectorAdd( pPoint0->m_vNormal, pPoint1->m_vNormal, vSharpNormal ); |
|
VectorNormalize( vSharpNormal ); |
|
|
|
// |
|
// calculate the "smooth" new edge point (if necessary) |
|
// |
|
Vector vSmoothPoint( 0.0f, 0.0f, 0.0f ); |
|
Vector vSmoothNormal( 0.0f, 0.0f, 0.0f ); |
|
if ( ( pEdge->m_QuadHandles[1] != m_Edges.InvalidIndex() ) && ( pEdge->m_flSharpness != 1.0f ) ) |
|
{ |
|
Quad_CalcCentroid( pEdge->m_QuadHandles[0] ); |
|
Quad_CalcCentroid( pEdge->m_QuadHandles[1] ); |
|
Quad_CalcNormal( pEdge->m_QuadHandles[0] ); |
|
Quad_CalcNormal( pEdge->m_QuadHandles[1] ); |
|
SubdivQuad_t *pQuad0 = GetQuad( pEdge->m_QuadHandles[0] ); |
|
SubdivQuad_t *pQuad1 = GetQuad( pEdge->m_QuadHandles[1] ); |
|
|
|
VectorAdd( pPoint0->m_vPoint, pPoint1->m_vPoint, vSmoothPoint ); |
|
VectorAdd( vSmoothPoint, pQuad0->m_vCentroid, vSmoothPoint ); |
|
VectorAdd( vSmoothPoint, pQuad1->m_vCentroid, vSmoothPoint ); |
|
VectorScale( vSmoothPoint, 0.25f, vSmoothPoint ); |
|
|
|
VectorAdd( pPoint0->m_vNormal, pPoint1->m_vNormal, vSmoothNormal ); |
|
VectorAdd( vSmoothNormal, pQuad0->m_vNormal, vSmoothNormal ); |
|
VectorAdd( vSmoothNormal, pQuad1->m_vNormal, vSmoothNormal ); |
|
VectorNormalize( vSmoothNormal ); |
|
} |
|
else |
|
{ |
|
pEdge->m_flSharpness = 1.0f; |
|
Quad_CalcCentroid( pEdge->m_QuadHandles[0] ); |
|
Quad_CalcNormal( pEdge->m_QuadHandles[0] ); |
|
} |
|
|
|
// |
|
// calculate the new edge point |
|
// |
|
// ( 1 - edge(sharpness) ) * vSmooth + edge(sharpness) * vSharp |
|
// |
|
VectorScale( vSmoothPoint, ( 1.0f - pEdge->m_flSharpness ), vSmoothPoint ); |
|
VectorScale( vSharpPoint, pEdge->m_flSharpness, vSharpPoint ); |
|
VectorAdd( vSmoothPoint, vSharpPoint, pEdge->m_vNewEdgePoint ); |
|
|
|
VectorScale( vSmoothNormal, ( 1.0f - pEdge->m_flSharpness ), vSmoothNormal ); |
|
VectorScale( vSharpNormal, pEdge->m_flSharpness, vSharpNormal ); |
|
VectorAdd( vSmoothNormal, vSharpNormal, pEdge->m_vNewEdgeNormal ); |
|
VectorNormalize( pEdge->m_vNewEdgeNormal ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Quad_Init( SubdivQuadHandle_t quadHandle ) |
|
{ |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
if ( pQuad ) |
|
{ |
|
VectorClear( pQuad->m_vCentroid ); |
|
VectorClear( pQuad->m_vNormal ); |
|
|
|
pQuad->m_ndxParent = m_Quads.InvalidIndex(); |
|
pQuad->m_EditDispHandle = EDITDISPHANDLE_INVALID; |
|
pQuad->m_Level = -1; |
|
|
|
for ( int ndx = 0; ndx < EDITDISP_QUADSIZE; ndx++ ) |
|
{ |
|
pQuad->m_ndxChild[ndx] = m_Quads.InvalidIndex(); |
|
|
|
pQuad->m_PointHandles[ndx] = m_Points.InvalidIndex(); |
|
pQuad->m_EdgeHandles[ndx] = m_Edges.InvalidIndex(); |
|
pQuad->m_QuadIndices[ndx] = -1; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Quad_CalcCentroid( SubdivQuadHandle_t quadHandle ) |
|
{ |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
if ( pQuad ) |
|
{ |
|
VectorClear( pQuad->m_vCentroid ); |
|
for ( int ndxPt = 0; ndxPt < EDITDISP_QUADSIZE; ndxPt++ ) |
|
{ |
|
SubdivPoint_t *pPoint = GetPoint( pQuad->m_PointHandles[ndxPt] ); |
|
VectorAdd( pQuad->m_vCentroid, pPoint->m_vPoint, pQuad->m_vCentroid ); |
|
} |
|
|
|
VectorScale( pQuad->m_vCentroid, 0.25f, pQuad->m_vCentroid ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Quad_CalcNormal( SubdivQuadHandle_t quadHandle ) |
|
{ |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
if ( pQuad ) |
|
{ |
|
SubdivPoint_t *pPoints[3]; |
|
Vector edges[2]; |
|
|
|
pPoints[0] = GetPoint( pQuad->m_PointHandles[0] ); |
|
pPoints[1] = GetPoint( pQuad->m_PointHandles[1] ); |
|
pPoints[2] = GetPoint( pQuad->m_PointHandles[2] ); |
|
|
|
VectorSubtract( pPoints[1]->m_vPoint, pPoints[0]->m_vPoint, edges[0] ); |
|
VectorSubtract( pPoints[2]->m_vPoint, pPoints[0]->m_vPoint, edges[1] ); |
|
|
|
CrossProduct( edges[1], edges[0], pQuad->m_vNormal ); |
|
VectorNormalize( pQuad->m_vNormal ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CEditDispSubdivMesh::CompareSubdivPoints( Vector const &pt1, Vector const &pt2, |
|
float flTolerance ) |
|
{ |
|
for ( int axis = 0 ; axis < 3 ; axis++ ) |
|
{ |
|
if ( fabs( pt1[axis] - pt2[axis] ) > flTolerance ) |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CEditDispSubdivMesh::CompareSubdivEdges( SubdivPointHandle_t ptEdge0Handle0, |
|
SubdivPointHandle_t ptEdge0Handle1, |
|
SubdivPointHandle_t ptEdge1Handle0, |
|
SubdivPointHandle_t ptEdge1Handle1 ) |
|
{ |
|
if ( ( ( ptEdge0Handle0 == ptEdge1Handle0 ) && ( ptEdge0Handle1 == ptEdge1Handle1 ) ) || |
|
( ( ptEdge0Handle0 == ptEdge1Handle1 ) && ( ptEdge0Handle1 == ptEdge1Handle0 ) ) ) |
|
return true; |
|
|
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CEditDispSubdivMesh::SubdivPointHandle_t CEditDispSubdivMesh::BuildSubdivPoint( Vector const &vPoint, |
|
Vector const &vPointNormal ) |
|
{ |
|
// |
|
// build a "unique" point |
|
// |
|
SubdivPointHandle_t ptHandle; |
|
for ( ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); |
|
ptHandle = m_Points.Next( ptHandle ) ) |
|
{ |
|
SubdivPoint_t *pPoint = GetPoint( ptHandle ); |
|
if ( pPoint ) |
|
{ |
|
// compare (positions) |
|
if ( CompareSubdivPoints( vPoint, pPoint->m_vPoint, 0.1f ) ) |
|
return ptHandle; |
|
} |
|
} |
|
|
|
ptHandle = m_Points.AddToTail(); |
|
Point_Init( ptHandle ); |
|
SubdivPoint_t *pPoint = GetPoint( ptHandle ); |
|
VectorCopy( vPoint, pPoint->m_vPoint ); |
|
VectorCopy( vPointNormal, pPoint->m_vNormal ); |
|
|
|
return ptHandle; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CEditDispSubdivMesh::SubdivEdgeHandle_t CEditDispSubdivMesh::BuildSubdivEdge( int ndxEdge, SubdivQuadHandle_t quadHandle, |
|
SubdivQuadHandle_t parentHandle, int ndxChild ) |
|
{ |
|
// get the quad |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
if ( !pQuad ) |
|
return m_Edges.InvalidIndex(); |
|
|
|
// |
|
// define a unique edge (m_PointHandlesX2, m_QuadHandle) |
|
// |
|
SubdivEdgeHandle_t edgeHandle; |
|
for ( edgeHandle = m_Edges.Head(); edgeHandle != m_Edges.InvalidIndex(); |
|
edgeHandle = m_Edges.Next( edgeHandle ) ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( edgeHandle ); |
|
if ( pEdge ) |
|
{ |
|
// compare (point handles) |
|
if ( CompareSubdivEdges( pQuad->m_PointHandles[ndxEdge], pQuad->m_PointHandles[(ndxEdge+1)%4], |
|
pEdge->m_PointHandles[0], pEdge->m_PointHandles[1] ) ) |
|
{ |
|
// check to see if the quad is quad 0 or 1 (or if it needs to be quad 1) |
|
if ( ( pEdge->m_QuadHandles[0] != quadHandle ) && |
|
( pEdge->m_QuadHandles[1] == m_Quads.InvalidIndex() ) ) |
|
{ |
|
pEdge->m_QuadHandles[1] = quadHandle; |
|
pEdge->m_flSharpness = 0.0f; // smooth edge (between two subdiv quads) |
|
} |
|
|
|
return edgeHandle; |
|
} |
|
} |
|
} |
|
|
|
edgeHandle = m_Edges.AddToTail(); |
|
Edge_Init( edgeHandle ); |
|
SubdivEdge_t *pEdge = GetEdge( edgeHandle ); |
|
|
|
pEdge->m_PointHandles[0] = pQuad->m_PointHandles[ndxEdge]; |
|
pEdge->m_PointHandles[1] = pQuad->m_PointHandles[(ndxEdge+1)%4]; |
|
pEdge->m_QuadHandles[0] = quadHandle; |
|
pEdge->m_bActive = true; |
|
|
|
// extra data for children (get edge sharpness from parent or |
|
// it may be an internal edge and its sharpness will be 0) |
|
if( ndxChild != -1 ) |
|
{ |
|
if ( ( ndxEdge == ndxChild ) || ( ndxEdge == ( (ndxChild+3)%4 ) ) ) |
|
{ |
|
SubdivQuad_t *pParentQuad = GetQuad( parentHandle ); |
|
if ( pParentQuad ) |
|
{ |
|
SubdivEdge_t *pParentEdge = GetEdge( pParentQuad->m_EdgeHandles[ndxEdge] ); |
|
pEdge->m_flSharpness = pParentEdge->m_flSharpness; |
|
} |
|
} |
|
else |
|
{ |
|
pEdge->m_flSharpness = 0.0f; |
|
} |
|
} |
|
|
|
return edgeHandle; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CEditDispSubdivMesh::SubdivQuadHandle_t CEditDispSubdivMesh::BuildSubdivQuad( int ndxChild, |
|
SubdivQuadHandle_t parentHandle ) |
|
{ |
|
// get parent quad |
|
SubdivQuad_t *pParentQuad = GetQuad( parentHandle ); |
|
if( !pParentQuad ) |
|
return m_Quads.InvalidIndex(); |
|
|
|
// allocate a new quad |
|
SubdivQuadHandle_t quadHandle = m_Quads.AddToTail(); |
|
Quad_Init( quadHandle ); |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
pQuad->m_ndxParent = parentHandle; |
|
pQuad->m_EditDispHandle = pParentQuad->m_EditDispHandle; |
|
pQuad->m_Level = pParentQuad->m_Level + 1; |
|
|
|
switch ( ndxChild ) |
|
{ |
|
case 0: |
|
{ |
|
// displacement quad indices |
|
pQuad->m_QuadIndices[0] = pParentQuad->m_QuadIndices[0]; |
|
pQuad->m_QuadIndices[1] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[1] ) * 0.5f; |
|
pQuad->m_QuadIndices[2] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f; |
|
pQuad->m_QuadIndices[3] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[3] ) * 0.5f; |
|
|
|
// new verts |
|
SubdivEdge_t *pEdge0 = GetEdge( pParentQuad->m_EdgeHandles[0] ); |
|
SubdivEdge_t *pEdge3 = GetEdge( pParentQuad->m_EdgeHandles[3] ); |
|
if ( pEdge0 && pEdge3 ) |
|
{ |
|
pQuad->m_PointHandles[0] = pParentQuad->m_PointHandles[0]; |
|
pQuad->m_PointHandles[1] = BuildSubdivPoint( pEdge0->m_vNewEdgePoint, pEdge0->m_vNewEdgeNormal ); |
|
pQuad->m_PointHandles[2] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal ); |
|
pQuad->m_PointHandles[3] = BuildSubdivPoint( pEdge3->m_vNewEdgePoint, pEdge3->m_vNewEdgeNormal ); |
|
} |
|
|
|
break; |
|
} |
|
case 1: |
|
{ |
|
// displacement quad indices |
|
pQuad->m_QuadIndices[0] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[1] ) * 0.5f; |
|
pQuad->m_QuadIndices[1] = pParentQuad->m_QuadIndices[1]; |
|
pQuad->m_QuadIndices[2] = ( pParentQuad->m_QuadIndices[1] + pParentQuad->m_QuadIndices[2] ) * 0.5f; |
|
pQuad->m_QuadIndices[3] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f; |
|
|
|
// new verts |
|
SubdivEdge_t *pEdge0 = GetEdge( pParentQuad->m_EdgeHandles[0] ); |
|
SubdivEdge_t *pEdge1 = GetEdge( pParentQuad->m_EdgeHandles[1] ); |
|
if ( pEdge0 && pEdge1 ) |
|
{ |
|
pQuad->m_PointHandles[0] = BuildSubdivPoint( pEdge0->m_vNewEdgePoint, pEdge0->m_vNewEdgeNormal ); |
|
pQuad->m_PointHandles[1] = pParentQuad->m_PointHandles[1]; |
|
pQuad->m_PointHandles[2] = BuildSubdivPoint( pEdge1->m_vNewEdgePoint, pEdge1->m_vNewEdgeNormal ); |
|
pQuad->m_PointHandles[3] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal ); |
|
} |
|
|
|
break; |
|
} |
|
case 2: |
|
{ |
|
// displacement quad indices |
|
pQuad->m_QuadIndices[0] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f; |
|
pQuad->m_QuadIndices[1] = ( pParentQuad->m_QuadIndices[1] + pParentQuad->m_QuadIndices[2] ) * 0.5f; |
|
pQuad->m_QuadIndices[2] = pParentQuad->m_QuadIndices[2]; |
|
pQuad->m_QuadIndices[3] = ( pParentQuad->m_QuadIndices[2] + pParentQuad->m_QuadIndices[3] ) * 0.5f; |
|
|
|
// new verts |
|
SubdivEdge_t *pEdge1 = GetEdge( pParentQuad->m_EdgeHandles[1] ); |
|
SubdivEdge_t *pEdge2 = GetEdge( pParentQuad->m_EdgeHandles[2] ); |
|
if ( pEdge1 && pEdge2 ) |
|
{ |
|
pQuad->m_PointHandles[0] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal ); |
|
pQuad->m_PointHandles[1] = BuildSubdivPoint( pEdge1->m_vNewEdgePoint, pEdge1->m_vNewEdgeNormal ); |
|
pQuad->m_PointHandles[2] = pParentQuad->m_PointHandles[2]; |
|
pQuad->m_PointHandles[3] = BuildSubdivPoint( pEdge2->m_vNewEdgePoint, pEdge2->m_vNewEdgeNormal ); |
|
} |
|
|
|
break; |
|
} |
|
case 3: |
|
{ |
|
// displacement quad indices |
|
pQuad->m_QuadIndices[0] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[3] ) * 0.5f; |
|
pQuad->m_QuadIndices[1] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f; |
|
pQuad->m_QuadIndices[2] = ( pParentQuad->m_QuadIndices[2] + pParentQuad->m_QuadIndices[3] ) * 0.5f; |
|
pQuad->m_QuadIndices[3] = pParentQuad->m_QuadIndices[3]; |
|
|
|
// new verts |
|
SubdivEdge_t *pEdge2 = GetEdge( pParentQuad->m_EdgeHandles[2] ); |
|
SubdivEdge_t *pEdge3 = GetEdge( pParentQuad->m_EdgeHandles[3] ); |
|
if ( pEdge2 && pEdge3 ) |
|
{ |
|
pQuad->m_PointHandles[0] = BuildSubdivPoint( pEdge3->m_vNewEdgePoint, pEdge3->m_vNewEdgeNormal ); |
|
pQuad->m_PointHandles[1] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal ); |
|
pQuad->m_PointHandles[2] = BuildSubdivPoint( pEdge2->m_vNewEdgePoint, pEdge2->m_vNewEdgeNormal ); |
|
pQuad->m_PointHandles[3] = pParentQuad->m_PointHandles[3]; |
|
} |
|
|
|
break; |
|
} |
|
} |
|
|
|
// |
|
// buidl new quad edges |
|
// |
|
for ( int ndxEdge = 0; ndxEdge < 4; ndxEdge++ ) |
|
{ |
|
pQuad->m_EdgeHandles[ndxEdge] = BuildSubdivEdge( ndxEdge, quadHandle, parentHandle, ndxChild ); |
|
} |
|
|
|
return quadHandle; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Init( void ) |
|
{ |
|
// ensure capacity on all lists |
|
IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager(); |
|
if( !pDispMgr ) |
|
return; |
|
|
|
int selectCount = pDispMgr->SelectCount(); |
|
m_Points.EnsureCapacity( SUBDIV_DISPPOINTS * selectCount ); |
|
m_Edges.EnsureCapacity( SUBDIV_DISPEDGES * selectCount ); |
|
m_Quads.EnsureCapacity( SUBDIV_DISPQUADS * selectCount ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::Shutdown( void ) |
|
{ |
|
// clear all lists |
|
m_Points.Purge(); |
|
m_Edges.Purge(); |
|
m_Quads.Purge(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::AddDispTo( CMapDisp *pDisp ) |
|
{ |
|
// add a quad to the subdivision mesh |
|
SubdivQuadHandle_t quadHandle = m_Quads.AddToTail(); |
|
Quad_Init( quadHandle ); |
|
SubdivQuad_t *pQuad = &m_Quads.Element( quadHandle ); |
|
|
|
// this is the parent! |
|
pQuad->m_ndxParent = m_Quads.InvalidIndex(); |
|
pQuad->m_EditDispHandle = pDisp->GetEditHandle(); |
|
pQuad->m_Level = 0; |
|
|
|
// |
|
// get displacement data |
|
// |
|
int dispWidth = pDisp->GetWidth(); |
|
int dispHeight = pDisp->GetHeight(); |
|
|
|
// |
|
// setup mapping between the displacement size and initial quad indices |
|
// |
|
pQuad->m_QuadIndices[0] = 0; |
|
pQuad->m_QuadIndices[1] = dispWidth * ( dispHeight - 1 ); |
|
pQuad->m_QuadIndices[2] = ( dispWidth * dispHeight ) - 1; |
|
pQuad->m_QuadIndices[3] = ( dispWidth - 1 ); |
|
|
|
// |
|
// find point normals and neighbors -- "smooth" |
|
// NOTE: this is slow -- should write a faster version (is offline process, do later) |
|
// |
|
IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager(); |
|
if( !pDispMgr ) |
|
return; |
|
|
|
Vector vPoints[4]; |
|
Vector vPointNormals[4]; |
|
for( int ndxPt = 0; ndxPt < EDITDISP_QUADSIZE; ndxPt++ ) |
|
{ |
|
// get the base face normal of all surfaces touching this point! |
|
pDisp->GetSurfNormal( vPointNormals[ndxPt] ); |
|
|
|
// get the point to compare to neighbors |
|
pDisp->GetSurfPoint( ndxPt, vPoints[ndxPt] ); |
|
|
|
int count = pDispMgr->SelectCount(); |
|
for( int ndxSelect = 0; ndxSelect < count; ndxSelect++ ) |
|
{ |
|
CMapDisp *pSelectDisp = pDispMgr->GetFromSelect( ndxSelect ); |
|
if( !pSelectDisp || ( pSelectDisp == pDisp ) ) |
|
continue; |
|
|
|
for( int ndxPt2 = 0; ndxPt2 < EDITDISP_QUADSIZE; ndxPt2++ ) |
|
{ |
|
Vector vPoint; |
|
pSelectDisp->GetSurfPoint( ndxPt2, vPoint ); |
|
|
|
if( CompareSubdivPoints( vPoints[ndxPt], vPoint, 0.01f ) ) |
|
{ |
|
Vector vNormal; |
|
pSelectDisp->GetSurfNormal( vNormal ); |
|
VectorAdd( vPointNormals[ndxPt], vNormal, vPointNormals[ndxPt] ); |
|
} |
|
} |
|
} |
|
|
|
VectorNormalize( vPointNormals[ndxPt] ); |
|
} |
|
|
|
// build subdivision points |
|
for( int ndxPt = 0; ndxPt < EDITDISP_QUADSIZE; ndxPt++ ) |
|
{ |
|
pQuad->m_PointHandles[ndxPt] = BuildSubdivPoint( vPoints[ndxPt], vPointNormals[ndxPt] ); |
|
} |
|
|
|
// build subdivision edges |
|
for( int ndxEdge = 0; ndxEdge < EDITDISP_QUADSIZE; ndxEdge++ ) |
|
{ |
|
pQuad->m_EdgeHandles[ndxEdge] = BuildSubdivEdge( ndxEdge, quadHandle, m_Quads.InvalidIndex(), -1 ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::GetDispFrom( CMapDisp *pDisp ) |
|
{ |
|
// |
|
// find the parent quad with the id of the displacement |
|
// |
|
for ( SubdivQuadHandle_t quadHandle = m_Quads.Head(); quadHandle != m_Quads.InvalidIndex(); |
|
quadHandle = m_Quads.Next( quadHandle ) ) |
|
{ |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
if ( pQuad ) |
|
{ |
|
// find children quads that "belong" to this displacement |
|
if( pQuad->m_EditDispHandle != pDisp->GetEditHandle() ) |
|
continue; |
|
|
|
// get the data at the appropriate level -- (based on the size of the displacement) |
|
if ( pQuad->m_Level != pDisp->GetPower() ) |
|
continue; |
|
|
|
// |
|
// fill in subdivision positions and normals |
|
// |
|
for ( int ndxPt = 0; ndxPt < 4; ndxPt++ ) |
|
{ |
|
SubdivPoint_t *pPoint = GetPoint( pQuad->m_PointHandles[ndxPt] ); |
|
if ( pPoint ) |
|
{ |
|
Vector vFlatVert, vSubVert; |
|
pDisp->GetFlatVert( pQuad->m_QuadIndices[ndxPt], vFlatVert ); |
|
VectorSubtract( pPoint->m_vPoint, vFlatVert, vSubVert ); |
|
pDisp->UpdateVertPositionForSubdiv( pQuad->m_QuadIndices[ndxPt], vSubVert ); |
|
pDisp->SetSubdivNormal( pQuad->m_QuadIndices[ndxPt], pPoint->m_vNormal ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// tell the dispalcemet to update itself |
|
pDisp->UpdateData(); |
|
|
|
// reset subdivision/subdivided flags |
|
pDisp->SetReSubdivision( false ); |
|
pDisp->SetSubdivided( true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::DoCatmullClarkSubdivision( void ) |
|
{ |
|
for ( int ndxLevel = 0; ndxLevel < NUM_SUBDIV_LEVELS; ndxLevel++ ) |
|
{ |
|
// subdivide |
|
CatmullClarkSubdivision(); |
|
|
|
// update the subdivision hierarchy (tree) |
|
UpdateSubdivisionHierarchy( ndxLevel ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::CatmullClarkSubdivision( void ) |
|
{ |
|
// |
|
// step 1: calculate the "new edge points" for all edges |
|
// |
|
for ( SubdivEdgeHandle_t edgeHandle = m_Edges.Head(); edgeHandle != m_Edges.InvalidIndex(); |
|
edgeHandle = m_Edges.Next( edgeHandle ) ) |
|
{ |
|
Edge_CalcNewPoint( edgeHandle ); |
|
} |
|
|
|
// |
|
// step 2: calculate the valence and edge list |
|
// |
|
for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); |
|
ptHandle = m_Points.Next( ptHandle ) ) |
|
{ |
|
for ( SubdivEdgeHandle_t edgeHandle = m_Edges.Head(); edgeHandle != m_Edges.InvalidIndex(); |
|
edgeHandle = m_Edges.Next( edgeHandle ) ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( edgeHandle ); |
|
if ( !pEdge->m_bActive ) |
|
continue; |
|
|
|
if ( ( ptHandle == pEdge->m_PointHandles[0] ) || ( ptHandle == pEdge->m_PointHandles[1] ) ) |
|
{ |
|
SubdivPoint_t *pPoint = GetPoint( ptHandle ); |
|
|
|
if ( pPoint->m_uValence < ( EDITDISP_QUADSIZE*4 ) ) |
|
{ |
|
pPoint->m_EdgeHandles[pPoint->m_uValence] = edgeHandle; |
|
pPoint->m_uValence++; |
|
} |
|
} |
|
} |
|
} |
|
|
|
// |
|
// step 3: determine the point's Type (Oridinary, Corner, Crease) |
|
// |
|
for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); ptHandle = m_Points.Next( ptHandle ) ) |
|
{ |
|
SubdivPoint_t *pPoint = GetPoint( ptHandle ); |
|
if ( pPoint ) |
|
{ |
|
int sharpCount = 0; |
|
int sharpThreshold = pPoint->m_uValence - 1; |
|
bool bHasNeighbors = false; |
|
|
|
// initialize as oridinary -- determine otherwise |
|
pPoint->m_uType = SUBDIV_POINTORDINARY; |
|
|
|
for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] ); |
|
if ( pEdge ) |
|
{ |
|
if ( pEdge->m_flSharpness > 0.0f ) |
|
{ |
|
sharpCount++; |
|
} |
|
|
|
if ( pEdge->m_QuadHandles[1] != m_Quads.InvalidIndex() ) |
|
{ |
|
bHasNeighbors = true; |
|
} |
|
} |
|
} |
|
|
|
if ( !bHasNeighbors || ( sharpCount >= sharpThreshold ) ) |
|
{ |
|
pPoint->m_uType = SUBDIV_POINTCORNER; |
|
} |
|
else if( sharpCount > 1 ) |
|
{ |
|
pPoint->m_uType = SUBDIV_POINTCREASE; |
|
} |
|
} |
|
} |
|
|
|
// |
|
// step 4: calculate the "new points" for all points |
|
// |
|
for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); ptHandle = m_Points.Next( ptHandle ) ) |
|
{ |
|
Point_CalcNewPoint( ptHandle ); |
|
} |
|
|
|
// |
|
// step 5: copy all "new point" data to point data |
|
// |
|
for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); ptHandle = m_Points.Next( ptHandle ) ) |
|
{ |
|
SubdivPoint_t *pPoint = GetPoint( ptHandle ); |
|
VectorCopy( pPoint->m_vNewPoint, pPoint->m_vPoint ); |
|
VectorCopy( pPoint->m_vNewNormal, pPoint->m_vNewNormal ); |
|
VectorClear( pPoint->m_vNewPoint ); |
|
VectorClear( pPoint->m_vNewNormal ); |
|
|
|
// reset valence |
|
pPoint->m_uValence = 0; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CEditDispSubdivMesh::UpdateSubdivisionHierarchy( int ndxLevel ) |
|
{ |
|
int quadCount = m_Quads.Count(); |
|
SubdivQuadHandle_t quadHandle = m_Quads.Head(); |
|
int ndxQuad = 0; |
|
|
|
while ( ( quadHandle != m_Quads.InvalidIndex() ) && ( ndxQuad < quadCount ) ) |
|
{ |
|
SubdivQuad_t *pQuad = GetQuad( quadHandle ); |
|
if ( pQuad ) |
|
{ |
|
// skip parent quads |
|
if ( pQuad->m_ndxChild[0] != m_Quads.InvalidIndex() ) |
|
{ |
|
ndxQuad++; |
|
quadHandle = m_Quads.Next( quadHandle ); |
|
continue; |
|
} |
|
|
|
for( int ndxChild = 0; ndxChild < 4; ndxChild++ ) |
|
{ |
|
pQuad->m_ndxChild[ndxChild] = BuildSubdivQuad( ndxChild, quadHandle ); |
|
} |
|
|
|
// de-activate all edges (children's edges are active now!) |
|
for ( int ndxEdge = 0; ndxEdge < 4; ndxEdge++ ) |
|
{ |
|
SubdivEdge_t *pEdge = GetEdge( pQuad->m_EdgeHandles[ndxEdge] ); |
|
if ( pEdge ) |
|
{ |
|
pEdge->m_bActive = false; |
|
} |
|
} |
|
} |
|
|
|
ndxQuad++; |
|
quadHandle = m_Quads.Next( quadHandle ); |
|
} |
|
}
|
|
|