/* NvRemoveTjunctions.cpp : A code snippet to remove tjunctions from a triangle mesh. This version is currently disabled as it appears to have a bug. */ /*! ** ** Copyright (c) 2009 by John W. Ratcliff mailto:jratcliffscarab@gmail.com ** ** Portions of this source has been released with the PhysXViewer application, as well as ** Rocket, CreateDynamics, ODF, and as a number of sample code snippets. ** ** If you find this code useful or you are feeling particularily generous I would ** ask that you please go to http://www.amillionpixels.us and make a donation ** to Troy DeMolay. ** ** DeMolay is a youth group for young men between the ages of 12 and 21. ** It teaches strong moral principles, as well as leadership skills and ** public speaking. The donations page uses the 'pay for pixels' paradigm ** where, in this case, a pixel is only a single penny. Donations can be ** made for as small as $4 or as high as a $100 block. Each person who donates ** will get a link to their own site as well as acknowledgement on the ** donations blog located here http://www.amillionpixels.blogspot.com/ ** ** If you wish to contact me you can use the following methods: ** ** Skype ID: jratcliff63367 ** Yahoo: jratcliff63367 ** AOL: jratcliff1961 ** email: jratcliffscarab@gmail.com ** ** ** The MIT license: ** ** Permission is hereby granted, free of charge, to any person obtaining a copy ** of this software and associated documentation files (the "Software"), to deal ** in the Software without restriction, including without limitation the rights ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ** copies of the Software, and to permit persons to whom the Software is furnished ** to do so, subject to the following conditions: ** ** The above copyright notice and this permission notice shall be included in all ** copies or substantial portions of the Software. ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, ** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #pragma warning(disable:4702) #pragma warning(disable:4127) //conditional expression is constant (because _HAS_EXCEPTIONS=0) #include #ifdef __APPLE__ #include #elif LINUX #include #elif _MSC_VER < 1500 #include #elif _MSC_VER > 1800 #include #endif #include "NvUserMemAlloc.h" #include "NvHashMap.h" #include "NvRemoveTjunctions.h" #include "NvFloatMath.h" #ifdef LINUX #include #endif #pragma warning(disable:4189) using namespace CONVEX_DECOMPOSITION; namespace CONVEX_DECOMPOSITION { class AABB { public: NxF32 mMin[3]; NxF32 mMax[3]; }; bool gDebug=false; NxU32 gCount=0; typedef CONVEX_DECOMPOSITION::Array< NxU32 > NxU32Vector; class Triangle { public: Triangle(void) { mPending = false; mSplit = false; mI1 = mI2 = mI3 = 0xFFFFFFFF; mId = 0; } Triangle(NxU32 i1,NxU32 i2,NxU32 i3,const float *vertices,NxU32 id) { mPending = false; init(i1,i2,i3,vertices,id); mSplit = false; } void init(NxU32 i1,NxU32 i2,NxU32 i3,const float *vertices,NxU32 id) { mSplit = false; mI1 = i1; mI2 = i2; mI3 = i3; mId = id; const float *p1 = &vertices[mI1*3]; const float *p2 = &vertices[mI2*3]; const float *p3 = &vertices[mI3*3]; initMinMax(p1,p2,p3); } void initMinMax(const float *p1,const float *p2,const float *p3) { fm_copy3(p1,mBmin); fm_copy3(p1,mBmax); fm_minmax(p2,mBmin,mBmax); fm_minmax(p3,mBmin,mBmax); } void init(const NxU32 *idx,const float *vertices,NxU32 id) { mSplit = false; mI1 = idx[0]; mI2 = idx[1]; mI3 = idx[2]; mId = id; const float *p1 = &vertices[mI1*3]; const float *p2 = &vertices[mI2*3]; const float *p3 = &vertices[mI3*3]; initMinMax(p1,p2,p3); } bool intersects(const float *pos,const float *p1,const float *p2,float epsilon) const { bool ret = false; float sect[3]; LineSegmentType type; float dist = fm_distancePointLineSegment(pos,p1,p2,sect,type,epsilon); if ( type == LS_MIDDLE && dist < epsilon ) { ret = true; } return ret; } bool intersects(NxU32 i,const float *vertices,NxU32 &edge,float epsilon) const { bool ret = true; const float *pos = &vertices[i*3]; const float *p1 = &vertices[mI1*3]; const float *p2 = &vertices[mI2*3]; const float *p3 = &vertices[mI3*3]; if ( intersects(pos,p1,p2,epsilon) ) { edge = 0; } else if ( intersects(pos,p2,p3,epsilon) ) { edge = 1; } else if ( intersects(pos,p3,p1,epsilon) ) { edge = 2; } else { ret = false; } return ret; } bool intersects(const Triangle *t,const float *vertices,NxU32 &intersection_index,NxU32 &edge,float epsilon) { bool ret = false; if ( fm_intersectAABB(mBmin,mBmax,t->mBmin,t->mBmax) ) // only if the AABB's of the two triangles intersect... { if ( t->intersects(mI1,vertices,edge,epsilon) ) { intersection_index = mI1; ret = true; } if ( t->intersects(mI2,vertices,edge,epsilon) ) { intersection_index = mI2; ret = true; } if ( t->intersects(mI3,vertices,edge,epsilon) ) { intersection_index = mI3; ret = true; } } return ret; } bool mSplit:1; bool mPending:1; NxU32 mI1; NxU32 mI2; NxU32 mI3; NxU32 mId; float mBmin[3]; float mBmax[3]; }; class RtEdge { public: RtEdge(void) { mNextEdge = 0; mTriangle = 0; mHash = 0; } NxU32 init(Triangle *t,NxU32 i1,NxU32 i2) { mTriangle = t; mNextEdge = 0; NX_ASSERT( i1 < 65536 ); NX_ASSERT( i2 < 65536 ); if ( i1 < i2 ) { mHash = (i1<<16)|i2; } else { mHash = (i2<<16)|i1; } return mHash; } RtEdge *mNextEdge; Triangle *mTriangle; NxU32 mHash; }; typedef CONVEX_DECOMPOSITION::Array< Triangle * > TriangleVector; typedef CONVEX_DECOMPOSITION::HashMap< NxU32, RtEdge * > EdgeMap; class MyRemoveTjunctions : public RemoveTjunctions { public: MyRemoveTjunctions(void) { mInputTriangles = 0; mEdges = 0; mVcount = 0; mVertices = 0; mEdgeCount = 0; } ~MyRemoveTjunctions(void) { release(); } virtual NxU32 removeTjunctions(RemoveTjunctionsDesc &desc) { NxU32 ret = 0; mEpsilon = desc.mEpsilon; size_t TcountOut; desc.mIndicesOut = removeTjunctions(desc.mVcount, desc.mVertices, desc.mTcount, desc.mIndices, TcountOut, desc.mIds); #ifdef WIN32 # pragma warning(push) # pragma warning(disable:4267) #endif NX_ASSERT( TcountOut < UINT_MAX ); desc.mTcountOut = TcountOut; #ifdef WIN32 # pragma warning(pop) #endif if ( !mIds.empty() ) { desc.mIdsOut = &mIds[0]; } ret = desc.mTcountOut; bool check = ret != desc.mTcount; #if 0 while ( check ) { NxU32 tcount = ret; NxU32 *indices = new NxU32[tcount*3]; NxU32 *ids = new NxU32[tcount]; memcpy(indices,desc.mIndicesOut,sizeof(NxU32)*ret*3); memcpy(ids,desc.mIdsOut,sizeof(NxU32)*ret); desc.mIndicesOut = removeTjunctions(desc.mVcount, desc.mVertices, tcount, indices, desc.mTcountOut, ids ); if ( !mIds.empty() ) { desc.mIdsOut = &mIds[0]; } ret = desc.mTcountOut; delete []indices; delete []ids; check = ret != tcount; } #endif return ret; } RtEdge * addEdge(Triangle *t,RtEdge *e,NxU32 i1,NxU32 i2) { NxU32 hash = e->init(t,i1,i2); const EdgeMap::Entry *found = mEdgeMap.find(hash); if ( found == NULL ) { mEdgeMap[hash] = e; } else { RtEdge *old_edge = (*found).second; e->mNextEdge = old_edge; mEdgeMap.erase(hash); mEdgeMap[hash] = e; } e++; mEdgeCount++; return e; } RtEdge * init(Triangle *t,const NxU32 *indices,const float *vertices,RtEdge *e,NxU32 id) { t->init(indices,vertices,id); e = addEdge(t,e,t->mI1,t->mI2); e = addEdge(t,e,t->mI2,t->mI3); e = addEdge(t,e,t->mI3,t->mI1); return e; } void release(void) { mIds.clear(); mEdgeMap.clear(); mIndices.clear(); mSplit.clear(); delete []mInputTriangles; delete []mEdges; mInputTriangles = 0; mEdges = 0; mVcount = 0; mVertices = 0; mEdgeCount = 0; } virtual NxU32 * removeTjunctions(NxU32 vcount, const float *vertices, size_t tcount, const NxU32 *indices, size_t &tcount_out, const NxU32 * ids) { NxU32 *ret = 0; release(); mVcount = vcount; mVertices = vertices; mTcount = (NxU32)tcount; tcount_out = 0; mTcount = (NxU32)tcount; mMaxTcount = (NxU32)tcount*2; mInputTriangles = new Triangle[mMaxTcount]; Triangle *t = mInputTriangles; mEdges = new RtEdge[mMaxTcount*3]; mEdgeCount = 0; NxU32 id = 0; RtEdge *e = mEdges; for (NxU32 i=0; imNextEdge == 0 ) // open edge! { Triangle *t = e->mTriangle; if ( !t->mPending ) { test.pushBack(t); t->mPending = true; } } } if ( !test.empty() ) { TriangleVector::Iterator i; for (i=test.begin(); i!=test.end(); ++i) { Triangle *t = (*i); locateIntersection(t); } } } while ( !mSplit.empty() ) { TriangleVector scan = mSplit; mSplit.clear(); TriangleVector::Iterator i; for (i=scan.begin(); i!=scan.end(); ++i) { Triangle *t = (*i); locateIntersection(t); } } mIndices.clear(); mIds.clear(); t = mInputTriangles; for (NxU32 i=0; imI1); mIndices.pushBack(t->mI2); mIndices.pushBack(t->mI3); mIds.pushBack(t->mId); t++; } mEdgeMap.clear(); delete []mEdges; mEdges = 0; delete []mInputTriangles; mInputTriangles = 0; tcount_out = mIndices.size()/3; ret = tcount_out ? &mIndices[0] : 0; #ifdef _DEBUG if ( ret ) { const NxU32 *scan = ret; for (NxU32 i=0; imI1 < mVcount ); NX_ASSERT( scan->mI2 < mVcount ); NX_ASSERT( scan->mI3 < mVcount ); NX_ASSERT( t->mI1 < mVcount ); NX_ASSERT( t->mI2 < mVcount ); NX_ASSERT( t->mI3 < mVcount ); NxU32 intersection_index; NxU32 edge; if ( scan != t && scan->intersects(t,mVertices,intersection_index,edge,mEpsilon) ) { if ( t->mI1 == intersection_index || t->mI2 == intersection_index || t->mI3 == intersection_index ) { } else { // here is where it intersects! NxU32 i1,i2,i3; NxU32 j1,j2,j3; NxU32 id = t->mId; switch ( edge ) { case 0: i1 = t->mI1; i2 = intersection_index; i3 = t->mI3; j1 = intersection_index; j2 = t->mI2; j3 = t->mI3; break; case 1: i1 = t->mI2; i2 = intersection_index; i3 = t->mI1; j1 = intersection_index; j2 = t->mI3; j3 = t->mI1; break; case 2: i1 = t->mI3; i2 = intersection_index; i3 = t->mI2; j1 = intersection_index; j2 = t->mI1; j3 = t->mI2; break; default: NX_ASSERT(0); i1 = i2 = i3 = 0; j1 = j2 = j3 = 0; break; } if ( mTcount < mMaxTcount ) { t->init(i1,i2,i3,mVertices,id); Triangle *newt = &mInputTriangles[mTcount]; newt->init(j1,j2,j3,mVertices,id); mTcount++; t->mSplit = true; newt->mSplit = true; mSplit.pushBack(t); mSplit.pushBack(newt); ret = scan; } } } return ret; } Triangle * testIntersection(Triangle *scan,Triangle *t) { Triangle *ret = 0; NxU32 t1 = (NxU32)(scan-mInputTriangles); NxU32 t2 = (NxU32)(t-mInputTriangles); NX_ASSERT( t1 < mTcount ); NX_ASSERT( t2 < mTcount ); NX_ASSERT( scan->mI1 < mVcount ); NX_ASSERT( scan->mI2 < mVcount ); NX_ASSERT( scan->mI3 < mVcount ); NX_ASSERT( t->mI1 < mVcount ); NX_ASSERT( t->mI2 < mVcount ); NX_ASSERT( t->mI3 < mVcount ); NxU32 intersection_index; NxU32 edge; assert( scan != t ); if ( scan->intersects(t,mVertices,intersection_index,edge,mEpsilon) ) { // here is where it intersects! NxU32 i1,i2,i3; NxU32 j1,j2,j3; NxU32 id = t->mId; switch ( edge ) { case 0: i1 = t->mI1; i2 = intersection_index; i3 = t->mI3; j1 = intersection_index; j2 = t->mI2; j3 = t->mI3; break; case 1: i1 = t->mI2; i2 = intersection_index; i3 = t->mI1; j1 = intersection_index; j2 = t->mI3; j3 = t->mI1; break; case 2: i1 = t->mI3; i2 = intersection_index; i3 = t->mI2; j1 = intersection_index; j2 = t->mI1; j3 = t->mI2; break; default: NX_ASSERT(0); i1 = i2 = i3 = 0; j1 = j2 = j3 = 0; break; } if ( mTcount < mMaxTcount ) { t->init(i1,i2,i3,mVertices,id); Triangle *newt = &mInputTriangles[mTcount]; newt->init(j1,j2,j3,mVertices,id); mTcount++; t->mSplit = true; newt->mSplit = true; mSplit.pushBack(t); mSplit.pushBack(newt); ret = scan; } } return ret; } Triangle * locateIntersection(Triangle *t) { Triangle *ret = 0; Triangle *scan = mInputTriangles; for (NxU32 i=0; i(m); } void releaseRemoveTjunctions(RemoveTjunctions *tj) { MyRemoveTjunctions *m = static_cast< MyRemoveTjunctions *>(tj); delete m; } }; // end of namespace