summaryrefslogtreecommitdiff
path: root/hammer/ssolid.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/ssolid.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/ssolid.cpp')
-rw-r--r--hammer/ssolid.cpp1711
1 files changed, 1711 insertions, 0 deletions
diff --git a/hammer/ssolid.cpp b/hammer/ssolid.cpp
new file mode 100644
index 0000000..1054cb9
--- /dev/null
+++ b/hammer/ssolid.cpp
@@ -0,0 +1,1711 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Structured Solid (CSSolid) implementation.
+//
+// Method of identifying different parts of solid (vertices/edges/faces) is
+// a unique-id system. The AddFace/AddEdge/AddVertex functions assign each
+// new "part" an id using GetNewID(). External objects referencing the CSSolid
+// do not have to worry about keeping track of indices into the private
+// arrays, since an ID is valid only if the part still exists. To get
+// information about an ID, use the GetHandleInfo() function -> it returns
+// FALSE if the given ID is no longer valid.
+//
+//=============================================================================
+
+#include "stdafx.h"
+#include "BrushOps.h"
+#include "GameConfig.h"
+#include "MapSolid.h"
+#include "MapWorld.h"
+#include "SSolid.h"
+#include "StockSolids.h"
+#include "Options.h"
+#include "WorldSize.h"
+#include "mapdisp.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+BOOL CheckFace(Vector *Points, int nPoints, Vector* pNormal, float dist, CCheckFaceInfo *pInfo)
+{
+ int j;
+ float d, edgedist;
+ Vector dir, edgenormal;
+
+ if(!pInfo)
+ {
+ static CCheckFaceInfo dummyinfo;
+ pInfo = &dummyinfo;
+ pInfo->iPoint = -1; // make sure it's reset to default
+ }
+
+ if(pInfo->iPoint == -2)
+ return TRUE; // stop!!!!!
+
+ // do we need to create a normal?
+ if(!pNormal)
+ {
+ static Vector _normal;
+ pNormal = &_normal;
+
+ // calc a plane from the points
+ Vector t1, t2, t3;
+
+ for(int i = 0; i < 3; i++)
+ {
+ t1[i] = Points[0][i] - Points[1][i];
+ t2[i] = Points[2][i] - Points[1][i];
+ t3[i] = Points[1][i];
+ }
+
+ CrossProduct(t1, t2, *pNormal);
+ VectorNormalize(*pNormal);
+ dist = DotProduct(t3, *pNormal);
+ }
+
+ if(!nPoints)
+ {
+ strcpy(pInfo->szDescription, "no points");
+ pInfo->iPoint = -2;
+ return FALSE;
+ }
+
+ if(nPoints < 3)
+ {
+ strcpy(pInfo->szDescription, "fewer than three points");
+ pInfo->iPoint = -2;
+ return FALSE;
+ }
+
+ for(int i = pInfo->iPoint + 1; i < nPoints; i++ )
+ {
+ pInfo->iPoint = i;
+
+ Vector& p1 = Points[i];
+
+ for (j=0 ; j<3 ; j++)
+ {
+ if (p1[j] > MAX_COORD_INTEGER || p1[j] < MIN_COORD_INTEGER)
+ {
+ strcpy(pInfo->szDescription, "out of range");
+ return FALSE;
+ }
+ }
+
+ // check the point is on the face plane
+ d = DotProduct (p1, *pNormal) - dist;
+ if (d < -ON_PLANE_EPSILON || d > ON_PLANE_EPSILON)
+ {
+ strcpy(pInfo->szDescription, "point off plane");
+ return FALSE;
+ }
+
+ // check the edge isn't degenerate
+ Vector& p2 = Points[i+1 == nPoints ? 0 : i+1]; // (next point)
+ VectorSubtract (p2, p1, dir);
+
+ if (VectorLength (dir) < MIN_EDGE_LENGTH_EPSILON)
+ {
+ strcpy(pInfo->szDescription, "edge is too small");
+ return FALSE;
+ }
+
+ CrossProduct(*pNormal, dir, edgenormal);
+ VectorNormalize (edgenormal);
+ edgedist = DotProduct(p1, edgenormal);
+ edgedist += ON_PLANE_EPSILON;
+
+ // all other points must be on front side
+ for (j=0 ; j< nPoints; j++)
+ {
+ if (j == i)
+ continue;
+ d = DotProduct (Points[j], edgenormal);
+ if (d > edgedist)
+ {
+ strcpy(pInfo->szDescription, "face is not convex");
+ return FALSE;
+ }
+ }
+ }
+
+ pInfo->iPoint = -2;
+ return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor.
+//-----------------------------------------------------------------------------
+CSSolid::CSSolid()
+{
+ m_nVertices = 0;
+ m_nEdges = 0;
+ m_nFaces = 0;
+ m_curid = 1;
+ m_pMapSolid = NULL;
+ m_bShowVertices = TRUE;
+ m_bShowEdges = TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor.
+//-----------------------------------------------------------------------------
+CSSolid::~CSSolid()
+{
+ memset(this, 0, sizeof(this));
+}
+
+
+SSHANDLE CSSolid::GetNewID()
+{
+ return m_curid++;
+}
+
+
+PVOID CSSolid::GetHandleData(SSHANDLE id)
+{
+ SSHANDLEINFO hi;
+ if(!GetHandleInfo(&hi, id))
+ return NULL;
+ return hi.pData;
+}
+
+
+BOOL CSSolid::GetHandleInfo(SSHANDLEINFO *pInfo, SSHANDLE id)
+{
+ // try vertices ..
+ for(int i = 0; i < m_nVertices; i++)
+ {
+ if(m_Vertices[i].id != id)
+ continue; // not this one
+
+ pInfo->Type = shtVertex;
+ pInfo->iIndex = i;
+ pInfo->pData = PVOID(& m_Vertices[i]);
+ pInfo->p2DHandle = & m_Vertices[i];
+ pInfo->pos = m_Vertices[i].pos;
+
+ return TRUE;
+ }
+
+ // try edges ..
+ for(int i = 0; i < m_nEdges; i++)
+ {
+ if(m_Edges[i].id != id)
+ continue; // not this one
+
+ pInfo->Type = shtEdge;
+ pInfo->iIndex = i;
+ pInfo->pData = PVOID(& m_Edges[i]);
+ pInfo->p2DHandle = & m_Edges[i];
+ pInfo->pos = m_Edges[i].ptCenter;
+
+ return TRUE;
+ }
+
+ // try faces ..
+ for(int i = 0; i < m_nFaces; i++)
+ {
+ if(m_Faces[i].id != id)
+ continue; // not this one
+
+ pInfo->Type = shtFace;
+ pInfo->iIndex = i;
+ pInfo->pData = PVOID(& m_Faces[i]);
+ pInfo->p2DHandle = & m_Faces[i];
+ pInfo->pos = m_Faces[i].ptCenter;
+
+ return TRUE;
+ }
+
+ pInfo->Type = shtNothing;
+ return FALSE;
+}
+
+
+// Find data functions ->
+int CSSolid::GetEdgeIndex(SSHANDLE v1, SSHANDLE v2)
+{
+ for(int i = 0; i < m_nEdges; i++)
+ {
+ CSSEdge & theEdge = m_Edges[i];
+ if((theEdge.hvStart == v1 && theEdge.hvEnd == v2) ||
+ (theEdge.hvStart == v2 && theEdge.hvEnd == v1))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : Point -
+// fLeniency -
+// Output :
+//-----------------------------------------------------------------------------
+int CSSolid::GetEdgeIndex(const Vector &Point, float fLeniency)
+{
+ for (int i = 0; i < m_nEdges; i++)
+ {
+ Vector ptEdgeCenter = m_Edges[i].ptCenter;
+
+ float fDiff = 0.0f;
+ for (int j = 0; j < 3; j++)
+ {
+ fDiff += (Point[j] - ptEdgeCenter[j]) * (Point[j] - ptEdgeCenter[j]);
+ }
+
+ if (fDiff > fLeniency * fLeniency)
+ {
+ continue;
+ }
+
+ // if we are here, the 3 axes compare ok.
+ return i;
+ }
+
+ // no edge matches
+ return -1;
+}
+
+
+int CSSolid::GetVertexIndex(const Vector &Point, float fLeniency)
+{
+ for(int i = 0; i < m_nVertices; i++)
+ {
+ Vector Vertex = m_Vertices[i].pos;
+
+ float fDiff = 0.0f;
+ for(int j = 0; j < 3; j++)
+ {
+ fDiff += (Point[j] - Vertex[j]) * (Point[j] - Vertex[j]);
+ }
+
+ if (fDiff > (fLeniency*fLeniency))
+ continue;
+
+ // if we are here, the 3 axes compare ok.
+ return i;
+ }
+
+ // no vertex matches.
+ return -1;
+}
+
+
+int CSSolid::GetFaceIndex(const Vector &Point, float fLeniency)
+{
+ return -1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Calculates the center of an edge.
+// Input : pEdge -
+//-----------------------------------------------------------------------------
+void CSSolid::CalcEdgeCenter(CSSEdge *pEdge)
+{
+ SSHANDLEINFO hi;
+
+ GetHandleInfo(&hi, pEdge->hvStart);
+ Vector &pt1 = m_Vertices[hi.iIndex].pos;
+
+ GetHandleInfo(&hi, pEdge->hvEnd);
+ Vector &pt2 = m_Vertices[hi.iIndex].pos;
+
+ for (int i = 0; i < 3; i++)
+ {
+ pEdge->ptCenter[i] = (pt1[i] + pt2[i]) / 2.0f;
+ }
+}
+
+// get common vertex from two edges ->
+
+SSHANDLE CSSolid::GetConnectionVertex(CSSEdge *pEdge1, CSSEdge *pEdge2)
+{
+ if((pEdge1->hvStart == pEdge2->hvStart) ||
+ (pEdge1->hvStart == pEdge2->hvEnd))
+ return pEdge1->hvStart;
+
+ if((pEdge1->hvEnd == pEdge2->hvStart) ||
+ (pEdge1->hvEnd == pEdge2->hvEnd))
+ return pEdge1->hvEnd;
+
+ return 0;
+}
+
+
+// Create list of points from face ->
+Vector * CSSolid::CreatePointList(CSSFace & face)
+{
+ Vector * pts = new Vector[face.nEdges+1];
+
+ for(int i = 0; i < face.nEdges; i++)
+ {
+ // calc next edge so we can see which is the next clockwise point
+ int iNextEdge = i+1;
+ if(iNextEdge == face.nEdges)
+ iNextEdge = 0;
+
+ CSSEdge * edgeCur = (CSSEdge*) GetHandleData(face.Edges[i]);
+ CSSEdge * edgeNext = (CSSEdge*) GetHandleData(face.Edges[iNextEdge]);
+
+ if(!edgeCur || !edgeNext)
+ {
+ CString str;
+ str.Format("Conversion error!\n"
+ "edgeCur = %p, edgeNext = %p", edgeCur, edgeNext);
+ AfxMessageBox(str);
+ return NULL;
+ }
+
+ SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext);
+
+ if(!hVertex)
+ {
+ CString str;
+ str.Format("Conversion error!\n"
+ "hVertex = %08X", hVertex);
+ AfxMessageBox(str);
+ return NULL;
+ }
+
+ CSSVertex *pVertex = (CSSVertex*) GetHandleData(hVertex);
+
+ pts[i] = pVertex->pos;
+ }
+
+ return pts;
+}
+
+
+// Create point list, but return indices instead of positions ->
+PINT CSSolid::CreatePointIndexList(CSSFace & face, PINT piPoints)
+{
+ PINT pts;
+ if(piPoints)
+ pts = piPoints;
+ else
+ pts = new int[face.nEdges+1];
+
+ SSHANDLEINFO hi;
+
+ for(int i = 0; i < face.nEdges; i++)
+ {
+ // calc next edge so we can see which is the next clockwise point
+ int iNextEdge = i+1;
+ if(iNextEdge == face.nEdges)
+ iNextEdge = 0;
+
+ CSSEdge * edgeCur = (CSSEdge*) GetHandleData(face.Edges[i]);
+ CSSEdge * edgeNext = (CSSEdge*) GetHandleData(face.Edges[iNextEdge]);
+
+ SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext);
+ Assert(hVertex);
+
+ GetHandleInfo(&hi, hVertex);
+ pts[i] = hi.iIndex;
+ }
+
+ return pts;
+}
+
+// Create point list, and use handles ->
+
+SSHANDLE* CSSolid::CreatePointHandleList(CSSFace & face, SSHANDLE* phPoints)
+{
+ SSHANDLE* pts;
+ if(phPoints)
+ pts = phPoints;
+ else
+ pts = new SSHANDLE[face.nEdges+1];
+
+ for(int i = 0; i < face.nEdges; i++)
+ {
+ // calc next edge so we can see which is the next clockwise point
+ int iNextEdge = i+1;
+ if(iNextEdge == face.nEdges)
+ iNextEdge = 0;
+
+ CSSEdge * edgeCur = (CSSEdge*) GetHandleData(face.Edges[i]);
+ CSSEdge * edgeNext = (CSSEdge*) GetHandleData(face.Edges[iNextEdge]);
+
+ SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext);
+ Assert(hVertex);
+
+ pts[i] = hVertex;
+ }
+
+ return pts;
+}
+
+
+void CSSolid::Attach(CMapSolid *pMapSolid)
+{
+ m_pMapSolid = pMapSolid;
+}
+
+
+CMapSolid *CSSolid::Detach()
+{
+ CMapSolid *pTmp = m_pMapSolid;
+ m_pMapSolid = NULL;
+ return pTmp;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns whether or not the SSolid has displacements.
+//-----------------------------------------------------------------------------
+bool CSSolid::HasDisps( void )
+{
+ for ( int iFace = 0; iFace < m_nFaces; ++iFace )
+ {
+ CSSFace *pFace = &m_Faces[iFace];
+ if ( pFace->m_hDisp != EDITDISPHANDLE_INVALID )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check to see if the SSolid with displacement surfaces has valid
+// base face surfaces.
+//-----------------------------------------------------------------------------
+bool CSSolid::IsValidWithDisps( void )
+{
+ if ( !HasDisps() )
+ return true;
+
+ for ( int iFace = 0; iFace < m_nFaces; ++iFace )
+ {
+ // Get the face(s) that have displacements.
+ CSSFace *pFace = &m_Faces[iFace];
+ if ( pFace->m_hDisp == EDITDISPHANDLE_INVALID )
+ continue;
+
+ // Create a face point list.
+ Vector *pFacePoints = CreatePointList( *pFace );
+
+ // If the face has changed the number of points - via merges, etc.
+ if ( pFace->nEdges != 4 )
+ return false;
+
+ // Check the face for validity.
+ CCheckFaceInfo faceInfo;
+ if ( !CheckFace( pFacePoints, pFace->nEdges, NULL, 0.0f, &faceInfo ) )
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destroy all the displacement data on the SSolid.
+//-----------------------------------------------------------------------------
+void CSSolid::DestroyDisps( void )
+{
+ for ( int iFace = 0; iFace < m_nFaces; ++iFace )
+ {
+ CSSFace *pFace = &m_Faces[iFace];
+ if ( pFace->m_hDisp != EDITDISPHANDLE_INVALID )
+ {
+ EditDispMgr()->Destroy( pFace->m_hDisp );
+ pFace->m_hDisp = EDITDISPHANDLE_INVALID;
+ }
+ }
+}
+
+void CSSolid::Convert(BOOL bFromMap, bool bSkipDisplacementFaces )
+{
+ if(bFromMap)
+ FromMapSolid(NULL, bSkipDisplacementFaces);
+ else
+ ToMapSolid();
+}
+
+
+void CSSolid::ToMapSolid(CMapSolid *p)
+{
+ // so we can pass NULL (default) or another solid (to copy):
+ CMapSolid *pSolid;
+ if (p)
+ {
+ pSolid = p;
+ }
+ else
+ {
+ pSolid = m_pMapSolid;
+ }
+
+ pSolid->SetFaceCount(m_nFaces);
+
+ unsigned char r, g, b;
+ pSolid->GetRenderColor( r,g,b );
+
+ for (int i = 0; i < m_nFaces; i++)
+ {
+ CSSFace &pFace = m_Faces[i];
+ CMapFace SolidFace;
+
+ //
+ // Copy original texture information and face ID back.
+ //
+ Q_memcpy(&SolidFace.texture, &pFace.texture, sizeof(TEXTURE));
+ SolidFace.SetTexture(SolidFace.texture.texture);
+ SolidFace.SetFaceID(pFace.m_nFaceID);
+
+ //
+ // Create face from new points.
+ //
+ Vector *pts = CreatePointList(pFace);
+
+ SolidFace.CreateFace(pts, pFace.nEdges);
+
+ //
+ // Vertex manipulation; the face orientation may have changed. If one of the texture axes is now
+ // perpendicular to the face, recalculate the texture axes using the default alignment (world or face).
+ // Ideally we would transform the texture axes so that their orientation relative to the face is preserved.
+ // By reinitializing the axes we risk having the axes rotate unpredictably.
+ //
+ if (!SolidFace.IsTextureAxisValid())
+ {
+ SolidFace.InitializeTextureAxes(Options.GetTextureAlignment(), INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE);
+ }
+
+ // Attempt to update the displacement - if there is one.
+ if ( pFace.m_hDisp != EDITDISPHANDLE_INVALID )
+ {
+ EditDispHandle_t hDisp = EditDispMgr()->Create();
+ CMapDisp *pSolidDisp = EditDispMgr()->GetDisp( hDisp );
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( pFace.m_hDisp );
+ pSolidDisp->CopyFrom( pDisp, false );
+ int iStart = pSolidDisp->GetSurfPointStartIndex();
+ pSolidDisp->SetSurfPointStartIndex( (iStart+3)%4 );
+ pSolidDisp->InitDispSurfaceData( &SolidFace, false );
+ pSolidDisp->Create();
+ SolidFace.SetDisp( hDisp );
+ }
+
+ CMapFace *pNewFace = pSolid->GetFace( i );
+ pNewFace->CopyFrom( &SolidFace, COPY_FACE_POINTS);
+ pNewFace->SetRenderColor(r, g, b);
+ pNewFace->SetParent(pSolid);
+
+ delete[] pts;
+ }
+
+ pSolid->PostUpdate(Notify_Changed);
+}
+
+
+CSSFace* CSSolid::AddFace(int* piNewIndex)
+{
+ m_Faces.SetCount(++m_nFaces);
+ if(piNewIndex)
+ piNewIndex[0] = m_nFaces-1;
+ CSSFace *pFace = & m_Faces[m_nFaces-1];
+ pFace->id = GetNewID();
+ return pFace;
+}
+
+// Add Edge ->
+
+CSSEdge* CSSolid::AddEdge(int* piNewIndex)
+{
+ m_Edges.SetCount(++m_nEdges);
+ if(piNewIndex)
+ piNewIndex[0] = m_nEdges-1;
+ CSSEdge *pEdge = & m_Edges[m_nEdges-1];
+ pEdge->id = GetNewID();
+ return pEdge;
+}
+
+// Add Vertex ->
+
+CSSVertex* CSSolid::AddVertex(int* piNewIndex)
+{
+ m_Vertices.SetCount(++m_nVertices);
+ if(piNewIndex)
+ piNewIndex[0] = m_nVertices-1;
+ CSSVertex *pVertex = & m_Vertices[m_nVertices-1];
+ pVertex->id = GetNewID();
+ return pVertex;
+}
+
+// Assign a face to an edge ->
+
+void CSSolid::AssignFace(CSSEdge* pEdge, SSHANDLE hFace, BOOL bRemove)
+{
+ if(!bRemove)
+ {
+ if(pEdge->Faces[0] == 0 || pEdge->Faces[0] == hFace)
+ pEdge->Faces[0] = hFace;
+ else if(pEdge->Faces[1] == 0)
+ pEdge->Faces[1] = hFace;
+ }
+ else
+ {
+ if(pEdge->Faces[0] == hFace)
+ pEdge->Faces[0] = 0;
+ if(pEdge->Faces[1] == hFace)
+ pEdge->Faces[1] = 0;
+ }
+}
+
+// Convert From Map Solid ->
+
+void CSSolid::FromMapSolid(CMapSolid *p, bool bSkipDisplacementFaces)
+{
+ // so we can pass NULL (default) or another solid (to copy):
+ CMapSolid *pSolid;
+ if(p)
+ pSolid = p;
+ else
+ pSolid = m_pMapSolid;
+
+ m_nFaces = 0;
+ m_nEdges = 0;
+ m_nVertices = 0;
+
+ // Create vertices, edges, faces.
+ int nSolidFaces = pSolid->GetFaceCount();
+ for(int i = 0; i < nSolidFaces; i++)
+ {
+ CMapFace *pSolidFace = pSolid->GetFace(i);
+
+ if (bSkipDisplacementFaces)
+ {
+ if (pSolidFace->HasDisp())
+ continue;
+ }
+
+ // Add a face
+ CSSFace *pFace = AddFace();
+
+ memcpy(pFace->PlanePts, pSolidFace->plane.planepts, sizeof(Vector) * 3);
+ pFace->texture = pSolidFace->texture;
+ pFace->normal = pSolidFace->plane.normal;
+ pFace->m_nFaceID = pSolidFace->GetFaceID();
+
+ // Displacement.
+ if ( pSolidFace->HasDisp() )
+ {
+ pFace->m_hDisp = EditDispMgr()->Create();
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( pFace->m_hDisp );
+ CMapDisp *pSolidDisp = EditDispMgr()->GetDisp( pSolidFace->GetDisp() );
+ pDisp->CopyFrom( pSolidDisp, false );
+ }
+
+ // Convert vertices and edges
+ int nFacePoints = pSolidFace->nPoints;
+ Vector *pFacePoints = pSolidFace->Points;
+ SSHANDLE hLastVertex = 0; // valid IDs start at 1
+ SSHANDLE hThisVertex, hFirstVertex = 0;
+ for(int pt = 0; pt <= nFacePoints; pt++)
+ {
+ int iVertex;
+
+ if(pt < nFacePoints)
+ {
+ // YWB: Change leniency from 1.0 down to 0.1
+ iVertex = GetVertexIndex(pFacePoints[pt], 0.1f);
+ if (iVertex == -1)
+ {
+ // not found - add the vertex
+ CSSVertex *pVertex = AddVertex(&iVertex);
+ pVertex->pos = pFacePoints[pt];
+ }
+
+ // assign this vertex handle
+ hThisVertex = m_Vertices[iVertex].id;
+
+ if (pt == 0)
+ hFirstVertex = hThisVertex;
+ }
+ else
+ {
+ // connect last to first
+ hThisVertex = hFirstVertex;
+ }
+
+ if (hLastVertex)
+ {
+ // create the edge from the last vertex to current vertex.
+ // first check to see if this edge already exists..
+ int iEdge = GetEdgeIndex(hLastVertex, hThisVertex);
+ CSSEdge *pEdge;
+ if (iEdge == -1)
+ {
+ // not found - add new edge
+ pEdge = AddEdge(&iEdge);
+ pEdge->hvStart = hLastVertex;
+ pEdge->hvEnd = hThisVertex;
+
+ // make sure edge center is valid:
+ CalcEdgeCenter(pEdge);
+ }
+ else
+ {
+ pEdge = &m_Edges[iEdge];
+ }
+
+ // add the edge to the face
+ pFace->Edges[pFace->nEdges++] = pEdge->id;
+
+ // set edge's face array
+ if(!pEdge->Faces[0])
+ pEdge->Faces[0] = pFace->id;
+ else if(!pEdge->Faces[1])
+ pEdge->Faces[1] = pFace->id;
+ else
+ {
+ // YWB try filling in front side
+ // rather than Assert(0) crash
+ pEdge->Faces[0] = pFace->id;
+ AfxMessageBox("Edge with both face id's already filled, skipping...");
+ }
+ }
+
+ hLastVertex = hThisVertex;
+ }
+ }
+}
+
+// Find edges that reference a vertex ->
+
+CSSEdge ** CSSolid::FindAffectedEdges(SSHANDLE *pHandles, int iNumHandles, int& iNumEdges)
+{
+ static CSSEdge *ppEdges[128];
+ iNumEdges = 0;
+
+ for(int h = 0; h < iNumHandles; h++)
+ {
+ for(int i = 0; i < m_nEdges; i++)
+ {
+ CSSEdge *pEdge = &m_Edges[i];
+ if(pEdge->hvStart == pHandles[h] ||
+ pEdge->hvEnd == pHandles[h])
+ {
+ // ensure it's not already stored
+ int s;
+ for(s = 0; s < iNumEdges; s++)
+ {
+ if(ppEdges[s] == pEdge)
+ break;
+ }
+ if(s == iNumEdges)
+ ppEdges[iNumEdges++] = pEdge;
+ }
+ }
+ }
+
+ return ppEdges;
+}
+
+
+// tell drawing code to show/hide kinds of handles
+void CSSolid::ShowHandles(BOOL bShowVertices, BOOL bShowEdges)
+{
+ m_bShowEdges = bShowEdges;
+ m_bShowVertices = bShowVertices;
+}
+
+
+// Move handle(s) to a new location ->
+void CSSolid::MoveSelectedHandles(const Vector &Delta)
+{
+ SSHANDLE MoveVertices[128];
+ int nMoveVertices = 0;
+
+ SSHANDLEINFO hi;
+
+ for(int i = 0; i < m_nVertices; i++)
+ {
+ if(m_Vertices[i].m_bSelected)
+ MoveVertices[nMoveVertices++] = m_Vertices[i].id;
+ }
+
+ for(int i = 0; i < m_nEdges; i++)
+ {
+ CSSEdge* pEdge = &m_Edges[i];
+
+ if(!pEdge->m_bSelected) // make sure it's selected
+ continue;
+
+ // add edge's vertices to the movement list
+ BOOL bAddStart = TRUE, bAddEnd = TRUE;
+ for(int i2 = 0; i2 < nMoveVertices; i2++)
+ {
+ if(pEdge->hvStart == MoveVertices[i2])
+ bAddStart = FALSE; // already got this one
+ if(pEdge->hvEnd == MoveVertices[i2])
+ bAddEnd = FALSE; // already got this one
+ }
+
+ if(bAddStart)
+ MoveVertices[nMoveVertices++] = pEdge->hvStart;
+ if(bAddEnd)
+ MoveVertices[nMoveVertices++] = pEdge->hvEnd;
+ }
+
+ // move vertices now
+ for(int i = 0; i < nMoveVertices; i++)
+ {
+ GetHandleInfo(&hi, MoveVertices[i]);
+ CSSVertex* pVertex = (CSSVertex*) hi.pData;
+ SetVertexPosition(hi.iIndex, pVertex->pos[0] + Delta[0], pVertex->pos[1] + Delta[1], pVertex->pos[2] + Delta[2]);
+ }
+
+ // calculate center of moved edges
+ int nEdges;
+ CSSEdge ** ppEdges = FindAffectedEdges(MoveVertices, nMoveVertices, nEdges);
+ for(int i = 0; i < nEdges; i++)
+ {
+ CalcEdgeCenter(ppEdges[i]);
+ }
+}
+
+
+// check faces for irregularities ->
+void CSSolid::CheckFaces()
+{
+ for(int i = 0; i < m_nFaces; i++)
+ {
+ CSSFace &face = m_Faces[i];
+
+ // get points for face
+ Vector *pts = CreatePointList(face);
+
+ // call checkface function
+ CCheckFaceInfo cfi;
+
+ while(CheckFace(pts, face.nEdges, NULL, 0, &cfi) == FALSE)
+ {
+ CString str;
+ str.Format("face %d - %s", i, cfi.szDescription);
+ AfxMessageBox(str);
+ }
+
+ delete[] pts;
+ }
+}
+
+
+void CSSolid::SetVertexPosition(int iVertex, float x, float y, float z)
+{
+ m_Vertices[iVertex].pos = Vector(x, y, z);
+}
+
+
+static int GetNext(int iIndex, int iDirection, int iMax)
+{
+ iIndex += iDirection;
+ if(iIndex == iMax)
+ iIndex = 0;
+ if(iIndex == -1)
+ iIndex = iMax-1;
+ return iIndex;
+}
+
+
+BOOL CSSolid::SplitFace(SSHANDLE h1, SSHANDLE h2)
+{
+ SSHANDLEINFO hi;
+ GetHandleInfo(&hi, h1);
+
+ if(m_nFaces == MAX_FACES-1)
+ return FALSE;
+
+ BOOL bRvl = FALSE;
+
+ if(hi.Type == shtEdge)
+ {
+ // edge-based face split
+ bRvl = SplitFaceByEdges((CSSEdge*) hi.pData,
+ (CSSEdge*) GetHandleData(h2));
+ }
+ else if(hi.Type == shtVertex)
+ {
+ // vertex-based face split
+ bRvl = SplitFaceByVertices((CSSVertex*) hi.pData,
+ (CSSVertex*) GetHandleData(h2));
+ }
+
+ return bRvl;
+}
+
+
+BOOL CSSolid::SplitFaceByVertices(CSSVertex *pVertex1, CSSVertex *pVertex2)
+{
+ if(GetEdgeIndex(pVertex1->id, pVertex2->id) != -1)
+ return FALSE; // already an edge there!
+
+ // find the face, first - get a list of affected edges and find
+ // two with a common face
+ int iNumEdges1, iNumEdges2;
+ SSHANDLE hFace = 0;
+ CSSEdge *pEdges1[64], *pEdges2[64], **pTmp;
+
+ pTmp = FindAffectedEdges(&pVertex1->id, 1, iNumEdges1);
+ memcpy(pEdges1, pTmp, iNumEdges1 * sizeof(CSSEdge*));
+ pTmp = FindAffectedEdges(&pVertex2->id, 1, iNumEdges2);
+ memcpy(pEdges2, pTmp, iNumEdges2 * sizeof(CSSEdge*));
+
+ for(int i = 0; i < iNumEdges1; i++)
+ {
+ SSHANDLE hFace0 = pEdges1[i]->Faces[0];
+ SSHANDLE hFace1 = pEdges1[i]->Faces[1];
+ for(int i2 = 0; i2 < iNumEdges2; i2++)
+ {
+ if(hFace0 == pEdges2[i2]->Faces[0] ||
+ hFace0 == pEdges2[i2]->Faces[1])
+ {
+ hFace = hFace0;
+ break;
+ }
+ else if(hFace1 == pEdges2[i2]->Faces[0] ||
+ hFace1 == pEdges2[i2]->Faces[1])
+ {
+ hFace = hFace1;
+ break;
+ }
+ }
+ }
+
+ // couldn't find a common face
+ if(hFace == 0)
+ return FALSE;
+
+ CSSFace *pFace = (CSSFace*) GetHandleData(hFace);
+
+ // create a new face
+ CSSFace *pNewFace = AddFace();
+ memcpy(&pNewFace->texture, &pFace->texture, sizeof(TEXTURE));
+
+ // create a new edge between two vertices
+ CSSEdge *pNewEdge = AddEdge();
+ pNewEdge->hvStart = pVertex1->id;
+ pNewEdge->hvEnd = pVertex2->id;
+ CalcEdgeCenter(pNewEdge);
+
+ // assign face ids to the new edge
+ AssignFace(pNewEdge, pFace->id);
+ AssignFace(pNewEdge, pNewFace->id);
+
+ // set up edges - start with newvertex1
+ SSHANDLE hNewEdges[64];
+ int nNewEdges;
+ BOOL bFirst = TRUE;
+ CSSFace *pStoreFace = pFace;
+
+ SSHANDLE *phVertexList = CreatePointHandleList(*pFace);
+ int nVertices = pFace->nEdges;
+
+ int v1index = 0, v2index = 0;
+
+ // find where the vertices are and
+ // kill face references in edges first
+ for(int i = 0; i < nVertices; i++)
+ {
+ int iNextVertex = GetNext(i, 1, nVertices);
+ int iEdgeIndex = GetEdgeIndex(phVertexList[i],
+ phVertexList[iNextVertex]);
+ CSSEdge *pEdge = &m_Edges[iEdgeIndex];
+ AssignFace(pEdge, pFace->id, TRUE);
+
+ if(phVertexList[i] == pVertex1->id)
+ v1index = i;
+ else if(phVertexList[i] == pVertex2->id)
+ v2index = i;
+ }
+
+DoNextFace:
+ nNewEdges = 0;
+ for(int i = v1index; ; i++)
+ {
+ if(i == nVertices)
+ i = 0;
+
+ if(i == v2index)
+ break;
+
+ int iNextVertex = GetNext(i, 1, nVertices);
+ int iEdgeIndex = GetEdgeIndex(phVertexList[i], phVertexList[iNextVertex]);
+ Assert(iEdgeIndex != -1);
+
+ hNewEdges[nNewEdges++] = m_Edges[iEdgeIndex].id;
+
+ AssignFace(&m_Edges[iEdgeIndex], pFace->id);
+ }
+ // now add the middle edge
+ hNewEdges[nNewEdges++] = pNewEdge->id;
+ // now set up in face
+ pStoreFace->nEdges = nNewEdges;
+ memcpy(pStoreFace->Edges, hNewEdges, sizeof(SSHANDLE) * nNewEdges);
+
+ if(bFirst)
+ {
+ int tmp = v1index;
+ v1index = v2index;
+ v2index = tmp;
+ pStoreFace = pNewFace;
+ bFirst = FALSE;
+ goto DoNextFace;
+ }
+
+ delete phVertexList;
+
+ return(TRUE);
+}
+
+BOOL CSSolid::SplitFaceByEdges(CSSEdge *pEdge1, CSSEdge *pEdge2)
+{
+ SSHANDLE hFace;
+
+ // find the handle of the face
+ if(pEdge1->Faces[0] == pEdge2->Faces[0] ||
+ pEdge1->Faces[0] == pEdge2->Faces[1])
+ {
+ hFace = pEdge1->Faces[0];
+ }
+ else if(pEdge1->Faces[1] == pEdge2->Faces[0] ||
+ pEdge1->Faces[1] == pEdge2->Faces[1])
+ {
+ hFace = pEdge1->Faces[1];
+ }
+ else return FALSE; // not the same face
+
+ // get pointer to face
+ CSSFace *pFace = (CSSFace*) GetHandleData(hFace);
+
+ // create new objects
+ CSSFace *pNewFace = AddFace();
+ CSSEdge *pNewEdgeMid = AddEdge();
+ int iNewVertex1, iNewVertex2;
+ CSSVertex *pNewVertex1 = AddVertex(&iNewVertex1);
+ CSSVertex *pNewVertex2 = AddVertex(&iNewVertex2);
+
+ // assign faces to new edge
+ AssignFace(pNewEdgeMid, pFace->id);
+ AssignFace(pNewEdgeMid, pNewFace->id);
+
+ // copy texture info from one face to the other
+ memcpy(&pNewFace->texture, &pFace->texture, sizeof(TEXTURE));
+
+ // set vertex positions
+ m_Vertices[iNewVertex1].pos = pEdge1->ptCenter;
+ m_Vertices[iNewVertex2].pos = pEdge2->ptCenter;
+
+ // set up middle edge
+ pNewEdgeMid->hvStart = pNewVertex1->id;
+ pNewEdgeMid->hvEnd = pNewVertex2->id;
+ CalcEdgeCenter(pNewEdgeMid);
+
+ // set up new side edges
+ CSSEdge *pEdgeTmp = AddEdge();
+ pEdgeTmp->hvStart = pEdge1->hvStart;
+ pEdgeTmp->hvEnd = pNewVertex1->id;
+ CalcEdgeCenter(pEdgeTmp);
+
+ pEdgeTmp = AddEdge();
+ pEdgeTmp->hvStart = pEdge1->hvEnd;
+ pEdgeTmp->hvEnd = pNewVertex1->id;
+ CalcEdgeCenter(pEdgeTmp);
+
+ pEdgeTmp = AddEdge();
+ pEdgeTmp->hvStart = pEdge2->hvStart;
+ pEdgeTmp->hvEnd = pNewVertex2->id;
+ CalcEdgeCenter(pEdgeTmp);
+
+ pEdgeTmp = AddEdge();
+ pEdgeTmp->hvStart = pEdge2->hvEnd;
+ pEdgeTmp->hvEnd = pNewVertex2->id;
+ CalcEdgeCenter(pEdgeTmp);
+
+/*
+ FILE *fp = fopen("split", "w");
+ for(i = 0; i < nVertices; i++)
+ {
+ fprintf(fp, "%lu\n", phVertexList[i]);
+ }
+ fclose(fp);
+*/
+
+ // set up edges - start with newvertex1
+ SSHANDLE hNewEdges[64];
+ int nNewEdges;
+ BOOL bFirst = TRUE;
+ CSSFace *pStoreFace = pFace;
+
+ // ** do two new faces first **
+
+ int nv1index, nv2index;
+ SSHANDLE *phVertexList = CreateNewVertexList(pFace, pEdge1, pEdge2,
+ nv1index, nv2index, pNewVertex1, pNewVertex2);
+ int nVertices = pFace->nEdges;
+ if(nv1index != -1)
+ ++nVertices;
+ if(nv2index != -1)
+ ++nVertices;
+
+ // kill face references in edges first
+ for(int i = 0; i < nVertices; i++)
+ {
+ int iNextVertex = GetNext(i, 1, nVertices);
+ int iEdgeIndex = GetEdgeIndex(phVertexList[i],
+ phVertexList[iNextVertex]);
+ CSSEdge *pEdge = &m_Edges[iEdgeIndex];
+ Assert(pEdge->id != pEdge1->id);
+ Assert(pEdge->id != pEdge2->id);
+ AssignFace(pEdge, pFace->id, TRUE);
+ }
+
+DoNextFace:
+ nNewEdges = 0;
+ for(int i = nv1index; ; i++)
+ {
+ if(i == nVertices)
+ i = 0;
+
+ if(i == nv2index)
+ break;
+
+ int iNextVertex = GetNext(i, 1, nVertices);
+ int iEdgeIndex = GetEdgeIndex(phVertexList[i], phVertexList[iNextVertex]);
+ Assert(iEdgeIndex != -1);
+
+ hNewEdges[nNewEdges++] = m_Edges[iEdgeIndex].id;
+
+ AssignFace(&m_Edges[iEdgeIndex], pStoreFace->id);
+ }
+ // now add the middle edge
+ hNewEdges[nNewEdges++] = pNewEdgeMid->id;
+ // now set up in face
+ pStoreFace->nEdges = nNewEdges;
+ memcpy(pStoreFace->Edges, hNewEdges, sizeof(SSHANDLE) * nNewEdges);
+
+ if(bFirst)
+ {
+ int tmp = nv1index;
+ nv1index = nv2index;
+ nv2index = tmp;
+ pStoreFace = pNewFace;
+ bFirst = FALSE;
+ goto DoNextFace;
+ }
+
+ delete phVertexList;
+
+ // ** now regular faces **
+ for(int iFace = 0; iFace < m_nFaces; iFace++)
+ {
+ CSSFace *pUpdFace = &m_Faces[iFace];
+
+ if(pUpdFace == pNewFace || pUpdFace == pFace)
+ continue;
+
+ phVertexList = CreateNewVertexList(pUpdFace, pEdge1, pEdge2,
+ nv1index, nv2index, pNewVertex1, pNewVertex2);
+
+ if(phVertexList == NULL) // don't need to update this face
+ continue;
+
+ nNewEdges = 0;
+ nVertices = pUpdFace->nEdges;
+ if(nv1index != -1)
+ ++nVertices;
+ if(nv2index != -1)
+ ++nVertices;
+ for(int i = 0; i < nVertices; i++)
+ {
+ int iNextVertex = GetNext(i, 1, nVertices);
+ int iEdgeIndex = GetEdgeIndex(phVertexList[i], phVertexList[iNextVertex]);
+ Assert(iEdgeIndex != -1);
+
+ AssignFace(&m_Edges[iEdgeIndex], pUpdFace->id);
+ hNewEdges[nNewEdges++] = m_Edges[iEdgeIndex].id;
+ }
+
+ // now set up in face
+ pUpdFace->nEdges = nNewEdges;
+ memcpy(pUpdFace->Edges, hNewEdges, sizeof(SSHANDLE) * nNewEdges);
+
+ delete phVertexList;
+ }
+
+ SSHANDLE id1 = pEdge1->id;
+ SSHANDLE id2 = pEdge2->id;
+
+ // delete old edges
+ for(int i = 0; i < m_nEdges; i++)
+ {
+ if(m_Edges[i].id == id1 || m_Edges[i].id == id2)
+ {
+ DeleteEdge(i);
+ --i;
+ }
+ }
+
+ return TRUE;
+}
+
+
+void CSSolid::DeleteEdge(int iEdge)
+{
+ SSHANDLE edgeid = m_Edges[iEdge].id;
+
+ // kill this edge
+ for(int i2 = iEdge; i2 < m_nEdges-1; i2++)
+ {
+ memcpy(&m_Edges[i2], &m_Edges[i2+1], sizeof(CSSEdge));
+ }
+ --m_nEdges;
+
+ memset(&m_Edges[m_nEdges], 0, sizeof(CSSEdge));
+
+ // kill all references to this edge in faces
+ for(int f = 0; f < m_nFaces; f++)
+ {
+ CSSFace& face = m_Faces[f];
+ for(int e = 0; e < face.nEdges; e++)
+ {
+ if(face.Edges[e] != edgeid)
+ continue;
+
+ memcpy(&face.Edges[e], &face.Edges[e+1], (face.nEdges-e) *
+ sizeof(face.Edges[0]));
+ --face.nEdges;
+ break; // no more in this face
+ }
+ }
+}
+
+
+void CSSolid::DeleteVertex(int iVertex)
+{
+ for(int i2 = iVertex; i2 < m_nVertices-1; i2++)
+ {
+ memcpy(&m_Vertices[i2], &m_Vertices[i2+1], sizeof(CSSVertex));
+ }
+ --m_nVertices;
+
+ memset(&m_Vertices[m_nVertices], 0, sizeof(CSSVertex));
+}
+
+
+void CSSolid::DeleteFace(int iFace)
+{
+ // Destroy the displacement if there is one.
+ CSSFace *pFace = &m_Faces[iFace];
+ if ( pFace )
+ {
+ if ( pFace->m_hDisp != EDITDISPHANDLE_INVALID )
+ {
+ EditDispMgr()->Destroy( pFace->m_hDisp );
+ pFace->m_hDisp = EDITDISPHANDLE_INVALID;
+ }
+ }
+
+ for(int i2 = iFace; i2 < m_nFaces-1; i2++)
+ {
+ memcpy(&m_Faces[i2], &m_Faces[i2+1], sizeof(CSSFace));
+ }
+ --m_nFaces;
+
+ m_Faces[m_nFaces].Init();
+}
+
+
+SSHANDLE* CSSolid::CreateNewVertexList(CSSFace *pFace, CSSEdge *pEdge1,
+ CSSEdge *pEdge2, int& nv1index, int& nv2index,
+ CSSVertex *pNewVertex1, CSSVertex *pNewVertex2)
+{
+ // get original vertex list
+ CUtlVector<SSHANDLE> hVertexList;
+ hVertexList.SetCount(pFace->nEdges+4);
+ CreatePointHandleList(*pFace, hVertexList.Base());
+
+ // add vertex1 and vertex2.
+ nv1index = -1;
+ nv2index = -1;
+
+ int nVertices = pFace->nEdges;
+ int iPass = 0;
+DoAgain:
+ for(int i = 0; i < nVertices; i++)
+ {
+ int iPrevIndex = GetNext(i, -1, nVertices);
+ int iNextIndex = GetNext(i, 1, nVertices);
+
+ if(nv1index == -1 && (hVertexList[i] == pEdge1->hvEnd ||
+ hVertexList[i] == pEdge1->hvStart))
+ {
+ // find pEdge1->hvStart
+ if(hVertexList[iPrevIndex] == pEdge1->hvStart ||
+ hVertexList[iPrevIndex] == pEdge1->hvEnd)
+ {
+ // add at i.
+ nv1index = i;
+ }
+ if(hVertexList[iNextIndex] == pEdge1->hvStart ||
+ hVertexList[iNextIndex] == pEdge1->hvEnd)
+ {
+ // add at iNextIndex
+ nv1index = iNextIndex;
+ }
+
+ if(nv1index != -1)
+ {
+ hVertexList.InsertBefore(nv1index, pNewVertex1->id);
+ ++nVertices;
+ break;
+ }
+ }
+
+ if(nv2index == -1 && (hVertexList[i] == pEdge2->hvEnd ||
+ hVertexList[i] == pEdge2->hvStart))
+ {
+ // find pEdge1->hvStart
+ if(hVertexList[iPrevIndex] == pEdge2->hvStart ||
+ hVertexList[iPrevIndex] == pEdge2->hvEnd)
+ {
+ // add at i.
+ nv2index = i;
+ }
+ if(hVertexList[iNextIndex] == pEdge2->hvStart ||
+ hVertexList[iNextIndex] == pEdge2->hvEnd)
+ {
+ // add at iNextIndex
+ nv2index = iNextIndex;
+ }
+
+ if(nv2index != -1)
+ {
+ hVertexList.InsertBefore(nv2index, pNewVertex2->id);
+ ++nVertices;
+ break;
+ }
+ }
+ }
+
+ SSHANDLE hTmp[64];
+ memcpy(hTmp, hVertexList.Base(), sizeof(SSHANDLE) * nVertices);
+
+ if(nv1index == -1 && nv2index == -1)
+ return NULL; // not used here.
+
+ if(nv1index == -1 || nv2index == -1)
+ {
+ if(++iPass != 2)
+ goto DoAgain;
+ }
+
+ SSHANDLE *rvl = new SSHANDLE[nVertices];
+ memcpy(rvl, hVertexList.Base(), sizeof(SSHANDLE) * nVertices);
+
+ return rvl;
+}
+
+// merge same vertices ->
+
+BOOL CSSolid::CanMergeVertices()
+{
+ for(int v1 = 0; v1 < m_nVertices; v1++)
+ {
+ for(int v2 = 0; v2 < m_nVertices; v2++)
+ {
+ if(v1 == v2)
+ continue; // no!
+ if(VectorCompare(m_Vertices[v1].pos, m_Vertices[v2].pos))
+ return TRUE; // got a match
+ }
+ }
+
+ return FALSE;
+}
+
+SSHANDLE * CSSolid::MergeSameVertices(int& nDeleted)
+{
+ int nMerged = 0;
+ nDeleted = 0;
+ static SSHANDLE hDeletedList[128];
+
+DoVertices:
+ for(int v1 = 0; v1 < m_nVertices; v1++)
+ {
+ for(int v2 = 0; v2 < m_nVertices; v2++)
+ {
+ if(v1 == v2)
+ continue; // no!
+ if(!VectorCompare(m_Vertices[v1].pos, m_Vertices[v2].pos))
+ { // no match
+ continue;
+ }
+
+ ++nMerged;
+
+ // same vertices - kill v1, set edge refs to use v2.
+ SSHANDLE hV1 = m_Vertices[v1].id;
+ SSHANDLE hV2 = m_Vertices[v2].id;
+
+ hDeletedList[nDeleted++] = hV1;
+
+ DeleteVertex(v1);
+
+ int nAffected;
+ CSSEdge **ppEdges = FindAffectedEdges(&hV1, 1, nAffected);
+
+ // run through edges and change references
+ for(int e = 0; e < nAffected; e++)
+ {
+ if(ppEdges[e]->hvStart == hV1)
+ ppEdges[e]->hvStart = hV2;
+ if(ppEdges[e]->hvEnd == hV1)
+ ppEdges[e]->hvEnd = hV2;
+ CalcEdgeCenter(ppEdges[e]);
+ }
+
+ goto DoVertices;
+ }
+ }
+
+ if(!nMerged)
+ return NULL;
+
+ int e;
+
+ // kill edges that have same vertices
+ for(e = 0; e < m_nEdges; e++)
+ {
+ CSSEdge &edge = m_Edges[e];
+
+ if(edge.hvStart != edge.hvEnd)
+ continue; // edge is OK
+
+ hDeletedList[nDeleted++] = edge.id;
+
+ DeleteEdge(e);
+ --e;
+ }
+
+ // kill similar edges (replace in faces too)
+DoEdges:
+ for(e = 0; e < m_nEdges; e++)
+ {
+ CSSEdge &edge = m_Edges[e];
+
+ for(int e2 = 0; e2 < m_nEdges; e2++)
+ {
+ if(e == e2)
+ continue;
+
+ CSSEdge &edge2 = m_Edges[e2];
+
+ if(!((edge2.hvStart == edge.hvStart && edge2.hvEnd == edge.hvEnd) ||
+ (edge2.hvEnd == edge.hvStart && edge2.hvStart == edge.hvEnd)))
+ continue;
+
+ // we're going to delete edge2.
+ SSHANDLE id2 = edge2.id;
+ SSHANDLE id1 = edge.id;
+
+ for(int f = 0; f < m_nFaces; f++)
+ {
+ CSSFace& face = m_Faces[f];
+ for(int ef = 0; ef < face.nEdges; ef++)
+ {
+ if(face.Edges[ef] == id2)
+ {
+ face.Edges[ef] = id1;
+ break;
+ }
+ }
+ }
+
+ hDeletedList[nDeleted++] = id2;
+ DeleteEdge(e2);
+
+ goto DoEdges;
+ }
+ }
+
+ // delete concurrent edge references in face
+ for(int f = 0; f < m_nFaces; f++)
+ {
+ CSSFace& face = m_Faces[f];
+
+DoConcurrentEdges:
+ for(int ef1 = 0; ef1 < face.nEdges; ef1++)
+ {
+ for(int ef2 = 0; ef2 < face.nEdges; ef2++)
+ {
+ if(ef2 == ef1)
+ continue;
+
+ if(face.Edges[ef1] != face.Edges[ef2])
+ continue;
+
+ // delete this ref
+ memcpy(&face.Edges[ef2], &face.Edges[ef2+1], (face.nEdges-ef2) *
+ sizeof(face.Edges[0]));
+ --face.nEdges;
+
+ goto DoConcurrentEdges;
+ }
+ }
+
+ if(face.nEdges < 3)
+ {
+ // kill this face
+ hDeletedList[nDeleted++] = face.id;
+ DeleteFace(f);
+ --f;
+ }
+ }
+
+ return hDeletedList;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor.
+//-----------------------------------------------------------------------------
+CSSFace::CSSFace(void)
+{
+ Init();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialize the SSFace.
+//-----------------------------------------------------------------------------
+void CSSFace::Init(void)
+{
+ nEdges = 0;
+ bModified = FALSE;
+
+ m_nFaceID = 0;
+ m_hDisp = EDITDISPHANDLE_INVALID;
+
+ memset(&texture, 0, sizeof(TEXTURE));
+
+ texture.scale[0] = g_pGameConfig->GetDefaultTextureScale();
+ texture.scale[1] = g_pGameConfig->GetDefaultTextureScale();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor.
+//-----------------------------------------------------------------------------
+CSSFace::~CSSFace(void)
+{
+ if ( m_hDisp != EDITDISPHANDLE_INVALID )
+ {
+ EditDispMgr()->Destroy( m_hDisp );
+ m_hDisp = EDITDISPHANDLE_INVALID;
+ }
+
+ memset(this, 0, sizeof(this));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor.
+//-----------------------------------------------------------------------------
+CSSEdge::CSSEdge(void)
+{
+ Faces[0] = Faces[1] = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor.
+//-----------------------------------------------------------------------------
+CSSEdge::~CSSEdge()
+{
+ memset(this, 0, sizeof(this));
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the world coordinates of the center point of this edge.
+// Input : Point - Receives the world coordinates of the center point.
+//-----------------------------------------------------------------------------
+void CSSEdge::GetCenterPoint(Vector& Point)
+{
+ Point = ptCenter;
+}
+
+
+CSSVertex::CSSVertex(void)
+{
+}
+
+
+CSSVertex::~CSSVertex(void)
+{
+ pos[0] = pos[1] = pos[2] = 0;
+ id = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the world coordinates of this vertex.
+// Input : Position - Receives the world coordinates.
+//-----------------------------------------------------------------------------
+void CSSVertex::GetPosition(Vector& Position)
+{
+ Position = pos;
+}
+
+
+//
+// save to .DXF
+//
+void CSSolid::SerializeDXF(FILE *stream, int nObject)
+{
+ char szName[128];
+ sprintf(szName, "OBJECT%03d", nObject);
+
+ // count number of triangulated faces
+ int nTriFaces = 0;
+ for(int i = 0; i < m_nFaces; i++)
+ {
+ CSSFace &face = m_Faces[i];
+ nTriFaces += face.nEdges-2;
+ }
+
+ fprintf(stream,"0\nPOLYLINE\n8\n%s\n66\n1\n70\n64\n71\n%u\n72\n%u\n", szName, m_nVertices, nTriFaces);
+ fprintf(stream,"62\n50\n");
+
+ for (int i = 0; i < m_nVertices; i++)
+ {
+ Vector &pos = m_Vertices[i].pos;
+ fprintf(stream, "0\nVERTEX\n8\n%s\n10\n%.6f\n20\n%.6f\n30\n%.6f\n70\n192\n", szName, pos[0], pos[1], pos[2]);
+ }
+
+ // triangulate each face and write
+ for(int i = 0; i < m_nFaces; i++)
+ {
+ CSSFace &face = m_Faces[i];
+ PINT pVerts = CreatePointIndexList(face);
+
+ for(int v = 0; v < face.nEdges; v++)
+ pVerts[v]++;
+
+ for(int v = 0; v < face.nEdges-2; v++)
+ {
+ fprintf(stream, "0\nVERTEX\n8\n%s\n10\n0\n20\n0\n30\n"
+ "0\n70\n128\n71\n%d\n72\n%d\n73\n%d\n", szName,
+ v == 0 ? pVerts[0] : -pVerts[0],
+ pVerts[v+1],
+ v == (face.nEdges-3) ? pVerts[v+2] : -pVerts[v+2]
+ );
+ }
+ }
+
+ fprintf(stream, "0\nSEQEND\n8\n%s\n", szName);
+}