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.

1128 lines
35 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <stdafx.h>
  9. #include "DispSubdiv.h"
  10. #include "MapDisp.h"
  11. #include "UtlLinkedList.h"
  12. #include "UtlVector.h"
  13. #include "GlobalFunctions.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include <tier0/memdbgon.h>
  16. //=============================================================================
  17. //
  18. // Editable Displacement Subdivision Mesh Implementation
  19. //
  20. class CEditDispSubdivMesh : public IEditDispSubdivMesh
  21. {
  22. public: // functions
  23. void Init( void );
  24. void Shutdown( void );
  25. void AddDispTo( CMapDisp *pDisp );
  26. void GetDispFrom( CMapDisp *pDisp );
  27. void DoCatmullClarkSubdivision( void );
  28. public: // typedefs, enums, structs
  29. enum { EDITDISP_QUADSIZE = 4 }; // should be in mapdisp (general define)
  30. private: // typedefs, enums, structs
  31. typedef int SubdivPointHandle_t;
  32. typedef int SubdivEdgeHandle_t;
  33. typedef int SubdivQuadHandle_t;
  34. enum { NUM_SUBDIV_LEVELS = 4 }; // number of subdivision levels
  35. enum
  36. {
  37. SUBDIV_DISPPOINTS = 512,
  38. SUBDIV_DISPEDGES = 1024,
  39. SUBDIV_DISPQUADS = 512
  40. };
  41. enum
  42. {
  43. SUBDIV_POINTORDINARY = 0,
  44. SUBDIV_POINTCORNER = 1,
  45. SUBDIV_POINTCREASE = 2
  46. };
  47. struct SubdivPoint_t
  48. {
  49. Vector m_vPoint;
  50. Vector m_vNormal;
  51. Vector m_vNewPoint;
  52. Vector m_vNewNormal;
  53. unsigned short m_uType;
  54. unsigned short m_uValence;
  55. SubdivEdgeHandle_t m_EdgeHandles[EDITDISP_QUADSIZE*4];
  56. };
  57. struct SubdivEdge_t
  58. {
  59. Vector m_vNewEdgePoint;
  60. Vector m_vNewEdgeNormal;
  61. SubdivPointHandle_t m_PointHandles[2];
  62. SubdivQuadHandle_t m_QuadHandles[2];
  63. float m_flSharpness;
  64. bool m_bActive;
  65. };
  66. struct SubdivQuad_t
  67. {
  68. // generated
  69. Vector m_vCentroid; // quad center
  70. Vector m_vNormal; // quad normal
  71. // linkage
  72. SubdivQuadHandle_t m_ndxParent; // parent quad index
  73. SubdivQuadHandle_t m_ndxChild[EDITDISP_QUADSIZE]; // chilren (4 of them) indices
  74. // quad data
  75. SubdivPointHandle_t m_PointHandles[EDITDISP_QUADSIZE]; // point indices - unique list
  76. SubdivEdgeHandle_t m_EdgeHandles[EDITDISP_QUADSIZE]; // edge indices - unique list
  77. // disp/quad mapping
  78. EditDispHandle_t m_EditDispHandle;
  79. short m_Level; // level of quad in the hierarchy (tree)
  80. short m_QuadIndices[EDITDISP_QUADSIZE]; // quad indices (in the X x X displacement surface)
  81. };
  82. private: // functions
  83. SubdivPoint_t *GetPoint( SubdivPointHandle_t ptHandle );
  84. SubdivEdge_t *GetEdge( SubdivEdgeHandle_t edgeHandle );
  85. SubdivQuad_t *GetQuad( SubdivQuadHandle_t quadHandle );
  86. void Point_Init( SubdivPointHandle_t ptHandle );
  87. void Point_CalcNewPoint( SubdivPointHandle_t ptHandle );
  88. void Point_PointOrdinary( SubdivPoint_t *pPoint );
  89. void Point_PointCorner( SubdivPoint_t *pPoint );
  90. void Point_PointCrease( SubdivPoint_t *pPoint );
  91. void Edge_Init( SubdivEdgeHandle_t edgeHandle );
  92. void Edge_CalcNewPoint( SubdivEdgeHandle_t edgeHandle );
  93. void Quad_Init( SubdivQuadHandle_t quadHandle );
  94. void Quad_CalcCentroid( SubdivQuadHandle_t quadHandle );
  95. void Quad_CalcNormal( SubdivQuadHandle_t quadHandle );
  96. bool CompareSubdivPoints( Vector const &pt1, Vector const &pt2, float flTolerance );
  97. bool CompareSubdivEdges( SubdivPointHandle_t ptEdge0Handle0, SubdivPointHandle_t ptEdge0Handle1,
  98. SubdivPointHandle_t ptEdge1Handle0, SubdivPointHandle_t ptEdge1Handle1 );
  99. SubdivPointHandle_t BuildSubdivPoint( Vector const &vPoint, Vector const &vNormal );
  100. SubdivEdgeHandle_t BuildSubdivEdge( int ndxEdge, SubdivQuadHandle_t quadHandle,
  101. SubdivQuadHandle_t parentHandle, int ndxChild );
  102. SubdivQuadHandle_t BuildSubdivQuad( int ndxChild, SubdivQuadHandle_t parentHandle );
  103. void CatmullClarkSubdivision( void );
  104. void UpdateSubdivisionHierarchy( int ndxLevel );
  105. private: // variables
  106. CUtlLinkedList<SubdivPoint_t, SubdivPointHandle_t> m_Points;
  107. CUtlLinkedList<SubdivEdge_t, SubdivEdgeHandle_t> m_Edges;
  108. CUtlLinkedList<SubdivQuad_t, SubdivQuadHandle_t> m_Quads;
  109. };
  110. //-----------------------------------------------------------------------------
  111. // Purpose:
  112. //-----------------------------------------------------------------------------
  113. IEditDispSubdivMesh *CreateEditDispSubdivMesh( void )
  114. {
  115. return new CEditDispSubdivMesh;
  116. }
  117. //-----------------------------------------------------------------------------
  118. // Purpose:
  119. //-----------------------------------------------------------------------------
  120. void DestroyEditDispSubdivMesh( IEditDispSubdivMesh **pSubdivMesh )
  121. {
  122. if ( *pSubdivMesh )
  123. {
  124. delete *pSubdivMesh;
  125. *pSubdivMesh = NULL;
  126. }
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. //-----------------------------------------------------------------------------
  131. CEditDispSubdivMesh::SubdivPoint_t *CEditDispSubdivMesh::GetPoint( SubdivPointHandle_t ptHandle )
  132. {
  133. if ( !m_Points.IsValidIndex( ptHandle ) )
  134. return NULL;
  135. return &m_Points.Element( ptHandle );
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose:
  139. //-----------------------------------------------------------------------------
  140. CEditDispSubdivMesh::SubdivEdge_t *CEditDispSubdivMesh::GetEdge( SubdivEdgeHandle_t edgeHandle )
  141. {
  142. if ( !m_Edges.IsValidIndex( edgeHandle ) )
  143. return NULL;
  144. return &m_Edges.Element( edgeHandle );
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose:
  148. //-----------------------------------------------------------------------------
  149. CEditDispSubdivMesh::SubdivQuad_t *CEditDispSubdivMesh::GetQuad( SubdivQuadHandle_t quadHandle )
  150. {
  151. if ( !m_Quads.IsValidIndex( quadHandle ) )
  152. return NULL;
  153. return &m_Quads.Element( quadHandle );
  154. }
  155. //=============================================================================
  156. //
  157. // Subdivision Edit Displacement Point Functions
  158. //
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. //-----------------------------------------------------------------------------
  162. void CEditDispSubdivMesh::Point_Init( SubdivPointHandle_t ptHandle )
  163. {
  164. SubdivPoint_t *pPoint = GetPoint( ptHandle );
  165. if ( pPoint )
  166. {
  167. VectorClear( pPoint->m_vPoint );
  168. VectorClear( pPoint->m_vNormal );
  169. VectorClear( pPoint->m_vNewPoint );
  170. VectorClear( pPoint->m_vNewNormal );
  171. pPoint->m_uType = (unsigned short)-1;
  172. pPoint->m_uValence = 0;
  173. for ( int ndxEdge = 0; ndxEdge < ( EDITDISP_QUADSIZE*2 ); ndxEdge++ )
  174. {
  175. pPoint->m_EdgeHandles[ndxEdge] = m_Edges.InvalidIndex();
  176. }
  177. }
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose:
  181. //-----------------------------------------------------------------------------
  182. void CEditDispSubdivMesh::Point_CalcNewPoint( SubdivPointHandle_t ptHandle )
  183. {
  184. // get the point to act on
  185. SubdivPoint_t *pPoint = GetPoint( ptHandle );
  186. if ( !pPoint )
  187. return;
  188. switch ( pPoint->m_uType )
  189. {
  190. case SUBDIV_POINTORDINARY: { Point_PointOrdinary( pPoint ); break; }
  191. case SUBDIV_POINTCORNER: { Point_PointCorner( pPoint ); break; }
  192. case SUBDIV_POINTCREASE: { Point_PointCrease( pPoint ); break; }
  193. }
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Purpose:
  197. //-----------------------------------------------------------------------------
  198. void CEditDispSubdivMesh::Point_PointOrdinary( SubdivPoint_t *pPoint )
  199. {
  200. //
  201. // accumulate the edge data and multiply by the valence (coincident edge)
  202. // ratio (squared)
  203. //
  204. Vector edgeAccumPoint( 0.0f, 0.0f, 0.0f );
  205. Vector edgeAccumNormal( 0.0f, 0.0f, 0.0f );
  206. for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ )
  207. {
  208. SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] );
  209. if ( pEdge )
  210. {
  211. VectorAdd( edgeAccumPoint, pEdge->m_vNewEdgePoint, edgeAccumPoint );
  212. VectorAdd( edgeAccumNormal, pEdge->m_vNewEdgeNormal, edgeAccumNormal );
  213. }
  214. }
  215. float ratio = 1.0f / ( float )( pPoint->m_uValence * pPoint->m_uValence );
  216. VectorScale( edgeAccumPoint, ratio, edgeAccumPoint );
  217. VectorScale( edgeAccumNormal, ratio, edgeAccumNormal );
  218. //
  219. // accumlate the centroid data from all neighboring quads and multiply by
  220. // the valence (coincident edge) ratio (squared)
  221. //
  222. int quadListCount = 0;
  223. SubdivQuadHandle_t quadList[32];
  224. for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ )
  225. {
  226. SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] );
  227. if ( pEdge )
  228. {
  229. for ( int ndxQuad = 0; ndxQuad < 2; ndxQuad++ )
  230. {
  231. if ( pEdge->m_QuadHandles[ndxQuad] != m_Quads.InvalidIndex() )
  232. {
  233. int ndxList;
  234. for ( ndxList = 0; ndxList < quadListCount; ndxList++ )
  235. {
  236. if( pEdge->m_QuadHandles[ndxQuad] == quadList[ndxList] )
  237. break;
  238. }
  239. if( ndxList == quadListCount )
  240. {
  241. quadList[quadListCount] = pEdge->m_QuadHandles[ndxQuad];
  242. quadListCount++;
  243. }
  244. }
  245. }
  246. }
  247. }
  248. Vector centroidAccum( 0.0f, 0.0f, 0.0f );
  249. for ( int ndxQuad = 0; ndxQuad < quadListCount; ndxQuad++ )
  250. {
  251. SubdivQuadHandle_t quadHandle = quadList[ndxQuad];
  252. Quad_CalcCentroid( quadHandle );
  253. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  254. VectorAdd( centroidAccum, pQuad->m_vCentroid, centroidAccum );
  255. }
  256. VectorScale( centroidAccum, ratio, centroidAccum );
  257. //
  258. //
  259. //
  260. ratio = ( ( float )pPoint->m_uValence - 2.0f ) / ( float )pPoint->m_uValence;
  261. VectorScale( pPoint->m_vPoint, ratio, pPoint->m_vNewPoint );
  262. VectorAdd( pPoint->m_vNewPoint, edgeAccumPoint, pPoint->m_vNewPoint );
  263. VectorAdd( pPoint->m_vNewPoint, centroidAccum, pPoint->m_vNewPoint );
  264. VectorScale( pPoint->m_vNormal, ratio, pPoint->m_vNewNormal );
  265. VectorAdd( pPoint->m_vNewNormal, edgeAccumNormal, pPoint->m_vNewNormal );
  266. VectorAdd( pPoint->m_vNewNormal, centroidAccum, pPoint->m_vNewNormal );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose:
  270. //-----------------------------------------------------------------------------
  271. void CEditDispSubdivMesh::Point_PointCorner( SubdivPoint_t *pPoint )
  272. {
  273. VectorCopy( pPoint->m_vPoint, pPoint->m_vNewPoint );
  274. VectorCopy( pPoint->m_vNormal, pPoint->m_vNewNormal );
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose:
  278. //-----------------------------------------------------------------------------
  279. void CEditDispSubdivMesh::Point_PointCrease( SubdivPoint_t *pPoint )
  280. {
  281. //
  282. // accumulate the edge data and multiply by the valence (coincident edge)
  283. // ratio (squared)
  284. //
  285. Vector edgeAccumPoint( 0.0f, 0.0f, 0.0f );
  286. Vector edgeAccumNormal( 0.0f, 0.0f, 0.0f );
  287. for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ )
  288. {
  289. SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] );
  290. if ( pEdge && ( pEdge->m_flSharpness > 0.0f ) )
  291. {
  292. VectorAdd( edgeAccumPoint, pEdge->m_vNewEdgePoint, edgeAccumPoint );
  293. VectorAdd( edgeAccumNormal, pEdge->m_vNewEdgeNormal, edgeAccumNormal );
  294. }
  295. }
  296. //
  297. //
  298. //
  299. VectorScale( pPoint->m_vPoint, 6.0f, pPoint->m_vNewPoint );
  300. VectorAdd( pPoint->m_vNewPoint, edgeAccumPoint, pPoint->m_vNewPoint );
  301. VectorScale( pPoint->m_vNewPoint, 0.125f, pPoint->m_vNewPoint );
  302. VectorScale( pPoint->m_vNormal, 6.0f, pPoint->m_vNewNormal );
  303. VectorAdd( pPoint->m_vNewNormal, edgeAccumNormal, pPoint->m_vNewNormal );
  304. VectorScale( pPoint->m_vNewNormal, 0.125f, pPoint->m_vNewNormal );
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Purpose:
  308. //-----------------------------------------------------------------------------
  309. void CEditDispSubdivMesh::Edge_Init( SubdivEdgeHandle_t edgeHandle )
  310. {
  311. SubdivEdge_t *pEdge = GetEdge( edgeHandle );
  312. if ( pEdge )
  313. {
  314. VectorClear( pEdge->m_vNewEdgePoint );
  315. VectorClear( pEdge->m_vNewEdgeNormal );
  316. pEdge->m_flSharpness = 1.0f;
  317. pEdge->m_bActive = false;
  318. for ( int ndx = 0; ndx < 2; ndx++ )
  319. {
  320. pEdge->m_PointHandles[ndx] = m_Points.InvalidIndex();
  321. pEdge->m_QuadHandles[ndx] = m_Quads.InvalidIndex();
  322. }
  323. }
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose:
  327. //-----------------------------------------------------------------------------
  328. void CEditDispSubdivMesh::Edge_CalcNewPoint( SubdivEdgeHandle_t edgeHandle )
  329. {
  330. SubdivEdge_t *pEdge = GetEdge( edgeHandle );
  331. if ( !pEdge )
  332. return;
  333. if ( !pEdge->m_bActive )
  334. return;
  335. //
  336. // get edge points
  337. //
  338. SubdivPoint_t *pPoint0 = GetPoint( pEdge->m_PointHandles[0] );
  339. SubdivPoint_t *pPoint1 = GetPoint( pEdge->m_PointHandles[1] );
  340. if ( !pPoint0 || !pPoint1 )
  341. return;
  342. //
  343. // calculate the "sharp" new edge point
  344. //
  345. Vector vSharpPoint( 0.0f, 0.0f, 0.0f );
  346. VectorAdd( pPoint0->m_vPoint, pPoint1->m_vPoint, vSharpPoint );
  347. VectorScale( vSharpPoint, 0.5f, vSharpPoint );
  348. Vector vSharpNormal( 0.0f, 0.0f, 0.0f );
  349. VectorAdd( pPoint0->m_vNormal, pPoint1->m_vNormal, vSharpNormal );
  350. VectorNormalize( vSharpNormal );
  351. //
  352. // calculate the "smooth" new edge point (if necessary)
  353. //
  354. Vector vSmoothPoint( 0.0f, 0.0f, 0.0f );
  355. Vector vSmoothNormal( 0.0f, 0.0f, 0.0f );
  356. if ( ( pEdge->m_QuadHandles[1] != m_Edges.InvalidIndex() ) && ( pEdge->m_flSharpness != 1.0f ) )
  357. {
  358. Quad_CalcCentroid( pEdge->m_QuadHandles[0] );
  359. Quad_CalcCentroid( pEdge->m_QuadHandles[1] );
  360. Quad_CalcNormal( pEdge->m_QuadHandles[0] );
  361. Quad_CalcNormal( pEdge->m_QuadHandles[1] );
  362. SubdivQuad_t *pQuad0 = GetQuad( pEdge->m_QuadHandles[0] );
  363. SubdivQuad_t *pQuad1 = GetQuad( pEdge->m_QuadHandles[1] );
  364. VectorAdd( pPoint0->m_vPoint, pPoint1->m_vPoint, vSmoothPoint );
  365. VectorAdd( vSmoothPoint, pQuad0->m_vCentroid, vSmoothPoint );
  366. VectorAdd( vSmoothPoint, pQuad1->m_vCentroid, vSmoothPoint );
  367. VectorScale( vSmoothPoint, 0.25f, vSmoothPoint );
  368. VectorAdd( pPoint0->m_vNormal, pPoint1->m_vNormal, vSmoothNormal );
  369. VectorAdd( vSmoothNormal, pQuad0->m_vNormal, vSmoothNormal );
  370. VectorAdd( vSmoothNormal, pQuad1->m_vNormal, vSmoothNormal );
  371. VectorNormalize( vSmoothNormal );
  372. }
  373. else
  374. {
  375. pEdge->m_flSharpness = 1.0f;
  376. Quad_CalcCentroid( pEdge->m_QuadHandles[0] );
  377. Quad_CalcNormal( pEdge->m_QuadHandles[0] );
  378. }
  379. //
  380. // calculate the new edge point
  381. //
  382. // ( 1 - edge(sharpness) ) * vSmooth + edge(sharpness) * vSharp
  383. //
  384. VectorScale( vSmoothPoint, ( 1.0f - pEdge->m_flSharpness ), vSmoothPoint );
  385. VectorScale( vSharpPoint, pEdge->m_flSharpness, vSharpPoint );
  386. VectorAdd( vSmoothPoint, vSharpPoint, pEdge->m_vNewEdgePoint );
  387. VectorScale( vSmoothNormal, ( 1.0f - pEdge->m_flSharpness ), vSmoothNormal );
  388. VectorScale( vSharpNormal, pEdge->m_flSharpness, vSharpNormal );
  389. VectorAdd( vSmoothNormal, vSharpNormal, pEdge->m_vNewEdgeNormal );
  390. VectorNormalize( pEdge->m_vNewEdgeNormal );
  391. }
  392. //-----------------------------------------------------------------------------
  393. // Purpose:
  394. //-----------------------------------------------------------------------------
  395. void CEditDispSubdivMesh::Quad_Init( SubdivQuadHandle_t quadHandle )
  396. {
  397. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  398. if ( pQuad )
  399. {
  400. VectorClear( pQuad->m_vCentroid );
  401. VectorClear( pQuad->m_vNormal );
  402. pQuad->m_ndxParent = m_Quads.InvalidIndex();
  403. pQuad->m_EditDispHandle = EDITDISPHANDLE_INVALID;
  404. pQuad->m_Level = -1;
  405. for ( int ndx = 0; ndx < EDITDISP_QUADSIZE; ndx++ )
  406. {
  407. pQuad->m_ndxChild[ndx] = m_Quads.InvalidIndex();
  408. pQuad->m_PointHandles[ndx] = m_Points.InvalidIndex();
  409. pQuad->m_EdgeHandles[ndx] = m_Edges.InvalidIndex();
  410. pQuad->m_QuadIndices[ndx] = -1;
  411. }
  412. }
  413. }
  414. //-----------------------------------------------------------------------------
  415. // Purpose:
  416. //-----------------------------------------------------------------------------
  417. void CEditDispSubdivMesh::Quad_CalcCentroid( SubdivQuadHandle_t quadHandle )
  418. {
  419. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  420. if ( pQuad )
  421. {
  422. VectorClear( pQuad->m_vCentroid );
  423. for ( int ndxPt = 0; ndxPt < EDITDISP_QUADSIZE; ndxPt++ )
  424. {
  425. SubdivPoint_t *pPoint = GetPoint( pQuad->m_PointHandles[ndxPt] );
  426. VectorAdd( pQuad->m_vCentroid, pPoint->m_vPoint, pQuad->m_vCentroid );
  427. }
  428. VectorScale( pQuad->m_vCentroid, 0.25f, pQuad->m_vCentroid );
  429. }
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose:
  433. //-----------------------------------------------------------------------------
  434. void CEditDispSubdivMesh::Quad_CalcNormal( SubdivQuadHandle_t quadHandle )
  435. {
  436. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  437. if ( pQuad )
  438. {
  439. SubdivPoint_t *pPoints[3];
  440. Vector edges[2];
  441. pPoints[0] = GetPoint( pQuad->m_PointHandles[0] );
  442. pPoints[1] = GetPoint( pQuad->m_PointHandles[1] );
  443. pPoints[2] = GetPoint( pQuad->m_PointHandles[2] );
  444. VectorSubtract( pPoints[1]->m_vPoint, pPoints[0]->m_vPoint, edges[0] );
  445. VectorSubtract( pPoints[2]->m_vPoint, pPoints[0]->m_vPoint, edges[1] );
  446. CrossProduct( edges[1], edges[0], pQuad->m_vNormal );
  447. VectorNormalize( pQuad->m_vNormal );
  448. }
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose:
  452. //-----------------------------------------------------------------------------
  453. bool CEditDispSubdivMesh::CompareSubdivPoints( Vector const &pt1, Vector const &pt2,
  454. float flTolerance )
  455. {
  456. for ( int axis = 0 ; axis < 3 ; axis++ )
  457. {
  458. if ( fabs( pt1[axis] - pt2[axis] ) > flTolerance )
  459. return false;
  460. }
  461. return true;
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Purpose:
  465. //-----------------------------------------------------------------------------
  466. bool CEditDispSubdivMesh::CompareSubdivEdges( SubdivPointHandle_t ptEdge0Handle0,
  467. SubdivPointHandle_t ptEdge0Handle1,
  468. SubdivPointHandle_t ptEdge1Handle0,
  469. SubdivPointHandle_t ptEdge1Handle1 )
  470. {
  471. if ( ( ( ptEdge0Handle0 == ptEdge1Handle0 ) && ( ptEdge0Handle1 == ptEdge1Handle1 ) ) ||
  472. ( ( ptEdge0Handle0 == ptEdge1Handle1 ) && ( ptEdge0Handle1 == ptEdge1Handle0 ) ) )
  473. return true;
  474. return false;
  475. }
  476. //-----------------------------------------------------------------------------
  477. // Purpose:
  478. //-----------------------------------------------------------------------------
  479. CEditDispSubdivMesh::SubdivPointHandle_t CEditDispSubdivMesh::BuildSubdivPoint( Vector const &vPoint,
  480. Vector const &vPointNormal )
  481. {
  482. //
  483. // build a "unique" point
  484. //
  485. SubdivPointHandle_t ptHandle;
  486. for ( ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex();
  487. ptHandle = m_Points.Next( ptHandle ) )
  488. {
  489. SubdivPoint_t *pPoint = GetPoint( ptHandle );
  490. if ( pPoint )
  491. {
  492. // compare (positions)
  493. if ( CompareSubdivPoints( vPoint, pPoint->m_vPoint, 0.1f ) )
  494. return ptHandle;
  495. }
  496. }
  497. ptHandle = m_Points.AddToTail();
  498. Point_Init( ptHandle );
  499. SubdivPoint_t *pPoint = GetPoint( ptHandle );
  500. VectorCopy( vPoint, pPoint->m_vPoint );
  501. VectorCopy( vPointNormal, pPoint->m_vNormal );
  502. return ptHandle;
  503. }
  504. //-----------------------------------------------------------------------------
  505. // Purpose:
  506. //-----------------------------------------------------------------------------
  507. CEditDispSubdivMesh::SubdivEdgeHandle_t CEditDispSubdivMesh::BuildSubdivEdge( int ndxEdge, SubdivQuadHandle_t quadHandle,
  508. SubdivQuadHandle_t parentHandle, int ndxChild )
  509. {
  510. // get the quad
  511. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  512. if ( !pQuad )
  513. return m_Edges.InvalidIndex();
  514. //
  515. // define a unique edge (m_PointHandlesX2, m_QuadHandle)
  516. //
  517. SubdivEdgeHandle_t edgeHandle;
  518. for ( edgeHandle = m_Edges.Head(); edgeHandle != m_Edges.InvalidIndex();
  519. edgeHandle = m_Edges.Next( edgeHandle ) )
  520. {
  521. SubdivEdge_t *pEdge = GetEdge( edgeHandle );
  522. if ( pEdge )
  523. {
  524. // compare (point handles)
  525. if ( CompareSubdivEdges( pQuad->m_PointHandles[ndxEdge], pQuad->m_PointHandles[(ndxEdge+1)%4],
  526. pEdge->m_PointHandles[0], pEdge->m_PointHandles[1] ) )
  527. {
  528. // check to see if the quad is quad 0 or 1 (or if it needs to be quad 1)
  529. if ( ( pEdge->m_QuadHandles[0] != quadHandle ) &&
  530. ( pEdge->m_QuadHandles[1] == m_Quads.InvalidIndex() ) )
  531. {
  532. pEdge->m_QuadHandles[1] = quadHandle;
  533. pEdge->m_flSharpness = 0.0f; // smooth edge (between two subdiv quads)
  534. }
  535. return edgeHandle;
  536. }
  537. }
  538. }
  539. edgeHandle = m_Edges.AddToTail();
  540. Edge_Init( edgeHandle );
  541. SubdivEdge_t *pEdge = GetEdge( edgeHandle );
  542. pEdge->m_PointHandles[0] = pQuad->m_PointHandles[ndxEdge];
  543. pEdge->m_PointHandles[1] = pQuad->m_PointHandles[(ndxEdge+1)%4];
  544. pEdge->m_QuadHandles[0] = quadHandle;
  545. pEdge->m_bActive = true;
  546. // extra data for children (get edge sharpness from parent or
  547. // it may be an internal edge and its sharpness will be 0)
  548. if( ndxChild != -1 )
  549. {
  550. if ( ( ndxEdge == ndxChild ) || ( ndxEdge == ( (ndxChild+3)%4 ) ) )
  551. {
  552. SubdivQuad_t *pParentQuad = GetQuad( parentHandle );
  553. if ( pParentQuad )
  554. {
  555. SubdivEdge_t *pParentEdge = GetEdge( pParentQuad->m_EdgeHandles[ndxEdge] );
  556. pEdge->m_flSharpness = pParentEdge->m_flSharpness;
  557. }
  558. }
  559. else
  560. {
  561. pEdge->m_flSharpness = 0.0f;
  562. }
  563. }
  564. return edgeHandle;
  565. }
  566. //-----------------------------------------------------------------------------
  567. // Purpose:
  568. //-----------------------------------------------------------------------------
  569. CEditDispSubdivMesh::SubdivQuadHandle_t CEditDispSubdivMesh::BuildSubdivQuad( int ndxChild,
  570. SubdivQuadHandle_t parentHandle )
  571. {
  572. // get parent quad
  573. SubdivQuad_t *pParentQuad = GetQuad( parentHandle );
  574. if( !pParentQuad )
  575. return m_Quads.InvalidIndex();
  576. // allocate a new quad
  577. SubdivQuadHandle_t quadHandle = m_Quads.AddToTail();
  578. Quad_Init( quadHandle );
  579. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  580. pQuad->m_ndxParent = parentHandle;
  581. pQuad->m_EditDispHandle = pParentQuad->m_EditDispHandle;
  582. pQuad->m_Level = pParentQuad->m_Level + 1;
  583. switch ( ndxChild )
  584. {
  585. case 0:
  586. {
  587. // displacement quad indices
  588. pQuad->m_QuadIndices[0] = pParentQuad->m_QuadIndices[0];
  589. pQuad->m_QuadIndices[1] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[1] ) * 0.5f;
  590. pQuad->m_QuadIndices[2] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f;
  591. pQuad->m_QuadIndices[3] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[3] ) * 0.5f;
  592. // new verts
  593. SubdivEdge_t *pEdge0 = GetEdge( pParentQuad->m_EdgeHandles[0] );
  594. SubdivEdge_t *pEdge3 = GetEdge( pParentQuad->m_EdgeHandles[3] );
  595. if ( pEdge0 && pEdge3 )
  596. {
  597. pQuad->m_PointHandles[0] = pParentQuad->m_PointHandles[0];
  598. pQuad->m_PointHandles[1] = BuildSubdivPoint( pEdge0->m_vNewEdgePoint, pEdge0->m_vNewEdgeNormal );
  599. pQuad->m_PointHandles[2] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal );
  600. pQuad->m_PointHandles[3] = BuildSubdivPoint( pEdge3->m_vNewEdgePoint, pEdge3->m_vNewEdgeNormal );
  601. }
  602. break;
  603. }
  604. case 1:
  605. {
  606. // displacement quad indices
  607. pQuad->m_QuadIndices[0] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[1] ) * 0.5f;
  608. pQuad->m_QuadIndices[1] = pParentQuad->m_QuadIndices[1];
  609. pQuad->m_QuadIndices[2] = ( pParentQuad->m_QuadIndices[1] + pParentQuad->m_QuadIndices[2] ) * 0.5f;
  610. pQuad->m_QuadIndices[3] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f;
  611. // new verts
  612. SubdivEdge_t *pEdge0 = GetEdge( pParentQuad->m_EdgeHandles[0] );
  613. SubdivEdge_t *pEdge1 = GetEdge( pParentQuad->m_EdgeHandles[1] );
  614. if ( pEdge0 && pEdge1 )
  615. {
  616. pQuad->m_PointHandles[0] = BuildSubdivPoint( pEdge0->m_vNewEdgePoint, pEdge0->m_vNewEdgeNormal );
  617. pQuad->m_PointHandles[1] = pParentQuad->m_PointHandles[1];
  618. pQuad->m_PointHandles[2] = BuildSubdivPoint( pEdge1->m_vNewEdgePoint, pEdge1->m_vNewEdgeNormal );
  619. pQuad->m_PointHandles[3] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal );
  620. }
  621. break;
  622. }
  623. case 2:
  624. {
  625. // displacement quad indices
  626. pQuad->m_QuadIndices[0] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f;
  627. pQuad->m_QuadIndices[1] = ( pParentQuad->m_QuadIndices[1] + pParentQuad->m_QuadIndices[2] ) * 0.5f;
  628. pQuad->m_QuadIndices[2] = pParentQuad->m_QuadIndices[2];
  629. pQuad->m_QuadIndices[3] = ( pParentQuad->m_QuadIndices[2] + pParentQuad->m_QuadIndices[3] ) * 0.5f;
  630. // new verts
  631. SubdivEdge_t *pEdge1 = GetEdge( pParentQuad->m_EdgeHandles[1] );
  632. SubdivEdge_t *pEdge2 = GetEdge( pParentQuad->m_EdgeHandles[2] );
  633. if ( pEdge1 && pEdge2 )
  634. {
  635. pQuad->m_PointHandles[0] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal );
  636. pQuad->m_PointHandles[1] = BuildSubdivPoint( pEdge1->m_vNewEdgePoint, pEdge1->m_vNewEdgeNormal );
  637. pQuad->m_PointHandles[2] = pParentQuad->m_PointHandles[2];
  638. pQuad->m_PointHandles[3] = BuildSubdivPoint( pEdge2->m_vNewEdgePoint, pEdge2->m_vNewEdgeNormal );
  639. }
  640. break;
  641. }
  642. case 3:
  643. {
  644. // displacement quad indices
  645. pQuad->m_QuadIndices[0] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[3] ) * 0.5f;
  646. pQuad->m_QuadIndices[1] = ( pParentQuad->m_QuadIndices[0] + pParentQuad->m_QuadIndices[2] ) * 0.5f;
  647. pQuad->m_QuadIndices[2] = ( pParentQuad->m_QuadIndices[2] + pParentQuad->m_QuadIndices[3] ) * 0.5f;
  648. pQuad->m_QuadIndices[3] = pParentQuad->m_QuadIndices[3];
  649. // new verts
  650. SubdivEdge_t *pEdge2 = GetEdge( pParentQuad->m_EdgeHandles[2] );
  651. SubdivEdge_t *pEdge3 = GetEdge( pParentQuad->m_EdgeHandles[3] );
  652. if ( pEdge2 && pEdge3 )
  653. {
  654. pQuad->m_PointHandles[0] = BuildSubdivPoint( pEdge3->m_vNewEdgePoint, pEdge3->m_vNewEdgeNormal );
  655. pQuad->m_PointHandles[1] = BuildSubdivPoint( pParentQuad->m_vCentroid, pParentQuad->m_vNormal );
  656. pQuad->m_PointHandles[2] = BuildSubdivPoint( pEdge2->m_vNewEdgePoint, pEdge2->m_vNewEdgeNormal );
  657. pQuad->m_PointHandles[3] = pParentQuad->m_PointHandles[3];
  658. }
  659. break;
  660. }
  661. }
  662. //
  663. // buidl new quad edges
  664. //
  665. for ( int ndxEdge = 0; ndxEdge < 4; ndxEdge++ )
  666. {
  667. pQuad->m_EdgeHandles[ndxEdge] = BuildSubdivEdge( ndxEdge, quadHandle, parentHandle, ndxChild );
  668. }
  669. return quadHandle;
  670. }
  671. //-----------------------------------------------------------------------------
  672. // Purpose:
  673. //-----------------------------------------------------------------------------
  674. void CEditDispSubdivMesh::Init( void )
  675. {
  676. // ensure capacity on all lists
  677. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  678. if( !pDispMgr )
  679. return;
  680. int selectCount = pDispMgr->SelectCount();
  681. m_Points.EnsureCapacity( SUBDIV_DISPPOINTS * selectCount );
  682. m_Edges.EnsureCapacity( SUBDIV_DISPEDGES * selectCount );
  683. m_Quads.EnsureCapacity( SUBDIV_DISPQUADS * selectCount );
  684. }
  685. //-----------------------------------------------------------------------------
  686. // Purpose:
  687. //-----------------------------------------------------------------------------
  688. void CEditDispSubdivMesh::Shutdown( void )
  689. {
  690. // clear all lists
  691. m_Points.Purge();
  692. m_Edges.Purge();
  693. m_Quads.Purge();
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Purpose:
  697. //-----------------------------------------------------------------------------
  698. void CEditDispSubdivMesh::AddDispTo( CMapDisp *pDisp )
  699. {
  700. // add a quad to the subdivision mesh
  701. SubdivQuadHandle_t quadHandle = m_Quads.AddToTail();
  702. Quad_Init( quadHandle );
  703. SubdivQuad_t *pQuad = &m_Quads.Element( quadHandle );
  704. // this is the parent!
  705. pQuad->m_ndxParent = m_Quads.InvalidIndex();
  706. pQuad->m_EditDispHandle = pDisp->GetEditHandle();
  707. pQuad->m_Level = 0;
  708. //
  709. // get displacement data
  710. //
  711. int dispWidth = pDisp->GetWidth();
  712. int dispHeight = pDisp->GetHeight();
  713. //
  714. // setup mapping between the displacement size and initial quad indices
  715. //
  716. pQuad->m_QuadIndices[0] = 0;
  717. pQuad->m_QuadIndices[1] = dispWidth * ( dispHeight - 1 );
  718. pQuad->m_QuadIndices[2] = ( dispWidth * dispHeight ) - 1;
  719. pQuad->m_QuadIndices[3] = ( dispWidth - 1 );
  720. //
  721. // find point normals and neighbors -- "smooth"
  722. // NOTE: this is slow -- should write a faster version (is offline process, do later)
  723. //
  724. IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
  725. if( !pDispMgr )
  726. return;
  727. Vector vPoints[4];
  728. Vector vPointNormals[4];
  729. for( int ndxPt = 0; ndxPt < EDITDISP_QUADSIZE; ndxPt++ )
  730. {
  731. // get the base face normal of all surfaces touching this point!
  732. pDisp->GetSurfNormal( vPointNormals[ndxPt] );
  733. // get the point to compare to neighbors
  734. pDisp->GetSurfPoint( ndxPt, vPoints[ndxPt] );
  735. int count = pDispMgr->SelectCount();
  736. for( int ndxSelect = 0; ndxSelect < count; ndxSelect++ )
  737. {
  738. CMapDisp *pSelectDisp = pDispMgr->GetFromSelect( ndxSelect );
  739. if( !pSelectDisp || ( pSelectDisp == pDisp ) )
  740. continue;
  741. for( int ndxPt2 = 0; ndxPt2 < EDITDISP_QUADSIZE; ndxPt2++ )
  742. {
  743. Vector vPoint;
  744. pSelectDisp->GetSurfPoint( ndxPt2, vPoint );
  745. if( CompareSubdivPoints( vPoints[ndxPt], vPoint, 0.01f ) )
  746. {
  747. Vector vNormal;
  748. pSelectDisp->GetSurfNormal( vNormal );
  749. VectorAdd( vPointNormals[ndxPt], vNormal, vPointNormals[ndxPt] );
  750. }
  751. }
  752. }
  753. VectorNormalize( vPointNormals[ndxPt] );
  754. }
  755. // build subdivision points
  756. for( int ndxPt = 0; ndxPt < EDITDISP_QUADSIZE; ndxPt++ )
  757. {
  758. pQuad->m_PointHandles[ndxPt] = BuildSubdivPoint( vPoints[ndxPt], vPointNormals[ndxPt] );
  759. }
  760. // build subdivision edges
  761. for( int ndxEdge = 0; ndxEdge < EDITDISP_QUADSIZE; ndxEdge++ )
  762. {
  763. pQuad->m_EdgeHandles[ndxEdge] = BuildSubdivEdge( ndxEdge, quadHandle, m_Quads.InvalidIndex(), -1 );
  764. }
  765. }
  766. //-----------------------------------------------------------------------------
  767. // Purpose:
  768. //-----------------------------------------------------------------------------
  769. void CEditDispSubdivMesh::GetDispFrom( CMapDisp *pDisp )
  770. {
  771. //
  772. // find the parent quad with the id of the displacement
  773. //
  774. for ( SubdivQuadHandle_t quadHandle = m_Quads.Head(); quadHandle != m_Quads.InvalidIndex();
  775. quadHandle = m_Quads.Next( quadHandle ) )
  776. {
  777. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  778. if ( pQuad )
  779. {
  780. // find children quads that "belong" to this displacement
  781. if( pQuad->m_EditDispHandle != pDisp->GetEditHandle() )
  782. continue;
  783. // get the data at the appropriate level -- (based on the size of the displacement)
  784. if ( pQuad->m_Level != pDisp->GetPower() )
  785. continue;
  786. //
  787. // fill in subdivision positions and normals
  788. //
  789. for ( int ndxPt = 0; ndxPt < 4; ndxPt++ )
  790. {
  791. SubdivPoint_t *pPoint = GetPoint( pQuad->m_PointHandles[ndxPt] );
  792. if ( pPoint )
  793. {
  794. Vector vFlatVert, vSubVert;
  795. pDisp->GetFlatVert( pQuad->m_QuadIndices[ndxPt], vFlatVert );
  796. VectorSubtract( pPoint->m_vPoint, vFlatVert, vSubVert );
  797. pDisp->UpdateVertPositionForSubdiv( pQuad->m_QuadIndices[ndxPt], vSubVert );
  798. pDisp->SetSubdivNormal( pQuad->m_QuadIndices[ndxPt], pPoint->m_vNormal );
  799. }
  800. }
  801. }
  802. }
  803. // tell the dispalcemet to update itself
  804. pDisp->UpdateData();
  805. // reset subdivision/subdivided flags
  806. pDisp->SetReSubdivision( false );
  807. pDisp->SetSubdivided( true );
  808. }
  809. //-----------------------------------------------------------------------------
  810. // Purpose:
  811. //-----------------------------------------------------------------------------
  812. void CEditDispSubdivMesh::DoCatmullClarkSubdivision( void )
  813. {
  814. for ( int ndxLevel = 0; ndxLevel < NUM_SUBDIV_LEVELS; ndxLevel++ )
  815. {
  816. // subdivide
  817. CatmullClarkSubdivision();
  818. // update the subdivision hierarchy (tree)
  819. UpdateSubdivisionHierarchy( ndxLevel );
  820. }
  821. }
  822. //-----------------------------------------------------------------------------
  823. // Purpose:
  824. //-----------------------------------------------------------------------------
  825. void CEditDispSubdivMesh::CatmullClarkSubdivision( void )
  826. {
  827. //
  828. // step 1: calculate the "new edge points" for all edges
  829. //
  830. for ( SubdivEdgeHandle_t edgeHandle = m_Edges.Head(); edgeHandle != m_Edges.InvalidIndex();
  831. edgeHandle = m_Edges.Next( edgeHandle ) )
  832. {
  833. Edge_CalcNewPoint( edgeHandle );
  834. }
  835. //
  836. // step 2: calculate the valence and edge list
  837. //
  838. for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex();
  839. ptHandle = m_Points.Next( ptHandle ) )
  840. {
  841. for ( SubdivEdgeHandle_t edgeHandle = m_Edges.Head(); edgeHandle != m_Edges.InvalidIndex();
  842. edgeHandle = m_Edges.Next( edgeHandle ) )
  843. {
  844. SubdivEdge_t *pEdge = GetEdge( edgeHandle );
  845. if ( !pEdge->m_bActive )
  846. continue;
  847. if ( ( ptHandle == pEdge->m_PointHandles[0] ) || ( ptHandle == pEdge->m_PointHandles[1] ) )
  848. {
  849. SubdivPoint_t *pPoint = GetPoint( ptHandle );
  850. if ( pPoint->m_uValence < ( EDITDISP_QUADSIZE*4 ) )
  851. {
  852. pPoint->m_EdgeHandles[pPoint->m_uValence] = edgeHandle;
  853. pPoint->m_uValence++;
  854. }
  855. }
  856. }
  857. }
  858. //
  859. // step 3: determine the point's Type (Oridinary, Corner, Crease)
  860. //
  861. for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); ptHandle = m_Points.Next( ptHandle ) )
  862. {
  863. SubdivPoint_t *pPoint = GetPoint( ptHandle );
  864. if ( pPoint )
  865. {
  866. int sharpCount = 0;
  867. int sharpThreshold = pPoint->m_uValence - 1;
  868. bool bHasNeighbors = false;
  869. // initialize as oridinary -- determine otherwise
  870. pPoint->m_uType = SUBDIV_POINTORDINARY;
  871. for ( int ndxEdge = 0; ndxEdge < pPoint->m_uValence; ndxEdge++ )
  872. {
  873. SubdivEdge_t *pEdge = GetEdge( pPoint->m_EdgeHandles[ndxEdge] );
  874. if ( pEdge )
  875. {
  876. if ( pEdge->m_flSharpness > 0.0f )
  877. {
  878. sharpCount++;
  879. }
  880. if ( pEdge->m_QuadHandles[1] != m_Quads.InvalidIndex() )
  881. {
  882. bHasNeighbors = true;
  883. }
  884. }
  885. }
  886. if ( !bHasNeighbors || ( sharpCount >= sharpThreshold ) )
  887. {
  888. pPoint->m_uType = SUBDIV_POINTCORNER;
  889. }
  890. else if( sharpCount > 1 )
  891. {
  892. pPoint->m_uType = SUBDIV_POINTCREASE;
  893. }
  894. }
  895. }
  896. //
  897. // step 4: calculate the "new points" for all points
  898. //
  899. for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); ptHandle = m_Points.Next( ptHandle ) )
  900. {
  901. Point_CalcNewPoint( ptHandle );
  902. }
  903. //
  904. // step 5: copy all "new point" data to point data
  905. //
  906. for ( SubdivPointHandle_t ptHandle = m_Points.Head(); ptHandle != m_Points.InvalidIndex(); ptHandle = m_Points.Next( ptHandle ) )
  907. {
  908. SubdivPoint_t *pPoint = GetPoint( ptHandle );
  909. VectorCopy( pPoint->m_vNewPoint, pPoint->m_vPoint );
  910. VectorCopy( pPoint->m_vNewNormal, pPoint->m_vNewNormal );
  911. VectorClear( pPoint->m_vNewPoint );
  912. VectorClear( pPoint->m_vNewNormal );
  913. // reset valence
  914. pPoint->m_uValence = 0;
  915. }
  916. }
  917. //-----------------------------------------------------------------------------
  918. // Purpose:
  919. //-----------------------------------------------------------------------------
  920. void CEditDispSubdivMesh::UpdateSubdivisionHierarchy( int ndxLevel )
  921. {
  922. int quadCount = m_Quads.Count();
  923. SubdivQuadHandle_t quadHandle = m_Quads.Head();
  924. int ndxQuad = 0;
  925. while ( ( quadHandle != m_Quads.InvalidIndex() ) && ( ndxQuad < quadCount ) )
  926. {
  927. SubdivQuad_t *pQuad = GetQuad( quadHandle );
  928. if ( pQuad )
  929. {
  930. // skip parent quads
  931. if ( pQuad->m_ndxChild[0] != m_Quads.InvalidIndex() )
  932. {
  933. ndxQuad++;
  934. quadHandle = m_Quads.Next( quadHandle );
  935. continue;
  936. }
  937. for( int ndxChild = 0; ndxChild < 4; ndxChild++ )
  938. {
  939. pQuad->m_ndxChild[ndxChild] = BuildSubdivQuad( ndxChild, quadHandle );
  940. }
  941. // de-activate all edges (children's edges are active now!)
  942. for ( int ndxEdge = 0; ndxEdge < 4; ndxEdge++ )
  943. {
  944. SubdivEdge_t *pEdge = GetEdge( pQuad->m_EdgeHandles[ndxEdge] );
  945. if ( pEdge )
  946. {
  947. pEdge->m_bActive = false;
  948. }
  949. }
  950. }
  951. ndxQuad++;
  952. quadHandle = m_Quads.Next( quadHandle );
  953. }
  954. }