Torque3D/Engine/lib/convexDecomp/NvRemoveTjunctions.cpp

707 lines
15 KiB
C++
Raw Normal View History

2012-09-19 15:15:01 +00:00
/*
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#pragma warning(disable:4702)
#pragma warning(disable:4127) //conditional expression is constant (because _HAS_EXCEPTIONS=0)
#include <vector>
#ifdef __APPLE__
#include <ext/hash_map>
#else
#include <hash_map>
#endif
#include "NvUserMemAlloc.h"
#include "NvHashMap.h"
#include "NvRemoveTjunctions.h"
#include "NvFloatMath.h"
#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; i<tcount; i++)
{
if ( ids ) id = *ids++;
e =init(t,indices,vertices,e,id);
indices+=3;
t++;
}
{
TriangleVector test;
for (EdgeMap::Iterator i = mEdgeMap.getIterator(); !i.done(); ++i)
{
RtEdge *e = (*i).second;
if ( e->mNextEdge == 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; i<mTcount; i++)
{
mIndices.pushBack(t->mI1);
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; i<tcount_out; i++)
{
NxU32 i1 = scan[0];
NxU32 i2 = scan[1];
NxU32 i3 = scan[2];
assert( i1 != i2 && i1 != i3 && i2 != i3 );
scan+=3;
}
}
#endif
return ret;
}
Triangle * locateIntersection(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;
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<mTcount; i++)
{
ret = locateIntersection(scan,t);
if ( ret )
break;
scan++;
}
return ret;
}
Triangle *mInputTriangles;
NxU32 mVcount;
NxU32 mMaxTcount;
NxU32 mTcount;
const float *mVertices;
NxU32Vector mIndices;
NxU32Vector mIds;
TriangleVector mSplit;
NxU32 mEdgeCount;
RtEdge *mEdges;
EdgeMap mEdgeMap;
NxF32 mEpsilon;
};
RemoveTjunctions * createRemoveTjunctions(void)
{
MyRemoveTjunctions *m = new MyRemoveTjunctions;
return static_cast< RemoveTjunctions *>(m);
}
void releaseRemoveTjunctions(RemoveTjunctions *tj)
{
MyRemoveTjunctions *m = static_cast< MyRemoveTjunctions *>(tj);
delete m;
}
}; // end of namespace