diff --git a/Engine/lib/CMakeLists.txt b/Engine/lib/CMakeLists.txt index f101dba06..1784b3685 100644 --- a/Engine/lib/CMakeLists.txt +++ b/Engine/lib/CMakeLists.txt @@ -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) diff --git a/Engine/lib/convexDecomp/CMakeLists.txt b/Engine/lib/convexDecomp/CMakeLists.txt deleted file mode 100644 index 0a58bb89f..000000000 --- a/Engine/lib/convexDecomp/CMakeLists.txt +++ /dev/null @@ -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) \ No newline at end of file diff --git a/Engine/lib/convexDecomp/NvConcavityVolume.cpp b/Engine/lib/convexDecomp/NvConcavityVolume.cpp deleted file mode 100644 index 4cda8811f..000000000 --- a/Engine/lib/convexDecomp/NvConcavityVolume.cpp +++ /dev/null @@ -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 - -#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; isetCurrentColor(0x0000FF,0xFFFFFF); - NVSHARE::gRenderDebug->addToCurrentState(NVSHARE::DebugRenderState::SolidWireShaded); - - for (NxU32 i=0; iDebugTri(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 diff --git a/Engine/lib/convexDecomp/NvConcavityVolume.h b/Engine/lib/convexDecomp/NvConcavityVolume.h deleted file mode 100644 index 18bbed073..000000000 --- a/Engine/lib/convexDecomp/NvConcavityVolume.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/NvConvexDecomposition.cpp b/Engine/lib/convexDecomp/NvConvexDecomposition.cpp deleted file mode 100644 index 386ac497c..000000000 --- a/Engine/lib/convexDecomp/NvConvexDecomposition.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -#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; imVertices; - for (NxU32 i=0; imVcount; 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; imVertices; - for (NxU32 i=0; imVcount; 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; ibeenTested() ) - { - 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; igetIsland(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; imTcount ) - { - hullCount++; - } - } - return hullCount; - } - - virtual bool getConvexHullResult(NxU32 hullIndex,ConvexHullResult &result) - { - bool ret = false; - - wait(); - NxU32 index = 0; - for (NxU32 i=0; imTcount ) - { - 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; ibeenTested() && 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 diff --git a/Engine/lib/convexDecomp/NvConvexDecomposition.h b/Engine/lib/convexDecomp/NvConvexDecomposition.h deleted file mode 100644 index bf5ded4b1..000000000 --- a/Engine/lib/convexDecomp/NvConvexDecomposition.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/NvFloatMath.cpp b/Engine/lib/convexDecomp/NvFloatMath.cpp deleted file mode 100644 index 91979b1ca..000000000 --- a/Engine/lib/convexDecomp/NvFloatMath.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include - -#include "NvFloatMath.h" - -#define REAL NxF32 - -#include "NvFloatMath.inl" - -#undef REAL -#define REAL NxF64 - -#include "NvFloatMath.inl" diff --git a/Engine/lib/convexDecomp/NvFloatMath.h b/Engine/lib/convexDecomp/NvFloatMath.h deleted file mode 100644 index 3b4a885e6..000000000 --- a/Engine/lib/convexDecomp/NvFloatMath.h +++ /dev/null @@ -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 - -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 diff --git a/Engine/lib/convexDecomp/NvFloatMath.inl b/Engine/lib/convexDecomp/NvFloatMath.inl deleted file mode 100644 index b8731013a..000000000 --- a/Engine/lib/convexDecomp/NvFloatMath.inl +++ /dev/null @@ -1,5607 +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. - -*/ -#pragma warning(disable:4996) - -#include "NvUserMemAlloc.h" -#include "NvHashMap.h" - -namespace CONVEX_DECOMPOSITION -{ - -void fm_inverseRT(const REAL matrix[16],const REAL pos[3],REAL t[3]) // inverse rotate translate the point. -{ - - REAL _x = pos[0] - matrix[3*4+0]; - REAL _y = pos[1] - matrix[3*4+1]; - REAL _z = pos[2] - matrix[3*4+2]; - - // Multiply inverse-translated source vector by inverted rotation transform - - t[0] = (matrix[0*4+0] * _x) + (matrix[0*4+1] * _y) + (matrix[0*4+2] * _z); - t[1] = (matrix[1*4+0] * _x) + (matrix[1*4+1] * _y) + (matrix[1*4+2] * _z); - t[2] = (matrix[2*4+0] * _x) + (matrix[2*4+1] * _y) + (matrix[2*4+2] * _z); - -} - -REAL fm_getDeterminant(const REAL matrix[16]) -{ - REAL tempv[3]; - REAL p0[3]; - REAL p1[3]; - REAL p2[3]; - - - p0[0] = matrix[0*4+0]; - p0[1] = matrix[0*4+1]; - p0[2] = matrix[0*4+2]; - - p1[0] = matrix[1*4+0]; - p1[1] = matrix[1*4+1]; - p1[2] = matrix[1*4+2]; - - p2[0] = matrix[2*4+0]; - p2[1] = matrix[2*4+1]; - p2[2] = matrix[2*4+2]; - - fm_cross(tempv,p1,p2); - - return fm_dot(p0,tempv); - -} - -REAL fm_squared(REAL x) { return x*x; }; - -void fm_decomposeTransform(const REAL local_transform[16],REAL trans[3],REAL rot[4],REAL scale[3]) -{ - - trans[0] = local_transform[12]; - trans[1] = local_transform[13]; - trans[2] = local_transform[14]; - - scale[0] = sqrt(fm_squared(local_transform[0*4+0]) + fm_squared(local_transform[0*4+1]) + fm_squared(local_transform[0*4+2])); - scale[1] = sqrt(fm_squared(local_transform[1*4+0]) + fm_squared(local_transform[1*4+1]) + fm_squared(local_transform[1*4+2])); - scale[2] = sqrt(fm_squared(local_transform[2*4+0]) + fm_squared(local_transform[2*4+1]) + fm_squared(local_transform[2*4+2])); - - REAL m[16]; - memcpy(m,local_transform,sizeof(REAL)*16); - - REAL sx = 1.0f / scale[0]; - REAL sy = 1.0f / scale[1]; - REAL sz = 1.0f / scale[2]; - - m[0*4+0]*=sx; - m[0*4+1]*=sx; - m[0*4+2]*=sx; - - m[1*4+0]*=sy; - m[1*4+1]*=sy; - m[1*4+2]*=sy; - - m[2*4+0]*=sz; - m[2*4+1]*=sz; - m[2*4+2]*=sz; - - fm_matrixToQuat(m,rot); - -} - -void fm_getSubMatrix(NxI32 ki,NxI32 kj,REAL pDst[16],const REAL matrix[16]) -{ - NxI32 row, col; - NxI32 dstCol = 0, dstRow = 0; - - for ( col = 0; col < 4; col++ ) - { - if ( col == kj ) - { - continue; - } - for ( dstRow = 0, row = 0; row < 4; row++ ) - { - if ( row == ki ) - { - continue; - } - pDst[dstCol*4+dstRow] = matrix[col*4+row]; - dstRow++; - } - dstCol++; - } -} - -void fm_inverseTransform(const REAL matrix[16],REAL inverse_matrix[16]) -{ - REAL determinant = fm_getDeterminant(matrix); - determinant = 1.0f / determinant; - for (NxI32 i = 0; i < 4; i++ ) - { - for (NxI32 j = 0; j < 4; j++ ) - { - NxI32 sign = 1 - ( ( i + j ) % 2 ) * 2; - REAL subMat[16]; - fm_identity(subMat); - fm_getSubMatrix( i, j, subMat, matrix ); - REAL subDeterminant = fm_getDeterminant(subMat); - inverse_matrix[i*4+j] = ( subDeterminant * sign ) * determinant; - } - } -} - -void fm_identity(REAL matrix[16]) // set 4x4 matrix to identity. -{ - matrix[0*4+0] = 1; - matrix[1*4+1] = 1; - matrix[2*4+2] = 1; - matrix[3*4+3] = 1; - - matrix[1*4+0] = 0; - matrix[2*4+0] = 0; - matrix[3*4+0] = 0; - - matrix[0*4+1] = 0; - matrix[2*4+1] = 0; - matrix[3*4+1] = 0; - - matrix[0*4+2] = 0; - matrix[1*4+2] = 0; - matrix[3*4+2] = 0; - - matrix[0*4+3] = 0; - matrix[1*4+3] = 0; - matrix[2*4+3] = 0; - -} - -void fm_quatToEuler(const REAL quat[4],REAL &ax,REAL &ay,REAL &az) -{ - REAL x = quat[0]; - REAL y = quat[1]; - REAL z = quat[2]; - REAL w = quat[3]; - - REAL sint = (2.0f * w * y) - (2.0f * x * z); - REAL cost_temp = 1.0f - (sint * sint); - REAL cost = 0; - - if ( (REAL)fabs(cost_temp) > 0.001f ) - { - cost = sqrt( cost_temp ); - } - - REAL sinv, cosv, sinf, cosf; - if ( (REAL)fabs(cost) > 0.001f ) - { - cost = 1.0f / cost; - sinv = ((2.0f * y * z) + (2.0f * w * x)) * cost; - cosv = (1.0f - (2.0f * x * x) - (2.0f * y * y)) * cost; - sinf = ((2.0f * x * y) + (2.0f * w * z)) * cost; - cosf = (1.0f - (2.0f * y * y) - (2.0f * z * z)) * cost; - } - else - { - sinv = (2.0f * w * x) - (2.0f * y * z); - cosv = 1.0f - (2.0f * x * x) - (2.0f * z * z); - sinf = 0; - cosf = 1.0f; - } - - // compute output rotations - ax = atan2( sinv, cosv ); - ay = atan2( sint, cost ); - az = atan2( sinf, cosf ); - -} - -void fm_eulerToMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) -{ - REAL quat[4]; - fm_eulerToQuat(ax,ay,az,quat); - fm_quatToMatrix(quat,matrix); -} - -void fm_getAABB(NxU32 vcount,const REAL *points,NxU32 pstride,REAL *bmin,REAL *bmax) -{ - - const NxU8 *source = (const NxU8 *) points; - - bmin[0] = points[0]; - bmin[1] = points[1]; - bmin[2] = points[2]; - - bmax[0] = points[0]; - bmax[1] = points[1]; - bmax[2] = points[2]; - - - for (NxU32 i=1; i bmax[0] ) bmax[0] = p[0]; - if ( p[1] > bmax[1] ) bmax[1] = p[1]; - if ( p[2] > bmax[2] ) bmax[2] = p[2]; - - } -} - -void fm_eulerToQuat(const REAL *euler,REAL *quat) // convert euler angles to quaternion. -{ - fm_eulerToQuat(euler[0],euler[1],euler[2],quat); -} - -void fm_eulerToQuat(REAL roll,REAL pitch,REAL yaw,REAL *quat) // convert euler angles to quaternion. -{ - roll *= 0.5f; - pitch *= 0.5f; - yaw *= 0.5f; - - REAL cr = cos(roll); - REAL cp = cos(pitch); - REAL cy = cos(yaw); - - REAL sr = sin(roll); - REAL sp = sin(pitch); - REAL sy = sin(yaw); - - REAL cpcy = cp * cy; - REAL spsy = sp * sy; - REAL spcy = sp * cy; - REAL cpsy = cp * sy; - - quat[0] = ( sr * cpcy - cr * spsy); - quat[1] = ( cr * spcy + sr * cpsy); - quat[2] = ( cr * cpsy - sr * spcy); - quat[3] = cr * cpcy + sr * spsy; -} - -void fm_quatToMatrix(const REAL *quat,REAL *matrix) // convert quaterinion rotation to matrix, zeros out the translation component. -{ - - REAL xx = quat[0]*quat[0]; - REAL yy = quat[1]*quat[1]; - REAL zz = quat[2]*quat[2]; - REAL xy = quat[0]*quat[1]; - REAL xz = quat[0]*quat[2]; - REAL yz = quat[1]*quat[2]; - REAL wx = quat[3]*quat[0]; - REAL wy = quat[3]*quat[1]; - REAL wz = quat[3]*quat[2]; - - matrix[0*4+0] = 1 - 2 * ( yy + zz ); - matrix[1*4+0] = 2 * ( xy - wz ); - matrix[2*4+0] = 2 * ( xz + wy ); - - matrix[0*4+1] = 2 * ( xy + wz ); - matrix[1*4+1] = 1 - 2 * ( xx + zz ); - matrix[2*4+1] = 2 * ( yz - wx ); - - matrix[0*4+2] = 2 * ( xz - wy ); - matrix[1*4+2] = 2 * ( yz + wx ); - matrix[2*4+2] = 1 - 2 * ( xx + yy ); - - matrix[3*4+0] = matrix[3*4+1] = matrix[3*4+2] = (REAL) 0.0f; - matrix[0*4+3] = matrix[1*4+3] = matrix[2*4+3] = (REAL) 0.0f; - matrix[3*4+3] =(REAL) 1.0f; - -} - - -void fm_quatRotate(const REAL *quat,const REAL *v,REAL *r) // rotate a vector directly by a quaternion. -{ - REAL left[4]; - - left[0] = quat[3]*v[0] + quat[1]*v[2] - v[1]*quat[2]; - left[1] = quat[3]*v[1] + quat[2]*v[0] - v[2]*quat[0]; - left[2] = quat[3]*v[2] + quat[0]*v[1] - v[0]*quat[1]; - left[3] = - quat[0]*v[0] - quat[1]*v[1] - quat[2]*v[2]; - - r[0] = (left[3]*-quat[0]) + (quat[3]*left[0]) + (left[1]*-quat[2]) - (-quat[1]*left[2]); - r[1] = (left[3]*-quat[1]) + (quat[3]*left[1]) + (left[2]*-quat[0]) - (-quat[2]*left[0]); - r[2] = (left[3]*-quat[2]) + (quat[3]*left[2]) + (left[0]*-quat[1]) - (-quat[0]*left[1]); - -} - - -void fm_getTranslation(const REAL *matrix,REAL *t) -{ - t[0] = matrix[3*4+0]; - t[1] = matrix[3*4+1]; - t[2] = matrix[3*4+2]; -} - -void fm_matrixToQuat(const REAL *matrix,REAL *quat) // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w -{ - - REAL tr = matrix[0*4+0] + matrix[1*4+1] + matrix[2*4+2]; - - // check the diagonal - - if (tr > 0.0f ) - { - REAL s = (REAL) sqrt ( (NxF64) (tr + 1.0f) ); - quat[3] = s * 0.5f; - s = 0.5f / s; - quat[0] = (matrix[1*4+2] - matrix[2*4+1]) * s; - quat[1] = (matrix[2*4+0] - matrix[0*4+2]) * s; - quat[2] = (matrix[0*4+1] - matrix[1*4+0]) * s; - - } - else - { - // diagonal is negative - NxI32 nxt[3] = {1, 2, 0}; - REAL qa[4]; - - NxI32 i = 0; - - if (matrix[1*4+1] > matrix[0*4+0]) i = 1; - if (matrix[2*4+2] > matrix[i*4+i]) i = 2; - - NxI32 j = nxt[i]; - NxI32 k = nxt[j]; - - REAL s = sqrt ( ((matrix[i*4+i] - (matrix[j*4+j] + matrix[k*4+k])) + 1.0f) ); - - qa[i] = s * 0.5f; - - if (s != 0.0f ) s = 0.5f / s; - - qa[3] = (matrix[j*4+k] - matrix[k*4+j]) * s; - qa[j] = (matrix[i*4+j] + matrix[j*4+i]) * s; - qa[k] = (matrix[i*4+k] + matrix[k*4+i]) * s; - - quat[0] = qa[0]; - quat[1] = qa[1]; - quat[2] = qa[2]; - quat[3] = qa[3]; - } - - -} - - -REAL fm_sphereVolume(REAL radius) // return's the volume of a sphere of this radius (4/3 PI * R cubed ) -{ - return (4.0f / 3.0f ) * FM_PI * radius * radius * radius; -} - - -REAL fm_cylinderVolume(REAL radius,REAL h) -{ - return FM_PI * radius * radius *h; -} - -REAL fm_capsuleVolume(REAL radius,REAL h) -{ - REAL volume = fm_sphereVolume(radius); // volume of the sphere portion. - REAL ch = h-radius*2; // this is the cylinder length - if ( ch > 0 ) - { - volume+=fm_cylinderVolume(radius,ch); - } - return volume; -} - -void fm_transform(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point -{ - if ( matrix ) - { - REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]) + matrix[3*4+0]; - REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]) + matrix[3*4+1]; - REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]) + matrix[3*4+2]; - t[0] = tx; - t[1] = ty; - t[2] = tz; - } - else - { - t[0] = v[0]; - t[1] = v[1]; - t[2] = v[2]; - } -} - -void fm_rotate(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point -{ - if ( matrix ) - { - REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]); - REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]); - REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]); - t[0] = tx; - t[1] = ty; - t[2] = tz; - } - else - { - t[0] = v[0]; - t[1] = v[1]; - t[2] = v[2]; - } -} - - -REAL fm_distance(const REAL *p1,const REAL *p2) -{ - REAL dx = p1[0] - p2[0]; - REAL dy = p1[1] - p2[1]; - REAL dz = p1[2] - p2[2]; - - return sqrt( dx*dx + dy*dy + dz *dz ); -} - -REAL fm_distanceSquared(const REAL *p1,const REAL *p2) -{ - REAL dx = p1[0] - p2[0]; - REAL dy = p1[1] - p2[1]; - REAL dz = p1[2] - p2[2]; - - return dx*dx + dy*dy + dz *dz; -} - - -REAL fm_distanceSquaredXZ(const REAL *p1,const REAL *p2) -{ - REAL dx = p1[0] - p2[0]; - REAL dz = p1[2] - p2[2]; - - return dx*dx + dz *dz; -} - - -REAL fm_computePlane(const REAL *A,const REAL *B,const REAL *C,REAL *n) // returns D -{ - REAL vx = (B[0] - C[0]); - REAL vy = (B[1] - C[1]); - REAL vz = (B[2] - C[2]); - - REAL wx = (A[0] - B[0]); - REAL wy = (A[1] - B[1]); - REAL wz = (A[2] - B[2]); - - REAL vw_x = vy * wz - vz * wy; - REAL vw_y = vz * wx - vx * wz; - REAL vw_z = vx * wy - vy * wx; - - REAL mag = sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); - - if ( mag < 0.000001f ) - { - mag = 0; - } - else - { - mag = 1.0f/mag; - } - - REAL x = vw_x * mag; - REAL y = vw_y * mag; - REAL z = vw_z * mag; - - - REAL D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2])); - - n[0] = x; - n[1] = y; - n[2] = z; - - return D; -} - -REAL fm_distToPlane(const REAL *plane,const REAL *p) // computes the distance of this point from the plane. -{ - return p[0]*plane[0]+p[1]*plane[1]+p[2]*plane[2]+plane[3]; -} - -REAL fm_dot(const REAL *p1,const REAL *p2) -{ - return p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]; -} - -void fm_cross(REAL *cross,const REAL *a,const REAL *b) -{ - cross[0] = a[1]*b[2] - a[2]*b[1]; - cross[1] = a[2]*b[0] - a[0]*b[2]; - cross[2] = a[0]*b[1] - a[1]*b[0]; -} - -void fm_computeNormalVector(REAL *n,const REAL *p1,const REAL *p2) -{ - n[0] = p2[0] - p1[0]; - n[1] = p2[1] - p1[1]; - n[2] = p2[2] - p1[2]; - fm_normalize(n); -} - -bool fm_computeWindingOrder(const REAL *p1,const REAL *p2,const REAL *p3) // returns true if the triangle is clockwise. -{ - bool ret = false; - - REAL v1[3]; - REAL v2[3]; - - fm_computeNormalVector(v1,p1,p2); // p2-p1 (as vector) and then normalized - fm_computeNormalVector(v2,p1,p3); // p3-p1 (as vector) and then normalized - - REAL cross[3]; - - fm_cross(cross, v1, v2 ); - REAL ref[3] = { 1, 0, 0 }; - - REAL d = fm_dot( cross, ref ); - - - if ( d <= 0 ) - ret = false; - else - ret = true; - - return ret; -} - -REAL fm_normalize(REAL *n) // normalize this vector -{ - REAL dist = (REAL)sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); - if ( dist > 0.0000001f ) - { - REAL mag = 1.0f / dist; - n[0]*=mag; - n[1]*=mag; - n[2]*=mag; - } - else - { - n[0] = 1; - n[1] = 0; - n[2] = 0; - } - - return dist; -} - - -void fm_matrixMultiply(const REAL *pA,const REAL *pB,REAL *pM) -{ -#if 1 - - REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; - REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; - REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; - REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; - - REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; - REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; - REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; - REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; - - REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; - REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; - REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; - REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; - - REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; - REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; - REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; - REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; - - pM[0] = a; - pM[1] = b; - pM[2] = c; - pM[3] = d; - - pM[4] = e; - pM[5] = f; - pM[6] = g; - pM[7] = h; - - pM[8] = i; - pM[9] = j; - pM[10] = k; - pM[11] = l; - - pM[12] = m; - pM[13] = n; - pM[14] = o; - pM[15] = p; - - -#else - memset(pM, 0, sizeof(REAL)*16); - for(NxI32 i=0; i<4; i++ ) - for(NxI32 j=0; j<4; j++ ) - for(NxI32 k=0; k<4; k++ ) - pM[4*i+j] += pA[4*i+k] * pB[4*k+j]; -#endif -} - - -void fm_eulerToQuatDX(REAL x,REAL y,REAL z,REAL *quat) // convert euler angles to quaternion using the fucked up DirectX method -{ - REAL matrix[16]; - fm_eulerToMatrix(x,y,z,matrix); - fm_matrixToQuat(matrix,quat); -} - -// implementation copied from: http://blogs.msdn.com/mikepelton/archive/2004/10/29/249501.aspx -void fm_eulerToMatrixDX(REAL x,REAL y,REAL z,REAL *matrix) // convert euler angles to quaternion using the fucked up DirectX method. -{ - fm_identity(matrix); - matrix[0*4+0] = cos(z)*cos(y) + sin(z)*sin(x)*sin(y); - matrix[0*4+1] = sin(z)*cos(x); - matrix[0*4+2] = cos(z)*-sin(y) + sin(z)*sin(x)*cos(y); - - matrix[1*4+0] = -sin(z)*cos(y)+cos(z)*sin(x)*sin(y); - matrix[1*4+1] = cos(z)*cos(x); - matrix[1*4+2] = sin(z)*sin(y) +cos(z)*sin(x)*cos(y); - - matrix[2*4+0] = cos(x)*sin(y); - matrix[2*4+1] = -sin(x); - matrix[2*4+2] = cos(x)*cos(y); -} - - -void fm_scale(REAL x,REAL y,REAL z,REAL *fscale) // apply scale to the matrix. -{ - fscale[0*4+0] = x; - fscale[1*4+1] = y; - fscale[2*4+2] = z; -} - - -void fm_composeTransform(const REAL *position,const REAL *quat,const REAL *scale,REAL *matrix) -{ - fm_identity(matrix); - fm_quatToMatrix(quat,matrix); - - if ( scale && ( scale[0] != 1 || scale[1] != 1 || scale[2] != 1 ) ) - { - REAL work[16]; - memcpy(work,matrix,sizeof(REAL)*16); - REAL mscale[16]; - fm_identity(mscale); - fm_scale(scale[0],scale[1],scale[2],mscale); - fm_matrixMultiply(work,mscale,matrix); - } - - matrix[12] = position[0]; - matrix[13] = position[1]; - matrix[14] = position[2]; -} - - -void fm_setTranslation(const REAL *translation,REAL *matrix) -{ - matrix[12] = translation[0]; - matrix[13] = translation[1]; - matrix[14] = translation[2]; -} - -static REAL enorm0_3d ( REAL x0, REAL y0, REAL z0, REAL x1, REAL y1, REAL z1 ) - -/**********************************************************************/ - -/* -Purpose: - -ENORM0_3D computes the Euclidean norm of (P1-P0) in 3D. - -Modified: - -18 April 1999 - -Author: - -John Burkardt - -Parameters: - -Input, REAL X0, Y0, Z0, X1, Y1, Z1, the coordinates of the points -P0 and P1. - -Output, REAL ENORM0_3D, the Euclidean norm of (P1-P0). -*/ -{ - REAL value; - - value = sqrt ( - ( x1 - x0 ) * ( x1 - x0 ) + - ( y1 - y0 ) * ( y1 - y0 ) + - ( z1 - z0 ) * ( z1 - z0 ) ); - - return value; -} - - -static REAL triangle_area_3d ( REAL x1, REAL y1, REAL z1, REAL x2,REAL y2, REAL z2, REAL x3, REAL y3, REAL z3 ) - - /**********************************************************************/ - - /* - Purpose: - - TRIANGLE_AREA_3D computes the area of a triangle in 3D. - - Modified: - - 22 April 1999 - - Author: - - John Burkardt - - Parameters: - - Input, REAL X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, the (X,Y,Z) - coordinates of the corners of the triangle. - - Output, REAL TRIANGLE_AREA_3D, the area of the triangle. - */ -{ - REAL a; - REAL alpha; - REAL area; - REAL b; - REAL base; - REAL c; - REAL dot; - REAL height; - /* - Find the projection of (P3-P1) onto (P2-P1). - */ - dot = - ( x2 - x1 ) * ( x3 - x1 ) + - ( y2 - y1 ) * ( y3 - y1 ) + - ( z2 - z1 ) * ( z3 - z1 ); - - base = enorm0_3d ( x1, y1, z1, x2, y2, z2 ); - /* - The height of the triangle is the length of (P3-P1) after its - projection onto (P2-P1) has been subtracted. - */ - if ( base == 0.0 ) { - - height = 0.0; - - } - else { - - alpha = dot / ( base * base ); - - a = x3 - x1 - alpha * ( x2 - x1 ); - b = y3 - y1 - alpha * ( y2 - y1 ); - c = z3 - z1 - alpha * ( z2 - z1 ); - - height = sqrt ( a * a + b * b + c * c ); - - } - - area = 0.5f * base * height; - - return area; -} - - -REAL fm_computeArea(const REAL *p1,const REAL *p2,const REAL *p3) -{ - REAL ret = 0; - - ret = triangle_area_3d(p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],p3[0],p3[1],p3[2]); - - return ret; -} - - -void fm_lerp(const REAL *p1,const REAL *p2,REAL *dest,REAL lerpValue) -{ - dest[0] = ((p2[0] - p1[0])*lerpValue) + p1[0]; - dest[1] = ((p2[1] - p1[1])*lerpValue) + p1[1]; - dest[2] = ((p2[2] - p1[2])*lerpValue) + p1[2]; -} - -bool fm_pointTestXZ(const REAL *p,const REAL *i,const REAL *j) -{ - bool ret = false; - - if (((( i[2] <= p[2] ) && ( p[2] < j[2] )) || (( j[2] <= p[2] ) && ( p[2] < i[2] ))) && ( p[0] < (j[0] - i[0]) * (p[2] - i[2]) / (j[2] - i[2]) + i[0])) - ret = true; - - return ret; -}; - - -bool fm_insideTriangleXZ(const REAL *p,const REAL *p1,const REAL *p2,const REAL *p3) -{ - bool ret = false; - - NxI32 c = 0; - if ( fm_pointTestXZ(p,p1,p2) ) c = !c; - if ( fm_pointTestXZ(p,p2,p3) ) c = !c; - if ( fm_pointTestXZ(p,p3,p1) ) c = !c; - if ( c ) ret = true; - - return ret; -} - -bool fm_insideAABB(const REAL *pos,const REAL *bmin,const REAL *bmax) -{ - bool ret = false; - - if ( pos[0] >= bmin[0] && pos[0] <= bmax[0] && - pos[1] >= bmin[1] && pos[1] <= bmax[1] && - pos[2] >= bmin[2] && pos[2] <= bmax[2] ) - ret = true; - - return ret; -} - - -NxU32 fm_clipTestPoint(const REAL *bmin,const REAL *bmax,const REAL *pos) -{ - NxU32 ret = 0; - - if ( pos[0] < bmin[0] ) - ret|=FMCS_XMIN; - else if ( pos[0] > bmax[0] ) - ret|=FMCS_XMAX; - - if ( pos[1] < bmin[1] ) - ret|=FMCS_YMIN; - else if ( pos[1] > bmax[1] ) - ret|=FMCS_YMAX; - - if ( pos[2] < bmin[2] ) - ret|=FMCS_ZMIN; - else if ( pos[2] > bmax[2] ) - ret|=FMCS_ZMAX; - - return ret; -} - -NxU32 fm_clipTestPointXZ(const REAL *bmin,const REAL *bmax,const REAL *pos) // only tests X and Z, not Y -{ - NxU32 ret = 0; - - if ( pos[0] < bmin[0] ) - ret|=FMCS_XMIN; - else if ( pos[0] > bmax[0] ) - ret|=FMCS_XMAX; - - if ( pos[2] < bmin[2] ) - ret|=FMCS_ZMIN; - else if ( pos[2] > bmax[2] ) - ret|=FMCS_ZMAX; - - return ret; -} - -NxU32 fm_clipTestAABB(const REAL *bmin,const REAL *bmax,const REAL *p1,const REAL *p2,const REAL *p3,NxU32 &andCode) -{ - NxU32 orCode = 0; - - andCode = FMCS_XMIN | FMCS_XMAX | FMCS_YMIN | FMCS_YMAX | FMCS_ZMIN | FMCS_ZMAX; - - NxU32 c = fm_clipTestPoint(bmin,bmax,p1); - orCode|=c; - andCode&=c; - - c = fm_clipTestPoint(bmin,bmax,p2); - orCode|=c; - andCode&=c; - - c = fm_clipTestPoint(bmin,bmax,p3); - orCode|=c; - andCode&=c; - - return orCode; -} - -bool intersect(const REAL *si,const REAL *ei,const REAL *bmin,const REAL *bmax,REAL *time) -{ - REAL st,et,fst = 0,fet = 1; - - for (NxI32 i = 0; i < 3; i++) - { - if (*si < *ei) - { - if (*si > *bmax || *ei < *bmin) - return false; - REAL di = *ei - *si; - st = (*si < *bmin)? (*bmin - *si) / di: 0; - et = (*ei > *bmax)? (*bmax - *si) / di: 1; - } - else - { - if (*ei > *bmax || *si < *bmin) - return false; - REAL di = *ei - *si; - st = (*si > *bmax)? (*bmax - *si) / di: 0; - et = (*ei < *bmin)? (*bmin - *si) / di: 1; - } - - if (st > fst) fst = st; - if (et < fet) fet = et; - if (fet < fst) - return false; - bmin++; bmax++; - si++; ei++; - } - - *time = fst; - return true; -} - - - -bool fm_lineTestAABB(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) -{ - bool sect = intersect(p1,p2,bmin,bmax,&time); - return sect; -} - - -bool fm_lineTestAABBXZ(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) -{ - REAL _bmin[3]; - REAL _bmax[3]; - - _bmin[0] = bmin[0]; - _bmin[1] = -1e9; - _bmin[2] = bmin[2]; - - _bmax[0] = bmax[0]; - _bmax[1] = 1e9; - _bmax[2] = bmax[2]; - - bool sect = intersect(p1,p2,_bmin,_bmax,&time); - - return sect; -} - -void fm_minmax(const REAL *p,REAL *bmin,REAL *bmax) // accmulate to a min-max value -{ - - if ( p[0] < bmin[0] ) bmin[0] = p[0]; - if ( p[1] < bmin[1] ) bmin[1] = p[1]; - if ( p[2] < bmin[2] ) bmin[2] = p[2]; - - if ( p[0] > bmax[0] ) bmax[0] = p[0]; - if ( p[1] > bmax[1] ) bmax[1] = p[1]; - if ( p[2] > bmax[2] ) bmax[2] = p[2]; - -} - -REAL fm_solveX(const REAL *plane,REAL y,REAL z) // solve for X given this plane equation and the other two components. -{ - REAL x = (y*plane[1]+z*plane[2]+plane[3]) / -plane[0]; - return x; -} - -REAL fm_solveY(const REAL *plane,REAL x,REAL z) // solve for Y given this plane equation and the other two components. -{ - REAL y = (x*plane[0]+z*plane[2]+plane[3]) / -plane[1]; - return y; -} - - -REAL fm_solveZ(const REAL *plane,REAL x,REAL y) // solve for Y given this plane equation and the other two components. -{ - REAL z = (x*plane[0]+y*plane[1]+plane[3]) / -plane[2]; - return z; -} - - -void fm_getAABBCenter(const REAL *bmin,const REAL *bmax,REAL *center) -{ - center[0] = (bmax[0]-bmin[0])*0.5f+bmin[0]; - center[1] = (bmax[1]-bmin[1])*0.5f+bmin[1]; - center[2] = (bmax[2]-bmin[2])*0.5f+bmin[2]; -} - -FM_Axis fm_getDominantAxis(const REAL normal[3]) -{ - FM_Axis ret = FM_XAXIS; - - REAL x = fabs(normal[0]); - REAL y = fabs(normal[1]); - REAL z = fabs(normal[2]); - - if ( y > x && y > z ) - ret = FM_YAXIS; - else if ( z > x && z > y ) - ret = FM_ZAXIS; - - return ret; -} - - -bool fm_lineSphereIntersect(const REAL *center,REAL radius,const REAL *p1,const REAL *p2,REAL *intersect) -{ - bool ret = false; - - REAL dir[3]; - - dir[0] = p2[0]-p1[0]; - dir[1] = p2[1]-p1[1]; - dir[2] = p2[2]-p1[2]; - - REAL distance = sqrt( dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]); - - if ( distance > 0 ) - { - REAL recip = 1.0f / distance; - dir[0]*=recip; - dir[1]*=recip; - dir[2]*=recip; - ret = fm_raySphereIntersect(center,radius,p1,dir,distance,intersect); - } - else - { - dir[0] = center[0]-p1[0]; - dir[1] = center[1]-p1[1]; - dir[2] = center[2]-p1[2]; - REAL d2 = dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]; - REAL r2 = radius*radius; - if ( d2 < r2 ) - { - ret = true; - if ( intersect ) - { - intersect[0] = p1[0]; - intersect[1] = p1[1]; - intersect[2] = p1[2]; - } - } - } - return ret; -} - -#define DOT(p1,p2) (p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]) - -bool fm_raySphereIntersect(const REAL *center,REAL radius,const REAL *pos,const REAL *dir,REAL distance,REAL *intersect) -{ - bool ret = false; - - REAL E0[3]; - - E0[0] = center[0] - pos[0]; - E0[1] = center[1] - pos[1]; - E0[2] = center[2] - pos[2]; - - REAL V[3]; - - V[0] = dir[0]; - V[1] = dir[1]; - V[2] = dir[2]; - - - REAL dist2 = E0[0]*E0[0] + E0[1]*E0[1] + E0[2] * E0[2]; - REAL radius2 = radius*radius; // radius squared.. - - // Bug Fix For Gem, if origin is *inside* the sphere, invert the - // direction vector so that we get a valid intersection location. - if ( dist2 < radius2 ) - { - V[0]*=-1; - V[1]*=-1; - V[2]*=-1; - } - - - REAL v = DOT(E0,V); - - REAL disc = radius2 - (dist2 - v*v); - - if (disc > 0.0f) - { - if ( intersect ) - { - REAL d = sqrt(disc); - REAL diff = v-d; - if ( diff < distance ) - { - intersect[0] = pos[0]+V[0]*diff; - intersect[1] = pos[1]+V[1]*diff; - intersect[2] = pos[2]+V[2]*diff; - ret = true; - } - } - } - - return ret; -} - - -void fm_catmullRom(REAL *out_vector,const REAL *p1,const REAL *p2,const REAL *p3,const REAL *p4, const REAL s) -{ - REAL s_squared = s * s; - REAL s_cubed = s_squared * s; - - REAL coefficient_p1 = -s_cubed + 2*s_squared - s; - REAL coefficient_p2 = 3 * s_cubed - 5 * s_squared + 2; - REAL coefficient_p3 = -3 * s_cubed +4 * s_squared + s; - REAL coefficient_p4 = s_cubed - s_squared; - - out_vector[0] = (coefficient_p1 * p1[0] + coefficient_p2 * p2[0] + coefficient_p3 * p3[0] + coefficient_p4 * p4[0])*0.5f; - out_vector[1] = (coefficient_p1 * p1[1] + coefficient_p2 * p2[1] + coefficient_p3 * p3[1] + coefficient_p4 * p4[1])*0.5f; - out_vector[2] = (coefficient_p1 * p1[2] + coefficient_p2 * p2[2] + coefficient_p3 * p3[2] + coefficient_p4 * p4[2])*0.5f; -} - -bool fm_intersectAABB(const REAL *bmin1,const REAL *bmax1,const REAL *bmin2,const REAL *bmax2) -{ - if ((bmin1[0] > bmax2[0]) || (bmin2[0] > bmax1[0])) return false; - if ((bmin1[1] > bmax2[1]) || (bmin2[1] > bmax1[1])) return false; - if ((bmin1[2] > bmax2[2]) || (bmin2[2] > bmax1[2])) return false; - return true; - -} - -bool fm_insideAABB(const REAL *obmin,const REAL *obmax,const REAL *tbmin,const REAL *tbmax) // test if bounding box tbmin/tmbax is fully inside obmin/obmax -{ - bool ret = false; - - if ( tbmax[0] <= obmax[0] && - tbmax[1] <= obmax[1] && - tbmax[2] <= obmax[2] && - tbmin[0] >= obmin[0] && - tbmin[1] >= obmin[1] && - tbmin[2] >= obmin[2] ) ret = true; - - return ret; -} - - -// Reference, from Stan Melax in Game Gems I -// Quaternion q; -// vector3 c = CrossProduct(v0,v1); -// REAL d = DotProduct(v0,v1); -// REAL s = (REAL)sqrt((1+d)*2); -// q.x = c.x / s; -// q.y = c.y / s; -// q.z = c.z / s; -// q.w = s /2.0f; -// return q; -void fm_rotationArc(const REAL *v0,const REAL *v1,REAL *quat) -{ - REAL cross[3]; - - fm_cross(cross,v0,v1); - REAL d = fm_dot(v0,v1); - REAL s = sqrt((1+d)*2); - REAL recip = 1.0f / s; - - quat[0] = cross[0] * recip; - quat[1] = cross[1] * recip; - quat[2] = cross[2] * recip; - quat[3] = s * 0.5f; - -} - - -REAL fm_distancePointLineSegment(const REAL *Point,const REAL *LineStart,const REAL *LineEnd,REAL *intersection,LineSegmentType &type,REAL epsilon) -{ - REAL ret; - - REAL LineMag = fm_distance( LineEnd, LineStart ); - - if ( LineMag > 0 ) - { - REAL U = ( ( ( Point[0] - LineStart[0] ) * ( LineEnd[0] - LineStart[0] ) ) + ( ( Point[1] - LineStart[1] ) * ( LineEnd[1] - LineStart[1] ) ) + ( ( Point[2] - LineStart[2] ) * ( LineEnd[2] - LineStart[2] ) ) ) / ( LineMag * LineMag ); - if( U < 0.0f || U > 1.0f ) - { - REAL d1 = fm_distanceSquared(Point,LineStart); - REAL d2 = fm_distanceSquared(Point,LineEnd); - if ( d1 <= d2 ) - { - ret = sqrt(d1); - intersection[0] = LineStart[0]; - intersection[1] = LineStart[1]; - intersection[2] = LineStart[2]; - type = LS_START; - } - else - { - ret = sqrt(d2); - intersection[0] = LineEnd[0]; - intersection[1] = LineEnd[1]; - intersection[2] = LineEnd[2]; - type = LS_END; - } - } - else - { - intersection[0] = LineStart[0] + U * ( LineEnd[0] - LineStart[0] ); - intersection[1] = LineStart[1] + U * ( LineEnd[1] - LineStart[1] ); - intersection[2] = LineStart[2] + U * ( LineEnd[2] - LineStart[2] ); - - ret = fm_distance(Point,intersection); - - REAL d1 = fm_distanceSquared(intersection,LineStart); - REAL d2 = fm_distanceSquared(intersection,LineEnd); - REAL mag = (epsilon*2)*(epsilon*2); - - if ( d1 < mag ) // if less than 1/100th the total distance, treat is as the 'start' - { - type = LS_START; - } - else if ( d2 < mag ) - { - type = LS_END; - } - else - { - type = LS_MIDDLE; - } - - } - } - else - { - ret = LineMag; - intersection[0] = LineEnd[0]; - intersection[1] = LineEnd[1]; - intersection[2] = LineEnd[2]; - type = LS_END; - } - - return ret; -} - - -#ifndef BEST_FIT_PLANE_H - -#define BEST_FIT_PLANE_H - -template class Eigen -{ -public: - - - void DecrSortEigenStuff(void) - { - Tridiagonal(); //diagonalize the matrix. - QLAlgorithm(); // - DecreasingSort(); - GuaranteeRotation(); - } - - void Tridiagonal(void) - { - Type fM00 = mElement[0][0]; - Type fM01 = mElement[0][1]; - Type fM02 = mElement[0][2]; - Type fM11 = mElement[1][1]; - Type fM12 = mElement[1][2]; - Type fM22 = mElement[2][2]; - - m_afDiag[0] = fM00; - m_afSubd[2] = 0; - if (fM02 != (Type)0.0) - { - Type fLength = sqrt(fM01*fM01+fM02*fM02); - Type fInvLength = ((Type)1.0)/fLength; - fM01 *= fInvLength; - fM02 *= fInvLength; - Type fQ = ((Type)2.0)*fM01*fM12+fM02*(fM22-fM11); - m_afDiag[1] = fM11+fM02*fQ; - m_afDiag[2] = fM22-fM02*fQ; - m_afSubd[0] = fLength; - m_afSubd[1] = fM12-fM01*fQ; - mElement[0][0] = (Type)1.0; - mElement[0][1] = (Type)0.0; - mElement[0][2] = (Type)0.0; - mElement[1][0] = (Type)0.0; - mElement[1][1] = fM01; - mElement[1][2] = fM02; - mElement[2][0] = (Type)0.0; - mElement[2][1] = fM02; - mElement[2][2] = -fM01; - m_bIsRotation = false; - } - else - { - m_afDiag[1] = fM11; - m_afDiag[2] = fM22; - m_afSubd[0] = fM01; - m_afSubd[1] = fM12; - mElement[0][0] = (Type)1.0; - mElement[0][1] = (Type)0.0; - mElement[0][2] = (Type)0.0; - mElement[1][0] = (Type)0.0; - mElement[1][1] = (Type)1.0; - mElement[1][2] = (Type)0.0; - mElement[2][0] = (Type)0.0; - mElement[2][1] = (Type)0.0; - mElement[2][2] = (Type)1.0; - m_bIsRotation = true; - } - } - - bool QLAlgorithm(void) - { - const NxI32 iMaxIter = 32; - - for (NxI32 i0 = 0; i0 <3; i0++) - { - NxI32 i1; - for (i1 = 0; i1 < iMaxIter; i1++) - { - NxI32 i2; - for (i2 = i0; i2 <= (3-2); i2++) - { - Type fTmp = fabs(m_afDiag[i2]) + fabs(m_afDiag[i2+1]); - if ( fabs(m_afSubd[i2]) + fTmp == fTmp ) - break; - } - if (i2 == i0) - { - break; - } - - Type fG = (m_afDiag[i0+1] - m_afDiag[i0])/(((Type)2.0) * m_afSubd[i0]); - Type fR = sqrt(fG*fG+(Type)1.0); - if (fG < (Type)0.0) - { - fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG-fR); - } - else - { - fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG+fR); - } - Type fSin = (Type)1.0, fCos = (Type)1.0, fP = (Type)0.0; - for (NxI32 i3 = i2-1; i3 >= i0; i3--) - { - Type fF = fSin*m_afSubd[i3]; - Type fB = fCos*m_afSubd[i3]; - if (fabs(fF) >= fabs(fG)) - { - fCos = fG/fF; - fR = sqrt(fCos*fCos+(Type)1.0); - m_afSubd[i3+1] = fF*fR; - fSin = ((Type)1.0)/fR; - fCos *= fSin; - } - else - { - fSin = fF/fG; - fR = sqrt(fSin*fSin+(Type)1.0); - m_afSubd[i3+1] = fG*fR; - fCos = ((Type)1.0)/fR; - fSin *= fCos; - } - fG = m_afDiag[i3+1]-fP; - fR = (m_afDiag[i3]-fG)*fSin+((Type)2.0)*fB*fCos; - fP = fSin*fR; - m_afDiag[i3+1] = fG+fP; - fG = fCos*fR-fB; - for (NxI32 i4 = 0; i4 < 3; i4++) - { - fF = mElement[i4][i3+1]; - mElement[i4][i3+1] = fSin*mElement[i4][i3]+fCos*fF; - mElement[i4][i3] = fCos*mElement[i4][i3]-fSin*fF; - } - } - m_afDiag[i0] -= fP; - m_afSubd[i0] = fG; - m_afSubd[i2] = (Type)0.0; - } - if (i1 == iMaxIter) - { - return false; - } - } - return true; - } - - void DecreasingSort(void) - { - //sort eigenvalues in decreasing order, e[0] >= ... >= e[iSize-1] - for (NxI32 i0 = 0, i1; i0 <= 3-2; i0++) - { - // locate maximum eigenvalue - i1 = i0; - Type fMax = m_afDiag[i1]; - NxI32 i2; - for (i2 = i0+1; i2 < 3; i2++) - { - if (m_afDiag[i2] > fMax) - { - i1 = i2; - fMax = m_afDiag[i1]; - } - } - - if (i1 != i0) - { - // swap eigenvalues - m_afDiag[i1] = m_afDiag[i0]; - m_afDiag[i0] = fMax; - // swap eigenvectors - for (i2 = 0; i2 < 3; i2++) - { - Type fTmp = mElement[i2][i0]; - mElement[i2][i0] = mElement[i2][i1]; - mElement[i2][i1] = fTmp; - m_bIsRotation = !m_bIsRotation; - } - } - } - } - - - void GuaranteeRotation(void) - { - if (!m_bIsRotation) - { - // change sign on the first column - for (NxI32 iRow = 0; iRow <3; iRow++) - { - mElement[iRow][0] = -mElement[iRow][0]; - } - } - } - - Type mElement[3][3]; - Type m_afDiag[3]; - Type m_afSubd[3]; - bool m_bIsRotation; -}; - -#endif - -bool fm_computeBestFitPlane(NxU32 vcount, - const REAL *points, - NxU32 vstride, - const REAL *weights, - NxU32 wstride, - REAL *plane) -{ - bool ret = false; - - REAL kOrigin[3] = { 0, 0, 0 }; - - REAL wtotal = 0; - - { - const char *source = (const char *) points; - const char *wsource = (const char *) weights; - - for (NxU32 i=0; i kES; - - kES.mElement[0][0] = fSumXX; - kES.mElement[0][1] = fSumXY; - kES.mElement[0][2] = fSumXZ; - - kES.mElement[1][0] = fSumXY; - kES.mElement[1][1] = fSumYY; - kES.mElement[1][2] = fSumYZ; - - kES.mElement[2][0] = fSumXZ; - kES.mElement[2][1] = fSumYZ; - kES.mElement[2][2] = fSumZZ; - - // compute eigenstuff, smallest eigenvalue is in last position - kES.DecrSortEigenStuff(); - - REAL kNormal[3]; - - kNormal[0] = kES.mElement[0][2]; - kNormal[1] = kES.mElement[1][2]; - kNormal[2] = kES.mElement[2][2]; - - // the minimum energy - plane[0] = kNormal[0]; - plane[1] = kNormal[1]; - plane[2] = kNormal[2]; - - plane[3] = 0 - fm_dot(kNormal,kOrigin); - - ret = true; - - return ret; -} - - -bool fm_colinear(const REAL a1[3],const REAL a2[3],const REAL b1[3],const REAL b2[3],REAL epsilon) // true if these two line segments are co-linear. -{ - bool ret = false; - - REAL dir1[3]; - REAL dir2[3]; - - dir1[0] = (a2[0] - a1[0]); - dir1[1] = (a2[1] - a1[1]); - dir1[2] = (a2[2] - a1[2]); - - dir2[0] = (b2[0]-a1[0]) - (b1[0]-a1[0]); - dir2[1] = (b2[1]-a1[1]) - (b1[1]-a1[1]); - dir2[2] = (b2[2]-a2[2]) - (b1[2]-a2[2]); - - fm_normalize(dir1); - fm_normalize(dir2); - - REAL dot = fm_dot(dir1,dir2); - - if ( dot >= epsilon ) - { - ret = true; - } - - - return ret; -} - -bool fm_colinear(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) -{ - bool ret = false; - - REAL dir1[3]; - REAL dir2[3]; - - dir1[0] = p2[0] - p1[0]; - dir1[1] = p2[1] - p1[1]; - dir1[2] = p2[2] - p1[2]; - - dir2[0] = p3[0] - p2[0]; - dir2[1] = p3[1] - p2[1]; - dir2[2] = p3[2] - p2[2]; - - fm_normalize(dir1); - fm_normalize(dir2); - - REAL dot = fm_dot(dir1,dir2); - - if ( dot >= epsilon ) - { - ret = true; - } - - - return ret; -} - -void fm_initMinMax(const REAL *p,REAL *bmin,REAL *bmax) -{ - bmax[0] = bmin[0] = p[0]; - bmax[1] = bmin[1] = p[1]; - bmax[2] = bmin[2] = p[2]; -} - -IntersectResult fm_intersectLineSegments2d(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL *intersection) -{ - IntersectResult ret; - - REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); - REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); - REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); - if (denom == 0 ) - { - if(nume_a == 0 && nume_b == 0) - { - ret = IR_COINCIDENT; - } - else - { - ret = IR_PARALLEL; - } - } - else - { - - REAL recip = 1 / denom; - REAL ua = nume_a * recip; - REAL ub = nume_b * recip; - - if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) - { - // Get the intersection point. - intersection[0] = a1[0] + ua*(a2[0] - a1[0]); - intersection[1] = a1[1] + ua*(a2[1] - a1[1]); - ret = IR_DO_INTERSECT; - } - else - { - ret = IR_DONT_INTERSECT; - } - } - return ret; -} - -IntersectResult fm_intersectLineSegments2dTime(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL &t1,REAL &t2) -{ - IntersectResult ret; - - REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); - REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); - REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); - if (denom == 0 ) - { - if(nume_a == 0 && nume_b == 0) - { - ret = IR_COINCIDENT; - } - else - { - ret = IR_PARALLEL; - } - } - else - { - - REAL recip = 1 / denom; - REAL ua = nume_a * recip; - REAL ub = nume_b * recip; - - if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) - { - t1 = ua; - t2 = ub; - ret = IR_DO_INTERSECT; - } - else - { - ret = IR_DONT_INTERSECT; - } - } - return ret; -} - -//**** Plane Triangle Intersection - - - - - -// assumes that the points are on opposite sides of the plane! -void fm_intersectPointPlane(const REAL *p1,const REAL *p2,REAL *split,const REAL *plane) -{ - - REAL dp1 = fm_distToPlane(plane,p1); - - REAL dir[3]; - - dir[0] = p2[0] - p1[0]; - dir[1] = p2[1] - p1[1]; - dir[2] = p2[2] - p1[2]; - - REAL dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2]; - REAL dot2 = dp1 - plane[3]; - - REAL t = -(plane[3] + dot2 ) / dot1; - - split[0] = (dir[0]*t)+p1[0]; - split[1] = (dir[1]*t)+p1[1]; - split[2] = (dir[2]*t)+p1[2]; - -} - -PlaneTriResult fm_getSidePlane(const REAL *p,const REAL *plane,REAL epsilon) -{ - PlaneTriResult ret = PTR_ON_PLANE; - - REAL d = fm_distToPlane(plane,p); - - if ( d < -epsilon || d > epsilon ) - { - if ( d > 0 ) - ret = PTR_FRONT; // it is 'in front' within the provided epsilon value. - else - ret = PTR_BACK; - } - - return ret; -} - - - -#ifndef PLANE_TRIANGLE_INTERSECTION_H - -#define PLANE_TRIANGLE_INTERSECTION_H - -#define MAXPTS 256 - -template class point -{ -public: - - void set(const Type *p) - { - x = p[0]; - y = p[1]; - z = p[2]; - } - - Type x; - Type y; - Type z; -}; - -template class plane -{ -public: - plane(const Type *p) - { - normal.x = p[0]; - normal.y = p[1]; - normal.z = p[2]; - D = p[3]; - } - - Type Classify_Point(const point &p) - { - return p.x*normal.x + p.y*normal.y + p.z*normal.z + D; - } - - point normal; - Type D; -}; - -template class polygon -{ -public: - polygon(void) - { - mVcount = 0; - } - - polygon(const Type *p1,const Type *p2,const Type *p3) - { - mVcount = 3; - mVertices[0].set(p1); - mVertices[1].set(p2); - mVertices[2].set(p3); - } - - - NxI32 NumVertices(void) const { return mVcount; }; - - const point& Vertex(NxI32 index) - { - if ( index < 0 ) index+=mVcount; - return mVertices[index]; - }; - - - void set(const point *pts,NxI32 count) - { - for (NxI32 i=0; i *poly,plane *part, polygon &front, polygon &back) - { - NxI32 count = poly->NumVertices (); - NxI32 out_c = 0, in_c = 0; - point ptA, ptB,outpts[MAXPTS],inpts[MAXPTS]; - Type sideA, sideB; - ptA = poly->Vertex (count - 1); - sideA = part->Classify_Point (ptA); - for (NxI32 i = -1; ++i < count;) - { - ptB = poly->Vertex(i); - sideB = part->Classify_Point(ptB); - if (sideB > 0) - { - if (sideA < 0) - { - point v; - fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); - outpts[out_c++] = inpts[in_c++] = v; - } - outpts[out_c++] = ptB; - } - else if (sideB < 0) - { - if (sideA > 0) - { - point v; - fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); - outpts[out_c++] = inpts[in_c++] = v; - } - inpts[in_c++] = ptB; - } - else - outpts[out_c++] = inpts[in_c++] = ptB; - ptA = ptB; - sideA = sideB; - } - - front.set(&outpts[0], out_c); - back.set(&inpts[0], in_c); - } - - NxI32 mVcount; - point mVertices[MAXPTS]; -}; - - - -#endif - -static inline void add(const REAL *p,REAL *dest,NxU32 tstride,NxU32 &pcount) -{ - char *d = (char *) dest; - d = d + pcount*tstride; - dest = (REAL *) d; - dest[0] = p[0]; - dest[1] = p[1]; - dest[2] = p[2]; - pcount++; - assert( pcount <= 4 ); -} - - -PlaneTriResult fm_planeTriIntersection(const REAL *_plane, // the plane equation in Ax+By+Cz+D format - const REAL *triangle, // the source triangle. - NxU32 tstride, // stride in bytes of the input and output *vertices* - REAL epsilon, // the co-planar epsilon value. - REAL *front, // the triangle in front of the - NxU32 &fcount, // number of vertices in the 'front' triangle - REAL *back, // the triangle in back of the plane - NxU32 &bcount) // the number of vertices in the 'back' triangle. -{ - - fcount = 0; - bcount = 0; - - const char *tsource = (const char *) triangle; - - // get the three vertices of the triangle. - const REAL *p1 = (const REAL *) (tsource); - const REAL *p2 = (const REAL *) (tsource+tstride); - const REAL *p3 = (const REAL *) (tsource+tstride*2); - - - PlaneTriResult r1 = fm_getSidePlane(p1,_plane,epsilon); // compute the side of the plane each vertex is on - PlaneTriResult r2 = fm_getSidePlane(p2,_plane,epsilon); - PlaneTriResult r3 = fm_getSidePlane(p3,_plane,epsilon); - - // If any of the points lay right *on* the plane.... - if ( r1 == PTR_ON_PLANE || r2 == PTR_ON_PLANE || r3 == PTR_ON_PLANE ) - { - // If the triangle is completely co-planar, then just treat it as 'front' and return! - if ( r1 == PTR_ON_PLANE && r2 == PTR_ON_PLANE && r3 == PTR_ON_PLANE ) - { - add(p1,front,tstride,fcount); - add(p2,front,tstride,fcount); - add(p3,front,tstride,fcount); - return PTR_FRONT; - } - // Decide to place the co-planar points on the same side as the co-planar point. - PlaneTriResult r= PTR_ON_PLANE; - if ( r1 != PTR_ON_PLANE ) - r = r1; - else if ( r2 != PTR_ON_PLANE ) - r = r2; - else if ( r3 != PTR_ON_PLANE ) - r = r3; - - if ( r1 == PTR_ON_PLANE ) r1 = r; - if ( r2 == PTR_ON_PLANE ) r2 = r; - if ( r3 == PTR_ON_PLANE ) r3 = r; - - } - - if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane. - { - if ( r1 == PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle. - { - add(p1,front,tstride,fcount); - add(p2,front,tstride,fcount); - add(p3,front,tstride,fcount); - } - else - { - add(p1,back,tstride,bcount); // if all three are in 'back' then copy to the 'back' output triangle. - add(p2,back,tstride,bcount); - add(p3,back,tstride,bcount); - } - return r1; // if all three points are on the same side of the plane return result - } - - - polygon pi(p1,p2,p3); - polygon pfront,pback; - - plane part(_plane); - - pi.Split_Polygon(&pi,&part,pfront,pback); - - for (NxI32 i=0; i bmax[0] ) bmax[0] = t[0]; - if ( t[1] > bmax[1] ) bmax[1] = t[1]; - if ( t[2] > bmax[2] ) bmax[2] = t[2]; - - src+=pstride; - } - - REAL center[3]; - - sides[0] = bmax[0]-bmin[0]; - sides[1] = bmax[1]-bmin[1]; - sides[2] = bmax[2]-bmin[2]; - - center[0] = sides[0]*0.5f+bmin[0]; - center[1] = sides[1]*0.5f+bmin[1]; - center[2] = sides[2]*0.5f+bmin[2]; - - REAL ocenter[3]; - - fm_rotate(matrix,center,ocenter); - - matrix[12]+=ocenter[0]; - matrix[13]+=ocenter[1]; - matrix[14]+=ocenter[2]; - -} - -void fm_computeBestFitOBB(NxU32 vcount,const REAL *points,NxU32 pstride,REAL *sides,REAL *matrix,bool bruteForce) -{ - REAL plane[4]; - fm_computeBestFitPlane(vcount,points,pstride,0,0,plane); - fm_planeToMatrix(plane,matrix); - computeOBB( vcount, points, pstride, sides, matrix ); - - REAL refmatrix[16]; - memcpy(refmatrix,matrix,16*sizeof(REAL)); - - REAL volume = sides[0]*sides[1]*sides[2]; - if ( bruteForce ) - { - for (REAL a=10; a<180; a+=10) - { - REAL quat[4]; - fm_eulerToQuat(0,a*FM_DEG_TO_RAD,0,quat); - REAL temp[16]; - REAL pmatrix[16]; - fm_quatToMatrix(quat,temp); - fm_matrixMultiply(temp,refmatrix,pmatrix); - REAL psides[3]; - computeOBB( vcount, points, pstride, psides, pmatrix ); - REAL v = psides[0]*psides[1]*psides[2]; - if ( v < volume ) - { - volume = v; - memcpy(matrix,pmatrix,sizeof(REAL)*16); - sides[0] = psides[0]; - sides[1] = psides[1]; - sides[2] = psides[2]; - } - } - } -} - -void fm_computeBestFitOBB(NxU32 vcount,const REAL *points,NxU32 pstride,REAL *sides,REAL *pos,REAL *quat,bool bruteForce) -{ - REAL matrix[16]; - fm_computeBestFitOBB(vcount,points,pstride,sides,matrix,bruteForce); - fm_getTranslation(matrix,pos); - fm_matrixToQuat(matrix,quat); -} - -void fm_computeBestFitABB(NxU32 vcount,const REAL *points,NxU32 pstride,REAL *sides,REAL *pos) -{ - REAL bmin[3]; - REAL bmax[3]; - - bmin[0] = points[0]; - bmin[1] = points[1]; - bmin[2] = points[2]; - - bmax[0] = points[0]; - bmax[1] = points[1]; - bmax[2] = points[2]; - - const char *cp = (const char *) points; - for (NxU32 i=0; i bmax[0] ) bmax[0] = p[0]; - if ( p[1] > bmax[1] ) bmax[1] = p[1]; - if ( p[2] > bmax[2] ) bmax[2] = p[2]; - - cp+=pstride; - } - - - sides[0] = bmax[0] - bmin[0]; - sides[1] = bmax[1] - bmin[1]; - sides[2] = bmax[2] - bmin[2]; - - pos[0] = bmin[0]+sides[0]*0.5f; - pos[1] = bmin[1]+sides[1]*0.5f; - pos[2] = bmin[2]+sides[2]*0.5f; - -} - - -void fm_planeToMatrix(const REAL *plane,REAL *matrix) // convert a plane equation to a 4x4 rotation matrix -{ - REAL ref[3] = { 0, 1, 0 }; - REAL quat[4]; - fm_rotationArc(ref,plane,quat); - fm_quatToMatrix(quat,matrix); - REAL origin[3] = { 0, -plane[3], 0 }; - REAL center[3]; - fm_transform(matrix,origin,center); - fm_setTranslation(center,matrix); -} - -void fm_planeToQuat(const REAL *plane,REAL *quat,REAL *pos) // convert a plane equation to a quaternion and translation -{ - REAL ref[3] = { 0, 1, 0 }; - REAL matrix[16]; - fm_rotationArc(ref,plane,quat); - fm_quatToMatrix(quat,matrix); - REAL origin[3] = { 0, plane[3], 0 }; - fm_transform(matrix,origin,pos); -} - -void fm_eulerMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) -{ - REAL quat[4]; - fm_eulerToQuat(ax,ay,az,quat); - fm_quatToMatrix(quat,matrix); -} - - -//********************************************************** -//********************************************************** -//**** Vertex Welding -//********************************************************** -//********************************************************** - -#ifndef VERTEX_INDEX_H - -#define VERTEX_INDEX_H - -namespace VERTEX_INDEX -{ - -class KdTreeNode; - -typedef CONVEX_DECOMPOSITION::Array< KdTreeNode * > KdTreeNodeVector; - -enum Axes -{ - X_AXIS = 0, - Y_AXIS = 1, - Z_AXIS = 2 -}; - -class KdTreeFindNode -{ -public: - KdTreeFindNode(void) - { - mNode = 0; - mDistance = 0; - } - KdTreeNode *mNode; - NxF64 mDistance; -}; - -class KdTreeInterface -{ -public: - virtual const NxF64 * getPositionDouble(NxU32 index) const = 0; - virtual const NxF32 * getPositionFloat(NxU32 index) const = 0; -}; - -class KdTreeNode -{ -public: - KdTreeNode(void) - { - mIndex = 0; - mLeft = 0; - mRight = 0; - } - - KdTreeNode(NxU32 index) - { - mIndex = index; - mLeft = 0; - mRight = 0; - }; - - ~KdTreeNode(void) - { - } - - - void addDouble(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) - { - const NxF64 *nodePosition = iface->getPositionDouble( node->mIndex ); - const NxF64 *position = iface->getPositionDouble( mIndex ); - switch ( dim ) - { - case X_AXIS: - if ( nodePosition[0] <= position[0] ) - { - if ( mLeft ) - mLeft->addDouble(node,Y_AXIS,iface); - else - mLeft = node; - } - else - { - if ( mRight ) - mRight->addDouble(node,Y_AXIS,iface); - else - mRight = node; - } - break; - case Y_AXIS: - if ( nodePosition[1] <= position[1] ) - { - if ( mLeft ) - mLeft->addDouble(node,Z_AXIS,iface); - else - mLeft = node; - } - else - { - if ( mRight ) - mRight->addDouble(node,Z_AXIS,iface); - else - mRight = node; - } - break; - case Z_AXIS: - if ( nodePosition[2] <= position[2] ) - { - if ( mLeft ) - mLeft->addDouble(node,X_AXIS,iface); - else - mLeft = node; - } - else - { - if ( mRight ) - mRight->addDouble(node,X_AXIS,iface); - else - mRight = node; - } - break; - } - - } - - - void addFloat(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) - { - const NxF32 *nodePosition = iface->getPositionFloat( node->mIndex ); - const NxF32 *position = iface->getPositionFloat( mIndex ); - switch ( dim ) - { - case X_AXIS: - if ( nodePosition[0] <= position[0] ) - { - if ( mLeft ) - mLeft->addFloat(node,Y_AXIS,iface); - else - mLeft = node; - } - else - { - if ( mRight ) - mRight->addFloat(node,Y_AXIS,iface); - else - mRight = node; - } - break; - case Y_AXIS: - if ( nodePosition[1] <= position[1] ) - { - if ( mLeft ) - mLeft->addFloat(node,Z_AXIS,iface); - else - mLeft = node; - } - else - { - if ( mRight ) - mRight->addFloat(node,Z_AXIS,iface); - else - mRight = node; - } - break; - case Z_AXIS: - if ( nodePosition[2] <= position[2] ) - { - if ( mLeft ) - mLeft->addFloat(node,X_AXIS,iface); - else - mLeft = node; - } - else - { - if ( mRight ) - mRight->addFloat(node,X_AXIS,iface); - else - mRight = node; - } - break; - } - - } - - - NxU32 getIndex(void) const { return mIndex; }; - - void search(Axes axis,const NxF64 *pos,NxF64 radius,NxU32 &count,NxU32 maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) - { - - const NxF64 *position = iface->getPositionDouble(mIndex); - - NxF64 dx = pos[0] - position[0]; - NxF64 dy = pos[1] - position[1]; - NxF64 dz = pos[2] - position[2]; - - KdTreeNode *search1 = 0; - KdTreeNode *search2 = 0; - - switch ( axis ) - { - case X_AXIS: - if ( dx <= 0 ) // JWR if we are to the left - { - search1 = mLeft; // JWR then search to the left - if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. - search2 = mRight; - } - else - { - search1 = mRight; // JWR ok, we go down the left tree - if ( dx < radius ) // JWR if the distance from the right is less than our search radius - search2 = mLeft; - } - axis = Y_AXIS; - break; - case Y_AXIS: - if ( dy <= 0 ) - { - search1 = mLeft; - if ( -dy < radius ) - search2 = mRight; - } - else - { - search1 = mRight; - if ( dy < radius ) - search2 = mLeft; - } - axis = Z_AXIS; - break; - case Z_AXIS: - if ( dz <= 0 ) - { - search1 = mLeft; - if ( -dz < radius ) - search2 = mRight; - } - else - { - search1 = mRight; - if ( dz < radius ) - search2 = mLeft; - } - axis = X_AXIS; - break; - } - - NxF64 r2 = radius*radius; - NxF64 m = dx*dx+dy*dy+dz*dz; - - if ( m < r2 ) - { - switch ( count ) - { - case 0: - found[count].mNode = this; - found[count].mDistance = m; - break; - case 1: - if ( m < found[0].mDistance ) - { - if ( maxObjects == 1 ) - { - found[0].mNode = this; - found[0].mDistance = m; - } - else - { - found[1] = found[0]; - found[0].mNode = this; - found[0].mDistance = m; - } - } - else if ( maxObjects > 1) - { - found[1].mNode = this; - found[1].mDistance = m; - } - break; - default: - { - bool inserted = false; - - for (NxU32 i=0; i= maxObjects ) scan=maxObjects-1; - for (NxU32 j=scan; j>i; j--) - { - found[j] = found[j-1]; - } - found[i].mNode = this; - found[i].mDistance = m; - inserted = true; - break; - } - } - - if ( !inserted && count < maxObjects ) - { - found[count].mNode = this; - found[count].mDistance = m; - } - } - break; - } - count++; - if ( count > maxObjects ) - { - count = maxObjects; - } - } - - - if ( search1 ) - search1->search( axis, pos,radius, count, maxObjects, found, iface); - - if ( search2 ) - search2->search( axis, pos,radius, count, maxObjects, found, iface); - - } - - void search(Axes axis,const NxF32 *pos,NxF32 radius,NxU32 &count,NxU32 maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) - { - - const NxF32 *position = iface->getPositionFloat(mIndex); - - NxF32 dx = pos[0] - position[0]; - NxF32 dy = pos[1] - position[1]; - NxF32 dz = pos[2] - position[2]; - - KdTreeNode *search1 = 0; - KdTreeNode *search2 = 0; - - switch ( axis ) - { - case X_AXIS: - if ( dx <= 0 ) // JWR if we are to the left - { - search1 = mLeft; // JWR then search to the left - if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. - search2 = mRight; - } - else - { - search1 = mRight; // JWR ok, we go down the left tree - if ( dx < radius ) // JWR if the distance from the right is less than our search radius - search2 = mLeft; - } - axis = Y_AXIS; - break; - case Y_AXIS: - if ( dy <= 0 ) - { - search1 = mLeft; - if ( -dy < radius ) - search2 = mRight; - } - else - { - search1 = mRight; - if ( dy < radius ) - search2 = mLeft; - } - axis = Z_AXIS; - break; - case Z_AXIS: - if ( dz <= 0 ) - { - search1 = mLeft; - if ( -dz < radius ) - search2 = mRight; - } - else - { - search1 = mRight; - if ( dz < radius ) - search2 = mLeft; - } - axis = X_AXIS; - break; - } - - NxF32 r2 = radius*radius; - NxF32 m = dx*dx+dy*dy+dz*dz; - - if ( m < r2 ) - { - switch ( count ) - { - case 0: - found[count].mNode = this; - found[count].mDistance = m; - break; - case 1: - if ( m < found[0].mDistance ) - { - if ( maxObjects == 1 ) - { - found[0].mNode = this; - found[0].mDistance = m; - } - else - { - found[1] = found[0]; - found[0].mNode = this; - found[0].mDistance = m; - } - } - else if ( maxObjects > 1) - { - found[1].mNode = this; - found[1].mDistance = m; - } - break; - default: - { - bool inserted = false; - - for (NxU32 i=0; i= maxObjects ) scan=maxObjects-1; - for (NxU32 j=scan; j>i; j--) - { - found[j] = found[j-1]; - } - found[i].mNode = this; - found[i].mDistance = m; - inserted = true; - break; - } - } - - if ( !inserted && count < maxObjects ) - { - found[count].mNode = this; - found[count].mDistance = m; - } - } - break; - } - count++; - if ( count > maxObjects ) - { - count = maxObjects; - } - } - - - if ( search1 ) - search1->search( axis, pos,radius, count, maxObjects, found, iface); - - if ( search2 ) - search2->search( axis, pos,radius, count, maxObjects, found, iface); - - } - -private: - - void setLeft(KdTreeNode *left) { mLeft = left; }; - void setRight(KdTreeNode *right) { mRight = right; }; - - KdTreeNode *getLeft(void) { return mLeft; } - KdTreeNode *getRight(void) { return mRight; } - - NxU32 mIndex; - KdTreeNode *mLeft; - KdTreeNode *mRight; -}; - - -#define MAX_BUNDLE_SIZE 1024 // 1024 nodes at a time, to minimize memory allocation and guarentee that pointers are persistent. - -class KdTreeNodeBundle : public Memalloc -{ -public: - - KdTreeNodeBundle(void) - { - mNext = 0; - mIndex = 0; - } - - bool isFull(void) const - { - return (bool)( mIndex == MAX_BUNDLE_SIZE ); - } - - KdTreeNode * getNextNode(void) - { - assert(mIndex DoubleVector; -typedef CONVEX_DECOMPOSITION::Array< NxF32 > FloatVector; - -class KdTree : public KdTreeInterface, public Memalloc -{ -public: - KdTree(void) - { - mRoot = 0; - mBundle = 0; - mVcount = 0; - mUseDouble = false; - } - - virtual ~KdTree(void) - { - reset(); - } - - const NxF64 * getPositionDouble(NxU32 index) const - { - assert( mUseDouble ); - assert ( index < mVcount ); - return &mVerticesDouble[index*3]; - } - - const NxF32 * getPositionFloat(NxU32 index) const - { - assert( !mUseDouble ); - assert ( index < mVcount ); - return &mVerticesFloat[index*3]; - } - - NxU32 search(const NxF64 *pos,NxF64 radius,NxU32 maxObjects,KdTreeFindNode *found) const - { - assert( mUseDouble ); - if ( !mRoot ) return 0; - NxU32 count = 0; - mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); - return count; - } - - NxU32 search(const NxF32 *pos,NxF32 radius,NxU32 maxObjects,KdTreeFindNode *found) const - { - assert( !mUseDouble ); - if ( !mRoot ) return 0; - NxU32 count = 0; - mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); - return count; - } - - void reset(void) - { - mRoot = 0; - mVerticesDouble.clear(); - mVerticesFloat.clear(); - KdTreeNodeBundle *bundle = mBundle; - while ( bundle ) - { - KdTreeNodeBundle *next = bundle->mNext; - delete bundle; - bundle = next; - } - mBundle = 0; - mVcount = 0; - } - - NxU32 add(NxF64 x,NxF64 y,NxF64 z) - { - assert(mUseDouble); - NxU32 ret = mVcount; - mVerticesDouble.pushBack(x); - mVerticesDouble.pushBack(y); - mVerticesDouble.pushBack(z); - mVcount++; - KdTreeNode *node = getNewNode(ret); - if ( mRoot ) - { - mRoot->addDouble(node,X_AXIS,this); - } - else - { - mRoot = node; - } - return ret; - } - - NxU32 add(NxF32 x,NxF32 y,NxF32 z) - { - assert(!mUseDouble); - NxU32 ret = mVcount; - mVerticesFloat.pushBack(x); - mVerticesFloat.pushBack(y); - mVerticesFloat.pushBack(z); - mVcount++; - KdTreeNode *node = getNewNode(ret); - if ( mRoot ) - { - mRoot->addFloat(node,X_AXIS,this); - } - else - { - mRoot = node; - } - return ret; - } - - KdTreeNode * getNewNode(NxU32 index) - { - if ( mBundle == 0 ) - { - mBundle = MEMALLOC_NEW(KdTreeNodeBundle); - } - if ( mBundle->isFull() ) - { - KdTreeNodeBundle *bundle = MEMALLOC_NEW(KdTreeNodeBundle); - mBundle->mNext = bundle; - mBundle = bundle; - } - KdTreeNode *node = mBundle->getNextNode(); - new ( node ) KdTreeNode(index); - return node; - } - - NxU32 getNearest(const NxF64 *pos,NxF64 radius,bool &_found) const // returns the nearest possible neighbor's index. - { - assert( mUseDouble ); - NxU32 ret = 0; - - _found = false; - KdTreeFindNode found[1]; - NxU32 count = search(pos,radius,1,found); - if ( count ) - { - KdTreeNode *node = found[0].mNode; - ret = node->getIndex(); - _found = true; - } - return ret; - } - - NxU32 getNearest(const NxF32 *pos,NxF32 radius,bool &_found) const // returns the nearest possible neighbor's index. - { - assert( !mUseDouble ); - NxU32 ret = 0; - - _found = false; - KdTreeFindNode found[1]; - NxU32 count = search(pos,radius,1,found); - if ( count ) - { - KdTreeNode *node = found[0].mNode; - ret = node->getIndex(); - _found = true; - } - return ret; - } - - const NxF64 * getVerticesDouble(void) const - { - assert( mUseDouble ); - const NxF64 *ret = 0; - if ( !mVerticesDouble.empty() ) - { - ret = &mVerticesDouble[0]; - } - return ret; - } - - const NxF32 * getVerticesFloat(void) const - { - assert( !mUseDouble ); - const NxF32 * ret = 0; - if ( !mVerticesFloat.empty() ) - { - ret = &mVerticesFloat[0]; - } - return ret; - } - - NxU32 getVcount(void) const { return mVcount; }; - - void setUseDouble(bool useDouble) - { - mUseDouble = useDouble; - } - -private: - bool mUseDouble; - KdTreeNode *mRoot; - KdTreeNodeBundle *mBundle; - NxU32 mVcount; - DoubleVector mVerticesDouble; - FloatVector mVerticesFloat; -}; - -}; // end of namespace VERTEX_INDEX - -class MyVertexIndex : public fm_VertexIndex, public Memalloc -{ -public: - MyVertexIndex(NxF64 granularity,bool snapToGrid) - { - mDoubleGranularity = granularity; - mFloatGranularity = (NxF32)granularity; - mSnapToGrid = snapToGrid; - mUseDouble = true; - mKdTree.setUseDouble(true); - } - - MyVertexIndex(NxF32 granularity,bool snapToGrid) - { - mDoubleGranularity = granularity; - mFloatGranularity = (NxF32)granularity; - mSnapToGrid = snapToGrid; - mUseDouble = false; - mKdTree.setUseDouble(false); - } - - virtual ~MyVertexIndex(void) - { - - } - - - NxF64 snapToGrid(NxF64 p) - { - NxF64 m = fmod(p,mDoubleGranularity); - p-=m; - return p; - } - - NxF32 snapToGrid(NxF32 p) - { - NxF32 m = fmodf(p,mFloatGranularity); - p-=m; - return p; - } - - NxU32 getIndex(const NxF32 *_p,bool &newPos) // get index for a vector NxF32 - { - NxU32 ret; - - if ( mUseDouble ) - { - NxF64 p[3]; - p[0] = _p[0]; - p[1] = _p[1]; - p[2] = _p[2]; - return getIndex(p,newPos); - } - - newPos = false; - - NxF32 p[3]; - - if ( mSnapToGrid ) - { - p[0] = snapToGrid(_p[0]); - p[1] = snapToGrid(_p[1]); - p[2] = snapToGrid(_p[2]); - } - else - { - p[0] = _p[0]; - p[1] = _p[1]; - p[2] = _p[2]; - } - - bool found; - ret = mKdTree.getNearest(p,mFloatGranularity,found); - if ( !found ) - { - newPos = true; - ret = mKdTree.add(p[0],p[1],p[2]); - } - - - return ret; - } - - NxU32 getIndex(const NxF64 *_p,bool &newPos) // get index for a vector NxF64 - { - NxU32 ret; - - if ( !mUseDouble ) - { - NxF32 p[3]; - p[0] = (NxF32)_p[0]; - p[1] = (NxF32)_p[1]; - p[2] = (NxF32)_p[2]; - return getIndex(p,newPos); - } - - newPos = false; - - NxF64 p[3]; - - if ( mSnapToGrid ) - { - p[0] = snapToGrid(_p[0]); - p[1] = snapToGrid(_p[1]); - p[2] = snapToGrid(_p[2]); - } - else - { - p[0] = _p[0]; - p[1] = _p[1]; - p[2] = _p[2]; - } - - bool found; - ret = mKdTree.getNearest(p,mDoubleGranularity,found); - if ( !found ) - { - newPos = true; - ret = mKdTree.add(p[0],p[1],p[2]); - } - - - return ret; - } - - const NxF32 * getVerticesFloat(void) const - { - const NxF32 * ret = 0; - - assert( !mUseDouble ); - - ret = mKdTree.getVerticesFloat(); - - return ret; - } - - const NxF64 * getVerticesDouble(void) const - { - const NxF64 * ret = 0; - - assert( mUseDouble ); - - ret = mKdTree.getVerticesDouble(); - - return ret; - } - - const NxF32 * getVertexFloat(NxU32 index) const - { - const NxF32 * ret = 0; - assert( !mUseDouble ); -#ifdef _DEBUG - NxU32 vcount = mKdTree.getVcount(); - assert( index < vcount ); -#endif - ret = mKdTree.getVerticesFloat(); - ret = &ret[index*3]; - return ret; - } - - const NxF64 * getVertexDouble(NxU32 index) const - { - const NxF64 * ret = 0; - assert( mUseDouble ); -#ifdef _DEBUG - NxU32 vcount = mKdTree.getVcount(); - assert( index < vcount ); -#endif - ret = mKdTree.getVerticesDouble(); - ret = &ret[index*3]; - - return ret; - } - - NxU32 getVcount(void) const - { - return mKdTree.getVcount(); - } - - bool isDouble(void) const - { - return mUseDouble; - } - - - bool saveAsObj(const char *fname,NxU32 tcount,NxU32 *indices) - { - bool ret = false; - - - FILE *fph = fopen(fname,"wb"); - if ( fph ) - { - ret = true; - - NxU32 vcount = getVcount(); - if ( mUseDouble ) - { - const NxF64 *v = getVerticesDouble(); - for (NxU32 i=0; i(ret); -} - -fm_VertexIndex * fm_createVertexIndex(NxF32 granularity,bool snapToGrid) // create an indexed vertext system for floats -{ - MyVertexIndex *ret = MEMALLOC_NEW(MyVertexIndex)(granularity,snapToGrid); - return static_cast< fm_VertexIndex *>(ret); -} - -void fm_releaseVertexIndex(fm_VertexIndex *vindex) -{ - MyVertexIndex *m = static_cast< MyVertexIndex *>(vindex); - delete m; -} - -#endif // END OF VERTEX WELDING CODE - - -//********************************************************** -//********************************************************** -//**** LineSweep Line-Segment Intersection Code -//********************************************************** -//********************************************************** - -//#ifndef LINE_SWEEP_H -#if 0 - -#define LINE_SWEEP_H - -class fm_quickSort -{ -public: - void qsort(void **base,NxI32 num); // perform the qsort. -protected: - // -1 less, 0 equal, +1 greater. - virtual NxI32 compare(void **p1,void **p2) = 0; -private: - void inline swap(char **a,char **b); -}; - - -void fm_quickSort::swap(char **a,char **b) -{ - char *tmp; - - if ( a != b ) - { - tmp = *a; - *a++ = *b; - *b++ = tmp; - } -} - - -void fm_quickSort::qsort(void **b,NxI32 num) -{ - char *lo,*hi; - char *mid; - char *bottom, *top; - NxI32 size; - char *lostk[30], *histk[30]; - NxI32 stkptr; - char **base = (char **)b; - - if (num < 2 ) return; - - stkptr = 0; - - lo = (char *)base; - hi = (char *)base + sizeof(char **) * (num-1); - -nextone: - - size = (NxI32)(hi - lo) / sizeof(char**) + 1; - - mid = lo + (size / 2) * sizeof(char **); - swap((char **)mid,(char **)lo); - bottom = lo; - top = hi + sizeof(char **); - - for (;;) - { - do - { - bottom += sizeof(char **); - } while (bottom <= hi && compare((void **)bottom,(void **)lo) <= 0); - - do - { - top -= sizeof(char **); - } while (top > lo && compare((void **)top,(void **)lo) >= 0); - - if (top < bottom) break; - - swap((char **)bottom,(char **)top); - - } - - swap((char **)lo,(char **)top); - - if ( top - 1 - lo >= hi - bottom ) - { - if (lo + sizeof(char **) < top) - { - lostk[stkptr] = lo; - histk[stkptr] = top - sizeof(char **); - stkptr++; - } - if (bottom < hi) - { - lo = bottom; - goto nextone; - } - } - else - { - if ( bottom < hi ) - { - lostk[stkptr] = bottom; - histk[stkptr] = hi; - stkptr++; - } - if (lo + sizeof(char **) < top) - { - hi = top - sizeof(char **); - goto nextone; /* do small recursion */ - } - } - - stkptr--; - - if (stkptr >= 0) - { - lo = lostk[stkptr]; - hi = histk[stkptr]; - goto nextone; - } - return; -} - - -typedef CONVEX_DECOMPOSITION::Array< fm_LineSegment > LineSegmentVector; - -static inline void setMinMax(NxF64 &vmin,NxF64 &vmax,NxF64 v1,NxF64 v2) -{ - if ( v1 <= v2 ) - { - vmin = v1; - vmax = v2; - } - else - { - vmin = v2; - vmax = v1; - } -} - - -class Intersection -{ -public: - Intersection(void) - { - mIndex = 0; - mTime = 0; - } - Intersection(NxF64 time,const NxF64 *from,const NxF64 *to,fm_VertexIndex *vpool) - { - mTime = time; - NxF64 pos[3]; - pos[0] = (to[0]-from[0])*time+from[0]; - pos[1] = (to[1]-from[1])*time+from[1]; - pos[2] = (to[2]-from[2])*time+from[2]; - bool newPos; - mIndex = vpool->getIndex(pos,newPos); - } - - NxU32 mIndex; - NxF64 mTime; -}; - - -typedef CONVEX_DECOMPOSITION::Array< Intersection > IntersectionList; - -class MyLineSegment : public fm_LineSegment, public Memalloc -{ -public: - - void init(const fm_LineSegment &s,fm_VertexIndex *vpool,NxU32 x) - { - fm_LineSegment *dest = static_cast< fm_LineSegment *>(this); - *dest = s; - - mFlipped = false; - - const NxF64 *p1 = vpool->getVertexDouble(mE1); - const NxF64 *p2 = vpool->getVertexDouble(mE2); - - setMinMax(mMin[0],mMax[0],p1[0],p2[0]); - setMinMax(mMin[1],mMax[1],p1[1],p2[1]); - setMinMax(mMin[2],mMax[2],p1[2],p2[2]); - - if ( p1[x] <= p2[x] ) - { - mFrom[0] = p1[0]; - mFrom[1] = p1[1]; - mFrom[2] = p1[2]; - - mTo[0] = p2[0]; - mTo[1] = p2[1]; - mTo[2] = p2[2]; - } - else - { - mFrom[0] = p2[0]; - mFrom[1] = p2[1]; - mFrom[2] = p2[2]; - - mTo[0] = p1[0]; - mTo[1] = p1[1]; - mTo[2] = p1[2]; - - mFlipped = true; - - swap(mE1,mE2); - } - - } - - // we already know that the x-extent overlaps or we wouldn't be in this routine.. - void intersect(MyLineSegment *segment,NxU32 x,NxU32 y,NxU32 /* z */,fm_VertexIndex *vpool) - { - NxU32 count = 0; - - // if the two segments share any start/end points then they cannot intersect at all! - - if ( segment->mE1 == mE1 || segment->mE1 == mE2 ) count++; - if ( segment->mE2 == mE1 || segment->mE2 == mE2 ) count++; - - if ( count == 0 ) - { - if ( mMax[y] < segment->mMin[y] ) // no intersection... - { - - } - else if ( mMin[y] > segment->mMax[y] ) // no intersection - { - - } - else - { - - NxF64 a1[2]; - NxF64 a2[2]; - NxF64 b1[2]; - NxF64 b2[2]; - - a1[0] = mFrom[x]; - a1[1] = mFrom[y]; - - a2[0] = mTo[x]; - a2[1] = mTo[y]; - - b1[0] = segment->mFrom[x]; - b1[1] = segment->mFrom[y]; - - b2[0] = segment->mTo[x]; - b2[1] = segment->mTo[y]; - - - NxF64 t1,t2; - IntersectResult result = fm_intersectLineSegments2dTime(a1,a2,b1,b2,t1,t2); - - if ( result == IR_DO_INTERSECT ) - { - addIntersect(t1,vpool); - segment->addIntersect(t2,vpool); - } - - - } - } - } - - void addIntersect(NxF64 time,fm_VertexIndex *vpool) - { - Intersection intersect(time,mFrom,mTo,vpool); - - if ( mE1 == intersect.mIndex || mE2 == intersect.mIndex ) - { - //printf("Split too close to the beginning or the end of the line segment.\r\n"); - } - else - { - if ( mIntersections.empty() ) - { - mIntersections.pushBack(intersect); - } - else - { - IntersectionList::Iterator i; - for (i=mIntersections.begin(); i!=mIntersections.end(); ++i) - { - Intersection &it = (*i); - if ( it.mIndex == intersect.mIndex ) - { - //printf("Duplicate Intersection, throwing it away.\r\n"); - break; - } - else - { - if ( it.mTime > time ) - { -//*** TODO TODO TODO mIntersections.insert(i,intersect); - break; - } - } - } - if ( i==mIntersections.end() ) - { - mIntersections.pushBack(intersect); - } - } - } - } - - void getResults(LineSegmentVector &results) - { - if ( mIntersections.empty() ) - { - fm_LineSegment seg(mE1,mE2); - if ( mFlipped ) - { - swap(seg.mE1,seg.mE2); - } - results.pushBack(seg); - } - else - { - NxU32 prev = mE1; - IntersectionList::Iterator i; - for (i=mIntersections.begin(); i!=mIntersections.end(); ++i) - { - Intersection &it = (*i); - fm_LineSegment seg(prev,it.mIndex); - if ( mFlipped ) - { - swap(seg.mE1,seg.mE2); - } - results.pushBack(seg); - prev = it.mIndex; - } - fm_LineSegment seg(prev,mE2); - if ( mFlipped ) - { - swap(seg.mE1,seg.mE2); - } - results.pushBack(seg); - } - } - - void swap(NxU32 &a,NxU32 &b) - { - NxU32 temp = a; - a = b; - b = temp; - } - - bool mFlipped; - NxF64 mFrom[3]; - NxF64 mTo[3]; - NxF64 mMin[3]; - NxF64 mMax[3]; - IntersectionList mIntersections; -}; - -typedef CONVEX_DECOMPOSITION::Array< MyLineSegment > MyLineSegmentVector; - -class MyLineSweep : public fm_LineSweep, public fm_quickSort, public Memalloc -{ -public: - virtual ~MyLineSweep(void) - { - - } - fm_LineSegment * performLineSweep(const fm_LineSegment *segments,NxU32 icount,const NxF64 *planeEquation,fm_VertexIndex *pool,NxU32 &scount) - { - fm_LineSegment *ret = 0; - - FM_Axis axis = fm_getDominantAxis(planeEquation); - switch ( axis ) - { - case FM_XAXIS: - mX = 1; - mY = 2; - mZ = 0; - break; - case FM_YAXIS: - mX = 0; - mY = 2; - mZ = 1; - break; - case FM_ZAXIS: - mX = 0; - mY = 1; - mZ = 2; - break; - } - - - mResults.clear(); - scount = 0; - - MyLineSegment *mls = MEMALLOC_NEW(MyLineSegment)[icount]; - MyLineSegment **mptr = (MyLineSegment **)MEMALLOC_MALLOC(sizeof(MyLineSegment *)*icount); - - for (NxU32 i=0; imTo[mX]; - for (NxU32 j=i+1; jmFrom[mX] >= esegment ) - { - break; - } - else - { - test->intersect(segment,mX,mY,mZ,pool); - } - } - } - - for (NxU32 i=0; igetResults(mResults); - } - - - delete []mls; - MEMALLOC_FREE(mptr); - - if ( !mResults.empty() ) - { - scount = (NxU32)mResults.size(); - ret = &mResults[0]; - } - - return ret; - } - - NxI32 compare(void **p1,void **p2) - { - NxI32 ret = 0; - - MyLineSegment **m1 = (MyLineSegment **) p1; - MyLineSegment **m2 = (MyLineSegment **) p2; - - MyLineSegment *s1 = *m1; - MyLineSegment *s2 = *m2; - - if ( s1->mFrom[mX] < s2->mFrom[mX] ) - ret = -1; - else if ( s1->mFrom[mX] > s2->mFrom[mX] ) - ret = 1; - else if ( s1->mFrom[mY] < s2->mFrom[mY] ) - ret = -1; - else if ( s1->mFrom[mY] > s2->mFrom[mY] ) - ret = 1; - - return ret; - } - - NxU32 mX; // index for the x-axis - NxU32 mY; // index for the y-axis - NxU32 mZ; - fm_VertexIndex *mfm_VertexIndex; - LineSegmentVector mResults; -}; - - -fm_LineSweep * fm_createLineSweep(void) -{ - MyLineSweep *mls = MEMALLOC_NEW(MyLineSweep); - return static_cast< fm_LineSweep *>(mls); -} - -void fm_releaseLineSweep(fm_LineSweep *sweep) -{ - MyLineSweep *mls = static_cast< MyLineSweep *>(sweep); - delete mls; -} - - - -#endif // End of LineSweep code - - - - -REAL fm_computeBestFitAABB(NxU32 vcount,const REAL *points,NxU32 pstride,REAL *bmin,REAL *bmax) // returns the diagonal distance -{ - - const NxU8 *source = (const NxU8 *) points; - - bmin[0] = points[0]; - bmin[1] = points[1]; - bmin[2] = points[2]; - - bmax[0] = points[0]; - bmax[1] = points[1]; - bmax[2] = points[2]; - - - for (NxU32 i=1; i bmax[0] ) bmax[0] = p[0]; - if ( p[1] > bmax[1] ) bmax[1] = p[1]; - if ( p[2] > bmax[2] ) bmax[2] = p[2]; - - } - - REAL dx = bmax[0] - bmin[0]; - REAL dy = bmax[1] - bmin[1]; - REAL dz = bmax[2] - bmin[2]; - - return (REAL) sqrt( dx*dx + dy*dy + dz*dz ); - -} - - - -/* a = b - c */ -#define vector(a,b,c) \ - (a)[0] = (b)[0] - (c)[0]; \ - (a)[1] = (b)[1] - (c)[1]; \ - (a)[2] = (b)[2] - (c)[2]; - - - -#define innerProduct(v,q) \ - ((v)[0] * (q)[0] + \ - (v)[1] * (q)[1] + \ - (v)[2] * (q)[2]) - -#define crossProduct(a,b,c) \ - (a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \ - (a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \ - (a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1]; - - -bool fm_lineIntersectsTriangle(const REAL *rayStart,const REAL *rayEnd,const REAL *p1,const REAL *p2,const REAL *p3,REAL *sect) -{ - REAL dir[3]; - - dir[0] = rayEnd[0] - rayStart[0]; - dir[1] = rayEnd[1] - rayStart[1]; - dir[2] = rayEnd[2] - rayStart[2]; - - REAL d = (REAL)sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); - REAL r = 1.0f / d; - - dir[0]*=r; - dir[1]*=r; - dir[2]*=r; - - - REAL t; - - bool ret = fm_rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t ); - - if ( ret ) - { - if ( t > d ) - { - sect[0] = rayStart[0] + dir[0]*t; - sect[1] = rayStart[1] + dir[1]*t; - sect[2] = rayStart[2] + dir[2]*t; - } - else - { - ret = false; - } - } - - return ret; -} - - - -bool fm_rayIntersectsTriangle(const REAL *p,const REAL *d,const REAL *v0,const REAL *v1,const REAL *v2,REAL &t) -{ - REAL e1[3],e2[3],h[3],s[3],q[3]; - REAL a,f,u,v; - - vector(e1,v1,v0); - vector(e2,v2,v0); - crossProduct(h,d,e2); - a = innerProduct(e1,h); - - if (a > -0.00001 && a < 0.00001) - return(false); - - f = 1/a; - vector(s,p,v0); - u = f * (innerProduct(s,h)); - - if (u < 0.0 || u > 1.0) - return(false); - - crossProduct(q,s,e1); - v = f * innerProduct(d,q); - if (v < 0.0 || u + v > 1.0) - return(false); - // at this stage we can compute t to find out where - // the intersection point is on the line - t = f * innerProduct(e2,q); - if (t > 0) // ray intersection - return(true); - else // this means that there is a line intersection - // but not a ray intersection - return (false); -} - - -inline REAL det(const REAL *p1,const REAL *p2,const REAL *p3) -{ - return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2]; -} - - -REAL fm_computeMeshVolume(const REAL *vertices,NxU32 tcount,const NxU32 *indices) -{ - REAL volume = 0; - - for (NxU32 i=0; i= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); -} - - -REAL fm_areaPolygon2d(NxU32 pcount,const REAL *points,NxU32 pstride) -{ - NxI32 n = (NxI32)pcount; - - REAL A=0.0f; - for(NxI32 p=n-1,q=0; q= y || y2 < y && y1 >= y ) - { - if (x1+(y-y1)/(y2-y1)*(x2-x1)= 3 ) - { - const REAL *prev = fm_getPoint(points,pstride,pcount-1); - const REAL *current = points; - const REAL *next = fm_getPoint(points,pstride,1); - REAL *dest = _dest; - - for (NxU32 i=0; i class Rect3d -{ -public: - Rect3d(void) { }; - - Rect3d(const T *bmin,const T *bmax) - { - - mMin[0] = bmin[0]; - mMin[1] = bmin[1]; - mMin[2] = bmin[2]; - - mMax[0] = bmax[0]; - mMax[1] = bmax[1]; - mMax[2] = bmax[2]; - - } - - void SetMin(const T *bmin) - { - mMin[0] = bmin[0]; - mMin[1] = bmin[1]; - mMin[2] = bmin[2]; - } - - void SetMax(const T *bmax) - { - mMax[0] = bmax[0]; - mMax[1] = bmax[1]; - mMax[2] = bmax[2]; - } - - void SetMin(T x,T y,T z) - { - mMin[0] = x; - mMin[1] = y; - mMin[2] = z; - } - - void SetMax(T x,T y,T z) - { - mMax[0] = x; - mMax[1] = y; - mMax[2] = z; - } - - T mMin[3]; - T mMax[3]; -}; - -#endif - -void splitRect(NxU32 axis, - const Rect3d &source, - Rect3d &b1, - Rect3d &b2, - const REAL *midpoint) -{ - switch ( axis ) - { - case 0: - b1.SetMin(source.mMin); - b1.SetMax( midpoint[0], source.mMax[1], source.mMax[2] ); - - b2.SetMin( midpoint[0], source.mMin[1], source.mMin[2] ); - b2.SetMax(source.mMax); - - break; - case 1: - b1.SetMin(source.mMin); - b1.SetMax( source.mMax[0], midpoint[1], source.mMax[2] ); - - b2.SetMin( source.mMin[0], midpoint[1], source.mMin[2] ); - b2.SetMax(source.mMax); - - break; - case 2: - b1.SetMin(source.mMin); - b1.SetMax( source.mMax[0], source.mMax[1], midpoint[2] ); - - b2.SetMin( source.mMin[0], source.mMin[1], midpoint[2] ); - b2.SetMax(source.mMax); - - break; - } -} - -bool fm_computeSplitPlane(NxU32 vcount, - const REAL *vertices, - NxU32 /* tcount */, - const NxU32 * /* indices */, - REAL *plane) -{ - - REAL sides[3]; - REAL matrix[16]; - - fm_computeBestFitOBB( vcount, vertices, sizeof(REAL)*3, sides, matrix ); - - REAL bmax[3]; - REAL bmin[3]; - - bmax[0] = sides[0]*0.5f; - bmax[1] = sides[1]*0.5f; - bmax[2] = sides[2]*0.5f; - - bmin[0] = -bmax[0]; - bmin[1] = -bmax[1]; - bmin[2] = -bmax[2]; - - - REAL dx = sides[0]; - REAL dy = sides[1]; - REAL dz = sides[2]; - - - REAL laxis = dx; - - NxU32 axis = 0; - - if ( dy > dx ) - { - axis = 1; - laxis = dy; - } - - if ( dz > dx && dz > dy ) - { - axis = 2; - laxis = dz; - } - - REAL p1[3]; - REAL p2[3]; - REAL p3[3]; - - p3[0] = p2[0] = p1[0] = bmin[0] + dx*0.5f; - p3[1] = p2[1] = p1[1] = bmin[1] + dy*0.5f; - p3[2] = p2[2] = p1[2] = bmin[2] + dz*0.5f; - - Rect3d b(bmin,bmax); - - Rect3d b1,b2; - - splitRect(axis,b,b1,b2,p1); - - - switch ( axis ) - { - case 0: - p2[1] = bmin[1]; - p2[2] = bmin[2]; - - if ( dz > dy ) - { - p3[1] = bmax[1]; - p3[2] = bmin[2]; - } - else - { - p3[1] = bmin[1]; - p3[2] = bmax[2]; - } - - break; - case 1: - p2[0] = bmin[0]; - p2[2] = bmin[2]; - - if ( dx > dz ) - { - p3[0] = bmax[0]; - p3[2] = bmin[2]; - } - else - { - p3[0] = bmin[0]; - p3[2] = bmax[2]; - } - - break; - case 2: - p2[0] = bmin[0]; - p2[1] = bmin[1]; - - if ( dx > dy ) - { - p3[0] = bmax[0]; - p3[1] = bmin[1]; - } - else - { - p3[0] = bmin[0]; - p3[1] = bmax[1]; - } - - break; - } - - REAL tp1[3]; - REAL tp2[3]; - REAL tp3[3]; - - fm_transform(matrix,p1,tp1); - fm_transform(matrix,p2,tp2); - fm_transform(matrix,p3,tp3); - - plane[3] = fm_computePlane(tp1,tp2,tp3,plane); - - return true; - -} - -#pragma warning(disable:4100) - -void fm_nearestPointInTriangle(const REAL *nearestPoint,const REAL *p1,const REAL *p2,const REAL *p3,REAL *nearest) -{ - -} - -static REAL Partial(const REAL *a,const REAL *p) -{ - return (a[0]*p[1]) - (p[0]*a[1]); -} - -REAL fm_areaTriangle(const REAL *p0,const REAL *p1,const REAL *p2) -{ - REAL A = Partial(p0,p1); - A+= Partial(p1,p2); - A+= Partial(p2,p0); - return A*0.5f; -} - -void fm_subtract(const REAL *A,const REAL *B,REAL *diff) // compute A-B and store the result in 'diff' -{ - diff[0] = A[0]-B[0]; - diff[1] = A[1]-B[1]; - diff[2] = A[2]-B[2]; -} - - -void fm_multiplyTransform(const REAL *pA,const REAL *pB,REAL *pM) -{ - - REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; - REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; - REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; - REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; - - REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; - REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; - REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; - REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; - - REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; - REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; - REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; - REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; - - REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; - REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; - REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; - REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; - - pM[0] = a; pM[1] = b; pM[2] = c; pM[3] = d; - - pM[4] = e; pM[5] = f; pM[6] = g; pM[7] = h; - - pM[8] = i; pM[9] = j; pM[10] = k; pM[11] = l; - - pM[12] = m; pM[13] = n; pM[14] = o; pM[15] = p; -} - -void fm_multiply(REAL *A,REAL scaler) -{ - A[0]*=scaler; - A[1]*=scaler; - A[2]*=scaler; -} - -void fm_add(const REAL *A,const REAL *B,REAL *sum) -{ - sum[0] = A[0]+B[0]; - sum[1] = A[1]+B[1]; - sum[2] = A[2]+B[2]; -} - -void fm_copy3(const REAL *source,REAL *dest) -{ - dest[0] = source[0]; - dest[1] = source[1]; - dest[2] = source[2]; -} - - -NxU32 fm_copyUniqueVertices(NxU32 vcount,const REAL *input_vertices,REAL *output_vertices,NxU32 tcount,const NxU32 *input_indices,NxU32 *output_indices) -{ - NxU32 ret = 0; - - REAL *vertices = (REAL *)MEMALLOC_MALLOC(sizeof(REAL)*vcount*3); - memcpy(vertices,input_vertices,sizeof(REAL)*vcount*3); - REAL *dest = output_vertices; - - NxU32 *reindex = (NxU32 *)MEMALLOC_MALLOC(sizeof(NxU32)*vcount); - memset(reindex,0xFF,sizeof(NxU32)*vcount); - - NxU32 icount = tcount*3; - - for (NxU32 i=0; i 0 ) - { - NxU32 i1 = indices[0]; - NxU32 i2 = indices[1]; - NxU32 i3 = indices[2]; - const REAL *p1 = &vertices[i1*3]; - const REAL *p2 = &vertices[i2*3]; - const REAL *p3 = &vertices[i3*3]; - REAL plane[4]; - plane[3] = fm_computePlane(p1,p2,p3,plane); - const NxU32 *scan = &indices[3]; - for (NxU32 i=1; i= dmin && dot <= dmax ) - { - ret = true; // then the plane equation is for practical purposes identical. - } - } - - return ret; -} - - -void fm_initMinMax(REAL bmin[3],REAL bmax[3]) -{ - bmin[0] = FLT_MAX; - bmin[1] = FLT_MAX; - bmin[2] = FLT_MAX; - bmax[0] = FLT_MIN; - bmax[1] = FLT_MIN; - bmax[2] = FLT_MIN; -} - - -#ifndef TESSELATE_H - -#define TESSELATE_H - -typedef CONVEX_DECOMPOSITION::Array< NxU32 > UintVector; - -class Myfm_Tesselate : public fm_Tesselate, public Memalloc -{ -public: - virtual ~Myfm_Tesselate(void) - { - - } - - const NxU32 * tesselate(fm_VertexIndex *vindex,NxU32 tcount,const NxU32 *indices,NxF32 longEdge,NxU32 maxDepth,NxU32 &outcount) - { - const NxU32 *ret = 0; - - mMaxDepth = maxDepth; - mLongEdge = longEdge*longEdge; - mLongEdgeD = mLongEdge; - mVertices = vindex; - - if ( mVertices->isDouble() ) - { - NxU32 vcount = mVertices->getVcount(); - NxF64 *vertices = (NxF64 *)MEMALLOC_MALLOC(sizeof(NxF64)*vcount*3); - memcpy(vertices,mVertices->getVerticesDouble(),sizeof(NxF64)*vcount*3); - - for (NxU32 i=0; igetVcount(); - NxF32 *vertices = (NxF32 *)MEMALLOC_MALLOC(sizeof(NxF32)*vcount*3); - memcpy(vertices,mVertices->getVerticesFloat(),sizeof(NxF32)*vcount*3); - - - for (NxU32 i=0; i mLongEdge || l2 > mLongEdge || l3 > mLongEdge ) - split = true; - - } - - if ( split ) - { - NxU32 edge; - - if ( l1 >= l2 && l1 >= l3 ) - edge = 0; - else if ( l2 >= l1 && l2 >= l3 ) - edge = 1; - else - edge = 2; - - NxF32 split[3]; - - switch ( edge ) - { - case 0: - { - fm_lerp(p1,p2,split,0.5f); - tesselate(p1,split,p3, recurse+1 ); - tesselate(split,p2,p3, recurse+1 ); - } - break; - case 1: - { - fm_lerp(p2,p3,split,0.5f); - tesselate(p1,p2,split, recurse+1 ); - tesselate(p1,split,p3, recurse+1 ); - } - break; - case 2: - { - fm_lerp(p3,p1,split,0.5f); - tesselate(p1,p2,split, recurse+1 ); - tesselate(split,p2,p3, recurse+1 ); - } - break; - } - } - else - { - bool newp; - - NxU32 i1 = mVertices->getIndex(p1,newp); - NxU32 i2 = mVertices->getIndex(p2,newp); - NxU32 i3 = mVertices->getIndex(p3,newp); - - mIndices.pushBack(i1); - mIndices.pushBack(i2); - mIndices.pushBack(i3); - } - - } - - void tesselate(const NxF64 *p1,const NxF64 *p2,const NxF64 *p3,NxU32 recurse) - { - bool split = false; - NxF64 l1,l2,l3; - - l1 = l2 = l3 = 0; - - if ( recurse < mMaxDepth ) - { - l1 = fm_distanceSquared(p1,p2); - l2 = fm_distanceSquared(p2,p3); - l3 = fm_distanceSquared(p3,p1); - - if ( l1 > mLongEdgeD || l2 > mLongEdgeD || l3 > mLongEdgeD ) - split = true; - - } - - if ( split ) - { - NxU32 edge; - - if ( l1 >= l2 && l1 >= l3 ) - edge = 0; - else if ( l2 >= l1 && l2 >= l3 ) - edge = 1; - else - edge = 2; - - NxF64 split[3]; - - switch ( edge ) - { - case 0: - { - fm_lerp(p1,p2,split,0.5); - tesselate(p1,split,p3, recurse+1 ); - tesselate(split,p2,p3, recurse+1 ); - } - break; - case 1: - { - fm_lerp(p2,p3,split,0.5); - tesselate(p1,p2,split, recurse+1 ); - tesselate(p1,split,p3, recurse+1 ); - } - break; - case 2: - { - fm_lerp(p3,p1,split,0.5); - tesselate(p1,p2,split, recurse+1 ); - tesselate(split,p2,p3, recurse+1 ); - } - break; - } - } - else - { - bool newp; - - NxU32 i1 = mVertices->getIndex(p1,newp); - NxU32 i2 = mVertices->getIndex(p2,newp); - NxU32 i3 = mVertices->getIndex(p3,newp); - - mIndices.pushBack(i1); - mIndices.pushBack(i2); - mIndices.pushBack(i3); - } - - } - -private: - NxF32 mLongEdge; - NxF64 mLongEdgeD; - fm_VertexIndex *mVertices; - UintVector mIndices; - NxU32 mMaxDepth; -}; - -fm_Tesselate * fm_createTesselate(void) -{ - Myfm_Tesselate *m = MEMALLOC_NEW(Myfm_Tesselate); - return static_cast< fm_Tesselate * >(m); -} - -void fm_releaseTesselate(fm_Tesselate *t) -{ - Myfm_Tesselate *m = static_cast< Myfm_Tesselate *>(t); - delete m; -} - -#endif - - -#ifndef RAY_ABB_INTERSECT - -#define RAY_ABB_INTERSECT - -//! Integer representation of a floating-point value. -#define IR(x) ((NxU32&)x) - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -/** -* A method to compute a ray-AABB intersection. -* Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 -* Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) -* Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) -* -* Hence this version is faster as well as more robust than the original one. -* -* Should work provided: -* 1) the integer representation of 0.0f is 0x00000000 -* 2) the sign bit of the NxF32 is the most significant one -* -* Report bugs: p.terdiman@codercorner.com -* -* \param aabb [in] the axis-aligned bounding box -* \param origin [in] ray origin -* \param dir [in] ray direction -* \param coord [out] impact coordinates -* \return true if ray intersects AABB -*/ -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -#define RAYAABB_EPSILON 0.00001f -bool fm_intersectRayAABB(const NxF32 MinB[3],const NxF32 MaxB[3],const NxF32 origin[3],const NxF32 dir[3],NxF32 coord[3]) -{ - bool Inside = true; - NxF32 MaxT[3]; - MaxT[0]=MaxT[1]=MaxT[2]=-1.0f; - - // Find candidate planes. - for(NxU32 i=0;i<3;i++) - { - if(origin[i] < MinB[i]) - { - coord[i] = MinB[i]; - Inside = false; - - // Calculate T distances to candidate planes - if(IR(dir[i])) MaxT[i] = (MinB[i] - origin[i]) / dir[i]; - } - else if(origin[i] > MaxB[i]) - { - coord[i] = MaxB[i]; - Inside = false; - - // Calculate T distances to candidate planes - if(IR(dir[i])) MaxT[i] = (MaxB[i] - origin[i]) / dir[i]; - } - } - - // Ray origin inside bounding box - if(Inside) - { - coord[0] = origin[0]; - coord[1] = origin[1]; - coord[2] = origin[2]; - return true; - } - - // Get largest of the maxT's for final choice of intersection - NxU32 WhichPlane = 0; - if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1; - if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; - - // Check final candidate actually inside box - if(IR(MaxT[WhichPlane])&0x80000000) return false; - - for(NxU32 i=0;i<3;i++) - { - if(i!=WhichPlane) - { - coord[i] = origin[i] + MaxT[WhichPlane] * dir[i]; -#ifdef RAYAABB_EPSILON - if(coord[i] < MinB[i] - RAYAABB_EPSILON || coord[i] > MaxB[i] + RAYAABB_EPSILON) return false; -#else - if(coord[i] < MinB[i] || coord[i] > MaxB[i]) return false; -#endif - } - } - return true; // ray hits box -} - -bool fm_intersectLineSegmentAABB(const NxF32 bmin[3],const NxF32 bmax[3],const NxF32 p1[3],const NxF32 p2[3],NxF32 intersect[3]) -{ - bool ret = false; - - NxF32 dir[3]; - dir[0] = p2[0] - p1[0]; - dir[1] = p2[1] - p1[1]; - dir[2] = p2[2] - p1[2]; - NxF32 dist = fm_normalize(dir); - if ( dist > RAYAABB_EPSILON ) - { - ret = fm_intersectRayAABB(bmin,bmax,p1,dir,intersect); - if ( ret ) - { - NxF32 d = fm_distanceSquared(p1,intersect); - if ( d > (dist*dist) ) - { - ret = false; - } - } - } - return ret; -} - -#endif - -#ifndef OBB_TO_AABB - -#define OBB_TO_AABB - -#pragma warning(disable:4100) -void fm_OBBtoAABB(const NxF32 obmin[3],const NxF32 obmax[3],const NxF32 matrix[16],NxF32 abmin[3],NxF32 abmax[3]) -{ - assert(0); // not yet implemented. -} - - -const REAL * computePos(NxU32 index,const REAL *vertices,NxU32 vstride) -{ - const char *tmp = (const char *)vertices; - tmp+=(index*vstride); - return (const REAL*)tmp; -} - -void computeNormal(NxU32 index,REAL *normals,NxU32 nstride,const REAL *normal) -{ - char *tmp = (char *)normals; - tmp+=(index*nstride); - REAL *dest = (REAL *)tmp; - dest[0]+=normal[0]; - dest[1]+=normal[1]; - dest[2]+=normal[2]; -} - -void fm_computeMeanNormals(NxU32 vcount, // the number of vertices - const REAL *vertices, // the base address of the vertex position data. - NxU32 vstride, // the stride between position data. - REAL *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 -{ - - // Step #1 : Zero out the vertex normals - char *dest = (char *)normals; - for (NxU32 i=0; ixmax[0]) - Copy(xmax,caller_p); - if (caller_p[1]ymax[1]) - Copy(ymax,caller_p); - if (caller_p[2]zmax[2]) - Copy(zmax,caller_p); - - scan+=pstride; - } - - /* Set xspan = distance between the 2 points xmin & xmax (squared) */ - REAL dx = xmax[0] - xmin[0]; - REAL dy = xmax[1] - xmin[1]; - REAL dz = xmax[2] - xmin[2]; - REAL xspan = dx*dx + dy*dy + dz*dz; - - /* Same for y & z spans */ - dx = ymax[0] - ymin[0]; - dy = ymax[1] - ymin[1]; - dz = ymax[2] - ymin[2]; - REAL yspan = dx*dx + dy*dy + dz*dz; - - dx = zmax[0] - zmin[0]; - dy = zmax[1] - zmin[1]; - dz = zmax[2] - zmin[2]; - REAL zspan = dx*dx + dy*dy + dz*dz; - - /* Set points dia1 & dia2 to the maximally separated pair */ - Copy(dia1,xmin); - Copy(dia2,xmax); /* assume xspan biggest */ - REAL maxspan = xspan; - - if (yspan>maxspan) - { - maxspan = yspan; - Copy(dia1,ymin); - Copy(dia2,ymax); - } - - if (zspan>maxspan) - { - Copy(dia1,zmin); - Copy(dia2,zmax); - } - - - /* dia1,dia2 is a diameter of initial sphere */ - /* calc initial center */ - center[0] = (dia1[0]+dia2[0])*0.5f; - center[1] = (dia1[1]+dia2[1])*0.5f; - center[2] = (dia1[2]+dia2[2])*0.5f; - - /* calculate initial radius**2 and radius */ - - dx = dia2[0]-center[0]; /* x component of radius vector */ - dy = dia2[1]-center[1]; /* y component of radius vector */ - dz = dia2[2]-center[2]; /* z component of radius vector */ - - radius2 = dx*dx + dy*dy + dz*dz; - radius = REAL(sqrt(radius2)); - - /* SECOND PASS: increment current sphere */ - { - const char *scan = (const char *)points; - for (NxU32 i=0; i radius2) /* do r**2 test first */ - { /* this point is outside of current sphere */ - REAL old_to_p = REAL(sqrt(old_to_p_sq)); - /* calc radius of new sphere */ - radius = (radius + old_to_p) * 0.5f; - radius2 = radius*radius; /* for next r**2 compare */ - REAL old_to_new = old_to_p - radius; - - /* calc center of new sphere */ - - REAL recip = 1.0f /old_to_p; - - REAL cx = (radius*center[0] + old_to_new*caller_p[0]) * recip; - REAL cy = (radius*center[1] + old_to_new*caller_p[1]) * recip; - REAL cz = (radius*center[2] + old_to_new*caller_p[2]) * recip; - - Set(center,cx,cy,cz); - - scan+=pstride; - } - } - } - - return radius; -} - - -void fm_computeBestFitCapsule(NxU32 vcount,const REAL *points,NxU32 pstride,REAL &radius,REAL &height,REAL matrix[16],bool bruteForce) -{ - REAL sides[3]; - REAL omatrix[16]; - fm_computeBestFitOBB(vcount,points,pstride,sides,omatrix,bruteForce); - - NxI32 axis = 0; - if ( sides[0] > sides[1] && sides[0] > sides[2] ) - axis = 0; - else if ( sides[1] > sides[0] && sides[1] > sides[2] ) - axis = 1; - else - axis = 2; - - REAL localTransform[16]; - - REAL maxDist = 0; - REAL maxLen = 0; - - switch ( axis ) - { - case 0: - { - fm_eulerMatrix(0,0,FM_PI/2,localTransform); - fm_matrixMultiply(localTransform,omatrix,matrix); - - const NxU8 *scan = (const NxU8 *)points; - for (NxU32 i=0; i maxDist ) - { - maxDist = dist; - } - REAL l = (REAL) fabs(t[0]); - if ( l > maxLen ) - { - maxLen = l; - } - scan+=pstride; - } - } - height = sides[0]; - break; - case 1: - { - fm_eulerMatrix(0,FM_PI/2,0,localTransform); - fm_matrixMultiply(localTransform,omatrix,matrix); - - const NxU8 *scan = (const NxU8 *)points; - for (NxU32 i=0; i maxDist ) - { - maxDist = dist; - } - REAL l = (REAL) fabs(t[1]); - if ( l > maxLen ) - { - maxLen = l; - } - scan+=pstride; - } - } - height = sides[1]; - break; - case 2: - { - fm_eulerMatrix(FM_PI/2,0,0,localTransform); - fm_matrixMultiply(localTransform,omatrix,matrix); - - const NxU8 *scan = (const NxU8 *)points; - for (NxU32 i=0; i maxDist ) - { - maxDist = dist; - } - REAL l = (REAL) fabs(t[2]); - if ( l > maxLen ) - { - maxLen = l; - } - scan+=pstride; - } - } - height = sides[2]; - break; - } - radius = (REAL)sqrt(maxDist); - height = (maxLen*2)-(radius*2); -} - - -//************* Triangulation - -#ifndef TRIANGULATE_H - -#define TRIANGULATE_H - -typedef NxU32 TU32; - -class TVec -{ -public: - TVec(NxF64 _x,NxF64 _y,NxF64 _z) { x = _x; y = _y; z = _z; }; - TVec(void) { }; - - NxF64 x; - NxF64 y; - NxF64 z; -}; - -typedef CONVEX_DECOMPOSITION::Array< TVec > TVecVector; -typedef CONVEX_DECOMPOSITION::Array< TU32 > TU32Vector; - -class CTriangulator -{ -public: - /// Default constructor - CTriangulator(); - - /// Default destructor - virtual ~CTriangulator(); - - /// Triangulates the contour - void triangulate(TU32Vector &indices); - - /// Returns the given point in the triangulator array - inline TVec get(const TU32 id) { return mPoints[id]; } - - virtual void reset(void) - { - mInputPoints.clear(); - mPoints.clear(); - mIndices.clear(); - } - - virtual void addPoint(NxF64 x,NxF64 y,NxF64 z) - { - TVec v(x,y,z); - // update bounding box... - if ( mInputPoints.empty() ) - { - mMin = v; - mMax = v; - } - else - { - if ( x < mMin.x ) mMin.x = x; - if ( y < mMin.y ) mMin.y = y; - if ( z < mMin.z ) mMin.z = z; - - if ( x > mMax.x ) mMax.x = x; - if ( y > mMax.y ) mMax.y = y; - if ( z > mMax.z ) mMax.z = z; - } - mInputPoints.pushBack(v); - } - - // Triangulation happens in 2d. We could inverse transform the polygon around the normal direction, or we just use the two most signficant axes - // Here we find the two longest axes and use them to triangulate. Inverse transforming them would introduce more doubleing point error and isn't worth it. - virtual NxU32 * triangulate(NxU32 &tcount,NxF64 epsilon) - { - NxU32 *ret = 0; - tcount = 0; - mEpsilon = epsilon; - - if ( !mInputPoints.empty() ) - { - mPoints.clear(); - - NxF64 dx = mMax.x - mMin.x; // locate the first, second and third longest edges and store them in i1, i2, i3 - NxF64 dy = mMax.y - mMin.y; - NxF64 dz = mMax.z - mMin.z; - - NxU32 i1,i2,i3; - - if ( dx > dy && dx > dz ) - { - i1 = 0; - if ( dy > dz ) - { - i2 = 1; - i3 = 2; - } - else - { - i2 = 2; - i3 = 1; - } - } - else if ( dy > dx && dy > dz ) - { - i1 = 1; - if ( dx > dz ) - { - i2 = 0; - i3 = 2; - } - else - { - i2 = 2; - i3 = 0; - } - } - else - { - i1 = 2; - if ( dx > dy ) - { - i2 = 0; - i3 = 1; - } - else - { - i2 = 1; - i3 = 0; - } - } - - NxU32 pcount = (NxU32)mInputPoints.size(); - const NxF64 *points = &mInputPoints[0].x; - for (NxU32 i=0; i 2;) - { - if (0 >= (count--)) - return; - - NxI32 u = v; - if (nv <= u) - u = 0; - v = u + 1; - if (nv <= v) - v = 0; - NxI32 w = v + 1; - if (nv <= w) - w = 0; - - if (_snip(u, v, w, nv, V)) - { - NxI32 a, b, c, s, t; - a = V[u]; - b = V[v]; - c = V[w]; - if ( flipped ) - { - indices.pushBack(a); - indices.pushBack(b); - indices.pushBack(c); - } - else - { - indices.pushBack(c); - indices.pushBack(b); - indices.pushBack(a); - } - m++; - for (s = v, t = v + 1; t < nv; s++, t++) - V[s] = V[t]; - nv--; - count = 2 * nv; - } - } - - MEMALLOC_FREE(V); -} - -/// Returns the area of the contour -NxF64 CTriangulator::_area() -{ - NxI32 n = (NxU32)mPoints.size(); - NxF64 A = 0.0f; - for (NxI32 p = n - 1, q = 0; q < n; p = q++) - { - const TVec &pval = mPoints[p]; - const TVec &qval = mPoints[q]; - A += pval.x * qval.y - qval.x * pval.y; - } - A*=0.5f; - return A; -} - -bool CTriangulator::_snip(NxI32 u, NxI32 v, NxI32 w, NxI32 n, NxI32 *V) -{ - NxI32 p; - - const TVec &A = mPoints[ V[u] ]; - const TVec &B = mPoints[ V[v] ]; - const TVec &C = mPoints[ V[w] ]; - - if (mEpsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))) ) - return false; - - for (p = 0; p < n; p++) - { - if ((p == u) || (p == v) || (p == w)) - continue; - const TVec &P = mPoints[ V[p] ]; - if (_insideTriangle(A, B, C, P)) - return false; - } - return true; -} - -/// Tests if a point is inside the given triangle -bool CTriangulator::_insideTriangle(const TVec& A, const TVec& B, const TVec& C,const TVec& P) -{ - NxF64 ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; - NxF64 cCROSSap, bCROSScp, aCROSSbp; - - ax = C.x - B.x; ay = C.y - B.y; - bx = A.x - C.x; by = A.y - C.y; - cx = B.x - A.x; cy = B.y - A.y; - apx = P.x - A.x; apy = P.y - A.y; - bpx = P.x - B.x; bpy = P.y - B.y; - cpx = P.x - C.x; cpy = P.y - C.y; - - aCROSSbp = ax * bpy - ay * bpx; - cCROSSap = cx * apy - cy * apx; - bCROSScp = bx * cpy - by * cpx; - - return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); -} - -class Triangulate : public fm_Triangulate, public Memalloc -{ -public: - Triangulate(void) - { - mPointsFloat = 0; - mPointsDouble = 0; - } - - virtual ~Triangulate(void) - { - reset(); - } - void reset(void) - { - MEMALLOC_FREE(mPointsFloat); - MEMALLOC_FREE(mPointsDouble); - mPointsFloat = 0; - mPointsDouble = 0; - } - - virtual const NxF64 * triangulate3d(NxU32 pcount, - const NxF64 *_points, - NxU32 vstride, - NxU32 &tcount, - bool consolidate, - NxF64 epsilon) - { - reset(); - - NxF64 *points = (NxF64 *)MEMALLOC_MALLOC(sizeof(NxF64)*pcount*3); - if ( consolidate ) - { - pcount = fm_consolidatePolygon(pcount,_points,vstride,points,1-epsilon); - } - else - { - NxF64 *dest = points; - for (NxU32 i=0; i= 3 ) - { - CTriangulator ct; - for (NxU32 i=0; i(t); -} - -void fm_releaseTriangulate(fm_Triangulate *t) -{ - Triangulate *tt = static_cast< Triangulate *>(t); - delete tt; -} - -#endif - -bool validDistance(const REAL *p1,const REAL *p2,REAL epsilon) -{ - bool ret = true; - - REAL dx = p1[0] - p2[0]; - REAL dy = p1[1] - p2[1]; - REAL dz = p1[2] - p2[2]; - REAL dist = dx*dx+dy*dy+dz*dz; - if ( dist < (epsilon*epsilon) ) - { - ret = false; - } - return ret; -} - -bool fm_isValidTriangle(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) -{ - bool ret = false; - - if ( validDistance(p1,p2,epsilon) && - validDistance(p1,p3,epsilon) && - validDistance(p2,p3,epsilon) ) - { - - REAL area = fm_computeArea(p1,p2,p3); - if ( area > epsilon ) - { - REAL _vertices[3*3],vertices[64*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]; - - NxU32 pcount = fm_consolidatePolygon(3,_vertices,sizeof(REAL)*3,vertices,1-epsilon); - if ( pcount == 3 ) - { - ret = true; - } - } - } - return ret; -} - - -void fm_multiplyQuat(const REAL *left,const REAL *right,REAL *quat) -{ - REAL a,b,c,d; - - a = left[3]*right[3] - left[0]*right[0] - left[1]*right[1] - left[2]*right[2]; - b = left[3]*right[0] + right[3]*left[0] + left[1]*right[2] - right[1]*left[2]; - c = left[3]*right[1] + right[3]*left[1] + left[2]*right[0] - right[2]*left[0]; - d = left[3]*right[2] + right[3]*left[2] + left[0]*right[1] - right[0]*left[1]; - - quat[3] = a; - quat[0] = b; - quat[1] = c; - quat[2] = d; -} - -}; // end of namespace diff --git a/Engine/lib/convexDecomp/NvHashMap.h b/Engine/lib/convexDecomp/NvHashMap.h deleted file mode 100644 index c8dfd7877..000000000 --- a/Engine/lib/convexDecomp/NvHashMap.h +++ /dev/null @@ -1,1905 +0,0 @@ -/* - -NvHashMap.h : A simple hash map and array template class to avoid introducing dependencies on the STL for containers. - -*/ - - -// This code contains NVIDIA Confidential Information and is disclosed -// under the Mutual Non-Disclosure Agreement. -// -// Notice -// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES -// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO -// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, -// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. -// -// Information and code furnished is believed to be accurate and reliable. -// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such -// information or for any infringement of patents or other rights of third parties that may -// result from its use. No license is granted by implication or otherwise under any patent -// or patent rights of NVIDIA Corporation. Details are subject to change without notice. -// This code supersedes and replaces all information previously supplied. -// NVIDIA Corporation products are not authorized for use as critical -// components in life support devices or systems without express written approval of -// NVIDIA Corporation. -// -// Copyright � 2009 NVIDIA Corporation. All rights reserved. -// Copyright � 2002-2008 AGEIA Technologies, Inc. All rights reserved. -// Copyright � 2001-2006 NovodeX. All rights reserved. - -#ifndef NV_HASH_MAP_H -#define NV_HASH_MAP_H - -#include "NvUserMemAlloc.h" - -#if (defined(NX_WINDOWS) | defined(NX_X360)) -#include -#endif - -#include -#include -#include -#include -//****************************************************** -//****************************************************** -//****************************************************** - - -#ifndef NV_FOUNDATION_BASIC_TEMPLATES_H -#define NV_FOUNDATION_BASIC_TEMPLATES_H - -#pragma warning(push) -#pragma warning(disable:4512) // suppress the 'assignment operator could not be generated' warning message. - -namespace CONVEX_DECOMPOSITION -{ - template - struct Equal - { - bool operator()(const A& a, const A& b) const { return a==b; } - }; - - template - struct Less - { - bool operator()(const A& a, const A& b) const { return a - struct Greater - { - bool operator()(const A& a, const A& b) const { return a>b; } - }; - - - template - class Pair - { - public: - F first; - S second; - Pair(): first(F()), second(S()) {} - Pair(const F &f, const S &s): first(f), second(s) {} - Pair(const Pair &p): first(p.first), second(p.second) {} - }; - - template struct LogTwo { static const unsigned int value = LogTwo<(A>>1)>::value + 1; }; - template<> struct LogTwo<1>{ static const unsigned int value = 0; }; - - template struct UnConst { typedef T Type; }; - template struct UnConst { typedef T Type; }; -} - -#pragma warning(pop) - -#endif - -#ifndef NV_FOUNDATION_ALLOCATOR -#define NV_FOUNDATION_ALLOCATOR - -#pragma warning(push) -#pragma warning(disable:4100) - -namespace CONVEX_DECOMPOSITION -{ - - -/** -\brief The return value is the greater of the two specified values. -*/ -template -NX_INLINE N NxMax(N a, N b) { return a -NX_INLINE NxF32 NxMax(NxF32 a, NxF32 b) { return a > b ? a : b; } - -/** -\brief The return value is the lesser of the two specified values. -*/ -template -NX_INLINE N NxMin(N a, N b) { return a -NX_INLINE NxF32 NxMin(NxF32 a, NxF32 b) { return a < b ? a : b; } - - - - /** - Allocator used to access the global NxUserAllocator instance without providing additional information. - */ - class Allocator - { - public: - Allocator(const char* dummy = 0) - { - } - void* allocate(size_t size, const char* file, int line) - { - return MEMALLOC_MALLOC(size); - } - void deallocate(void* ptr) - { - MEMALLOC_FREE(ptr); - } - }; - - /** - Allocator used to access the global NxUserAllocator instance using a dynamic name. - */ - class NamedAllocator - { - public: - NamedAllocator(const char* name = 0) - - { - - } - void* allocate(size_t size, const char* filename, int line) - { - return MEMALLOC_MALLOC(size); - } - void deallocate(void* ptr) - { - MEMALLOC_FREE(ptr); - } - private: - }; - - /** - Allocator used to access the global NxUserAllocator instance using a static name derived from T. - */ - template - class ReflectionAllocator - { - static const char* getName() - { -#if defined NX_GNUC - return __PRETTY_FUNCTION__; -#else - return typeid(T).name(); -#endif - } - public: - ReflectionAllocator(const char* dummy=0) - { - } - void* allocate(size_t size, const char* filename, int line) - { - return MEMALLOC_MALLOC(size); - } - void deallocate(void* ptr) - { - MEMALLOC_FREE(ptr); - } - }; - - // if you get a build error here, you are trying to NX_NEW a class - // that is neither plain-old-type nor derived from CONVEX_DECOMPOSITION::UserAllocated - template - union EnableIfPod - { - int i; T t; - typedef X Type; - }; - -} - -// Global placement new for ReflectionAllocator templated by plain-old-type. Allows using NX_NEW for pointers and built-in-types. -// ATTENTION: You need to use NX_DELETE_POD or NX_FREE to deallocate memory, not NX_DELETE. NX_DELETE_POD redirects to NX_FREE. -// Rationale: NX_DELETE uses global operator delete(void*), which we dont' want to overload. -// Any other definition of NX_DELETE couldn't support array syntax 'NX_DELETE([]a);'. -// NX_DELETE_POD was preferred over NX_DELETE_ARRAY because it is used less often and applies to both single instances and arrays. -template -NX_INLINE void* operator new(size_t size, CONVEX_DECOMPOSITION::ReflectionAllocator alloc, const char* fileName, typename CONVEX_DECOMPOSITION::EnableIfPod::Type line) -{ - return alloc.allocate(size, fileName, line); -} - -template -NX_INLINE void* operator new[](size_t size, CONVEX_DECOMPOSITION::ReflectionAllocator alloc, const char* fileName, typename CONVEX_DECOMPOSITION::EnableIfPod::Type line) -{ - return alloc.allocate(size, fileName, line); -} - -// If construction after placement new throws, this placement delete is being called. -template -NX_INLINE void operator delete(void* ptr, CONVEX_DECOMPOSITION::ReflectionAllocator alloc, const char* fileName, typename CONVEX_DECOMPOSITION::EnableIfPod::Type line) -{ - alloc.deallocate(ptr); -} - -// If construction after placement new throws, this placement delete is being called. -template -NX_INLINE void operator delete[](void* ptr, CONVEX_DECOMPOSITION::ReflectionAllocator alloc, const char* fileName, typename CONVEX_DECOMPOSITION::EnableIfPod::Type line) -{ - alloc.deallocate(ptr); -} - -#pragma warning(pop) - -#endif - - -#ifndef NV_FOUNDATION_USERALLOCATED -#define NV_FOUNDATION_USERALLOCATED - -// an expression that should expand to nothing in _DEBUG builds. We currently -// use this only for tagging the purpose of containers for memory use tracking. -#if defined(_DEBUG) -#define NV_DEBUG_EXP(x) (x) -#define NV_DEBUG_EXP_C(x) x, -#else -#define NV_DEBUG_EXP(x) -#define NV_DEBUG_EXP_C(x) -#endif - -#if defined (NX_X360) | defined (NX_WINDOWS) | defined (NX_CELL) | defined (NXLINUX) | defined(NX_WII) -// Stack allocation with alloc fallback for large allocations (>50% of default stack size for platform) -# define NX_ALLOCA(var, type, number) \ - bool alloced_##var = false; \ - if (sizeof(type)*number*2 > (CONVEX_DECOMPOSITION::gSystemServices ? gSystemServices->getAllocaThreshold() : 8192) ) \ - { \ - var = (type *)MEMALLOC_MALLOC(sizeof(type)*number); \ - alloced_##var = true; \ - } else { \ - var = (type *)MEMALLOC_ALLOCA(sizeof(type)*number); \ - } -# define NX_FREEA(var) if (alloced_##var) MEMALLOC_FREE(var); -#else -# define NX_ALLOCA(var, type, number) var = (type *)NxAlloca(sizeof(type)*number); -# define NX_FREEA(var) 0; -#endif - -namespace CONVEX_DECOMPOSITION -{ - /** - Provides new and delete using a UserAllocator. - Guarantees that 'delete x;' uses the UserAllocator too. - */ - class UserAllocated - { - public: - - template - NX_INLINE void* operator new(size_t size, Alloc alloc, const char* fileName, int line) - { - return MEMALLOC_MALLOC(size); - } - template - NX_INLINE void* operator new[](size_t size, Alloc alloc, const char* fileName, int line) - { - return MEMALLOC_MALLOC(size); - } - - NX_INLINE void operator delete(void* ptr) - { - MEMALLOC_FREE(ptr); - } - NX_INLINE void operator delete[](void* ptr) - { - MEMALLOC_FREE(ptr); - } - }; -}; - -#endif - - -#ifndef NV_FOUNDATION_ALIGNEDMALLOC_H -#define NV_FOUNDATION_ALIGNEDMALLOC_H - -/*! -Allocate aligned memory. -Alignment must be a power of 2! --- should be templated by a base allocator -*/ - -namespace CONVEX_DECOMPOSITION -{ - /** - Allocator, which is used to access the global NxUserAllocator instance - (used for dynamic data types template instantiation), which can align memory - */ - - // SCS: AlignedMalloc with 3 params not found, seems not used on PC either - // disabled for now to avoid GCC error - - template - class AlignedAllocator : public BaseAllocator - { - public: - AlignedAllocator(const BaseAllocator& base = BaseAllocator()) - : BaseAllocator(base) {} - - void* allocate(size_t size, const char* file, int line) - { - size_t pad = N - 1 + sizeof(size_t); // store offset for delete. - NxU8* base = (NxU8*)BaseAllocator::allocate(size+pad, file, line); - - NxU8* ptr = (NxU8*)(size_t(base + pad) & ~(N - 1)); // aligned pointer - ((size_t*)ptr)[-1] = ptr - base; // store offset - - return ptr; - } - void deallocate(void* ptr) - { - if(ptr == NULL) - return; - - NxU8* base = ((NxU8*)ptr) - ((size_t*)ptr)[-1]; - BaseAllocator::deallocate(base); - } - }; -} - -#endif - - -#ifndef NV_FOUNDATION_INLINE_ALLOCATOR_H -#define NV_FOUNDATION_INLINE_ALLOCATOR_H - -namespace CONVEX_DECOMPOSITION -{ - // this is used by the array class to allocate some space for a small number - // of objects along with the metadata - template - class InlineAllocator : private BaseAllocator - { - public: - - InlineAllocator(const BaseAllocator& alloc = BaseAllocator()) - : BaseAllocator(alloc) - {} - - void* allocate(size_t size, const char* filename, int line) - { - return size <= N ? mBuffer : BaseAllocator::allocate(size, filename, line); - } - - void deallocate(void* ptr) - { - if(ptr != mBuffer) - BaseAllocator::deallocate(ptr); - } - - private: - NxU8 mBuffer[N]; - }; -} - -#endif - - -#ifndef NV_FOUNDATION_NXSTRIDEDDATA -#define NV_FOUNDATION_NXSTRIDEDDATA -/** \addtogroup foundation - @{ -*/ - -template -class NvStrideIterator -{ - template - struct StripConst - { - typedef X Type; - }; - - template - struct StripConst - { - typedef X Type; - }; - -public: - explicit NX_INLINE NvStrideIterator(T* ptr = NULL, NxU32 stride = sizeof(T)) : - mPtr(ptr), mStride(stride) - { - NX_ASSERT(mStride == 0 || sizeof(T) <= mStride); - } - - NX_INLINE NvStrideIterator(const NvStrideIterator::Type>& strideIterator) : - mPtr(strideIterator.ptr()), mStride(strideIterator.stride()) - { - NX_ASSERT(mStride == 0 || sizeof(T) <= mStride); - } - - NX_INLINE T* ptr() const - { - return mPtr; - } - - NX_INLINE NxU32 stride() const - { - return mStride; - } - - NX_INLINE T& operator*() const - { - return *mPtr; - } - - NX_INLINE T* operator->() const - { - return mPtr; - } - - NX_INLINE T& operator[](int i) const - { - return *byteAdd(mPtr, i * stride()); - } - - // preincrement - NX_INLINE NvStrideIterator& operator++() - { - mPtr = byteAdd(mPtr, stride()); - return *this; - } - - // postincrement - NX_INLINE NvStrideIterator operator++(int) - { - NvStrideIterator tmp = *this; - mPtr = byteAdd(mPtr, stride()); - return tmp; - } - - // predecrement - NX_INLINE NvStrideIterator& operator--() - { - mPtr = byteSub(mPtr, stride()); - return *this; - } - - // postdecrement - NX_INLINE NvStrideIterator operator--(int) - { - NvStrideIterator tmp = *this; - mPtr = byteSub(mPtr, stride()); - return tmp; - } - - NX_INLINE NvStrideIterator& operator+=(int i) - { - mPtr = byteAdd(mPtr, i * stride()); - return *this; - } - - NX_INLINE NvStrideIterator operator+(int i) const - { - return NvStrideIterator(byteAdd(mPtr, i * stride()), stride()); - } - - NX_INLINE NvStrideIterator& operator-=(int i) - { - mPtr = byteSub(mPtr, i * stride()); - return *this; - } - - NX_INLINE NvStrideIterator operator-(int i) const - { - return NvStrideIterator(byteSub(mPtr, i * stride()), stride()); - } - - // iterator difference - NX_INLINE int operator-(const NvStrideIterator& other) const - { - NX_ASSERT(isCompatible(other)); - int byteDiff = static_cast(reinterpret_cast(mPtr) - reinterpret_cast(other.mPtr)); - return byteDiff / static_cast(stride()); - } - - NX_INLINE bool operator==(const NvStrideIterator& other) const - { - NX_ASSERT(isCompatible(other)); - return mPtr == other.mPtr; - } - - NX_INLINE bool operator!=(const NvStrideIterator& other) const - { - NX_ASSERT(isCompatible(other)); - return mPtr != other.mPtr; - } - - NX_INLINE bool operator<(const NvStrideIterator& other) const - { - NX_ASSERT(isCompatible(other)); - return mPtr < other.mPtr; - } - - NX_INLINE bool operator>(const NvStrideIterator& other) const - { - NX_ASSERT(isCompatible(other)); - return mPtr > other.mPtr; - } - - NX_INLINE bool operator<=(const NvStrideIterator& other) const - { - NX_ASSERT(isCompatible(other)); - return mPtr <= other.mPtr; - } - - NX_INLINE bool operator>=(const NvStrideIterator& other) const - { - NX_ASSERT(isCompatible(other)); - return mPtr >= other.mPtr; - } - -private: - NX_INLINE static T* byteAdd(T* ptr, NxU32 bytes) - { - return const_cast(reinterpret_cast(reinterpret_cast(ptr) + bytes)); - } - - NX_INLINE static T* byteSub(T* ptr, NxU32 bytes) - { - return const_cast(reinterpret_cast(reinterpret_cast(ptr) - bytes)); - } - - NX_INLINE bool isCompatible(const NvStrideIterator& other) const - { - int byteDiff = static_cast(reinterpret_cast(mPtr) - reinterpret_cast(other.mPtr)); - return (stride() == other.stride()) && (abs(byteDiff) % stride() == 0); - } - - T* mPtr; - NxU32 mStride; -}; - - -template -NX_INLINE NvStrideIterator operator+(int i, NvStrideIterator it) -{ - it += i; - return it; -} - - /** @} */ -#endif - -#ifndef NV_FOUNDATION_ARRAY -#define NV_FOUNDATION_ARRAY - -namespace CONVEX_DECOMPOSITION -{ - namespace Internal - { - template - struct ArrayMetaData - { - T* mData; - NxU32 mCapacity; - NxU32 mSize; - ArrayMetaData(): mSize(0), mCapacity(0), mData(0) {} - }; - - template - struct AllocatorTraits - { -#if defined _DEBUG - typedef NamedAllocator Type; -#else - typedef ReflectionAllocator Type; -#endif - }; - } - - /*! - An array is a sequential container. - - Implementation note - * entries between 0 and size are valid objects - * we use inheritance to build this because the array is included inline in a lot - of objects and we want the allocator to take no space if it's not stateful, which - aggregation doesn't allow. Also, we want the metadata at the front for the inline - case where the allocator contains some inline storage space - */ - template::Type > - class Array : private Internal::ArrayMetaData, private Alloc - { - typedef Internal::ArrayMetaData MetaData; - - using MetaData::mCapacity; - using MetaData::mData; - using MetaData::mSize; - - public: - - typedef T* Iterator; - typedef const T* ConstIterator; - - /*! - Default array constructor. Initialize an empty array - */ - NX_INLINE Array(const Alloc& alloc = Alloc()) : Alloc(alloc) {} - - /*! - Initialize array with given length - */ - NX_INLINE explicit Array(NxU32 capacity, const Alloc& alloc = Alloc()) - : Alloc(alloc) - { - if(mCapacity>0) - allocate(mCapacity); - } - - /*! - Copy-constructor. Copy all entries from other array - */ - template - NX_INLINE Array(const Array& other, const Alloc& alloc = Alloc()) - { - if(other.mSize > 0) - { - mData = allocate(mSize = mCapacity = other.mSize); - copy(mData, other.mData, mSize); - } - } - - /*! - Default destructor - */ - NX_INLINE ~Array() - { - destroy(0, mSize); - if(mCapacity) - deallocate(mData); - } - - /*! - Assignment operator. Copy content (deep-copy) - */ - template - NX_INLINE const Array& operator= (const Array& t) - { - if(&t == this) - return *this; - - if(mCapacity < t.mSize) - { - destroy(0,mSize); - deallocate(mData); - - mData = allocate(t.mCapacity); - mCapacity = t.mCapacity; - - copy(mData,t.mData,t.mSize); - } - else - { - NxU32 m = NxMin(t.mSize,mSize); - copy(mData,t.mData,m); - for(NxU32 i = m; i < mSize;i++) - mData[i].~T(); - for(NxU32 i = m; i < t.mSize; i++) - new(mData+i)T(t.mData[i]); - } - - mSize = t.mSize; - return *this; - } - - /*! - Array indexing operator. - \param i - The index of the element that will be returned. - \return - The element i in the array. - */ - NX_INLINE const T& operator[] (NxU32 i) const - { - return mData[i]; - } - - /*! - Array indexing operator. - \param i - The index of the element that will be returned. - \return - The element i in the array. - */ - NX_INLINE T& operator[] (NxU32 i) - { - return mData[i]; - } - - /*! - Returns a pointer to the initial element of the array. - \return - a pointer to the initial element of the array. - */ - NX_INLINE ConstIterator begin() const - { - return mData; - } - - NX_INLINE Iterator begin() - { - return mData; - } - - /*! - Returns an iterator beyond the last element of the array. Do not dereference. - \return - a pointer to the element beyond the last element of the array. - */ - - NX_INLINE ConstIterator end() const - { - return mData+mSize; - } - - NX_INLINE Iterator end() - { - return mData+mSize; - } - - /*! - Returns a reference to the first element of the array. Undefined if the array is empty. - \return a reference to the first element of the array - */ - - NX_INLINE const T& front() const - { - NX_ASSERT(mSize); - return mData[0]; - } - - NX_INLINE T& front() - { - NX_ASSERT(mSize); - return mData[0]; - } - - /*! - Returns a reference to the last element of the array. Undefined if the array is empty - \return a reference to the last element of the array - */ - - NX_INLINE const T& back() const - { - NX_ASSERT(mSize); - return mData[mSize-1]; - } - - NX_INLINE T& back() - { - NX_ASSERT(mSize); - return mData[mSize-1]; - } - - - /*! - Returns the number of entries in the array. This can, and probably will, - differ from the array capacity. - \return - The number of of entries in the array. - */ - NX_INLINE NxU32 size() const - { - return mSize; - } - - /*! - Clears the array. - */ - NX_INLINE void clear() - { - destroy(0,mSize); - mSize = 0; - } - - /*! - Returns whether the array is empty (i.e. whether its size is 0). - \return - true if the array is empty - */ - NX_INLINE bool empty() const - { - return mSize==0; - } - - /*! - Finds the first occurrence of an element in the array. - \param a - The element that will be removed. - */ - - - NX_INLINE Iterator find(const T&a) - { - NxU32 index; - for(index=0;index(i-mData)); - } - - ///////////////////////////////////////////////////////////////////////// - /*! - Replaces the first occurrence of the element a with the last element - Operation is O(n) - \param i - The position of the element that will be subtracted from this array. - \return Returns true if the element has been removed. - */ - ///////////////////////////////////////////////////////////////////////// - - NX_INLINE bool findAndReplaceWithLast(const T& a) - { - NxU32 index; - for(index=0;index= mSize) - return false; - replaceWithLast(index); - return true; - } - - ///////////////////////////////////////////////////////////////////////// - /*! - Subtracts the element on position i from the array. Shift the entire - array one step. - Operation is O(n) - \param i - The position of the element that will be subtracted from this array. - \return - The element that was removed. - */ - ///////////////////////////////////////////////////////////////////////// - NX_INLINE void remove(NxU32 i) - { - NX_ASSERT(i mCapacity) - { - grow(size); - } - else if (compaction && (size != mCapacity)) - { - recreate(size, NxMin(mSize, size)); - } - - for(NxU32 i = mSize; i < size; i++) - ::new(mData+i)T(a); - - if (!compaction) // With compaction, these elements have been deleted already - { - for(NxU32 i = size; i < mSize; i++) - mData[i].~T(); - } - - mSize = size; - } - - - ////////////////////////////////////////////////////////////////////////// - /*! - Resize array such that only as much memory is allocated to hold the - existing elements - */ - ////////////////////////////////////////////////////////////////////////// - NX_INLINE void shrink() - { - resize(mSize, true); - } - - - ////////////////////////////////////////////////////////////////////////// - /*! - Deletes all array elements and frees memory. - */ - ////////////////////////////////////////////////////////////////////////// - NX_INLINE void reset() - { - resize(0, true); - } - - - ////////////////////////////////////////////////////////////////////////// - /*! - Ensure that the array has at least size capacity. - */ - ////////////////////////////////////////////////////////////////////////// - NX_INLINE void reserve(const NxU32 size) - { - if(size > mCapacity) - grow(size); - } - - ////////////////////////////////////////////////////////////////////////// - /*! - Query the capacity(allocated mem) for the array. - */ - ////////////////////////////////////////////////////////////////////////// - NX_INLINE NxU32 capacity() const - { - return mCapacity; - } - - - private: - - NX_INLINE T* allocate(size_t capacity) - { - return (T*)Alloc::allocate(sizeof(T) * capacity, __FILE__, __LINE__); - } - - NX_INLINE void deallocate(void *mem) - { - Alloc::deallocate(mem); - } - - NX_INLINE void copy(T* dst, const T* src, size_t count) - { - for(size_t i=0;i= copyCount); - NX_ASSERT(mSize >= copyCount); - T* newData = allocate(capacity); - NX_ASSERT( ((newData != NULL) && (capacity > 0)) || - ((newData == NULL) && (capacity == 0)) ); - - if(mCapacity) - { - copy(newData,mData,copyCount); - destroy(0,mSize); - deallocate(mData); - } - - mData = newData; - mCapacity = capacity; - } - - /*! - Resizes the available memory for the array. - - \param capacity - The number of entries that the set should be able to hold. - */ - NX_INLINE void grow(NxU32 capacity) - { - NX_ASSERT(mCapacity < capacity); - recreate(capacity, mSize); - } - }; - - // array that pre-allocates for N elements - template ::Type> - class InlineArray : public Array > - { - typedef InlineAllocator Allocator; - public: - NX_INLINE InlineArray(const Alloc& alloc = Alloc()) - : Array(alloc) - {} - }; -} - -template -NX_INLINE NvStrideIterator getStrideIterator(CONVEX_DECOMPOSITION::Array& array) -{ - return NvStrideIterator(array.begin(), sizeof(T)); -} - -template -NX_INLINE NvStrideIterator getConstStrideIterator(CONVEX_DECOMPOSITION::Array& array) -{ - return NvStrideIterator(array.begin(), sizeof(T)); -} - - -#endif - -#ifndef NV_FOUNDATION_BITUTILS_H -#define NV_FOUNDATION_BITUTILS_H - -namespace CONVEX_DECOMPOSITION -{ - NX_INLINE NxU32 bitCount32(NxU32 v) - { - // from http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel - NxU32 const w = v - ((v >> 1) & 0x55555555); - NxU32 const x = (w & 0x33333333) + ((w >> 2) & 0x33333333); - return ((x + (x >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; - } - - /*! - Return the index of the highest set bit. Or 0 if no bits are set. - */ - NX_INLINE NxU32 highestSetBit32(NxU32 v) - { - for(NxU32 j = 32; j-- > 0;) - { - if(v&(1<> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - return x+1; - } - - // Helper function to approximate log2 of an integer value (assumes that the input is actually power of two) - NX_INLINE NxU32 ilog2(NxU32 num) - { - for (NxU32 i=0; i<32; i++) - { - num >>= 1; - if (num == 0) return i; - } - - NX_ASSERT(0); - return (NxU32)-1; - } - - NX_INLINE int intChop(const NxF32& f) - { - NxI32 a = *reinterpret_cast(&f); // take bit pattern of float into a register - NxI32 sign = (a>>31); // sign = 0xFFFFFFFF if original value is negative, 0 if positive - NxI32 mantissa = (a&((1<<23)-1))|(1<<23); // extract mantissa and add the hidden bit - NxI32 exponent = ((a&0x7fffffff)>>23)-127; // extract the exponent - NxI32 r = ((NxU32)(mantissa)<<8)>>(31-exponent); // ((1<>24 -- (we know that mantissa > (1<<24)) - return ((r ^ (sign)) - sign ) &~ (exponent>>31); // add original sign. If exponent was negative, make return value 0. - } - - NX_INLINE int intFloor(const NxF32& f) - { - NxI32 a = *reinterpret_cast(&f); // take bit pattern of float into a register - NxI32 sign = (a>>31); // sign = 0xFFFFFFFF if original value is negative, 0 if positive - a&=0x7fffffff; // we don't need the sign any more - NxI32 exponent = (a>>23)-127; // extract the exponent - NxI32 expsign = ~(exponent>>31); // 0xFFFFFFFF if exponent is positive, 0 otherwise - NxI32 imask = ( (1<<(31-(exponent))))-1; // mask for true integer values - NxI32 mantissa = (a&((1<<23)-1)); // extract mantissa (without the hidden bit) - NxI32 r = ((NxU32)(mantissa|(1<<23))<<8)>>(31-exponent); // ((1<>24 -- (we know that mantissa > (1<<24)) - r = ((r & expsign) ^ (sign)) + ((!((mantissa<<8)&imask)&(expsign^((a-1)>>31)))&sign); // if (fabs(value)<1.0) value = 0; copy sign; if (value < 0 && value==(int)(value)) value++; - return r; - } - - NX_INLINE int intCeil(const NxF32& f) - { - NxI32 a = *reinterpret_cast(&f) ^ 0x80000000; // take bit pattern of float into a register - NxI32 sign = (a>>31); // sign = 0xFFFFFFFF if original value is negative, 0 if positive - a&=0x7fffffff; // we don't need the sign any more - NxI32 exponent = (a>>23)-127; // extract the exponent - NxI32 expsign = ~(exponent>>31); // 0xFFFFFFFF if exponent is positive, 0 otherwise - NxI32 imask = ( (1<<(31-(exponent))))-1; // mask for true integer values - NxI32 mantissa = (a&((1<<23)-1)); // extract mantissa (without the hidden bit) - NxI32 r = ((NxU32)(mantissa|(1<<23))<<8)>>(31-exponent); // ((1<>24 -- (we know that mantissa > (1<<24)) - r = ((r & expsign) ^ (sign)) + ((!((mantissa<<8)&imask)&(expsign^((a-1)>>31)))&sign); // if (fabs(value)<1.0) value = 0; copy sign; if (value < 0 && value==(int)(value)) value++; - return -r; - } - -} - -#endif - -#ifndef NV_FOUNDATION_HASHFUNCTION_H -#define NV_FOUNDATION_HASHFUNCTION_H - -/*! -Central definition of hash functions -*/ - -namespace CONVEX_DECOMPOSITION -{ - // Hash functions - template - NxU32 hash(const T& key) - { - return (NxU32)key; - } - - // Thomas Wang's 32 bit mix - // http://www.cris.com/~Ttwang/tech/inthash.htm - template<> - NX_INLINE NxU32 hash(const NxU32& key) - { - NxU32 k = key; - k += ~(k << 15); - k ^= (k >> 10); - k += (k << 3); - k ^= (k >> 6); - k += ~(k << 11); - k ^= (k >> 16); - return (NxU32)k; - } - - template<> - NX_INLINE NxU32 hash(const NxI32& key) - { - return hash((NxU32)key); - } - - // Thomas Wang's 64 bit mix - // http://www.cris.com/~Ttwang/tech/inthash.htm - template<> - NX_INLINE NxU32 hash(const NxU64& key) - { - NxU64 k = key; - k += ~(k << 32); - k ^= (k >> 22); - k += ~(k << 13); - k ^= (k >> 8); - k += (k << 3); - k ^= (k >> 15); - k += ~(k << 27); - k ^= (k >> 31); - return (NxU32)k; - } - - // Helper for pointer hashing - template - NxU32 PointerHash(const void* ptr); - - template<> - NX_INLINE NxU32 PointerHash<4>(const void* ptr) - { - return hash(static_cast(reinterpret_cast(ptr))); - } - - - template<> - NX_INLINE NxU32 PointerHash<8>(const void* ptr) - { - return hash(reinterpret_cast(ptr)); - } - - // Hash function for pointers - template - NX_INLINE NxU32 hash(T* key) - { - return PointerHash(key); - } - - // Hash function object for pointers - template - struct PointerHashFunctor - { - NxU32 operator()(const T* t) const - { - return PointerHash(t); - } - bool operator()(const T* t0, const T* t1) const - { - return t0 == t1; - } - }; - - /* - -------------------------------------------------------------------- - lookup2.c, by Bob Jenkins, December 1996, Public Domain. - -------------------------------------------------------------------- - -------------------------------------------------------------------- - mix -- mix 3 32-bit values reversibly. - For every delta with one or two bit set, and the deltas of all three - high bits or all three low bits, whether the original value of a,b,c - is almost all zero or is uniformly distributed, - * If mix() is run forward or backward, at least 32 bits in a,b,c - have at least 1/4 probability of changing. - * If mix() is run forward, every bit of c will change between 1/3 and - 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) - mix() was built out of 36 single-cycle latency instructions in a - structure that could supported 2x parallelism, like so: - a -= b; - a -= c; x = (c>>13); - b -= c; a ^= x; - b -= a; x = (a<<8); - c -= a; b ^= x; - c -= b; x = (b>>13); - ... - Unfortunately, superscalar Pentiums and Sparcs can't take advantage - of that parallelism. They've also turned some of those single-cycle - latency instructions into multi-cycle latency instructions. Still, - this is the fastest good hash I could find. There were about 2^^68 - to choose from. I only looked at a billion or so. - -------------------------------------------------------------------- - */ - NX_INLINE NxU32 hashMix(NxU32 &a, NxU32 &b, NxU32 &c) - { - a -= b; a -= c; a ^= (c>>13); - b -= c; b -= a; b ^= (a<<8); - c -= a; c -= b; c ^= (b>>13); - a -= b; a -= c; a ^= (c>>12); - b -= c; b -= a; b ^= (a<<16); - c -= a; c -= b; c ^= (b>>5); - a -= b; a -= c; a ^= (c>>3); - b -= c; b -= a; b ^= (a<<10); - c -= a; c -= b; c ^= (b>>15); - } - - NX_INLINE NxU32 hash(const NxU32 *k, NxU32 length) - { - NxU32 a,b,c,len; - - /* Set up the internal state */ - len = length; - a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ - c = 0; /* the previous hash value */ - - /*---------------------------------------- handle most of the key */ - while (len >= 3) - { - a += k[0]; - b += k[1]; - c += k[2]; - hashMix(a,b,c); - k += 3; - len -= 3; - } - - /*-------------------------------------- handle the last 2 ub4's */ - c += length; - switch(len) /* all the case statements fall through */ - { - /* c is reserved for the length */ - case 2 : b+=k[1]; - case 1 : a+=k[0]; - /* case 0: nothing left to add */ - } - hashMix(a,b,c); - /*-------------------------------------------- report the result */ - return c; - } - - template - class Hash - { - public: - NxU32 operator()(const Key &k) const { return hash(k); } - bool operator()(const Key &k0, const Key &k1) const { return k0 == k1; } - }; - - class NvStringHash - { - public: - NxU32 operator()(const char *string) const - { - // "DJB" string hash - NxU32 h = 5381; - for(const char *ptr = string; *ptr; ptr++) - h = ((h<<5)+h)^*ptr; - return h; - } - bool operator()(const char* string0, const char* string1) const - { - return !strcmp(string0, string1); - } - }; -} - -#endif - - -#ifndef NV_FOUNDATION_HASHINTERNALS -#define NV_FOUNDATION_HASHINTERNALS - - -#pragma warning(push) -#pragma warning(disable:4127 4512) // disable the 'conditoinal expression is constant' warning message - -namespace CONVEX_DECOMPOSITION -{ - namespace Internal - { - template - class HashBase - { - public: - typedef Entry EntryType; - - HashBase(NxU32 initialTableSize = 64, float loadFactor = 0.75f): - mLoadFactor(loadFactor), - mFreeList((NxU32)EOL), - mTimestamp(0), - mSize(0), - mEntries(Allocator(NV_DEBUG_EXP("hashBaseEntries"))), - mNext(Allocator(NV_DEBUG_EXP("hashBaseNext"))), - mHash(Allocator(NV_DEBUG_EXP("hashBaseHash"))) - { - if(initialTableSize) - reserveInternal(initialTableSize); - } - - ~HashBase() - { - for(NxU32 i = 0;imHash.size()) - reserveInternal(size); - } - - NX_INLINE const Entry *getEntries() const - { - return &mEntries[0]; - } - - private: - - // free list management - if we're coalescing, then we use mFreeList to hold - // the top of the free list and it should always be equal to size(). Otherwise, - // we build a free list in the next() pointers. - - NX_INLINE void freeListAdd(NxU32 index) - { - if(compacting) - { - mFreeList--; - NX_ASSERT(mFreeList == mSize); - } - else - { - mNext[index] = mFreeList; - mFreeList = index; - } - } - - NX_INLINE void freeListAdd(NxU32 start, NxU32 end) - { - if(!compacting) - { - for(NxU32 i = start; i mEntries; - Array mNext; - Array mHash; - float mLoadFactor; - NxU32 mFreeList; - NxU32 mTimestamp; - NxU32 mSize; - - friend class Iter; - - public: - class Iter - { - public: - NX_INLINE Iter(HashBase &b): mBase(b), mTimestamp(b.mTimestamp), mBucket(0), mEntry((NxU32)b.EOL) - { - if(mBase.mEntries.size()>0) - { - mEntry = mBase.mHash[0]; - skip(); - } - } - - NX_INLINE void check() { NX_ASSERT(mTimestamp == mBase.mTimestamp); } - NX_INLINE Entry operator*() { check(); return mBase.mEntries[mEntry]; } - NX_INLINE Entry *operator->() { check(); return &mBase.mEntries[mEntry]; } - NX_INLINE Iter operator++() { check(); advance(); return *this; } - NX_INLINE Iter operator++(int) { check(); Iter i = *this; advance(); return i; } - NX_INLINE bool done() { check(); return mEntry == mBase.EOL; } - - private: - NX_INLINE void advance() { mEntry = mBase.mNext[mEntry]; skip(); } - NX_INLINE void skip() - { - while(mEntry==mBase.EOL) - { - if(++mBucket == mBase.mHash.size()) - break; - mEntry = mBase.mHash[mBucket]; - } - } - - NxU32 mBucket; - NxU32 mEntry; - NxU32 mTimestamp; - HashBase &mBase; - }; - }; - - template - class HashSetBase - { - public: - struct GetKey { NX_INLINE const Key &operator()(const Key &e) { return e; } }; - - typedef HashBase BaseMap; - typedef typename BaseMap::Iter Iterator; - - HashSetBase(NxU32 initialTableSize = 64, - float loadFactor = 0.75f): mBase(initialTableSize,loadFactor) {} - - bool insert(const Key &k) - { - bool exists; - Key *e = mBase.create(k,exists); - if(!exists) - new(e)Key(k); - return !exists; - } - - NX_INLINE bool contains(const Key &k) const { return mBase.find(k)!=0; } - NX_INLINE bool erase(const Key &k) { return mBase.erase(k); } - NX_INLINE NxU32 size() const { return mBase.size(); } - NX_INLINE void reserve(NxU32 size) { mBase.reserve(size); } - NX_INLINE void clear() { mBase.clear(); } - protected: - BaseMap mBase; - - }; - - template - - class HashMapBase - { - public: - typedef Pair Entry; - struct GetKey { NX_INLINE const Key &operator()(const Entry &e) { return e.first; } }; - typedef HashBase, Key, HashFn, GetKey, Allocator, true> BaseMap; - typedef typename BaseMap::Iter Iterator; - - HashMapBase(NxU32 initialTableSize = 64, float loadFactor = 0.75f): mBase(initialTableSize,loadFactor) {} - - bool insert(const Key &k, const Value &v) - { - bool exists; - Entry *e = mBase.create(k,exists); - if(!exists) - new(e)Entry(k,v); - return !exists; - } - - Value &operator [](const Key &k) - { - bool exists; - Entry *e = mBase.create(k, exists); - if(!exists) - new(e)Entry(k,Value()); - - return e->second; - } - - NX_INLINE const Entry * find(const Key &k) const { return mBase.find(k); } - NX_INLINE bool erase(const Key &k) { return mBase.erase(k); } - NX_INLINE NxU32 size() const { return mBase.size(); } - NX_INLINE Iterator getIterator() { return Iterator(mBase); } - NX_INLINE void reserve(NxU32 size) { mBase.reserve(size); } - NX_INLINE void clear() { mBase.clear(); } - - protected: - BaseMap mBase; - }; - - } -} - -#pragma warning(pop) - -#endif - -#ifndef NV_FOUNDATION_HASHMAP -#define NV_FOUNDATION_HASHMAP - - -// TODO: make this doxy-format -// -// This header defines two hash maps. Hash maps -// * support custom initial table sizes (rounded up internally to power-of-2) -// * support custom static allocator objects -// * auto-resize, based on a load factor (i.e. a 64-entry .75 load factor hash will resize -// when the 49th element is inserted) -// * are based on open hashing -// * have O(1) contains, erase -// -// Maps have STL-like copying semantics, and properly initialize and destruct copies of objects -// -// There are two forms of map: coalesced and uncoalesced. Coalesced maps keep the entries in the -// initial segment of an array, so are fast to iterate over; however deletion is approximately -// twice as expensive. -// -// HashMap: -// bool insert(const Key &k, const Value &v) O(1) amortized (exponential resize policy) -// Value & operator[](const Key &k) O(1) for existing objects, else O(1) amortized -// const Entry * find(const Key &k); O(1) -// bool erase(const T &k); O(1) -// NxU32 size(); constant -// void reserve(NxU32 size); O(MAX(currentOccupancy,size)) -// void clear(); O(currentOccupancy) (with zero constant for objects without destructors) -// Iterator getIterator(); -// -// operator[] creates an entry if one does not exist, initializing with the default constructor. -// CoalescedHashMap does not support getInterator, but instead supports -// const Key *getEntries(); -// -// Use of iterators: -// -// for(HashMap::Iterator iter = test.getIterator(); !iter.done(); ++iter) -// myFunction(iter->first, iter->second); - -namespace CONVEX_DECOMPOSITION -{ - template , - class Allocator = Allocator > - class HashMap: public Internal::HashMapBase - { - public: - - typedef Internal::HashMapBase HashMapBase; - typedef typename HashMapBase::Iterator Iterator; - - HashMap(NxU32 initialTableSize = 64, float loadFactor = 0.75f): HashMapBase(initialTableSize,loadFactor) {} - Iterator getIterator() { return Iterator(HashMapBase::mBase); } - }; - - template , - class Allocator = Allocator > - class CoalescedHashMap: public Internal::HashMapBase - { - typedef Internal::HashMapBase HashMapBase; - - CoalescedHashMap(NxU32 initialTableSize = 64, float loadFactor = 0.75f): HashMapBase(initialTableSize,loadFactor){} - const Key *getEntries() const { return HashMapBase::mBase.getEntries(); } - }; - -} -#endif - -#endif diff --git a/Engine/lib/convexDecomp/NvMeshIslandGeneration.cpp b/Engine/lib/convexDecomp/NvMeshIslandGeneration.cpp deleted file mode 100644 index 35157200b..000000000 --- a/Engine/lib/convexDecomp/NvMeshIslandGeneration.cpp +++ /dev/null @@ -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 -#include -#include -#include - -#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; isecond->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; imCoplanar = 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; imerge(*_i); - delete _i; - } - } - else - { - - - Triangle *t = mTriangles; - for (NxU32 i=0; ibuildBox(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 - diff --git a/Engine/lib/convexDecomp/NvMeshIslandGeneration.h b/Engine/lib/convexDecomp/NvMeshIslandGeneration.h deleted file mode 100644 index 5c9347613..000000000 --- a/Engine/lib/convexDecomp/NvMeshIslandGeneration.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/NvRayCast.cpp b/Engine/lib/convexDecomp/NvRayCast.cpp deleted file mode 100644 index 6a9f02fe7..000000000 --- a/Engine/lib/convexDecomp/NvRayCast.cpp +++ /dev/null @@ -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(rc); -} - -void releaseRayCast(iRayCast *rc) -{ - RayCast *r = static_cast< RayCast *>(rc); - delete r; -} - -}; - diff --git a/Engine/lib/convexDecomp/NvRayCast.h b/Engine/lib/convexDecomp/NvRayCast.h deleted file mode 100644 index 4f4cf1fc5..000000000 --- a/Engine/lib/convexDecomp/NvRayCast.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/NvRemoveTjunctions.cpp b/Engine/lib/convexDecomp/NvRemoveTjunctions.cpp deleted file mode 100644 index 3d0aefafd..000000000 --- a/Engine/lib/convexDecomp/NvRemoveTjunctions.cpp +++ /dev/null @@ -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 -#include -#include -#include -#pragma warning(disable:4702) -#pragma warning(disable:4127) //conditional expression is constant (because _HAS_EXCEPTIONS=0) -#include -#if defined( __APPLE__ ) || defined( __FreeBSD__) - #include -#elif LINUX - #include -#elif _MSC_VER < 1500 - #include -#elif _MSC_VER > 1800 - #include -#endif -#include "NvUserMemAlloc.h" -#include "NvHashMap.h" -#include "NvRemoveTjunctions.h" -#include "NvFloatMath.h" -#ifdef LINUX - #include -#endif - -#pragma warning(disable:4189) - -using namespace CONVEX_DECOMPOSITION; - -namespace CONVEX_DECOMPOSITION -{ - -class AABB -{ -public: - NxF32 mMin[3]; - NxF32 mMax[3]; -}; - -bool gDebug=false; -NxU32 gCount=0; - -typedef CONVEX_DECOMPOSITION::Array< NxU32 > NxU32Vector; - -class Triangle -{ -public: - Triangle(void) - { - mPending = false; - mSplit = false; - mI1 = mI2 = mI3 = 0xFFFFFFFF; - mId = 0; - } - - Triangle(NxU32 i1,NxU32 i2,NxU32 i3,const float *vertices,NxU32 id) - { - mPending = false; - init(i1,i2,i3,vertices,id); - mSplit = false; - } - - void init(NxU32 i1,NxU32 i2,NxU32 i3,const float *vertices,NxU32 id) - { - mSplit = false; - mI1 = i1; - mI2 = i2; - mI3 = i3; - mId = id; - - const float *p1 = &vertices[mI1*3]; - const float *p2 = &vertices[mI2*3]; - const float *p3 = &vertices[mI3*3]; - - initMinMax(p1,p2,p3); - } - - void initMinMax(const float *p1,const float *p2,const float *p3) - { - fm_copy3(p1,mBmin); - fm_copy3(p1,mBmax); - fm_minmax(p2,mBmin,mBmax); - fm_minmax(p3,mBmin,mBmax); - } - - void init(const NxU32 *idx,const float *vertices,NxU32 id) - { - mSplit = false; - mI1 = idx[0]; - mI2 = idx[1]; - mI3 = idx[2]; - mId = id; - - const float *p1 = &vertices[mI1*3]; - const float *p2 = &vertices[mI2*3]; - const float *p3 = &vertices[mI3*3]; - - initMinMax(p1,p2,p3); - - } - - bool intersects(const float *pos,const float *p1,const float *p2,float epsilon) const - { - bool ret = false; - - float sect[3]; - LineSegmentType type; - - float dist = fm_distancePointLineSegment(pos,p1,p2,sect,type,epsilon); - - if ( type == LS_MIDDLE && dist < epsilon ) - { - ret = true; - } - - return ret; - } - - bool intersects(NxU32 i,const float *vertices,NxU32 &edge,float epsilon) const - { - bool ret = true; - - const float *pos = &vertices[i*3]; - const float *p1 = &vertices[mI1*3]; - const float *p2 = &vertices[mI2*3]; - const float *p3 = &vertices[mI3*3]; - if ( intersects(pos,p1,p2,epsilon) ) - { - edge = 0; - } - else if ( intersects(pos,p2,p3,epsilon) ) - { - edge = 1; - } - else if ( intersects(pos,p3,p1,epsilon) ) - { - edge = 2; - } - else - { - ret = false; - } - return ret; - } - - bool intersects(const Triangle *t,const float *vertices,NxU32 &intersection_index,NxU32 &edge,float epsilon) - { - bool ret = false; - - if ( fm_intersectAABB(mBmin,mBmax,t->mBmin,t->mBmax) ) // only if the AABB's of the two triangles intersect... - { - - if ( t->intersects(mI1,vertices,edge,epsilon) ) - { - intersection_index = mI1; - ret = true; - } - - if ( t->intersects(mI2,vertices,edge,epsilon) ) - { - intersection_index = mI2; - ret = true; - } - - if ( t->intersects(mI3,vertices,edge,epsilon) ) - { - intersection_index = mI3; - ret = true; - } - - } - - return ret; - } - - bool mSplit:1; - bool mPending:1; - NxU32 mI1; - NxU32 mI2; - NxU32 mI3; - NxU32 mId; - float mBmin[3]; - float mBmax[3]; -}; - -class RtEdge -{ -public: - RtEdge(void) - { - mNextEdge = 0; - mTriangle = 0; - mHash = 0; - } - - NxU32 init(Triangle *t,NxU32 i1,NxU32 i2) - { - mTriangle = t; - mNextEdge = 0; - NX_ASSERT( i1 < 65536 ); - NX_ASSERT( i2 < 65536 ); - if ( i1 < i2 ) - { - mHash = (i1<<16)|i2; - } - else - { - mHash = (i2<<16)|i1; - } - return mHash; - } - RtEdge *mNextEdge; - Triangle *mTriangle; - NxU32 mHash; -}; - - -typedef CONVEX_DECOMPOSITION::Array< Triangle * > TriangleVector; -typedef CONVEX_DECOMPOSITION::HashMap< NxU32, RtEdge * > EdgeMap; - -class MyRemoveTjunctions : public RemoveTjunctions -{ -public: - MyRemoveTjunctions(void) - { - mInputTriangles = 0; - mEdges = 0; - mVcount = 0; - mVertices = 0; - mEdgeCount = 0; - } - ~MyRemoveTjunctions(void) - { - release(); - } - - virtual NxU32 removeTjunctions(RemoveTjunctionsDesc &desc) - { - NxU32 ret = 0; - - mEpsilon = desc.mEpsilon; - - size_t TcountOut; - - desc.mIndicesOut = removeTjunctions(desc.mVcount, desc.mVertices, desc.mTcount, desc.mIndices, TcountOut, desc.mIds); - -#ifdef WIN32 -# pragma warning(push) -# pragma warning(disable:4267) -#endif - - NX_ASSERT( TcountOut < UINT_MAX ); - desc.mTcountOut = TcountOut; - -#ifdef WIN32 -# pragma warning(pop) -#endif - - if ( !mIds.empty() ) - { - desc.mIdsOut = &mIds[0]; - } - - ret = desc.mTcountOut; - - bool check = ret != desc.mTcount; -#if 0 - while ( check ) - { - NxU32 tcount = ret; - NxU32 *indices = new NxU32[tcount*3]; - NxU32 *ids = new NxU32[tcount]; - memcpy(indices,desc.mIndicesOut,sizeof(NxU32)*ret*3); - memcpy(ids,desc.mIdsOut,sizeof(NxU32)*ret); - desc.mIndicesOut = removeTjunctions(desc.mVcount, desc.mVertices, tcount, indices, desc.mTcountOut, ids ); - if ( !mIds.empty() ) - { - desc.mIdsOut = &mIds[0]; - } - ret = desc.mTcountOut; - delete []indices; - delete []ids; - check = ret != tcount; - } -#endif - return ret; - } - - RtEdge * addEdge(Triangle *t,RtEdge *e,NxU32 i1,NxU32 i2) - { - NxU32 hash = e->init(t,i1,i2); - const EdgeMap::Entry *found = mEdgeMap.find(hash); - if ( found == NULL ) - { - mEdgeMap[hash] = e; - } - else - { - RtEdge *old_edge = (*found).second; - e->mNextEdge = old_edge; - mEdgeMap.erase(hash); - mEdgeMap[hash] = e; - } - e++; - mEdgeCount++; - return e; - } - - RtEdge * init(Triangle *t,const NxU32 *indices,const float *vertices,RtEdge *e,NxU32 id) - { - t->init(indices,vertices,id); - e = addEdge(t,e,t->mI1,t->mI2); - e = addEdge(t,e,t->mI2,t->mI3); - e = addEdge(t,e,t->mI3,t->mI1); - return e; - } - - void release(void) - { - mIds.clear(); - mEdgeMap.clear(); - mIndices.clear(); - mSplit.clear(); - delete []mInputTriangles; - delete []mEdges; - mInputTriangles = 0; - mEdges = 0; - mVcount = 0; - mVertices = 0; - mEdgeCount = 0; - - } - - virtual NxU32 * removeTjunctions(NxU32 vcount, - const float *vertices, - size_t tcount, - const NxU32 *indices, - size_t &tcount_out, - const NxU32 * ids) - { - NxU32 *ret = 0; - - release(); - - mVcount = vcount; - mVertices = vertices; - mTcount = (NxU32)tcount; - tcount_out = 0; - - mTcount = (NxU32)tcount; - mMaxTcount = (NxU32)tcount*2; - mInputTriangles = new Triangle[mMaxTcount]; - Triangle *t = mInputTriangles; - - mEdges = new RtEdge[mMaxTcount*3]; - mEdgeCount = 0; - - NxU32 id = 0; - - RtEdge *e = mEdges; - for (NxU32 i=0; imNextEdge == 0 ) // open edge! - { - Triangle *t = e->mTriangle; - if ( !t->mPending ) - { - test.pushBack(t); - t->mPending = true; - } - } - } - - if ( !test.empty() ) - { - TriangleVector::Iterator i; - for (i=test.begin(); i!=test.end(); ++i) - { - Triangle *t = (*i); - locateIntersection(t); - } - } - - } - - while ( !mSplit.empty() ) - { - TriangleVector scan = mSplit; - mSplit.clear(); - TriangleVector::Iterator i; - for (i=scan.begin(); i!=scan.end(); ++i) - { - Triangle *t = (*i); - locateIntersection(t); - } - } - - - mIndices.clear(); - mIds.clear(); - - t = mInputTriangles; - for (NxU32 i=0; imI1); - mIndices.pushBack(t->mI2); - mIndices.pushBack(t->mI3); - mIds.pushBack(t->mId); - t++; - } - - - mEdgeMap.clear(); - - delete []mEdges; - mEdges = 0; - delete []mInputTriangles; - mInputTriangles = 0; - tcount_out = mIndices.size()/3; - ret = tcount_out ? &mIndices[0] : 0; -#ifdef _DEBUG - if ( ret ) - { - const NxU32 *scan = ret; - for (NxU32 i=0; imI1 < mVcount ); - NX_ASSERT( scan->mI2 < mVcount ); - NX_ASSERT( scan->mI3 < mVcount ); - - NX_ASSERT( t->mI1 < mVcount ); - NX_ASSERT( t->mI2 < mVcount ); - NX_ASSERT( t->mI3 < mVcount ); - - - NxU32 intersection_index; - NxU32 edge; - - if ( scan != t && scan->intersects(t,mVertices,intersection_index,edge,mEpsilon) ) - { - - if ( t->mI1 == intersection_index || t->mI2 == intersection_index || t->mI3 == intersection_index ) - { - } - else - { - // here is where it intersects! - NxU32 i1,i2,i3; - NxU32 j1,j2,j3; - NxU32 id = t->mId; - - switch ( edge ) - { - case 0: - i1 = t->mI1; - i2 = intersection_index; - i3 = t->mI3; - j1 = intersection_index; - j2 = t->mI2; - j3 = t->mI3; - break; - case 1: - i1 = t->mI2; - i2 = intersection_index; - i3 = t->mI1; - j1 = intersection_index; - j2 = t->mI3; - j3 = t->mI1; - break; - case 2: - i1 = t->mI3; - i2 = intersection_index; - i3 = t->mI2; - j1 = intersection_index; - j2 = t->mI1; - j3 = t->mI2; - break; - default: - NX_ASSERT(0); - i1 = i2 = i3 = 0; - j1 = j2 = j3 = 0; - break; - } - - if ( mTcount < mMaxTcount ) - { - t->init(i1,i2,i3,mVertices,id); - Triangle *newt = &mInputTriangles[mTcount]; - newt->init(j1,j2,j3,mVertices,id); - mTcount++; - t->mSplit = true; - newt->mSplit = true; - - mSplit.pushBack(t); - mSplit.pushBack(newt); - ret = scan; - } - } - } - return ret; - } - - Triangle * testIntersection(Triangle *scan,Triangle *t) - { - Triangle *ret = 0; - - NxU32 t1 = (NxU32)(scan-mInputTriangles); - NxU32 t2 = (NxU32)(t-mInputTriangles); - - NX_ASSERT( t1 < mTcount ); - NX_ASSERT( t2 < mTcount ); - - NX_ASSERT( scan->mI1 < mVcount ); - NX_ASSERT( scan->mI2 < mVcount ); - NX_ASSERT( scan->mI3 < mVcount ); - - NX_ASSERT( t->mI1 < mVcount ); - NX_ASSERT( t->mI2 < mVcount ); - NX_ASSERT( t->mI3 < mVcount ); - - - NxU32 intersection_index; - NxU32 edge; - - assert( scan != t ); - - if ( scan->intersects(t,mVertices,intersection_index,edge,mEpsilon) ) - { - // here is where it intersects! - NxU32 i1,i2,i3; - NxU32 j1,j2,j3; - NxU32 id = t->mId; - - switch ( edge ) - { - case 0: - i1 = t->mI1; - i2 = intersection_index; - i3 = t->mI3; - j1 = intersection_index; - j2 = t->mI2; - j3 = t->mI3; - break; - case 1: - i1 = t->mI2; - i2 = intersection_index; - i3 = t->mI1; - j1 = intersection_index; - j2 = t->mI3; - j3 = t->mI1; - break; - case 2: - i1 = t->mI3; - i2 = intersection_index; - i3 = t->mI2; - j1 = intersection_index; - j2 = t->mI1; - j3 = t->mI2; - break; - default: - NX_ASSERT(0); - i1 = i2 = i3 = 0; - j1 = j2 = j3 = 0; - break; - } - - if ( mTcount < mMaxTcount ) - { - t->init(i1,i2,i3,mVertices,id); - Triangle *newt = &mInputTriangles[mTcount]; - newt->init(j1,j2,j3,mVertices,id); - mTcount++; - t->mSplit = true; - newt->mSplit = true; - - mSplit.pushBack(t); - mSplit.pushBack(newt); - ret = scan; - } - } - return ret; - } - - Triangle * locateIntersection(Triangle *t) - { - Triangle *ret = 0; - - Triangle *scan = mInputTriangles; - - for (NxU32 i=0; i(m); -} - -void releaseRemoveTjunctions(RemoveTjunctions *tj) -{ - MyRemoveTjunctions *m = static_cast< MyRemoveTjunctions *>(tj); - delete m; -} - - -}; // end of namespace - diff --git a/Engine/lib/convexDecomp/NvRemoveTjunctions.h b/Engine/lib/convexDecomp/NvRemoveTjunctions.h deleted file mode 100644 index b6a674722..000000000 --- a/Engine/lib/convexDecomp/NvRemoveTjunctions.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/NvSimpleTypes.h b/Engine/lib/convexDecomp/NvSimpleTypes.h deleted file mode 100644 index 3dddaa2fc..000000000 --- a/Engine/lib/convexDecomp/NvSimpleTypes.h +++ /dev/null @@ -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 -#else -#if defined( __FreeBSD__) - #include -#else - #include -#endif -#endif -#include - -#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 diff --git a/Engine/lib/convexDecomp/NvSplitMesh.cpp b/Engine/lib/convexDecomp/NvSplitMesh.cpp deleted file mode 100644 index 49905f91e..000000000 --- a/Engine/lib/convexDecomp/NvSplitMesh.cpp +++ /dev/null @@ -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; igetIndex( &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 diff --git a/Engine/lib/convexDecomp/NvSplitMesh.h b/Engine/lib/convexDecomp/NvSplitMesh.h deleted file mode 100644 index d9d623b54..000000000 --- a/Engine/lib/convexDecomp/NvSplitMesh.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/NvStanHull.cpp b/Engine/lib/convexDecomp/NvStanHull.cpp deleted file mode 100644 index 09448aaca..000000000 --- a/Engine/lib/convexDecomp/NvStanHull.cpp +++ /dev/null @@ -1,3464 +0,0 @@ - -/* - -NvStanHull.cpp : 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 -#include -#include -#include -#include -#include - - -#include -#include - -#include "NvStanHull.h" - -namespace CONVEX_DECOMPOSITION -{ - -//***************************************************** -//*** DARRAY.H -//***************************************************** - -template class ArrayRet; -template class Array -{ - public: - Array(NxI32 s=0); - Array(Array &array); - Array(ArrayRet &array); - ~Array(); - void allocate(NxI32 s); - void SetSize(NxI32 s); - void Pack(); - Type& Add(Type); - void AddUnique(Type); - NxI32 Contains(Type); - void Insert(Type,NxI32); - NxI32 IndexOf(Type); - void Remove(Type); - void DelIndex(NxI32 i); - Type * element; - NxI32 count; - NxI32 array_size; - const Type &operator[](NxI32 i) const { assert(i>=0 && i=0 && i &operator=(Array &array); - Array &operator=(ArrayRet &array); - // operator ArrayRet &() { return *(ArrayRet *)this;} // this worked but i suspect could be dangerous -}; - -template class ArrayRet:public Array -{ -}; - -template Array::Array(NxI32 s) -{ - count=0; - array_size = 0; - element = NULL; - if(s) - { - allocate(s); - } -} - - -template Array::Array(Array &array) -{ - count=0; - array_size = 0; - element = NULL; - for(NxI32 i=0;i Array::Array(ArrayRet &array) -{ - *this = array; -} -template Array &Array::operator=(ArrayRet &array) -{ - count=array.count; - array_size = array.array_size; - element = array.element; - array.element=NULL; - array.count=0; - array.array_size=0; - return *this; -} - - -template Array &Array::operator=(Array &array) -{ - count=0; - for(NxI32 i=0;i Array::~Array() -{ - if (element != NULL) - { - MEMALLOC_FREE(element); - } - count=0;array_size=0;element=NULL; -} - -template void Array::allocate(NxI32 s) -{ - assert(s>0); - assert(s>=count); - Type *old = element; - array_size =s; - element = (Type *) MEMALLOC_MALLOC( sizeof(Type)*array_size ); - assert(element); - for(NxI32 i=0;i void Array::SetSize(NxI32 s) -{ - if(s==0) - { - if(element) - { - MEMALLOC_FREE(element); - element = NULL; - } - array_size = s; - } - else - { - allocate(s); - } - count=s; -} - -template void Array::Pack() -{ - allocate(count); -} - -template Type& Array::Add(Type t) -{ - assert(count<=array_size); - if(count==array_size) - { - allocate((array_size)?array_size *2:16); - } - element[count++] = t; - return element[count-1]; -} - -template NxI32 Array::Contains(Type t) -{ - NxI32 i; - NxI32 found=0; - for(i=0;i void Array::AddUnique(Type t) -{ - if(!Contains(t)) Add(t); -} - - -template void Array::DelIndex(NxI32 i) -{ - assert(i void Array::Remove(Type t) -{ - NxI32 i; - for(i=0;i void Array::Insert(Type t,NxI32 k) -{ - NxI32 i=count; - Add(t); // to allocate space - while(i>k) - { - element[i]=element[i-1]; - i--; - } - assert(i==k); - element[k]=t; -} - - -template NxI32 Array::IndexOf(Type t) -{ - NxI32 i; - for(i=0;i Member )))- ((char*)NULL)) - - - -NxI32 argmin(NxF32 a[],NxI32 n); -NxF32 sqr(NxF32 a); -NxF32 clampf(NxF32 a) ; -NxF32 Round(NxF32 a,NxF32 precision); -NxF32 Interpolate(const NxF32 &f0,const NxF32 &f1,NxF32 alpha) ; - -template -void Swap(T &a,T &b) -{ - T tmp = a; - a=b; - b=tmp; -} - - - -template -T Max(const T &a,const T &b) -{ - return (a>b)?a:b; -} - -template -T Min(const T &a,const T &b) -{ - return (a=0&&i<2);return ((NxF32*)this)[i];} - const NxF32& operator[](NxI32 i) const {assert(i>=0&&i<2);return ((NxF32*)this)[i];} -}; -inline float2 operator-( const float2& a, const float2& b ){return float2(a.x-b.x,a.y-b.y);} -inline float2 operator+( const float2& a, const float2& b ){return float2(a.x+b.x,a.y+b.y);} - -//--------- 3D --------- - -class float3 : public Memalloc // 3D -{ - public: - NxF32 x,y,z; - float3(){x=0;y=0;z=0;}; - float3(NxF32 _x,NxF32 _y,NxF32 _z){x=_x;y=_y;z=_z;}; - //operator NxF32 *() { return &x;}; - NxF32& operator[](NxI32 i) {assert(i>=0&&i<3);return ((NxF32*)this)[i];} - const NxF32& operator[](NxI32 i) const {assert(i>=0&&i<3);return ((NxF32*)this)[i];} -}; - - -float3& operator+=( float3 &a, const float3& b ); -float3& operator-=( float3 &a ,const float3& b ); -float3& operator*=( float3 &v ,const NxF32 s ); -float3& operator/=( float3 &v, const NxF32 s ); - -NxF32 magnitude( const float3& v ); -float3 normalize( const float3& v ); -float3 safenormalize(const float3 &v); -float3 vabs(const float3 &v); -float3 operator+( const float3& a, const float3& b ); -float3 operator-( const float3& a, const float3& b ); -float3 operator-( const float3& v ); -float3 operator*( const float3& v, const NxF32 s ); -float3 operator*( const NxF32 s, const float3& v ); -float3 operator/( const float3& v, const NxF32 s ); -inline NxI32 operator==( const float3 &a, const float3 &b ) { return (a.x==b.x && a.y==b.y && a.z==b.z); } -inline NxI32 operator!=( const float3 &a, const float3 &b ) { return (a.x!=b.x || a.y!=b.y || a.z!=b.z); } -// due to ambiguity and inconsistent standards ther are no overloaded operators for mult such as va*vb. -NxF32 dot( const float3& a, const float3& b ); -float3 cmul( const float3 &a, const float3 &b); -float3 cross( const float3& a, const float3& b ); -float3 Interpolate(const float3 &v0,const float3 &v1,NxF32 alpha); -float3 Round(const float3& a,NxF32 precision); -float3 VectorMax(const float3 &a, const float3 &b); -float3 VectorMin(const float3 &a, const float3 &b); - - - -class float3x3 : public Memalloc -{ - public: - float3 x,y,z; // the 3 rows of the Matrix - float3x3(){} - float3x3(NxF32 xx,NxF32 xy,NxF32 xz,NxF32 yx,NxF32 yy,NxF32 yz,NxF32 zx,NxF32 zy,NxF32 zz):x(xx,xy,xz),y(yx,yy,yz),z(zx,zy,zz){} - float3x3(float3 _x,float3 _y,float3 _z):x(_x),y(_y),z(_z){} - float3& operator[](NxI32 i) {assert(i>=0&&i<3);return (&x)[i];} - const float3& operator[](NxI32 i) const {assert(i>=0&&i<3);return (&x)[i];} - NxF32& operator()(NxI32 r, NxI32 c) {assert(r>=0&&r<3&&c>=0&&c<3);return ((&x)[r])[c];} - const NxF32& operator()(NxI32 r, NxI32 c) const {assert(r>=0&&r<3&&c>=0&&c<3);return ((&x)[r])[c];} -}; -float3x3 Transpose( const float3x3& m ); -float3 operator*( const float3& v , const float3x3& m ); -float3 operator*( const float3x3& m , const float3& v ); -float3x3 operator*( const float3x3& m , const NxF32& s ); -float3x3 operator*( const float3x3& ma, const float3x3& mb ); -float3x3 operator/( const float3x3& a, const NxF32& s ) ; -float3x3 operator+( const float3x3& a, const float3x3& b ); -float3x3 operator-( const float3x3& a, const float3x3& b ); -float3x3 &operator+=( float3x3& a, const float3x3& b ); -float3x3 &operator-=( float3x3& a, const float3x3& b ); -float3x3 &operator*=( float3x3& a, const NxF32& s ); -NxF32 Determinant(const float3x3& m ); -float3x3 Inverse(const float3x3& a); // its just 3x3 so we simply do that cofactor method - - -//-------- 4D Math -------- - -class float4 : public Memalloc -{ -public: - NxF32 x,y,z,w; - float4(){x=0;y=0;z=0;w=0;}; - float4(NxF32 _x,NxF32 _y,NxF32 _z,NxF32 _w){x=_x;y=_y;z=_z;w=_w;} - float4(const float3 &v,NxF32 _w){x=v.x;y=v.y;z=v.z;w=_w;} - //operator NxF32 *() { return &x;}; - NxF32& operator[](NxI32 i) {assert(i>=0&&i<4);return ((NxF32*)this)[i];} - const NxF32& operator[](NxI32 i) const {assert(i>=0&&i<4);return ((NxF32*)this)[i];} - const float3& xyz() const { return *((float3*)this);} - float3& xyz() { return *((float3*)this);} -}; - - -struct D3DXMATRIX; - -class float4x4 : public Memalloc -{ - public: - float4 x,y,z,w; // the 4 rows - float4x4(){} - float4x4(const float4 &_x, const float4 &_y, const float4 &_z, const float4 &_w):x(_x),y(_y),z(_z),w(_w){} - float4x4(NxF32 m00, NxF32 m01, NxF32 m02, NxF32 m03, - NxF32 m10, NxF32 m11, NxF32 m12, NxF32 m13, - NxF32 m20, NxF32 m21, NxF32 m22, NxF32 m23, - NxF32 m30, NxF32 m31, NxF32 m32, NxF32 m33 ) - :x(m00,m01,m02,m03),y(m10,m11,m12,m13),z(m20,m21,m22,m23),w(m30,m31,m32,m33){} - NxF32& operator()(NxI32 r, NxI32 c) {assert(r>=0&&r<4&&c>=0&&c<4);return ((&x)[r])[c];} - const NxF32& operator()(NxI32 r, NxI32 c) const {assert(r>=0&&r<4&&c>=0&&c<4);return ((&x)[r])[c];} - operator NxF32* () {return &x.x;} - operator const NxF32* () const {return &x.x;} - operator struct D3DXMATRIX* () { return (struct D3DXMATRIX*) this;} - operator const struct D3DXMATRIX* () const { return (struct D3DXMATRIX*) this;} -}; - - -NxI32 operator==( const float4 &a, const float4 &b ); -float4 Homogenize(const float3 &v3,const NxF32 &w=1.0f); // Turns a 3D float3 4D vector4 by appending w -float4 cmul( const float4 &a, const float4 &b); -float4 operator*( const float4 &v, NxF32 s); -float4 operator*( NxF32 s, const float4 &v); -float4 operator+( const float4 &a, const float4 &b); -float4 operator-( const float4 &a, const float4 &b); -float4x4 operator*( const float4x4& a, const float4x4& b ); -float4 operator*( const float4& v, const float4x4& m ); -float4x4 Inverse(const float4x4 &m); -float4x4 MatrixRigidInverse(const float4x4 &m); -float4x4 MatrixTranspose(const float4x4 &m); -float4x4 MatrixPerspectiveFov(NxF32 fovy, NxF32 Aspect, NxF32 zn, NxF32 zf ); -float4x4 MatrixTranslation(const float3 &t); -float4x4 MatrixRotationZ(const NxF32 angle_radians); -float4x4 MatrixLookAt(const float3& eye, const float3& at, const float3& up); -NxI32 operator==( const float4x4 &a, const float4x4 &b ); - - -//-------- Quaternion ------------ - -class Quaternion :public float4 -{ - public: - Quaternion() { x = y = z = 0.0f; w = 1.0f; } - Quaternion( float3 v, NxF32 t ) { v = normalize(v); w = cosf(t/2.0f); v = v*sinf(t/2.0f); x = v.x; y = v.y; z = v.z; } - Quaternion(NxF32 _x, NxF32 _y, NxF32 _z, NxF32 _w){x=_x;y=_y;z=_z;w=_w;} - NxF32 angle() const { return acosf(w)*2.0f; } - float3 axis() const { float3 a(x,y,z); if(fabsf(angle())<0.0000001f) return float3(1,0,0); return a*(1/sinf(angle()/2.0f)); } - float3 xdir() const { return float3( 1-2*(y*y+z*z), 2*(x*y+w*z), 2*(x*z-w*y) ); } - float3 ydir() const { return float3( 2*(x*y-w*z),1-2*(x*x+z*z), 2*(y*z+w*x) ); } - float3 zdir() const { return float3( 2*(x*z+w*y), 2*(y*z-w*x),1-2*(x*x+y*y) ); } - float3x3 getmatrix() const { return float3x3( xdir(), ydir(), zdir() ); } - operator float3x3() { return getmatrix(); } - void Normalize(); -}; - -Quaternion& operator*=(Quaternion& a, NxF32 s ); -Quaternion operator*( const Quaternion& a, NxF32 s ); -Quaternion operator*( const Quaternion& a, const Quaternion& b); -Quaternion operator+( const Quaternion& a, const Quaternion& b ); -Quaternion normalize( Quaternion a ); -NxF32 dot( const Quaternion &a, const Quaternion &b ); -float3 operator*( const Quaternion& q, const float3& v ); -float3 operator*( const float3& v, const Quaternion& q ); -Quaternion slerp( Quaternion a, const Quaternion& b, NxF32 interp ); -Quaternion Interpolate(const Quaternion &q0,const Quaternion &q1,NxF32 alpha); -Quaternion RotationArc(float3 v0, float3 v1 ); // returns quat q where q*v0=v1 -Quaternion Inverse(const Quaternion &q); -float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v); - - -//------ Euler Angle ----- - -Quaternion YawPitchRoll( NxF32 yaw, NxF32 pitch, NxF32 roll ); -NxF32 Yaw( const Quaternion& q ); -NxF32 Pitch( const Quaternion& q ); -NxF32 Roll( Quaternion q ); -NxF32 Yaw( const float3& v ); -NxF32 Pitch( const float3& v ); - - -//------- Plane ---------- - -class Plane -{ - public: - float3 normal; - NxF32 dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0 - Plane(const float3 &n,NxF32 d):normal(n),dist(d){} - Plane():normal(),dist(0){} - void Transform(const float3 &position, const Quaternion &orientation); -}; - -inline Plane PlaneFlip(const Plane &plane){return Plane(-plane.normal,-plane.dist);} -inline NxI32 operator==( const Plane &a, const Plane &b ) { return (a.normal==b.normal && a.dist==b.dist); } -inline NxI32 coplanar( const Plane &a, const Plane &b ) { return (a==b || a==PlaneFlip(b)); } - - -//--------- Utility Functions ------ - -float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1); -float3 PlaneProject(const Plane &plane, const float3 &point); -float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a); // projects a onto infinite line p0p1 -NxF32 LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a); -float3 ThreePlaneIntersection(const Plane &p0,const Plane &p1, const Plane &p2); -NxI32 PolyHit(const float3 *vert,const NxI32 n,const float3 &v0, const float3 &v1, float3 *impact=NULL, float3 *normal=NULL); -NxI32 BoxInside(const float3 &p,const float3 &bmin, const float3 &bmax) ; -NxI32 BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax, float3 *impact); -NxF32 DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint=NULL, float3 *vpoint=NULL); -float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2); -float3 NormalOf(const float3 *vert, const NxI32 n); -Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir0, const float3 &dir1); - - - - -//***************************************************** -// ** VECMATH.CPP -//***************************************************** - - -NxF32 sqr(NxF32 a) {return a*a;} -NxF32 clampf(NxF32 a) {return Min(1.0f,Max(0.0f,a));} - - -NxF32 Round(NxF32 a,NxF32 precision) -{ - return floorf(0.5f+a/precision)*precision; -} - - -NxF32 Interpolate(const NxF32 &f0,const NxF32 &f1,NxF32 alpha) -{ - return f0*(1-alpha) + f1*alpha; -} - - -NxI32 argmin(NxF32 a[],NxI32 n) -{ - NxI32 r=0; - for(NxI32 i=1;i=1.0) { - return a; - } - NxF32 theta = acosf(d); - if(theta==0.0f) { return(a);} - return a*(sinf(theta-interp*theta)/sinf(theta)) + b*(sinf(interp*theta)/sinf(theta)); -} - - -Quaternion Interpolate(const Quaternion &q0,const Quaternion &q1,NxF32 alpha) { - return slerp(q0,q1,alpha); -} - - -Quaternion YawPitchRoll( NxF32 yaw, NxF32 pitch, NxF32 roll ) -{ - roll *= DEG2RAD; - yaw *= DEG2RAD; - pitch *= DEG2RAD; - return Quaternion(float3(0.0f,0.0f,1.0f),yaw)*Quaternion(float3(1.0f,0.0f,0.0f),pitch)*Quaternion(float3(0.0f,1.0f,0.0f),roll); -} - -NxF32 Yaw( const Quaternion& q ) -{ - static float3 v; - v=q.ydir(); - return (v.y==0.0&&v.x==0.0) ? 0.0f: atan2f(-v.x,v.y)*RAD2DEG; -} - -NxF32 Pitch( const Quaternion& q ) -{ - static float3 v; - v=q.ydir(); - return atan2f(v.z,sqrtf(sqr(v.x)+sqr(v.y)))*RAD2DEG; -} - -NxF32 Roll( Quaternion q ) -{ - q = Quaternion(float3(0.0f,0.0f,1.0f),-Yaw(q)*DEG2RAD) *q; - q = Quaternion(float3(1.0f,0.0f,0.0f),-Pitch(q)*DEG2RAD) *q; - return atan2f(-q.xdir().z,q.xdir().x)*RAD2DEG; -} - -NxF32 Yaw( const float3& v ) -{ - return (v.y==0.0&&v.x==0.0) ? 0.0f: atan2f(-v.x,v.y)*RAD2DEG; -} - -NxF32 Pitch( const float3& v ) -{ - return atan2f(v.z,sqrtf(sqr(v.x)+sqr(v.y)))*RAD2DEG; -} - - -//------------- Plane -------------- - - -void Plane::Transform(const float3 &position, const Quaternion &orientation) { - // Transforms the plane to the space defined by the - // given position/orientation. - static float3 newnormal; - static float3 origin; - - newnormal = Inverse(orientation)*normal; - origin = Inverse(orientation)*(-normal*dist - position); - - normal = newnormal; - dist = -dot(newnormal, origin); -} - - - - -//--------- utility functions ------------- - -// RotationArc() -// Given two vectors v0 and v1 this function -// returns quaternion q where q*v0==v1. -// Routine taken from game programming gems. -Quaternion RotationArc(float3 v0,float3 v1){ - static Quaternion q; - v0 = normalize(v0); // Comment these two lines out if you know its not needed. - v1 = normalize(v1); // If vector is already unit length then why do it again? - float3 c = cross(v0,v1); - NxF32 d = dot(v0,v1); - if(d<=-1.0f) { return Quaternion(1,0,0,0);} // 180 about x axis - NxF32 s = sqrtf((1+d)*2); - q.x = c.x / s; - q.y = c.y / s; - q.z = c.z / s; - q.w = s /2.0f; - return q; -} - - -float4x4 MatrixFromQuatVec(const Quaternion &q, const float3 &v) -{ - // builds a 4x4 transformation matrix based on orientation q and translation v - NxF32 qx2 = q.x*q.x; - NxF32 qy2 = q.y*q.y; - NxF32 qz2 = q.z*q.z; - - NxF32 qxqy = q.x*q.y; - NxF32 qxqz = q.x*q.z; - NxF32 qxqw = q.x*q.w; - NxF32 qyqz = q.y*q.z; - NxF32 qyqw = q.y*q.w; - NxF32 qzqw = q.z*q.w; - - return float4x4( - 1-2*(qy2+qz2), - 2*(qxqy+qzqw), - 2*(qxqz-qyqw), - 0 , - 2*(qxqy-qzqw), - 1-2*(qx2+qz2), - 2*(qyqz+qxqw), - 0 , - 2*(qxqz+qyqw), - 2*(qyqz-qxqw), - 1-2*(qx2+qy2), - 0 , - v.x , - v.y , - v.z , - 1.0f ); -} - - -float3 PlaneLineIntersection(const Plane &plane, const float3 &p0, const float3 &p1) -{ - // returns the point where the line p0-p1 intersects the plane n&d - static float3 dif; - dif = p1-p0; - NxF32 dn= dot(plane.normal,dif); - NxF32 t = -(plane.dist+dot(plane.normal,p0) )/dn; - return p0 + (dif*t); -} - -float3 PlaneProject(const Plane &plane, const float3 &point) -{ - return point - plane.normal * (dot(point,plane.normal)+plane.dist); -} - -float3 LineProject(const float3 &p0, const float3 &p1, const float3 &a) -{ - float3 w; - w = p1-p0; - NxF32 t= dot(w,(a-p0)) / (sqr(w.x)+sqr(w.y)+sqr(w.z)); - return p0+ w*t; -} - - -NxF32 LineProjectTime(const float3 &p0, const float3 &p1, const float3 &a) -{ - float3 w; - w = p1-p0; - NxF32 t= dot(w,(a-p0)) / (sqr(w.x)+sqr(w.y)+sqr(w.z)); - return t; -} - - - -float3 TriNormal(const float3 &v0, const float3 &v1, const float3 &v2) -{ - // return the normal of the triangle - // inscribed by v0, v1, and v2 - float3 cp=cross(v1-v0,v2-v1); - NxF32 m=magnitude(cp); - if(m==0) return float3(1,0,0); - return cp*(1.0f/m); -} - - - -NxI32 BoxInside(const float3 &p, const float3 &bmin, const float3 &bmax) -{ - return (p.x >= bmin.x && p.x <=bmax.x && - p.y >= bmin.y && p.y <=bmax.y && - p.z >= bmin.z && p.z <=bmax.z ); -} - - -NxI32 BoxIntersect(const float3 &v0, const float3 &v1, const float3 &bmin, const float3 &bmax,float3 *impact) -{ - if(BoxInside(v0,bmin,bmax)) - { - *impact=v0; - return 1; - } - if(v0.x<=bmin.x && v1.x>=bmin.x) - { - NxF32 a = (bmin.x-v0.x)/(v1.x-v0.x); - //v.x = bmin.x; - NxF32 vy = (1-a) *v0.y + a*v1.y; - NxF32 vz = (1-a) *v0.z + a*v1.z; - if(vy>=bmin.y && vy<=bmax.y && vz>=bmin.z && vz<=bmax.z) - { - impact->x = bmin.x; - impact->y = vy; - impact->z = vz; - return 1; - } - } - else if(v0.x >= bmax.x && v1.x <= bmax.x) - { - NxF32 a = (bmax.x-v0.x)/(v1.x-v0.x); - //v.x = bmax.x; - NxF32 vy = (1-a) *v0.y + a*v1.y; - NxF32 vz = (1-a) *v0.z + a*v1.z; - if(vy>=bmin.y && vy<=bmax.y && vz>=bmin.z && vz<=bmax.z) - { - impact->x = bmax.x; - impact->y = vy; - impact->z = vz; - return 1; - } - } - if(v0.y<=bmin.y && v1.y>=bmin.y) - { - NxF32 a = (bmin.y-v0.y)/(v1.y-v0.y); - NxF32 vx = (1-a) *v0.x + a*v1.x; - //v.y = bmin.y; - NxF32 vz = (1-a) *v0.z + a*v1.z; - if(vx>=bmin.x && vx<=bmax.x && vz>=bmin.z && vz<=bmax.z) - { - impact->x = vx; - impact->y = bmin.y; - impact->z = vz; - return 1; - } - } - else if(v0.y >= bmax.y && v1.y <= bmax.y) - { - NxF32 a = (bmax.y-v0.y)/(v1.y-v0.y); - NxF32 vx = (1-a) *v0.x + a*v1.x; - // vy = bmax.y; - NxF32 vz = (1-a) *v0.z + a*v1.z; - if(vx>=bmin.x && vx<=bmax.x && vz>=bmin.z && vz<=bmax.z) - { - impact->x = vx; - impact->y = bmax.y; - impact->z = vz; - return 1; - } - } - if(v0.z<=bmin.z && v1.z>=bmin.z) - { - NxF32 a = (bmin.z-v0.z)/(v1.z-v0.z); - NxF32 vx = (1-a) *v0.x + a*v1.x; - NxF32 vy = (1-a) *v0.y + a*v1.y; - // v.z = bmin.z; - if(vy>=bmin.y && vy<=bmax.y && vx>=bmin.x && vx<=bmax.x) - { - impact->x = vx; - impact->y = vy; - impact->z = bmin.z; - return 1; - } - } - else if(v0.z >= bmax.z && v1.z <= bmax.z) - { - NxF32 a = (bmax.z-v0.z)/(v1.z-v0.z); - NxF32 vx = (1-a) *v0.x + a*v1.x; - NxF32 vy = (1-a) *v0.y + a*v1.y; - // v.z = bmax.z; - if(vy>=bmin.y && vy<=bmax.y && vx>=bmin.x && vx<=bmax.x) - { - impact->x = vx; - impact->y = vy; - impact->z = bmax.z; - return 1; - } - } - return 0; -} - - -NxF32 DistanceBetweenLines(const float3 &ustart, const float3 &udir, const float3 &vstart, const float3 &vdir, float3 *upoint, float3 *vpoint) -{ - static float3 cp; - cp = normalize(cross(udir,vdir)); - - NxF32 distu = -dot(cp,ustart); - NxF32 distv = -dot(cp,vstart); - NxF32 dist = (NxF32)fabs(distu-distv); - if(upoint) - { - Plane plane; - plane.normal = normalize(cross(vdir,cp)); - plane.dist = -dot(plane.normal,vstart); - *upoint = PlaneLineIntersection(plane,ustart,ustart+udir); - } - if(vpoint) - { - Plane plane; - plane.normal = normalize(cross(udir,cp)); - plane.dist = -dot(plane.normal,ustart); - *vpoint = PlaneLineIntersection(plane,vstart,vstart+vdir); - } - return dist; -} - - -Quaternion VirtualTrackBall(const float3 &cop, const float3 &cor, const float3 &dir1, const float3 &dir2) -{ - // routine taken from game programming gems. - // Implement track ball functionality to spin stuf on the screen - // cop center of projection - // cor center of rotation - // dir1 old mouse direction - // dir2 new mouse direction - // pretend there is a sphere around cor. Then find the points - // where dir1 and dir2 intersect that sphere. Find the - // rotation that takes the first point to the second. - NxF32 m; - // compute plane - float3 nrml = cor - cop; - NxF32 fudgefactor = 1.0f/(magnitude(nrml) * 0.25f); // since trackball proportional to distance from cop - nrml = normalize(nrml); - NxF32 dist = -dot(nrml,cor); - float3 u= PlaneLineIntersection(Plane(nrml,dist),cop,cop+dir1); - u=u-cor; - u=u*fudgefactor; - m= magnitude(u); - if(m>1) - { - u/=m; - } - else - { - u=u - (nrml * sqrtf(1-m*m)); - } - float3 v= PlaneLineIntersection(Plane(nrml,dist),cop,cop+dir2); - v=v-cor; - v=v*fudgefactor; - m= magnitude(v); - if(m>1) - { - v/=m; - } - else - { - v=v - (nrml * sqrtf(1-m*m)); - } - return RotationArc(u,v); -} - - -NxI32 countpolyhit=0; -NxI32 PolyHit(const float3 *vert, const NxI32 n, const float3 &v0, const float3 &v1, float3 *impact, float3 *normal) -{ - countpolyhit++; - NxI32 i; - float3 nrml(0,0,0); - for(i=0;i0) - { - return 0; - } - - static float3 the_point; - // By using the cached plane distances d0 and d1 - // we can optimize the following: - // the_point = planelineintersection(nrml,dist,v0,v1); - NxF32 a = d0/(d0-d1); - the_point = v0*(1-a) + v1*a; - - - NxI32 inside=1; - for(NxI32 j=0;inside && j= 0.0); - } - if(inside) - { - if(normal){*normal=nrml;} - if(impact){*impact=the_point;} - } - return inside; -} - -//**************************************************** -// HULL.H source code goes here -//**************************************************** -class PHullResult -{ -public: - - PHullResult(void) - { - mVcount = 0; - mIndexCount = 0; - mFaceCount = 0; - mVertices = 0; - mIndices = 0; - } - - NxU32 mVcount; - NxU32 mIndexCount; - NxU32 mFaceCount; - NxF32 *mVertices; - NxU32 *mIndices; -}; - -bool ComputeHull(NxU32 vcount,const NxF32 *vertices,PHullResult &result,NxU32 maxverts,NxF32 inflate); -void ReleaseHull(PHullResult &result); - -//***************************************************** -// HULL.cpp source code goes here -//***************************************************** - - -#define REAL3 float3 -#define REAL NxF32 - -#define COPLANAR (0) -#define UNDER (1) -#define OVER (2) -#define SPLIT (OVER|UNDER) -#define PAPERWIDTH (0.001f) -#define VOLUME_EPSILON (1e-20f) - -NxF32 planetestepsilon = PAPERWIDTH; - -class ConvexH : public Memalloc -{ - public: - class HalfEdge - { - public: - short ea; // the other half of the edge (index into edges list) - NxU8 v; // the vertex at the start of this edge (index into vertices list) - NxU8 p; // the facet on which this edge lies (index into facets list) - HalfEdge(){} - HalfEdge(short _ea,NxU8 _v, NxU8 _p):ea(_ea),v(_v),p(_p){} - }; - Array vertices; - Array edges; - Array facets; - ConvexH(NxI32 vertices_size,NxI32 edges_size,NxI32 facets_size); -}; - -typedef ConvexH::HalfEdge HalfEdge; - -ConvexH::ConvexH(NxI32 vertices_size,NxI32 edges_size,NxI32 facets_size) - :vertices(vertices_size) - ,edges(edges_size) - ,facets(facets_size) -{ - vertices.count=vertices_size; - edges.count = edges_size; - facets.count = facets_size; -} - -ConvexH *ConvexHDup(ConvexH *src) -{ - ConvexH *dst = MEMALLOC_NEW(ConvexH)(src->vertices.count,src->edges.count,src->facets.count); - - memcpy(dst->vertices.element,src->vertices.element,sizeof(float3)*src->vertices.count); - memcpy(dst->edges.element,src->edges.element,sizeof(HalfEdge)*src->edges.count); - memcpy(dst->facets.element,src->facets.element,sizeof(Plane)*src->facets.count); - return dst; -} - - -NxI32 PlaneTest(const Plane &p, const REAL3 &v) { - REAL a = dot(v,p.normal)+p.dist; - NxI32 flag = (a>planetestepsilon)?OVER:((a<-planetestepsilon)?UNDER:COPLANAR); - return flag; -} - -NxI32 SplitTest(ConvexH &convex,const Plane &plane) { - NxI32 flag=0; - for(NxI32 i=0;i= convex.edges.count || convex.edges[inext].p != convex.edges[i].p) { - inext = estart; - } - assert(convex.edges[inext].p == convex.edges[i].p); - NxI32 nb = convex.edges[i].ea; - assert(nb!=255); - if(nb==255 || nb==-1) return 0; - assert(nb!=-1); - assert(i== convex.edges[nb].ea); - } - for(i=0;i= convex.edges.count || convex.edges[i1].p != convex.edges[i].p) { - i1 = estart; - } - NxI32 i2 = i1+1; - if(i2>= convex.edges.count || convex.edges[i2].p != convex.edges[i].p) { - i2 = estart; - } - if(i==i2) continue; // i sliced tangent to an edge and created 2 meaningless edges - REAL3 localnormal = TriNormal(convex.vertices[convex.edges[i ].v], - convex.vertices[convex.edges[i1].v], - convex.vertices[convex.edges[i2].v]); - //assert(dot(localnormal,convex.facets[convex.edges[i].p].normal)>0);//Commented out on Stan Melax' advice - if(dot(localnormal,convex.facets[convex.edges[i].p].normal)<=0)return 0; - } - return 1; -} - -ConvexH *ConvexHCrop(ConvexH &convex,const Plane &slice) -{ - NxI32 i; - NxI32 vertcountunder=0; - NxI32 vertcountover =0; - static Array vertscoplanar; // existing vertex members of convex that are coplanar - vertscoplanar.count=0; - static Array edgesplit; // existing edges that members of convex that cross the splitplane - edgesplit.count=0; - - assert(convex.edges.count<480); - - EdgeFlag edgeflag[512]; - VertFlag vertflag[256]; - PlaneFlag planeflag[128]; - HalfEdge tmpunderedges[512]; - Plane tmpunderplanes[128]; - Coplanar coplanaredges[512]; - NxI32 coplanaredges_num=0; - - Array createdverts; - // do the side-of-plane tests - for(i=0;i= convex.edges.count || convex.edges[e1].p!=currentplane) { - enextface = e1; - e1=estart; - } - HalfEdge &edge0 = convex.edges[e0]; - HalfEdge &edge1 = convex.edges[e1]; - HalfEdge &edgea = convex.edges[edge0.ea]; - - - planeside |= vertflag[edge0.v].planetest; - //if((vertflag[edge0.v].planetest & vertflag[edge1.v].planetest) == COPLANAR) { - // assert(ecop==-1); - // ecop=e; - //} - - - if(vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == OVER){ - // both endpoints over plane - edgeflag[e0].undermap = -1; - } - else if((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == UNDER) { - // at least one endpoint under, the other coplanar or under - - edgeflag[e0].undermap = (short)under_edge_count; - tmpunderedges[under_edge_count].v = (NxU8)vertflag[edge0.v].undermap; - tmpunderedges[under_edge_count].p = (NxU8)underplanescount; - if(edge0.ea < e0) { - // connect the neighbors - assert(edgeflag[edge0.ea].undermap !=-1); - tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; - tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; - } - under_edge_count++; - } - else if((vertflag[edge0.v].planetest | vertflag[edge1.v].planetest) == COPLANAR) { - // both endpoints coplanar - // must check a 3rd point to see if UNDER - NxI32 e2 = e1+1; - if(e2>=convex.edges.count || convex.edges[e2].p!=currentplane) { - e2 = estart; - } - assert(convex.edges[e2].p==currentplane); - HalfEdge &edge2 = convex.edges[e2]; - if(vertflag[edge2.v].planetest==UNDER) { - - edgeflag[e0].undermap = (short)under_edge_count; - tmpunderedges[under_edge_count].v = (NxU8)vertflag[edge0.v].undermap; - tmpunderedges[under_edge_count].p = (NxU8)underplanescount; - tmpunderedges[under_edge_count].ea = -1; - // make sure this edge is added to the "coplanar" list - coplanaredge = under_edge_count; - vout = vertflag[edge0.v].undermap; - vin = vertflag[edge1.v].undermap; - under_edge_count++; - } - else { - edgeflag[e0].undermap = -1; - } - } - else if(vertflag[edge0.v].planetest == UNDER && vertflag[edge1.v].planetest == OVER) { - // first is under 2nd is over - - edgeflag[e0].undermap = (short) under_edge_count; - tmpunderedges[under_edge_count].v = (NxU8)vertflag[edge0.v].undermap; - tmpunderedges[under_edge_count].p = (NxU8)underplanescount; - if(edge0.ea < e0) { - assert(edgeflag[edge0.ea].undermap !=-1); - // connect the neighbors - tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; - tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; - vout = tmpunderedges[edgeflag[edge0.ea].undermap].v; - } - else { - Plane &p0 = convex.facets[edge0.p]; - Plane &pa = convex.facets[edgea.p]; - createdverts.Add(ThreePlaneIntersection(p0,pa,slice)); - //createdverts.Add(PlaneProject(slice,PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v]))); - //createdverts.Add(PlaneLineIntersection(slice,convex.vertices[edge0.v],convex.vertices[edgea.v])); - vout = vertcountunder++; - } - under_edge_count++; - /// hmmm something to think about: i might be able to output this edge regarless of - // wheter or not we know v-in yet. ok i;ll try this now: - tmpunderedges[under_edge_count].v = (NxU8)vout; - tmpunderedges[under_edge_count].p = (NxU8)underplanescount; - tmpunderedges[under_edge_count].ea = -1; - coplanaredge = under_edge_count; - under_edge_count++; - - if(vin!=-1) { - // we previously processed an edge where we came under - // now we know about vout as well - - // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! - } - - } - else if(vertflag[edge0.v].planetest == COPLANAR && vertflag[edge1.v].planetest == OVER) { - // first is coplanar 2nd is over - - edgeflag[e0].undermap = -1; - vout = vertflag[edge0.v].undermap; - // I hate this but i have to make sure part of this face is UNDER before ouputting this vert - NxI32 k=estart; - assert(edge0.p == currentplane); - while(!(planeside&UNDER) && kedge0.ea) { - assert(edgeflag[edge0.ea].undermap !=-1); - // connect the neighbors - tmpunderedges[under_edge_count].ea = edgeflag[edge0.ea].undermap; - tmpunderedges[edgeflag[edge0.ea].undermap].ea = (short)under_edge_count; - } - assert(edgeflag[e0].undermap == under_edge_count); - under_edge_count++; - } - else if(vertflag[edge0.v].planetest == OVER && vertflag[edge1.v].planetest == COPLANAR) { - // first is over next is coplanar - - edgeflag[e0].undermap = -1; - vin = vertflag[edge1.v].undermap; - if (vin==-1) return NULL; - if(vout!=-1) { - // we previously processed an edge where we came under - // now we know both endpoints - // ADD THIS EDGE TO THE LIST OF EDGES THAT NEED NEIGHBOR ON PARTITION PLANE!! - } - - } - else { - assert(0); - } - - - e0=e1; - e1++; // do the modulo at the beginning of the loop - - } while(e0!=estart) ; - e0 = enextface; - if(planeside&UNDER) { - planeflag[currentplane].undermap = (NxU8)underplanescount; - tmpunderplanes[underplanescount] = convex.facets[currentplane]; - underplanescount++; - } - else { - planeflag[currentplane].undermap = 0; - } - if(vout>=0 && (planeside&UNDER)) { - assert(vin>=0); - assert(coplanaredge>=0); - assert(coplanaredge!=511); - coplanaredges[coplanaredges_num].ea = (short)coplanaredge; - coplanaredges[coplanaredges_num].v0 = (NxU8)vin; - coplanaredges[coplanaredges_num].v1 = (NxU8)vout; - coplanaredges_num++; - } - } - - // add the new plane to the mix: - if(coplanaredges_num>0) { - tmpunderplanes[underplanescount++]=slice; - } - for(i=0;i=coplanaredges_num) - { - // assert(jvertices.count;j++) - { - dmax = Max(dmax,dot(convex->vertices[j],planes[i].normal)+planes[i].dist); - dmin = Min(dmin,dot(convex->vertices[j],planes[i].normal)+planes[i].dist); - } - NxF32 dr = dmax-dmin; - if(drfacets.count;j++) - { - if(planes[i]==convex->facets[j]) - { - d=0;continue; - } - if(dot(planes[i].normal,convex->facets[j].normal)>maxdot_minang) - { - for(NxI32 k=0;kedges.count;k++) - { - if(convex->edges[k].p!=j) continue; - if(dot(convex->vertices[convex->edges[k].v],planes[i].normal)+planes[i].dist<0) - { - d=0; // so this plane wont get selected. - break; - } - } - } - } - if(d>md) - { - p=i; - md=d; - } - } - return (md>epsilon)?p:-1; -} - - - -template -inline NxI32 maxdir(const T *p,NxI32 count,const T &dir) -{ - assert(count); - NxI32 m=0; - for(NxI32 i=1;idot(p[m],dir)) m=i; - } - return m; -} - - -template -NxI32 maxdirfiltered(const T *p,NxI32 count,const T &dir,Array &allow) -{ - assert(count); - NxI32 m=-1; - for(NxI32 i=0;idot(p[m],dir)) m=i; - } - assert(m!=-1); - return m; -} - -float3 orth(const float3 &v) -{ - float3 a=cross(v,float3(0,0,1)); - float3 b=cross(v,float3(0,1,0)); - return normalize((magnitude(a)>magnitude(b))?a:b); -} - - -template -NxI32 maxdirsterid(const T *p,NxI32 count,const T &dir,Array &allow) -{ - NxI32 m=-1; - while(m==-1) - { - m = maxdirfiltered(p,count,dir,allow); - if(allow[m]==3) return m; - T u = orth(dir); - T v = cross(u,dir); - NxI32 ma=-1; - for(NxF32 x = 0.0f ; x<= 360.0f ; x+= 45.0f) - { - NxF32 s = sinf(DEG2RAD*(x)); - NxF32 c = cosf(DEG2RAD*(x)); - NxI32 mb = maxdirfiltered(p,count,dir+(u*s+v*c)*0.025f,allow); - if(ma==m && mb==m) - { - allow[m]=3; - return m; - } - if(ma!=-1 && ma!=mb) // Yuck - this is really ugly - { - NxI32 mc = ma; - for(NxF32 xx = x-40.0f ; xx <= x ; xx+= 5.0f) - { - NxF32 s = sinf(DEG2RAD*(xx)); - NxF32 c = cosf(DEG2RAD*(xx)); - NxI32 md = maxdirfiltered(p,count,dir+(u*s+v*c)*0.025f,allow); - if(mc==m && md==m) - { - allow[m]=3; - return m; - } - mc=md; - } - } - ma=mb; - } - allow[m]=0; - m=-1; - } - assert(0); - return m; -} - - - - -NxI32 operator ==(const int3 &a,const int3 &b) -{ - for(NxI32 i=0;i<3;i++) - { - if(a[i]!=b[i]) return 0; - } - return 1; -} - -int3 roll3(int3 a) -{ - NxI32 tmp=a[0]; - a[0]=a[1]; - a[1]=a[2]; - a[2]=tmp; - return a; -} -NxI32 isa(const int3 &a,const int3 &b) -{ - return ( a==b || roll3(a)==b || a==roll3(b) ); -} -NxI32 b2b(const int3 &a,const int3 &b) -{ - return isa(a,int3(b[2],b[1],b[0])); -} -NxI32 above(float3* vertices,const int3& t, const float3 &p, NxF32 epsilon) -{ - float3 n=TriNormal(vertices[t[0]],vertices[t[1]],vertices[t[2]]); - return (dot(n,p-vertices[t[0]]) > epsilon); // EPSILON??? -} -NxI32 hasedge(const int3 &t, NxI32 a,NxI32 b) -{ - for(NxI32 i=0;i<3;i++) - { - NxI32 i1= (i+1)%3; - if(t[i]==a && t[i1]==b) return 1; - } - return 0; -} -NxI32 hasvert(const int3 &t, NxI32 v) -{ - return (t[0]==v || t[1]==v || t[2]==v) ; -} -NxI32 shareedge(const int3 &a,const int3 &b) -{ - NxI32 i; - for(i=0;i<3;i++) - { - NxI32 i1= (i+1)%3; - if(hasedge(a,b[i1],b[i])) return 1; - } - return 0; -} - -class Tri; - -static Array tris; // djs: For heaven's sake!!!! - -class Tri : public int3 -{ -public: - int3 n; - NxI32 id; - NxI32 vmax; - NxF32 rise; - Tri(NxI32 a,NxI32 b,NxI32 c):int3(a,b,c),n(-1,-1,-1) - { - id = tris.count; - tris.Add(this); - vmax=-1; - rise = 0.0f; - } - ~Tri() - { - assert(tris[id]==this); - tris[id]=NULL; - } - NxI32 &neib(NxI32 a,NxI32 b); -}; - - -NxI32 &Tri::neib(NxI32 a,NxI32 b) -{ - static NxI32 er=-1; - NxI32 i; - for(i=0;i<3;i++) - { - NxI32 i1=(i+1)%3; - NxI32 i2=(i+2)%3; - if((*this)[i]==a && (*this)[i1]==b) return n[i2]; - if((*this)[i]==b && (*this)[i1]==a) return n[i2]; - } - assert(0); - return er; -} -void b2bfix(Tri* s,Tri*t) -{ - NxI32 i; - for(i=0;i<3;i++) - { - NxI32 i1=(i+1)%3; - NxI32 i2=(i+2)%3; - NxI32 a = (*s)[i1]; - NxI32 b = (*s)[i2]; - assert(tris[s->neib(a,b)]->neib(b,a) == s->id); - assert(tris[t->neib(a,b)]->neib(b,a) == t->id); - tris[s->neib(a,b)]->neib(b,a) = t->neib(b,a); - tris[t->neib(b,a)]->neib(a,b) = s->neib(a,b); - } -} - -void removeb2b(Tri* s,Tri*t) -{ - b2bfix(s,t); - delete s; - delete t; -} - -void extrude(Tri *t0,NxI32 v) -{ - int3 t= *t0; - NxI32 n = tris.count; - Tri* ta = MEMALLOC_NEW(Tri)(v,t[1],t[2]); - ta->n = int3(t0->n[0],n+1,n+2); - tris[t0->n[0]]->neib(t[1],t[2]) = n+0; - Tri* tb = MEMALLOC_NEW(Tri)(v,t[2],t[0]); - tb->n = int3(t0->n[1],n+2,n+0); - tris[t0->n[1]]->neib(t[2],t[0]) = n+1; - Tri* tc = MEMALLOC_NEW(Tri)(v,t[0],t[1]); - tc->n = int3(t0->n[2],n+0,n+1); - tris[t0->n[2]]->neib(t[0],t[1]) = n+2; - if(hasvert(*tris[ta->n[0]],v)) removeb2b(ta,tris[ta->n[0]]); - if(hasvert(*tris[tb->n[0]],v)) removeb2b(tb,tris[tb->n[0]]); - if(hasvert(*tris[tc->n[0]],v)) removeb2b(tc,tris[tc->n[0]]); - delete t0; - -} - -Tri *extrudable(NxF32 epsilon) -{ - NxI32 i; - Tri *t=NULL; - for(i=0;iriserise)) - { - t = tris[i]; - } - } - return (t->rise >epsilon)?t:NULL ; -} - -class int4 -{ -public: - NxI32 x,y,z,w; - int4(){}; - int4(NxI32 _x,NxI32 _y, NxI32 _z,NxI32 _w){x=_x;y=_y;z=_z;w=_w;} - const NxI32& operator[](NxI32 i) const {return (&x)[i];} - NxI32& operator[](NxI32 i) {return (&x)[i];} -}; - - - -bool hasVolume(float3 *verts, NxI32 p0, NxI32 p1, NxI32 p2, NxI32 p3) -{ - float3 result3 = cross(verts[p1]-verts[p0], verts[p2]-verts[p0]); - if (magnitude(result3) < VOLUME_EPSILON && magnitude(result3) > -VOLUME_EPSILON) // Almost collinear or otherwise very close to each other - return false; - NxF32 result = dot(normalize(result3), verts[p3]-verts[p0]); - return (result > VOLUME_EPSILON || result < -VOLUME_EPSILON); // Returns true iff volume is significantly non-zero -} - -int4 FindSimplex(float3 *verts,NxI32 verts_count,Array &allow) -{ - float3 basis[3]; - basis[0] = float3( 0.01f, 0.02f, 1.0f ); - NxI32 p0 = maxdirsterid(verts,verts_count, basis[0],allow); - NxI32 p1 = maxdirsterid(verts,verts_count,-basis[0],allow); - basis[0] = verts[p0]-verts[p1]; - if(p0==p1 || basis[0]==float3(0,0,0)) - return int4(-1,-1,-1,-1); - basis[1] = cross(float3( 1, 0.02f, 0),basis[0]); - basis[2] = cross(float3(-0.02f, 1, 0),basis[0]); - basis[1] = normalize( (magnitude(basis[1])>magnitude(basis[2])) ? basis[1]:basis[2]); - NxI32 p2 = maxdirsterid(verts,verts_count,basis[1],allow); - if(p2 == p0 || p2 == p1) - { - p2 = maxdirsterid(verts,verts_count,-basis[1],allow); - } - if(p2 == p0 || p2 == p1) - return int4(-1,-1,-1,-1); - basis[1] = verts[p2] - verts[p0]; - basis[2] = normalize(cross(basis[1],basis[0])); - NxI32 p3 = maxdirsterid(verts,verts_count,basis[2],allow); - if(p3==p0||p3==p1||p3==p2||!hasVolume(verts, p0, p1, p2, p3)) p3 = maxdirsterid(verts,verts_count,-basis[2],allow); - if(p3==p0||p3==p1||p3==p2) - return int4(-1,-1,-1,-1); - assert(!(p0==p1||p0==p2||p0==p3||p1==p2||p1==p3||p2==p3)); - if(dot(verts[p3]-verts[p0],cross(verts[p1]-verts[p0],verts[p2]-verts[p0])) <0) {Swap(p2,p3);} - return int4(p0,p1,p2,p3); -} -#pragma warning(push) -#pragma warning(disable:4706) -NxI32 calchullgen(float3 *verts,NxI32 verts_count, NxI32 vlimit) -{ - if(verts_count <4) return 0; - if(vlimit==0) vlimit=1000000000; - NxI32 j; - float3 bmin(*verts),bmax(*verts); - Array isextreme(verts_count); - Array allow(verts_count); - for(j=0;jn=int3(2,3,1); - Tri *t1 = MEMALLOC_NEW(Tri)(p[3],p[2],p[0]); t1->n=int3(3,2,0); - Tri *t2 = MEMALLOC_NEW(Tri)(p[0],p[1],p[3]); t2->n=int3(0,1,3); - Tri *t3 = MEMALLOC_NEW(Tri)(p[1],p[0],p[2]); t3->n=int3(1,0,2); - isextreme[p[0]]=isextreme[p[1]]=isextreme[p[2]]=isextreme[p[3]]=1; - - for(j=0;jvmax<0); - float3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); - t->vmax = maxdirsterid(verts,verts_count,n,allow); - t->rise = dot(n,verts[t->vmax]-verts[(*t)[0]]); - } - Tri *te; - vlimit-=4; - while(vlimit >0 && (te=extrudable(epsilon))) - { - int3 ti=*te; - NxI32 v=te->vmax; - assert(!isextreme[v]); // wtf we've already done this vertex - isextreme[v]=1; - //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already - j=tris.count; - while(j--) { - if(!tris[j]) continue; - int3 t=*tris[j]; - if(above(verts,t,verts[v],0.01f*epsilon)) - { - extrude(tris[j],v); - } - } - // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle - j=tris.count; - while(j--) - { - if(!tris[j]) continue; - if(!hasvert(*tris[j],v)) break; - int3 nt=*tris[j]; - if(above(verts,nt,center,0.01f*epsilon) || magnitude(cross(verts[nt[1]]-verts[nt[0]],verts[nt[2]]-verts[nt[1]]))< epsilon*epsilon*0.1f ) - { - Tri *nb = tris[tris[j]->n[0]]; - assert(nb);assert(!hasvert(*nb,v));assert(nb->idvmax>=0) break; - float3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); - t->vmax = maxdirsterid(verts,verts_count,n,allow); - if(isextreme[t->vmax]) - { - t->vmax=-1; // already done that vertex - algorithm needs to be able to terminate. - } - else - { - t->rise = dot(n,verts[t->vmax]-verts[(*t)[0]]); - } - } - vlimit --; - } - return 1; -} -#pragma warning(pop) - -NxI32 calchull(float3 *verts,NxI32 verts_count, NxI32 *&tris_out, NxI32 &tris_count,NxI32 vlimit) -{ - NxI32 rc=calchullgen(verts,verts_count, vlimit) ; - if(!rc) return 0; - Array ts; - for(NxI32 i=0;i &planes,NxF32 bevangle) -{ - NxI32 i,j; - Array bplanes; - planes.count=0; - NxI32 rc = calchullgen(verts,verts_count,vlimit); - if(!rc) return 0; - extern NxF32 minadjangle; // default is 3.0f; // in degrees - result wont have two adjacent facets within this angle of each other. - NxF32 maxdot_minang = cosf(DEG2RAD*minadjangle); - for(i=0;in[j]id) continue; - Tri *s = tris[t->n[j]]; - REAL3 snormal = TriNormal(verts[(*s)[0]],verts[(*s)[1]],verts[(*s)[2]]); - if(dot(snormal,p.normal)>=cos(bevangle*DEG2RAD)) continue; - REAL3 e = verts[(*t)[(j+2)%3]] - verts[(*t)[(j+1)%3]]; - REAL3 n = (e!=REAL3(0,0,0))? cross(snormal,e)+cross(e,p.normal) : snormal+p.normal; - assert(n!=REAL3(0,0,0)); - if(n==REAL3(0,0,0)) return 0; - n=normalize(n); - bplanes.Add(Plane(n,-dot(n,verts[maxdir(verts,verts_count,n)]))); - } - } - for(i=0;imaxdot_minang) - { - // somebody has to die, keep the biggest triangle - if( area2(verts[(*ti)[0]],verts[(*ti)[1]],verts[(*ti)[2]]) < area2(verts[(*tj)[0]],verts[(*tj)[1]],verts[(*tj)[2]])) - { - delete tris[i]; - } - else - { - delete tris[j]; - } - } - } - for(i=0;imaxdot_minang) break; - } - if(j==planes.count) - { - planes.Add(bplanes[i]); - } - } - for(i=0;ivertices[0] = REAL3(0,0,0); - convex->vertices[1] = REAL3(0,0,1); - convex->vertices[2] = REAL3(0,1,0); - convex->vertices[3] = REAL3(0,1,1); - convex->vertices[4] = REAL3(1,0,0); - convex->vertices[5] = REAL3(1,0,1); - convex->vertices[6] = REAL3(1,1,0); - convex->vertices[7] = REAL3(1,1,1); - - convex->facets[0] = Plane(REAL3(-1,0,0),0); - convex->facets[1] = Plane(REAL3(1,0,0),-1); - convex->facets[2] = Plane(REAL3(0,-1,0),0); - convex->facets[3] = Plane(REAL3(0,1,0),-1); - convex->facets[4] = Plane(REAL3(0,0,-1),0); - convex->facets[5] = Plane(REAL3(0,0,1),-1); - - convex->edges[0 ] = HalfEdge(11,0,0); - convex->edges[1 ] = HalfEdge(23,1,0); - convex->edges[2 ] = HalfEdge(15,3,0); - convex->edges[3 ] = HalfEdge(16,2,0); - - convex->edges[4 ] = HalfEdge(13,6,1); - convex->edges[5 ] = HalfEdge(21,7,1); - convex->edges[6 ] = HalfEdge( 9,5,1); - convex->edges[7 ] = HalfEdge(18,4,1); - - convex->edges[8 ] = HalfEdge(19,0,2); - convex->edges[9 ] = HalfEdge( 6,4,2); - convex->edges[10] = HalfEdge(20,5,2); - convex->edges[11] = HalfEdge( 0,1,2); - - convex->edges[12] = HalfEdge(22,3,3); - convex->edges[13] = HalfEdge( 4,7,3); - convex->edges[14] = HalfEdge(17,6,3); - convex->edges[15] = HalfEdge( 2,2,3); - - convex->edges[16] = HalfEdge( 3,0,4); - convex->edges[17] = HalfEdge(14,2,4); - convex->edges[18] = HalfEdge( 7,6,4); - convex->edges[19] = HalfEdge( 8,4,4); - - convex->edges[20] = HalfEdge(10,1,5); - convex->edges[21] = HalfEdge( 5,5,5); - convex->edges[22] = HalfEdge(12,7,5); - convex->edges[23] = HalfEdge( 1,3,5); - - - return convex; -} - -ConvexH *ConvexHMakeCube(const REAL3 &bmin, const REAL3 &bmax) -{ - ConvexH *convex = test_cube(); - convex->vertices[0] = REAL3(bmin.x,bmin.y,bmin.z); - convex->vertices[1] = REAL3(bmin.x,bmin.y,bmax.z); - convex->vertices[2] = REAL3(bmin.x,bmax.y,bmin.z); - convex->vertices[3] = REAL3(bmin.x,bmax.y,bmax.z); - convex->vertices[4] = REAL3(bmax.x,bmin.y,bmin.z); - convex->vertices[5] = REAL3(bmax.x,bmin.y,bmax.z); - convex->vertices[6] = REAL3(bmax.x,bmax.y,bmin.z); - convex->vertices[7] = REAL3(bmax.x,bmax.y,bmax.z); - - convex->facets[0] = Plane(REAL3(-1,0,0), bmin.x); - convex->facets[1] = Plane(REAL3(1,0,0), -bmax.x); - convex->facets[2] = Plane(REAL3(0,-1,0), bmin.y); - convex->facets[3] = Plane(REAL3(0,1,0), -bmax.y); - convex->facets[4] = Plane(REAL3(0,0,-1), bmin.z); - convex->facets[5] = Plane(REAL3(0,0,1), -bmax.z); - return convex; -} - - -static NxI32 overhull(Plane *planes,NxI32 planes_count,float3 *verts, NxI32 verts_count,NxI32 maxplanes, - float3 *&verts_out, NxI32 &verts_count_out, NxI32 *&faces_out, NxI32 &faces_count_out ,NxF32 inflate) -{ - NxI32 i,j; - if (verts_count < 4) return 0; - maxplanes = Min(maxplanes,planes_count); - float3 bmin(verts[0]),bmax(verts[0]); - for(i=0;i maxdot_minang) - { - (*((j%2)?&bmax:&bmin)) += n * (diameter*0.5f); - break; - } - } - } - ConvexH *c = ConvexHMakeCube(REAL3(bmin),REAL3(bmax)); - NxI32 k; - while(maxplanes-- && (k=candidateplane(planes,planes_count,c,epsilon))>=0) - { - ConvexH *tmp = c; - c = ConvexHCrop(*tmp,planes[k]); - if(c==NULL) {c=tmp; break;} // might want to debug this case better!!! - if(!AssertIntact(*c)) {c=tmp; break;} // might want to debug this case better too!!! - delete tmp; - } - - assert(AssertIntact(*c)); - //return c; - faces_out = (NxI32*)MEMALLOC_MALLOC(sizeof(NxI32)*(1+c->facets.count+c->edges.count)); // new NxI32[1+c->facets.count+c->edges.count]; - faces_count_out=0; - i=0; - faces_out[faces_count_out++]=-1; - k=0; - while(iedges.count) - { - j=1; - while(j+iedges.count && c->edges[i].p==c->edges[i+j].p) { j++; } - faces_out[faces_count_out++]=j; - while(j--) - { - faces_out[faces_count_out++] = c->edges[i].v; - i++; - } - k++; - } - faces_out[0]=k; // number of faces. - assert(k==c->facets.count); - assert(faces_count_out == 1+c->facets.count+c->edges.count); - verts_out = c->vertices.element; // new float3[c->vertices.count]; - verts_count_out = c->vertices.count; - for(i=0;ivertices.count;i++) - { - verts_out[i] = float3(c->vertices[i]); - } - c->vertices.count=c->vertices.array_size=0; c->vertices.element=NULL; - delete c; - return 1; -} - -static NxI32 overhullv(float3 *verts, NxI32 verts_count,NxI32 maxplanes, - float3 *&verts_out, NxI32 &verts_count_out, NxI32 *&faces_out, NxI32 &faces_count_out ,NxF32 inflate,NxF32 bevangle,NxI32 vlimit) -{ - if(!verts_count) return 0; - extern NxI32 calchullpbev(float3 *verts,NxI32 verts_count,NxI32 vlimit, Array &planes,NxF32 bevangle) ; - Array planes; - NxI32 rc=calchullpbev(verts,verts_count,vlimit,planes,bevangle) ; - if(!rc) return 0; - return overhull(planes.element,planes.count,verts,verts_count,maxplanes,verts_out,verts_count_out,faces_out,faces_count_out,inflate); -} - - -//***************************************************** -//***************************************************** - - -bool ComputeHull(NxU32 vcount,const NxF32 *vertices,PHullResult &result,NxU32 vlimit,NxF32 inflate) -{ - - NxI32 index_count; - NxI32 *faces; - float3 *verts_out; - NxI32 verts_count_out; - - if(inflate==0.0f) - { - NxI32 *tris_out; - NxI32 tris_count; - NxI32 ret = calchull( (float3 *) vertices, (NxI32) vcount, tris_out, tris_count, vlimit ); - if(!ret) return false; - result.mIndexCount = (NxU32) (tris_count*3); - result.mFaceCount = (NxU32) tris_count; - result.mVertices = (NxF32*) vertices; - result.mVcount = (NxU32) vcount; - result.mIndices = (NxU32 *) tris_out; - return true; - } - - NxI32 ret = overhullv((float3*)vertices,vcount,35,verts_out,verts_count_out,faces,index_count,inflate,120.0f,vlimit); - if(!ret) { - tris.SetSize(0); //have to set the size to 0 in order to protect from a "pure virtual function call" problem - return false; - } - - Array tris; - NxI32 n=faces[0]; - NxI32 k=1; - for(NxI32 i=0;i bmax[j] ) bmax[j] = p[j]; - } - } - } - - NxF32 dx = bmax[0] - bmin[0]; - NxF32 dy = bmax[1] - bmin[1]; - NxF32 dz = bmax[2] - bmin[2]; - - NxF32 center[3]; - - center[0] = dx*0.5f + bmin[0]; - center[1] = dy*0.5f + bmin[1]; - center[2] = dz*0.5f + bmin[2]; - - if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3 ) - { - - NxF32 len = FLT_MAX; - - if ( dx > EPSILON && dx < len ) len = dx; - if ( dy > EPSILON && dy < len ) len = dy; - if ( dz > EPSILON && dz < len ) len = dz; - - if ( len == FLT_MAX ) - { - dx = dy = dz = 0.01f; // one centimeter - } - else - { - if ( dx < EPSILON ) dx = len * 0.05f; // 1/5th the shortest non-zero edge. - if ( dy < EPSILON ) dy = len * 0.05f; - if ( dz < EPSILON ) dz = len * 0.05f; - } - - NxF32 x1 = center[0] - dx; - NxF32 x2 = center[0] + dx; - - NxF32 y1 = center[1] - dy; - NxF32 y2 = center[1] + dy; - - NxF32 z1 = center[2] - dz; - NxF32 z2 = center[2] + dz; - - AddPoint(vcount,vertices,x1,y1,z1); - AddPoint(vcount,vertices,x2,y1,z1); - AddPoint(vcount,vertices,x2,y2,z1); - AddPoint(vcount,vertices,x1,y2,z1); - AddPoint(vcount,vertices,x1,y1,z2); - AddPoint(vcount,vertices,x2,y1,z2); - AddPoint(vcount,vertices,x2,y2,z2); - AddPoint(vcount,vertices,x1,y2,z2); - - return true; // return cube - - - } - else - { - if ( scale ) - { - scale[0] = dx; - scale[1] = dy; - scale[2] = dz; - - recip[0] = 1 / dx; - recip[1] = 1 / dy; - recip[2] = 1 / dz; - - center[0]*=recip[0]; - center[1]*=recip[1]; - center[2]*=recip[2]; - - } - - } - - - - vtx = (const char *) svertices; - - for (NxU32 i=0; i dist2 ) - { - v[0] = px; - v[1] = py; - v[2] = pz; - } - - break; - } - } - - if ( j == vcount ) - { - NxF32 *dest = &vertices[vcount*3]; - dest[0] = px; - dest[1] = py; - dest[2] = pz; - vcount++; - } - } - } - - // ok..now make sure we didn't prune so many vertices it is now invalid. - { - NxF32 bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX }; - NxF32 bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX }; - - for (NxU32 i=0; i bmax[j] ) bmax[j] = p[j]; - } - } - - NxF32 dx = bmax[0] - bmin[0]; - NxF32 dy = bmax[1] - bmin[1]; - NxF32 dz = bmax[2] - bmin[2]; - - if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3) - { - NxF32 cx = dx*0.5f + bmin[0]; - NxF32 cy = dy*0.5f + bmin[1]; - NxF32 cz = dz*0.5f + bmin[2]; - - NxF32 len = FLT_MAX; - - if ( dx >= EPSILON && dx < len ) len = dx; - if ( dy >= EPSILON && dy < len ) len = dy; - if ( dz >= EPSILON && dz < len ) len = dz; - - if ( len == FLT_MAX ) - { - dx = dy = dz = 0.01f; // one centimeter - } - else - { - if ( dx < EPSILON ) dx = len * 0.05f; // 1/5th the shortest non-zero edge. - if ( dy < EPSILON ) dy = len * 0.05f; - if ( dz < EPSILON ) dz = len * 0.05f; - } - - NxF32 x1 = cx - dx; - NxF32 x2 = cx + dx; - - NxF32 y1 = cy - dy; - NxF32 y2 = cy + dy; - - NxF32 z1 = cz - dz; - NxF32 z2 = cz + dz; - - vcount = 0; // add box - - AddPoint(vcount,vertices,x1,y1,z1); - AddPoint(vcount,vertices,x2,y1,z1); - AddPoint(vcount,vertices,x2,y2,z1); - AddPoint(vcount,vertices,x1,y2,z1); - AddPoint(vcount,vertices,x1,y1,z2); - AddPoint(vcount,vertices,x2,y1,z2); - AddPoint(vcount,vertices,x2,y2,z2); - AddPoint(vcount,vertices,x1,y2,z2); - - return true; - } - } - - return true; -} - -void HullLibrary::BringOutYourDead(const NxF32 *verts,NxU32 vcount, NxF32 *overts,NxU32 &ocount,NxU32 *indices,NxU32 indexcount) -{ - NxU32 *used = (NxU32 *)MEMALLOC_MALLOC(sizeof(NxU32)*vcount); - memset(used,0,sizeof(NxU32)*vcount); - - ocount = 0; - - for (NxU32 i=0; iConvexHullTriangle(v3,v2,v1); -} - -//================================================================================== -NxF32 HullLibrary::ComputeNormal(NxF32 *n,const NxF32 *A,const NxF32 *B,const NxF32 *C) -{ - NxF32 vx,vy,vz,wx,wy,wz,vw_x,vw_y,vw_z,mag; - - vx = (B[0] - C[0]); - vy = (B[1] - C[1]); - vz = (B[2] - C[2]); - - wx = (A[0] - B[0]); - wy = (A[1] - B[1]); - wz = (A[2] - B[2]); - - vw_x = vy * wz - vz * wy; - vw_y = vz * wx - vx * wz; - vw_z = vx * wy - vy * wx; - - mag = sqrtf((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); - - if ( mag < 0.000001f ) - { - mag = 0; - } - else - { - mag = 1.0f/mag; - } - - n[0] = vw_x * mag; - n[1] = vw_y * mag; - n[2] = vw_z * mag; - - return mag; -} - -}; // End of namespace diff --git a/Engine/lib/convexDecomp/NvStanHull.h b/Engine/lib/convexDecomp/NvStanHull.h deleted file mode 100644 index 7890d05bf..000000000 --- a/Engine/lib/convexDecomp/NvStanHull.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/NvThreadConfig.cpp b/Engine/lib/convexDecomp/NvThreadConfig.cpp deleted file mode 100644 index 5ae9907ca..000000000 --- a/Engine/lib/convexDecomp/NvThreadConfig.cpp +++ /dev/null @@ -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 -#include "NvThreadConfig.h" - -#if defined(WIN32) - -#define _WIN32_WINNT 0x400 -#include - -#pragma comment(lib,"winmm.lib") - -// #ifndef _WIN32_WINNT - -// #endif -// #include -//#include -#endif - -#if defined(_XBOX) - #include -#endif - -#if defined(__linux__) || defined( __APPLE__ ) || defined( __FreeBSD__) - //#include - #include - #include - #include - #define __stdcall -#endif - -#if defined( __APPLE__ ) || defined( __FreeBSD__) - - #include -#endif - -#if defined(__APPLE__) || defined(__linux__) || defined( __FreeBSD__) - - #include -#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(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(m); -} - -void tc_releaseThreadEvent(ThreadEvent *t) -{ - MyThreadEvent *m = static_cast< MyThreadEvent *>(t); - delete m; -} - -}; // end of namespace diff --git a/Engine/lib/convexDecomp/NvThreadConfig.h b/Engine/lib/convexDecomp/NvThreadConfig.h deleted file mode 100644 index 1074c045c..000000000 --- a/Engine/lib/convexDecomp/NvThreadConfig.h +++ /dev/null @@ -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 -#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 diff --git a/Engine/lib/convexDecomp/NvUserMemAlloc.h b/Engine/lib/convexDecomp/NvUserMemAlloc.h deleted file mode 100644 index 14ae899d9..000000000 --- a/Engine/lib/convexDecomp/NvUserMemAlloc.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexDecomp/readme.txt b/Engine/lib/convexDecomp/readme.txt deleted file mode 100644 index 679396aa3..000000000 --- a/Engine/lib/convexDecomp/readme.txt +++ /dev/null @@ -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. - - diff --git a/Engine/lib/convexDecomp/wavefront.cpp b/Engine/lib/convexDecomp/wavefront.cpp deleted file mode 100644 index 0d4b979b1..000000000 --- a/Engine/lib/convexDecomp/wavefront.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include - -#include "wavefront.h" - -#include - -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; iNodeTriangle(&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; imPos, 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 diff --git a/Engine/lib/convexDecomp/wavefront.h b/Engine/lib/convexDecomp/wavefront.h deleted file mode 100644 index 601d28885..000000000 --- a/Engine/lib/convexDecomp/wavefront.h +++ /dev/null @@ -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 diff --git a/Engine/lib/convexMath/CMakeLists.txt b/Engine/lib/convexMath/CMakeLists.txt new file mode 100644 index 000000000..1cd502166 --- /dev/null +++ b/Engine/lib/convexMath/CMakeLists.txt @@ -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}) \ No newline at end of file diff --git a/Engine/lib/convexMath/FloatMath.cpp b/Engine/lib/convexMath/FloatMath.cpp new file mode 100644 index 000000000..481e87510 --- /dev/null +++ b/Engine/lib/convexMath/FloatMath.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include +#include +#include "FloatMath.h" +#include + +#define REAL float + +#include "FloatMath.inl" + +#undef REAL +#define REAL double + +#include "FloatMath.inl" diff --git a/Engine/lib/convexMath/FloatMath.h b/Engine/lib/convexMath/FloatMath.h new file mode 100644 index 000000000..71b6043ce --- /dev/null +++ b/Engine/lib/convexMath/FloatMath.h @@ -0,0 +1,525 @@ +#ifndef FLOAT_MATH_LIB_H + +#define FLOAT_MATH_LIB_H + + +#include +#include + +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 diff --git a/Engine/lib/convexMath/FloatMath.inl b/Engine/lib/convexMath/FloatMath.inl new file mode 100644 index 000000000..fde892c5f --- /dev/null +++ b/Engine/lib/convexMath/FloatMath.inl @@ -0,0 +1,5280 @@ +// 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 'float *' to 3 floating point numbers. +// a matrix is a 'float *' to an array of 16 floating point numbers representing a 4x4 transformation matrix compatible with D3D or OGL +// a quaternion is a 'float *' to 4 floats representing a quaternion x,y,z,w +// + +#ifdef _MSC_VER +#pragma warning(disable:4996) +#endif + +namespace FLOAT_MATH +{ + +void fm_inverseRT(const REAL matrix[16],const REAL pos[3],REAL t[3]) // inverse rotate translate the point. +{ + + REAL _x = pos[0] - matrix[3*4+0]; + REAL _y = pos[1] - matrix[3*4+1]; + REAL _z = pos[2] - matrix[3*4+2]; + + // Multiply inverse-translated source vector by inverted rotation transform + + t[0] = (matrix[0*4+0] * _x) + (matrix[0*4+1] * _y) + (matrix[0*4+2] * _z); + t[1] = (matrix[1*4+0] * _x) + (matrix[1*4+1] * _y) + (matrix[1*4+2] * _z); + t[2] = (matrix[2*4+0] * _x) + (matrix[2*4+1] * _y) + (matrix[2*4+2] * _z); + +} + +REAL fm_getDeterminant(const REAL matrix[16]) +{ + REAL tempv[3]; + REAL p0[3]; + REAL p1[3]; + REAL p2[3]; + + + p0[0] = matrix[0*4+0]; + p0[1] = matrix[0*4+1]; + p0[2] = matrix[0*4+2]; + + p1[0] = matrix[1*4+0]; + p1[1] = matrix[1*4+1]; + p1[2] = matrix[1*4+2]; + + p2[0] = matrix[2*4+0]; + p2[1] = matrix[2*4+1]; + p2[2] = matrix[2*4+2]; + + fm_cross(tempv,p1,p2); + + return fm_dot(p0,tempv); + +} + +REAL fm_squared(REAL x) { return x*x; }; + +void fm_decomposeTransform(const REAL local_transform[16],REAL trans[3],REAL rot[4],REAL scale[3]) +{ + + trans[0] = local_transform[12]; + trans[1] = local_transform[13]; + trans[2] = local_transform[14]; + + scale[0] = (REAL)sqrt(fm_squared(local_transform[0*4+0]) + fm_squared(local_transform[0*4+1]) + fm_squared(local_transform[0*4+2])); + scale[1] = (REAL)sqrt(fm_squared(local_transform[1*4+0]) + fm_squared(local_transform[1*4+1]) + fm_squared(local_transform[1*4+2])); + scale[2] = (REAL)sqrt(fm_squared(local_transform[2*4+0]) + fm_squared(local_transform[2*4+1]) + fm_squared(local_transform[2*4+2])); + + REAL m[16]; + memcpy(m,local_transform,sizeof(REAL)*16); + + REAL sx = 1.0f / scale[0]; + REAL sy = 1.0f / scale[1]; + REAL sz = 1.0f / scale[2]; + + m[0*4+0]*=sx; + m[0*4+1]*=sx; + m[0*4+2]*=sx; + + m[1*4+0]*=sy; + m[1*4+1]*=sy; + m[1*4+2]*=sy; + + m[2*4+0]*=sz; + m[2*4+1]*=sz; + m[2*4+2]*=sz; + + fm_matrixToQuat(m,rot); + +} + +void fm_getSubMatrix(int32_t ki,int32_t kj,REAL pDst[16],const REAL matrix[16]) +{ + int32_t row, col; + int32_t dstCol = 0, dstRow = 0; + + for ( col = 0; col < 4; col++ ) + { + if ( col == kj ) + { + continue; + } + for ( dstRow = 0, row = 0; row < 4; row++ ) + { + if ( row == ki ) + { + continue; + } + pDst[dstCol*4+dstRow] = matrix[col*4+row]; + dstRow++; + } + dstCol++; + } +} + +void fm_inverseTransform(const REAL matrix[16],REAL inverse_matrix[16]) +{ + REAL determinant = fm_getDeterminant(matrix); + determinant = 1.0f / determinant; + for (int32_t i = 0; i < 4; i++ ) + { + for (int32_t j = 0; j < 4; j++ ) + { + int32_t sign = 1 - ( ( i + j ) % 2 ) * 2; + REAL subMat[16]; + fm_identity(subMat); + fm_getSubMatrix( i, j, subMat, matrix ); + REAL subDeterminant = fm_getDeterminant(subMat); + inverse_matrix[i*4+j] = ( subDeterminant * sign ) * determinant; + } + } +} + +void fm_identity(REAL matrix[16]) // set 4x4 matrix to identity. +{ + matrix[0*4+0] = 1; + matrix[1*4+1] = 1; + matrix[2*4+2] = 1; + matrix[3*4+3] = 1; + + matrix[1*4+0] = 0; + matrix[2*4+0] = 0; + matrix[3*4+0] = 0; + + matrix[0*4+1] = 0; + matrix[2*4+1] = 0; + matrix[3*4+1] = 0; + + matrix[0*4+2] = 0; + matrix[1*4+2] = 0; + matrix[3*4+2] = 0; + + matrix[0*4+3] = 0; + matrix[1*4+3] = 0; + matrix[2*4+3] = 0; + +} + +void fm_quatToEuler(const REAL quat[4],REAL &ax,REAL &ay,REAL &az) +{ + REAL x = quat[0]; + REAL y = quat[1]; + REAL z = quat[2]; + REAL w = quat[3]; + + REAL sint = (2.0f * w * y) - (2.0f * x * z); + REAL cost_temp = 1.0f - (sint * sint); + REAL cost = 0; + + if ( (REAL)fabs(cost_temp) > 0.001f ) + { + cost = (REAL)sqrt( cost_temp ); + } + + REAL sinv, cosv, sinf, cosf; + if ( (REAL)fabs(cost) > 0.001f ) + { + cost = 1.0f / cost; + sinv = ((2.0f * y * z) + (2.0f * w * x)) * cost; + cosv = (1.0f - (2.0f * x * x) - (2.0f * y * y)) * cost; + sinf = ((2.0f * x * y) + (2.0f * w * z)) * cost; + cosf = (1.0f - (2.0f * y * y) - (2.0f * z * z)) * cost; + } + else + { + sinv = (2.0f * w * x) - (2.0f * y * z); + cosv = 1.0f - (2.0f * x * x) - (2.0f * z * z); + sinf = 0; + cosf = 1.0f; + } + + // compute output rotations + ax = (REAL)atan2( sinv, cosv ); + ay = (REAL)atan2( sint, cost ); + az = (REAL)atan2( sinf, cosf ); + +} + +void fm_eulerToMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) +{ + REAL quat[4]; + fm_eulerToQuat(ax,ay,az,quat); + fm_quatToMatrix(quat,matrix); +} + +void fm_getAABB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *bmin,REAL *bmax) +{ + + const uint8_t *source = (const uint8_t *) points; + + bmin[0] = points[0]; + bmin[1] = points[1]; + bmin[2] = points[2]; + + bmax[0] = points[0]; + bmax[1] = points[1]; + bmax[2] = points[2]; + + + for (uint32_t i=1; i bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + + } +} + +void fm_eulerToQuat(const REAL *euler,REAL *quat) // convert euler angles to quaternion. +{ + fm_eulerToQuat(euler[0],euler[1],euler[2],quat); +} + +void fm_eulerToQuat(REAL roll,REAL pitch,REAL yaw,REAL *quat) // convert euler angles to quaternion. +{ + roll *= 0.5f; + pitch *= 0.5f; + yaw *= 0.5f; + + REAL cr = (REAL)cos(roll); + REAL cp = (REAL)cos(pitch); + REAL cy = (REAL)cos(yaw); + + REAL sr = (REAL)sin(roll); + REAL sp = (REAL)sin(pitch); + REAL sy = (REAL)sin(yaw); + + REAL cpcy = cp * cy; + REAL spsy = sp * sy; + REAL spcy = sp * cy; + REAL cpsy = cp * sy; + + quat[0] = ( sr * cpcy - cr * spsy); + quat[1] = ( cr * spcy + sr * cpsy); + quat[2] = ( cr * cpsy - sr * spcy); + quat[3] = cr * cpcy + sr * spsy; +} + +void fm_quatToMatrix(const REAL *quat,REAL *matrix) // convert quaternion rotation to matrix, zeros out the translation component. +{ + + REAL xx = quat[0]*quat[0]; + REAL yy = quat[1]*quat[1]; + REAL zz = quat[2]*quat[2]; + REAL xy = quat[0]*quat[1]; + REAL xz = quat[0]*quat[2]; + REAL yz = quat[1]*quat[2]; + REAL wx = quat[3]*quat[0]; + REAL wy = quat[3]*quat[1]; + REAL wz = quat[3]*quat[2]; + + matrix[0*4+0] = 1 - 2 * ( yy + zz ); + matrix[1*4+0] = 2 * ( xy - wz ); + matrix[2*4+0] = 2 * ( xz + wy ); + + matrix[0*4+1] = 2 * ( xy + wz ); + matrix[1*4+1] = 1 - 2 * ( xx + zz ); + matrix[2*4+1] = 2 * ( yz - wx ); + + matrix[0*4+2] = 2 * ( xz - wy ); + matrix[1*4+2] = 2 * ( yz + wx ); + matrix[2*4+2] = 1 - 2 * ( xx + yy ); + + matrix[3*4+0] = matrix[3*4+1] = matrix[3*4+2] = (REAL) 0.0f; + matrix[0*4+3] = matrix[1*4+3] = matrix[2*4+3] = (REAL) 0.0f; + matrix[3*4+3] =(REAL) 1.0f; + +} + + +void fm_quatRotate(const REAL *quat,const REAL *v,REAL *r) // rotate a vector directly by a quaternion. +{ + REAL left[4]; + + left[0] = quat[3]*v[0] + quat[1]*v[2] - v[1]*quat[2]; + left[1] = quat[3]*v[1] + quat[2]*v[0] - v[2]*quat[0]; + left[2] = quat[3]*v[2] + quat[0]*v[1] - v[0]*quat[1]; + left[3] = - quat[0]*v[0] - quat[1]*v[1] - quat[2]*v[2]; + + r[0] = (left[3]*-quat[0]) + (quat[3]*left[0]) + (left[1]*-quat[2]) - (-quat[1]*left[2]); + r[1] = (left[3]*-quat[1]) + (quat[3]*left[1]) + (left[2]*-quat[0]) - (-quat[2]*left[0]); + r[2] = (left[3]*-quat[2]) + (quat[3]*left[2]) + (left[0]*-quat[1]) - (-quat[0]*left[1]); + +} + + +void fm_getTranslation(const REAL *matrix,REAL *t) +{ + t[0] = matrix[3*4+0]; + t[1] = matrix[3*4+1]; + t[2] = matrix[3*4+2]; +} + +void fm_matrixToQuat(const REAL *matrix,REAL *quat) // convert the 3x3 portion of a 4x4 matrix into a quaternion as x,y,z,w +{ + + REAL tr = matrix[0*4+0] + matrix[1*4+1] + matrix[2*4+2]; + + // check the diagonal + + if (tr > 0.0f ) + { + REAL s = (REAL) sqrt ( (double) (tr + 1.0f) ); + quat[3] = s * 0.5f; + s = 0.5f / s; + quat[0] = (matrix[1*4+2] - matrix[2*4+1]) * s; + quat[1] = (matrix[2*4+0] - matrix[0*4+2]) * s; + quat[2] = (matrix[0*4+1] - matrix[1*4+0]) * s; + + } + else + { + // diagonal is negative + int32_t nxt[3] = {1, 2, 0}; + REAL qa[4]; + + int32_t i = 0; + + if (matrix[1*4+1] > matrix[0*4+0]) i = 1; + if (matrix[2*4+2] > matrix[i*4+i]) i = 2; + + int32_t j = nxt[i]; + int32_t k = nxt[j]; + + REAL s = (REAL)sqrt ( ((matrix[i*4+i] - (matrix[j*4+j] + matrix[k*4+k])) + 1.0f) ); + + qa[i] = s * 0.5f; + + if (s != 0.0f ) s = 0.5f / s; + + qa[3] = (matrix[j*4+k] - matrix[k*4+j]) * s; + qa[j] = (matrix[i*4+j] + matrix[j*4+i]) * s; + qa[k] = (matrix[i*4+k] + matrix[k*4+i]) * s; + + quat[0] = qa[0]; + quat[1] = qa[1]; + quat[2] = qa[2]; + quat[3] = qa[3]; + } +// fm_normalizeQuat(quat); +} + + +REAL fm_sphereVolume(REAL radius) // return's the volume of a sphere of this radius (4/3 PI * R cubed ) +{ + return (4.0f / 3.0f ) * FM_PI * radius * radius * radius; +} + + +REAL fm_cylinderVolume(REAL radius,REAL h) +{ + return FM_PI * radius * radius *h; +} + +REAL fm_capsuleVolume(REAL radius,REAL h) +{ + REAL volume = fm_sphereVolume(radius); // volume of the sphere portion. + REAL ch = h-radius*2; // this is the cylinder length + if ( ch > 0 ) + { + volume+=fm_cylinderVolume(radius,ch); + } + return volume; +} + +void fm_transform(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point +{ + if ( matrix ) + { + REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]) + matrix[3*4+0]; + REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]) + matrix[3*4+1]; + REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]) + matrix[3*4+2]; + t[0] = tx; + t[1] = ty; + t[2] = tz; + } + else + { + t[0] = v[0]; + t[1] = v[1]; + t[2] = v[2]; + } +} + +void fm_rotate(const REAL matrix[16],const REAL v[3],REAL t[3]) // rotate and translate this point +{ + if ( matrix ) + { + REAL tx = (matrix[0*4+0] * v[0]) + (matrix[1*4+0] * v[1]) + (matrix[2*4+0] * v[2]); + REAL ty = (matrix[0*4+1] * v[0]) + (matrix[1*4+1] * v[1]) + (matrix[2*4+1] * v[2]); + REAL tz = (matrix[0*4+2] * v[0]) + (matrix[1*4+2] * v[1]) + (matrix[2*4+2] * v[2]); + t[0] = tx; + t[1] = ty; + t[2] = tz; + } + else + { + t[0] = v[0]; + t[1] = v[1]; + t[2] = v[2]; + } +} + + +REAL fm_distance(const REAL *p1,const REAL *p2) +{ + REAL dx = p1[0] - p2[0]; + REAL dy = p1[1] - p2[1]; + REAL dz = p1[2] - p2[2]; + + return (REAL)sqrt( dx*dx + dy*dy + dz *dz ); +} + +REAL fm_distanceSquared(const REAL *p1,const REAL *p2) +{ + REAL dx = p1[0] - p2[0]; + REAL dy = p1[1] - p2[1]; + REAL dz = p1[2] - p2[2]; + + return dx*dx + dy*dy + dz *dz; +} + + +REAL fm_distanceSquaredXZ(const REAL *p1,const REAL *p2) +{ + REAL dx = p1[0] - p2[0]; + REAL dz = p1[2] - p2[2]; + + return dx*dx + dz *dz; +} + + +REAL fm_computePlane(const REAL *A,const REAL *B,const REAL *C,REAL *n) // returns D +{ + REAL vx = (B[0] - C[0]); + REAL vy = (B[1] - C[1]); + REAL vz = (B[2] - C[2]); + + REAL wx = (A[0] - B[0]); + REAL wy = (A[1] - B[1]); + REAL wz = (A[2] - B[2]); + + REAL vw_x = vy * wz - vz * wy; + REAL vw_y = vz * wx - vx * wz; + REAL vw_z = vx * wy - vy * wx; + + REAL mag = (REAL)sqrt((vw_x * vw_x) + (vw_y * vw_y) + (vw_z * vw_z)); + + if ( mag < 0.000001f ) + { + mag = 0; + } + else + { + mag = 1.0f/mag; + } + + REAL x = vw_x * mag; + REAL y = vw_y * mag; + REAL z = vw_z * mag; + + + REAL D = 0.0f - ((x*A[0])+(y*A[1])+(z*A[2])); + + n[0] = x; + n[1] = y; + n[2] = z; + + return D; +} + +REAL fm_distToPlane(const REAL *plane,const REAL *p) // computes the distance of this point from the plane. +{ + return p[0]*plane[0]+p[1]*plane[1]+p[2]*plane[2]+plane[3]; +} + +REAL fm_dot(const REAL *p1,const REAL *p2) +{ + return p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]; +} + +void fm_cross(REAL *cross,const REAL *a,const REAL *b) +{ + cross[0] = a[1]*b[2] - a[2]*b[1]; + cross[1] = a[2]*b[0] - a[0]*b[2]; + cross[2] = a[0]*b[1] - a[1]*b[0]; +} + +REAL fm_computeNormalVector(REAL *n,const REAL *p1,const REAL *p2) +{ + n[0] = p2[0] - p1[0]; + n[1] = p2[1] - p1[1]; + n[2] = p2[2] - p1[2]; + return fm_normalize(n); +} + +bool fm_computeWindingOrder(const REAL *p1,const REAL *p2,const REAL *p3) // returns true if the triangle is clockwise. +{ + bool ret = false; + + REAL v1[3]; + REAL v2[3]; + + fm_computeNormalVector(v1,p1,p2); // p2-p1 (as vector) and then normalized + fm_computeNormalVector(v2,p1,p3); // p3-p1 (as vector) and then normalized + + REAL cross[3]; + + fm_cross(cross, v1, v2 ); + REAL ref[3] = { 1, 0, 0 }; + + REAL d = fm_dot( cross, ref ); + + + if ( d <= 0 ) + ret = false; + else + ret = true; + + return ret; +} + +REAL fm_normalize(REAL *n) // normalize this vector +{ + REAL dist = (REAL)sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]); + if ( dist > 0.0000001f ) + { + REAL mag = 1.0f / dist; + n[0]*=mag; + n[1]*=mag; + n[2]*=mag; + } + else + { + n[0] = 1; + n[1] = 0; + n[2] = 0; + } + + return dist; +} + + +void fm_matrixMultiply(const REAL *pA,const REAL *pB,REAL *pM) +{ +#if 1 + + REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; + REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; + REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; + REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; + + REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; + REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; + REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; + REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; + + REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; + REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; + REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; + REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; + + REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; + REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; + REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; + REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; + + pM[0] = a; + pM[1] = b; + pM[2] = c; + pM[3] = d; + + pM[4] = e; + pM[5] = f; + pM[6] = g; + pM[7] = h; + + pM[8] = i; + pM[9] = j; + pM[10] = k; + pM[11] = l; + + pM[12] = m; + pM[13] = n; + pM[14] = o; + pM[15] = p; + + +#else + memset(pM, 0, sizeof(REAL)*16); + for(int32_t i=0; i<4; i++ ) + for(int32_t j=0; j<4; j++ ) + for(int32_t k=0; k<4; k++ ) + pM[4*i+j] += pA[4*i+k] * pB[4*k+j]; +#endif +} + + +void fm_eulerToQuatDX(REAL x,REAL y,REAL z,REAL *quat) // convert euler angles to quaternion using the fucked up DirectX method +{ + REAL matrix[16]; + fm_eulerToMatrix(x,y,z,matrix); + fm_matrixToQuat(matrix,quat); +} + +// implementation copied from: http://blogs.msdn.com/mikepelton/archive/2004/10/29/249501.aspx +void fm_eulerToMatrixDX(REAL x,REAL y,REAL z,REAL *matrix) // convert euler angles to quaternion using the fucked up DirectX method. +{ + fm_identity(matrix); + matrix[0*4+0] = (REAL)(cos(z)*cos(y) + sin(z)*sin(x)*sin(y)); + matrix[0*4+1] = (REAL)(sin(z)*cos(x)); + matrix[0*4+2] = (REAL)(cos(z)*-sin(y) + sin(z)*sin(x)*cos(y)); + + matrix[1*4+0] = (REAL)(-sin(z)*cos(y)+cos(z)*sin(x)*sin(y)); + matrix[1*4+1] = (REAL)(cos(z)*cos(x)); + matrix[1*4+2] = (REAL)(sin(z)*sin(y) +cos(z)*sin(x)*cos(y)); + + matrix[2*4+0] = (REAL)(cos(x)*sin(y)); + matrix[2*4+1] = (REAL)(-sin(x)); + matrix[2*4+2] = (REAL)(cos(x)*cos(y)); +} + + +void fm_scale(REAL x,REAL y,REAL z,REAL *fscale) // apply scale to the matrix. +{ + fscale[0*4+0] = x; + fscale[1*4+1] = y; + fscale[2*4+2] = z; +} + + +void fm_composeTransform(const REAL *position,const REAL *quat,const REAL *scale,REAL *matrix) +{ + fm_identity(matrix); + fm_quatToMatrix(quat,matrix); + + if ( scale && ( scale[0] != 1 || scale[1] != 1 || scale[2] != 1 ) ) + { + REAL work[16]; + memcpy(work,matrix,sizeof(REAL)*16); + REAL mscale[16]; + fm_identity(mscale); + fm_scale(scale[0],scale[1],scale[2],mscale); + fm_matrixMultiply(work,mscale,matrix); + } + + matrix[12] = position[0]; + matrix[13] = position[1]; + matrix[14] = position[2]; +} + + +void fm_setTranslation(const REAL *translation,REAL *matrix) +{ + matrix[12] = translation[0]; + matrix[13] = translation[1]; + matrix[14] = translation[2]; +} + +static REAL enorm0_3d ( REAL x0, REAL y0, REAL z0, REAL x1, REAL y1, REAL z1 ) + +/**********************************************************************/ + +/* +Purpose: + +ENORM0_3D computes the Euclidean norm of (P1-P0) in 3D. + +Modified: + +18 April 1999 + +Author: + +John Burkardt + +Parameters: + +Input, REAL X0, Y0, Z0, X1, Y1, Z1, the coordinates of the points +P0 and P1. + +Output, REAL ENORM0_3D, the Euclidean norm of (P1-P0). +*/ +{ + REAL value; + + value = (REAL)sqrt ( + ( x1 - x0 ) * ( x1 - x0 ) + + ( y1 - y0 ) * ( y1 - y0 ) + + ( z1 - z0 ) * ( z1 - z0 ) ); + + return value; +} + + +static REAL triangle_area_3d ( REAL x1, REAL y1, REAL z1, REAL x2,REAL y2, REAL z2, REAL x3, REAL y3, REAL z3 ) + + /**********************************************************************/ + + /* + Purpose: + + TRIANGLE_AREA_3D computes the area of a triangle in 3D. + + Modified: + + 22 April 1999 + + Author: + + John Burkardt + + Parameters: + + Input, REAL X1, Y1, Z1, X2, Y2, Z2, X3, Y3, Z3, the (X,Y,Z) + coordinates of the corners of the triangle. + + Output, REAL TRIANGLE_AREA_3D, the area of the triangle. + */ +{ + REAL a; + REAL alpha; + REAL area; + REAL b; + REAL base; + REAL c; + REAL dot; + REAL height; + /* + Find the projection of (P3-P1) onto (P2-P1). + */ + dot = + ( x2 - x1 ) * ( x3 - x1 ) + + ( y2 - y1 ) * ( y3 - y1 ) + + ( z2 - z1 ) * ( z3 - z1 ); + + base = enorm0_3d ( x1, y1, z1, x2, y2, z2 ); + /* + The height of the triangle is the length of (P3-P1) after its + projection onto (P2-P1) has been subtracted. + */ + if ( base == 0.0 ) { + + height = 0.0; + + } + else { + + alpha = dot / ( base * base ); + + a = x3 - x1 - alpha * ( x2 - x1 ); + b = y3 - y1 - alpha * ( y2 - y1 ); + c = z3 - z1 - alpha * ( z2 - z1 ); + + height = (REAL)sqrt ( a * a + b * b + c * c ); + + } + + area = 0.5f * base * height; + + return area; +} + + +REAL fm_computeArea(const REAL *p1,const REAL *p2,const REAL *p3) +{ + REAL ret = 0; + + ret = triangle_area_3d(p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],p3[0],p3[1],p3[2]); + + return ret; +} + + +void fm_lerp(const REAL *p1,const REAL *p2,REAL *dest,REAL lerpValue) +{ + dest[0] = ((p2[0] - p1[0])*lerpValue) + p1[0]; + dest[1] = ((p2[1] - p1[1])*lerpValue) + p1[1]; + dest[2] = ((p2[2] - p1[2])*lerpValue) + p1[2]; +} + +bool fm_pointTestXZ(const REAL *p,const REAL *i,const REAL *j) +{ + bool ret = false; + + if (((( i[2] <= p[2] ) && ( p[2] < j[2] )) || (( j[2] <= p[2] ) && ( p[2] < i[2] ))) && ( p[0] < (j[0] - i[0]) * (p[2] - i[2]) / (j[2] - i[2]) + i[0])) + ret = true; + + return ret; +}; + + +bool fm_insideTriangleXZ(const REAL *p,const REAL *p1,const REAL *p2,const REAL *p3) +{ + bool ret = false; + + int32_t c = 0; + if ( fm_pointTestXZ(p,p1,p2) ) c = !c; + if ( fm_pointTestXZ(p,p2,p3) ) c = !c; + if ( fm_pointTestXZ(p,p3,p1) ) c = !c; + if ( c ) ret = true; + + return ret; +} + +bool fm_insideAABB(const REAL *pos,const REAL *bmin,const REAL *bmax) +{ + bool ret = false; + + if ( pos[0] >= bmin[0] && pos[0] <= bmax[0] && + pos[1] >= bmin[1] && pos[1] <= bmax[1] && + pos[2] >= bmin[2] && pos[2] <= bmax[2] ) + ret = true; + + return ret; +} + + +uint32_t fm_clipTestPoint(const REAL *bmin,const REAL *bmax,const REAL *pos) +{ + uint32_t ret = 0; + + if ( pos[0] < bmin[0] ) + ret|=FMCS_XMIN; + else if ( pos[0] > bmax[0] ) + ret|=FMCS_XMAX; + + if ( pos[1] < bmin[1] ) + ret|=FMCS_YMIN; + else if ( pos[1] > bmax[1] ) + ret|=FMCS_YMAX; + + if ( pos[2] < bmin[2] ) + ret|=FMCS_ZMIN; + else if ( pos[2] > bmax[2] ) + ret|=FMCS_ZMAX; + + return ret; +} + +uint32_t fm_clipTestPointXZ(const REAL *bmin,const REAL *bmax,const REAL *pos) // only tests X and Z, not Y +{ + uint32_t ret = 0; + + if ( pos[0] < bmin[0] ) + ret|=FMCS_XMIN; + else if ( pos[0] > bmax[0] ) + ret|=FMCS_XMAX; + + if ( pos[2] < bmin[2] ) + ret|=FMCS_ZMIN; + else if ( pos[2] > bmax[2] ) + ret|=FMCS_ZMAX; + + return ret; +} + +uint32_t fm_clipTestAABB(const REAL *bmin,const REAL *bmax,const REAL *p1,const REAL *p2,const REAL *p3,uint32_t &andCode) +{ + uint32_t orCode = 0; + + andCode = FMCS_XMIN | FMCS_XMAX | FMCS_YMIN | FMCS_YMAX | FMCS_ZMIN | FMCS_ZMAX; + + uint32_t c = fm_clipTestPoint(bmin,bmax,p1); + orCode|=c; + andCode&=c; + + c = fm_clipTestPoint(bmin,bmax,p2); + orCode|=c; + andCode&=c; + + c = fm_clipTestPoint(bmin,bmax,p3); + orCode|=c; + andCode&=c; + + return orCode; +} + +bool intersect(const REAL *si,const REAL *ei,const REAL *bmin,const REAL *bmax,REAL *time) +{ + REAL st,et,fst = 0,fet = 1; + + for (int32_t i = 0; i < 3; i++) + { + if (*si < *ei) + { + if (*si > *bmax || *ei < *bmin) + return false; + REAL di = *ei - *si; + st = (*si < *bmin)? (*bmin - *si) / di: 0; + et = (*ei > *bmax)? (*bmax - *si) / di: 1; + } + else + { + if (*ei > *bmax || *si < *bmin) + return false; + REAL di = *ei - *si; + st = (*si > *bmax)? (*bmax - *si) / di: 0; + et = (*ei < *bmin)? (*bmin - *si) / di: 1; + } + + if (st > fst) fst = st; + if (et < fet) fet = et; + if (fet < fst) + return false; + bmin++; bmax++; + si++; ei++; + } + + *time = fst; + return true; +} + + + +bool fm_lineTestAABB(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) +{ + bool sect = intersect(p1,p2,bmin,bmax,&time); + return sect; +} + + +bool fm_lineTestAABBXZ(const REAL *p1,const REAL *p2,const REAL *bmin,const REAL *bmax,REAL &time) +{ + REAL _bmin[3]; + REAL _bmax[3]; + + _bmin[0] = bmin[0]; + _bmin[1] = -1e9; + _bmin[2] = bmin[2]; + + _bmax[0] = bmax[0]; + _bmax[1] = 1e9; + _bmax[2] = bmax[2]; + + bool sect = intersect(p1,p2,_bmin,_bmax,&time); + + return sect; +} + +void fm_minmax(const REAL *p,REAL *bmin,REAL *bmax) // accumulate to a min-max value +{ + + if ( p[0] < bmin[0] ) bmin[0] = p[0]; + if ( p[1] < bmin[1] ) bmin[1] = p[1]; + if ( p[2] < bmin[2] ) bmin[2] = p[2]; + + if ( p[0] > bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + +} + +REAL fm_solveX(const REAL *plane,REAL y,REAL z) // solve for X given this plane equation and the other two components. +{ + REAL x = (y*plane[1]+z*plane[2]+plane[3]) / -plane[0]; + return x; +} + +REAL fm_solveY(const REAL *plane,REAL x,REAL z) // solve for Y given this plane equation and the other two components. +{ + REAL y = (x*plane[0]+z*plane[2]+plane[3]) / -plane[1]; + return y; +} + + +REAL fm_solveZ(const REAL *plane,REAL x,REAL y) // solve for Y given this plane equation and the other two components. +{ + REAL z = (x*plane[0]+y*plane[1]+plane[3]) / -plane[2]; + return z; +} + + +void fm_getAABBCenter(const REAL *bmin,const REAL *bmax,REAL *center) +{ + center[0] = (bmax[0]-bmin[0])*0.5f+bmin[0]; + center[1] = (bmax[1]-bmin[1])*0.5f+bmin[1]; + center[2] = (bmax[2]-bmin[2])*0.5f+bmin[2]; +} + +FM_Axis fm_getDominantAxis(const REAL normal[3]) +{ + FM_Axis ret = FM_XAXIS; + + REAL x = (REAL)fabs(normal[0]); + REAL y = (REAL)fabs(normal[1]); + REAL z = (REAL)fabs(normal[2]); + + if ( y > x && y > z ) + ret = FM_YAXIS; + else if ( z > x && z > y ) + ret = FM_ZAXIS; + + return ret; +} + + +bool fm_lineSphereIntersect(const REAL *center,REAL radius,const REAL *p1,const REAL *p2,REAL *intersect) +{ + bool ret = false; + + REAL dir[3]; + + dir[0] = p2[0]-p1[0]; + dir[1] = p2[1]-p1[1]; + dir[2] = p2[2]-p1[2]; + + REAL distance = (REAL)sqrt( dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]); + + if ( distance > 0 ) + { + REAL recip = 1.0f / distance; + dir[0]*=recip; + dir[1]*=recip; + dir[2]*=recip; + ret = fm_raySphereIntersect(center,radius,p1,dir,distance,intersect); + } + else + { + dir[0] = center[0]-p1[0]; + dir[1] = center[1]-p1[1]; + dir[2] = center[2]-p1[2]; + REAL d2 = dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]; + REAL r2 = radius*radius; + if ( d2 < r2 ) + { + ret = true; + if ( intersect ) + { + intersect[0] = p1[0]; + intersect[1] = p1[1]; + intersect[2] = p1[2]; + } + } + } + return ret; +} + +#define DOT(p1,p2) (p1[0]*p2[0]+p1[1]*p2[1]+p1[2]*p2[2]) + +bool fm_raySphereIntersect(const REAL *center,REAL radius,const REAL *pos,const REAL *dir,REAL distance,REAL *intersect) +{ + bool ret = false; + + REAL E0[3]; + + E0[0] = center[0] - pos[0]; + E0[1] = center[1] - pos[1]; + E0[2] = center[2] - pos[2]; + + REAL V[3]; + + V[0] = dir[0]; + V[1] = dir[1]; + V[2] = dir[2]; + + + REAL dist2 = E0[0]*E0[0] + E0[1]*E0[1] + E0[2] * E0[2]; + REAL radius2 = radius*radius; // radius squared.. + + // Bug Fix For Gem, if origin is *inside* the sphere, invert the + // direction vector so that we get a valid intersection location. + if ( dist2 < radius2 ) + { + V[0]*=-1; + V[1]*=-1; + V[2]*=-1; + } + + + REAL v = DOT(E0,V); + + REAL disc = radius2 - (dist2 - v*v); + + if (disc > 0.0f) + { + if ( intersect ) + { + REAL d = (REAL)sqrt(disc); + REAL diff = v-d; + if ( diff < distance ) + { + intersect[0] = pos[0]+V[0]*diff; + intersect[1] = pos[1]+V[1]*diff; + intersect[2] = pos[2]+V[2]*diff; + ret = true; + } + } + } + + return ret; +} + + +void fm_catmullRom(REAL *out_vector,const REAL *p1,const REAL *p2,const REAL *p3,const REAL *p4, const REAL s) +{ + REAL s_squared = s * s; + REAL s_cubed = s_squared * s; + + REAL coefficient_p1 = -s_cubed + 2*s_squared - s; + REAL coefficient_p2 = 3 * s_cubed - 5 * s_squared + 2; + REAL coefficient_p3 = -3 * s_cubed +4 * s_squared + s; + REAL coefficient_p4 = s_cubed - s_squared; + + out_vector[0] = (coefficient_p1 * p1[0] + coefficient_p2 * p2[0] + coefficient_p3 * p3[0] + coefficient_p4 * p4[0])*0.5f; + out_vector[1] = (coefficient_p1 * p1[1] + coefficient_p2 * p2[1] + coefficient_p3 * p3[1] + coefficient_p4 * p4[1])*0.5f; + out_vector[2] = (coefficient_p1 * p1[2] + coefficient_p2 * p2[2] + coefficient_p3 * p3[2] + coefficient_p4 * p4[2])*0.5f; +} + +bool fm_intersectAABB(const REAL *bmin1,const REAL *bmax1,const REAL *bmin2,const REAL *bmax2) +{ + if ((bmin1[0] > bmax2[0]) || (bmin2[0] > bmax1[0])) return false; + if ((bmin1[1] > bmax2[1]) || (bmin2[1] > bmax1[1])) return false; + if ((bmin1[2] > bmax2[2]) || (bmin2[2] > bmax1[2])) return false; + return true; + +} + +bool fm_insideAABB(const REAL *obmin,const REAL *obmax,const REAL *tbmin,const REAL *tbmax) // test if bounding box tbmin/tmbax is fully inside obmin/obmax +{ + bool ret = false; + + if ( tbmax[0] <= obmax[0] && + tbmax[1] <= obmax[1] && + tbmax[2] <= obmax[2] && + tbmin[0] >= obmin[0] && + tbmin[1] >= obmin[1] && + tbmin[2] >= obmin[2] ) ret = true; + + return ret; +} + + +// Reference, from Stan Melax in Game Gems I +// Quaternion q; +// vector3 c = CrossProduct(v0,v1); +// REAL d = DotProduct(v0,v1); +// REAL s = (REAL)sqrt((1+d)*2); +// q.x = c.x / s; +// q.y = c.y / s; +// q.z = c.z / s; +// q.w = s /2.0f; +// return q; +void fm_rotationArc(const REAL *v0,const REAL *v1,REAL *quat) +{ + REAL cross[3]; + + fm_cross(cross,v0,v1); + REAL d = fm_dot(v0,v1); + + if( d<= -0.99999f ) // 180 about x axis + { + if ( fabsf((float)v0[0]) < 0.1f ) + { + quat[0] = 0; + quat[1] = v0[2]; + quat[2] = -v0[1]; + quat[3] = 0; + } + else + { + quat[0] = v0[1]; + quat[1] = -v0[0]; + quat[2] = 0; + quat[3] = 0; + } + REAL magnitudeSquared = quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2] + quat[3]*quat[3]; + REAL magnitude = sqrtf((float)magnitudeSquared); + REAL recip = 1.0f / magnitude; + quat[0]*=recip; + quat[1]*=recip; + quat[2]*=recip; + quat[3]*=recip; + } + else + { + REAL s = (REAL)sqrt((1+d)*2); + REAL recip = 1.0f / s; + + quat[0] = cross[0] * recip; + quat[1] = cross[1] * recip; + quat[2] = cross[2] * recip; + quat[3] = s * 0.5f; + } +} + + +REAL fm_distancePointLineSegment(const REAL *Point,const REAL *LineStart,const REAL *LineEnd,REAL *intersection,LineSegmentType &type,REAL epsilon) +{ + REAL ret; + + REAL LineMag = fm_distance( LineEnd, LineStart ); + + if ( LineMag > 0 ) + { + REAL U = ( ( ( Point[0] - LineStart[0] ) * ( LineEnd[0] - LineStart[0] ) ) + ( ( Point[1] - LineStart[1] ) * ( LineEnd[1] - LineStart[1] ) ) + ( ( Point[2] - LineStart[2] ) * ( LineEnd[2] - LineStart[2] ) ) ) / ( LineMag * LineMag ); + if( U < 0.0f || U > 1.0f ) + { + REAL d1 = fm_distanceSquared(Point,LineStart); + REAL d2 = fm_distanceSquared(Point,LineEnd); + if ( d1 <= d2 ) + { + ret = (REAL)sqrt(d1); + intersection[0] = LineStart[0]; + intersection[1] = LineStart[1]; + intersection[2] = LineStart[2]; + type = LS_START; + } + else + { + ret = (REAL)sqrt(d2); + intersection[0] = LineEnd[0]; + intersection[1] = LineEnd[1]; + intersection[2] = LineEnd[2]; + type = LS_END; + } + } + else + { + intersection[0] = LineStart[0] + U * ( LineEnd[0] - LineStart[0] ); + intersection[1] = LineStart[1] + U * ( LineEnd[1] - LineStart[1] ); + intersection[2] = LineStart[2] + U * ( LineEnd[2] - LineStart[2] ); + + ret = fm_distance(Point,intersection); + + REAL d1 = fm_distanceSquared(intersection,LineStart); + REAL d2 = fm_distanceSquared(intersection,LineEnd); + REAL mag = (epsilon*2)*(epsilon*2); + + if ( d1 < mag ) // if less than 1/100th the total distance, treat is as the 'start' + { + type = LS_START; + } + else if ( d2 < mag ) + { + type = LS_END; + } + else + { + type = LS_MIDDLE; + } + + } + } + else + { + ret = LineMag; + intersection[0] = LineEnd[0]; + intersection[1] = LineEnd[1]; + intersection[2] = LineEnd[2]; + type = LS_END; + } + + return ret; +} + + +#ifndef BEST_FIT_PLANE_H + +#define BEST_FIT_PLANE_H + +template class Eigen +{ +public: + + + void DecrSortEigenStuff(void) + { + Tridiagonal(); //diagonalize the matrix. + QLAlgorithm(); // + DecreasingSort(); + GuaranteeRotation(); + } + + void Tridiagonal(void) + { + Type fM00 = mElement[0][0]; + Type fM01 = mElement[0][1]; + Type fM02 = mElement[0][2]; + Type fM11 = mElement[1][1]; + Type fM12 = mElement[1][2]; + Type fM22 = mElement[2][2]; + + m_afDiag[0] = fM00; + m_afSubd[2] = 0; + if (fM02 != (Type)0.0) + { + Type fLength = (REAL)sqrt(fM01*fM01+fM02*fM02); + Type fInvLength = ((Type)1.0)/fLength; + fM01 *= fInvLength; + fM02 *= fInvLength; + Type fQ = ((Type)2.0)*fM01*fM12+fM02*(fM22-fM11); + m_afDiag[1] = fM11+fM02*fQ; + m_afDiag[2] = fM22-fM02*fQ; + m_afSubd[0] = fLength; + m_afSubd[1] = fM12-fM01*fQ; + mElement[0][0] = (Type)1.0; + mElement[0][1] = (Type)0.0; + mElement[0][2] = (Type)0.0; + mElement[1][0] = (Type)0.0; + mElement[1][1] = fM01; + mElement[1][2] = fM02; + mElement[2][0] = (Type)0.0; + mElement[2][1] = fM02; + mElement[2][2] = -fM01; + m_bIsRotation = false; + } + else + { + m_afDiag[1] = fM11; + m_afDiag[2] = fM22; + m_afSubd[0] = fM01; + m_afSubd[1] = fM12; + mElement[0][0] = (Type)1.0; + mElement[0][1] = (Type)0.0; + mElement[0][2] = (Type)0.0; + mElement[1][0] = (Type)0.0; + mElement[1][1] = (Type)1.0; + mElement[1][2] = (Type)0.0; + mElement[2][0] = (Type)0.0; + mElement[2][1] = (Type)0.0; + mElement[2][2] = (Type)1.0; + m_bIsRotation = true; + } + } + + bool QLAlgorithm(void) + { + const int32_t iMaxIter = 32; + + for (int32_t i0 = 0; i0 <3; i0++) + { + int32_t i1; + for (i1 = 0; i1 < iMaxIter; i1++) + { + int32_t i2; + for (i2 = i0; i2 <= (3-2); i2++) + { + Type fTmp = Type(fabs(m_afDiag[i2]) + fabs(m_afDiag[i2+1])); + if ( fabs(m_afSubd[i2]) + fTmp == fTmp ) + break; + } + if (i2 == i0) + { + break; + } + + Type fG = (m_afDiag[i0+1] - m_afDiag[i0])/(((Type)2.0) * m_afSubd[i0]); + Type fR = (REAL)sqrt(fG*fG+(Type)1.0); + if (fG < (Type)0.0) + { + fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG-fR); + } + else + { + fG = m_afDiag[i2]-m_afDiag[i0]+m_afSubd[i0]/(fG+fR); + } + Type fSin = (Type)1.0, fCos = (Type)1.0, fP = (Type)0.0; + for (int32_t i3 = i2-1; i3 >= i0; i3--) + { + Type fF = fSin*m_afSubd[i3]; + Type fB = fCos*m_afSubd[i3]; + if (fabs(fF) >= fabs(fG)) + { + fCos = fG/fF; + fR = (REAL)sqrt(fCos*fCos+(Type)1.0); + m_afSubd[i3+1] = fF*fR; + fSin = ((Type)1.0)/fR; + fCos *= fSin; + } + else + { + fSin = fF/fG; + fR = (REAL)sqrt(fSin*fSin+(Type)1.0); + m_afSubd[i3+1] = fG*fR; + fCos = ((Type)1.0)/fR; + fSin *= fCos; + } + fG = m_afDiag[i3+1]-fP; + fR = (m_afDiag[i3]-fG)*fSin+((Type)2.0)*fB*fCos; + fP = fSin*fR; + m_afDiag[i3+1] = fG+fP; + fG = fCos*fR-fB; + for (int32_t i4 = 0; i4 < 3; i4++) + { + fF = mElement[i4][i3+1]; + mElement[i4][i3+1] = fSin*mElement[i4][i3]+fCos*fF; + mElement[i4][i3] = fCos*mElement[i4][i3]-fSin*fF; + } + } + m_afDiag[i0] -= fP; + m_afSubd[i0] = fG; + m_afSubd[i2] = (Type)0.0; + } + if (i1 == iMaxIter) + { + return false; + } + } + return true; + } + + void DecreasingSort(void) + { + //sort eigenvalues in decreasing order, e[0] >= ... >= e[iSize-1] + for (int32_t i0 = 0, i1; i0 <= 3-2; i0++) + { + // locate maximum eigenvalue + i1 = i0; + Type fMax = m_afDiag[i1]; + int32_t i2; + for (i2 = i0+1; i2 < 3; i2++) + { + if (m_afDiag[i2] > fMax) + { + i1 = i2; + fMax = m_afDiag[i1]; + } + } + + if (i1 != i0) + { + // swap eigenvalues + m_afDiag[i1] = m_afDiag[i0]; + m_afDiag[i0] = fMax; + // swap eigenvectors + for (i2 = 0; i2 < 3; i2++) + { + Type fTmp = mElement[i2][i0]; + mElement[i2][i0] = mElement[i2][i1]; + mElement[i2][i1] = fTmp; + m_bIsRotation = !m_bIsRotation; + } + } + } + } + + + void GuaranteeRotation(void) + { + if (!m_bIsRotation) + { + // change sign on the first column + for (int32_t iRow = 0; iRow <3; iRow++) + { + mElement[iRow][0] = -mElement[iRow][0]; + } + } + } + + Type mElement[3][3]; + Type m_afDiag[3]; + Type m_afSubd[3]; + bool m_bIsRotation; +}; + +#endif + +bool fm_computeBestFitPlane(uint32_t vcount, + const REAL *points, + uint32_t vstride, + const REAL *weights, + uint32_t wstride, + REAL *plane, + REAL *center) +{ + bool ret = false; + + REAL kOrigin[3] = { 0, 0, 0 }; + + REAL wtotal = 0; + + { + const char *source = (const char *) points; + const char *wsource = (const char *) weights; + + for (uint32_t i=0; i kES; + + kES.mElement[0][0] = fSumXX; + kES.mElement[0][1] = fSumXY; + kES.mElement[0][2] = fSumXZ; + + kES.mElement[1][0] = fSumXY; + kES.mElement[1][1] = fSumYY; + kES.mElement[1][2] = fSumYZ; + + kES.mElement[2][0] = fSumXZ; + kES.mElement[2][1] = fSumYZ; + kES.mElement[2][2] = fSumZZ; + + // compute eigenstuff, smallest eigenvalue is in last position + kES.DecrSortEigenStuff(); + + REAL kNormal[3]; + + kNormal[0] = kES.mElement[0][2]; + kNormal[1] = kES.mElement[1][2]; + kNormal[2] = kES.mElement[2][2]; + + // the minimum energy + plane[0] = kNormal[0]; + plane[1] = kNormal[1]; + plane[2] = kNormal[2]; + + plane[3] = 0 - fm_dot(kNormal,kOrigin); + + ret = true; + + return ret; +} + + +bool fm_colinear(const REAL a1[3],const REAL a2[3],const REAL b1[3],const REAL b2[3],REAL epsilon) // true if these two line segments are co-linear. +{ + bool ret = false; + + REAL dir1[3]; + REAL dir2[3]; + + dir1[0] = (a2[0] - a1[0]); + dir1[1] = (a2[1] - a1[1]); + dir1[2] = (a2[2] - a1[2]); + + dir2[0] = (b2[0]-a1[0]) - (b1[0]-a1[0]); + dir2[1] = (b2[1]-a1[1]) - (b1[1]-a1[1]); + dir2[2] = (b2[2]-a2[2]) - (b1[2]-a2[2]); + + fm_normalize(dir1); + fm_normalize(dir2); + + REAL dot = fm_dot(dir1,dir2); + + if ( dot >= epsilon ) + { + ret = true; + } + + + return ret; +} + +bool fm_colinear(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) +{ + bool ret = false; + + REAL dir1[3]; + REAL dir2[3]; + + dir1[0] = p2[0] - p1[0]; + dir1[1] = p2[1] - p1[1]; + dir1[2] = p2[2] - p1[2]; + + dir2[0] = p3[0] - p2[0]; + dir2[1] = p3[1] - p2[1]; + dir2[2] = p3[2] - p2[2]; + + fm_normalize(dir1); + fm_normalize(dir2); + + REAL dot = fm_dot(dir1,dir2); + + if ( dot >= epsilon ) + { + ret = true; + } + + + return ret; +} + +void fm_initMinMax(const REAL *p,REAL *bmin,REAL *bmax) +{ + bmax[0] = bmin[0] = p[0]; + bmax[1] = bmin[1] = p[1]; + bmax[2] = bmin[2] = p[2]; +} + +IntersectResult fm_intersectLineSegments2d(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL *intersection) +{ + IntersectResult ret; + + REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); + REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); + REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); + if (denom == 0 ) + { + if(nume_a == 0 && nume_b == 0) + { + ret = IR_COINCIDENT; + } + else + { + ret = IR_PARALLEL; + } + } + else + { + + REAL recip = 1 / denom; + REAL ua = nume_a * recip; + REAL ub = nume_b * recip; + + if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) + { + // Get the intersection point. + intersection[0] = a1[0] + ua*(a2[0] - a1[0]); + intersection[1] = a1[1] + ua*(a2[1] - a1[1]); + ret = IR_DO_INTERSECT; + } + else + { + ret = IR_DONT_INTERSECT; + } + } + return ret; +} + +IntersectResult fm_intersectLineSegments2dTime(const REAL *a1,const REAL *a2,const REAL *b1,const REAL *b2,REAL &t1,REAL &t2) +{ + IntersectResult ret; + + REAL denom = ((b2[1] - b1[1])*(a2[0] - a1[0])) - ((b2[0] - b1[0])*(a2[1] - a1[1])); + REAL nume_a = ((b2[0] - b1[0])*(a1[1] - b1[1])) - ((b2[1] - b1[1])*(a1[0] - b1[0])); + REAL nume_b = ((a2[0] - a1[0])*(a1[1] - b1[1])) - ((a2[1] - a1[1])*(a1[0] - b1[0])); + if (denom == 0 ) + { + if(nume_a == 0 && nume_b == 0) + { + ret = IR_COINCIDENT; + } + else + { + ret = IR_PARALLEL; + } + } + else + { + + REAL recip = 1 / denom; + REAL ua = nume_a * recip; + REAL ub = nume_b * recip; + + if(ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1 ) + { + t1 = ua; + t2 = ub; + ret = IR_DO_INTERSECT; + } + else + { + ret = IR_DONT_INTERSECT; + } + } + return ret; +} + +//**** Plane Triangle Intersection + + + + + +// assumes that the points are on opposite sides of the plane! +bool fm_intersectPointPlane(const REAL *p1,const REAL *p2,REAL *split,const REAL *plane) +{ + + REAL dp1 = fm_distToPlane(plane,p1); + REAL dp2 = fm_distToPlane(plane, p2); + if (dp1 <= 0 && dp2 <= 0) + { + return false; + } + if (dp1 >= 0 && dp2 >= 0) + { + return false; + } + + REAL dir[3]; + + dir[0] = p2[0] - p1[0]; + dir[1] = p2[1] - p1[1]; + dir[2] = p2[2] - p1[2]; + + REAL dot1 = dir[0]*plane[0] + dir[1]*plane[1] + dir[2]*plane[2]; + REAL dot2 = dp1 - plane[3]; + + REAL t = -(plane[3] + dot2 ) / dot1; + + split[0] = (dir[0]*t)+p1[0]; + split[1] = (dir[1]*t)+p1[1]; + split[2] = (dir[2]*t)+p1[2]; + + return true; +} + +PlaneTriResult fm_getSidePlane(const REAL *p,const REAL *plane,REAL epsilon) +{ + PlaneTriResult ret = PTR_ON_PLANE; + + REAL d = fm_distToPlane(plane,p); + + if ( d < -epsilon || d > epsilon ) + { + if ( d > 0 ) + ret = PTR_FRONT; // it is 'in front' within the provided epsilon value. + else + ret = PTR_BACK; + } + + return ret; +} + + + +#ifndef PLANE_TRIANGLE_INTERSECTION_H + +#define PLANE_TRIANGLE_INTERSECTION_H + +#define MAXPTS 256 + +template class point +{ +public: + + void set(const Type *p) + { + x = p[0]; + y = p[1]; + z = p[2]; + } + + Type x; + Type y; + Type z; +}; + +template class plane +{ +public: + plane(const Type *p) + { + normal.x = p[0]; + normal.y = p[1]; + normal.z = p[2]; + D = p[3]; + } + + Type Classify_Point(const point &p) + { + return p.x*normal.x + p.y*normal.y + p.z*normal.z + D; + } + + point normal; + Type D; +}; + +template class polygon +{ +public: + polygon(void) + { + mVcount = 0; + } + + polygon(const Type *p1,const Type *p2,const Type *p3) + { + mVcount = 3; + mVertices[0].set(p1); + mVertices[1].set(p2); + mVertices[2].set(p3); + } + + + int32_t NumVertices(void) const { return mVcount; }; + + const point& Vertex(int32_t index) + { + if ( index < 0 ) index+=mVcount; + return mVertices[index]; + }; + + + void set(const point *pts,int32_t count) + { + for (int32_t i=0; i *poly,plane *part, polygon &front, polygon &back) + { + int32_t count = poly->NumVertices (); + int32_t out_c = 0, in_c = 0; + point ptA, ptB,outpts[MAXPTS],inpts[MAXPTS]; + Type sideA, sideB; + ptA = poly->Vertex (count - 1); + sideA = part->Classify_Point (ptA); + for (int32_t i = -1; ++i < count;) + { + ptB = poly->Vertex(i); + sideB = part->Classify_Point(ptB); + if (sideB > 0) + { + if (sideA < 0) + { + point v; + fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); + outpts[out_c++] = inpts[in_c++] = v; + } + outpts[out_c++] = ptB; + } + else if (sideB < 0) + { + if (sideA > 0) + { + point v; + fm_intersectPointPlane(&ptB.x, &ptA.x, &v.x, &part->normal.x ); + outpts[out_c++] = inpts[in_c++] = v; + } + inpts[in_c++] = ptB; + } + else + outpts[out_c++] = inpts[in_c++] = ptB; + ptA = ptB; + sideA = sideB; + } + + front.set(&outpts[0], out_c); + back.set(&inpts[0], in_c); + } + + int32_t mVcount; + point mVertices[MAXPTS]; +}; + + + +#endif + +static inline void add(const REAL *p,REAL *dest,uint32_t tstride,uint32_t &pcount) +{ + char *d = (char *) dest; + d = d + pcount*tstride; + dest = (REAL *) d; + dest[0] = p[0]; + dest[1] = p[1]; + dest[2] = p[2]; + pcount++; + assert( pcount <= 4 ); +} + + +PlaneTriResult fm_planeTriIntersection(const REAL *_plane, // the plane equation in Ax+By+Cz+D format + const REAL *triangle, // the source triangle. + uint32_t tstride, // stride in bytes of the input and output *vertices* + REAL epsilon, // the co-planar epsilon value. + REAL *front, // the triangle in front of the + uint32_t &fcount, // number of vertices in the 'front' triangle + REAL *back, // the triangle in back of the plane + uint32_t &bcount) // the number of vertices in the 'back' triangle. +{ + + fcount = 0; + bcount = 0; + + const char *tsource = (const char *) triangle; + + // get the three vertices of the triangle. + const REAL *p1 = (const REAL *) (tsource); + const REAL *p2 = (const REAL *) (tsource+tstride); + const REAL *p3 = (const REAL *) (tsource+tstride*2); + + + PlaneTriResult r1 = fm_getSidePlane(p1,_plane,epsilon); // compute the side of the plane each vertex is on + PlaneTriResult r2 = fm_getSidePlane(p2,_plane,epsilon); + PlaneTriResult r3 = fm_getSidePlane(p3,_plane,epsilon); + + // If any of the points lay right *on* the plane.... + if ( r1 == PTR_ON_PLANE || r2 == PTR_ON_PLANE || r3 == PTR_ON_PLANE ) + { + // If the triangle is completely co-planar, then just treat it as 'front' and return! + if ( r1 == PTR_ON_PLANE && r2 == PTR_ON_PLANE && r3 == PTR_ON_PLANE ) + { + add(p1,front,tstride,fcount); + add(p2,front,tstride,fcount); + add(p3,front,tstride,fcount); + return PTR_FRONT; + } + // Decide to place the co-planar points on the same side as the co-planar point. + PlaneTriResult r= PTR_ON_PLANE; + if ( r1 != PTR_ON_PLANE ) + r = r1; + else if ( r2 != PTR_ON_PLANE ) + r = r2; + else if ( r3 != PTR_ON_PLANE ) + r = r3; + + if ( r1 == PTR_ON_PLANE ) r1 = r; + if ( r2 == PTR_ON_PLANE ) r2 = r; + if ( r3 == PTR_ON_PLANE ) r3 = r; + + } + + if ( r1 == r2 && r1 == r3 ) // if all three vertices are on the same side of the plane. + { + if ( r1 == PTR_FRONT ) // if all three are in front of the plane, then copy to the 'front' output triangle. + { + add(p1,front,tstride,fcount); + add(p2,front,tstride,fcount); + add(p3,front,tstride,fcount); + } + else + { + add(p1,back,tstride,bcount); // if all three are in 'back' then copy to the 'back' output triangle. + add(p2,back,tstride,bcount); + add(p3,back,tstride,bcount); + } + return r1; // if all three points are on the same side of the plane return result + } + + + polygon pi(p1,p2,p3); + polygon pfront,pback; + + plane part(_plane); + + pi.Split_Polygon(&pi,&part,pfront,pback); + + for (int32_t i=0; i bmax[0] ) bmax[0] = t[0]; + if ( t[1] > bmax[1] ) bmax[1] = t[1]; + if ( t[2] > bmax[2] ) bmax[2] = t[2]; + + src+=pstride; + } + + REAL center[3]; + + sides[0] = bmax[0]-bmin[0]; + sides[1] = bmax[1]-bmin[1]; + sides[2] = bmax[2]-bmin[2]; + + center[0] = sides[0]*0.5f+bmin[0]; + center[1] = sides[1]*0.5f+bmin[1]; + center[2] = sides[2]*0.5f+bmin[2]; + + REAL ocenter[3]; + + fm_rotate(matrix,center,ocenter); + + matrix[12]+=ocenter[0]; + matrix[13]+=ocenter[1]; + matrix[14]+=ocenter[2]; + +} + +void fm_computeBestFitOBB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *sides,REAL *matrix,bool bruteForce) +{ + REAL plane[4]; + REAL center[3]; + fm_computeBestFitPlane(vcount,points,pstride,0,0,plane,center); + fm_planeToMatrix(plane,matrix); + computeOBB( vcount, points, pstride, sides, matrix ); + + REAL refmatrix[16]; + memcpy(refmatrix,matrix,16*sizeof(REAL)); + + REAL volume = sides[0]*sides[1]*sides[2]; + if ( bruteForce ) + { + for (REAL a=10; a<180; a+=10) + { + REAL quat[4]; + fm_eulerToQuat(0,a*FM_DEG_TO_RAD,0,quat); + REAL temp[16]; + REAL pmatrix[16]; + fm_quatToMatrix(quat,temp); + fm_matrixMultiply(temp,refmatrix,pmatrix); + REAL psides[3]; + computeOBB( vcount, points, pstride, psides, pmatrix ); + REAL v = psides[0]*psides[1]*psides[2]; + if ( v < volume ) + { + volume = v; + memcpy(matrix,pmatrix,sizeof(REAL)*16); + sides[0] = psides[0]; + sides[1] = psides[1]; + sides[2] = psides[2]; + } + } + } +} + +void fm_computeBestFitOBB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *sides,REAL *pos,REAL *quat,bool bruteForce) +{ + REAL matrix[16]; + fm_computeBestFitOBB(vcount,points,pstride,sides,matrix,bruteForce); + fm_getTranslation(matrix,pos); + fm_matrixToQuat(matrix,quat); +} + +void fm_computeBestFitABB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *sides,REAL *pos) +{ + REAL bmin[3]; + REAL bmax[3]; + + bmin[0] = points[0]; + bmin[1] = points[1]; + bmin[2] = points[2]; + + bmax[0] = points[0]; + bmax[1] = points[1]; + bmax[2] = points[2]; + + const char *cp = (const char *) points; + for (uint32_t i=0; i bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + + cp+=pstride; + } + + + sides[0] = bmax[0] - bmin[0]; + sides[1] = bmax[1] - bmin[1]; + sides[2] = bmax[2] - bmin[2]; + + pos[0] = bmin[0]+sides[0]*0.5f; + pos[1] = bmin[1]+sides[1]*0.5f; + pos[2] = bmin[2]+sides[2]*0.5f; + +} + + +void fm_planeToMatrix(const REAL *plane,REAL *matrix) // convert a plane equation to a 4x4 rotation matrix +{ + REAL ref[3] = { 0, 1, 0 }; + REAL quat[4]; + fm_rotationArc(ref,plane,quat); + fm_quatToMatrix(quat,matrix); + REAL origin[3] = { 0, -plane[3], 0 }; + REAL center[3]; + fm_transform(matrix,origin,center); + fm_setTranslation(center,matrix); +} + +void fm_planeToQuat(const REAL *plane,REAL *quat,REAL *pos) // convert a plane equation to a quaternion and translation +{ + REAL ref[3] = { 0, 1, 0 }; + REAL matrix[16]; + fm_rotationArc(ref,plane,quat); + fm_quatToMatrix(quat,matrix); + REAL origin[3] = { 0, plane[3], 0 }; + fm_transform(matrix,origin,pos); +} + +void fm_eulerMatrix(REAL ax,REAL ay,REAL az,REAL *matrix) // convert euler (in radians) to a dest 4x4 matrix (translation set to zero) +{ + REAL quat[4]; + fm_eulerToQuat(ax,ay,az,quat); + fm_quatToMatrix(quat,matrix); +} + + +//********************************************************** +//********************************************************** +//**** Vertex Welding +//********************************************************** +//********************************************************** + +#ifndef VERTEX_INDEX_H + +#define VERTEX_INDEX_H + +namespace VERTEX_INDEX +{ + +class KdTreeNode; + +typedef std::vector< KdTreeNode * > KdTreeNodeVector; + +enum Axes +{ + X_AXIS = 0, + Y_AXIS = 1, + Z_AXIS = 2 +}; + +class KdTreeFindNode +{ +public: + KdTreeFindNode(void) + { + mNode = 0; + mDistance = 0; + } + KdTreeNode *mNode; + double mDistance; +}; + +class KdTreeInterface +{ +public: + virtual const double * getPositionDouble(uint32_t index) const = 0; + virtual const float * getPositionFloat(uint32_t index) const = 0; +}; + +class KdTreeNode +{ +public: + KdTreeNode(void) + { + mIndex = 0; + mLeft = 0; + mRight = 0; + } + + KdTreeNode(uint32_t index) + { + mIndex = index; + mLeft = 0; + mRight = 0; + }; + + ~KdTreeNode(void) + { + } + + + void addDouble(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) + { + const double *nodePosition = iface->getPositionDouble( node->mIndex ); + const double *position = iface->getPositionDouble( mIndex ); + switch ( dim ) + { + case X_AXIS: + if ( nodePosition[0] <= position[0] ) + { + if ( mLeft ) + mLeft->addDouble(node,Y_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addDouble(node,Y_AXIS,iface); + else + mRight = node; + } + break; + case Y_AXIS: + if ( nodePosition[1] <= position[1] ) + { + if ( mLeft ) + mLeft->addDouble(node,Z_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addDouble(node,Z_AXIS,iface); + else + mRight = node; + } + break; + case Z_AXIS: + if ( nodePosition[2] <= position[2] ) + { + if ( mLeft ) + mLeft->addDouble(node,X_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addDouble(node,X_AXIS,iface); + else + mRight = node; + } + break; + } + + } + + + void addFloat(KdTreeNode *node,Axes dim,const KdTreeInterface *iface) + { + const float *nodePosition = iface->getPositionFloat( node->mIndex ); + const float *position = iface->getPositionFloat( mIndex ); + switch ( dim ) + { + case X_AXIS: + if ( nodePosition[0] <= position[0] ) + { + if ( mLeft ) + mLeft->addFloat(node,Y_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addFloat(node,Y_AXIS,iface); + else + mRight = node; + } + break; + case Y_AXIS: + if ( nodePosition[1] <= position[1] ) + { + if ( mLeft ) + mLeft->addFloat(node,Z_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addFloat(node,Z_AXIS,iface); + else + mRight = node; + } + break; + case Z_AXIS: + if ( nodePosition[2] <= position[2] ) + { + if ( mLeft ) + mLeft->addFloat(node,X_AXIS,iface); + else + mLeft = node; + } + else + { + if ( mRight ) + mRight->addFloat(node,X_AXIS,iface); + else + mRight = node; + } + break; + } + + } + + + uint32_t getIndex(void) const { return mIndex; }; + + void search(Axes axis,const double *pos,double radius,uint32_t &count,uint32_t maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) + { + + const double *position = iface->getPositionDouble(mIndex); + + double dx = pos[0] - position[0]; + double dy = pos[1] - position[1]; + double dz = pos[2] - position[2]; + + KdTreeNode *search1 = 0; + KdTreeNode *search2 = 0; + + switch ( axis ) + { + case X_AXIS: + if ( dx <= 0 ) // JWR if we are to the left + { + search1 = mLeft; // JWR then search to the left + if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. + search2 = mRight; + } + else + { + search1 = mRight; // JWR ok, we go down the left tree + if ( dx < radius ) // JWR if the distance from the right is less than our search radius + search2 = mLeft; + } + axis = Y_AXIS; + break; + case Y_AXIS: + if ( dy <= 0 ) + { + search1 = mLeft; + if ( -dy < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dy < radius ) + search2 = mLeft; + } + axis = Z_AXIS; + break; + case Z_AXIS: + if ( dz <= 0 ) + { + search1 = mLeft; + if ( -dz < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dz < radius ) + search2 = mLeft; + } + axis = X_AXIS; + break; + } + + double r2 = radius*radius; + double m = dx*dx+dy*dy+dz*dz; + + if ( m < r2 ) + { + switch ( count ) + { + case 0: + found[count].mNode = this; + found[count].mDistance = m; + break; + case 1: + if ( m < found[0].mDistance ) + { + if ( maxObjects == 1 ) + { + found[0].mNode = this; + found[0].mDistance = m; + } + else + { + found[1] = found[0]; + found[0].mNode = this; + found[0].mDistance = m; + } + } + else if ( maxObjects > 1) + { + found[1].mNode = this; + found[1].mDistance = m; + } + break; + default: + { + bool inserted = false; + + for (uint32_t i=0; i= maxObjects ) scan=maxObjects-1; + for (uint32_t j=scan; j>i; j--) + { + found[j] = found[j-1]; + } + found[i].mNode = this; + found[i].mDistance = m; + inserted = true; + break; + } + } + + if ( !inserted && count < maxObjects ) + { + found[count].mNode = this; + found[count].mDistance = m; + } + } + break; + } + count++; + if ( count > maxObjects ) + { + count = maxObjects; + } + } + + + if ( search1 ) + search1->search( axis, pos,radius, count, maxObjects, found, iface); + + if ( search2 ) + search2->search( axis, pos,radius, count, maxObjects, found, iface); + + } + + void search(Axes axis,const float *pos,float radius,uint32_t &count,uint32_t maxObjects,KdTreeFindNode *found,const KdTreeInterface *iface) + { + + const float *position = iface->getPositionFloat(mIndex); + + float dx = pos[0] - position[0]; + float dy = pos[1] - position[1]; + float dz = pos[2] - position[2]; + + KdTreeNode *search1 = 0; + KdTreeNode *search2 = 0; + + switch ( axis ) + { + case X_AXIS: + if ( dx <= 0 ) // JWR if we are to the left + { + search1 = mLeft; // JWR then search to the left + if ( -dx < radius ) // JWR if distance to the right is less than our search radius, continue on the right as well. + search2 = mRight; + } + else + { + search1 = mRight; // JWR ok, we go down the left tree + if ( dx < radius ) // JWR if the distance from the right is less than our search radius + search2 = mLeft; + } + axis = Y_AXIS; + break; + case Y_AXIS: + if ( dy <= 0 ) + { + search1 = mLeft; + if ( -dy < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dy < radius ) + search2 = mLeft; + } + axis = Z_AXIS; + break; + case Z_AXIS: + if ( dz <= 0 ) + { + search1 = mLeft; + if ( -dz < radius ) + search2 = mRight; + } + else + { + search1 = mRight; + if ( dz < radius ) + search2 = mLeft; + } + axis = X_AXIS; + break; + } + + float r2 = radius*radius; + float m = dx*dx+dy*dy+dz*dz; + + if ( m < r2 ) + { + switch ( count ) + { + case 0: + found[count].mNode = this; + found[count].mDistance = m; + break; + case 1: + if ( m < found[0].mDistance ) + { + if ( maxObjects == 1 ) + { + found[0].mNode = this; + found[0].mDistance = m; + } + else + { + found[1] = found[0]; + found[0].mNode = this; + found[0].mDistance = m; + } + } + else if ( maxObjects > 1) + { + found[1].mNode = this; + found[1].mDistance = m; + } + break; + default: + { + bool inserted = false; + + for (uint32_t i=0; i= maxObjects ) scan=maxObjects-1; + for (uint32_t j=scan; j>i; j--) + { + found[j] = found[j-1]; + } + found[i].mNode = this; + found[i].mDistance = m; + inserted = true; + break; + } + } + + if ( !inserted && count < maxObjects ) + { + found[count].mNode = this; + found[count].mDistance = m; + } + } + break; + } + count++; + if ( count > maxObjects ) + { + count = maxObjects; + } + } + + + if ( search1 ) + search1->search( axis, pos,radius, count, maxObjects, found, iface); + + if ( search2 ) + search2->search( axis, pos,radius, count, maxObjects, found, iface); + + } + +private: + + void setLeft(KdTreeNode *left) { mLeft = left; }; + void setRight(KdTreeNode *right) { mRight = right; }; + + KdTreeNode *getLeft(void) { return mLeft; } + KdTreeNode *getRight(void) { return mRight; } + + uint32_t mIndex; + KdTreeNode *mLeft; + KdTreeNode *mRight; +}; + + +#define MAX_BUNDLE_SIZE 1024 // 1024 nodes at a time, to minimize memory allocation and guarantee that pointers are persistent. + +class KdTreeNodeBundle +{ +public: + + KdTreeNodeBundle(void) + { + mNext = 0; + mIndex = 0; + } + + bool isFull(void) const + { + return (bool)( mIndex == MAX_BUNDLE_SIZE ); + } + + KdTreeNode * getNextNode(void) + { + assert(mIndex DoubleVector; +typedef std::vector< float > FloatVector; + +class KdTree : public KdTreeInterface +{ +public: + KdTree(void) + { + mRoot = 0; + mBundle = 0; + mVcount = 0; + mUseDouble = false; + } + + virtual ~KdTree(void) + { + reset(); + } + + const double * getPositionDouble(uint32_t index) const + { + assert( mUseDouble ); + assert ( index < mVcount ); + return &mVerticesDouble[index*3]; + } + + const float * getPositionFloat(uint32_t index) const + { + assert( !mUseDouble ); + assert ( index < mVcount ); + return &mVerticesFloat[index*3]; + } + + uint32_t search(const double *pos,double radius,uint32_t maxObjects,KdTreeFindNode *found) const + { + assert( mUseDouble ); + if ( !mRoot ) return 0; + uint32_t count = 0; + mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); + return count; + } + + uint32_t search(const float *pos,float radius,uint32_t maxObjects,KdTreeFindNode *found) const + { + assert( !mUseDouble ); + if ( !mRoot ) return 0; + uint32_t count = 0; + mRoot->search(X_AXIS,pos,radius,count,maxObjects,found,this); + return count; + } + + void reset(void) + { + mRoot = 0; + mVerticesDouble.clear(); + mVerticesFloat.clear(); + KdTreeNodeBundle *bundle = mBundle; + while ( bundle ) + { + KdTreeNodeBundle *next = bundle->mNext; + delete bundle; + bundle = next; + } + mBundle = 0; + mVcount = 0; + } + + uint32_t add(double x,double y,double z) + { + assert(mUseDouble); + uint32_t ret = mVcount; + mVerticesDouble.push_back(x); + mVerticesDouble.push_back(y); + mVerticesDouble.push_back(z); + mVcount++; + KdTreeNode *node = getNewNode(ret); + if ( mRoot ) + { + mRoot->addDouble(node,X_AXIS,this); + } + else + { + mRoot = node; + } + return ret; + } + + uint32_t add(float x,float y,float z) + { + assert(!mUseDouble); + uint32_t ret = mVcount; + mVerticesFloat.push_back(x); + mVerticesFloat.push_back(y); + mVerticesFloat.push_back(z); + mVcount++; + KdTreeNode *node = getNewNode(ret); + if ( mRoot ) + { + mRoot->addFloat(node,X_AXIS,this); + } + else + { + mRoot = node; + } + return ret; + } + + KdTreeNode * getNewNode(uint32_t index) + { + if ( mBundle == 0 ) + { + mBundle = new KdTreeNodeBundle; + } + if ( mBundle->isFull() ) + { + KdTreeNodeBundle *bundle = new KdTreeNodeBundle; + mBundle->mNext = bundle; + mBundle = bundle; + } + KdTreeNode *node = mBundle->getNextNode(); + new ( node ) KdTreeNode(index); + return node; + } + + uint32_t getNearest(const double *pos,double radius,bool &_found) const // returns the nearest possible neighbor's index. + { + assert( mUseDouble ); + uint32_t ret = 0; + + _found = false; + KdTreeFindNode found[1]; + uint32_t count = search(pos,radius,1,found); + if ( count ) + { + KdTreeNode *node = found[0].mNode; + ret = node->getIndex(); + _found = true; + } + return ret; + } + + uint32_t getNearest(const float *pos,float radius,bool &_found) const // returns the nearest possible neighbor's index. + { + assert( !mUseDouble ); + uint32_t ret = 0; + + _found = false; + KdTreeFindNode found[1]; + uint32_t count = search(pos,radius,1,found); + if ( count ) + { + KdTreeNode *node = found[0].mNode; + ret = node->getIndex(); + _found = true; + } + return ret; + } + + const double * getVerticesDouble(void) const + { + assert( mUseDouble ); + const double *ret = 0; + if ( !mVerticesDouble.empty() ) + { + ret = &mVerticesDouble[0]; + } + return ret; + } + + const float * getVerticesFloat(void) const + { + assert( !mUseDouble ); + const float * ret = 0; + if ( !mVerticesFloat.empty() ) + { + ret = &mVerticesFloat[0]; + } + return ret; + } + + uint32_t getVcount(void) const { return mVcount; }; + + void setUseDouble(bool useDouble) + { + mUseDouble = useDouble; + } + +private: + bool mUseDouble; + KdTreeNode *mRoot; + KdTreeNodeBundle *mBundle; + uint32_t mVcount; + DoubleVector mVerticesDouble; + FloatVector mVerticesFloat; +}; + +}; // end of namespace VERTEX_INDEX + +class MyVertexIndex : public fm_VertexIndex +{ +public: + MyVertexIndex(double granularity,bool snapToGrid) + { + mDoubleGranularity = granularity; + mFloatGranularity = (float)granularity; + mSnapToGrid = snapToGrid; + mUseDouble = true; + mKdTree.setUseDouble(true); + } + + MyVertexIndex(float granularity,bool snapToGrid) + { + mDoubleGranularity = granularity; + mFloatGranularity = (float)granularity; + mSnapToGrid = snapToGrid; + mUseDouble = false; + mKdTree.setUseDouble(false); + } + + virtual ~MyVertexIndex(void) + { + + } + + + double snapToGrid(double p) + { + double m = fmod(p,mDoubleGranularity); + p-=m; + return p; + } + + float snapToGrid(float p) + { + float m = fmodf(p,mFloatGranularity); + p-=m; + return p; + } + + uint32_t getIndex(const float *_p,bool &newPos) // get index for a vector float + { + uint32_t ret; + + if ( mUseDouble ) + { + double p[3]; + p[0] = _p[0]; + p[1] = _p[1]; + p[2] = _p[2]; + return getIndex(p,newPos); + } + + newPos = false; + + float p[3]; + + if ( mSnapToGrid ) + { + p[0] = snapToGrid(_p[0]); + p[1] = snapToGrid(_p[1]); + p[2] = snapToGrid(_p[2]); + } + else + { + p[0] = _p[0]; + p[1] = _p[1]; + p[2] = _p[2]; + } + + bool found; + ret = mKdTree.getNearest(p,mFloatGranularity,found); + if ( !found ) + { + newPos = true; + ret = mKdTree.add(p[0],p[1],p[2]); + } + + + return ret; + } + + uint32_t getIndex(const double *_p,bool &newPos) // get index for a vector double + { + uint32_t ret; + + if ( !mUseDouble ) + { + float p[3]; + p[0] = (float)_p[0]; + p[1] = (float)_p[1]; + p[2] = (float)_p[2]; + return getIndex(p,newPos); + } + + newPos = false; + + double p[3]; + + if ( mSnapToGrid ) + { + p[0] = snapToGrid(_p[0]); + p[1] = snapToGrid(_p[1]); + p[2] = snapToGrid(_p[2]); + } + else + { + p[0] = _p[0]; + p[1] = _p[1]; + p[2] = _p[2]; + } + + bool found; + ret = mKdTree.getNearest(p,mDoubleGranularity,found); + if ( !found ) + { + newPos = true; + ret = mKdTree.add(p[0],p[1],p[2]); + } + + + return ret; + } + + const float * getVerticesFloat(void) const + { + const float * ret = 0; + + assert( !mUseDouble ); + + ret = mKdTree.getVerticesFloat(); + + return ret; + } + + const double * getVerticesDouble(void) const + { + const double * ret = 0; + + assert( mUseDouble ); + + ret = mKdTree.getVerticesDouble(); + + return ret; + } + + const float * getVertexFloat(uint32_t index) const + { + const float * ret = 0; + assert( !mUseDouble ); +#ifdef _DEBUG + uint32_t vcount = mKdTree.getVcount(); + assert( index < vcount ); +#endif + ret = mKdTree.getVerticesFloat(); + ret = &ret[index*3]; + return ret; + } + + const double * getVertexDouble(uint32_t index) const + { + const double * ret = 0; + assert( mUseDouble ); +#ifdef _DEBUG + uint32_t vcount = mKdTree.getVcount(); + assert( index < vcount ); +#endif + ret = mKdTree.getVerticesDouble(); + ret = &ret[index*3]; + + return ret; + } + + uint32_t getVcount(void) const + { + return mKdTree.getVcount(); + } + + bool isDouble(void) const + { + return mUseDouble; + } + + + bool saveAsObj(const char *fname,uint32_t tcount,uint32_t *indices) + { + bool ret = false; + + + FILE *fph = fopen(fname,"wb"); + if ( fph ) + { + ret = true; + + uint32_t vcount = getVcount(); + if ( mUseDouble ) + { + const double *v = getVerticesDouble(); + for (uint32_t i=0; i(ret); +} + +fm_VertexIndex * fm_createVertexIndex(float granularity,bool snapToGrid) // create an indexed vertext system for floats +{ + MyVertexIndex *ret = new MyVertexIndex(granularity,snapToGrid); + return static_cast< fm_VertexIndex *>(ret); +} + +void fm_releaseVertexIndex(fm_VertexIndex *vindex) +{ + MyVertexIndex *m = static_cast< MyVertexIndex *>(vindex); + delete m; +} + +#endif // END OF VERTEX WELDING CODE + + +REAL fm_computeBestFitAABB(uint32_t vcount,const REAL *points,uint32_t pstride,REAL *bmin,REAL *bmax) // returns the diagonal distance +{ + + const uint8_t *source = (const uint8_t *) points; + + bmin[0] = points[0]; + bmin[1] = points[1]; + bmin[2] = points[2]; + + bmax[0] = points[0]; + bmax[1] = points[1]; + bmax[2] = points[2]; + + + for (uint32_t i=1; i bmax[0] ) bmax[0] = p[0]; + if ( p[1] > bmax[1] ) bmax[1] = p[1]; + if ( p[2] > bmax[2] ) bmax[2] = p[2]; + + } + + REAL dx = bmax[0] - bmin[0]; + REAL dy = bmax[1] - bmin[1]; + REAL dz = bmax[2] - bmin[2]; + + return (REAL) sqrt( dx*dx + dy*dy + dz*dz ); + +} + + + +/* a = b - c */ +#define vector(a,b,c) \ + (a)[0] = (b)[0] - (c)[0]; \ + (a)[1] = (b)[1] - (c)[1]; \ + (a)[2] = (b)[2] - (c)[2]; + + + +#define innerProduct(v,q) \ + ((v)[0] * (q)[0] + \ + (v)[1] * (q)[1] + \ + (v)[2] * (q)[2]) + +#define crossProduct(a,b,c) \ + (a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \ + (a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \ + (a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1]; + + +bool fm_lineIntersectsTriangle(const REAL *rayStart,const REAL *rayEnd,const REAL *p1,const REAL *p2,const REAL *p3,REAL *sect) +{ + REAL dir[3]; + + dir[0] = rayEnd[0] - rayStart[0]; + dir[1] = rayEnd[1] - rayStart[1]; + dir[2] = rayEnd[2] - rayStart[2]; + + REAL d = (REAL)sqrt(dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2]); + REAL r = 1.0f / d; + + dir[0]*=r; + dir[1]*=r; + dir[2]*=r; + + + REAL t; + + bool ret = fm_rayIntersectsTriangle(rayStart, dir, p1, p2, p3, t ); + + if ( ret ) + { + if ( t > d ) + { + sect[0] = rayStart[0] + dir[0]*t; + sect[1] = rayStart[1] + dir[1]*t; + sect[2] = rayStart[2] + dir[2]*t; + } + else + { + ret = false; + } + } + + return ret; +} + + + +bool fm_rayIntersectsTriangle(const REAL *p,const REAL *d,const REAL *v0,const REAL *v1,const REAL *v2,REAL &t) +{ + REAL e1[3],e2[3],h[3],s[3],q[3]; + REAL a,f,u,v; + + vector(e1,v1,v0); + vector(e2,v2,v0); + crossProduct(h,d,e2); + a = innerProduct(e1,h); + + if (a > -0.00001 && a < 0.00001) + return(false); + + f = 1/a; + vector(s,p,v0); + u = f * (innerProduct(s,h)); + + if (u < 0.0 || u > 1.0) + return(false); + + crossProduct(q,s,e1); + v = f * innerProduct(d,q); + if (v < 0.0 || u + v > 1.0) + return(false); + // at this stage we can compute t to find out where + // the intersection point is on the line + t = f * innerProduct(e2,q); + if (t > 0) // ray intersection + return(true); + else // this means that there is a line intersection + // but not a ray intersection + return (false); +} + + +inline REAL det(const REAL *p1,const REAL *p2,const REAL *p3) +{ + return p1[0]*p2[1]*p3[2] + p2[0]*p3[1]*p1[2] + p3[0]*p1[1]*p2[2] -p1[0]*p3[1]*p2[2] - p2[0]*p1[1]*p3[2] - p3[0]*p2[1]*p1[2]; +} + + +REAL fm_computeMeshVolume(const REAL *vertices,uint32_t tcount,const uint32_t *indices) +{ + REAL volume = 0; + + for (uint32_t i=0; i= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); +} + + +REAL fm_areaPolygon2d(uint32_t pcount,const REAL *points,uint32_t pstride) +{ + int32_t n = (int32_t)pcount; + + REAL A=0.0f; + for(int32_t p=n-1,q=0; q= y) || (y2 < y && y1 >= y) ) + { + if (x1+(y-y1)/(y2-y1)*(x2-x1)= 3 ) + { + const REAL *prev = fm_getPoint(points,pstride,pcount-1); + const REAL *current = points; + const REAL *next = fm_getPoint(points,pstride,1); + REAL *dest = _dest; + + for (uint32_t i=0; i class Rect3d +{ +public: + Rect3d(void) { }; + + Rect3d(const T *bmin,const T *bmax) + { + + mMin[0] = bmin[0]; + mMin[1] = bmin[1]; + mMin[2] = bmin[2]; + + mMax[0] = bmax[0]; + mMax[1] = bmax[1]; + mMax[2] = bmax[2]; + + } + + void SetMin(const T *bmin) + { + mMin[0] = bmin[0]; + mMin[1] = bmin[1]; + mMin[2] = bmin[2]; + } + + void SetMax(const T *bmax) + { + mMax[0] = bmax[0]; + mMax[1] = bmax[1]; + mMax[2] = bmax[2]; + } + + void SetMin(T x,T y,T z) + { + mMin[0] = x; + mMin[1] = y; + mMin[2] = z; + } + + void SetMax(T x,T y,T z) + { + mMax[0] = x; + mMax[1] = y; + mMax[2] = z; + } + + T mMin[3]; + T mMax[3]; +}; + +#endif + +void splitRect(uint32_t axis, + const Rect3d &source, + Rect3d &b1, + Rect3d &b2, + const REAL *midpoint) +{ + switch ( axis ) + { + case 0: + b1.SetMin(source.mMin); + b1.SetMax( midpoint[0], source.mMax[1], source.mMax[2] ); + + b2.SetMin( midpoint[0], source.mMin[1], source.mMin[2] ); + b2.SetMax(source.mMax); + + break; + case 1: + b1.SetMin(source.mMin); + b1.SetMax( source.mMax[0], midpoint[1], source.mMax[2] ); + + b2.SetMin( source.mMin[0], midpoint[1], source.mMin[2] ); + b2.SetMax(source.mMax); + + break; + case 2: + b1.SetMin(source.mMin); + b1.SetMax( source.mMax[0], source.mMax[1], midpoint[2] ); + + b2.SetMin( source.mMin[0], source.mMin[1], midpoint[2] ); + b2.SetMax(source.mMax); + + break; + } +} + +bool fm_computeSplitPlane(uint32_t vcount, + const REAL *vertices, + uint32_t /* tcount */, + const uint32_t * /* indices */, + REAL *plane) +{ + + REAL sides[3]; + REAL matrix[16]; + + fm_computeBestFitOBB( vcount, vertices, sizeof(REAL)*3, sides, matrix ); + + REAL bmax[3]; + REAL bmin[3]; + + bmax[0] = sides[0]*0.5f; + bmax[1] = sides[1]*0.5f; + bmax[2] = sides[2]*0.5f; + + bmin[0] = -bmax[0]; + bmin[1] = -bmax[1]; + bmin[2] = -bmax[2]; + + + REAL dx = sides[0]; + REAL dy = sides[1]; + REAL dz = sides[2]; + + + uint32_t axis = 0; + + if ( dy > dx ) + { + axis = 1; + } + + if ( dz > dx && dz > dy ) + { + axis = 2; + } + + REAL p1[3]; + REAL p2[3]; + REAL p3[3]; + + p3[0] = p2[0] = p1[0] = bmin[0] + dx*0.5f; + p3[1] = p2[1] = p1[1] = bmin[1] + dy*0.5f; + p3[2] = p2[2] = p1[2] = bmin[2] + dz*0.5f; + + Rect3d b(bmin,bmax); + + Rect3d b1,b2; + + splitRect(axis,b,b1,b2,p1); + + + switch ( axis ) + { + case 0: + p2[1] = bmin[1]; + p2[2] = bmin[2]; + + if ( dz > dy ) + { + p3[1] = bmax[1]; + p3[2] = bmin[2]; + } + else + { + p3[1] = bmin[1]; + p3[2] = bmax[2]; + } + + break; + case 1: + p2[0] = bmin[0]; + p2[2] = bmin[2]; + + if ( dx > dz ) + { + p3[0] = bmax[0]; + p3[2] = bmin[2]; + } + else + { + p3[0] = bmin[0]; + p3[2] = bmax[2]; + } + + break; + case 2: + p2[0] = bmin[0]; + p2[1] = bmin[1]; + + if ( dx > dy ) + { + p3[0] = bmax[0]; + p3[1] = bmin[1]; + } + else + { + p3[0] = bmin[0]; + p3[1] = bmax[1]; + } + + break; + } + + REAL tp1[3]; + REAL tp2[3]; + REAL tp3[3]; + + fm_transform(matrix,p1,tp1); + fm_transform(matrix,p2,tp2); + fm_transform(matrix,p3,tp3); + + plane[3] = fm_computePlane(tp1,tp2,tp3,plane); + + return true; + +} + +#pragma warning(disable:4100) + +void fm_nearestPointInTriangle(const REAL * /*nearestPoint*/,const REAL * /*p1*/,const REAL * /*p2*/,const REAL * /*p3*/,REAL * /*nearest*/) +{ + +} + +static REAL Partial(const REAL *a,const REAL *p) +{ + return (a[0]*p[1]) - (p[0]*a[1]); +} + +REAL fm_areaTriangle(const REAL *p0,const REAL *p1,const REAL *p2) +{ + REAL A = Partial(p0,p1); + A+= Partial(p1,p2); + A+= Partial(p2,p0); + return A*0.5f; +} + +void fm_subtract(const REAL *A,const REAL *B,REAL *diff) // compute A-B and store the result in 'diff' +{ + diff[0] = A[0]-B[0]; + diff[1] = A[1]-B[1]; + diff[2] = A[2]-B[2]; +} + + +void fm_multiplyTransform(const REAL *pA,const REAL *pB,REAL *pM) +{ + + REAL a = pA[0*4+0] * pB[0*4+0] + pA[0*4+1] * pB[1*4+0] + pA[0*4+2] * pB[2*4+0] + pA[0*4+3] * pB[3*4+0]; + REAL b = pA[0*4+0] * pB[0*4+1] + pA[0*4+1] * pB[1*4+1] + pA[0*4+2] * pB[2*4+1] + pA[0*4+3] * pB[3*4+1]; + REAL c = pA[0*4+0] * pB[0*4+2] + pA[0*4+1] * pB[1*4+2] + pA[0*4+2] * pB[2*4+2] + pA[0*4+3] * pB[3*4+2]; + REAL d = pA[0*4+0] * pB[0*4+3] + pA[0*4+1] * pB[1*4+3] + pA[0*4+2] * pB[2*4+3] + pA[0*4+3] * pB[3*4+3]; + + REAL e = pA[1*4+0] * pB[0*4+0] + pA[1*4+1] * pB[1*4+0] + pA[1*4+2] * pB[2*4+0] + pA[1*4+3] * pB[3*4+0]; + REAL f = pA[1*4+0] * pB[0*4+1] + pA[1*4+1] * pB[1*4+1] + pA[1*4+2] * pB[2*4+1] + pA[1*4+3] * pB[3*4+1]; + REAL g = pA[1*4+0] * pB[0*4+2] + pA[1*4+1] * pB[1*4+2] + pA[1*4+2] * pB[2*4+2] + pA[1*4+3] * pB[3*4+2]; + REAL h = pA[1*4+0] * pB[0*4+3] + pA[1*4+1] * pB[1*4+3] + pA[1*4+2] * pB[2*4+3] + pA[1*4+3] * pB[3*4+3]; + + REAL i = pA[2*4+0] * pB[0*4+0] + pA[2*4+1] * pB[1*4+0] + pA[2*4+2] * pB[2*4+0] + pA[2*4+3] * pB[3*4+0]; + REAL j = pA[2*4+0] * pB[0*4+1] + pA[2*4+1] * pB[1*4+1] + pA[2*4+2] * pB[2*4+1] + pA[2*4+3] * pB[3*4+1]; + REAL k = pA[2*4+0] * pB[0*4+2] + pA[2*4+1] * pB[1*4+2] + pA[2*4+2] * pB[2*4+2] + pA[2*4+3] * pB[3*4+2]; + REAL l = pA[2*4+0] * pB[0*4+3] + pA[2*4+1] * pB[1*4+3] + pA[2*4+2] * pB[2*4+3] + pA[2*4+3] * pB[3*4+3]; + + REAL m = pA[3*4+0] * pB[0*4+0] + pA[3*4+1] * pB[1*4+0] + pA[3*4+2] * pB[2*4+0] + pA[3*4+3] * pB[3*4+0]; + REAL n = pA[3*4+0] * pB[0*4+1] + pA[3*4+1] * pB[1*4+1] + pA[3*4+2] * pB[2*4+1] + pA[3*4+3] * pB[3*4+1]; + REAL o = pA[3*4+0] * pB[0*4+2] + pA[3*4+1] * pB[1*4+2] + pA[3*4+2] * pB[2*4+2] + pA[3*4+3] * pB[3*4+2]; + REAL p = pA[3*4+0] * pB[0*4+3] + pA[3*4+1] * pB[1*4+3] + pA[3*4+2] * pB[2*4+3] + pA[3*4+3] * pB[3*4+3]; + + pM[0] = a; pM[1] = b; pM[2] = c; pM[3] = d; + + pM[4] = e; pM[5] = f; pM[6] = g; pM[7] = h; + + pM[8] = i; pM[9] = j; pM[10] = k; pM[11] = l; + + pM[12] = m; pM[13] = n; pM[14] = o; pM[15] = p; +} + +void fm_multiply(REAL *A,REAL scalar) +{ + A[0]*=scalar; + A[1]*=scalar; + A[2]*=scalar; +} + +void fm_add(const REAL *A,const REAL *B,REAL *sum) +{ + sum[0] = A[0]+B[0]; + sum[1] = A[1]+B[1]; + sum[2] = A[2]+B[2]; +} + +void fm_copy3(const REAL *source,REAL *dest) +{ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; +} + + +uint32_t fm_copyUniqueVertices(uint32_t vcount,const REAL *input_vertices,REAL *output_vertices,uint32_t tcount,const uint32_t *input_indices,uint32_t *output_indices) +{ + uint32_t ret = 0; + + REAL *vertices = (REAL *)malloc(sizeof(REAL)*vcount*3); + memcpy(vertices,input_vertices,sizeof(REAL)*vcount*3); + REAL *dest = output_vertices; + + uint32_t *reindex = (uint32_t *)malloc(sizeof(uint32_t)*vcount); + memset(reindex,0xFF,sizeof(uint32_t)*vcount); + + uint32_t icount = tcount*3; + + for (uint32_t i=0; i 0 ) + { + uint32_t i1 = indices[0]; + uint32_t i2 = indices[1]; + uint32_t i3 = indices[2]; + const REAL *p1 = &vertices[i1*3]; + const REAL *p2 = &vertices[i2*3]; + const REAL *p3 = &vertices[i3*3]; + REAL plane[4]; + plane[3] = fm_computePlane(p1,p2,p3,plane); + const uint32_t *scan = &indices[3]; + for (uint32_t i=1; i= dmin && dot <= dmax ) + { + ret = true; // then the plane equation is for practical purposes identical. + } + } +#endif + return ret; +} + + +void fm_initMinMax(REAL bmin[3],REAL bmax[3]) +{ + bmin[0] = FLT_MAX; + bmin[1] = FLT_MAX; + bmin[2] = FLT_MAX; + + bmax[0] = -FLT_MAX; + bmax[1] = -FLT_MAX; + bmax[2] = -FLT_MAX; +} + +void fm_inflateMinMax(REAL bmin[3], REAL bmax[3], REAL ratio) +{ + REAL inflate = fm_distance(bmin, bmax)*0.5f*ratio; + + bmin[0] -= inflate; + bmin[1] -= inflate; + bmin[2] -= inflate; + + bmax[0] += inflate; + bmax[1] += inflate; + bmax[2] += inflate; +} + +#ifndef TESSELATE_H + +#define TESSELATE_H + +typedef std::vector< uint32_t > UintVector; + +class Myfm_Tesselate : public fm_Tesselate +{ +public: + virtual ~Myfm_Tesselate(void) + { + + } + + const uint32_t * tesselate(fm_VertexIndex *vindex,uint32_t tcount,const uint32_t *indices,float longEdge,uint32_t maxDepth,uint32_t &outcount) + { + const uint32_t *ret = 0; + + mMaxDepth = maxDepth; + mLongEdge = longEdge*longEdge; + mLongEdgeD = mLongEdge; + mVertices = vindex; + + if ( mVertices->isDouble() ) + { + uint32_t vcount = mVertices->getVcount(); + double *vertices = (double *)malloc(sizeof(double)*vcount*3); + memcpy(vertices,mVertices->getVerticesDouble(),sizeof(double)*vcount*3); + + for (uint32_t i=0; igetVcount(); + float *vertices = (float *)malloc(sizeof(float)*vcount*3); + memcpy(vertices,mVertices->getVerticesFloat(),sizeof(float)*vcount*3); + + + for (uint32_t i=0; i mLongEdge || l2 > mLongEdge || l3 > mLongEdge ) + split = true; + + } + + if ( split ) + { + uint32_t edge; + + if ( l1 >= l2 && l1 >= l3 ) + edge = 0; + else if ( l2 >= l1 && l2 >= l3 ) + edge = 1; + else + edge = 2; + + float splits[3]; + + switch ( edge ) + { + case 0: + { + fm_lerp(p1,p2,splits,0.5f); + tesselate(p1,splits,p3, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + case 1: + { + fm_lerp(p2,p3,splits,0.5f); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(p1,splits,p3, recurse+1 ); + } + break; + case 2: + { + fm_lerp(p3,p1,splits,0.5f); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + } + } + else + { + bool newp; + + uint32_t i1 = mVertices->getIndex(p1,newp); + uint32_t i2 = mVertices->getIndex(p2,newp); + uint32_t i3 = mVertices->getIndex(p3,newp); + + mIndices.push_back(i1); + mIndices.push_back(i2); + mIndices.push_back(i3); + } + + } + + void tesselate(const double *p1,const double *p2,const double *p3,uint32_t recurse) + { + bool split = false; + double l1,l2,l3; + + l1 = l2 = l3 = 0; + + if ( recurse < mMaxDepth ) + { + l1 = fm_distanceSquared(p1,p2); + l2 = fm_distanceSquared(p2,p3); + l3 = fm_distanceSquared(p3,p1); + + if ( l1 > mLongEdgeD || l2 > mLongEdgeD || l3 > mLongEdgeD ) + split = true; + + } + + if ( split ) + { + uint32_t edge; + + if ( l1 >= l2 && l1 >= l3 ) + edge = 0; + else if ( l2 >= l1 && l2 >= l3 ) + edge = 1; + else + edge = 2; + + double splits[3]; + + switch ( edge ) + { + case 0: + { + fm_lerp(p1,p2,splits,0.5); + tesselate(p1,splits,p3, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + case 1: + { + fm_lerp(p2,p3,splits,0.5); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(p1,splits,p3, recurse+1 ); + } + break; + case 2: + { + fm_lerp(p3,p1,splits,0.5); + tesselate(p1,p2,splits, recurse+1 ); + tesselate(splits,p2,p3, recurse+1 ); + } + break; + } + } + else + { + bool newp; + + uint32_t i1 = mVertices->getIndex(p1,newp); + uint32_t i2 = mVertices->getIndex(p2,newp); + uint32_t i3 = mVertices->getIndex(p3,newp); + + mIndices.push_back(i1); + mIndices.push_back(i2); + mIndices.push_back(i3); + } + + } + +private: + float mLongEdge; + double mLongEdgeD; + fm_VertexIndex *mVertices; + UintVector mIndices; + uint32_t mMaxDepth; +}; + +fm_Tesselate * fm_createTesselate(void) +{ + Myfm_Tesselate *m = new Myfm_Tesselate; + return static_cast< fm_Tesselate * >(m); +} + +void fm_releaseTesselate(fm_Tesselate *t) +{ + Myfm_Tesselate *m = static_cast< Myfm_Tesselate *>(t); + delete m; +} + +#endif + + +#ifndef RAY_ABB_INTERSECT + +#define RAY_ABB_INTERSECT + +//! Integer representation of a floating-point value. +#define IR(x) ((uint32_t&)x) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** +* A method to compute a ray-AABB intersection. +* Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990 +* Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500) +* Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only) +* +* Hence this version is faster as well as more robust than the original one. +* +* Should work provided: +* 1) the integer representation of 0.0f is 0x00000000 +* 2) the sign bit of the float is the most significant one +* +* Report bugs: p.terdiman@codercorner.com +* +* \param aabb [in] the axis-aligned bounding box +* \param origin [in] ray origin +* \param dir [in] ray direction +* \param coord [out] impact coordinates +* \return true if ray intersects AABB +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#define RAYAABB_EPSILON 0.00001f +bool fm_intersectRayAABB(const float MinB[3],const float MaxB[3],const float origin[3],const float dir[3],float coord[3]) +{ + bool Inside = true; + float MaxT[3]; + MaxT[0]=MaxT[1]=MaxT[2]=-1.0f; + + // Find candidate planes. + for(uint32_t i=0;i<3;i++) + { + if(origin[i] < MinB[i]) + { + coord[i] = MinB[i]; + Inside = false; + + // Calculate T distances to candidate planes + if(IR(dir[i])) MaxT[i] = (MinB[i] - origin[i]) / dir[i]; + } + else if(origin[i] > MaxB[i]) + { + coord[i] = MaxB[i]; + Inside = false; + + // Calculate T distances to candidate planes + if(IR(dir[i])) MaxT[i] = (MaxB[i] - origin[i]) / dir[i]; + } + } + + // Ray origin inside bounding box + if(Inside) + { + coord[0] = origin[0]; + coord[1] = origin[1]; + coord[2] = origin[2]; + return true; + } + + // Get largest of the maxT's for final choice of intersection + uint32_t WhichPlane = 0; + if(MaxT[1] > MaxT[WhichPlane]) WhichPlane = 1; + if(MaxT[2] > MaxT[WhichPlane]) WhichPlane = 2; + + // Check final candidate actually inside box + if(IR(MaxT[WhichPlane])&0x80000000) return false; + + for(uint32_t i=0;i<3;i++) + { + if(i!=WhichPlane) + { + coord[i] = origin[i] + MaxT[WhichPlane] * dir[i]; +#ifdef RAYAABB_EPSILON + if(coord[i] < MinB[i] - RAYAABB_EPSILON || coord[i] > MaxB[i] + RAYAABB_EPSILON) return false; +#else + if(coord[i] < MinB[i] || coord[i] > MaxB[i]) return false; +#endif + } + } + return true; // ray hits box +} + +bool fm_intersectLineSegmentAABB(const float bmin[3],const float bmax[3],const float p1[3],const float p2[3],float intersect[3]) +{ + bool ret = false; + + float dir[3]; + dir[0] = p2[0] - p1[0]; + dir[1] = p2[1] - p1[1]; + dir[2] = p2[2] - p1[2]; + float dist = fm_normalize(dir); + if ( dist > RAYAABB_EPSILON ) + { + ret = fm_intersectRayAABB(bmin,bmax,p1,dir,intersect); + if ( ret ) + { + float d = fm_distanceSquared(p1,intersect); + if ( d > (dist*dist) ) + { + ret = false; + } + } + } + return ret; +} + +#endif + +#ifndef OBB_TO_AABB + +#define OBB_TO_AABB + +#pragma warning(disable:4100) + +void fm_OBBtoAABB(const float /*obmin*/[3],const float /*obmax*/[3],const float /*matrix*/[16],float /*abmin*/[3],float /*abmax*/[3]) +{ + assert(0); // not yet implemented. +} + + +const REAL * computePos(uint32_t index,const REAL *vertices,uint32_t vstride) +{ + const char *tmp = (const char *)vertices; + tmp+=(index*vstride); + return (const REAL*)tmp; +} + +void computeNormal(uint32_t index,REAL *normals,uint32_t nstride,const REAL *normal) +{ + char *tmp = (char *)normals; + tmp+=(index*nstride); + REAL *dest = (REAL *)tmp; + dest[0]+=normal[0]; + dest[1]+=normal[1]; + dest[2]+=normal[2]; +} + +void fm_computeMeanNormals(uint32_t vcount, // the number of vertices + const REAL *vertices, // the base address of the vertex position data. + uint32_t vstride, // the stride between position data. + REAL *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 +{ + + // Step #1 : Zero out the vertex normals + char *dest = (char *)normals; + for (uint32_t i=0; ixmax[0]) + Copy(xmax,caller_p); + if (caller_p[1]ymax[1]) + Copy(ymax,caller_p); + if (caller_p[2]zmax[2]) + Copy(zmax,caller_p); + scan+=pstride; + } + } + + /* Set xspan = distance between the 2 points xmin & xmax (squared) */ + REAL dx = xmax[0] - xmin[0]; + REAL dy = xmax[1] - xmin[1]; + REAL dz = xmax[2] - xmin[2]; + REAL xspan = dx*dx + dy*dy + dz*dz; + +/* Same for y & z spans */ + dx = ymax[0] - ymin[0]; + dy = ymax[1] - ymin[1]; + dz = ymax[2] - ymin[2]; + REAL yspan = dx*dx + dy*dy + dz*dz; + + dx = zmax[0] - zmin[0]; + dy = zmax[1] - zmin[1]; + dz = zmax[2] - zmin[2]; + REAL zspan = dx*dx + dy*dy + dz*dz; + + /* Set points dia1 & dia2 to the maximally separated pair */ + Copy(dia1,xmin); + Copy(dia2,xmax); /* assume xspan biggest */ + REAL maxspan = xspan; + + if (yspan>maxspan) + { + maxspan = yspan; + Copy(dia1,ymin); + Copy(dia2,ymax); + } + + if (zspan>maxspan) + { + maxspan = zspan; + Copy(dia1,zmin); + Copy(dia2,zmax); + } + + + /* dia1,dia2 is a diameter of initial sphere */ + /* calc initial center */ + center[0] = (dia1[0]+dia2[0])*0.5f; + center[1] = (dia1[1]+dia2[1])*0.5f; + center[2] = (dia1[2]+dia2[2])*0.5f; + + /* calculate initial radius**2 and radius */ + + dx = dia2[0]-center[0]; /* x component of radius vector */ + dy = dia2[1]-center[1]; /* y component of radius vector */ + dz = dia2[2]-center[2]; /* z component of radius vector */ + + radius2 = dx*dx + dy*dy + dz*dz; + radius = REAL(sqrt(radius2)); + + /* SECOND PASS: increment current sphere */ + { + const char *scan = (const char *)points; + for (uint32_t i=0; i radius2) /* do r**2 test first */ + { /* this point is outside of current sphere */ + REAL old_to_p = REAL(sqrt(old_to_p_sq)); + /* calc radius of new sphere */ + radius = (radius + old_to_p) * 0.5f; + radius2 = radius*radius; /* for next r**2 compare */ + REAL old_to_new = old_to_p - radius; + /* calc center of new sphere */ + REAL recip = 1.0f /old_to_p; + REAL cx = (radius*center[0] + old_to_new*caller_p[0]) * recip; + REAL cy = (radius*center[1] + old_to_new*caller_p[1]) * recip; + REAL cz = (radius*center[2] + old_to_new*caller_p[2]) * recip; + Set(center,cx,cy,cz); + scan+=pstride; + } + } + } + return radius; +} + + +void fm_computeBestFitCapsule(uint32_t vcount,const REAL *points,uint32_t pstride,REAL &radius,REAL &height,REAL matrix[16],bool bruteForce) +{ + REAL sides[3]; + REAL omatrix[16]; + fm_computeBestFitOBB(vcount,points,pstride,sides,omatrix,bruteForce); + + int32_t axis = 0; + if ( sides[0] > sides[1] && sides[0] > sides[2] ) + axis = 0; + else if ( sides[1] > sides[0] && sides[1] > sides[2] ) + axis = 1; + else + axis = 2; + + REAL localTransform[16]; + + REAL maxDist = 0; + REAL maxLen = 0; + + switch ( axis ) + { + case 0: + { + fm_eulerMatrix(0,0,FM_PI/2,localTransform); + fm_matrixMultiply(localTransform,omatrix,matrix); + + const uint8_t *scan = (const uint8_t *)points; + for (uint32_t i=0; i maxDist ) + { + maxDist = dist; + } + REAL l = (REAL) fabs(t[0]); + if ( l > maxLen ) + { + maxLen = l; + } + scan+=pstride; + } + } + height = sides[0]; + break; + case 1: + { + fm_eulerMatrix(0,FM_PI/2,0,localTransform); + fm_matrixMultiply(localTransform,omatrix,matrix); + + const uint8_t *scan = (const uint8_t *)points; + for (uint32_t i=0; i maxDist ) + { + maxDist = dist; + } + REAL l = (REAL) fabs(t[1]); + if ( l > maxLen ) + { + maxLen = l; + } + scan+=pstride; + } + } + height = sides[1]; + break; + case 2: + { + fm_eulerMatrix(FM_PI/2,0,0,localTransform); + fm_matrixMultiply(localTransform,omatrix,matrix); + + const uint8_t *scan = (const uint8_t *)points; + for (uint32_t i=0; i maxDist ) + { + maxDist = dist; + } + REAL l = (REAL) fabs(t[2]); + if ( l > maxLen ) + { + maxLen = l; + } + scan+=pstride; + } + } + height = sides[2]; + break; + } + radius = (REAL)sqrt(maxDist); + height = (maxLen*2)-(radius*2); +} + + +//************* Triangulation + +#ifndef TRIANGULATE_H + +#define TRIANGULATE_H + +typedef uint32_t TU32; + +class TVec +{ +public: + TVec(double _x,double _y,double _z) { x = _x; y = _y; z = _z; }; + TVec(void) { }; + + double x; + double y; + double z; +}; + +typedef std::vector< TVec > TVecVector; +typedef std::vector< TU32 > TU32Vector; + +class CTriangulator +{ +public: + /// Default constructor + CTriangulator(); + + /// Default destructor + virtual ~CTriangulator(); + + /// Triangulates the contour + void triangulate(TU32Vector &indices); + + /// Returns the given point in the triangulator array + inline TVec get(const TU32 id) { return mPoints[id]; } + + virtual void reset(void) + { + mInputPoints.clear(); + mPoints.clear(); + mIndices.clear(); + } + + virtual void addPoint(double x,double y,double z) + { + TVec v(x,y,z); + // update bounding box... + if ( mInputPoints.empty() ) + { + mMin = v; + mMax = v; + } + else + { + if ( x < mMin.x ) mMin.x = x; + if ( y < mMin.y ) mMin.y = y; + if ( z < mMin.z ) mMin.z = z; + + if ( x > mMax.x ) mMax.x = x; + if ( y > mMax.y ) mMax.y = y; + if ( z > mMax.z ) mMax.z = z; + } + mInputPoints.push_back(v); + } + + // Triangulation happens in 2d. We could inverse transform the polygon around the normal direction, or we just use the two most significant axes + // Here we find the two longest axes and use them to triangulate. Inverse transforming them would introduce more doubling point error and isn't worth it. + virtual uint32_t * triangulate(uint32_t &tcount,double epsilon) + { + uint32_t *ret = 0; + tcount = 0; + mEpsilon = epsilon; + + if ( !mInputPoints.empty() ) + { + mPoints.clear(); + + double dx = mMax.x - mMin.x; // locate the first, second and third longest edges and store them in i1, i2, i3 + double dy = mMax.y - mMin.y; + double dz = mMax.z - mMin.z; + + uint32_t i1,i2,i3; + + if ( dx > dy && dx > dz ) + { + i1 = 0; + if ( dy > dz ) + { + i2 = 1; + i3 = 2; + } + else + { + i2 = 2; + i3 = 1; + } + } + else if ( dy > dx && dy > dz ) + { + i1 = 1; + if ( dx > dz ) + { + i2 = 0; + i3 = 2; + } + else + { + i2 = 2; + i3 = 0; + } + } + else + { + i1 = 2; + if ( dx > dy ) + { + i2 = 0; + i3 = 1; + } + else + { + i2 = 1; + i3 = 0; + } + } + + uint32_t pcount = (uint32_t)mInputPoints.size(); + const double *points = &mInputPoints[0].x; + for (uint32_t i=0; i 2;) + { + if (0 >= (count--)) + return; + + int32_t u = v; + if (nv <= u) + u = 0; + v = u + 1; + if (nv <= v) + v = 0; + int32_t w = v + 1; + if (nv <= w) + w = 0; + + if (_snip(u, v, w, nv, V)) + { + int32_t a, b, c, s, t; + a = V[u]; + b = V[v]; + c = V[w]; + if ( flipped ) + { + indices.push_back(a); + indices.push_back(b); + indices.push_back(c); + } + else + { + indices.push_back(c); + indices.push_back(b); + indices.push_back(a); + } + m++; + for (s = v, t = v + 1; t < nv; s++, t++) + V[s] = V[t]; + nv--; + count = 2 * nv; + } + } + + free(V); +} + +/// Returns the area of the contour +double CTriangulator::_area() +{ + int32_t n = (uint32_t)mPoints.size(); + double A = 0.0f; + for (int32_t p = n - 1, q = 0; q < n; p = q++) + { + const TVec &pval = mPoints[p]; + const TVec &qval = mPoints[q]; + A += pval.x * qval.y - qval.x * pval.y; + } + A*=0.5f; + return A; +} + +bool CTriangulator::_snip(int32_t u, int32_t v, int32_t w, int32_t n, int32_t *V) +{ + int32_t p; + + const TVec &A = mPoints[ V[u] ]; + const TVec &B = mPoints[ V[v] ]; + const TVec &C = mPoints[ V[w] ]; + + if (mEpsilon > (((B.x - A.x) * (C.y - A.y)) - ((B.y - A.y) * (C.x - A.x))) ) + return false; + + for (p = 0; p < n; p++) + { + if ((p == u) || (p == v) || (p == w)) + continue; + const TVec &P = mPoints[ V[p] ]; + if (_insideTriangle(A, B, C, P)) + return false; + } + return true; +} + +/// Tests if a point is inside the given triangle +bool CTriangulator::_insideTriangle(const TVec& A, const TVec& B, const TVec& C,const TVec& P) +{ + double ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy; + double cCROSSap, bCROSScp, aCROSSbp; + + ax = C.x - B.x; ay = C.y - B.y; + bx = A.x - C.x; by = A.y - C.y; + cx = B.x - A.x; cy = B.y - A.y; + apx = P.x - A.x; apy = P.y - A.y; + bpx = P.x - B.x; bpy = P.y - B.y; + cpx = P.x - C.x; cpy = P.y - C.y; + + aCROSSbp = ax * bpy - ay * bpx; + cCROSSap = cx * apy - cy * apx; + bCROSScp = bx * cpy - by * cpx; + + return ((aCROSSbp >= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); +} + +class Triangulate : public fm_Triangulate +{ +public: + Triangulate(void) + { + mPointsFloat = 0; + mPointsDouble = 0; + } + + virtual ~Triangulate(void) + { + reset(); + } + void reset(void) + { + free(mPointsFloat); + free(mPointsDouble); + mPointsFloat = 0; + mPointsDouble = 0; + } + + virtual const double * triangulate3d(uint32_t pcount, + const double *_points, + uint32_t vstride, + uint32_t &tcount, + bool consolidate, + double epsilon) + { + reset(); + + double *points = (double *)malloc(sizeof(double)*pcount*3); + if ( consolidate ) + { + pcount = fm_consolidatePolygon(pcount,_points,vstride,points,1-epsilon); + } + else + { + double *dest = points; + for (uint32_t i=0; i= 3 ) + { + CTriangulator ct; + for (uint32_t i=0; i(t); +} + +void fm_releaseTriangulate(fm_Triangulate *t) +{ + Triangulate *tt = static_cast< Triangulate *>(t); + delete tt; +} + +#endif + +bool validDistance(const REAL *p1,const REAL *p2,REAL epsilon) +{ + bool ret = true; + + REAL dx = p1[0] - p2[0]; + REAL dy = p1[1] - p2[1]; + REAL dz = p1[2] - p2[2]; + REAL dist = dx*dx+dy*dy+dz*dz; + if ( dist < (epsilon*epsilon) ) + { + ret = false; + } + return ret; +} + +bool fm_isValidTriangle(const REAL *p1,const REAL *p2,const REAL *p3,REAL epsilon) +{ + bool ret = false; + + if ( validDistance(p1,p2,epsilon) && + validDistance(p1,p3,epsilon) && + validDistance(p2,p3,epsilon) ) + { + + REAL area = fm_computeArea(p1,p2,p3); + if ( area > epsilon ) + { + REAL _vertices[3*3],vertices[64*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]; + + uint32_t pcount = fm_consolidatePolygon(3,_vertices,sizeof(REAL)*3,vertices,1-epsilon); + if ( pcount == 3 ) + { + ret = true; + } + } + } + return ret; +} + + +void fm_multiplyQuat(const REAL *left,const REAL *right,REAL *quat) +{ + REAL a,b,c,d; + + a = left[3]*right[3] - left[0]*right[0] - left[1]*right[1] - left[2]*right[2]; + b = left[3]*right[0] + right[3]*left[0] + left[1]*right[2] - right[1]*left[2]; + c = left[3]*right[1] + right[3]*left[1] + left[2]*right[0] - right[2]*left[0]; + d = left[3]*right[2] + right[3]*left[2] + left[0]*right[1] - right[0]*left[1]; + + quat[3] = a; + quat[0] = b; + quat[1] = c; + quat[2] = d; +} + +bool fm_computeCentroid(uint32_t vcount, // number of input data points + const REAL *points, // starting address of points array. + REAL *center) + +{ + bool ret = false; + if ( vcount ) + { + center[0] = 0; + center[1] = 0; + center[2] = 0; + const REAL *p = points; + for (uint32_t i=0; i class Vec3 +{ +public: + Vec3(void) + { + + } + Vec3(Type _x,Type _y,Type _z) + { + x = _x; + y = _y; + z = _z; + } + Type x; + Type y; + Type z; +}; +#endif + +void fm_transformAABB(const REAL bmin[3],const REAL bmax[3],const REAL matrix[16],REAL tbmin[3],REAL tbmax[3]) +{ + Vec3 box[8]; + box[0] = Vec3< REAL >( bmin[0], bmin[1], bmin[2] ); + box[1] = Vec3< REAL >( bmax[0], bmin[1], bmin[2] ); + box[2] = Vec3< REAL >( bmax[0], bmax[1], bmin[2] ); + box[3] = Vec3< REAL >( bmin[0], bmax[1], bmin[2] ); + box[4] = Vec3< REAL >( bmin[0], bmin[1], bmax[2] ); + box[5] = Vec3< REAL >( bmax[0], bmin[1], bmax[2] ); + box[6] = Vec3< REAL >( bmax[0], bmax[1], bmax[2] ); + box[7] = Vec3< REAL >( bmin[0], bmax[1], bmax[2] ); + // transform all 8 corners of the box and then recompute a new AABB + for (unsigned int i=0; i<8; i++) + { + Vec3< REAL > &p = box[i]; + fm_transform(matrix,&p.x,&p.x); + if ( i == 0 ) + { + tbmin[0] = tbmax[0] = p.x; + tbmin[1] = tbmax[1] = p.y; + tbmin[2] = tbmax[2] = p.z; + } + else + { + if ( p.x < tbmin[0] ) tbmin[0] = p.x; + if ( p.y < tbmin[1] ) tbmin[1] = p.y; + if ( p.z < tbmin[2] ) tbmin[2] = p.z; + if ( p.x > tbmax[0] ) tbmax[0] = p.x; + if ( p.y > tbmax[1] ) tbmax[1] = p.y; + if ( p.z > tbmax[2] ) tbmax[2] = p.z; + } + } +} + +REAL fm_normalizeQuat(REAL n[4]) // normalize this quat +{ + REAL dx = n[0]*n[0]; + REAL dy = n[1]*n[1]; + REAL dz = n[2]*n[2]; + REAL dw = n[3]*n[3]; + + REAL dist = dx*dx+dy*dy+dz*dz+dw*dw; + + dist = (REAL)sqrt(dist); + + REAL recip = 1.0f / dist; + + n[0]*=recip; + n[1]*=recip; + n[2]*=recip; + n[3]*=recip; + + return dist; +} + + +}; // end of namespace diff --git a/Engine/source/ts/tsMeshFit.cpp b/Engine/source/ts/tsMeshFit.cpp index 98975ca60..ceef8a992 100644 --- a/Engine/source/ts/tsMeshFit.cpp +++ b/Engine/source/ts/tsMeshFit.cpp @@ -29,6 +29,7 @@ #define ENABLE_VHACD_IMPLEMENTATION 1 #define VHACD_DISABLE_THREADING 0 #include +#include //----------------------------------------------------------------------------- @@ -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() ) ); } diff --git a/Tools/CMake/torque_configs.cmake b/Tools/CMake/torque_configs.cmake index 113710b5e..7cfbd2f6b 100644 --- a/Tools/CMake/torque_configs.cmake +++ b/Tools/CMake/torque_configs.cmake @@ -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)