#include #include #include #include #include #include #include "./ConvexDecomposition/ConvexDecomposition.h" #include "./ConvexDecomposition/cd_wavefront.h" using namespace ConvexDecomposition; // Test application to demonstrate how to use the ConvexDecomposition system. typedef std::vector< ConvexResult * > ConvexResultVector; static const char * fstring(float v) { static char data[64*16]; static int index=0; char *ret = &data[index*64]; index++; if (index == 16 ) index = 0; if ( v == FLT_MIN ) return "-INF"; // collada notation for FLT_MIN and FLT_MAX if ( v == FLT_MAX ) return "INF"; if ( v == 1 ) { strcpy(ret,"1"); } else if ( v == 0 ) { strcpy(ret,"0"); } else if ( v == - 1 ) { strcpy(ret,"-1"); } else { sprintf(ret,"%.9f", v ); const char *dot = strstr(ret,"."); if ( dot ) { int len = (int)strlen(ret); char *foo = &ret[len-1]; while ( *foo == '0' ) foo--; if ( *foo == '.' ) *foo = 0; else foo[1] = 0; } } return ret; } class CBuilder : public ConvexDecompInterface { public: CBuilder(const char *fname,const DecompDesc &d) { strcpy(mBaseName,fname); char *dot = strstr(mBaseName,"."); if ( dot ) *dot = 0; sprintf(mObjName,"%s_convex.obj", mBaseName ); mBaseCount = 0; mHullCount = 0; mSkinWidth = (float)d.mSkinWidth; mFph = fopen(mObjName,"wb"); printf("########################################################################\r\n"); printf("# Perfomring approximate convex decomposition for triangle mesh %s\r\n", fname ); printf("# Input Mesh has %d vertices and %d triangles.\r\n", d.mVcount, d.mTcount ); printf("# Recursion depth: %d\r\n", d.mDepth ); printf("# Concavity Threshold Percentage: %0.2f\r\n", d.mCpercent ); printf("# Hull Merge Volume Percentage: %0.2f\r\n", d.mPpercent ); printf("# Maximum output vertices per hull: %d\r\n", d.mMaxVertices ); printf("# Hull Skin Width: %0.2f\r\n", d.mSkinWidth ); printf("########################################################################\r\n"); if ( mFph ) { fprintf(mFph,"########################################################################\r\n"); fprintf(mFph,"# Approximate convex decomposition for triangle mesh %s\r\n", fname ); fprintf(mFph,"# Input Mesh has %d vertices and %d triangles.\r\n", d.mVcount, d.mTcount ); fprintf(mFph,"# Recursion depth: %d\r\n", d.mDepth ); fprintf(mFph,"# Concavity Threshold Percentage: %0.2f\r\n", d.mCpercent ); fprintf(mFph,"# Hull Merge Volume Percentage: %0.2f\r\n", d.mPpercent ); fprintf(mFph,"# Maximum output vertices per hull: %d\r\n", d.mMaxVertices ); fprintf(mFph,"# Hull Skin Width: %0.2f\r\n", d.mSkinWidth ); fprintf(mFph,"########################################################################\r\n"); printf("Opened Wavefront file %s for output.\r\n", mObjName ); } else { printf("Failed to open output file %s\r\n", mObjName ); } } ~CBuilder(void) { if ( mFph ) { fclose(mFph); } for (unsigned int i=0; i\r\n", mBaseName, index, mBaseName, index); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName, index); fprintf(fph," \r\n", cr->mHullVcount*3, mBaseName, index); fprintf(fph," "); for (unsigned int i=0; imHullVcount; i++) { const double *p = &cr->mHullVertices[i*3]; fprintf(fph,"%s %s %s ", fstring((float)p[0]), fstring((float)p[1]), fstring((float)p[2]) ); if ( ((i+1)&3) == 0 && (i+1) < cr->mHullVcount ) { fprintf(fph,"\r\n"); fprintf(fph," "); } } fprintf(fph,"\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", cr->mHullVcount, mBaseName, index ); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName, index); fprintf(fph," \r\n", mBaseName, index); fprintf(fph," \r\n"); fprintf(fph," \r\n", cr->mHullTcount ); fprintf(fph," \r\n", mBaseName, index); fprintf(fph,"

\r\n"); fprintf(fph," "); for (unsigned int i=0; imHullTcount; i++) { unsigned int *tri = &cr->mHullIndices[i*3]; fprintf(fph,"%d %d %d ", tri[0], tri[1], tri[2] ); if ( ((i+1)&3) == 0 && (i+1) < cr->mHullTcount ) { fprintf(fph,"\r\n"); fprintf(fph," "); } } fprintf(fph,"\r\n"); fprintf(fph,"

