final cleanup

final cleanup removal of the old convexDecomp library
ADDDED: library for the floatmath from v-hacd resource, required for fit sphere/capsule/box functions
This commit is contained in:
marauder2k7 2024-05-12 15:13:03 +01:00
parent eb33fe04af
commit 109d8c06e9
33 changed files with 5851 additions and 17189 deletions

View file

@ -112,6 +112,7 @@ mark_as_advanced(SDL_XINPUT)
add_subdirectory(sdl ${TORQUE_LIB_TARG_DIRECTORY}/sdl2 EXCLUDE_FROM_ALL)
add_subdirectory(nativeFileDialogs ${TORQUE_LIB_TARG_DIRECTORY}/nfd EXCLUDE_FROM_ALL)
add_subdirectory(convexMath ${TORQUE_LIB_TARG_DIRECTORY}/convexMath EXCLUDE_FROM_ALL)
# Assimp
advanced_option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)

View file

@ -1,7 +0,0 @@
file(GLOB CONVEX_DECOMP_SOURCES "*.cpp")
add_library(convexDecomp STATIC ${CONVEX_DECOMP_SOURCES})
target_include_directories(convexDecomp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
if (UNIX AND NOT APPLE)
target_compile_definitions(convexDecomp PUBLIC LINUX)
endif (UNIX AND NOT APPLE)

View file

@ -1,252 +0,0 @@
/*
NvConcavityVolume.cpp : This is a code snippet that computes the volume of concavity of a traingle mesh.
*/
/*!
**
** 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.
*/
#define SHOW_DEBUG 0
#if SHOW_DEBUG
#include "RenderDebug.h"
#endif
#include "NvConcavityVolume.h"
#include "NvFloatMath.h"
#include "NvRayCast.h"
#include <stdio.h>
#pragma warning(disable:4100 4189 4505 4127 4101)
namespace CONVEX_DECOMPOSITION
{
bool raycast(const NxF32 *p1,const NxF32 *normal,NxF32 *dest,iRayCast *cast_hull,iRayCast *cast_mesh)
{
bool ret = true;
NxF32 hit_hull[3];
NxF32 hit_hullNormal[3];
NxF32 hit_mesh[3];
NxF32 hit_meshNormal[3];
bool hitHull = cast_hull->castRay(p1,normal,hit_hull,hit_hullNormal);
bool hitMesh = cast_mesh->castRay(p1,normal,hit_mesh,hit_meshNormal);
if ( hitMesh )
{
float dot = fm_dot(normal,hit_meshNormal);
if ( dot < 0 ) // skip if we hit an internal face of the mesh when projection out towards the convex hull.
{
ret = false;
}
else
{
NxF32 d1 = fm_distanceSquared(p1,hit_mesh);
NxF32 d2 = fm_distanceSquared(p1,hit_hull);
if ( d1 < d2 )
{
dest[0] = hit_mesh[0];
dest[1] = hit_mesh[1];
dest[2] = hit_mesh[2];
}
else
{
dest[0] = hit_hull[0];
dest[1] = hit_hull[1];
dest[2] = hit_hull[2];
}
}
}
else if ( hitHull )
{
dest[0] = hit_hull[0];
dest[1] = hit_hull[1];
dest[2] = hit_hull[2];
}
else
{
ret = false;
}
return ret;
}
void addTri(NxU32 *indices,NxU32 i1,NxU32 i2,NxU32 i3,NxU32 &tcount)
{
indices[tcount*3+0] = i1;
indices[tcount*3+1] = i2;
indices[tcount*3+2] = i3;
tcount++;
}
NxF32 computeConcavityVolume(NxU32 vcount_hull,
const NxF32 *vertices_hull,
NxU32 tcount_hull,
const NxU32 *indices_hull,
NxU32 vcount_mesh,
const NxF32 *vertices_mesh,
NxU32 tcount_mesh,
const NxU32 *indices_mesh)
{
NxF32 total_volume = 0;
#if SHOW_DEBUG
NVSHARE::gRenderDebug->pushRenderState();
NVSHARE::gRenderDebug->setCurrentDisplayTime(150.0f);
#endif
iRayCast *cast_hull = createRayCast(vertices_hull,tcount_hull,indices_hull);
iRayCast *cast_mesh = createRayCast(vertices_mesh,tcount_mesh,indices_mesh);
const NxU32 *indices = indices_mesh;
#if 0
static NxU32 index = 0;
NxU32 i = index++;
indices = &indices[i*3];
#else
for (NxU32 i=0; i<tcount_mesh; i++)
#endif
{
NxU32 i1 = indices[0];
NxU32 i2 = indices[1];
NxU32 i3 = indices[2];
const NxF32 *p1 = &vertices_mesh[i1*3];
const NxF32 *p2 = &vertices_mesh[i2*3];
const NxF32 *p3 = &vertices_mesh[i3*3];
NxF32 normal[3];
NxF32 d = fm_computePlane(p3,p2,p1,normal);
NxF32 vertices[6*3];
vertices[0] = p1[0];
vertices[1] = p1[1];
vertices[2] = p1[2];
vertices[3] = p2[0];
vertices[4] = p2[1];
vertices[5] = p2[2];
vertices[6] = p3[0];
vertices[7] = p3[1];
vertices[8] = p3[2];
NxF32 midPoint[3];
midPoint[0] = (p1[0]+p2[0]+p3[0])/3;
midPoint[1] = (p1[1]+p2[1]+p3[1])/3;
midPoint[2] = (p1[2]+p2[2]+p3[2])/3;
fm_lerp(midPoint,p1,&vertices[0],0.9999f);
fm_lerp(midPoint,p2,&vertices[3],0.9999f);
fm_lerp(midPoint,p3,&vertices[6],0.9999f);
NxF32 *_p1 = &vertices[3*3];
NxF32 *_p2 = &vertices[4*3];
NxF32 *_p3 = &vertices[5*3];
NxU32 hitCount = 0;
if ( raycast(&vertices[0],normal, _p1,cast_hull,cast_mesh) ) hitCount++;
if ( raycast(&vertices[3],normal, _p2,cast_hull,cast_mesh) ) hitCount++;
if ( raycast(&vertices[6],normal, _p3,cast_hull,cast_mesh) ) hitCount++;
// form triangle mesh!
if ( hitCount == 3 )
{
NxU32 tcount = 0;
NxU32 tindices[8*3];
addTri(tindices,2,1,0,tcount);
addTri(tindices,3,4,5,tcount);
addTri(tindices,0,3,2,tcount);
addTri(tindices,2,3,5,tcount);
addTri(tindices,1,3,0,tcount);
addTri(tindices,4,3,1,tcount);
addTri(tindices,5,4,1,tcount);
addTri(tindices,2,5,1,tcount);
NxF32 volume = fm_computeMeshVolume(vertices,tcount,tindices);
total_volume+=volume;
#if SHOW_DEBUG
NVSHARE::gRenderDebug->setCurrentColor(0x0000FF,0xFFFFFF);
NVSHARE::gRenderDebug->addToCurrentState(NVSHARE::DebugRenderState::SolidWireShaded);
for (NxU32 i=0; i<tcount; i++)
{
NxU32 i1 = tindices[i*3+0];
NxU32 i2 = tindices[i*3+1];
NxU32 i3 = tindices[i*3+2];
const NxF32 *p1 = &vertices[i1*3];
const NxF32 *p2 = &vertices[i2*3];
const NxF32 *p3 = &vertices[i3*3];
NVSHARE::gRenderDebug->DebugTri(p1,p2,p3);
}
#endif
}
indices+=3;
}
#if SHOW_DEBUG
NVSHARE::gRenderDebug->popRenderState();
#endif
releaseRayCast(cast_hull);
releaseRayCast(cast_mesh);
return total_volume;
}
}; // end of namespace

View file

@ -1,78 +0,0 @@
#ifndef NV_CONCAVITY_H
#define NV_CONCAVITY_H
/*
NvConcavityVolume.h : This is a code snippet that computes the volume of concavity of a traingle mesh.
*/
/*!
**
** 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 "NvUserMemAlloc.h"
namespace CONVEX_DECOMPOSITION
{
// computes the 'volume of concavity' of a triangle mesh projected against its surrounding convex hull.
NxF32 computeConcavityVolume(NxU32 vcount_hull,
const NxF32 *vertices_hull,
NxU32 tcount_hull,
const NxU32 *indices_hull,
NxU32 vcount_mesh,
const NxF32 *vertices_mesh,
NxU32 tcount_mesh,
const NxU32 *indices_mesh);
}; // end of namespace
#endif

View file

@ -1,788 +0,0 @@
/*
NvConvexDecomposition.cpp : The main interface to the convex decomposition library.
*/
/*!
**
** 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 <math.h>
#include <float.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "NvConvexDecomposition.h"
#include "NvHashMap.h"
#include "NvFloatMath.h"
#include "NvRemoveTjunctions.h"
#include "NvMeshIslandGeneration.h"
#include "NvStanHull.h"
#include "NvConcavityVolume.h"
#include "NvSplitMesh.h"
#include "NvThreadConfig.h"
#pragma warning(disable:4996 4100 4189)
namespace CONVEX_DECOMPOSITION
{
#define GRANULARITY 0.0000000001f
typedef CONVEX_DECOMPOSITION::Array< NxU32 > NxU32Array;
class ConvexHull : public Memalloc
{
public:
ConvexHull(NxU32 vcount,const NxF32 *vertices,NxU32 tcount,const NxU32 *indices)
{
mTested = false;
mVcount = vcount;
mTcount = tcount;
mVertices = 0;
mIndices = 0;
mHullVolume = 0;
if ( vcount )
{
mVertices = (NxF32 *)MEMALLOC_MALLOC(sizeof(NxF32)*3*vcount);
memcpy(mVertices,vertices,sizeof(NxF32)*3*vcount);
}
if ( tcount )
{
mIndices = (NxU32 *)MEMALLOC_MALLOC(sizeof(NxU32)*3*tcount);
memcpy(mIndices,indices,sizeof(NxU32)*3*tcount);
}
if ( mVcount && mTcount )
{
mHullVolume = fm_computeMeshVolume( mVertices, mTcount, mIndices);
}
}
~ConvexHull(void)
{
reset();
}
void reset(void)
{
MEMALLOC_FREE(mVertices);
MEMALLOC_FREE(mIndices);
mVertices = 0;
mIndices = 0;
mVcount = 0;
mTcount = 0;
mHullVolume = 0;
}
// return true if merging this hull with the 'mergeHull' produces a new convex hull which is no greater in volume than the
// mergeThresholdPercentage
bool canMerge(ConvexHull *mergeHull,NxF32 mergeThresholdPercent,NxU32 maxVertices,NxF32 skinWidth,NxF32 &percent)
{
bool ret = false;
if ( mHullVolume > 0 && mergeHull->mHullVolume > 0 )
{
NxU32 combineVcount = mVcount + mergeHull->mVcount;
NxF32 *vertices = (NxF32 *)MEMALLOC_MALLOC(sizeof(NxF32)*combineVcount*3);
NxF32 *dest = vertices;
const NxF32 *source = mVertices;
for (NxU32 i=0; i<mVcount; i++)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
dest+=3;
source+=3;
}
source = mergeHull->mVertices;
for (NxU32 i=0; i<mergeHull->mVcount; i++)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
dest+=3;
source+=3;
}
// create the combined convex hull.
HullDesc hd;
hd.mVcount = combineVcount;
hd.mVertices = vertices;
hd.mVertexStride = sizeof(NxF32)*3;
hd.mMaxVertices = maxVertices;
hd.mSkinWidth = skinWidth;
HullLibrary hl;
HullResult result;
hl.CreateConvexHull(hd,result);
NxF32 combinedVolume = fm_computeMeshVolume(result.mOutputVertices, result.mNumFaces, result.mIndices );
NxF32 seperateVolume = mHullVolume+mergeHull->mHullVolume;
NxF32 percentMerge = 100 - (seperateVolume*100 / combinedVolume );
if ( percentMerge <= mergeThresholdPercent )
{
percent = percentMerge;
ret = true;
}
MEMALLOC_FREE(vertices);
hl.ReleaseResult(result);
}
return ret;
}
void merge(ConvexHull *mergeHull,NxU32 maxVertices,NxF32 skinWidth)
{
NxU32 combineVcount = mVcount + mergeHull->mVcount;
NxF32 *vertices = (NxF32 *)MEMALLOC_MALLOC(sizeof(NxF32)*combineVcount*3);
NxF32 *dest = vertices;
const NxF32 *source = mVertices;
for (NxU32 i=0; i<mVcount; i++)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
dest+=3;
source+=3;
}
source = mergeHull->mVertices;
for (NxU32 i=0; i<mergeHull->mVcount; i++)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
dest+=3;
source+=3;
}
// create the combined convex hull.
HullDesc hd;
hd.mVcount = combineVcount;
hd.mVertices = vertices;
hd.mVertexStride = sizeof(NxF32)*3;
hd.mMaxVertices = maxVertices;
hd.mSkinWidth = skinWidth;
HullLibrary hl;
HullResult result;
hl.CreateConvexHull(hd,result);
reset();
mergeHull->reset();
mergeHull->mTested = true; // it's been tested.
mVcount = result.mNumOutputVertices;
mVertices = (NxF32 *)MEMALLOC_MALLOC(sizeof(NxF32)*3*mVcount);
memcpy(mVertices,result.mOutputVertices,sizeof(NxF32)*3*mVcount);
mTcount = result.mNumFaces;
mIndices = (NxU32 *)MEMALLOC_MALLOC(sizeof(NxU32)*mTcount*3);
memcpy(mIndices, result.mIndices, sizeof(NxU32)*mTcount*3);
MEMALLOC_FREE(vertices);
hl.ReleaseResult(result);
}
void setTested(bool state)
{
mTested = state;
}
bool beenTested(void) const { return mTested; };
bool mTested;
NxF32 mHullVolume;
NxU32 mVcount;
NxF32 *mVertices;
NxU32 mTcount;
NxU32 *mIndices;
};
typedef Array< ConvexHull *> ConvexHullVector;
class ConvexDecomposition : public iConvexDecomposition, public CONVEX_DECOMPOSITION::Memalloc, public ThreadInterface
{
public:
ConvexDecomposition(void)
{
mVertexIndex = 0;
mComplete = false;
mCancel = false;
mThread = 0;
}
~ConvexDecomposition(void)
{
wait();
reset();
if ( mThread )
{
tc_releaseThread(mThread);
}
}
void wait(void) const
{
while ( mThread && !mComplete );
}
virtual void reset(void) // reset the input mesh data.
{
wait();
if ( mVertexIndex )
{
fm_releaseVertexIndex(mVertexIndex);
mVertexIndex = 0;
}
mIndices.clear();
ConvexHullVector::Iterator i;
for (i=mHulls.begin(); i!=mHulls.end(); ++i)
{
ConvexHull *ch = (*i);
delete ch;
}
mHulls.clear();
}
virtual bool addTriangle(const NxF32 *p1,const NxF32 *p2,const NxF32 *p3)
{
bool ret = true;
wait();
if ( mVertexIndex == 0 )
{
mVertexIndex = fm_createVertexIndex(GRANULARITY,false);
}
bool newPos;
NxU32 i1 = mVertexIndex->getIndex(p1,newPos);
NxU32 i2 = mVertexIndex->getIndex(p2,newPos);
NxU32 i3 = mVertexIndex->getIndex(p3,newPos);
if ( i1 == i2 || i1 == i3 || i2 == i3 )
{
ret = false; // triangle is degenerate
}
else
{
mIndices.pushBack(i1);
mIndices.pushBack(i2);
mIndices.pushBack(i3);
}
return ret;
}
ConvexHull * getNonTested(void) const
{
ConvexHull *ret = 0;
for (NxU32 i=0; i<mHulls.size(); i++)
{
ConvexHull *ch = mHulls[i];
if ( !ch->beenTested() )
{
ret = ch;
break;
}
}
return ret;
}
virtual NxU32 computeConvexDecomposition(NxF32 skinWidth,
NxU32 decompositionDepth,
NxU32 maxHullVertices,
NxF32 concavityThresholdPercent,
NxF32 mergeThresholdPercent,
NxF32 volumeSplitThresholdPercent,
bool useInitialIslandGeneration,
bool useIslandGeneration,
bool useThreads)
{
NxU32 ret = 0;
if ( mThread )
return 0;
if ( mVertexIndex )
{
mSkinWidth = skinWidth;
mDecompositionDepth = decompositionDepth;
mMaxHullVertices = maxHullVertices;
mConcavityThresholdPercent = concavityThresholdPercent;
mMergeThresholdPercent = mergeThresholdPercent;
mVolumeSplitThresholdPercent = volumeSplitThresholdPercent;
mUseInitialIslandGeneration = useInitialIslandGeneration;
mUseIslandGeneration = false; // Not currently supported. useIslandGeneration;
mComplete = false;
mCancel = false;
if ( useThreads )
{
mThread = tc_createThread(this);
}
else
{
threadMain();
ret = getHullCount();
}
}
return ret;
}
void performConvexDecomposition(NxU32 vcount,
const NxF32 *vertices,
NxU32 tcount,
const NxU32 *indices,
NxF32 skinWidth,
NxU32 decompositionDepth,
NxU32 maxHullVertices,
NxF32 concavityThresholdPercent,
NxF32 mergeThresholdPercent,
NxF32 volumeSplitThresholdPercent,
bool useInitialIslandGeneration,
bool useIslandGeneration,
NxU32 depth)
{
if ( mCancel ) return;
if ( depth >= decompositionDepth ) return;
RemoveTjunctionsDesc desc;
desc.mVcount = vcount;
desc.mVertices = vertices;
desc.mTcount = tcount;
desc.mIndices = indices;
#if 0
RemoveTjunctions *rt = createRemoveTjunctions();
rt->removeTjunctions(desc);
#else
desc.mTcountOut = desc.mTcount;
desc.mIndicesOut = desc.mIndices;
#endif
// ok..we now have a clean mesh without any tjunctions.
bool island = (depth == 0 ) ? useInitialIslandGeneration : useIslandGeneration;
if ( island )
{
MeshIslandGeneration *mi = createMeshIslandGeneration();
NxU32 icount = mi->islandGenerate(desc.mTcountOut,desc.mIndicesOut,desc.mVertices);
for (NxU32 i=0; i<icount && !mCancel; i++)
{
NxU32 tcount;
NxU32 *indices = mi->getIsland(i,tcount);
baseConvexDecomposition(desc.mVcount,desc.mVertices,
tcount,indices,
skinWidth,
decompositionDepth,
maxHullVertices,
concavityThresholdPercent,
mergeThresholdPercent,
volumeSplitThresholdPercent,
useInitialIslandGeneration,
useIslandGeneration,depth);
}
releaseMeshIslandGeneration(mi);
}
else
{
baseConvexDecomposition(desc.mVcount,desc.mVertices,desc.mTcountOut,
desc.mIndicesOut,
skinWidth,
decompositionDepth,
maxHullVertices,
concavityThresholdPercent,
mergeThresholdPercent,
volumeSplitThresholdPercent,
useInitialIslandGeneration,
useIslandGeneration,depth);
}
#if 0
releaseRemoveTjunctions(rt);
#endif
}
virtual void baseConvexDecomposition(NxU32 vcount,
const NxF32 *vertices,
NxU32 tcount,
const NxU32 *indices,
NxF32 skinWidth,
NxU32 decompositionDepth,
NxU32 maxHullVertices,
NxF32 concavityThresholdPercent,
NxF32 mergeThresholdPercent,
NxF32 volumeSplitThresholdPercent,
bool useInitialIslandGeneration,
bool useIslandGeneration,
NxU32 depth)
{
if ( mCancel ) return;
bool split = false; // by default we do not split
NxU32 *out_indices = (NxU32 *)MEMALLOC_MALLOC( sizeof(NxU32)*tcount*3 );
NxF32 *out_vertices = (NxF32 *)MEMALLOC_MALLOC( sizeof(NxF32)*3*vcount );
NxU32 out_vcount = fm_copyUniqueVertices( vcount, vertices, out_vertices, tcount, indices, out_indices );
// get a copy of only the unique vertices which are actually being used.
HullDesc hd;
hd.mVcount = out_vcount;
hd.mVertices = out_vertices;
hd.mVertexStride = sizeof(NxF32)*3;
hd.mMaxVertices = maxHullVertices;
hd.mSkinWidth = skinWidth;
HullLibrary hl;
HullResult result;
hl.CreateConvexHull(hd,result);
NxF32 meshVolume = fm_computeMeshVolume(result.mOutputVertices, result.mNumFaces, result.mIndices );
if ( (depth+1) < decompositionDepth )
{
// compute the volume of this mesh...
NxF32 percentVolume = (meshVolume*100)/mOverallMeshVolume; // what percentage of the overall mesh volume are we?
if ( percentVolume > volumeSplitThresholdPercent ) // this piece must be greater thant he volume split threshold percent
{
// ok..now we will compute the concavity...
NxF32 concave_volume = computeConcavityVolume(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices, out_vcount, out_vertices, tcount, out_indices );
NxF32 concave_percent = (concave_volume*100) / meshVolume;
if ( concave_percent >= concavityThresholdPercent )
{
// ready to do split here..
split = true;
}
}
}
if ( !split )
{
saveConvexHull(result.mNumOutputVertices,result.mOutputVertices,result.mNumFaces,result.mIndices);
}
// Compute the best fit plane relative to the computed convex hull.
NxF32 plane[4];
bool ok = fm_computeSplitPlane(result.mNumOutputVertices,result.mOutputVertices,result.mNumFaces,result.mIndices,plane);
assert(ok);
hl.ReleaseResult(result);
MEMALLOC_FREE(out_indices);
MEMALLOC_FREE(out_vertices);
if ( split )
{
iSplitMesh *sm = createSplitMesh();
NvSplitMesh n;
n.mVcount = vcount;
n.mVertices = vertices;
n.mTcount = tcount;
n.mIndices = indices;
if ( ok )
{
NvSplitMesh leftMesh;
NvSplitMesh rightMesh;
sm->splitMesh(n,leftMesh,rightMesh,plane,GRANULARITY);
if ( leftMesh.mTcount )
{
performConvexDecomposition(leftMesh.mVcount,
leftMesh.mVertices,
leftMesh.mTcount,
leftMesh.mIndices,
skinWidth,
decompositionDepth,
maxHullVertices,
concavityThresholdPercent,
mergeThresholdPercent,
volumeSplitThresholdPercent,
useInitialIslandGeneration,
useIslandGeneration,
depth+1);
}
if ( rightMesh.mTcount )
{
performConvexDecomposition(rightMesh.mVcount,
rightMesh.mVertices,
rightMesh.mTcount,
rightMesh.mIndices,
skinWidth,
decompositionDepth,
maxHullVertices,
concavityThresholdPercent,
mergeThresholdPercent,
volumeSplitThresholdPercent,
useInitialIslandGeneration,
useIslandGeneration,
depth+1);
}
}
releaseSplitMesh(sm);
}
}
// Copies only the vertices which are actually used.
// Then computes the convex hull around these used vertices.
// Next computes the volume of this convex hull.
// Frees up scratch memory and returns the volume of the convex hull around the source triangle mesh.
NxF32 computeHullMeshVolume(NxU32 vcount,const NxF32 *vertices,NxU32 tcount,const NxU32 *indices,NxU32 maxVertices,NxF32 skinWidth)
{
if ( mCancel ) return 0;
// first thing we should do is compute the overall mesh volume.
NxU32 *out_indices = (NxU32 *)MEMALLOC_MALLOC( sizeof(NxU32)*tcount*3 );
NxF32 *out_vertices = (NxF32 *)MEMALLOC_MALLOC( sizeof(NxF32)*3*vcount );
NxU32 out_vcount = fm_copyUniqueVertices( vcount, vertices, out_vertices, tcount, indices, out_indices );
// get a copy of only the unique vertices which are actually being used.
HullDesc hd;
hd.mVcount = out_vcount;
hd.mVertices = out_vertices;
hd.mVertexStride = sizeof(NxF32)*3;
hd.mMaxVertices = maxVertices;
hd.mSkinWidth = skinWidth;
HullLibrary hl;
HullResult result;
hl.CreateConvexHull(hd,result);
NxF32 volume = fm_computeMeshVolume(result.mOutputVertices, result.mNumFaces, result.mIndices );
hl.ReleaseResult(result);
MEMALLOC_FREE(out_indices);
MEMALLOC_FREE(out_vertices);
return volume;
}
virtual bool isComputeComplete(void) // if building the convex hulls in a background thread, this returns true if it is complete.
{
bool ret = true;
if ( mThread )
{
ret = mComplete;
if ( ret )
{
tc_releaseThread(mThread);
mThread = 0;
}
}
return ret;
}
virtual NxU32 getHullCount(void)
{
NxU32 hullCount = 0;
wait();
if ( mCancel )
{
reset();
}
for (NxU32 i=0; i<mHulls.size(); i++)
{
ConvexHull *ch = mHulls[i];
if ( ch->mTcount )
{
hullCount++;
}
}
return hullCount;
}
virtual bool getConvexHullResult(NxU32 hullIndex,ConvexHullResult &result)
{
bool ret = false;
wait();
NxU32 index = 0;
for (NxU32 i=0; i<mHulls.size(); i++)
{
ConvexHull *ch = mHulls[i];
if ( ch->mTcount )
{
if ( hullIndex == index )
{
ret = true;
result.mVcount = ch->mVcount;
result.mTcount = ch->mTcount;
result.mVertices = ch->mVertices;
result.mIndices = ch->mIndices;
break;
}
index++;
}
}
return ret;
}
void saveConvexHull(NxU32 vcount,const NxF32 *vertices,NxU32 tcount,const NxU32 *indices)
{
ConvexHull *ch = MEMALLOC_NEW(ConvexHull)(vcount,vertices,tcount,indices);
mHulls.pushBack(ch);
}
virtual void threadMain(void)
{
mOverallMeshVolume = computeHullMeshVolume( mVertexIndex->getVcount(),
mVertexIndex->getVerticesFloat(),
mIndices.size()/3,
&mIndices[0],
mMaxHullVertices, mSkinWidth );
performConvexDecomposition(mVertexIndex->getVcount(),mVertexIndex->getVerticesFloat(),
mIndices.size()/3,&mIndices[0],
mSkinWidth,
mDecompositionDepth,
mMaxHullVertices,
mConcavityThresholdPercent,
mMergeThresholdPercent,
mVolumeSplitThresholdPercent,
mUseInitialIslandGeneration,
mUseIslandGeneration,0);
if ( mHulls.size() && !mCancel )
{
// While convex hulls can be merged...
ConvexHull *ch = getNonTested();
while ( ch && !mCancel )
{
// Sort all convex hulls by volume, largest to smallest.
NxU32 hullCount = mHulls.size();
ConvexHull *bestHull = 0;
NxF32 bestPercent = 100;
for (NxU32 i=0; i<hullCount; i++)
{
ConvexHull *mergeHull = mHulls[i];
if ( !mergeHull->beenTested() && mergeHull != ch )
{
NxF32 percent;
if ( ch->canMerge(mergeHull,mMergeThresholdPercent,mMaxHullVertices,mSkinWidth,percent) )
{
if ( percent < bestPercent )
{
bestHull = mergeHull;
bestPercent = percent;
}
}
}
}
if ( bestHull )
{
ch->merge(bestHull,mMaxHullVertices,mSkinWidth);
}
else
{
ch->setTested(true);
}
ch = getNonTested();
}
}
mComplete = true;
}
virtual bool cancelCompute(void) // cause background thread computation to abort early. Will return no results. Use 'isComputeComplete' to confirm the thread is done.
{
bool ret = false;
if ( mThread && !mComplete )
{
mCancel = true;
ret = true;
}
return ret;
}
private:
bool mComplete;
bool mCancel;
fm_VertexIndex *mVertexIndex;
NxU32Array mIndices;
NxF32 mOverallMeshVolume;
ConvexHullVector mHulls;
Thread *mThread;
NxF32 mSkinWidth;
NxU32 mDecompositionDepth;
NxU32 mMaxHullVertices;
NxF32 mConcavityThresholdPercent;
NxF32 mMergeThresholdPercent;
NxF32 mVolumeSplitThresholdPercent;
bool mUseInitialIslandGeneration;
bool mUseIslandGeneration;
};
iConvexDecomposition * createConvexDecomposition(void)
{
ConvexDecomposition *cd = MEMALLOC_NEW(ConvexDecomposition);
return static_cast< iConvexDecomposition *>(cd);
}
void releaseConvexDecomposition(iConvexDecomposition *ic)
{
ConvexDecomposition *cd = static_cast< ConvexDecomposition *>(ic);
delete cd;
}
}; // end of namespace

View file

@ -1,111 +0,0 @@
#ifndef CONVEX_DECOMPOSITION_H
#define CONVEX_DECOMPOSITION_H
/*
NvConvexDecomposition.h : The main interface to the convex decomposition library.
*/
/*!
**
** 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 "NvSimpleTypes.h"
namespace CONVEX_DECOMPOSITION
{
struct ConvexHullResult
{
NxU32 mVcount; // number of vertices.
NxF32 *mVertices; // vertex positions.
NxU32 mTcount; // number of triangles.
NxU32 *mIndices; // indexed triangle list.
};
class iConvexDecomposition
{
public:
virtual void reset(void) = 0; // reset the input mesh data.
virtual bool addTriangle(const NxF32 *p1,const NxF32 *p2,const NxF32 *p3) = 0; // add the input mesh one triangle at a time.
virtual NxU32 computeConvexDecomposition(NxF32 skinWidth=0, // Skin width on the convex hulls generated
NxU32 decompositionDepth=8, // recursion depth for convex decomposition.
NxU32 maxHullVertices=64, // maximum number of vertices in output convex hulls.
NxF32 concavityThresholdPercent=0.1f, // The percentage of concavity allowed without causing a split to occur.
NxF32 mergeThresholdPercent=30.0f, // The percentage of volume difference allowed to merge two convex hulls.
NxF32 volumeSplitThresholdPercent=0.1f, // The percentage of the total volume of the object above which splits will still occur.
bool useInitialIslandGeneration=true, // whether or not to perform initial island generation on the input mesh.
bool useIslandGeneration=false, // Whether or not to perform island generation at each split. Currently disabled due to bug in RemoveTjunctions
bool useBackgroundThread=true) = 0; // Whether or not to compute the convex decomposition in a background thread, the default is true.
virtual bool isComputeComplete(void) = 0; // if building the convex hulls in a background thread, this returns true if it is complete.
virtual bool cancelCompute(void) = 0; // cause background thread computation to abort early. Will return no results. Use 'isComputeComplete' to confirm the thread is done.
virtual NxU32 getHullCount(void) = 0; // returns the number of convex hulls produced.
virtual bool getConvexHullResult(NxU32 hullIndex,ConvexHullResult &result) = 0; // returns each convex hull result.
protected:
virtual ~iConvexDecomposition(void)
{
}
};
iConvexDecomposition * createConvexDecomposition(void);
void releaseConvexDecomposition(iConvexDecomposition *ic);
}; // end of namespace
#endif

View file

@ -1,74 +0,0 @@
// a set of routines that let you do common 3d math
// operations without any vector, matrix, or quaternion
// classes or templates.
//
// a vector (or point) is a 'NxF32 *' to 3 floating point numbers.
// a matrix is a 'NxF32 *' to an array of 16 floating point numbers representing a 4x4 transformation matrix compatible with D3D or OGL
// a quaternion is a 'NxF32 *' to 4 floats representing a quaternion x,y,z,w
//
//
/*!
**
** 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>
#include <math.h>
#include <float.h>
#include "NvFloatMath.h"
#define REAL NxF32
#include "NvFloatMath.inl"
#undef REAL
#define REAL NxF64
#include "NvFloatMath.inl"

View file

@ -1,586 +0,0 @@
#ifndef NV_FLOAT_MATH_H
#define NV_FLOAT_MATH_H
#include "NvUserMemAlloc.h"
// a set of routines that let you do common 3d math
// operations without any vector, matrix, or quaternion
// classes or templates.
//
// a vector (or point) is a 'NxF32 *' to 3 floating point numbers.
// a matrix is a 'NxF32 *' to an array of 16 floating point numbers representing a 4x4 transformation matrix compatible with D3D or OGL
// a quaternion is a 'NxF32 *' to 4 floats representing a quaternion x,y,z,w
//
//
/*!
**
** 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 <float.h>
namespace CONVEX_DECOMPOSITION
{
enum FM_ClipState
{
FMCS_XMIN = (1<<0),
FMCS_XMAX = (1<<1),
FMCS_YMIN = (1<<2),
FMCS_YMAX = (1<<3),
FMCS_ZMIN = (1<<4),
FMCS_ZMAX = (1<<5),
};
enum FM_Axis
{
FM_XAXIS = (1<<0),
FM_YAXIS = (1<<1),
FM_ZAXIS = (1<<2)
};
enum LineSegmentType
{
LS_START,
LS_MIDDLE,
LS_END
};
const NxF32 FM_PI = 3.1415926535897932384626433832795028841971693993751f;
const NxF32 FM_DEG_TO_RAD = ((2.0f * FM_PI) / 360.0f);
const NxF32 FM_RAD_TO_DEG = (360.0f / (2.0f * FM_PI));
//***************** Float versions
//***
//*** vectors are assumed to be 3 floats or 3 doubles representing X, Y, Z
//*** quaternions are assumed to be 4 floats or 4 doubles representing X,Y,Z,W
//*** matrices are assumed to be 16 floats or 16 doubles representing a standard D3D or OpenGL style 4x4 matrix
//*** bounding volumes are expressed as two sets of 3 floats/NxF64 representing bmin(x,y,z) and bmax(x,y,z)
//*** Plane equations are assumed to be 4 floats or 4 doubles representing Ax,By,Cz,D
FM_Axis fm_getDominantAxis(const NxF32 normal[3]);
FM_Axis fm_getDominantAxis(const NxF64 normal[3]);
void fm_decomposeTransform(const NxF32 local_transform[16],NxF32 trans[3],NxF32 rot[4],NxF32 scale[3]);
void fm_decomposeTransform(const NxF64 local_transform[16],NxF64 trans[3],NxF64 rot[4],NxF64 scale[3]);
void fm_multiplyTransform(const NxF32 *pA,const NxF32 *pB,NxF32 *pM);
void fm_multiplyTransform(const NxF64 *pA,const NxF64 *pB,NxF64 *pM);
void fm_inverseTransform(const NxF32 matrix[16],NxF32 inverse_matrix[16]);
void fm_inverseTransform(const NxF64 matrix[16],NxF64 inverse_matrix[16]);
void fm_identity(NxF32 matrix[16]); // set 4x4 matrix to identity.
void fm_identity(NxF64 matrix[16]); // set 4x4 matrix to identity.
void fm_inverseRT(const NxF32 matrix[16], const NxF32 pos[3], NxF32 t[3]); // inverse rotate translate the point.
void fm_inverseRT(const NxF64 matrix[16],const NxF64 pos[3],NxF64 t[3]); // inverse rotate translate the point.
void fm_transform(const NxF32 matrix[16], const NxF32 pos[3], NxF32 t[3]); // rotate and translate this point.
void fm_transform(const NxF64 matrix[16],const NxF64 pos[3],NxF64 t[3]); // rotate and translate this point.
NxF32 fm_getDeterminant(const NxF32 matrix[16]);
NxF64 fm_getDeterminant(const NxF64 matrix[16]);
void fm_getSubMatrix(NxI32 ki,NxI32 kj,NxF32 pDst[16],const NxF32 matrix[16]);
void fm_getSubMatrix(NxI32 ki,NxI32 kj,NxF64 pDst[16],const NxF32 matrix[16]);
void fm_rotate(const NxF32 matrix[16],const NxF32 pos[3],NxF32 t[3]); // only rotate the point by a 4x4 matrix, don't translate.
void fm_rotate(const NxF64 matri[16],const NxF64 pos[3],NxF64 t[3]); // only rotate the point by a 4x4 matrix, don't translate.
void fm_eulerToMatrix(NxF32 ax,NxF32 ay,NxF32 az,NxF32 matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_eulerToMatrix(NxF64 ax,NxF64 ay,NxF64 az,NxF64 matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_getAABB(NxU32 vcount,const NxF32 *points,NxU32 pstride,NxF32 bmin[3],NxF32 bmax[3]);
void fm_getAABB(NxU32 vcount,const NxF64 *points,NxU32 pstride,NxF64 bmin[3],NxF64 bmax[3]);
void fm_getAABBCenter(const NxF32 bmin[3],const NxF32 bmax[3],NxF32 center[3]);
void fm_getAABBCenter(const NxF64 bmin[3],const NxF64 bmax[3],NxF64 center[3]);
void fm_eulerToQuat(NxF32 x,NxF32 y,NxF32 z,NxF32 quat[4]); // convert euler angles to quaternion.
void fm_eulerToQuat(NxF64 x,NxF64 y,NxF64 z,NxF64 quat[4]); // convert euler angles to quaternion.
void fm_quatToEuler(const NxF32 quat[4],NxF32 &ax,NxF32 &ay,NxF32 &az);
void fm_quatToEuler(const NxF64 quat[4],NxF64 &ax,NxF64 &ay,NxF64 &az);
void fm_eulerToQuat(const NxF32 euler[3],NxF32 quat[4]); // convert euler angles to quaternion. Angles must be radians not degrees!
void fm_eulerToQuat(const NxF64 euler[3],NxF64 quat[4]); // convert euler angles to quaternion.
void fm_scale(NxF32 x,NxF32 y,NxF32 z,NxF32 matrix[16]); // apply scale to the matrix.
void fm_scale(NxF64 x,NxF64 y,NxF64 z,NxF64 matrix[16]); // apply scale to the matrix.
void fm_eulerToQuatDX(NxF32 x,NxF32 y,NxF32 z,NxF32 quat[4]); // convert euler angles to quaternion using the fucked up DirectX method
void fm_eulerToQuatDX(NxF64 x,NxF64 y,NxF64 z,NxF64 quat[4]); // convert euler angles to quaternion using the fucked up DirectX method
void fm_eulerToMatrixDX(NxF32 x,NxF32 y,NxF32 z,NxF32 matrix[16]); // convert euler angles to quaternion using the fucked up DirectX method.
void fm_eulerToMatrixDX(NxF64 x,NxF64 y,NxF64 z,NxF64 matrix[16]); // convert euler angles to quaternion using the fucked up DirectX method.
void fm_quatToMatrix(const NxF32 quat[4],NxF32 matrix[16]); // convert quaterinion rotation to matrix, translation set to zero.
void fm_quatToMatrix(const NxF64 quat[4],NxF64 matrix[16]); // convert quaterinion rotation to matrix, translation set to zero.
void fm_quatRotate(const NxF32 quat[4],const NxF32 v[3],NxF32 r[3]); // rotate a vector directly by a quaternion.
void fm_quatRotate(const NxF64 quat[4],const NxF64 v[3],NxF64 r[3]); // rotate a vector directly by a quaternion.
void fm_getTranslation(const NxF32 matrix[16],NxF32 t[3]);
void fm_getTranslation(const NxF64 matrix[16],NxF64 t[3]);
void fm_setTranslation(const NxF32 *translation,NxF32 matrix[16]);
void fm_setTranslation(const NxF64 *translation,NxF64 matrix[16]);
void fm_multiplyQuat(const NxF32 *qa,const NxF32 *qb,NxF32 *quat);
void fm_multiplyQuat(const NxF64 *qa,const NxF64 *qb,NxF64 *quat);
void fm_matrixToQuat(const NxF32 matrix[16],NxF32 quat[4]); // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
void fm_matrixToQuat(const NxF64 matrix[16],NxF64 quat[4]); // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
NxF32 fm_sphereVolume(NxF32 radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
NxF64 fm_sphereVolume(NxF64 radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
NxF32 fm_cylinderVolume(NxF32 radius,NxF32 h);
NxF64 fm_cylinderVolume(NxF64 radius,NxF64 h);
NxF32 fm_capsuleVolume(NxF32 radius,NxF32 h);
NxF64 fm_capsuleVolume(NxF64 radius,NxF64 h);
NxF32 fm_distance(const NxF32 p1[3],const NxF32 p2[3]);
NxF64 fm_distance(const NxF64 p1[3],const NxF64 p2[3]);
NxF32 fm_distanceSquared(const NxF32 p1[3],const NxF32 p2[3]);
NxF64 fm_distanceSquared(const NxF64 p1[3],const NxF64 p2[3]);
NxF32 fm_distanceSquaredXZ(const NxF32 p1[3],const NxF32 p2[3]);
NxF64 fm_distanceSquaredXZ(const NxF64 p1[3],const NxF64 p2[3]);
NxF32 fm_computePlane(const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3],NxF32 *n); // return D
NxF64 fm_computePlane(const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3],NxF64 *n); // return D
NxF32 fm_distToPlane(const NxF32 plane[4],const NxF32 pos[3]); // computes the distance of this point from the plane.
NxF64 fm_distToPlane(const NxF64 plane[4],const NxF64 pos[3]); // computes the distance of this point from the plane.
NxF32 fm_dot(const NxF32 p1[3],const NxF32 p2[3]);
NxF64 fm_dot(const NxF64 p1[3],const NxF64 p2[3]);
void fm_cross(NxF32 cross[3],const NxF32 a[3],const NxF32 b[3]);
void fm_cross(NxF64 cross[3],const NxF64 a[3],const NxF64 b[3]);
void fm_computeNormalVector(NxF32 n[3],const NxF32 p1[3],const NxF32 p2[3]); // as P2-P1 normalized.
void fm_computeNormalVector(NxF64 n[3],const NxF64 p1[3],const NxF64 p2[3]); // as P2-P1 normalized.
bool fm_computeWindingOrder(const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3]); // returns true if the triangle is clockwise.
bool fm_computeWindingOrder(const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3]); // returns true if the triangle is clockwise.
NxF32 fm_normalize(NxF32 n[3]); // normalize this vector and return the distance
NxF64 fm_normalize(NxF64 n[3]); // normalize this vector and return the distance
void fm_matrixMultiply(const NxF32 A[16],const NxF32 B[16],NxF32 dest[16]);
void fm_matrixMultiply(const NxF64 A[16],const NxF64 B[16],NxF64 dest[16]);
void fm_composeTransform(const NxF32 position[3],const NxF32 quat[4],const NxF32 scale[3],NxF32 matrix[16]);
void fm_composeTransform(const NxF64 position[3],const NxF64 quat[4],const NxF64 scale[3],NxF64 matrix[16]);
NxF32 fm_computeArea(const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3]);
NxF64 fm_computeArea(const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3]);
void fm_lerp(const NxF32 p1[3],const NxF32 p2[3],NxF32 dest[3],NxF32 lerpValue);
void fm_lerp(const NxF64 p1[3],const NxF64 p2[3],NxF64 dest[3],NxF64 lerpValue);
bool fm_insideTriangleXZ(const NxF32 test[3],const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3]);
bool fm_insideTriangleXZ(const NxF64 test[3],const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3]);
bool fm_insideAABB(const NxF32 pos[3],const NxF32 bmin[3],const NxF32 bmax[3]);
bool fm_insideAABB(const NxF64 pos[3],const NxF64 bmin[3],const NxF64 bmax[3]);
bool fm_insideAABB(const NxF32 obmin[3],const NxF32 obmax[3],const NxF32 tbmin[3],const NxF32 tbmax[3]); // test if bounding box tbmin/tmbax is fully inside obmin/obmax
bool fm_insideAABB(const NxF64 obmin[3],const NxF64 obmax[3],const NxF64 tbmin[3],const NxF64 tbmax[3]); // test if bounding box tbmin/tmbax is fully inside obmin/obmax
NxU32 fm_clipTestPoint(const NxF32 bmin[3],const NxF32 bmax[3],const NxF32 pos[3]);
NxU32 fm_clipTestPoint(const NxF64 bmin[3],const NxF64 bmax[3],const NxF64 pos[3]);
NxU32 fm_clipTestPointXZ(const NxF32 bmin[3],const NxF32 bmax[3],const NxF32 pos[3]); // only tests X and Z, not Y
NxU32 fm_clipTestPointXZ(const NxF64 bmin[3],const NxF64 bmax[3],const NxF64 pos[3]); // only tests X and Z, not Y
NxU32 fm_clipTestAABB(const NxF32 bmin[3],const NxF32 bmax[3],const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3],NxU32 &andCode);
NxU32 fm_clipTestAABB(const NxF64 bmin[3],const NxF64 bmax[3],const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3],NxU32 &andCode);
bool fm_lineTestAABBXZ(const NxF32 p1[3],const NxF32 p2[3],const NxF32 bmin[3],const NxF32 bmax[3],NxF32 &time);
bool fm_lineTestAABBXZ(const NxF64 p1[3],const NxF64 p2[3],const NxF64 bmin[3],const NxF64 bmax[3],NxF64 &time);
bool fm_lineTestAABB(const NxF32 p1[3],const NxF32 p2[3],const NxF32 bmin[3],const NxF32 bmax[3],NxF32 &time);
bool fm_lineTestAABB(const NxF64 p1[3],const NxF64 p2[3],const NxF64 bmin[3],const NxF64 bmax[3],NxF64 &time);
void fm_initMinMax(const NxF32 p[3],NxF32 bmin[3],NxF32 bmax[3]);
void fm_initMinMax(const NxF64 p[3],NxF64 bmin[3],NxF64 bmax[3]);
void fm_initMinMax(NxF32 bmin[3],NxF32 bmax[3]);
void fm_initMinMax(NxF64 bmin[3],NxF64 bmax[3]);
void fm_minmax(const NxF32 p[3],NxF32 bmin[3],NxF32 bmax[3]); // accmulate to a min-max value
void fm_minmax(const NxF64 p[3],NxF64 bmin[3],NxF64 bmax[3]); // accmulate to a min-max value
NxF32 fm_solveX(const NxF32 plane[4],NxF32 y,NxF32 z); // solve for X given this plane equation and the other two components.
NxF64 fm_solveX(const NxF64 plane[4],NxF64 y,NxF64 z); // solve for X given this plane equation and the other two components.
NxF32 fm_solveY(const NxF32 plane[4],NxF32 x,NxF32 z); // solve for Y given this plane equation and the other two components.
NxF64 fm_solveY(const NxF64 plane[4],NxF64 x,NxF64 z); // solve for Y given this plane equation and the other two components.
NxF32 fm_solveZ(const NxF32 plane[4],NxF32 x,NxF32 y); // solve for Z given this plane equation and the other two components.
NxF64 fm_solveZ(const NxF64 plane[4],NxF64 x,NxF64 y); // solve for Z given this plane equation and the other two components.
bool fm_computeBestFitPlane(NxU32 vcount, // number of input data points
const NxF32 *points, // starting address of points array.
NxU32 vstride, // stride between input points.
const NxF32 *weights, // *optional point weighting values.
NxU32 wstride, // weight stride for each vertex.
NxF32 plane[4]);
bool fm_computeBestFitPlane(NxU32 vcount, // number of input data points
const NxF64 *points, // starting address of points array.
NxU32 vstride, // stride between input points.
const NxF64 *weights, // *optional point weighting values.
NxU32 wstride, // weight stride for each vertex.
NxF64 plane[4]);
NxF32 fm_computeBestFitAABB(NxU32 vcount,const NxF32 *points,NxU32 pstride,NxF32 bmin[3],NxF32 bmax[3]); // returns the diagonal distance
NxF64 fm_computeBestFitAABB(NxU32 vcount,const NxF64 *points,NxU32 pstride,NxF64 bmin[3],NxF64 bmax[3]); // returns the diagonal distance
NxF32 fm_computeBestFitSphere(NxU32 vcount,const NxF32 *points,NxU32 pstride,NxF32 center[3]);
NxF64 fm_computeBestFitSphere(NxU32 vcount,const NxF64 *points,NxU32 pstride,NxF64 center[3]);
bool fm_lineSphereIntersect(const NxF32 center[3],NxF32 radius,const NxF32 p1[3],const NxF32 p2[3],NxF32 intersect[3]);
bool fm_lineSphereIntersect(const NxF64 center[3],NxF64 radius,const NxF64 p1[3],const NxF64 p2[3],NxF64 intersect[3]);
bool fm_intersectRayAABB(const NxF32 bmin[3],const NxF32 bmax[3],const NxF32 pos[3],const NxF32 dir[3],NxF32 intersect[3]);
bool fm_intersectLineSegmentAABB(const NxF32 bmin[3],const NxF32 bmax[3],const NxF32 p1[3],const NxF32 p2[3],NxF32 intersect[3]);
bool fm_lineIntersectsTriangle(const NxF32 rayStart[3],const NxF32 rayEnd[3],const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3],NxF32 sect[3]);
bool fm_lineIntersectsTriangle(const NxF64 rayStart[3],const NxF64 rayEnd[3],const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3],NxF64 sect[3]);
bool fm_rayIntersectsTriangle(const NxF32 origin[3],const NxF32 dir[3],const NxF32 v0[3],const NxF32 v1[3],const NxF32 v2[3],NxF32 &t);
bool fm_rayIntersectsTriangle(const NxF64 origin[3],const NxF64 dir[3],const NxF64 v0[3],const NxF64 v1[3],const NxF64 v2[3],NxF64 &t);
bool fm_raySphereIntersect(const NxF32 center[3],NxF32 radius,const NxF32 pos[3],const NxF32 dir[3],NxF32 distance,NxF32 intersect[3]);
bool fm_raySphereIntersect(const NxF64 center[3],NxF64 radius,const NxF64 pos[3],const NxF64 dir[3],NxF64 distance,NxF64 intersect[3]);
void fm_catmullRom(NxF32 out_vector[3],const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3],const NxF32 *p4, const NxF32 s);
void fm_catmullRom(NxF64 out_vector[3],const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3],const NxF64 *p4, const NxF64 s);
bool fm_intersectAABB(const NxF32 bmin1[3],const NxF32 bmax1[3],const NxF32 bmin2[3],const NxF32 bmax2[3]);
bool fm_intersectAABB(const NxF64 bmin1[3],const NxF64 bmax1[3],const NxF64 bmin2[3],const NxF64 bmax2[3]);
// computes the rotation quaternion to go from unit-vector v0 to unit-vector v1
void fm_rotationArc(const NxF32 v0[3],const NxF32 v1[3],NxF32 quat[4]);
void fm_rotationArc(const NxF64 v0[3],const NxF64 v1[3],NxF64 quat[4]);
NxF32 fm_distancePointLineSegment(const NxF32 Point[3],const NxF32 LineStart[3],const NxF32 LineEnd[3],NxF32 intersection[3],LineSegmentType &type,NxF32 epsilon);
NxF64 fm_distancePointLineSegment(const NxF64 Point[3],const NxF64 LineStart[3],const NxF64 LineEnd[3],NxF64 intersection[3],LineSegmentType &type,NxF64 epsilon);
bool fm_colinear(const NxF64 p1[3],const NxF64 p2[3],const NxF64 p3[3],NxF64 epsilon=0.999); // true if these three points in a row are co-linear
bool fm_colinear(const NxF32 p1[3],const NxF32 p2[3],const NxF32 p3[3],NxF32 epsilon=0.999f);
bool fm_colinear(const NxF32 a1[3],const NxF32 a2[3],const NxF32 b1[3],const NxF32 b2[3],NxF32 epsilon=0.999f); // true if these two line segments are co-linear.
bool fm_colinear(const NxF64 a1[3],const NxF64 a2[3],const NxF64 b1[3],const NxF64 b2[3],NxF64 epsilon=0.999); // true if these two line segments are co-linear.
enum IntersectResult
{
IR_DONT_INTERSECT,
IR_DO_INTERSECT,
IR_COINCIDENT,
IR_PARALLEL,
};
IntersectResult fm_intersectLineSegments2d(const NxF32 a1[3], const NxF32 a2[3], const NxF32 b1[3], const NxF32 b2[3], NxF32 intersectionPoint[3]);
IntersectResult fm_intersectLineSegments2d(const NxF64 a1[3],const NxF64 a2[3],const NxF64 b1[3],const NxF64 b2[3],NxF64 intersectionPoint[3]);
IntersectResult fm_intersectLineSegments2dTime(const NxF32 a1[3], const NxF32 a2[3], const NxF32 b1[3], const NxF32 b2[3],NxF32 &t1,NxF32 &t2);
IntersectResult fm_intersectLineSegments2dTime(const NxF64 a1[3],const NxF64 a2[3],const NxF64 b1[3],const NxF64 b2[3],NxF64 &t1,NxF64 &t2);
// Plane-Triangle splitting
enum PlaneTriResult
{
PTR_ON_PLANE,
PTR_FRONT,
PTR_BACK,
PTR_SPLIT,
};
PlaneTriResult fm_planeTriIntersection(const NxF32 plane[4], // the plane equation in Ax+By+Cz+D format
const NxF32 *triangle, // the source triangle.
NxU32 tstride, // stride in bytes of the input and output *vertices*
NxF32 epsilon, // the co-planer epsilon value.
NxF32 *front, // the triangle in front of the
NxU32 &fcount, // number of vertices in the 'front' triangle
NxF32 *back, // the triangle in back of the plane
NxU32 &bcount); // the number of vertices in the 'back' triangle.
PlaneTriResult fm_planeTriIntersection(const NxF64 plane[4], // the plane equation in Ax+By+Cz+D format
const NxF64 *triangle, // the source triangle.
NxU32 tstride, // stride in bytes of the input and output *vertices*
NxF64 epsilon, // the co-planer epsilon value.
NxF64 *front, // the triangle in front of the
NxU32 &fcount, // number of vertices in the 'front' triangle
NxF64 *back, // the triangle in back of the plane
NxU32 &bcount); // the number of vertices in the 'back' triangle.
void fm_intersectPointPlane(const NxF32 p1[3],const NxF32 p2[3],NxF32 *split,const NxF32 plane[4]);
void fm_intersectPointPlane(const NxF64 p1[3],const NxF64 p2[3],NxF64 *split,const NxF64 plane[4]);
PlaneTriResult fm_getSidePlane(const NxF32 p[3],const NxF32 plane[4],NxF32 epsilon);
PlaneTriResult fm_getSidePlane(const NxF64 p[3],const NxF64 plane[4],NxF64 epsilon);
void fm_computeBestFitOBB(NxU32 vcount,const NxF32 *points,NxU32 pstride,NxF32 *sides,NxF32 matrix[16],bool bruteForce=true);
void fm_computeBestFitOBB(NxU32 vcount,const NxF64 *points,NxU32 pstride,NxF64 *sides,NxF64 matrix[16],bool bruteForce=true);
void fm_computeBestFitOBB(NxU32 vcount,const NxF32 *points,NxU32 pstride,NxF32 *sides,NxF32 pos[3],NxF32 quat[4],bool bruteForce=true);
void fm_computeBestFitOBB(NxU32 vcount,const NxF64 *points,NxU32 pstride,NxF64 *sides,NxF64 pos[3],NxF64 quat[4],bool bruteForce=true);
void fm_computeBestFitABB(NxU32 vcount,const NxF32 *points,NxU32 pstride,NxF32 *sides,NxF32 pos[3]);
void fm_computeBestFitABB(NxU32 vcount,const NxF64 *points,NxU32 pstride,NxF64 *sides,NxF64 pos[3]);
//** Note, if the returned capsule height is less than zero, then you must represent it is a sphere of size radius.
void fm_computeBestFitCapsule(NxU32 vcount,const NxF32 *points,NxU32 pstride,NxF32 &radius,NxF32 &height,NxF32 matrix[16],bool bruteForce=true);
void fm_computeBestFitCapsule(NxU32 vcount,const NxF64 *points,NxU32 pstride,NxF32 &radius,NxF32 &height,NxF64 matrix[16],bool bruteForce=true);
void fm_planeToMatrix(const NxF32 plane[4],NxF32 matrix[16]); // convert a plane equation to a 4x4 rotation matrix. Reference vector is 0,1,0
void fm_planeToQuat(const NxF32 plane[4],NxF32 quat[4],NxF32 pos[3]); // convert a plane equation to a quaternion and translation
void fm_planeToMatrix(const NxF64 plane[4],NxF64 matrix[16]); // convert a plane equation to a 4x4 rotation matrix
void fm_planeToQuat(const NxF64 plane[4],NxF64 quat[4],NxF64 pos[3]); // convert a plane equation to a quaternion and translation
inline void fm_doubleToFloat3(const NxF64 p[3],NxF32 t[3]) { t[0] = (NxF32) p[0]; t[1] = (NxF32)p[1]; t[2] = (NxF32)p[2]; };
inline void fm_floatToDouble3(const NxF32 p[3],NxF64 t[3]) { t[0] = (NxF64)p[0]; t[1] = (NxF64)p[1]; t[2] = (NxF64)p[2]; };
void fm_eulerMatrix(NxF32 ax,NxF32 ay,NxF32 az,NxF32 matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_eulerMatrix(NxF64 ax,NxF64 ay,NxF64 az,NxF64 matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
NxF32 fm_computeMeshVolume(const NxF32 *vertices,NxU32 tcount,const NxU32 *indices);
NxF64 fm_computeMeshVolume(const NxF64 *vertices,NxU32 tcount,const NxU32 *indices);
#define FM_DEFAULT_GRANULARITY 0.001f // 1 millimeter is the default granularity
class fm_VertexIndex
{
public:
virtual NxU32 getIndex(const NxF32 pos[3],bool &newPos) = 0; // get welded index for this NxF32 vector[3]
virtual NxU32 getIndex(const NxF64 pos[3],bool &newPos) = 0; // get welded index for this NxF64 vector[3]
virtual const NxF32 * getVerticesFloat(void) const = 0;
virtual const NxF64 * getVerticesDouble(void) const = 0;
virtual const NxF32 * getVertexFloat(NxU32 index) const = 0;
virtual const NxF64 * getVertexDouble(NxU32 index) const = 0;
virtual NxU32 getVcount(void) const = 0;
virtual bool isDouble(void) const = 0;
virtual bool saveAsObj(const char *fname,NxU32 tcount,NxU32 *indices) = 0;
};
fm_VertexIndex * fm_createVertexIndex(NxF64 granularity,bool snapToGrid); // create an indexed vertex system for doubles
fm_VertexIndex * fm_createVertexIndex(NxF32 granularity,bool snapToGrid); // create an indexed vertext system for floats
void fm_releaseVertexIndex(fm_VertexIndex *vindex);
#if 0 // currently disabled
class fm_LineSegment
{
public:
fm_LineSegment(void)
{
mE1 = mE2 = 0;
}
fm_LineSegment(NxU32 e1,NxU32 e2)
{
mE1 = e1;
mE2 = e2;
}
NxU32 mE1;
NxU32 mE2;
};
// LineSweep *only* supports doublees. As a geometric operation it needs as much precision as possible.
class fm_LineSweep
{
public:
virtual fm_LineSegment * performLineSweep(const fm_LineSegment *segments,
NxU32 icount,
const NxF64 *planeEquation,
fm_VertexIndex *pool,
NxU32 &scount) = 0;
};
fm_LineSweep * fm_createLineSweep(void);
void fm_releaseLineSweep(fm_LineSweep *sweep);
#endif
class fm_Triangulate
{
public:
virtual const NxF64 * triangulate3d(NxU32 pcount,
const NxF64 *points,
NxU32 vstride,
NxU32 &tcount,
bool consolidate,
NxF64 epsilon) = 0;
virtual const NxF32 * triangulate3d(NxU32 pcount,
const NxF32 *points,
NxU32 vstride,
NxU32 &tcount,
bool consolidate,
NxF32 epsilon) = 0;
};
fm_Triangulate * fm_createTriangulate(void);
void fm_releaseTriangulate(fm_Triangulate *t);
const NxF32 * fm_getPoint(const NxF32 *points,NxU32 pstride,NxU32 index);
const NxF64 * fm_getPoint(const NxF64 *points,NxU32 pstride,NxU32 index);
bool fm_insideTriangle(NxF32 Ax, NxF32 Ay,NxF32 Bx, NxF32 By,NxF32 Cx, NxF32 Cy,NxF32 Px, NxF32 Py);
bool fm_insideTriangle(NxF64 Ax, NxF64 Ay,NxF64 Bx, NxF64 By,NxF64 Cx, NxF64 Cy,NxF64 Px, NxF64 Py);
NxF32 fm_areaPolygon2d(NxU32 pcount,const NxF32 *points,NxU32 pstride);
NxF64 fm_areaPolygon2d(NxU32 pcount,const NxF64 *points,NxU32 pstride);
bool fm_pointInsidePolygon2d(NxU32 pcount,const NxF32 *points,NxU32 pstride,const NxF32 *point,NxU32 xindex=0,NxU32 yindex=1);
bool fm_pointInsidePolygon2d(NxU32 pcount,const NxF64 *points,NxU32 pstride,const NxF64 *point,NxU32 xindex=0,NxU32 yindex=1);
NxU32 fm_consolidatePolygon(NxU32 pcount,const NxF32 *points,NxU32 pstride,NxF32 *dest,NxF32 epsilon=0.999999f); // collapses co-linear edges.
NxU32 fm_consolidatePolygon(NxU32 pcount,const NxF64 *points,NxU32 pstride,NxF64 *dest,NxF64 epsilon=0.999999); // collapses co-linear edges.
bool fm_computeSplitPlane(NxU32 vcount,const NxF64 *vertices,NxU32 tcount,const NxU32 *indices,NxF64 *plane);
bool fm_computeSplitPlane(NxU32 vcount,const NxF32 *vertices,NxU32 tcount,const NxU32 *indices,NxF32 *plane);
void fm_nearestPointInTriangle(const NxF32 *pos,const NxF32 *p1,const NxF32 *p2,const NxF32 *p3,NxF32 *nearest);
void fm_nearestPointInTriangle(const NxF64 *pos,const NxF64 *p1,const NxF64 *p2,const NxF64 *p3,NxF64 *nearest);
NxF32 fm_areaTriangle(const NxF32 *p1,const NxF32 *p2,const NxF32 *p3);
NxF64 fm_areaTriangle(const NxF64 *p1,const NxF64 *p2,const NxF64 *p3);
void fm_subtract(const NxF32 *A,const NxF32 *B,NxF32 *diff); // compute A-B and store the result in 'diff'
void fm_subtract(const NxF64 *A,const NxF64 *B,NxF64 *diff); // compute A-B and store the result in 'diff'
void fm_multiply(NxF32 *A,NxF32 scaler);
void fm_multiply(NxF64 *A,NxF64 scaler);
void fm_add(const NxF32 *A,const NxF32 *B,NxF32 *sum);
void fm_add(const NxF64 *A,const NxF64 *B,NxF64 *sum);
void fm_copy3(const NxF32 *source,NxF32 *dest);
void fm_copy3(const NxF64 *source,NxF64 *dest);
// re-indexes an indexed triangle mesh but drops unused vertices. The output_indices can be the same pointer as the input indices.
// the output_vertices can point to the input vertices if you desire. The output_vertices buffer should be at least the same size
// is the input buffer. The routine returns the new vertex count after re-indexing.
NxU32 fm_copyUniqueVertices(NxU32 vcount,const NxF32 *input_vertices,NxF32 *output_vertices,NxU32 tcount,const NxU32 *input_indices,NxU32 *output_indices);
NxU32 fm_copyUniqueVertices(NxU32 vcount,const NxF64 *input_vertices,NxF64 *output_vertices,NxU32 tcount,const NxU32 *input_indices,NxU32 *output_indices);
bool fm_isMeshCoplanar(NxU32 tcount,const NxU32 *indices,const NxF32 *vertices,bool doubleSided); // returns true if this collection of indexed triangles are co-planar!
bool fm_isMeshCoplanar(NxU32 tcount,const NxU32 *indices,const NxF64 *vertices,bool doubleSided); // returns true if this collection of indexed triangles are co-planar!
bool fm_samePlane(const NxF32 p1[4],const NxF32 p2[4],NxF32 normalEpsilon=0.01f,NxF32 dEpsilon=0.001f,bool doubleSided=false); // returns true if these two plane equations are identical within an epsilon
bool fm_samePlane(const NxF64 p1[4],const NxF64 p2[4],NxF64 normalEpsilon=0.01,NxF64 dEpsilon=0.001,bool doubleSided=false);
void fm_OBBtoAABB(const NxF32 obmin[3],const NxF32 obmax[3],const NxF32 matrix[16],NxF32 abmin[3],NxF32 abmax[3]);
// a utility class that will tesseleate a mesh.
class fm_Tesselate
{
public:
virtual const NxU32 * tesselate(fm_VertexIndex *vindex,NxU32 tcount,const NxU32 *indices,NxF32 longEdge,NxU32 maxDepth,NxU32 &outcount) = 0;
};
fm_Tesselate * fm_createTesselate(void);
void fm_releaseTesselate(fm_Tesselate *t);
void fm_computeMeanNormals(NxU32 vcount, // the number of vertices
const NxF32 *vertices, // the base address of the vertex position data.
NxU32 vstride, // the stride between position data.
NxF32 *normals, // the base address of the destination for mean vector normals
NxU32 nstride, // the stride between normals
NxU32 tcount, // the number of triangles
const NxU32 *indices); // the triangle indices
void fm_computeMeanNormals(NxU32 vcount, // the number of vertices
const NxF64 *vertices, // the base address of the vertex position data.
NxU32 vstride, // the stride between position data.
NxF64 *normals, // the base address of the destination for mean vector normals
NxU32 nstride, // the stride between normals
NxU32 tcount, // the number of triangles
const NxU32 *indices); // the triangle indices
bool fm_isValidTriangle(const NxF32 *p1,const NxF32 *p2,const NxF32 *p3,NxF32 epsilon=0.00001f);
bool fm_isValidTriangle(const NxF64 *p1,const NxF64 *p2,const NxF64 *p3,NxF64 epsilon=0.00001f);
}; // end of namespace
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,783 +0,0 @@
/*
NvMeshIslandGeneration.cpp : This code snippet walks the toplogy of a triangle mesh and detects the set of unique connected 'mesh islands'
*/
/*!
**
** 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:4100 4288)
#include "NvMeshIslandGeneration.h"
#include "NvFloatMath.h"
#include "NvHashMap.h"
namespace CONVEX_DECOMPOSITION
{
typedef CONVEX_DECOMPOSITION::Array< NxU32 > NxU32Vector;
class Edge;
class Island;
class AABB
{
public:
NxF32 mMin[3];
NxF32 mMax[3];
};
class Triangle
{
public:
Triangle(void)
{
mConsumed = false;
mIsland = 0;
mHandle = 0;
mId = 0;
}
void minmax(const NxF32 *p,AABB &box)
{
if ( p[0] < box.mMin[0] ) box.mMin[0] = p[0];
if ( p[1] < box.mMin[1] ) box.mMin[1] = p[1];
if ( p[2] < box.mMin[2] ) box.mMin[2] = p[2];
if ( p[0] > box.mMax[0] ) box.mMax[0] = p[0];
if ( p[1] > box.mMax[1] ) box.mMax[1] = p[1];
if ( p[2] > box.mMax[2] ) box.mMax[2] = p[2];
}
void minmax(const NxF64 *p,AABB &box)
{
if ( (NxF32)p[0] < box.mMin[0] ) box.mMin[0] = (NxF32)p[0];
if ( (NxF32)p[1] < box.mMin[1] ) box.mMin[1] = (NxF32)p[1];
if ( (NxF32)p[2] < box.mMin[2] ) box.mMin[2] = (NxF32)p[2];
if ( (NxF32)p[0] > box.mMax[0] ) box.mMax[0] = (NxF32)p[0];
if ( (NxF32)p[1] > box.mMax[1] ) box.mMax[1] = (NxF32)p[1];
if ( (NxF32)p[2] > box.mMax[2] ) box.mMax[2] = (NxF32)p[2];
}
void buildBox(const NxF32 *vertices_f,const NxF64 *vertices_d,NxU32 id);
void render(NxU32 color)
{
// gRenderDebug->DebugBound(&mBox.mMin[0],&mBox.mMax[0],color,60.0f);
}
void getTriangle(NxF32 *tri,const NxF32 *vertices_f,const NxF64 *vertices_d);
NxU32 mHandle;
bool mConsumed;
Edge *mEdges[3];
Island *mIsland; // identifies which island it is a member of
unsigned short mId;
AABB mBox;
};
class Edge
{
public:
Edge(void)
{
mI1 = 0;
mI2 = 0;
mHash = 0;
mNext = 0;
mPrevious = 0;
mParent = 0;
mNextTriangleEdge = 0;
}
void init(NxU32 i1,NxU32 i2,Triangle *parent)
{
assert( i1 < 65536 );
assert( i2 < 65536 );
mI1 = i1;
mI2 = i2;
mHash = (i2<<16)|i1;
mReverseHash = (i1<<16)|i2;
mNext = 0;
mPrevious = 0;
mParent = parent;
}
NxU32 mI1;
NxU32 mI2;
NxU32 mHash;
NxU32 mReverseHash;
Edge *mNext;
Edge *mPrevious;
Edge *mNextTriangleEdge;
Triangle *mParent;
};
typedef CONVEX_DECOMPOSITION::HashMap< NxU32, Edge * > EdgeHashMap;
typedef CONVEX_DECOMPOSITION::Array< Triangle * > TriangleVector;
class EdgeCheck
{
public:
EdgeCheck(Triangle *t,Edge *e)
{
mTriangle = t;
mEdge = e;
}
Triangle *mTriangle;
Edge *mEdge;
};
typedef CONVEX_DECOMPOSITION::Array< EdgeCheck > EdgeCheckQueue;
class Island
{
public:
Island(Triangle *t,Triangle *root)
{
mVerticesFloat = 0;
mVerticesDouble = 0;
t->mIsland = this;
mTriangles.pushBack(t);
mCoplanar = false;
fm_initMinMax(mMin,mMax);
}
void add(Triangle *t,Triangle *root)
{
t->mIsland = this;
mTriangles.pushBack(t);
}
void merge(Island &isl)
{
TriangleVector::Iterator i;
for (i=isl.mTriangles.begin(); i!=isl.mTriangles.end(); ++i)
{
Triangle *t = (*i);
mTriangles.pushBack(t);
}
isl.mTriangles.clear();
}
bool isTouching(Island *isl,const NxF32 *vertices_f,const NxF64 *vertices_d)
{
bool ret = false;
mVerticesFloat = vertices_f;
mVerticesDouble = vertices_d;
if ( fm_intersectAABB(mMin,mMax,isl->mMin,isl->mMax) ) // if the two islands has an intersecting AABB
{
// todo..
}
return ret;
}
void SAP_DeletePair(const void* object0, const void* object1, void* user_data, void* pair_user_data)
{
}
void render(NxU32 color)
{
// gRenderDebug->DebugBound(mMin,mMax,color,60.0f);
TriangleVector::Iterator i;
for (i=mTriangles.begin(); i!=mTriangles.end(); ++i)
{
Triangle *t = (*i);
t->render(color);
}
}
const NxF64 *mVerticesDouble;
const NxF32 *mVerticesFloat;
NxF32 mMin[3];
NxF32 mMax[3];
bool mCoplanar; // marked as co-planar..
TriangleVector mTriangles;
};
void Triangle::getTriangle(NxF32 *tri,const NxF32 *vertices_f,const NxF64 *vertices_d)
{
NxU32 i1 = mEdges[0]->mI1;
NxU32 i2 = mEdges[1]->mI1;
NxU32 i3 = mEdges[2]->mI1;
if ( vertices_f )
{
const NxF32 *p1 = &vertices_f[i1*3];
const NxF32 *p2 = &vertices_f[i2*3];
const NxF32 *p3 = &vertices_f[i3*3];
fm_copy3(p1,tri);
fm_copy3(p2,tri+3);
fm_copy3(p3,tri+6);
}
else
{
const NxF64 *p1 = &vertices_d[i1*3];
const NxF64 *p2 = &vertices_d[i2*3];
const NxF64 *p3 = &vertices_d[i3*3];
fm_doubleToFloat3(p1,tri);
fm_doubleToFloat3(p2,tri+3);
fm_doubleToFloat3(p3,tri+6);
}
}
void Triangle::buildBox(const NxF32 *vertices_f,const NxF64 *vertices_d,NxU32 id)
{
mId = (unsigned short)id;
NxU32 i1 = mEdges[0]->mI1;
NxU32 i2 = mEdges[1]->mI1;
NxU32 i3 = mEdges[2]->mI1;
if ( vertices_f )
{
const NxF32 *p1 = &vertices_f[i1*3];
const NxF32 *p2 = &vertices_f[i2*3];
const NxF32 *p3 = &vertices_f[i3*3];
mBox.mMin[0] = p1[0];
mBox.mMin[1] = p1[1];
mBox.mMin[2] = p1[2];
mBox.mMax[0] = p1[0];
mBox.mMax[1] = p1[1];
mBox.mMax[2] = p1[2];
minmax(p2,mBox);
minmax(p3,mBox);
}
else
{
const NxF64 *p1 = &vertices_d[i1*3];
const NxF64 *p2 = &vertices_d[i2*3];
const NxF64 *p3 = &vertices_d[i3*3];
mBox.mMin[0] = (NxF32)p1[0];
mBox.mMin[1] = (NxF32)p1[1];
mBox.mMin[2] = (NxF32)p1[2];
mBox.mMax[0] = (NxF32)p1[0];
mBox.mMax[1] = (NxF32)p1[1];
mBox.mMax[2] = (NxF32)p1[2];
minmax(p2,mBox);
minmax(p3,mBox);
}
assert(mIsland);
if ( mIsland )
{
if ( mBox.mMin[0] < mIsland->mMin[0] ) mIsland->mMin[0] = mBox.mMin[0];
if ( mBox.mMin[1] < mIsland->mMin[1] ) mIsland->mMin[1] = mBox.mMin[1];
if ( mBox.mMin[2] < mIsland->mMin[2] ) mIsland->mMin[2] = mBox.mMin[2];
if ( mBox.mMax[0] > mIsland->mMax[0] ) mIsland->mMax[0] = mBox.mMax[0];
if ( mBox.mMax[1] > mIsland->mMax[1] ) mIsland->mMax[1] = mBox.mMax[1];
if ( mBox.mMax[2] > mIsland->mMax[2] ) mIsland->mMax[2] = mBox.mMax[2];
}
}
typedef CONVEX_DECOMPOSITION::Array< Island * > IslandVector;
class MyMeshIslandGeneration : public MeshIslandGeneration
{
public:
MyMeshIslandGeneration(void)
{
mTriangles = 0;
mEdges = 0;
mVerticesDouble = 0;
mVerticesFloat = 0;
}
~MyMeshIslandGeneration(void)
{
reset();
}
void reset(void)
{
delete []mTriangles;
delete []mEdges;
mTriangles = 0;
mEdges = 0;
mTriangleEdges.clear();
IslandVector::Iterator i;
for (i=mIslands.begin(); i!=mIslands.end(); ++i)
{
Island *_i = (*i);
delete _i;
}
mIslands.clear();
}
NxU32 islandGenerate(NxU32 tcount,const NxU32 *indices,const NxF64 *vertices)
{
mVerticesDouble = vertices;
mVerticesFloat = 0;
return islandGenerate(tcount,indices);
}
NxU32 islandGenerate(NxU32 tcount,const NxU32 *indices,const NxF32 *vertices)
{
mVerticesDouble = 0;
mVerticesFloat = vertices;
return islandGenerate(tcount,indices);
}
NxU32 islandGenerate(NxU32 tcount,const NxU32 *indices)
{
NxU32 ret = 0;
reset();
mTcount = tcount;
mTriangles = new Triangle[tcount];
mEdges = new Edge[tcount*3];
Edge *e = mEdges;
for (NxU32 i=0; i<tcount; i++)
{
Triangle &t = mTriangles[i];
NxU32 i1 = *indices++;
NxU32 i2 = *indices++;
NxU32 i3 = *indices++;
t.mEdges[0] = e;
t.mEdges[1] = e+1;
t.mEdges[2] = e+2;
e = addEdge(e,&t,i1,i2);
e = addEdge(e,&t,i2,i3);
e = addEdge(e,&t,i3,i1);
}
// while there are still edges to process...
while ( mTriangleEdges.size() != 0 )
{
EdgeHashMap::Iterator iter = mTriangleEdges.getIterator();
Triangle *t = iter->second->mParent;
Island *i = new Island(t,mTriangles); // the initial triangle...
removeTriangle(t); // remove this triangle from the triangle-edges hashmap
mIslands.pushBack(i);
// now keep adding to this island until we can no longer walk any shared edges..
addEdgeCheck(t,t->mEdges[0]);
addEdgeCheck(t,t->mEdges[1]);
addEdgeCheck(t,t->mEdges[2]);
while ( !mEdgeCheckQueue.empty() )
{
EdgeCheck e = mEdgeCheckQueue.popBack();
// Process all triangles which share this edge
Edge *edge = locateSharedEdge(e.mEdge);
while ( edge )
{
Triangle *t = edge->mParent;
assert(!t->mConsumed);
i->add(t,mTriangles);
removeTriangle(t); // remove this triangle from the triangle-edges hashmap
// now keep adding to this island until we can no longer walk any shared edges..
if ( edge != t->mEdges[0] )
{
addEdgeCheck(t,t->mEdges[0]);
}
if ( edge != t->mEdges[1] )
{
addEdgeCheck(t,t->mEdges[1]);
}
if ( edge != t->mEdges[2] )
{
addEdgeCheck(t,t->mEdges[2]);
}
edge = locateSharedEdge(e.mEdge); // keep going until all shared edges have been processed!
}
}
}
ret = (NxU32)mIslands.size();
return ret;
}
NxU32 * getIsland(NxU32 index,NxU32 &otcount)
{
NxU32 *ret = 0;
mIndices.clear();
if ( index < mIslands.size() )
{
Island *i = mIslands[index];
otcount = (NxU32)i->mTriangles.size();
TriangleVector::Iterator j;
for (j=i->mTriangles.begin(); j!=i->mTriangles.end(); ++j)
{
Triangle *t = (*j);
mIndices.pushBack(t->mEdges[0]->mI1);
mIndices.pushBack(t->mEdges[1]->mI1);
mIndices.pushBack(t->mEdges[2]->mI1);
}
ret = &mIndices[0];
}
return ret;
}
private:
void removeTriangle(Triangle *t)
{
t->mConsumed = true;
removeEdge(t->mEdges[0]);
removeEdge(t->mEdges[1]);
removeEdge(t->mEdges[2]);
}
Edge * locateSharedEdge(Edge *e)
{
Edge *ret = 0;
const EdgeHashMap::Entry *found = mTriangleEdges.find( e->mReverseHash );
if ( found != NULL )
{
ret = (*found).second;
assert( ret->mHash == e->mReverseHash );
}
return ret;
}
void removeEdge(Edge *e)
{
const EdgeHashMap::Entry *found = mTriangleEdges.find( e->mHash );
if ( found != NULL )
{
Edge *prev = 0;
Edge *scan = (*found).second;
while ( scan && scan != e )
{
prev = scan;
scan = scan->mNextTriangleEdge;
}
if ( scan )
{
if ( prev == 0 )
{
if ( scan->mNextTriangleEdge )
{
mTriangleEdges.erase(e->mHash);
mTriangleEdges[e->mHash] = scan->mNextTriangleEdge;
}
else
{
mTriangleEdges.erase(e->mHash); // no more polygons have an edge here
}
}
else
{
prev->mNextTriangleEdge = scan->mNextTriangleEdge;
}
}
else
{
assert(0);
}
}
else
{
assert(0); // impossible!
}
}
Edge * addEdge(Edge *e,Triangle *t,NxU32 i1,NxU32 i2)
{
e->init(i1,i2,t);
const EdgeHashMap::Entry *found = mTriangleEdges.find(e->mHash);
if ( found == NULL )
{
mTriangleEdges[ e->mHash ] = e;
}
else
{
Edge *pn = (*found).second;
e->mNextTriangleEdge = pn;
mTriangleEdges.erase(e->mHash);
mTriangleEdges[e->mHash] = e;
}
e++;
return e;
}
void addEdgeCheck(Triangle *t,Edge *e)
{
EdgeCheck ec(t,e);
mEdgeCheckQueue.pushBack(ec);
}
NxU32 mergeCoplanarIslands(const NxF32 *vertices)
{
mVerticesFloat = vertices;
mVerticesDouble = 0;
return mergeCoplanarIslands();
}
NxU32 mergeCoplanarIslands(const NxF64 *vertices)
{
mVerticesDouble = vertices;
mVerticesFloat = 0;
return mergeCoplanarIslands();
}
// this island needs to be merged
void mergeTouching(Island *isl)
{
Island *touching = 0;
IslandVector::Iterator i;
for (i=mIslands.begin(); i!=mIslands.end(); ++i)
{
Island *_i = (*i);
if ( !_i->mCoplanar ) // can't merge with coplanar islands!
{
if ( _i->isTouching(isl,mVerticesFloat,mVerticesDouble) )
{
touching = _i;
}
}
}
}
NxU32 mergeCoplanarIslands(void)
{
NxU32 ret = 0;
if ( !mIslands.empty() )
{
NxU32 cp_count = 0;
NxU32 npc_count = 0;
NxU32 count = (NxU32)mIslands.size();
for (NxU32 i=0; i<count; i++)
{
NxU32 otcount;
const NxU32 *oindices = getIsland(i,otcount);
if ( otcount )
{
bool isCoplanar;
if ( mVerticesFloat )
isCoplanar = fm_isMeshCoplanar(otcount, oindices, mVerticesFloat, true);
else
isCoplanar = fm_isMeshCoplanar(otcount, oindices, mVerticesDouble, true);
if ( isCoplanar )
{
Island *isl = mIslands[i];
isl->mCoplanar = true;
cp_count++;
}
else
{
npc_count++;
}
}
else
{
assert(0);
}
}
if ( cp_count )
{
if ( npc_count == 0 ) // all islands are co-planar!
{
IslandVector temp = mIslands;
mIslands.clear();
Island *isl = mIslands[0];
mIslands.pushBack(isl);
for (NxU32 i=1; i<cp_count; i++)
{
Island *_i = mIslands[i];
isl->merge(*_i);
delete _i;
}
}
else
{
Triangle *t = mTriangles;
for (NxU32 i=0; i<mTcount; i++)
{
t->buildBox(mVerticesFloat,mVerticesDouble,i);
t++;
}
IslandVector::Iterator i;
for (i=mIslands.begin(); i!=mIslands.end(); ++i)
{
Island *isl = (*i);
NxU32 color = 0x00FF00;
if ( isl->mCoplanar )
{
color = 0xFFFF00;
}
mergeTouching(isl);
}
IslandVector temp = mIslands;
mIslands.clear();
for (i=temp.begin(); i!=temp.end(); i++)
{
Island *isl = (*i);
if ( isl->mCoplanar )
{
delete isl; // kill it
}
else
{
mIslands.pushBack(isl);
}
}
ret = (NxU32)mIslands.size();
}
}
else
{
ret = npc_count;
}
}
return ret;
}
NxU32 mergeTouchingIslands(const NxF32 *vertices)
{
NxU32 ret = 0;
return ret;
}
NxU32 mergeTouchingIslands(const NxF64 *vertices)
{
NxU32 ret = 0;
return ret;
}
NxU32 mTcount;
Triangle *mTriangles;
Edge *mEdges;
EdgeHashMap mTriangleEdges;
IslandVector mIslands;
EdgeCheckQueue mEdgeCheckQueue;
const NxF64 *mVerticesDouble;
const NxF32 *mVerticesFloat;
NxU32Vector mIndices;
};
MeshIslandGeneration * createMeshIslandGeneration(void)
{
MyMeshIslandGeneration *mig = new MyMeshIslandGeneration;
return static_cast< MeshIslandGeneration *>(mig);
}
void releaseMeshIslandGeneration(MeshIslandGeneration *cm)
{
MyMeshIslandGeneration *mig = static_cast< MyMeshIslandGeneration *>(cm);
delete mig;
}
}; // end of namespace

View file

@ -1,91 +0,0 @@
#ifndef MESH_ISLAND_GENERATION_H
#define MESH_ISLAND_GENERATION_H
/*
NvMeshIslandGeneration.h : This code snippet walks the toplogy of a triangle mesh and detects the set of unique connected 'mesh islands'
*/
#include "NvUserMemAlloc.h"
/*!
**
** 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.
*/
namespace CONVEX_DECOMPOSITION
{
class MeshIslandGeneration
{
public:
virtual NxU32 islandGenerate(NxU32 tcount,const NxU32 *indices,const NxF32 *vertices) = 0;
virtual NxU32 islandGenerate(NxU32 tcount,const NxU32 *indices,const NxF64 *vertices) = 0;
// sometimes island generation can produce co-planar islands. Slivers if you will. If you are passing these islands into a geometric system
// that wants to turn them into physical objects, they may not be acceptable. In this case it may be preferable to merge the co-planar islands with
// other islands that it 'touches'.
virtual NxU32 mergeCoplanarIslands(const NxF32 *vertices) = 0;
virtual NxU32 mergeCoplanarIslands(const NxF64 *vertices) = 0;
virtual NxU32 mergeTouchingIslands(const NxF32 *vertices) = 0;
virtual NxU32 mergeTouchingIslands(const NxF64 *vertices) = 0;
virtual NxU32 * getIsland(NxU32 index,NxU32 &tcount) = 0;
};
MeshIslandGeneration * createMeshIslandGeneration(void);
void releaseMeshIslandGeneration(MeshIslandGeneration *cm);
}; // end of namespace
#endif

View file

@ -1,153 +0,0 @@
/*
NvRayCast.cpp : A code snippet to cast a ray against a triangle mesh. This implementation does not use any acceleration data structures. That is a 'to do' item.
*/
/*!
**
** 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 "NvRayCast.h"
#include "NvUserMemAlloc.h"
#include "NvFloatMath.h"
#pragma warning(disable:4100)
namespace CONVEX_DECOMPOSITION
{
class RayCast : public iRayCast, public Memalloc
{
public:
RayCast(const NxF32 *vertices,NxU32 tcount,const NxU32 *indices)
{
mVertices = vertices;
mTcount = tcount;
mIndices = indices;
}
~RayCast(void)
{
}
virtual bool castRay(const NxF32 *orig,const NxF32 *dir,NxF32 *dest,NxF32 *hitNormal)
{
bool ret = false;
NxF32 p2[3];
const NxF32 RAY_DIST=50;
dest[0] = p2[0] = orig[0]+ dir[0]*RAY_DIST;
dest[1] = p2[1] = orig[1]+ dir[1]*RAY_DIST;
dest[2] = p2[2] = orig[2]+ dir[2]*RAY_DIST;
NxF32 nearest = 1e9;
NxU32 near_face=0;
for (NxU32 i=0; i<mTcount; i++)
{
NxU32 i1 = mIndices[i*3+0];
NxU32 i2 = mIndices[i*3+1];
NxU32 i3 = mIndices[i*3+2];
const NxF32 *t1 = &mVertices[i1*3];
const NxF32 *t2 = &mVertices[i2*3];
const NxF32 *t3 = &mVertices[i3*3];
NxF32 t;
if ( fm_rayIntersectsTriangle(orig,dir,t1,t2,t3,t) )
{
if ( t < nearest )
{
dest[0] = orig[0]+dir[0]*t;
dest[1] = orig[1]+dir[1]*t;
dest[2] = orig[2]+dir[2]*t;
ret = true;
near_face = i;
nearest = t;
}
}
}
if ( ret )
{
// If the nearest face we hit was back-facing, then reject this cast!
NxU32 i1 = mIndices[near_face*3+0];
NxU32 i2 = mIndices[near_face*3+1];
NxU32 i3 = mIndices[near_face*3+2];
const NxF32 *t1 = &mVertices[i1*3];
const NxF32 *t2 = &mVertices[i2*3];
const NxF32 *t3 = &mVertices[i3*3];
fm_computePlane(t3,t2,t1,hitNormal);
}
return ret;
}
private:
const NxF32 *mVertices;
NxU32 mTcount;
const NxU32 *mIndices;
};
iRayCast *createRayCast(const NxF32 *vertices,NxU32 tcount,const NxU32 *indices)
{
RayCast *rc = MEMALLOC_NEW(RayCast)(vertices,tcount,indices);
return static_cast< iRayCast *>(rc);
}
void releaseRayCast(iRayCast *rc)
{
RayCast *r = static_cast< RayCast *>(rc);
delete r;
}
};

View file

@ -1,79 +0,0 @@
#ifndef NV_RAYCAST_H
#define NV_RAYCAST_H
/*
NvRayCast.h : A code snippet to cast a ray against a triangle mesh. This implementation does not use any acceleration data structures. That is a 'to do' item.
*/
#include "NvSimpleTypes.h"
/*!
**
** 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.
*/
namespace CONVEX_DECOMPOSITION
{
class iRayCast
{
public:
virtual bool castRay(const NxF32 *orig,const NxF32 *dir,NxF32 *hitPoint,NxF32 *hitNormal) = 0;
protected:
virtual ~iRayCast(void) { };
};
iRayCast *createRayCast(const NxF32 *vertices,NxU32 tcount,const NxU32 *indices);
void releaseRayCast(iRayCast *rc);
};
#endif

View file

@ -1,713 +0,0 @@
/*
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>
#if defined( __APPLE__ ) || defined( __FreeBSD__)
#include <ext/hash_map>
#elif LINUX
#include <hash_map>
#elif _MSC_VER < 1500
#include <hash_map>
#elif _MSC_VER > 1800
#include <unordered_map>
#endif
#include "NvUserMemAlloc.h"
#include "NvHashMap.h"
#include "NvRemoveTjunctions.h"
#include "NvFloatMath.h"
#ifdef LINUX
#include <climits>
#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; 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

View file

@ -1,110 +0,0 @@
#ifndef REMOVE_TJUNCTIONS_H
#define REMOVE_TJUNCTIONS_H
/*
NvRemoveTjunctions.h : A code snippet to remove tjunctions from a triangle mesh. This version is currently disabled as it appears to have a bug.
*/
#include "NvUserMemAlloc.h"
/*!
**
** 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.
*/
namespace CONVEX_DECOMPOSITION
{
class RemoveTjunctionsDesc
{
public:
RemoveTjunctionsDesc(void)
{
mVcount = 0;
mVertices = 0;
mTcount = 0;
mIndices = 0;
mIds = 0;
mTcountOut = 0;
mIndicesOut = 0;
mIdsOut = 0;
mEpsilon = 0.00000001f;
}
// input
NxF32 mEpsilon;
NxF32 mDistanceEpsilon;
NxU32 mVcount; // input vertice count.
const NxF32 *mVertices; // input vertices as NxF32s or...
NxU32 mTcount; // number of input triangles.
const NxU32 *mIndices; // triangle indices.
const NxU32 *mIds; // optional triangle Id numbers.
// output..
NxU32 mTcountOut; // number of output triangles.
const NxU32 *mIndicesOut; // output triangle indices
const NxU32 *mIdsOut; // output retained id numbers.
};
// Removes t-junctions from an input mesh. Does not generate any new data points, but may possible produce additional triangles and new indices.
class RemoveTjunctions
{
public:
virtual NxU32 removeTjunctions(RemoveTjunctionsDesc &desc) =0; // returns number of triangles output and the descriptor is filled with the appropriate results.
};
RemoveTjunctions * createRemoveTjunctions(void);
void releaseRemoveTjunctions(RemoveTjunctions *tj);
}; // end of namespace
#endif

View file

@ -1,189 +0,0 @@
#ifndef NV_SIMPLE_TYPES_H
#define NV_SIMPLE_TYPES_H
/*
NvSimpleTypes.h : Defines basic data types for integers and floats.
*/
/*!
**
** 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.
*/
#if defined(__APPLE__)
#include <sys/malloc.h>
#else
#if defined( __FreeBSD__)
#include <stdlib.h>
#else
#include <malloc.h>
#endif
#endif
#include <assert.h>
#if defined(__APPLE__) || defined(__CELLOS_LV2__) || defined(LINUX)
#ifndef stricmp
#define stricmp(a, b) strcasecmp((a), (b))
#define _stricmp(a, b) strcasecmp((a), (b))
#endif
#endif
#if defined(WIN32)
typedef __int64 NxI64;
typedef signed int NxI32;
typedef signed short NxI16;
typedef signed char NxI8;
typedef unsigned __int64 NxU64;
typedef unsigned int NxU32;
typedef unsigned short NxU16;
typedef unsigned char NxU8;
typedef float NxF32;
typedef double NxF64;
#elif defined(LINUX)
typedef long long NxI64;
typedef signed int NxI32;
typedef signed short NxI16;
typedef signed char NxI8;
typedef unsigned long long NxU64;
typedef unsigned int NxU32;
typedef unsigned short NxU16;
typedef unsigned char NxU8;
typedef float NxF32;
typedef double NxF64;
#elif defined(__APPLE__)
typedef long long NxI64;
typedef signed int NxI32;
typedef signed short NxI16;
typedef signed char NxI8;
typedef unsigned long long NxU64;
typedef unsigned int NxU32;
typedef unsigned short NxU16;
typedef unsigned char NxU8;
typedef float NxF32;
typedef double NxF64;
#elif defined(__FreeBSD__)
typedef long long NxI64;
typedef signed int NxI32;
typedef signed short NxI16;
typedef signed char NxI8;
typedef unsigned long long NxU64;
typedef unsigned int NxU32;
typedef unsigned short NxU16;
typedef unsigned char NxU8;
typedef float NxF32;
typedef double NxF64;
#elif defined(__CELLOS_LV2__)
typedef long long NxI64;
typedef signed int NxI32;
typedef signed short NxI16;
typedef signed char NxI8;
typedef unsigned long long NxU64;
typedef unsigned int NxU32;
typedef unsigned short NxU16;
typedef unsigned char NxU8;
typedef float NxF32;
typedef double NxF64;
#elif defined(_XBOX)
typedef __int64 NxI64;
typedef signed int NxI32;
typedef signed short NxI16;
typedef signed char NxI8;
typedef unsigned __int64 NxU64;
typedef unsigned int NxU32;
typedef unsigned short NxU16;
typedef unsigned char NxU8;
typedef float NxF32;
typedef double NxF64;
#elif defined(__PPCGEKKO__)
typedef long long NxI64;
typedef signed int NxI32;
typedef signed short NxI16;
typedef signed char NxI8;
typedef unsigned long long NxU64;
typedef unsigned int NxU32;
typedef unsigned short NxU16;
typedef unsigned char NxU8;
typedef float NxF32;
typedef double NxF64;
#else
#error Unknown platform!
#endif
#ifndef NX_INLINE
#define NX_INLINE inline
#define NX_ASSERT assert
#endif
#endif

View file

@ -1,224 +0,0 @@
/*
NvSplitMesh.cpp : A code snippet to split a mesh into two seperate meshes based on a slicing plane.
*/
/*!
**
** 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.
*/
#define SHOW_DEBUG 0
#if SHOW_DEBUG
#include "RenderDebug.h"
#endif
#include "NvSplitMesh.h"
#include "NvFloatMath.h"
#include "NvHashMap.h"
#pragma warning(disable:4100)
namespace CONVEX_DECOMPOSITION
{
typedef Array< NxU32 > NxU32Array;
class SplitMesh : public iSplitMesh, public Memalloc
{
public:
SplitMesh(void)
{
mLeftVertices = 0;
mRightVertices = 0;
}
~SplitMesh(void)
{
reset();
}
void reset(void)
{
if ( mLeftVertices )
{
fm_releaseVertexIndex(mLeftVertices);
mLeftVertices = 0;
}
if ( mRightVertices )
{
fm_releaseVertexIndex(mRightVertices);
mRightVertices = 0;
}
mLeftIndices.clear();
mRightIndices.clear();
}
virtual void splitMesh(const NvSplitMesh &source,NvSplitMesh &leftMesh,NvSplitMesh &rightMesh,const NxF32 *planeEquation,NxF32 precision)
{
reset();
mLeftVertices = fm_createVertexIndex(precision,false);
mRightVertices = fm_createVertexIndex(precision,false);
for (NxU32 i=0; i<source.mTcount; i++)
{
NxU32 i1 = source.mIndices[i*3+0];
NxU32 i2 = source.mIndices[i*3+1];
NxU32 i3 = source.mIndices[i*3+2];
const NxF32 *p1 = &source.mVertices[i1*3];
const NxF32 *p2 = &source.mVertices[i2*3];
const NxF32 *p3 = &source.mVertices[i3*3];
NxF32 source_tri[3*3];
source_tri[0] = p1[0];
source_tri[1] = p1[1];
source_tri[2] = p1[2];
source_tri[3] = p2[0];
source_tri[4] = p2[1];
source_tri[5] = p2[2];
source_tri[6] = p3[0];
source_tri[7] = p3[1];
source_tri[8] = p3[2];
NxF32 front_tri[3*5];
NxF32 back_tri[3*5];
NxU32 fcount,bcount;
fm_planeTriIntersection(planeEquation,source_tri,sizeof(NxF32)*3,0.000001f,front_tri,fcount,back_tri,bcount);
bool newPos;
if ( fcount )
{
NxU32 i1,i2,i3,i4;
i1 = mLeftVertices->getIndex( &front_tri[0],newPos );
i2 = mLeftVertices->getIndex( &front_tri[3],newPos );
i3 = mLeftVertices->getIndex( &front_tri[6],newPos );
mLeftIndices.pushBack(i1);
mLeftIndices.pushBack(i2);
mLeftIndices.pushBack(i3);
#if SHOW_DEBUG
NVSHARE::gRenderDebug->setCurrentColor(0xFFFFFF);
NVSHARE::gRenderDebug->DebugTri(&front_tri[0],&front_tri[3],&front_tri[6]);
#endif
if ( fcount == 4 )
{
i4 = mLeftVertices->getIndex( &front_tri[9],newPos );
mLeftIndices.pushBack(i1);
mLeftIndices.pushBack(i3);
mLeftIndices.pushBack(i4);
#if SHOW_DEBUG
NVSHARE::gRenderDebug->setCurrentColor(0xFFFF00);
NVSHARE::gRenderDebug->DebugTri(&front_tri[0],&front_tri[6],&front_tri[9]);
#endif
}
}
if ( bcount )
{
NxU32 i1,i2,i3,i4;
i1 = mRightVertices->getIndex( &back_tri[0],newPos );
i2 = mRightVertices->getIndex( &back_tri[3],newPos );
i3 = mRightVertices->getIndex( &back_tri[6],newPos );
mRightIndices.pushBack(i1);
mRightIndices.pushBack(i2);
mRightIndices.pushBack(i3);
#if SHOW_DEBUG
NVSHARE::gRenderDebug->setCurrentColor(0xFF8080);
NVSHARE::gRenderDebug->DebugTri(&back_tri[0],&back_tri[3],&back_tri[6]);
#endif
if ( bcount == 4 )
{
i4 = mRightVertices->getIndex( &back_tri[9],newPos );
mRightIndices.pushBack(i1);
mRightIndices.pushBack(i3);
mRightIndices.pushBack(i4);
#if SHOW_DEBUG
NVSHARE::gRenderDebug->setCurrentColor(0x00FF00);
NVSHARE::gRenderDebug->DebugTri(&back_tri[0],&back_tri[6],&back_tri[9]);
#endif
}
}
}
leftMesh.mVcount = mLeftVertices->getVcount();
leftMesh.mVertices = mLeftVertices->getVerticesFloat();
leftMesh.mTcount = mLeftIndices.size()/3;
leftMesh.mIndices = &mLeftIndices[0];
rightMesh.mVcount = mRightVertices->getVcount();
rightMesh.mVertices = mRightVertices->getVerticesFloat();
rightMesh.mTcount = mRightIndices.size()/3;
rightMesh.mIndices = &mRightIndices[0];
}
fm_VertexIndex *mLeftVertices;
fm_VertexIndex *mRightVertices;
NxU32Array mLeftIndices;
NxU32Array mRightIndices;
};
iSplitMesh *createSplitMesh(void)
{
SplitMesh *sm = MEMALLOC_NEW(SplitMesh);
return static_cast< iSplitMesh *>(sm);
}
void releaseSplitMesh(iSplitMesh *splitMesh)
{
SplitMesh *sm = static_cast< SplitMesh *>(splitMesh);
delete sm;
}
}; // end of namespace

View file

@ -1,88 +0,0 @@
#ifndef NV_SPLIT_MESH_H
#define NV_SPLIT_MESH_H
/*
NvSplitMesh.h : A code snippet to split a mesh into two seperate meshes based on a slicing plane.
*/
#include "NvUserMemAlloc.h"
/*!
**
** 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.
*/
namespace CONVEX_DECOMPOSITION
{
struct NvSplitMesh
{
NxU32 mVcount;
const NxF32 *mVertices;
NxU32 mTcount;
const NxU32 *mIndices;
};
class iSplitMesh
{
public:
virtual void splitMesh(const NvSplitMesh &source,NvSplitMesh &leftMesh,NvSplitMesh &rightMesh,const NxF32 *planeEquation,NxF32 precision) = 0;
protected:
virtual ~iSplitMesh(void) { };
};
iSplitMesh *createSplitMesh(void);
void releaseSplitMesh(iSplitMesh *splitMesh);
}; // end of namespace
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,201 +0,0 @@
#ifndef NV_STAN_HULL_H
#define NV_STAN_HULL_H
/*
NvStanHull.h : A convex hull generator written by Stan Melax
*/
/*!
**
** 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 "NvUserMemAlloc.h"
namespace CONVEX_DECOMPOSITION
{
class HullResult
{
public:
HullResult(void)
{
mPolygons = true;
mNumOutputVertices = 0;
mOutputVertices = 0;
mNumFaces = 0;
mNumIndices = 0;
mIndices = 0;
}
bool mPolygons; // true if indices represents polygons, false indices are triangles
NxU32 mNumOutputVertices; // number of vertices in the output hull
NxF32 *mOutputVertices; // array of vertices, 3 floats each x,y,z
NxU32 mNumFaces; // the number of faces produced
NxU32 mNumIndices; // the total number of indices
NxU32 *mIndices; // pointer to indices.
// If triangles, then indices are array indexes into the vertex list.
// If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc..
};
enum HullFlag
{
QF_TRIANGLES = (1<<0), // report results as triangles, not polygons.
QF_REVERSE_ORDER = (1<<1), // reverse order of the triangle indices.
QF_SKIN_WIDTH = (1<<2), // extrude hull based on this skin width
QF_DEFAULT = (QF_TRIANGLES | QF_SKIN_WIDTH)
};
class HullDesc
{
public:
HullDesc(void)
{
mFlags = QF_DEFAULT;
mVcount = 0;
mVertices = 0;
mVertexStride = 0;
mNormalEpsilon = 0.001f;
mMaxVertices = 4096; // maximum number of points to be considered for a convex hull.
mSkinWidth = 0.01f; // default is one centimeter
};
HullDesc(HullFlag flag,
NxU32 vcount,
const NxF32 *vertices,
NxU32 stride)
{
mFlags = flag;
mVcount = vcount;
mVertices = vertices;
mVertexStride = stride;
mNormalEpsilon = 0.001f;
mMaxVertices = 4096;
mSkinWidth = 0.01f; // default is one centimeter
}
bool HasHullFlag(HullFlag flag) const
{
if ( mFlags & flag ) return true;
return false;
}
void SetHullFlag(HullFlag flag)
{
mFlags|=flag;
}
void ClearHullFlag(HullFlag flag)
{
mFlags&=~flag;
}
NxU32 mFlags; // flags to use when generating the convex hull.
NxU32 mVcount; // number of vertices in the input point cloud
const NxF32 *mVertices; // the array of vertices.
NxU32 mVertexStride; // the stride of each vertex, in bytes.
NxF32 mNormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on.
NxF32 mSkinWidth;
NxU32 mMaxVertices; // maximum number of vertices to be considered for the hull!
};
enum HullError
{
QE_OK, // success!
QE_FAIL, // failed.
QE_NOT_READY,
};
// This class is used when converting a convex hull into a triangle mesh.
class ConvexHullVertex
{
public:
NxF32 mPos[3];
NxF32 mNormal[3];
NxF32 mTexel[2];
};
// A virtual interface to receive the triangles from the convex hull.
class ConvexHullTriangleInterface
{
public:
virtual void ConvexHullTriangle(const ConvexHullVertex &v1,const ConvexHullVertex &v2,const ConvexHullVertex &v3) = 0;
};
class HullLibrary
{
public:
HullError CreateConvexHull(const HullDesc &desc, // describes the input request
HullResult &result); // contains the resulst
HullError ReleaseResult(HullResult &result); // release memory allocated for this result, we are done with it.
HullError CreateTriangleMesh(HullResult &answer,ConvexHullTriangleInterface *iface);
private:
NxF32 ComputeNormal(NxF32 *n,const NxF32 *A,const NxF32 *B,const NxF32 *C);
void AddConvexTriangle(ConvexHullTriangleInterface *callback,const NxF32 *p1,const NxF32 *p2,const NxF32 *p3);
void BringOutYourDead(const NxF32 *verts,NxU32 vcount, NxF32 *overts,NxU32 &ocount,NxU32 *indices,NxU32 indexcount);
bool CleanupVertices(NxU32 svcount,
const NxF32 *svertices,
NxU32 stride,
NxU32 &vcount, // output number of vertices
NxF32 *vertices, // location to store the results.
NxF32 normalepsilon,
NxF32 *scale);
};
}; // end of namespace
#endif

View file

@ -1,511 +0,0 @@
/*
NvThreadConfig.cpp : A simple wrapper class to define threading and mutex locks.
*/
/*!
**
** 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 <cassert>
#include "NvThreadConfig.h"
#if defined(WIN32)
#define _WIN32_WINNT 0x400
#include <windows.h>
#pragma comment(lib,"winmm.lib")
// #ifndef _WIN32_WINNT
// #endif
// #include <windows.h>
//#include <winbase.h>
#endif
#if defined(_XBOX)
#include <xtl.h>
#endif
#if defined(__linux__) || defined( __APPLE__ ) || defined( __FreeBSD__)
//#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#define __stdcall
#endif
#if defined( __APPLE__ ) || defined( __FreeBSD__)
#include <sys/time.h>
#endif
#if defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
#include <pthread.h>
#endif
#if defined( __APPLE__ ) || defined( __FreeBSD__)
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#endif
#ifdef NDEBUG
#define VERIFY( x ) (x)
#else
#define VERIFY( x ) assert((x))
#endif
namespace CONVEX_DECOMPOSITION
{
NxU32 tc_timeGetTime(void)
{
#if defined(__linux__)
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
#elif defined( __APPLE__ ) || defined( __FreeBSD__)
struct timeval tp;
gettimeofday(&tp, (struct timezone *)0);
return tp.tv_sec * 1000 + tp.tv_usec / 1000;
#elif defined( _XBOX )
return GetTickCount();
#else
return timeGetTime();
#endif
}
void tc_sleep(NxU32 ms)
{
#if defined(__linux__) || defined( __APPLE__ ) || defined( __FreeBSD__)
usleep(ms * 1000);
#else
Sleep(ms);
#endif
}
void tc_spinloop()
{
#if defined( _XBOX )
// Pause would do nothing on the Xbox. Threads are not scheduled.
#elif defined( _WIN64 )
YieldProcessor( );
#elif defined( __APPLE__ )
pthread_yield_np();
#elif defined(__linux__) || defined(__FreeBSD__)
#if defined(_POSIX_PRIORITY_SCHEDULING)
sched_yield();
#else
asm("pause");
#endif
#elif
__asm { pause };
#endif
}
void tc_interlockedExchange(void *dest, const int64_t exchange)
{
#if defined( __linux__ ) || defined( __APPLE__ ) || defined( __FreeBSD__)
// not working
assert(false);
//__sync_lock_test_and_set((int64_t*)dest, exchange);
#elif defined( _XBOX ) || defined( _WIN64 )
InterlockedExchange((volatile LONG *)dest, exchange);
#else
__asm
{
mov ebx, dword ptr [exchange]
mov ecx, dword ptr [exchange + 4]
mov edi, dest
mov eax, dword ptr [edi]
mov edx, dword ptr [edi + 4]
jmp start
retry:
pause
start:
lock cmpxchg8b [edi]
jnz retry
};
#endif
}
NxI32 tc_interlockedCompareExchange(void *dest, NxI32 exchange, NxI32 compare)
{
#if defined( __linux__ ) || defined( __APPLE__ ) || defined( __FreeBSD__)
// not working
assert(false);
return 0;
//return __sync_val_compare_and_swap((uintptr_t*)dest, exchange, compare);
//return __sync_bool_compare_and_swap((uintptr_t*)dest, exchange, compare);
#elif defined( _XBOX ) || defined( _WIN64 )
return InterlockedCompareExchange((volatile LONG *)dest, exchange, compare);
#else
char _ret;
//
__asm
{
mov edx, [dest]
mov eax, [compare]
mov ecx, [exchange]
lock cmpxchg [edx], ecx
setz al
mov byte ptr [_ret], al
}
//
return _ret;
#endif
}
NxI32 tc_interlockedCompareExchange(void *dest, const NxI32 exchange1, const NxI32 exchange2, const NxI32 compare1, const NxI32 compare2)
{
#if defined( __linux__ ) || defined( __APPLE__ ) || defined( __FreeBSD__)
// not working
assert(false);
return 0;
//uint64_t exchange = ((uint64_t)exchange1 << 32) | (uint64_t)exchange2;
//uint64_t compare = ((uint64_t)compare1 << 32) | (uint64_t)compare2;
//return __sync_bool_compare_and_swap((int64_t*)dest, exchange, compare);
#elif defined( _XBOX ) || defined( _WIN64 )
assert(false);
return 0;
#else
char _ret;
//
__asm
{
mov ebx, [exchange1]
mov ecx, [exchange2]
mov edi, [dest]
mov eax, [compare1]
mov edx, [compare2]
lock cmpxchg8b [edi]
setz al
mov byte ptr [_ret], al
}
//
return _ret;
#endif
}
class MyThreadMutex : public ThreadMutex
{
public:
MyThreadMutex(void)
{
#if defined(WIN32) || defined(_XBOX)
InitializeCriticalSection(&m_Mutex);
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
pthread_mutexattr_t mutexAttr; // Mutex Attribute
VERIFY( pthread_mutexattr_init(&mutexAttr) == 0 );
VERIFY( pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE_NP) == 0 );
VERIFY( pthread_mutex_init(&m_Mutex, &mutexAttr) == 0 );
VERIFY( pthread_mutexattr_destroy(&mutexAttr) == 0 );
#endif
}
~MyThreadMutex(void)
{
#if defined(WIN32) || defined(_XBOX)
DeleteCriticalSection(&m_Mutex);
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
VERIFY( pthread_mutex_destroy(&m_Mutex) == 0 );
#endif
}
void lock(void)
{
#if defined(WIN32) || defined(_XBOX)
EnterCriticalSection(&m_Mutex);
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
VERIFY( pthread_mutex_lock(&m_Mutex) == 0 );
#endif
}
bool tryLock(void)
{
#if defined(WIN32) || defined(_XBOX)
bool bRet = false;
//assert(("TryEnterCriticalSection seems to not work on XP???", 0));
bRet = TryEnterCriticalSection(&m_Mutex) ? true : false;
return bRet;
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
NxI32 result = pthread_mutex_trylock(&m_Mutex);
return (result == 0);
#endif
}
void unlock(void)
{
#if defined(WIN32) || defined(_XBOX)
LeaveCriticalSection(&m_Mutex);
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
VERIFY( pthread_mutex_unlock(&m_Mutex) == 0 );
#endif
}
private:
#if defined(WIN32) || defined(_XBOX)
CRITICAL_SECTION m_Mutex;
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
pthread_mutex_t m_Mutex;
#endif
};
ThreadMutex * tc_createThreadMutex(void)
{
MyThreadMutex *m = new MyThreadMutex;
return static_cast< ThreadMutex *>(m);
}
void tc_releaseThreadMutex(ThreadMutex *tm)
{
MyThreadMutex *m = static_cast< MyThreadMutex *>(tm);
delete m;
}
#if defined(WIN32) || defined(_XBOX)
static unsigned long __stdcall _ThreadWorkerFunc(LPVOID arg);
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
static void* _ThreadWorkerFunc(void* arg);
#endif
class MyThread : public Thread
{
public:
MyThread(ThreadInterface *iface)
{
mInterface = iface;
#if defined(WIN32) || defined(_XBOX)
mThread = CreateThread(0, 0, _ThreadWorkerFunc, this, 0, 0);
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
VERIFY( pthread_create(&mThread, NULL, _ThreadWorkerFunc, this) == 0 );
#endif
}
~MyThread(void)
{
#if defined(WIN32) || defined(_XBOX)
if ( mThread )
{
CloseHandle(mThread);
mThread = 0;
}
#endif
}
void onJobExecute(void)
{
mInterface->threadMain();
}
private:
ThreadInterface *mInterface;
#if defined(WIN32) || defined(_XBOX)
HANDLE mThread;
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
pthread_t mThread;
#endif
};
Thread * tc_createThread(ThreadInterface *tinterface)
{
MyThread *m = new MyThread(tinterface);
return static_cast< Thread *>(m);
}
void tc_releaseThread(Thread *t)
{
MyThread *m = static_cast<MyThread *>(t);
delete m;
}
#if defined(WIN32) || defined(_XBOX)
static unsigned long __stdcall _ThreadWorkerFunc(LPVOID arg)
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
static void* _ThreadWorkerFunc(void* arg)
#endif
{
MyThread *worker = (MyThread *) arg;
worker->onJobExecute();
return 0;
}
class MyThreadEvent : public ThreadEvent
{
public:
MyThreadEvent(void)
{
#if defined(WIN32) || defined(_XBOX)
mEvent = ::CreateEventA(NULL,TRUE,TRUE,"ThreadEvent");
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
pthread_mutexattr_t mutexAttr; // Mutex Attribute
VERIFY( pthread_mutexattr_init(&mutexAttr) == 0 );
VERIFY( pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE_NP) == 0 );
VERIFY( pthread_mutex_init(&mEventMutex, &mutexAttr) == 0 );
VERIFY( pthread_mutexattr_destroy(&mutexAttr) == 0 );
VERIFY( pthread_cond_init(&mEvent, NULL) == 0 );
#endif
}
~MyThreadEvent(void)
{
#if defined(WIN32) || defined(_XBOX)
if ( mEvent )
{
::CloseHandle(mEvent);
}
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
VERIFY( pthread_cond_destroy(&mEvent) == 0 );
VERIFY( pthread_mutex_destroy(&mEventMutex) == 0 );
#endif
}
virtual void setEvent(void) // signal the event
{
#if defined(WIN32) || defined(_XBOX)
if ( mEvent )
{
::SetEvent(mEvent);
}
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
VERIFY( pthread_mutex_lock(&mEventMutex) == 0 );
VERIFY( pthread_cond_signal(&mEvent) == 0 );
VERIFY( pthread_mutex_unlock(&mEventMutex) == 0 );
#endif
}
void resetEvent(void)
{
#if defined(WIN32) || defined(_XBOX)
if ( mEvent )
{
::ResetEvent(mEvent);
}
#endif
}
virtual void waitForSingleObject(NxU32 ms)
{
#if defined(WIN32) || defined(_XBOX)
if ( mEvent )
{
::WaitForSingleObject(mEvent,ms);
}
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
VERIFY( pthread_mutex_lock(&mEventMutex) == 0 );
if (ms == 0xffffffff)
{
VERIFY( pthread_cond_wait(&mEvent, &mEventMutex) == 0 );
}
else
{
struct timespec ts;
#ifdef __APPLE__
struct timeval tp;
gettimeofday(&tp, (struct timezone *)0);
ts.tv_nsec = tp.tv_usec * 1000;
ts.tv_sec = tp.tv_sec;
#else
clock_gettime(CLOCK_REALTIME, &ts);
#endif
ts.tv_nsec += ms * 1000000;
ts.tv_sec += ts.tv_nsec / 1000000000;
ts.tv_nsec %= 1000000000;
NxI32 result = pthread_cond_timedwait(&mEvent, &mEventMutex, &ts);
assert(result == 0 || result == ETIMEDOUT);
}
VERIFY( pthread_mutex_unlock(&mEventMutex) == 0 );
#endif
}
private:
#if defined(WIN32) || defined(_XBOX)
HANDLE mEvent;
#elif defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__)
pthread_mutex_t mEventMutex;
pthread_cond_t mEvent;
#endif
};
ThreadEvent * tc_createThreadEvent(void)
{
MyThreadEvent *m = new MyThreadEvent;
return static_cast<ThreadEvent *>(m);
}
void tc_releaseThreadEvent(ThreadEvent *t)
{
MyThreadEvent *m = static_cast< MyThreadEvent *>(t);
delete m;
}
}; // end of namespace

View file

@ -1,119 +0,0 @@
#ifndef NV_THREAD_CONFIG_H
#define NV_THREAD_CONFIG_H
#include "NvUserMemAlloc.h"
/*
NvThreadConfig.h : A simple wrapper class to define threading and mutex locks.
*/
/*!
**
** 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.
*/
#ifdef _MSC_VER
typedef __int64 int64_t;
#else
#include <stdint.h>
#endif
namespace CONVEX_DECOMPOSITION
{
NxU32 tc_timeGetTime(void);
void tc_sleep(NxU32 ms);
void tc_spinloop();
void tc_interlockedExchange(void *dest, const int64_t exchange);
NxI32 tc_interlockedCompareExchange(void *dest, NxI32 exchange, NxI32 compare);
NxI32 tc_interlockedCompareExchange(void *dest, const NxI32 exchange1, const NxI32 exchange2, const NxI32 compare1, const NxI32 compare2);
class ThreadMutex
{
public:
virtual void lock(void) = 0;
virtual void unlock(void) = 0;
virtual bool tryLock(void) = 0;
};
ThreadMutex * tc_createThreadMutex(void);
void tc_releaseThreadMutex(ThreadMutex *tm);
class ThreadInterface
{
public:
virtual void threadMain(void) = 0;
};
class Thread
{
public:
};
Thread * tc_createThread(ThreadInterface *tinterface);
void tc_releaseThread(Thread *t);
class ThreadEvent
{
public:
virtual void setEvent(void) = 0; // signal the event
virtual void resetEvent(void) = 0;
virtual void waitForSingleObject(NxU32 ms) = 0;
};
ThreadEvent * tc_createThreadEvent(void);
void tc_releaseThreadEvent(ThreadEvent *t);
}; // end of namespace
#endif

View file

@ -1,81 +0,0 @@
#ifndef NV_USER_MEMALLOC_H
#define NV_USER_MEMALLOC_H
#include "NvSimpleTypes.h"
/*
NvUserMemAlloc.h : Modify these macros to change the default memory allocation behavior of the convex decomposition code.
*/
/*!
**
** 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.
*/
#ifndef MEMALLOC_NEW
#define MEMALLOC_NEW(x) new x
#define MEMALLOC_MALLOC(x) ::malloc(x)
#define MEMALLOC_FREE(x) ::free(x)
#define MEMALLOC_REALLOC(x,y) ::realloc(x,y)
#endif
namespace CONVEX_DECOMPOSITION
{
class Memalloc
{
public:
};
}; // end of namespace
#endif

View file

@ -1,38 +0,0 @@
The ConvexDecomposition library was written by John W. Ratcliff mailto:jratcliffscarab@gmail.com
What is Convex Decomposition?
Convex Decomposition is when you take an arbitrarily complex triangle mesh and sub-divide it into
a collection of discrete compound pieces (each represented as a convex hull) to approximate
the original shape of the objet.
This is required since few physics engines can treat aribtrary triangle mesh objects as dynamic
objects. Even those engines which can handle this use case incurr a huge performance and memory
penalty to do so.
By breaking a complex triangle mesh up into a discrete number of convex components you can greatly
improve performance for dynamic simulations.
--------------------------------------------------------------------------------
This code is released under the MIT license.
The code is functional but could use the following improvements:
(1) The convex hull generator, originally written by Stan Melax, could use some major code cleanup.
(2) The code to remove T-junctions appears to have a bug in it. This code was working fine before,
but I haven't had time to debug why it stopped working.
(3) Island generation once the mesh has been split is currently disabled due to the fact that the
Remove Tjunctions functionality has a bug in it.
(4) The code to perform a raycast against a triangle mesh does not currently use any acceleration
data structures.
(5) When a split is performed, the surface that got split is not 'capped'. This causes a problem
if you use a high recursion depth on your convex decomposition. It will cause the object to
be modelled as if it had a hollow interior. A lot of work was done to solve this problem, but
it hasn't been integrated into this code drop yet.

View file

@ -1,852 +0,0 @@
/*
wavefront.cpp : A very small code snippet to read a Wavefront OBJ file into memory.
*/
/*!
**
** 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.
*/
#ifndef __PPCGEKKO__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include "wavefront.h"
#include <vector>
typedef std::vector< NxI32 > IntVector;
typedef std::vector< NxF32 > FloatVector;
#pragma warning(disable:4996)
namespace WAVEFRONT
{
/*******************************************************************/
/******************** InParser.h ********************************/
/*******************************************************************/
class InPlaceParserInterface
{
public:
virtual NxI32 ParseLine(NxI32 lineno,NxI32 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,NxI32 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 (NxI32 i=0; i<256; i++)
{
mHard[i] = ST_DATA;
mHardString[i*2] = 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,NxI32 len)
{
mData = data;
mLen = len;
mMyAlloc = false;
};
NxI32 Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
NxI32 ProcessLine(NxI32 lineno,char *line,InPlaceParserInterface *callback);
const char ** GetArglist(char *source,NxI32 &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(NxI32 &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.
NxI32 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(NxI32 &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;
}
NxI32 InPlaceParser::ProcessLine(NxI32 lineno,char *line,InPlaceParserInterface *callback)
{
NxI32 ret = 0;
const char *argv[MAXARGS];
NxI32 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;
}
NxI32 InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
{
assert( callback );
if ( !mData ) return 0;
NxI32 ret = 0;
NxI32 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...
{
NxI32 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.
NxI32 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,NxI32 &count) // convert source string into an arg list, this is a destructive parse.
{
const char **ret = 0;
static const char *argv[MAXARGS];
NxI32 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:
NxF32 mPos[3];
NxF32 mNormal[3];
NxF32 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:
NxI32 LoadMesh(const char *fname,GeometryInterface *callback, bool textured);
NxI32 ParseLine(NxI32 lineno,NxI32 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 ********************************/
/*******************************************************************/
NxI32 OBJ::LoadMesh(const char *fname,GeometryInterface *iface, bool textured)
{
mTextured = textured;
NxI32 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,NxI32 i,NxI32 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;
NxI32 index = atoi( face )-1;
const char *texel = strstr(face,"/");
if ( texel )
{
NxI32 tindex = atoi( texel+1) - 1;
if ( tindex >=0 && tindex < (NxI32)(mTexels.size()/2) )
{
const NxF32 *t = &mTexels[tindex*2];
v.mTexel[0] = t[0];
v.mTexel[1] = t[1];
}
const char *normal = strstr(texel+1,"/");
if ( normal )
{
NxI32 nindex = atoi( normal+1 ) - 1;
if (nindex >= 0 && nindex < (NxI32)(mNormals.size()/3) )
{
const NxF32 *n = &mNormals[nindex*3];
v.mNormal[0] = n[0];
v.mNormal[1] = n[1];
v.mNormal[2] = n[2];
}
}
}
if ( index >= 0 && index < (NxI32)(mVerts.size()/3) )
{
const NxF32 *p = &mVerts[index*3];
v.mPos[0] = p[0];
v.mPos[1] = p[1];
v.mPos[2] = p[2];
}
}
NxI32 OBJ::ParseLine(NxI32 lineno,NxI32 argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
{
NxI32 ret = 0;
if ( argc >= 1 )
{
const char *foo = argv[0];
if ( *foo != '#' )
{
if ( _stricmp(argv[0],"v") == 0 && argc == 4 )
{
NxF32 vx = (NxF32) atof( argv[1] );
NxF32 vy = (NxF32) atof( argv[2] );
NxF32 vz = (NxF32) atof( argv[3] );
mVerts.push_back(vx);
mVerts.push_back(vy);
mVerts.push_back(vz);
}
else if ( _stricmp(argv[0],"vt") == 0 && (argc == 3 || argc == 4))
{
// ignore 4rd component if present
NxF32 tx = (NxF32) atof( argv[1] );
NxF32 ty = (NxF32) atof( argv[2] );
mTexels.push_back(tx);
mTexels.push_back(ty);
}
else if ( _stricmp(argv[0],"vn") == 0 && argc == 4 )
{
NxF32 normalx = (NxF32) atof(argv[1]);
NxF32 normaly = (NxF32) atof(argv[2]);
NxF32 normalz = (NxF32) atof(argv[3]);
mNormals.push_back(normalx);
mNormals.push_back(normaly);
mNormals.push_back(normalz);
}
else if ( _stricmp(argv[0],"f") == 0 && argc >= 4 )
{
GeometryVertex v[32];
NxI32 vcount = argc-1;
for (NxI32 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 (NxI32 i=2; i<(vcount-1); i++)
{
mCallback->NodeTriangle(&v[0],&v[i],&v[i+1], mTextured);
}
}
}
}
}
return ret;
}
class BuildMesh : public GeometryInterface
{
public:
NxI32 GetIndex(const NxF32 *p, const NxF32 *texCoord)
{
NxI32 vcount = (NxI32)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 NxF32 *v = &mVertices[0];
const NxF32 *t = texCoord != NULL ? &mTexCoords[0] : NULL;
for (NxI32 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;
}
NxU32 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.
{
NxU32 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 = (NxI32)vlist.size()/3;
mVertices = new NxF32[mVertexCount*3];
memcpy( mVertices, &vlist[0], sizeof(NxF32)*mVertexCount*3 );
if (textured)
{
mTexCoords = new NxF32[mVertexCount * 2];
const FloatVector& tList = bm.GetTexCoords();
memcpy( mTexCoords, &tList[0], sizeof(NxF32) * mVertexCount * 2);
}
mTriCount = (NxI32)indices.size()/3;
mIndices = new NxU32[mTriCount*3*sizeof(NxU32)];
memcpy(mIndices, &indices[0], sizeof(NxU32)*mTriCount*3);
ret = mTriCount;
}
return ret;
}
#endif

View file

@ -1,77 +0,0 @@
#ifndef WAVEFRONT_OBJ_H
#define WAVEFRONT_OBJ_H
/*
wavefront.h : A very small code snippet to read a Wavefront OBJ file into memory.
*/
/*!
**
** 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 "NvUserMemAlloc.h"
class WavefrontObj
{
public:
WavefrontObj(void);
~WavefrontObj(void);
NxU32 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.
NxU32 mVertexCount;
NxU32 mTriCount;
NxU32 *mIndices;
NxF32 *mVertices;
NxF32 *mTexCoords;
};
#endif

View file

@ -0,0 +1,3 @@
file(GLOB CONVEX_DECOMP_SOURCES "*.cpp")
add_library(convexMath STATIC ${CONVEX_DECOMP_SOURCES})
target_include_directories(convexMath PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View file

@ -0,0 +1,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include "FloatMath.h"
#include <vector>
#define REAL float
#include "FloatMath.inl"
#undef REAL
#define REAL double
#include "FloatMath.inl"

View file

@ -0,0 +1,525 @@
#ifndef FLOAT_MATH_LIB_H
#define FLOAT_MATH_LIB_H
#include <float.h>
#include <stdint.h>
namespace FLOAT_MATH
{
enum FM_ClipState
{
FMCS_XMIN = (1<<0),
FMCS_XMAX = (1<<1),
FMCS_YMIN = (1<<2),
FMCS_YMAX = (1<<3),
FMCS_ZMIN = (1<<4),
FMCS_ZMAX = (1<<5),
};
enum FM_Axis
{
FM_XAXIS = (1<<0),
FM_YAXIS = (1<<1),
FM_ZAXIS = (1<<2)
};
enum LineSegmentType
{
LS_START,
LS_MIDDLE,
LS_END
};
const float FM_PI = 3.1415926535897932384626433832795028841971693993751f;
const float FM_DEG_TO_RAD = ((2.0f * FM_PI) / 360.0f);
const float FM_RAD_TO_DEG = (360.0f / (2.0f * FM_PI));
//***************** Float versions
//***
//*** vectors are assumed to be 3 floats or 3 doubles representing X, Y, Z
//*** quaternions are assumed to be 4 floats or 4 doubles representing X,Y,Z,W
//*** matrices are assumed to be 16 floats or 16 doubles representing a standard D3D or OpenGL style 4x4 matrix
//*** bounding volumes are expressed as two sets of 3 floats/double representing bmin(x,y,z) and bmax(x,y,z)
//*** Plane equations are assumed to be 4 floats or 4 doubles representing Ax,By,Cz,D
FM_Axis fm_getDominantAxis(const float normal[3]);
FM_Axis fm_getDominantAxis(const double normal[3]);
void fm_decomposeTransform(const float local_transform[16],float trans[3],float rot[4],float scale[3]);
void fm_decomposeTransform(const double local_transform[16],double trans[3],double rot[4],double scale[3]);
void fm_multiplyTransform(const float *pA,const float *pB,float *pM);
void fm_multiplyTransform(const double *pA,const double *pB,double *pM);
void fm_inverseTransform(const float matrix[16],float inverse_matrix[16]);
void fm_inverseTransform(const double matrix[16],double inverse_matrix[16]);
void fm_identity(float matrix[16]); // set 4x4 matrix to identity.
void fm_identity(double matrix[16]); // set 4x4 matrix to identity.
void fm_inverseRT(const float matrix[16], const float pos[3], float t[3]); // inverse rotate translate the point.
void fm_inverseRT(const double matrix[16],const double pos[3],double t[3]); // inverse rotate translate the point.
void fm_transform(const float matrix[16], const float pos[3], float t[3]); // rotate and translate this point.
void fm_transform(const double matrix[16],const double pos[3],double t[3]); // rotate and translate this point.
float fm_getDeterminant(const float matrix[16]);
double fm_getDeterminant(const double matrix[16]);
void fm_getSubMatrix(int32_t ki,int32_t kj,float pDst[16],const float matrix[16]);
void fm_getSubMatrix(int32_t ki,int32_t kj,double pDst[16],const float matrix[16]);
void fm_rotate(const float matrix[16],const float pos[3],float t[3]); // only rotate the point by a 4x4 matrix, don't translate.
void fm_rotate(const double matrix[16],const double pos[3],double t[3]); // only rotate the point by a 4x4 matrix, don't translate.
void fm_eulerToMatrix(float ax,float ay,float az,float matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_eulerToMatrix(double ax,double ay,double az,double matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_getAABB(uint32_t vcount,const float *points,uint32_t pstride,float bmin[3],float bmax[3]);
void fm_getAABB(uint32_t vcount,const double *points,uint32_t pstride,double bmin[3],double bmax[3]);
void fm_getAABBCenter(const float bmin[3],const float bmax[3],float center[3]);
void fm_getAABBCenter(const double bmin[3],const double bmax[3],double center[3]);
void fm_transformAABB(const float bmin[3],const float bmax[3],const float matrix[16],float tbmin[3],float tbmax[3]);
void fm_transformAABB(const double bmin[3],const double bmax[3],const double matrix[16],double tbmin[3],double tbmax[3]);
void fm_eulerToQuat(float x,float y,float z,float quat[4]); // convert euler angles to quaternion.
void fm_eulerToQuat(double x,double y,double z,double quat[4]); // convert euler angles to quaternion.
void fm_quatToEuler(const float quat[4],float &ax,float &ay,float &az);
void fm_quatToEuler(const double quat[4],double &ax,double &ay,double &az);
void fm_eulerToQuat(const float euler[3],float quat[4]); // convert euler angles to quaternion. Angles must be radians not degrees!
void fm_eulerToQuat(const double euler[3],double quat[4]); // convert euler angles to quaternion.
void fm_scale(float x,float y,float z,float matrix[16]); // apply scale to the matrix.
void fm_scale(double x,double y,double z,double matrix[16]); // apply scale to the matrix.
void fm_eulerToQuatDX(float x,float y,float z,float quat[4]); // convert euler angles to quaternion using the fucked up DirectX method
void fm_eulerToQuatDX(double x,double y,double z,double quat[4]); // convert euler angles to quaternion using the fucked up DirectX method
void fm_eulerToMatrixDX(float x,float y,float z,float matrix[16]); // convert euler angles to quaternion using the fucked up DirectX method.
void fm_eulerToMatrixDX(double x,double y,double z,double matrix[16]); // convert euler angles to quaternion using the fucked up DirectX method.
void fm_quatToMatrix(const float quat[4],float matrix[16]); // convert quaternion rotation to matrix, translation set to zero.
void fm_quatToMatrix(const double quat[4],double matrix[16]); // convert quaternion rotation to matrix, translation set to zero.
void fm_quatRotate(const float quat[4],const float v[3],float r[3]); // rotate a vector directly by a quaternion.
void fm_quatRotate(const double quat[4],const double v[3],double r[3]); // rotate a vector directly by a quaternion.
void fm_getTranslation(const float matrix[16],float t[3]);
void fm_getTranslation(const double matrix[16],double t[3]);
void fm_setTranslation(const float *translation,float matrix[16]);
void fm_setTranslation(const double *translation,double matrix[16]);
void fm_multiplyQuat(const float *qa,const float *qb,float *quat);
void fm_multiplyQuat(const double *qa,const double *qb,double *quat);
void fm_matrixToQuat(const float matrix[16],float quat[4]); // convert the 3x3 portion of a 4x4 matrix into a quaternion as x,y,z,w
void fm_matrixToQuat(const double matrix[16],double quat[4]); // convert the 3x3 portion of a 4x4 matrix into a quaternion as x,y,z,w
float fm_sphereVolume(float radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
double fm_sphereVolume(double radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
float fm_cylinderVolume(float radius,float h);
double fm_cylinderVolume(double radius,double h);
float fm_capsuleVolume(float radius,float h);
double fm_capsuleVolume(double radius,double h);
float fm_distance(const float p1[3],const float p2[3]);
double fm_distance(const double p1[3],const double p2[3]);
float fm_distanceSquared(const float p1[3],const float p2[3]);
double fm_distanceSquared(const double p1[3],const double p2[3]);
float fm_distanceSquaredXZ(const float p1[3],const float p2[3]);
double fm_distanceSquaredXZ(const double p1[3],const double p2[3]);
float fm_computePlane(const float p1[3],const float p2[3],const float p3[3],float *n); // return D
double fm_computePlane(const double p1[3],const double p2[3],const double p3[3],double *n); // return D
float fm_distToPlane(const float plane[4],const float pos[3]); // computes the distance of this point from the plane.
double fm_distToPlane(const double plane[4],const double pos[3]); // computes the distance of this point from the plane.
float fm_dot(const float p1[3],const float p2[3]);
double fm_dot(const double p1[3],const double p2[3]);
void fm_cross(float cross[3],const float a[3],const float b[3]);
void fm_cross(double cross[3],const double a[3],const double b[3]);
float fm_computeNormalVector(float n[3],const float p1[3],const float p2[3]); // as P2-P1 normalized.
double fm_computeNormalVector(double n[3],const double p1[3],const double p2[3]); // as P2-P1 normalized.
bool fm_computeWindingOrder(const float p1[3],const float p2[3],const float p3[3]); // returns true if the triangle is clockwise.
bool fm_computeWindingOrder(const double p1[3],const double p2[3],const double p3[3]); // returns true if the triangle is clockwise.
float fm_normalize(float n[3]); // normalize this vector and return the distance
double fm_normalize(double n[3]); // normalize this vector and return the distance
float fm_normalizeQuat(float n[4]); // normalize this quat
double fm_normalizeQuat(double n[4]); // normalize this quat
void fm_matrixMultiply(const float A[16],const float B[16],float dest[16]);
void fm_matrixMultiply(const double A[16],const double B[16],double dest[16]);
void fm_composeTransform(const float position[3],const float quat[4],const float scale[3],float matrix[16]);
void fm_composeTransform(const double position[3],const double quat[4],const double scale[3],double matrix[16]);
float fm_computeArea(const float p1[3],const float p2[3],const float p3[3]);
double fm_computeArea(const double p1[3],const double p2[3],const double p3[3]);
void fm_lerp(const float p1[3],const float p2[3],float dest[3],float lerpValue);
void fm_lerp(const double p1[3],const double p2[3],double dest[3],double lerpValue);
bool fm_insideTriangleXZ(const float test[3],const float p1[3],const float p2[3],const float p3[3]);
bool fm_insideTriangleXZ(const double test[3],const double p1[3],const double p2[3],const double p3[3]);
bool fm_insideAABB(const float pos[3],const float bmin[3],const float bmax[3]);
bool fm_insideAABB(const double pos[3],const double bmin[3],const double bmax[3]);
bool fm_insideAABB(const float obmin[3],const float obmax[3],const float tbmin[3],const float tbmax[3]); // test if bounding box tbmin/tmbax is fully inside obmin/obmax
bool fm_insideAABB(const double obmin[3],const double obmax[3],const double tbmin[3],const double tbmax[3]); // test if bounding box tbmin/tmbax is fully inside obmin/obmax
uint32_t fm_clipTestPoint(const float bmin[3],const float bmax[3],const float pos[3]);
uint32_t fm_clipTestPoint(const double bmin[3],const double bmax[3],const double pos[3]);
uint32_t fm_clipTestPointXZ(const float bmin[3],const float bmax[3],const float pos[3]); // only tests X and Z, not Y
uint32_t fm_clipTestPointXZ(const double bmin[3],const double bmax[3],const double pos[3]); // only tests X and Z, not Y
uint32_t fm_clipTestAABB(const float bmin[3],const float bmax[3],const float p1[3],const float p2[3],const float p3[3],uint32_t &andCode);
uint32_t fm_clipTestAABB(const double bmin[3],const double bmax[3],const double p1[3],const double p2[3],const double p3[3],uint32_t &andCode);
bool fm_lineTestAABBXZ(const float p1[3],const float p2[3],const float bmin[3],const float bmax[3],float &time);
bool fm_lineTestAABBXZ(const double p1[3],const double p2[3],const double bmin[3],const double bmax[3],double &time);
bool fm_lineTestAABB(const float p1[3],const float p2[3],const float bmin[3],const float bmax[3],float &time);
bool fm_lineTestAABB(const double p1[3],const double p2[3],const double bmin[3],const double bmax[3],double &time);
void fm_initMinMax(const float p[3],float bmin[3],float bmax[3]);
void fm_initMinMax(const double p[3],double bmin[3],double bmax[3]);
void fm_initMinMax(float bmin[3],float bmax[3]);
void fm_initMinMax(double bmin[3],double bmax[3]);
void fm_minmax(const float p[3],float bmin[3],float bmax[3]); // accumulate to a min-max value
void fm_minmax(const double p[3],double bmin[3],double bmax[3]); // accumulate to a min-max value
// Computes the diagonal length of the bounding box and then inflates the bounding box on all sides
// by the ratio provided.
void fm_inflateMinMax(float bmin[3], float bmax[3], float ratio);
void fm_inflateMinMax(double bmin[3], double bmax[3], double ratio);
float fm_solveX(const float plane[4],float y,float z); // solve for X given this plane equation and the other two components.
double fm_solveX(const double plane[4],double y,double z); // solve for X given this plane equation and the other two components.
float fm_solveY(const float plane[4],float x,float z); // solve for Y given this plane equation and the other two components.
double fm_solveY(const double plane[4],double x,double z); // solve for Y given this plane equation and the other two components.
float fm_solveZ(const float plane[4],float x,float y); // solve for Z given this plane equation and the other two components.
double fm_solveZ(const double plane[4],double x,double y); // solve for Z given this plane equation and the other two components.
bool fm_computeBestFitPlane(uint32_t vcount, // number of input data points
const float *points, // starting address of points array.
uint32_t vstride, // stride between input points.
const float *weights, // *optional point weighting values.
uint32_t wstride, // weight stride for each vertex.
float plane[4], // Best fit plane equation
float center[3]); // Best fit weighted center of input points
bool fm_computeBestFitPlane(uint32_t vcount, // number of input data points
const double *points, // starting address of points array.
uint32_t vstride, // stride between input points.
const double *weights, // *optional point weighting values.
uint32_t wstride, // weight stride for each vertex.
double plane[4],
double center[3]);
// Computes the average center of a set of data points
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const float *points, // starting address of points array.
float *center);
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const double *points, // starting address of points array.
double *center);
// Compute centroid of a triangle mesh; takes area of each triangle into account
// weighted average
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const float *points, // starting address of points array.
uint32_t triangleCount,
const uint32_t *indices,
float *center);
// Compute centroid of a triangle mesh; takes area of each triangle into account
// weighted average
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const double *points, // starting address of points array.
uint32_t triangleCount,
const uint32_t *indices,
double *center);
float fm_computeBestFitAABB(uint32_t vcount,const float *points,uint32_t pstride,float bmin[3],float bmax[3]); // returns the diagonal distance
double fm_computeBestFitAABB(uint32_t vcount,const double *points,uint32_t pstride,double bmin[3],double bmax[3]); // returns the diagonal distance
float fm_computeBestFitSphere(uint32_t vcount,const float *points,uint32_t pstride,float center[3]);
double fm_computeBestFitSphere(uint32_t vcount,const double *points,uint32_t pstride,double center[3]);
bool fm_lineSphereIntersect(const float center[3],float radius,const float p1[3],const float p2[3],float intersect[3]);
bool fm_lineSphereIntersect(const double center[3],double radius,const double p1[3],const double p2[3],double intersect[3]);
bool fm_intersectRayAABB(const float bmin[3],const float bmax[3],const float pos[3],const float dir[3],float intersect[3]);
bool fm_intersectLineSegmentAABB(const float bmin[3],const float bmax[3],const float p1[3],const float p2[3],float intersect[3]);
bool fm_lineIntersectsTriangle(const float rayStart[3],const float rayEnd[3],const float p1[3],const float p2[3],const float p3[3],float sect[3]);
bool fm_lineIntersectsTriangle(const double rayStart[3],const double rayEnd[3],const double p1[3],const double p2[3],const double p3[3],double sect[3]);
bool fm_rayIntersectsTriangle(const float origin[3],const float dir[3],const float v0[3],const float v1[3],const float v2[3],float &t);
bool fm_rayIntersectsTriangle(const double origin[3],const double dir[3],const double v0[3],const double v1[3],const double v2[3],double &t);
bool fm_raySphereIntersect(const float center[3],float radius,const float pos[3],const float dir[3],float distance,float intersect[3]);
bool fm_raySphereIntersect(const double center[3],double radius,const double pos[3],const double dir[3],double distance,double intersect[3]);
void fm_catmullRom(float out_vector[3],const float p1[3],const float p2[3],const float p3[3],const float *p4, const float s);
void fm_catmullRom(double out_vector[3],const double p1[3],const double p2[3],const double p3[3],const double *p4, const double s);
bool fm_intersectAABB(const float bmin1[3],const float bmax1[3],const float bmin2[3],const float bmax2[3]);
bool fm_intersectAABB(const double bmin1[3],const double bmax1[3],const double bmin2[3],const double bmax2[3]);
// computes the rotation quaternion to go from unit-vector v0 to unit-vector v1
void fm_rotationArc(const float v0[3],const float v1[3],float quat[4]);
void fm_rotationArc(const double v0[3],const double v1[3],double quat[4]);
float fm_distancePointLineSegment(const float Point[3],const float LineStart[3],const float LineEnd[3],float intersection[3],LineSegmentType &type,float epsilon);
double fm_distancePointLineSegment(const double Point[3],const double LineStart[3],const double LineEnd[3],double intersection[3],LineSegmentType &type,double epsilon);
bool fm_colinear(const double p1[3],const double p2[3],const double p3[3],double epsilon=0.999); // true if these three points in a row are co-linear
bool fm_colinear(const float p1[3],const float p2[3],const float p3[3],float epsilon=0.999f);
bool fm_colinear(const float a1[3],const float a2[3],const float b1[3],const float b2[3],float epsilon=0.999f); // true if these two line segments are co-linear.
bool fm_colinear(const double a1[3],const double a2[3],const double b1[3],const double b2[3],double epsilon=0.999); // true if these two line segments are co-linear.
enum IntersectResult
{
IR_DONT_INTERSECT,
IR_DO_INTERSECT,
IR_COINCIDENT,
IR_PARALLEL,
};
IntersectResult fm_intersectLineSegments2d(const float a1[3], const float a2[3], const float b1[3], const float b2[3], float intersectionPoint[3]);
IntersectResult fm_intersectLineSegments2d(const double a1[3],const double a2[3],const double b1[3],const double b2[3],double intersectionPoint[3]);
IntersectResult fm_intersectLineSegments2dTime(const float a1[3], const float a2[3], const float b1[3], const float b2[3],float &t1,float &t2);
IntersectResult fm_intersectLineSegments2dTime(const double a1[3],const double a2[3],const double b1[3],const double b2[3],double &t1,double &t2);
// Plane-Triangle splitting
enum PlaneTriResult
{
PTR_ON_PLANE,
PTR_FRONT,
PTR_BACK,
PTR_SPLIT,
};
PlaneTriResult fm_planeTriIntersection(const float plane[4], // the plane equation in Ax+By+Cz+D format
const float *triangle, // the source triangle.
uint32_t tstride, // stride in bytes of the input and output *vertices*
float epsilon, // the co-planer epsilon value.
float *front, // the triangle in front of the
uint32_t &fcount, // number of vertices in the 'front' triangle
float *back, // the triangle in back of the plane
uint32_t &bcount); // the number of vertices in the 'back' triangle.
PlaneTriResult fm_planeTriIntersection(const double plane[4], // the plane equation in Ax+By+Cz+D format
const double *triangle, // the source triangle.
uint32_t tstride, // stride in bytes of the input and output *vertices*
double epsilon, // the co-planer epsilon value.
double *front, // the triangle in front of the
uint32_t &fcount, // number of vertices in the 'front' triangle
double *back, // the triangle in back of the plane
uint32_t &bcount); // the number of vertices in the 'back' triangle.
bool fm_intersectPointPlane(const float p1[3],const float p2[3],float *split,const float plane[4]);
bool fm_intersectPointPlane(const double p1[3],const double p2[3],double *split,const double plane[4]);
PlaneTriResult fm_getSidePlane(const float p[3],const float plane[4],float epsilon);
PlaneTriResult fm_getSidePlane(const double p[3],const double plane[4],double epsilon);
void fm_computeBestFitOBB(uint32_t vcount,const float *points,uint32_t pstride,float *sides,float matrix[16],bool bruteForce=true);
void fm_computeBestFitOBB(uint32_t vcount,const double *points,uint32_t pstride,double *sides,double matrix[16],bool bruteForce=true);
void fm_computeBestFitOBB(uint32_t vcount,const float *points,uint32_t pstride,float *sides,float pos[3],float quat[4],bool bruteForce=true);
void fm_computeBestFitOBB(uint32_t vcount,const double *points,uint32_t pstride,double *sides,double pos[3],double quat[4],bool bruteForce=true);
void fm_computeBestFitABB(uint32_t vcount,const float *points,uint32_t pstride,float *sides,float pos[3]);
void fm_computeBestFitABB(uint32_t vcount,const double *points,uint32_t pstride,double *sides,double pos[3]);
//** Note, if the returned capsule height is less than zero, then you must represent it is a sphere of size radius.
void fm_computeBestFitCapsule(uint32_t vcount,const float *points,uint32_t pstride,float &radius,float &height,float matrix[16],bool bruteForce=true);
void fm_computeBestFitCapsule(uint32_t vcount,const double *points,uint32_t pstride,float &radius,float &height,double matrix[16],bool bruteForce=true);
void fm_planeToMatrix(const float plane[4],float matrix[16]); // convert a plane equation to a 4x4 rotation matrix. Reference vector is 0,1,0
void fm_planeToQuat(const float plane[4],float quat[4],float pos[3]); // convert a plane equation to a quaternion and translation
void fm_planeToMatrix(const double plane[4],double matrix[16]); // convert a plane equation to a 4x4 rotation matrix
void fm_planeToQuat(const double plane[4],double quat[4],double pos[3]); // convert a plane equation to a quaternion and translation
inline void fm_doubleToFloat3(const double p[3],float t[3]) { t[0] = (float) p[0]; t[1] = (float)p[1]; t[2] = (float)p[2]; };
inline void fm_floatToDouble3(const float p[3],double t[3]) { t[0] = (double)p[0]; t[1] = (double)p[1]; t[2] = (double)p[2]; };
void fm_eulerMatrix(float ax,float ay,float az,float matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_eulerMatrix(double ax,double ay,double az,double matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
float fm_computeMeshVolume(const float *vertices,uint32_t tcount,const uint32_t *indices);
double fm_computeMeshVolume(const double *vertices,uint32_t tcount,const uint32_t *indices);
#define FM_DEFAULT_GRANULARITY 0.001f // 1 millimeter is the default granularity
class fm_VertexIndex
{
public:
virtual uint32_t getIndex(const float pos[3],bool &newPos) = 0; // get welded index for this float vector[3]
virtual uint32_t getIndex(const double pos[3],bool &newPos) = 0; // get welded index for this double vector[3]
virtual const float * getVerticesFloat(void) const = 0;
virtual const double * getVerticesDouble(void) const = 0;
virtual const float * getVertexFloat(uint32_t index) const = 0;
virtual const double * getVertexDouble(uint32_t index) const = 0;
virtual uint32_t getVcount(void) const = 0;
virtual bool isDouble(void) const = 0;
virtual bool saveAsObj(const char *fname,uint32_t tcount,uint32_t *indices) = 0;
};
fm_VertexIndex * fm_createVertexIndex(double granularity,bool snapToGrid); // create an indexed vertex system for doubles
fm_VertexIndex * fm_createVertexIndex(float granularity,bool snapToGrid); // create an indexed vertex system for floats
void fm_releaseVertexIndex(fm_VertexIndex *vindex);
class fm_Triangulate
{
public:
virtual const double * triangulate3d(uint32_t pcount,
const double *points,
uint32_t vstride,
uint32_t &tcount,
bool consolidate,
double epsilon) = 0;
virtual const float * triangulate3d(uint32_t pcount,
const float *points,
uint32_t vstride,
uint32_t &tcount,
bool consolidate,
float epsilon) = 0;
};
fm_Triangulate * fm_createTriangulate(void);
void fm_releaseTriangulate(fm_Triangulate *t);
const float * fm_getPoint(const float *points,uint32_t pstride,uint32_t index);
const double * fm_getPoint(const double *points,uint32_t pstride,uint32_t index);
bool fm_insideTriangle(float Ax, float Ay,float Bx, float By,float Cx, float Cy,float Px, float Py);
bool fm_insideTriangle(double Ax, double Ay,double Bx, double By,double Cx, double Cy,double Px, double Py);
float fm_areaPolygon2d(uint32_t pcount,const float *points,uint32_t pstride);
double fm_areaPolygon2d(uint32_t pcount,const double *points,uint32_t pstride);
bool fm_pointInsidePolygon2d(uint32_t pcount,const float *points,uint32_t pstride,const float *point,uint32_t xindex=0,uint32_t yindex=1);
bool fm_pointInsidePolygon2d(uint32_t pcount,const double *points,uint32_t pstride,const double *point,uint32_t xindex=0,uint32_t yindex=1);
uint32_t fm_consolidatePolygon(uint32_t pcount,const float *points,uint32_t pstride,float *dest,float epsilon=0.999999f); // collapses co-linear edges.
uint32_t fm_consolidatePolygon(uint32_t pcount,const double *points,uint32_t pstride,double *dest,double epsilon=0.999999); // collapses co-linear edges.
bool fm_computeSplitPlane(uint32_t vcount,const double *vertices,uint32_t tcount,const uint32_t *indices,double *plane);
bool fm_computeSplitPlane(uint32_t vcount,const float *vertices,uint32_t tcount,const uint32_t *indices,float *plane);
void fm_nearestPointInTriangle(const float *pos,const float *p1,const float *p2,const float *p3,float *nearest);
void fm_nearestPointInTriangle(const double *pos,const double *p1,const double *p2,const double *p3,double *nearest);
float fm_areaTriangle(const float *p1,const float *p2,const float *p3);
double fm_areaTriangle(const double *p1,const double *p2,const double *p3);
void fm_subtract(const float *A,const float *B,float *diff); // compute A-B and store the result in 'diff'
void fm_subtract(const double *A,const double *B,double *diff); // compute A-B and store the result in 'diff'
void fm_multiply(float *A,float scalar);
void fm_multiply(double *A,double scalar);
void fm_add(const float *A,const float *B,float *sum);
void fm_add(const double *A,const double *B,double *sum);
void fm_copy3(const float *source,float *dest);
void fm_copy3(const double *source,double *dest);
// re-indexes an indexed triangle mesh but drops unused vertices. The output_indices can be the same pointer as the input indices.
// the output_vertices can point to the input vertices if you desire. The output_vertices buffer should be at least the same size
// is the input buffer. The routine returns the new vertex count after re-indexing.
uint32_t fm_copyUniqueVertices(uint32_t vcount,const float *input_vertices,float *output_vertices,uint32_t tcount,const uint32_t *input_indices,uint32_t *output_indices);
uint32_t fm_copyUniqueVertices(uint32_t vcount,const double *input_vertices,double *output_vertices,uint32_t tcount,const uint32_t *input_indices,uint32_t *output_indices);
bool fm_isMeshCoplanar(uint32_t tcount,const uint32_t *indices,const float *vertices,bool doubleSided); // returns true if this collection of indexed triangles are co-planar!
bool fm_isMeshCoplanar(uint32_t tcount,const uint32_t *indices,const double *vertices,bool doubleSided); // returns true if this collection of indexed triangles are co-planar!
bool fm_samePlane(const float p1[4],const float p2[4],float normalEpsilon=0.01f,float dEpsilon=0.001f,bool doubleSided=false); // returns true if these two plane equations are identical within an epsilon
bool fm_samePlane(const double p1[4],const double p2[4],double normalEpsilon=0.01,double dEpsilon=0.001,bool doubleSided=false);
void fm_OBBtoAABB(const float obmin[3],const float obmax[3],const float matrix[16],float abmin[3],float abmax[3]);
// a utility class that will tessellate a mesh.
class fm_Tesselate
{
public:
virtual const uint32_t * tesselate(fm_VertexIndex *vindex,uint32_t tcount,const uint32_t *indices,float longEdge,uint32_t maxDepth,uint32_t &outcount) = 0;
};
fm_Tesselate * fm_createTesselate(void);
void fm_releaseTesselate(fm_Tesselate *t);
void fm_computeMeanNormals(uint32_t vcount, // the number of vertices
const float *vertices, // the base address of the vertex position data.
uint32_t vstride, // the stride between position data.
float *normals, // the base address of the destination for mean vector normals
uint32_t nstride, // the stride between normals
uint32_t tcount, // the number of triangles
const uint32_t *indices); // the triangle indices
void fm_computeMeanNormals(uint32_t vcount, // the number of vertices
const double *vertices, // the base address of the vertex position data.
uint32_t vstride, // the stride between position data.
double *normals, // the base address of the destination for mean vector normals
uint32_t nstride, // the stride between normals
uint32_t tcount, // the number of triangles
const uint32_t *indices); // the triangle indices
bool fm_isValidTriangle(const float *p1,const float *p2,const float *p3,float epsilon=0.00001f);
bool fm_isValidTriangle(const double *p1,const double *p2,const double *p3,double epsilon=0.00001f);
}; // end of namespace
#endif

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@
#define ENABLE_VHACD_IMPLEMENTATION 1
#define VHACD_DISABLE_THREADING 0
#include <VHACD.H>
#include <FloatMath.h>
//-----------------------------------------------------------------------------
@ -102,18 +103,18 @@ public:
void fitBox( U32 vertCount, const F32* verts )
{
//FLOAT_MATH::fm_computeBestFitOBB( vertCount, verts, sizeof(F32)*3, (F32*)mBoxSides, (F32*)mBoxTransform, false );
FLOAT_MATH::fm_computeBestFitOBB( vertCount, verts, sizeof(F32)*3, (F32*)mBoxSides, (F32*)mBoxTransform, false );
mBoxTransform.transpose();
}
void fitSphere( U32 vertCount, const F32* verts )
{
//mSphereRadius = FLOAT_MATH::fm_computeBestFitSphere( vertCount, verts, sizeof(F32)*3, (F32*)mSphereCenter );
mSphereRadius = FLOAT_MATH::fm_computeBestFitSphere( vertCount, verts, sizeof(F32)*3, (F32*)mSphereCenter );
}
void fitCapsule( U32 vertCount, const F32* verts )
{
//FLOAT_MATH::fm_computeBestFitCapsule( vertCount, verts, sizeof(F32)*3, mCapRadius, mCapHeight, (F32*)mCapTransform );
FLOAT_MATH::fm_computeBestFitCapsule( vertCount, verts, sizeof(F32)*3, mCapRadius, mCapHeight, (F32*)mCapTransform );
mCapTransform.transpose();
}
};
@ -696,23 +697,39 @@ void MeshFit::fitConvexHulls( U32 depth, F32 mergeThreshold, F32 concavityThresh
if (( boxMaxError > 0 ) || ( sphereMaxError > 0 ) || ( capsuleMaxError > 0 ))
{
// Compute error between actual mesh and fitted primitives
F32 meshVolume = 10.0f; // FLOAT_MATH::fm_computeMeshVolume((F32*)&ch.m_points, ch.m_triangles.size(), (U32*)&ch.m_triangles);
F32* points = new F32[ch.m_points.size() * 3];
for (U32 i = 0; i < ch.m_points.size(); i++)
{
points[i * 3 + 0] = ch.m_points[i].mX;
points[i * 3 + 1] = ch.m_points[i].mY;
points[i * 3 + 2] = ch.m_points[i].mZ;
}
U32* indices = new U32[ch.m_triangles.size() * 3];
for (U32 i = 0; i < ch.m_triangles.size(); i++)
{
indices[i * 3 + 0] = ch.m_triangles[i].mI0;
indices[i * 3 + 1] = ch.m_triangles[i].mI1;
indices[i * 3 + 2] = ch.m_triangles[i].mI2;
}
F32 meshVolume = FLOAT_MATH::fm_computeMeshVolume(points, ch.m_triangles.size(), indices);
PrimFit primFitter;
F32 boxError = 100.0f, sphereError = 100.0f, capsuleError = 100.0f;
if ( boxMaxError > 0 )
{
primFitter.fitBox(ch.m_points.size(), (F32*)&ch.m_points);
primFitter.fitBox(ch.m_points.size(), points);
boxError = 100.0f * ( 1.0f - ( meshVolume / primFitter.getBoxVolume() ) );
}
if ( sphereMaxError > 0 )
{
primFitter.fitSphere(ch.m_points.size(), (F32*)&ch.m_points);
primFitter.fitSphere(ch.m_points.size(), points);
sphereError = 100.0f * ( 1.0f - ( meshVolume / primFitter.getSphereVolume() ) );
}
if ( capsuleMaxError > 0 )
{
primFitter.fitCapsule(ch.m_points.size(), (F32*)&ch.m_points);
primFitter.fitCapsule(ch.m_points.size(), points);
capsuleError = 100.0f * ( 1.0f - ( meshVolume / primFitter.getCapsuleVolume() ) );
}

View file

@ -15,7 +15,7 @@ set(TORQUE_COMPILE_DEFINITIONS ICE_NO_DLL PCRE_STATIC TORQUE_ADVANCED_LIGHTING T
# All link libraries. Modules should append to this the path to specify additional link libraries (.a, .lib, .dylib, .so)
set(TORQUE_LINK_LIBRARIES tinyxml collada squish opcode assimp FLAC FLAC++ ogg vorbis
vorbisfile vorbisenc opus sndfile SDL2 glad pcre zlib)
vorbisfile vorbisenc opus sndfile SDL2 glad pcre convexMath zlib)
if(TORQUE_TESTING)
set(TORQUE_LINK_LIBRARIES ${TORQUE_LINK_LIBRARIES} gtest gmock)