mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
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:
parent
eb33fe04af
commit
109d8c06e9
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
3
Engine/lib/convexMath/CMakeLists.txt
Normal file
3
Engine/lib/convexMath/CMakeLists.txt
Normal 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})
|
||||
17
Engine/lib/convexMath/FloatMath.cpp
Normal file
17
Engine/lib/convexMath/FloatMath.cpp
Normal 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"
|
||||
525
Engine/lib/convexMath/FloatMath.h
Normal file
525
Engine/lib/convexMath/FloatMath.h
Normal 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
|
||||
5280
Engine/lib/convexMath/FloatMath.inl
Normal file
5280
Engine/lib/convexMath/FloatMath.inl
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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() ) );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue