aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/shared/general/ConvexDecomposition
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/general/ConvexDecomposition
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/shared/general/ConvexDecomposition')
-rw-r--r--APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/TestConvexDecomposition.cpp351
-rw-r--r--APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.cpp854
-rw-r--r--APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.h53
-rw-r--r--APEX_1.4/shared/general/ConvexDecomposition/include/ConvexDecomposition.h145
-rw-r--r--APEX_1.4/shared/general/ConvexDecomposition/include/SplitMesh.h99
-rw-r--r--APEX_1.4/shared/general/ConvexDecomposition/src/ConvexDecomposition.cpp1507
-rw-r--r--APEX_1.4/shared/general/ConvexDecomposition/src/SplitMesh.cpp190
7 files changed, 3199 insertions, 0 deletions
diff --git a/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/TestConvexDecomposition.cpp b/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/TestConvexDecomposition.cpp
new file mode 100644
index 00000000..3eae80b9
--- /dev/null
+++ b/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/TestConvexDecomposition.cpp
@@ -0,0 +1,351 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <math.h>
+#include <conio.h>
+
+#pragma warning(disable:4996 4100)
+
+#include "ConvexDecomposition.h"
+#include "wavefront.h"
+#include "PxAllocatorCallback.h"
+#include "PxErrorCallback.h"
+#include "PsShare.h"
+#include "PxFoundation.h"
+#include "PsFoundation.h"
+
+namespace CONVEX_DECOMPOSITION
+{
+ ConvexDecomposition *gConvexDecomposition = NULL;
+};
+
+float getFloatArg(int arg,int argc,const char **argv)
+{
+ float ret = 0;
+ if ( arg < argc )
+ {
+ ret = (float)atof(argv[arg]);
+ }
+ else
+ {
+ printf("Error: Missing input argument value at argument location %d.\r\n",arg+1);
+ }
+ return ret;
+}
+
+int getIntArg(int arg,int argc,const char **argv)
+{
+ int ret = 0;
+ if ( arg < argc )
+ {
+ ret = atoi(argv[arg]);
+ }
+ else
+ {
+ printf("Error: Missing input argument value at argument location %d.\r\n",arg+1);
+ }
+ return ret;
+}
+
+class AppUserAllocator : public physx::PxAllocatorCallback
+{
+public:
+
+ virtual void* allocate(size_t size, const char * , const char* , int )
+ {
+#ifdef PX_WINDOWS
+ return ::_aligned_malloc(size, 16);
+#else
+ return ::malloc(size);
+#endif
+ }
+
+ // this method needs to be removed
+ virtual void* allocate(size_t size, physx::PxU32 , const char* , int )
+ {
+#ifdef PX_WINDOWS
+ return ::_aligned_malloc(size, 16);
+#else
+ return ::malloc(size);
+#endif
+ }
+
+ virtual void deallocate(void* ptr)
+ {
+#ifdef PX_WINDOWS
+ ::_aligned_free(ptr);
+#else
+ ::free(ptr);
+#endif
+ }
+
+};
+
+class AppUserOutputStream : public physx::PxErrorCallback
+{
+public:
+ virtual void reportError(physx::PxErrorCode::Enum code, const char* message, const char* file, int line)
+ {
+
+ }
+
+};
+
+
+static AppUserAllocator appAlloc;
+static AppUserOutputStream appOutputStream;
+
+void main(int argc,const char ** argv)
+{
+ PX_UNUSED(argc);
+ PX_UNUSED(argv);
+
+ physx::Foundation::createInstance(PX_PUBLIC_FOUNDATION_VERSION, appOutputStream, appAlloc);
+
+
+ if ( argc == 1 )
+ {
+ printf("Usage: TestConvexDecomposition <wavefront.obj> (options)\r\n");
+ printf("\r\n");
+ printf("Options:\r\n");
+ printf("\r\n");
+ printf("-split : Tests mesh splitting.\r\n");
+ printf("-plane A B C D : Specifies the plane equation to split the mesh by, if testing split only.\r\n");
+ printf("-closed : Indicates that the mesh should be closed when it is split. Off by default; experimental.\r\n");
+ printf("-depth <value> : Specify the convex decomposition depth.\r\n");
+ printf("-merge <value> : Specify the merge threshold percentage. Reasonable ranges 0-10.\r\n");
+ printf("-concavity <value> : Specify the concavity threshold as a percentage reasonable ranges 0-10.\r\n");
+ printf("-hacd <concavity> <minCluster> : Use HACD (recommended). Specify the concavity value for HACD (default 100) and the mininum number of clusters (hulls)\r\n");
+ printf("-connect : Is using HACD; this specifies the connectivity distance.\r\n");
+ printf("-maxhullverts <v> : Specify the maxmium number of vertices in the output convex hulls.\r\n");
+ }
+ else
+ {
+ const char *wavefront = argv[1];
+
+ bool splitOnly = false;
+ bool closed = false;
+ bool useHACD = false;
+ physx::PxF32 hacdConcavity = 100;
+ physx::PxU32 hacdMinClusterSize = 10;
+ physx::PxF32 connectionDistance = 0;
+
+ physx::PxF32 plane[4] = { 1, 0, 0, 0 };
+ physx::PxU32 depth = 5;
+ physx::PxF32 mergePercentage = 3; //1;
+ physx::PxF32 concavityPercentage = 3; //;
+ physx::PxU32 maxHullVerts = 64;
+
+ int scan = 2;
+ while ( scan < argc )
+ {
+ const char *option = argv[scan];
+ if ( strcmp(option,"-split") == 0 )
+ {
+ splitOnly = true;
+ printf("Testing a single split operation.\r\n");
+ scan++;
+ }
+ else if ( strcmp(option,"-plane") == 0 )
+ {
+ plane[0] = getFloatArg(scan+1,argc,argv);
+ plane[1] = getFloatArg(scan+2,argc,argv);
+ plane[2] = getFloatArg(scan+3,argc,argv);
+ plane[3] = getFloatArg(scan+4,argc,argv);
+ scan+=5;
+ }
+ else if ( strcmp(option,"-closed") == 0 )
+ {
+ closed = true;
+ printf("Will produce closed split meshes.\r\n");
+ scan++;
+ }
+ else if ( strcmp(option,"-depth") == 0 )
+ {
+ depth = getIntArg(scan+1,argc,argv);
+ scan+=2;
+ }
+ else if ( strcmp(option,"-connect") == 0 )
+ {
+ connectionDistance = getFloatArg(scan+1,argc,argv);
+ scan+=2;
+ }
+ else if ( strcmp(option,"-merge") == 0 )
+ {
+ mergePercentage = getFloatArg(scan+1,argc,argv);
+ scan+=2;
+ }
+ else if ( strcmp(option,"-concavity") == 0 )
+ {
+ concavityPercentage = getFloatArg(scan+1,argc,argv);
+ scan+=2;
+ }
+ else if ( strcmp(option,"-maxhullverts") == 0 )
+ {
+ maxHullVerts = getIntArg(scan+1,argc,argv);
+ scan+=2;
+ }
+ else if ( strcmp(option,"-hacd")== 0)
+ {
+ useHACD = true;
+ hacdConcavity = getFloatArg(scan+1,argc,argv);
+ hacdMinClusterSize = getIntArg(scan+2,argc,argv);
+ scan+=3;
+ }
+ else
+ {
+ printf("Unknown option: %s\r\n", option );
+ scan++;
+ }
+
+ }
+
+ CONVEX_DECOMPOSITION::gConvexDecomposition = CONVEX_DECOMPOSITION::createConvexDecomposition();
+ if ( CONVEX_DECOMPOSITION::gConvexDecomposition )
+ {
+ WavefrontObj obj;
+ unsigned int tcount = obj.loadObj(wavefront,false);
+ if ( tcount )
+ {
+ if ( splitOnly )
+ {
+ CONVEX_DECOMPOSITION::TriangleMesh input;
+ CONVEX_DECOMPOSITION::TriangleMesh left;
+ CONVEX_DECOMPOSITION::TriangleMesh right;
+ input.mVcount = obj.mVertexCount;
+ input.mVertices = obj.mVertices;
+ input.mTriCount = obj.mTriCount;
+ input.mIndices = (physx::PxU32 *)obj.mIndices;
+ CONVEX_DECOMPOSITION::gConvexDecomposition->splitMesh(plane,input,left,right,closed);
+
+ if ( left.mTriCount )
+ {
+ printf("Left Half of the split mesh has %d triangles. Saving as 'left.obj'\r\n", left.mTriCount);
+ WavefrontObj::saveObj("left.obj", left.mVcount, left.mVertices, left.mTriCount,(const int *) left.mIndices );
+ }
+ else
+ {
+ printf("No triangles on the left half of the split mesh.\r\n");
+ }
+ if ( right.mTriCount )
+ {
+ printf("Left Half of the split mesh has %d triangles. Saving as 'right.obj'\r\n", right.mTriCount);
+ WavefrontObj::saveObj("right.obj", right.mVcount, right.mVertices, right.mTriCount, (const int *)right.mIndices );
+ }
+ else
+ {
+ printf("No triangles on the right half of the split mesh.\r\n");
+ }
+
+ CONVEX_DECOMPOSITION::gConvexDecomposition->releaseTriangleMeshMemory(left);
+ CONVEX_DECOMPOSITION::gConvexDecomposition->releaseTriangleMeshMemory(right);
+ }
+ else
+ {
+ CONVEX_DECOMPOSITION::DecompDesc desc;
+ desc.mClosedSplit = closed;
+ desc.mDepth = depth;
+ desc.mCpercent = concavityPercentage;
+ desc.mPpercent = mergePercentage;
+ desc.mTcount = obj.mTriCount;
+ desc.mVcount = obj.mVertexCount;
+ desc.mVertices = obj.mVertices;
+ desc.mIndices = (physx::PxU32 *)obj.mIndices;
+ desc.mUseHACD = useHACD;
+ desc.mConcavityHACD = hacdConcavity;
+ desc.mMinClusterSizeHACD = hacdMinClusterSize;
+ desc.mConnectionDistanceHACD = connectionDistance;
+
+
+ printf("Performing convex decomposition.\r\n");
+
+ physx::PxU32 count = CONVEX_DECOMPOSITION::gConvexDecomposition->performConvexDecomposition(desc);
+ if ( count )
+ {
+ printf("Produced %d output convex hulls.\r\n", count );
+ FILE *fph = fopen("ConvexDecomposition.obj", "wb");
+ if ( fph )
+ {
+ fprintf(fph,"# Input mesh '%s' produced %d convex hulls.\r\n", wavefront, count );
+ physx::PxU32 *baseVertex = new physx::PxU32[count];
+ physx::PxU32 vertexCount = 0;
+ for (physx::PxU32 i=0; i<count; i++)
+ {
+ baseVertex[i] = vertexCount;
+ const CONVEX_DECOMPOSITION::ConvexResult &r = *CONVEX_DECOMPOSITION::gConvexDecomposition->getConvexResult(i);
+ fprintf(fph,"## Hull %d has %d vertices.\r\n", i+1, r.mHullVcount );
+ for (physx::PxU32 i=0; i<r.mHullVcount; i++)
+ {
+ const physx::PxF32 *p = &r.mHullVertices[i*3];
+ fprintf(fph,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] );
+ }
+ vertexCount+=r.mHullVcount;
+ }
+
+ for (physx::PxU32 i=0; i<count; i++)
+ {
+ const CONVEX_DECOMPOSITION::ConvexResult &r = *CONVEX_DECOMPOSITION::gConvexDecomposition->getConvexResult(i);
+ physx::PxU32 startVertex = baseVertex[i];
+ fprintf(fph,"# Convex Hull %d contains %d triangles and %d vertices. Starting vertex index is: %d It has a volume of: %0.9f\r\n", i+1, r.mHullTcount, r.mHullVcount, startVertex, r.mHullVolume );
+ for (physx::PxU32 j=0; j<r.mHullTcount; j++)
+ {
+ physx::PxU32 i1 = r.mHullIndices[j*3+0]+startVertex+1;
+ physx::PxU32 i2 = r.mHullIndices[j*3+1]+startVertex+1;
+ physx::PxU32 i3 = r.mHullIndices[j*3+2]+startVertex+1;
+ fprintf(fph,"f %d %d %d\r\n", i1, i2, i3 );
+ }
+ }
+ fclose(fph);
+ delete []baseVertex;
+ }
+ else
+ {
+ printf("Failed to open file 'ConvexDecomposition.obj' for output.\r\n");
+ }
+ }
+ else
+ {
+ printf("Failed to produce any convex hull results!?\r\n");
+ }
+
+ }
+ }
+ else
+ {
+ printf("Failed to load Wavefront OBJ file '%s'\r\n",wavefront);
+ }
+ }
+ else
+ {
+ printf("Failed to load the convex decomposition plugin DLL.\r\n");
+ }
+ }
+}
diff --git a/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.cpp b/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.cpp
new file mode 100644
index 00000000..a6498fa3
--- /dev/null
+++ b/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.cpp
@@ -0,0 +1,854 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+#ifndef __PPCGEKKO__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <vector>
+
+#include "wavefront.h"
+
+#ifdef _WIN32
+# define strcasecmp _stricmp
+#endif
+
+typedef std::vector< int > IntVector;
+typedef std::vector< float > FloatVector;
+
+#pragma warning(disable:4996)
+
+namespace WAVEFRONT
+{
+
+/*******************************************************************/
+/******************** InParser.h ********************************/
+/*******************************************************************/
+class InPlaceParserInterface
+{
+public:
+ virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process
+};
+
+enum SeparatorType
+{
+ ST_DATA, // is data
+ ST_HARD, // is a hard separator
+ ST_SOFT, // is a soft separator
+ ST_EOS // is a comment symbol, and everything past this character should be ignored
+};
+
+class InPlaceParser
+{
+public:
+ InPlaceParser(void)
+ {
+ Init();
+ }
+
+ InPlaceParser(char *data,int len)
+ {
+ Init();
+ SetSourceData(data,len);
+ }
+
+ InPlaceParser(const char *fname)
+ {
+ Init();
+ SetFile(fname);
+ }
+
+ ~InPlaceParser(void);
+
+ void Init(void)
+ {
+ mQuoteChar = 34;
+ mData = 0;
+ mLen = 0;
+ mMyAlloc = false;
+ for (int i=0; i<256; i++)
+ {
+ mHard[i] = ST_DATA;
+ mHardString[i*2] = (char)i;
+ mHardString[i*2+1] = 0;
+ }
+ mHard[0] = ST_EOS;
+ mHard[32] = ST_SOFT;
+ mHard[9] = ST_SOFT;
+ mHard[13] = ST_SOFT;
+ mHard[10] = ST_SOFT;
+ }
+
+ void SetFile(const char *fname); // use this file as source data to parse.
+
+ void SetSourceData(char *data,int len)
+ {
+ mData = data;
+ mLen = len;
+ mMyAlloc = false;
+ };
+
+ int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
+
+ int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback);
+
+ const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse.
+
+ void SetHardSeparator(char c) // add a hard separator
+ {
+ mHard[c] = ST_HARD;
+ }
+
+ void SetHard(char c) // add a hard separator
+ {
+ mHard[c] = ST_HARD;
+ }
+
+
+ void SetCommentSymbol(char c) // comment character, treated as 'end of string'
+ {
+ mHard[c] = ST_EOS;
+ }
+
+ void ClearHardSeparator(char c)
+ {
+ mHard[c] = ST_DATA;
+ }
+
+
+ void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character.
+
+ bool EOS(char c)
+ {
+ if ( mHard[c] == ST_EOS )
+ {
+ return true;
+ }
+ return false;
+ }
+
+ void SetQuoteChar(char c)
+ {
+ mQuoteChar = c;
+ }
+
+private:
+
+
+ inline char * AddHard(int &argc,const char **argv,char *foo);
+ inline bool IsHard(char c);
+ inline char * SkipSpaces(char *foo);
+ inline bool IsWhiteSpace(char c);
+ inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft
+
+ bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it.
+ char *mData; // ascii data to parse.
+ int mLen; // length of data
+ SeparatorType mHard[256];
+ char mHardString[256*2];
+ char mQuoteChar;
+};
+
+/*******************************************************************/
+/******************** InParser.cpp ********************************/
+/*******************************************************************/
+void InPlaceParser::SetFile(const char *fname)
+{
+ if ( mMyAlloc )
+ {
+ free(mData);
+ }
+ mData = 0;
+ mLen = 0;
+ mMyAlloc = false;
+
+ FILE *fph = fopen(fname,"rb");
+ if ( fph )
+ {
+ fseek(fph,0L,SEEK_END);
+ mLen = ftell(fph);
+ fseek(fph,0L,SEEK_SET);
+ if ( mLen )
+ {
+ mData = (char *) malloc(sizeof(char)*(mLen+1));
+ size_t ok = fread(mData, mLen, 1, fph);
+ if ( !ok )
+ {
+ free(mData);
+ mData = 0;
+ }
+ else
+ {
+ mData[mLen] = 0; // zero byte terminate end of file marker.
+ mMyAlloc = true;
+ }
+ }
+ fclose(fph);
+ }
+
+}
+
+InPlaceParser::~InPlaceParser(void)
+{
+ if ( mMyAlloc )
+ {
+ free(mData);
+ }
+}
+
+#define MAXARGS 512
+
+bool InPlaceParser::IsHard(char c)
+{
+ return mHard[c] == ST_HARD;
+}
+
+char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo)
+{
+ while ( IsHard(*foo) )
+ {
+ const char *hard = &mHardString[*foo*2];
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = hard;
+ }
+ foo++;
+ }
+ return foo;
+}
+
+bool InPlaceParser::IsWhiteSpace(char c)
+{
+ return mHard[c] == ST_SOFT;
+}
+
+char * InPlaceParser::SkipSpaces(char *foo)
+{
+ while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++;
+ return foo;
+}
+
+bool InPlaceParser::IsNonSeparator(char c)
+{
+ if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true;
+ return false;
+}
+
+
+int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback)
+{
+ int ret = 0;
+
+ const char *argv[MAXARGS];
+ int argc = 0;
+
+ char *foo = line;
+
+ while ( !EOS(*foo) && argc < MAXARGS )
+ {
+
+ foo = SkipSpaces(foo); // skip any leading spaces
+
+ if ( EOS(*foo) ) break;
+
+ if ( *foo == mQuoteChar ) // if it is an open quote
+ {
+ foo++;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+ while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
+ if ( !EOS(*foo) )
+ {
+ *foo = 0; // replace close quote with zero byte EOS
+ foo++;
+ }
+ }
+ else
+ {
+
+ foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
+
+ if ( IsNonSeparator(*foo) ) // add non-hard argument.
+ {
+ bool quote = false;
+ if ( *foo == mQuoteChar )
+ {
+ foo++;
+ quote = true;
+ }
+
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+
+ if ( quote )
+ {
+ while (*foo && *foo != mQuoteChar ) foo++;
+ if ( *foo ) *foo = 32;
+ }
+
+ // continue..until we hit an eos ..
+ while ( !EOS(*foo) ) // until we hit EOS
+ {
+ if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
+ {
+ *foo = 0;
+ foo++;
+ break;
+ }
+ else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
+ {
+ const char *hard = &mHardString[*foo*2];
+ *foo = 0;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = hard;
+ }
+ foo++;
+ break;
+ }
+ foo++;
+ } // end of while loop...
+ }
+ }
+ }
+
+ if ( argc )
+ {
+ ret = callback->ParseLine(lineno, argc, argv );
+ }
+
+ return ret;
+}
+
+int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
+{
+ assert( callback );
+ if ( !mData ) return 0;
+
+ int ret = 0;
+
+ int lineno = 0;
+
+ char *foo = mData;
+ char *begin = foo;
+
+
+ while ( *foo )
+ {
+ if ( *foo == 10 || *foo == 13 )
+ {
+ lineno++;
+ *foo = 0;
+
+ if ( *begin ) // if there is any data to parse at all...
+ {
+ int v = ProcessLine(lineno,begin,callback);
+ if ( v ) ret = v;
+ }
+
+ foo++;
+ if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format...
+ begin = foo;
+ }
+ else
+ {
+ foo++;
+ }
+ }
+
+ lineno++; // lasst line.
+
+ int v = ProcessLine(lineno,begin,callback);
+ if ( v ) ret = v;
+ return ret;
+}
+
+
+void InPlaceParser::DefaultSymbols(void)
+{
+ SetHardSeparator(',');
+ SetHardSeparator('(');
+ SetHardSeparator(')');
+ SetHardSeparator('=');
+ SetHardSeparator('[');
+ SetHardSeparator(']');
+ SetHardSeparator('{');
+ SetHardSeparator('}');
+ SetCommentSymbol('#');
+}
+
+
+const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse.
+{
+ const char **ret = 0;
+
+ static const char *argv[MAXARGS];
+ int argc = 0;
+
+ char *foo = line;
+
+ while ( !EOS(*foo) && argc < MAXARGS )
+ {
+
+ foo = SkipSpaces(foo); // skip any leading spaces
+
+ if ( EOS(*foo) ) break;
+
+ if ( *foo == mQuoteChar ) // if it is an open quote
+ {
+ foo++;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+ while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
+ if ( !EOS(*foo) )
+ {
+ *foo = 0; // replace close quote with zero byte EOS
+ foo++;
+ }
+ }
+ else
+ {
+
+ foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
+
+ if ( IsNonSeparator(*foo) ) // add non-hard argument.
+ {
+ bool quote = false;
+ if ( *foo == mQuoteChar )
+ {
+ foo++;
+ quote = true;
+ }
+
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = foo;
+ }
+
+ if ( quote )
+ {
+ while (*foo && *foo != mQuoteChar ) foo++;
+ if ( *foo ) *foo = 32;
+ }
+
+ // continue..until we hit an eos ..
+ while ( !EOS(*foo) ) // until we hit EOS
+ {
+ if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
+ {
+ *foo = 0;
+ foo++;
+ break;
+ }
+ else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
+ {
+ const char *hard = &mHardString[*foo*2];
+ *foo = 0;
+ if ( argc < MAXARGS )
+ {
+ argv[argc++] = hard;
+ }
+ foo++;
+ break;
+ }
+ foo++;
+ } // end of while loop...
+ }
+ }
+ }
+
+ count = argc;
+ if ( argc )
+ {
+ ret = argv;
+ }
+
+ return ret;
+}
+
+/*******************************************************************/
+/******************** Geometry.h ********************************/
+/*******************************************************************/
+
+class GeometryVertex
+{
+public:
+ float mPos[3];
+ float mNormal[3];
+ float mTexel[2];
+};
+
+
+class GeometryInterface
+{
+public:
+
+ virtual void NodeTriangle(const GeometryVertex * /*v1*/,const GeometryVertex * /*v2*/,const GeometryVertex * /*v3*/, bool /*textured*/)
+ {
+ }
+
+};
+
+
+/*******************************************************************/
+/******************** Obj.h ********************************/
+/*******************************************************************/
+
+
+class OBJ : public InPlaceParserInterface
+{
+public:
+ int LoadMesh(const char *fname,GeometryInterface *callback, bool textured);
+ int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process
+private:
+
+ void GetVertex(GeometryVertex &v,const char *face) const;
+
+ FloatVector mVerts;
+ FloatVector mTexels;
+ FloatVector mNormals;
+
+ bool mTextured;
+
+ GeometryInterface *mCallback;
+};
+
+
+/*******************************************************************/
+/******************** Obj.cpp ********************************/
+/*******************************************************************/
+
+int OBJ::LoadMesh(const char *fname,GeometryInterface *iface, bool textured)
+{
+ mTextured = textured;
+ int ret = 0;
+
+ mVerts.clear();
+ mTexels.clear();
+ mNormals.clear();
+
+ mCallback = iface;
+
+ InPlaceParser ipp(fname);
+
+ ipp.Parse(this);
+
+return ret;
+}
+
+/***
+static const char * GetArg(const char **argv,int i,int argc)
+{
+ const char * ret = 0;
+ if ( i < argc ) ret = argv[i];
+ return ret;
+}
+****/
+
+void OBJ::GetVertex(GeometryVertex &v,const char *face) const
+{
+ v.mPos[0] = 0;
+ v.mPos[1] = 0;
+ v.mPos[2] = 0;
+
+ v.mTexel[0] = 0;
+ v.mTexel[1] = 0;
+
+ v.mNormal[0] = 0;
+ v.mNormal[1] = 1;
+ v.mNormal[2] = 0;
+
+ int index = atoi( face )-1;
+
+ const char *texel = strstr(face,"/");
+
+ if ( texel )
+ {
+ int tindex = atoi( texel+1) - 1;
+
+ if ( tindex >=0 && tindex < (int)(mTexels.size()/2) )
+ {
+ const float *t = &mTexels[tindex*2];
+
+ v.mTexel[0] = t[0];
+ v.mTexel[1] = t[1];
+
+ }
+
+ const char *normal = strstr(texel+1,"/");
+ if ( normal )
+ {
+ int nindex = atoi( normal+1 ) - 1;
+
+ if (nindex >= 0 && nindex < (int)(mNormals.size()/3) )
+ {
+ const float *n = &mNormals[nindex*3];
+
+ v.mNormal[0] = n[0];
+ v.mNormal[1] = n[1];
+ v.mNormal[2] = n[2];
+ }
+ }
+ }
+
+ if ( index >= 0 && index < (int)(mVerts.size()/3) )
+ {
+
+ const float *p = &mVerts[index*3];
+
+ v.mPos[0] = p[0];
+ v.mPos[1] = p[1];
+ v.mPos[2] = p[2];
+ }
+
+}
+
+int OBJ::ParseLine(int /*lineno*/,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
+{
+ int ret = 0;
+
+ if ( argc >= 1 )
+ {
+ const char *foo = argv[0];
+ if ( *foo != '#' )
+ {
+ if ( strcasecmp(argv[0],"v") == 0 && argc == 4 )
+ {
+ float vx = (float) atof( argv[1] );
+ float vy = (float) atof( argv[2] );
+ float vz = (float) atof( argv[3] );
+ mVerts.push_back(vx);
+ mVerts.push_back(vy);
+ mVerts.push_back(vz);
+ }
+ else if ( strcasecmp(argv[0],"vt") == 0 && (argc == 3 || argc == 4))
+ {
+ // ignore 4rd component if present
+ float tx = (float) atof( argv[1] );
+ float ty = (float) atof( argv[2] );
+ mTexels.push_back(tx);
+ mTexels.push_back(ty);
+ }
+ else if ( strcasecmp(argv[0],"vn") == 0 && argc == 4 )
+ {
+ float normalx = (float) atof(argv[1]);
+ float normaly = (float) atof(argv[2]);
+ float normalz = (float) atof(argv[3]);
+ mNormals.push_back(normalx);
+ mNormals.push_back(normaly);
+ mNormals.push_back(normalz);
+ }
+ else if ( strcasecmp(argv[0],"f") == 0 && argc >= 4 )
+ {
+ GeometryVertex v[32];
+
+ int vcount = argc-1;
+
+ for (int i=1; i<argc; i++)
+ {
+ GetVertex(v[i-1],argv[i] );
+ }
+
+
+ mCallback->NodeTriangle(&v[0],&v[1],&v[2], mTextured);
+
+ if ( vcount >=3 ) // do the fan
+ {
+ for (int i=2; i<(vcount-1); i++)
+ {
+ mCallback->NodeTriangle(&v[0],&v[i],&v[i+1], mTextured);
+ }
+ }
+
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+class BuildMesh : public GeometryInterface
+{
+public:
+
+ int GetIndex(const float *p, const float *texCoord)
+ {
+
+ int vcount = (int)mVertices.size()/3;
+
+ if(vcount>0)
+ {
+ //New MS STL library checks indices in debug build, so zero causes an assert if it is empty.
+ const float *v = &mVertices[0];
+ const float *t = texCoord != NULL ? &mTexCoords[0] : NULL;
+
+ for (int i=0; i<vcount; i++)
+ {
+ if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] )
+ {
+ if (texCoord == NULL || (t[0] == texCoord[0] && t[1] == texCoord[1]))
+ {
+ return i;
+ }
+ }
+ v+=3;
+ if (t != NULL)
+ t += 2;
+ }
+ }
+
+ mVertices.push_back( p[0] );
+ mVertices.push_back( p[1] );
+ mVertices.push_back( p[2] );
+
+ if (texCoord != NULL)
+ {
+ mTexCoords.push_back( texCoord[0] );
+ mTexCoords.push_back( texCoord[1] );
+ }
+
+ return vcount;
+ }
+
+ virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3, bool textured)
+ {
+ mIndices.push_back( GetIndex(v1->mPos, textured ? v1->mTexel : NULL) );
+ mIndices.push_back( GetIndex(v2->mPos, textured ? v2->mTexel : NULL) );
+ mIndices.push_back( GetIndex(v3->mPos, textured ? v3->mTexel : NULL) );
+ }
+
+ const FloatVector& GetVertices(void) const { return mVertices; };
+ const FloatVector& GetTexCoords(void) const { return mTexCoords; };
+ const IntVector& GetIndices(void) const { return mIndices; };
+
+private:
+ FloatVector mVertices;
+ FloatVector mTexCoords;
+ IntVector mIndices;
+};
+
+};
+
+using namespace WAVEFRONT;
+
+WavefrontObj::WavefrontObj(void)
+{
+ mVertexCount = 0;
+ mTriCount = 0;
+ mIndices = 0;
+ mVertices = NULL;
+ mTexCoords = NULL;
+}
+
+WavefrontObj::~WavefrontObj(void)
+{
+ delete mIndices;
+ delete mVertices;
+}
+
+unsigned int WavefrontObj::loadObj(const char *fname, bool textured) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
+{
+
+ unsigned int ret = 0;
+
+ delete mVertices;
+ mVertices = 0;
+ delete mIndices;
+ mIndices = 0;
+ mVertexCount = 0;
+ mTriCount = 0;
+
+
+ BuildMesh bm;
+
+ OBJ obj;
+
+ obj.LoadMesh(fname,&bm, textured);
+
+
+ const FloatVector &vlist = bm.GetVertices();
+ const IntVector &indices = bm.GetIndices();
+ if ( vlist.size() )
+ {
+ mVertexCount = (int)vlist.size()/3;
+ mVertices = new float[mVertexCount*3];
+ memcpy( mVertices, &vlist[0], sizeof(float)*mVertexCount*3 );
+
+ if (textured)
+ {
+ mTexCoords = new float[mVertexCount * 2];
+ const FloatVector& tList = bm.GetTexCoords();
+ memcpy( mTexCoords, &tList[0], sizeof(float) * mVertexCount * 2);
+ }
+
+ mTriCount = (int)indices.size()/3;
+ mIndices = new int[mTriCount*3*sizeof(int)];
+ memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3);
+ ret = mTriCount;
+ }
+
+
+ return ret;
+}
+
+
+bool WavefrontObj::saveObj(const char *fname,int vcount,const float *vertices,int tcount,const int *indices)
+{
+ bool ret = false;
+
+ FILE *fph = fopen(fname,"wb");
+ if ( fph )
+ {
+ for (int i=0; i<vcount; i++)
+ {
+ fprintf(fph,"v %0.9f %0.9f %0.9f\r\n", vertices[0], vertices[1], vertices[2] );
+ vertices+=3;
+ }
+ for (int i=0; i<tcount; i++)
+ {
+ fprintf(fph,"f %d %d %d\r\n", indices[0]+1, indices[1]+1, indices[2]+1 );
+ indices+=3;
+ }
+ fclose(fph);
+ ret = true;
+ }
+ return ret;
+}
+
+#endif
diff --git a/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.h b/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.h
new file mode 100644
index 00000000..57e0f7e6
--- /dev/null
+++ b/APEX_1.4/shared/general/ConvexDecomposition/app/TestConvexDecomposition/wavefront.h
@@ -0,0 +1,53 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+#ifndef WAVEFRONT_OBJ_H
+
+
+#define WAVEFRONT_OBJ_H
+
+
+class WavefrontObj
+{
+public:
+
+ WavefrontObj(void);
+ ~WavefrontObj(void);
+
+ unsigned int loadObj(const char *fname, bool textured); // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
+
+
+ static bool saveObj(const char *fname,int vcount,const float *vertices,int tcount,const int *indices);
+
+ int mVertexCount;
+ int mTriCount;
+ int *mIndices;
+ float *mVertices;
+ float *mTexCoords;
+};
+
+#endif
diff --git a/APEX_1.4/shared/general/ConvexDecomposition/include/ConvexDecomposition.h b/APEX_1.4/shared/general/ConvexDecomposition/include/ConvexDecomposition.h
new file mode 100644
index 00000000..8e86699a
--- /dev/null
+++ b/APEX_1.4/shared/general/ConvexDecomposition/include/ConvexDecomposition.h
@@ -0,0 +1,145 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+#ifndef CONVEX_DECOMPOSITION_H
+
+#define CONVEX_DECOMPOSITION_H
+
+#include "foundation/PxSimpleTypes.h"
+
+namespace CONVEX_DECOMPOSITION
+{
+
+class TriangleMesh
+{
+public:
+ TriangleMesh(void)
+ {
+ mVcount = 0;
+ mVertices = NULL;
+ mTriCount = 0;
+ mIndices = NULL;
+ }
+
+ physx::PxU32 mVcount;
+ physx::PxF32 *mVertices;
+ physx::PxU32 mTriCount;
+ physx::PxU32 *mIndices;
+};
+
+class ConvexResult
+{
+public:
+ ConvexResult(void)
+ {
+ mHullVcount = 0;
+ mHullVertices = 0;
+ mHullTcount = 0;
+ mHullIndices = 0;
+ }
+
+// the convex hull.result
+ physx::PxU32 mHullVcount; // Number of vertices in this convex hull.
+ physx::PxF32 *mHullVertices; // The array of vertices (x,y,z)(x,y,z)...
+ physx::PxU32 mHullTcount; // The number of triangles int he convex hull
+ physx::PxU32 *mHullIndices; // The triangle indices (0,1,2)(3,4,5)...
+ physx::PxF32 mHullVolume; // the volume of the convex hull.
+
+};
+
+// just to avoid passing a zillion parameters to the method the
+// options are packed into this descriptor.
+class DecompDesc
+{
+public:
+ DecompDesc(void)
+ {
+ mVcount = 0;
+ mVertices = 0;
+ mTcount = 0;
+ mIndices = 0;
+ mDepth = 10;
+ mCpercent = 4;
+ mPpercent = 4;
+ mVpercent = 0.2f;
+ mMaxVertices = 32;
+ mSkinWidth = 0;
+ mRemoveTjunctions = false;
+ mInitialIslandGeneration = false;
+ mUseIslandGeneration = false;
+ mClosedSplit = false;
+ mUseHACD = false;
+ mConcavityHACD = 100;
+ mMinClusterSizeHACD = 10;
+ mConnectionDistanceHACD = 0;
+ }
+
+// describes the input triangle.
+ physx::PxU32 mVcount; // the number of vertices in the source mesh.
+ const physx::PxF32 *mVertices; // start of the vertex position array. Assumes a stride of 3 doubles.
+ physx::PxU32 mTcount; // the number of triangles in the source mesh.
+ const physx::PxU32 *mIndices; // the indexed triangle list array (zero index based)
+// options
+ physx::PxU32 mDepth; // depth to split, a maximum of 10, generally not over 7.
+ physx::PxF32 mCpercent; // the concavity threshold percentage. 0=20 is reasonable.
+ physx::PxF32 mPpercent; // the percentage volume conservation threshold to collapse hulls. 0-30 is reasonable.
+ physx::PxF32 mVpercent; // the pecentage of total mesh volume before we stop splitting.
+
+ bool mInitialIslandGeneration; // true if the initial mesh should be subjected to island generation.
+ bool mUseIslandGeneration; // true if the decomposition code should break the input mesh and split meshes into discrete 'islands/pieces'
+ bool mRemoveTjunctions; // whether or not to initially remove tjunctions found in the original mesh.
+ bool mClosedSplit; // true if the hulls should be closed as they are split
+ bool mUseHACD; // True if using the hierarchical approximate convex decomposition algorithm; recommended
+ physx::PxF32 mConcavityHACD; // The concavity value to use for HACD (not the same as concavity percentage used with ACD.
+ physx::PxU32 mMinClusterSizeHACD; // Minimum number of clusters to consider.
+ physx::PxF32 mConnectionDistanceHACD; // The connection distance for HACD
+
+// hull output limits.
+ physx::PxU32 mMaxVertices; // maximum number of vertices in the output hull. Recommended 32 or less.
+ physx::PxF32 mSkinWidth; // a skin width to apply to the output hulls.
+};
+
+class ConvexDecomposition
+{
+public:
+ virtual physx::PxU32 performConvexDecomposition(const DecompDesc &desc) = 0; // returns the number of hulls produced.
+ virtual void release(void) = 0;
+ virtual ConvexResult * getConvexResult(physx::PxU32 index) = 0;
+
+
+ virtual void splitMesh(const physx::PxF32 *planeEquation,const TriangleMesh &input,TriangleMesh &left,TriangleMesh &right,bool closedMesh) = 0;
+ virtual void releaseTriangleMeshMemory(TriangleMesh &mesh) = 0;
+
+protected:
+ virtual ~ConvexDecomposition(void) { };
+};
+
+ConvexDecomposition * createConvexDecomposition(void);
+
+};
+
+#endif
diff --git a/APEX_1.4/shared/general/ConvexDecomposition/include/SplitMesh.h b/APEX_1.4/shared/general/ConvexDecomposition/include/SplitMesh.h
new file mode 100644
index 00000000..b033443b
--- /dev/null
+++ b/APEX_1.4/shared/general/ConvexDecomposition/include/SplitMesh.h
@@ -0,0 +1,99 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+#ifndef SPLIT_MESH_H
+
+#define SPLIT_MESH_H
+
+#include <stdlib.h>
+#include "foundation/PxSimpleTypes.h"
+#include "PsAllocator.h"
+
+namespace SPLIT_MESH
+{
+
+class SimpleMesh
+{
+public:
+ SimpleMesh(void)
+ {
+ mVcount = 0;
+ mTcount = 0;
+ mVertices = NULL;
+ mIndices = NULL;
+ }
+ SimpleMesh(physx::PxU32 vcount,physx::PxU32 tcount,const physx::PxF32 *vertices,const physx::PxU32 *indices)
+ {
+ mVcount = 0;
+ mTcount = 0;
+ mVertices = NULL;
+ mIndices = NULL;
+ set(vcount,tcount,vertices,indices);
+ }
+
+ void set(physx::PxU32 vcount,physx::PxU32 tcount,const physx::PxF32 *vertices,const physx::PxU32 *indices)
+ {
+ release();
+ mVcount = vcount;
+ mTcount = tcount;
+ mVertices = (physx::PxF32 *)PX_ALLOC(sizeof(physx::PxF32)*3*mVcount, PX_DEBUG_EXP("SimpleMesh"));
+ memcpy(mVertices,vertices,sizeof(physx::PxF32)*3*mVcount);
+ mIndices = (physx::PxU32 *)PX_ALLOC(sizeof(physx::PxU32)*3*mTcount, PX_DEBUG_EXP("SimpleMesh"));
+ memcpy(mIndices,indices,sizeof(physx::PxU32)*3*mTcount);
+ }
+
+
+ ~SimpleMesh(void)
+ {
+ release();
+ }
+
+ void release(void)
+ {
+ PX_FREE(mVertices);
+ PX_FREE(mIndices);
+ mVertices = NULL;
+ mIndices = NULL;
+ mVcount = 0;
+ mTcount = 0;
+ }
+
+
+ physx::PxU32 mVcount;
+ physx::PxU32 mTcount;
+ physx::PxF32 *mVertices;
+ physx::PxU32 *mIndices;
+};
+
+
+void splitMesh(const physx::PxF32 *planeEquation,const SimpleMesh &input,SimpleMesh &left,SimpleMesh &right,bool closedMesh);
+
+
+};
+
+
+#endif
diff --git a/APEX_1.4/shared/general/ConvexDecomposition/src/ConvexDecomposition.cpp b/APEX_1.4/shared/general/ConvexDecomposition/src/ConvexDecomposition.cpp
new file mode 100644
index 00000000..f159852e
--- /dev/null
+++ b/APEX_1.4/shared/general/ConvexDecomposition/src/ConvexDecomposition.cpp
@@ -0,0 +1,1507 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+
+#include "ConvexDecomposition.h"
+#include "StanHull.h"
+#include "FloatMath.h"
+#include "SplitMesh.h"
+#include "PsArray.h"
+#include "PsUserAllocated.h"
+#include "foundation/PxErrorCallback.h"
+#include "PsFoundation.h"
+#include "foundation/PxAllocatorCallback.h"
+#include "HACD.h"
+
+#pragma warning(disable:4702)
+#pragma warning(disable:4996 4100)
+#pragma warning(disable:4267)
+
+static const physx::PxF32 EPSILON=0.0001;
+
+typedef physx::Array< physx::PxU32 > UintVector;
+
+using namespace physx::general_floatmath2;
+using namespace physx::stanhull;
+using namespace physx;
+using namespace physx::shdfnd;
+
+namespace CONVEX_DECOMPOSITION
+{
+#if 0
+static bool saveObj(SPLIT_MESH::SimpleMesh &mesh,int saveCount,const char *prefix)
+{
+ bool ret = false;
+
+ if ( mesh.mVcount )
+ {
+ char fname[512];
+ sprintf_s(fname,512,"%s_%02d.obj", prefix, saveCount );
+ int vcount = mesh.mVcount;
+ float *vertices = mesh.mVertices;
+ int tcount = mesh.mTcount;
+ const int *indices = (const int *)mesh.mIndices;
+
+
+ FILE *fph = fopen(fname,"wb");
+ if ( fph )
+ {
+ for (int i=0; i<vcount; i++)
+ {
+ fprintf(fph,"v %0.9f %0.9f %0.9f\r\n", vertices[0], vertices[1], vertices[2] );
+ vertices+=3;
+ }
+ for (int i=0; i<tcount; i++)
+ {
+ fprintf(fph,"f %d %d %d\r\n", indices[0]+1, indices[1]+1, indices[2]+1 );
+ indices+=3;
+ }
+ fclose(fph);
+ ret = true;
+ }
+ }
+ return ret;
+}
+#endif
+
+ class MyConvexResult : public ConvexResult, public physx::UserAllocated
+ {
+ public:
+ MyConvexResult(physx::PxU32 hvcount,const physx::PxF32 *hvertices,physx::PxU32 htcount,const physx::PxU32 *hindices)
+ {
+ mHullVcount = 0;
+ mHullTcount = 0;
+ mHullIndices = NULL;
+ mHullVertices = NULL;
+ if ( hvcount && hvertices && hindices == NULL )
+ {
+ HullResult result;
+ HullLibrary hl;
+ HullDesc desc;
+ desc.mMaxVertices = 256;
+ desc.SetHullFlag(QF_TRIANGLES);
+ desc.mVcount = hvcount;
+ desc.mVertices = hvertices;
+ desc.mVertexStride = sizeof(physx::PxF32)*3;
+ HullError ret = hl.CreateConvexHull(desc,result);
+ if ( ret == QE_OK )
+ {
+ mHullVcount = result.mNumOutputVertices;
+ mHullVertices = (physx::PxF32 *)PX_ALLOC(mHullVcount*sizeof(physx::PxF32)*3, PX_DEBUG_EXP("ConvexResult"));
+ memcpy(mHullVertices,result.mOutputVertices,mHullVcount*sizeof(physx::PxF32)*3);
+ mHullTcount = result.mNumFaces;
+ mHullIndices =(physx::PxU32 *)PX_ALLOC(sizeof(physx::PxU32)*mHullTcount*3, PX_DEBUG_EXP("ConvexResult"));
+ memcpy(mHullIndices,result.mIndices,sizeof(physx::PxU32)*mHullTcount*3);
+ hl.ReleaseResult(result);
+ }
+ }
+ else
+ {
+ mHullVcount = hvcount;
+ if ( mHullVcount )
+ {
+ mHullVertices = (physx::PxF32 *)PX_ALLOC(mHullVcount*sizeof(physx::PxF32)*3, PX_DEBUG_EXP("ConvexResult"));
+ memcpy(mHullVertices, hvertices, sizeof(physx::PxF32)*3*mHullVcount );
+ }
+ mHullTcount = htcount;
+ if ( mHullTcount )
+ {
+ mHullIndices = (physx::PxU32 *)PX_ALLOC(sizeof(physx::PxU32)*mHullTcount*3, PX_DEBUG_EXP("ConvexResult"));
+ memcpy(mHullIndices,hindices, sizeof(physx::PxU32)*mHullTcount*3 );
+ }
+ }
+ }
+
+ MyConvexResult(const MyConvexResult &r) // copy constructor, perform a deep copy of the data.
+ {
+ mHullVcount = r.mHullVcount;
+ if ( mHullVcount )
+ {
+ mHullVertices = (physx::PxF32 *)PX_ALLOC(mHullVcount*sizeof(physx::PxF32)*3, PX_DEBUG_EXP("ConvexResult"));
+ memcpy(mHullVertices, r.mHullVertices, sizeof(physx::PxF32)*3*mHullVcount );
+ }
+ else
+ {
+ mHullVertices = 0;
+ }
+ mHullTcount = r.mHullTcount;
+ if ( mHullTcount )
+ {
+ mHullIndices = (physx::PxU32 *)PX_ALLOC(sizeof(physx::PxU32)*mHullTcount*3, PX_DEBUG_EXP("ConvexResult"));
+ memcpy(mHullIndices, r.mHullIndices, sizeof(physx::PxU32)*mHullTcount*3 );
+ }
+ else
+ {
+ mHullIndices = 0;
+ }
+ }
+
+ ~MyConvexResult(void)
+ {
+ PX_FREE(mHullVertices);
+ PX_FREE(mHullIndices);
+ }
+
+
+
+
+
+ };
+
+
+class QuickSortPointers
+{
+public:
+ void qsort(void **base,PxI32 num); // perform the qsort.
+protected:
+ // -1 less, 0 equal, +1 greater.
+ virtual PxI32 compare(void **p1,void **p2) = 0;
+private:
+ void inline swap(char **a,char **b);
+};
+
+void QuickSortPointers::swap(char **a,char **b)
+{
+ char *tmp;
+
+ if ( a != b )
+ {
+ tmp = *a;
+ *a++ = *b;
+ *b++ = tmp;
+ }
+}
+
+
+void QuickSortPointers::qsort(void **b,PxI32 num)
+{
+ char *lo,*hi;
+ char *mid;
+ char *bottom, *top;
+ PxI32 size;
+ char *lostk[30], *histk[30];
+ PxI32 stkptr;
+ char **base = (char **)b;
+
+ if (num < 2 ) return;
+
+ stkptr = 0;
+
+ lo = (char *)base;
+ hi = (char *)base + sizeof(char **) * (num-1);
+
+nextone:
+
+ size = (hi - lo) / sizeof(char**) + 1;
+
+ mid = lo + (size / 2) * sizeof(char **);
+ swap((char **)mid,(char **)lo);
+ bottom = lo;
+ top = hi + sizeof(char **);
+
+ for (;;)
+ {
+ do
+ {
+ bottom += sizeof(char **);
+ } while (bottom <= hi && compare((void **)bottom,(void **)lo) <= 0);
+
+ do
+ {
+ top -= sizeof(char **);
+ } while (top > lo && compare((void **)top,(void **)lo) >= 0);
+
+ if (top < bottom) break;
+
+ swap((char **)bottom,(char **)top);
+
+ }
+
+ swap((char **)lo,(char **)top);
+
+ if ( top - 1 - lo >= hi - bottom )
+ {
+ if (lo + sizeof(char **) < top)
+ {
+ lostk[stkptr] = lo;
+ histk[stkptr] = top - sizeof(char **);
+ stkptr++;
+ }
+ if (bottom < hi)
+ {
+ lo = bottom;
+ goto nextone;
+ }
+ }
+ else
+ {
+ if ( bottom < hi )
+ {
+ lostk[stkptr] = bottom;
+ histk[stkptr] = hi;
+ stkptr++;
+ }
+ if (lo + sizeof(char **) < top)
+ {
+ hi = top - sizeof(char **);
+ goto nextone; /* do small recursion */
+ }
+ }
+
+ stkptr--;
+
+ if (stkptr >= 0)
+ {
+ lo = lostk[stkptr];
+ hi = histk[stkptr];
+ goto nextone;
+ }
+ return;
+}
+
+
+
+class ConvexDecompInterface
+{
+public:
+ virtual void ConvexDecompResult(MyConvexResult &result) = 0;
+};
+
+
+
+class Cdesc
+{
+public:
+ ConvexDecompInterface *mCallback;
+ physx::PxF32 mMasterVolume;
+ bool mUseIslandGeneration;
+ bool mClosedSplit;
+ physx::PxF32 mMasterMeshVolume;
+ physx::PxU32 mMaxDepth;
+ physx::PxF32 mConcavePercent;
+ physx::PxF32 mMergePercent;
+ physx::PxF32 mMeshVolumePercent;
+};
+
+template <class Type> class Vector3d
+{
+public:
+ Vector3d(void) { }; // null constructor, does not inialize point.
+
+ Vector3d(const Vector3d &a) // constructor copies existing vector.
+ {
+ x = a.x;
+ y = a.y;
+ z = a.z;
+ };
+
+ Vector3d(Type a,Type b,Type c) // construct with initial point.
+ {
+ x = a;
+ y = b;
+ z = c;
+ };
+
+ Vector3d(const physx::PxF32 *t)
+ {
+ x = t[0];
+ y = t[1];
+ z = t[2];
+ };
+
+ void Set(const physx::PxF32 *p)
+ {
+ x = (Type)p[0];
+ y = (Type)p[1];
+ z = (Type)p[2];
+ }
+
+
+
+ const Type* Ptr() const { return &x; }
+ Type* Ptr() { return &x; }
+
+
+ Type x;
+ Type y;
+ Type z;
+};
+
+
+
+#define WSCALE 4
+#define CONCAVE_THRESH 0.05f
+
+
+class Wpoint
+{
+public:
+ Wpoint(const Vector3d<physx::PxF32> &p,physx::PxF32 w)
+ {
+ mPoint = p;
+ mWeight = w;
+ }
+
+ Vector3d<physx::PxF32> mPoint;
+ physx::PxF32 mWeight;
+};
+
+typedef physx::Array< Wpoint > WpointVector;
+
+
+class CTri
+{
+public:
+ CTri(void) { };
+
+ CTri(const physx::PxF32 *p1,const physx::PxF32 *p2,const physx::PxF32 *p3,physx::PxU32 i1,physx::PxU32 i2,physx::PxU32 i3)
+ {
+ mProcessed = 0;
+ mI1 = i1;
+ mI2 = i2;
+ mI3 = i3;
+
+ mP1.Set(p1);
+ mP2.Set(p2);
+ mP3.Set(p3);
+ mPlaneD = fm_computePlane(mP1.Ptr(),mP2.Ptr(),mP3.Ptr(),mNormal.Ptr());
+ }
+
+ physx::PxF32 Facing(const CTri &t)
+ {
+ physx::PxF32 d = fm_dot(mNormal.Ptr(),t.mNormal.Ptr());
+ return d;
+ }
+
+ // clip this line segment against this triangle.
+ bool clip(const Vector3d<physx::PxF32> &start,Vector3d<physx::PxF32> &end) const
+ {
+ Vector3d<physx::PxF32> sect;
+
+ bool hit = fm_lineIntersectsTriangle(start.Ptr(), end.Ptr(), mP1.Ptr(), mP2.Ptr(), mP3.Ptr(), sect.Ptr() );
+
+ if ( hit )
+ {
+ end = sect;
+ }
+ return hit;
+ }
+
+ bool Concave(const Vector3d<physx::PxF32> &p,physx::PxF32 &distance,Vector3d<physx::PxF32> &n) const
+ {
+ fm_nearestPointInTriangle(p.Ptr(),mP1.Ptr(),mP2.Ptr(),mP3.Ptr(),n.Ptr());
+ distance = fm_distance(p.Ptr(),n.Ptr());
+ return true;
+ }
+
+ void addTri(physx::PxU32 *indices,physx::PxU32 i1,physx::PxU32 i2,physx::PxU32 i3,physx::PxU32 &tcount) const
+ {
+ indices[tcount*3+0] = i1;
+ indices[tcount*3+1] = i2;
+ indices[tcount*3+2] = i3;
+ tcount++;
+ }
+
+ physx::PxF32 getVolume(ConvexDecompInterface *) const
+ {
+ physx::PxU32 indices[8*3];
+
+
+ physx::PxU32 tcount = 0;
+
+ addTri(indices,0,1,2,tcount);
+ addTri(indices,3,4,5,tcount);
+
+ addTri(indices,0,3,4,tcount);
+ addTri(indices,0,4,1,tcount);
+
+ addTri(indices,1,4,5,tcount);
+ addTri(indices,1,5,2,tcount);
+
+ addTri(indices,0,3,5,tcount);
+ addTri(indices,0,5,2,tcount);
+
+ physx::PxF32 v = fm_computeMeshVolume(mP1.Ptr(), tcount, indices );
+
+ return v;
+
+ }
+
+ physx::PxF32 raySect(const Vector3d<physx::PxF32> &p,const Vector3d<physx::PxF32> &dir,Vector3d<physx::PxF32> &sect) const
+ {
+ physx::PxF32 plane[4];
+
+ plane[0] = mNormal.x;
+ plane[1] = mNormal.y;
+ plane[2] = mNormal.z;
+ plane[3] = mPlaneD;
+
+ Vector3d<physx::PxF32> dest;
+
+ dest.x = p.x+dir.x*10000;
+ dest.y = p.y+dir.y*10000;
+ dest.z = p.z+dir.z*10000;
+
+
+ fm_intersectPointPlane( p.Ptr(), dest.Ptr(), sect.Ptr(), plane );
+
+ return fm_distance(sect.Ptr(),p.Ptr()); // return the intersection distance.
+
+ }
+
+ physx::PxF32 planeDistance(const Vector3d<physx::PxF32> &p) const
+ {
+ physx::PxF32 plane[4];
+
+ plane[0] = mNormal.x;
+ plane[1] = mNormal.y;
+ plane[2] = mNormal.z;
+ plane[3] = mPlaneD;
+
+ return fm_distToPlane(plane,p.Ptr());
+
+ }
+
+ bool samePlane(const CTri &t) const
+ {
+ const physx::PxF32 THRESH = 0.001f;
+ physx::PxF32 dd = fabs( t.mPlaneD - mPlaneD );
+ if ( dd > THRESH ) return false;
+ dd = fabs( t.mNormal.x - mNormal.x );
+ if ( dd > THRESH ) return false;
+ dd = fabs( t.mNormal.y - mNormal.y );
+ if ( dd > THRESH ) return false;
+ dd = fabs( t.mNormal.z - mNormal.z );
+ if ( dd > THRESH ) return false;
+ return true;
+ }
+
+ bool hasIndex(physx::PxU32 i) const
+ {
+ if ( i == mI1 || i == mI2 || i == mI3 ) return true;
+ return false;
+ }
+
+ bool sharesEdge(const CTri &t) const
+ {
+ bool ret = false;
+ physx::PxU32 count = 0;
+
+ if ( t.hasIndex(mI1) ) count++;
+ if ( t.hasIndex(mI2) ) count++;
+ if ( t.hasIndex(mI3) ) count++;
+
+ if ( count >= 2 ) ret = true;
+
+ return ret;
+ }
+
+ physx::PxF32 area(void)
+ {
+ physx::PxF32 a = mConcavity * fm_areaTriangle(mP1.Ptr(),mP2.Ptr(),mP3.Ptr());
+ return a;
+ }
+
+ void addWeighted(WpointVector &list,ConvexDecompInterface * /* callback */)
+ {
+
+ Wpoint p1(mP1,mC1);
+ Wpoint p2(mP2,mC2);
+ Wpoint p3(mP3,mC3);
+
+ Vector3d<physx::PxF32> d1,d2,d3;
+
+ fm_subtract(mNear1.Ptr(),mP1.Ptr(),d1.Ptr());
+ fm_subtract(mNear2.Ptr(),mP2.Ptr(),d2.Ptr());
+ fm_subtract(mNear3.Ptr(),mP3.Ptr(),d3.Ptr());
+
+ fm_multiply(d1.Ptr(),WSCALE);
+ fm_multiply(d2.Ptr(),WSCALE);
+ fm_multiply(d3.Ptr(),WSCALE);
+
+ fm_add(d1.Ptr(), mP1.Ptr(), d1.Ptr());
+ fm_add(d2.Ptr(), mP2.Ptr(), d2.Ptr());
+ fm_add(d3.Ptr(), mP3.Ptr(), d3.Ptr());
+
+ Wpoint p4(d1,mC1);
+ Wpoint p5(d2,mC2);
+ Wpoint p6(d3,mC3);
+
+ list.pushBack(p1);
+ list.pushBack(p2);
+ list.pushBack(p3);
+
+ list.pushBack(p4);
+ list.pushBack(p5);
+ list.pushBack(p6);
+
+ }
+
+ Vector3d<physx::PxF32> mP1;
+ Vector3d<physx::PxF32> mP2;
+ Vector3d<physx::PxF32> mP3;
+ Vector3d<physx::PxF32> mNear1;
+ Vector3d<physx::PxF32> mNear2;
+ Vector3d<physx::PxF32> mNear3;
+ Vector3d<physx::PxF32> mNormal;
+ physx::PxF32 mPlaneD;
+ physx::PxF32 mConcavity;
+ physx::PxF32 mC1;
+ physx::PxF32 mC2;
+ physx::PxF32 mC3;
+ physx::PxU32 mI1;
+ physx::PxU32 mI2;
+ physx::PxU32 mI3;
+ physx::PxI32 mProcessed; // already been added...
+};
+
+typedef physx::Array< CTri > CTriVector;
+
+bool featureMatch(CTri &m,const CTriVector &tris,ConvexDecompInterface * /* callback */,const CTriVector & /* input_mesh */)
+{
+
+ bool ret = false;
+
+ physx::PxF32 neardot = 0.707f;
+
+ m.mConcavity = 0;
+
+ CTriVector::ConstIterator i;
+
+ CTri nearest;
+
+ for (i=tris.begin(); i!=tris.end(); ++i)
+ {
+ const CTri &t = (*i);
+
+
+ if ( t.samePlane(m) )
+ {
+ ret = false;
+ break;
+ }
+
+ physx::PxF32 dot = fm_dot(t.mNormal.Ptr(),m.mNormal.Ptr());
+
+ if ( dot > neardot )
+ {
+
+ physx::PxF32 d1 = t.planeDistance( m.mP1 );
+ physx::PxF32 d2 = t.planeDistance( m.mP2 );
+ physx::PxF32 d3 = t.planeDistance( m.mP3 );
+
+ if ( d1 > 0.001f || d2 > 0.001f || d3 > 0.001f ) // can't be near coplaner!
+ {
+
+ neardot = dot;
+
+ Vector3d<physx::PxF32> n1,n2,n3;
+
+ t.raySect( m.mP1, m.mNormal, m.mNear1 );
+ t.raySect( m.mP2, m.mNormal, m.mNear2 );
+ t.raySect( m.mP3, m.mNormal, m.mNear3 );
+
+ nearest = t;
+
+ ret = true;
+ }
+
+ }
+ }
+
+ if ( ret )
+ {
+ m.mC1 = fm_distance(m.mP1.Ptr(), m.mNear1.Ptr() );
+ m.mC2 = fm_distance(m.mP2.Ptr(), m.mNear2.Ptr() );
+ m.mC3 = fm_distance(m.mP3.Ptr(), m.mNear3.Ptr() );
+
+ m.mConcavity = m.mC1;
+
+ if ( m.mC2 > m.mConcavity ) m.mConcavity = m.mC2;
+ if ( m.mC3 > m.mConcavity ) m.mConcavity = m.mC3;
+
+
+ }
+ return ret;
+}
+
+bool isFeatureTri(CTri &t,CTriVector &flist,physx::PxF32 fc,ConvexDecompInterface * /* callback */,physx::PxU32 /* color */)
+{
+ bool ret = false;
+
+ if ( t.mProcessed == 0 ) // if not already processed
+ {
+
+ physx::PxF32 c = t.mConcavity / fc; // must be within 80% of the concavity of the parent.
+
+ if ( c > 0.85f )
+ {
+ // see if this triangle is a 'feature' triangle. Meaning it shares an
+ // edge with any existing feature triangle and is within roughly the same
+ // concavity of the parent.
+ if ( flist.size() )
+ {
+ CTriVector::Iterator i;
+ for (i=flist.begin(); i!=flist.end(); ++i)
+ {
+ CTri &ftri = (*i);
+ if ( ftri.sharesEdge(t) )
+ {
+ t.mProcessed = 2; // it is now part of a feature.
+ flist.pushBack(t); // add it to the feature list.
+ ret = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ t.mProcessed = 2;
+ flist.pushBack(t); // add it to the feature list.
+ ret = true;
+ }
+ }
+ else
+ {
+ t.mProcessed = 1; // eliminated for this feature, but might be valid for the next one..
+ }
+
+ }
+ return ret;
+}
+
+physx::PxF32 computeConcavity(physx::PxU32 vcount,
+ const physx::PxF32 *vertices,
+ physx::PxU32 tcount,
+ const physx::PxU32 *indices,
+ ConvexDecompInterface *callback,
+ physx::PxF32 *plane, // plane equation to split on
+ physx::PxF32 &volume)
+{
+
+
+ physx::PxF32 cret = 0;
+ volume = 1;
+
+ HullResult result;
+ HullLibrary hl;
+ HullDesc desc;
+
+ desc.mMaxVertices = 256;
+ desc.SetHullFlag(QF_TRIANGLES);
+
+
+ desc.mVcount = vcount;
+ desc.mVertices = vertices;
+ desc.mVertexStride = sizeof(physx::PxF32)*3;
+
+ HullError ret = hl.CreateConvexHull(desc,result);
+
+ if ( ret == QE_OK )
+ {
+
+ physx::PxF32 bmin[3];
+ physx::PxF32 bmax[3];
+
+ fm_computeBestFitAABB( result.mNumOutputVertices, result.mOutputVertices, sizeof(physx::PxF32)*3, bmin, bmax );
+
+ physx::PxF32 dx = bmax[0] - bmin[0];
+ physx::PxF32 dy = bmax[1] - bmin[1];
+ physx::PxF32 dz = bmax[2] - bmin[2];
+
+ Vector3d<physx::PxF32> center;
+
+ center.x = bmin[0] + dx*0.5f;
+ center.y = bmin[1] + dy*0.5f;
+ center.z = bmin[2] + dz*0.5f;
+
+ volume = fm_computeMeshVolume( result.mOutputVertices, result.mNumFaces, result.mIndices );
+
+#if 1
+ // ok..now..for each triangle on the original mesh..
+ // we extrude the points to the nearest point on the hull.
+ const physx::PxU32 *source = result.mIndices;
+
+ CTriVector tris;
+
+ for (physx::PxU32 i=0; i<result.mNumFaces; i++)
+ {
+ physx::PxU32 i1 = *source++;
+ physx::PxU32 i2 = *source++;
+ physx::PxU32 i3 = *source++;
+
+ const physx::PxF32 *p1 = &result.mOutputVertices[i1*3];
+ const physx::PxF32 *p2 = &result.mOutputVertices[i2*3];
+ const physx::PxF32 *p3 = &result.mOutputVertices[i3*3];
+
+ CTri t(p1,p2,p3,i1,i2,i3); //
+ tris.pushBack(t);
+ }
+
+ // we have not pre-computed the plane equation for each triangle in the convex hull..
+
+ physx::PxF32 totalVolume = 0;
+
+ CTriVector ftris; // 'feature' triangles.
+
+ const physx::PxU32 *src = indices;
+
+
+ physx::PxF32 maxc=0;
+
+
+ {
+ CTriVector input_mesh;
+ {
+ const physx::PxU32 *src = indices;
+ for (physx::PxU32 i=0; i<tcount; i++)
+ {
+
+ physx::PxU32 i1 = *src++;
+ physx::PxU32 i2 = *src++;
+ physx::PxU32 i3 = *src++;
+
+ const physx::PxF32 *p1 = &vertices[i1*3];
+ const physx::PxF32 *p2 = &vertices[i2*3];
+ const physx::PxF32 *p3 = &vertices[i3*3];
+
+ CTri t(p1,p2,p3,i1,i2,i3);
+ input_mesh.pushBack(t);
+ }
+ }
+
+ CTri maxctri;
+
+ for (physx::PxU32 i=0; i<tcount; i++)
+ {
+
+ physx::PxU32 i1 = *src++;
+ physx::PxU32 i2 = *src++;
+ physx::PxU32 i3 = *src++;
+
+ const physx::PxF32 *p1 = &vertices[i1*3];
+ const physx::PxF32 *p2 = &vertices[i2*3];
+ const physx::PxF32 *p3 = &vertices[i3*3];
+
+ CTri t(p1,p2,p3,i1,i2,i3);
+
+ featureMatch(t, tris, callback, input_mesh );
+
+ if ( t.mConcavity > CONCAVE_THRESH )
+ {
+
+ if ( t.mConcavity > maxc )
+ {
+ maxc = t.mConcavity;
+ maxctri = t;
+ }
+
+ physx::PxF32 v = t.getVolume(0);
+ totalVolume+=v;
+ ftris.pushBack(t);
+ }
+
+ }
+ }
+ fm_computeSplitPlane( vcount, vertices, tcount, indices, plane );
+#endif
+
+ cret = totalVolume;
+
+ hl.ReleaseResult(result);
+ }
+
+
+ return cret;
+}
+
+
+
+
+
+class FaceTri
+{
+public:
+ FaceTri(void) { };
+
+ FaceTri(const physx::PxF32 *vertices,physx::PxU32 i1,physx::PxU32 i2,physx::PxU32 i3)
+ {
+ fm_copy3(&vertices[i1*3],mP1 );
+ fm_copy3(&vertices[i2*3],mP2 );
+ fm_copy3(&vertices[i3*3],mP3 );
+ }
+
+ physx::PxF32 mP1[3];
+ physx::PxF32 mP2[3];
+ physx::PxF32 mP3[3];
+ physx::PxF32 mNormal[3];
+
+};
+
+
+
+
+
+class CHull : public UserAllocated
+{
+public:
+ CHull(const MyConvexResult &result)
+ {
+ if ( result.mHullVertices )
+ {
+ mResult = PX_NEW(MyConvexResult)(result);
+ mVolume = fm_computeMeshVolume( result.mHullVertices, result.mHullTcount, result.mHullIndices );
+ mDiagonal = fm_computeBestFitAABB( result.mHullVcount, result.mHullVertices, sizeof(physx::PxF32)*3, mMin, mMax );
+
+ physx::PxF32 dx = mMax[0] - mMin[0];
+ physx::PxF32 dy = mMax[1] - mMin[1];
+ physx::PxF32 dz = mMax[2] - mMin[2];
+
+ dx*=0.1f; // inflate 1/10th on each edge
+ dy*=0.1f; // inflate 1/10th on each edge
+ dz*=0.1f; // inflate 1/10th on each edge
+
+ mMin[0]-=dx;
+ mMin[1]-=dy;
+ mMin[2]-=dz;
+
+ mMax[0]+=dx;
+ mMax[1]+=dy;
+ mMax[2]+=dz;
+ }
+ else
+ {
+ mResult = NULL;
+ mVolume = 0;
+ mDiagonal = 0;
+ }
+
+
+ }
+
+ ~CHull(void)
+ {
+ delete mResult;
+ }
+
+ bool overlap(const CHull &h) const
+ {
+ return fm_intersectAABB(mMin,mMax, h.mMin, h.mMax );
+ }
+
+ physx::PxF32 mMin[3];
+ physx::PxF32 mMax[3];
+ physx::PxF32 mVolume;
+ physx::PxF32 mDiagonal; // long edge..
+ MyConvexResult *mResult;
+};
+
+// Usage: std::sort( list.begin(), list.end(), StringSortRef() );
+class CHullSort
+{
+ public:
+
+ bool operator()(const CHull *a,const CHull *b) const
+ {
+ return a->mVolume < b->mVolume;
+ }
+};
+
+
+typedef physx::Array< CHull * > CHullVector;
+typedef physx::Array<MyConvexResult *> ConvexResultVector;
+
+
+class ConvexBuilder : public ConvexDecompInterface, public QuickSortPointers, public HACD::HACD_API::UserCallback
+{
+public:
+ ConvexBuilder(void)
+ {
+ };
+
+ virtual ~ConvexBuilder(void)
+ {
+ CHullVector::Iterator i;
+ for (i=mChulls.begin(); i!=mChulls.end(); ++i)
+ {
+ CHull *cr = (*i);
+ delete cr;
+ }
+ for (ConvexResultVector::Iterator i=mResults.begin(); i!=mResults.end(); ++i)
+ {
+ MyConvexResult *cr = (*i);
+ delete cr;
+ }
+ }
+
+ virtual bool hacdProgressUpdate(const char * /*message*/, physx::PxF32 /*progress*/, physx::PxF32 /*concavity*/, physx::PxU32 /*nVertices*/)
+ {
+// printf("%s",message);
+ return true;
+ }
+
+ bool isDuplicate(physx::PxU32 i1,physx::PxU32 i2,physx::PxU32 i3,physx::PxU32 ci1,physx::PxU32 ci2,physx::PxU32 ci3)
+ {
+ physx::PxU32 dcount = 0;
+
+ assert( i1 != i2 && i1 != i3 && i2 != i3 );
+ assert( ci1 != ci2 && ci1 != ci3 && ci2 != ci3 );
+
+ if ( i1 == ci1 || i1 == ci2 || i1 == ci3 ) dcount++;
+ if ( i2 == ci1 || i2 == ci2 || i2 == ci3 ) dcount++;
+ if ( i3 == ci1 || i3 == ci2 || i3 == ci3 ) dcount++;
+
+ return dcount == 3;
+ }
+
+ void getMesh(const MyConvexResult &cr,fm_VertexIndex *vc)
+ {
+ physx::PxU32 *src = cr.mHullIndices;
+
+ for (physx::PxU32 i=0; i<cr.mHullTcount; i++)
+ {
+ size_t i1 = *src++;
+ size_t i2 = *src++;
+ size_t i3 = *src++;
+
+ const physx::PxF32 *p1 = &cr.mHullVertices[i1*3];
+ const physx::PxF32 *p2 = &cr.mHullVertices[i2*3];
+ const physx::PxF32 *p3 = &cr.mHullVertices[i3*3];
+ bool newPos;
+ i1 = vc->getIndex(p1,newPos);
+ i2 = vc->getIndex(p2,newPos);
+ i3 = vc->getIndex(p3,newPos);
+ }
+ }
+
+ CHull * canMerge(CHull *a,CHull *b)
+ {
+ if ( !a->overlap(*b) ) return 0; // if their AABB's (with a little slop) don't overlap, then return.
+
+ if ( mMergePercent < 0 ) return 0;
+
+ assert( a->mVolume > 0 );
+ assert( b->mVolume > 0 );
+
+ CHull *ret = 0;
+
+ // ok..we are going to combine both meshes into a single mesh
+ // and then we are going to compute the concavity...
+
+ fm_VertexIndex *vc = fm_createVertexIndex((physx::PxF32)EPSILON,false);
+
+ getMesh( *a->mResult, vc);
+ getMesh( *b->mResult, vc);
+
+ size_t vcount = vc->getVcount();
+ const physx::PxF32 *vertices = vc->getVerticesFloat();
+
+ HullResult hresult;
+ HullLibrary hl;
+ HullDesc desc;
+
+ desc.SetHullFlag(QF_TRIANGLES);
+
+ desc.mVcount = (physx::PxU32)vcount;
+ desc.mVertices = vertices;
+ desc.mVertexStride = sizeof(physx::PxF32)*3;
+
+ HullError hret = hl.CreateConvexHull(desc,hresult);
+
+ if ( hret == QE_OK )
+ {
+ physx::PxF32 combineVolume = fm_computeMeshVolume( hresult.mOutputVertices, hresult.mNumFaces, hresult.mIndices );
+ physx::PxF32 sumVolume = a->mVolume + b->mVolume;
+
+ physx::PxF32 percent = (sumVolume*100) / combineVolume;
+
+ if ( percent >= (100.0f-mMergePercent) )
+ {
+ MyConvexResult cr(hresult.mNumOutputVertices, hresult.mOutputVertices, hresult.mNumFaces, hresult.mIndices);
+ ret = PX_NEW(CHull)(cr);
+ }
+ hl.ReleaseResult(hresult);
+ }
+ fm_releaseVertexIndex(vc);
+ return ret;
+ }
+
+ bool combineHulls(void)
+ {
+
+ bool combine = false;
+
+ sortChulls(mChulls); // sort the convex hulls, largest volume to least...
+
+ CHullVector output; // the output hulls...
+
+
+ CHullVector::Iterator i;
+
+ for (i=mChulls.begin(); i!=mChulls.end() && !combine; ++i)
+ {
+ CHull *cr = (*i);
+
+ CHullVector::Iterator j = i + 1;
+ for (; j!=mChulls.end(); ++j)
+ {
+ CHull *match = (*j);
+
+ if ( cr != match ) // don't try to merge a hull with itself, that be stoopid
+ {
+
+ CHull *merge = canMerge(cr,match); // if we can merge these two....
+ if ( !merge )
+ {
+ merge = canMerge(match,cr);
+ }
+
+ if ( merge )
+ {
+ output.pushBack(merge);
+ ++i;
+ while ( i != mChulls.end() )
+ {
+ CHull *cr = (*i);
+ if ( cr != match )
+ {
+ output.pushBack(cr);
+ }
+ i++;
+ }
+
+ delete cr;
+ delete match;
+ combine = true;
+ break;
+ }
+ }
+ }
+
+ if ( combine )
+ {
+ break;
+ }
+ else
+ {
+ output.pushBack(cr);
+ }
+ }
+
+ if ( combine )
+ {
+ mChulls.clear();
+ mChulls = output;
+ output.clear();
+ }
+
+
+ return combine;
+ }
+
+ MyConvexResult * getHull(PxU32 index)
+ {
+ return mResults[index];
+ }
+
+ physx::PxU32 process(const DecompDesc &desc)
+ {
+
+ physx::PxU32 ret = 0;
+
+ Cdesc cdesc;
+ cdesc.mMaxDepth = desc.mDepth;
+ cdesc.mConcavePercent = desc.mCpercent;
+ cdesc.mMeshVolumePercent = desc.mVpercent;
+ mMergePercent = cdesc.mMergePercent = desc.mPpercent;
+ cdesc.mUseIslandGeneration = desc.mUseIslandGeneration;
+ cdesc.mClosedSplit = desc.mClosedSplit;
+ cdesc.mCallback = this;
+
+
+ HullResult result;
+ HullLibrary hl;
+ HullDesc hdesc;
+ hdesc.SetHullFlag(QF_TRIANGLES);
+ hdesc.mVcount = desc.mVcount;
+ hdesc.mVertices = desc.mVertices;
+ hdesc.mVertexStride = sizeof(physx::PxF32)*3;
+ hdesc.mMaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output
+ HullError eret = hl.CreateConvexHull(hdesc,result);
+
+ if ( eret == QE_OK )
+ {
+ cdesc.mMasterVolume = fm_computeMeshVolume( result.mOutputVertices, result.mNumFaces, result.mIndices ); // the volume of the hull.
+ cdesc.mMasterMeshVolume = fm_computeMeshVolume( desc.mVertices, desc.mTcount, desc.mIndices );
+ hl.ReleaseResult(result);
+
+
+ if ( desc.mUseHACD )
+ {
+ HACD::HACD_API *hacd = HACD::createHACD_API();
+ if ( hacd )
+ {
+ HACD::HACD_API::Desc hdesc;
+ hdesc.mCallback = this;
+ hdesc.mTriangleCount = desc.mTcount;
+ hdesc.mIndices = desc.mIndices;
+ hdesc.mVertexCount = desc.mVcount;
+ hdesc.mVertices = desc.mVertices;
+ hdesc.mMinHullCount = desc.mMinClusterSizeHACD;
+ hdesc.mConcavity = desc.mConcavityHACD;
+ hdesc.mMaxHullVertices = desc.mMaxVertices;
+ hdesc.mConnectDistance = desc.mConnectionDistanceHACD;
+ physx::PxU32 hullCount = hacd->performHACD(hdesc);
+ for (physx::PxU32 i=0; i<hullCount; i++)
+ {
+ const HACD::HACD_API::Hull *hull = hacd->getHull(i);
+ if ( hull )
+ {
+ MyConvexResult result(hull->mVertexCount,hull->mVertices,hull->mTriangleCount,hull->mIndices);
+ ConvexDecompResult(result);
+ }
+ }
+ hacd->release();
+ }
+ }
+ else
+ {
+ const physx::PxU32 *indices = desc.mIndices;
+ size_t tcount = desc.mTcount;
+ doConvexDecomposition(desc.mVcount, desc.mVertices, tcount, indices, cdesc, 0);
+ }
+
+
+ while ( combineHulls() ); // keep combinging hulls until I can't combine any more...
+
+ CHullVector::Iterator i;
+ for (i=mChulls.begin(); i!=mChulls.end(); ++i)
+ {
+ CHull *cr = (*i);
+
+ // before we hand it back to the application, we need to regenerate the hull based on the
+ // limits given by the user.
+
+ const MyConvexResult &c = *cr->mResult; // the high resolution hull...
+
+ HullResult result;
+ HullLibrary hl;
+ HullDesc hdesc;
+
+ hdesc.SetHullFlag(QF_TRIANGLES);
+
+ hdesc.mVcount = c.mHullVcount;
+ hdesc.mVertices = c.mHullVertices;
+ hdesc.mVertexStride = sizeof(physx::PxF32)*3;
+ hdesc.mMaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output
+
+ if ( desc.mSkinWidth > 0 )
+ {
+ hdesc.mSkinWidth = desc.mSkinWidth;
+ hdesc.SetHullFlag(QF_SKIN_WIDTH); // do skin width computation.
+ }
+
+ HullError ret = hl.CreateConvexHull(hdesc,result);
+
+ if ( ret == QE_OK )
+ {
+ MyConvexResult *r = PX_NEW(MyConvexResult)(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices);
+ r->mHullVolume = fm_computeMeshVolume( result.mOutputVertices, result.mNumFaces, result.mIndices ); // the volume of the hull.
+ mResults.pushBack(r);
+ hl.ReleaseResult(result);
+ }
+ delete cr;
+ }
+ mChulls.clear();
+ ret = mResults.size();
+ }
+
+ return ret;
+ }
+
+
+ virtual void ConvexDecompResult(MyConvexResult &result)
+ {
+ CHull *ch = PX_NEW(CHull)(result);
+ if ( ch->mVolume > 0.00001f )
+ {
+ mChulls.pushBack(ch);
+ }
+ else
+ {
+ delete ch;
+ }
+ }
+
+ virtual PxI32 compare(void **p1,void **p2)
+ {
+ CHull **cp1 = (CHull **)p1;
+ CHull **cp2 = (CHull **)p2;
+ CHull *h1 = cp1[0];
+ CHull *h2 = cp2[0];
+
+ if ( h1->mVolume > h2->mVolume )
+ return -1;
+ else if ( h1->mVolume < h2->mVolume )
+ return 1;
+ return 0;
+ }
+
+ void sortChulls(CHullVector & hulls)
+ {
+ if ( hulls.size() )
+ {
+ CHull **hptr = &hulls[0];
+ QuickSortPointers::qsort((void **)hptr,hulls.size());
+ }
+ }
+
+ bool addTri(fm_VertexIndex *vl,
+ UintVector &list,
+ const physx::PxF32 *p1,
+ const physx::PxF32 *p2,
+ const physx::PxF32 *p3)
+ {
+ bool ret = false;
+
+ bool newPos;
+ physx::PxU32 i1 = vl->getIndex(p1,newPos );
+ physx::PxU32 i2 = vl->getIndex(p2,newPos );
+ physx::PxU32 i3 = vl->getIndex(p3,newPos );
+
+ // do *not* process degenerate triangles!
+
+ if ( i1 != i2 && i1 != i3 && i2 != i3 )
+ {
+
+ list.pushBack(i1);
+ list.pushBack(i2);
+ list.pushBack(i3);
+ ret = true;
+ }
+ return ret;
+ }
+
+#pragma warning(disable:4702)
+
+
+
+ void doConvexDecomposition(physx::PxU32 vcount,
+ const physx::PxF32 *vertices,
+ physx::PxU32 tcount,
+ const physx::PxU32 *indices,
+ const Cdesc &cdesc,
+ physx::PxU32 depth)
+
+ {
+
+ physx::PxF32 plane[4];
+
+ bool split = false;
+
+ bool isCoplanar = fm_isMeshCoplanar(tcount,indices,vertices,true);
+
+ if ( isCoplanar ) // we can't do convex decomposition on co-planar meshes!
+ {
+ // skipping co-planar mesh here...
+ }
+ else
+ {
+ if ( depth < cdesc.mMaxDepth )
+ {
+ if ( cdesc.mConcavePercent >= 0 )
+ {
+ physx::PxF32 volume;
+ physx::PxF32 c = computeConcavity( vcount, vertices, tcount, indices, cdesc.mCallback, plane, volume );
+ physx::PxF32 percent = (c*100.0f)/cdesc.mMasterVolume;
+ if ( percent > cdesc.mConcavePercent ) // if great than 5% of the total volume is concave, go ahead and keep splitting.
+ {
+ split = true;
+ }
+ }
+
+
+ physx::PxF32 mvolume = fm_computeMeshVolume(vertices, tcount, indices );
+ physx::PxF32 mpercent = (mvolume*100.0f)/cdesc.mMasterMeshVolume;
+ if ( mpercent < cdesc.mMeshVolumePercent )
+ {
+ split = false; // it's too tiny to bother with!
+ }
+
+ if ( split )
+ {
+ split = fm_computeSplitPlane(vcount,vertices,tcount,indices,plane);
+ }
+
+ }
+
+ if ( depth >= cdesc.mMaxDepth || !split )
+ {
+
+ HullResult result;
+ HullLibrary hl;
+ HullDesc desc;
+
+ desc.SetHullFlag(QF_TRIANGLES);
+
+ desc.mVcount = vcount;
+ desc.mVertices = vertices;
+ desc.mVertexStride = sizeof(physx::PxF32)*3;
+
+ HullError ret = hl.CreateConvexHull(desc,result);
+
+ if ( ret == QE_OK )
+ {
+ MyConvexResult r(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices);
+ cdesc.mCallback->ConvexDecompResult(r);
+ hl.ReleaseResult(result);
+ }
+
+ return;
+ }
+
+// printf("Performing split operation.\r\n");
+ SPLIT_MESH::SimpleMesh mesh(vcount, tcount, vertices, indices);
+ SPLIT_MESH::SimpleMesh leftMesh;
+ SPLIT_MESH::SimpleMesh rightMesh;
+ SPLIT_MESH::splitMesh(plane,mesh,leftMesh,rightMesh,cdesc.mClosedSplit);
+#if 0
+ static int splitCount=0;
+ splitCount++;
+ saveObj(mesh,splitCount,"InputMesh");
+ saveObj(leftMesh,splitCount,"LeftMesh");
+ saveObj(rightMesh,splitCount,"RightMesh");
+#endif
+
+ if ( leftMesh.mTcount )
+ {
+ doConvexDecomposition(leftMesh.mVcount, leftMesh.mVertices, leftMesh.mTcount,leftMesh.mIndices,cdesc,depth+1);
+ }
+
+ if ( rightMesh.mTcount )
+ {
+ doConvexDecomposition(rightMesh.mVcount, rightMesh.mVertices, rightMesh.mTcount,rightMesh.mIndices, cdesc, depth+1);
+ }
+ }
+ }
+
+
+
+
+
+physx::PxF32 mMergePercent;
+CHullVector mChulls;
+ConvexResultVector mResults;
+};
+
+class MyConvexDecomposition : public ConvexDecomposition, public UserAllocated, public ConvexBuilder
+{
+public:
+ MyConvexDecomposition(void)
+ {
+
+ }
+ ~MyConvexDecomposition(void)
+ {
+
+ }
+
+ virtual physx::PxU32 performConvexDecomposition(const DecompDesc &desc) // returns the number of hulls produced.
+ {
+ return ConvexBuilder::process(desc);
+ }
+
+ virtual void release(void)
+ {
+ delete this;
+ }
+
+ virtual ConvexResult * getConvexResult(physx::PxU32 index)
+ {
+ MyConvexResult *r = ConvexBuilder::getHull(index);
+ return static_cast< ConvexResult *>(r);
+ }
+
+ void setEmpty(SPLIT_MESH::SimpleMesh &m)
+ {
+ m.mVcount = 0;
+ m.mVertices = NULL;
+ m.mTcount = 0;
+ m.mIndices = NULL;
+ }
+
+ virtual void splitMesh(const physx::PxF32 *planeEquation,const TriangleMesh &input,TriangleMesh &left,TriangleMesh &right,bool closedMesh)
+ {
+
+ SPLIT_MESH::SimpleMesh sinput(input.mVcount,input.mTriCount,input.mVertices,input.mIndices);
+ SPLIT_MESH::SimpleMesh sleft;
+ SPLIT_MESH::SimpleMesh sright;
+
+ SPLIT_MESH::splitMesh(planeEquation,sinput,sleft,sright,closedMesh);
+
+ left.mVcount = sleft.mVcount;
+ left.mVertices = sleft.mVertices;
+ left.mTriCount = sleft.mTcount;
+ left.mIndices = sleft.mIndices;
+ right.mVcount = sright.mVcount;
+ right.mTriCount = sright.mTcount;
+ right.mVertices = sright.mVertices;
+ right.mIndices = sright.mIndices;
+
+ setEmpty(sleft);
+ setEmpty(sright);
+
+ }
+
+ virtual void releaseTriangleMeshMemory(TriangleMesh &mesh)
+ {
+ PX_FREE(mesh.mVertices);
+ PX_FREE(mesh.mIndices);
+ mesh.mIndices = NULL;
+ mesh.mVertices = NULL;
+ mesh.mTriCount = 0;
+ mesh.mVcount = 0;
+ }
+
+};
+
+
+ConvexDecomposition * createConvexDecomposition(void)
+{
+ MyConvexDecomposition *m = PX_NEW(MyConvexDecomposition);
+ return static_cast<ConvexDecomposition *>(m);
+}
+
+
+}; // end of namespace
+
diff --git a/APEX_1.4/shared/general/ConvexDecomposition/src/SplitMesh.cpp b/APEX_1.4/shared/general/ConvexDecomposition/src/SplitMesh.cpp
new file mode 100644
index 00000000..253257d3
--- /dev/null
+++ b/APEX_1.4/shared/general/ConvexDecomposition/src/SplitMesh.cpp
@@ -0,0 +1,190 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved.
+
+#include "SplitMesh.h"
+#include "FloatMath.h"
+#include "PsArray.h"
+#include "foundation/PxVec3.h"
+#include "foundation/PxQuat.h"
+#include "foundation/PxMat44.h"
+
+using namespace physx::general_floatmath2;
+using namespace physx::shdfnd;
+using namespace physx;
+
+#pragma warning(disable:4100)
+
+namespace SPLIT_MESH
+{
+
+static void addTri(const PxF32 *p1,
+ const PxF32 *p2,
+ const PxF32 *p3,
+ Array< PxU32 > &indices,
+ fm_VertexIndex *vertices)
+{
+ bool newPos;
+
+ PxU32 i1 = vertices->getIndex(p1,newPos);
+ PxU32 i2 = vertices->getIndex(p2,newPos);
+ PxU32 i3 = vertices->getIndex(p3,newPos);
+
+ indices.pushBack(i1);
+ indices.pushBack(i2);
+ indices.pushBack(i3);
+}
+
+PX_INLINE void rotationArc(const PxVec3 &v0,const PxVec3 &v1,PxQuat &quat)
+{
+ PxVec3 cross = v0.cross(v1);
+ PxF32 d = v0.dot(v1);
+
+ if(d<=-1.0f) // 180 about x axis
+ {
+ quat.x = 1.0f;
+ quat.y = quat.z = quat.w =0.0f;
+ return;
+ }
+
+ PxF32 s = PxSqrt((1+d)*2);
+ PxF32 recip = 1.0f / s;
+
+ quat.x = cross.x * recip;
+ quat.y = cross.y * recip;
+ quat.z = cross.z * recip;
+ quat.w = s * 0.5f;
+
+}
+
+void computePlaneQuad(const PxF32 *planeEquation,physx::PxVec3 *quad)
+{
+ PxVec3 ref(0,1,0);
+ PxQuat quat;
+ PxVec3 normal(planeEquation[0],planeEquation[1],planeEquation[2]);
+ rotationArc(ref,normal,quat);
+ PxMat44 matrix(quat);
+
+ PxVec3 origin(0,-planeEquation[3],0);
+ PxVec3 center = matrix.transform(origin);
+#define PLANE_DIST 1000
+ PxVec3 upperLeft(-PLANE_DIST,0,-PLANE_DIST);
+ PxVec3 upperRight(PLANE_DIST,0,-PLANE_DIST);
+ PxVec3 lowerRight(PLANE_DIST,0,PLANE_DIST);
+ PxVec3 lowerLeft(-PLANE_DIST,0,PLANE_DIST);
+
+ quad[0] = matrix.transform(upperLeft);
+ quad[1] = matrix.transform(upperRight);
+ quad[2] = matrix.transform(lowerRight);
+ quad[3] = matrix.transform(lowerLeft);
+}
+
+void splitMesh(const PxF32 *planeEquation,const SimpleMesh &input,SimpleMesh &leftMesh,SimpleMesh &rightMesh,bool /*closedMesh*/)
+{
+ Array< PxU32 > leftIndices;
+ Array< PxU32 > rightIndices;
+
+ fm_VertexIndex *leftVertices = fm_createVertexIndex(0.00001f,false);
+ fm_VertexIndex *rightVertices = fm_createVertexIndex(0.00001f,false);
+
+ {
+ for (PxU32 i=0; i<input.mTcount; i++)
+ {
+ PxU32 i1 = input.mIndices[i*3+0];
+ PxU32 i2 = input.mIndices[i*3+1];
+ PxU32 i3 = input.mIndices[i*3+2];
+
+ PxF32 *p1 = &input.mVertices[i1*3];
+ PxF32 *p2 = &input.mVertices[i2*3];
+ PxF32 *p3 = &input.mVertices[i3*3];
+
+ PxF32 tri[3*3];
+
+ tri[0] = p1[0];
+ tri[1] = p1[1];
+ tri[2] = p1[2];
+
+ tri[3] = p2[0];
+ tri[4] = p2[1];
+ tri[5] = p2[2];
+
+ tri[6] = p3[0];
+ tri[7] = p3[1];
+ tri[8] = p3[2];
+
+ PxF32 front[3*5];
+ PxF32 back[3*5];
+
+ PxU32 fcount,bcount;
+
+ PlaneTriResult result = fm_planeTriIntersection(planeEquation,tri,sizeof(PxF32)*3,0.00001f,front,fcount,back,bcount);
+
+ switch ( result )
+ {
+ case PTR_FRONT:
+ addTri(p1,p2,p3,leftIndices,leftVertices);
+ break;
+ case PTR_BACK:
+ addTri(p1,p2,p3,rightIndices,rightVertices);
+ break;
+ case PTR_SPLIT:
+ if ( fcount )
+ {
+ addTri(&front[0],&front[3],&front[6],leftIndices,leftVertices);
+ if ( fcount == 4 )
+ {
+ addTri(&front[0],&front[6],&front[9],leftIndices,leftVertices);
+ }
+ }
+ if ( bcount )
+ {
+ addTri(&back[0],&back[3],&back[6],rightIndices,rightVertices);
+ if ( bcount == 4 )
+ {
+ addTri(&back[0],&back[6],&back[9],rightIndices,rightVertices);
+ }
+ }
+ break;
+ case PTR_ON_PLANE: // Make compiler happy
+ break;
+ }
+ }
+ }
+
+ if ( !leftIndices.empty() )
+ {
+ leftMesh.set(leftVertices->getVcount(),leftIndices.size()/3,leftVertices->getVerticesFloat(),&leftIndices[0]);
+ }
+
+ if ( !rightIndices.empty() )
+ {
+ rightMesh.set(rightVertices->getVcount(),rightIndices.size()/3,rightVertices->getVerticesFloat(),&rightIndices[0]);
+ }
+ fm_releaseVertexIndex(leftVertices);
+ fm_releaseVertexIndex(rightVertices);
+}
+
+};