From 2e7fa2dfc8b1fe5a60ee71cb83fa084f4a8bd4e1 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Sun, 19 Jun 2022 15:07:41 +0300 Subject: [PATCH] aarch64: fix android build --- engine/host.cpp | 4 +- mathlib/sse.cpp | 12 +- public/XUnzip.cpp | 4 +- public/mathlib/mathlib.h | 4 +- public/mathlib/polyhedron.cpp | 2293 +++++++++++++++++++++++++++ public/mathlib/polyhedron.h | 6 +- public/mathlib/ssemath.h | 15 +- public/mathlib/vector4d.h | 2 +- public/saverestoretypes.h | 2 +- public/steam/steamtypes.h | 2 +- public/tier0/memvirt.h | 46 + public/tier0/platform.h | 14 +- public/tier0/threadtools.h | 16 +- public/tier0/threadtools.inl | 8 +- public/togles/linuxwin/dxabstract.h | 2 +- public/togles/linuxwin/glmgr.h | 4 +- tier0/cpu.cpp | 2 +- tier0/cpu_posix.cpp | 2 +- tier0/mem_impl_type.h | 6 + tier0/memdbg.cpp | 4 +- tier0/threadtools.cpp | 61 +- tier1/processor_detect_linux.cpp | 2 +- tier1/reliabletimer.cpp | 2 +- tier1/strtools.cpp | 8 +- tier1/wscript | 1 + togles/linuxwin/glmgr.cpp | 6 +- togles/linuxwin/glmgr_flush.inl | 2 +- vphysics/vphysics_saverestore.cpp | 2 +- 28 files changed, 2446 insertions(+), 86 deletions(-) create mode 100644 public/mathlib/polyhedron.cpp create mode 100644 public/tier0/memvirt.h create mode 100644 tier0/mem_impl_type.h diff --git a/engine/host.cpp b/engine/host.cpp index 57370866..1bc1693d 100644 --- a/engine/host.cpp +++ b/engine/host.cpp @@ -4850,7 +4850,9 @@ void Host_FreeToLowMark( bool server ) //----------------------------------------------------------------------------- void Host_Shutdown(void) { +#ifndef ANDROID extern void ShutdownMixerControls(); +#endif if ( host_checkheap ) { @@ -4962,7 +4964,7 @@ void Host_Shutdown(void) #ifndef SWDS TRACESHUTDOWN( Key_Shutdown() ); -#ifndef _X360 +#if !defined _X360 && !defined ANDROID TRACESHUTDOWN( ShutdownMixerControls() ); #endif #endif diff --git a/mathlib/sse.cpp b/mathlib/sse.cpp index 86377a6f..6122b664 100644 --- a/mathlib/sse.cpp +++ b/mathlib/sse.cpp @@ -11,7 +11,7 @@ #include "tier0/dbg.h" #include "mathlib/mathlib.h" #include "mathlib/vector.h" -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) #include "sse2neon.h" #endif @@ -180,7 +180,7 @@ float _SSE_RSqrtFast(float x) Assert( s_bMathlibInitialized ); float rroot; -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) rroot = _SSE_RSqrtAccurate(x); #elif _WIN32 _asm @@ -217,7 +217,7 @@ float FASTCALL _SSE_VectorNormalize (Vector& vec) // be much of a performance win, considering you will very likely miss 3 branch predicts in a row. if ( v[0] || v[1] || v[2] ) { -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) float rsqrt = _SSE_RSqrtAccurate( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); r[0] = v[0] * rsqrt; r[1] = v[1] * rsqrt; @@ -296,7 +296,7 @@ void FASTCALL _SSE_VectorNormalizeFast (Vector& vec) float _SSE_InvRSquared(const float* v) { float inv_r2 = 1.f; -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) return _SSE_RSqrtAccurate( FLT_EPSILON + v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); #elif _WIN32 _asm { // Intel SSE only routine @@ -391,7 +391,7 @@ typedef __m64 v2si; // vector of 2 int (mmx) void _SSE_SinCos(float x, float* s, float* c) { -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) #if defined( OSX ) __sincosf(x, s, c); #elif defined( POSIX ) @@ -607,7 +607,7 @@ void _SSE_SinCos(float x, float* s, float* c) float _SSE_cos( float x ) { -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) return cos(x); #elif _WIN32 float temp; diff --git a/public/XUnzip.cpp b/public/XUnzip.cpp index 9d7c4362..bf6310a7 100644 --- a/public/XUnzip.cpp +++ b/public/XUnzip.cpp @@ -4244,12 +4244,12 @@ ZRESULT TUnzip::Unzip(int index,void *dst,unsigned int len,DWORD flags) #ifdef _WIN32 SetFileTime(h,&ze.ctime,&ze.atime,&ze.mtime); #elif defined( ANDROID ) - struct timespec ts[2]; + struct timespec ts[2]; ts[0].tv_sec = ze.atime; ts[0].tv_nsec = 0; ts[1].tv_sec = ze.mtime; ts[1].tv_nsec = 0; - utimensat((int)h, NULL, ts, 0); + utimensat((intptr_t)h, NULL, ts, 0); #else struct timeval tv[2]; tv[0].tv_sec = ze.atime; diff --git a/public/mathlib/mathlib.h b/public/mathlib/mathlib.h index 4a765fcd..3afb27f2 100644 --- a/public/mathlib/mathlib.h +++ b/public/mathlib/mathlib.h @@ -1215,7 +1215,7 @@ FORCEINLINE int RoundFloatToInt(float f) }; flResult = __fctiw( f ); return pResult[1]; -#elif defined (__arm__) || defined (__arm64__) +#elif defined (__arm__) || defined (__aarch64__) return (int)(f + 0.5f); #else #error Unknown architecture @@ -1247,7 +1247,7 @@ FORCEINLINE unsigned long RoundFloatToUnsignedLong(float f) Assert( pIntResult[1] >= 0 ); return pResult[1]; #else // !X360 -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) return (unsigned long)(f + 0.5f); #elif defined( PLATFORM_WINDOWS_PC64 ) uint nRet = ( uint ) f; diff --git a/public/mathlib/polyhedron.cpp b/public/mathlib/polyhedron.cpp new file mode 100644 index 00000000..54e243ff --- /dev/null +++ b/public/mathlib/polyhedron.cpp @@ -0,0 +1,2293 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "mathlib/polyhedron.h" +#include "mathlib/vmatrix.h" +#include +#include +#include "tier1/utlvector.h" + + + +struct GeneratePolyhedronFromPlanes_Point; +struct GeneratePolyhedronFromPlanes_PointLL; +struct GeneratePolyhedronFromPlanes_Line; +struct GeneratePolyhedronFromPlanes_LineLL; +struct GeneratePolyhedronFromPlanes_Polygon; +struct GeneratePolyhedronFromPlanes_PolygonLL; + +struct GeneratePolyhedronFromPlanes_UnorderedPointLL; +struct GeneratePolyhedronFromPlanes_UnorderedLineLL; +struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL; + +Vector FindPointInPlanes( const float *pPlanes, int planeCount ); +bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ); +CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ); +CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory ); + +//#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 +//#define DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS //dumps successfully generated polyhedrons + +#ifdef _DEBUG +void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform ); +void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform ); +void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile ); +void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile ); + +#if defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( WIN32 ) +#include "winlite.h" +#endif + +static VMatrix s_matIdentity( 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f ); +#endif + +#if defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS ) +static int g_iPolyhedronDumpCounter = 0; +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) +void CreateDumpDirectory( const char *szDirectoryName ) +{ +#if defined( WIN32 ) + CreateDirectory( szDirectoryName, NULL ); +#else + Assert( false ); //TODO: create directories in linux +#endif +} +#endif + + + +void CPolyhedron_AllocByNew::Release( void ) +{ + delete this; +} + +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 +{ + void *pMemory = new unsigned char [ sizeof( CPolyhedron_AllocByNew ) + + (iVertices * sizeof(Vector)) + + (iLines * sizeof(Polyhedron_IndexedLine_t)) + + (iIndices * sizeof( Polyhedron_IndexedLineReference_t )) + + (iPolygons * sizeof( Polyhedron_IndexedPolygon_t ))]; + +#include "tier0/memdbgoff.h" //the following placement new doesn't compile with memory debugging + CPolyhedron_AllocByNew *pAllocated = new ( pMemory ) CPolyhedron_AllocByNew; +#include "tier0/memdbgon.h" + + pAllocated->iVertexCount = iVertices; + pAllocated->iLineCount = iLines; + pAllocated->iIndexCount = iIndices; + pAllocated->iPolygonCount = iPolygons; + pAllocated->pVertices = (Vector *)(pAllocated + 1); //start vertex memory at the end of the class + pAllocated->pLines = (Polyhedron_IndexedLine_t *)(pAllocated->pVertices + iVertices); + pAllocated->pIndices = (Polyhedron_IndexedLineReference_t *)(pAllocated->pLines + iLines); + pAllocated->pPolygons = (Polyhedron_IndexedPolygon_t *)(pAllocated->pIndices + iIndices); + + return pAllocated; +} + + +class CPolyhedron_TempMemory : public CPolyhedron +{ +public: +#ifdef DBGFLAG_ASSERT + int iReferenceCount; +#endif + + virtual void Release( void ) + { +#ifdef DBGFLAG_ASSERT + --iReferenceCount; +#endif + } + + CPolyhedron_TempMemory( void ) +#ifdef DBGFLAG_ASSERT + : iReferenceCount( 0 ) +#endif + { }; +}; + + +static CUtlVector s_TempMemoryPolyhedron_Buffer; +static CPolyhedron_TempMemory s_TempMemoryPolyhedron; + +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 +{ + AssertMsg( s_TempMemoryPolyhedron.iReferenceCount == 0, "Temporary polyhedron memory being rewritten before released" ); +#ifdef DBGFLAG_ASSERT + ++s_TempMemoryPolyhedron.iReferenceCount; +#endif + s_TempMemoryPolyhedron_Buffer.SetCount( (sizeof( Vector ) * iVertices) + + (sizeof( Polyhedron_IndexedLine_t ) * iLines) + + (sizeof( Polyhedron_IndexedLineReference_t ) * iIndices) + + (sizeof( Polyhedron_IndexedPolygon_t ) * iPolygons) ); + + s_TempMemoryPolyhedron.iVertexCount = iVertices; + s_TempMemoryPolyhedron.iLineCount = iLines; + s_TempMemoryPolyhedron.iIndexCount = iIndices; + s_TempMemoryPolyhedron.iPolygonCount = iPolygons; + + s_TempMemoryPolyhedron.pVertices = (Vector *)s_TempMemoryPolyhedron_Buffer.Base(); + s_TempMemoryPolyhedron.pLines = (Polyhedron_IndexedLine_t *)(&s_TempMemoryPolyhedron.pVertices[s_TempMemoryPolyhedron.iVertexCount]); + s_TempMemoryPolyhedron.pIndices = (Polyhedron_IndexedLineReference_t *)(&s_TempMemoryPolyhedron.pLines[s_TempMemoryPolyhedron.iLineCount]); + s_TempMemoryPolyhedron.pPolygons = (Polyhedron_IndexedPolygon_t *)(&s_TempMemoryPolyhedron.pIndices[s_TempMemoryPolyhedron.iIndexCount]); + + return &s_TempMemoryPolyhedron; +} + + +Vector CPolyhedron::Center( void ) +{ + if( iVertexCount == 0 ) + return vec3_origin; + + Vector vAABBMin, vAABBMax; + vAABBMin = vAABBMax = pVertices[0]; + for( int i = 1; i != iVertexCount; ++i ) + { + Vector &vPoint = pVertices[i]; + if( vPoint.x < vAABBMin.x ) + vAABBMin.x = vPoint.x; + if( vPoint.y < vAABBMin.y ) + vAABBMin.y = vPoint.y; + if( vPoint.z < vAABBMin.z ) + vAABBMin.z = vPoint.z; + + if( vPoint.x > vAABBMax.x ) + vAABBMax.x = vPoint.x; + if( vPoint.y > vAABBMax.y ) + vAABBMax.y = vPoint.y; + if( vPoint.z > vAABBMax.z ) + vAABBMax.z = vPoint.z; + } + return ((vAABBMin + vAABBMax) * 0.5f); +} + +enum PolyhedronPointPlanarity +{ + POINT_DEAD, + POINT_ONPLANE, + POINT_ALIVE +}; + +struct GeneratePolyhedronFromPlanes_Point +{ + Vector ptPosition; + GeneratePolyhedronFromPlanes_LineLL *pConnectedLines; //keep these in a clockwise order, circular linking + float fPlaneDist; //used in plane cutting + PolyhedronPointPlanarity planarity; + int iSaveIndices; +}; + +struct GeneratePolyhedronFromPlanes_Line +{ + GeneratePolyhedronFromPlanes_Point *pPoints[2]; //the 2 connecting points in no particular order + GeneratePolyhedronFromPlanes_Polygon *pPolygons[2]; //viewing from the outside with the point connections going up, 0 is the left polygon, 1 is the right + int iSaveIndices; + bool bAlive; //connected to at least one living point + bool bCut; //connected to at least one dead point + + GeneratePolyhedronFromPlanes_LineLL *pPointLineLinks[2]; //rather than going into a point and searching for its link to this line, lets just cache it to eliminate searching + GeneratePolyhedronFromPlanes_LineLL *pPolygonLineLinks[2]; //rather than going into a polygon and searching for its link to this line, lets just cache it to eliminate searching +#ifdef POLYHEDRON_EXTENSIVE_DEBUGGING + int iDebugFlags; +#endif +}; + +struct GeneratePolyhedronFromPlanes_LineLL +{ + GeneratePolyhedronFromPlanes_Line *pLine; + int iReferenceIndex; //whatever is referencing the line should know which side of the line it's on (points and polygons), for polygons, it's which point to follow to continue going clockwise, which makes polygon 0 the one on the left side of an upward facing line vector, for points, it's the OTHER point's index + GeneratePolyhedronFromPlanes_LineLL *pPrev; + GeneratePolyhedronFromPlanes_LineLL *pNext; +}; + +struct GeneratePolyhedronFromPlanes_Polygon +{ + Vector vSurfaceNormal; + GeneratePolyhedronFromPlanes_LineLL *pLines; //keep these in a clockwise order, circular linking + + bool bMissingASide; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedPolygonLL //an unordered collection of polygons +{ + GeneratePolyhedronFromPlanes_Polygon *pPolygon; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPrev; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedLineLL //an unordered collection of lines +{ + GeneratePolyhedronFromPlanes_Line *pLine; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pPrev; +}; + +struct GeneratePolyhedronFromPlanes_UnorderedPointLL //an unordered collection of points +{ + GeneratePolyhedronFromPlanes_Point *pPoint; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext; + GeneratePolyhedronFromPlanes_UnorderedPointLL *pPrev; +}; + + + + +CPolyhedron *ClipPolyhedron( const CPolyhedron *pExistingPolyhedron, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + if( pExistingPolyhedron == NULL ) + return NULL; + + AssertMsg( (pExistingPolyhedron->iVertexCount >= 3) && (pExistingPolyhedron->iPolygonCount >= 2), "Polyhedron doesn't meet absolute minimum spec" ); + + float *pUsefulPlanes = (float *)stackalloc( sizeof( float ) * 4 * iPlaneCount ); + int iUsefulPlaneCount = 0; + Vector *pExistingVertices = pExistingPolyhedron->pVertices; + + //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 + { + int iLiveCount = 0; + int iDeadCount = 0; + const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon; + + for( int i = 0; i != iPlaneCount; ++i ) + { + Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(i * 4) + 0]); + float fPlaneDist = pOutwardFacingPlanes[(i * 4) + 3]; + + for( int j = 0; j != pExistingPolyhedron->iVertexCount; ++j ) + { + float fPointDist = vNormal.Dot( pExistingVertices[j] ) - fPlaneDist; + + if( fPointDist <= fNegativeOnPlaneEpsilon ) + ++iLiveCount; + else if( fPointDist > fOnPlaneEpsilon ) + ++iDeadCount; + } + + if( iLiveCount == 0 ) + { + //all points are dead or on the plane, so the polyhedron is dead + return NULL; + } + + if( iDeadCount != 0 ) + { + //at least one point died, this plane yields useful results + pUsefulPlanes[(iUsefulPlaneCount * 4) + 0] = vNormal.x; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 1] = vNormal.y; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 2] = vNormal.z; + pUsefulPlanes[(iUsefulPlaneCount * 4) + 3] = fPlaneDist; + ++iUsefulPlaneCount; + } + } + } + + if( iUsefulPlaneCount == 0 ) + { + //testing shows that the polyhedron won't even be cut, clone the existing polyhedron and return that + + CPolyhedron *pReturn; + if( bUseTemporaryMemory ) + { + pReturn = GetTempPolyhedron( pExistingPolyhedron->iVertexCount, + pExistingPolyhedron->iLineCount, + pExistingPolyhedron->iIndexCount, + pExistingPolyhedron->iPolygonCount ); + } + else + { + pReturn = CPolyhedron_AllocByNew::Allocate( pExistingPolyhedron->iVertexCount, + pExistingPolyhedron->iLineCount, + pExistingPolyhedron->iIndexCount, + pExistingPolyhedron->iPolygonCount ); + } + + memcpy( pReturn->pVertices, pExistingPolyhedron->pVertices, sizeof( Vector ) * pReturn->iVertexCount ); + memcpy( pReturn->pLines, pExistingPolyhedron->pLines, sizeof( Polyhedron_IndexedLine_t ) * pReturn->iLineCount ); + memcpy( pReturn->pIndices, pExistingPolyhedron->pIndices, sizeof( Polyhedron_IndexedLineReference_t ) * pReturn->iIndexCount ); + memcpy( pReturn->pPolygons, pExistingPolyhedron->pPolygons, sizeof( Polyhedron_IndexedPolygon_t ) * pReturn->iPolygonCount ); + + return pReturn; + } + + + + //convert the polyhedron to linked geometry + GeneratePolyhedronFromPlanes_Point *pStartPoints = (GeneratePolyhedronFromPlanes_Point *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_Point ) ); + GeneratePolyhedronFromPlanes_Line *pStartLines = (GeneratePolyhedronFromPlanes_Line *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_Line ) ); + GeneratePolyhedronFromPlanes_Polygon *pStartPolygons = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_Polygon ) ); + + GeneratePolyhedronFromPlanes_LineLL *pStartLineLinks = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( pExistingPolyhedron->iLineCount * 4 * sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + int iCurrentLineLinkIndex = 0; + + //setup points + for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i ) + { + pStartPoints[i].ptPosition = pExistingPolyhedron->pVertices[i]; + pStartPoints[i].pConnectedLines = NULL; //we won't be circular linking until later + } + + //setup lines and interlink to points (line links are not yet circularly linked, and are unordered) + for( int i = 0; i != pExistingPolyhedron->iLineCount; ++i ) + { + for( int j = 0; j != 2; ++j ) + { + pStartLines[i].pPoints[j] = &pStartPoints[pExistingPolyhedron->pLines[i].iPointIndices[j]]; + + GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++]; + pStartLines[i].pPointLineLinks[j] = pLineLink; + pLineLink->pLine = &pStartLines[i]; + pLineLink->iReferenceIndex = 1 - j; + //pLineLink->pPrev = NULL; + pLineLink->pNext = pStartLines[i].pPoints[j]->pConnectedLines; + pStartLines[i].pPoints[j]->pConnectedLines = pLineLink; + } + } + + + + //setup polygons + for( int i = 0; i != pExistingPolyhedron->iPolygonCount; ++i ) + { + pStartPolygons[i].vSurfaceNormal = pExistingPolyhedron->pPolygons[i].polyNormal; + Polyhedron_IndexedLineReference_t *pOffsetPolyhedronLines = &pExistingPolyhedron->pIndices[pExistingPolyhedron->pPolygons[i].iFirstIndex]; + + + GeneratePolyhedronFromPlanes_LineLL *pFirstLink = &pStartLineLinks[iCurrentLineLinkIndex]; + pStartPolygons[i].pLines = pFirstLink; //technically going to link to itself on first pass, then get linked properly immediately afterward + for( int j = 0; j != pExistingPolyhedron->pPolygons[i].iIndexCount; ++j ) + { + GeneratePolyhedronFromPlanes_LineLL *pLineLink = &pStartLineLinks[iCurrentLineLinkIndex++]; + pLineLink->pLine = &pStartLines[pOffsetPolyhedronLines[j].iLineIndex]; + pLineLink->iReferenceIndex = pOffsetPolyhedronLines[j].iEndPointIndex; + + pLineLink->pLine->pPolygons[pLineLink->iReferenceIndex] = &pStartPolygons[i]; + pLineLink->pLine->pPolygonLineLinks[pLineLink->iReferenceIndex] = pLineLink; + + pLineLink->pPrev = pStartPolygons[i].pLines; + pStartPolygons[i].pLines->pNext = pLineLink; + pStartPolygons[i].pLines = pLineLink; + } + + pFirstLink->pPrev = pStartPolygons[i].pLines; + pStartPolygons[i].pLines->pNext = pFirstLink; + } + + Assert( iCurrentLineLinkIndex == (pExistingPolyhedron->iLineCount * 4) ); + + //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 + for( int i = 0; i != pExistingPolyhedron->iVertexCount; ++i ) + { + //interlink the points + { + GeneratePolyhedronFromPlanes_LineLL *pLastVisitedLink = pStartPoints[i].pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pCurrentLink = pLastVisitedLink; + + do + { + pCurrentLink->pPrev = pLastVisitedLink; + pLastVisitedLink = pCurrentLink; + pCurrentLink = pCurrentLink->pNext; + } while( pCurrentLink ); + + //circular link + pLastVisitedLink->pNext = pStartPoints[i].pConnectedLines; + pStartPoints[i].pConnectedLines->pPrev = pLastVisitedLink; + } + + + //fix ordering + GeneratePolyhedronFromPlanes_LineLL *pFirstLink = pStartPoints[i].pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pFirstLink; + GeneratePolyhedronFromPlanes_LineLL *pSearchLink; + GeneratePolyhedronFromPlanes_Polygon *pLookingForPolygon; + Assert( pFirstLink->pNext != pFirstLink ); + do + { + pLookingForPolygon = pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex]; //grab pointer to left polygon + pSearchLink = pWorkLink->pPrev; + + while( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] != pLookingForPolygon ) + pSearchLink = pSearchLink->pPrev; + + Assert( pSearchLink->pLine->pPolygons[pSearchLink->iReferenceIndex] == pWorkLink->pLine->pPolygons[1 - pWorkLink->iReferenceIndex] ); + + //pluck the search link from wherever it is + pSearchLink->pPrev->pNext = pSearchLink->pNext; + pSearchLink->pNext->pPrev = pSearchLink->pPrev; + + //insert the search link just before the work link + pSearchLink->pPrev = pWorkLink->pPrev; + pSearchLink->pNext = pWorkLink; + + pSearchLink->pPrev->pNext = pSearchLink; + pWorkLink->pPrev = pSearchLink; + + pWorkLink = pSearchLink; + } while( pWorkLink != pFirstLink ); + } + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( pExistingPolyhedron->iVertexCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) ); + GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( pExistingPolyhedron->iLineCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) ); + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( pExistingPolyhedron->iPolygonCount * sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) ); + + //setup point collection + { + pPoints[0].pPrev = NULL; + pPoints[0].pPoint = &pStartPoints[0]; + pPoints[0].pNext = &pPoints[1]; + int iLastPoint = pExistingPolyhedron->iVertexCount - 1; + for( int i = 1; i != iLastPoint; ++i ) + { + pPoints[i].pPrev = &pPoints[i - 1]; + pPoints[i].pPoint = &pStartPoints[i]; + pPoints[i].pNext = &pPoints[i + 1]; + } + pPoints[iLastPoint].pPrev = &pPoints[iLastPoint - 1]; + pPoints[iLastPoint].pPoint = &pStartPoints[iLastPoint]; + pPoints[iLastPoint].pNext = NULL; + } + + //setup line collection + { + pLines[0].pPrev = NULL; + pLines[0].pLine = &pStartLines[0]; + pLines[0].pNext = &pLines[1]; + int iLastLine = pExistingPolyhedron->iLineCount - 1; + for( int i = 1; i != iLastLine; ++i ) + { + pLines[i].pPrev = &pLines[i - 1]; + pLines[i].pLine = &pStartLines[i]; + pLines[i].pNext = &pLines[i + 1]; + } + pLines[iLastLine].pPrev = &pLines[iLastLine - 1]; + pLines[iLastLine].pLine = &pStartLines[iLastLine]; + pLines[iLastLine].pNext = NULL; + } + + //setup polygon collection + { + pPolygons[0].pPrev = NULL; + pPolygons[0].pPolygon = &pStartPolygons[0]; + pPolygons[0].pNext = &pPolygons[1]; + int iLastPolygon = pExistingPolyhedron->iPolygonCount - 1; + for( int i = 1; i != iLastPolygon; ++i ) + { + pPolygons[i].pPrev = &pPolygons[i - 1]; + pPolygons[i].pPolygon = &pStartPolygons[i]; + pPolygons[i].pNext = &pPolygons[i + 1]; + } + pPolygons[iLastPolygon].pPrev = &pPolygons[iLastPolygon - 1]; + pPolygons[iLastPolygon].pPolygon = &pStartPolygons[iLastPolygon]; + pPolygons[iLastPolygon].pNext = NULL; + } + + return ClipLinkedGeometry( pPolygons, pLines, pPoints, pUsefulPlanes, iUsefulPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory ); +} + + + +Vector FindPointInPlanes( const float *pPlanes, int planeCount ) +{ + Vector point = vec3_origin; + + for ( int i = 0; i < planeCount; i++ ) + { + float fD = DotProduct( *(Vector *)&pPlanes[i*4], point ) - pPlanes[i*4 + 3]; + if ( fD < 0 ) + { + point -= fD * (*(Vector *)&pPlanes[i*4]); + } + } + return point; +} + + + +bool FindConvexShapeLooseAABB( const float *pInwardFacingPlanes, int iPlaneCount, Vector *pAABBMins, Vector *pAABBMaxs ) //bounding box of the convex shape (subject to floating point error) +{ + //returns false if the AABB hasn't been set + if( pAABBMins == NULL && pAABBMaxs == NULL ) //no use in actually finding out what it is + return false; + + struct FindConvexShapeAABB_Polygon_t + { + float *verts; + int iVertCount; + }; + + float *pMovedPlanes = (float *)stackalloc( iPlaneCount * 4 * sizeof( float ) ); + //Vector vPointInPlanes = FindPointInPlanes( pInwardFacingPlanes, iPlaneCount ); + + for( int i = 0; i != iPlaneCount; ++i ) + { + pMovedPlanes[(i * 4) + 0] = pInwardFacingPlanes[(i * 4) + 0]; + pMovedPlanes[(i * 4) + 1] = pInwardFacingPlanes[(i * 4) + 1]; + pMovedPlanes[(i * 4) + 2] = pInwardFacingPlanes[(i * 4) + 2]; + pMovedPlanes[(i * 4) + 3] = pInwardFacingPlanes[(i * 4) + 3] - 100.0f; //move planes out a lot to kill some imprecision problems + } + + + + //vAABBMins = vAABBMaxs = FindPointInPlanes( pPlanes, iPlaneCount ); + float *vertsIn = NULL; //we'll be allocating a new buffer for this with each new polygon, and moving it off to the polygon array + 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 + float *vertsSwap; + + FindConvexShapeAABB_Polygon_t *pPolygons = (FindConvexShapeAABB_Polygon_t *)stackalloc( iPlaneCount * sizeof( FindConvexShapeAABB_Polygon_t ) ); + int iPolyCount = 0; + + for ( int i = 0; i < iPlaneCount; i++ ) + { + Vector *pPlaneNormal = (Vector *)&pInwardFacingPlanes[i*4]; + float fPlaneDist = pInwardFacingPlanes[(i*4) + 3]; + + if( vertsIn == NULL ) + vertsIn = (float *)stackalloc( (iPlaneCount + 4) * (sizeof( float ) * 3) ); + + // Build a big-ass poly in this plane + int vertCount = PolyFromPlane( (Vector *)vertsIn, *pPlaneNormal, fPlaneDist, 100000.0f ); + + //chop it by every other plane + for( int j = 0; j < iPlaneCount; j++ ) + { + // don't clip planes with themselves + if ( i == j ) + continue; + + // Chop the polygon against this plane + vertCount = ClipPolyToPlane( (Vector *)vertsIn, vertCount, (Vector *)vertsOut, *(Vector *)&pMovedPlanes[j*4], pMovedPlanes[(j*4) + 3], 0.0f ); + + //swap the input and output arrays + vertsSwap = vertsIn; vertsIn = vertsOut; vertsOut = vertsSwap; + + // Less than a poly left, something's wrong, don't bother with this polygon + if ( vertCount < 3 ) + break; + } + + if ( vertCount < 3 ) + continue; //not enough to work with + + pPolygons[iPolyCount].iVertCount = vertCount; + pPolygons[iPolyCount].verts = vertsIn; + vertsIn = NULL; + ++iPolyCount; + } + + if( iPolyCount == 0 ) + return false; + + //initialize the AABB to the first point available + Vector vAABBMins, vAABBMaxs; + vAABBMins = vAABBMaxs = ((Vector *)pPolygons[0].verts)[0]; + + if( pAABBMins && pAABBMaxs ) //they want the full box + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x < vAABBMins.x ) + vAABBMins.x = PolyVerts[j].x; + if( PolyVerts[j].y < vAABBMins.y ) + vAABBMins.y = PolyVerts[j].y; + if( PolyVerts[j].z < vAABBMins.z ) + vAABBMins.z = PolyVerts[j].z; + + if( PolyVerts[j].x > vAABBMaxs.x ) + vAABBMaxs.x = PolyVerts[j].x; + if( PolyVerts[j].y > vAABBMaxs.y ) + vAABBMaxs.y = PolyVerts[j].y; + if( PolyVerts[j].z > vAABBMaxs.z ) + vAABBMaxs.z = PolyVerts[j].z; + } + } + *pAABBMins = vAABBMins; + *pAABBMaxs = vAABBMaxs; + } + else if( pAABBMins ) //they only want the min + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x < vAABBMins.x ) + vAABBMins.x = PolyVerts[j].x; + if( PolyVerts[j].y < vAABBMins.y ) + vAABBMins.y = PolyVerts[j].y; + if( PolyVerts[j].z < vAABBMins.z ) + vAABBMins.z = PolyVerts[j].z; + } + } + *pAABBMins = vAABBMins; + } + else //they only want the max + { + for( int i = 0; i != iPolyCount; ++i ) + { + Vector *PolyVerts = (Vector *)pPolygons[i].verts; + for( int j = 0; j != pPolygons[i].iVertCount; ++j ) + { + if( PolyVerts[j].x > vAABBMaxs.x ) + vAABBMaxs.x = PolyVerts[j].x; + if( PolyVerts[j].y > vAABBMaxs.y ) + vAABBMaxs.y = PolyVerts[j].y; + if( PolyVerts[j].z > vAABBMaxs.z ) + vAABBMaxs.z = PolyVerts[j].z; + } + } + *pAABBMaxs = vAABBMaxs; + } + + return true; +} + + + + + + + +CPolyhedron *ConvertLinkedGeometryToPolyhedron( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pPoints, bool bUseTemporaryMemory ) +{ + Assert( (pPolygons != NULL) && (pLines != NULL) && (pPoints != NULL) ); + unsigned int iPolyCount = 0, iLineCount = 0, iPointCount = 0, iIndexCount = 0; + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pPolygons; + do + { + ++iPolyCount; + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + Assert( pLineWalk != NULL ); + + do + { + ++iIndexCount; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } while( pActivePolygonWalk ); + + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pLines; + do + { + ++iLineCount; + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pPoints; + do + { + ++iPointCount; + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + + CPolyhedron *pReturn; + if( bUseTemporaryMemory ) + { + pReturn = GetTempPolyhedron( iPointCount, iLineCount, iIndexCount, iPolyCount ); + } + else + { + pReturn = CPolyhedron_AllocByNew::Allocate( iPointCount, iLineCount, iIndexCount, iPolyCount ); + } + + Vector *pVertexArray = pReturn->pVertices; + Polyhedron_IndexedLine_t *pLineArray = pReturn->pLines; + Polyhedron_IndexedLineReference_t *pIndexArray = pReturn->pIndices; + Polyhedron_IndexedPolygon_t *pPolyArray = pReturn->pPolygons; + + //copy points + pActivePointWalk = pPoints; + for( unsigned int i = 0; i != iPointCount; ++i ) + { + pVertexArray[i] = pActivePointWalk->pPoint->ptPosition; + pActivePointWalk->pPoint->iSaveIndices = i; //storing array indices + pActivePointWalk = pActivePointWalk->pNext; + } + + //copy lines + pActiveLineWalk = pLines; + for( unsigned int i = 0; i != iLineCount; ++i ) + { + pLineArray[i].iPointIndices[0] = (unsigned short)pActiveLineWalk->pLine->pPoints[0]->iSaveIndices; + pLineArray[i].iPointIndices[1] = (unsigned short)pActiveLineWalk->pLine->pPoints[1]->iSaveIndices; + + pActiveLineWalk->pLine->iSaveIndices = i; //storing array indices + + pActiveLineWalk = pActiveLineWalk->pNext; + } + + //copy polygons and indices at the same time + pActivePolygonWalk = pPolygons; + iIndexCount = 0; + for( unsigned int i = 0; i != iPolyCount; ++i ) + { + pPolyArray[i].polyNormal = pActivePolygonWalk->pPolygon->vSurfaceNormal; + pPolyArray[i].iFirstIndex = iIndexCount; + + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pActivePolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + //pIndexArray[iIndexCount] = pLineWalk->pLine->pPoints[pLineWalk->iReferenceIndex]->iWorkData; //startpoint of each line, iWorkData is the index of the vertex + pIndexArray[iIndexCount].iLineIndex = pLineWalk->pLine->iSaveIndices; + pIndexArray[iIndexCount].iEndPointIndex = pLineWalk->iReferenceIndex; + + ++iIndexCount; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + pPolyArray[i].iIndexCount = iIndexCount - pPolyArray[i].iFirstIndex; + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + +#if defined( _DEBUG ) && defined( ENABLE_DEBUG_POLYHEDRON_DUMPS ) && defined( DEBUG_DUMP_POLYHEDRONS_TO_NUMBERED_GLVIEWS ) + char szCollisionFile[128]; + CreateDumpDirectory( "PolyhedronDumps" ); + Q_snprintf( szCollisionFile, 128, "PolyhedronDumps/NewStyle_PolyhedronDump%i.txt", g_iPolyhedronDumpCounter ); + ++g_iPolyhedronDumpCounter; + + remove( szCollisionFile ); + DumpPolyhedronToGLView( pReturn, szCollisionFile, &s_matIdentity ); + DumpPolyhedronToGLView( pReturn, "PolyhedronDumps/NewStyle_PolyhedronDump_All-Appended.txt", &s_matIdentity ); +#endif + + return pReturn; +} + + + +#ifdef _DEBUG + +void DumpPointListToGLView( GeneratePolyhedronFromPlanes_UnorderedPointLL *pHead, PolyhedronPointPlanarity planarity, const Vector &vColor, const char *szDumpFile, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + FILE *pFile = fopen( szDumpFile, "ab" ); + + while( pHead ) + { + if( pHead->pPoint->planarity == planarity ) + { + const Vector vPointExtents( 0.5f, 0.5f, 0.01f ); + DumpAABBToGLView( (*pTransform) * pHead->pPoint->ptPosition, vPointExtents, vColor, pFile ); + } + pHead = pHead->pNext; + } + + fclose( pFile ); +#endif +} + +const char * DumpPolyhedronCutHistory( const CUtlVector &DumpedHistory, const CUtlVector &CutHistory, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + static char szDumpFile[100] = "FailedPolyhedronCut_Error.txt"; //most recent filename returned for further dumping + + for( int i = 0; i != DumpedHistory.Count(); ++i ) + { + if( DumpedHistory[i] != NULL ) + { + Q_snprintf( szDumpFile, 100, "FailedPolyhedronCut_%d.txt", i ); + DumpPolyhedronToGLView( DumpedHistory[i], szDumpFile, pTransform ); + DumpPlaneToGlView( CutHistory[i], 1.0f, szDumpFile, pTransform ); + } + } + + return szDumpFile; +#else + return NULL; +#endif +} + +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS +#define AssertMsg_DumpPolyhedron(condition, message)\ + if( (condition) == false )\ + {\ + VMatrix matTransform;\ + matTransform.Identity();\ + matTransform[0][0] = matTransform[1][1] = matTransform[2][2] = 25.0f;\ + matTransform.SetTranslation( -DebugCutHistory.Tail()->Center() * 25.0f );\ + const char *szLastDumpFile = DumpPolyhedronCutHistory( DebugCutHistory, PlaneCutHistory, &matTransform );\ + DumpPointListToGLView( pAllPoints, POINT_ALIVE, Vector( 0.9f, 0.9f, 0.9f ), szLastDumpFile, &matTransform );\ + DumpPointListToGLView( pAllPoints, POINT_ONPLANE, Vector( 0.5f, 0.5f, 0.5f ), szLastDumpFile, &matTransform );\ + DumpPointListToGLView( pDeadPointCollection, POINT_DEAD, Vector( 0.1f, 0.1f, 0.1f ), szLastDumpFile, &matTransform );\ + if( pStartPoint )\ + {\ + FILE *pFileDumpRepairProgress = fopen( szLastDumpFile, "ab" );\ + DumpAABBToGLView( matTransform * pStartPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 0.0f, 1.0f, 0.0f ), pFileDumpRepairProgress );\ + DumpAABBToGLView( matTransform * pWorkPoint->ptPosition, Vector( 2.0f, 0.05f, 0.05f ), Vector( 1.0f, 0.0f, 0.0f ), pFileDumpRepairProgress );\ + fclose( pFileDumpRepairProgress );\ + }\ + AssertMsg( condition, message );\ + } +#else +#define AssertMsg_DumpPolyhedron(condition, message) AssertMsg( condition, message ) +#endif +#define Assert_DumpPolyhedron(condition) AssertMsg_DumpPolyhedron( condition, #condition ) + +#else + +#define AssertMsg_DumpPolyhedron(condition, message) NULL; +#define Assert_DumpPolyhedron(condition) NULL; + +#endif + +CPolyhedron *ClipLinkedGeometry( GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pAllPolygons, GeneratePolyhedronFromPlanes_UnorderedLineLL *pAllLines, GeneratePolyhedronFromPlanes_UnorderedPointLL *pAllPoints, const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + const float fNegativeOnPlaneEpsilon = -fOnPlaneEpsilon; + +#ifdef _DEBUG + CUtlVector DebugCutHistory; + CUtlVector PlaneCutHistory; + GeneratePolyhedronFromPlanes_Point *pStartPoint = NULL; + GeneratePolyhedronFromPlanes_Point *pWorkPoint = NULL; + + static int iPolyhedronClipCount = 0; + ++iPolyhedronClipCount; + + DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) ); +#endif + + //clear out polygon work variables + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + do + { + pActivePolygonWalk->pPolygon->bMissingASide = false; + pActivePolygonWalk = pActivePolygonWalk->pNext; + } while( pActivePolygonWalk ); + } + + + //Collections of dead pointers for reallocation, shouldn't be touched until the current loop iteration is done. + GeneratePolyhedronFromPlanes_UnorderedPointLL *pDeadPointCollection = NULL; + GeneratePolyhedronFromPlanes_UnorderedLineLL *pDeadLineCollection = NULL; + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDeadPolygonCollection = NULL; + GeneratePolyhedronFromPlanes_LineLL *pDeadLineLinkCollection = NULL; + + + for( int iCurrentPlane = 0; iCurrentPlane != iPlaneCount; ++iCurrentPlane ) + { + //clear out line work variables + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + pActiveLineWalk->pLine->bAlive = false; + pActiveLineWalk->pLine->bCut = false; + + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + } + + //TODO: Move these pointers into a reallocation pool + pDeadPointCollection = NULL; + pDeadLineCollection = NULL; + pDeadLineLinkCollection = NULL; + pDeadPolygonCollection = NULL; + + Vector vNormal = *((Vector *)&pOutwardFacingPlanes[(iCurrentPlane * 4) + 0]); + /*double vNormalAsDouble[3]; + vNormalAsDouble[0] = vNormal.x; + vNormalAsDouble[1] = vNormal.y; + vNormalAsDouble[2] = vNormal.z;*/ + float fPlaneDist = pOutwardFacingPlanes[(iCurrentPlane * 4) + 3]; + + //=================================================================================================== + // Step 1: Categorize each point as being either cut, split, or alive + //=================================================================================================== + { + bool bAllPointsDead = true; + bool bAllPointsAlive = true; + + //find point distances from the plane + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + GeneratePolyhedronFromPlanes_Point *pPoint = pActivePointWalk->pPoint; + float fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; + if( fPointDist > fOnPlaneEpsilon ) + { + pPoint->planarity = POINT_DEAD; //point is dead, bang bang + + //mark connected lines as cut + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + pLineWalk->pLine->bCut = true; + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + + bAllPointsAlive = false; + } + else if( fPointDist <= fNegativeOnPlaneEpsilon ) + { + pPoint->planarity = POINT_ALIVE; //point is in behind plane, not voted off the island....yet + bAllPointsDead = false; + + //mark connected lines as alive + GeneratePolyhedronFromPlanes_LineLL *pLineWalk = pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstLine = pLineWalk; + do + { + pLineWalk->pLine->bAlive = true; //mark the line as alive + pLineWalk = pLineWalk->pNext; + } while( pLineWalk != pFirstLine ); + } + else + { + pPoint->planarity = POINT_ONPLANE; //point is on the plane, he's everyone's buddy + + //Project on-plane points leaning towards death closer to the plane. This battles floating point precision decay. + // Consider the case of a large on-plane epsilon leaving protrusions over time + /*if( fPointDist < 0.0f ) + { + double distAsDouble = fPointDist; + double vPositionAsDouble[3]; + vPositionAsDouble[0] = pPoint->ptPosition.x; + vPositionAsDouble[1] = pPoint->ptPosition.y; + vPositionAsDouble[2] = pPoint->ptPosition.z; + + pPoint->ptPosition.x = vPositionAsDouble[0] - (distAsDouble * vNormalAsDouble[0]); + pPoint->ptPosition.y = vPositionAsDouble[1] - (distAsDouble * vNormalAsDouble[1]); + pPoint->ptPosition.z = vPositionAsDouble[2] - (distAsDouble * vNormalAsDouble[2]); + +#if ( 0 && defined( _DEBUG ) ) + float fDebugDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows + AssertMsg( fabs( fDebugDist ) < fabs(fPointDist), "Projected point is further from plane than unprojected." ); +#endif + fPointDist = vNormal.Dot( pPoint->ptPosition ) - fPlaneDist; //recompute dist (not guaranteed to be 0.0 like we want) + }*/ + } + + pPoint->fPlaneDist = fPointDist; + + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + + if( bAllPointsDead ) //all the points either died or are on the plane, no polyhedron left at all + { +#ifdef _DEBUG + for( int i = DebugCutHistory.Count(); --i >= 0; ) + { + if( DebugCutHistory[i] ) + DebugCutHistory[i]->Release(); + } + DebugCutHistory.RemoveAll(); +#endif + + return NULL; + } + + if( bAllPointsAlive ) + continue; //no cuts made + + + //Scan for onplane points connected to only other onplane/dead points, these points get downgraded to dead status. + { + pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint->planarity == POINT_ONPLANE ) + { + GeneratePolyhedronFromPlanes_LineLL *pOnPlaneLineWalk = pActivePointWalk->pPoint->pConnectedLines; + GeneratePolyhedronFromPlanes_LineLL *pStartLineWalk = pOnPlaneLineWalk; + bool bDead = true; //assume it's dead and disprove + do + { + if ( pOnPlaneLineWalk->pLine->bAlive ) + { + bDead = false; + } + else if ( pOnPlaneLineWalk->pLine->bCut ) + { + //connected to a dead point. + if( pOnPlaneLineWalk->pNext->pLine->bCut || pOnPlaneLineWalk->pPrev->pLine->bCut ) + { + //This on-plane point is surrounded by dead points on one polygon of the polyhedron. + // We have to downgrade this point to dead to avoid situations where float imprecision + // turns the polyhedron into a *slightly* concave shape. Concave shapes might break this algorithm, even falsely concave shapes. + bDead = true; + break; + } + } + + pOnPlaneLineWalk = pOnPlaneLineWalk->pNext; + } while( pOnPlaneLineWalk != pStartLineWalk ); + + if( bDead ) + { + pActivePointWalk->pPoint->planarity = POINT_DEAD; + + pOnPlaneLineWalk = pStartLineWalk; + + //mark connected lines as cut + do + { + pOnPlaneLineWalk->pLine->bCut = true; + pOnPlaneLineWalk = pOnPlaneLineWalk->pNext; + } while( pOnPlaneLineWalk != pStartLineWalk ); + } + } + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + } +#ifdef _DEBUG + PlaneCutHistory.AddToTail( &pOutwardFacingPlanes[iCurrentPlane * 4] ); +#endif + } + + + + +#ifdef _DEBUG + //Run around the edges of all the polygons and ensure they don't have more than one point of lowered "alive" status (alive > onplane > dead) surrounded by higher status + // It indicates a concave shape. It's impossible to have it occur in theoretical space. But floating point numbers introduce error. + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons; + do + { + int iSurroundedCount = 0; + GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pDebugPolygonWalk->pPolygon->pLines; + GeneratePolyhedronFromPlanes_LineLL *pFirstDebugLine = pDebugLineWalk; + + do + { + PolyhedronPointPlanarity currentPlanarity = pDebugLineWalk->pLine->pPoints[pDebugLineWalk->iReferenceIndex]->planarity; + + GeneratePolyhedronFromPlanes_LineLL *pNext = pDebugLineWalk->pNext; + PolyhedronPointPlanarity nextPlanarity = pNext->pLine->pPoints[pNext->iReferenceIndex]->planarity; + + if( currentPlanarity < nextPlanarity ) + { + GeneratePolyhedronFromPlanes_LineLL *pPrev = pDebugLineWalk->pPrev; + PolyhedronPointPlanarity prevPlanarity = pPrev->pLine->pPoints[pPrev->iReferenceIndex]->planarity; + + if( currentPlanarity < prevPlanarity ) + { + ++iSurroundedCount; + } + } + + pDebugLineWalk = pDebugLineWalk->pNext; + } while( pDebugLineWalk != pFirstDebugLine ); + + AssertMsg_DumpPolyhedron( iSurroundedCount <= 1, "Concave polygon, cutting process might break. Consider adjusting the on-plane epsilon to better compensate for floating point precision." ); + pDebugPolygonWalk = pDebugPolygonWalk->pNext; + } while( pDebugPolygonWalk ); + } +#endif + + //=================================================================================================== + // Step 2: Remove dead lines. A dead line is one with a dead point that isn't connected to a living point + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + GeneratePolyhedronFromPlanes_Line *pLine = pActiveLineWalk->pLine; + if( (pLine->bAlive == false) && (pLine->bCut == true) ) //not connected to a live point, but connected to a dead one. Dead line + { + //remove line from connected polygons + for( int i = 0; i != 2; ++i ) + { + GeneratePolyhedronFromPlanes_Polygon *pPolygon = pLine->pPolygons[i]; + GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPolygonLineLinks[i]; + + pPolygon->bMissingASide = true; + + if( pLineLink->pNext == pLineLink ) + { + //this was the last line of the polygon, it's dead + pPolygon->pLines = NULL; + } + else + { + //link around this line + pPolygon->pLines = pLineLink->pPrev; //Always have the polygon's head line be just before the gap in the polygon + pLineLink->pNext->pPrev = pLineLink->pPrev; + pLineLink->pPrev->pNext = pLineLink->pNext; + } + + //move the line link to the dead list + pLineLink->pNext = pDeadLineLinkCollection; + pDeadLineLinkCollection = pLineLink; + } + + //remove the line from connected points + for( int i = 0; i != 2; ++i ) + { + GeneratePolyhedronFromPlanes_Point *pPoint = pLine->pPoints[i]; + GeneratePolyhedronFromPlanes_LineLL *pLineLink = pLine->pPointLineLinks[i]; + + if( pLineLink->pNext == pLineLink ) + { + //this is the last line + pPoint->pConnectedLines = NULL; + Assert( pPoint->planarity != POINT_ALIVE ); + pPoint->planarity = POINT_DEAD; //in case it was merely POINT_ONPLANE before + } + else + { + //link around this line + pPoint->pConnectedLines = pLineLink->pNext; //in case pLineLink was the head line + pLineLink->pNext->pPrev = pLineLink->pPrev; + pLineLink->pPrev->pNext = pLineLink->pNext; + } + + //move the line link to the dead list + pLineLink->pNext = pDeadLineLinkCollection; + pDeadLineLinkCollection = pLineLink; + } + + //move the line to the dead list + { + //link past this node + if( pActiveLineWalk->pPrev ) + pActiveLineWalk->pPrev->pNext = pActiveLineWalk->pNext; + else + pAllLines = pActiveLineWalk->pNext; + + if( pActiveLineWalk->pNext ) + pActiveLineWalk->pNext->pPrev = pActiveLineWalk->pPrev; + + GeneratePolyhedronFromPlanes_UnorderedLineLL *pNextLineWalk = pActiveLineWalk->pNext; + + //add to the dead list + pActiveLineWalk->pNext = pDeadLineCollection; + pDeadLineCollection = pActiveLineWalk; + + //next + pActiveLineWalk = pNextLineWalk; + } + } + else + { + pActiveLineWalk = pActiveLineWalk->pNext; + } + } while( pActiveLineWalk ); + } + + + //=================================================================================================== + // Step 3: Remove dead polygons. A dead polygon has less than 2 lines. + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + do + { + GeneratePolyhedronFromPlanes_Polygon *pPolygon = pActivePolygonWalk->pPolygon; + GeneratePolyhedronFromPlanes_LineLL *pHeadLine = pPolygon->pLines; + + bool bDead = (pHeadLine == NULL) || (pHeadLine->pNext == pHeadLine); + if( !bDead ) + { + //there's a rare case where a polygon can be almost entirely coplanar with the cut, it comes purely out of the land of imprecision + bDead = true; //assume it's dead, and disprove + + GeneratePolyhedronFromPlanes_LineLL *pTestLineWalk = pHeadLine; + do + { + if( pTestLineWalk->pLine->bAlive ) + { + bDead = false; + break; + } + + pTestLineWalk = pTestLineWalk->pNext; + } while( pTestLineWalk != pHeadLine ); + } + + if( bDead ) + { + //dead polygon, move it to the dead list + + //link around this node + if( pActivePolygonWalk->pPrev ) + pActivePolygonWalk->pPrev->pNext = pActivePolygonWalk->pNext; + else + pAllPolygons = pAllPolygons->pNext; //pActivePolygonWalk was the head node + + if( pActivePolygonWalk->pNext ) + pActivePolygonWalk->pNext->pPrev = pActivePolygonWalk->pPrev; + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pNextPolygonWalk = pActivePolygonWalk->pNext; + + //add to the dead list + pActivePolygonWalk->pNext = pDeadPolygonCollection; + pDeadPolygonCollection = pActivePolygonWalk; + + //next + pActivePolygonWalk = pNextPolygonWalk; + } + else + { + AssertMsg_DumpPolyhedron( (pActivePolygonWalk->pPolygon->pLines != NULL) && + (pActivePolygonWalk->pPolygon->pLines != pActivePolygonWalk->pPolygon->pLines->pNext), "Living polygon with less than 2 lines" ); + + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + } while( pActivePolygonWalk ); + } + + //=================================================================================================== + // Step 4: Remove dead points. + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint->planarity == POINT_DEAD ) + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pNext = pActivePointWalk->pNext; + + if( pActivePointWalk->pPrev ) + pActivePointWalk->pPrev->pNext = pActivePointWalk->pNext; + else + pAllPoints = pAllPoints->pNext; + + if( pActivePointWalk->pNext ) + pActivePointWalk->pNext->pPrev = pActivePointWalk->pPrev; + + pActivePointWalk->pNext = pDeadPointCollection; + pDeadPointCollection = pActivePointWalk; + + pActivePointWalk = pNext; + } + else + { + pActivePointWalk = pActivePointWalk->pNext; + } + } while( pActivePointWalk ); + } + + + //=================================================================================================== + // Step 5: Handle cut lines + //=================================================================================================== + { + GeneratePolyhedronFromPlanes_UnorderedLineLL *pActiveLineWalk = pAllLines; + do + { + GeneratePolyhedronFromPlanes_Line *pWorkLine = pActiveLineWalk->pLine; + Assert_DumpPolyhedron( (pWorkLine->bAlive == true) || (pWorkLine->bCut == false) ); //all dead lines should have already been removed + + if( pWorkLine->bCut ) + { + GeneratePolyhedronFromPlanes_Point **pLinePoints = pWorkLine->pPoints; + + Assert_DumpPolyhedron( (pLinePoints[0]->planarity == POINT_DEAD) || (pLinePoints[1]->planarity == POINT_DEAD) ); //one of the two has to be a dead point + + int iDeadIndex = (pLinePoints[0]->planarity == POINT_DEAD)?(0):(1); + int iLivingIndex = 1 - iDeadIndex; + GeneratePolyhedronFromPlanes_Point *pDeadPoint = pLinePoints[iDeadIndex]; + GeneratePolyhedronFromPlanes_Point *pLivingPoint = pLinePoints[iLivingIndex]; + + Assert_DumpPolyhedron( pLivingPoint->planarity == POINT_ALIVE ); //if this point were on-plane or dead, the line should be dead + + //We'll be de-linking from the old point and generating a new one. We do this so other lines can still access the dead point's untouched data. + + //Generate a new point + GeneratePolyhedronFromPlanes_Point *pNewPoint = (GeneratePolyhedronFromPlanes_Point *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Point ) ); + { + //add this point to the active list + pAllPoints->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPointLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPointLL ) ); + pAllPoints->pPrev->pNext = pAllPoints; + pAllPoints = pAllPoints->pPrev; + pAllPoints->pPrev = NULL; + pAllPoints->pPoint = pNewPoint; + + + float fInvTotalDist = 1.0f/(pDeadPoint->fPlaneDist - pLivingPoint->fPlaneDist); //subtraction because the living index is known to be negative + pNewPoint->ptPosition = (pLivingPoint->ptPosition * (pDeadPoint->fPlaneDist * fInvTotalDist)) - (pDeadPoint->ptPosition * (pLivingPoint->fPlaneDist * fInvTotalDist)); + +#if ( 0 && defined( _DEBUG ) ) + float fDebugDist = vNormal.Dot( pNewPoint->ptPosition ) - fPlaneDist; //just for looking at in watch windows + AssertMsg_DumpPolyhedron( fabs( fDebugDist ) < fOnPlaneEpsilon, "Generated split point is far from plane" ); + + //verify that the new point isn't sitting on top of another + { + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + do + { + if( pActivePointWalk->pPoint != pNewPoint ) + { + Vector vDiff = pActivePointWalk->pPoint->ptPosition - pNewPoint->ptPosition; + + AssertMsg_DumpPolyhedron( vDiff.Length() > fOnPlaneEpsilon, "Generated a point on top of another" ); + } + pActivePointWalk = pActivePointWalk->pNext; + } while( pActivePointWalk ); + } +#endif + + pNewPoint->planarity = POINT_ONPLANE; + pNewPoint->fPlaneDist = 0.0f; + } + + GeneratePolyhedronFromPlanes_LineLL *pNewLineLink = pNewPoint->pConnectedLines = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pNewLineLink->pLine = pWorkLine; + pNewLineLink->pNext = pNewLineLink; + pNewLineLink->pPrev = pNewLineLink; + pNewLineLink->iReferenceIndex = iLivingIndex; + + pWorkLine->pPoints[iDeadIndex] = pNewPoint; + pWorkLine->pPointLineLinks[iDeadIndex] = pNewLineLink; + pNewPoint->pConnectedLines = pNewLineLink; + + //A new line is needed on each polygon touching the dead point to connect the two new endpoints for split lines. + // So mark connected polygons as missing a side. + for( int i = 0; i != 2; ++i ) + pWorkLine->pPolygons[i]->bMissingASide = true; + + + //Always have a cut polygon's head line be just before the gap in the polygon. + // In this case, we know that one of the two polygons goes clockwise into the dead point, so have that polygon point at this line. + // We don't know enough about the other polygon to do anything here, but another cut line will handle that polygon. So it all works out in the end. + pWorkLine->pPolygons[iDeadIndex]->pLines = pWorkLine->pPolygonLineLinks[iDeadIndex]; + } + + pActiveLineWalk = pActiveLineWalk->pNext; + } while( pActiveLineWalk ); + } + + + //=================================================================================================== + // Step 6: Repair polygons that are missing a side. And generate the new coplanar polygon. + //=================================================================================================== + { + //Find the first polygon missing a side. + // We'll then walk from polygon to polygon using line connections so that we can generate the new polygon in a clockwise manner. + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pActivePolygonWalk = pAllPolygons; + + while( (pActivePolygonWalk != NULL) && (pActivePolygonWalk->pPolygon->bMissingASide == false) ) + { + pActivePolygonWalk = pActivePolygonWalk->pNext; + } + + //acquire iteration data +#ifndef _DEBUG + GeneratePolyhedronFromPlanes_Point *pStartPoint; + GeneratePolyhedronFromPlanes_Point *pWorkPoint; +#endif + + GeneratePolyhedronFromPlanes_LineLL *pLastLineLink; + GeneratePolyhedronFromPlanes_Polygon *pWorkPolygon; + GeneratePolyhedronFromPlanes_LineLL *pTestLine; + +#ifdef _DEBUG + GeneratePolyhedronFromPlanes_Polygon *pLastWorkPolygon = NULL; + GeneratePolyhedronFromPlanes_Point *pLastWorkPoint = NULL; +#endif + + if( pActivePolygonWalk ) + { + //grab the polygon we'll be starting with + GeneratePolyhedronFromPlanes_Polygon *pBrokenPolygon = pActivePolygonWalk->pPolygon; + + { + GeneratePolyhedronFromPlanes_LineLL *pTemp = pBrokenPolygon->pLines->pNext; + pStartPoint = pTemp->pLine->pPoints[1 - pTemp->iReferenceIndex]; + Assert_DumpPolyhedron( pStartPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + pLastLineLink = pTemp->pLine->pPointLineLinks[1 - pTemp->iReferenceIndex]->pNext; + pWorkPolygon = pBrokenPolygon; + } + + pWorkPoint = pStartPoint; + pTestLine = pLastLineLink->pPrev; //rotate counterclockwise around the point + } + else + { + //apparently the plane was entirely through existing polygonal borders, extremely rare but it can happen with inefficient cutting planes + GeneratePolyhedronFromPlanes_UnorderedPointLL *pActivePointWalk = pAllPoints; + while( (pActivePointWalk != NULL) && (pActivePointWalk->pPoint->planarity != POINT_ONPLANE) ) + { + pActivePointWalk = pActivePointWalk->pNext; + } + + Assert( pActivePointWalk != NULL ); + + pStartPoint = pWorkPoint = pActivePointWalk->pPoint; + GeneratePolyhedronFromPlanes_LineLL *pLines = pWorkPoint->pConnectedLines; + + while( !pLines->pLine->bAlive ) //seek clockwise until we find a line not on the plane + pLines = pLines->pNext; + + while( pLines->pLine->bAlive ) //now seek counterclockwise until we find a line on the plane (in case we started on an alive line last seek) + pLines = pLines->pPrev; + + //now pLines points at one side of the polygon, with pActivePointWalk + pLastLineLink = pLines; + pTestLine = pLines->pPrev; + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + } + + //create the new polygon + GeneratePolyhedronFromPlanes_Polygon *pNewPolygon = (GeneratePolyhedronFromPlanes_Polygon *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Polygon ) ); + { + //before we forget, add this polygon to the active list + pAllPolygons->pPrev = (GeneratePolyhedronFromPlanes_UnorderedPolygonLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedPolygonLL ) ); + pAllPolygons->pPrev->pNext = pAllPolygons; + pAllPolygons = pAllPolygons->pPrev; + pAllPolygons->pPrev = NULL; + pAllPolygons->pPolygon = pNewPolygon; + + pNewPolygon->bMissingASide = false; //technically missing all it's sides, but we're fixing it now + pNewPolygon->vSurfaceNormal = vNormal; + pNewPolygon->pLines = NULL; + } + + + + //=================================================================================================================== + // The general idea of the upcoming algorithm to put together a new polygon and patch broken polygons... + // You have a point and a line the algorithm just jumped across. + // 1. Rotate through the point's line links one time counterclockwise (pPrev) + // 2. If the line is cut, then we make a new bridging line in the polygon between that line and the one counterclockwise to it. (pPrev) + // If the line is on-plane. Skip the bridge line making, but set links to the new polygon as if we'd just created the bridge + // 3. Once we follow a line back to the point where we started, we should be all done. + + do + { + if( pWorkPolygon->bMissingASide ) + { + //during the cutting process we made sure that the head line link was going clockwise into the missing area + GeneratePolyhedronFromPlanes_LineLL *pGapLines[2]; + pGapLines[1] = pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex]; //get the same line, but in the polygons linked list. + Assert_DumpPolyhedron( pGapLines[1]->pLine == pTestLine->pLine ); + pGapLines[0] = pGapLines[1]->pPrev; + + Assert_DumpPolyhedron( pWorkPolygon->bMissingASide ); + +#ifdef _DEBUG + { + //ensure that the space between the gap lines is the only space where fixing is required + GeneratePolyhedronFromPlanes_LineLL *pDebugLineWalk = pGapLines[1]->pNext; + + while( pDebugLineWalk != pGapLines[0] ) + { + Assert_DumpPolyhedron( pDebugLineWalk->pLine->bCut == false ); + pDebugLineWalk = pDebugLineWalk->pNext; + } + } +#endif + + GeneratePolyhedronFromPlanes_Line *pJoinLine = (GeneratePolyhedronFromPlanes_Line *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_Line ) ); + { + //before we forget, add this line to the active list + pAllLines->pPrev = (GeneratePolyhedronFromPlanes_UnorderedLineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_UnorderedLineLL ) ); + pAllLines->pPrev->pNext = pAllLines; + pAllLines = pAllLines->pPrev; + pAllLines->pPrev = NULL; + pAllLines->pLine = pJoinLine; + + pJoinLine->bAlive = false; + pJoinLine->bCut = false; + } + + + pJoinLine->pPoints[0] = pGapLines[0]->pLine->pPoints[pGapLines[0]->iReferenceIndex]; + pJoinLine->pPoints[1] = pGapLines[1]->pLine->pPoints[1 - pGapLines[1]->iReferenceIndex]; + + pJoinLine->pPolygons[0] = pNewPolygon; + pJoinLine->pPolygons[1] = pWorkPolygon; + + //now create all 4 links into the line + GeneratePolyhedronFromPlanes_LineLL *pPointLinks[2]; + pPointLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pPointLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + GeneratePolyhedronFromPlanes_LineLL *pPolygonLinks[2]; + pPolygonLinks[0] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + pPolygonLinks[1] = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + pPointLinks[0]->pLine = pPointLinks[1]->pLine = pPolygonLinks[0]->pLine = pPolygonLinks[1]->pLine = pJoinLine; + + pJoinLine->pPointLineLinks[0] = pPointLinks[0]; + pJoinLine->pPointLineLinks[1] = pPointLinks[1]; + pJoinLine->pPolygonLineLinks[0] = pPolygonLinks[0]; + pJoinLine->pPolygonLineLinks[1] = pPolygonLinks[1]; + + + + pPointLinks[0]->iReferenceIndex = 1; + pPointLinks[1]->iReferenceIndex = 0; + + //Insert before the link from point 0 to gap line 0 (counterclockwise rotation) + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[0]->pLine->pPointLineLinks[pGapLines[0]->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[0]->pLine ); + + pPointLinks[0]->pPrev = pWorkLink->pPrev; + pPointLinks[0]->pNext = pWorkLink; + + pWorkLink->pPrev->pNext = pPointLinks[0]; + pWorkLink->pPrev = pPointLinks[0]; + } + + //Insert after the link from point 1 to gap line 1 (clockwise rotation) + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pGapLines[1]->pLine->pPointLineLinks[1 - pGapLines[1]->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkLink->pLine == pGapLines[1]->pLine ); + + pPointLinks[1]->pNext = pWorkLink->pNext; + pPointLinks[1]->pPrev = pWorkLink; + + pWorkLink->pNext->pPrev = pPointLinks[1]; + pWorkLink->pNext = pPointLinks[1]; + } + + + + + pPolygonLinks[0]->iReferenceIndex = 0; + pPolygonLinks[1]->iReferenceIndex = 1; + + //Insert before the head line in the new polygon (at the end of the clockwise order) + { + if( pNewPolygon->pLines == NULL ) + { + //this is the first line being added to the polygon + pNewPolygon->pLines = pPolygonLinks[0]; + pPolygonLinks[0]->pNext = pPolygonLinks[0]; + pPolygonLinks[0]->pPrev = pPolygonLinks[0]; + } + else + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines; + + pPolygonLinks[0]->pNext = pWorkLink; + pPolygonLinks[0]->pPrev = pWorkLink->pPrev; + + pWorkLink->pPrev->pNext = pPolygonLinks[0]; + pWorkLink->pPrev = pPolygonLinks[0]; + } + } + + //Insert after the head line in the work polygon + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pWorkPolygon->pLines; + + pPolygonLinks[1]->pNext = pWorkLink->pNext; + pPolygonLinks[1]->pPrev = pWorkLink; + + pWorkLink->pNext->pPrev = pPolygonLinks[1]; + pWorkLink->pNext = pPolygonLinks[1]; + } + + pWorkPolygon->bMissingASide = false; //repairs are finished + +#ifdef _DEBUG + pLastWorkPolygon = pWorkPolygon; + pLastWorkPoint = pWorkPoint; +#endif + //move to the next point + pWorkPoint = pJoinLine->pPoints[0]; + pLastLineLink = pJoinLine->pPointLineLinks[0]; + Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + + pTestLine = pLastLineLink->pPrev; + if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE ) + pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex]; + else + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon ); + Assert_DumpPolyhedron( (pWorkPoint == pStartPoint) || + (pGapLines[0]->pLine->bCut == false) || + (pWorkPolygon->bMissingASide == true) ); //if we're not done fixing, and if the shared line was cut, the next polygon must be missing a side + } + else + { + //line is on the plane, meaning the polygon isn't broken and doesn't need patching + Assert_DumpPolyhedron( pTestLine->pLine->bCut == false ); + Assert_DumpPolyhedron( (pTestLine->pLine->pPoints[0]->planarity == POINT_ONPLANE) && (pTestLine->pLine->pPoints[1]->planarity == POINT_ONPLANE) ); + + + //link to this line from the new polygon + GeneratePolyhedronFromPlanes_LineLL *pNewLineLink; + pNewLineLink = (GeneratePolyhedronFromPlanes_LineLL *)stackalloc( sizeof( GeneratePolyhedronFromPlanes_LineLL ) ); + + pNewLineLink->pLine = pTestLine->pLine; + pNewLineLink->iReferenceIndex = pTestLine->iReferenceIndex; + + //Insert before the head line in the new polygon (at the end of the clockwise order) + { + if( pNewPolygon->pLines == NULL ) + { + //this is the first line being added to the polygon + pNewPolygon->pLines = pNewLineLink; + pNewLineLink->pNext = pNewLineLink; + pNewLineLink->pPrev = pNewLineLink; + } + else + { + GeneratePolyhedronFromPlanes_LineLL *pWorkLink = pNewPolygon->pLines; + + pNewLineLink->pNext = pWorkLink; + pNewLineLink->pPrev = pWorkLink->pPrev; + + pWorkLink->pPrev->pNext = pNewLineLink; + pWorkLink->pPrev = pNewLineLink; + } + } + + //Since the entire line is on the plane, that means it used to point to something that used to reside where the new polygon is going + // Update the link to the new the polygon pointer and be on our way + pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex] = pNewPolygon; + pTestLine->pLine->pPolygonLineLinks[pTestLine->iReferenceIndex] = pNewLineLink; + +#ifdef _DEBUG + pLastWorkPolygon = pWorkPolygon; + pLastWorkPoint = pWorkPoint; +#endif + + pWorkPoint = pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]; + pLastLineLink = pTestLine->pLine->pPointLineLinks[pTestLine->iReferenceIndex]; + Assert_DumpPolyhedron( pWorkPoint->planarity == POINT_ONPLANE ); //every working point should be coplanar + + pTestLine = pLastLineLink->pPrev; + if( pTestLine->pLine->pPoints[pTestLine->iReferenceIndex]->planarity == POINT_ALIVE ) + pWorkPolygon = pTestLine->pLine->pPolygons[pTestLine->iReferenceIndex]; + else + pWorkPolygon = pTestLine->pLine->pPolygons[1 - pTestLine->iReferenceIndex]; + + Assert_DumpPolyhedron( pWorkPolygon != pLastWorkPolygon ); + } + } while( pWorkPoint != pStartPoint ); + } + +#ifdef _DEBUG + //verify that repairs are complete + { + GeneratePolyhedronFromPlanes_UnorderedPolygonLL *pDebugPolygonWalk = pAllPolygons; + do + { + AssertMsg_DumpPolyhedron( pDebugPolygonWalk->pPolygon->bMissingASide == false, "Some polygons not repaired after cut" ); + pDebugPolygonWalk = pDebugPolygonWalk->pNext; + } while( pDebugPolygonWalk ); + + + GeneratePolyhedronFromPlanes_UnorderedPointLL *pDebugPointWalk = pAllPoints; + do + { + AssertMsg_DumpPolyhedron( pDebugPointWalk->pPoint->pConnectedLines, "Point connected to no lines after cut" ); + pDebugPointWalk = pDebugPointWalk->pNext; + } while( pDebugPointWalk ); + + pStartPoint = NULL; + } + + //maintain the cut history + DebugCutHistory.AddToTail( ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, false ) ); +#endif + } + +#ifdef _DEBUG + for( int i = DebugCutHistory.Count(); --i >= 0; ) + { + if( DebugCutHistory[i] ) + DebugCutHistory[i]->Release(); + } + DebugCutHistory.RemoveAll(); +#endif + + return ConvertLinkedGeometryToPolyhedron( pAllPolygons, pAllLines, pAllPoints, bUseTemporaryMemory ); +} + + + +#define STARTPOINTTOLINELINKS(iPointNum, lineindex1, iOtherPointIndex1, lineindex2, iOtherPointIndex2, lineindex3, iOtherPointIndex3 )\ + StartingBoxPoints[iPointNum].pConnectedLines = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pLine = &StartingBoxLines[lineindex1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].iReferenceIndex = iOtherPointIndex1;\ + StartingBoxLines[lineindex1].pPointLineLinks[1 - iOtherPointIndex1] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 0].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pLine = &StartingBoxLines[lineindex2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].iReferenceIndex = iOtherPointIndex2;\ + StartingBoxLines[lineindex2].pPointLineLinks[1 - iOtherPointIndex2] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 1].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pLine = &StartingBoxLines[lineindex3];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].iReferenceIndex = iOtherPointIndex3;\ + StartingBoxLines[lineindex3].pPointLineLinks[1 - iOtherPointIndex3] = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 2];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pPrev = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 1];\ + StartingPoints_To_Lines_Links[(iPointNum * 3) + 2].pNext = &StartingPoints_To_Lines_Links[(iPointNum * 3) + 0]; + +#define STARTBOXCONNECTION( linenum, point1, point2, poly1, poly2 )\ + StartingBoxLines[linenum].pPoints[0] = &StartingBoxPoints[point1];\ + StartingBoxLines[linenum].pPoints[1] = &StartingBoxPoints[point2];\ + StartingBoxLines[linenum].pPolygons[0] = &StartingBoxPolygons[poly1];\ + StartingBoxLines[linenum].pPolygons[1] = &StartingBoxPolygons[poly2]; + +#define STARTPOLYGONTOLINELINKS( polynum, lineindex1, iThisPolyIndex1, lineindex2, iThisPolyIndex2, lineindex3, iThisPolyIndex3, lineindex4, iThisPolyIndex4 )\ + StartingBoxPolygons[polynum].pLines = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pLine = &StartingBoxLines[lineindex1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].iReferenceIndex = iThisPolyIndex1;\ + StartingBoxLines[lineindex1].pPolygonLineLinks[iThisPolyIndex1] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 0].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pLine = &StartingBoxLines[lineindex2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].iReferenceIndex = iThisPolyIndex2;\ + StartingBoxLines[lineindex2].pPolygonLineLinks[iThisPolyIndex2] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 1].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pLine = &StartingBoxLines[lineindex3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].iReferenceIndex = iThisPolyIndex3;\ + StartingBoxLines[lineindex3].pPolygonLineLinks[iThisPolyIndex3] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 1];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 2].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pLine = &StartingBoxLines[lineindex4];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].iReferenceIndex = iThisPolyIndex4;\ + StartingBoxLines[lineindex4].pPolygonLineLinks[iThisPolyIndex4] = &StartingPolygon_To_Lines_Links[(polynum * 4) + 3];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pPrev = &StartingPolygon_To_Lines_Links[(polynum * 4) + 2];\ + StartingPolygon_To_Lines_Links[(polynum * 4) + 3].pNext = &StartingPolygon_To_Lines_Links[(polynum * 4) + 0]; + + +CPolyhedron *GeneratePolyhedronFromPlanes( const float *pOutwardFacingPlanes, int iPlaneCount, float fOnPlaneEpsilon, bool bUseTemporaryMemory ) +{ + //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 + //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 + + //the polygon clipping functions we're going to use want inward facing planes + float *pFlippedPlanes = (float *)stackalloc( (iPlaneCount * 4) * sizeof( float ) ); + for( int i = 0; i != iPlaneCount * 4; ++i ) + { + pFlippedPlanes[i] = -pOutwardFacingPlanes[i]; + } + + //our first goal is to find the size of a cube big enough to encapsulate all points that will be in the final polyhedron + Vector vAABBMins, vAABBMaxs; + if( FindConvexShapeLooseAABB( pFlippedPlanes, iPlaneCount, &vAABBMins, &vAABBMaxs ) == false ) + return NULL; //no shape to work with apparently + + + //grow the bounding box to a larger size since it's probably inaccurate a bit + { + Vector vGrow = (vAABBMaxs - vAABBMins) * 0.5f; + vGrow.x += 100.0f; + vGrow.y += 100.0f; + vGrow.z += 100.0f; + + vAABBMaxs += vGrow; + vAABBMins -= vGrow; + } + + //generate our starting cube using the 2x AABB so we can start hacking away at it + + + + //create our starting box on the stack + GeneratePolyhedronFromPlanes_Point StartingBoxPoints[8]; + GeneratePolyhedronFromPlanes_Line StartingBoxLines[12]; + GeneratePolyhedronFromPlanes_Polygon StartingBoxPolygons[6]; + GeneratePolyhedronFromPlanes_LineLL StartingPoints_To_Lines_Links[24]; //8 points, 3 lines per point + GeneratePolyhedronFromPlanes_LineLL StartingPolygon_To_Lines_Links[24]; //6 polygons, 4 lines per poly + + GeneratePolyhedronFromPlanes_UnorderedPolygonLL StartingPolygonList[6]; //6 polygons + GeneratePolyhedronFromPlanes_UnorderedLineLL StartingLineList[12]; //12 lines + GeneratePolyhedronFromPlanes_UnorderedPointLL StartingPointList[8]; //8 points + + + //I had to work all this out on a whiteboard if it seems completely unintuitive. + { + StartingBoxPoints[0].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 0, 0, 1, 4, 1, 3, 0 ); + + StartingBoxPoints[1].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 1, 0, 0, 1, 1, 5, 1 ); + + StartingBoxPoints[2].ptPosition.Init( vAABBMins.x, vAABBMins.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 2, 4, 0, 8, 1, 11, 0 ); + + StartingBoxPoints[3].ptPosition.Init( vAABBMins.x, vAABBMaxs.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 3, 5, 0, 9, 1, 8, 0 ); + + StartingBoxPoints[4].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 4, 2, 0, 3, 1, 7, 1 ); + + StartingBoxPoints[5].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMins.z ); + STARTPOINTTOLINELINKS( 5, 1, 0, 2, 1, 6, 1 ); + + StartingBoxPoints[6].ptPosition.Init( vAABBMaxs.x, vAABBMins.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 6, 7, 0, 11, 1, 10, 0 ); + + StartingBoxPoints[7].ptPosition.Init( vAABBMaxs.x, vAABBMaxs.y, vAABBMaxs.z ); + STARTPOINTTOLINELINKS( 7, 6, 0, 10, 1, 9, 0 ); + + STARTBOXCONNECTION( 0, 0, 1, 0, 5 ); + STARTBOXCONNECTION( 1, 1, 5, 1, 5 ); + STARTBOXCONNECTION( 2, 5, 4, 2, 5 ); + STARTBOXCONNECTION( 3, 4, 0, 3, 5 ); + STARTBOXCONNECTION( 4, 0, 2, 3, 0 ); + STARTBOXCONNECTION( 5, 1, 3, 0, 1 ); + STARTBOXCONNECTION( 6, 5, 7, 1, 2 ); + STARTBOXCONNECTION( 7, 4, 6, 2, 3 ); + STARTBOXCONNECTION( 8, 2, 3, 4, 0 ); + STARTBOXCONNECTION( 9, 3, 7, 4, 1 ); + STARTBOXCONNECTION( 10, 7, 6, 4, 2 ); + STARTBOXCONNECTION( 11, 6, 2, 4, 3 ); + + + STARTBOXCONNECTION( 0, 0, 1, 5, 0 ); + STARTBOXCONNECTION( 1, 1, 5, 5, 1 ); + STARTBOXCONNECTION( 2, 5, 4, 5, 2 ); + STARTBOXCONNECTION( 3, 4, 0, 5, 3 ); + STARTBOXCONNECTION( 4, 0, 2, 0, 3 ); + STARTBOXCONNECTION( 5, 1, 3, 1, 0 ); + STARTBOXCONNECTION( 6, 5, 7, 2, 1 ); + STARTBOXCONNECTION( 7, 4, 6, 3, 2 ); + STARTBOXCONNECTION( 8, 2, 3, 0, 4 ); + STARTBOXCONNECTION( 9, 3, 7, 1, 4 ); + STARTBOXCONNECTION( 10, 7, 6, 2, 4 ); + STARTBOXCONNECTION( 11, 6, 2, 3, 4 ); + + StartingBoxPolygons[0].vSurfaceNormal.Init( -1.0f, 0.0f, 0.0f ); + StartingBoxPolygons[1].vSurfaceNormal.Init( 0.0f, 1.0f, 0.0f ); + StartingBoxPolygons[2].vSurfaceNormal.Init( 1.0f, 0.0f, 0.0f ); + StartingBoxPolygons[3].vSurfaceNormal.Init( 0.0f, -1.0f, 0.0f ); + StartingBoxPolygons[4].vSurfaceNormal.Init( 0.0f, 0.0f, 1.0f ); + StartingBoxPolygons[5].vSurfaceNormal.Init( 0.0f, 0.0f, -1.0f ); + + + STARTPOLYGONTOLINELINKS( 0, 0, 1, 5, 1, 8, 0, 4, 0 ); + STARTPOLYGONTOLINELINKS( 1, 1, 1, 6, 1, 9, 0, 5, 0 ); + STARTPOLYGONTOLINELINKS( 2, 2, 1, 7, 1, 10, 0, 6, 0 ); + STARTPOLYGONTOLINELINKS( 3, 3, 1, 4, 1, 11, 0, 7, 0 ); + STARTPOLYGONTOLINELINKS( 4, 8, 1, 9, 1, 10, 1, 11, 1 ); + STARTPOLYGONTOLINELINKS( 5, 0, 0, 3, 0, 2, 0, 1, 0 ); + + + { + StartingPolygonList[0].pPolygon = &StartingBoxPolygons[0]; + StartingPolygonList[0].pNext = &StartingPolygonList[1]; + StartingPolygonList[0].pPrev = NULL; + + StartingPolygonList[1].pPolygon = &StartingBoxPolygons[1]; + StartingPolygonList[1].pNext = &StartingPolygonList[2]; + StartingPolygonList[1].pPrev = &StartingPolygonList[0]; + + StartingPolygonList[2].pPolygon = &StartingBoxPolygons[2]; + StartingPolygonList[2].pNext = &StartingPolygonList[3]; + StartingPolygonList[2].pPrev = &StartingPolygonList[1]; + + StartingPolygonList[3].pPolygon = &StartingBoxPolygons[3]; + StartingPolygonList[3].pNext = &StartingPolygonList[4]; + StartingPolygonList[3].pPrev = &StartingPolygonList[2]; + + StartingPolygonList[4].pPolygon = &StartingBoxPolygons[4]; + StartingPolygonList[4].pNext = &StartingPolygonList[5]; + StartingPolygonList[4].pPrev = &StartingPolygonList[3]; + + StartingPolygonList[5].pPolygon = &StartingBoxPolygons[5]; + StartingPolygonList[5].pNext = NULL; + StartingPolygonList[5].pPrev = &StartingPolygonList[4]; + } + + + + { + StartingLineList[0].pLine = &StartingBoxLines[0]; + StartingLineList[0].pNext = &StartingLineList[1]; + StartingLineList[0].pPrev = NULL; + + StartingLineList[1].pLine = &StartingBoxLines[1]; + StartingLineList[1].pNext = &StartingLineList[2]; + StartingLineList[1].pPrev = &StartingLineList[0]; + + StartingLineList[2].pLine = &StartingBoxLines[2]; + StartingLineList[2].pNext = &StartingLineList[3]; + StartingLineList[2].pPrev = &StartingLineList[1]; + + StartingLineList[3].pLine = &StartingBoxLines[3]; + StartingLineList[3].pNext = &StartingLineList[4]; + StartingLineList[3].pPrev = &StartingLineList[2]; + + StartingLineList[4].pLine = &StartingBoxLines[4]; + StartingLineList[4].pNext = &StartingLineList[5]; + StartingLineList[4].pPrev = &StartingLineList[3]; + + StartingLineList[5].pLine = &StartingBoxLines[5]; + StartingLineList[5].pNext = &StartingLineList[6]; + StartingLineList[5].pPrev = &StartingLineList[4]; + + StartingLineList[6].pLine = &StartingBoxLines[6]; + StartingLineList[6].pNext = &StartingLineList[7]; + StartingLineList[6].pPrev = &StartingLineList[5]; + + StartingLineList[7].pLine = &StartingBoxLines[7]; + StartingLineList[7].pNext = &StartingLineList[8]; + StartingLineList[7].pPrev = &StartingLineList[6]; + + StartingLineList[8].pLine = &StartingBoxLines[8]; + StartingLineList[8].pNext = &StartingLineList[9]; + StartingLineList[8].pPrev = &StartingLineList[7]; + + StartingLineList[9].pLine = &StartingBoxLines[9]; + StartingLineList[9].pNext = &StartingLineList[10]; + StartingLineList[9].pPrev = &StartingLineList[8]; + + StartingLineList[10].pLine = &StartingBoxLines[10]; + StartingLineList[10].pNext = &StartingLineList[11]; + StartingLineList[10].pPrev = &StartingLineList[9]; + + StartingLineList[11].pLine = &StartingBoxLines[11]; + StartingLineList[11].pNext = NULL; + StartingLineList[11].pPrev = &StartingLineList[10]; + } + + { + StartingPointList[0].pPoint = &StartingBoxPoints[0]; + StartingPointList[0].pNext = &StartingPointList[1]; + StartingPointList[0].pPrev = NULL; + + StartingPointList[1].pPoint = &StartingBoxPoints[1]; + StartingPointList[1].pNext = &StartingPointList[2]; + StartingPointList[1].pPrev = &StartingPointList[0]; + + StartingPointList[2].pPoint = &StartingBoxPoints[2]; + StartingPointList[2].pNext = &StartingPointList[3]; + StartingPointList[2].pPrev = &StartingPointList[1]; + + StartingPointList[3].pPoint = &StartingBoxPoints[3]; + StartingPointList[3].pNext = &StartingPointList[4]; + StartingPointList[3].pPrev = &StartingPointList[2]; + + StartingPointList[4].pPoint = &StartingBoxPoints[4]; + StartingPointList[4].pNext = &StartingPointList[5]; + StartingPointList[4].pPrev = &StartingPointList[3]; + + StartingPointList[5].pPoint = &StartingBoxPoints[5]; + StartingPointList[5].pNext = &StartingPointList[6]; + StartingPointList[5].pPrev = &StartingPointList[4]; + + StartingPointList[6].pPoint = &StartingBoxPoints[6]; + StartingPointList[6].pNext = &StartingPointList[7]; + StartingPointList[6].pPrev = &StartingPointList[5]; + + StartingPointList[7].pPoint = &StartingBoxPoints[7]; + StartingPointList[7].pNext = NULL; + StartingPointList[7].pPrev = &StartingPointList[6]; + } + } + + return ClipLinkedGeometry( StartingPolygonList, StartingLineList, StartingPointList, pOutwardFacingPlanes, iPlaneCount, fOnPlaneEpsilon, bUseTemporaryMemory ); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#ifdef _DEBUG +void DumpAABBToGLView( const Vector &vCenter, const Vector &vExtents, const Vector &vColor, FILE *pFile ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + Vector vMins = vCenter - vExtents; + Vector vMaxs = vCenter + vExtents; + + //x min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + //x max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + //y min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + + //y max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + + //z min side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMins.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMins.z, vColor.x, vColor.y, vColor.z ); + + + //z max side + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + + fprintf( pFile, "4\n" ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMaxs.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMaxs.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vMins.x, vMins.y, vMaxs.z, vColor.x, vColor.y, vColor.z ); +#endif +} + +void DumpLineToGLView( const Vector &vPoint1, const Vector &vColor1, const Vector &vPoint2, const Vector &vColor2, float fThickness, FILE *pFile ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + Vector vDirection = vPoint2 - vPoint1; + vDirection.NormalizeInPlace(); + + Vector vPseudoPerpandicular = vec3_origin; + + if( vDirection.x != 0.0f ) + vPseudoPerpandicular.z = 1.0f; + else + vPseudoPerpandicular.x = 1.0f; + + Vector vWidth = vDirection.Cross( vPseudoPerpandicular ); + vWidth.NormalizeInPlace(); + + Vector vHeight = vDirection.Cross( vWidth ); + vHeight.NormalizeInPlace(); + + fThickness *= 0.5f; //we use half thickness in both directions + vDirection *= fThickness; + vWidth *= fThickness; + vHeight *= fThickness; + + Vector vLinePoints[8]; + vLinePoints[0] = vPoint1 - vDirection - vWidth - vHeight; + vLinePoints[1] = vPoint1 - vDirection - vWidth + vHeight; + vLinePoints[2] = vPoint1 - vDirection + vWidth - vHeight; + vLinePoints[3] = vPoint1 - vDirection + vWidth + vHeight; + + vLinePoints[4] = vPoint2 + vDirection - vWidth - vHeight; + vLinePoints[5] = vPoint2 + vDirection - vWidth + vHeight; + vLinePoints[6] = vPoint2 + vDirection + vWidth - vHeight; + vLinePoints[7] = vPoint2 + vDirection + vWidth + vHeight; + + const Vector *pLineColors[8] = { &vColor1, &vColor1, &vColor1, &vColor1, &vColor2, &vColor2, &vColor2, &vColor2 }; + + +#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 ); +#define DPTGLV_LINE_DOUBLESIDEDQUAD(index1,index2,index3,index4)\ + fprintf( pFile, "4\n" );\ + DPTGLV_LINE_WRITEPOINT(index1);\ + DPTGLV_LINE_WRITEPOINT(index2);\ + DPTGLV_LINE_WRITEPOINT(index3);\ + DPTGLV_LINE_WRITEPOINT(index4);\ + fprintf( pFile, "4\n" );\ + DPTGLV_LINE_WRITEPOINT(index4);\ + DPTGLV_LINE_WRITEPOINT(index3);\ + DPTGLV_LINE_WRITEPOINT(index2);\ + DPTGLV_LINE_WRITEPOINT(index1); + + + DPTGLV_LINE_DOUBLESIDEDQUAD(0,4,6,2); + DPTGLV_LINE_DOUBLESIDEDQUAD(3,7,5,1); + DPTGLV_LINE_DOUBLESIDEDQUAD(1,5,4,0); + DPTGLV_LINE_DOUBLESIDEDQUAD(2,6,7,3); + DPTGLV_LINE_DOUBLESIDEDQUAD(0,2,3,1); + DPTGLV_LINE_DOUBLESIDEDQUAD(5,7,6,4); +#endif +} + +void DumpPolyhedronToGLView( const CPolyhedron *pPolyhedron, const char *pFilename, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if ( (pPolyhedron == NULL) || (pPolyhedron->iVertexCount == 0) ) + return; + + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + printf("Writing %s...\n", pFilename ); + + FILE *pFile = fopen( pFilename, "ab" ); + + //randomizing an array of colors to help spot shared/unshared vertices + Vector *pColors = (Vector *)stackalloc( sizeof( Vector ) * pPolyhedron->iVertexCount ); + int counter; + for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + pColors[counter].Init( rand()/32768.0f, rand()/32768.0f, rand()/32768.0f ); + } + + Vector *pTransformedPoints = (Vector *)stackalloc( pPolyhedron->iVertexCount * sizeof( Vector ) ); + for ( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + pTransformedPoints[counter] = (*pTransform) * pPolyhedron->pVertices[counter]; + } + + for ( counter = 0; counter != pPolyhedron->iPolygonCount; ++counter ) + { + fprintf( pFile, "%i\n", pPolyhedron->pPolygons[counter].iIndexCount ); + int counter2; + for( counter2 = 0; counter2 != pPolyhedron->pPolygons[counter].iIndexCount; ++counter2 ) + { + Polyhedron_IndexedLineReference_t *pLineReference = &pPolyhedron->pIndices[pPolyhedron->pPolygons[counter].iFirstIndex + counter2]; + + Vector *pVertex = &pTransformedPoints[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]]; + Vector *pColor = &pColors[pPolyhedron->pLines[pLineReference->iLineIndex].iPointIndices[pLineReference->iEndPointIndex]]; + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n",pVertex->x, pVertex->y, pVertex->z, pColor->x, pColor->y, pColor->z ); + } + } + + for( counter = 0; counter != pPolyhedron->iLineCount; ++counter ) + { + const Vector vOne( 1.0f, 1.0f, 1.0f ); + DumpLineToGLView( pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[0]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[0]], + pTransformedPoints[pPolyhedron->pLines[counter].iPointIndices[1]], vOne - pColors[pPolyhedron->pLines[counter].iPointIndices[1]], + 0.1f, pFile ); + } + + for( counter = 0; counter != pPolyhedron->iVertexCount; ++counter ) + { + const Vector vPointHalfSize(0.15f, 0.15f, 0.15f ); + DumpAABBToGLView( pTransformedPoints[counter], vPointHalfSize, pColors[counter], pFile ); + } + + fclose( pFile ); +#endif +} + + +void DumpPlaneToGlView( const float *pPlane, float fGrayScale, const char *pszFileName, const VMatrix *pTransform ) +{ +#ifdef ENABLE_DEBUG_POLYHEDRON_DUMPS + if( pTransform == NULL ) + pTransform = &s_matIdentity; + + FILE *pFile = fopen( pszFileName, "ab" ); + + //transform the plane + Vector vNormal = pTransform->ApplyRotation( *(Vector *)pPlane ); + float fDist = pPlane[3] * vNormal.NormalizeInPlace(); //possible scaling going on + fDist += vNormal.Dot( pTransform->GetTranslation() ); + + Vector vPlaneVerts[4]; + + PolyFromPlane( vPlaneVerts, vNormal, fDist, 100000.0f ); + + fprintf( pFile, "4\n" ); + + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[0].x, vPlaneVerts[0].y, vPlaneVerts[0].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[1].x, vPlaneVerts[1].y, vPlaneVerts[1].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[2].x, vPlaneVerts[2].y, vPlaneVerts[2].z, fGrayScale, fGrayScale, fGrayScale ); + fprintf( pFile, "%6.3f %6.3f %6.3f %.2f %.2f %.2f\n", vPlaneVerts[3].x, vPlaneVerts[3].y, vPlaneVerts[3].z, fGrayScale, fGrayScale, fGrayScale ); + + fclose( pFile ); +#endif +} +#endif + + diff --git a/public/mathlib/polyhedron.h b/public/mathlib/polyhedron.h index 8f4a4955..38b465c7 100644 --- a/public/mathlib/polyhedron.h +++ b/public/mathlib/polyhedron.h @@ -42,7 +42,7 @@ public: Polyhedron_IndexedLine_t *pLines; Polyhedron_IndexedLineReference_t *pIndices; Polyhedron_IndexedPolygon_t *pPolygons; - + unsigned short iVertexCount; unsigned short iLineCount; unsigned short iIndexCount; @@ -53,10 +53,10 @@ public: Vector Center( void ); }; -class CPolyhedron_AllocByNew final : public CPolyhedron +class CPolyhedron_AllocByNew : public CPolyhedron { public: - void Release( void ) override; + virtual void Release( void ); static 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 private: diff --git a/public/mathlib/ssemath.h b/public/mathlib/ssemath.h index 4580a4bd..b8cba33b 100644 --- a/public/mathlib/ssemath.h +++ b/public/mathlib/ssemath.h @@ -8,7 +8,7 @@ #if defined( _X360 ) #include -#elif defined(__arm__) || defined(__arm64__) +#elif defined(__arm__) || defined(__aarch64__) #include "sse2neon.h" #else #include @@ -1787,6 +1787,18 @@ FORCEINLINE fltx4 LoadAlignedSIMD( const VectorAligned & pSIMD ) return SetWToZeroSIMD( LoadAlignedSIMD(pSIMD.Base()) ); } +#ifdef __SANITIZE_ADDRESS__ +static __attribute__((no_sanitize("address"))) fltx4 LoadUnalignedSIMD( const void *pSIMD ) +{ + return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); + +} + +static __attribute__((no_sanitize("address"))) fltx4 LoadUnaligned3SIMD( const void *pSIMD ) +{ + return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); +} +#else FORCEINLINE fltx4 LoadUnalignedSIMD( const void *pSIMD ) { return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); @@ -1796,6 +1808,7 @@ FORCEINLINE fltx4 LoadUnaligned3SIMD( const void *pSIMD ) { return _mm_loadu_ps( reinterpret_cast( pSIMD ) ); } +#endif /// replicate a single 32 bit integer value to all 4 components of an m128 FORCEINLINE fltx4 ReplicateIX4( int i ) diff --git a/public/mathlib/vector4d.h b/public/mathlib/vector4d.h index 72c63129..cca45242 100644 --- a/public/mathlib/vector4d.h +++ b/public/mathlib/vector4d.h @@ -23,7 +23,7 @@ #include "tier0/dbg.h" #include "mathlib/math_pfns.h" -#ifdef __arm__ +#if defined (__arm__) || defined(__aarch64__) #include "sse2neon.h" #endif diff --git a/public/saverestoretypes.h b/public/saverestoretypes.h index 55fa0042..45a3d844 100644 --- a/public/saverestoretypes.h +++ b/public/saverestoretypes.h @@ -512,7 +512,7 @@ inline const char *CSaveRestoreSegment::StringFromSymbol( int token ) /// compilers. Either way, there's no portable intrinsic. // Newer GCC versions provide this in this header, older did by default. -#if !defined( _rotr ) && defined( COMPILER_GCC ) && !defined( __arm__ ) && !defined( __arm64__ ) +#if !defined( _rotr ) && defined( COMPILER_GCC ) && !defined( __arm__ ) && !defined( __aarch64__ ) #include #endif diff --git a/public/steam/steamtypes.h b/public/steam/steamtypes.h index f229f238..c32150e2 100644 --- a/public/steam/steamtypes.h +++ b/public/steam/steamtypes.h @@ -24,7 +24,7 @@ typedef unsigned char uint8; #define POSIX 1 #endif -#if defined(__x86_64__) || defined(_WIN64) || defined(__arm64__) +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) #define X64BITS #endif diff --git a/public/tier0/memvirt.h b/public/tier0/memvirt.h new file mode 100644 index 00000000..eeb09964 --- /dev/null +++ b/public/tier0/memvirt.h @@ -0,0 +1,46 @@ +//========== Copyright (C) Valve Corporation, All rights reserved. ==========// +// +// Purpose: CVirtualMemoryManager interface +// +//===========================================================================// + +#ifndef MEM_VIRT_H +#define MEM_VIRT_H +#ifdef _WIN32 +#pragma once +#endif + + +#define VMM_KB ( 1024 ) +#define VMM_MB ( 1024 * VMM_KB ) + +#ifdef _PS3 +// Total virtual address space reserved by CVirtualMemoryManager on startup: +#define VMM_VIRTUAL_SIZE ( 512 * VMM_MB ) +#define VMM_PAGE_SIZE ( 64 * VMM_KB ) +#endif + + + +// Allocate virtual sections via IMemAlloc::AllocateVirtualMemorySection +abstract_class IVirtualMemorySection +{ +public: + // Information about memory section + virtual void * GetBaseAddress() = 0; + virtual size_t GetPageSize() = 0; + virtual size_t GetTotalSize() = 0; + + // Functions to manage physical memory mapped to virtual memory + virtual bool CommitPages( void *pvBase, size_t numBytes ) = 0; + virtual void DecommitPages( void *pvBase, size_t numBytes ) = 0; + + // Release the physical memory and associated virtual address space + virtual void Release() = 0; +}; + +// Get the IVirtualMemorySection associated with a given memory address (if any): +extern IVirtualMemorySection *GetMemorySectionForAddress( void *pAddress ); + + +#endif // MEM_VIRT_H diff --git a/public/tier0/platform.h b/public/tier0/platform.h index 701c62ff..30b2ec0f 100644 --- a/public/tier0/platform.h +++ b/public/tier0/platform.h @@ -9,7 +9,7 @@ #ifndef PLATFORM_H #define PLATFORM_H -#if defined(__x86_64__) || defined(_WIN64) || defined(__arm64__) +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) #define PLATFORM_64BITS 1 #endif @@ -440,7 +440,7 @@ typedef void * HINSTANCE; // On OSX, SIGTRAP doesn't really stop the thread cold when debugging. // So if being debugged, use INT3 which is precise. #ifdef OSX -#if defined(__arm__) || defined(__arm64__) +#if defined(__arm__) || defined(__aarch64__) #ifdef __clang__ #define DebuggerBreak() do { if ( Plat_IsInDebugSession() ) { __builtin_debugtrap(); } else { raise(SIGTRAP); } } while(0) #elif defined __GNUC__ @@ -631,6 +631,7 @@ typedef void * HINSTANCE; #endif // Used for standard calling conventions + #if defined( _WIN32 ) && !defined( _X360 ) #define STDCALL __stdcall #define FASTCALL __fastcall @@ -687,6 +688,11 @@ typedef void * HINSTANCE; #ifdef _WIN32 +#ifdef __SANITIZE_ADDRESS__ +#undef FORCEINLINE +#define FORCEINLINE static +#endif + // Remove warnings from warning level 4. #pragma warning(disable : 4514) // warning C4514: 'acosl' : unreferenced inline function has been removed #pragma warning(disable : 4100) // warning C4100: 'hwnd' : unreferenced formal parameter @@ -861,7 +867,7 @@ static FORCEINLINE double fsel(double fComparand, double fValGE, double fLT) #endif #endif -#elif defined (__arm__) || defined (__arm64__) +#elif defined (__arm__) || defined (__aarch64__) inline void SetupFPUControlWord() {} #else inline void SetupFPUControlWord() @@ -1198,7 +1204,7 @@ PLATFORM_INTERFACE struct tm * Plat_localtime( const time_t *timep, struct tm * inline uint64 Plat_Rdtsc() { -#if (defined( __arm__ ) || defined( __arm64__ )) && defined (POSIX) +#if (defined( __arm__ ) || defined( __aarch64__ )) && defined (POSIX) struct timespec t; clock_gettime( CLOCK_REALTIME, &t); return t.tv_sec * 1000000000ULL + t.tv_nsec; diff --git a/public/tier0/threadtools.h b/public/tier0/threadtools.h index 00a38422..7714fe4f 100644 --- a/public/tier0/threadtools.h +++ b/public/tier0/threadtools.h @@ -81,7 +81,7 @@ enum ThreadPriorityEnum_t TP_PRIORITY_LOW = 2001, TP_PRIORITY_DEFAULT = 1001 #error "Need PRIORITY_LOWEST/HIGHEST" -#elif defined( PLATFORM_LINUX ) +#elif defined( LINUX ) // We can use nice on Linux threads to change scheduling. // pthreads on Linux only allows priority setting on // real-time threads. @@ -103,7 +103,7 @@ enum ThreadPriorityEnum_t #endif // PLATFORM_PS3 }; -#if defined( PLATFORM_LINUX ) +#if defined( LINUX ) #define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) < ( b ) ) #else #define TP_IS_PRIORITY_HIGHER( a, b ) ( ( a ) > ( b ) ) @@ -229,6 +229,8 @@ inline void ThreadPause() { #if defined( COMPILER_PS3 ) __db16cyc(); +#elif defined(__arm__) || defined(__aarch64__) + sched_yield(); #elif defined( COMPILER_GCC ) __asm __volatile( "pause" ); #elif defined ( COMPILER_MSVC64 ) @@ -301,15 +303,7 @@ inline int32 ThreadInterlockedDecrement( int32 volatile *p ) inline int32 ThreadInterlockedExchange( int32 volatile *p, int32 value ) { Assert( (size_t)p % 4 == 0 ); - int32 nRet; - - // Note: The LOCK instruction prefix is assumed on the XCHG instruction and GCC gets very confused on the Mac when we use it. - __asm __volatile( - "xchgl %2,(%1)" - : "=r" (nRet) - : "r" (p), "0" (value) - : "memory"); - return nRet; + return __sync_lock_test_and_set( p, value ); } inline int32 ThreadInterlockedExchangeAdd( int32 volatile *p, int32 value ) diff --git a/public/tier0/threadtools.inl b/public/tier0/threadtools.inl index dda4b5f5..694c653e 100644 --- a/public/tier0/threadtools.inl +++ b/public/tier0/threadtools.inl @@ -120,7 +120,7 @@ INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nP } #endif -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 m_hThread = (HANDLE)CreateThread( NULL, nBytesStack, (LPTHREAD_START_ROUTINE)GetThreadProc(), @@ -168,7 +168,7 @@ INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nP } bInitSuccess = true; -#elif PLATFORM_POSIX +#elif POSIX pthread_attr_t attr; pthread_attr_init( &attr ); pthread_attr_setstacksize( &attr, MAX( nBytesStack, 1024u*1024 ) ); @@ -236,7 +236,7 @@ INLINE_ON_PS3 bool CThread::Start( unsigned nBytesStack, ThreadPriorityEnum_t nP INLINE_ON_PS3 bool CThread::IsAlive() { -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 DWORD dwExitCode; return ( m_hThread @@ -526,7 +526,7 @@ INLINE_ON_PS3 void CThread::ThreadProcRunWithMinidumpHandler( void *pv ) pInit->pThread->m_result = pInit->pThread->Run(); } -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 unsigned long STDCALL CThread::ThreadProc(LPVOID pv) #else INLINE_ON_PS3 void* CThread::ThreadProc(LPVOID pv) diff --git a/public/togles/linuxwin/dxabstract.h b/public/togles/linuxwin/dxabstract.h index 93ef9267..d335c650 100644 --- a/public/togles/linuxwin/dxabstract.h +++ b/public/togles/linuxwin/dxabstract.h @@ -373,7 +373,7 @@ struct RenderTargetState_t static inline bool LessFunc( const RenderTargetState_t &lhs, const RenderTargetState_t &rhs ) { - COMPILE_TIME_ASSERT( sizeof( lhs.m_pRenderTargets[0] ) == sizeof( uint32 ) ); + COMPILE_TIME_ASSERT( sizeof( lhs.m_pRenderTargets[0] ) == sizeof( uintp ) ); uint64 lhs0 = reinterpret_cast(lhs.m_pRenderTargets)[0]; uint64 rhs0 = reinterpret_cast(rhs.m_pRenderTargets)[0]; if ( lhs0 < rhs0 ) diff --git a/public/togles/linuxwin/glmgr.h b/public/togles/linuxwin/glmgr.h index 3729911e..cd02464f 100644 --- a/public/togles/linuxwin/glmgr.h +++ b/public/togles/linuxwin/glmgr.h @@ -1838,11 +1838,11 @@ FORCEINLINE void GLMContext::DrawRangeElements( GLenum mode, GLuint start, GLuin if ( pIndexBuf->m_bPseudo ) { // you have to pass actual address, not offset - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_pPseudoBuf ); } if (pIndexBuf->m_bUsingPersistentBuffer) { - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_nPersistentBufferStartOffset ); } //#if GLMDEBUG diff --git a/tier0/cpu.cpp b/tier0/cpu.cpp index 9b0a9d6a..2018c8b0 100644 --- a/tier0/cpu.cpp +++ b/tier0/cpu.cpp @@ -22,7 +22,7 @@ const tchar* GetProcessorVendorId(); static bool cpuid(uint32 function, uint32& out_eax, uint32& out_ebx, uint32& out_ecx, uint32& out_edx) { -#if defined (__arm__) || defined (__arm64__) || defined( _X360 ) +#if defined (__arm__) || defined (__aarch64__) || defined( _X360 ) return false; #elif defined(GNUC) diff --git a/tier0/cpu_posix.cpp b/tier0/cpu_posix.cpp index 2b158947..d822883c 100644 --- a/tier0/cpu_posix.cpp +++ b/tier0/cpu_posix.cpp @@ -129,7 +129,7 @@ uint64 CalculateCPUFreq() } #endif -#if !defined(__arm__) && !defined(__arm64__) +#if !defined(__arm__) && !defined(__aarch64__) // Compute the period. Loop until we get 3 consecutive periods that // are the same to within a small error. The error is chosen // to be +/- 0.02% on a P-200. diff --git a/tier0/mem_impl_type.h b/tier0/mem_impl_type.h new file mode 100644 index 00000000..f01b6538 --- /dev/null +++ b/tier0/mem_impl_type.h @@ -0,0 +1,6 @@ + +#if ( (!defined( POSIX )||defined(_GAMECONSOLE)) && (defined(_DEBUG) || defined(USE_MEM_DEBUG) ) ) +#define MEM_IMPL_TYPE_DBG 1 +#else +#define MEM_IMPL_TYPE_STD 1 +#endif diff --git a/tier0/memdbg.cpp b/tier0/memdbg.cpp index 6b9379f0..e5304869 100644 --- a/tier0/memdbg.cpp +++ b/tier0/memdbg.cpp @@ -1836,7 +1836,7 @@ static inline void unprotect_malloc_zone( malloc_zone_t *malloc_zone ) // The version check may not be necessary, but we know it was RW before that. if ( malloc_zone->version >= 8 ) { -#ifdef __arm64__ +#ifdef __aarch64__ // MoeMod : this is required for Apple Silicon pthread_jit_write_protect_np(false); #endif @@ -1849,7 +1849,7 @@ static inline void protect_malloc_zone( malloc_zone_t *malloc_zone ) if ( malloc_zone->version >= 8 ) { vm_protect( mach_task_self(), (uintptr_t)malloc_zone, sizeof( malloc_zone_t ), 0, VM_PROT_READ ); -#ifdef __arm64__ +#ifdef __aarch64__ // MoeMod : this is required for Apple Silicon pthread_jit_write_protect_np(true); #endif diff --git a/tier0/threadtools.cpp b/tier0/threadtools.cpp index 2d00d706..01217e49 100644 --- a/tier0/threadtools.cpp +++ b/tier0/threadtools.cpp @@ -6,29 +6,19 @@ #include "tier0/platform.h" -#if defined( PLATFORM_WINDOWS_PC ) +#if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #define _WIN32_WINNT 0x0403 #include #endif -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 #include - #ifdef PLATFORM_WINDOWS_PC + #ifdef _WIN32 #include #pragma comment(lib, "winmm.lib") #endif -#elif PLATFORM_PS3 - #include - #include - #include - #include - #include - #include - #include - #define GetLastError() errno - typedef void *LPVOID; -#elif PLATFORM_POSIX +#elif POSIX #include #include #include @@ -38,8 +28,13 @@ #define GetLastError() errno typedef void *LPVOID; #if !defined(OSX) - #include - #include +#if defined(ANDROID) + #include + #include +#else + #include + #include +#endif #define sem_unlink( arg ) #define OS_TO_PTHREAD(x) (x) #else @@ -155,7 +150,7 @@ struct ThreadProcInfo_t //--------------------------------------------------------- -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 static DWORD WINAPI ThreadProcConvert( void *pParam ) { ThreadProcInfo_t info = *((ThreadProcInfo_t *)pParam); @@ -165,7 +160,7 @@ static DWORD WINAPI ThreadProcConvert( void *pParam ) FreeThreadID(); return nRet; } -#elif defined( PLATFORM_PS3 ) +#elif defined( PS3 ) union ThreadProcInfoUnion_t { struct Val_t @@ -262,7 +257,7 @@ void TlsSetValue( uint32 index, void *pValue ) -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 class CThreadHandleToIDMap { public: @@ -421,12 +416,12 @@ void JoinTestThreads( ThreadHandle_t *pHandles ) ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigned stackSize ) { -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 DWORD threadID; HANDLE hThread = (HANDLE)CreateThread( NULL, stackSize, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), stackSize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0, &threadID ); AddThreadHandleToIDMap( hThread, threadID ); return (ThreadHandle_t)hThread; -#elif PLATFORM_PS3 +#elif PS3 //TestThreads(); ThreadHandle_t th; ThreadProcInfoUnion_t info; @@ -439,7 +434,7 @@ ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigne return 0; } return th; -#elif PLATFORM_POSIX +#elif POSIX pthread_t tid; pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) ); return ( ThreadHandle_t ) tid; @@ -452,14 +447,14 @@ ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, unsigne ThreadHandle_t CreateSimpleThread( ThreadFunc_t pfnThread, void *pParam, ThreadId_t *pID, unsigned stackSize ) { -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 DWORD threadID; HANDLE hThread = (HANDLE)CreateThread( NULL, stackSize, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ), stackSize ? STACK_SIZE_PARAM_IS_A_RESERVATION : 0, &threadID ); if( pID ) *pID = (ThreadId_t)threadID; AddThreadHandleToIDMap( hThread, threadID ); return (ThreadHandle_t)hThread; -#elif PLATFORM_POSIX +#elif POSIX pthread_t tid; pthread_create( &tid, NULL, ThreadProcConvert, new ThreadProcInfo_t( pfnThread, pParam ) ); if( pID ) @@ -494,7 +489,7 @@ void ThreadSleep(unsigned nMilliseconds) { #ifdef _WIN32 -#ifdef PLATFORM_WINDOWS_PC +#ifdef _WIN32_PC static bool bInitialized = false; if ( !bInitialized ) { @@ -508,7 +503,7 @@ void ThreadSleep(unsigned nMilliseconds) #endif Sleep( nMilliseconds ); -#elif PLATFORM_PS3 +#elif PS3 if( nMilliseconds == 0 ) { // sys_ppu_thread_yield doesn't seem to function properly, so sleep instead. @@ -530,7 +525,7 @@ void ThreadNanoSleep(unsigned ns) #ifdef _WIN32 // ceil Sleep( ( ns + 999 ) / 1000 ); -#elif PLATFORM_PS3 +#elif PS3 sys_timer_usleep( ns ); #elif defined(POSIX) struct timespec tm; @@ -814,7 +809,7 @@ sys_lwmutex_t CThreadSyncObject::m_staticMutex; CThreadSyncObject::CThreadSyncObject() #ifdef _WIN32 : m_hSyncObject( NULL ), m_bCreatedHandle(false) -#elif defined(POSIX) && !defined(PLATFORM_PS3) +#elif defined(POSIX) && !defined(PS3) : m_bInitalized( false ) #endif { @@ -857,7 +852,7 @@ CThreadSyncObject::~CThreadSyncObject() Assert( 0 ); } } -#elif defined(POSIX) && !defined( PLATFORM_PS3 ) +#elif defined(POSIX) && !defined( PS3 ) if ( m_bInitalized ) { pthread_cond_destroy( &m_Condition ); @@ -871,7 +866,7 @@ CThreadSyncObject::~CThreadSyncObject() bool CThreadSyncObject::operator!() const { -#if PLATFORM_PS3 +#if PS3 return m_bstaticMutexInitialized; #elif defined( _WIN32 ) return !m_hSyncObject; @@ -885,7 +880,7 @@ bool CThreadSyncObject::operator!() const void CThreadSyncObject::AssertUseable() { #ifdef THREADS_DEBUG -#if PLATFORM_PS3 +#if PS3 AssertMsg( m_bstaticMutexInitialized, "Thread synchronization object is unuseable" ); #elif defined( _WIN32 ) AssertMsg( m_hSyncObject, "Thread synchronization object is unuseable" ); @@ -905,7 +900,7 @@ bool CThreadSyncObject::Wait( uint32 dwTimeout ) #endif #ifdef _WIN32 return ( WaitForSingleObject( m_hSyncObject, dwTimeout ) == WAIT_OBJECT_0 ); -#elif defined( POSIX ) && !defined( PLATFORM_PS3 ) +#elif defined( POSIX ) && !defined( PS3 ) pthread_mutex_lock( &m_Mutex ); bool bRet = false; if ( m_cSet > 0 ) @@ -1263,7 +1258,7 @@ void CThreadEvent::UnregisterWaitingThread(sys_semaphore_t *pSemaphore) #endif // _PS3 -#ifdef PLATFORM_WINDOWS +#ifdef _WIN32 CThreadEvent::CThreadEvent( const char *name, bool initialState, bool bManualReset ) { m_hSyncObject = CreateEvent( NULL, bManualReset, (BOOL) initialState, name ); diff --git a/tier1/processor_detect_linux.cpp b/tier1/processor_detect_linux.cpp index 8887926e..64d771a2 100644 --- a/tier1/processor_detect_linux.cpp +++ b/tier1/processor_detect_linux.cpp @@ -13,7 +13,7 @@ bool CheckMMXTechnology(void) { return false; } bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } bool Check3DNowTechnology(void) { return false; } -#elif defined (__arm__) || defined (__arm64__) +#elif defined (__arm__) || defined (__aarch64__) bool CheckMMXTechnology(void) { return false; } bool CheckSSETechnology(void) { return false; } bool CheckSSE2Technology(void) { return false; } diff --git a/tier1/reliabletimer.cpp b/tier1/reliabletimer.cpp index 73556e90..f575a679 100644 --- a/tier1/reliabletimer.cpp +++ b/tier1/reliabletimer.cpp @@ -87,7 +87,7 @@ int64 CReliableTimer::GetPerformanceCountNow() uint64 ulNow; SYS_TIMEBASE_GET( ulNow ); return ulNow; -#elif (defined( __arm__ ) || defined( __arm64__ )) && defined (POSIX) +#elif (defined( __arm__ ) || defined( __aarch64__ )) && defined (POSIX) struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return ts.tv_sec * 1000000000ULL + ts.tv_nsec; diff --git a/tier1/strtools.cpp b/tier1/strtools.cpp index af4fa688..af81b059 100644 --- a/tier1/strtools.cpp +++ b/tier1/strtools.cpp @@ -47,7 +47,6 @@ #include #ifdef POSIX -#include #include #include #include @@ -79,7 +78,12 @@ #include "xbox/xbox_win32stubs.h" #endif #include "tier0/memdbgon.h" -#include "iconv.h" + +#ifdef ANDROID +#include "common/iconv.h" +#elif POSIX +#include +#endif static int FastToLower( char c ) { diff --git a/tier1/wscript b/tier1/wscript index 80a32f69..903fb5da 100755 --- a/tier1/wscript +++ b/tier1/wscript @@ -66,6 +66,7 @@ def build(bld): includes = [ '.', + '../', '../public', '../public/tier1', '../public/tier0', diff --git a/togles/linuxwin/glmgr.cpp b/togles/linuxwin/glmgr.cpp index 01a2bf72..8271b236 100644 --- a/togles/linuxwin/glmgr.cpp +++ b/togles/linuxwin/glmgr.cpp @@ -667,7 +667,7 @@ void GLMContext::DumpCaps( void ) #define dumpfield_hex( fff ) printf( "\n %-30s : 0x%08x", #fff, (int) m_caps.fff ) #define dumpfield_str( fff ) printf( "\n %-30s : %s", #fff, m_caps.fff ) - printf("\n-------------------------------- context caps for context %08x", (uint)this); + printf("\n-------------------------------- context caps for context %zx", (size_t)this); dumpfield( m_fullscreen ); dumpfield( m_accelerated ); @@ -4925,11 +4925,11 @@ void GLMContext::DrawRangeElementsNonInline( GLenum mode, GLuint start, GLuint e if ( pIndexBuf->m_bPseudo ) { // you have to pass actual address, not offset - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_pPseudoBuf ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_pPseudoBuf ); } if (pIndexBuf->m_bUsingPersistentBuffer) { - indicesActual = (void*)( (int)indicesActual + (int)pIndexBuf->m_nPersistentBufferStartOffset ); + indicesActual = (void*)( (intp)indicesActual + (intp)pIndexBuf->m_nPersistentBufferStartOffset ); } #if GL_ENABLE_INDEX_VERIFICATION diff --git a/togles/linuxwin/glmgr_flush.inl b/togles/linuxwin/glmgr_flush.inl index be98692f..126d08b1 100644 --- a/togles/linuxwin/glmgr_flush.inl +++ b/togles/linuxwin/glmgr_flush.inl @@ -573,7 +573,7 @@ FORCEINLINE void GLMContext::FlushDrawStates( uint nStartIndex, uint nEndIndex, SetBufAndVertexAttribPointer( nIndex, pBuf->GetHandle(), pStream->m_stride, pDeclElem->m_gldecl.m_datatype, pDeclElem->m_gldecl.m_normalized, pDeclElem->m_gldecl.m_nCompCount, - reinterpret_cast< const GLvoid * >( reinterpret_cast< int >( pBuf->m_pPseudoBuf ) + nBufOffset ), + reinterpret_cast< const GLvoid * >( reinterpret_cast< intp >( pBuf->m_pPseudoBuf ) + nBufOffset ), pBuf->m_nRevision ); if ( !( m_lastKnownVertexAttribMask & nMask ) ) diff --git a/vphysics/vphysics_saverestore.cpp b/vphysics/vphysics_saverestore.cpp index dc4b8434..34fb585b 100644 --- a/vphysics/vphysics_saverestore.cpp +++ b/vphysics/vphysics_saverestore.cpp @@ -131,7 +131,7 @@ void CPhysicsEnvironment::PostRestore() void CVPhysPtrSaveRestoreOps::Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave ) { - void *pField = (void *)fieldInfo.pField; + char *pField = (char *)fieldInfo.pField; int nObjects = fieldInfo.pTypeDesc->fieldSize; for ( int i = 0; i < nObjects; i++ ) {