\r\n"); fprintf(fph,"
\r\n"); fprintf(fph,"
\r\n"); fprintf(fph," \r\n"); } void saveCOLLADA(void) { char scratch[512]; sprintf(scratch,"%s.dae", mBaseName ); FILE *fph = fopen(scratch,"wb"); if ( fph ) { printf("Saving convex decomposition of %d hulls to COLLADA file '%s'\r\n", (int)mHulls.size(), scratch ); fprintf(fph,"\r\n"); fprintf(fph,"\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," NxuStream2 converter - http://www.ageia.com\r\n"); fprintf(fph," PhysX Rocket, PhysX Viewer, or CreateDynamics\r\n"); fprintf(fph," questions to: jratcliff@ageia.com\r\n"); fprintf(fph," \r\n"); fprintf(fph," chair_gothic_tilted\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," Y_UP\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0.803922 0.588235 0.92549 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0.803922 0.588235 0.92549 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0.631373 0.631373 0.631373 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0 0 0 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 1 1 1 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); for (unsigned int i=0; i\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName, mBaseName ); fprintf(fph," 0 0 0\r\n"); fprintf(fph," 1 0 0 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0.5\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0.5\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName, mBaseName); fprintf(fph," \r\n"); fprintf(fph," \r\n"); for (unsigned int i=0; i\r\n"); fprintf(fph," 0 0 0\r\n"); fprintf(fph," 1 0 0 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," %s\r\n", fstring( mSkinWidth ) ); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName, i); fprintf(fph," \r\n"); } fprintf(fph," true\r\n"); fprintf(fph," 1\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 32\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," false\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName, mBaseName ); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0 -9.800000191 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph,"\r\n"); fclose(fph); } else { printf("Failed to open file '%s' for write access.\r\n", scratch ); } } void saveXML(FILE *fph,unsigned int index,ConvexResult *cr) { fprintf(fph," \r\n", mBaseName, index); fprintf(fph," \r\n"); fprintf(fph," "); for (unsigned int i=0; imHullVcount; i++) { const double *p = &cr->mHullVertices[i*3]; fprintf(fph,"%s %s %s ", fstring((float)p[0]), fstring((float)p[1]), fstring((float)p[2]) ); if ( ((i+1)&3) == 0 && (i+1) < cr->mHullVcount ) { fprintf(fph,"\r\n"); fprintf(fph," "); } } fprintf(fph,"\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," "); for (unsigned int i=0; imHullTcount; i++) { unsigned int *tri = &cr->mHullIndices[i*3]; fprintf(fph,"%d %d %d ", tri[0], tri[1], tri[2] ); if ( ((i+1)&3) == 0 && (i+1) < cr->mHullTcount ) { fprintf(fph,"\r\n"); fprintf(fph," "); } } fprintf(fph,"\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); } void saveNxuStream(void) { char scratch[512]; sprintf(scratch,"%s.xml", mBaseName ); FILE *fph = fopen(scratch,"wb"); if ( fph ) { printf("Saving convex decomposition of %d hulls to NxuStream file '%s'\r\n", mHulls.size(), scratch ); fprintf(fph,"\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 65536\r\n"); fprintf(fph," 256\r\n"); fprintf(fph," 2048\r\n"); fprintf(fph," \r\n"); for (unsigned int i=0; i\r\n", mBaseName); fprintf(fph," false\r\n"); fprintf(fph," NX_FILTEROP_AND\r\n"); fprintf(fph," NX_FILTEROP_AND\r\n"); fprintf(fph," NX_FILTEROP_AND\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," 0 -9.800000191 0\r\n"); fprintf(fph," 0.016666668\r\n"); fprintf(fph," 8\r\n"); fprintf(fph," NX_TIMESTEP_FIXED\r\n"); fprintf(fph," FLT_MIN FLT_MIN FLT_MIN FLT_MAX FLT_MAX FLT_MAX\r\n"); fprintf(fph," \r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," NX_SIMULATION_SW\r\n"); fprintf(fph," true\r\n"); fprintf(fph," false\r\n"); fprintf(fph," \r\n"); fprintf(fph," false\r\n"); fprintf(fph," false\r\n"); fprintf(fph," true\r\n"); fprintf(fph," false\r\n"); fprintf(fph," \r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 1431655764\r\n"); fprintf(fph," 1431655764\r\n"); fprintf(fph," \r\n"); fprintf(fph," 0.5\r\n"); fprintf(fph," 0.5\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," NX_CM_AVERAGE\r\n"); fprintf(fph," NX_CM_AVERAGE\r\n"); fprintf(fph," 1 0 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," false\r\n"); fprintf(fph," false\r\n"); fprintf(fph," false\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName, mBaseName); fprintf(fph," 1 0 0 0 1 0 0 0 1 0 0 0 \r\n"); fprintf(fph," \r\n"); fprintf(fph," 1\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," 32\r\n"); fprintf(fph," \r\n"); fprintf(fph," true\r\n"); fprintf(fph," false\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," Bip01 Pelvis\r\n"); for (unsigned int i=0; i\r\n", i, mBaseName, i); fprintf(fph," \r\n"); fprintf(fph," 1 0 0 0 1 0 0 0 1 0 0 0 \r\n"); fprintf(fph," 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); } fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n", mBaseName); fprintf(fph," beshon\r\n"); fprintf(fph," \r\n"); fprintf(fph," 1 0 0 0 1 0 0 0 1 0 0 0\r\n"); fprintf(fph," false\r\n"); fprintf(fph," true\r\n"); fprintf(fph," 0\r\n"); fprintf(fph," \r\n"); fprintf(fph," \r\n"); fprintf(fph,"\r\n"); } else { printf("Failed to open file '%s' for write access.\r\n", scratch ); } } float mSkinWidth; unsigned int mHullCount; FILE *mFph; unsigned int mBaseCount; char mObjName[512]; char mBaseName[512]; ConvexResultVector mHulls; }; int main(int argc,const char **argv) { if ( argc < 2 ) { printf("Usage: Test (options)\r\n"); printf("\r\n"); printf("Options:\r\n"); printf("\r\n"); printf(" -d : How deep to recursively split. Values of 3-7 are reasonable.\r\n"); printf(" -c : Percentage of concavity to keep splitting. 0-20% is reasonable.\r\n"); printf(" -p : Percentage of volume delta to collapse hulls. 0-30% is reasonable.\r\n"); printf(" -v : Maximum number of vertices in the output hull. Default is 32.\r\n"); printf(" -s : Skin Width inflation. Default is 0.\r\n"); } else { unsigned int depth = 5; float cpercent = 5; float ppercent = 5; unsigned int maxv = 32; float skinWidth = 0; // process command line switches. for (int i=2; i 10 ) { depth = 5; printf("Invalid depth value in switch, defaulting to 5.\r\n"); } } if ( strncmp(o,"-c",2) == 0 ) { cpercent = (float) atof( &o[2] ); if ( cpercent < 0 || cpercent > 100 ) { cpercent = 5; printf("Invalid concavity percentage in switch, defaulting to 5.\r\n"); } } if ( strncmp(o,"-p",2) == 0 ) { ppercent = (float) atof( &o[2] ); if ( ppercent < 0 || ppercent > 100 ) { ppercent = 5; printf("Invalid hull merge percentage in switch, defaulting to 5.\r\n"); } } if ( strncmp(o,"-v",2) == 0 ) { maxv = (unsigned int) atoi( &o[2] ); if ( maxv < 8 || maxv > 256 ) { maxv = 32; printf("Invalid max vertices in switch, defaulting to 32.\r\n"); } } if ( strncmp(o,"-s",2) == 0 ) { skinWidth = (float) atof( &o[2] ); if ( skinWidth < 0 || skinWidth > 0.1f ) { skinWidth = 0; printf("Invalid skinWidth in switch, defaulting to 0.\r\n"); } } } WavefrontObj wo; unsigned int tcount = wo.loadObj(argv[1]); if ( tcount ) { DecompDesc d; d.mVcount = wo.mVertexCount; d.mVertices = wo.mVertices; d.mTcount = wo.mTriCount; d.mIndices = (unsigned int *)wo.mIndices; d.mDepth = depth; d.mCpercent = cpercent; d.mPpercent = ppercent; d.mMaxVertices = maxv; d.mSkinWidth = skinWidth; CBuilder cb(argv[1],d); // receives the answers and writes out a wavefront OBJ file. d.mCallback = &cb; unsigned int count = performConvexDecomposition(d); if ( count ) { printf("Input triangle mesh with %d triangles produced %d output hulls.\r\n", d.mTcount, count ); cb.saveNxuStream(); // save results in NxuStream format. cb.saveCOLLADA(); // save results in COLLADA physics 1.4.1 format. } else { printf("Failed to produce any convex hulls.\r\n"); } } else { // sorry..no printf("Sorry unable to load file '%s'\r\n", argv[1] ); } } }