Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3895 lines
159 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. // Notes: For some semblance of clarity. All spatial orientation notation assumes you're
  8. // looking at the polyhedron from an outside point located spherically above
  9. // the primitive in question
  10. //
  11. //======================================================================================//
  12. #include "mathlib/polyhedron.h"
  13. #include "mathlib/vmatrix.h"
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include "tier1/utlvector.h"
  17. #include "mathlib/ssemath.h"
  18. struct GeneratePolyhedronFromPlanes_Point;
  19. struct GeneratePolyhedronFromPlanes_PointLL;
  20. struct GeneratePolyhedronFromPlanes_Line;
  21. struct GeneratePolyhedronFromPlanes_LineLL;
  22. struct GeneratePolyhedronFromPlanes_Polygon;
  23. struct GeneratePolyhedronFromPlanes_PolygonLL;
  24. struct GeneratePolyhedronFromPlanes_UnorderedPointLL;
  25. struct GeneratePolyhedronFromPlanes_UnorderedLineLL;
  26. struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL;
  27. Vector FindPointInPlanes( const float *pPlanes, int planeCount );
  28. bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs );
  29. CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, int iPointCount, const fltx4 *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory, fltx4 vShiftResultPositions );
  30. CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory, fltx4 vShiftResultPositions );
  31. //#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
  32. //#define DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS //dumps successfully generated polyhedrons
  33. #define USE_WORLD_CENTERED_POSITIONS //shift all our incoming math towards world origin before performing operations on it, shift it back in the result.
  34. #ifdef DBGFLAG_ASSERT
  35. void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform, const char *szfileOpenOptions = "ab" );
  36. void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform );
  37. void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile );
  38. void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile );
  39. #if defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( WIN32 )
  40. #include "winlite.h"
  41. #endif
  42. static VMatrix s_matIdentity( 1.0f, 0.0f, 0.0f, 0.0f,
  43. 0.0f, 1.0f, 0.0f, 0.0f,
  44. 0.0f, 0.0f, 1.0f, 0.0f,
  45. 0.0f, 0.0f, 0.0f, 1.0f );
  46. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  47. void DumpWorkingStatePolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDeadPolygons,
  48. GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines, GeneratePolyhedronFromPlanes_UnorderedLineLL *pDeadLines,
  49. GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPoints,
  50. const char *pFilename, const VMatrix *pTransform );
  51. #endif
  52. #if defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS )
  53. static int g_iPolyhedronDumpCounter = 0;
  54. #endif
  55. #define DBG_ONLY(x) x
  56. #else
  57. #define DBG_ONLY(x)
  58. #endif
  59. // memdbgon must be the last include file in a .cpp file!!!
  60. #include "tier0/memdbgon.h"
  61. #if defined( DBGFLAG_ASSERT ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  62. void CreateDumpDirectory( const char *szDirectoryName )
  63. {
  64. #if defined( WIN32 )
  65. CreateDirectory( szDirectoryName, NULL );
  66. #else
  67. Assert( false ); //TODO: create directories in linux
  68. #endif
  69. }
  70. #define DEBUG_POLYHEDRON_CONVERSION 1
  71. typedef bool (*PFN_PolyhedronCarvingDebugStepCallback)( CPolyhedron *pPolyhedron ); //function that receives a polyhedron conversion after each cut. For the slowest, surest debugging possible. Returns true if the polyhedron passes mustard, false to dump the current work state
  72. PFN_PolyhedronCarvingDebugStepCallback g_pPolyhedronCarvingDebugStepCallback = NULL;
  73. #endif
  74. void CPolyhedron_AllocByNew::Release( void )
  75. {
  76. delete this;
  77. }
  78. 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
  79. {
  80. void *pMemory = new unsigned char [ sizeof( CPolyhedron_AllocByNew ) +
  81. (iVertices * sizeof(Vector)) +
  82. (iLines * sizeof(Polyhedron_IndexedLine_t)) +
  83. (iIndices * sizeof( Polyhedron_IndexedLineReference_t )) +
  84. (iPolygons * sizeof( Polyhedron_IndexedPolygon_t ))];
  85. #include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging
  86. CPolyhedron_AllocByNew *pAllocated = new ( pMemory ) CPolyhedron_AllocByNew;
  87. #include "tier0/memdbgon.h"
  88. pAllocated->iVertexCount = iVertices;
  89. pAllocated->iLineCount = iLines;
  90. pAllocated->iIndexCount = iIndices;
  91. pAllocated->iPolygonCount = iPolygons;
  92. pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class
  93. pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices);
  94. pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines);
  95. pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices);
  96. return pAllocated;
  97. }
  98. class CPolyhedron_TempMemory : public CPolyhedron
  99. {
  100. public:
  101. #ifdef DBGFLAG_ASSERT
  102. int iReferenceCount;
  103. #endif
  104. virtual void Release( void )
  105. {
  106. #ifdef DBGFLAG_ASSERT
  107. --iReferenceCount;
  108. #endif
  109. }
  110. CPolyhedron_TempMemory( void )
  111. #ifdef DBGFLAG_ASSERT
  112. : iReferenceCount( 0 )
  113. #endif
  114. { };
  115. };
  116. static CUtlVector<unsigned char> s_TempMemoryPolyhedron_Buffer;
  117. static CPolyhedron_TempMemory s_TempMemoryPolyhedron;
  118. 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
  119. {
  120. AssertMsg( s_TempMemoryPolyhedron.iReferenceCount == 0, "Temporary polyhedron memory being rewritten before released" );
  121. #ifdef DBGFLAG_ASSERT
  122. ++s_TempMemoryPolyhedron.iReferenceCount;
  123. #endif
  124. s_TempMemoryPolyhedron_Buffer.SetCount( (sizeof( Vector ) * iVertices) +
  125. (sizeof( Polyhedron_IndexedLine_t ) * iLines) +
  126. (sizeof( Polyhedron_IndexedLineReference_t ) * iIndices) +
  127. (sizeof( Polyhedron_IndexedPolygon_t ) * iPolygons) );
  128. s_TempMemoryPolyhedron.iVertexCount = iVertices;
  129. s_TempMemoryPolyhedron.iLineCount = iLines;
  130. s_TempMemoryPolyhedron.iIndexCount = iIndices;
  131. s_TempMemoryPolyhedron.iPolygonCount = iPolygons;
  132. s_TempMemoryPolyhedron.pVertices = (Vector *)s_TempMemoryPolyhedron_Buffer.Base();
  133. s_TempMemoryPolyhedron.pLines = (Polyhedron_IndexedLine_t *)(&s_TempMemoryPolyhedron.pVertices[s_TempMemoryPolyhedron.iVertexCount]);
  134. s_TempMemoryPolyhedron.pIndices = (Polyhedron_IndexedLineReference_t *)(&s_TempMemoryPolyhedron.pLines[s_TempMemoryPolyhedron.iLineCount]);
  135. s_TempMemoryPolyhedron.pPolygons = (Polyhedron_IndexedPolygon_t *)(&s_TempMemoryPolyhedron.pIndices[s_TempMemoryPolyhedron.iIndexCount]);
  136. return &s_TempMemoryPolyhedron;
  137. }
  138. Vector CPolyhedron::Center( void ) const
  139. {
  140. if( iVertexCount == 0 )
  141. return vec3_origin;
  142. Vector vAABBMin, vAABBMax;
  143. vAABBMin = vAABBMax = pVertices[0];
  144. for( int i = 1; i != iVertexCount; ++i )
  145. {
  146. Vector &vPoint = pVertices[i];
  147. if( vPoint.x < vAABBMin.x )
  148. vAABBMin.x = vPoint.x;
  149. if( vPoint.y < vAABBMin.y )
  150. vAABBMin.y = vPoint.y;
  151. if( vPoint.z < vAABBMin.z )
  152. vAABBMin.z = vPoint.z;
  153. if( vPoint.x > vAABBMax.x )
  154. vAABBMax.x = vPoint.x;
  155. if( vPoint.y > vAABBMax.y )
  156. vAABBMax.y = vPoint.y;
  157. if( vPoint.z > vAABBMax.z )
  158. vAABBMax.z = vPoint.z;
  159. }
  160. return ((vAABBMin + vAABBMax) * 0.5f);
  161. }
  162. enum PolyhedronPointPlanarity
  163. {
  164. POINT_DEAD,
  165. POINT_ONPLANE,
  166. POINT_ALIVE
  167. };
  168. struct GeneratePolyhedronFromPlanes_Point //must be aligned to 16 byte boundary
  169. {
  170. fltx4 ptPosition; //w = -1 to make plane distance an all addition operation after the multiply
  171. GeneratePolyhedronFromPlanes_LineLL *pConnectedLines; //keep these in a clockwise order, circular linking
  172. float fPlaneDist; //used in plane cutting
  173. PolyhedronPointPlanarity planarity;
  174. union //temporary work variables
  175. {
  176. int iSaveIndices;
  177. };
  178. #ifdef DBGFLAG_ASSERT
  179. struct ClipDebugData_t
  180. {
  181. void Reset( void ) { memset( this, 0, sizeof( *this ) ); }
  182. bool bIsNew;
  183. Vector vWorkingStateColorOverride;
  184. bool bVisited;
  185. float fInitialPlaneDistance;
  186. } debugdata;
  187. #endif
  188. };
  189. enum PolyhedronLinePlanarity
  190. {
  191. LINE_ONPLANE = 0,
  192. LINE_ALIVE = (1 << 0),
  193. LINE_DEAD = (1 << 1),
  194. LINE_CUT = LINE_ALIVE | LINE_DEAD,
  195. };
  196. PolyhedronLinePlanarity &operator|=( PolyhedronLinePlanarity &a, const PolyhedronLinePlanarity &b )
  197. {
  198. a = (PolyhedronLinePlanarity)((int)a | int(b));
  199. return a;
  200. }
  201. struct GeneratePolyhedronFromPlanes_LineLL
  202. {
  203. GeneratePolyhedronFromPlanes_Line *pLine;
  204. //whatever is referencing the line should know which side of the line it's on (points and polygons).
  205. //for polygons, it's the index back to the polygon's self. It's also which point to follow to continue going clockwise, which makes polygon 0 the one on the left side of an upward facing line vector
  206. //for points, it's the OTHER point's index
  207. int iReferenceIndex;
  208. GeneratePolyhedronFromPlanes_LineLL *pPrev;
  209. GeneratePolyhedronFromPlanes_LineLL *pNext;
  210. };
  211. struct GeneratePolyhedronFromPlanes_Line
  212. {
  213. GeneratePolyhedronFromPlanes_Point *pPoints[2]; //the 2 connecting points in no particular order
  214. GeneratePolyhedronFromPlanes_Polygon *pPolygons[2]; //viewing from the outside with the point connections going up, 0 is the left polygon, 1 is the right
  215. int iSaveIndices;
  216. PolyhedronLinePlanarity planarity;
  217. bool bNewLengthThisPass;
  218. GeneratePolyhedronFromPlanes_LineLL PointLineLinks[2]; //rather than going into a point and searching for its link to this line, lets just cache it to eliminate searching
  219. GeneratePolyhedronFromPlanes_LineLL PolygonLineLinks[2]; //rather than going into a polygon and searching for its link to this line, lets just cache it to eliminate searching
  220. #ifdef POLYHEDRON_EXTENSIVE_DEBUGGING
  221. int iDebugFlags;
  222. #endif
  223. void InitLineLinks( void )
  224. {
  225. PointLineLinks[0].iReferenceIndex = 1;
  226. PointLineLinks[1].iReferenceIndex = 0;
  227. PolygonLineLinks[0].iReferenceIndex = 0;
  228. PolygonLineLinks[1].iReferenceIndex = 1;
  229. PointLineLinks[0].pLine = PointLineLinks[1].pLine = PolygonLineLinks[0].pLine = PolygonLineLinks[1].pLine = this;
  230. }
  231. #ifdef DBGFLAG_ASSERT
  232. struct ClipDebugData_t
  233. {
  234. void Reset( void ) { memset( this, 0, sizeof( *this ) ); }
  235. bool bIsNew; //was generated during this cut
  236. Vector vWorkingStateColorOverride;
  237. bool bTested;
  238. } debugdata;
  239. #endif
  240. };
  241. struct GeneratePolyhedronFromPlanes_Polygon
  242. {
  243. Vector vSurfaceNormal;
  244. //float fNormalDist;
  245. GeneratePolyhedronFromPlanes_LineLL *pLines; //keep these in a clockwise order, circular linking
  246. bool bDead;
  247. bool bHasNewPoints;
  248. bool bMovedExistingPoints;
  249. #ifdef DBGFLAG_ASSERT
  250. struct ClipDebugData_t
  251. {
  252. void Reset( void ) { memset( this, 0, sizeof( *this ) ); }
  253. bool bIsNew; //only one should be new per clip, unless we triangulate
  254. Vector vWorkingStateColorOverride;
  255. } debugdata;
  256. #endif
  257. };
  258. struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL //an unordered collection of polygons
  259. {
  260. GeneratePolyhedronFromPlanes_Polygon polygon;
  261. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNext;
  262. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPrev;
  263. };
  264. struct GeneratePolyhedronFromPlanes_UnorderedLineLL //an unordered collection of lines
  265. {
  266. GeneratePolyhedronFromPlanes_Line line;
  267. GeneratePolyhedronFromPlanes_UnorderedLineLL *pNext;
  268. GeneratePolyhedronFromPlanes_UnorderedLineLL *pPrev;
  269. };
  270. #pragma pack( push )
  271. #pragma pack( 16 ) //help align the position to 16 byte boundaries when in arrays
  272. struct GeneratePolyhedronFromPlanes_UnorderedPointLL //an unordered collection of points
  273. {
  274. GeneratePolyhedronFromPlanes_Point point;
  275. GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext;
  276. GeneratePolyhedronFromPlanes_UnorderedPointLL *pPrev;
  277. };
  278. #pragma pack(pop)
  279. #ifdef DBGFLAG_ASSERT
  280. void Debug_ResetWorkingStateColorOverrides( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines )
  281. {
  282. while( pAllPolygons )
  283. {
  284. pAllPolygons->polygon.debugdata.vWorkingStateColorOverride.Init();
  285. pAllPolygons = pAllPolygons->pNext;
  286. }
  287. while( pAllPoints )
  288. {
  289. pAllPoints->point.debugdata.vWorkingStateColorOverride.Init();
  290. pAllPoints = pAllPoints->pNext;
  291. }
  292. while( pAllLines )
  293. {
  294. pAllLines->line.debugdata.vWorkingStateColorOverride.Init();
  295. pAllLines = pAllLines->pNext;
  296. }
  297. }
  298. #define DBG_RESETWORKINGSTATECOLORS() Debug_ResetWorkingStateColorOverrides( pAllPolygons, pAllPoints, pAllLines );
  299. #else
  300. #define DBG_RESETWORKINGSTATECOLORS()
  301. #endif
  302. CPolyhedron *ClipPolyhedron( const CPolyhedron *pExistingPolyhedron, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory )
  303. {
  304. if( pExistingPolyhedron == NULL )
  305. return NULL;
  306. AssertMsg( (pExistingPolyhedron->iVertexCount >= 3) && (pExistingPolyhedron->iPolygonCount >= 2), "Polyhedron doesn't meet absolute minimum spec" );
  307. const size_t kFltX4Align = sizeof( fltx4 ) - 1;
  308. uint8 *pAlignedAlloc = (uint8 *)stackalloc( (sizeof( fltx4 ) * iPlaneCount) + kFltX4Align );
  309. pAlignedAlloc = (uint8 *)(((size_t)(pAlignedAlloc + kFltX4Align)) & ~kFltX4Align);
  310. fltx4 *pUsefulPlanes = (fltx4 *)pAlignedAlloc;
  311. int iUsefulPlaneCount = 0;
  312. Vector *pExistingVertices = pExistingPolyhedron->pVertices;
  313. //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
  314. {
  315. int iLiveCount = 0;
  316. int iDeadCount = 0;
  317. const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon;
  318. for( int i = 0; i != iPlaneCount; ++i )
  319. {
  320. Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(i * 4) + 0]);
  321. float fPlaneDist = pOutwardFacingPlanes[(i * 4) + 3];
  322. for( int j = 0; j != pExistingPolyhedron->iVertexCount; ++j )
  323. {
  324. float fPointDist = vNormal.Dot( pExistingVertices[j] ) - fPlaneDist;
  325. if( fPointDist <= fNegativeOnPlaneEpsilon )
  326. ++iLiveCount;
  327. else if( fPointDist > fOnPlaneEpsilon )
  328. ++iDeadCount;
  329. }
  330. if( iLiveCount == 0 )
  331. {
  332. //all points are dead or on the plane, so the polyhedron is dead
  333. return NULL;
  334. }
  335. if( iDeadCount != 0 )
  336. {
  337. //at least one point died, this plane yields useful results
  338. SubFloat( pUsefulPlanes[iUsefulPlaneCount], 0 ) = vNormal.x; //PolyhedronFloatStandardize( vNormal.x );
  339. SubFloat( pUsefulPlanes[iUsefulPlaneCount], 1 ) = vNormal.y; //PolyhedronFloatStandardize( vNormal.y );
  340. SubFloat( pUsefulPlanes[iUsefulPlaneCount], 2 ) = vNormal.z; //PolyhedronFloatStandardize( vNormal.z );
  341. SubFloat( pUsefulPlanes[iUsefulPlaneCount], 3 ) = fPlaneDist; //PolyhedronFloatStandardize( fPlaneDist );
  342. ++iUsefulPlaneCount;
  343. }
  344. }
  345. }
  346. if( iUsefulPlaneCount == 0 )
  347. {
  348. //testing shows that the polyhedron won't even be cut, clone the existing polyhedron and return that
  349. CPolyhedron *pReturn;
  350. if( bUseTemporaryMemory )
  351. {
  352. pReturn = GetTempPolyhedron( pExistingPolyhedron->iVertexCount,
  353. pExistingPolyhedron->iLineCount,
  354. pExistingPolyhedron->iIndexCount,
  355. pExistingPolyhedron->iPolygonCount );
  356. }
  357. else
  358. {
  359. pReturn = CPolyhedron_AllocByNew::Allocate( pExistingPolyhedron->iVertexCount,
  360. pExistingPolyhedron->iLineCount,
  361. pExistingPolyhedron->iIndexCount,
  362. pExistingPolyhedron->iPolygonCount );
  363. }
  364. memcpy( pReturn->pVertices, pExistingPolyhedron->pVertices, sizeof( Vector ) * pReturn->iVertexCount );
  365. memcpy( pReturn->pLines, pExistingPolyhedron->pLines, sizeof( Polyhedron_IndexedLine_t ) * pReturn->iLineCount );
  366. memcpy( pReturn->pIndices, pExistingPolyhedron->pIndices, sizeof( Polyhedron_IndexedLineReference_t ) * pReturn->iIndexCount );
  367. memcpy( pReturn->pPolygons, pExistingPolyhedron->pPolygons, sizeof( Polyhedron_IndexedPolygon_t ) * pReturn->iPolygonCount );
  368. #if defined( DEBUG_POLYHEDRON_CONVERSION )
  369. //last bit of debugging from whatever outside source wants this stupid thing
  370. if( g_pPolyhedronCarvingDebugStepCallback != NULL )
  371. {
  372. AssertMsg( g_pPolyhedronCarvingDebugStepCallback( pReturn ), "Outside conversion failed" );
  373. }
  374. #endif
  375. return pReturn;
  376. }
  377. //convert the polyhedron to linked geometry
  378. GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) );
  379. GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) );
  380. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) );
  381. #if defined( USE_WORLD_CENTERED_POSITIONS )
  382. fltx4 vPointOffset = LoadZeroSIMD();
  383. #endif
  384. //setup points
  385. for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i )
  386. {
  387. SubFloat( pPoints[i].point.ptPosition, 0 ) = pExistingPolyhedron->pVertices[i].x;
  388. SubFloat( pPoints[i].point.ptPosition, 1 ) = pExistingPolyhedron->pVertices[i].y;
  389. SubFloat( pPoints[i].point.ptPosition, 2 ) = pExistingPolyhedron->pVertices[i].z;
  390. SubFloat( pPoints[i].point.ptPosition, 3 ) = -1.0f;
  391. #if defined( USE_WORLD_CENTERED_POSITIONS )
  392. vPointOffset = AddSIMD( vPointOffset, pPoints[i].point.ptPosition );
  393. #endif
  394. pPoints[i].point.pConnectedLines = NULL; //we won't be circular linking until later
  395. }
  396. #if defined( USE_WORLD_CENTERED_POSITIONS )
  397. //move everything towards origin for more precise math
  398. vPointOffset = MulSIMD( vPointOffset, ReplicateX4( -1.0f / (float)pExistingPolyhedron->iVertexCount ) );
  399. vPointOffset = FloorSIMD( vPointOffset );
  400. SubFloat( vPointOffset, 3 ) = -1.0f;
  401. for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i )
  402. {
  403. pPoints[i].point.ptPosition = AddSIMD( pPoints[i].point.ptPosition, vPointOffset );
  404. SubFloat( pPoints[i].point.ptPosition, 3 ) = -1.0f;
  405. }
  406. for( int i = 0; i != iUsefulPlaneCount; ++i )
  407. {
  408. fltx4 vMul = MulSIMD( pUsefulPlanes[i], vPointOffset );
  409. SubFloat( pUsefulPlanes[i], 3 ) = SubFloat(vMul, 0) + SubFloat(vMul, 1) + SubFloat(vMul, 2) - SubFloat(vMul, 3 );
  410. }
  411. fltx4 vResultOffset = NegSIMD( vPointOffset );
  412. SubFloat( vResultOffset, 3 ) = 0.0f;
  413. #else
  414. fltx4 vResultOffset = LoadZeroSIMD();
  415. #endif
  416. //setup lines and interlink to points (line links are not yet circularly linked, and are unordered)
  417. for( int i = 0; i != pExistingPolyhedron->iLineCount; ++i )
  418. {
  419. pLines[i].line.InitLineLinks();
  420. for( int j = 0; j != 2; ++j )
  421. {
  422. pLines[i].line.pPoints[j] = &pPoints[pExistingPolyhedron->pLines[i].iPointIndices[j]].point;
  423. GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pLines[i].line.PointLineLinks[j];
  424. //pLineLink->pPrev = NULL;
  425. pLineLink->pNext = pLines[i].line.pPoints[j]->pConnectedLines;
  426. pLines[i].line.pPoints[j]->pConnectedLines = pLineLink;
  427. }
  428. }
  429. //setup polygons
  430. for( int i = 0; i != pExistingPolyhedron->iPolygonCount; ++i )
  431. {
  432. pPolygons[i].polygon.vSurfaceNormal = pExistingPolyhedron->pPolygons[i].polyNormal;
  433. Polyhedron_IndexedLineReference_t *pOffsetPolyhedronLines = &pExistingPolyhedron->pIndices[pExistingPolyhedron->pPolygons[i].iFirstIndex];
  434. GeneratePolyhedronFromPlanes_LineLL *pFirstLink = &pLines[pOffsetPolyhedronLines[0].iLineIndex].line.PolygonLineLinks[pOffsetPolyhedronLines[0].iEndPointIndex];
  435. pPolygons[i].polygon.pLines = pFirstLink; //technically going to link to itself on first pass, then get linked properly immediately afterward
  436. for( int j = 0; j != pExistingPolyhedron->pPolygons[i].iIndexCount; ++j )
  437. {
  438. GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pLines[pOffsetPolyhedronLines[j].iLineIndex].line.PolygonLineLinks[pOffsetPolyhedronLines[j].iEndPointIndex];
  439. pLineLink->pLine->pPolygons[pLineLink->iReferenceIndex] = &pPolygons[i].polygon;
  440. pLineLink->pPrev = pPolygons[i].polygon.pLines;
  441. pPolygons[i].polygon.pLines->pNext = pLineLink;
  442. pPolygons[i].polygon.pLines = pLineLink;
  443. }
  444. pFirstLink->pPrev = pPolygons[i].polygon.pLines;
  445. pPolygons[i].polygon.pLines->pNext = pFirstLink;
  446. }
  447. //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
  448. for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i )
  449. {
  450. //interlink the points
  451. {
  452. GeneratePolyhedronFromPlanes_LineLL *pLastVisitedLink = pPoints[i].point.pConnectedLines;
  453. GeneratePolyhedronFromPlanes_LineLL *pCurrentLink = pLastVisitedLink;
  454. do
  455. {
  456. pCurrentLink->pPrev = pLastVisitedLink;
  457. pLastVisitedLink = pCurrentLink;
  458. pCurrentLink = pCurrentLink->pNext;
  459. } while( pCurrentLink );
  460. //circular link
  461. pLastVisitedLink->pNext = pPoints[i].point.pConnectedLines;
  462. pPoints[i].point.pConnectedLines->pPrev = pLastVisitedLink;
  463. }
  464. //fix ordering
  465. GeneratePolyhedronFromPlanes_LineLL *pFirstLink = pPoints[i].point.pConnectedLines;
  466. GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pFirstLink;
  467. GeneratePolyhedronFromPlanes_LineLL *pSearchLink;
  468. GeneratePolyhedronFromPlanes_Polygon *pLookingForPolygon;
  469. Assert( pFirstLink->pNext != pFirstLink );
  470. do
  471. {
  472. pLookingForPolygon = pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex]; //grab pointer to left polygon
  473. pSearchLink = pWorkLink->pPrev;
  474. while( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] != pLookingForPolygon )
  475. pSearchLink = pSearchLink->pPrev;
  476. Assert( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] == pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex] );
  477. //pluck the search link from wherever it is
  478. pSearchLink->pPrev->pNext = pSearchLink->pNext;
  479. pSearchLink->pNext->pPrev = pSearchLink->pPrev;
  480. //insert the search link just before the work link
  481. pSearchLink->pPrev = pWorkLink->pPrev;
  482. pSearchLink->pNext = pWorkLink;
  483. pSearchLink->pPrev->pNext = pSearchLink;
  484. pWorkLink->pPrev = pSearchLink;
  485. pWorkLink = pSearchLink;
  486. } while( pWorkLink != pFirstLink );
  487. }
  488. //setup point collection
  489. {
  490. pPoints[0].pPrev = NULL;
  491. pPoints[0].pNext = &pPoints[1];
  492. int iLastPoint = pExistingPolyhedron->iVertexCount - 1;
  493. for( int i = 1; i != iLastPoint; ++i )
  494. {
  495. pPoints[i].pPrev = &pPoints[i - 1];
  496. pPoints[i].pNext = &pPoints[i + 1];
  497. }
  498. pPoints[iLastPoint].pPrev = &pPoints[iLastPoint - 1];
  499. pPoints[iLastPoint].pNext = NULL;
  500. }
  501. //setup line collection
  502. {
  503. pLines[0].pPrev = NULL;
  504. pLines[0].pNext = &pLines[1];
  505. int iLastLine = pExistingPolyhedron->iLineCount - 1;
  506. for( int i = 1; i != iLastLine; ++i )
  507. {
  508. pLines[i].pPrev = &pLines[i - 1];
  509. pLines[i].pNext = &pLines[i + 1];
  510. }
  511. pLines[iLastLine].pPrev = &pLines[iLastLine - 1];
  512. pLines[iLastLine].pNext = NULL;
  513. }
  514. //setup polygon collection
  515. {
  516. pPolygons[0].pPrev = NULL;
  517. pPolygons[0].pNext = &pPolygons[1];
  518. int iLastPolygon = pExistingPolyhedron->iPolygonCount - 1;
  519. for( int i = 1; i != iLastPolygon; ++i )
  520. {
  521. pPolygons[i].pPrev = &pPolygons[i - 1];
  522. pPolygons[i].pNext = &pPolygons[i + 1];
  523. }
  524. pPolygons[iLastPolygon].pPrev = &pPolygons[iLastPolygon - 1];
  525. pPolygons[iLastPolygon].pNext = NULL;
  526. }
  527. CPolyhedron *pRetVal = ClipLinkedGeometry( pPolygons, pLines, pPoints, pExistingPolyhedron->iVertexCount, pUsefulPlanes, iUsefulPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory, vResultOffset );
  528. #if defined( USE_WORLD_CENTERED_POSITIONS ) && defined( DEBUG_POLYHEDRON_CONVERSION )
  529. //last bit of debugging from whatever outside source wants this stupid thing
  530. if( pRetVal && (g_pPolyhedronCarvingDebugStepCallback != NULL) )
  531. {
  532. VMatrix matScaleCentered;
  533. matScaleCentered.Identity();
  534. matScaleCentered[0][0] = matScaleCentered[1][1] = matScaleCentered[2][2] = 10.0f;
  535. matScaleCentered.SetTranslation( -pRetVal->Center() * 10.0f );
  536. DumpPolyhedronToGLView( pRetVal, "AssertPolyhedron.txt", &matScaleCentered );
  537. AssertMsg( g_pPolyhedronCarvingDebugStepCallback( pRetVal ), "Outside conversion failed. Offset failure" ); //this REALLY sucks. Because the difference between success and failure was a translation of all points by the same vector. LAME
  538. }
  539. #endif //#if defined( USE_WORLD_CENTERED_POSITIONS )
  540. return pRetVal;
  541. }
  542. Vector FindPointInPlanes( const float *pPlanes, int planeCount )
  543. {
  544. Vector point = vec3_origin;
  545. for ( int i = 0; i < planeCount; i++ )
  546. {
  547. float fD = DotProduct( *(Vector *)&pPlanes[i*4], point ) - pPlanes[i*4 + 3];
  548. if ( fD < 0 )
  549. {
  550. point -= fD * (*(Vector *)&pPlanes[i*4]);
  551. }
  552. }
  553. return point;
  554. }
  555. bool FindConvexShapeLooseAABB( const fltx4 *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ) //bounding box of the convex shape (subject to floating point error)
  556. {
  557. //returns false if the AABB hasn't been set
  558. if( pAABBMins == NULL && pAABBMaxs == NULL ) //no use in actually finding out what it is
  559. return false;
  560. struct FindConvexShapeAABB_Polygon_t
  561. {
  562. float *verts;
  563. int iVertCount;
  564. };
  565. const size_t kPlaneAlign = sizeof( Vector4D ) - 1;
  566. uint8 *pAlignedAlloc = (uint8 *)stackalloc( (sizeof( Vector4D ) * iPlaneCount) + kPlaneAlign );
  567. pAlignedAlloc = (uint8 *)(((size_t)(pAlignedAlloc + kPlaneAlign)) & ~kPlaneAlign);
  568. Vector4D *pMovedPlanes = (Vector4D *)pAlignedAlloc;
  569. for( int i = 0; i != iPlaneCount; ++i )
  570. {
  571. pMovedPlanes[i].Init( SubFloat( pInwardFacingPlanes[i], 0 ), SubFloat( pInwardFacingPlanes[i], 1 ), SubFloat( pInwardFacingPlanes[i], 2 ), SubFloat( pInwardFacingPlanes[i], 3 ) - 100.0f ); //move planes out a lot to kill some imprecision problems
  572. }
  573. //vAABBMins = vAABBMaxs = FindPointInPlanes( pPlanes, iPlaneCount );
  574. float *vertsIn = NULL; //we'll be allocating a new buffer for this with each new polygon, and moving it off to the polygon array
  575. 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
  576. float *vertsSwap;
  577. FindConvexShapeAABB_Polygon_t *pPolygons = (FindConvexShapeAABB_Polygon_t *)stackalloc( iPlaneCount * sizeof( FindConvexShapeAABB_Polygon_t ) );
  578. int iPolyCount = 0;
  579. for ( int i = 0; i < iPlaneCount; i++ )
  580. {
  581. Vector vPlaneNormal = pMovedPlanes[i].AsVector3D();
  582. float fPlaneDist = pMovedPlanes[i].w;// + 50.0f;
  583. if( vertsIn == NULL )
  584. vertsIn = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) );
  585. // Build a big-ass poly in this plane
  586. int vertCount = PolyFromPlane( (Vector *)vertsIn, vPlaneNormal, fPlaneDist, 100000.0f );
  587. //chop it by every other plane
  588. for( int j = 0; j < iPlaneCount; j++ )
  589. {
  590. // don't clip planes with themselves
  591. if ( i == j )
  592. continue;
  593. // Chop the polygon against this plane
  594. vertCount = ClipPolyToPlane( (Vector *)vertsIn, vertCount, (Vector *)vertsOut, pMovedPlanes[j].AsVector3D(), pMovedPlanes[j].w, 0.0f );
  595. //swap the input and output arrays
  596. vertsSwap = vertsIn; vertsIn = vertsOut; vertsOut = vertsSwap;
  597. // Less than a poly left, something's wrong, don't bother with this polygon
  598. if ( vertCount < 3 )
  599. break;
  600. }
  601. if ( vertCount < 3 )
  602. continue; //not enough to work with
  603. pPolygons[iPolyCount].iVertCount = vertCount;
  604. pPolygons[iPolyCount].verts = vertsIn;
  605. vertsIn = NULL;
  606. ++iPolyCount;
  607. }
  608. if( iPolyCount == 0 )
  609. return false;
  610. //initialize the AABB to the first point available
  611. Vector vAABBMins, vAABBMaxs;
  612. vAABBMins = vAABBMaxs = ((Vector *)pPolygons[0].verts)[0];
  613. if( pAABBMins && pAABBMaxs ) //they want the full box
  614. {
  615. for( int i = 0; i != iPolyCount; ++i )
  616. {
  617. Vector *PolyVerts = (Vector *)pPolygons[i].verts;
  618. for( int j = 0; j != pPolygons[i].iVertCount; ++j )
  619. {
  620. if( PolyVerts[j].x < vAABBMins.x )
  621. vAABBMins.x = PolyVerts[j].x;
  622. if( PolyVerts[j].y < vAABBMins.y )
  623. vAABBMins.y = PolyVerts[j].y;
  624. if( PolyVerts[j].z < vAABBMins.z )
  625. vAABBMins.z = PolyVerts[j].z;
  626. if( PolyVerts[j].x > vAABBMaxs.x )
  627. vAABBMaxs.x = PolyVerts[j].x;
  628. if( PolyVerts[j].y > vAABBMaxs.y )
  629. vAABBMaxs.y = PolyVerts[j].y;
  630. if( PolyVerts[j].z > vAABBMaxs.z )
  631. vAABBMaxs.z = PolyVerts[j].z;
  632. }
  633. }
  634. *pAABBMins = vAABBMins;
  635. *pAABBMaxs = vAABBMaxs;
  636. }
  637. else if( pAABBMins ) //they only want the min
  638. {
  639. for( int i = 0; i != iPolyCount; ++i )
  640. {
  641. Vector *PolyVerts = (Vector *)pPolygons[i].verts;
  642. for( int j = 0; j != pPolygons[i].iVertCount; ++j )
  643. {
  644. if( PolyVerts[j].x < vAABBMins.x )
  645. vAABBMins.x = PolyVerts[j].x;
  646. if( PolyVerts[j].y < vAABBMins.y )
  647. vAABBMins.y = PolyVerts[j].y;
  648. if( PolyVerts[j].z < vAABBMins.z )
  649. vAABBMins.z = PolyVerts[j].z;
  650. }
  651. }
  652. *pAABBMins = vAABBMins;
  653. }
  654. else //they only want the max
  655. {
  656. for( int i = 0; i != iPolyCount; ++i )
  657. {
  658. Vector *PolyVerts = (Vector *)pPolygons[i].verts;
  659. for( int j = 0; j != pPolygons[i].iVertCount; ++j )
  660. {
  661. if( PolyVerts[j].x > vAABBMaxs.x )
  662. vAABBMaxs.x = PolyVerts[j].x;
  663. if( PolyVerts[j].y > vAABBMaxs.y )
  664. vAABBMaxs.y = PolyVerts[j].y;
  665. if( PolyVerts[j].z > vAABBMaxs.z )
  666. vAABBMaxs.z = PolyVerts[j].z;
  667. }
  668. }
  669. *pAABBMaxs = vAABBMaxs;
  670. }
  671. return true;
  672. }
  673. CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory, fltx4 vShiftResultPositions )
  674. {
  675. Assert( (pPolygons != NULL) && (pLines != NULL) && (pPoints != NULL) );
  676. unsigned int iPolyCount = 0, iLineCount = 0, iPointCount = 0, iIndexCount = 0;
  677. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pPolygons;
  678. do
  679. {
  680. ++iPolyCount;
  681. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->polygon.pLines;
  682. GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk;
  683. Assert( pLineWalk != NULL );
  684. do
  685. {
  686. ++iIndexCount;
  687. pLineWalk = pLineWalk->pNext;
  688. } while( pLineWalk != pFirstLine );
  689. pActivePolygonWalk = pActivePolygonWalk->pNext;
  690. } while( pActivePolygonWalk );
  691. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pLines;
  692. do
  693. {
  694. ++iLineCount;
  695. pActiveLineWalk = pActiveLineWalk->pNext;
  696. } while( pActiveLineWalk );
  697. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pPoints;
  698. do
  699. {
  700. ++iPointCount;
  701. pActivePointWalk = pActivePointWalk->pNext;
  702. } while( pActivePointWalk );
  703. CPolyhedron *pReturn;
  704. if( bUseTemporaryMemory )
  705. {
  706. pReturn = GetTempPolyhedron( iPointCount, iLineCount, iIndexCount, iPolyCount );
  707. }
  708. else
  709. {
  710. pReturn = CPolyhedron_AllocByNew::Allocate( iPointCount, iLineCount, iIndexCount, iPolyCount );
  711. }
  712. Vector *pVertexArray = pReturn->pVertices;
  713. Polyhedron_IndexedLine_t *pLineArray = pReturn->pLines;
  714. Polyhedron_IndexedLineReference_t *pIndexArray = pReturn->pIndices;
  715. Polyhedron_IndexedPolygon_t *pPolyArray = pReturn->pPolygons;
  716. //copy points
  717. pActivePointWalk = pPoints;
  718. for( unsigned int i = 0; i != iPointCount; ++i )
  719. {
  720. #if defined( USE_WORLD_CENTERED_POSITIONS )
  721. fltx4 vShiftedResult = AddSIMD( pActivePointWalk->point.ptPosition, vShiftResultPositions );
  722. pVertexArray[i].Init( SubFloat( vShiftedResult, 0 ), SubFloat( vShiftedResult, 1 ), SubFloat( vShiftedResult, 2 ) );
  723. #else
  724. pVertexArray[i].Init( SubFloat( pActivePointWalk->point.ptPosition, 0 ), SubFloat( pActivePointWalk->point.ptPosition, 1 ), SubFloat( pActivePointWalk->point.ptPosition, 2 ) );
  725. #endif
  726. pActivePointWalk->point.iSaveIndices = i; //storing array indices
  727. pActivePointWalk = pActivePointWalk->pNext;
  728. }
  729. //copy lines
  730. pActiveLineWalk = pLines;
  731. for( unsigned int i = 0; i != iLineCount; ++i )
  732. {
  733. pLineArray[i].iPointIndices[0] = (unsigned short)pActiveLineWalk->line.pPoints[0]->iSaveIndices;
  734. pLineArray[i].iPointIndices[1] = (unsigned short)pActiveLineWalk->line.pPoints[1]->iSaveIndices;
  735. pActiveLineWalk->line.iSaveIndices = i; //storing array indices
  736. pActiveLineWalk = pActiveLineWalk->pNext;
  737. }
  738. //copy polygons and indices at the same time
  739. pActivePolygonWalk = pPolygons;
  740. iIndexCount = 0;
  741. for( unsigned int i = 0; i != iPolyCount; ++i )
  742. {
  743. pPolyArray[i].polyNormal = pActivePolygonWalk->polygon.vSurfaceNormal;
  744. pPolyArray[i].iFirstIndex = iIndexCount;
  745. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->polygon.pLines;
  746. GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk;
  747. do
  748. {
  749. pIndexArray[iIndexCount].iLineIndex = pLineWalk->pLine->iSaveIndices;
  750. pIndexArray[iIndexCount].iEndPointIndex = pLineWalk->iReferenceIndex;
  751. ++iIndexCount;
  752. pLineWalk = pLineWalk->pNext;
  753. } while( pLineWalk != pFirstLine );
  754. pPolyArray[i].iIndexCount = iIndexCount - pPolyArray[i].iFirstIndex;
  755. pActivePolygonWalk = pActivePolygonWalk->pNext;
  756. }
  757. #if defined( DBGFLAG_ASSERT ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS )
  758. char szCollisionFile[128];
  759. CreateDumpDirectory( "PolyhedronDumps" );
  760. Q_snprintf( szCollisionFile, 128, "PolyhedronDumps/NewStyle_PolyhedronDump%i.txt", g_iPolyhedronDumpCounter );
  761. ++g_iPolyhedronDumpCounter;
  762. remove( szCollisionFile );
  763. DumpPolyhedronToGLView( pReturn, szCollisionFile, &s_matIdentity );
  764. DumpPolyhedronToGLView( pReturn, "PolyhedronDumps/NewStyle_PolyhedronDump_All-Appended.txt", &s_matIdentity );
  765. #endif
  766. #if defined( DEBUG_POLYHEDRON_CONVERSION ) && 0 //probably too redundant to check here
  767. //last bit of debugging from whatever outside source wants this stupid thing
  768. if( (g_pPolyhedronCarvingDebugStepCallback != NULL) && (pReturn != NULL) )
  769. {
  770. AssertMsg( g_pPolyhedronCarvingDebugStepCallback( pReturn ), "Outside conversion failed" );
  771. }
  772. #endif
  773. return pReturn;
  774. }
  775. #ifdef DBGFLAG_ASSERT
  776. void DumpPointListToGLView( GeneratePolyhedronFromPlanes_UnorderedPointLL *pHead, PolyhedronPointPlanarity planarity, const Vector &vColor, const char *szDumpFile, const VMatrix *pTransform )
  777. {
  778. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  779. if( pTransform == NULL )
  780. pTransform = &s_matIdentity;
  781. FILE *pFile = fopen( szDumpFile, "ab" );
  782. while( pHead )
  783. {
  784. if( pHead->point.planarity == planarity )
  785. {
  786. const Vector vPointExtents( 0.5f, 0.5f, 0.01f );
  787. fltx4 f4Pos = pHead->point.ptPosition;
  788. Vector vPos( SubFloat( f4Pos, 0 ), SubFloat( f4Pos, 1 ), SubFloat( f4Pos, 2 ) );
  789. DumpAABBToGLView( (*pTransform) * vPos, vPointExtents, vColor, pFile );
  790. }
  791. pHead = pHead->pNext;
  792. }
  793. fclose( pFile );
  794. #endif
  795. }
  796. const char * DumpPolyhedronCutHistory( const CUtlVector<CPolyhedron *> &DumpedHistory, const CUtlVector<const float *> &CutHistory, const VMatrix *pTransform )
  797. {
  798. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  799. if( pTransform == NULL )
  800. pTransform = &s_matIdentity;
  801. static char szDumpFile[100] = "FailedPolyhedronCut_Error.txt"; //most recent filename returned for further dumping
  802. for( int i = 0; i != DumpedHistory.Count(); ++i )
  803. {
  804. if( DumpedHistory[i] != NULL )
  805. {
  806. Q_snprintf( szDumpFile, 100, "FailedPolyhedronCut_%d.txt", i );
  807. DumpPolyhedronToGLView( DumpedHistory[i], szDumpFile, pTransform, "wb" );
  808. if( CutHistory.Count() > i )
  809. {
  810. DumpPlaneToGlView( CutHistory[i], 1.0f, szDumpFile, pTransform );
  811. }
  812. }
  813. }
  814. return szDumpFile;
  815. #else
  816. return NULL;
  817. #endif
  818. }
  819. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  820. #define DUMP_POLYHEDRON_SCALE 10.0f
  821. bool g_bDumpNullPolyhedrons = false;
  822. #define AssertMsg_DumpPolyhedron_Destructors(condition, destructors, message)\
  823. if( (condition) == false )\
  824. {\
  825. if( ((destructors).DebugCutHistory.Count() != 0) && ((destructors).PlaneCutHistory.Count() != 0) )\
  826. {\
  827. VMatrix matTransform;\
  828. matTransform.Identity();\
  829. matTransform[0][0] = matTransform[1][1] = matTransform[2][2] = DUMP_POLYHEDRON_SCALE;\
  830. matTransform.SetTranslation( -(destructors).DebugCutHistory.Tail()->Center() * DUMP_POLYHEDRON_SCALE );\
  831. const char *szLastDumpFile = DumpPolyhedronCutHistory( (destructors).DebugCutHistory, (destructors).PlaneCutHistory, &matTransform );\
  832. DumpPointListToGLView( (destructors).pAllPoints, POINT_ALIVE, Vector( 0.9f, 0.9f, 0.9f ), szLastDumpFile, &matTransform );\
  833. DumpPointListToGLView( (destructors).pAllPoints, POINT_ONPLANE, Vector( 0.5f, 0.5f, 0.5f ), szLastDumpFile, &matTransform );\
  834. DumpPointListToGLView( (destructors).pDeadPointCollection, POINT_DEAD, Vector( 0.1f, 0.1f, 0.1f ), szLastDumpFile, &matTransform );\
  835. DumpWorkingStatePolyhedron( (destructors).pAllPolygons, (destructors).pDeadPolygonCollection, (destructors).pAllLines, (destructors).pDeadLineCollection, (destructors).pAllPoints, (destructors).pDeadPointCollection, "FailedPolyhedronCut_LastCutDebug.txt", &matTransform );\
  836. DumpPlaneToGlView( (destructors).PlaneCutHistory.Tail(), 1.0f, "FailedPolyhedronCut_LastCutDebug.txt", &matTransform );\
  837. }\
  838. AssertMsg( condition, message );\
  839. }
  840. #else
  841. #define AssertMsg_DumpPolyhedron_Destructors(condition, destructors, message) AssertMsg( condition, message )
  842. #endif
  843. #else
  844. #define AssertMsg_DumpPolyhedron_Destructors(condition, destructors, message) NULL;
  845. #endif
  846. #define Assert_DumpPolyhedron_Destructors(condition, destructors) AssertMsg_DumpPolyhedron_Destructors( condition, destructors, #condition )
  847. #define AssertMsg_DumpPolyhedron(condition, message) AssertMsg_DumpPolyhedron_Destructors(condition, destructors, message)
  848. #define Assert_DumpPolyhedron(condition) Assert_DumpPolyhedron_Destructors( condition, destructors )
  849. //a little class that acts like a small block heap, using stack memory given to it
  850. class CStackMemoryDispenser
  851. {
  852. public:
  853. CStackMemoryDispenser( void *pStackAllocation, size_t iStackAllocationSize )
  854. {
  855. m_pDispenserBuffer = (unsigned char *)pStackAllocation;
  856. m_iDispenserSizeLeft = iStackAllocationSize;
  857. m_pDeleteList = NULL;
  858. }
  859. ~CStackMemoryDispenser( void )
  860. {
  861. RecurseDelete( m_pDeleteList );
  862. }
  863. void *Allocate( size_t iSize, size_t iAlignTo = 16 )
  864. {
  865. AssertMsg( ((iAlignTo - 1) & iAlignTo) == 0, "Alignment must be a power of 2" );
  866. size_t iAlignOffset = iAlignTo - ((size_t)m_pDispenserBuffer) & (iAlignTo - 1);
  867. m_iDispenserSizeLeft -= iAlignOffset;
  868. m_pDispenserBuffer += iAlignOffset;
  869. if( iSize > m_iDispenserSizeLeft )
  870. {
  871. //allocate a new buffer
  872. size_t iNewBufferSize = MAX( 128 * 1024, (iSize + iAlignTo) * 2 ); //either allocate 128k or enough to hold 2x the allocation.
  873. unsigned char *pNewBuffer = new unsigned char [iNewBufferSize]; //allocate 128k at a time
  874. *(void **)pNewBuffer = NULL;
  875. //insert this allocation into the linked list of allocations to delete on destruct
  876. void **pWriteDeleteAddress = &m_pDeleteList;
  877. while( *pWriteDeleteAddress != NULL )
  878. {
  879. pWriteDeleteAddress = (void **)*pWriteDeleteAddress;
  880. }
  881. *pWriteDeleteAddress = pNewBuffer;
  882. //save this as the new dispenser buffer, skipping the linked list pointer
  883. m_pDispenserBuffer = pNewBuffer + sizeof( void * );
  884. m_iDispenserSizeLeft = iNewBufferSize - sizeof( void * );
  885. iAlignOffset = iAlignTo - ((size_t)m_pDispenserBuffer) & (iAlignTo - 1); //recompute alignment offset
  886. m_iDispenserSizeLeft -= iAlignOffset;
  887. m_pDispenserBuffer += iAlignOffset;
  888. }
  889. void *pRetVal = m_pDispenserBuffer;
  890. m_pDispenserBuffer += iSize;
  891. m_iDispenserSizeLeft -= iSize;
  892. Assert( (((size_t)pRetVal) & (iAlignTo - 1)) == 0 );
  893. return pRetVal;
  894. }
  895. private:
  896. static void RecurseDelete( void *pDelete )
  897. {
  898. if( pDelete != NULL )
  899. {
  900. RecurseDelete( *(void **)pDelete );
  901. delete [](void**)pDelete;
  902. }
  903. }
  904. unsigned char *m_pDispenserBuffer;
  905. size_t m_iDispenserSizeLeft;
  906. void *m_pDeleteList; //a linked list of pointers to actual memory allocations we had to make that need to be deleted. The first thing in each allocation is a reserved space for another pointer
  907. };
  908. template<class T>
  909. class CStackItemDispenser
  910. {
  911. public:
  912. CStackItemDispenser( CStackMemoryDispenser &MemoryDispenser ) : m_FallbackDispenser( MemoryDispenser )
  913. {
  914. COMPILE_TIME_ASSERT( sizeof( T ) > sizeof( void * ) );
  915. m_pHead = NULL;
  916. }
  917. T *Allocate( void )
  918. {
  919. if( m_pHead != NULL )
  920. {
  921. T *pRetVal = m_pHead;
  922. m_pHead = *(T **)m_pHead;
  923. #ifdef DBGFLAG_ASSERT
  924. memset( pRetVal, 0xCCCCCCCC, sizeof( T ) );
  925. #endif
  926. return pRetVal;
  927. }
  928. else
  929. {
  930. return (T *)m_FallbackDispenser.Allocate( sizeof( T ) );
  931. }
  932. }
  933. void Free( T *pFree )
  934. {
  935. *(T **)pFree = m_pHead;
  936. m_pHead = pFree;
  937. }
  938. private:
  939. CStackMemoryDispenser &m_FallbackDispenser;
  940. T *m_pHead;
  941. };
  942. inline void ComputePlanarDistances( GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, int iPointCount, fltx4 fPlane )
  943. {
  944. uint8 *pAlignedAlloc = (uint8 *)stackalloc( (iPointCount) * sizeof(fltx4) + 15 );
  945. pAlignedAlloc = (uint8 *)(((size_t)(pAlignedAlloc + 15)) & ~15);
  946. fltx4 *pIntermediateResults = (fltx4 *)pAlignedAlloc;
  947. int i = 0;
  948. GeneratePolyhedronFromPlanes_UnorderedPointLL *pPointWalk = pAllPoints;
  949. do
  950. {
  951. Assert( SubFloat( pPointWalk->point.ptPosition, 3 ) == -1.0f );
  952. pIntermediateResults[i] = MulSIMD( fPlane, pPointWalk->point.ptPosition );
  953. ++i;
  954. pPointWalk = pPointWalk->pNext;
  955. } while( pPointWalk != NULL );
  956. i = 0;
  957. pPointWalk = pAllPoints;
  958. do
  959. {
  960. pPointWalk->point.fPlaneDist = SubFloat( pIntermediateResults[i], 0 ) + SubFloat( pIntermediateResults[i], 1 ) + SubFloat( pIntermediateResults[i], 2 ) + SubFloat( pIntermediateResults[i], 3 );
  961. DBG_ONLY( pPointWalk->point.debugdata.fInitialPlaneDistance = pPointWalk->point.fPlaneDist; );
  962. ++i;
  963. pPointWalk = pPointWalk->pNext;
  964. } while( pPointWalk != NULL );
  965. }
  966. class CClipLinkedGeometryDestructors
  967. {
  968. public:
  969. int &iPointCount;
  970. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *&pAllPolygons;
  971. GeneratePolyhedronFromPlanes_UnorderedLineLL *&pAllLines;
  972. GeneratePolyhedronFromPlanes_UnorderedPointLL *&pAllPoints;
  973. GeneratePolyhedronFromPlanes_UnorderedPointLL *&pDeadPointCollection;
  974. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  975. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *&pDeadPolygonCollection;
  976. GeneratePolyhedronFromPlanes_UnorderedLineLL *&pDeadLineCollection;
  977. CClipLinkedGeometryDestructors( int &iPointCount_IN,
  978. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *&pAllPolygons_IN,
  979. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *&pDeadPolygonCollection_IN,
  980. GeneratePolyhedronFromPlanes_UnorderedLineLL *&pAllLines_IN,
  981. GeneratePolyhedronFromPlanes_UnorderedLineLL *&pDeadLineCollection_IN,
  982. GeneratePolyhedronFromPlanes_UnorderedPointLL *&pAllPoints_IN,
  983. GeneratePolyhedronFromPlanes_UnorderedPointLL *&pDeadPointCollection_IN )
  984. : iPointCount( iPointCount_IN ), pAllPolygons( pAllPolygons_IN ), pAllLines( pAllLines_IN ), pDeadPolygonCollection( pDeadPolygonCollection_IN ), pDeadLineCollection( pDeadLineCollection_IN ), pAllPoints( pAllPoints_IN ), pDeadPointCollection( pDeadPointCollection_IN ) {};
  985. #else
  986. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPolygonLL> &polygonAllocator;
  987. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedLineLL> &lineAllocator;
  988. CClipLinkedGeometryDestructors( int &iPointCount_IN,
  989. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *&pAllPolygons_IN,
  990. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPolygonLL> &polygonAllocator_IN,
  991. GeneratePolyhedronFromPlanes_UnorderedLineLL *&pAllLines_IN,
  992. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedLineLL> &lineAllocator_IN,
  993. GeneratePolyhedronFromPlanes_UnorderedPointLL *&pAllPoints_IN,
  994. GeneratePolyhedronFromPlanes_UnorderedPointLL *&pDeadPointCollection_IN )
  995. : iPointCount( iPointCount_IN ), pAllPolygons( pAllPolygons_IN ), pAllLines( pAllLines_IN ), polygonAllocator( polygonAllocator_IN ), lineAllocator( lineAllocator_IN ), pAllPoints( pAllPoints_IN ), pDeadPointCollection( pDeadPointCollection_IN ) {};
  996. #endif
  997. #if defined( DBGFLAG_ASSERT )
  998. //let some generic debug data hitch a ride on this structure since it goes pretty much everywhere
  999. CUtlVector<CPolyhedron *> DebugCutHistory;
  1000. CUtlVector<const float *> PlaneCutHistory;
  1001. CUtlVector<int> DebugCutPlaneIndex;
  1002. bool bDebugTrigger;
  1003. ~CClipLinkedGeometryDestructors( void )
  1004. {
  1005. for( int i = 0; i != DebugCutHistory.Count(); ++i )
  1006. {
  1007. if( DebugCutHistory[i] != NULL )
  1008. {
  1009. DebugCutHistory[i]->Release();
  1010. }
  1011. }
  1012. }
  1013. #endif
  1014. };
  1015. static FORCEINLINE GeneratePolyhedronFromPlanes_UnorderedPointLL *DestructPoint( GeneratePolyhedronFromPlanes_UnorderedPointLL *pKillPoint, CClipLinkedGeometryDestructors &destructors )
  1016. {
  1017. #if defined( DBGFLAG_ASSERT )
  1018. {
  1019. GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPointWalk = destructors.pDeadPointCollection;
  1020. while( pDeadPointWalk )
  1021. {
  1022. Assert( pDeadPointWalk != pKillPoint );
  1023. pDeadPointWalk = pDeadPointWalk->pNext;
  1024. }
  1025. }
  1026. #endif
  1027. GeneratePolyhedronFromPlanes_UnorderedPointLL *pRetVal = pKillPoint->pNext;
  1028. DBG_ONLY( pKillPoint->point.planarity = POINT_DEAD; );
  1029. if( pKillPoint->pNext )
  1030. {
  1031. pKillPoint->pNext->pPrev = pKillPoint->pPrev;
  1032. }
  1033. if( pKillPoint == destructors.pAllPoints )
  1034. {
  1035. destructors.pAllPoints = pKillPoint->pNext;
  1036. }
  1037. else
  1038. {
  1039. pKillPoint->pPrev->pNext = pKillPoint->pNext;
  1040. }
  1041. pKillPoint->pNext = destructors.pDeadPointCollection;
  1042. destructors.pDeadPointCollection = pKillPoint;
  1043. --destructors.iPointCount;
  1044. return pRetVal;
  1045. }
  1046. static FORCEINLINE GeneratePolyhedronFromPlanes_UnorderedPointLL *DestructPoint( GeneratePolyhedronFromPlanes_Point *pKillPoint, CClipLinkedGeometryDestructors &destructors )
  1047. {
  1048. #ifdef OSX
  1049. Assert( &(((GeneratePolyhedronFromPlanes_UnorderedPointLL *)pKillPoint)->point) == pKillPoint );
  1050. #else
  1051. // This COMPILE_TIME_ASSERT was breaking gcc under OSX
  1052. COMPILE_TIME_ASSERT( offsetof(GeneratePolyhedronFromPlanes_UnorderedPointLL, point) == 0 );
  1053. #endif
  1054. return DestructPoint( (GeneratePolyhedronFromPlanes_UnorderedPointLL *)pKillPoint, destructors );
  1055. }
  1056. static FORCEINLINE GeneratePolyhedronFromPlanes_UnorderedLineLL *DestructLine( GeneratePolyhedronFromPlanes_UnorderedLineLL *pKillLine, CClipLinkedGeometryDestructors &destructors )
  1057. {
  1058. GeneratePolyhedronFromPlanes_UnorderedLineLL *pRetVal = pKillLine->pNext;
  1059. DBG_ONLY( pKillLine->line.planarity = LINE_DEAD; );
  1060. if( pKillLine->pNext )
  1061. {
  1062. pKillLine->pNext->pPrev = pKillLine->pPrev;
  1063. }
  1064. if( pKillLine == destructors.pAllLines )
  1065. {
  1066. destructors.pAllLines = pKillLine->pNext;
  1067. }
  1068. else
  1069. {
  1070. pKillLine->pPrev->pNext = pKillLine->pNext;
  1071. }
  1072. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1073. pKillLine->pNext = destructors.pDeadLineCollection;
  1074. destructors.pDeadLineCollection = pKillLine;
  1075. #else
  1076. destructors.lineAllocator.Free( pKillLine );
  1077. #endif
  1078. return pRetVal;
  1079. }
  1080. static FORCEINLINE GeneratePolyhedronFromPlanes_UnorderedLineLL *DestructLine( GeneratePolyhedronFromPlanes_Line *pKillLine, CClipLinkedGeometryDestructors &destructors )
  1081. {
  1082. #ifdef OSX
  1083. Assert( &(((GeneratePolyhedronFromPlanes_UnorderedLineLL *)pKillLine)->line) == pKillLine );
  1084. #else
  1085. // This COMPILE_TIME_ASSERT was breaking gcc under OSX
  1086. COMPILE_TIME_ASSERT( offsetof(GeneratePolyhedronFromPlanes_UnorderedLineLL, line) == 0 );
  1087. #endif
  1088. return DestructLine( (GeneratePolyhedronFromPlanes_UnorderedLineLL *)pKillLine, destructors );
  1089. }
  1090. static FORCEINLINE void UnlinkLine( GeneratePolyhedronFromPlanes_Line *pUnlinkLine )
  1091. {
  1092. //disconnect the line from everything
  1093. for( int i = 0; i != 2; ++i )
  1094. {
  1095. pUnlinkLine->PointLineLinks[i].pNext->pPrev = pUnlinkLine->PointLineLinks[i].pPrev;
  1096. pUnlinkLine->PointLineLinks[i].pPrev->pNext = pUnlinkLine->PointLineLinks[i].pNext;
  1097. pUnlinkLine->PolygonLineLinks[i].pNext->pPrev = pUnlinkLine->PolygonLineLinks[i].pPrev;
  1098. pUnlinkLine->PolygonLineLinks[i].pPrev->pNext = pUnlinkLine->PolygonLineLinks[i].pNext;
  1099. pUnlinkLine->pPoints[i]->pConnectedLines = pUnlinkLine->PointLineLinks[i].pNext;
  1100. pUnlinkLine->pPolygons[i]->pLines = pUnlinkLine->PolygonLineLinks[i].pNext;
  1101. Assert( (pUnlinkLine->pPoints[i]->pConnectedLines != &pUnlinkLine->PointLineLinks[i]) || (pUnlinkLine->pPoints[i]->planarity == POINT_DEAD) );
  1102. Assert( (pUnlinkLine->pPolygons[i]->pLines != &pUnlinkLine->PolygonLineLinks[i]) || (pUnlinkLine->pPolygons[i]->bDead == true) );
  1103. }
  1104. }
  1105. static FORCEINLINE void UnlinkLine( GeneratePolyhedronFromPlanes_UnorderedLineLL *pUnlinkLine )
  1106. {
  1107. UnlinkLine( &pUnlinkLine->line );
  1108. }
  1109. static FORCEINLINE GeneratePolyhedronFromPlanes_UnorderedPolygonLL *DestructPolygon( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pKillPolygon, CClipLinkedGeometryDestructors &destructors )
  1110. {
  1111. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pRetVal = pKillPolygon->pNext;
  1112. if( pKillPolygon->pNext )
  1113. {
  1114. pKillPolygon->pNext->pPrev = pKillPolygon->pPrev;
  1115. }
  1116. if( pKillPolygon == destructors.pAllPolygons )
  1117. {
  1118. destructors.pAllPolygons = pKillPolygon->pNext;
  1119. }
  1120. else
  1121. {
  1122. pKillPolygon->pPrev->pNext = pKillPolygon->pNext;
  1123. }
  1124. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1125. pKillPolygon->pNext = destructors.pDeadPolygonCollection;
  1126. destructors.pDeadPolygonCollection = pKillPolygon;
  1127. #else
  1128. destructors.polygonAllocator.Free( pKillPolygon );
  1129. #endif
  1130. return pRetVal;
  1131. }
  1132. static FORCEINLINE GeneratePolyhedronFromPlanes_UnorderedPolygonLL *DestructPolygon( GeneratePolyhedronFromPlanes_Polygon *pKillPolygon, CClipLinkedGeometryDestructors &destructors )
  1133. {
  1134. #ifdef OSX
  1135. Assert( &(((GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)pKillPolygon)->polygon) == pKillPolygon );
  1136. #else
  1137. // This COMPILE_TIME_ASSERT was breaking gcc under OSX
  1138. COMPILE_TIME_ASSERT( offsetof(GeneratePolyhedronFromPlanes_UnorderedPolygonLL, polygon) == 0 );
  1139. #endif
  1140. return DestructPolygon( (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)pKillPolygon, destructors );
  1141. }
  1142. //remove a known degenerate polygon. Returns INVALID pointer to the line we destroy in here.
  1143. GeneratePolyhedronFromPlanes_Line *RemoveDegeneratePolygon( GeneratePolyhedronFromPlanes_Polygon *pDegeneratePolygon, CClipLinkedGeometryDestructors &destructors )
  1144. {
  1145. Assert_DumpPolyhedron( pDegeneratePolygon->pLines->pNext == pDegeneratePolygon->pLines->pPrev );
  1146. Assert_DumpPolyhedron( pDegeneratePolygon->pLines->pNext != pDegeneratePolygon->pLines ); //just for the sake of paranoia. Check that it's not a single-lined polygon
  1147. Assert_DumpPolyhedron( (pDegeneratePolygon->pLines->pLine->pPoints[pDegeneratePolygon->pLines->iReferenceIndex] == pDegeneratePolygon->pLines->pNext->pLine->pPoints[1 - pDegeneratePolygon->pLines->pNext->iReferenceIndex]) &&
  1148. (pDegeneratePolygon->pLines->pLine->pPoints[1 - pDegeneratePolygon->pLines->iReferenceIndex] == pDegeneratePolygon->pLines->pNext->pLine->pPoints[pDegeneratePolygon->pLines->pNext->iReferenceIndex]) );
  1149. //both the lines are the same, just ditch one and link up the real polygons
  1150. GeneratePolyhedronFromPlanes_LineLL *pKeepLine = pDegeneratePolygon->pLines;
  1151. GeneratePolyhedronFromPlanes_LineLL *pDeadLine = pKeepLine->pNext;
  1152. GeneratePolyhedronFromPlanes_Line *pRetVal = pDeadLine->pLine;
  1153. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  1154. pDegeneratePolygon->bDead = true; //to avoid future asserts, also for coloration. Not useful otherwise as we're about to delete it.
  1155. pDeadLine->pLine->planarity = LINE_DEAD;
  1156. #endif
  1157. pKeepLine->pLine->pPolygons[pKeepLine->iReferenceIndex] = pDeadLine->pLine->pPolygons[1 - pDeadLine->iReferenceIndex];
  1158. //unlink pDeadLine from the dead polygon so it doesn't mess with pKeepLine when we unlink it
  1159. pDeadLine->pLine->PolygonLineLinks[pDeadLine->iReferenceIndex].pNext = &pDeadLine->pLine->PolygonLineLinks[pDeadLine->iReferenceIndex];
  1160. pDeadLine->pLine->PolygonLineLinks[pDeadLine->iReferenceIndex].pPrev = &pDeadLine->pLine->PolygonLineLinks[pDeadLine->iReferenceIndex];
  1161. //insert pKeepLine just after pDeadLine on pDeadLine's flip side polygon, so when we unlink pDeadLine, everything links into place smoothly
  1162. pKeepLine->pLine->PolygonLineLinks[pKeepLine->iReferenceIndex].pPrev = &pDeadLine->pLine->PolygonLineLinks[1 - pDeadLine->iReferenceIndex];
  1163. pKeepLine->pLine->PolygonLineLinks[pKeepLine->iReferenceIndex].pNext = pDeadLine->pLine->PolygonLineLinks[1 - pDeadLine->iReferenceIndex].pNext;
  1164. pKeepLine->pLine->PolygonLineLinks[pKeepLine->iReferenceIndex].pPrev->pNext = &pKeepLine->pLine->PolygonLineLinks[pKeepLine->iReferenceIndex];
  1165. pKeepLine->pLine->PolygonLineLinks[pKeepLine->iReferenceIndex].pNext->pPrev = &pKeepLine->pLine->PolygonLineLinks[pKeepLine->iReferenceIndex];
  1166. UnlinkLine( pDeadLine->pLine );
  1167. DestructLine( pDeadLine->pLine, destructors );
  1168. DestructPolygon( pDegeneratePolygon, destructors );
  1169. return pRetVal;
  1170. }
  1171. //search/kill redundant points on the specified polygon
  1172. void RemoveDegeneratePoints( GeneratePolyhedronFromPlanes_Polygon *pSearchPolygon, CClipLinkedGeometryDestructors &destructors )
  1173. {
  1174. AssertMsg( destructors.pAllPolygons->pNext != NULL && destructors.pAllPolygons->pNext->pNext != NULL, "RemoveDegeneratePoints() is not safe to run on 2D polyhedrons, early out before you get here" );
  1175. GeneratePolyhedronFromPlanes_LineLL *pHeadLine = pSearchPolygon->pLines;
  1176. GeneratePolyhedronFromPlanes_LineLL *pWalkLine = pHeadLine;
  1177. do
  1178. {
  1179. while( true ) //inner loop to support retesting the same line over and over again( even if it's the head )
  1180. {
  1181. GeneratePolyhedronFromPlanes_LineLL *pPointLineLink = &pWalkLine->pLine->PointLineLinks[1 - pWalkLine->iReferenceIndex];
  1182. Assert_DumpPolyhedron( (pPointLineLink->pLine->pPolygons[0]->pLines != pPointLineLink->pLine->pPolygons[0]->pLines->pNext) &&
  1183. (pPointLineLink->pLine->pPolygons[0]->pLines != pPointLineLink->pLine->pPolygons[0]->pLines->pNext->pNext) &&
  1184. (pPointLineLink->pLine->pPolygons[1]->pLines != pPointLineLink->pLine->pPolygons[1]->pLines->pNext) &&
  1185. (pPointLineLink->pLine->pPolygons[1]->pLines != pPointLineLink->pLine->pPolygons[1]->pLines->pNext->pNext) );
  1186. //try iterating forward 2 lines, jumping over already-dead lines.
  1187. //if we end up where we started, the point is redundant
  1188. //go forward 1
  1189. GeneratePolyhedronFromPlanes_LineLL *pCircleBackLineLink = pPointLineLink->pNext;
  1190. //and again
  1191. pCircleBackLineLink = pCircleBackLineLink->pNext;
  1192. //point is connected to only 2 lines. This can only be part of a convex if that convex is entirely 2D or if the lines perfectly agree with eachother.
  1193. //Based on the assumption that the convex is 3D. We can force the lines to perfectly agree with each other by eliminating one and patching the other to do the work of both.
  1194. if( pCircleBackLineLink == pPointLineLink )
  1195. {
  1196. //connect the root of the next line to our root, this way multiple occurrences in a row can chain to the same root
  1197. GeneratePolyhedronFromPlanes_Point *pDeadPoint = pWalkLine->pLine->pPoints[1 - pWalkLine->iReferenceIndex];
  1198. GeneratePolyhedronFromPlanes_LineLL *pRootLine = &pWalkLine->pPrev->pLine->PointLineLinks[1 - pWalkLine->pPrev->iReferenceIndex];
  1199. GeneratePolyhedronFromPlanes_LineLL *pSurvivingLine = pWalkLine;
  1200. Assert_DumpPolyhedron( pDeadPoint->planarity != POINT_DEAD );
  1201. Assert_DumpPolyhedron( pRootLine->pLine->planarity != LINE_DEAD );
  1202. if( pWalkLine->pPrev == pHeadLine )
  1203. {
  1204. pHeadLine = pWalkLine;
  1205. }
  1206. pSurvivingLine = &pSurvivingLine->pLine->PointLineLinks[1 - pSurvivingLine->iReferenceIndex]; //convert it to point space
  1207. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  1208. pDeadPoint->planarity = POINT_DEAD;
  1209. pRootLine->pLine->planarity = LINE_DEAD;
  1210. #endif
  1211. //the dead line/point removal code will unlink these properly. But will leave surviving line's endpoint pointing at the dead point.
  1212. //relink surviving to the root point
  1213. {
  1214. //unlink dead point from surviving line
  1215. pSurvivingLine->pNext->pPrev = pSurvivingLine->pPrev;
  1216. pSurvivingLine->pPrev->pNext = pSurvivingLine->pNext;
  1217. //arbitrarily insert after dead line on the root point, before or after doesn't matter as it'll be unlinked soon anyway
  1218. pSurvivingLine->pNext = pRootLine->pNext;
  1219. pSurvivingLine->pNext->pPrev = pSurvivingLine;
  1220. pSurvivingLine->pPrev = pRootLine;
  1221. pRootLine->pNext = pSurvivingLine;
  1222. //steal root from dead line
  1223. pSurvivingLine->pLine->pPoints[1 - pSurvivingLine->iReferenceIndex] = pRootLine->pLine->pPoints[1 - pRootLine->iReferenceIndex];
  1224. }
  1225. //pRootLine is fully connected to the root point, dead point, and both polygons. Unlink should work properly
  1226. UnlinkLine( pRootLine->pLine );
  1227. DestructLine( pRootLine->pLine, destructors );
  1228. DestructPoint( pDeadPoint, destructors );
  1229. }
  1230. else
  1231. {
  1232. break;
  1233. }
  1234. }
  1235. pWalkLine = pWalkLine->pNext;
  1236. } while (pWalkLine != pHeadLine);
  1237. }
  1238. //given two lines that are both connected to the same two points, merge them.
  1239. //returns true if any deleted line was on the new polygon's edge. (could have deleted pValidLineForNewPolygon)
  1240. //pMergeLine[1] needs to be deleted after completion
  1241. static bool MergeTwoLines( GeneratePolyhedronFromPlanes_Line *pMergeLines[2], int iDyingPolygonReferenceIndices[2], CClipLinkedGeometryDestructors &destructors, bool bAllowNullPolygonCollapse )
  1242. {
  1243. //pMergeLines[0] will be the surviving line and pMergeLines[1] will be eliminated.
  1244. Assert( pMergeLines[0]->pPolygons[iDyingPolygonReferenceIndices[0]] == pMergeLines[1]->pPolygons[iDyingPolygonReferenceIndices[1]] );
  1245. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pKillPolygon = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)pMergeLines[1]->pPolygons[iDyingPolygonReferenceIndices[1]];
  1246. //merge the polygon pointer from good side of 1 to the dead side of 0
  1247. pMergeLines[0]->pPolygons[iDyingPolygonReferenceIndices[0]] = pMergeLines[1]->pPolygons[1 - iDyingPolygonReferenceIndices[1]];
  1248. bool bDeletedALineBorderingNewPolygon = (pMergeLines[1]->pPolygons[0] == NULL) || (pMergeLines[1]->pPolygons[1] == NULL);
  1249. //swap the link from the polygon attached to 1 so it points at 0 instead of 1
  1250. {
  1251. GeneratePolyhedronFromPlanes_LineLL *pEditLink = &pMergeLines[1]->PolygonLineLinks[1 - iDyingPolygonReferenceIndices[1]];
  1252. GeneratePolyhedronFromPlanes_LineLL *pSwappedLink = &pMergeLines[0]->PolygonLineLinks[iDyingPolygonReferenceIndices[0]];
  1253. pSwappedLink->pNext = pEditLink->pNext;
  1254. pSwappedLink->pPrev = pEditLink->pPrev;
  1255. pSwappedLink->pPrev->pNext = pSwappedLink;
  1256. pSwappedLink->pNext->pPrev = pSwappedLink;
  1257. if( pMergeLines[1]->pPolygons[1 - iDyingPolygonReferenceIndices[1]]->pLines == pEditLink )
  1258. {
  1259. pMergeLines[1]->pPolygons[1 - iDyingPolygonReferenceIndices[1]]->pLines = pSwappedLink;
  1260. }
  1261. }
  1262. //have all associated points use 0 as their head pointer in case any were using 1 as a head pointer.
  1263. pMergeLines[0]->pPoints[0]->pConnectedLines = &pMergeLines[0]->PointLineLinks[0];
  1264. pMergeLines[0]->pPoints[1]->pConnectedLines = &pMergeLines[0]->PointLineLinks[1];
  1265. //unlink 1 from both points
  1266. {
  1267. for( int i = 0; i != 2; ++i )
  1268. {
  1269. GeneratePolyhedronFromPlanes_LineLL *pUnlinkLine = &pMergeLines[1]->PointLineLinks[i];
  1270. pUnlinkLine->pNext->pPrev = pUnlinkLine->pPrev;
  1271. pUnlinkLine->pPrev->pNext = pUnlinkLine->pNext;
  1272. }
  1273. }
  1274. //kill the line
  1275. DestructLine( pMergeLines[1], destructors );
  1276. if( pKillPolygon || bAllowNullPolygonCollapse )
  1277. {
  1278. if( pKillPolygon ) //kill the polygon as well
  1279. {
  1280. DestructPolygon( pKillPolygon, destructors );
  1281. }
  1282. //in cases where we collapse a polygon, it's possible for the new line to be completely redundant along with 1 point in a set of 2 polygons
  1283. for( int i = 0; i != 2; ++i )
  1284. {
  1285. GeneratePolyhedronFromPlanes_LineLL *pPointLink = &pMergeLines[0]->PointLineLinks[i];
  1286. GeneratePolyhedronFromPlanes_LineLL *pNextLink = pPointLink->pNext;
  1287. if( (pNextLink->pNext == pPointLink) && //only 2 lines connected to this point
  1288. (pPointLink->pLine->pPolygons[1 - pPointLink->iReferenceIndex] == pNextLink->pLine->pPolygons[pNextLink->iReferenceIndex]) &&
  1289. (pPointLink->pLine->pPolygons[pPointLink->iReferenceIndex] == pNextLink->pLine->pPolygons[1 - pNextLink->iReferenceIndex]) ) //and they're bounded by the same 2 polygons
  1290. {
  1291. Assert( pPointLink->pLine->pPolygons[pPointLink->iReferenceIndex] == pNextLink->pLine->pPolygons[1 - pNextLink->iReferenceIndex] ); //one rotation around a point should yield this as a shared polygon in all cases
  1292. GeneratePolyhedronFromPlanes_Point *pRedundantPoint = pMergeLines[0]->pPoints[i];
  1293. GeneratePolyhedronFromPlanes_LineLL *pSurvivingLine = pRedundantPoint->pConnectedLines;
  1294. GeneratePolyhedronFromPlanes_LineLL *pRedundantLine = pSurvivingLine->pNext;
  1295. Assert( pSurvivingLine->pNext == pRedundantLine );
  1296. Assert( pRedundantLine->pNext == pSurvivingLine );
  1297. //link over the redundant point in the surviving line
  1298. pSurvivingLine->pLine->pPoints[1 - pSurvivingLine->iReferenceIndex] = pRedundantLine->pLine->pPoints[pRedundantLine->iReferenceIndex];
  1299. //link over the redunant line from the side opposite the redundant point
  1300. {
  1301. GeneratePolyhedronFromPlanes_LineLL *pRedunantPointLink = &pRedundantLine->pLine->PointLineLinks[pRedundantLine->iReferenceIndex];
  1302. GeneratePolyhedronFromPlanes_LineLL *pSwapLink = &pSurvivingLine->pLine->PointLineLinks[1 - pSurvivingLine->iReferenceIndex];
  1303. pSwapLink->pNext = pRedunantPointLink->pNext;
  1304. pSwapLink->pPrev = pRedunantPointLink->pPrev;
  1305. pSwapLink->pNext->pPrev = pSwapLink;
  1306. pSwapLink->pPrev->pNext = pSwapLink;
  1307. pRedundantLine->pLine->pPoints[pRedundantLine->iReferenceIndex]->pConnectedLines = pSwapLink;
  1308. }
  1309. //link past the redundant line in both polygons
  1310. for( int j = 0; j != 2; ++j )
  1311. {
  1312. if( pRedundantLine->pLine->pPolygons[i] == NULL )
  1313. {
  1314. bDeletedALineBorderingNewPolygon = true;
  1315. }
  1316. else
  1317. {
  1318. GeneratePolyhedronFromPlanes_LineLL *pLinkOver = &pRedundantLine->pLine->PolygonLineLinks[j];
  1319. pLinkOver->pNext->pPrev = pLinkOver->pPrev;
  1320. pLinkOver->pPrev->pNext = pLinkOver->pNext;
  1321. if( pRedundantLine->pLine->pPolygons[j]->pLines == pLinkOver )
  1322. pRedundantLine->pLine->pPolygons[j]->pLines = pLinkOver->pNext;
  1323. }
  1324. }
  1325. //kill the redundant line
  1326. DestructLine( pRedundantLine->pLine, destructors );
  1327. //kill the redundant point
  1328. DestructPoint( pRedundantPoint, destructors );
  1329. break;
  1330. }
  1331. }
  1332. }
  1333. return bDeletedALineBorderingNewPolygon;
  1334. }
  1335. static inline GeneratePolyhedronFromPlanes_Point *AllocatePoint( GeneratePolyhedronFromPlanes_UnorderedPointLL * &pAllPoints, CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPointLL> &pointAllocator, int &iPointCount )
  1336. {
  1337. pAllPoints->pPrev = pointAllocator.Allocate();
  1338. DBG_ONLY( pAllPoints->pPrev->point.debugdata.Reset() );
  1339. pAllPoints->pPrev->pNext = pAllPoints;
  1340. pAllPoints = pAllPoints->pPrev;
  1341. pAllPoints->pPrev = NULL;
  1342. DBG_ONLY( pAllPoints->point.debugdata.bIsNew = true; );
  1343. Assert( (((size_t)&pAllPoints->point.ptPosition) & 15) == 0 );
  1344. ++iPointCount;
  1345. return &pAllPoints->point;
  1346. }
  1347. static inline GeneratePolyhedronFromPlanes_Line *AllocateLine( GeneratePolyhedronFromPlanes_UnorderedLineLL * &pAllLines, CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedLineLL> &lineAllocator )
  1348. {
  1349. //before we forget, add this line to the active list
  1350. pAllLines->pPrev = lineAllocator.Allocate();
  1351. DBG_ONLY( pAllLines->pPrev->line.debugdata.Reset(); );
  1352. pAllLines->pPrev->pNext = pAllLines;
  1353. pAllLines = pAllLines->pPrev;
  1354. pAllLines->pPrev = NULL;
  1355. pAllLines->line.InitLineLinks();
  1356. pAllLines->line.planarity = LINE_ONPLANE;
  1357. pAllLines->line.bNewLengthThisPass = true;
  1358. DBG_ONLY( pAllLines->line.debugdata.bIsNew = true; );
  1359. return &pAllLines->line;
  1360. }
  1361. static inline GeneratePolyhedronFromPlanes_Polygon *AllocatePolygon( GeneratePolyhedronFromPlanes_UnorderedPolygonLL * &pAllPolygons, CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPolygonLL> &polygonAllocator, const Vector &vSurfaceNormal/*, float fPlaneDist*/ )
  1362. {
  1363. pAllPolygons->pPrev = polygonAllocator.Allocate();
  1364. DBG_ONLY( pAllPolygons->pPrev->polygon.debugdata.Reset() );
  1365. pAllPolygons->pPrev->pNext = pAllPolygons;
  1366. pAllPolygons = pAllPolygons->pPrev;
  1367. pAllPolygons->pPrev = NULL;
  1368. pAllPolygons->polygon.bDead = false; //technically missing all it's sides, but we're fixing it now
  1369. pAllPolygons->polygon.bHasNewPoints = true;
  1370. pAllPolygons->polygon.bMovedExistingPoints = false;
  1371. pAllPolygons->polygon.vSurfaceNormal = vSurfaceNormal;
  1372. //pAllPolygons->polygon.fNormalDist = fPlaneDist;
  1373. DBG_ONLY( pAllPolygons->polygon.debugdata.bIsNew = true; );
  1374. return &pAllPolygons->polygon;
  1375. }
  1376. #if defined( DBGFLAG_ASSERT )
  1377. int g_iDebugPolyhedronClipProcess = -1;
  1378. #endif
  1379. struct MarkPlanarityControlStruct_t
  1380. {
  1381. MarkPlanarityControlStruct_t( GeneratePolyhedronFromPlanes_Polygon *pPolygon,
  1382. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedLineLL> &lineAlloc, GeneratePolyhedronFromPlanes_UnorderedLineLL *&pLines,
  1383. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPointLL> &pointAlloc, GeneratePolyhedronFromPlanes_UnorderedPointLL *&pPoints, int &iPoints, float fPlaneEpsilon )
  1384. : pNewPolygon( pPolygon ),
  1385. lineAllocator( lineAlloc ), pAllLines( pLines ),
  1386. pointAllocator( pointAlloc ), pAllPoints( pPoints ), iPointCount( iPoints ),
  1387. fOnPlaneEpsilon( fPlaneEpsilon ), fNegativeOnPlaneEpsilon( -fPlaneEpsilon )
  1388. {
  1389. bAllPointsDead = true;
  1390. GeneratePolyhedronFromPlanes_Line *pStartLine = AllocateLine( pAllLines, lineAllocator );
  1391. {
  1392. //A bit of setup on the dummy line, links to nothing
  1393. pStartLine->pPolygons[0] = NULL;
  1394. pStartLine->PolygonLineLinks[0].pNext = &pStartLine->PolygonLineLinks[0];
  1395. pStartLine->PolygonLineLinks[0].pPrev = &pStartLine->PolygonLineLinks[0];
  1396. pStartLine->pPolygons[1] = pNewPolygon;
  1397. pStartLine->PolygonLineLinks[1].pNext = &pStartLine->PolygonLineLinks[1];
  1398. pStartLine->PolygonLineLinks[1].pPrev = &pStartLine->PolygonLineLinks[1];
  1399. pStartLine->pPoints[0] = NULL;
  1400. pStartLine->PointLineLinks[0].pNext = &pStartLine->PointLineLinks[0];
  1401. pStartLine->PointLineLinks[0].pPrev = &pStartLine->PointLineLinks[0];
  1402. pStartLine->pPoints[1] = NULL;
  1403. pStartLine->PointLineLinks[1].pNext = &pStartLine->PointLineLinks[1];
  1404. pStartLine->PointLineLinks[1].pPrev = &pStartLine->PointLineLinks[1];
  1405. pStartLine->planarity = LINE_ONPLANE;
  1406. }
  1407. pActivePolyLine = &pStartLine->PolygonLineLinks[1];
  1408. pPolygon->pLines = pActivePolyLine;
  1409. }
  1410. GeneratePolyhedronFromPlanes_LineLL *pActivePolyLine;
  1411. GeneratePolyhedronFromPlanes_Polygon *pNewPolygon;
  1412. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedLineLL> &lineAllocator;
  1413. GeneratePolyhedronFromPlanes_UnorderedLineLL *&pAllLines;
  1414. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPointLL> &pointAllocator;
  1415. GeneratePolyhedronFromPlanes_UnorderedPointLL *&pAllPoints;
  1416. int &iPointCount;
  1417. float fOnPlaneEpsilon;
  1418. float fNegativeOnPlaneEpsilon;
  1419. bool bAllPointsDead;
  1420. #if defined( DBGFLAG_ASSERT )
  1421. fltx4 vCutPlane;
  1422. #endif
  1423. };
  1424. GeneratePolyhedronFromPlanes_Line *MarkPlanarity_CreateNewPolyLine( MarkPlanarityControlStruct_t &control )
  1425. {
  1426. GeneratePolyhedronFromPlanes_Line *pNewLine = AllocateLine( control.pAllLines, control.lineAllocator );
  1427. //make sure we can link into it
  1428. {
  1429. pNewLine->pPoints[0] = NULL;
  1430. pNewLine->PointLineLinks[0].pPrev = NULL;
  1431. pNewLine->PointLineLinks[0].pNext = NULL;
  1432. pNewLine->pPoints[1] = NULL;
  1433. pNewLine->PointLineLinks[1].pPrev = NULL;
  1434. pNewLine->PointLineLinks[1].pNext = NULL;
  1435. pNewLine->pPolygons[0] = NULL;
  1436. pNewLine->PolygonLineLinks[0].pNext = NULL;
  1437. pNewLine->PolygonLineLinks[0].pPrev = NULL;
  1438. pNewLine->pPolygons[1] = control.pNewPolygon;
  1439. pNewLine->PolygonLineLinks[1].pNext = control.pActivePolyLine->pNext;
  1440. pNewLine->PolygonLineLinks[1].pPrev = control.pActivePolyLine;
  1441. control.pActivePolyLine->pNext->pPrev = &pNewLine->PolygonLineLinks[1];
  1442. control.pActivePolyLine->pNext = &pNewLine->PolygonLineLinks[1];
  1443. control.pActivePolyLine = &pNewLine->PolygonLineLinks[1];
  1444. control.pActivePolyLine->pLine->planarity = LINE_ONPLANE;
  1445. }
  1446. return pNewLine;
  1447. }
  1448. //design the following algorithms to never crawl past the cutting plane. That way we can get consistent results
  1449. void Recursive_MarkPlanarity_OnPlane( GeneratePolyhedronFromPlanes_LineLL *pLineWalk, MarkPlanarityControlStruct_t &control );
  1450. void Recursive_MarkPlanarity_Dead( GeneratePolyhedronFromPlanes_LineLL *pLineWalk, MarkPlanarityControlStruct_t &control )
  1451. {
  1452. Assert( pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->planarity == POINT_DEAD );
  1453. //Assert( !pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->debugdata.bVisited || (pLineWalk->pLine->planarity == LINE_DEAD) );
  1454. DBG_ONLY( pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->debugdata.bVisited = true; );
  1455. while( pLineWalk->pLine->planarity == LINE_ALIVE ) //any line connected to a dead point can't be alive, therefore has not been traversed since we only travel through dead points
  1456. {
  1457. Assert( !pLineWalk->pLine->debugdata.bTested && !pLineWalk->pLine->debugdata.bIsNew );
  1458. DBG_ONLY( pLineWalk->pLine->debugdata.bTested = true; );
  1459. GeneratePolyhedronFromPlanes_Point *pConnectedPoint = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex];
  1460. if( pConnectedPoint->fPlaneDist > control.fOnPlaneEpsilon )
  1461. {
  1462. //point dead, line is also dead
  1463. pConnectedPoint->planarity = POINT_DEAD;
  1464. pLineWalk->pLine->planarity = LINE_DEAD;
  1465. //branch into the point as a new root
  1466. Recursive_MarkPlanarity_Dead( pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex].pNext, control );
  1467. }
  1468. else if( pConnectedPoint->fPlaneDist >= control.fNegativeOnPlaneEpsilon )
  1469. {
  1470. //point onplane, line is dead
  1471. pConnectedPoint->planarity = POINT_ONPLANE;
  1472. pLineWalk->pLine->planarity = LINE_DEAD;
  1473. control.pNewPolygon->bMovedExistingPoints = true; //mark the polygon as using off-plane points
  1474. Recursive_MarkPlanarity_OnPlane( pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex].pNext, control );
  1475. control.pActivePolyLine->pLine->pPoints[0] = pConnectedPoint;
  1476. control.pActivePolyLine->pLine->PointLineLinks[0].pNext = &pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex];
  1477. control.pActivePolyLine->pLine->PointLineLinks[0].pPrev = pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex].pPrev;
  1478. }
  1479. else
  1480. {
  1481. //point alive, line is cut
  1482. Assert( pConnectedPoint->planarity == POINT_ALIVE );
  1483. pLineWalk->pLine->planarity = LINE_CUT;
  1484. control.bAllPointsDead = false;
  1485. int iDeadIndex = 1 - pLineWalk->iReferenceIndex;
  1486. int iLivingIndex = pLineWalk->iReferenceIndex;
  1487. GeneratePolyhedronFromPlanes_Point *pDeadPoint = pLineWalk->pLine->pPoints[iDeadIndex];
  1488. GeneratePolyhedronFromPlanes_Point *pLivingPoint = pLineWalk->pLine->pPoints[iLivingIndex];
  1489. //Generate a new point
  1490. GeneratePolyhedronFromPlanes_Point *pNewPoint = AllocatePoint( control.pAllPoints, control.pointAllocator, control.iPointCount );
  1491. {
  1492. Assert( (pDeadPoint->fPlaneDist - pLivingPoint->fPlaneDist) > control.fOnPlaneEpsilon );
  1493. float fInvTotalDist = 1.0f/(pDeadPoint->fPlaneDist - pLivingPoint->fPlaneDist); //subtraction because the living index is known to be negative
  1494. pNewPoint->ptPosition = SubSIMD( MulSIMD(pLivingPoint->ptPosition, ReplicateX4(pDeadPoint->fPlaneDist * fInvTotalDist)),
  1495. MulSIMD(pDeadPoint->ptPosition, ReplicateX4(pLivingPoint->fPlaneDist * fInvTotalDist)) );
  1496. SubFloat( pNewPoint->ptPosition, 3 ) = -1.0f;
  1497. #if defined( DBGFLAG_ASSERT ) //check length of line that will remain in the polyhedron, and doublecheck planar distance of new point
  1498. {
  1499. fltx4 vAliveLineDiff = SubSIMD( pNewPoint->ptPosition, pLivingPoint->ptPosition );
  1500. Vector vecAliveLineDiff( SubFloat( vAliveLineDiff, 0 ), SubFloat( vAliveLineDiff, 1 ), SubFloat( vAliveLineDiff, 2 ) );
  1501. float fLineLength = vecAliveLineDiff.Length();
  1502. AssertMsg( fLineLength > control.fOnPlaneEpsilon, "Dangerously short line" );
  1503. fltx4 vDist = MulSIMD( control.vCutPlane, pNewPoint->ptPosition );
  1504. float fDebugDist;
  1505. fDebugDist = SubFloat( vDist, 0 ) + SubFloat( vDist, 1 ) + SubFloat( vDist, 2 ) + SubFloat( vDist, 3 ); //just for looking at in watch windows
  1506. //Assert( fabs( fDebugDist ) <= control.fOnPlaneEpsilon );
  1507. }
  1508. #endif
  1509. pNewPoint->planarity = POINT_ONPLANE;
  1510. pNewPoint->fPlaneDist = 0.0f;
  1511. }
  1512. pLineWalk->pLine->pPolygons[0]->bHasNewPoints = true;
  1513. pLineWalk->pLine->pPolygons[1]->bHasNewPoints = true;
  1514. GeneratePolyhedronFromPlanes_Line *pCompletedPolyLine = control.pActivePolyLine->pLine;
  1515. GeneratePolyhedronFromPlanes_Line *pNewPolyLine = MarkPlanarity_CreateNewPolyLine( control );
  1516. GeneratePolyhedronFromPlanes_Line *pCutLine = pLineWalk->pLine;
  1517. GeneratePolyhedronFromPlanes_Line *pNewLivingLine = AllocateLine( control.pAllLines, control.lineAllocator );
  1518. //going to relink the cut line to be between the dead point and the new point
  1519. //also going to create a new line between new point and live point
  1520. //The new line will copy the cut line's iReferenceIndex orientation
  1521. {
  1522. //relink point pointers
  1523. pNewLivingLine->pPoints[iDeadIndex] = pNewPoint;
  1524. pNewLivingLine->pPoints[iLivingIndex] = pCutLine->pPoints[iLivingIndex];
  1525. pCutLine->pPoints[iLivingIndex] = pNewPoint;
  1526. pNewPoint->pConnectedLines = &pNewLivingLine->PointLineLinks[iDeadIndex];
  1527. pCutLine->planarity = LINE_DEAD;
  1528. pNewLivingLine->planarity = LINE_ALIVE;
  1529. //new line steals cut line's living index linkages
  1530. pNewLivingLine->PointLineLinks[iLivingIndex].pNext = pCutLine->PointLineLinks[iLivingIndex].pNext;
  1531. pNewLivingLine->PointLineLinks[iLivingIndex].pPrev = pCutLine->PointLineLinks[iLivingIndex].pPrev;
  1532. pNewLivingLine->PointLineLinks[iLivingIndex].pNext->pPrev = &pNewLivingLine->PointLineLinks[iLivingIndex];
  1533. pNewLivingLine->PointLineLinks[iLivingIndex].pPrev->pNext = &pNewLivingLine->PointLineLinks[iLivingIndex];
  1534. pNewLivingLine->pPoints[iLivingIndex]->pConnectedLines = &pNewLivingLine->PointLineLinks[iLivingIndex];
  1535. //crosslink cut living to new dead
  1536. pCutLine->PointLineLinks[iLivingIndex].pNext = pCutLine->PointLineLinks[iLivingIndex].pPrev = &pNewLivingLine->PointLineLinks[iDeadIndex];
  1537. pNewLivingLine->PointLineLinks[iDeadIndex].pNext = pNewLivingLine->PointLineLinks[iDeadIndex].pPrev = &pCutLine->PointLineLinks[iLivingIndex];
  1538. //fix up polygon linkages
  1539. pNewLivingLine->pPolygons[0] = pCutLine->pPolygons[0];
  1540. pNewLivingLine->pPolygons[1] = pCutLine->pPolygons[1];
  1541. //insert after cut line for 0 polygon
  1542. pNewLivingLine->PolygonLineLinks[0].pNext = pCutLine->PolygonLineLinks[0].pNext;
  1543. pNewLivingLine->PolygonLineLinks[0].pPrev = &pCutLine->PolygonLineLinks[0];
  1544. pCutLine->PolygonLineLinks[0].pNext = &pNewLivingLine->PolygonLineLinks[0];
  1545. pNewLivingLine->PolygonLineLinks[0].pNext->pPrev = &pNewLivingLine->PolygonLineLinks[0];
  1546. //insert before cut line for 1 polygon
  1547. pNewLivingLine->PolygonLineLinks[1].pNext = &pCutLine->PolygonLineLinks[1];
  1548. pNewLivingLine->PolygonLineLinks[1].pPrev = pCutLine->PolygonLineLinks[1].pPrev;
  1549. pCutLine->PolygonLineLinks[1].pPrev = &pNewLivingLine->PolygonLineLinks[1];
  1550. pNewLivingLine->PolygonLineLinks[1].pPrev->pNext = &pNewLivingLine->PolygonLineLinks[1];
  1551. }
  1552. //We now should have everything we need to finish constructing pCompletedPolyLine
  1553. {
  1554. //link polygon completed line to new point
  1555. pCompletedPolyLine->pPoints[1] = pNewPoint;
  1556. //Make a T junction between cut line, new line, and completed polygon line
  1557. pCompletedPolyLine->PointLineLinks[1].pPrev = &pCutLine->PointLineLinks[iLivingIndex];
  1558. pCutLine->PointLineLinks[iLivingIndex].pNext = &pCompletedPolyLine->PointLineLinks[1];
  1559. pCompletedPolyLine->PointLineLinks[1].pNext = &pNewLivingLine->PointLineLinks[iDeadIndex];
  1560. pNewLivingLine->PointLineLinks[iDeadIndex].pPrev = &pCompletedPolyLine->PointLineLinks[1];
  1561. //pCompletedLine->pLine->pPoints[0] should already have valid values that just need to be linked back in
  1562. pCompletedPolyLine->PointLineLinks[0].pNext->pPrev = &pCompletedPolyLine->PointLineLinks[0];
  1563. pCompletedPolyLine->PointLineLinks[0].pPrev->pNext = &pCompletedPolyLine->PointLineLinks[0];
  1564. //link outwardly into the patched up polygon
  1565. pCompletedPolyLine->pPolygons[0] = pNewLivingLine->pPolygons[iDeadIndex]; //left side of line going to living point is the polygon that will survive the planar clip
  1566. pCompletedPolyLine->PolygonLineLinks[0].pPrev = &pNewLivingLine->PolygonLineLinks[iDeadIndex];
  1567. pCompletedPolyLine->PolygonLineLinks[0].pNext = pNewLivingLine->PolygonLineLinks[iDeadIndex].pNext;
  1568. pCompletedPolyLine->PolygonLineLinks[0].pNext->pPrev = &pCompletedPolyLine->PolygonLineLinks[0];
  1569. pCompletedPolyLine->PolygonLineLinks[0].pPrev->pNext = &pCompletedPolyLine->PolygonLineLinks[0];
  1570. #if defined( DBGFLAG_ASSERT )
  1571. if( pCompletedPolyLine->pPoints[0] && pCompletedPolyLine->pPoints[1] )
  1572. {
  1573. fltx4 vLineTemp = SubSIMD( pCompletedPolyLine->pPoints[1]->ptPosition, pCompletedPolyLine->pPoints[0]->ptPosition );
  1574. AssertMsg( (SubFloat( vLineTemp, 0 ) != 0.0f) || (SubFloat( vLineTemp, 1 ) != 0.0f) || (SubFloat( vLineTemp, 2 ) != 0.0f), "Created zero length line" );
  1575. }
  1576. #endif
  1577. }
  1578. //keep updating the drag line
  1579. pNewPolyLine->pPoints[0] = pNewPoint;
  1580. pNewPolyLine->PointLineLinks[0].pNext = &pCutLine->PointLineLinks[iLivingIndex];
  1581. pNewPolyLine->PointLineLinks[0].pPrev = &pNewLivingLine->PointLineLinks[iDeadIndex];
  1582. }
  1583. pLineWalk = pLineWalk->pNext;
  1584. }
  1585. /*if( pLineWalk->pLine->planarity == LINE_DEAD )
  1586. {
  1587. //left polygon is dead
  1588. #if defined( DBGFLAG_ASSERT ) //make sure
  1589. {
  1590. //walk the polygon and ensure it should be dead
  1591. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalkHead = &pLineWalk->pLine->PolygonLineLinks[1 - pLineWalk->iReferenceIndex];
  1592. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pDebugLineWalkHead;
  1593. do
  1594. {
  1595. Assert( pDebugLineWalk->pLine->planarity != LINE_ALIVE );
  1596. pDebugLineWalk = pDebugLineWalk->pNext;
  1597. } while (pDebugLineWalk != pDebugLineWalkHead);
  1598. }
  1599. #endif
  1600. Assert( !pLineWalk->pLine->pPolygons[1 - pLineWalk->iReferenceIndex]->bDead ); //not already marked dead
  1601. pLineWalk->pLine->pPolygons[1 - pLineWalk->iReferenceIndex]->bDead = true;
  1602. }*/
  1603. }
  1604. bool Recursive_CanOnPlanePolyCrawlDead( GeneratePolyhedronFromPlanes_LineLL *pLineWalk, MarkPlanarityControlStruct_t &control );
  1605. //Once we start traversing on-plane points, our options reduce. We do this to ensure we never traverse a section that isn't touching the cut plane
  1606. void Recursive_MarkPlanarity_OnPlane( GeneratePolyhedronFromPlanes_LineLL *pLineWalk, MarkPlanarityControlStruct_t &control )
  1607. {
  1608. Assert( pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->planarity == POINT_ONPLANE );
  1609. //Assert( !pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->debugdata.bVisited );
  1610. DBG_ONLY( pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->debugdata.bVisited = true; );
  1611. //onplane's are only allowed to crawl within their polygon. So if the very next line is onplane, recurse. Alive has no work to do, and dead will be picked up later in the dead-crawling algorithm
  1612. if( pLineWalk->pLine->planarity == LINE_ALIVE ) //not already traversed
  1613. {
  1614. Assert( !pLineWalk->pLine->debugdata.bTested && !pLineWalk->pLine->debugdata.bIsNew );
  1615. //DBG_ONLY( pLineWalk->pLine->debugdata.bTested = true; );
  1616. GeneratePolyhedronFromPlanes_Point *pConnectedPoint = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex];
  1617. if( (pConnectedPoint->fPlaneDist > control.fOnPlaneEpsilon) && !Recursive_CanOnPlanePolyCrawlDead( pLineWalk, control ) )
  1618. {
  1619. //do nothing, for consistency we want to be sure we traverse from the dead point to here
  1620. }
  1621. else if( pConnectedPoint->fPlaneDist >= control.fNegativeOnPlaneEpsilon )
  1622. {
  1623. //point onplane, line is onplane, line is part of the new polygon
  1624. pConnectedPoint->planarity = POINT_ONPLANE;
  1625. pLineWalk->pLine->planarity = LINE_ONPLANE;
  1626. Recursive_MarkPlanarity_OnPlane( pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex].pNext, control );
  1627. //Stitch the line we just traversed into the polygon as-is
  1628. {
  1629. //remove from existing dead polygon
  1630. int iDeadSide = 1 - pLineWalk->iReferenceIndex;
  1631. pLineWalk->pLine->PolygonLineLinks[iDeadSide].pNext->pPrev = pLineWalk->pLine->PolygonLineLinks[iDeadSide].pPrev;
  1632. pLineWalk->pLine->PolygonLineLinks[iDeadSide].pPrev->pNext = pLineWalk->pLine->PolygonLineLinks[iDeadSide].pNext;
  1633. /*if( pLineWalk->pLine->PolygonLineLinks[iDeadSide].pNext == &pLineWalk->pLine->PolygonLineLinks[iDeadSide] )
  1634. {
  1635. //this was the last line in the polygon
  1636. pLineWalk->pLine->pPolygons[iDeadSide]->pLines = NULL;
  1637. pLineWalk->pLine->pPolygons[iDeadSide]->bDead = true;
  1638. }
  1639. else*/
  1640. {
  1641. pLineWalk->pLine->pPolygons[iDeadSide]->pLines = pLineWalk->pLine->PolygonLineLinks[iDeadSide].pNext;
  1642. }
  1643. //now replace it with the new polygon
  1644. pLineWalk->pLine->pPolygons[iDeadSide] = control.pNewPolygon;
  1645. //insert before pActivePolyLine
  1646. pLineWalk->pLine->PolygonLineLinks[iDeadSide].pPrev = control.pActivePolyLine->pPrev;
  1647. control.pActivePolyLine->pPrev->pNext = &pLineWalk->pLine->PolygonLineLinks[iDeadSide];
  1648. pLineWalk->pLine->PolygonLineLinks[iDeadSide].pNext = control.pActivePolyLine;
  1649. control.pActivePolyLine->pPrev = &pLineWalk->pLine->PolygonLineLinks[iDeadSide];
  1650. }
  1651. }
  1652. else
  1653. {
  1654. //point alive, line is alive, root point stitched into the new polygon
  1655. GeneratePolyhedronFromPlanes_Line *pCompletedPolyLine = control.pActivePolyLine->pLine;
  1656. //We now should have everything we need to finish constructing pCompletedLine
  1657. {
  1658. //pCompletedLine->pLine->pPoints[0] should already have valid values that just need to be linked back in
  1659. pCompletedPolyLine->PointLineLinks[0].pNext->pPrev = &pCompletedPolyLine->PointLineLinks[0];
  1660. pCompletedPolyLine->PointLineLinks[0].pPrev->pNext = &pCompletedPolyLine->PointLineLinks[0];
  1661. pCompletedPolyLine->pPoints[1] = pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]; //root point is endpoint for completed polygon line
  1662. pCompletedPolyLine->PointLineLinks[1].pPrev = pLineWalk->pPrev;
  1663. pCompletedPolyLine->PointLineLinks[1].pNext = pLineWalk;
  1664. pCompletedPolyLine->PointLineLinks[1].pNext->pPrev = &pCompletedPolyLine->PointLineLinks[1];
  1665. pCompletedPolyLine->PointLineLinks[1].pPrev->pNext = &pCompletedPolyLine->PointLineLinks[1];
  1666. //link outwardly into the patched up polygon
  1667. pCompletedPolyLine->pPolygons[0] = pLineWalk->pLine->pPolygons[1 - pLineWalk->iReferenceIndex]; //left side of line going to live point is the polygon that will survive the planar clip
  1668. pCompletedPolyLine->PolygonLineLinks[0].pPrev = &pLineWalk->pLine->PolygonLineLinks[1 - pLineWalk->iReferenceIndex];
  1669. pCompletedPolyLine->PolygonLineLinks[0].pNext = pCompletedPolyLine->PolygonLineLinks[0].pPrev->pNext;
  1670. pCompletedPolyLine->PolygonLineLinks[0].pNext->pPrev = &pCompletedPolyLine->PolygonLineLinks[0];
  1671. pCompletedPolyLine->PolygonLineLinks[0].pPrev->pNext = &pCompletedPolyLine->PolygonLineLinks[0];
  1672. }
  1673. #if defined( DBGFLAG_ASSERT )
  1674. if( pCompletedPolyLine->pPoints[0] && pCompletedPolyLine->pPoints[1] )
  1675. {
  1676. fltx4 vLineTemp = SubSIMD( pCompletedPolyLine->pPoints[1]->ptPosition, pCompletedPolyLine->pPoints[0]->ptPosition );
  1677. AssertMsg( (SubFloat( vLineTemp, 0 ) != 0.0f) || (SubFloat( vLineTemp, 1 ) != 0.0f) || (SubFloat( vLineTemp, 2 ) != 0.0f), "Created zero length line" );
  1678. }
  1679. #endif
  1680. //point 0 will be filled in as we backtrack to a dead point that recursed into Recursive_MarkPlanarity_OnPlane(). If we recursed from another onplane point, we'll be recycling its line
  1681. MarkPlanarity_CreateNewPolyLine( control );
  1682. }
  1683. }
  1684. /*if( pLineWalk->pLine->planarity == LINE_DEAD )
  1685. {
  1686. //left polygon is dead
  1687. #if defined( DBGFLAG_ASSERT ) //make sure
  1688. {
  1689. //walk the polygon and ensure it should be dead
  1690. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalkHead = &pLineWalk->pLine->PolygonLineLinks[1 - pLineWalk->iReferenceIndex];
  1691. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pDebugLineWalkHead;
  1692. do
  1693. {
  1694. Assert( pDebugLineWalk->pLine->planarity != LINE_ALIVE );
  1695. pDebugLineWalk = pDebugLineWalk->pNext;
  1696. } while (pDebugLineWalk != pDebugLineWalkHead);
  1697. }
  1698. #endif
  1699. Assert( !pLineWalk->pLine->pPolygons[1 - pLineWalk->iReferenceIndex]->bDead ); //not already marked dead
  1700. pLineWalk->pLine->pPolygons[1 - pLineWalk->iReferenceIndex]->bDead = true;
  1701. }*/
  1702. }
  1703. bool Recursive_CanOnPlanePolyCrawlDead( GeneratePolyhedronFromPlanes_LineLL *pLineWalk, MarkPlanarityControlStruct_t &control )
  1704. {
  1705. pLineWalk = pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex].pNext;
  1706. if( pLineWalk->pLine->planarity == LINE_ALIVE ) //not already traversed
  1707. {
  1708. GeneratePolyhedronFromPlanes_Point *pConnectedPoint = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex];
  1709. if( pConnectedPoint->fPlaneDist > control.fOnPlaneEpsilon )
  1710. {
  1711. GeneratePolyhedronFromPlanes_LineLL *pTestAlive = pLineWalk->pNext;
  1712. if( pTestAlive->pLine->pPoints[pTestAlive->iReferenceIndex]->fPlaneDist < control.fNegativeOnPlaneEpsilon )
  1713. {
  1714. //couldn't have possibly crawled here from the other direction if we continue the onplane streak
  1715. return Recursive_CanOnPlanePolyCrawlDead( pLineWalk, control );
  1716. }
  1717. }
  1718. if( pConnectedPoint->fPlaneDist >= control.fNegativeOnPlaneEpsilon )
  1719. {
  1720. GeneratePolyhedronFromPlanes_LineLL *pTestAlive = pLineWalk->pNext;
  1721. if( pTestAlive->pLine->pPoints[pTestAlive->iReferenceIndex]->fPlaneDist < control.fNegativeOnPlaneEpsilon )
  1722. {
  1723. //couldn't have possibly crawled here from the other direction
  1724. return true;
  1725. }
  1726. }
  1727. }
  1728. return false;
  1729. }
  1730. void RecomputePolygonSurfaceNormal( GeneratePolyhedronFromPlanes_Polygon *pPolygon )
  1731. {
  1732. Vector vAggregateNormal = vec3_origin;
  1733. GeneratePolyhedronFromPlanes_LineLL *pLineWalkHead = pPolygon->pLines;
  1734. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pLineWalkHead->pPrev;
  1735. Vector vLastLine;
  1736. fltx4 vLineTemp = SubSIMD( pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition, pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition );
  1737. pLineWalk = pLineWalk->pNext;
  1738. vLastLine.Init( SubFloat( vLineTemp, 0 ), SubFloat( vLineTemp, 1 ), SubFloat( vLineTemp, 2 ) );
  1739. do
  1740. {
  1741. vLineTemp = SubSIMD( pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition, pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition );
  1742. Vector vThisLine( SubFloat( vLineTemp, 0 ), SubFloat( vLineTemp, 1 ), SubFloat( vLineTemp, 2 ) );
  1743. Vector vCross = vThisLine.Cross( vLastLine );
  1744. vAggregateNormal += vThisLine.Cross( vLastLine ); //intentionally not normalizing until the end. Larger lines deserve more influence in the result
  1745. vLastLine = vThisLine;
  1746. pLineWalk = pLineWalk->pNext;
  1747. } while ( pLineWalk != pLineWalkHead );
  1748. vAggregateNormal.NormalizeInPlace();
  1749. pPolygon->vSurfaceNormal = vAggregateNormal;
  1750. }
  1751. CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, int iPointCount, const fltx4 *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory, fltx4 vShiftResultPositions )
  1752. {
  1753. //const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon;
  1754. const float fOnPlaneEpsilonSquared = fOnPlaneEpsilon * fOnPlaneEpsilon;
  1755. #ifdef DBGFLAG_ASSERT
  1756. GeneratePolyhedronFromPlanes_Point *pStartPoint = NULL;
  1757. static int iPolyhedronClipCount = 0;
  1758. ++iPolyhedronClipCount;
  1759. #endif
  1760. size_t iStackMemorySize = (64 * 1024); //start off trying to allocate 128k
  1761. void *pStackMemory = stackalloc( iStackMemorySize );
  1762. while( pStackMemory == NULL )
  1763. {
  1764. iStackMemorySize = iStackMemorySize >> 1;
  1765. pStackMemory = stackalloc( iStackMemorySize );
  1766. }
  1767. CStackMemoryDispenser memoryDispenser( pStackMemory, iStackMemorySize );
  1768. //Collections of dead pointers for reallocation, data in them shouldn't be touched until the current loop iteration is done.
  1769. GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPointCollection = NULL;
  1770. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1771. GeneratePolyhedronFromPlanes_UnorderedLineLL *pDeadLineCollection = NULL;
  1772. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDeadPolygonCollection = NULL;
  1773. #endif
  1774. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPointLL> pointAllocator( memoryDispenser );
  1775. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedLineLL> lineAllocator( memoryDispenser );
  1776. CStackItemDispenser<GeneratePolyhedronFromPlanes_UnorderedPolygonLL> polygonAllocator( memoryDispenser );
  1777. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1778. CClipLinkedGeometryDestructors destructors( iPointCount, pAllPolygons, pDeadPolygonCollection, pAllLines, pDeadLineCollection, pAllPoints, pDeadPointCollection );
  1779. #else
  1780. CClipLinkedGeometryDestructors destructors( iPointCount, pAllPolygons, polygonAllocator, pAllLines, lineAllocator, pAllPoints, pDeadPointCollection );
  1781. #endif
  1782. DBG_ONLY( destructors.DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false, vShiftResultPositions ) ) );
  1783. DBG_ONLY( destructors.DebugCutPlaneIndex.AddToTail( -1 ) );
  1784. for( int iCurrentPlane = 0; iCurrentPlane != iPlaneCount; ++iCurrentPlane )
  1785. {
  1786. #if defined( DBGFLAG_ASSERT )
  1787. destructors.bDebugTrigger = (g_iDebugPolyhedronClipProcess == iCurrentPlane);
  1788. if( destructors.bDebugTrigger )
  1789. {
  1790. g_iDebugPolyhedronClipProcess = -1; //remove the need for cleanup code wherever someone wanted this to break;
  1791. }
  1792. #endif
  1793. //clear out work variables
  1794. {
  1795. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons;
  1796. do
  1797. {
  1798. pActivePolygonWalk->polygon.bDead = false;
  1799. pActivePolygonWalk->polygon.bHasNewPoints = false;
  1800. pActivePolygonWalk->polygon.bMovedExistingPoints = false;
  1801. DBG_ONLY( pActivePolygonWalk->polygon.debugdata.Reset(); );
  1802. pActivePolygonWalk = pActivePolygonWalk->pNext;
  1803. } while( pActivePolygonWalk );
  1804. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines;
  1805. do
  1806. {
  1807. pActiveLineWalk->line.planarity = LINE_ALIVE;
  1808. pActiveLineWalk->line.bNewLengthThisPass = false;
  1809. DBG_ONLY( pActiveLineWalk->line.debugdata.Reset(); );
  1810. pActiveLineWalk = pActiveLineWalk->pNext;
  1811. } while( pActiveLineWalk );
  1812. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints;
  1813. do
  1814. {
  1815. pActivePointWalk->point.planarity = POINT_ALIVE;
  1816. DBG_ONLY( pActivePointWalk->point.debugdata.Reset(); );
  1817. pActivePointWalk = pActivePointWalk->pNext;
  1818. } while( pActivePointWalk );
  1819. }
  1820. while( pDeadPointCollection != NULL )
  1821. {
  1822. GeneratePolyhedronFromPlanes_UnorderedPointLL *pFree = pDeadPointCollection;
  1823. pDeadPointCollection = pDeadPointCollection->pNext;
  1824. pointAllocator.Free( pFree );
  1825. }
  1826. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  1827. while( pDeadLineCollection != NULL )
  1828. {
  1829. GeneratePolyhedronFromPlanes_UnorderedLineLL *pFree = pDeadLineCollection;
  1830. pDeadLineCollection = pDeadLineCollection->pNext;
  1831. lineAllocator.Free( pFree );
  1832. }
  1833. while( pDeadPolygonCollection != NULL )
  1834. {
  1835. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pFree = pDeadPolygonCollection;
  1836. pDeadPolygonCollection = pDeadPolygonCollection->pNext;
  1837. polygonAllocator.Free( pFree );
  1838. }
  1839. #endif
  1840. #if defined( DBGFLAG_ASSERT )
  1841. int iPatchMethod = -1;
  1842. #endif
  1843. //find point distances from the plane
  1844. ComputePlanarDistances( pAllPoints, iPointCount, pOutwardFacingPlanes[iCurrentPlane] );
  1845. //find "most dead" point. We'll be using that as a starting point for an algorithm that walks the edge of the new polygon
  1846. //this walk method lets us categorize points without getting into impossible situations where 2 diagonal corners of a quad are dead, but the other points are onplane/alive
  1847. GeneratePolyhedronFromPlanes_Point *pMostDeadPoint = &pAllPoints->point;
  1848. float fMostDeadPointDist = pAllPoints->point.fPlaneDist;
  1849. {
  1850. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints->pNext;
  1851. do
  1852. {
  1853. if( pActivePointWalk->point.fPlaneDist > fMostDeadPointDist )
  1854. {
  1855. pMostDeadPoint = &pActivePointWalk->point;
  1856. fMostDeadPointDist = pActivePointWalk->point.fPlaneDist;
  1857. }
  1858. pActivePointWalk = pActivePointWalk->pNext;
  1859. } while( pActivePointWalk );
  1860. }
  1861. if( fMostDeadPointDist <= fOnPlaneEpsilon )
  1862. {
  1863. //no cuts made
  1864. continue;
  1865. }
  1866. Vector vSurfaceNormal( SubFloat( pOutwardFacingPlanes[iCurrentPlane], 0 ), SubFloat( pOutwardFacingPlanes[iCurrentPlane], 1 ), SubFloat( pOutwardFacingPlanes[iCurrentPlane], 2 ) );
  1867. GeneratePolyhedronFromPlanes_Polygon *pNewPolygon = AllocatePolygon( pAllPolygons, polygonAllocator, vSurfaceNormal );
  1868. pMostDeadPoint->planarity = POINT_DEAD;
  1869. {
  1870. MarkPlanarityControlStruct_t control( pNewPolygon, lineAllocator, pAllLines, pointAllocator, pAllPoints, iPointCount, fOnPlaneEpsilon );
  1871. #if defined( DBGFLAG_ASSERT )
  1872. GeneratePolyhedronFromPlanes_LineLL *pStartLine = control.pActivePolyLine;
  1873. control.vCutPlane = pOutwardFacingPlanes[iCurrentPlane];
  1874. #endif
  1875. Recursive_MarkPlanarity_Dead( pMostDeadPoint->pConnectedLines, control );
  1876. //it's possible that the crawling algorithm didn't encounter any live points if the plane didn't cut any lines (All intersections between plane and mesh were at an existing vertex)
  1877. if( control.bAllPointsDead )
  1878. {
  1879. //doublecheck
  1880. GeneratePolyhedronFromPlanes_UnorderedPointLL *pPointWalk = pAllPoints;
  1881. while( pPointWalk )
  1882. {
  1883. if( pPointWalk->point.planarity == POINT_ALIVE )
  1884. {
  1885. control.bAllPointsDead = false;
  1886. break;
  1887. }
  1888. pPointWalk = pPointWalk->pNext;
  1889. }
  1890. }
  1891. if( control.bAllPointsDead ) //all the points either died or are on the plane, no polyhedron left at all
  1892. {
  1893. #ifdef DBGFLAG_ASSERT
  1894. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints->pNext;
  1895. do
  1896. {
  1897. Assert( pActivePointWalk->point.planarity != POINT_ALIVE );
  1898. pActivePointWalk = pActivePointWalk->pNext;
  1899. } while( pActivePointWalk );
  1900. #endif
  1901. #if defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  1902. Assert_DumpPolyhedron( g_bDumpNullPolyhedrons == false ); //if someone set it to true, we'll dump the polyhedron then halt
  1903. #endif
  1904. return NULL;
  1905. }
  1906. Assert( (control.pActivePolyLine->pNext == pStartLine) || (pStartLine->pLine->pPoints[0] != NULL) );
  1907. Assert( (pStartLine->pLine->pPoints[1] != NULL) || (pStartLine == control.pActivePolyLine) );
  1908. //search/mark dead polygons, there should be a way to do this in the crawl algorithm
  1909. {
  1910. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygonWalk = pAllPolygons;
  1911. while( pPolygonWalk )
  1912. {
  1913. if( &pPolygonWalk->polygon != control.pNewPolygon )
  1914. {
  1915. bool bDead = true;
  1916. GeneratePolyhedronFromPlanes_LineLL *pStartLine = pPolygonWalk->polygon.pLines;
  1917. GeneratePolyhedronFromPlanes_LineLL *pWalkLine = pStartLine;
  1918. do
  1919. {
  1920. Assert( pWalkLine->pLine->pPolygons[pWalkLine->iReferenceIndex] == &pPolygonWalk->polygon );
  1921. if( pWalkLine->pLine->planarity & LINE_ALIVE )
  1922. {
  1923. bDead = false;
  1924. break;
  1925. }
  1926. pWalkLine = pWalkLine->pNext;
  1927. } while ( pWalkLine != pStartLine );
  1928. if( bDead )
  1929. {
  1930. pPolygonWalk->polygon.bDead = true;
  1931. }
  1932. }
  1933. pPolygonWalk = pPolygonWalk->pNext;
  1934. }
  1935. }
  1936. GeneratePolyhedronFromPlanes_LineLL *pFinal = control.pActivePolyLine;
  1937. if( pFinal->pNext->pLine->pPoints[1 - pFinal->pNext->iReferenceIndex] == NULL )
  1938. {
  1939. //last line redundant, copy partial data into first line
  1940. GeneratePolyhedronFromPlanes_LineLL *pFirst = pFinal->pNext;
  1941. Assert_DumpPolyhedron( pFinal != pFirst );
  1942. Assert_DumpPolyhedron( pFirst->pLine->pPoints[pFirst->iReferenceIndex] != NULL );
  1943. Assert_DumpPolyhedron( pFinal->pLine->pPoints[1 - pFinal->iReferenceIndex] != NULL );
  1944. //link over redundant last line
  1945. pFirst->pPrev = pFinal->pPrev;
  1946. pFinal->pPrev->pNext = pFirst;
  1947. //fill in first point of first line
  1948. pFirst->pLine->pPoints[1 - pFirst->iReferenceIndex] = pFinal->pLine->pPoints[1 - pFinal->iReferenceIndex];
  1949. pFirst->pLine->PointLineLinks[1 - pFirst->iReferenceIndex].pNext = pFinal->pLine->PointLineLinks[1 - pFinal->iReferenceIndex].pNext;
  1950. pFirst->pLine->PointLineLinks[1 - pFirst->iReferenceIndex].pPrev = pFinal->pLine->PointLineLinks[1 - pFinal->iReferenceIndex].pPrev;
  1951. pFirst->pLine->PointLineLinks[1 - pFirst->iReferenceIndex].pNext->pPrev = &pFirst->pLine->PointLineLinks[1 - pFirst->iReferenceIndex];
  1952. pFirst->pLine->PointLineLinks[1 - pFirst->iReferenceIndex].pPrev->pNext = &pFirst->pLine->PointLineLinks[1 - pFirst->iReferenceIndex];
  1953. control.pNewPolygon->pLines = pFirst;
  1954. DestructLine( pFinal->pLine, destructors );
  1955. #if defined( DBGFLAG_ASSERT )
  1956. iPatchMethod = 1;
  1957. {
  1958. fltx4 vLineTemp = SubSIMD( pFirst->pLine->pPoints[1]->ptPosition, pFirst->pLine->pPoints[0]->ptPosition );
  1959. AssertMsg( (SubFloat( vLineTemp, 0 ) != 0.0f) || (SubFloat( vLineTemp, 1 ) != 0.0f) || (SubFloat( vLineTemp, 2 ) != 0.0f), "Created zero length line" );
  1960. }
  1961. #endif
  1962. }
  1963. else
  1964. {
  1965. if( pFinal->pLine->pPoints[1 - pFinal->iReferenceIndex] != pFinal->pNext->pLine->pPoints[1 - pFinal->pNext->iReferenceIndex] )
  1966. {
  1967. //link up the last line to the first line
  1968. GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pFinal->pNext;
  1969. GeneratePolyhedronFromPlanes_Line *pCompletedPolyLine = pFinal->pLine;
  1970. //We now should have everything we need to finish constructing pCompletedLine
  1971. {
  1972. //pCompletedLine->pLine->pPoints[0] should already have valid values that just need to be linked back in
  1973. pCompletedPolyLine->PointLineLinks[0].pNext->pPrev = &pCompletedPolyLine->PointLineLinks[0];
  1974. pCompletedPolyLine->PointLineLinks[0].pPrev->pNext = &pCompletedPolyLine->PointLineLinks[0];
  1975. pCompletedPolyLine->pPoints[1] = pFirstLine->pLine->pPoints[1 - pFirstLine->iReferenceIndex];
  1976. pCompletedPolyLine->PointLineLinks[1].pPrev = &pFirstLine->pLine->PointLineLinks[1 - pFirstLine->iReferenceIndex];
  1977. pCompletedPolyLine->PointLineLinks[1].pNext = pFirstLine->pLine->PointLineLinks[1 - pFirstLine->iReferenceIndex].pNext;
  1978. Assert_DumpPolyhedron( pCompletedPolyLine->PointLineLinks[1].pNext->pLine->planarity != LINE_DEAD );
  1979. pCompletedPolyLine->PointLineLinks[1].pNext->pPrev = &pCompletedPolyLine->PointLineLinks[1];
  1980. pCompletedPolyLine->PointLineLinks[1].pPrev->pNext = &pCompletedPolyLine->PointLineLinks[1];
  1981. GeneratePolyhedronFromPlanes_LineLL *pLivingPolySide = pCompletedPolyLine->PointLineLinks[1].pNext;
  1982. pLivingPolySide = &pLivingPolySide->pLine->PolygonLineLinks[1 - pLivingPolySide->iReferenceIndex]; //convert the link from a point space to polygon space
  1983. //link outwardly into the patched up polygon
  1984. pCompletedPolyLine->pPolygons[0] = pLivingPolySide->pLine->pPolygons[pLivingPolySide->iReferenceIndex];
  1985. pCompletedPolyLine->PolygonLineLinks[0].pPrev = &pLivingPolySide->pLine->PolygonLineLinks[pLivingPolySide->iReferenceIndex];
  1986. pCompletedPolyLine->PolygonLineLinks[0].pNext = pCompletedPolyLine->PolygonLineLinks[0].pPrev->pNext;
  1987. pCompletedPolyLine->PolygonLineLinks[0].pNext->pPrev = &pCompletedPolyLine->PolygonLineLinks[0];
  1988. pCompletedPolyLine->PolygonLineLinks[0].pPrev->pNext = &pCompletedPolyLine->PolygonLineLinks[0];
  1989. Assert_DumpPolyhedron( pCompletedPolyLine->pPolygons[0] != pCompletedPolyLine->pPolygons[1] );
  1990. #if defined( DBGFLAG_ASSERT )
  1991. iPatchMethod = 2;
  1992. {
  1993. fltx4 vLineTemp = SubSIMD( pCompletedPolyLine->pPoints[1]->ptPosition, pCompletedPolyLine->pPoints[0]->ptPosition );
  1994. AssertMsg( (SubFloat( vLineTemp, 0 ) != 0.0f) || (SubFloat( vLineTemp, 1 ) != 0.0f) || (SubFloat( vLineTemp, 2 ) != 0.0f), "Created zero length line" );
  1995. }
  1996. #endif
  1997. }
  1998. }
  1999. else
  2000. {
  2001. //first and last lines were on-plane
  2002. control.pNewPolygon->pLines = control.pActivePolyLine->pNext;
  2003. control.pActivePolyLine->pNext->pPrev = control.pActivePolyLine->pPrev;
  2004. control.pActivePolyLine->pPrev->pNext = control.pActivePolyLine->pNext;
  2005. DestructLine( control.pActivePolyLine->pLine, destructors );
  2006. #if defined( DBGFLAG_ASSERT )
  2007. iPatchMethod = 3;
  2008. #endif
  2009. }
  2010. }
  2011. #if defined( DBGFLAG_ASSERT )
  2012. {
  2013. GeneratePolyhedronFromPlanes_UnorderedLineLL *pLineWalk = pAllLines;
  2014. do
  2015. {
  2016. Assert( pLineWalk->line.pPoints[0] != NULL && pLineWalk->line.pPoints[1] != NULL );
  2017. pLineWalk = pLineWalk->pNext;
  2018. } while (pLineWalk);
  2019. }
  2020. #endif
  2021. }
  2022. #ifdef DBGFLAG_ASSERT
  2023. destructors.PlaneCutHistory.AddToTail( (float *)&pOutwardFacingPlanes[iCurrentPlane] );
  2024. #endif
  2025. //remove dead lines
  2026. {
  2027. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines;
  2028. do
  2029. {
  2030. if( pActiveLineWalk->line.planarity == LINE_DEAD )
  2031. {
  2032. UnlinkLine( pActiveLineWalk );
  2033. //move the line to the dead list
  2034. pActiveLineWalk = DestructLine( pActiveLineWalk, destructors );
  2035. }
  2036. else
  2037. {
  2038. pActiveLineWalk = pActiveLineWalk->pNext;
  2039. }
  2040. } while( pActiveLineWalk );
  2041. }
  2042. //remove dead polygons
  2043. {
  2044. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons;
  2045. do
  2046. {
  2047. if( pActivePolygonWalk->polygon.bDead )
  2048. {
  2049. pActivePolygonWalk = DestructPolygon( pActivePolygonWalk, destructors );
  2050. }
  2051. else
  2052. {
  2053. pActivePolygonWalk = pActivePolygonWalk->pNext;
  2054. }
  2055. } while( pActivePolygonWalk );
  2056. }
  2057. //remove dead points
  2058. {
  2059. GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints;
  2060. do
  2061. {
  2062. if( pActivePointWalk->point.planarity == POINT_DEAD )
  2063. {
  2064. pActivePointWalk = DestructPoint( pActivePointWalk, destructors );
  2065. }
  2066. else
  2067. {
  2068. pActivePointWalk = pActivePointWalk->pNext;
  2069. }
  2070. } while( pActivePointWalk );
  2071. }
  2072. #if defined( DEBUG_POLYHEDRON_CONVERSION )
  2073. if( g_pPolyhedronCarvingDebugStepCallback != NULL )
  2074. {
  2075. CPolyhedron *pTestPolyhedron = ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false, vShiftResultPositions );
  2076. Assert_DumpPolyhedron( pTestPolyhedron );
  2077. if( !g_pPolyhedronCarvingDebugStepCallback( pTestPolyhedron ) )
  2078. {
  2079. VMatrix matScaleCentered;
  2080. matScaleCentered.Identity();
  2081. matScaleCentered[0][0] = matScaleCentered[1][1] = matScaleCentered[2][2] = 10.0f;
  2082. matScaleCentered.SetTranslation( -pTestPolyhedron->Center() * 10.0f );
  2083. DumpPolyhedronToGLView( pTestPolyhedron, "AssertPolyhedron.txt", &matScaleCentered, "wb" );
  2084. AssertMsg_DumpPolyhedron( false, "Outside conversion failed" );
  2085. }
  2086. pTestPolyhedron->Release();
  2087. }
  2088. #endif
  2089. //When clipping a 2D polyhedron, the result of any clipping is a faux 3rd polygon which is degenerate (2 lines, both connected to the same set of points). Remove it now
  2090. if( pNewPolygon->pLines->pNext == pNewPolygon->pLines->pPrev )
  2091. {
  2092. AssertMsg_DumpPolyhedron( (pAllPolygons->pNext != NULL) && //more than 1
  2093. (pAllPolygons->pNext->pNext != NULL) && //more than 2
  2094. (pAllPolygons->pNext->pNext->pNext == NULL), //exactly 3 polygons, and no more
  2095. "This case should only pop up if the input to the last cutting pass was a 2 sided polyhedron" );
  2096. RemoveDegeneratePolygon( pNewPolygon, destructors );
  2097. pNewPolygon = NULL;
  2098. }
  2099. //remove super-short lines
  2100. {
  2101. //ideally this behavior should be integrated with the Recursive_MarkPlanarity_Dead() behavior to avoid creating them in the first place.
  2102. //But choosing safety over performance for now since Recursive_MarkPlanarity_Dead() is stable right now
  2103. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines;
  2104. do
  2105. {
  2106. if( pActiveLineWalk->line.bNewLengthThisPass )
  2107. {
  2108. fltx4 vDiff = SubSIMD( pActiveLineWalk->line.pPoints[0]->ptPosition, pActiveLineWalk->line.pPoints[1]->ptPosition );
  2109. vDiff = MulSIMD( vDiff, vDiff );
  2110. float fLengthSqr = SubFloat( vDiff, 0 ) + SubFloat( vDiff, 1 ) + SubFloat( vDiff, 2 );
  2111. if( fLengthSqr <= fOnPlaneEpsilonSquared ) //eq for 0.0 epsilon case
  2112. {
  2113. //this line needs to go. But removing it might have repercussions
  2114. GeneratePolyhedronFromPlanes_Polygon *pPolygons[2] = { pActiveLineWalk->line.pPolygons[0], pActiveLineWalk->line.pPolygons[1] };
  2115. GeneratePolyhedronFromPlanes_Line *pShortLine = &pActiveLineWalk->line;
  2116. GeneratePolyhedronFromPlanes_Point *pDeadPoint = pShortLine->pPoints[1];
  2117. GeneratePolyhedronFromPlanes_Point *pKeepPoint = pShortLine->pPoints[0];
  2118. //reposition point 0 to be the midpoint? In my experience it's best to just leave it alone when dealing with small distances.
  2119. //relink point 1 links to point 0
  2120. {
  2121. //update point pointers
  2122. {
  2123. GeneratePolyhedronFromPlanes_LineLL *pPointLineWalkHead = pDeadPoint->pConnectedLines;
  2124. GeneratePolyhedronFromPlanes_LineLL *pPointLineWalk = pPointLineWalkHead;
  2125. do
  2126. {
  2127. pPointLineWalk->pLine->pPoints[1- pPointLineWalk->iReferenceIndex] = pKeepPoint;
  2128. pPointLineWalk->pLine->pPolygons[pPointLineWalk->iReferenceIndex]->bMovedExistingPoints = true;//also inform touching polygons that we're changing their geometry
  2129. pPointLineWalk = pPointLineWalk->pNext;
  2130. } while( pPointLineWalk != pPointLineWalkHead );
  2131. //except the line we're killing
  2132. pShortLine->pPoints[1] = pDeadPoint;
  2133. }
  2134. //insert all lines from point 1 as a fan between point 0 prev and the short line.
  2135. pShortLine->PointLineLinks[1].pNext->pPrev = pShortLine->PointLineLinks[0].pPrev;
  2136. pShortLine->PointLineLinks[0].pPrev->pNext = pShortLine->PointLineLinks[1].pNext;
  2137. pShortLine->PointLineLinks[1].pPrev->pNext = &pShortLine->PointLineLinks[0];
  2138. pShortLine->PointLineLinks[0].pPrev = pShortLine->PointLineLinks[1].pPrev;
  2139. pShortLine->PointLineLinks[1].pNext = &pShortLine->PointLineLinks[1];
  2140. pShortLine->PointLineLinks[1].pPrev = &pShortLine->PointLineLinks[1];
  2141. }
  2142. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  2143. pDeadPoint->planarity = POINT_DEAD; //to avoid future asserts, also for coloration. Not useful otherwise as we're about to delete it.
  2144. #endif
  2145. UnlinkLine( pShortLine );
  2146. pActiveLineWalk = DestructLine( pShortLine, destructors );
  2147. DestructPoint( pDeadPoint, destructors );
  2148. for( int i = 0; i != 2; ++i )
  2149. {
  2150. if( pPolygons[i]->pLines->pNext == pPolygons[i]->pLines->pPrev )
  2151. {
  2152. //this polygon is dead
  2153. if( pAllPolygons->pNext->pNext == NULL )
  2154. {
  2155. //It's conceivably possible to either start or collapse down to a 2D polyhedron with every line cut save one.
  2156. //We can't have 1 polygon, and I don't want to mentally run down what would happen below if we tried to collapse down to 1.
  2157. //So just bail now
  2158. #if defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  2159. Assert_DumpPolyhedron( g_bDumpNullPolyhedrons == false ); //if someone set it to true, we'll dump the polyhedron then halt
  2160. #endif
  2161. return NULL;
  2162. }
  2163. if( pPolygons[i] == pNewPolygon )
  2164. {
  2165. pNewPolygon = NULL;
  2166. }
  2167. if( pActiveLineWalk )
  2168. {
  2169. GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalkNext = pActiveLineWalk->pNext;
  2170. GeneratePolyhedronFromPlanes_Line *pTestDelete = &pActiveLineWalk->line;
  2171. if( pTestDelete == RemoveDegeneratePolygon( pPolygons[i], destructors ) )
  2172. {
  2173. pActiveLineWalk = pActiveLineWalkNext;
  2174. }
  2175. }
  2176. else
  2177. {
  2178. RemoveDegeneratePolygon( pPolygons[i], destructors );
  2179. }
  2180. }
  2181. }
  2182. continue; //pActiveLineWalk already updated
  2183. }
  2184. }
  2185. pActiveLineWalk = pActiveLineWalk->pNext;
  2186. } while( pActiveLineWalk );
  2187. }
  2188. #if defined( DEBUG_POLYHEDRON_CONVERSION )
  2189. if( g_pPolyhedronCarvingDebugStepCallback != NULL )
  2190. {
  2191. CPolyhedron *pTestPolyhedron = ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false, vShiftResultPositions );
  2192. Assert_DumpPolyhedron( pTestPolyhedron );
  2193. if( !g_pPolyhedronCarvingDebugStepCallback( pTestPolyhedron ) )
  2194. {
  2195. VMatrix matScaleCentered;
  2196. matScaleCentered.Identity();
  2197. matScaleCentered[0][0] = matScaleCentered[1][1] = matScaleCentered[2][2] = 10.0f;
  2198. matScaleCentered.SetTranslation( -pTestPolyhedron->Center() * 10.0f );
  2199. DumpPolyhedronToGLView( pTestPolyhedron, "AssertPolyhedron.txt", &matScaleCentered, "wb" );
  2200. AssertMsg_DumpPolyhedron( false, "Outside conversion failed" );
  2201. }
  2202. pTestPolyhedron->Release();
  2203. }
  2204. #endif
  2205. AssertMsg( pAllPolygons->pNext != NULL, "A polyhedron must have at least 2 sides to be a 2D Polyhedron, and at least 4 to be a 3D polyhedron" );
  2206. //if any polygons had their geometry adjusted (or new poly uses existing on-plane points), we need to recompute the surface normal and check for degenerate points
  2207. {
  2208. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons;
  2209. if( pAllPolygons->pNext->pNext != NULL )
  2210. {
  2211. //for 3D polyhedrons, remove degenerate points and recompute normals
  2212. do
  2213. {
  2214. if( pActivePolygonWalk->polygon.bMovedExistingPoints || pActivePolygonWalk->polygon.bHasNewPoints )
  2215. {
  2216. RemoveDegeneratePoints( &pActivePolygonWalk->polygon, destructors );
  2217. RecomputePolygonSurfaceNormal( &pActivePolygonWalk->polygon );
  2218. }
  2219. pActivePolygonWalk = pActivePolygonWalk->pNext;
  2220. } while( pActivePolygonWalk );
  2221. }
  2222. else
  2223. {
  2224. //for 2D polyhedrons, only recompute normals. RemoveDegeneratePoints() is not safe for 2D polyhedrons as it assumes the shape is 3 dimensional to avoid angle computations and checks
  2225. do
  2226. {
  2227. if( pActivePolygonWalk->polygon.bMovedExistingPoints || pActivePolygonWalk->polygon.bHasNewPoints )
  2228. {
  2229. RecomputePolygonSurfaceNormal( &pActivePolygonWalk->polygon );
  2230. }
  2231. pActivePolygonWalk = pActivePolygonWalk->pNext;
  2232. } while( pActivePolygonWalk );
  2233. }
  2234. }
  2235. #if defined( DEBUG_POLYHEDRON_CONVERSION )
  2236. if( g_pPolyhedronCarvingDebugStepCallback != NULL )
  2237. {
  2238. CPolyhedron *pTestPolyhedron = ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false, vShiftResultPositions );
  2239. Assert_DumpPolyhedron( pTestPolyhedron );
  2240. if( !g_pPolyhedronCarvingDebugStepCallback( pTestPolyhedron ) )
  2241. {
  2242. VMatrix matScaleCentered;
  2243. matScaleCentered.Identity();
  2244. matScaleCentered[0][0] = matScaleCentered[1][1] = matScaleCentered[2][2] = 10.0f;
  2245. matScaleCentered.SetTranslation( -pTestPolyhedron->Center() * 10.0f );
  2246. DumpPolyhedronToGLView( pTestPolyhedron, "AssertPolyhedron.txt", &matScaleCentered, "wb" );
  2247. AssertMsg_DumpPolyhedron( false, "Outside conversion failed" );
  2248. }
  2249. pTestPolyhedron->Release();
  2250. }
  2251. #endif
  2252. //remove points which, although seemingly useful. Actually create concave shapes
  2253. {
  2254. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons;
  2255. do
  2256. {
  2257. if( pActivePolygonWalk->polygon.bHasNewPoints )
  2258. {
  2259. Vector vTestNormal = pActivePolygonWalk->polygon.vSurfaceNormal;
  2260. GeneratePolyhedronFromPlanes_LineLL *pLineWalkHead = pActivePolygonWalk->polygon.pLines;
  2261. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pLineWalkHead->pPrev;
  2262. Vector vLastLine;
  2263. fltx4 vLineTemp = SubSIMD( pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition, pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition );
  2264. pLineWalk = pLineWalk->pNext;
  2265. vLastLine.Init( SubFloat( vLineTemp, 0 ), SubFloat( vLineTemp, 1 ), SubFloat( vLineTemp, 2 ) );
  2266. do
  2267. {
  2268. vLineTemp = SubSIMD( pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition, pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition );
  2269. Vector vThisLine( SubFloat( vLineTemp, 0 ), SubFloat( vLineTemp, 1 ), SubFloat( vLineTemp, 2 ) );
  2270. Vector vCross = vThisLine.Cross( vLastLine );
  2271. if( vCross.Dot( vTestNormal ) <= 0.0f )
  2272. {
  2273. //this point is a troublemaker
  2274. GeneratePolyhedronFromPlanes_Point *pProblemPoint = pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex];
  2275. if( pLineWalk->pPrev == pLineWalkHead )
  2276. {
  2277. //about to delete our start/stop point. Avoid infinite loops
  2278. pLineWalkHead = pLineWalk;
  2279. }
  2280. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  2281. pProblemPoint->planarity = POINT_DEAD; //to avoid future asserts, also for coloration. Not useful otherwise as we're about to delete it.
  2282. #endif
  2283. #if defined( DBGFLAG_ASSERT )
  2284. {
  2285. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalkHead = pProblemPoint->pConnectedLines;
  2286. GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pDebugLineWalkHead;
  2287. do
  2288. {
  2289. Assert( (pDebugLineWalk->pLine->pPolygons[0] == &pActivePolygonWalk->polygon) ||
  2290. (pDebugLineWalk->pLine->pPolygons[1] == &pActivePolygonWalk->polygon) ||
  2291. (pDebugLineWalk->pLine->pPolygons[0]->vSurfaceNormal.Dot( pDebugLineWalk->pLine->pPolygons[1]->vSurfaceNormal ) > 0.95f) );
  2292. pDebugLineWalk = pDebugLineWalk->pNext;
  2293. } while( pDebugLineWalk != pDebugLineWalkHead );
  2294. }
  2295. #endif
  2296. //what we're going to do is eliminate the problem point and every line connected to it save one.
  2297. //That one saved line will take the place of both lines on the new poly edge connected to this point
  2298. //As part of eliminating all the lines connected to this point, we need to merge polygons separated by those lines.
  2299. //To do that we'll just take the first polygon we encounter and stitch the other polygon lines into it.
  2300. GeneratePolyhedronFromPlanes_LineLL *pPatchStop = &pLineWalk->pLine->PolygonLineLinks[1 - pLineWalk->iReferenceIndex]; //where the polygon patching algorithm should stop
  2301. GeneratePolyhedronFromPlanes_LineLL *pPatchWalk = pLineWalk->pPrev; //rewind to prev line
  2302. pPatchWalk = &pPatchWalk->pLine->PolygonLineLinks[1 - pPatchWalk->iReferenceIndex]; //convert to the non-new polygon walk space, pPatchWalk is the on-polygon line we'll be killing
  2303. GeneratePolyhedronFromPlanes_Polygon *pPatchPolygon = pPatchWalk->pLine->pPolygons[pPatchWalk->iReferenceIndex];
  2304. //pPatchStop doubles as the surviving on-polygon line. Go ahead and do all the fix ups necessary to allow us to clean up the dead lines as we come across them
  2305. pPatchStop->pLine->pPoints[pPatchStop->iReferenceIndex] = pPatchWalk->pLine->pPoints[pPatchWalk->iReferenceIndex];
  2306. {
  2307. GeneratePolyhedronFromPlanes_LineLL *pRelink = &pPatchStop->pLine->PointLineLinks[pPatchStop->iReferenceIndex];
  2308. //unlink pPatchStop from dead point
  2309. pRelink->pNext->pPrev = pRelink->pPrev;
  2310. pRelink->pPrev->pNext = pRelink->pNext;
  2311. //relink into pPatchWalk's living point (insert arbitrarily before pPatchWalk)
  2312. pRelink->pNext = &pPatchWalk->pLine->PointLineLinks[pPatchWalk->iReferenceIndex];
  2313. pRelink->pPrev = pRelink->pNext->pPrev;
  2314. pRelink->pNext->pPrev = pRelink;
  2315. pRelink->pPrev->pNext = pRelink;
  2316. }
  2317. pPatchWalk = pPatchWalk->pNext; //forward to the next line that won't be dead when we're done. From here on it's a clockwise walk on this polygon until we reach a line we'll kill, then we switch to the next
  2318. //go ahead and kill the dead on-polygon line
  2319. {
  2320. GeneratePolyhedronFromPlanes_Line *pKillLine = pPatchWalk->pPrev->pLine;
  2321. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  2322. pKillLine->planarity = LINE_DEAD; //to avoid future asserts, also for coloration. Not useful otherwise as we're about to delete it.
  2323. #endif
  2324. UnlinkLine( pKillLine );
  2325. DestructLine( pKillLine, destructors );
  2326. }
  2327. do
  2328. {
  2329. if( pPatchWalk->pLine->pPoints[pPatchWalk->iReferenceIndex] == pProblemPoint )
  2330. {
  2331. //done walking this polygon, stitch it to the next
  2332. GeneratePolyhedronFromPlanes_Line *pKillLine = pPatchWalk->pLine;
  2333. GeneratePolyhedronFromPlanes_Polygon *pKillPolygon = pPatchWalk->pLine->pPolygons[pPatchWalk->iReferenceIndex];
  2334. GeneratePolyhedronFromPlanes_LineLL *pPatchPrev = pPatchWalk->pPrev;
  2335. pPatchWalk = pPatchWalk->pLine->PolygonLineLinks[1 - pPatchWalk->iReferenceIndex].pNext; //flip to the other side's polygon, then forward to the next line we'll keep
  2336. //patching will be more straightforward if we kill all the dead stuff now
  2337. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  2338. pKillLine->planarity = LINE_DEAD; //to avoid future asserts, also for coloration. Not useful otherwise as we're about to delete it.
  2339. #endif
  2340. UnlinkLine( pKillLine );
  2341. DestructLine( pKillLine, destructors );
  2342. if( pKillPolygon != pPatchPolygon )
  2343. {
  2344. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  2345. pKillPolygon->bDead = true; //to avoid future asserts, also for coloration. Not useful otherwise as we're about to delete it.
  2346. #endif
  2347. DestructPolygon( pKillPolygon, destructors );
  2348. }
  2349. //link the far end of the polygon to our start (which should continually be the first living pPatchWalk line on pPatchPolygon
  2350. pPatchWalk->pPrev->pNext = pPatchPrev->pNext;
  2351. pPatchPrev->pNext->pPrev = pPatchWalk->pPrev;
  2352. pPatchPrev->pNext = pPatchWalk;
  2353. pPatchWalk->pPrev = pPatchPrev; //at this point, the two polygons's line linkages are one large polygon except that the new polygon's line are pointing at the dead polygon which will be fixed as we continue to walk it
  2354. }
  2355. pPatchWalk->pLine->pPolygons[pPatchWalk->iReferenceIndex] = pPatchPolygon;
  2356. pPatchWalk = pPatchWalk->pNext;
  2357. } while( pPatchWalk != pPatchStop );
  2358. //final patch is just slightly different than other patches
  2359. {
  2360. #if defined( DBGFLAG_ASSERT ) || defined( ENABLE_DEBUG_POLYHEDRON_DUMPS )
  2361. pPatchStop->pLine->pPolygons[pPatchStop->iReferenceIndex]->bDead = true; //to avoid future asserts, also for coloration. Not useful otherwise as we're about to delete it.
  2362. #endif
  2363. DestructPolygon( pPatchStop->pLine->pPolygons[pPatchStop->iReferenceIndex], destructors );
  2364. pPatchStop->pLine->pPolygons[pPatchStop->iReferenceIndex] = pPatchPolygon;
  2365. }
  2366. DestructPoint( pProblemPoint, destructors );
  2367. Assert( pAllPolygons->pNext != NULL );
  2368. if( pAllPolygons->pNext->pNext != NULL )
  2369. {
  2370. RemoveDegeneratePoints( pPatchPolygon, destructors );
  2371. }
  2372. //vLastLine and vThisLine are invalidated. Luckily we just need to recompute vThisLine and it'll copy to vLastLine
  2373. vLineTemp = SubSIMD( pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition, pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition );
  2374. vThisLine.Init( SubFloat( vLineTemp, 0 ), SubFloat( vLineTemp, 1 ), SubFloat( vLineTemp, 2 ) );
  2375. }
  2376. vLastLine = vThisLine;
  2377. pLineWalk = pLineWalk->pNext;
  2378. } while ( pLineWalk != pLineWalkHead );
  2379. }
  2380. pActivePolygonWalk = pActivePolygonWalk->pNext;
  2381. } while( pActivePolygonWalk );
  2382. }
  2383. #ifdef DBGFLAG_ASSERT
  2384. //verify that repairs are complete
  2385. {
  2386. DBG_RESETWORKINGSTATECOLORS();
  2387. GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons;
  2388. do
  2389. {
  2390. GeneratePolyhedronFromPlanes_LineLL *pLineStart = pDebugPolygonWalk->polygon.pLines;
  2391. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pLineStart;
  2392. GeneratePolyhedronFromPlanes_Point *pCheckPoint = pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex];
  2393. int iCount = 0;
  2394. //walk around the polygon according to its line links
  2395. do
  2396. {
  2397. Assert_DumpPolyhedron( pLineWalk->pLine->planarity != LINE_DEAD );
  2398. Assert_DumpPolyhedron( (pLineWalk->pLine->pPoints[0]->planarity != POINT_DEAD) && (pLineWalk->pLine->pPoints[1]->planarity != POINT_DEAD) );
  2399. AssertMsg_DumpPolyhedron( pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex] == pCheckPoint, "Line endpoint mismatch" ); //last line's endpoint does not match up with this lines start point
  2400. AssertMsg_DumpPolyhedron( pLineWalk->pLine->pPolygons[pLineWalk->iReferenceIndex] == &pDebugPolygonWalk->polygon, "Line links to wrong polygon" );
  2401. #if 1
  2402. fltx4 f4Diff1 = SubSIMD( pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition, pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition );
  2403. fltx4 f4Diff2 = SubSIMD( pLineWalk->pNext->pLine->pPoints[pLineWalk->pNext->iReferenceIndex]->ptPosition, pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition );
  2404. Vector vDiff1( SubFloat( f4Diff1, 0 ), SubFloat( f4Diff1, 1 ), SubFloat( f4Diff1, 2 ) );
  2405. Vector vDiff2( SubFloat( f4Diff2, 0 ), SubFloat( f4Diff2, 1 ), SubFloat( f4Diff2, 2 ) );
  2406. Vector vCross = vDiff2.Cross( vDiff1 );
  2407. float fDot = vCross.Dot( pDebugPolygonWalk->polygon.vSurfaceNormal );
  2408. AssertMsg_DumpPolyhedron( fDot >= 0.0f, "Concave polygon" );
  2409. #endif
  2410. pCheckPoint = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex];
  2411. pLineWalk = pLineWalk->pNext;
  2412. ++iCount;
  2413. } while( pLineWalk != pLineStart );
  2414. AssertMsg_DumpPolyhedron( iCount >= 3, "Degenerate polygon" );
  2415. #if 0
  2416. fltx4 vSurfaceNormal;
  2417. SubFloat( vSurfaceNormal, 0 ) = pDebugPolygonWalk->polygon.vSurfaceNormal.x;
  2418. SubFloat( vSurfaceNormal, 1 ) = pDebugPolygonWalk->polygon.vSurfaceNormal.y;
  2419. SubFloat( vSurfaceNormal, 2 ) = pDebugPolygonWalk->polygon.vSurfaceNormal.z;
  2420. SubFloat( vSurfaceNormal, 3 ) = 0.0f;
  2421. #endif
  2422. pLineStart = &pLineStart->pLine->PointLineLinks[1 - pLineStart->iReferenceIndex];
  2423. pLineWalk = pLineStart;
  2424. //walk around the polygon again using point traversal
  2425. do
  2426. {
  2427. AssertMsg_DumpPolyhedron( pLineWalk->pLine->pPolygons[pLineWalk->iReferenceIndex] == &pDebugPolygonWalk->polygon, "bad line/polygon linkage" );
  2428. #if 0
  2429. //at each point of each polygon, make sure every line connected to that point goes away from our normal
  2430. {
  2431. GeneratePolyhedronFromPlanes_LineLL *pConcavityWalk = &pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex];
  2432. GeneratePolyhedronFromPlanes_LineLL *pConcavityWalkStop = pConcavityWalk->pPrev;
  2433. pConcavityWalk = pConcavityWalk->pNext;
  2434. while ( pConcavityWalk != pConcavityWalkStop )
  2435. {
  2436. fltx4 vLine = SubSIMD( pConcavityWalk->pLine->pPoints[pConcavityWalk->iReferenceIndex]->ptPosition, pConcavityWalk->pLine->pPoints[1 - pConcavityWalk->iReferenceIndex]->ptPosition );
  2437. fltx4 vMul = MulSIMD( vSurfaceNormal, vLine );
  2438. float fDot = SubFloat( vMul, 0 ) + SubFloat( vMul, 1 ) + SubFloat( vMul, 2 );
  2439. AssertMsg_DumpPolyhedron( fDot <= kfPointRounding, "Concave polyhedron" );
  2440. pConcavityWalk = pConcavityWalk->pNext;
  2441. }
  2442. }
  2443. #endif
  2444. pLineWalk = pLineWalk->pLine->PointLineLinks[pLineWalk->iReferenceIndex].pPrev;
  2445. } while( pLineWalk != pLineStart );
  2446. pDebugPolygonWalk = pDebugPolygonWalk->pNext;
  2447. } while( pDebugPolygonWalk );
  2448. bool bTwoPolygons = (pAllPolygons->pNext->pNext == NULL);
  2449. GeneratePolyhedronFromPlanes_UnorderedPointLL *pDebugPointWalk = pAllPoints;
  2450. do
  2451. {
  2452. int iCount = 0;
  2453. AssertMsg_DumpPolyhedron( pDebugPointWalk->point.pConnectedLines, "Point connected to no lines after cut" );
  2454. GeneratePolyhedronFromPlanes_LineLL *pLineStart = pDebugPointWalk->point.pConnectedLines;
  2455. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pLineStart;
  2456. GeneratePolyhedronFromPlanes_Point *pTestPoint = &pDebugPointWalk->point;
  2457. do
  2458. {
  2459. fltx4 f4Diff = SubSIMD( pTestPoint->ptPosition, pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition );
  2460. Vector vDiff( SubFloat( f4Diff, 0 ), SubFloat( f4Diff, 1 ), SubFloat( f4Diff, 2 ) );
  2461. float fLengthSqr = vDiff.LengthSqr();
  2462. AssertMsg_DumpPolyhedron( fLengthSqr > 0.0f, "Generated a point on top of another" );
  2463. AssertMsg_DumpPolyhedron( pLineWalk->pLine->pPolygons[pLineWalk->iReferenceIndex] == pLineWalk->pNext->pLine->pPolygons[1 - pLineWalk->pNext->iReferenceIndex], "Bad line/polygon linkage" );
  2464. GeneratePolyhedronFromPlanes_LineLL *pSubLineWalk = pLineWalk->pNext;
  2465. while( pSubLineWalk != pLineStart )
  2466. {
  2467. AssertMsg_DumpPolyhedron( (pLineWalk->pLine->pPolygons[pLineWalk->iReferenceIndex] != pSubLineWalk->pLine->pPolygons[pSubLineWalk->iReferenceIndex]) &&
  2468. (pLineWalk->pLine->pPolygons[1 - pLineWalk->iReferenceIndex] != pSubLineWalk->pLine->pPolygons[1 - pSubLineWalk->iReferenceIndex]), "Point connected to two other points on the same polygon" );
  2469. pSubLineWalk = pSubLineWalk->pNext;
  2470. }
  2471. pLineWalk = pLineWalk->pNext;
  2472. ++iCount;
  2473. } while( pLineWalk != pLineStart );
  2474. AssertMsg_DumpPolyhedron( bTwoPolygons || iCount >= 3, "Degenerate point" ); //there can be two-sided polyhedrons where this is not a degenerate case
  2475. pDebugPointWalk = pDebugPointWalk->pNext;
  2476. } while( pDebugPointWalk );
  2477. GeneratePolyhedronFromPlanes_UnorderedLineLL *pDebugLineWalk = pAllLines;
  2478. do
  2479. {
  2480. AssertMsg_DumpPolyhedron( (pDebugLineWalk->line.pPolygons[0] != NULL) && (pDebugLineWalk->line.pPolygons[1] != NULL), "There's a polygon missing" );
  2481. AssertMsg_DumpPolyhedron( pDebugLineWalk->line.pPoints[0] && pDebugLineWalk->line.pPoints[1], "Line missing a point" );
  2482. #if 0
  2483. fltx4 f4Line = SubSIMD( pDebugLineWalk->line.pPoints[0]->ptPosition, pDebugLineWalk->line.pPoints[1]->ptPosition );
  2484. Vector vLine( SubFloat( f4Line, 0 ), SubFloat( f4Line, 1 ), SubFloat( f4Line, 2 ) );
  2485. float fLength = vLine.Length();
  2486. AssertMsg_DumpPolyhedron( fLength > FLT_EPSILON, "Ridiculously short line" );
  2487. if( fLength > fOnPlaneEpsilon )
  2488. {
  2489. if( fLength > 1.0f )
  2490. vLine *= 1.0f / fLength;
  2491. float fDots[2] = { vLine.Dot( pDebugLineWalk->line.pPolygons[0]->vSurfaceNormal ), vLine.Dot( pDebugLineWalk->line.pPolygons[1]->vSurfaceNormal ) };
  2492. AssertMsg_DumpPolyhedron( (fabs( fDots[0] ) < (1.0f/128.0f) ) &&
  2493. (fabs( fDots[1] ) < (1.0f/128.0f) ),
  2494. "Line is not orthogonal to plane normal it's surrounding" );
  2495. }
  2496. #endif
  2497. pDebugLineWalk = pDebugLineWalk->pNext;
  2498. } while( pDebugLineWalk );
  2499. pStartPoint = NULL;
  2500. }
  2501. CPolyhedron *pHistoryPolyhedron = ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false, vShiftResultPositions );
  2502. #if defined( DEBUG_POLYHEDRON_CONVERSION )
  2503. //last bit of debugging from whatever outside source wants this stupid thing
  2504. if( g_pPolyhedronCarvingDebugStepCallback != NULL )
  2505. {
  2506. if( !g_pPolyhedronCarvingDebugStepCallback( pHistoryPolyhedron ) )
  2507. {
  2508. VMatrix matScaleCentered;
  2509. matScaleCentered.Identity();
  2510. matScaleCentered[0][0] = matScaleCentered[1][1] = matScaleCentered[2][2] = 10.0f;
  2511. matScaleCentered.SetTranslation( -pHistoryPolyhedron->Center() * 10.0f );
  2512. DumpPolyhedronToGLView( pHistoryPolyhedron, "AssertPolyhedron.txt", &matScaleCentered, "wb" );
  2513. AssertMsg_DumpPolyhedron( false, "Outside conversion failed" );
  2514. }
  2515. }
  2516. #endif
  2517. //maintain the cut history
  2518. destructors.DebugCutHistory.AddToTail( pHistoryPolyhedron );
  2519. destructors.DebugCutPlaneIndex.AddToTail( iCurrentPlane );
  2520. #endif
  2521. }
  2522. return ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, bUseTemporaryMemory, vShiftResultPositions );
  2523. }
  2524. #define STARTPOINTTOLINELINKS(iPointNum, lineindex1, iOtherPointIndex1, lineindex2, iOtherPointIndex2, lineindex3, iOtherPointIndex3 )\
  2525. StartingPointList[iPointNum].point.pConnectedLines = &StartingLineList[lineindex1].line.PointLineLinks[1 - iOtherPointIndex1];\
  2526. StartingPointList[iPointNum].point.pConnectedLines->pNext = &StartingLineList[lineindex2].line.PointLineLinks[1 - iOtherPointIndex2];\
  2527. StartingPointList[iPointNum].point.pConnectedLines->pPrev = &StartingLineList[lineindex3].line.PointLineLinks[1 - iOtherPointIndex3];\
  2528. StartingPointList[iPointNum].point.pConnectedLines->pNext->pNext = StartingPointList[iPointNum].point.pConnectedLines->pPrev;\
  2529. StartingPointList[iPointNum].point.pConnectedLines->pNext->pPrev = StartingPointList[iPointNum].point.pConnectedLines;\
  2530. StartingPointList[iPointNum].point.pConnectedLines->pPrev->pNext = StartingPointList[iPointNum].point.pConnectedLines;\
  2531. StartingPointList[iPointNum].point.pConnectedLines->pPrev->pPrev = StartingPointList[iPointNum].point.pConnectedLines->pNext;
  2532. #define STARTBOXCONNECTION( linenum, point1, point2, poly1, poly2 )\
  2533. StartingLineList[linenum].line.pPoints[0] = &StartingPointList[point1].point;\
  2534. StartingLineList[linenum].line.pPoints[1] = &StartingPointList[point2].point;\
  2535. StartingLineList[linenum].line.pPolygons[0] = &StartingPolygonList[poly1].polygon;\
  2536. StartingLineList[linenum].line.pPolygons[1] = &StartingPolygonList[poly2].polygon;
  2537. #define STARTPOLYGONTOLINELINKS( polynum, lineindex1, iThisPolyIndex1, lineindex2, iThisPolyIndex2, lineindex3, iThisPolyIndex3, lineindex4, iThisPolyIndex4 )\
  2538. StartingPolygonList[polynum].polygon.pLines = &StartingLineList[lineindex1].line.PolygonLineLinks[iThisPolyIndex1];\
  2539. StartingPolygonList[polynum].polygon.pLines->pNext = &StartingLineList[lineindex2].line.PolygonLineLinks[iThisPolyIndex2];\
  2540. StartingPolygonList[polynum].polygon.pLines->pPrev = &StartingLineList[lineindex4].line.PolygonLineLinks[iThisPolyIndex4];\
  2541. StartingPolygonList[polynum].polygon.pLines->pNext->pPrev = StartingPolygonList[polynum].polygon.pLines;\
  2542. StartingPolygonList[polynum].polygon.pLines->pPrev->pNext = StartingPolygonList[polynum].polygon.pLines;\
  2543. StartingPolygonList[polynum].polygon.pLines->pNext->pNext = &StartingLineList[lineindex3].line.PolygonLineLinks[iThisPolyIndex3];\
  2544. StartingPolygonList[polynum].polygon.pLines->pPrev->pPrev = StartingPolygonList[polynum].polygon.pLines->pNext->pNext;\
  2545. StartingPolygonList[polynum].polygon.pLines->pNext->pNext->pPrev = StartingPolygonList[polynum].polygon.pLines->pNext;\
  2546. StartingPolygonList[polynum].polygon.pLines->pPrev->pPrev->pNext = StartingPolygonList[polynum].polygon.pLines->pPrev;
  2547. CPolyhedron *GeneratePolyhedronFromPlanes( const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory )
  2548. {
  2549. //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
  2550. //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
  2551. //the polygon clipping functions we're going to use want inward facing planes
  2552. const size_t kFltX4Align = sizeof( fltx4 ) - 1;
  2553. uint8 *pAlignedAlloc = (uint8 *)stackalloc( (sizeof( fltx4 ) * iPlaneCount) + kFltX4Align );
  2554. pAlignedAlloc = (uint8 *)(((size_t)(pAlignedAlloc + kFltX4Align)) & ~kFltX4Align);
  2555. fltx4 *pAlteredPlanes = (fltx4 *)pAlignedAlloc;
  2556. for( int i = 0; i != iPlaneCount; ++i )
  2557. {
  2558. SubFloat( pAlteredPlanes[i], 0 ) = -pOutwardFacingPlanes[(i * 4) + 0];
  2559. SubFloat( pAlteredPlanes[i], 1 ) = -pOutwardFacingPlanes[(i * 4) + 1];
  2560. SubFloat( pAlteredPlanes[i], 2 ) = -pOutwardFacingPlanes[(i * 4) + 2];
  2561. SubFloat( pAlteredPlanes[i], 3 ) = -pOutwardFacingPlanes[(i * 4) + 3];
  2562. }
  2563. //our first goal is to find the size of a cube big enough to encapsulate all points that will be in the final polyhedron
  2564. Vector vAABBMinsVec, vAABBMaxsVec;
  2565. if( FindConvexShapeLooseAABB( pAlteredPlanes, iPlaneCount, &vAABBMinsVec, &vAABBMaxsVec ) == false )
  2566. return NULL; //no shape to work with apparently
  2567. fltx4 vAABBMins;
  2568. SubFloat( vAABBMins, 0 ) = vAABBMinsVec.x;
  2569. SubFloat( vAABBMins, 1 ) = vAABBMinsVec.y;
  2570. SubFloat( vAABBMins, 2 ) = vAABBMinsVec.z;
  2571. SubFloat( vAABBMins, 3 ) = 1.0f;
  2572. fltx4 vAABBMaxs;
  2573. SubFloat( vAABBMaxs, 0 ) = vAABBMaxsVec.x;
  2574. SubFloat( vAABBMaxs, 1 ) = vAABBMaxsVec.y;
  2575. SubFloat( vAABBMaxs, 2 ) = vAABBMaxsVec.z;
  2576. SubFloat( vAABBMaxs, 3 ) = 1.0f;
  2577. #if defined( USE_WORLD_CENTERED_POSITIONS )
  2578. fltx4 vPointOffset = MulSIMD( AddSIMD( vAABBMins, vAABBMaxs ), ReplicateX4( -0.5f ) );
  2579. vPointOffset = FloorSIMD( vPointOffset );
  2580. SubFloat( vPointOffset, 3 ) = -1.0f;
  2581. #endif
  2582. for( int i = 0; i != iPlaneCount; ++i )
  2583. {
  2584. pAlteredPlanes[i] = NegSIMD( pAlteredPlanes[i] );
  2585. }
  2586. #if defined( USE_WORLD_CENTERED_POSITIONS )
  2587. //shift all the planes toward origin
  2588. for( int i = 0; i != iPlaneCount; ++i )
  2589. {
  2590. fltx4 vMul = MulSIMD( pAlteredPlanes[i], vPointOffset );
  2591. SubFloat( pAlteredPlanes[i], 3 ) = SubFloat( vMul, 0 ) + SubFloat( vMul, 1 ) + SubFloat( vMul, 2 ) - SubFloat( vMul, 3 );
  2592. }
  2593. //shift the AABB (and all starting points) toward the origin
  2594. vAABBMins = AddSIMD( vAABBMins, vPointOffset );
  2595. vAABBMaxs = AddSIMD( vAABBMaxs, vPointOffset );
  2596. fltx4 vResultOffset = NegSIMD( vPointOffset );
  2597. SubFloat( vResultOffset, 3 ) = 0.0f;
  2598. #else
  2599. fltx4 vResultOffset = LoadZeroSIMD();
  2600. #endif
  2601. //grow the bounding box to a larger size since it's probably inaccurate a bit
  2602. {
  2603. fltx4 vGrow = MulSIMD( SubSIMD( vAABBMaxs, vAABBMins ), Four_PointFives );
  2604. vGrow = AddSIMD( vGrow, ReplicateX4( 10.0f ) );
  2605. SubFloat( vGrow, 3 ) = 0.0f;
  2606. vAABBMins = SubSIMD( vAABBMins, vGrow );
  2607. vAABBMaxs = AddSIMD( vAABBMaxs, vGrow );
  2608. }
  2609. vAABBMins = FloorSIMD( vAABBMins );
  2610. vAABBMaxs = FloorSIMD( vAABBMaxs );
  2611. vAABBMinsVec.x = SubFloat( vAABBMins, 0 );
  2612. vAABBMinsVec.y = SubFloat( vAABBMins, 1 );
  2613. vAABBMinsVec.z = SubFloat( vAABBMins, 2 );
  2614. vAABBMaxsVec.x = SubFloat( vAABBMaxs, 0 );
  2615. vAABBMaxsVec.y = SubFloat( vAABBMaxs, 1 );
  2616. vAABBMaxsVec.z = SubFloat( vAABBMaxs, 2 );
  2617. //generate our starting cube using the 2x AABB so we can start hacking away at it
  2618. //create our starting box on the stack
  2619. GeneratePolyhedronFromPlanes_UnorderedPolygonLL StartingPolygonList[6]; //6 polygons
  2620. GeneratePolyhedronFromPlanes_UnorderedLineLL StartingLineList[12]; //12 lines
  2621. GeneratePolyhedronFromPlanes_UnorderedPointLL StartingPointList[8]; //8 points
  2622. for( int i = 0; i != 12; ++i )
  2623. {
  2624. StartingLineList[i].line.InitLineLinks();
  2625. }
  2626. //I had to work all this out on a whiteboard if it seems completely unintuitive.
  2627. {
  2628. SubFloat( StartingPointList[0].point.ptPosition, 0 ) = vAABBMinsVec.x;
  2629. SubFloat( StartingPointList[0].point.ptPosition, 1 ) = vAABBMinsVec.y;
  2630. SubFloat( StartingPointList[0].point.ptPosition, 2 ) = vAABBMinsVec.z;
  2631. SubFloat( StartingPointList[0].point.ptPosition, 3 ) = -1.0f;
  2632. STARTPOINTTOLINELINKS( 0, 0, 1, 4, 1, 3, 0 );
  2633. SubFloat( StartingPointList[1].point.ptPosition, 0 ) = vAABBMinsVec.x;
  2634. SubFloat( StartingPointList[1].point.ptPosition, 1 ) = vAABBMaxsVec.y;
  2635. SubFloat( StartingPointList[1].point.ptPosition, 2 ) = vAABBMinsVec.z;
  2636. SubFloat( StartingPointList[1].point.ptPosition, 3 ) = -1.0f;
  2637. STARTPOINTTOLINELINKS( 1, 0, 0, 1, 1, 5, 1 );
  2638. SubFloat( StartingPointList[2].point.ptPosition, 0 ) = vAABBMinsVec.x;
  2639. SubFloat( StartingPointList[2].point.ptPosition, 1 ) = vAABBMinsVec.y;
  2640. SubFloat( StartingPointList[2].point.ptPosition, 2 ) = vAABBMaxsVec.z;
  2641. SubFloat( StartingPointList[2].point.ptPosition, 3 ) = -1.0f;
  2642. STARTPOINTTOLINELINKS( 2, 4, 0, 8, 1, 11, 0 );
  2643. SubFloat( StartingPointList[3].point.ptPosition, 0 ) = vAABBMinsVec.x;
  2644. SubFloat( StartingPointList[3].point.ptPosition, 1 ) = vAABBMaxsVec.y;
  2645. SubFloat( StartingPointList[3].point.ptPosition, 2 ) = vAABBMaxsVec.z;
  2646. SubFloat( StartingPointList[3].point.ptPosition, 3 ) = -1.0f;
  2647. STARTPOINTTOLINELINKS( 3, 5, 0, 9, 1, 8, 0 );
  2648. SubFloat( StartingPointList[4].point.ptPosition, 0 ) = vAABBMaxsVec.x;
  2649. SubFloat( StartingPointList[4].point.ptPosition, 1 ) = vAABBMinsVec.y;
  2650. SubFloat( StartingPointList[4].point.ptPosition, 2 ) = vAABBMinsVec.z;
  2651. SubFloat( StartingPointList[4].point.ptPosition, 3 ) = -1.0f;
  2652. STARTPOINTTOLINELINKS( 4, 2, 0, 3, 1, 7, 1 );
  2653. SubFloat( StartingPointList[5].point.ptPosition, 0 ) = vAABBMaxsVec.x;
  2654. SubFloat( StartingPointList[5].point.ptPosition, 1 ) = vAABBMaxsVec.y;
  2655. SubFloat( StartingPointList[5].point.ptPosition, 2 ) = vAABBMinsVec.z;
  2656. SubFloat( StartingPointList[5].point.ptPosition, 3 ) = -1.0f;
  2657. STARTPOINTTOLINELINKS( 5, 1, 0, 2, 1, 6, 1 );
  2658. SubFloat( StartingPointList[6].point.ptPosition, 0 ) = vAABBMaxsVec.x;
  2659. SubFloat( StartingPointList[6].point.ptPosition, 1 ) = vAABBMinsVec.y;
  2660. SubFloat( StartingPointList[6].point.ptPosition, 2 ) = vAABBMaxsVec.z;
  2661. SubFloat( StartingPointList[6].point.ptPosition, 3 ) = -1.0f;
  2662. STARTPOINTTOLINELINKS( 6, 7, 0, 11, 1, 10, 0 );
  2663. SubFloat( StartingPointList[7].point.ptPosition, 0 ) = vAABBMaxsVec.x;
  2664. SubFloat( StartingPointList[7].point.ptPosition, 1 ) = vAABBMaxsVec.y;
  2665. SubFloat( StartingPointList[7].point.ptPosition, 2 ) = vAABBMaxsVec.z;
  2666. SubFloat( StartingPointList[7].point.ptPosition, 3 ) = -1.0f;
  2667. STARTPOINTTOLINELINKS( 7, 6, 0, 10, 1, 9, 0 );
  2668. STARTBOXCONNECTION( 0, 0, 1, 0, 5 );
  2669. STARTBOXCONNECTION( 1, 1, 5, 1, 5 );
  2670. STARTBOXCONNECTION( 2, 5, 4, 2, 5 );
  2671. STARTBOXCONNECTION( 3, 4, 0, 3, 5 );
  2672. STARTBOXCONNECTION( 4, 0, 2, 3, 0 );
  2673. STARTBOXCONNECTION( 5, 1, 3, 0, 1 );
  2674. STARTBOXCONNECTION( 6, 5, 7, 1, 2 );
  2675. STARTBOXCONNECTION( 7, 4, 6, 2, 3 );
  2676. STARTBOXCONNECTION( 8, 2, 3, 4, 0 );
  2677. STARTBOXCONNECTION( 9, 3, 7, 4, 1 );
  2678. STARTBOXCONNECTION( 10, 7, 6, 4, 2 );
  2679. STARTBOXCONNECTION( 11, 6, 2, 4, 3 );
  2680. STARTBOXCONNECTION( 0, 0, 1, 5, 0 );
  2681. STARTBOXCONNECTION( 1, 1, 5, 5, 1 );
  2682. STARTBOXCONNECTION( 2, 5, 4, 5, 2 );
  2683. STARTBOXCONNECTION( 3, 4, 0, 5, 3 );
  2684. STARTBOXCONNECTION( 4, 0, 2, 0, 3 );
  2685. STARTBOXCONNECTION( 5, 1, 3, 1, 0 );
  2686. STARTBOXCONNECTION( 6, 5, 7, 2, 1 );
  2687. STARTBOXCONNECTION( 7, 4, 6, 3, 2 );
  2688. STARTBOXCONNECTION( 8, 2, 3, 0, 4 );
  2689. STARTBOXCONNECTION( 9, 3, 7, 1, 4 );
  2690. STARTBOXCONNECTION( 10, 7, 6, 2, 4 );
  2691. STARTBOXCONNECTION( 11, 6, 2, 3, 4 );
  2692. StartingPolygonList[0].polygon.vSurfaceNormal.Init( -1.0f, 0.0f, 0.0f );
  2693. //StartingPolygonList[0].polygon.fNormalDist = -vAABBMinsVec.x;
  2694. StartingPolygonList[1].polygon.vSurfaceNormal.Init( 0.0f, 1.0f, 0.0f );
  2695. //StartingPolygonList[1].polygon.fNormalDist = vAABBMaxsVec.y;
  2696. StartingPolygonList[2].polygon.vSurfaceNormal.Init( 1.0f, 0.0f, 0.0f );
  2697. //StartingPolygonList[2].polygon.fNormalDist = vAABBMaxsVec.x;
  2698. StartingPolygonList[3].polygon.vSurfaceNormal.Init( 0.0f, -1.0f, 0.0f );
  2699. //StartingPolygonList[3].polygon.fNormalDist = -vAABBMinsVec.y;
  2700. StartingPolygonList[4].polygon.vSurfaceNormal.Init( 0.0f, 0.0f, 1.0f );
  2701. //StartingPolygonList[4].polygon.fNormalDist = vAABBMaxsVec.z;
  2702. StartingPolygonList[5].polygon.vSurfaceNormal.Init( 0.0f, 0.0f, -1.0f );
  2703. //StartingPolygonList[5].polygon.fNormalDist = -vAABBMinsVec.z;
  2704. STARTPOLYGONTOLINELINKS( 0, 0, 1, 5, 1, 8, 0, 4, 0 );
  2705. STARTPOLYGONTOLINELINKS( 1, 1, 1, 6, 1, 9, 0, 5, 0 );
  2706. STARTPOLYGONTOLINELINKS( 2, 2, 1, 7, 1, 10, 0, 6, 0 );
  2707. STARTPOLYGONTOLINELINKS( 3, 3, 1, 4, 1, 11, 0, 7, 0 );
  2708. STARTPOLYGONTOLINELINKS( 4, 8, 1, 9, 1, 10, 1, 11, 1 );
  2709. STARTPOLYGONTOLINELINKS( 5, 0, 0, 3, 0, 2, 0, 1, 0 );
  2710. {
  2711. StartingPolygonList[0].pNext = &StartingPolygonList[1];
  2712. StartingPolygonList[0].pPrev = NULL;
  2713. StartingPolygonList[1].pNext = &StartingPolygonList[2];
  2714. StartingPolygonList[1].pPrev = &StartingPolygonList[0];
  2715. StartingPolygonList[2].pNext = &StartingPolygonList[3];
  2716. StartingPolygonList[2].pPrev = &StartingPolygonList[1];
  2717. StartingPolygonList[3].pNext = &StartingPolygonList[4];
  2718. StartingPolygonList[3].pPrev = &StartingPolygonList[2];
  2719. StartingPolygonList[4].pNext = &StartingPolygonList[5];
  2720. StartingPolygonList[4].pPrev = &StartingPolygonList[3];
  2721. StartingPolygonList[5].pNext = NULL;
  2722. StartingPolygonList[5].pPrev = &StartingPolygonList[4];
  2723. }
  2724. {
  2725. StartingLineList[0].pNext = &StartingLineList[1];
  2726. StartingLineList[0].pPrev = NULL;
  2727. StartingLineList[1].pNext = &StartingLineList[2];
  2728. StartingLineList[1].pPrev = &StartingLineList[0];
  2729. StartingLineList[2].pNext = &StartingLineList[3];
  2730. StartingLineList[2].pPrev = &StartingLineList[1];
  2731. StartingLineList[3].pNext = &StartingLineList[4];
  2732. StartingLineList[3].pPrev = &StartingLineList[2];
  2733. StartingLineList[4].pNext = &StartingLineList[5];
  2734. StartingLineList[4].pPrev = &StartingLineList[3];
  2735. StartingLineList[5].pNext = &StartingLineList[6];
  2736. StartingLineList[5].pPrev = &StartingLineList[4];
  2737. StartingLineList[6].pNext = &StartingLineList[7];
  2738. StartingLineList[6].pPrev = &StartingLineList[5];
  2739. StartingLineList[7].pNext = &StartingLineList[8];
  2740. StartingLineList[7].pPrev = &StartingLineList[6];
  2741. StartingLineList[8].pNext = &StartingLineList[9];
  2742. StartingLineList[8].pPrev = &StartingLineList[7];
  2743. StartingLineList[9].pNext = &StartingLineList[10];
  2744. StartingLineList[9].pPrev = &StartingLineList[8];
  2745. StartingLineList[10].pNext = &StartingLineList[11];
  2746. StartingLineList[10].pPrev = &StartingLineList[9];
  2747. StartingLineList[11].pNext = NULL;
  2748. StartingLineList[11].pPrev = &StartingLineList[10];
  2749. }
  2750. {
  2751. StartingPointList[0].pNext = &StartingPointList[1];
  2752. StartingPointList[0].pPrev = NULL;
  2753. StartingPointList[1].pNext = &StartingPointList[2];
  2754. StartingPointList[1].pPrev = &StartingPointList[0];
  2755. StartingPointList[2].pNext = &StartingPointList[3];
  2756. StartingPointList[2].pPrev = &StartingPointList[1];
  2757. StartingPointList[3].pNext = &StartingPointList[4];
  2758. StartingPointList[3].pPrev = &StartingPointList[2];
  2759. StartingPointList[4].pNext = &StartingPointList[5];
  2760. StartingPointList[4].pPrev = &StartingPointList[3];
  2761. StartingPointList[5].pNext = &StartingPointList[6];
  2762. StartingPointList[5].pPrev = &StartingPointList[4];
  2763. StartingPointList[6].pNext = &StartingPointList[7];
  2764. StartingPointList[6].pPrev = &StartingPointList[5];
  2765. StartingPointList[7].pNext = NULL;
  2766. StartingPointList[7].pPrev = &StartingPointList[6];
  2767. }
  2768. }
  2769. CPolyhedron *pRetVal = ClipLinkedGeometry( StartingPolygonList, StartingLineList, StartingPointList, 8, pAlteredPlanes, iPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory, vResultOffset );
  2770. #if defined( DEBUG_POLYHEDRON_CONVERSION )
  2771. //last bit of debugging from whatever outside source wants this stupid thing
  2772. if( (g_pPolyhedronCarvingDebugStepCallback != NULL) && (pRetVal != NULL) )
  2773. {
  2774. AssertMsg( g_pPolyhedronCarvingDebugStepCallback( pRetVal ), "Outside conversion failed" );
  2775. }
  2776. #endif
  2777. return pRetVal;
  2778. }
  2779. #ifdef DBGFLAG_ASSERT
  2780. void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile )
  2781. {
  2782. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  2783. Vector vMins = vCenter - vExtents;
  2784. Vector vMaxs = vCenter + vExtents;
  2785. //x min side
  2786. fprintf( pFile, "4\n" );
  2787. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2788. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2789. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2790. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2791. fprintf( pFile, "4\n" );
  2792. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2793. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2794. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2795. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2796. //x max side
  2797. fprintf( pFile, "4\n" );
  2798. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2799. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2800. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2801. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2802. fprintf( pFile, "4\n" );
  2803. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2804. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2805. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2806. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2807. //y min side
  2808. fprintf( pFile, "4\n" );
  2809. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2810. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2811. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2812. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2813. fprintf( pFile, "4\n" );
  2814. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2815. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2816. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2817. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2818. //y max side
  2819. fprintf( pFile, "4\n" );
  2820. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2821. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2822. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2823. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2824. fprintf( pFile, "4\n" );
  2825. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2826. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2827. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2828. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2829. //z min side
  2830. fprintf( pFile, "4\n" );
  2831. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2832. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2833. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2834. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2835. fprintf( pFile, "4\n" );
  2836. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2837. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2838. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2839. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z );
  2840. //z max side
  2841. fprintf( pFile, "4\n" );
  2842. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2843. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2844. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2845. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2846. fprintf( pFile, "4\n" );
  2847. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2848. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2849. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2850. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z );
  2851. #endif
  2852. }
  2853. void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile )
  2854. {
  2855. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  2856. Vector vDirection = vPoint2 - vPoint1;
  2857. vDirection.NormalizeInPlace();
  2858. Vector vPseudoPerpandicular = vec3_origin;
  2859. if( vDirection.x != 0.0f )
  2860. vPseudoPerpandicular.z = 1.0f;
  2861. else
  2862. vPseudoPerpandicular.x = 1.0f;
  2863. Vector vWidth = vDirection.Cross( vPseudoPerpandicular );
  2864. vWidth.NormalizeInPlace();
  2865. Vector vHeight = vDirection.Cross( vWidth );
  2866. vHeight.NormalizeInPlace();
  2867. fThickness *= 0.5f; //we use half thickness in both directions
  2868. vDirection *= fThickness;
  2869. vWidth *= fThickness;
  2870. vHeight *= fThickness;
  2871. Vector vLinePoints[8];
  2872. vLinePoints[0] = vPoint1 - vDirection - vWidth - vHeight;
  2873. vLinePoints[1] = vPoint1 - vDirection - vWidth + vHeight;
  2874. vLinePoints[2] = vPoint1 - vDirection + vWidth - vHeight;
  2875. vLinePoints[3] = vPoint1 - vDirection + vWidth + vHeight;
  2876. vLinePoints[4] = vPoint2 + vDirection - vWidth - vHeight;
  2877. vLinePoints[5] = vPoint2 + vDirection - vWidth + vHeight;
  2878. vLinePoints[6] = vPoint2 + vDirection + vWidth - vHeight;
  2879. vLinePoints[7] = vPoint2 + vDirection + vWidth + vHeight;
  2880. const Vector *pLineColors[8] = { &vColor1, &vColor1, &vColor1, &vColor1, &vColor2, &vColor2, &vColor2, &vColor2 };
  2881. #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 );
  2882. #define DPTGLV_LINE_DOUBLESIDEDQUAD(index1,index2,index3,index4)\
  2883. fprintf( pFile, "4\n" );\
  2884. DPTGLV_LINE_WRITEPOINT(index1);\
  2885. DPTGLV_LINE_WRITEPOINT(index2);\
  2886. DPTGLV_LINE_WRITEPOINT(index3);\
  2887. DPTGLV_LINE_WRITEPOINT(index4);\
  2888. fprintf( pFile, "4\n" );\
  2889. DPTGLV_LINE_WRITEPOINT(index4);\
  2890. DPTGLV_LINE_WRITEPOINT(index3);\
  2891. DPTGLV_LINE_WRITEPOINT(index2);\
  2892. DPTGLV_LINE_WRITEPOINT(index1);
  2893. DPTGLV_LINE_DOUBLESIDEDQUAD(0,4,6,2);
  2894. DPTGLV_LINE_DOUBLESIDEDQUAD(3,7,5,1);
  2895. DPTGLV_LINE_DOUBLESIDEDQUAD(1,5,4,0);
  2896. DPTGLV_LINE_DOUBLESIDEDQUAD(2,6,7,3);
  2897. DPTGLV_LINE_DOUBLESIDEDQUAD(0,2,3,1);
  2898. DPTGLV_LINE_DOUBLESIDEDQUAD(5,7,6,4);
  2899. #endif
  2900. }
  2901. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  2902. void DumpWorkingStatePolygons( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, bool bIsDeadList, const VMatrix *pTransform, FILE *pFile )
  2903. {
  2904. while( pPolygons )
  2905. {
  2906. GeneratePolyhedronFromPlanes_Polygon *pPoly = &pPolygons->polygon;
  2907. #ifdef DBGFLAG_ASSERT
  2908. if( pPoly->pLines == (void *)0xCCCCCCCC )
  2909. {
  2910. //this function gets called when something is already wrong. No need to crash instead of reporting something useful
  2911. pPolygons = pPolygons->pNext;
  2912. continue;
  2913. }
  2914. #endif
  2915. if( (pPoly->pLines == NULL) || (pPoly->pLines == pPoly->pLines->pNext) )
  2916. {
  2917. pPolygons = pPolygons->pNext;
  2918. continue; //less than 3 points in the polygon so far, undrawable
  2919. }
  2920. Vector vColor; //dead is dark grey, missing a side is red, complete is green, new is blue
  2921. if( pPoly->debugdata.vWorkingStateColorOverride != vec3_origin )
  2922. {
  2923. vColor = pPoly->debugdata.vWorkingStateColorOverride;
  2924. }
  2925. else
  2926. {
  2927. if( bIsDeadList )
  2928. {
  2929. vColor = Vector( 0.25f, 0.25f, 0.25f );
  2930. }
  2931. else
  2932. {
  2933. /*if(pPoly->bMissingASide)
  2934. {
  2935. vColor = Vector( 1.0f, 0.0f, 0.0f );
  2936. Vector vPatchLineColor( 1.0f, 0.0f, 1.0f );
  2937. fltx4 f4P1 = pPoly->pLines->pLine->pPoints[pPoly->pLines->iReferenceIndex]->ptPosition;
  2938. fltx4 f4P2 = pPoly->pLines->pNext->pLine->pPoints[1 - pPoly->pLines->pNext->iReferenceIndex]->ptPosition;
  2939. Vector vP1( SubFloat( f4P1, 0 ), SubFloat( f4P1, 1 ), SubFloat( f4P1, 2 ) );
  2940. Vector vP2( SubFloat( f4P2, 0 ), SubFloat( f4P2, 1 ), SubFloat( f4P2, 2 ) );
  2941. Vector vP1 = (*pTransform) * vP1;
  2942. Vector vP2 = (*pTransform) * vP2;
  2943. DumpLineToGLView( vP1, vPatchLineColor, vP2, vPatchLineColor, 0.1f, pFile );
  2944. }
  2945. else*/
  2946. {
  2947. if( pPoly->debugdata.bIsNew )
  2948. vColor = Vector( 0.0f, 0.0f, 1.0f );
  2949. else
  2950. vColor = Vector( 0.0f, 1.0f, 0.0f );
  2951. }
  2952. }
  2953. vColor *= 0.33f;
  2954. }
  2955. GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoly->pLines;
  2956. GeneratePolyhedronFromPlanes_LineLL *pLineWalkStart = pLineWalk;
  2957. int iVertexCount = 1;
  2958. do
  2959. {
  2960. ++iVertexCount;
  2961. pLineWalk = pLineWalk->pNext;
  2962. } while(pLineWalk != pLineWalkStart);
  2963. fprintf( pFile, "%i\n", iVertexCount );
  2964. fltx4 f4vertex = pLineWalk->pLine->pPoints[1 - pLineWalk->iReferenceIndex]->ptPosition;
  2965. Vector vertex( SubFloat( f4vertex, 0 ), SubFloat( f4vertex, 1 ), SubFloat( f4vertex, 2 ) );
  2966. vertex = (*pTransform) * vertex;
  2967. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vertex.x, vertex.y, vertex.z, vColor.x, vColor.y, vColor.z );
  2968. do
  2969. {
  2970. f4vertex = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->ptPosition;
  2971. vertex.Init( SubFloat( f4vertex, 0 ), SubFloat( f4vertex, 1 ), SubFloat( f4vertex, 2 ) );
  2972. vertex = (*pTransform) * vertex;
  2973. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vertex.x, vertex.y, vertex.z, vColor.x, vColor.y, vColor.z );
  2974. pLineWalk = pLineWalk->pNext;
  2975. } while(pLineWalk != pLineWalkStart);
  2976. pPolygons = pPolygons->pNext;
  2977. }
  2978. }
  2979. void DumpWorkingStateLines( GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, const VMatrix *pTransform, FILE *pFile )
  2980. {
  2981. while( pLines )
  2982. {
  2983. GeneratePolyhedronFromPlanes_Line *pLine = &pLines->line;
  2984. if( (pLine->pPoints[0] == NULL) || (pLine->pPoints[1] == NULL) )
  2985. {
  2986. pLines = pLines->pNext;
  2987. continue;
  2988. }
  2989. #ifdef DBGFLAG_ASSERT
  2990. if( (pLine->pPoints[0] == (void *)0xCCCCCCCC) || (pLine->pPoints[1] == (void *)0xCCCCCCCC) )
  2991. {
  2992. //this function gets called when something is already wrong. No need to crash instead of reporting something useful
  2993. pLines = pLines->pNext;
  2994. continue;
  2995. }
  2996. #endif
  2997. Vector vColor; //dead is dark grey, cut is red, complete is green, re-lengthened is green+blue, onplane is yellow, new is blue
  2998. if( pLine->debugdata.vWorkingStateColorOverride != vec3_origin )
  2999. {
  3000. vColor = pLine->debugdata.vWorkingStateColorOverride;
  3001. }
  3002. else
  3003. {
  3004. if( pLine->debugdata.bIsNew )
  3005. {
  3006. if( pLine->planarity == LINE_DEAD )
  3007. {
  3008. //created and then ditched
  3009. vColor = Vector( 0.5f, 0.5f, 1.0f );
  3010. }
  3011. else
  3012. {
  3013. vColor = Vector( 0.0f, 0.0f, 1.0f );
  3014. }
  3015. }
  3016. else
  3017. {
  3018. switch( pLine->planarity )
  3019. {
  3020. case LINE_ONPLANE:
  3021. vColor = Vector( 1.0f, 1.0f, 0.0f );
  3022. break;
  3023. case LINE_ALIVE:
  3024. /*if( pLine->debugdata.initialPlanarity & LINE_DEAD )
  3025. {
  3026. vColor = Vector( 0.0f, 1.0f, 1.0f ); //re-lengthened
  3027. }
  3028. else*/
  3029. {
  3030. vColor = Vector( 0.0f, 1.0f, 0.0f ); //always alive
  3031. }
  3032. break;
  3033. case LINE_DEAD:
  3034. vColor = Vector( 0.25f, 0.25f, 0.25f );
  3035. break;
  3036. case LINE_CUT:
  3037. vColor = Vector( 1.0f, 0.0f, 0.0f );
  3038. break;
  3039. };
  3040. }
  3041. }
  3042. fltx4 f4Pos0 = pLine->pPoints[0]->ptPosition;
  3043. Vector vPos0( SubFloat( f4Pos0, 0 ), SubFloat( f4Pos0, 1 ), SubFloat( f4Pos0, 2 ) );
  3044. fltx4 f4Pos1 = pLine->pPoints[1]->ptPosition;
  3045. Vector vPos1( SubFloat( f4Pos1, 0 ), SubFloat( f4Pos1, 1 ), SubFloat( f4Pos1, 2 ) );
  3046. DumpLineToGLView( (*pTransform) * vPos0, vColor, (*pTransform) * vPos1, vColor, 0.1f, pFile );
  3047. pLines = pLines->pNext;
  3048. }
  3049. }
  3050. void DumpWorkingStatePoints( GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, const VMatrix *pTransform, FILE *pFile )
  3051. {
  3052. while( pPoints )
  3053. {
  3054. GeneratePolyhedronFromPlanes_Point *pPoint = &pPoints->point;
  3055. Vector vColor; //dead is red, alive is green, onplane is red+green, new is blue
  3056. if( pPoint->debugdata.vWorkingStateColorOverride != vec3_origin )
  3057. {
  3058. vColor = pPoint->debugdata.vWorkingStateColorOverride;
  3059. }
  3060. else
  3061. {
  3062. if( pPoint->debugdata.bIsNew )
  3063. {
  3064. if( pPoint->planarity == POINT_DEAD )
  3065. {
  3066. //created and then merged away
  3067. vColor = Vector( 0.5f, 0.5f, 1.0f );
  3068. }
  3069. else
  3070. {
  3071. vColor = Vector( 0.0f, 0.0f, 1.0f );
  3072. }
  3073. }
  3074. else
  3075. {
  3076. switch( pPoint->planarity )
  3077. {
  3078. case POINT_ONPLANE:
  3079. vColor = Vector( 1.0f, 1.0f, 0.0f );
  3080. break;
  3081. case POINT_ALIVE:
  3082. vColor = Vector( 0.0f, 1.0f, 0.0f ); //always alive
  3083. break;
  3084. case POINT_DEAD:
  3085. vColor = Vector( 1.0f, 0.0f, 0.0f );
  3086. break;
  3087. };
  3088. }
  3089. }
  3090. fltx4 f4Pos = pPoint->ptPosition;
  3091. Vector vPos( SubFloat( f4Pos, 0 ), SubFloat( f4Pos, 1 ), SubFloat( f4Pos, 2 ) );
  3092. DumpAABBToGLView( (*pTransform) * vPos, Vector( 0.15f, 0.15f, 0.15f ), vColor, pFile );
  3093. pPoints = pPoints->pNext;
  3094. }
  3095. }
  3096. //dumps color coded information about a polyhedron that's in the middle of a cut (debugging only)
  3097. void DumpWorkingStatePolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDeadPolygons,
  3098. GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines, GeneratePolyhedronFromPlanes_UnorderedLineLL *pDeadLines,
  3099. GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPoints,
  3100. const char *pFilename, const VMatrix *pTransform )
  3101. {
  3102. if( pTransform == NULL )
  3103. pTransform = &s_matIdentity;
  3104. printf("Writing %s...\n", pFilename );
  3105. FILE *pFile = fopen( pFilename, "wb" );
  3106. if( pFile == NULL )
  3107. return;
  3108. DumpWorkingStatePolygons( pAllPolygons, false, pTransform, pFile );
  3109. //DumpWorkingStatePolygons( pDeadPolygons, true, pTransform, pFile ); //they're undrawable, they have less than 3 lines
  3110. DumpWorkingStateLines( pAllLines, pTransform, pFile );
  3111. DumpWorkingStateLines( pDeadLines, pTransform, pFile );
  3112. DumpWorkingStatePoints( pAllPoints, pTransform, pFile );
  3113. DumpWorkingStatePoints( pDeadPoints, pTransform, pFile );
  3114. fclose( pFile );
  3115. }
  3116. #endif
  3117. void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform, const char *szfileOpenOptions )
  3118. {
  3119. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  3120. Assert( pPolyhedron && (pPolyhedron->iVertexCount > 2) );
  3121. if( pTransform == NULL )
  3122. pTransform = &s_matIdentity;
  3123. printf("Writing %s...\n", pFilename );
  3124. FILE *pFile = fopen( pFilename, szfileOpenOptions );
  3125. const Vector vOne( 1.0f, 1.0f, 1.0f );
  3126. //randomizing an array of colors to help spot shared/unshared vertices
  3127. Vector *pColors = (Vector *)stackalloc( sizeof( Vector ) * pPolyhedron->iVertexCount );
  3128. int counter;
  3129. for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter )
  3130. {
  3131. pColors[counter].Init( rand()/32768.0f, rand()/32768.0f, rand()/32768.0f );
  3132. }
  3133. Vector *pTransformedPoints = (Vector *)stackalloc( pPolyhedron->iVertexCount * sizeof( Vector ) );
  3134. for ( counter = 0; counter != pPolyhedron->iVertexCount; ++counter )
  3135. {
  3136. pTransformedPoints[counter] = (*pTransform) * pPolyhedron->pVertices[counter];
  3137. }
  3138. for ( counter = 0; counter != pPolyhedron->iPolygonCount; ++counter )
  3139. {
  3140. fprintf( pFile, "%i\n", pPolyhedron->pPolygons[counter].iIndexCount );
  3141. int counter2;
  3142. for( counter2 = 0; counter2 != pPolyhedron->pPolygons[counter].iIndexCount; ++counter2 )
  3143. {
  3144. Polyhedron_IndexedLineReference_t *pLineReference = &pPolyhedron->pIndices[pPolyhedron->pPolygons[counter].iFirstIndex + counter2];
  3145. Vector *pVertex = &pTransformedPoints[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]];
  3146. Vector *pColor = &pColors[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]];
  3147. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n",pVertex->x, pVertex->y, pVertex->z, pColor->x, pColor->y, pColor->z );
  3148. }
  3149. }
  3150. for( counter = 0; counter != pPolyhedron->iLineCount; ++counter )
  3151. {
  3152. Vector vPoints[2] = { pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[0]], pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[1]] };
  3153. const float fShortenEnds = 0.0f;
  3154. if( fShortenEnds != 0.0f )
  3155. {
  3156. Vector vDiff = vPoints[0] - vPoints[1];
  3157. vDiff.NormalizeInPlace();
  3158. vPoints[0] -= vDiff * fShortenEnds;
  3159. vPoints[1] += vDiff * fShortenEnds;
  3160. }
  3161. DumpLineToGLView( vPoints[0], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[0]],
  3162. vPoints[1], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[1]],
  3163. 0.1f, pFile );
  3164. }
  3165. for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter )
  3166. {
  3167. const Vector vPointHalfSize(0.15f, 0.15f, 0.15f );
  3168. DumpAABBToGLView( pTransformedPoints[counter], vPointHalfSize, pColors[counter], pFile );
  3169. }
  3170. fclose( pFile );
  3171. #endif
  3172. }
  3173. void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform )
  3174. {
  3175. #ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS
  3176. if( pTransform == NULL )
  3177. pTransform = &s_matIdentity;
  3178. FILE *pFile = fopen( pszFileName, "ab" );
  3179. //transform the plane
  3180. Vector vNormal = pTransform->ApplyRotation( *(Vector *)pPlane );
  3181. float fDist = pPlane[3] * vNormal.NormalizeInPlace(); //possible scaling going on
  3182. fDist += vNormal.Dot( pTransform->GetTranslation() );
  3183. Vector vPlaneVerts[4];
  3184. PolyFromPlane( vPlaneVerts, vNormal, fDist, 100000.0f );
  3185. fprintf( pFile, "4\n" );
  3186. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[0].x, vPlaneVerts[0].y, vPlaneVerts[0].z, fGrayScale, fGrayScale, fGrayScale );
  3187. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[1].x, vPlaneVerts[1].y, vPlaneVerts[1].z, fGrayScale, fGrayScale, fGrayScale );
  3188. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[2].x, vPlaneVerts[2].y, vPlaneVerts[2].z, fGrayScale, fGrayScale, fGrayScale );
  3189. fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[3].x, vPlaneVerts[3].y, vPlaneVerts[3].z, fGrayScale, fGrayScale, fGrayScale );
  3190. fclose( pFile );
  3191. #endif
  3192. }
  3193. #endif