Counter Strike : Global Offensive Source Code
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.

1711 lines
38 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ====
  2. //
  3. // Purpose: Structured Solid (CSSolid) implementation.
  4. //
  5. // Method of identifying different parts of solid (vertices/edges/faces) is
  6. // a unique-id system. The AddFace/AddEdge/AddVertex functions assign each
  7. // new "part" an id using GetNewID(). External objects referencing the CSSolid
  8. // do not have to worry about keeping track of indices into the private
  9. // arrays, since an ID is valid only if the part still exists. To get
  10. // information about an ID, use the GetHandleInfo() function -> it returns
  11. // FALSE if the given ID is no longer valid.
  12. //
  13. //=============================================================================
  14. #include "stdafx.h"
  15. #include "BrushOps.h"
  16. #include "GameConfig.h"
  17. #include "MapSolid.h"
  18. #include "MapWorld.h"
  19. #include "SSolid.h"
  20. #include "StockSolids.h"
  21. #include "Options.h"
  22. #include "WorldSize.h"
  23. #include "mapdisp.h"
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include <tier0/memdbgon.h>
  26. BOOL CheckFace(Vector *Points, int nPoints, Vector* pNormal, float dist, CCheckFaceInfo *pInfo)
  27. {
  28. int i, j;
  29. float d, edgedist;
  30. Vector dir, edgenormal;
  31. if(!pInfo)
  32. {
  33. static CCheckFaceInfo dummyinfo;
  34. pInfo = &dummyinfo;
  35. pInfo->iPoint = -1; // make sure it's reset to default
  36. }
  37. if(pInfo->iPoint == -2)
  38. return TRUE; // stop!!!!!
  39. // do we need to create a normal?
  40. if(!pNormal)
  41. {
  42. static Vector _normal;
  43. pNormal = &_normal;
  44. // calc a plane from the points
  45. Vector t1, t2, t3;
  46. for(int i = 0; i < 3; i++)
  47. {
  48. t1[i] = Points[0][i] - Points[1][i];
  49. t2[i] = Points[2][i] - Points[1][i];
  50. t3[i] = Points[1][i];
  51. }
  52. CrossProduct(t1, t2, *pNormal);
  53. VectorNormalize(*pNormal);
  54. dist = DotProduct(t3, *pNormal);
  55. }
  56. if(!nPoints)
  57. {
  58. strcpy(pInfo->szDescription, "no points");
  59. pInfo->iPoint = -2;
  60. return FALSE;
  61. }
  62. if(nPoints < 3)
  63. {
  64. strcpy(pInfo->szDescription, "fewer than three points");
  65. pInfo->iPoint = -2;
  66. return FALSE;
  67. }
  68. for(i = pInfo->iPoint + 1; i < nPoints; i++ )
  69. {
  70. pInfo->iPoint = i;
  71. Vector& p1 = Points[i];
  72. for (j=0 ; j<3 ; j++)
  73. {
  74. if (p1[j] > MAX_COORD_INTEGER || p1[j] < MIN_COORD_INTEGER)
  75. {
  76. strcpy(pInfo->szDescription, "out of range");
  77. return FALSE;
  78. }
  79. }
  80. // check the point is on the face plane
  81. d = DotProduct (p1, *pNormal) - dist;
  82. if (d < -ON_PLANE_EPSILON || d > ON_PLANE_EPSILON)
  83. {
  84. strcpy(pInfo->szDescription, "point off plane");
  85. return FALSE;
  86. }
  87. // check the edge isn't degenerate
  88. Vector& p2 = Points[i+1 == nPoints ? 0 : i+1]; // (next point)
  89. VectorSubtract (p2, p1, dir);
  90. if (VectorLength (dir) < MIN_EDGE_LENGTH_EPSILON)
  91. {
  92. strcpy(pInfo->szDescription, "edge is too small");
  93. return FALSE;
  94. }
  95. CrossProduct(*pNormal, dir, edgenormal);
  96. VectorNormalize (edgenormal);
  97. edgedist = DotProduct(p1, edgenormal);
  98. edgedist += ON_PLANE_EPSILON;
  99. // all other points must be on front side
  100. for (j=0 ; j< nPoints; j++)
  101. {
  102. if (j == i)
  103. continue;
  104. d = DotProduct (Points[j], edgenormal);
  105. if (d > edgedist)
  106. {
  107. strcpy(pInfo->szDescription, "face is not convex");
  108. return FALSE;
  109. }
  110. }
  111. }
  112. pInfo->iPoint = -2;
  113. return TRUE;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose: Constructor.
  117. //-----------------------------------------------------------------------------
  118. CSSolid::CSSolid()
  119. {
  120. m_nVertices = 0;
  121. m_nEdges = 0;
  122. m_nFaces = 0;
  123. m_curid = 1;
  124. m_pMapSolid = NULL;
  125. m_bShowVertices = TRUE;
  126. m_bShowEdges = TRUE;
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: Destructor.
  130. //-----------------------------------------------------------------------------
  131. CSSolid::~CSSolid()
  132. {
  133. memset(this, 0, sizeof(this));
  134. }
  135. SSHANDLE CSSolid::GetNewID()
  136. {
  137. return m_curid++;
  138. }
  139. PVOID CSSolid::GetHandleData(SSHANDLE id)
  140. {
  141. SSHANDLEINFO hi;
  142. if(!GetHandleInfo(&hi, id))
  143. return NULL;
  144. return hi.pData;
  145. }
  146. BOOL CSSolid::GetHandleInfo(SSHANDLEINFO *pInfo, SSHANDLE id)
  147. {
  148. // try vertices ..
  149. for(int i = 0; i < m_nVertices; i++)
  150. {
  151. if(m_Vertices[i].id != id)
  152. continue; // not this one
  153. pInfo->Type = shtVertex;
  154. pInfo->iIndex = i;
  155. pInfo->pData = PVOID(& m_Vertices[i]);
  156. pInfo->p2DHandle = & m_Vertices[i];
  157. pInfo->pos = m_Vertices[i].pos;
  158. return TRUE;
  159. }
  160. // try edges ..
  161. for(int i = 0; i < m_nEdges; i++)
  162. {
  163. if(m_Edges[i].id != id)
  164. continue; // not this one
  165. pInfo->Type = shtEdge;
  166. pInfo->iIndex = i;
  167. pInfo->pData = PVOID(& m_Edges[i]);
  168. pInfo->p2DHandle = & m_Edges[i];
  169. pInfo->pos = m_Edges[i].ptCenter;
  170. return TRUE;
  171. }
  172. // try faces ..
  173. for(int i = 0; i < m_nFaces; i++)
  174. {
  175. if(m_Faces[i].id != id)
  176. continue; // not this one
  177. pInfo->Type = shtFace;
  178. pInfo->iIndex = i;
  179. pInfo->pData = PVOID(& m_Faces[i]);
  180. pInfo->p2DHandle = & m_Faces[i];
  181. pInfo->pos = m_Faces[i].ptCenter;
  182. return TRUE;
  183. }
  184. pInfo->Type = shtNothing;
  185. return FALSE;
  186. }
  187. // Find data functions ->
  188. int CSSolid::GetEdgeIndex(SSHANDLE v1, SSHANDLE v2)
  189. {
  190. for(int i = 0; i < m_nEdges; i++)
  191. {
  192. CSSEdge & theEdge = m_Edges[i];
  193. if((theEdge.hvStart == v1 && theEdge.hvEnd == v2) ||
  194. (theEdge.hvStart == v2 && theEdge.hvEnd == v1))
  195. {
  196. return i;
  197. }
  198. }
  199. return -1;
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose:
  203. // Input : Point -
  204. // fLeniency -
  205. // Output :
  206. //-----------------------------------------------------------------------------
  207. int CSSolid::GetEdgeIndex(const Vector &Point, float fLeniency)
  208. {
  209. for (int i = 0; i < m_nEdges; i++)
  210. {
  211. Vector ptEdgeCenter = m_Edges[i].ptCenter;
  212. float fDiff = 0.0f;
  213. for (int j = 0; j < 3; j++)
  214. {
  215. fDiff += (Point[j] - ptEdgeCenter[j]) * (Point[j] - ptEdgeCenter[j]);
  216. }
  217. if (fDiff > fLeniency * fLeniency)
  218. {
  219. continue;
  220. }
  221. // if we are here, the 3 axes compare ok.
  222. return i;
  223. }
  224. // no edge matches
  225. return -1;
  226. }
  227. int CSSolid::GetVertexIndex(const Vector &Point, float fLeniency)
  228. {
  229. for(int i = 0; i < m_nVertices; i++)
  230. {
  231. Vector Vertex = m_Vertices[i].pos;
  232. float fDiff = 0.0f;
  233. for(int j = 0; j < 3; j++)
  234. {
  235. fDiff += (Point[j] - Vertex[j]) * (Point[j] - Vertex[j]);
  236. }
  237. if (fDiff > (fLeniency*fLeniency))
  238. continue;
  239. // if we are here, the 3 axes compare ok.
  240. return i;
  241. }
  242. // no vertex matches.
  243. return -1;
  244. }
  245. int CSSolid::GetFaceIndex(const Vector &Point, float fLeniency)
  246. {
  247. return -1;
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Purpose: Calculates the center of an edge.
  251. // Input : pEdge -
  252. //-----------------------------------------------------------------------------
  253. void CSSolid::CalcEdgeCenter(CSSEdge *pEdge)
  254. {
  255. SSHANDLEINFO hi;
  256. GetHandleInfo(&hi, pEdge->hvStart);
  257. Vector &pt1 = m_Vertices[hi.iIndex].pos;
  258. GetHandleInfo(&hi, pEdge->hvEnd);
  259. Vector &pt2 = m_Vertices[hi.iIndex].pos;
  260. for (int i = 0; i < 3; i++)
  261. {
  262. pEdge->ptCenter[i] = (pt1[i] + pt2[i]) / 2.0f;
  263. }
  264. }
  265. // get common vertex from two edges ->
  266. SSHANDLE CSSolid::GetConnectionVertex(CSSEdge *pEdge1, CSSEdge *pEdge2)
  267. {
  268. if((pEdge1->hvStart == pEdge2->hvStart) ||
  269. (pEdge1->hvStart == pEdge2->hvEnd))
  270. return pEdge1->hvStart;
  271. if((pEdge1->hvEnd == pEdge2->hvStart) ||
  272. (pEdge1->hvEnd == pEdge2->hvEnd))
  273. return pEdge1->hvEnd;
  274. return 0;
  275. }
  276. // Create list of points from face ->
  277. Vector * CSSolid::CreatePointList(CSSFace & face)
  278. {
  279. Vector * pts = new Vector[face.nEdges+1];
  280. for(int i = 0; i < face.nEdges; i++)
  281. {
  282. // calc next edge so we can see which is the next clockwise point
  283. int iNextEdge = i+1;
  284. if(iNextEdge == face.nEdges)
  285. iNextEdge = 0;
  286. CSSEdge * edgeCur = (CSSEdge*) GetHandleData(face.Edges[i]);
  287. CSSEdge * edgeNext = (CSSEdge*) GetHandleData(face.Edges[iNextEdge]);
  288. if(!edgeCur || !edgeNext)
  289. {
  290. CString str;
  291. str.Format("Conversion error!\n"
  292. "edgeCur = %08X, edgeNext = %08X", edgeCur, edgeNext);
  293. AfxMessageBox(str);
  294. return NULL;
  295. }
  296. SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext);
  297. if(!hVertex)
  298. {
  299. CString str;
  300. str.Format("Conversion error!\n"
  301. "hVertex = %08X", hVertex);
  302. AfxMessageBox(str);
  303. return NULL;
  304. }
  305. CSSVertex *pVertex = (CSSVertex*) GetHandleData(hVertex);
  306. pts[i] = pVertex->pos;
  307. }
  308. return pts;
  309. }
  310. // Create point list, but return indices instead of positions ->
  311. PINT CSSolid::CreatePointIndexList(CSSFace & face, PINT piPoints)
  312. {
  313. PINT pts;
  314. if(piPoints)
  315. pts = piPoints;
  316. else
  317. pts = new int[face.nEdges+1];
  318. SSHANDLEINFO hi;
  319. for(int i = 0; i < face.nEdges; i++)
  320. {
  321. // calc next edge so we can see which is the next clockwise point
  322. int iNextEdge = i+1;
  323. if(iNextEdge == face.nEdges)
  324. iNextEdge = 0;
  325. CSSEdge * edgeCur = (CSSEdge*) GetHandleData(face.Edges[i]);
  326. CSSEdge * edgeNext = (CSSEdge*) GetHandleData(face.Edges[iNextEdge]);
  327. SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext);
  328. Assert(hVertex);
  329. GetHandleInfo(&hi, hVertex);
  330. pts[i] = hi.iIndex;
  331. }
  332. return pts;
  333. }
  334. // Create point list, and use handles ->
  335. SSHANDLE* CSSolid::CreatePointHandleList(CSSFace & face, SSHANDLE* phPoints)
  336. {
  337. SSHANDLE* pts;
  338. if(phPoints)
  339. pts = phPoints;
  340. else
  341. pts = new SSHANDLE[face.nEdges+1];
  342. for(int i = 0; i < face.nEdges; i++)
  343. {
  344. // calc next edge so we can see which is the next clockwise point
  345. int iNextEdge = i+1;
  346. if(iNextEdge == face.nEdges)
  347. iNextEdge = 0;
  348. CSSEdge * edgeCur = (CSSEdge*) GetHandleData(face.Edges[i]);
  349. CSSEdge * edgeNext = (CSSEdge*) GetHandleData(face.Edges[iNextEdge]);
  350. SSHANDLE hVertex = GetConnectionVertex(edgeCur, edgeNext);
  351. Assert(hVertex);
  352. pts[i] = hVertex;
  353. }
  354. return pts;
  355. }
  356. void CSSolid::Attach(CMapSolid *pMapSolid)
  357. {
  358. m_pMapSolid = pMapSolid;
  359. }
  360. CMapSolid *CSSolid::Detach()
  361. {
  362. CMapSolid *pTmp = m_pMapSolid;
  363. m_pMapSolid = NULL;
  364. return pTmp;
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Purpose: Returns whether or not the SSolid has displacements.
  368. //-----------------------------------------------------------------------------
  369. bool CSSolid::HasDisps( void )
  370. {
  371. for ( int iFace = 0; iFace < m_nFaces; ++iFace )
  372. {
  373. CSSFace *pFace = &m_Faces[iFace];
  374. if ( pFace->m_hDisp != EDITDISPHANDLE_INVALID )
  375. return true;
  376. }
  377. return false;
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Purpose: Check to see if the SSolid with displacement surfaces has valid
  381. // base face surfaces.
  382. //-----------------------------------------------------------------------------
  383. bool CSSolid::IsValidWithDisps( void )
  384. {
  385. if ( !HasDisps() )
  386. return true;
  387. for ( int iFace = 0; iFace < m_nFaces; ++iFace )
  388. {
  389. // Get the face(s) that have displacements.
  390. CSSFace *pFace = &m_Faces[iFace];
  391. if ( pFace->m_hDisp == EDITDISPHANDLE_INVALID )
  392. continue;
  393. // Create a face point list.
  394. Vector *pFacePoints = CreatePointList( *pFace );
  395. // If the face has changed the number of points - via merges, etc.
  396. if ( pFace->nEdges != 4 )
  397. return false;
  398. // Check the face for validity.
  399. CCheckFaceInfo faceInfo;
  400. if ( !CheckFace( pFacePoints, pFace->nEdges, NULL, 0.0f, &faceInfo ) )
  401. return false;
  402. }
  403. return true;
  404. }
  405. //-----------------------------------------------------------------------------
  406. // Purpose: Destroy all the displacement data on the SSolid.
  407. //-----------------------------------------------------------------------------
  408. void CSSolid::DestroyDisps( void )
  409. {
  410. for ( int iFace = 0; iFace < m_nFaces; ++iFace )
  411. {
  412. CSSFace *pFace = &m_Faces[iFace];
  413. if ( pFace->m_hDisp != EDITDISPHANDLE_INVALID )
  414. {
  415. EditDispMgr()->Destroy( pFace->m_hDisp );
  416. pFace->m_hDisp = EDITDISPHANDLE_INVALID;
  417. }
  418. }
  419. }
  420. void CSSolid::Convert(BOOL bFromMap, bool bSkipDisplacementFaces )
  421. {
  422. if(bFromMap)
  423. FromMapSolid(NULL, bSkipDisplacementFaces);
  424. else
  425. ToMapSolid();
  426. }
  427. void CSSolid::ToMapSolid(CMapSolid *p)
  428. {
  429. // so we can pass NULL (default) or another solid (to copy):
  430. CMapSolid *pSolid;
  431. if (p)
  432. {
  433. pSolid = p;
  434. }
  435. else
  436. {
  437. pSolid = m_pMapSolid;
  438. }
  439. pSolid->SetFaceCount(m_nFaces);
  440. unsigned char r, g, b;
  441. pSolid->GetRenderColor( r,g,b );
  442. for (int i = 0; i < m_nFaces; i++)
  443. {
  444. CSSFace &pFace = m_Faces[i];
  445. CMapFace SolidFace;
  446. //
  447. // Copy original texture information and face ID back.
  448. //
  449. Q_memcpy(&SolidFace.texture, &pFace.texture, sizeof(TEXTURE));
  450. SolidFace.SetTexture(SolidFace.texture.texture);
  451. SolidFace.SetFaceID(pFace.m_nFaceID);
  452. //
  453. // Create face from new points.
  454. //
  455. Vector *pts = CreatePointList(pFace);
  456. SolidFace.CreateFace(pts, pFace.nEdges);
  457. //
  458. // Vertex manipulation; the face orientation may have changed. If one of the texture axes is now
  459. // perpendicular to the face, recalculate the texture axes using the default alignment (world or face).
  460. // Ideally we would transform the texture axes so that their orientation relative to the face is preserved.
  461. // By reinitializing the axes we risk having the axes rotate unpredictably.
  462. //
  463. if (!SolidFace.IsTextureAxisValid())
  464. {
  465. SolidFace.InitializeTextureAxes(Options.GetTextureAlignment(), INIT_TEXTURE_AXES | INIT_TEXTURE_FORCE);
  466. }
  467. // Attempt to update the displacement - if there is one.
  468. if ( pFace.m_hDisp != EDITDISPHANDLE_INVALID )
  469. {
  470. EditDispHandle_t hDisp = EditDispMgr()->Create();
  471. CMapDisp *pSolidDisp = EditDispMgr()->GetDisp( hDisp );
  472. CMapDisp *pDisp = EditDispMgr()->GetDisp( pFace.m_hDisp );
  473. pSolidDisp->CopyFrom( pDisp, false );
  474. int iStart = pSolidDisp->GetSurfPointStartIndex();
  475. pSolidDisp->SetSurfPointStartIndex( (iStart+3)%4 );
  476. pSolidDisp->InitDispSurfaceData( &SolidFace, false );
  477. pSolidDisp->Create();
  478. SolidFace.SetDisp( hDisp );
  479. }
  480. CMapFace *pNewFace = pSolid->GetFace( i );
  481. pNewFace->CopyFrom( &SolidFace, COPY_FACE_POINTS);
  482. pNewFace->SetRenderColor(r, g, b);
  483. pNewFace->SetParent(pSolid);
  484. delete[] pts;
  485. }
  486. pSolid->PostUpdate(Notify_Changed);
  487. }
  488. CSSFace* CSSolid::AddFace(int* piNewIndex)
  489. {
  490. m_Faces.SetCount(++m_nFaces);
  491. if(piNewIndex)
  492. piNewIndex[0] = m_nFaces-1;
  493. CSSFace *pFace = & m_Faces[m_nFaces-1];
  494. pFace->id = GetNewID();
  495. return pFace;
  496. }
  497. // Add Edge ->
  498. CSSEdge* CSSolid::AddEdge(int* piNewIndex)
  499. {
  500. m_Edges.SetCount(++m_nEdges);
  501. if(piNewIndex)
  502. piNewIndex[0] = m_nEdges-1;
  503. CSSEdge *pEdge = & m_Edges[m_nEdges-1];
  504. pEdge->id = GetNewID();
  505. return pEdge;
  506. }
  507. // Add Vertex ->
  508. CSSVertex* CSSolid::AddVertex(int* piNewIndex)
  509. {
  510. m_Vertices.SetCount(++m_nVertices);
  511. if(piNewIndex)
  512. piNewIndex[0] = m_nVertices-1;
  513. CSSVertex *pVertex = & m_Vertices[m_nVertices-1];
  514. pVertex->id = GetNewID();
  515. return pVertex;
  516. }
  517. // Assign a face to an edge ->
  518. void CSSolid::AssignFace(CSSEdge* pEdge, SSHANDLE hFace, BOOL bRemove)
  519. {
  520. if(!bRemove)
  521. {
  522. if(pEdge->Faces[0] == 0 || pEdge->Faces[0] == hFace)
  523. pEdge->Faces[0] = hFace;
  524. else if(pEdge->Faces[1] == 0)
  525. pEdge->Faces[1] = hFace;
  526. }
  527. else
  528. {
  529. if(pEdge->Faces[0] == hFace)
  530. pEdge->Faces[0] = 0;
  531. if(pEdge->Faces[1] == hFace)
  532. pEdge->Faces[1] = 0;
  533. }
  534. }
  535. // Convert From Map Solid ->
  536. void CSSolid::FromMapSolid(CMapSolid *p, bool bSkipDisplacementFaces)
  537. {
  538. // so we can pass NULL (default) or another solid (to copy):
  539. CMapSolid *pSolid;
  540. if(p)
  541. pSolid = p;
  542. else
  543. pSolid = m_pMapSolid;
  544. m_nFaces = 0;
  545. m_nEdges = 0;
  546. m_nVertices = 0;
  547. // Create vertices, edges, faces.
  548. int nSolidFaces = pSolid->GetFaceCount();
  549. for(int i = 0; i < nSolidFaces; i++)
  550. {
  551. CMapFace *pSolidFace = pSolid->GetFace(i);
  552. if (bSkipDisplacementFaces)
  553. {
  554. if (pSolidFace->HasDisp())
  555. continue;
  556. }
  557. // Add a face
  558. CSSFace *pFace = AddFace();
  559. memcpy(pFace->PlanePts, pSolidFace->plane.planepts, sizeof(Vector) * 3);
  560. pFace->texture = pSolidFace->texture;
  561. pFace->normal = pSolidFace->plane.normal;
  562. pFace->m_nFaceID = pSolidFace->GetFaceID();
  563. // Displacement.
  564. if ( pSolidFace->HasDisp() )
  565. {
  566. pFace->m_hDisp = EditDispMgr()->Create();
  567. CMapDisp *pDisp = EditDispMgr()->GetDisp( pFace->m_hDisp );
  568. CMapDisp *pSolidDisp = EditDispMgr()->GetDisp( pSolidFace->GetDisp() );
  569. pDisp->CopyFrom( pSolidDisp, false );
  570. }
  571. // Convert vertices and edges
  572. int nFacePoints = pSolidFace->nPoints;
  573. Vector *pFacePoints = pSolidFace->Points;
  574. SSHANDLE hLastVertex = 0; // valid IDs start at 1
  575. SSHANDLE hThisVertex, hFirstVertex = 0;
  576. for(int pt = 0; pt <= nFacePoints; pt++)
  577. {
  578. int iVertex;
  579. if(pt < nFacePoints)
  580. {
  581. // YWB: Change leniency from 1.0 down to 0.1
  582. iVertex = GetVertexIndex(pFacePoints[pt], 0.1f);
  583. if (iVertex == -1)
  584. {
  585. // not found - add the vertex
  586. CSSVertex *pVertex = AddVertex(&iVertex);
  587. pVertex->pos = pFacePoints[pt];
  588. }
  589. // assign this vertex handle
  590. hThisVertex = m_Vertices[iVertex].id;
  591. if (pt == 0)
  592. hFirstVertex = hThisVertex;
  593. }
  594. else
  595. {
  596. // connect last to first
  597. hThisVertex = hFirstVertex;
  598. }
  599. if (hLastVertex)
  600. {
  601. // create the edge from the last vertex to current vertex.
  602. // first check to see if this edge already exists..
  603. int iEdge = GetEdgeIndex(hLastVertex, hThisVertex);
  604. CSSEdge *pEdge;
  605. if (iEdge == -1)
  606. {
  607. // not found - add new edge
  608. pEdge = AddEdge(&iEdge);
  609. pEdge->hvStart = hLastVertex;
  610. pEdge->hvEnd = hThisVertex;
  611. // make sure edge center is valid:
  612. CalcEdgeCenter(pEdge);
  613. }
  614. else
  615. {
  616. pEdge = &m_Edges[iEdge];
  617. }
  618. // add the edge to the face
  619. pFace->Edges[pFace->nEdges++] = pEdge->id;
  620. // set edge's face array
  621. if(!pEdge->Faces[0])
  622. pEdge->Faces[0] = pFace->id;
  623. else if(!pEdge->Faces[1])
  624. pEdge->Faces[1] = pFace->id;
  625. else
  626. {
  627. // YWB try filling in front side
  628. // rather than Assert(0) crash
  629. pEdge->Faces[0] = pFace->id;
  630. AfxMessageBox("Edge with both face id's already filled, skipping...");
  631. }
  632. }
  633. hLastVertex = hThisVertex;
  634. }
  635. }
  636. }
  637. // Find edges that reference a vertex ->
  638. CSSEdge ** CSSolid::FindAffectedEdges(SSHANDLE *pHandles, int iNumHandles, int& iNumEdges)
  639. {
  640. static CSSEdge *ppEdges[128];
  641. iNumEdges = 0;
  642. for(int h = 0; h < iNumHandles; h++)
  643. {
  644. for(int i = 0; i < m_nEdges; i++)
  645. {
  646. CSSEdge *pEdge = &m_Edges[i];
  647. if(pEdge->hvStart == pHandles[h] ||
  648. pEdge->hvEnd == pHandles[h])
  649. {
  650. // ensure it's not already stored
  651. int s;
  652. for(s = 0; s < iNumEdges; s++)
  653. {
  654. if(ppEdges[s] == pEdge)
  655. break;
  656. }
  657. if(s == iNumEdges)
  658. ppEdges[iNumEdges++] = pEdge;
  659. }
  660. }
  661. }
  662. return ppEdges;
  663. }
  664. // tell drawing code to show/hide kinds of handles
  665. void CSSolid::ShowHandles(BOOL bShowVertices, BOOL bShowEdges)
  666. {
  667. m_bShowEdges = bShowEdges;
  668. m_bShowVertices = bShowVertices;
  669. }
  670. // Move handle(s) to a new location ->
  671. void CSSolid::MoveSelectedHandles(const Vector &Delta)
  672. {
  673. SSHANDLE MoveVertices[128];
  674. int nMoveVertices = 0;
  675. SSHANDLEINFO hi;
  676. for(int i = 0; i < m_nVertices; i++)
  677. {
  678. if(m_Vertices[i].m_bSelected)
  679. MoveVertices[nMoveVertices++] = m_Vertices[i].id;
  680. }
  681. for(int i = 0; i < m_nEdges; i++)
  682. {
  683. CSSEdge* pEdge = &m_Edges[i];
  684. if(!pEdge->m_bSelected) // make sure it's selected
  685. continue;
  686. // add edge's vertices to the movement list
  687. BOOL bAddStart = TRUE, bAddEnd = TRUE;
  688. for(int i2 = 0; i2 < nMoveVertices; i2++)
  689. {
  690. if(pEdge->hvStart == MoveVertices[i2])
  691. bAddStart = FALSE; // already got this one
  692. if(pEdge->hvEnd == MoveVertices[i2])
  693. bAddEnd = FALSE; // already got this one
  694. }
  695. if(bAddStart)
  696. MoveVertices[nMoveVertices++] = pEdge->hvStart;
  697. if(bAddEnd)
  698. MoveVertices[nMoveVertices++] = pEdge->hvEnd;
  699. }
  700. // move vertices now
  701. for(int i = 0; i < nMoveVertices; i++)
  702. {
  703. GetHandleInfo(&hi, MoveVertices[i]);
  704. CSSVertex* pVertex = (CSSVertex*) hi.pData;
  705. SetVertexPosition(hi.iIndex, pVertex->pos[0] + Delta[0], pVertex->pos[1] + Delta[1], pVertex->pos[2] + Delta[2]);
  706. }
  707. // calculate center of moved edges
  708. int nEdges;
  709. CSSEdge ** ppEdges = FindAffectedEdges(MoveVertices, nMoveVertices, nEdges);
  710. for(int i = 0; i < nEdges; i++)
  711. {
  712. CalcEdgeCenter(ppEdges[i]);
  713. }
  714. }
  715. // check faces for irregularities ->
  716. void CSSolid::CheckFaces()
  717. {
  718. for(int i = 0; i < m_nFaces; i++)
  719. {
  720. CSSFace &face = m_Faces[i];
  721. // get points for face
  722. Vector *pts = CreatePointList(face);
  723. // call checkface function
  724. CCheckFaceInfo cfi;
  725. while(CheckFace(pts, face.nEdges, NULL, 0, &cfi) == FALSE)
  726. {
  727. CString str;
  728. str.Format("face %d - %s", i, cfi.szDescription);
  729. AfxMessageBox(str);
  730. }
  731. delete[] pts;
  732. }
  733. }
  734. void CSSolid::SetVertexPosition(int iVertex, float x, float y, float z)
  735. {
  736. m_Vertices[iVertex].pos = Vector(x, y, z);
  737. }
  738. static int GetNext(int iIndex, int iDirection, int iMax)
  739. {
  740. iIndex += iDirection;
  741. if(iIndex == iMax)
  742. iIndex = 0;
  743. if(iIndex == -1)
  744. iIndex = iMax-1;
  745. return iIndex;
  746. }
  747. BOOL CSSolid::SplitFace(SSHANDLE h1, SSHANDLE h2)
  748. {
  749. SSHANDLEINFO hi;
  750. GetHandleInfo(&hi, h1);
  751. if(m_nFaces == MAX_FACES-1)
  752. return FALSE;
  753. BOOL bRvl = FALSE;
  754. if(hi.Type == shtEdge)
  755. {
  756. // edge-based face split
  757. bRvl = SplitFaceByEdges((CSSEdge*) hi.pData,
  758. (CSSEdge*) GetHandleData(h2));
  759. }
  760. else if(hi.Type == shtVertex)
  761. {
  762. // vertex-based face split
  763. bRvl = SplitFaceByVertices((CSSVertex*) hi.pData,
  764. (CSSVertex*) GetHandleData(h2));
  765. }
  766. return bRvl;
  767. }
  768. BOOL CSSolid::SplitFaceByVertices(CSSVertex *pVertex1, CSSVertex *pVertex2)
  769. {
  770. if(GetEdgeIndex(pVertex1->id, pVertex2->id) != -1)
  771. return FALSE; // already an edge there!
  772. // find the face, first - get a list of affected edges and find
  773. // two with a common face
  774. int iNumEdges1, iNumEdges2;
  775. SSHANDLE hFace = 0;
  776. CSSEdge *pEdges1[64], *pEdges2[64], **pTmp;
  777. pTmp = FindAffectedEdges(&pVertex1->id, 1, iNumEdges1);
  778. memcpy(pEdges1, pTmp, iNumEdges1 * sizeof(CSSEdge*));
  779. pTmp = FindAffectedEdges(&pVertex2->id, 1, iNumEdges2);
  780. memcpy(pEdges2, pTmp, iNumEdges2 * sizeof(CSSEdge*));
  781. for(int i = 0; i < iNumEdges1; i++)
  782. {
  783. SSHANDLE hFace0 = pEdges1[i]->Faces[0];
  784. SSHANDLE hFace1 = pEdges1[i]->Faces[1];
  785. for(int i2 = 0; i2 < iNumEdges2; i2++)
  786. {
  787. if(hFace0 == pEdges2[i2]->Faces[0] ||
  788. hFace0 == pEdges2[i2]->Faces[1])
  789. {
  790. hFace = hFace0;
  791. break;
  792. }
  793. else if(hFace1 == pEdges2[i2]->Faces[0] ||
  794. hFace1 == pEdges2[i2]->Faces[1])
  795. {
  796. hFace = hFace1;
  797. break;
  798. }
  799. }
  800. }
  801. // couldn't find a common face
  802. if(hFace == 0)
  803. return FALSE;
  804. CSSFace *pFace = (CSSFace*) GetHandleData(hFace);
  805. // create a new face
  806. CSSFace *pNewFace = AddFace();
  807. memcpy(&pNewFace->texture, &pFace->texture, sizeof(TEXTURE));
  808. // create a new edge between two vertices
  809. CSSEdge *pNewEdge = AddEdge();
  810. pNewEdge->hvStart = pVertex1->id;
  811. pNewEdge->hvEnd = pVertex2->id;
  812. CalcEdgeCenter(pNewEdge);
  813. // assign face ids to the new edge
  814. AssignFace(pNewEdge, pFace->id);
  815. AssignFace(pNewEdge, pNewFace->id);
  816. // set up edges - start with newvertex1
  817. SSHANDLE hNewEdges[64];
  818. int nNewEdges;
  819. BOOL bFirst = TRUE;
  820. CSSFace *pStoreFace = pFace;
  821. SSHANDLE *phVertexList = CreatePointHandleList(*pFace);
  822. int nVertices = pFace->nEdges;
  823. int v1index = 0, v2index = 0;
  824. // find where the vertices are and
  825. // kill face references in edges first
  826. for(int i = 0; i < nVertices; i++)
  827. {
  828. int iNextVertex = GetNext(i, 1, nVertices);
  829. int iEdgeIndex = GetEdgeIndex(phVertexList[i],
  830. phVertexList[iNextVertex]);
  831. CSSEdge *pEdge = &m_Edges[iEdgeIndex];
  832. AssignFace(pEdge, pFace->id, TRUE);
  833. if(phVertexList[i] == pVertex1->id)
  834. v1index = i;
  835. else if(phVertexList[i] == pVertex2->id)
  836. v2index = i;
  837. }
  838. DoNextFace:
  839. nNewEdges = 0;
  840. for(int i = v1index; ; i++)
  841. {
  842. if(i == nVertices)
  843. i = 0;
  844. if(i == v2index)
  845. break;
  846. int iNextVertex = GetNext(i, 1, nVertices);
  847. int iEdgeIndex = GetEdgeIndex(phVertexList[i], phVertexList[iNextVertex]);
  848. Assert(iEdgeIndex != -1);
  849. hNewEdges[nNewEdges++] = m_Edges[iEdgeIndex].id;
  850. AssignFace(&m_Edges[iEdgeIndex], pFace->id);
  851. }
  852. // now add the middle edge
  853. hNewEdges[nNewEdges++] = pNewEdge->id;
  854. // now set up in face
  855. pStoreFace->nEdges = nNewEdges;
  856. memcpy(pStoreFace->Edges, hNewEdges, sizeof(SSHANDLE) * nNewEdges);
  857. if(bFirst)
  858. {
  859. int tmp = v1index;
  860. v1index = v2index;
  861. v2index = tmp;
  862. pStoreFace = pNewFace;
  863. bFirst = FALSE;
  864. goto DoNextFace;
  865. }
  866. delete phVertexList;
  867. return(TRUE);
  868. }
  869. BOOL CSSolid::SplitFaceByEdges(CSSEdge *pEdge1, CSSEdge *pEdge2)
  870. {
  871. SSHANDLE hFace;
  872. // find the handle of the face
  873. if(pEdge1->Faces[0] == pEdge2->Faces[0] ||
  874. pEdge1->Faces[0] == pEdge2->Faces[1])
  875. {
  876. hFace = pEdge1->Faces[0];
  877. }
  878. else if(pEdge1->Faces[1] == pEdge2->Faces[0] ||
  879. pEdge1->Faces[1] == pEdge2->Faces[1])
  880. {
  881. hFace = pEdge1->Faces[1];
  882. }
  883. else return FALSE; // not the same face
  884. // get pointer to face
  885. CSSFace *pFace = (CSSFace*) GetHandleData(hFace);
  886. // create new objects
  887. CSSFace *pNewFace = AddFace();
  888. CSSEdge *pNewEdgeMid = AddEdge();
  889. int iNewVertex1, iNewVertex2;
  890. CSSVertex *pNewVertex1 = AddVertex(&iNewVertex1);
  891. CSSVertex *pNewVertex2 = AddVertex(&iNewVertex2);
  892. // assign faces to new edge
  893. AssignFace(pNewEdgeMid, pFace->id);
  894. AssignFace(pNewEdgeMid, pNewFace->id);
  895. // copy texture info from one face to the other
  896. memcpy(&pNewFace->texture, &pFace->texture, sizeof(TEXTURE));
  897. // set vertex positions
  898. m_Vertices[iNewVertex1].pos = pEdge1->ptCenter;
  899. m_Vertices[iNewVertex2].pos = pEdge2->ptCenter;
  900. // set up middle edge
  901. pNewEdgeMid->hvStart = pNewVertex1->id;
  902. pNewEdgeMid->hvEnd = pNewVertex2->id;
  903. CalcEdgeCenter(pNewEdgeMid);
  904. // set up new side edges
  905. CSSEdge *pEdgeTmp = AddEdge();
  906. pEdgeTmp->hvStart = pEdge1->hvStart;
  907. pEdgeTmp->hvEnd = pNewVertex1->id;
  908. CalcEdgeCenter(pEdgeTmp);
  909. pEdgeTmp = AddEdge();
  910. pEdgeTmp->hvStart = pEdge1->hvEnd;
  911. pEdgeTmp->hvEnd = pNewVertex1->id;
  912. CalcEdgeCenter(pEdgeTmp);
  913. pEdgeTmp = AddEdge();
  914. pEdgeTmp->hvStart = pEdge2->hvStart;
  915. pEdgeTmp->hvEnd = pNewVertex2->id;
  916. CalcEdgeCenter(pEdgeTmp);
  917. pEdgeTmp = AddEdge();
  918. pEdgeTmp->hvStart = pEdge2->hvEnd;
  919. pEdgeTmp->hvEnd = pNewVertex2->id;
  920. CalcEdgeCenter(pEdgeTmp);
  921. /*
  922. FILE *fp = fopen("split", "w");
  923. for(i = 0; i < nVertices; i++)
  924. {
  925. fprintf(fp, "%lu\n", phVertexList[i]);
  926. }
  927. fclose(fp);
  928. */
  929. // set up edges - start with newvertex1
  930. SSHANDLE hNewEdges[64];
  931. int nNewEdges;
  932. BOOL bFirst = TRUE;
  933. CSSFace *pStoreFace = pFace;
  934. // ** do two new faces first **
  935. int nv1index, nv2index;
  936. SSHANDLE *phVertexList = CreateNewVertexList(pFace, pEdge1, pEdge2,
  937. nv1index, nv2index, pNewVertex1, pNewVertex2);
  938. int nVertices = pFace->nEdges;
  939. if(nv1index != -1)
  940. ++nVertices;
  941. if(nv2index != -1)
  942. ++nVertices;
  943. // kill face references in edges first
  944. for(int i = 0; i < nVertices; i++)
  945. {
  946. int iNextVertex = GetNext(i, 1, nVertices);
  947. int iEdgeIndex = GetEdgeIndex(phVertexList[i],
  948. phVertexList[iNextVertex]);
  949. CSSEdge *pEdge = &m_Edges[iEdgeIndex];
  950. Assert(pEdge->id != pEdge1->id);
  951. Assert(pEdge->id != pEdge2->id);
  952. AssignFace(pEdge, pFace->id, TRUE);
  953. }
  954. DoNextFace:
  955. nNewEdges = 0;
  956. for(int i = nv1index; ; i++)
  957. {
  958. if(i == nVertices)
  959. i = 0;
  960. if(i == nv2index)
  961. break;
  962. int iNextVertex = GetNext(i, 1, nVertices);
  963. int iEdgeIndex = GetEdgeIndex(phVertexList[i], phVertexList[iNextVertex]);
  964. Assert(iEdgeIndex != -1);
  965. hNewEdges[nNewEdges++] = m_Edges[iEdgeIndex].id;
  966. AssignFace(&m_Edges[iEdgeIndex], pStoreFace->id);
  967. }
  968. // now add the middle edge
  969. hNewEdges[nNewEdges++] = pNewEdgeMid->id;
  970. // now set up in face
  971. pStoreFace->nEdges = nNewEdges;
  972. memcpy(pStoreFace->Edges, hNewEdges, sizeof(SSHANDLE) * nNewEdges);
  973. if(bFirst)
  974. {
  975. int tmp = nv1index;
  976. nv1index = nv2index;
  977. nv2index = tmp;
  978. pStoreFace = pNewFace;
  979. bFirst = FALSE;
  980. goto DoNextFace;
  981. }
  982. delete phVertexList;
  983. // ** now regular faces **
  984. for(int iFace = 0; iFace < m_nFaces; iFace++)
  985. {
  986. CSSFace *pUpdFace = &m_Faces[iFace];
  987. if(pUpdFace == pNewFace || pUpdFace == pFace)
  988. continue;
  989. SSHANDLE *phVertexList = CreateNewVertexList(pUpdFace, pEdge1, pEdge2,
  990. nv1index, nv2index, pNewVertex1, pNewVertex2);
  991. if(phVertexList == NULL) // don't need to update this face
  992. continue;
  993. nNewEdges = 0;
  994. nVertices = pUpdFace->nEdges;
  995. if(nv1index != -1)
  996. ++nVertices;
  997. if(nv2index != -1)
  998. ++nVertices;
  999. for(int i = 0; i < nVertices; i++)
  1000. {
  1001. int iNextVertex = GetNext(i, 1, nVertices);
  1002. int iEdgeIndex = GetEdgeIndex(phVertexList[i], phVertexList[iNextVertex]);
  1003. Assert(iEdgeIndex != -1);
  1004. AssignFace(&m_Edges[iEdgeIndex], pUpdFace->id);
  1005. hNewEdges[nNewEdges++] = m_Edges[iEdgeIndex].id;
  1006. }
  1007. // now set up in face
  1008. pUpdFace->nEdges = nNewEdges;
  1009. memcpy(pUpdFace->Edges, hNewEdges, sizeof(SSHANDLE) * nNewEdges);
  1010. delete phVertexList;
  1011. }
  1012. SSHANDLE id1 = pEdge1->id;
  1013. SSHANDLE id2 = pEdge2->id;
  1014. // delete old edges
  1015. for(int i = 0; i < m_nEdges; i++)
  1016. {
  1017. if(m_Edges[i].id == id1 || m_Edges[i].id == id2)
  1018. {
  1019. DeleteEdge(i);
  1020. --i;
  1021. }
  1022. }
  1023. return TRUE;
  1024. }
  1025. void CSSolid::DeleteEdge(int iEdge)
  1026. {
  1027. SSHANDLE edgeid = m_Edges[iEdge].id;
  1028. // kill this edge
  1029. for(int i2 = iEdge; i2 < m_nEdges-1; i2++)
  1030. {
  1031. memcpy(&m_Edges[i2], &m_Edges[i2+1], sizeof(CSSEdge));
  1032. }
  1033. --m_nEdges;
  1034. memset(&m_Edges[m_nEdges], 0, sizeof(CSSEdge));
  1035. // kill all references to this edge in faces
  1036. for(int f = 0; f < m_nFaces; f++)
  1037. {
  1038. CSSFace& face = m_Faces[f];
  1039. for(int e = 0; e < face.nEdges; e++)
  1040. {
  1041. if(face.Edges[e] != edgeid)
  1042. continue;
  1043. memcpy(&face.Edges[e], &face.Edges[e+1], (face.nEdges-e) *
  1044. sizeof(face.Edges[0]));
  1045. --face.nEdges;
  1046. break; // no more in this face
  1047. }
  1048. }
  1049. }
  1050. void CSSolid::DeleteVertex(int iVertex)
  1051. {
  1052. for(int i2 = iVertex; i2 < m_nVertices-1; i2++)
  1053. {
  1054. memcpy(&m_Vertices[i2], &m_Vertices[i2+1], sizeof(CSSVertex));
  1055. }
  1056. --m_nVertices;
  1057. memset(&m_Vertices[m_nVertices], 0, sizeof(CSSVertex));
  1058. }
  1059. void CSSolid::DeleteFace(int iFace)
  1060. {
  1061. // Destroy the displacement if there is one.
  1062. CSSFace *pFace = &m_Faces[iFace];
  1063. if ( pFace )
  1064. {
  1065. if ( pFace->m_hDisp != EDITDISPHANDLE_INVALID )
  1066. {
  1067. EditDispMgr()->Destroy( pFace->m_hDisp );
  1068. pFace->m_hDisp = EDITDISPHANDLE_INVALID;
  1069. }
  1070. }
  1071. for(int i2 = iFace; i2 < m_nFaces-1; i2++)
  1072. {
  1073. memcpy(&m_Faces[i2], &m_Faces[i2+1], sizeof(CSSFace));
  1074. }
  1075. --m_nFaces;
  1076. m_Faces[m_nFaces].Init();
  1077. }
  1078. SSHANDLE* CSSolid::CreateNewVertexList(CSSFace *pFace, CSSEdge *pEdge1,
  1079. CSSEdge *pEdge2, int& nv1index, int& nv2index,
  1080. CSSVertex *pNewVertex1, CSSVertex *pNewVertex2)
  1081. {
  1082. // get original vertex list
  1083. CUtlVector<SSHANDLE> hVertexList;
  1084. hVertexList.SetCount(pFace->nEdges+4);
  1085. CreatePointHandleList(*pFace, hVertexList.Base());
  1086. // add vertex1 and vertex2.
  1087. nv1index = -1;
  1088. nv2index = -1;
  1089. int nVertices = pFace->nEdges;
  1090. int iPass = 0;
  1091. DoAgain:
  1092. for(int i = 0; i < nVertices; i++)
  1093. {
  1094. int iPrevIndex = GetNext(i, -1, nVertices);
  1095. int iNextIndex = GetNext(i, 1, nVertices);
  1096. if(nv1index == -1 && (hVertexList[i] == pEdge1->hvEnd ||
  1097. hVertexList[i] == pEdge1->hvStart))
  1098. {
  1099. // find pEdge1->hvStart
  1100. if(hVertexList[iPrevIndex] == pEdge1->hvStart ||
  1101. hVertexList[iPrevIndex] == pEdge1->hvEnd)
  1102. {
  1103. // add at i.
  1104. nv1index = i;
  1105. }
  1106. if(hVertexList[iNextIndex] == pEdge1->hvStart ||
  1107. hVertexList[iNextIndex] == pEdge1->hvEnd)
  1108. {
  1109. // add at iNextIndex
  1110. nv1index = iNextIndex;
  1111. }
  1112. if(nv1index != -1)
  1113. {
  1114. hVertexList.InsertBefore(nv1index, pNewVertex1->id);
  1115. ++nVertices;
  1116. break;
  1117. }
  1118. }
  1119. if(nv2index == -1 && (hVertexList[i] == pEdge2->hvEnd ||
  1120. hVertexList[i] == pEdge2->hvStart))
  1121. {
  1122. // find pEdge1->hvStart
  1123. if(hVertexList[iPrevIndex] == pEdge2->hvStart ||
  1124. hVertexList[iPrevIndex] == pEdge2->hvEnd)
  1125. {
  1126. // add at i.
  1127. nv2index = i;
  1128. }
  1129. if(hVertexList[iNextIndex] == pEdge2->hvStart ||
  1130. hVertexList[iNextIndex] == pEdge2->hvEnd)
  1131. {
  1132. // add at iNextIndex
  1133. nv2index = iNextIndex;
  1134. }
  1135. if(nv2index != -1)
  1136. {
  1137. hVertexList.InsertBefore(nv2index, pNewVertex2->id);
  1138. ++nVertices;
  1139. break;
  1140. }
  1141. }
  1142. }
  1143. SSHANDLE hTmp[64];
  1144. memcpy(hTmp, hVertexList.Base(), sizeof(SSHANDLE) * nVertices);
  1145. if(nv1index == -1 && nv2index == -1)
  1146. return NULL; // not used here.
  1147. if(nv1index == -1 || nv2index == -1)
  1148. {
  1149. if(++iPass != 2)
  1150. goto DoAgain;
  1151. }
  1152. SSHANDLE *rvl = new SSHANDLE[nVertices];
  1153. memcpy(rvl, hVertexList.Base(), sizeof(SSHANDLE) * nVertices);
  1154. return rvl;
  1155. }
  1156. // merge same vertices ->
  1157. BOOL CSSolid::CanMergeVertices()
  1158. {
  1159. for(int v1 = 0; v1 < m_nVertices; v1++)
  1160. {
  1161. for(int v2 = 0; v2 < m_nVertices; v2++)
  1162. {
  1163. if(v1 == v2)
  1164. continue; // no!
  1165. if(VectorCompare(m_Vertices[v1].pos, m_Vertices[v2].pos))
  1166. return TRUE; // got a match
  1167. }
  1168. }
  1169. return FALSE;
  1170. }
  1171. SSHANDLE * CSSolid::MergeSameVertices(int& nDeleted)
  1172. {
  1173. int nMerged = 0;
  1174. nDeleted = 0;
  1175. static SSHANDLE hDeletedList[128];
  1176. DoVertices:
  1177. for(int v1 = 0; v1 < m_nVertices; v1++)
  1178. {
  1179. for(int v2 = 0; v2 < m_nVertices; v2++)
  1180. {
  1181. if(v1 == v2)
  1182. continue; // no!
  1183. if(!VectorCompare(m_Vertices[v1].pos, m_Vertices[v2].pos))
  1184. { // no match
  1185. continue;
  1186. }
  1187. ++nMerged;
  1188. // same vertices - kill v1, set edge refs to use v2.
  1189. SSHANDLE hV1 = m_Vertices[v1].id;
  1190. SSHANDLE hV2 = m_Vertices[v2].id;
  1191. hDeletedList[nDeleted++] = hV1;
  1192. DeleteVertex(v1);
  1193. int nAffected;
  1194. CSSEdge **ppEdges = FindAffectedEdges(&hV1, 1, nAffected);
  1195. // run through edges and change references
  1196. for(int e = 0; e < nAffected; e++)
  1197. {
  1198. if(ppEdges[e]->hvStart == hV1)
  1199. ppEdges[e]->hvStart = hV2;
  1200. if(ppEdges[e]->hvEnd == hV1)
  1201. ppEdges[e]->hvEnd = hV2;
  1202. CalcEdgeCenter(ppEdges[e]);
  1203. }
  1204. goto DoVertices;
  1205. }
  1206. }
  1207. if(!nMerged)
  1208. return NULL;
  1209. int e;
  1210. // kill edges that have same vertices
  1211. for(e = 0; e < m_nEdges; e++)
  1212. {
  1213. CSSEdge &edge = m_Edges[e];
  1214. if(edge.hvStart != edge.hvEnd)
  1215. continue; // edge is OK
  1216. hDeletedList[nDeleted++] = edge.id;
  1217. DeleteEdge(e);
  1218. --e;
  1219. }
  1220. // kill similar edges (replace in faces too)
  1221. DoEdges:
  1222. for(e = 0; e < m_nEdges; e++)
  1223. {
  1224. CSSEdge &edge = m_Edges[e];
  1225. for(int e2 = 0; e2 < m_nEdges; e2++)
  1226. {
  1227. if(e == e2)
  1228. continue;
  1229. CSSEdge &edge2 = m_Edges[e2];
  1230. if(!((edge2.hvStart == edge.hvStart && edge2.hvEnd == edge.hvEnd) ||
  1231. (edge2.hvEnd == edge.hvStart && edge2.hvStart == edge.hvEnd)))
  1232. continue;
  1233. // we're going to delete edge2.
  1234. SSHANDLE id2 = edge2.id;
  1235. SSHANDLE id1 = edge.id;
  1236. for(int f = 0; f < m_nFaces; f++)
  1237. {
  1238. CSSFace& face = m_Faces[f];
  1239. for(int ef = 0; ef < face.nEdges; ef++)
  1240. {
  1241. if(face.Edges[ef] == id2)
  1242. {
  1243. face.Edges[ef] = id1;
  1244. break;
  1245. }
  1246. }
  1247. }
  1248. hDeletedList[nDeleted++] = id2;
  1249. DeleteEdge(e2);
  1250. goto DoEdges;
  1251. }
  1252. }
  1253. // delete concurrent edge references in face
  1254. for(int f = 0; f < m_nFaces; f++)
  1255. {
  1256. CSSFace& face = m_Faces[f];
  1257. DoConcurrentEdges:
  1258. for(int ef1 = 0; ef1 < face.nEdges; ef1++)
  1259. {
  1260. for(int ef2 = 0; ef2 < face.nEdges; ef2++)
  1261. {
  1262. if(ef2 == ef1)
  1263. continue;
  1264. if(face.Edges[ef1] != face.Edges[ef2])
  1265. continue;
  1266. // delete this ref
  1267. memcpy(&face.Edges[ef2], &face.Edges[ef2+1], (face.nEdges-ef2) *
  1268. sizeof(face.Edges[0]));
  1269. --face.nEdges;
  1270. goto DoConcurrentEdges;
  1271. }
  1272. }
  1273. if(face.nEdges < 3)
  1274. {
  1275. // kill this face
  1276. hDeletedList[nDeleted++] = face.id;
  1277. DeleteFace(f);
  1278. --f;
  1279. }
  1280. }
  1281. return hDeletedList;
  1282. }
  1283. //-----------------------------------------------------------------------------
  1284. // Purpose: Constructor.
  1285. //-----------------------------------------------------------------------------
  1286. CSSFace::CSSFace(void)
  1287. {
  1288. Init();
  1289. }
  1290. //-----------------------------------------------------------------------------
  1291. // Purpose: Initialize the SSFace.
  1292. //-----------------------------------------------------------------------------
  1293. void CSSFace::Init(void)
  1294. {
  1295. nEdges = 0;
  1296. bModified = FALSE;
  1297. m_nFaceID = 0;
  1298. m_hDisp = EDITDISPHANDLE_INVALID;
  1299. memset(&texture, 0, sizeof(TEXTURE));
  1300. texture.scale[0] = g_pGameConfig->GetDefaultTextureScale();
  1301. texture.scale[1] = g_pGameConfig->GetDefaultTextureScale();
  1302. }
  1303. //-----------------------------------------------------------------------------
  1304. // Purpose: Destructor.
  1305. //-----------------------------------------------------------------------------
  1306. CSSFace::~CSSFace(void)
  1307. {
  1308. if ( m_hDisp != EDITDISPHANDLE_INVALID )
  1309. {
  1310. EditDispMgr()->Destroy( m_hDisp );
  1311. m_hDisp = EDITDISPHANDLE_INVALID;
  1312. }
  1313. memset(this, 0, sizeof(this));
  1314. }
  1315. //-----------------------------------------------------------------------------
  1316. // Purpose: Constructor.
  1317. //-----------------------------------------------------------------------------
  1318. CSSEdge::CSSEdge(void)
  1319. {
  1320. Faces[0] = Faces[1] = 0;
  1321. }
  1322. //-----------------------------------------------------------------------------
  1323. // Purpose: Destructor.
  1324. //-----------------------------------------------------------------------------
  1325. CSSEdge::~CSSEdge()
  1326. {
  1327. memset(this, 0, sizeof(this));
  1328. }
  1329. //-----------------------------------------------------------------------------
  1330. // Purpose: Gets the world coordinates of the center point of this edge.
  1331. // Input : Point - Receives the world coordinates of the center point.
  1332. //-----------------------------------------------------------------------------
  1333. void CSSEdge::GetCenterPoint(Vector& Point)
  1334. {
  1335. Point = ptCenter;
  1336. }
  1337. CSSVertex::CSSVertex(void)
  1338. {
  1339. }
  1340. CSSVertex::~CSSVertex(void)
  1341. {
  1342. pos[0] = pos[1] = pos[2] = 0;
  1343. id = 0;
  1344. }
  1345. //-----------------------------------------------------------------------------
  1346. // Purpose: Gets the world coordinates of this vertex.
  1347. // Input : Position - Receives the world coordinates.
  1348. //-----------------------------------------------------------------------------
  1349. void CSSVertex::GetPosition(Vector& Position)
  1350. {
  1351. Position = pos;
  1352. }
  1353. //
  1354. // save to .DXF
  1355. //
  1356. void CSSolid::SerializeDXF(FILE *stream, int nObject)
  1357. {
  1358. char szName[128];
  1359. sprintf(szName, "OBJECT%03d", nObject);
  1360. // count number of triangulated faces
  1361. int nTriFaces = 0;
  1362. for(int i = 0; i < m_nFaces; i++)
  1363. {
  1364. CSSFace &face = m_Faces[i];
  1365. nTriFaces += face.nEdges-2;
  1366. }
  1367. fprintf(stream,"0\nPOLYLINE\n8\n%s\n66\n1\n70\n64\n71\n%u\n72\n%u\n", szName, m_nVertices, nTriFaces);
  1368. fprintf(stream,"62\n50\n");
  1369. for (int i = 0; i < m_nVertices; i++)
  1370. {
  1371. Vector &pos = m_Vertices[i].pos;
  1372. 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]);
  1373. }
  1374. // triangulate each face and write
  1375. for(int i = 0; i < m_nFaces; i++)
  1376. {
  1377. CSSFace &face = m_Faces[i];
  1378. PINT pVerts = CreatePointIndexList(face);
  1379. for(int v = 0; v < face.nEdges; v++)
  1380. pVerts[v]++;
  1381. for(int v = 0; v < face.nEdges-2; v++)
  1382. {
  1383. fprintf(stream, "0\nVERTEX\n8\n%s\n10\n0\n20\n0\n30\n"
  1384. "0\n70\n128\n71\n%d\n72\n%d\n73\n%d\n", szName,
  1385. v == 0 ? pVerts[0] : -pVerts[0],
  1386. pVerts[v+1],
  1387. v == (face.nEdges-3) ? pVerts[v+2] : -pVerts[v+2]
  1388. );
  1389. }
  1390. }
  1391. fprintf(stream, "0\nSEQEND\n8\n%s\n", szName);
  1392. }