Team Fortress 2 Source Code as on 22/4/2020
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.

2293 lines
89 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "mathlib/polyhedron.h"
  9. #include "mathlib/vmatrix.h"
  10. #include <stdlib.h>
  11. #include <stdio.h>
  12. #include "tier1/utlvector.h"
  13. struct GeneratePolyhedronFromPlanes_Point;
  14. struct GeneratePolyhedronFromPlanes_PointLL;
  15. struct GeneratePolyhedronFromPlanes_Line;
  16. struct GeneratePolyhedronFromPlanes_LineLL;
  17. struct GeneratePolyhedronFromPlanes_Polygon;
  18. struct GeneratePolyhedronFromPlanes_PolygonLL;
  19. struct GeneratePolyhedronFromPlanes_UnorderedPointLL;
  20. struct GeneratePolyhedronFromPlanes_UnorderedLineLL;
  21. struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL;
  22. Vector FindPointInPlanes( const float *pPlanes, int planeCount );
  23. bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs );
  24. CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory );
  25. CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory );
  26. //#define ENABLE_DEBUG_POLYHEDRON_DUMPS //Dumps debug information to disk for use with glview. Requires that tier2 also be in all projects using debug mathlib
  27. //#define DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS //dumps successfully generated polyhedrons
  28. #ifdef _DEBUG
  29. void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform );
  30. void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform );
  31. void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile );
  32. void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile );
  33. #if defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( WIN32 )
  34. #include "winlite.h"
  35. #endif
  36. static VMatrix s_matIdentity( 1.0f, 0.0f, 0.0f, 0.0f,
  37. 0.0f, 1.0f, 0.0f, 0.0f,
  38. 0.0f, 0.0f, 1.0f, 0.0f,
  39. 0.0f, 0.0f, 0.0f, 1.0f );
  40. #endif
  41. #if defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS )
  42. static int g_iPolyhedronDumpCounter = 0;
  43. #endif
  44. // memdbgon must be the last include file in a .cpp file!!!
  45. #include "tier0/memdbgon.h"
  46. #if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  47. void CreateDumpDirectory( const char *szDirectoryName )
  48. {
  49. #if defined( WIN32 )
  50. CreateDirectory( szDirectoryName, NULL );
  51. #else
  52. Assert( false ); //TODO: create directories in linux
  53. #endif
  54. }
  55. #endif
  56. void CPolyhedron_AllocByNew::Release( void )
  57. {
  58. delete this;
  59. }
  60. CPolyhedron_AllocByNew *CPolyhedron_AllocByNew::Allocate( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ) //creates the polyhedron along with enough memory to hold all it's data in a single allocation
  61. {
  62. void *pMemory = new unsigned char [ sizeof( CPolyhedron_AllocByNew ) +
  63. (iVertices * sizeof(Vector)) +
  64. (iLines * sizeof(Polyhedron_IndexedLine_t)) +
  65. (iIndices * sizeof( Polyhedron_IndexedLineReference_t )) +
  66. (iPolygons * sizeof( Polyhedron_IndexedPolygon_t ))];
  67. #include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging
  68. CPolyhedron_AllocByNew *pAllocated = new ( pMemory ) CPolyhedron_AllocByNew;
  69. #include "tier0/memdbgon.h"
  70. pAllocated->iVertexCount = iVertices;
  71. pAllocated->iLineCount = iLines;
  72. pAllocated->iIndexCount = iIndices;
  73. pAllocated->iPolygonCount = iPolygons;
  74. pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class
  75. pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices);
  76. pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines);
  77. pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices);
  78. return pAllocated;
  79. }
  80. class CPolyhedron_TempMemory : public CPolyhedron
  81. {
  82. public:
  83. #ifdef DBGFLAG_ASSERT
  84. int iReferenceCount;
  85. #endif
  86. virtual void Release( void )
  87. {
  88. #ifdef DBGFLAG_ASSERT
  89. --iReferenceCount;
  90. #endif
  91. }
  92. CPolyhedron_TempMemory( void )
  93. #ifdef DBGFLAG_ASSERT
  94. : iReferenceCount( 0 )
  95. #endif
  96. { };
  97. };
  98. static CUtlVector<unsigned char> s_TempMemoryPolyhedron_Buffer;
  99. static CPolyhedron_TempMemory s_TempMemoryPolyhedron;
  100. CPolyhedron *GetTempPolyhedron( unsigned short iVertices, unsigned short iLines, unsigned short iIndices, unsigned short iPolygons ) //grab the temporary polyhedron. Avoids new/delete for quick work. Can only be in use by one chunk of code at a time
  101. {
  102. AssertMsg( s_TempMemoryPolyhedron.iReferenceCount == 0, "Temporary polyhedron memory being rewritten before released" );
  103. #ifdef DBGFLAG_ASSERT
  104. ++s_TempMemoryPolyhedron.iReferenceCount;
  105. #endif
  106. s_TempMemoryPolyhedron_Buffer.SetCount( (sizeof( Vector ) * iVertices) +
  107. (sizeof( Polyhedron_IndexedLine_t ) * iLines) +
  108. (sizeof( Polyhedron_IndexedLineReference_t ) * iIndices) +
  109. (sizeof( Polyhedron_IndexedPolygon_t ) * iPolygons) );
  110. s_TempMemoryPolyhedron.iVertexCount = iVertices;
  111. s_TempMemoryPolyhedron.iLineCount = iLines;
  112. s_TempMemoryPolyhedron.iIndexCount = iIndices;
  113. s_TempMemoryPolyhedron.iPolygonCount = iPolygons;
  114. s_TempMemoryPolyhedron.pVertices = (Vector *)s_TempMemoryPolyhedron_Buffer.Base();
  115. s_TempMemoryPolyhedron.pLines = (Polyhedron_IndexedLine_t *)(&s_TempMemoryPolyhedron.pVertices[s_TempMemoryPolyhedron.iVertexCount]);
  116. s_TempMemoryPolyhedron.pIndices = (Polyhedron_IndexedLineReference_t *)(&s_TempMemoryPolyhedron.pLines[s_TempMemoryPolyhedron.iLineCount]);
  117. s_TempMemoryPolyhedron.pPolygons = (Polyhedron_IndexedPolygon_t *)(&s_TempMemoryPolyhedron.pIndices[s_TempMemoryPolyhedron.iIndexCount]);
  118. return &s_TempMemoryPolyhedron;
  119. }
  120. Vector CPolyhedron::Center( void )
  121. {
  122. if( iVertexCount == 0 )
  123. return vec3_origin;
  124. Vector vAABBMin, vAABBMax;
  125. vAABBMin = vAABBMax = pVertices[0];
  126. for( int i = 1; i != iVertexCount; ++i )
  127. {
  128. Vector &vPoint = pVertices[i];
  129. if( vPoint.x < vAABBMin.x )
  130. vAABBMin.x = vPoint.x;
  131. if( vPoint.y < vAABBMin.y )
  132. vAABBMin.y = vPoint.y;
  133. if( vPoint.z < vAABBMin.z )
  134. vAABBMin.z = vPoint.z;
  135. if( vPoint.x > vAABBMax.x )
  136. vAABBMax.x = vPoint.x;
  137. if( vPoint.y > vAABBMax.y )
  138. vAABBMax.y = vPoint.y;
  139. if( vPoint.z > vAABBMax.z )
  140. vAABBMax.z = vPoint.z;
  141. }
  142. return ((vAABBMin + vAABBMax) * 0.5f);
  143. }
  144. enum PolyhedronPointPlanarity
  145. {
  146. POINT_DEAD,
  147. POINT_ONPLANE,
  148. POINT_ALIVE
  149. };
  150. struct GeneratePolyhedronFromPlanes_Point
  151. {
  152. Vector ptPosition;
  153. GeneratePolyhedronFromPlanes_LineLL *pConnectedLines; //keep these in a clockwise order, circular linking
  154. float fPlaneDist; //used in plane cutting
  155. PolyhedronPointPlanarity planarity;
  156. int iSaveIndices;
  157. };
  158. struct GeneratePolyhedronFromPlanes_Line
  159. {
  160. GeneratePolyhedronFromPlanes_Point *pPoints[2]; //the 2 connecting points in no particular order
  161. GeneratePolyhedronFromPlanes_Polygon *pPolygons[2]; //viewing from the outside with the point connections going up, 0 is the left polygon, 1 is the right
  162. int iSaveIndices;
  163. bool bAlive; //connected to at least one living point
  164. bool bCut; //connected to at least one dead point
  165. GeneratePolyhedronFromPlanes_LineLL *pPointLineLinks[2]; //rather than going into a point and searching for its link to this line, lets just cache it to eliminate searching
  166. GeneratePolyhedronFromPlanes_LineLL *pPolygonLineLinks[2]; //rather than going into a polygon and searching for its link to this line, lets just cache it to eliminate searching
  167. #ifdef POLYHEDRON_EXTENSIVE_DEBUGGING
  168. int iDebugFlags;
  169. #endif
  170. };
  171. struct GeneratePolyhedronFromPlanes_LineLL
  172. {
  173. GeneratePolyhedronFromPlanes_Line *pLine;
  174. int iReferenceIndex; //whatever is referencing the line should know which side of the line it's on (points and polygons), for polygons, it's which point to follow to continue going clockwise, which makes polygon 0 the one on the left side of an upward facing line vector, for points, it's the OTHER point's index
  175. GeneratePolyhedronFromPlanes_LineLL *pPrev;
  176. GeneratePolyhedronFromPlanes_LineLL *pNext;
  177. };
  178. struct GeneratePolyhedronFromPlanes_Polygon
  179. {
  180. Vector vSurfaceNormal;
  181. GeneratePolyhedronFromPlanes_LineLL *pLines; //keep these in a clockwise order, circular linking
  182. bool bMissingASide;
  183. };
  184. struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL //an unordered collection of polygons
  185. {
  186. GeneratePolyhedronFromPlanes_Polygon *pPolygon;
  187. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNext;
  188. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPrev;
  189. };
  190. struct GeneratePolyhedronFromPlanes_UnorderedLineLL //an unordered collection of lines
  191. {
  192. GeneratePolyhedronFromPlanes_Line *pLine;
  193. GeneratePolyhedronFromPlanes_UnorderedLineLL *pNext;
  194. GeneratePolyhedronFromPlanes_UnorderedLineLL *pPrev;
  195. };
  196. struct GeneratePolyhedronFromPlanes_UnorderedPointLL //an unordered collection of points
  197. {
  198. GeneratePolyhedronFromPlanes_Point *pPoint;
  199. GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext;
  200. GeneratePolyhedronFromPlanes_UnorderedPointLL *pPrev;
  201. };
  202. CPolyhedron *ClipPolyhedron( const CPolyhedron *pExistingPolyhedron, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory )
  203. {
  204. if( pExistingPolyhedron == NULL )
  205. return NULL;
  206. AssertMsg( (pExistingPolyhedron->iVertexCount >= 3) && (pExistingPolyhedron->iPolygonCount >= 2), "Polyhedron doesn't meet absolute minimum spec" );
  207. float *pUsefulPlanes = (float *)stackalloc( sizeof( float ) * 4 * iPlaneCount );
  208. int iUsefulPlaneCount = 0;
  209. Vector *pExistingVertices = pExistingPolyhedron->pVertices;
  210. //A large part of clipping will either eliminate the polyhedron entirely, or clip nothing at all, so lets just check for those first and throw away useless planes
  211. {
  212. int iLiveCount = 0;
  213. int iDeadCount = 0;
  214. const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon;
  215. for( int i = 0; i != iPlaneCount; ++i )
  216. {
  217. Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(i * 4) + 0]);
  218. float fPlaneDist = pOutwardFacingPlanes[(i * 4) + 3];
  219. for( int j = 0; j != pExistingPolyhedron->iVertexCount; ++j )
  220. {
  221. float fPointDist = vNormal.Dot( pExistingVertices[j] ) - fPlaneDist;
  222. if( fPointDist <= fNegativeOnPlaneEpsilon )
  223. ++iLiveCount;
  224. else if( fPointDist > fOnPlaneEpsilon )
  225. ++iDeadCount;
  226. }
  227. if( iLiveCount == 0 )
  228. {
  229. //all points are dead or on the plane, so the polyhedron is dead
  230. return NULL;
  231. }
  232. if( iDeadCount != 0 )
  233. {
  234. //at least one point died, this plane yields useful results
  235. pUsefulPlanes[(iUsefulPlaneCount * 4) + 0] = vNormal.x;
  236. pUsefulPlanes[(iUsefulPlaneCount * 4) + 1] = vNormal.y;
  237. pUsefulPlanes[(iUsefulPlaneCount * 4) + 2] = vNormal.z;
  238. pUsefulPlanes[(iUsefulPlaneCount * 4) + 3] = fPlaneDist;
  239. ++iUsefulPlaneCount;
  240. }
  241. }
  242. }
  243. if( iUsefulPlaneCount == 0 )
  244. {
  245. //testing shows that the polyhedron won't even be cut, clone the existing polyhedron and return that
  246. CPolyhedron *pReturn;
  247. if( bUseTemporaryMemory )
  248. {
  249. pReturn = GetTempPolyhedron( pExistingPolyhedron->iVertexCount,
  250. pExistingPolyhedron->iLineCount,
  251. pExistingPolyhedron->iIndexCount,
  252. pExistingPolyhedron->iPolygonCount );
  253. }
  254. else
  255. {
  256. pReturn = CPolyhedron_AllocByNew::Allocate( pExistingPolyhedron->iVertexCount,
  257. pExistingPolyhedron->iLineCount,
  258. pExistingPolyhedron->iIndexCount,
  259. pExistingPolyhedron->iPolygonCount );
  260. }
  261. memcpy( pReturn->pVertices, pExistingPolyhedron->pVertices, sizeof( Vector ) * pReturn->iVertexCount );
  262. memcpy( pReturn->pLines, pExistingPolyhedron->pLines, sizeof( Polyhedron_IndexedLine_t ) * pReturn->iLineCount );
  263. memcpy( pReturn->pIndices, pExistingPolyhedron->pIndices, sizeof( Polyhedron_IndexedLineReference_t ) * pReturn->iIndexCount );
  264. memcpy( pReturn->pPolygons, pExistingPolyhedron->pPolygons, sizeof( Polyhedron_IndexedPolygon_t ) * pReturn->iPolygonCount );
  265. return pReturn;
  266. }
  267. //convert the polyhedron to linked geometry
  268. GeneratePolyhedronFromPlanes_Point *pStartPoints = (GeneratePolyhedronFromPlanes_Point *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_Point ) );
  269. GeneratePolyhedronFromPlanes_Line *pStartLines = (GeneratePolyhedronFromPlanes_Line *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_Line ) );
  270. GeneratePolyhedronFromPlanes_Polygon *pStartPolygons = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_Polygon ) );
  271. GeneratePolyhedronFromPlanes_LineLL *pStartLineLinks = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( pExistingPolyhedron->iLineCount * 4 * sizeof( GeneratePolyhedronFromPlanes_LineLL ) );
  272. int iCurrentLineLinkIndex = 0;
  273. //setup points
  274. for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i )
  275. {
  276. pStartPoints[i].ptPosition = pExistingPolyhedron->pVertices[i];
  277. pStartPoints[i].pConnectedLines = NULL; //we won't be circular linking until later
  278. }
  279. //setup lines and interlink to points (line links are not yet circularly linked, and are unordered)
  280. for( int i = 0; i != pExistingPolyhedron->iLineCount; ++i )
  281. {
  282. for( int j = 0; j != 2; ++j )
  283. {
  284. pStartLines[i].pPoints[j] = &pStartPoints[pExistingPolyhedron->pLines[i].iPointIndices[j]];
  285. GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++];
  286. pStartLines[i].pPointLineLinks[j] = pLineLink;
  287. pLineLink->pLine = &pStartLines[i];
  288. pLineLink->iReferenceIndex = 1 - j;
  289. //pLineLink->pPrev = NULL;
  290. pLineLink->pNext = pStartLines[i].pPoints[j]->pConnectedLines;
  291. pStartLines[i].pPoints[j]->pConnectedLines = pLineLink;
  292. }
  293. }
  294. //setup polygons
  295. for( int i = 0; i != pExistingPolyhedron->iPolygonCount; ++i )
  296. {
  297. pStartPolygons[i].vSurfaceNormal = pExistingPolyhedron->pPolygons[i].polyNormal;
  298. Polyhedron_IndexedLineReference_t *pOffsetPolyhedronLines = &pExistingPolyhedron->pIndices[pExistingPolyhedron->pPolygons[i].iFirstIndex];
  299. GeneratePolyhedronFromPlanes_LineLL *pFirstLink = &pStartLineLinks[iCurrentLineLinkIndex];
  300. pStartPolygons[i].pLines = pFirstLink; //technically going to link to itself on first pass, then get linked properly immediately afterward
  301. for( int j = 0; j != pExistingPolyhedron->pPolygons[i].iIndexCount; ++j )
  302. {
  303. GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++];
  304. pLineLink->pLine = &pStartLines[pOffsetPolyhedronLines[j].iLineIndex];
  305. pLineLink->iReferenceIndex = pOffsetPolyhedronLines[j].iEndPointIndex;
  306. pLineLink->pLine->pPolygons[pLineLink->iReferenceIndex] = &pStartPolygons[i];
  307. pLineLink->pLine->pPolygonLineLinks[pLineLink->iReferenceIndex] = pLineLink;
  308. pLineLink->pPrev = pStartPolygons[i].pLines;
  309. pStartPolygons[i].pLines->pNext = pLineLink;
  310. pStartPolygons[i].pLines = pLineLink;
  311. }
  312. pFirstLink->pPrev = pStartPolygons[i].pLines;
  313. pStartPolygons[i].pLines->pNext = pFirstLink;
  314. }
  315. Assert( iCurrentLineLinkIndex == (pExistingPolyhedron->iLineCount * 4) );
  316. //go back to point line links so we can circularly link them as well as order them now that every point has all its line links
  317. for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i )
  318. {
  319. //interlink the points
  320. {
  321. GeneratePolyhedronFromPlanes_LineLL *pLastVisitedLink = pStartPoints[i].pConnectedLines;
  322. GeneratePolyhedronFromPlanes_LineLL *pCurrentLink = pLastVisitedLink;
  323. do
  324. {
  325. pCurrentLink->pPrev = pLastVisitedLink;
  326. pLastVisitedLink = pCurrentLink;
  327. pCurrentLink = pCurrentLink->pNext;
  328. } while( pCurrentLink );
  329. //circular link
  330. pLastVisitedLink->pNext = pStartPoints[i].pConnectedLines;
  331. pStartPoints[i].pConnectedLines->pPrev = pLastVisitedLink;
  332. }
  333. //fix ordering
  334. GeneratePolyhedronFromPlanes_LineLL *pFirstLink = pStartPoints[i].pConnectedLines;
  335. GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pFirstLink;
  336. GeneratePolyhedronFromPlanes_LineLL *pSearchLink;
  337. GeneratePolyhedronFromPlanes_Polygon *pLookingForPolygon;
  338. Assert( pFirstLink->pNext != pFirstLink );
  339. do
  340. {
  341. pLookingForPolygon = pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex]; //grab pointer to left polygon
  342. pSearchLink = pWorkLink->pPrev;
  343. while( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] != pLookingForPolygon )
  344. pSearchLink = pSearchLink->pPrev;
  345. Assert( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] == pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex] );
  346. //pluck the search link from wherever it is
  347. pSearchLink->pPrev->pNext = pSearchLink->pNext;
  348. pSearchLink->pNext->pPrev = pSearchLink->pPrev;
  349. //insert the search link just before the work link
  350. pSearchLink->pPrev = pWorkLink->pPrev;
  351. pSearchLink->pNext = pWorkLink;
  352. pSearchLink->pPrev->pNext = pSearchLink;
  353. pWorkLink->pPrev = pSearchLink;
  354. pWorkLink = pSearchLink;
  355. } while( pWorkLink != pFirstLink );
  356. }
  357. GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) );
  358. GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) );
  359. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) );
  360. //setup point collection
  361. {
  362. pPoints[0].pPrev = NULL;
  363. pPoints[0].pPoint = &pStartPoints[0];
  364. pPoints[0].pNext = &pPoints[1];
  365. int iLastPoint = pExistingPolyhedron->iVertexCount - 1;
  366. for( int i = 1; i != iLastPoint; ++i )
  367. {
  368. pPoints[i].pPrev = &pPoints[i - 1];
  369. pPoints[i].pPoint = &pStartPoints[i];
  370. pPoints[i].pNext = &pPoints[i + 1];
  371. }
  372. pPoints[iLastPoint].pPrev = &pPoints[iLastPoint - 1];
  373. pPoints[iLastPoint].pPoint = &pStartPoints[iLastPoint];
  374. pPoints[iLastPoint].pNext = NULL;
  375. }
  376. //setup line collection
  377. {
  378. pLines[0].pPrev = NULL;
  379. pLines[0].pLine = &pStartLines[0];
  380. pLines[0].pNext = &pLines[1];
  381. int iLastLine = pExistingPolyhedron->iLineCount - 1;
  382. for( int i = 1; i != iLastLine; ++i )
  383. {
  384. pLines[i].pPrev = &pLines[i - 1];
  385. pLines[i].pLine = &pStartLines[i];
  386. pLines[i].pNext = &pLines[i + 1];
  387. }
  388. pLines[iLastLine].pPrev = &pLines[iLastLine - 1];
  389. pLines[iLastLine].pLine = &pStartLines[iLastLine];
  390. pLines[iLastLine].pNext = NULL;
  391. }
  392. //setup polygon collection
  393. {
  394. pPolygons[0].pPrev = NULL;
  395. pPolygons[0].pPolygon = &pStartPolygons[0];
  396. pPolygons[0].pNext = &pPolygons[1];
  397. int iLastPolygon = pExistingPolyhedron->iPolygonCount - 1;
  398. for( int i = 1; i != iLastPolygon; ++i )
  399. {
  400. pPolygons[i].pPrev = &pPolygons[i - 1];
  401. pPolygons[i].pPolygon = &pStartPolygons[i];
  402. pPolygons[i].pNext = &pPolygons[i + 1];
  403. }
  404. pPolygons[iLastPolygon].pPrev = &pPolygons[iLastPolygon - 1];
  405. pPolygons[iLastPolygon].pPolygon = &pStartPolygons[iLastPolygon];
  406. pPolygons[iLastPolygon].pNext = NULL;
  407. }
  408. return ClipLinkedGeometry( pPolygons, pLines, pPoints, pUsefulPlanes, iUsefulPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory );
  409. }
  410. Vector FindPointInPlanes( const float *pPlanes, int planeCount )
  411. {
  412. Vector point = vec3_origin;
  413. for ( int i = 0; i < planeCount; i++ )
  414. {
  415. float fD = DotProduct( *(Vector *)&pPlanes[i*4], point ) - pPlanes[i*4 + 3];
  416. if ( fD < 0 )
  417. {
  418. point -= fD * (*(Vector *)&pPlanes[i*4]);
  419. }
  420. }
  421. return point;
  422. }
  423. bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ) //bounding box of the convex shape (subject to floating point error)
  424. {
  425. //returns false if the AABB hasn't been set
  426. if( pAABBMins == NULL && pAABBMaxs == NULL ) //no use in actually finding out what it is
  427. return false;
  428. struct FindConvexShapeAABB_Polygon_t
  429. {
  430. float *verts;
  431. int iVertCount;
  432. };
  433. float *pMovedPlanes = (float *)stackalloc( iPlaneCount * 4 * sizeof( float ) );
  434. //Vector vPointInPlanes = FindPointInPlanes( pInwardFacingPlanes, iPlaneCount );
  435. for( int i = 0; i != iPlaneCount; ++i )
  436. {
  437. pMovedPlanes[(i * 4) + 0] = pInwardFacingPlanes[(i * 4) + 0];
  438. pMovedPlanes[(i * 4) + 1] = pInwardFacingPlanes[(i * 4) + 1];
  439. pMovedPlanes[(i * 4) + 2] = pInwardFacingPlanes[(i * 4) + 2];
  440. pMovedPlanes[(i * 4) + 3] = pInwardFacingPlanes[(i * 4) + 3] - 100.0f; //move planes out a lot to kill some imprecision problems
  441. }
  442. //vAABBMins = vAABBMaxs = FindPointInPlanes( pPlanes, iPlaneCount );
  443. float *vertsIn = NULL; //we'll be allocating a new buffer for this with each new polygon, and moving it off to the polygon array
  444. float *vertsOut = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) ); //each plane will initially have 4 points in its polygon representation, and each plane clip has the possibility to add 1 point to the polygon
  445. float *vertsSwap;
  446. FindConvexShapeAABB_Polygon_t *pPolygons = (FindConvexShapeAABB_Polygon_t *)stackalloc( iPlaneCount * sizeof( FindConvexShapeAABB_Polygon_t ) );
  447. int iPolyCount = 0;
  448. for ( int i = 0; i < iPlaneCount; i++ )
  449. {
  450. Vector *pPlaneNormal = (Vector *)&pInwardFacingPlanes[i*4];
  451. float fPlaneDist = pInwardFacingPlanes[(i*4) + 3];
  452. if( vertsIn == NULL )
  453. vertsIn = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) );
  454. // Build a big-ass poly in this plane
  455. int vertCount = PolyFromPlane( (Vector *)vertsIn, *pPlaneNormal, fPlaneDist, 100000.0f );
  456. //chop it by every other plane
  457. for( int j = 0; j < iPlaneCount; j++ )
  458. {
  459. // don't clip planes with themselves
  460. if ( i == j )
  461. continue;
  462. // Chop the polygon against this plane
  463. vertCount = ClipPolyToPlane( (Vector *)vertsIn, vertCount, (Vector *)vertsOut, *(Vector *)&pMovedPlanes[j*4], pMovedPlanes[(j*4) + 3], 0.0f );
  464. //swap the input and output arrays
  465. vertsSwap = vertsIn; vertsIn = vertsOut; vertsOut = vertsSwap;
  466. // Less than a poly left, something's wrong, don't bother with this polygon
  467. if ( vertCount < 3 )
  468. break;
  469. }
  470. if ( vertCount < 3 )
  471. continue; //not enough to work with
  472. pPolygons[iPolyCount].iVertCount = vertCount;
  473. pPolygons[iPolyCount].verts = vertsIn;
  474. vertsIn = NULL;
  475. ++iPolyCount;
  476. }
  477. if( iPolyCount == 0 )
  478. return false;
  479. //initialize the AABB to the first point available
  480. Vector vAABBMins, vAABBMaxs;
  481. vAABBMins = vAABBMaxs = ((Vector *)pPolygons[0].verts)[0];
  482. if( pAABBMins && pAABBMaxs ) //they want the full box
  483. {
  484. for( int i = 0; i != iPolyCount; ++i )
  485. {
  486. Vector *PolyVerts = (Vector *)pPolygons[i].verts;
  487. for( int j = 0; j != pPolygons[i].iVertCount; ++j )
  488. {
  489. if( PolyVerts[j].x < vAABBMins.x )
  490. vAABBMins.x = PolyVerts[j].x;
  491. if( PolyVerts[j].y < vAABBMins.y )
  492. vAABBMins.y = PolyVerts[j].y;
  493. if( PolyVerts[j].z < vAABBMins.z )
  494. vAABBMins.z = PolyVerts[j].z;
  495. if( PolyVerts[j].x > vAABBMaxs.x )
  496. vAABBMaxs.x = PolyVerts[j].x;
  497. if( PolyVerts[j].y > vAABBMaxs.y )
  498. vAABBMaxs.y = PolyVerts[j].y;
  499. if( PolyVerts[j].z > vAABBMaxs.z )
  500. vAABBMaxs.z = PolyVerts[j].z;
  501. }
  502. }
  503. *pAABBMins = vAABBMins;
  504. *pAABBMaxs = vAABBMaxs;
  505. }
  506. else if( pAABBMins ) //they only want the min
  507. {
  508. for( int i = 0; i != iPolyCount; ++i )
  509. {
  510. Vector *PolyVerts = (Vector *)pPolygons[i].verts;
  511. for( int j = 0; j != pPolygons[i].iVertCount; ++j )
  512. {
  513. if( PolyVerts[j].x < vAABBMins.x )
  514. vAABBMins.x = PolyVerts[j].x;
  515. if( PolyVerts[j].y < vAABBMins.y )
  516. vAABBMins.y = PolyVerts[j].y;
  517. if( PolyVerts[j].z < vAABBMins.z )
  518. vAABBMins.z = PolyVerts[j].z;
  519. }
  520. }
  521. *pAABBMins = vAABBMins;
  522. }
  523. else //they only want the max
  524. {
  525. for( int i = 0; i != iPolyCount; ++i )
  526. {
  527. Vector *PolyVerts = (Vector *)pPolygons[i].verts;
  528. for( int j = 0; j != pPolygons[i].iVertCount; ++j )
  529. {
  530. if( PolyVerts[j].x > vAABBMaxs.x )
  531. vAABBMaxs.x = PolyVerts[j].x;
  532. if( PolyVerts[j].y > vAABBMaxs.y )
  533. vAABBMaxs.y = PolyVerts[j].y;
  534. if( PolyVerts[j].z > vAABBMaxs.z )
  535. vAABBMaxs.z = PolyVerts[j].z;
  536. }
  537. }
  538. *pAABBMaxs = vAABBMaxs;
  539. }
  540. return true;
  541. }
  542. CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory )
  543. {
  544. Assert( (pPolygons != NULL) && (pLines != NULL) && (pPoints != NULL) );
  545. unsigned int iPolyCount = 0, iLineCount = 0, iPointCount = 0, iIndexCount = 0;
  546. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pPolygons;
  547. do
  548. {
  549. ++iPolyCount;
  550. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines;
  551. GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk;
  552. Assert( pLineWalk != NULL );
  553. do
  554. {
  555. ++iIndexCount;
  556. pLineWalk = pLineWalk->pNext;
  557. } while( pLineWalk != pFirstLine );
  558. pActivePolygonWalk = pActivePolygonWalk->pNext;
  559. } while( pActivePolygonWalk );
  560. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pLines;
  561. do
  562. {
  563. ++iLineCount;
  564. pActiveLineWalk = pActiveLineWalk->pNext;
  565. } while( pActiveLineWalk );
  566. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pPoints;
  567. do
  568. {
  569. ++iPointCount;
  570. pActivePointWalk = pActivePointWalk->pNext;
  571. } while( pActivePointWalk );
  572. CPolyhedron *pReturn;
  573. if( bUseTemporaryMemory )
  574. {
  575. pReturn = GetTempPolyhedron( iPointCount, iLineCount, iIndexCount, iPolyCount );
  576. }
  577. else
  578. {
  579. pReturn = CPolyhedron_AllocByNew::Allocate( iPointCount, iLineCount, iIndexCount, iPolyCount );
  580. }
  581. Vector *pVertexArray = pReturn->pVertices;
  582. Polyhedron_IndexedLine_t *pLineArray = pReturn->pLines;
  583. Polyhedron_IndexedLineReference_t *pIndexArray = pReturn->pIndices;
  584. Polyhedron_IndexedPolygon_t *pPolyArray = pReturn->pPolygons;
  585. //copy points
  586. pActivePointWalk = pPoints;
  587. for( unsigned int i = 0; i != iPointCount; ++i )
  588. {
  589. pVertexArray[i] = pActivePointWalk->pPoint->ptPosition;
  590. pActivePointWalk->pPoint->iSaveIndices = i; //storing array indices
  591. pActivePointWalk = pActivePointWalk->pNext;
  592. }
  593. //copy lines
  594. pActiveLineWalk = pLines;
  595. for( unsigned int i = 0; i != iLineCount; ++i )
  596. {
  597. pLineArray[i].iPointIndices[0] = (unsigned short)pActiveLineWalk->pLine->pPoints[0]->iSaveIndices;
  598. pLineArray[i].iPointIndices[1] = (unsigned short)pActiveLineWalk->pLine->pPoints[1]->iSaveIndices;
  599. pActiveLineWalk->pLine->iSaveIndices = i; //storing array indices
  600. pActiveLineWalk = pActiveLineWalk->pNext;
  601. }
  602. //copy polygons and indices at the same time
  603. pActivePolygonWalk = pPolygons;
  604. iIndexCount = 0;
  605. for( unsigned int i = 0; i != iPolyCount; ++i )
  606. {
  607. pPolyArray[i].polyNormal = pActivePolygonWalk->pPolygon->vSurfaceNormal;
  608. pPolyArray[i].iFirstIndex = iIndexCount;
  609. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines;
  610. GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk;
  611. do
  612. {
  613. //pIndexArray[iIndexCount] = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->iWorkData; //startpoint of each line, iWorkData is the index of the vertex
  614. pIndexArray[iIndexCount].iLineIndex = pLineWalk->pLine->iSaveIndices;
  615. pIndexArray[iIndexCount].iEndPointIndex = pLineWalk->iReferenceIndex;
  616. ++iIndexCount;
  617. pLineWalk = pLineWalk->pNext;
  618. } while( pLineWalk != pFirstLine );
  619. pPolyArray[i].iIndexCount = iIndexCount - pPolyArray[i].iFirstIndex;
  620. pActivePolygonWalk = pActivePolygonWalk->pNext;
  621. }
  622. #if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS )
  623. char szCollisionFile[128];
  624. CreateDumpDirectory( "PolyhedronDumps" );
  625. Q_snprintf( szCollisionFile, 128, "PolyhedronDumps/NewStyle_PolyhedronDump%i.txt", g_iPolyhedronDumpCounter );
  626. ++g_iPolyhedronDumpCounter;
  627. remove( szCollisionFile );
  628. DumpPolyhedronToGLView( pReturn, szCollisionFile, &s_matIdentity );
  629. DumpPolyhedronToGLView( pReturn, "PolyhedronDumps/NewStyle_PolyhedronDump_All-Appended.txt", &s_matIdentity );
  630. #endif
  631. return pReturn;
  632. }
  633. #ifdef _DEBUG
  634. void DumpPointListToGLView( GeneratePolyhedronFromPlanes_UnorderedPointLL *pHead, PolyhedronPointPlanarity planarity, const Vector &vColor, const char *szDumpFile, const VMatrix *pTransform )
  635. {
  636. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  637. if( pTransform == NULL )
  638. pTransform = &s_matIdentity;
  639. FILE *pFile = fopen( szDumpFile, "ab" );
  640. while( pHead )
  641. {
  642. if( pHead->pPoint->planarity == planarity )
  643. {
  644. const Vector vPointExtents( 0.5f, 0.5f, 0.01f );
  645. DumpAABBToGLView( (*pTransform) * pHead->pPoint->ptPosition, vPointExtents, vColor, pFile );
  646. }
  647. pHead = pHead->pNext;
  648. }
  649. fclose( pFile );
  650. #endif
  651. }
  652. const char * DumpPolyhedronCutHistory( const CUtlVector<CPolyhedron *> &DumpedHistory, const CUtlVector<const float *> &CutHistory, const VMatrix *pTransform )
  653. {
  654. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  655. if( pTransform == NULL )
  656. pTransform = &s_matIdentity;
  657. static char szDumpFile[100] = "FailedPolyhedronCut_Error.txt"; //most recent filename returned for further dumping
  658. for( int i = 0; i != DumpedHistory.Count(); ++i )
  659. {
  660. if( DumpedHistory[i] != NULL )
  661. {
  662. Q_snprintf( szDumpFile, 100, "FailedPolyhedronCut_%d.txt", i );
  663. DumpPolyhedronToGLView( DumpedHistory[i], szDumpFile, pTransform );
  664. DumpPlaneToGlView( CutHistory[i], 1.0f, szDumpFile, pTransform );
  665. }
  666. }
  667. return szDumpFile;
  668. #else
  669. return NULL;
  670. #endif
  671. }
  672. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  673. #define AssertMsg_DumpPolyhedron(condition, message)\
  674. if( (condition) == false )\
  675. {\
  676. VMatrix matTransform;\
  677. matTransform.Identity();\
  678. matTransform[0][0] = matTransform[1][1] = matTransform[2][2] = 25.0f;\
  679. matTransform.SetTranslation( -DebugCutHistory.Tail()->Center() * 25.0f );\
  680. const char *szLastDumpFile = DumpPolyhedronCutHistory( DebugCutHistory, PlaneCutHistory, &matTransform );\
  681. DumpPointListToGLView( pAllPoints, POINT_ALIVE, Vector( 0.9f, 0.9f, 0.9f ), szLastDumpFile, &matTransform );\
  682. DumpPointListToGLView( pAllPoints, POINT_ONPLANE, Vector( 0.5f, 0.5f, 0.5f ), szLastDumpFile, &matTransform );\
  683. DumpPointListToGLView( pDeadPointCollection, POINT_DEAD, Vector( 0.1f, 0.1f, 0.1f ), szLastDumpFile, &matTransform );\
  684. if( pStartPoint )\
  685. {\
  686. FILE *pFileDumpRepairProgress = fopen( szLastDumpFile, "ab" );\
  687. DumpAABBToGLView( matTransform * pStartPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 0.0f, 1.0f, 0.0f ), pFileDumpRepairProgress );\
  688. DumpAABBToGLView( matTransform * pWorkPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 1.0f, 0.0f, 0.0f ), pFileDumpRepairProgress );\
  689. fclose( pFileDumpRepairProgress );\
  690. }\
  691. AssertMsg( condition, message );\
  692. }
  693. #else
  694. #define AssertMsg_DumpPolyhedron(condition, message) AssertMsg( condition, message )
  695. #endif
  696. #define Assert_DumpPolyhedron(condition) AssertMsg_DumpPolyhedron( condition, #condition )
  697. #else
  698. #define AssertMsg_DumpPolyhedron(condition, message) NULL;
  699. #define Assert_DumpPolyhedron(condition) NULL;
  700. #endif
  701. CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory )
  702. {
  703. const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon;
  704. #ifdef _DEBUG
  705. CUtlVector<CPolyhedron *> DebugCutHistory;
  706. CUtlVector<const float *> PlaneCutHistory;
  707. GeneratePolyhedronFromPlanes_Point *pStartPoint = NULL;
  708. GeneratePolyhedronFromPlanes_Point *pWorkPoint = NULL;
  709. static int iPolyhedronClipCount = 0;
  710. ++iPolyhedronClipCount;
  711. DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) );
  712. #endif
  713. //clear out polygon work variables
  714. {
  715. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons;
  716. do
  717. {
  718. pActivePolygonWalk->pPolygon->bMissingASide = false;
  719. pActivePolygonWalk = pActivePolygonWalk->pNext;
  720. } while( pActivePolygonWalk );
  721. }
  722. //Collections of dead pointers for reallocation, shouldn't be touched until the current loop iteration is done.
  723. GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPointCollection = NULL;
  724. GeneratePolyhedronFromPlanes_UnorderedLineLL *pDeadLineCollection = NULL;
  725. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDeadPolygonCollection = NULL;
  726. GeneratePolyhedronFromPlanes_LineLL *pDeadLineLinkCollection = NULL;
  727. for( int iCurrentPlane = 0; iCurrentPlane != iPlaneCount; ++iCurrentPlane )
  728. {
  729. //clear out line work variables
  730. {
  731. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines;
  732. do
  733. {
  734. pActiveLineWalk->pLine->bAlive = false;
  735. pActiveLineWalk->pLine->bCut = false;
  736. pActiveLineWalk = pActiveLineWalk->pNext;
  737. } while( pActiveLineWalk );
  738. }
  739. //TODO: Move these pointers into a reallocation pool
  740. pDeadPointCollection = NULL;
  741. pDeadLineCollection = NULL;
  742. pDeadLineLinkCollection = NULL;
  743. pDeadPolygonCollection = NULL;
  744. Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(iCurrentPlane * 4) + 0]);
  745. /*double vNormalAsDouble[3];
  746. vNormalAsDouble[0] = vNormal.x;
  747. vNormalAsDouble[1] = vNormal.y;
  748. vNormalAsDouble[2] = vNormal.z;*/
  749. float fPlaneDist = pOutwardFacingPlanes[(iCurrentPlane * 4) + 3];
  750. //===================================================================================================
  751. // Step 1: Categorize each point as being either cut, split, or alive
  752. //===================================================================================================
  753. {
  754. bool bAllPointsDead = true;
  755. bool bAllPointsAlive = true;
  756. //find point distances from the plane
  757. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints;
  758. do
  759. {
  760. GeneratePolyhedronFromPlanes_Point *pPoint = pActivePointWalk->pPoint;
  761. float fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist;
  762. if( fPointDist > fOnPlaneEpsilon )
  763. {
  764. pPoint->planarity = POINT_DEAD; //point is dead, bang bang
  765. //mark connected lines as cut
  766. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines;
  767. GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk;
  768. do
  769. {
  770. pLineWalk->pLine->bCut = true;
  771. pLineWalk = pLineWalk->pNext;
  772. } while( pLineWalk != pFirstLine );
  773. bAllPointsAlive = false;
  774. }
  775. else if( fPointDist <= fNegativeOnPlaneEpsilon )
  776. {
  777. pPoint->planarity = POINT_ALIVE; //point is in behind plane, not voted off the island....yet
  778. bAllPointsDead = false;
  779. //mark connected lines as alive
  780. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines;
  781. GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk;
  782. do
  783. {
  784. pLineWalk->pLine->bAlive = true; //mark the line as alive
  785. pLineWalk = pLineWalk->pNext;
  786. } while( pLineWalk != pFirstLine );
  787. }
  788. else
  789. {
  790. pPoint->planarity = POINT_ONPLANE; //point is on the plane, he's everyone's buddy
  791. //Project on-plane points leaning towards death closer to the plane. This battles floating point precision decay.
  792. // Consider the case of a large on-plane epsilon leaving protrusions over time
  793. /*if( fPointDist < 0.0f )
  794. {
  795. double distAsDouble = fPointDist;
  796. double vPositionAsDouble[3];
  797. vPositionAsDouble[0] = pPoint->ptPosition.x;
  798. vPositionAsDouble[1] = pPoint->ptPosition.y;
  799. vPositionAsDouble[2] = pPoint->ptPosition.z;
  800. pPoint->ptPosition.x = vPositionAsDouble[0] - (distAsDouble * vNormalAsDouble[0]);
  801. pPoint->ptPosition.y = vPositionAsDouble[1] - (distAsDouble * vNormalAsDouble[1]);
  802. pPoint->ptPosition.z = vPositionAsDouble[2] - (distAsDouble * vNormalAsDouble[2]);
  803. #if ( 0 && defined( _DEBUG ) )
  804. float fDebugDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows
  805. AssertMsg( fabs( fDebugDist ) < fabs(fPointDist), "Projected point is further from plane than unprojected." );
  806. #endif
  807. fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //recompute dist (not guaranteed to be 0.0 like we want)
  808. }*/
  809. }
  810. pPoint->fPlaneDist = fPointDist;
  811. pActivePointWalk = pActivePointWalk->pNext;
  812. } while( pActivePointWalk );
  813. if( bAllPointsDead ) //all the points either died or are on the plane, no polyhedron left at all
  814. {
  815. #ifdef _DEBUG
  816. for( int i = DebugCutHistory.Count(); --i >= 0; )
  817. {
  818. if( DebugCutHistory[i] )
  819. DebugCutHistory[i]->Release();
  820. }
  821. DebugCutHistory.RemoveAll();
  822. #endif
  823. return NULL;
  824. }
  825. if( bAllPointsAlive )
  826. continue; //no cuts made
  827. //Scan for onplane points connected to only other onplane/dead points, these points get downgraded to dead status.
  828. {
  829. pActivePointWalk = pAllPoints;
  830. do
  831. {
  832. if( pActivePointWalk->pPoint->planarity == POINT_ONPLANE )
  833. {
  834. GeneratePolyhedronFromPlanes_LineLL *pOnPlaneLineWalk = pActivePointWalk->pPoint->pConnectedLines;
  835. GeneratePolyhedronFromPlanes_LineLL *pStartLineWalk = pOnPlaneLineWalk;
  836. bool bDead = true; //assume it's dead and disprove
  837. do
  838. {
  839. if ( pOnPlaneLineWalk->pLine->bAlive )
  840. {
  841. bDead = false;
  842. }
  843. else if ( pOnPlaneLineWalk->pLine->bCut )
  844. {
  845. //connected to a dead point.
  846. if( pOnPlaneLineWalk->pNext->pLine->bCut || pOnPlaneLineWalk->pPrev->pLine->bCut )
  847. {
  848. //This on-plane point is surrounded by dead points on one polygon of the polyhedron.
  849. // We have to downgrade this point to dead to avoid situations where float imprecision
  850. // turns the polyhedron into a *slightly* concave shape. Concave shapes might break this algorithm, even falsely concave shapes.
  851. bDead = true;
  852. break;
  853. }
  854. }
  855. pOnPlaneLineWalk = pOnPlaneLineWalk->pNext;
  856. } while( pOnPlaneLineWalk != pStartLineWalk );
  857. if( bDead )
  858. {
  859. pActivePointWalk->pPoint->planarity = POINT_DEAD;
  860. pOnPlaneLineWalk = pStartLineWalk;
  861. //mark connected lines as cut
  862. do
  863. {
  864. pOnPlaneLineWalk->pLine->bCut = true;
  865. pOnPlaneLineWalk = pOnPlaneLineWalk->pNext;
  866. } while( pOnPlaneLineWalk != pStartLineWalk );
  867. }
  868. }
  869. pActivePointWalk = pActivePointWalk->pNext;
  870. } while( pActivePointWalk );
  871. }
  872. #ifdef _DEBUG
  873. PlaneCutHistory.AddToTail( &pOutwardFacingPlanes[iCurrentPlane * 4] );
  874. #endif
  875. }
  876. #ifdef _DEBUG
  877. //Run around the edges of all the polygons and ensure they don't have more than one point of lowered "alive" status (alive > onplane > dead) surrounded by higher status
  878. // It indicates a concave shape. It's impossible to have it occur in theoretical space. But floating point numbers introduce error.
  879. {
  880. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons;
  881. do
  882. {
  883. int iSurroundedCount = 0;
  884. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pDebugPolygonWalk->pPolygon->pLines;
  885. GeneratePolyhedronFromPlanes_LineLL *pFirstDebugLine = pDebugLineWalk;
  886. do
  887. {
  888. PolyhedronPointPlanarity currentPlanarity = pDebugLineWalk->pLine->pPoints[pDebugLineWalk->iReferenceIndex]->planarity;
  889. GeneratePolyhedronFromPlanes_LineLL *pNext = pDebugLineWalk->pNext;
  890. PolyhedronPointPlanarity nextPlanarity = pNext->pLine->pPoints[pNext->iReferenceIndex]->planarity;
  891. if( currentPlanarity < nextPlanarity )
  892. {
  893. GeneratePolyhedronFromPlanes_LineLL *pPrev = pDebugLineWalk->pPrev;
  894. PolyhedronPointPlanarity prevPlanarity = pPrev->pLine->pPoints[pPrev->iReferenceIndex]->planarity;
  895. if( currentPlanarity < prevPlanarity )
  896. {
  897. ++iSurroundedCount;
  898. }
  899. }
  900. pDebugLineWalk = pDebugLineWalk->pNext;
  901. } while( pDebugLineWalk != pFirstDebugLine );
  902. AssertMsg_DumpPolyhedron( iSurroundedCount <= 1, "Concave polygon, cutting process might break. Consider adjusting the on-plane epsilon to better compensate for floating point precision." );
  903. pDebugPolygonWalk = pDebugPolygonWalk->pNext;
  904. } while( pDebugPolygonWalk );
  905. }
  906. #endif
  907. //===================================================================================================
  908. // Step 2: Remove dead lines. A dead line is one with a dead point that isn't connected to a living point
  909. //===================================================================================================
  910. {
  911. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines;
  912. do
  913. {
  914. GeneratePolyhedronFromPlanes_Line *pLine = pActiveLineWalk->pLine;
  915. if( (pLine->bAlive == false) && (pLine->bCut == true) ) //not connected to a live point, but connected to a dead one. Dead line
  916. {
  917. //remove line from connected polygons
  918. for( int i = 0; i != 2; ++i )
  919. {
  920. GeneratePolyhedronFromPlanes_Polygon *pPolygon = pLine->pPolygons[i];
  921. GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPolygonLineLinks[i];
  922. pPolygon->bMissingASide = true;
  923. if( pLineLink->pNext == pLineLink )
  924. {
  925. //this was the last line of the polygon, it's dead
  926. pPolygon->pLines = NULL;
  927. }
  928. else
  929. {
  930. //link around this line
  931. pPolygon->pLines = pLineLink->pPrev; //Always have the polygon's head line be just before the gap in the polygon
  932. pLineLink->pNext->pPrev = pLineLink->pPrev;
  933. pLineLink->pPrev->pNext = pLineLink->pNext;
  934. }
  935. //move the line link to the dead list
  936. pLineLink->pNext = pDeadLineLinkCollection;
  937. pDeadLineLinkCollection = pLineLink;
  938. }
  939. //remove the line from connected points
  940. for( int i = 0; i != 2; ++i )
  941. {
  942. GeneratePolyhedronFromPlanes_Point *pPoint = pLine->pPoints[i];
  943. GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPointLineLinks[i];
  944. if( pLineLink->pNext == pLineLink )
  945. {
  946. //this is the last line
  947. pPoint->pConnectedLines = NULL;
  948. Assert( pPoint->planarity != POINT_ALIVE );
  949. pPoint->planarity = POINT_DEAD; //in case it was merely POINT_ONPLANE before
  950. }
  951. else
  952. {
  953. //link around this line
  954. pPoint->pConnectedLines = pLineLink->pNext; //in case pLineLink was the head line
  955. pLineLink->pNext->pPrev = pLineLink->pPrev;
  956. pLineLink->pPrev->pNext = pLineLink->pNext;
  957. }
  958. //move the line link to the dead list
  959. pLineLink->pNext = pDeadLineLinkCollection;
  960. pDeadLineLinkCollection = pLineLink;
  961. }
  962. //move the line to the dead list
  963. {
  964. //link past this node
  965. if( pActiveLineWalk->pPrev )
  966. pActiveLineWalk->pPrev->pNext = pActiveLineWalk->pNext;
  967. else
  968. pAllLines = pActiveLineWalk->pNext;
  969. if( pActiveLineWalk->pNext )
  970. pActiveLineWalk->pNext->pPrev = pActiveLineWalk->pPrev;
  971. GeneratePolyhedronFromPlanes_UnorderedLineLL *pNextLineWalk = pActiveLineWalk->pNext;
  972. //add to the dead list
  973. pActiveLineWalk->pNext = pDeadLineCollection;
  974. pDeadLineCollection = pActiveLineWalk;
  975. //next
  976. pActiveLineWalk = pNextLineWalk;
  977. }
  978. }
  979. else
  980. {
  981. pActiveLineWalk = pActiveLineWalk->pNext;
  982. }
  983. } while( pActiveLineWalk );
  984. }
  985. //===================================================================================================
  986. // Step 3: Remove dead polygons. A dead polygon has less than 2 lines.
  987. //===================================================================================================
  988. {
  989. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons;
  990. do
  991. {
  992. GeneratePolyhedronFromPlanes_Polygon *pPolygon = pActivePolygonWalk->pPolygon;
  993. GeneratePolyhedronFromPlanes_LineLL *pHeadLine = pPolygon->pLines;
  994. bool bDead = (pHeadLine == NULL) || (pHeadLine->pNext == pHeadLine);
  995. if( !bDead )
  996. {
  997. //there's a rare case where a polygon can be almost entirely coplanar with the cut, it comes purely out of the land of imprecision
  998. bDead = true; //assume it's dead, and disprove
  999. GeneratePolyhedronFromPlanes_LineLL *pTestLineWalk = pHeadLine;
  1000. do
  1001. {
  1002. if( pTestLineWalk->pLine->bAlive )
  1003. {
  1004. bDead = false;
  1005. break;
  1006. }
  1007. pTestLineWalk = pTestLineWalk->pNext;
  1008. } while( pTestLineWalk != pHeadLine );
  1009. }
  1010. if( bDead )
  1011. {
  1012. //dead polygon, move it to the dead list
  1013. //link around this node
  1014. if( pActivePolygonWalk->pPrev )
  1015. pActivePolygonWalk->pPrev->pNext = pActivePolygonWalk->pNext;
  1016. else
  1017. pAllPolygons = pAllPolygons->pNext; //pActivePolygonWalk was the head node
  1018. if( pActivePolygonWalk->pNext )
  1019. pActivePolygonWalk->pNext->pPrev = pActivePolygonWalk->pPrev;
  1020. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNextPolygonWalk = pActivePolygonWalk->pNext;
  1021. //add to the dead list
  1022. pActivePolygonWalk->pNext = pDeadPolygonCollection;
  1023. pDeadPolygonCollection = pActivePolygonWalk;
  1024. //next
  1025. pActivePolygonWalk = pNextPolygonWalk;
  1026. }
  1027. else
  1028. {
  1029. AssertMsg_DumpPolyhedron( (pActivePolygonWalk->pPolygon->pLines != NULL) &&
  1030. (pActivePolygonWalk->pPolygon->pLines != pActivePolygonWalk->pPolygon->pLines->pNext), "Living polygon with less than 2 lines" );
  1031. pActivePolygonWalk = pActivePolygonWalk->pNext;
  1032. }
  1033. } while( pActivePolygonWalk );
  1034. }
  1035. //===================================================================================================
  1036. // Step 4: Remove dead points.
  1037. //===================================================================================================
  1038. {
  1039. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints;
  1040. do
  1041. {
  1042. if( pActivePointWalk->pPoint->planarity == POINT_DEAD )
  1043. {
  1044. GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext = pActivePointWalk->pNext;
  1045. if( pActivePointWalk->pPrev )
  1046. pActivePointWalk->pPrev->pNext = pActivePointWalk->pNext;
  1047. else
  1048. pAllPoints = pAllPoints->pNext;
  1049. if( pActivePointWalk->pNext )
  1050. pActivePointWalk->pNext->pPrev = pActivePointWalk->pPrev;
  1051. pActivePointWalk->pNext = pDeadPointCollection;
  1052. pDeadPointCollection = pActivePointWalk;
  1053. pActivePointWalk = pNext;
  1054. }
  1055. else
  1056. {
  1057. pActivePointWalk = pActivePointWalk->pNext;
  1058. }
  1059. } while( pActivePointWalk );
  1060. }
  1061. //===================================================================================================
  1062. // Step 5: Handle cut lines
  1063. //===================================================================================================
  1064. {
  1065. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines;
  1066. do
  1067. {
  1068. GeneratePolyhedronFromPlanes_Line *pWorkLine = pActiveLineWalk->pLine;
  1069. Assert_DumpPolyhedron( (pWorkLine->bAlive == true) || (pWorkLine->bCut == false) ); //all dead lines should have already been removed
  1070. if( pWorkLine->bCut )
  1071. {
  1072. GeneratePolyhedronFromPlanes_Point **pLinePoints = pWorkLine->pPoints;
  1073. Assert_DumpPolyhedron( (pLinePoints[0]->planarity == POINT_DEAD) || (pLinePoints[1]->planarity == POINT_DEAD) ); //one of the two has to be a dead point
  1074. int iDeadIndex = (pLinePoints[0]->planarity == POINT_DEAD)?(0):(1);
  1075. int iLivingIndex = 1 - iDeadIndex;
  1076. GeneratePolyhedronFromPlanes_Point *pDeadPoint = pLinePoints[iDeadIndex];
  1077. GeneratePolyhedronFromPlanes_Point *pLivingPoint = pLinePoints[iLivingIndex];
  1078. Assert_DumpPolyhedron( pLivingPoint->planarity == POINT_ALIVE ); //if this point were on-plane or dead, the line should be dead
  1079. //We'll be de-linking from the old point and generating a new one. We do this so other lines can still access the dead point's untouched data.
  1080. //Generate a new point
  1081. GeneratePolyhedronFromPlanes_Point *pNewPoint = (GeneratePolyhedronFromPlanes_Point *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Point ) );
  1082. {
  1083. //add this point to the active list
  1084. pAllPoints->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) );
  1085. pAllPoints->pPrev->pNext = pAllPoints;
  1086. pAllPoints = pAllPoints->pPrev;
  1087. pAllPoints->pPrev = NULL;
  1088. pAllPoints->pPoint = pNewPoint;
  1089. float fInvTotalDist = 1.0f/(pDeadPoint->fPlaneDist - pLivingPoint->fPlaneDist); //subtraction because the living index is known to be negative
  1090. pNewPoint->ptPosition = (pLivingPoint->ptPosition * (pDeadPoint->fPlaneDist * fInvTotalDist)) - (pDeadPoint->ptPosition * (pLivingPoint->fPlaneDist * fInvTotalDist));
  1091. #if ( 0 && defined( _DEBUG ) )
  1092. float fDebugDist = vNormal.Dot( pNewPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows
  1093. AssertMsg_DumpPolyhedron( fabs( fDebugDist ) < fOnPlaneEpsilon, "Generated split point is far from plane" );
  1094. //verify that the new point isn't sitting on top of another
  1095. {
  1096. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints;
  1097. do
  1098. {
  1099. if( pActivePointWalk->pPoint != pNewPoint )
  1100. {
  1101. Vector vDiff = pActivePointWalk->pPoint->ptPosition - pNewPoint->ptPosition;
  1102. AssertMsg_DumpPolyhedron( vDiff.Length() > fOnPlaneEpsilon, "Generated a point on top of another" );
  1103. }
  1104. pActivePointWalk = pActivePointWalk->pNext;
  1105. } while( pActivePointWalk );
  1106. }
  1107. #endif
  1108. pNewPoint->planarity = POINT_ONPLANE;
  1109. pNewPoint->fPlaneDist = 0.0f;
  1110. }
  1111. GeneratePolyhedronFromPlanes_LineLL *pNewLineLink = pNewPoint->pConnectedLines = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) );
  1112. pNewLineLink->pLine = pWorkLine;
  1113. pNewLineLink->pNext = pNewLineLink;
  1114. pNewLineLink->pPrev = pNewLineLink;
  1115. pNewLineLink->iReferenceIndex = iLivingIndex;
  1116. pWorkLine->pPoints[iDeadIndex] = pNewPoint;
  1117. pWorkLine->pPointLineLinks[iDeadIndex] = pNewLineLink;
  1118. pNewPoint->pConnectedLines = pNewLineLink;
  1119. //A new line is needed on each polygon touching the dead point to connect the two new endpoints for split lines.
  1120. // So mark connected polygons as missing a side.
  1121. for( int i = 0; i != 2; ++i )
  1122. pWorkLine->pPolygons[i]->bMissingASide = true;
  1123. //Always have a cut polygon's head line be just before the gap in the polygon.
  1124. // In this case, we know that one of the two polygons goes clockwise into the dead point, so have that polygon point at this line.
  1125. // We don't know enough about the other polygon to do anything here, but another cut line will handle that polygon. So it all works out in the end.
  1126. pWorkLine->pPolygons[iDeadIndex]->pLines = pWorkLine->pPolygonLineLinks[iDeadIndex];
  1127. }
  1128. pActiveLineWalk = pActiveLineWalk->pNext;
  1129. } while( pActiveLineWalk );
  1130. }
  1131. //===================================================================================================
  1132. // Step 6: Repair polygons that are missing a side. And generate the new coplanar polygon.
  1133. //===================================================================================================
  1134. {
  1135. //Find the first polygon missing a side.
  1136. // We'll then walk from polygon to polygon using line connections so that we can generate the new polygon in a clockwise manner.
  1137. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons;
  1138. while( (pActivePolygonWalk != NULL) && (pActivePolygonWalk->pPolygon->bMissingASide == false) )
  1139. {
  1140. pActivePolygonWalk = pActivePolygonWalk->pNext;
  1141. }
  1142. //acquire iteration data
  1143. #ifndef _DEBUG
  1144. GeneratePolyhedronFromPlanes_Point *pStartPoint;
  1145. GeneratePolyhedronFromPlanes_Point *pWorkPoint;
  1146. #endif
  1147. GeneratePolyhedronFromPlanes_LineLL *pLastLineLink;
  1148. GeneratePolyhedronFromPlanes_Polygon *pWorkPolygon;
  1149. GeneratePolyhedronFromPlanes_LineLL *pTestLine;
  1150. #ifdef _DEBUG
  1151. GeneratePolyhedronFromPlanes_Polygon *pLastWorkPolygon = NULL;
  1152. GeneratePolyhedronFromPlanes_Point *pLastWorkPoint = NULL;
  1153. #endif
  1154. if( pActivePolygonWalk )
  1155. {
  1156. //grab the polygon we'll be starting with
  1157. GeneratePolyhedronFromPlanes_Polygon *pBrokenPolygon = pActivePolygonWalk->pPolygon;
  1158. {
  1159. GeneratePolyhedronFromPlanes_LineLL *pTemp = pBrokenPolygon->pLines->pNext;
  1160. pStartPoint = pTemp->pLine->pPoints[1 - pTemp->iReferenceIndex];
  1161. Assert_DumpPolyhedron( pStartPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar
  1162. pLastLineLink = pTemp->pLine->pPointLineLinks[1 - pTemp->iReferenceIndex]->pNext;
  1163. pWorkPolygon = pBrokenPolygon;
  1164. }
  1165. pWorkPoint = pStartPoint;
  1166. pTestLine = pLastLineLink->pPrev; //rotate counterclockwise around the point
  1167. }
  1168. else
  1169. {
  1170. //apparently the plane was entirely through existing polygonal borders, extremely rare but it can happen with inefficient cutting planes
  1171. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints;
  1172. while( (pActivePointWalk != NULL) && (pActivePointWalk->pPoint->planarity != POINT_ONPLANE) )
  1173. {
  1174. pActivePointWalk = pActivePointWalk->pNext;
  1175. }
  1176. Assert( pActivePointWalk != NULL );
  1177. pStartPoint = pWorkPoint = pActivePointWalk->pPoint;
  1178. GeneratePolyhedronFromPlanes_LineLL *pLines = pWorkPoint->pConnectedLines;
  1179. while( !pLines->pLine->bAlive ) //seek clockwise until we find a line not on the plane
  1180. pLines = pLines->pNext;
  1181. while( pLines->pLine->bAlive ) //now seek counterclockwise until we find a line on the plane (in case we started on an alive line last seek)
  1182. pLines = pLines->pPrev;
  1183. //now pLines points at one side of the polygon, with pActivePointWalk
  1184. pLastLineLink = pLines;
  1185. pTestLine = pLines->pPrev;
  1186. pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex];
  1187. }
  1188. //create the new polygon
  1189. GeneratePolyhedronFromPlanes_Polygon *pNewPolygon = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Polygon ) );
  1190. {
  1191. //before we forget, add this polygon to the active list
  1192. pAllPolygons->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) );
  1193. pAllPolygons->pPrev->pNext = pAllPolygons;
  1194. pAllPolygons = pAllPolygons->pPrev;
  1195. pAllPolygons->pPrev = NULL;
  1196. pAllPolygons->pPolygon = pNewPolygon;
  1197. pNewPolygon->bMissingASide = false; //technically missing all it's sides, but we're fixing it now
  1198. pNewPolygon->vSurfaceNormal = vNormal;
  1199. pNewPolygon->pLines = NULL;
  1200. }
  1201. //===================================================================================================================
  1202. // The general idea of the upcoming algorithm to put together a new polygon and patch broken polygons...
  1203. // You have a point and a line the algorithm just jumped across.
  1204. // 1. Rotate through the point's line links one time counterclockwise (pPrev)
  1205. // 2. If the line is cut, then we make a new bridging line in the polygon between that line and the one counterclockwise to it. (pPrev)
  1206. // If the line is on-plane. Skip the bridge line making, but set links to the new polygon as if we'd just created the bridge
  1207. // 3. Once we follow a line back to the point where we started, we should be all done.
  1208. do
  1209. {
  1210. if( pWorkPolygon->bMissingASide )
  1211. {
  1212. //during the cutting process we made sure that the head line link was going clockwise into the missing area
  1213. GeneratePolyhedronFromPlanes_LineLL *pGapLines[2];
  1214. pGapLines[1] = pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex]; //get the same line, but in the polygons linked list.
  1215. Assert_DumpPolyhedron( pGapLines[1]->pLine == pTestLine->pLine );
  1216. pGapLines[0] = pGapLines[1]->pPrev;
  1217. Assert_DumpPolyhedron( pWorkPolygon->bMissingASide );
  1218. #ifdef _DEBUG
  1219. {
  1220. //ensure that the space between the gap lines is the only space where fixing is required
  1221. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pGapLines[1]->pNext;
  1222. while( pDebugLineWalk != pGapLines[0] )
  1223. {
  1224. Assert_DumpPolyhedron( pDebugLineWalk->pLine->bCut == false );
  1225. pDebugLineWalk = pDebugLineWalk->pNext;
  1226. }
  1227. }
  1228. #endif
  1229. GeneratePolyhedronFromPlanes_Line *pJoinLine = (GeneratePolyhedronFromPlanes_Line *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Line ) );
  1230. {
  1231. //before we forget, add this line to the active list
  1232. pAllLines->pPrev = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) );
  1233. pAllLines->pPrev->pNext = pAllLines;
  1234. pAllLines = pAllLines->pPrev;
  1235. pAllLines->pPrev = NULL;
  1236. pAllLines->pLine = pJoinLine;
  1237. pJoinLine->bAlive = false;
  1238. pJoinLine->bCut = false;
  1239. }
  1240. pJoinLine->pPoints[0] = pGapLines[0]->pLine->pPoints[pGapLines[0]->iReferenceIndex];
  1241. pJoinLine->pPoints[1] = pGapLines[1]->pLine->pPoints[1 - pGapLines[1]->iReferenceIndex];
  1242. pJoinLine->pPolygons[0] = pNewPolygon;
  1243. pJoinLine->pPolygons[1] = pWorkPolygon;
  1244. //now create all 4 links into the line
  1245. GeneratePolyhedronFromPlanes_LineLL *pPointLinks[2];
  1246. pPointLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) );
  1247. pPointLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) );
  1248. GeneratePolyhedronFromPlanes_LineLL *pPolygonLinks[2];
  1249. pPolygonLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) );
  1250. pPolygonLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) );
  1251. pPointLinks[0]->pLine = pPointLinks[1]->pLine = pPolygonLinks[0]->pLine = pPolygonLinks[1]->pLine = pJoinLine;
  1252. pJoinLine->pPointLineLinks[0] = pPointLinks[0];
  1253. pJoinLine->pPointLineLinks[1] = pPointLinks[1];
  1254. pJoinLine->pPolygonLineLinks[0] = pPolygonLinks[0];
  1255. pJoinLine->pPolygonLineLinks[1] = pPolygonLinks[1];
  1256. pPointLinks[0]->iReferenceIndex = 1;
  1257. pPointLinks[1]->iReferenceIndex = 0;
  1258. //Insert before the link from point 0 to gap line 0 (counterclockwise rotation)
  1259. {
  1260. GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[0]->pLine->pPointLineLinks[pGapLines[0]->iReferenceIndex];
  1261. Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[0]->pLine );
  1262. pPointLinks[0]->pPrev = pWorkLink->pPrev;
  1263. pPointLinks[0]->pNext = pWorkLink;
  1264. pWorkLink->pPrev->pNext = pPointLinks[0];
  1265. pWorkLink->pPrev = pPointLinks[0];
  1266. }
  1267. //Insert after the link from point 1 to gap line 1 (clockwise rotation)
  1268. {
  1269. GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[1]->pLine->pPointLineLinks[1 - pGapLines[1]->iReferenceIndex];
  1270. Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[1]->pLine );
  1271. pPointLinks[1]->pNext = pWorkLink->pNext;
  1272. pPointLinks[1]->pPrev = pWorkLink;
  1273. pWorkLink->pNext->pPrev = pPointLinks[1];
  1274. pWorkLink->pNext = pPointLinks[1];
  1275. }
  1276. pPolygonLinks[0]->iReferenceIndex = 0;
  1277. pPolygonLinks[1]->iReferenceIndex = 1;
  1278. //Insert before the head line in the new polygon (at the end of the clockwise order)
  1279. {
  1280. if( pNewPolygon->pLines == NULL )
  1281. {
  1282. //this is the first line being added to the polygon
  1283. pNewPolygon->pLines = pPolygonLinks[0];
  1284. pPolygonLinks[0]->pNext = pPolygonLinks[0];
  1285. pPolygonLinks[0]->pPrev = pPolygonLinks[0];
  1286. }
  1287. else
  1288. {
  1289. GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines;
  1290. pPolygonLinks[0]->pNext = pWorkLink;
  1291. pPolygonLinks[0]->pPrev = pWorkLink->pPrev;
  1292. pWorkLink->pPrev->pNext = pPolygonLinks[0];
  1293. pWorkLink->pPrev = pPolygonLinks[0];
  1294. }
  1295. }
  1296. //Insert after the head line in the work polygon
  1297. {
  1298. GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pWorkPolygon->pLines;
  1299. pPolygonLinks[1]->pNext = pWorkLink->pNext;
  1300. pPolygonLinks[1]->pPrev = pWorkLink;
  1301. pWorkLink->pNext->pPrev = pPolygonLinks[1];
  1302. pWorkLink->pNext = pPolygonLinks[1];
  1303. }
  1304. pWorkPolygon->bMissingASide = false; //repairs are finished
  1305. #ifdef _DEBUG
  1306. pLastWorkPolygon = pWorkPolygon;
  1307. pLastWorkPoint = pWorkPoint;
  1308. #endif
  1309. //move to the next point
  1310. pWorkPoint = pJoinLine->pPoints[0];
  1311. pLastLineLink = pJoinLine->pPointLineLinks[0];
  1312. Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar
  1313. pTestLine = pLastLineLink->pPrev;
  1314. if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE )
  1315. pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex];
  1316. else
  1317. pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex];
  1318. Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon );
  1319. Assert_DumpPolyhedron( (pWorkPoint == pStartPoint) ||
  1320. (pGapLines[0]->pLine->bCut == false) ||
  1321. (pWorkPolygon->bMissingASide == true) ); //if we're not done fixing, and if the shared line was cut, the next polygon must be missing a side
  1322. }
  1323. else
  1324. {
  1325. //line is on the plane, meaning the polygon isn't broken and doesn't need patching
  1326. Assert_DumpPolyhedron( pTestLine->pLine->bCut == false );
  1327. Assert_DumpPolyhedron( (pTestLine->pLine->pPoints[0]->planarity == POINT_ONPLANE) && (pTestLine->pLine->pPoints[1]->planarity == POINT_ONPLANE) );
  1328. //link to this line from the new polygon
  1329. GeneratePolyhedronFromPlanes_LineLL *pNewLineLink;
  1330. pNewLineLink = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) );
  1331. pNewLineLink->pLine = pTestLine->pLine;
  1332. pNewLineLink->iReferenceIndex = pTestLine->iReferenceIndex;
  1333. //Insert before the head line in the new polygon (at the end of the clockwise order)
  1334. {
  1335. if( pNewPolygon->pLines == NULL )
  1336. {
  1337. //this is the first line being added to the polygon
  1338. pNewPolygon->pLines = pNewLineLink;
  1339. pNewLineLink->pNext = pNewLineLink;
  1340. pNewLineLink->pPrev = pNewLineLink;
  1341. }
  1342. else
  1343. {
  1344. GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines;
  1345. pNewLineLink->pNext = pWorkLink;
  1346. pNewLineLink->pPrev = pWorkLink->pPrev;
  1347. pWorkLink->pPrev->pNext = pNewLineLink;
  1348. pWorkLink->pPrev = pNewLineLink;
  1349. }
  1350. }
  1351. //Since the entire line is on the plane, that means it used to point to something that used to reside where the new polygon is going
  1352. // Update the link to the new the polygon pointer and be on our way
  1353. pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex] = pNewPolygon;
  1354. pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex] = pNewLineLink;
  1355. #ifdef _DEBUG
  1356. pLastWorkPolygon = pWorkPolygon;
  1357. pLastWorkPoint = pWorkPoint;
  1358. #endif
  1359. pWorkPoint = pTestLine->pLine->pPoints[pTestLine->iReferenceIndex];
  1360. pLastLineLink = pTestLine->pLine->pPointLineLinks[pTestLine->iReferenceIndex];
  1361. Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar
  1362. pTestLine = pLastLineLink->pPrev;
  1363. if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE )
  1364. pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex];
  1365. else
  1366. pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex];
  1367. Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon );
  1368. }
  1369. } while( pWorkPoint != pStartPoint );
  1370. }
  1371. #ifdef _DEBUG
  1372. //verify that repairs are complete
  1373. {
  1374. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons;
  1375. do
  1376. {
  1377. AssertMsg_DumpPolyhedron( pDebugPolygonWalk->pPolygon->bMissingASide == false, "Some polygons not repaired after cut" );
  1378. pDebugPolygonWalk = pDebugPolygonWalk->pNext;
  1379. } while( pDebugPolygonWalk );
  1380. GeneratePolyhedronFromPlanes_UnorderedPointLL *pDebugPointWalk = pAllPoints;
  1381. do
  1382. {
  1383. AssertMsg_DumpPolyhedron( pDebugPointWalk->pPoint->pConnectedLines, "Point connected to no lines after cut" );
  1384. pDebugPointWalk = pDebugPointWalk->pNext;
  1385. } while( pDebugPointWalk );
  1386. pStartPoint = NULL;
  1387. }
  1388. //maintain the cut history
  1389. DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) );
  1390. #endif
  1391. }
  1392. #ifdef _DEBUG
  1393. for( int i = DebugCutHistory.Count(); --i >= 0; )
  1394. {
  1395. if( DebugCutHistory[i] )
  1396. DebugCutHistory[i]->Release();
  1397. }
  1398. DebugCutHistory.RemoveAll();
  1399. #endif
  1400. return ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, bUseTemporaryMemory );
  1401. }
  1402. #define STARTPOINTTOLINELINKS(iPointNum, lineindex1, iOtherPointIndex1, lineindex2, iOtherPointIndex2, lineindex3, iOtherPointIndex3 )\
  1403. StartingBoxPoints[iPointNum].pConnectedLines = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\
  1404. StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pLine = &StartingBoxLines[lineindex1];\
  1405. StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].iReferenceIndex = iOtherPointIndex1;\
  1406. StartingBoxLines[lineindex1].pPointLineLinks[1 - iOtherPointIndex1] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\
  1407. StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\
  1408. StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\
  1409. StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pLine = &StartingBoxLines[lineindex2];\
  1410. StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].iReferenceIndex = iOtherPointIndex2;\
  1411. StartingBoxLines[lineindex2].pPointLineLinks[1 - iOtherPointIndex2] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\
  1412. StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\
  1413. StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\
  1414. StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pLine = &StartingBoxLines[lineindex3];\
  1415. StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].iReferenceIndex = iOtherPointIndex3;\
  1416. StartingBoxLines[lineindex3].pPointLineLinks[1 - iOtherPointIndex3] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\
  1417. StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\
  1418. StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];
  1419. #define STARTBOXCONNECTION( linenum, point1, point2, poly1, poly2 )\
  1420. StartingBoxLines[linenum].pPoints[0] = &StartingBoxPoints[point1];\
  1421. StartingBoxLines[linenum].pPoints[1] = &StartingBoxPoints[point2];\
  1422. StartingBoxLines[linenum].pPolygons[0] = &StartingBoxPolygons[poly1];\
  1423. StartingBoxLines[linenum].pPolygons[1] = &StartingBoxPolygons[poly2];
  1424. #define STARTPOLYGONTOLINELINKS( polynum, lineindex1, iThisPolyIndex1, lineindex2, iThisPolyIndex2, lineindex3, iThisPolyIndex3, lineindex4, iThisPolyIndex4 )\
  1425. StartingBoxPolygons[polynum].pLines = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\
  1426. StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pLine = &StartingBoxLines[lineindex1];\
  1427. StartingPolygon_To_Lines_Links[(polynum * 4) + 0].iReferenceIndex = iThisPolyIndex1;\
  1428. StartingBoxLines[lineindex1].pPolygonLineLinks[iThisPolyIndex1] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\
  1429. StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\
  1430. StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\
  1431. StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pLine = &StartingBoxLines[lineindex2];\
  1432. StartingPolygon_To_Lines_Links[(polynum * 4) + 1].iReferenceIndex = iThisPolyIndex2;\
  1433. StartingBoxLines[lineindex2].pPolygonLineLinks[iThisPolyIndex2] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\
  1434. StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\
  1435. StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\
  1436. StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pLine = &StartingBoxLines[lineindex3];\
  1437. StartingPolygon_To_Lines_Links[(polynum * 4) + 2].iReferenceIndex = iThisPolyIndex3;\
  1438. StartingBoxLines[lineindex3].pPolygonLineLinks[iThisPolyIndex3] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\
  1439. StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\
  1440. StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\
  1441. StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pLine = &StartingBoxLines[lineindex4];\
  1442. StartingPolygon_To_Lines_Links[(polynum * 4) + 3].iReferenceIndex = iThisPolyIndex4;\
  1443. StartingBoxLines[lineindex4].pPolygonLineLinks[iThisPolyIndex4] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\
  1444. StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\
  1445. StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];
  1446. CPolyhedron *GeneratePolyhedronFromPlanes( const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory )
  1447. {
  1448. //this is version 2 of the polyhedron generator, version 1 made individual polygons and joined points together, some guesswork is involved and it therefore isn't a solid method
  1449. //this version will start with a cube and hack away at it (retaining point connection information) to produce a polyhedron with no guesswork involved, this method should be rock solid
  1450. //the polygon clipping functions we're going to use want inward facing planes
  1451. float *pFlippedPlanes = (float *)stackalloc( (iPlaneCount * 4) * sizeof( float ) );
  1452. for( int i = 0; i != iPlaneCount * 4; ++i )
  1453. {
  1454. pFlippedPlanes[i] = -pOutwardFacingPlanes[i];
  1455. }
  1456. //our first goal is to find the size of a cube big enough to encapsulate all points that will be in the final polyhedron
  1457. Vector vAABBMins, vAABBMaxs;
  1458. if( FindConvexShapeLooseAABB( pFlippedPlanes, iPlaneCount, &vAABBMins, &vAABBMaxs ) == false )
  1459. return NULL; //no shape to work with apparently
  1460. //grow the bounding box to a larger size since it's probably inaccurate a bit
  1461. {
  1462. Vector vGrow = (vAABBMaxs - vAABBMins) * 0.5f;
  1463. vGrow.x += 100.0f;
  1464. vGrow.y += 100.0f;
  1465. vGrow.z += 100.0f;
  1466. vAABBMaxs += vGrow;
  1467. vAABBMins -= vGrow;
  1468. }
  1469. //generate our starting cube using the 2x AABB so we can start hacking away at it
  1470. //create our starting box on the stack
  1471. GeneratePolyhedronFromPlanes_Point StartingBoxPoints[8];
  1472. GeneratePolyhedronFromPlanes_Line StartingBoxLines[12];
  1473. GeneratePolyhedronFromPlanes_Polygon StartingBoxPolygons[6];
  1474. GeneratePolyhedronFromPlanes_LineLL StartingPoints_To_Lines_Links[24]; //8 points, 3 lines per point
  1475. GeneratePolyhedronFromPlanes_LineLL StartingPolygon_To_Lines_Links[24]; //6 polygons, 4 lines per poly
  1476. GeneratePolyhedronFromPlanes_UnorderedPolygonLL StartingPolygonList[6]; //6 polygons
  1477. GeneratePolyhedronFromPlanes_UnorderedLineLL StartingLineList[12]; //12 lines
  1478. GeneratePolyhedronFromPlanes_UnorderedPointLL StartingPointList[8]; //8 points
  1479. //I had to work all this out on a whiteboard if it seems completely unintuitive.
  1480. {
  1481. StartingBoxPoints[0].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMins.z );
  1482. STARTPOINTTOLINELINKS( 0, 0, 1, 4, 1, 3, 0 );
  1483. StartingBoxPoints[1].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMins.z );
  1484. STARTPOINTTOLINELINKS( 1, 0, 0, 1, 1, 5, 1 );
  1485. StartingBoxPoints[2].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMaxs.z );
  1486. STARTPOINTTOLINELINKS( 2, 4, 0, 8, 1, 11, 0 );
  1487. StartingBoxPoints[3].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMaxs.z );
  1488. STARTPOINTTOLINELINKS( 3, 5, 0, 9, 1, 8, 0 );
  1489. StartingBoxPoints[4].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMins.z );
  1490. STARTPOINTTOLINELINKS( 4, 2, 0, 3, 1, 7, 1 );
  1491. StartingBoxPoints[5].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMins.z );
  1492. STARTPOINTTOLINELINKS( 5, 1, 0, 2, 1, 6, 1 );
  1493. StartingBoxPoints[6].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMaxs.z );
  1494. STARTPOINTTOLINELINKS( 6, 7, 0, 11, 1, 10, 0 );
  1495. StartingBoxPoints[7].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMaxs.z );
  1496. STARTPOINTTOLINELINKS( 7, 6, 0, 10, 1, 9, 0 );
  1497. STARTBOXCONNECTION( 0, 0, 1, 0, 5 );
  1498. STARTBOXCONNECTION( 1, 1, 5, 1, 5 );
  1499. STARTBOXCONNECTION( 2, 5, 4, 2, 5 );
  1500. STARTBOXCONNECTION( 3, 4, 0, 3, 5 );
  1501. STARTBOXCONNECTION( 4, 0, 2, 3, 0 );
  1502. STARTBOXCONNECTION( 5, 1, 3, 0, 1 );
  1503. STARTBOXCONNECTION( 6, 5, 7, 1, 2 );
  1504. STARTBOXCONNECTION( 7, 4, 6, 2, 3 );
  1505. STARTBOXCONNECTION( 8, 2, 3, 4, 0 );
  1506. STARTBOXCONNECTION( 9, 3, 7, 4, 1 );
  1507. STARTBOXCONNECTION( 10, 7, 6, 4, 2 );
  1508. STARTBOXCONNECTION( 11, 6, 2, 4, 3 );
  1509. STARTBOXCONNECTION( 0, 0, 1, 5, 0 );
  1510. STARTBOXCONNECTION( 1, 1, 5, 5, 1 );
  1511. STARTBOXCONNECTION( 2, 5, 4, 5, 2 );
  1512. STARTBOXCONNECTION( 3, 4, 0, 5, 3 );
  1513. STARTBOXCONNECTION( 4, 0, 2, 0, 3 );
  1514. STARTBOXCONNECTION( 5, 1, 3, 1, 0 );
  1515. STARTBOXCONNECTION( 6, 5, 7, 2, 1 );
  1516. STARTBOXCONNECTION( 7, 4, 6, 3, 2 );
  1517. STARTBOXCONNECTION( 8, 2, 3, 0, 4 );
  1518. STARTBOXCONNECTION( 9, 3, 7, 1, 4 );
  1519. STARTBOXCONNECTION( 10, 7, 6, 2, 4 );
  1520. STARTBOXCONNECTION( 11, 6, 2, 3, 4 );
  1521. StartingBoxPolygons[0].vSurfaceNormal.Init( -1.0f, 0.0f, 0.0f );
  1522. StartingBoxPolygons[1].vSurfaceNormal.Init( 0.0f, 1.0f, 0.0f );
  1523. StartingBoxPolygons[2].vSurfaceNormal.Init( 1.0f, 0.0f, 0.0f );
  1524. StartingBoxPolygons[3].vSurfaceNormal.Init( 0.0f, -1.0f, 0.0f );
  1525. StartingBoxPolygons[4].vSurfaceNormal.Init( 0.0f, 0.0f, 1.0f );
  1526. StartingBoxPolygons[5].vSurfaceNormal.Init( 0.0f, 0.0f, -1.0f );
  1527. STARTPOLYGONTOLINELINKS( 0, 0, 1, 5, 1, 8, 0, 4, 0 );
  1528. STARTPOLYGONTOLINELINKS( 1, 1, 1, 6, 1, 9, 0, 5, 0 );
  1529. STARTPOLYGONTOLINELINKS( 2, 2, 1, 7, 1, 10, 0, 6, 0 );
  1530. STARTPOLYGONTOLINELINKS( 3, 3, 1, 4, 1, 11, 0, 7, 0 );
  1531. STARTPOLYGONTOLINELINKS( 4, 8, 1, 9, 1, 10, 1, 11, 1 );
  1532. STARTPOLYGONTOLINELINKS( 5, 0, 0, 3, 0, 2, 0, 1, 0 );
  1533. {
  1534. StartingPolygonList[0].pPolygon = &StartingBoxPolygons[0];
  1535. StartingPolygonList[0].pNext = &StartingPolygonList[1];
  1536. StartingPolygonList[0].pPrev = NULL;
  1537. StartingPolygonList[1].pPolygon = &StartingBoxPolygons[1];
  1538. StartingPolygonList[1].pNext = &StartingPolygonList[2];
  1539. StartingPolygonList[1].pPrev = &StartingPolygonList[0];
  1540. StartingPolygonList[2].pPolygon = &StartingBoxPolygons[2];
  1541. StartingPolygonList[2].pNext = &StartingPolygonList[3];
  1542. StartingPolygonList[2].pPrev = &StartingPolygonList[1];
  1543. StartingPolygonList[3].pPolygon = &StartingBoxPolygons[3];
  1544. StartingPolygonList[3].pNext = &StartingPolygonList[4];
  1545. StartingPolygonList[3].pPrev = &StartingPolygonList[2];
  1546. StartingPolygonList[4].pPolygon = &StartingBoxPolygons[4];
  1547. StartingPolygonList[4].pNext = &StartingPolygonList[5];
  1548. StartingPolygonList[4].pPrev = &StartingPolygonList[3];
  1549. StartingPolygonList[5].pPolygon = &StartingBoxPolygons[5];
  1550. StartingPolygonList[5].pNext = NULL;
  1551. StartingPolygonList[5].pPrev = &StartingPolygonList[4];
  1552. }
  1553. {
  1554. StartingLineList[0].pLine = &StartingBoxLines[0];
  1555. StartingLineList[0].pNext = &StartingLineList[1];
  1556. StartingLineList[0].pPrev = NULL;
  1557. StartingLineList[1].pLine = &StartingBoxLines[1];
  1558. StartingLineList[1].pNext = &StartingLineList[2];
  1559. StartingLineList[1].pPrev = &StartingLineList[0];
  1560. StartingLineList[2].pLine = &StartingBoxLines[2];
  1561. StartingLineList[2].pNext = &StartingLineList[3];
  1562. StartingLineList[2].pPrev = &StartingLineList[1];
  1563. StartingLineList[3].pLine = &StartingBoxLines[3];
  1564. StartingLineList[3].pNext = &StartingLineList[4];
  1565. StartingLineList[3].pPrev = &StartingLineList[2];
  1566. StartingLineList[4].pLine = &StartingBoxLines[4];
  1567. StartingLineList[4].pNext = &StartingLineList[5];
  1568. StartingLineList[4].pPrev = &StartingLineList[3];
  1569. StartingLineList[5].pLine = &StartingBoxLines[5];
  1570. StartingLineList[5].pNext = &StartingLineList[6];
  1571. StartingLineList[5].pPrev = &StartingLineList[4];
  1572. StartingLineList[6].pLine = &StartingBoxLines[6];
  1573. StartingLineList[6].pNext = &StartingLineList[7];
  1574. StartingLineList[6].pPrev = &StartingLineList[5];
  1575. StartingLineList[7].pLine = &StartingBoxLines[7];
  1576. StartingLineList[7].pNext = &StartingLineList[8];
  1577. StartingLineList[7].pPrev = &StartingLineList[6];
  1578. StartingLineList[8].pLine = &StartingBoxLines[8];
  1579. StartingLineList[8].pNext = &StartingLineList[9];
  1580. StartingLineList[8].pPrev = &StartingLineList[7];
  1581. StartingLineList[9].pLine = &StartingBoxLines[9];
  1582. StartingLineList[9].pNext = &StartingLineList[10];
  1583. StartingLineList[9].pPrev = &StartingLineList[8];
  1584. StartingLineList[10].pLine = &StartingBoxLines[10];
  1585. StartingLineList[10].pNext = &StartingLineList[11];
  1586. StartingLineList[10].pPrev = &StartingLineList[9];
  1587. StartingLineList[11].pLine = &StartingBoxLines[11];
  1588. StartingLineList[11].pNext = NULL;
  1589. StartingLineList[11].pPrev = &StartingLineList[10];
  1590. }
  1591. {
  1592. StartingPointList[0].pPoint = &StartingBoxPoints[0];
  1593. StartingPointList[0].pNext = &StartingPointList[1];
  1594. StartingPointList[0].pPrev = NULL;
  1595. StartingPointList[1].pPoint = &StartingBoxPoints[1];
  1596. StartingPointList[1].pNext = &StartingPointList[2];
  1597. StartingPointList[1].pPrev = &StartingPointList[0];
  1598. StartingPointList[2].pPoint = &StartingBoxPoints[2];
  1599. StartingPointList[2].pNext = &StartingPointList[3];
  1600. StartingPointList[2].pPrev = &StartingPointList[1];
  1601. StartingPointList[3].pPoint = &StartingBoxPoints[3];
  1602. StartingPointList[3].pNext = &StartingPointList[4];
  1603. StartingPointList[3].pPrev = &StartingPointList[2];
  1604. StartingPointList[4].pPoint = &StartingBoxPoints[4];
  1605. StartingPointList[4].pNext = &StartingPointList[5];
  1606. StartingPointList[4].pPrev = &StartingPointList[3];
  1607. StartingPointList[5].pPoint = &StartingBoxPoints[5];
  1608. StartingPointList[5].pNext = &StartingPointList[6];
  1609. StartingPointList[5].pPrev = &StartingPointList[4];
  1610. StartingPointList[6].pPoint = &StartingBoxPoints[6];
  1611. StartingPointList[6].pNext = &StartingPointList[7];
  1612. StartingPointList[6].pPrev = &StartingPointList[5];
  1613. StartingPointList[7].pPoint = &StartingBoxPoints[7];
  1614. StartingPointList[7].pNext = NULL;
  1615. StartingPointList[7].pPrev = &StartingPointList[6];
  1616. }
  1617. }
  1618. return ClipLinkedGeometry( StartingPolygonList, StartingLineList, StartingPointList, pOutwardFacingPlanes, iPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory );
  1619. }
  1620. #ifdef _DEBUG
  1621. void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile )
  1622. {
  1623. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1624. Vector vMins = vCenter - vExtents;
  1625. Vector vMaxs = vCenter + vExtents;
  1626. //x min side
  1627. fprintf( pFile, "4\n" );
  1628. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1629. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1630. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1631. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1632. fprintf( pFile, "4\n" );
  1633. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1634. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1635. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1636. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1637. //x max side
  1638. fprintf( pFile, "4\n" );
  1639. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1640. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1641. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1642. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1643. fprintf( pFile, "4\n" );
  1644. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1645. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1646. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1647. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1648. //y min side
  1649. fprintf( pFile, "4\n" );
  1650. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1651. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1652. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1653. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1654. fprintf( pFile, "4\n" );
  1655. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1656. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1657. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1658. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1659. //y max side
  1660. fprintf( pFile, "4\n" );
  1661. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1662. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1663. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1664. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1665. fprintf( pFile, "4\n" );
  1666. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1667. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1668. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1669. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1670. //z min side
  1671. fprintf( pFile, "4\n" );
  1672. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1673. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1674. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1675. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1676. fprintf( pFile, "4\n" );
  1677. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1678. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1679. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1680. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  1681. //z max side
  1682. fprintf( pFile, "4\n" );
  1683. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1684. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1685. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1686. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1687. fprintf( pFile, "4\n" );
  1688. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1689. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1690. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1691. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  1692. #endif
  1693. }
  1694. void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile )
  1695. {
  1696. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1697. Vector vDirection = vPoint2 - vPoint1;
  1698. vDirection.NormalizeInPlace();
  1699. Vector vPseudoPerpandicular = vec3_origin;
  1700. if( vDirection.x != 0.0f )
  1701. vPseudoPerpandicular.z = 1.0f;
  1702. else
  1703. vPseudoPerpandicular.x = 1.0f;
  1704. Vector vWidth = vDirection.Cross( vPseudoPerpandicular );
  1705. vWidth.NormalizeInPlace();
  1706. Vector vHeight = vDirection.Cross( vWidth );
  1707. vHeight.NormalizeInPlace();
  1708. fThickness *= 0.5f; //we use half thickness in both directions
  1709. vDirection *= fThickness;
  1710. vWidth *= fThickness;
  1711. vHeight *= fThickness;
  1712. Vector vLinePoints[8];
  1713. vLinePoints[0] = vPoint1 - vDirection - vWidth - vHeight;
  1714. vLinePoints[1] = vPoint1 - vDirection - vWidth + vHeight;
  1715. vLinePoints[2] = vPoint1 - vDirection + vWidth - vHeight;
  1716. vLinePoints[3] = vPoint1 - vDirection + vWidth + vHeight;
  1717. vLinePoints[4] = vPoint2 + vDirection - vWidth - vHeight;
  1718. vLinePoints[5] = vPoint2 + vDirection - vWidth + vHeight;
  1719. vLinePoints[6] = vPoint2 + vDirection + vWidth - vHeight;
  1720. vLinePoints[7] = vPoint2 + vDirection + vWidth + vHeight;
  1721. const Vector *pLineColors[8] = { &vColor1, &vColor1, &vColor1, &vColor1, &vColor2, &vColor2, &vColor2, &vColor2 };
  1722. #define DPTGLV_LINE_WRITEPOINT(index) fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vLinePoints[index].x, vLinePoints[index].y, vLinePoints[index].z, pLineColors[index]->x, pLineColors[index]->y, pLineColors[index]->z );
  1723. #define DPTGLV_LINE_DOUBLESIDEDQUAD(index1,index2,index3,index4)\
  1724. fprintf( pFile, "4\n" );\
  1725. DPTGLV_LINE_WRITEPOINT(index1);\
  1726. DPTGLV_LINE_WRITEPOINT(index2);\
  1727. DPTGLV_LINE_WRITEPOINT(index3);\
  1728. DPTGLV_LINE_WRITEPOINT(index4);\
  1729. fprintf( pFile, "4\n" );\
  1730. DPTGLV_LINE_WRITEPOINT(index4);\
  1731. DPTGLV_LINE_WRITEPOINT(index3);\
  1732. DPTGLV_LINE_WRITEPOINT(index2);\
  1733. DPTGLV_LINE_WRITEPOINT(index1);
  1734. DPTGLV_LINE_DOUBLESIDEDQUAD(0,4,6,2);
  1735. DPTGLV_LINE_DOUBLESIDEDQUAD(3,7,5,1);
  1736. DPTGLV_LINE_DOUBLESIDEDQUAD(1,5,4,0);
  1737. DPTGLV_LINE_DOUBLESIDEDQUAD(2,6,7,3);
  1738. DPTGLV_LINE_DOUBLESIDEDQUAD(0,2,3,1);
  1739. DPTGLV_LINE_DOUBLESIDEDQUAD(5,7,6,4);
  1740. #endif
  1741. }
  1742. void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform )
  1743. {
  1744. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1745. if ( (pPolyhedron == NULL) || (pPolyhedron->iVertexCount == 0) )
  1746. return;
  1747. if( pTransform == NULL )
  1748. pTransform = &s_matIdentity;
  1749. printf("Writing %s...\n", pFilename );
  1750. FILE *pFile = fopen( pFilename, "ab" );
  1751. //randomizing an array of colors to help spot shared/unshared vertices
  1752. Vector *pColors = (Vector *)stackalloc( sizeof( Vector ) * pPolyhedron->iVertexCount );
  1753. int counter;
  1754. for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter )
  1755. {
  1756. pColors[counter].Init( rand()/32768.0f, rand()/32768.0f, rand()/32768.0f );
  1757. }
  1758. Vector *pTransformedPoints = (Vector *)stackalloc( pPolyhedron->iVertexCount * sizeof( Vector ) );
  1759. for ( counter = 0; counter != pPolyhedron->iVertexCount; ++counter )
  1760. {
  1761. pTransformedPoints[counter] = (*pTransform) * pPolyhedron->pVertices[counter];
  1762. }
  1763. for ( counter = 0; counter != pPolyhedron->iPolygonCount; ++counter )
  1764. {
  1765. fprintf( pFile, "%i\n", pPolyhedron->pPolygons[counter].iIndexCount );
  1766. int counter2;
  1767. for( counter2 = 0; counter2 != pPolyhedron->pPolygons[counter].iIndexCount; ++counter2 )
  1768. {
  1769. Polyhedron_IndexedLineReference_t *pLineReference = &pPolyhedron->pIndices[pPolyhedron->pPolygons[counter].iFirstIndex + counter2];
  1770. Vector *pVertex = &pTransformedPoints[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]];
  1771. Vector *pColor = &pColors[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]];
  1772. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n",pVertex->x, pVertex->y, pVertex->z, pColor->x, pColor->y, pColor->z );
  1773. }
  1774. }
  1775. for( counter = 0; counter != pPolyhedron->iLineCount; ++counter )
  1776. {
  1777. const Vector vOne( 1.0f, 1.0f, 1.0f );
  1778. DumpLineToGLView( pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[0]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[0]],
  1779. pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[1]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[1]],
  1780. 0.1f, pFile );
  1781. }
  1782. for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter )
  1783. {
  1784. const Vector vPointHalfSize(0.15f, 0.15f, 0.15f );
  1785. DumpAABBToGLView( pTransformedPoints[counter], vPointHalfSize, pColors[counter], pFile );
  1786. }
  1787. fclose( pFile );
  1788. #endif
  1789. }
  1790. void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform )
  1791. {
  1792. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1793. if( pTransform == NULL )
  1794. pTransform = &s_matIdentity;
  1795. FILE *pFile = fopen( pszFileName, "ab" );
  1796. //transform the plane
  1797. Vector vNormal = pTransform->ApplyRotation( *(Vector *)pPlane );
  1798. float fDist = pPlane[3] * vNormal.NormalizeInPlace(); //possible scaling going on
  1799. fDist += vNormal.Dot( pTransform->GetTranslation() );
  1800. Vector vPlaneVerts[4];
  1801. PolyFromPlane( vPlaneVerts, vNormal, fDist, 100000.0f );
  1802. fprintf( pFile, "4\n" );
  1803. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[0].x, vPlaneVerts[0].y, vPlaneVerts[0].z, fGrayScale, fGrayScale, fGrayScale );
  1804. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[1].x, vPlaneVerts[1].y, vPlaneVerts[1].z, fGrayScale, fGrayScale, fGrayScale );
  1805. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[2].x, vPlaneVerts[2].y, vPlaneVerts[2].z, fGrayScale, fGrayScale, fGrayScale );
  1806. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[3].x, vPlaneVerts[3].y, vPlaneVerts[3].z, fGrayScale, fGrayScale, fGrayScale );
  1807. fclose( pFile );
  1808. #endif
  1809. }
  1810. #endif