aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/destructible/fracture
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/destructible/fracture
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/module/destructible/fracture')
-rw-r--r--APEX_1.4/module/destructible/fracture/Actor.cpp292
-rw-r--r--APEX_1.4/module/destructible/fracture/Actor.h97
-rw-r--r--APEX_1.4/module/destructible/fracture/Compound.cpp51
-rw-r--r--APEX_1.4/module/destructible/fracture/Compound.h41
-rw-r--r--APEX_1.4/module/destructible/fracture/CompoundCreator.cpp23
-rw-r--r--APEX_1.4/module/destructible/fracture/CompoundCreator.h39
-rw-r--r--APEX_1.4/module/destructible/fracture/CompoundGeometry.cpp23
-rw-r--r--APEX_1.4/module/destructible/fracture/CompoundGeometry.h36
-rw-r--r--APEX_1.4/module/destructible/fracture/Convex.cpp24
-rw-r--r--APEX_1.4/module/destructible/fracture/Convex.h36
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/ActorBase.cpp270
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/ActorBase.h74
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/CompoundBase.cpp686
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/CompoundBase.h160
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.cpp805
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.h110
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.cpp95
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.h77
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/ConvexBase.cpp1371
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/ConvexBase.h223
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.cpp319
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.h110
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.cpp566
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.h139
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.cpp1021
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.h95
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.cpp270
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.h76
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.cpp500
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.h84
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.cpp440
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.h118
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/MeshBase.cpp225
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/MeshBase.h78
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.cpp1439
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.h190
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.cpp285
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.h71
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/SimSceneBase.cpp654
-rw-r--r--APEX_1.4/module/destructible/fracture/Core/SimSceneBase.h271
-rw-r--r--APEX_1.4/module/destructible/fracture/Delaunay2d.cpp24
-rw-r--r--APEX_1.4/module/destructible/fracture/Delaunay2d.h38
-rw-r--r--APEX_1.4/module/destructible/fracture/Delaunay3d.cpp23
-rw-r--r--APEX_1.4/module/destructible/fracture/Delaunay3d.h40
-rw-r--r--APEX_1.4/module/destructible/fracture/FracturePattern.cpp17
-rw-r--r--APEX_1.4/module/destructible/fracture/FracturePattern.h45
-rw-r--r--APEX_1.4/module/destructible/fracture/IceBoxPruning.cpp25
-rw-r--r--APEX_1.4/module/destructible/fracture/IceBoxPruning.h41
-rw-r--r--APEX_1.4/module/destructible/fracture/IceRevisitedRadix.cpp23
-rw-r--r--APEX_1.4/module/destructible/fracture/IceRevisitedRadix.h32
-rw-r--r--APEX_1.4/module/destructible/fracture/IslandDetector.cpp23
-rw-r--r--APEX_1.4/module/destructible/fracture/IslandDetector.h39
-rw-r--r--APEX_1.4/module/destructible/fracture/Mesh.cpp125
-rw-r--r--APEX_1.4/module/destructible/fracture/Mesh.h51
-rw-r--r--APEX_1.4/module/destructible/fracture/MeshClipper.cpp23
-rw-r--r--APEX_1.4/module/destructible/fracture/MeshClipper.h40
-rw-r--r--APEX_1.4/module/destructible/fracture/PolygonTriangulator.cpp23
-rw-r--r--APEX_1.4/module/destructible/fracture/PolygonTriangulator.h38
-rw-r--r--APEX_1.4/module/destructible/fracture/RTdef.h26
-rw-r--r--APEX_1.4/module/destructible/fracture/Renderable.cpp467
-rw-r--r--APEX_1.4/module/destructible/fracture/Renderable.h107
-rw-r--r--APEX_1.4/module/destructible/fracture/SimScene.cpp155
-rw-r--r--APEX_1.4/module/destructible/fracture/SimScene.h60
63 files changed, 12969 insertions, 0 deletions
diff --git a/APEX_1.4/module/destructible/fracture/Actor.cpp b/APEX_1.4/module/destructible/fracture/Actor.cpp
new file mode 100644
index 00000000..1eb12b66
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Actor.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include <DestructibleActorImpl.h>
+#include <RenderMeshAsset.h>
+#include <DestructibleStructure.h>
+
+#include "../fracture/Actor.h"
+
+#include "FracturePattern.h"
+#include "SimScene.h"
+#include "Compound.h"
+#include "Mesh.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+Actor::Actor(base::SimScene* scene, DestructibleActorImpl* actor):
+ base::Actor(scene),
+ mActor(actor),
+ mRenderResourcesDirty(false),
+ mMinRadius(0.f),
+ mRadiusMultiplier(1.f),
+ mImpulseScale(1.f),
+ mSheetFracture(true)
+{
+ if(actor == NULL)
+ {
+ const uint32_t numSectors = 10;
+ const float sectorRand = 0.3f;
+ const float firstSegmentSize = 0.06f;
+ const float segmentScale = 1.4f;
+ const float segmentRand = 0.3f;
+ const float size = 10.f;
+ const float radius = size;
+ const float thickness = size;
+ mDefaultFracturePattern = (FracturePattern*)mScene->createFracturePattern();
+ mDefaultFracturePattern->createGlass(radius,thickness,numSectors,sectorRand,firstSegmentSize,segmentScale,segmentRand);
+ }
+ else
+ {
+ // create fracture pattern
+ const nvidia::destructible::DestructibleActorParamNS::RuntimeFracture_Type& params = actor->getParams()->destructibleParameters.runtimeFracture;
+ const uint32_t numSectors = params.glass.numSectors;
+ const float sectorRand = params.glass.sectorRand;
+ const float firstSegmentSize = params.glass.firstSegmentSize;
+ const float segmentScale = params.glass.segmentScale;
+ const float segmentRand = params.glass.segmentRand;
+ const float size = actor->getBounds().getDimensions().maxElement();
+ const float radius = size;
+ const float thickness = size;
+ mDefaultFracturePattern = (FracturePattern*)mScene->createFracturePattern();
+ mDefaultFracturePattern->createGlass(radius,thickness,(int32_t)numSectors,sectorRand,firstSegmentSize,segmentScale,segmentRand);
+ // attachment
+ mAttachmentFlags.posX = (uint32_t)params.attachment.posX;
+ mAttachmentFlags.negX = (uint32_t)params.attachment.negX;
+ mAttachmentFlags.posY = (uint32_t)params.attachment.posY;
+ mAttachmentFlags.negY = (uint32_t)params.attachment.negY;
+ mAttachmentFlags.posZ = (uint32_t)params.attachment.posZ;
+ mAttachmentFlags.negZ = (uint32_t)params.attachment.negZ;
+ // other
+ mDepthLimit = params.depthLimit;
+ mDestroyIfAtDepthLimit = params.destroyIfAtDepthLimit;
+ mImpulseScale = params.impulseScale;
+ mMinConvexSize = params.minConvexSize;
+ mSheetFracture = params.sheetFracture;
+ }
+}
+
+Actor::~Actor()
+{
+ PX_DELETE(mDefaultFracturePattern);
+ mDefaultFracturePattern = NULL;
+}
+
+Compound* Actor::createCompound()
+{
+ base::Compound* c = mScene->createCompound((base::FracturePattern*)mDefaultFracturePattern);
+ addCompound(c);
+ return (Compound*)c;
+}
+
+Compound* Actor::createCompoundFromChunk(const destructible::DestructibleActorImpl& actor, uint32_t partIndex)
+{
+ Mesh RTmesh;
+ RTmesh.loadFromRenderMesh(*actor.getDestructibleAsset()->getRenderMeshAsset(),partIndex);
+
+ // Fix texture v's (different between right hand and left hand)
+ RTmesh.flipV();
+
+ PxTransform pose(actor.getChunkPose(partIndex));
+ pose.p = actor.getStructure()->getChunkWorldCentroid(actor.getChunk(partIndex));
+
+ Compound* c = createCompound();
+
+ c->createFromMesh(&RTmesh,pose,actor.getChunkLinearVelocity(partIndex),actor.getChunkAngularVelocity(partIndex),-1,actor.getScale());
+
+ const DestructibleActorParamNS::BehaviorGroup_Type& behaviorGroup = actor.getBehaviorGroup(partIndex);
+ mMinRadius = behaviorGroup.damageSpread.minimumRadius;
+ mRadiusMultiplier = behaviorGroup.damageSpread.radiusMultiplier;
+
+ // attachment
+ //const DestructibleActorParamNS::RuntimeFracture_Type& params = mActor->getParams()->destructibleParameters.runtimeFracture;
+ DestructibleParameters& params = mActor->getDestructibleParameters();
+ mAttachmentFlags.posX |= params.rtFractureParameters.attachment.posX;
+ mAttachmentFlags.negX |= params.rtFractureParameters.attachment.negX;
+ mAttachmentFlags.posY |= params.rtFractureParameters.attachment.posY;
+ mAttachmentFlags.negY |= params.rtFractureParameters.attachment.negY;
+ mAttachmentFlags.posZ |= params.rtFractureParameters.attachment.posZ;
+ mAttachmentFlags.negZ |= params.rtFractureParameters.attachment.negZ;
+
+ attachBasedOnFlags(c);
+
+ mRenderResourcesDirty = true;
+
+ return c;
+}
+
+bool Actor::patternFracture(const PxVec3& hitLocation, const PxVec3& dirIn, float scale, float vel, float radiusIn)
+{
+ int compoundNr = -1;
+ int convexNr = -1;
+ PxVec3 normal;
+ float dist;
+ bool ret = false;
+ PxVec3 dir = dirIn;
+
+ mScene->getScene()->lockWrite();
+
+ bool hit = false;
+ if (dir.magnitudeSquared() < 0.5f)
+ {
+ dir = PxVec3(1.f,0.f,0.f);
+ hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
+ if(!hit)
+ {
+ dir = PxVec3(0.f,1.f,0.f);
+ hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
+ if(!hit)
+ {
+ dir = PxVec3(0.f,0.f,1.f);
+ hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
+ }
+ }
+ }
+ else
+ {
+ hit = base::Actor::rayCast(hitLocation-dir,dir,dist,compoundNr,convexNr,normal);
+ }
+ if (hit)
+ {
+ float radius = mMinRadius + mRadiusMultiplier*radiusIn;
+ float impulseMagn = scale*vel*mImpulseScale;
+
+ if (mSheetFracture)
+ {
+ normal = ((Compound*)mCompounds[(uint32_t)compoundNr])->mNormal;
+ }
+ PxVec3 a(0.f,0.f,1.f);
+ normal.normalize();
+ a -= a.dot(normal)*normal;
+ if( a.magnitudeSquared() < 0.1f )
+ {
+ a = PxVec3(0.f,1.f,0.f);
+ a -= a.dot(normal)*normal;
+ }
+ a.normalize();
+ PxVec3 b(normal.cross(a));
+ PxMat33 trans(a,b,normal);
+ ret = base::Actor::patternFracture(hitLocation,dir,compoundNr,trans,radius,impulseMagn,impulseMagn);
+ }
+
+ mScene->getScene()->unlockWrite();
+
+ mRenderResourcesDirty = true;
+
+ return ret;
+}
+
+bool Actor::patternFracture(const DamageEvent& damageEvent)
+{
+ mDamageEvent.position = damageEvent.position;
+ mDamageEvent.direction = damageEvent.direction;
+ mDamageEvent.damage = damageEvent.damage;
+ mDamageEvent.radius = damageEvent.radius;
+ return patternFracture(damageEvent.position, damageEvent.direction, 1.f, damageEvent.damage, damageEvent.radius);
+}
+
+bool Actor::patternFracture(const FractureEvent& fractureEvent, bool fractureOnLoad)
+{
+ createCompoundFromChunk(*mActor,fractureEvent.chunkIndexInAsset);
+ if(fractureOnLoad)
+ {
+ patternFracture(mDamageEvent.position, mDamageEvent.direction, 1.f, mDamageEvent.damage, mDamageEvent.radius);
+ //patternFracture(fractureEvent.position,fractureEvent.hitDirection,1.f,fractureEvent.impulse.magnitude()/mActor->getChunkMass(fractureEvent.chunkIndexInAsset),1);
+ }
+ return true;
+}
+
+bool Actor::rayCast(const PxVec3& orig, const PxVec3& dir, float &dist) const
+{
+ int compoundNr = 0;
+ int convexNr = 0;
+ PxVec3 n;
+ bool ret = false;
+
+ mScene->getScene()->lockRead();
+ ret = base::Actor::rayCast(orig,dir,dist,compoundNr,convexNr,n);
+ mScene->getScene()->unlockRead();
+
+ return ret;
+}
+
+void Actor::attachBasedOnFlags(base::Compound* c)
+{
+ PxBounds3 b;
+ c->getLocalBounds(b);
+ // Determine sheet face
+ if (mSheetFracture)
+ {
+ PxVec3 dim = b.getDimensions();
+ if ( dim.x < dim.y && dim.x < dim.z )
+ {
+ ((Compound*)c)->mNormal = PxVec3(1.f,0.f,0.f);
+ }
+ else if ( dim.y < dim.x && dim.y < dim.z )
+ {
+ ((Compound*)c)->mNormal = PxVec3(0.f,1.f,0.f);
+ }
+ else
+ {
+ ((Compound*)c)->mNormal = PxVec3(0.f,0.f,1.f);
+ }
+ }
+ // Attach
+ const float w = 0.01f*b.getDimensions().maxElement();
+ nvidia::Array<PxBounds3> bounds;
+ bounds.reserve(6);
+ if (mAttachmentFlags.posX)
+ {
+ PxBounds3 a(b);
+ a.minimum.x = a.maximum.x-w;
+ bounds.pushBack(a);
+ }
+ if (mAttachmentFlags.negX)
+ {
+ PxBounds3 a(b);
+ a.maximum.x = a.minimum.x+w;
+ bounds.pushBack(a);
+ }
+ if (mAttachmentFlags.posY)
+ {
+ PxBounds3 a(b);
+ a.minimum.y = a.maximum.y-w;
+ bounds.pushBack(a);
+ }
+ if (mAttachmentFlags.negY)
+ {
+ PxBounds3 a(b);
+ a.maximum.y = a.minimum.y+w;
+ bounds.pushBack(a);
+ }
+ if (mAttachmentFlags.posZ)
+ {
+ PxBounds3 a(b);
+ a.minimum.z = a.maximum.z-w;
+ bounds.pushBack(a);
+ }
+ if (mAttachmentFlags.negZ)
+ {
+ PxBounds3 a(b);
+ a.maximum.z = a.minimum.z+w;
+ bounds.pushBack(a);
+ }
+ c->attachLocal(bounds);
+}
+
+}
+}
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Actor.h b/APEX_1.4/module/destructible/fracture/Actor.h
new file mode 100644
index 00000000..f23e4b88
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Actor.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef RT_ACTOR_H
+#define RT_ACTOR_H
+
+#include "ActorBase.h"
+
+namespace nvidia
+{
+namespace destructible
+{
+ class DestructibleActorImpl;
+ struct DamageEvent;
+ struct FractureEvent;
+}
+
+using namespace destructible;
+namespace fracture
+{
+
+class Compound;
+class FracturePattern;
+class Renderable;
+
+class Actor : public base::Actor
+{
+ friend class SimScene;
+ friend class Renderable;
+protected:
+ Actor(base::SimScene* scene, DestructibleActorImpl* actor);
+public:
+ virtual ~Actor();
+
+ Compound* createCompound();
+
+ Compound* createCompoundFromChunk(const destructible::DestructibleActorImpl& destructibleActor, uint32_t partIndex);
+
+ bool patternFracture(const PxVec3& hitLocation, const PxVec3& dir, float scale = 1.f, float vel = 0.f, float radius = 0.f);
+ bool patternFracture(const DamageEvent& damageEvent);
+ bool patternFracture(const FractureEvent& fractureEvent, bool fractureOnLoad = true);
+
+ bool rayCast(const PxVec3& orig, const PxVec3& dir, float &dist) const;
+
+ DestructibleActorImpl* getDestructibleActor() {return mActor;}
+
+protected:
+ void attachBasedOnFlags(base::Compound* c);
+
+ FracturePattern* mDefaultFracturePattern;
+ DestructibleActorImpl* mActor;
+ bool mRenderResourcesDirty;
+
+ float mMinRadius;
+ float mRadiusMultiplier;
+ float mImpulseScale;
+ bool mSheetFracture;
+
+ struct AttachmentFlags
+ {
+ AttachmentFlags() :
+ posX(0), negX(0), posY(0), negY(0), posZ(0), negZ(0) {}
+
+ uint32_t posX : 1;
+ uint32_t negX : 1;
+ uint32_t posY : 1;
+ uint32_t negY : 1;
+ uint32_t posZ : 1;
+ uint32_t negZ : 1;
+ }mAttachmentFlags;
+
+ struct MyDamageEvent
+ {
+ PxVec3 position;
+ PxVec3 direction;
+ float damage;
+ float radius;
+ };
+ MyDamageEvent mDamageEvent;
+
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Compound.cpp b/APEX_1.4/module/destructible/fracture/Compound.cpp
new file mode 100644
index 00000000..2d49f19d
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Compound.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "ApexActor.h"
+#include "DestructibleScene.h"
+#include "DestructibleActorImpl.h"
+#include "SimScene.h"
+#include "Actor.h"
+#include "PxShape.h"
+
+#include "Compound.h"
+
+namespace nvidia
+{
+
+namespace fracture
+{
+
+void Compound::applyShapeTemplate(PxShape* shape)
+{
+ if( shape && mActor)
+ {
+ DestructibleActorImpl* dactor = ((Actor*)mActor)->getDestructibleActor();
+ {
+ PhysX3DescTemplateImpl physX3Template;
+ dactor->getPhysX3Template(physX3Template);
+ physX3Template.apply(shape);
+ }
+ }
+}
+
+::nvidia::destructible::DestructibleActorImpl* Compound::getDestructibleActor() const
+{
+ ::nvidia::destructible::DestructibleActorImpl* dactor = NULL;
+ if(mActor)
+ dactor = ((Actor*)mActor)->getDestructibleActor();
+ return dactor;
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Compound.h b/APEX_1.4/module/destructible/fracture/Compound.h
new file mode 100644
index 00000000..8f07c393
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Compound.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUND_H
+#define COMPOUND_H
+
+#include "CompoundBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class Compound : public base::Compound
+{
+ friend class SimScene;
+ friend class Actor;
+protected:
+ Compound(SimScene* scene, const base::FracturePattern *pattern, const base::FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f):
+ nvidia::fracture::base::Compound((base::SimScene*)scene,pattern,secondaryPattern,contactOffset,restOffset) {}
+public:
+ virtual void applyShapeTemplate(PxShape* shape);
+ virtual ::nvidia::destructible::DestructibleActorImpl* getDestructibleActor() const;
+};
+
+}
+}
+
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/CompoundCreator.cpp b/APEX_1.4/module/destructible/fracture/CompoundCreator.cpp
new file mode 100644
index 00000000..14a29b7b
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/CompoundCreator.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "CompoundCreator.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/CompoundCreator.h b/APEX_1.4/module/destructible/fracture/CompoundCreator.h
new file mode 100644
index 00000000..40198fe6
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/CompoundCreator.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUND_CREATOR_H
+#define COMPOUND_CREATOR_H
+
+#include <PxVec3.h>
+#include <PxTransform.h>
+#include <PsArray.h>
+
+#include "CompoundCreatorBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class CompoundCreator : public base::CompoundCreator
+{
+ friend class SimScene;
+protected:
+ CompoundCreator(base::SimScene* scene): base::CompoundCreator((base::SimScene*)scene) {}
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/CompoundGeometry.cpp b/APEX_1.4/module/destructible/fracture/CompoundGeometry.cpp
new file mode 100644
index 00000000..9429174a
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/CompoundGeometry.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "CompoundGeometry.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/CompoundGeometry.h b/APEX_1.4/module/destructible/fracture/CompoundGeometry.h
new file mode 100644
index 00000000..689be78c
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/CompoundGeometry.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUND_GEOMETRY
+#define COMPOUND_GEOMETRY
+
+#include <PxVec3.h>
+#include <PxPlane.h>
+#include <PsArray.h>
+
+#include "CompoundGeometryBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class CompoundGeometry : public nvidia::fracture::base::CompoundGeometry
+{
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Convex.cpp b/APEX_1.4/module/destructible/fracture/Convex.cpp
new file mode 100644
index 00000000..4fc5de4c
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Convex.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "Convex.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Convex.h b/APEX_1.4/module/destructible/fracture/Convex.h
new file mode 100644
index 00000000..40717e67
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Convex.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef CONVEX
+#define CONVEX
+
+#include "ConvexBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class Convex : public base::Convex
+{
+ friend class SimScene;
+protected:
+ Convex(base::SimScene* scene): base::Convex(scene) {}
+public:
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/ActorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/ActorBase.cpp
new file mode 100644
index 00000000..2c88a262
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/ActorBase.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "ActorBase.h"
+
+#include <PxMat44.h>
+#include "PxRigidBodyExt.h"
+#include "PxScene.h"
+
+#include "SimSceneBase.h"
+#include "CompoundBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+Actor::Actor(SimScene* scene):
+ mScene(scene),
+ mMinConvexSize(scene->mMinConvexSize),
+ mDepthLimit(100),
+ mDestroyIfAtDepthLimit(false)
+{
+
+}
+
+Actor::~Actor()
+{
+ PxScene* pxScene = mScene->getScene();
+ if(pxScene != NULL)
+ {
+ pxScene->lockWrite();
+ }
+ clear();
+ if(pxScene != NULL)
+ {
+ pxScene->unlockWrite();
+ }
+ mScene->removeActor(this);
+}
+
+void Actor::clear()
+{
+ for (uint32_t i = 0; i < mCompounds.size(); i++) {
+ PX_DELETE(mCompounds[i]);
+ }
+ mCompounds.clear();
+}
+
+void Actor::addCompound(Compound *c)
+{
+ mCompounds.pushBack(c);
+ PxRigidDynamic *a = c->getPxActor();
+ if (a) {
+// a->setContactReportFlags(Px_NOTIFY_ON_TOUCH_FORCE_THRESHOLD | Px_NOTIFY_ON_START_TOUCH_FORCE_THRESHOLD);
+ a->setContactReportThreshold(mScene->mFractureForceThreshold);
+ }
+ c->mActor = this;
+ ++(mScene->mSceneVersion);
+}
+
+void Actor::removeCompound(Compound *c)
+{
+ uint32_t num = 0;
+ for (uint32_t i = 0; i < mCompounds.size(); i++) {
+ if (mCompounds[i] != c) {
+ mCompounds[num] = mCompounds[i];
+ num++;
+ }
+ }
+ if (mScene->mPickActor == c->getPxActor())
+ mScene->mPickActor = NULL;
+
+ c->clear();
+ //delCompoundList.push_back(c);
+ //delete c;
+ mScene->delCompoundList.pushBack(c);
+ mCompounds.resize(num);
+ ++mScene->mSceneVersion;
+}
+
+void Actor::preSim(float dt)
+{
+ uint32_t num = 0;
+ for (uint32_t i = 0; i < (uint32_t)mCompounds.size(); i++) {
+ mCompounds[i]->step(dt);
+ if (mCompounds[i]->getLifeFrames() == 0) {
+ mCompounds[i]->clear();
+ //delCompoundList.push_back(mCompounds[i]);
+ //delete mCompounds[i];
+ mScene->delCompoundList.pushBack(mCompounds[i]);
+ }
+ else {
+ mCompounds[num] = mCompounds[i];
+ num++;
+ }
+ }
+ mCompounds.resize(num);
+}
+
+void Actor::postSim(float /*dt*/)
+{
+}
+
+bool Actor::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &compoundNr, int &convexNr, PxVec3 &normal) const
+{
+ dist = PX_MAX_F32;
+ compoundNr = -1;
+ convexNr = -1;
+
+ for (uint32_t i = 0; i < mCompounds.size(); i++) {
+ float d;
+ int cNr;
+ PxVec3 n;
+ if (mCompounds[i]->rayCast(orig, dir, d, cNr, n)) {
+ if (d < dist) {
+ dist = d;
+ compoundNr = (int)i;
+ convexNr = cNr;
+ normal = n;
+ }
+ }
+ }
+ return compoundNr >= 0;
+}
+
+bool Actor::patternFracture(const PxVec3 &orig, const PxVec3 &dir, const PxMat33 patternTransform, float impactRadius, float radialImpulse, float directionalImpulse)
+{
+ float dist;
+ float objectSize = 0.0f;
+ int actorNr;
+ int compoundNr;
+ int convexNr;
+ PxVec3 normal;
+
+ // do global rayCast.
+ if (!mScene->rayCast(orig, dir, dist, actorNr, compoundNr, convexNr, normal))
+ return false;
+ if (mScene->mActors[(uint32_t)actorNr] != this)
+ return false;
+
+ mScene->debugPoints.clear();
+ nvidia::Array<Compound*> compounds;
+
+ mScene->profileBegin("patternFracture");
+ bool OK = mCompounds[(uint32_t)compoundNr]->patternFracture(orig + dir * dist, mMinConvexSize,
+ compounds, patternTransform, mScene->debugPoints, impactRadius, radialImpulse, normal * directionalImpulse);
+ mScene->profileEnd("patternFracture");
+ if (!OK)
+ return false;
+
+ if (compounds.empty())
+ return false;
+
+ if (mCompounds[(uint32_t)compoundNr]->getPxActor() == mScene->mPickActor)
+ mScene->mPickActor = NULL;
+
+ PxBounds3 bounds;
+ mCompounds[(uint32_t)compoundNr]->getWorldBounds(bounds);
+ objectSize = bounds.getDimensions().magnitude();
+
+ //delCompoundList.push_back( mCompounds[compoundNr]);
+ mScene->delCompoundList.pushBack( mCompounds[(uint32_t)compoundNr]);
+ mCompounds[(uint32_t)compoundNr]->clear();
+ //delete mCompounds[compoundNr];
+
+ mCompounds[(uint32_t)compoundNr] = compounds[0];
+
+ for (uint32_t i = 1; i < compounds.size(); i++)
+ mCompounds.pushBack(compounds[i]);
+
+ ++mScene->mSceneVersion;
+
+
+ // playShatterSound(objectSize);
+ //if (fluidSim)
+ //fluidSim->mistPS->seedDustParticles((PxVec3*)&debugPoints[0], debugPoints.size(), seedDustRadius, seedDustNumPerSite, dustMinLife, dustMaxLife, 0.0f, 1.0f);
+
+ uint32_t numConvexes = 0;
+ for (uint32_t i = 0; i < mCompounds.size(); i++)
+ numConvexes += mCompounds[i]->getConvexes().size();
+
+ //printf("\n------- pattern fracture------\n");
+ //printf("i compounds, %i convexes after fracture\n", mCompounds.size(), numConvexes);
+
+ return true;
+}
+
+bool Actor::patternFracture(const PxVec3 &hitLocation, const PxVec3 &normal, const int &compoundNr, const PxMat33 patternTransform, float impactRadius, float radialImpulse, float directionalImpulse)
+{
+ float objectSize = 0.0f;
+
+ mScene->debugPoints.clear();
+ nvidia::Array<Compound*> compounds;
+
+ mScene->profileBegin("patternFracture");
+ bool OK = mCompounds[(uint32_t)compoundNr]->patternFracture(hitLocation, mMinConvexSize,
+ compounds, patternTransform, mScene->debugPoints, impactRadius, radialImpulse, normal * directionalImpulse);
+ mScene->profileEnd("patternFracture");
+ if (!OK)
+ return false;
+
+ if (compounds.empty())
+ return false;
+
+ if (mCompounds[(uint32_t)compoundNr]->getPxActor() == mScene->mPickActor)
+ mScene->mPickActor = NULL;
+
+ PxBounds3 bounds;
+ mCompounds[(uint32_t)compoundNr]->getWorldBounds(bounds);
+ objectSize = bounds.getDimensions().magnitude();
+
+ //delCompoundList.push_back( mCompounds[compoundNr]);
+ mScene->delCompoundList.pushBack( mCompounds[(uint32_t)compoundNr]);
+ mCompounds[(uint32_t)compoundNr]->clear();
+ //delete mCompounds[compoundNr];
+
+ mCompounds[(uint32_t)compoundNr] = compounds[0];
+
+ for (uint32_t i = 1; i < compounds.size(); i++)
+ mCompounds.pushBack(compounds[i]);
+
+ ++mScene->mSceneVersion;
+
+
+ // playShatterSound(objectSize);
+ //if (fluidSim)
+ //fluidSim->mistPS->seedDustParticles((PxVec3*)&debugPoints[0], debugPoints.size(), seedDustRadius, seedDustNumPerSite, dustMinLife, dustMaxLife, 0.0f, 1.0f);
+
+ uint32_t numConvexes = 0;
+ for (uint32_t i = 0; i < mCompounds.size(); i++)
+ numConvexes += mCompounds[i]->getConvexes().size();
+
+ //printf("\n------- pattern fracture------\n");
+ //printf("i compounds, %i convexes after fracture\n", mCompounds.size(), numConvexes);
+
+ return true;
+}
+
+bool Actor::findCompound(const Compound* c, int& compoundNr)
+{
+ for(uint32_t i = 0; i < mCompounds.size(); i++)
+ {
+ if(mCompounds[i] == c)
+ {
+ compoundNr = (int32_t)i;
+ return true;
+ }
+ }
+ return false;
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/ActorBase.h b/APEX_1.4/module/destructible/fracture/Core/ActorBase.h
new file mode 100644
index 00000000..38fc4843
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/ActorBase.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef ACTOR_BASE_H
+#define ACTOR_BASE_H
+
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+class SimScene;
+class Compound;
+
+class Actor : public UserAllocated
+{
+ friend class SimScene;
+ friend class Compound;
+protected:
+ Actor(SimScene* scene);
+public:
+ virtual ~Actor();
+
+ void clear();
+ void addCompound(Compound *m);
+ void removeCompound(Compound *m);
+
+ bool findCompound(const Compound* c, int& compoundNr);
+
+ void preSim(float dt);
+ void postSim(float dt);
+
+ bool rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &compoundNr, int &convexNr, PxVec3 &normal) const;
+
+ // performs raycast
+ bool patternFracture(const PxVec3 &orig, const PxVec3 &dir,
+ const PxMat33 patternTransform, float impactRadius = 0.0f, float radialImpulse = 0.0f, float directionalImpulse = 0.0f);
+
+ // take in raycast results
+ bool patternFracture(const PxVec3 &hitLocation, const PxVec3 &normal, const int &compoundNr,
+ const PxMat33 patternTransform, float impactRadius = 0.0f, float radialImpulse = 0.0f, float directionalImpulse = 0.0f);
+
+ nvidia::Array<Compound*> getCompounds() { return mCompounds; }
+
+protected:
+ SimScene* mScene;
+ nvidia::Array<Compound*> mCompounds;
+
+ float mMinConvexSize;
+ uint32_t mDepthLimit;
+ bool mDestroyIfAtDepthLimit;
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundBase.cpp b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.cpp
new file mode 100644
index 00000000..8e273564
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.cpp
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "FracturePatternBase.h"
+#include "MeshBase.h"
+#include "CompoundGeometryBase.h"
+#include "CompoundCreatorBase.h"
+#include "PxConvexMeshGeometry.h"
+#include "PxRigidBodyExt.h"
+#include "PxMat44.h"
+#include "PxScene.h"
+#include "PxShape.h"
+
+#include "SimSceneBase.h"
+#include "CompoundBase.h"
+#include "ActorBase.h"
+#include "ConvexBase.h"
+#include "PsMathUtils.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace physx;
+
+//vector<PxVec3> tmpPoints;
+void Compound::appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, nvidia::Array<PxVec3>& samples, nvidia::Array<PxVec3>* normals) {
+ using namespace physx::shdfnd;
+ PxVec3& p0 = vertices[0];
+ PxVec3 normal;
+ if (numV < 3) {
+ normal = PxVec3(0.0f,1.0f,0.0f);
+ } else {
+ normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]);
+ normal.normalize();
+ }
+ for (int i = 1; i < numV-1; i++) {
+ PxVec3& p1 = vertices[i];
+ PxVec3& p2 = vertices[i+1];
+ float tarea = 0.5f*((p1-p0).cross(p2-p0)).magnitude();
+ float aa = tarea / area;
+ int np = (int)physx::shdfnd::floor(aa);
+
+ if (rand(0.0f,1.0f) <= aa-np) np++;
+
+ for (int j = 0; j < np; j++) {
+ float r1 = rand(0.0f,1.0f);
+ float sr1 = PxSqrt(r1);
+ float r2 = rand(0.0f, 1.0f);
+
+ PxVec3 p = (1 - sr1) * p0 + (sr1 * (1 - r2)) * p1 + (sr1 * r2) * p2;
+ samples.pushBack(p);
+ if (normals) normals->pushBack(normal);
+
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+Compound::Compound(SimScene *scene, const FracturePattern *pattern, const FracturePattern *secondaryPattern, float contactOffset, float restOffset)
+{
+ mScene = scene;
+ mActor = NULL;
+ mPxActor = NULL;
+ mFracturePattern = pattern;
+ mSecondardFracturePattern = secondaryPattern;
+ mContactOffset = contactOffset;
+ mRestOffset = restOffset;
+ mLifeFrames = -1; // live forever
+ mDepth = 0;
+ clear();
+}
+
+// --------------------------------------------------------------------------------------------
+Compound::~Compound()
+{
+ clear();
+}
+
+// --------------------------------------------------------------------------------------------
+#define SHAPE_BUFFER_SIZE 100
+
+void Compound::clear()
+{
+ if (mPxActor != NULL) {
+ // Unmap all shapes for this actor
+ const uint32_t shapeCount = mPxActor->getNbShapes();
+ physx::PxShape* shapeBuffer[SHAPE_BUFFER_SIZE];
+ for (uint32_t shapeStartIndex = 0; shapeStartIndex < shapeCount; shapeStartIndex += SHAPE_BUFFER_SIZE)
+ {
+ uint32_t shapesRead = mPxActor->getShapes(shapeBuffer, SHAPE_BUFFER_SIZE, shapeStartIndex);
+ for (uint32_t shapeBufferIndex = 0; shapeBufferIndex < shapesRead; ++shapeBufferIndex)
+ {
+ mScene->unmapShape(*shapeBuffer[shapeBufferIndex]);
+ }
+ }
+ // release the actor
+ mPxActor->release();
+ mPxActor = NULL;
+ }
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ if (mConvexes[i]->decreaseRefCounter() <= 0) {
+ convexRemoved(mConvexes[i]); //mScene->getConvexRenderer().remove(mConvexes[i]);
+ PX_DELETE(mConvexes[i]);
+ }
+ }
+
+ mConvexes.clear();
+ mEdges.clear();
+
+ //mShader = NULL;
+ //mShaderMat.init();
+
+ mKinematicVel = PxVec3(0.0f, 0.0f, 0.0f);
+ mAttachmentBounds.clear();
+
+ mAdditionalImpactNormalImpulse = 0.0f;
+ mAdditionalImpactRadialImpulse = 0.0f;
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::setKinematic(const PxVec3 &vel)
+{
+ if (mPxActor == NULL)
+ return;
+
+ mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+ mKinematicVel = vel;
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::step(float dt)
+{
+ //if (mPxActor == NULL)
+ // return;
+
+ if (!mKinematicVel.isZero()) {
+ PxTransform pose = mPxActor->getGlobalPose();
+ pose.p += mKinematicVel * dt;
+ mPxActor->setKinematicTarget(pose);
+ }
+
+ if (mLifeFrames > 0)
+ mLifeFrames--;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::createFromConvex(Convex* convex, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes)
+{
+ return createFromConvexes(&convex, 1, pose, vel, omega, copyConvexes);
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::createFromConvexes(Convex** convexes, int numConvexes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes)
+{
+ if (numConvexes == 0)
+ return false;
+
+ clear();
+ PxVec3 center(0.0f, 0.0f, 0.0f);
+ for (int i = 0; i < numConvexes; i++)
+ center += convexes[i]->getCenter();
+ center /= (float)numConvexes;
+
+ nvidia::Array<PxShape*> shapes;
+
+ for (int i = 0; i < numConvexes; i++) {
+ Convex *c;
+ if (copyConvexes) {
+ c = mScene->createConvex();
+ c->createFromConvex(convexes[i]);
+ }
+ else
+ c = convexes[i];
+
+ c->increaseRefCounter();
+ mConvexes.pushBack(c);
+
+ PxVec3 off = c->centerAtZero();
+ c->setMaterialOffset(c->getMaterialOffset() + off);
+ c->setLocalPose(PxTransform(off - center));
+
+ if (convexes[i]->isGhostConvex())
+ continue;
+
+ bool reused = c->getPxConvexMesh() != NULL;
+
+ mScene->profileBegin("cook convex meshes"); //Profiler::getInstance()->begin("cook convex meshes");
+ PxConvexMesh* mesh = c->createPxConvexMesh(this, mScene->getPxPhysics(), mScene->getPxCooking());
+ mScene->profileEnd("cook convex meshes"); //Profiler::getInstance()->end("cook convex meshes");
+
+ if (mesh == NULL) {
+ if (c->decreaseRefCounter() <= 0)
+ PX_DELETE(c);
+ mConvexes.popBack();
+ continue;
+ }
+
+ if (!c->hasExplicitVisMesh())
+ c->createVisMeshFromConvex();
+
+ if (!reused)
+ convexAdded(c); //mScene->getConvexRenderer().add(c);
+
+#if (PX_PHYSICS_VERSION_MAJOR == 3) && (PX_PHYSICS_VERSION_MINOR < 3)
+ PxShape *shape = mScene->getPxPhysics()->createShape(
+ PxConvexMeshGeometry(mesh),
+ *mScene->getPxDefaultMaterial(),
+ true,
+ c->getLocalPose());
+#else
+ PxShape *shape = mScene->getPxPhysics()->createShape(
+ PxConvexMeshGeometry(mesh),
+ *mScene->getPxDefaultMaterial(),
+ true
+ );
+ shape->setLocalPose(c->getLocalPose());
+#endif
+
+ shape->setContactOffset(mContactOffset);
+ shape->setRestOffset(mRestOffset);
+
+ mScene->mapShapeToConvex(*shape, *c);
+
+ shapes.pushBack(shape);
+ }
+
+ if (shapes.empty())
+ {
+ return false;
+ }
+
+ createPxActor(shapes, pose, vel, omega);
+ //if (!createPxActor(shapes, pose, vel, omega))
+ /*int foo = 0*/;
+
+ //createPointSamples(applyForcePointAreaPerSample);
+
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega)
+{
+ clear();
+
+ nvidia::Array<PxShape*> shapes;
+
+ for (int i = 0; i < (int)geom.convexes.size(); i++) {
+ Convex *c = mScene->createConvex();
+ c->createFromGeometry(geom, i);
+ c->increaseRefCounter();
+ mConvexes.pushBack(c);
+
+ PxVec3 off = c->centerAtZero();
+ c->setMaterialOffset(c->getMaterialOffset() + off);
+ c->createVisMeshFromConvex();
+ c->setLocalPose(PxTransform(off));
+
+ bool reused = c->getPxConvexMesh() != NULL;
+
+ PxConvexMesh* mesh = c->createPxConvexMesh(this, mScene->getPxPhysics(), mScene->getPxCooking());
+ if (mesh == NULL) {
+ if (c->decreaseRefCounter() <= 0)
+ PX_DELETE(c);
+ mConvexes.popBack();
+ continue;
+ }
+
+ if (!reused)
+ convexAdded(c); //mScene->getConvexRenderer().add(c);
+
+#if (PX_PHYSICS_VERSION_MAJOR == 3) && (PX_PHYSICS_VERSION_MINOR < 3)
+ PxShape *shape = mScene->getPxPhysics()->createShape(
+ PxConvexMeshGeometry(mesh),
+ *mScene->getPxDefaultMaterial(),
+ true,
+ c->getLocalPose());
+#else
+ PxShape *shape = mScene->getPxPhysics()->createShape(
+ PxConvexMeshGeometry(mesh),
+ *mScene->getPxDefaultMaterial(),
+ true
+ );
+ shape->setLocalPose(c->getLocalPose());
+#endif
+
+ shape->setContactOffset(mContactOffset);
+ shape->setRestOffset(mRestOffset);
+
+ mScene->mapShapeToConvex(*shape, *c);
+
+ shapes.pushBack(shape);
+ }
+
+ if (shapes.empty())
+ return false;
+
+ createPxActor(shapes, pose, vel, omega);
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::createFromMesh(const Mesh *mesh, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, int submeshNr, const PxVec3& scale)
+{
+ const nvidia::Array<PxVec3> &verts = mesh->getVertices();
+ const nvidia::Array<PxVec3> &normals = mesh->getNormals();
+ const nvidia::Array<PxVec2> &texcoords = mesh->getTexCoords();
+ const nvidia::Array<uint32_t> &indices = mesh->getIndices();
+
+ if (verts.empty() || indices.empty())
+ return;
+
+ if (submeshNr >= 0 && submeshNr >= (int)mesh->getSubMeshes().size())
+ return;
+
+ PxBounds3 bounds;
+ mesh->getBounds(bounds, submeshNr);
+ PxMat33 scaleMat(PxMat33::createDiagonal(scale));
+ bounds = PxBounds3::transformSafe(scaleMat, bounds);
+
+ PxVec3 dims = bounds.getDimensions() * 1.01f;
+ PxVec3 center = bounds.getCenter();
+
+ mScene->getCompoundCreator()->createBox(dims);
+ createFromGeometry(mScene->getCompoundCreator()->getGeometry(), pose, vel, omega);
+ PxTransform trans(-center);
+
+ if (submeshNr < 0)
+ mConvexes[0]->setExplicitVisMeshFromTriangles((int32_t)verts.size(), &verts[0], &normals[0], &texcoords[0], (int32_t)indices.size(), &indices[0], &trans, &scale);
+ else {
+ const Mesh::SubMesh &sm = mesh->getSubMeshes()[(uint32_t)submeshNr];
+ mConvexes[0]->setExplicitVisMeshFromTriangles((int32_t)verts.size(), &verts[0], &normals[0], &texcoords[0], sm.numIndices, &indices[(uint32_t)sm.firstIndex], &trans, &scale);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::createPxActor(nvidia::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega)
+{
+ if (shapes.empty())
+ return false;
+
+ for(uint32_t i = 0; i < shapes.size(); i++)
+ {
+ applyShapeTemplate(shapes[i]);
+ }
+
+ PxRigidDynamic* body = mScene->getPxPhysics()->createRigidDynamic(pose);
+ if (body == NULL)
+ return false;
+
+ body->setSleepThreshold(getSleepingThresholdRB());
+
+ physx::PxActorFlags actorFlags = body->getActorFlags();
+ actorFlags |= physx::PxActorFlag::eSEND_SLEEP_NOTIFIES;
+ body->setActorFlags(actorFlags);
+
+ mScene->getScene()->addActor(*body);
+
+ for (uint32_t i = 0; i < shapes.size(); i++)
+ body->attachShape(*shapes[i]);
+
+ //KS - we clamp the mass in the range [minMass, maxMass]. This helps to improve stability
+ PxRigidBodyExt::updateMassAndInertia(*body, 1000.0f);
+/*
+ const float maxMass = 50.f;
+ const float minMass = 1.f;
+
+ float mass = PxMax(PxMin(maxMass, body->getMass()), minMass);
+ PxRigidBodyExt::setMassAndUpdateInertia(*body, mass);
+*/
+
+
+ body->setLinearVelocity(vel);
+ body->setAngularVelocity(omega);
+
+ mPxActor = body;
+ for (uint32_t i = 0; i < mConvexes.size(); i++)
+ mConvexes[i]->setPxActor(mPxActor);
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &convexNr, PxVec3 &normal)
+{
+ dist = PX_MAX_F32;
+ convexNr = -1;
+
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ float d;
+ PxVec3 n;
+ if (mConvexes[i]->rayCast(orig, dir, d, n)) {
+ if (d < dist) {
+ dist = d;
+ convexNr = (int32_t)i;
+ normal = n;
+ }
+ }
+ }
+ return convexNr >= 0;
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::getRestBounds(PxBounds3 &bounds) const
+{
+ bounds.setEmpty();
+ PxBounds3 bi;
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ Convex *c = mConvexes[i];
+ PxBounds3 bi = c->getBounds();
+ bi = PxBounds3::transformSafe(c->getLocalPose(), bi);
+ bounds.include(bi);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::getWorldBounds(PxBounds3 &bounds) const
+{
+ bounds.setEmpty();
+ PxBounds3 bi;
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ mConvexes[i]->getWorldBounds(bi);
+ bounds.include(bi);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::getLocalBounds(PxBounds3 &bounds) const
+{
+ bounds.setEmpty();
+ PxBounds3 bi;
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ mConvexes[i]->getLocalBounds(bi);
+ bounds.include(bi);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::isAttached()
+{
+ if (mAttachmentBounds.empty())
+ return false;
+
+ PxBounds3 b;
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ Convex *c = mConvexes[i];
+ b = c->getBounds();
+ b.minimum += c->getMaterialOffset();
+ b.maximum += c->getMaterialOffset();
+ for (uint32_t j = 0; j < mAttachmentBounds.size(); j++) {
+ if (b.intersects(mAttachmentBounds[j]))
+ return true;
+ }
+ }
+ return false;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::patternFracture(const PxVec3 &pos, float minConvexSize, nvidia::Array<Compound*> &compounds,
+ const PxMat33 &patternTransform, nvidia::Array<PxVec3>& debugPoints, float impactRadius,
+ float radialImpulse, const PxVec3 &directedImpulse)
+{
+ if (mFracturePattern == NULL)
+ return false;
+
+ if (mDepth >= mActor->mDepthLimit)
+ {
+ if (mActor->mDestroyIfAtDepthLimit)
+ {
+ mActor->removeCompound(this);
+ }
+ else
+ {
+ PxTransform pose = mPxActor->getGlobalPose();
+ // additional impulse
+ PxVec3 imp(0.0f, 0.0f, 0.0f);
+ PxVec3 n = pose.p - pos;
+ n.normalize();
+ imp += n * radialImpulse;
+ imp += directedImpulse;
+ // prevent small pieces from getting too fast
+ const float minMass = 1.0f;
+ float mass = getPxActor()->getMass();
+ if (mass < minMass)
+ imp *= mass / minMass;
+ PxRigidBodyExt::addForceAtPos(*getPxActor(), imp, pos, PxForceMode::eIMPULSE);
+ }
+ return false;
+ }
+
+ compounds.clear();
+
+ //Profiler *p = Profiler::getInstance();
+
+ PxVec3 hit = pos;
+ PxTransform pose = mPxActor->getGlobalPose();
+ PxVec3 localHit = pose.transformInv(hit);
+ PxVec3 lv = mPxActor->getLinearVelocity();
+ PxVec3 av = mPxActor->getAngularVelocity();
+
+// localHit = -pose.t; // foo
+
+ nvidia::Array<Convex*> newConvexes;
+ nvidia::Array<int> compoundSizes;
+ nvidia::Array<PxVec3>& crackNormals = mScene->getCrackNormals();
+ crackNormals.clear();
+
+ mScene->profileBegin("getCompoundIntersection"); //Profiler::getInstance()->begin("getCompoundIntersection");
+ mFracturePattern->getCompoundIntersection(this, PxMat44(patternTransform, localHit), impactRadius, minConvexSize, compoundSizes, newConvexes);
+ mScene->profileEnd("getCompoundIntersection"); //Profiler::getInstance()->end("getCompoundIntersection");
+
+ if (compoundSizes.empty())
+ {
+ return false;
+ }
+
+ int debugPointsStart = (int32_t)debugPoints.size();
+
+ uint32_t convexNr = 0;
+ for (uint32_t i = 0; i < compoundSizes.size(); i++) {
+ uint32_t num = (uint32_t)compoundSizes[i];
+
+ PxVec3 off(0.0f, 0.0f, 0.0f);
+ for (uint32_t j = 0; j < num; j++) {
+ off += newConvexes[convexNr+j]->getCenter();
+
+ //PxVec3 pp = pose.p + pose.rotate(newConvexes[convexNr+j]->getCenter());
+ //debugPoints.push_back(pp);
+ }
+ off /= (float)num;
+
+ addDust(newConvexes,debugPoints,(int32_t&)convexNr,(int32_t&)num);
+
+ mScene->profileBegin("create new compounds"); //Profiler::getInstance()->begin("create new compounds");
+
+ Compound *m = mScene->createCompound(mSecondardFracturePattern ? mSecondardFracturePattern : mFracturePattern);
+
+ m->mActor = mActor;
+ m->mDepth = mDepth+1;
+ m->mNormal = mNormal;
+
+ PxVec3 v = lv + av.cross(pose.rotate(off));
+ PxTransform posei = pose;
+ posei.p += pose.rotate(off);
+
+ if (m->createFromConvexes(&newConvexes[convexNr], (int32_t)num, posei, v, av, false)) {
+ m->mAttachmentBounds = mAttachmentBounds;
+ if (m->isAttached())
+ {
+ m->getPxActor()->setActorFlag(physx::PxActorFlag::eSEND_SLEEP_NOTIFIES, false);
+ m->getPxActor()->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+ }
+ compounds.pushBack(m);
+ }
+ else
+ {
+ PX_DELETE(m);
+ return false;
+ }
+
+ // decrement depth if outside fracture radius
+ if (impactRadius > 0.f)
+ {
+ const nvidia::Array<Convex*>& convexes = m->getConvexes();
+ for (uint32_t i = 0; i < convexes.size(); i++)
+ {
+ if (convexes[i]->getIsFarConvex())
+ {
+ m->mDepth--;
+ break;
+ }
+ }
+ }
+
+ // additional impulse
+ PxVec3 imp(0.0f, 0.0f, 0.0f);
+ PxVec3 n = posei.p - hit;
+ n.normalize();
+ imp += n * radialImpulse;
+ imp += directedImpulse;
+
+ // prevent small pieces from getting too fast
+ const float minMass = 1.0f;
+ float mass = m->getPxActor()->getMass();
+ if (mass < minMass)
+ imp *= mass / minMass;
+
+ if (!m->isAttached())
+ PxRigidBodyExt::addForceAtPos(*m->getPxActor(), imp, hit, PxForceMode::eIMPULSE);
+// m->getPxActor()->addForce(imp / mass, PxForceMode::PxForceMode::eIMPULSE);
+
+ copyShaders(m);
+
+ mScene->profileEnd("create new compounds"); //Profiler::getInstance()->end("create new compounds");
+
+ convexNr += num;
+ }
+
+ spawnParticles(crackNormals,debugPoints,debugPointsStart,radialImpulse);
+
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::attach(const nvidia::Array<PxBounds3> &bounds)
+{
+ mAttachmentBounds.resize(bounds.size());
+
+ PxTransform t = getPxActor()->getGlobalPose().getInverse();
+ for (uint32_t i = 0; i < bounds.size(); i++) {
+ PxVec3 a = t.transform(bounds[i].minimum);
+ PxVec3 b = t.transform(bounds[i].maximum);
+ mAttachmentBounds[i].minimum = PxVec3(PxMin(a.x,b.x),PxMin(a.y,b.y),PxMin(a.z,b.z));
+ mAttachmentBounds[i].maximum = PxVec3(PxMax(a.x,b.x),PxMax(a.y,b.y),PxMax(a.z,b.z));
+ }
+
+ if (isAttached())
+ mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::attachLocal(const nvidia::Array<PxBounds3> &bounds)
+{
+ mAttachmentBounds.resize(bounds.size());
+
+ for (uint32_t i = 0; i < bounds.size(); i++) {
+ mAttachmentBounds[i] = bounds[i];
+ }
+
+ if (isAttached())
+ mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+}
+
+void Compound::createPointSamples(float area) {
+
+ pointSamples.clear();
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ Convex* c = mConvexes[i];
+ const nvidia::Array<Convex::Face> &faces = c->getFaces();
+ const nvidia::Array<int> &indices = c->getIndices();
+ const nvidia::Array<PxVec3> &verts = c->getVertices();
+
+
+
+ for (uint32_t k = 0; k < faces.size(); k++) {
+ const Convex::Face& f = faces[k];
+ /*int nv = f.numIndices;*/
+
+ /*
+ PxVec3 avg(0.0f);
+ for (int q = 0; q < f.numIndices; q++) {
+ avg += verts[indices[f.firstIndex+q]];
+ }
+ avg /= f.numIndices;
+ pointSamples.pushBack(avg);
+ */
+ nvidia::Array<PxVec3>& tmpPoints = mScene->getTmpPoints();
+ tmpPoints.clear();
+ for (int q = 0; q < f.numIndices; q++) {
+ tmpPoints.pushBack(verts[(uint32_t)indices[uint32_t(f.firstIndex+q)]]);
+ }
+ appendUniformSamplesOfConvexPolygon(&tmpPoints[0], (int32_t)tmpPoints.size(), area, pointSamples);
+
+ }
+
+ }
+}
+
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundBase.h b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.h
new file mode 100644
index 00000000..d21f2edc
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/CompoundBase.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUNDBASE
+#define COMPOUNDBASE
+
+#define DEMO_MODE 1
+#define TECHNICAL_MODE 0
+
+#include <PxVec3.h>
+#include <PxPlane.h>
+#include <PxBounds3.h>
+#include <PxTransform.h>
+#include <PsArray.h>
+#include <PxRigidDynamic.h>
+#include <PsUserAllocated.h>
+
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+class Convex;
+class FracturePattern;
+class Mesh;
+class SimScene;
+class CompoundGeometry;
+class Actor;
+
+// -----------------------------------------------------------------------------------
+class Compound : public UserAllocated
+{
+ friend class SimScene;
+ friend class Actor;
+protected:
+ Compound(SimScene* scene, const FracturePattern *pattern, const FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f);
+public:
+ virtual ~Compound();
+
+ virtual bool createFromConvexes(Convex** convexes, int numConvexes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes = true);
+ bool createFromConvex(Convex* convex, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes = true);
+ bool createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega);
+ void createFromMesh(const Mesh *mesh, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, int submeshNr = -1, const PxVec3& scale = PxVec3(1.f));
+ //bool createFromXml(XMLParser *p, float scale, const PxTransform &trans, bool ignoreVisualMesh = false);
+
+ virtual void applyShapeTemplate(PxShape* /*shape*/) {}
+
+ bool rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &convexNr, PxVec3 &normal);
+ void setLifeFrames(int frames) { mLifeFrames = frames == 0 ? 1 : frames; }
+ int getLifeFrames() { return mLifeFrames; }
+
+ bool patternFracture(const PxVec3 &pos, float minConvexSize, nvidia::Array<Compound*> &compounds,
+ const PxMat33 &patternTransform, nvidia::Array<PxVec3>& debugPoints, float impactRadius, float radialImpulse, const PxVec3 &directedImpulse);
+ // impactRadius controls partial fracture. For impactRadius == 0.0f the fracture is global
+
+ // event notification
+ virtual void spawnParticles(nvidia::Array<PxVec3>& /*crackNormals*/,nvidia::Array<PxVec3>& /*debugPoints*/,int /*debugPointsStart*/, float /*radialImpulse*/) {}
+ virtual void convexAdded(Convex* /*c*/) {}
+ virtual void convexRemoved(Convex* /*c*/) {}
+
+ bool decompose(FracturePattern *pattern, nvidia::Array<Compound*> &compounds);
+ void attach(const nvidia::Array<PxBounds3> &bounds);
+ void attachLocal(const nvidia::Array<PxBounds3> &bounds);
+
+ const nvidia::Array<Convex*>& getConvexes() const { return mConvexes; }
+ const nvidia::Array<PxBounds3>& getAttachmentBounds() const { return mAttachmentBounds; }
+
+ PxRigidDynamic* getPxActor() { return mPxActor; }
+ void getWorldBounds(PxBounds3 &bounds) const;
+ void getLocalBounds(PxBounds3 &bounds) const;
+ void getRestBounds(PxBounds3 &bounds) const;
+
+ //void setShader(Shader* shader, const ShaderMaterial &mat) { mShader = shader; mShaderMat = mat; }
+ //Shader* getShader() const { return mShader; }
+ //const ShaderMaterial& getShaderMat() { return mShaderMat; }
+
+ void setKinematic(const PxVec3 &vel);
+ void step(float dt);
+
+ virtual void draw(bool /*useShader*/, bool /*debug*/ = false) {}
+
+ virtual void clear();
+
+ void setAdditionalImpactImpulse(float radial, float normal) {
+ mAdditionalImpactRadialImpulse = radial; mAdditionalImpactNormalImpulse = normal;
+ }
+ float getAdditionalImpactRadialImpulse() const { return mAdditionalImpactRadialImpulse; }
+ float getAdditionalImpactNormalImpulse() const { return mAdditionalImpactNormalImpulse; }
+
+ virtual void copyShaders(Compound*) {}
+
+protected:
+ void createPointSamples(float area);
+
+ bool isAttached();
+
+ bool createPxActor(nvidia::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega);
+
+ virtual void addDust(nvidia::Array<Convex*>& /*newConvexes*/,nvidia::Array<PxVec3>& /*debugPoints*/,int& /*convexNr*/,int& /*num*/) {}
+
+ static void appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, nvidia::Array<PxVec3>& samples, nvidia::Array<PxVec3>* normals = NULL);
+
+ virtual float getSleepingThresholdRB() {return 0.1f;}
+
+ struct Edge {
+ void init(int c0, int c1) {
+ this->c0 = c0; this->c1 = c1;
+ restLen = 0.0f;
+ deleted = false;
+ }
+ int c0, c1;
+ float restLen;
+ bool deleted;
+ };
+
+ nvidia::Array<Convex*> mConvexes;
+ nvidia::Array<Edge> mEdges;
+
+ SimScene *mScene;
+ Actor *mActor;
+ PxRigidDynamic *mPxActor;
+ const FracturePattern *mFracturePattern;
+ const FracturePattern *mSecondardFracturePattern;
+ PxVec3 mKinematicVel;
+ nvidia::Array<PxBounds3> mAttachmentBounds;
+
+ //Shader *mShader;
+ //ShaderMaterial mShaderMat;
+
+ float mContactOffset;
+ float mRestOffset;
+
+ int mLifeFrames;
+
+ float mAdditionalImpactNormalImpulse;
+ float mAdditionalImpactRadialImpulse;
+
+ nvidia::Array<PxVec3> pointSamples;
+
+ uint32_t mDepth; // fracture depth
+ PxVec3 mNormal; // normal use with mSheetFracture
+};
+
+}}}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.cpp
new file mode 100644
index 00000000..d68df78f
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.cpp
@@ -0,0 +1,805 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "CompoundCreatorBase.h"
+#include <algorithm>
+#include <PxAssert.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+int CompoundCreator::tetFaceIds[4][3] = {{0,1,3},{1,2,3},{2,0,3},{0,2,1}};
+int CompoundCreator::tetEdgeVerts[6][2] = {{0,1},{1,2},{2,0},{0,3},{1,3},{2,3}};
+int CompoundCreator::tetFaceEdges[4][3] = {{0,4,3},{1,5,4},{2,3,5},{0,2,1}};
+
+#define CONVEX_THRESHOLD (PxPi + 0.05f)
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::createTorus(float r0, float r1, int numSegs0, int numSegs1, const PxTransform *trans)
+{
+ mGeom.clear();
+ CompoundGeometry::Convex c;
+ PxVec3 nr0,nr1,nz;
+ nz = PxVec3(0.0f, 0.0f, 1.0f);
+ PxVec3 p,n;
+ PxTransform t = PxTransform(PxIdentity);
+ if (trans)
+ t = *trans;
+
+ nvidia::Array<PxVec3> normals;
+
+ float dphi0 = PxTwoPi / (float)numSegs0;
+ float dphi1 = PxTwoPi / (float)numSegs1;
+ for (int i = 0; i < numSegs0; i++) {
+ nr0 = PxVec3(PxCos(i*dphi0), PxSin(i*dphi0), 0.0f);
+ nr1 = PxVec3(PxCos((i+1)*dphi0), PxSin((i+1)*dphi0), 0.0f);
+ mGeom.initConvex(c);
+ c.numVerts = 2*numSegs1;
+ normals.clear();
+ for (int j = 0; j < numSegs1; j++) {
+ p = nr0 * (r0 + r1 * PxCos(j*dphi1)) + nz * r1 * PxSin(j*dphi1);
+ mGeom.vertices.pushBack(t.transform(p));
+ n = nr0 * (PxCos(j*dphi1)) + nz * PxSin(j*dphi1);
+ normals.pushBack(t.rotate(n));
+
+ p = nr1 * (r0 + r1 * PxCos(j*dphi1)) + nz * r1 * PxSin(j*dphi1);
+ mGeom.vertices.pushBack(t.transform(p));
+ n = nr1 * (PxCos(j*dphi1)) + nz * PxSin(j*dphi1);
+ normals.pushBack(t.rotate(n));
+ }
+
+ c.numFaces = 2 + numSegs1;
+ mGeom.indices.pushBack(numSegs1); // face size
+ mGeom.indices.pushBack(CompoundGeometry::FF_INVISIBLE); // face flags
+ for (int j = 0; j < numSegs1; j++)
+ mGeom.indices.pushBack(2*j);
+ mGeom.indices.pushBack(numSegs1); // face size
+ mGeom.indices.pushBack(CompoundGeometry::FF_INVISIBLE); // face flags
+ for (int j = 0; j < numSegs1; j++) {
+ mGeom.indices.pushBack(2*(numSegs1-1-j) + 1);
+ }
+ for (int j = 0; j < numSegs1; j++) {
+ int k = (j+1)%numSegs1;
+ mGeom.indices.pushBack(4); // face size
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE | CompoundGeometry::FF_HAS_NORMALS);
+ int i0 = 2*j;
+ int i1 = 2*j+1;
+ int i2 = 2*k+1;
+ int i3 = 2*k;
+ mGeom.indices.pushBack(i0);
+ mGeom.indices.pushBack(i1);
+ mGeom.indices.pushBack(i2);
+ mGeom.indices.pushBack(i3);
+ mGeom.normals.pushBack(normals[(uint32_t)i0]);
+ mGeom.normals.pushBack(normals[(uint32_t)i1]);
+ mGeom.normals.pushBack(normals[(uint32_t)i2]);
+ mGeom.normals.pushBack(normals[(uint32_t)i3]);
+ }
+ c.numNeighbors = 2;
+ mGeom.neighbors.pushBack((i + (numSegs0-1)) % numSegs0);
+ mGeom.neighbors.pushBack((i + 1) % numSegs0);
+ mGeom.convexes.pushBack(c);
+ }
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::createCylinder(float r, float h, int numSegs, const PxTransform *trans)
+{
+ PxTransform t = PxTransform(PxIdentity);
+ if (trans)
+ t = *trans;
+
+ mGeom.clear();
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+
+ float dphi = PxTwoPi / (float)numSegs;
+ c.numVerts = 2*numSegs;
+ mGeom.vertices.resize((uint32_t)c.numVerts);
+
+ for (int i = 0; i < numSegs; i++) {
+ PxVec3 p0(r * PxCos(i*dphi), r * PxSin(i*dphi), -0.5f * h);
+ PxVec3 p1(r * PxCos(i*dphi), r * PxSin(i*dphi), 0.5f * h);
+ mGeom.vertices[2*(uint32_t)i] = t.transform(p0);
+ mGeom.vertices[2*(uint32_t)i+1] = t.transform(p1);
+ }
+
+ c.numFaces = 2 + numSegs;
+
+ mGeom.indices.pushBack(numSegs);
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE);
+ for (int i = 0; i < numSegs; i++)
+ mGeom.indices.pushBack(2*(numSegs-1-i));
+ mGeom.indices.pushBack(numSegs);
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE);
+ for (int i = 0; i < numSegs; i++)
+ mGeom.indices.pushBack(2*i+1);
+
+ for (int i = 0; i < numSegs; i++) {
+ int j = (i+1) % numSegs;
+
+ PxVec3 n0(PxCos(i*dphi),PxSin(i*dphi),0.0f);
+ PxVec3 n1(PxCos(j*dphi),PxSin(j*dphi),0.0f);
+
+ n0 = t.rotate(n0);
+ n1 = t.rotate(n1);
+ //n0*=-1;
+ //n1*=-1;
+ mGeom.indices.pushBack(4);
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE | CompoundGeometry::FF_HAS_NORMALS);
+ mGeom.indices.pushBack(2*i);
+ mGeom.indices.pushBack(2*j);
+ mGeom.indices.pushBack(2*j+1);
+ mGeom.indices.pushBack(2*i+1);
+ mGeom.normals.pushBack(n0);
+ mGeom.normals.pushBack(n1);
+ mGeom.normals.pushBack(n1);
+ mGeom.normals.pushBack(n0);
+ }
+ mGeom.convexes.pushBack(c);
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::createBox(const PxVec3 &dims, const PxTransform *trans)
+{
+ PxTransform t = PxTransform(PxIdentity);
+ if (trans)
+ t = *trans;
+
+ mGeom.clear();
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+
+ c.numVerts = 8;
+ mGeom.vertices.clear();
+ mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, -0.5f * dims.y, -0.5f * dims.z)));
+ mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, -0.5f * dims.y, -0.5f * dims.z)));
+ mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, 0.5f * dims.y, -0.5f * dims.z)));
+ mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, 0.5f * dims.y, -0.5f * dims.z)));
+ mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, -0.5f * dims.y, 0.5f * dims.z)));
+ mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, -0.5f * dims.y, 0.5f * dims.z)));
+ mGeom.vertices.pushBack(t.transform(PxVec3( 0.5f * dims.x, 0.5f * dims.y, 0.5f * dims.z)));
+ mGeom.vertices.pushBack(t.transform(PxVec3(-0.5f * dims.x, 0.5f * dims.y, 0.5f * dims.z)));
+
+ static int faceIds[6][4] = {{0,1,5,4},{1,2,6,5},{2,3,7,6},{3,0,4,7},{0,3,2,1},{4,5,6,7}};
+
+ c.numFaces = 6;
+ for (int i = 0; i < 6; i++) {
+ mGeom.indices.pushBack(4);
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE);
+ for (int j = 0; j < 4; j++)
+ mGeom.indices.pushBack(faceIds[i][j]);
+ }
+ mGeom.convexes.pushBack(c);
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::createSphere(const PxVec3 &dims, int resolution, const PxTransform *trans)
+{
+ PxTransform t = PxTransform(PxIdentity);
+ if (trans)
+ t = *trans;
+
+ if (resolution < 2) resolution = 2;
+ int numSegs0 = 2*resolution;
+ int numSegs1 = resolution;
+
+ float rx = 0.5f * dims.x;
+ float ry = 0.5f * dims.y;
+ float rz = 0.5f * dims.z;
+
+ mGeom.clear();
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+
+ float dphi = PxTwoPi / (float)numSegs0;
+ float dteta = PxPi / (float)numSegs1;
+ PxVec3 p, n;
+
+ for (int i = 1; i < numSegs1; i++) {
+ for (int j = 0; j < numSegs0; j++) {
+ float phi = j * dphi;
+ float teta = -PxHalfPi + i * dteta;
+ p = PxVec3(PxCos(phi)*PxCos(teta), PxSin(phi)*PxCos(teta), PxSin(teta));
+ mGeom.vertices.pushBack(PxVec3(p.x * rx, p.y * ry, p.z * rz));
+ }
+ }
+ int bottomNr = (int32_t)mGeom.vertices.size();
+ mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, -rz));
+ int topNr = (int32_t)mGeom.vertices.size();
+ mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, +rz));
+
+ c.numVerts = (int32_t)mGeom.vertices.size();
+
+ for (int i = 0; i < numSegs1-2; i++) {
+ for (int j = 0; j < numSegs0; j++) {
+ mGeom.indices.pushBack(4); // face size
+ mGeom.indices.pushBack(CompoundGeometry::FF_HAS_NORMALS | CompoundGeometry::FF_OBJECT_SURFACE);
+ int i0 = i*numSegs0 + j;
+ int i1 = i*numSegs0 + (j+1)%numSegs0;
+ int i2 = (i+1)*numSegs0 + (j+1)%numSegs0;
+ int i3 = (i+1)*numSegs0 + j;
+ mGeom.indices.pushBack(i0);
+ mGeom.indices.pushBack(i1);
+ mGeom.indices.pushBack(i2);
+ mGeom.indices.pushBack(i3);
+ n = mGeom.vertices[(uint32_t)i0]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[(uint32_t)i1]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[(uint32_t)i2]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[(uint32_t)i3]; n.normalize(); mGeom.normals.pushBack(n);
+ c.numFaces++;
+ }
+ }
+
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < numSegs0; j++) {
+ mGeom.indices.pushBack(3); // face size
+ mGeom.indices.pushBack(CompoundGeometry::FF_HAS_NORMALS | CompoundGeometry::FF_OBJECT_SURFACE);
+ int i0,i1,i2;
+ if (i == 0) {
+ i0 = j;
+ i1 = bottomNr;
+ i2 = (j+1)%numSegs0;
+ }
+ else {
+ i0 = (numSegs1-2)*numSegs0 + j;
+ i1 = (numSegs1-2)*numSegs0 + (j+1)%numSegs0;
+ i2 = topNr;
+ }
+ mGeom.indices.pushBack(i0);
+ mGeom.indices.pushBack(i1);
+ mGeom.indices.pushBack(i2);
+ n = mGeom.vertices[(uint32_t)i0]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[(uint32_t)i1]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[(uint32_t)i2]; n.normalize(); mGeom.normals.pushBack(n);
+ c.numFaces++;
+ }
+ }
+ mGeom.convexes.pushBack(c);
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::fromTetraMesh(const nvidia::Array<PxVec3> &tetVerts, const nvidia::Array<int> &tetIndices)
+{
+ mTetVertices = tetVerts;
+ mTetIndices = tetIndices;
+ deleteColors();
+
+ computeTetNeighbors();
+ computeTetEdges();
+ colorTets();
+ colorsToConvexes();
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::computeTetNeighbors()
+{
+ uint32_t numTets = mTetIndices.size() / 4;
+
+ struct TetFace {
+ void init(int i0, int i1, int i2, int faceNr, int tetNr) {
+ if (i0 > i1) { int i = i0; i0 = i1; i1 = i; }
+ if (i1 > i2) { int i = i1; i1 = i2; i2 = i; }
+ if (i0 > i1) { int i = i0; i0 = i1; i1 = i; }
+ this->i0 = i0; this->i1 = i1; this->i2 = i2;
+ this->faceNr = faceNr; this->tetNr = tetNr;
+ }
+ bool operator < (const TetFace &f) const {
+ if (i0 < f.i0) return true;
+ if (i0 > f.i0) return false;
+ if (i1 < f.i1) return true;
+ if (i1 > f.i1) return false;
+ return i2 < f.i2;
+ }
+ bool operator == (const TetFace &f) const {
+ return i0 == f.i0 && i1 == f.i1 && i2 == f.i2;
+ }
+ int i0,i1,i2;
+ int faceNr, tetNr;
+ };
+ nvidia::Array<TetFace> faces(numTets * 4);
+
+ for (uint32_t i = 0; i < numTets; i++) {
+ int ids[4];
+ ids[0] = mTetIndices[4*i];
+ ids[1] = mTetIndices[4*i+1];
+ ids[2] = mTetIndices[4*i+2];
+ ids[3] = mTetIndices[4*i+3];
+ for (uint32_t j = 0; j < 4; j++) {
+ int i0 = ids[(uint32_t)tetFaceIds[j][0]];
+ int i1 = ids[(uint32_t)tetFaceIds[j][1]];
+ int i2 = ids[(uint32_t)tetFaceIds[j][2]];
+ faces[4*i+j].init(i0,i1,i2, (int32_t)j, (int32_t)i);
+ }
+ }
+ std::sort(faces.begin(), faces.end());
+
+ mTetNeighbors.clear();
+ mTetNeighbors.resize(numTets * 4, -1);
+ uint32_t i = 0;
+ while (i < faces.size()) {
+ TetFace &f0 = faces[i];
+ i++;
+ if (i < faces.size() && faces[i] == f0) {
+ TetFace &f1 = faces[i];
+ mTetNeighbors[uint32_t(4*f0.tetNr + f0.faceNr)] = f1.tetNr;
+ mTetNeighbors[uint32_t(4*f1.tetNr + f1.faceNr)] = f0.tetNr;
+ while (i < faces.size() && faces[i] == f0)
+ i++;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::computeTetEdges()
+{
+ uint32_t numTets = mTetIndices.size() / 4;
+
+ struct SortEdge {
+ void init(int i0, int i1, int edgeNr, int tetNr) {
+ if (i0 < i1) { this->i0 = i0; this->i1 = i1; }
+ else { this->i0 = i1; this->i1 = i0; }
+ this->edgeNr = edgeNr; this->tetNr = tetNr;
+ }
+ bool operator < (const SortEdge &e) const {
+ if (i0 < e.i0) return true;
+ if (i0 > e.i0) return false;
+ return i1 < e.i1;
+ }
+ bool operator == (const SortEdge &e) const {
+ return i0 == e.i0 && i1 == e.i1;
+ }
+ int i0,i1;
+ int edgeNr, tetNr;
+ };
+ nvidia::Array<SortEdge> edges(numTets * 6);
+
+ for (uint32_t i = 0; i < numTets; i++) {
+ int ids[4];
+ ids[0] = mTetIndices[4*i];
+ ids[1] = mTetIndices[4*i+1];
+ ids[2] = mTetIndices[4*i+2];
+ ids[3] = mTetIndices[4*i+3];
+ for (uint32_t j = 0; j < 6; j++) {
+ int i0 = ids[(uint32_t)tetEdgeVerts[j][0]];
+ int i1 = ids[(uint32_t)tetEdgeVerts[j][1]];
+ edges[6*i + j].init(i0,i1, (int32_t)j, (int32_t)i);
+ }
+ }
+ std::sort(edges.begin(), edges.end());
+
+ mTetEdgeNrs.clear();
+ mTetEdgeNrs.resize(numTets * 6, -1);
+ mTetEdges.clear();
+ mEdgeTetNrs.clear();
+ mEdgeTetAngles.clear();
+ TetEdge te;
+
+ struct ChainVert {
+ int adjVert0;
+ int adjVert1;
+ int tet0;
+ int tet1;
+ float dihed0;
+ float dihed1;
+ int mark;
+ };
+ ChainVert cv;
+ cv.mark = 0;
+ nvidia::Array<ChainVert> chainVerts(mTetVertices.size(), cv);
+ nvidia::Array<int> chainVertNrs;
+
+ int mark = 1;
+
+ uint32_t i = 0;
+ while (i < edges.size()) {
+ SortEdge &e0 = edges[i];
+ int edgeNr = (int32_t)mTetEdges.size();
+ te.init(e0.i0, e0.i1);
+ te.firstTet = (int32_t)mEdgeTetNrs.size();
+ te.numTets = 0;
+ mark++;
+ chainVertNrs.clear();
+ do {
+ SortEdge &e = edges[i];
+ mTetEdgeNrs[uint32_t(6 * e.tetNr + e.edgeNr)] = edgeNr;
+ int i2 = -1;
+ int i3 = -1;
+ for (uint32_t j = 0; j < 4; j++) {
+ int id = mTetIndices[4 * (uint32_t)e.tetNr + j];
+ if (id != e0.i0 && id != e0.i1) {
+ if (i2 < 0) i2 = id;
+ else i3 = id;
+ }
+ }
+ PX_ASSERT(i2 >= 0 && i3 >= 0);
+
+ // dihedral angle at edge
+ PxVec3 &p0 = mTetVertices[(uint32_t)e0.i0];
+ PxVec3 &p1 = mTetVertices[(uint32_t)e0.i1];
+ PxVec3 &p2 = mTetVertices[(uint32_t)i2];
+ PxVec3 &p3 = mTetVertices[(uint32_t)i3];
+ PxVec3 n2 = (p1-p0).cross(p2-p0); n2.normalize();
+ if ((p3-p0).dot(n2) > 0.0f) n2 = -n2;
+ PxVec3 n3 = (p1-p0).cross(p3-p0); n3.normalize();
+ if ((p2-p0).dot(n3) > 0.0f) n3 = -n3;
+ float dot = n2.dot(n3);
+ float dihed = PxPi - PxAcos(dot);
+
+ // chain for ordering tets of edge correctly
+ ChainVert &cv2 = chainVerts[(uint32_t)i2];
+ ChainVert &cv3 = chainVerts[(uint32_t)i3];
+ if (cv2.mark != mark) { cv2.adjVert0 = -1; cv2.adjVert1 = -1; cv2.mark = mark; }
+ if (cv3.mark != mark) { cv3.adjVert0 = -1; cv3.adjVert1 = -1; cv3.mark = mark; }
+
+ if (cv2.adjVert0 < 0) { cv2.adjVert0 = i3; cv2.tet0 = e.tetNr; cv2.dihed0 = dihed; }
+ else { cv2.adjVert1 = i3; cv2.tet1 = e.tetNr; cv2.dihed1 = dihed; }
+ if (cv3.adjVert0 < 0) { cv3.adjVert0 = i2; cv3.tet0 = e.tetNr; cv3.dihed0 = dihed; }
+ else { cv3.adjVert1 = i2; cv3.tet1 = e.tetNr; cv3.dihed1 = dihed; }
+
+ chainVertNrs.pushBack(i2);
+ chainVertNrs.pushBack(i3);
+ i++;
+ }
+ while (i < edges.size() && edges[i] == e0);
+
+ te.numTets = (int32_t)chainVertNrs.size() / 2;
+ // find chain start;
+ int startVertNr = -1;
+ for (uint32_t j = 0; j < chainVertNrs.size(); j++) {
+ ChainVert &cv = chainVerts[(uint32_t)chainVertNrs[j]];
+ if (cv.adjVert0 < 0 || cv.adjVert1 < 0) {
+ startVertNr = chainVertNrs[j];
+ break;
+ }
+ }
+ te.onSurface = startVertNr >= 0;
+ mTetEdges.pushBack(te);
+
+ int curr = startVertNr;
+ if (curr < 0) curr = chainVertNrs[0];
+ int prev = -1;
+
+ // collect adjacent tetrahedra
+ for (int j = 0; j < te.numTets; j++) {
+ ChainVert &cv = chainVerts[(uint32_t)curr];
+ int next;
+ if (cv.adjVert0 == prev) {
+ next = cv.adjVert1;
+ mEdgeTetNrs.pushBack(cv.tet1);
+ mEdgeTetAngles.pushBack(cv.dihed1);
+ }
+ else {
+ next = cv.adjVert0;
+ mEdgeTetNrs.pushBack(cv.tet0);
+ mEdgeTetAngles.pushBack(cv.dihed0);
+ }
+ prev = curr;
+ curr = next;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+bool CompoundCreator::tetHasColor(int tetNr, int color)
+{
+ int nr = mTetFirstColor[(uint32_t)tetNr];
+ while (nr >= 0) {
+ if (mTetColors[(uint32_t)nr].color == color)
+ return true;
+ nr = mTetColors[(uint32_t)nr].next;
+ }
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+bool CompoundCreator::tetAddColor(int tetNr, int color)
+{
+ if (tetHasColor(tetNr, color))
+ return false;
+ Color c;
+ c.color = color;
+ c.next = mTetFirstColor[(uint32_t)tetNr];
+
+ if (mTetColorsFirstEmpty <= 0) { // new entry
+ mTetFirstColor[(uint32_t)tetNr] = (int32_t)mTetColors.size();
+ mTetColors.pushBack(c);
+ }
+ else { // take from empty list
+ int newNr = mTetColorsFirstEmpty;
+ mTetFirstColor[(uint32_t)tetNr] = newNr;
+ mTetColorsFirstEmpty = mTetColors[(uint32_t)newNr].next;
+ mTetColors[(uint32_t)newNr] = c;
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+bool CompoundCreator::tetRemoveColor(int tetNr, int color)
+{
+ int nr = mTetFirstColor[(uint32_t)tetNr];
+ int prev = -1;
+ while (nr >= 0) {
+ if (mTetColors[(uint32_t)nr].color == color) {
+ if (prev < 0)
+ mTetFirstColor[(uint32_t)tetNr] = mTetColors[(uint32_t)nr].next;
+ else
+ mTetColors[(uint32_t)prev].next = mTetColors[(uint32_t)nr].next;
+
+ // add to empty list
+ mTetColors[(uint32_t)nr].next = mTetColorsFirstEmpty;
+ mTetColorsFirstEmpty = nr;
+ return true;
+ }
+ prev = nr;
+ nr = mTetColors[(uint32_t)nr].next;
+ }
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+int CompoundCreator::tetNumColors(int tetNr)
+{
+ int num = 0;
+ int nr = mTetFirstColor[(uint32_t)tetNr];
+ while (nr >= 0) {
+ num++;
+ nr = mTetColors[(uint32_t)nr].next;
+ }
+ return num;
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::deleteColors()
+{
+ mTetFirstColor.resize(mTetIndices.size()/4, -1);
+ mTetColors.clear();
+ mTetColorsFirstEmpty = -1;
+}
+
+// -----------------------------------------------------------------------------
+bool CompoundCreator::tryTet(int tetNr, int color)
+{
+ if (tetNr < 0)
+ return false;
+
+ //if (mTetColors[tetNr] >= 0)
+ // return false;
+
+ if (tetHasColor(tetNr, color))
+ return false;
+
+ mTestEdges.clear();
+ mAddedTets.clear();
+
+ tetAddColor(tetNr, color);
+ mAddedTets.pushBack(tetNr);
+
+ for (int i = 0; i < 6; i++)
+ mTestEdges.pushBack(mTetEdgeNrs[uint32_t(6*tetNr+i)]);
+
+ bool failed = false;
+
+ while (mTestEdges.size() > 0) {
+ int edgeNr = mTestEdges[mTestEdges.size()-1];
+ mTestEdges.popBack();
+
+ TetEdge &e = mTetEdges[(uint32_t)edgeNr];
+ bool anyOtherCol = false;
+ float sumAng = 0.0f;
+ for (int i = 0; i < e.numTets; i++) {
+ int edgeTetNr = mEdgeTetNrs[uint32_t(e.firstTet + i)];
+ if (tetHasColor(edgeTetNr, color))
+ sumAng += mEdgeTetAngles[uint32_t(e.firstTet + i)];
+ else if (tetNumColors(edgeTetNr) > 0)
+ anyOtherCol = true;
+ }
+ if (sumAng < CONVEX_THRESHOLD)
+ continue;
+
+// if (e.onSurface || anyOtherCol) {
+ if (e.onSurface) {
+ failed = true;
+ break;
+ }
+
+ for (int i = 0; i < e.numTets; i++) {
+ int edgeTetNr = mEdgeTetNrs[uint32_t(e.firstTet + i)];
+ if (!tetHasColor(edgeTetNr, color)) {
+ tetAddColor(edgeTetNr, color);
+ mAddedTets.pushBack(edgeTetNr);
+ for (int j = 0; j < 6; j++)
+ mTestEdges.pushBack(mTetEdgeNrs[uint32_t(6*edgeTetNr+j)]);
+ }
+ }
+ }
+ if (failed) {
+ for (uint32_t i = 0; i < mAddedTets.size(); i++)
+ tetRemoveColor(mAddedTets[i], color);
+ mAddedTets.clear();
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::colorTets()
+{
+ int numTets = (int32_t)mTetIndices.size() / 4;
+ deleteColors();
+
+ int color = 0;
+ nvidia::Array<int> edges;
+ nvidia::Array<int> faces;
+
+ for (int i = 0; i < numTets; i++) {
+ if (tetNumColors(i) > 0)
+ continue;
+
+ tetAddColor(i, color);
+ faces.clear();
+ faces.pushBack(4*i);
+ faces.pushBack(4*i+1);
+ faces.pushBack(4*i+2);
+ faces.pushBack(4*i+3);
+
+ while (faces.size() > 0) {
+ int faceNr = faces[faces.size()-1];
+ faces.popBack();
+
+ int adjTetNr = mTetNeighbors[(uint32_t)faceNr];
+
+ if (adjTetNr < 0)
+ continue;
+
+ //if (tetNumColors(adjTetNr) > 0)
+ // continue;
+
+ if (!tryTet(adjTetNr, color))
+ continue;
+
+ for (uint32_t j = 0; j < mAddedTets.size(); j++) {
+ int addedTet = mAddedTets[j];
+ for (int k = 0; k < 4; k++) {
+ int adj = mTetNeighbors[uint32_t(4*addedTet+k)];
+ if (adj >= 0 && !tetHasColor(adj, color))
+ faces.pushBack(4*addedTet+k);
+ }
+ }
+ }
+ color++;
+ }
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::colorsToConvexes()
+{
+ mGeom.clear();
+
+ int numTets = (int32_t)mTetIndices.size() / 4;
+ int numColors = 0;
+ for (uint32_t i = 0; i < mTetColors.size(); i++) {
+ int color = mTetColors[i].color;
+ if (color >= numColors)
+ numColors = color+1;
+ }
+
+ nvidia::Array<bool> colorVisited((uint32_t)numColors, false);
+ nvidia::Array<int> queue;
+ nvidia::Array<int> globalToLocal(mTetVertices.size(), -1);
+
+ nvidia::Array<int> tetMarks((uint32_t)numTets, 0);
+ nvidia::Array<int> vertMarks(mTetVertices.size(), 0);
+ int mark = 1;
+
+ nvidia::Array<int> colorToConvexNr;
+
+ CompoundGeometry::Convex c;
+
+ for (uint32_t i = 0; i < (uint32_t)numTets; i++) {
+ int nr = mTetFirstColor[i];
+ while (nr >= 0) {
+ uint32_t color = (uint32_t)mTetColors[(uint32_t)nr].color;
+ nr = mTetColors[(uint32_t)nr].next;
+
+ if (colorVisited[color])
+ continue;
+ colorVisited[color] = true;
+
+ if ((uint32_t)colorToConvexNr.size() <= color)
+ colorToConvexNr.resize(color+1, -1);
+ colorToConvexNr[color] = (int32_t)mGeom.convexes.size();
+
+ queue.clear();
+ queue.pushBack((int32_t)i);
+
+ mGeom.initConvex(c);
+ mark++;
+ c.numVerts = 0;
+
+ // flood fill
+ while (!queue.empty()) {
+ uint32_t tetNr = (uint32_t)queue[queue.size()-1];
+ queue.popBack();
+ if (tetMarks[tetNr] == mark)
+ continue;
+ tetMarks[tetNr] = mark;
+
+ for (uint32_t j = 0; j < 4; j++) {
+ int adjNr = mTetNeighbors[4*tetNr + j];
+ if (adjNr < 0 || !tetHasColor(adjNr, (int32_t)color)) {
+ // create new face
+ mGeom.indices.pushBack(3); // face size
+ int flags = 0;
+ if (adjNr < 0) flags |= CompoundGeometry::FF_OBJECT_SURFACE;
+ mGeom.indices.pushBack(flags);
+
+ for (uint32_t k = 0; k < 3; k++) {
+ uint32_t id = (uint32_t)mTetIndices[4*tetNr + tetFaceIds[j][k]];
+ if (vertMarks[id] != mark) {
+ vertMarks[id] = mark;
+ globalToLocal[id] = c.numVerts;
+ c.numVerts++;
+ mGeom.vertices.pushBack(mTetVertices[id]);
+ }
+ mGeom.indices.pushBack(globalToLocal[id]);
+ }
+ c.numFaces++;
+ }
+ if (adjNr >= 0) {
+ // add neighbors
+ int colNr = mTetFirstColor[(uint32_t)adjNr];
+ while (colNr >= 0) {
+ int adjColor = mTetColors[(uint32_t)colNr].color;
+ colNr = mTetColors[(uint32_t)colNr].next;
+ if (adjColor != (int32_t)color) {
+ bool isNew = true;
+ for (int k = 0; k < c.numNeighbors; k++) {
+ if (mGeom.neighbors[uint32_t(c.firstNeighbor+k)] == adjColor) {
+ isNew = false;
+ break;
+ }
+ }
+ if (isNew) {
+ mGeom.neighbors.pushBack(adjColor);
+ c.numNeighbors++;
+ }
+ }
+ }
+ }
+ if (adjNr < 0 || !tetHasColor(adjNr, (int32_t)color) || tetMarks[(uint32_t)adjNr] == mark)
+ continue;
+ queue.pushBack(adjNr);
+ }
+ }
+ mGeom.convexes.pushBack(c);
+ }
+ }
+
+ for (uint32_t i = 0; i < mGeom.neighbors.size(); i++) {
+ if (mGeom.neighbors[i] >= 0)
+ mGeom.neighbors[i] = colorToConvexNr[(uint32_t)mGeom.neighbors[i]];
+ }
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.h b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.h
new file mode 100644
index 00000000..0805fc67
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/CompoundCreatorBase.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUND_CREATOR_BASE_H
+#define COMPOUND_CREATOR_BASE_H
+
+// Matthias Muller-Fischer
+
+#include <PxVec3.h>
+#include <PxTransform.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+#include "CompoundGeometryBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+ class SimScene;
+
+// ---------------------------------------------------------------------------------------
+class CompoundCreator : public UserAllocated {
+ friend class nvidia::fracture::base::SimScene;
+public:
+ // direct
+ void createTorus(float r0, float r1, int numSegs0, int numSegs1, const PxTransform *trans = NULL);
+ void createCylinder(float r, float h, int numSegs, const PxTransform *trans = NULL);
+ void createBox(const PxVec3 &dims, const PxTransform *trans = NULL);
+ void createSphere(const PxVec3 &dims, int resolution = 5, const PxTransform *trans = NULL);
+ void fromTetraMesh(const nvidia::Array<PxVec3> &tetVerts, const nvidia::Array<int> &tetIndices);
+
+ const CompoundGeometry &getGeometry() { return mGeom; }
+
+ virtual void debugDraw() {}
+
+protected:
+ CompoundCreator(SimScene* scene): mScene(scene) {}
+ virtual ~CompoundCreator() {}
+
+ SimScene* mScene;
+
+ static int tetFaceIds[4][3];
+ static int tetEdgeVerts[6][2];
+ static int tetFaceEdges[4][3];
+
+ void computeTetNeighbors();
+ void computeTetEdges();
+ void colorTets();
+ void colorsToConvexes();
+
+ bool tetHasColor(int tetNr, int color);
+ bool tetAddColor(int tetNr, int color);
+ bool tetRemoveColor(int tetNr, int color);
+ int tetNumColors(int tetNr);
+ void deleteColors();
+
+ bool tryTet(int tetNr, int color);
+
+ // from tet mesh
+ nvidia::Array<PxVec3> mTetVertices;
+ nvidia::Array<int> mTetIndices;
+ nvidia::Array<int> mTetNeighbors;
+
+ nvidia::Array<int> mTetFirstColor;
+ struct Color {
+ int color;
+ int next;
+ };
+ int mTetColorsFirstEmpty;
+ nvidia::Array<Color> mTetColors;
+
+ struct TetEdge {
+ void init(int i0, int i1) { this->i0 = i0; this->i1 = i1; firstTet = 0; numTets = 0; onSurface = false; }
+ int i0, i1;
+ int firstTet, numTets;
+ bool onSurface;
+ };
+ nvidia::Array<TetEdge> mTetEdges;
+ nvidia::Array<int> mTetEdgeNrs;
+ nvidia::Array<int> mEdgeTetNrs;
+ nvidia::Array<float> mEdgeTetAngles;
+
+ nvidia::Array<int> mAddedTets;
+ nvidia::Array<int> mTestEdges;
+
+ // input
+ nvidia::Array<PxVec3> mVertices;
+ nvidia::Array<int> mIndices;
+
+ // output
+ CompoundGeometry mGeom;
+};
+
+}}}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.cpp b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.cpp
new file mode 100644
index 00000000..014a37bb
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "CompoundGeometryBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+// -------------------------------------------------------------------------------
+void CompoundGeometry::clear()
+{
+ convexes.clear();
+ vertices.clear();;
+ normals.clear();
+ indices.clear();
+ neighbors.clear();
+ planes.clear();
+}
+
+// -------------------------------------------------------------------------------
+bool CompoundGeometry::loadFromFile(const char * /*filename*/)
+{
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+bool CompoundGeometry::saveFromFile(const char * /*filename*/)
+{
+ return true;
+}
+
+// -------------------------------------------------------------------------------
+void CompoundGeometry::initConvex(Convex &c)
+{
+ c.firstVert = (int32_t)vertices.size();
+ c.numVerts = 0;
+ c.firstNormal = (int32_t)normals.size();
+ c.firstIndex = (int32_t)indices.size();
+ c.numFaces = 0;
+ c.firstPlane = 0;
+ c.firstNeighbor = (int32_t)neighbors.size();
+ c.numNeighbors = 0;
+}
+
+// -------------------------------------------------------------------------------
+void CompoundGeometry::derivePlanes()
+{
+ planes.clear();
+ PxPlane p;
+
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ Convex &c = convexes[i];
+ c.firstPlane = (int32_t)planes.size();
+ int *ids = &indices[(uint32_t)c.firstIndex];
+ PxVec3 *verts = &vertices[(uint32_t)c.firstVert];
+ for (int j = 0; j < c.numFaces; j++) {
+ int num = *ids++;
+ ids++; //int flags = *ids++;
+ if (num < 3)
+ p = PxPlane(1.0f, 0.0f, 0.0f, 0.0f);
+ else {
+ p.n = PxVec3(0.0f, 0.0f, 0.0f);
+ for (int k = 1; k < num-1; k++) {
+ const PxVec3 &p0 = verts[ids[0]];
+ const PxVec3 &p1 = verts[ids[k]];
+ const PxVec3 &p2 = verts[ids[k+1]];
+ p.n += (p1-p0).cross(p2-p1);
+ }
+ p.n.normalize();
+ p.d = p.n.dot(verts[ids[0]]);
+ }
+ planes.pushBack(p);
+ ids += num;
+ }
+ }
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.h b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.h
new file mode 100644
index 00000000..30452676
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/CompoundGeometryBase.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUND_GEOMETRY_BASE
+#define COMPOUND_GEOMETRY_BASE
+
+#include <PxVec3.h>
+#include <PxPlane.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+// -----------------------------------------------------------------------------------
+class CompoundGeometry : public UserAllocated
+{
+public:
+ CompoundGeometry() {}
+ virtual ~CompoundGeometry() {}
+ bool loadFromFile(const char *filename);
+ bool saveFromFile(const char *filename);
+ void clear();
+ void derivePlanes();
+
+ virtual void debugDraw(int /*maxConvexes*/ = 0) const {}
+
+ struct Convex { // init using CompoundGeometry::initConvex()
+ int firstVert;
+ int numVerts;
+ int firstNormal; // one per face index! If not provided (see face flags) face normal is used
+ int firstIndex;
+ int numFaces;
+ int firstPlane;
+ int firstNeighbor;
+ int numNeighbors;
+ };
+
+ void initConvex(Convex &c);
+
+ nvidia::Array<Convex> convexes;
+ nvidia::Array<PxVec3> vertices;
+ nvidia::Array<PxVec3> normals; // one per face and vertex!
+ // face size, face flags, id, id, .., face size, face flags, id ..
+ nvidia::Array<int> indices;
+ nvidia::Array<int> neighbors;
+
+ nvidia::Array<PxPlane> planes; // derived for faster cuts
+
+ enum FaceFlags {
+ FF_OBJECT_SURFACE = 1,
+ FF_HAS_NORMALS = 2,
+ FF_INVISIBLE = 4,
+ FF_NEW = 8,
+ };
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/ConvexBase.cpp b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.cpp
new file mode 100644
index 00000000..35906cc7
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.cpp
@@ -0,0 +1,1371 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "PxPhysics.h"
+#include "PxCooking.h"
+#include "PxDefaultStreams.h"
+#include "PxShape.h"
+#include "PxMath.h"
+#include "PxRigidDynamic.h"
+#include "PxConvexMesh.h"
+#include "PxMat44.h"
+#include "PsMathUtils.h"
+#include "PxVec2.h"
+
+#include "CompoundGeometryBase.h"
+#include "SimSceneBase.h"
+#include "PolygonTriangulatorBase.h"
+#include "MeshClipperBase.h"
+
+#include "ConvexBase.h"
+
+#define COOK_TRIANGLES 0
+
+#include <algorithm>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace physx;
+
+// --------------------------------------------------------------------------------------------
+Convex::Convex(SimScene* scene)
+{
+ mScene = scene;
+ mPxConvexMesh = NULL;
+ mPxActor = NULL;
+ mLocalPose = PxTransform(PxIdentity);
+ mParent = NULL;
+ mNewConvex = NULL;
+ mRefCounter = 0;
+ mIsFarConvex = false;
+ clear();
+}
+
+// --------------------------------------------------------------------------------------------
+Convex::~Convex()
+{
+ clear();
+ if (mNewConvex != NULL)
+ PX_DELETE(mNewConvex);
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::clear()
+{
+ mFaces.clear();
+ mIndices.clear();
+ mVertices.clear();
+ mNormals.clear();
+ mPlanes.clear();
+
+ mVisVertices.clear();
+ mVisNormals.clear();
+ mVisTangents.clear();
+ mVisTexCoords.clear();
+ mVisTriIndices.clear();
+
+ mHasExplicitVisMesh = false;
+ mIsGhostConvex = false;
+ mVisPolyStarts.clear();
+ mVisPolyIndices.clear();
+ mVisPolyNeighbors.clear();
+
+ if (mPxConvexMesh != NULL)
+ mPxConvexMesh->release();
+
+ mPxConvexMesh = NULL;
+ mPxActor = NULL;
+ mLocalPose = PxTransform(PxIdentity);
+
+ mBounds.setEmpty();
+ mMaterialOffset = PxVec3(0.0f, 0.0f, 0.0f);
+ mTexScale = 1.0f;
+
+ mUse2dTexture = false;
+ mIndestructible = false;
+ mMaterialId = 0;
+ mSurfaceMaterialId = 0;
+ mModelIslandNr = 0;
+
+ mVolume = 0.0f;
+ mVolumeDirty = true;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::createFromConvex(const Convex *convex, const PxTransform *trans)
+{
+ clear();
+ mVertices = convex->mVertices;
+ mFaces = convex->mFaces;
+ clearFraceFlags(CompoundGeometry::FF_NEW);
+
+ mIndices = convex->mIndices;
+ mNormals = convex->mNormals;
+ mMaterialOffset = convex->mMaterialOffset;
+ mTexScale = convex->mTexScale;
+ mIsGhostConvex = convex->mIsGhostConvex;
+ mLocalPose = convex->mLocalPose;
+
+ if (trans != NULL) {
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ mVertices[i] = trans->transform(mVertices[i]);
+ for (uint32_t i = 0; i < mNormals.size(); i++)
+ mNormals[i] = trans->rotate(mNormals[i]);
+ mMaterialOffset -= trans->p;
+ }
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::transform(const PxMat44 &trans)
+{
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ mVertices[i] = trans.transform(mVertices[i]);
+ for (uint32_t i = 0; i < mNormals.size(); i++)
+ mNormals[i] = trans.rotate(mNormals[i]);
+ mMaterialOffset -= trans.getPosition();
+
+ if (mHasExplicitVisMesh) {
+ for (uint32_t i = 0; i < mVisVertices.size(); i++)
+ mVisVertices[i] = trans.transform(mVisVertices[i]);
+ for (uint32_t i = 0; i < mVisNormals.size(); i++)
+ mVisNormals[i] = trans.rotate(mVisNormals[i]);
+ }
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans)
+{
+ clear();
+ const CompoundGeometry::Convex &c = geom.convexes[(uint32_t)convexNr];
+
+ PxMat44 t = PxMat44(PxIdentity);
+
+ if (trans)
+ t = *trans;
+
+ mVertices.resize((uint32_t)c.numVerts);
+ for (int i = 0; i < c.numVerts; i++)
+ mVertices[(uint32_t)i] = t.transform(geom.vertices[uint32_t(c.firstVert + i)]);
+
+ mFaces.resize((uint32_t)c.numFaces);
+ int num = 0;
+ const int *id = &geom.indices[(uint32_t)c.firstIndex];
+ const PxVec3 *normals = (geom.normals.size() > 0) ? &geom.normals[(uint32_t)c.firstNormal] : NULL;
+
+ for (uint32_t i = 0; i < (uint32_t)c.numFaces; i++) {
+ Face &f = mFaces[i];
+ f.init();
+ f.firstIndex = num;
+ f.numIndices = *id++;
+ f.flags = *id++;
+ for (int j = 0; j < f.numIndices; j++)
+ mIndices.pushBack(*id++);
+ if (f.flags & CompoundGeometry::FF_HAS_NORMALS) {
+ f.firstNormal = (int32_t)mNormals.size();
+ for (int j = 0; j < f.numIndices; j++) {
+ mNormals.pushBack(t.rotate(*normals));
+ normals++;
+ }
+ }
+ num += f.numIndices;
+ }
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::setPxActor(PxRigidActor *actor)
+{
+ mPxActor = actor;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::setLocalPose(const PxTransform &pose)
+{
+ mLocalPose = pose;
+}
+
+// --------------------------------------------------------------------------------------------
+PxVec3 Convex::getCenter() const
+{
+ PxVec3 center(0.0f, 0.0f, 0.0f);
+
+ if (mVertices.empty())
+ return center;
+
+ uint32_t numVerts = mVertices.size();
+ for (uint32_t i = 0; i < numVerts; i++)
+ center += mVertices[i];
+ center /= (float)numVerts;
+
+ return center;
+}
+
+// --------------------------------------------------------------------------------------------
+PxVec3 Convex::centerAtZero()
+{
+ PxVec3 center = getCenter();
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ mVertices[i] -= center;
+ finalize();
+ return center;
+}
+
+// --------------------------------------------------------------------------------------------
+PxTransform Convex::getGlobalPose() const
+{
+ if (mPxActor == NULL)
+ return mLocalPose;
+ else
+ return mPxActor->getGlobalPose() * mLocalPose;
+}
+
+// --------------------------------------------------------------------------------------------
+PxTransform Convex::getLocalPose() const
+{
+ return mLocalPose;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const
+{
+ PxVec3 o,d;
+ PxTransform pose = getGlobalPose();
+ d = pose.rotateInv(dir);
+ o = pose.transformInv(orig);
+
+ if (mHasExplicitVisMesh)
+ return rayCastVisMesh(o,d, dist, normal);
+ else
+ return rayCastConvex(o,d, dist, normal);
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::rayCastConvex(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const
+{
+ float maxEntry = -PX_MAX_F32;
+ float minExit = PX_MAX_F32;
+ normal = PxVec3(0.0f, 1.0f, 0.0f);
+
+ for (uint32_t i = 0; i < mPlanes.size(); i++) {
+ const PxPlane &plane = mPlanes[i];
+ float dot = plane.n.dot(dir);
+ if (dot == 0.0f)
+ continue;
+
+ float t = (plane.d - orig.dot(plane.n)) / dot;
+ if (dot < 0.0f) {
+ if (t > maxEntry) {
+ maxEntry = t;
+ normal = plane.n;
+ }
+ }
+ else {
+ minExit = PxMin(minExit, t);
+ }
+ }
+
+ if (maxEntry > minExit) {
+ dist = PX_MAX_F32;
+ return false;
+ }
+
+ dist = maxEntry;
+ normal.normalize();
+ return dist >= 0.0f;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::rayCastVisMesh(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const
+{
+ normal = PxVec3(0.0f, 1.0f, 0.0f);
+ dist = PX_MAX_F32;
+ int minTri = -1;
+
+ for (uint32_t i = 0; i < mVisTriIndices.size(); i += 3) {
+ const PxVec3 &p0 = mVisVertices[(uint32_t)mVisTriIndices[i]];
+ const PxVec3 &p1 = mVisVertices[(uint32_t)mVisTriIndices[i+1]];
+ const PxVec3 &p2 = mVisVertices[(uint32_t)mVisTriIndices[i+2]];
+ PxVec3 n = (p1-p0).cross(p2-p0);
+ float t = dir.dot(n);
+ if (t >= 0.0f)
+ continue;
+ t = n.dot(p0 - orig) / t;
+ if (t < 0.0f)
+ continue;
+
+ // hit inside triangle?
+ PxVec3 hit = orig + t * dir;
+ float b2 = (p1-p0).cross(hit-p0).dot(n);
+ float b0 = (p2-p1).cross(hit-p1).dot(n);
+ float b1 = (p0-p2).cross(hit-p2).dot(n);
+ if (b0 < 0.0f || b1 < 0.0f || b2 < 0.0f)
+ continue;
+
+ float d = (orig - hit).magnitude();
+
+ if (d < dist) {
+ dist = d;
+ minTri = (int32_t)i / 3;
+ normal = n;
+ }
+ }
+ normal.normalize();
+ return minTri >= 0;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::collide(const PxVec3 &pos, float r, float &penetration, PxVec3 &surfaceNormal, PxVec3 &surfaceVel) const
+{
+ PxVec3 p = getGlobalPose().transformInv(pos);
+
+ float minDist = PX_MAX_F32;
+ int minPlane = -1;
+
+ for (uint32_t i = 0; i < mPlanes.size(); i++) {
+ const PxPlane &plane = mPlanes[i];
+ float dist = plane.d - p.dot(plane.n) + r;
+ if (dist < 0.0f)
+ return false;
+ if (dist < minDist) {
+ minDist = dist;
+ minPlane = (int32_t)i;
+ }
+ }
+
+ if (minPlane < 0)
+ return false;
+ else {
+ PxPlane plane = mPlanes[(uint32_t)minPlane];
+ surfaceNormal = plane.n;
+ penetration = minDist;
+ surfaceVel = PxVec3(0.0f, 0.0f, 0.0f);
+
+ if (mPxActor != NULL) {
+ PxRigidDynamic *actor = mPxActor->is<physx::PxRigidDynamic>();
+ if (actor != NULL) {
+ surfaceNormal = getGlobalPose().rotate(surfaceNormal);
+ surfaceVel = actor->getLinearVelocity() + actor->getAngularVelocity().cross(surfaceNormal * plane.d);
+ }
+ }
+ return true;
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::finalize()
+{
+ updateBounds();
+ updatePlanes();
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::updateBounds()
+{
+ mBounds.setEmpty();
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ mBounds.include(mVertices[i]);
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::updatePlanes()
+{
+ uint32_t numFaces = mFaces.size();
+ mPlanes.resize(numFaces);
+
+ for (uint32_t i = 0; i < numFaces; i++) {
+ Face &f = mFaces[i];
+ if (f.numIndices < 3) { // should not happen
+ mPlanes[i].n = PxVec3(0.0f, 1.0f, 0.0f);
+ mPlanes[i].d = 0.0f;
+ continue;
+ }
+ PxVec3 n(0.0f, 0.0f, 0.0f);
+ PxVec3 &p0 = mVertices[(uint32_t)mIndices[(uint32_t)f.firstIndex]];
+ for (int j = 1; j < f.numIndices-1; j++) {
+ PxVec3 &p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]];
+ PxVec3 &p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j+1)]];
+ n += (p1-p0).cross(p2-p0);
+ }
+ n.normalize();
+ mPlanes[i].n = n;
+ mPlanes[i].d = mPlanes[i].n.dot(p0);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::getWorldBounds(PxBounds3 &bounds) const
+{
+ bounds = PxBounds3::transformSafe(getGlobalPose(), mBounds);
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::getLocalBounds(PxBounds3 &bounds) const
+{
+ bounds = mBounds;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::intersectWithConvex(const PxPlane *planes, int numPlanes, const PxMat44 &trans, bool &empty)
+{
+ empty = false;
+
+ PxMat33 M(trans.getBasis(0), trans.getBasis(1), trans.getBasis(2));
+ PxMat33 M1 = M.getInverse();
+ PxMat33 M1T = M1.getTranspose();
+
+ for (int i = 0; i < numPlanes; i++) {
+ PxPlane p;
+ p.n = M1T.transform(planes[i].n);
+ p.d = planes[i].d + trans.getPosition().dot(p.n);
+ float len = p.n.normalize();
+ p.d /= len;
+ cut(p.n, p.d, empty);
+ if (empty)
+ return;
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::cut(const PxVec3 &localPlaneN, float localPlaneD, bool &cutEmpty, bool setNewFaceFlag)
+{
+ float eps = 1e-4f;
+
+ //bool pos = false;
+ //bool neg = false;
+
+ PxVec3 pn = localPlaneN;
+ float pd = localPlaneD;
+
+ // does the plane pass through the convex?
+ float minD = PX_MAX_F32;
+ float maxD = -PX_MAX_F32;
+
+ for (uint32_t i = 0; i < mVertices.size(); i++) {
+ float dot = mVertices[i].dot(pn);
+ if (dot < minD) minD = dot;
+ if (dot > maxD) maxD = dot;
+ }
+
+ cutEmpty = minD > pd - eps;
+ if (cutEmpty || maxD < pd + eps)
+ return false;
+
+ // new: avoid singular cases
+ for (uint32_t i = 0; i < mVertices.size(); i++) {
+ float dot = mVertices[i].dot(pn);
+ if (fabs(dot - pd) < 1e-5f)
+ pd += 1e-5f;
+ }
+
+ // member so the memory does not have to be re-allocated for every cut
+ if (mNewConvex == NULL)
+ mNewConvex = mScene->createConvex();
+ mNewConvex->clear();
+
+ // create vertices
+ uint32_t numFaces = mFaces.size();
+ nvidia::Array<int> newNr(mVertices.size(), -1);
+
+ struct Cut {
+ void set(int i0, int i1, int newId) {
+ this->i0 = i0; this->i1 = i1; this->newId = newId; next = -1;
+ }
+ bool is(int i0, int i1) {
+ return (this->i0 == i0 && this->i1 == i1) || (this->i0 == i1 && this->i1 == i0);
+ }
+ int i0, i1;
+ int newId;
+ int next;
+ };
+ nvidia::Array<Cut> cuts;
+
+ for (uint32_t i = 0; i < numFaces; i++) {
+ Face &f = mFaces[i];
+ int *ids = &mIndices[(uint32_t)f.firstIndex];
+ mNewConvex->mFaces.resize(mNewConvex->mFaces.size() + 1);
+ Face &newFace = mNewConvex->mFaces[mNewConvex->mFaces.size()-1];
+ newFace.init();
+ newFace.flags = f.flags;
+ newFace.firstIndex = (int32_t)mNewConvex->mIndices.size();
+ bool hasNormals = (f.flags & CompoundGeometry::FF_HAS_NORMALS) != 0;
+ if (hasNormals)
+ newFace.firstNormal = (int32_t)mNewConvex->mNormals.size();
+
+ int cutNrs[2];
+ uint32_t numCuts = 0;
+ bool winding = false;
+
+ for (int j = 0; j < f.numIndices; j++) {
+ int j1 = (j+1)%f.numIndices;
+ int i0 = ids[j];
+ int i1 = ids[j1];
+ PxVec3 &p0 = mVertices[(uint32_t)i0];
+ PxVec3 &p1 = mVertices[(uint32_t)i1];
+ PxVec3 n0,n1;
+ if (hasNormals) {
+ n0 = mNormals[uint32_t(f.firstNormal+j)];
+ n1 = mNormals[uint32_t(f.firstNormal+j1)];
+ }
+ bool sign0 = p0.dot(pn) >= pd;
+ bool sign1 = p1.dot(pn) >= pd;
+ if (!sign0) {
+ if (newNr[(uint32_t)i0] < 0) {
+ newNr[(uint32_t)i0] = (int32_t)mNewConvex->mVertices.size();
+ mNewConvex->mVertices.pushBack(p0);
+ }
+ mNewConvex->mIndices.pushBack(newNr[(uint32_t)i0]);
+ if (hasNormals)
+ mNewConvex->mNormals.pushBack(n0);
+ if (numCuts == 1)
+ winding = true;
+ }
+
+ // cut?
+ if (sign0 != sign1) {
+ // do we have the cut vertex already?
+ uint32_t totalCuts = cuts.size();
+ uint32_t k = 0;
+ while (k < totalCuts && !cuts[k].is(i0,i1))
+ k++;
+
+ float t = (pd - p0.dot(pn)) / (p1 - p0).dot(pn);
+ // create new cut vertex
+ if (k == totalCuts) {
+ cuts.resize(totalCuts+1);
+ cuts[totalCuts].set(i0, i1, (int32_t)mNewConvex->mVertices.size());
+ PxVec3 p = p0 + (p1-p0) * t;
+ mNewConvex->mVertices.pushBack(p);
+ }
+ mNewConvex->mIndices.pushBack(cuts[k].newId);
+ if (hasNormals) {
+ PxVec3 n = n0 + (n1-n0) * t;
+ n.normalize();
+ mNewConvex->mNormals.pushBack(n);
+ }
+ if (numCuts >= 2) { // numerical problems!
+ cutEmpty = true;
+ return false;
+ }
+ cutNrs[numCuts] = (int32_t)k;
+ numCuts++;
+ }
+ }
+
+ if (numCuts == 1) { // numerical problems!
+ cutEmpty = true;
+ return false;
+ }
+
+ if (numCuts == 2) {
+ Cut &cut0 = cuts[(uint32_t)cutNrs[0]];
+ Cut &cut1 = cuts[(uint32_t)cutNrs[1]];
+ if (winding) {
+ cut0.next = cutNrs[1];
+ }
+ else {
+ cut1.next = cutNrs[0];
+ }
+ }
+
+ // check whether the new convex got a new face
+
+ newFace.numIndices = (int32_t)mNewConvex->mIndices.size() - newFace.firstIndex;
+ if (newFace.numIndices == 0)
+ mNewConvex->mFaces.popBack();
+ else if (newFace.numIndices < 3) {
+ cutEmpty = true;
+ return false;
+ }
+ }
+
+ // create closing face
+ Face closingFace;
+ closingFace.init();
+ closingFace.firstIndex = (int32_t)mNewConvex->mIndices.size();
+
+ int nr = 0;
+ for (uint32_t i = 0; i < cuts.size(); i++) {
+ mNewConvex->mIndices.pushBack(cuts[(uint32_t)nr].newId);
+ closingFace.numIndices++;
+ nr = cuts[(uint32_t)nr].next;
+
+ if (nr < 0) { // numerical problems
+ cutEmpty = true;
+ return false;
+ }
+ }
+ if (closingFace.numIndices < 3) {
+ cutEmpty = true;
+ return false;
+ }
+ if (setNewFaceFlag)
+ closingFace.flags |= CompoundGeometry::FF_NEW;
+
+ mNewConvex->mFaces.pushBack(closingFace);
+
+ mVertices = mNewConvex->mVertices;
+ mIndices = mNewConvex->mIndices;
+ mFaces = mNewConvex->mFaces;
+ mNormals = mNewConvex->mNormals;
+ mVolumeDirty = true;
+ finalize();
+
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+PxConvexMesh* Convex::createPxConvexMesh(Compound *parent, PxPhysics *pxPhysics, PxCooking *pxCooking)
+{
+ mParent = parent;
+
+ if (mVertices.empty())
+ return NULL;
+
+ if (mPxConvexMesh != NULL)
+ return mPxConvexMesh;
+
+ mPxConvexMesh = NULL;
+ mPxActor = NULL;
+
+#if COOK_TRIANGLES
+ // create tri mesh
+ // in this tri mesh vertices are shared in contrast to the tri mesh for rendering
+ nvidia::Array<uint32_t> indices;
+ for (int i = 0; i < (int)mFaces.size(); i++) {
+ Face &f = mFaces[i];
+ if (f.numIndices < 3)
+ continue;
+ int *ids = &mIndices[f.firstIndex];
+ for (int j = 1; j < f.numIndices-1; j++) {
+ indices.pushBack(ids[0]);
+ indices.pushBack(ids[j]);
+ indices.pushBack(ids[j+1]);
+ }
+ }
+
+ physx::PxConvexMeshDesc meshDesc;
+ meshDesc.setToDefault();
+ meshDesc.points.count = mVertices.size();
+ meshDesc.points.stride = sizeof(PxVec3);
+ meshDesc.points.data = &mVertices[0];
+ meshDesc.triangles.count = indices.size() / 3;
+ meshDesc.triangles.stride = 3*sizeof(uint32_t);
+ meshDesc.triangles.data = &indices[0];
+#else
+ nvidia::Array<physx::PxHullPolygon> polygons;
+ polygons.reserve(mFaces.size());
+ if (mPlanes.size() != mFaces.size())
+ updatePlanes();
+
+ for (uint32_t i = 0; i < mFaces.size(); i++) {
+ Face &f = mFaces[i];
+ if (f.numIndices < 3)
+ continue;
+ physx::PxHullPolygon p;
+ p.mIndexBase = (uint16_t)f.firstIndex;
+ p.mNbVerts = (uint16_t)f.numIndices;
+ p.mPlane[0] = mPlanes[i].n.x;
+ p.mPlane[1] = mPlanes[i].n.y;
+ p.mPlane[2] = mPlanes[i].n.z;
+ p.mPlane[3] = -mPlanes[i].d;
+ polygons.pushBack(p);
+ }
+
+ physx::PxConvexMeshDesc meshDesc;
+ meshDesc.setToDefault();
+ meshDesc.points.count = mVertices.size();
+ meshDesc.points.stride = sizeof(PxVec3);
+ meshDesc.points.data = &mVertices[0];
+ meshDesc.indices.count = mIndices.size();
+ meshDesc.indices.data = &mIndices[0];
+ meshDesc.indices.stride = sizeof(uint32_t);
+ meshDesc.polygons.count = mFaces.size();
+ meshDesc.polygons.data = &polygons[0];
+ meshDesc.polygons.stride = sizeof(physx::PxHullPolygon);
+
+#endif
+
+ // Cooking from memory
+ PxDefaultMemoryOutputStream outBuffer;
+ if (!pxCooking->cookConvexMesh(meshDesc, outBuffer))
+ return NULL;
+
+ PxDefaultMemoryInputData inBuffer(outBuffer.getData(), outBuffer.getSize());
+ mPxConvexMesh = pxPhysics->createConvexMesh(inBuffer);
+
+ return mPxConvexMesh;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::setMaterialOffset(const PxVec3 &offset)
+{
+ if (mHasExplicitVisMesh) {
+ for (uint32_t i = 0; i < mVisVertices.size(); i++)
+ mVisVertices[i] += mMaterialOffset - offset;
+ }
+ mMaterialOffset = offset;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::createVisMeshFromConvex()
+{
+ // vertices are duplicated for each face to get sharp edges with multiple normals
+ mHasExplicitVisMesh = false;
+ mVisVertices.clear();
+ mVisNormals.clear();
+ mVisTangents.clear();
+ mVisTriIndices.clear();
+ mVisTexCoords.clear();
+ PxVec3 n;
+ PxVec3 t0, t1;
+
+ for (uint32_t i = 0; i < mFaces.size(); i++) {
+ Face &f = mFaces[i];
+ if (f.flags & CompoundGeometry::FF_INVISIBLE)
+ continue;
+ if (f.numIndices < 3)
+ continue;
+ // normal
+ int *ids = &mIndices[(uint32_t)f.firstIndex];
+ if (!(f.flags & CompoundGeometry::FF_HAS_NORMALS)) {
+ n = (mVertices[(uint32_t)ids[1]] - mVertices[(uint32_t)ids[0]]).cross(mVertices[(uint32_t)ids[2]] - mVertices[(uint32_t)ids[0]]);
+ n.normalize();
+ }
+ // tangents
+ if (fabs(n.x) < fabs(n.y) && fabs(n.x) < fabs(n.z))
+ t0 = PxVec3(1.0f, 0.0f, 0.0f);
+ else if (fabs(n.y) < fabs(n.z))
+ t0 = PxVec3(0.0f, 1.0f, 0.0);
+ else
+ t0 = PxVec3(0.0f, 0.0f, 1.0f);
+ t1 = n.cross(t0);
+ t1.normalize();
+ t0 = t1.cross(n);
+
+ int firstVertNr = (int32_t)mVisVertices.size();
+ for (int j = 0; j < f.numIndices; j++) {
+ PxVec3 p = mVertices[(uint32_t)ids[(uint32_t)j]];
+ mVisVertices.pushBack(p);
+ if (f.flags & CompoundGeometry::FF_HAS_NORMALS) {
+ mVisNormals.pushBack(mNormals[uint32_t(f.firstNormal + j)]);
+ mVisTangents.pushBack(PxVec3(0.0f, 0.0f, 0.0f)); // on surface, not bump map
+ }
+ else {
+ mVisNormals.pushBack(n);
+ mVisTangents.pushBack(t0); // internal face, bump map
+ }
+ mVisTexCoords.pushBack(p.dot(t0) * mTexScale);
+ mVisTexCoords.pushBack(p.dot(t1) * mTexScale);
+ }
+ for (int j = 1; j < f.numIndices-1; j++) {
+ mVisTriIndices.pushBack(firstVertNr);
+ mVisTriIndices.pushBack(firstVertNr+j);
+ mVisTriIndices.pushBack(firstVertNr+j+1);
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+struct Edge {
+ // not using indices for edge match but positions
+ // so duplicated vertices are handled as one vertex
+ bool smaller(const PxVec3 &v0, const PxVec3 &v1) const {
+ if (v0.x < v1.x) return true;
+ if (v0.x > v1.x) return false;
+ if (v0.y < v1.y) return true;
+ if (v0.y > v1.y) return false;
+ return (v0.z < v1.z);
+ }
+ void set(const PxVec3 &v0, const PxVec3 &v1, int faceNr, int edgeNr) {
+ if (smaller(v0,v1)) { this->v0 = v0; this->v1 = v1; }
+ else { this->v0 = v1; this->v1 = v0; }
+ this->faceNr = faceNr; this->edgeNr = edgeNr;
+ }
+ bool operator < (const Edge &e) const {
+ if (smaller(v0, e.v0)) return true;
+ if (v0 == e.v0 && smaller(v1, e.v1)) return true;
+ return false;
+ }
+ bool operator == (const Edge &e) const { return v0 == e.v0 && v1 == e.v1; }
+ PxVec3 v0,v1;
+ int faceNr, edgeNr;
+};
+
+// --------------------------------------------------------------------------------------------
+bool Convex::computeVisMeshNeighbors()
+{
+ uint32_t numIndices = mVisPolyIndices.size();
+ uint32_t numPolygons = mVisPolyStarts.size()-1;
+
+ nvidia::Array<Edge> edges(numIndices);
+
+ for (uint32_t i = 0; i < numPolygons; i++) {
+ int first = mVisPolyStarts[i];
+ int num = mVisPolyStarts[i+1] - first;
+ for (int j = 0; j < num; j++) {
+ edges[uint32_t(first + j)].set(
+ mVisVertices[(uint32_t)mVisPolyIndices[uint32_t(first + j)]],
+ mVisVertices[(uint32_t)mVisPolyIndices[uint32_t(first + (j+1)%num)]], (int32_t)i, first + j);
+ }
+ }
+ std::sort(edges.begin(), edges.end());
+
+ mVisPolyNeighbors.resize(numIndices);
+ bool manifold = true;
+ uint32_t i = 0;
+ while (i < edges.size()) {
+ Edge &e0 = edges[i];
+ i++;
+ if (i < edges.size() && edges[i] == e0) {
+ Edge &e1 = edges[i];
+ mVisPolyNeighbors[(uint32_t)e0.edgeNr] = e1.faceNr;
+ mVisPolyNeighbors[(uint32_t)e1.edgeNr] = e0.faceNr;
+ i++;
+ }
+ while (i < edges.size() && edges[i] == e0) {
+ manifold = false;
+ i++;
+ }
+ }
+ return manifold;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::setExplicitVisMeshFromTriangles(int numVertices, const PxVec3 *vertices, const PxVec3 *normals, const PxVec2 *texcoords,
+ int numIndices, const uint32_t *indices, PxTransform *trans, const PxVec3* scale)
+{
+ mHasExplicitVisMesh = true;
+
+ // reduce to vertices referenced by indices
+ // needed if submesh is provided
+ nvidia::Array<int> oldToNew((uint32_t)numVertices, -1);
+ mVisVertices.clear();
+ mVisNormals.clear();
+ mVisTangents.clear();
+ mVisTexCoords.clear();
+
+ const float scaleMagn = scale ? scale->magnitude() : 1.f;
+
+ for (int i = 0; i < numIndices; i++) {
+ uint32_t id = (uint32_t)indices[(uint32_t)i];
+ if (oldToNew[id] < 0) {
+ oldToNew[id] = (int32_t)mVisVertices.size();
+
+ PxVec3 p = vertices[id];
+ PxVec3 n = normals[id];
+ if (scale != NULL)
+ {
+ p.x = scale->x*p.x;
+ p.y = scale->y*p.y;
+ p.z = scale->z*p.z;
+ n.x = scale->x*n.x/scaleMagn;
+ n.y = scale->y*n.y/scaleMagn;
+ n.z = scale->z*n.z/scaleMagn;
+ }
+ if (trans != NULL) {
+ p = trans->transform(p);
+ n = trans->rotate(n);
+ }
+ mVisVertices.pushBack(p);
+ mVisNormals.pushBack(n);
+ mVisTangents.pushBack(PxVec3(0.0f, 0.0f, 0.0f)); // on surface, no bump map
+ mVisTexCoords.pushBack(texcoords[id].x); // to do, get as input
+ mVisTexCoords.pushBack(texcoords[id].y);
+ }
+ }
+
+ uint32_t numTris = (uint32_t)numIndices / 3;
+ mVisPolyStarts.resize(numTris+1);
+ for (uint32_t i = 0; i < numTris+1; i++)
+ mVisPolyStarts[i] = 3*(int32_t)i;
+
+ mVisPolyIndices.resize((uint32_t)numIndices);
+ for (uint32_t i = 0; i < (uint32_t)numIndices; i++)
+ mVisPolyIndices[i] = oldToNew[(uint32_t)indices[i]];
+
+ mVisTriIndices.clear();
+
+ bool manifold = computeVisMeshNeighbors();
+ createVisTrisFromPolys();
+ computeVisTangentsFromPoly();
+
+ return manifold;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::setExplicitVisMeshFromPolygons(int numVertices, const PxVec3 *vertices, const PxVec3 *normals, const PxVec3 *tangents, const float *texCoords,
+ int numPolygons, const int *polyStarts,
+ int numIndices, const int *indices, PxTransform *trans, const PxVec3* scale)
+{
+ mHasExplicitVisMesh = true;
+
+ mVisVertices.resize((uint32_t)numVertices);
+ mVisNormals.resize((uint32_t)numVertices);
+ mVisTangents.resize((uint32_t)numVertices);
+ mVisTexCoords.resize(2*(uint32_t)numVertices);
+
+ const float scaleMagn = scale ? scale->magnitude() : 1.f;
+
+ for (uint32_t i = 0; i < (uint32_t)numVertices; i++) {
+ if (trans != NULL) {
+ mVisVertices[i] = trans->transform(vertices[i]);
+ mVisNormals[i] = trans->rotate(normals[i]);
+ if (tangents != NULL)
+ mVisTangents[i] = trans->rotate(tangents[i]);
+ else
+ mVisTangents[i] = PxVec3(0.0f, 0.0f, 0.0f);
+ }
+ else {
+ mVisVertices[i] = vertices[i];
+ mVisNormals[i] = normals[i];
+ if (tangents != NULL)
+ mVisTangents[i] = tangents[i];
+ else
+ mVisTangents[i] = PxVec3(0.0f, 0.0f, 0.0f);
+ }
+ if (texCoords != NULL) {
+ mVisTexCoords[2*i] = texCoords[2*i];
+ mVisTexCoords[2*i+1] = texCoords[2*i+1];
+ }
+ if (scale != NULL)
+ {
+ mVisVertices[i].x *= scale->x;
+ mVisVertices[i].y *= scale->y;
+ mVisVertices[i].z *= scale->z;
+ mVisNormals[i].x *= scale->x/scaleMagn;
+ mVisNormals[i].y *= scale->y/scaleMagn;
+ mVisNormals[i].z *= scale->z/scaleMagn;
+ }
+ }
+
+ mVisPolyStarts.resize((uint32_t)numPolygons+1);
+ for (uint32_t i = 0; i < (uint32_t)numPolygons+1; i++)
+ mVisPolyStarts[i] = polyStarts[i];
+
+ mVisPolyIndices.resize((uint32_t)numIndices);
+ for (uint32_t i = 0; i < (uint32_t)numIndices; i++)
+ mVisPolyIndices[i] = indices[i];
+
+ bool manifold = computeVisMeshNeighbors();
+ createVisTrisFromPolys();
+ computeVisTangentsFromPoly();
+
+ return manifold;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::computeVisTangentsFromPoly() {
+ // Must be called after createVisTrisFromPolys
+ //Adapt from Lengyel, Eric. "Computing Tangent Space Basis Vectors for an Arbitrary Mesh". Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
+
+ uint32_t numTris = mVisTriIndices.size() / 3;
+ int* tris = &mVisTriIndices[0];
+ uint32_t numV = mVisVertices.size();
+
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ uint32_t i0 = (uint32_t)tris[0];
+ uint32_t i1 = (uint32_t)tris[1];
+ uint32_t i2 = (uint32_t)tris[2];
+
+ PxVec3& v0 = mVisVertices[i0];
+ PxVec3& v1 = mVisVertices[i1];
+ PxVec3& v2 = mVisVertices[i2];
+
+
+ float* tex0 = &mVisTexCoords[2*i0];
+ float* tex1 = &mVisTexCoords[2*i1];
+ float* tex2 = &mVisTexCoords[2*i2];
+
+ float x0 = v1.x - v0.x;
+ float x1 = v2.x - v0.x;
+ float y0 = v1.y - v0.y;
+ float y1 = v2.y - v0.y;
+ float z1 = v1.z - v0.z;
+ float z2 = v2.z - v0.z;
+
+ float s0 = tex1[0] - tex0[0];
+ float s1 = tex2[0] - tex0[0];
+ float t0 = tex1[1] - tex0[1];
+ float t1 = tex2[1] - tex0[1];
+
+ float idet = 1.0f / (s0*t1 - s1*t0);
+ PxVec3 t = idet*PxVec3(t1*x0 - t0*x1,t1*y0 - t0*y1,t1*z1 - t0*z2);
+ //PxVec3 b = idet*PxVec3(s0*x1 - s1*x0,s0*y1 - s1*y0,s0*z2 - s1*z1);
+
+/* if ( (i0 == 0) || (i1 == 0) || (i2 == 0) ) {
+ cout<<t[0]<<" "<<t[1]<<" "<<t[2]<<endl;
+ ok= true;
+ }*/
+ mVisTangents[i0] += t;
+ mVisTangents[i1] += t;
+ mVisTangents[i2] += t;
+
+ tris+=3;
+ }
+ //cout<<"OK = "<<ok<<endl;
+
+ for (uint32_t i = 0; i < numV; i++)
+ {
+ PxVec3& n = mVisNormals[i];
+ PxVec3& t = mVisTangents[i];
+
+
+ // Gram-Schmidt orthogonalize
+ t = (t - n * n.dot(t));
+ t.normalize();
+
+ if (!t.isFinite()) t = PxVec3(0.0f, 0.0f, 0.0f);
+
+ mVisTexCoords[2*i] += 5.0f;
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::createVisTrisFromPolys()
+{
+ mVisTriIndices.clear();
+ for (uint32_t i = 0; i < mVisPolyStarts.size()-1; i++) {
+ uint32_t first = (uint32_t)mVisPolyStarts[i];
+ uint32_t num = (uint32_t)mVisPolyStarts[i+1] - first;
+ if (num == 3) {
+ mVisTriIndices.pushBack(mVisPolyIndices[first]);
+ mVisTriIndices.pushBack(mVisPolyIndices[first+1]);
+ mVisTriIndices.pushBack(mVisPolyIndices[first+2]);
+ continue;
+ }
+ PolygonTriangulator *pt = mScene->getPolygonTriangulator(); //PolygonTriangulator::getInstance();
+ pt->triangulate(&mVisVertices[0], (int32_t)num, &mVisPolyIndices[first]);
+ const nvidia::Array<int> indices = pt->getIndices();
+
+ uint32_t numIds = mVisTriIndices.size();
+ mVisTriIndices.resize(numIds + indices.size());
+ for (uint32_t j = 0; j < indices.size(); j++)
+ mVisTriIndices[numIds+j] = indices[j];
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::transformVisualMesh(const PxTransform &trans)
+{
+ for (uint32_t i = 0; i < mVisVertices.size(); i++)
+ mVisVertices[i] = trans.transform(mVisVertices[i]);
+ for (uint32_t i = 0; i < mVisNormals.size(); i++)
+ mVisNormals[i] = trans.rotate(mVisNormals[i]);
+ for (uint32_t i = 0; i < mVisTangents.size(); i++)
+ mVisTangents[i] = trans.rotate(mVisTangents[i]);
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::insideVisualMesh(const PxVec3 &pos) const
+{
+ int num[6] = {0,0,0,0,0,0};
+ const uint32_t numAxes = 2; // max 3: the nigher the more robust but slower
+
+ for (uint32_t i = 0; i < mVisTriIndices.size(); i += 3) {
+ const PxVec3 &p0 = mVisVertices[(uint32_t)mVisTriIndices[i]];
+ const PxVec3 &p1 = mVisVertices[(uint32_t)mVisTriIndices[i+1]];
+ const PxVec3 &p2 = mVisVertices[(uint32_t)mVisTriIndices[i+2]];
+ PxVec3 n = (p1-p0).cross(p2-p0);
+ float d = n.dot(p0);
+ float ds = d - pos.dot(n);
+
+ // for all axes, cound the hits of the ray starting from pos with the mesh
+ for (uint32_t j = 0; j < numAxes; j++) {
+ if (n[j] == 0.0f)
+ continue;
+
+ uint32_t j0 = (j+1)%3;
+ uint32_t j1 = (j+2)%3;
+ float x0 = p0[j0];
+ float y0 = p0[j1];
+ float x1 = p1[j0];
+ float y1 = p1[j1];
+ float x2 = p2[j0];
+ float y2 = p2[j1];
+
+ float px = pos[j0];
+ float py = pos[j1];
+
+ // inside triangle?
+ float d0 = (x1-x0) * (py-y0) - (y1-y0) * (px-x0);
+ float d1 = (x2-x1) * (py-y1) - (y2-y1) * (px-x1);
+ float d2 = (x0-x2) * (py-y2) - (y0-y2) * (px-x2);
+ bool inside =
+ (d0 <= 0.0f && d1 <= 0.0f && d2 <= 0.0f) ||
+ (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f);
+ if (!inside)
+ continue;
+
+ float s = ds / n[j];
+ if (s > 0.0f)
+ num[2*j] += (n[j] > 0.0f) ? +1 : -1;
+ else
+ num[2*j+1] += (n[j] < 0.0f) ? +1 : -1;
+ }
+ }
+ uint32_t numVotes = 0;
+ for (uint32_t i = 0; i < 6; i++) {
+ if (num[i] > 0)
+ numVotes++;
+ }
+ return numVotes > numAxes;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::clipVisualMesh(MeshClipper *clipper, const PxTransform &trans, nvidia::Array<Convex*> &newConvexes)
+{
+ bool empty, completelyInside;
+ newConvexes.clear();
+
+ clipper->clip(this, trans, mTexScale, true, empty, completelyInside);
+
+ if (completelyInside) {
+ mHasExplicitVisMesh = false;
+ return true;
+ }
+
+ if (empty)
+ return false;
+
+ const MeshClipper::Mesh &mesh = clipper->getMesh(0);
+
+ mVisVertices = mesh.vertices;
+ mVisNormals = mesh.normals;
+ mVisTangents = mesh.tangents;
+ mVisTexCoords = mesh.texCoords;
+ mVisPolyStarts = mesh.polyStarts;
+ mVisPolyIndices = mesh.polyIndices;
+ mVisPolyNeighbors = mesh.polyNeighbors;
+ mHasExplicitVisMesh = true;
+
+ createVisTrisFromPolys();
+
+ finalize();
+
+ int numMeshes = clipper->getNumMeshes();
+ if (numMeshes > 1) {
+ newConvexes.resize((uint32_t)numMeshes-1);
+ for (int i = 1; i < numMeshes; i++) {
+ const MeshClipper::Mesh &mesh = clipper->getMesh(i);
+ Convex *c = mScene->createConvex();
+ newConvexes[(uint32_t)i-1] = c;
+ c->createFromConvex(this);
+ c->mVisVertices = mesh.vertices;
+ c->mVisNormals = mesh.normals;
+ c->mVisTangents = mesh.tangents;
+ c->mVisTexCoords = mesh.texCoords;
+ c->mVisPolyStarts = mesh.polyStarts;
+ c->mVisPolyIndices = mesh.polyIndices;
+ c->mVisPolyNeighbors = mesh.polyNeighbors;
+ c->mHasExplicitVisMesh = true;
+ c->createVisTrisFromPolys();
+ c->finalize();
+ }
+ }
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::fitToVisualMesh(bool &cutEmpty, int numFitDirections)
+{
+ cutEmpty = false;
+ if (!mHasExplicitVisMesh)
+ return;
+
+ static const int numNormals = 3 + 4;
+ static const float normals[numNormals][3] = {
+ {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}
+ // avoid singular cases
+ // {1.0f, 1.1f, 1.2f}, {-1.3f, 1.2f, 1.0f}, {1.0f, -1.2f, 1.0f}, {1.2f, 1.3f, -1.0f}
+ };
+
+ cutEmpty = false;
+ const float eps = 1e-3f;
+
+ int num = numFitDirections;
+ if (num > numNormals)
+ num = numNormals;
+
+ for (int i = 0; i < num; i++) {
+ PxVec3 n(normals[i][0], normals[i][1], normals[i][2]);
+ n.normalize();
+ float minVD = PX_MAX_F32;
+ float maxVD = -PX_MAX_F32;
+ float minCD = PX_MAX_F32;
+ float maxCD = -PX_MAX_F32;
+ for (uint32_t j = 0; j < mVisVertices.size(); j++) {
+ float d = mVisVertices[j].dot(n);
+ if (d < minVD) minVD = d;
+ if (d > maxVD) maxVD = d;
+ }
+ for (uint32_t j = 0; j < mVertices.size(); j++) {
+ float d = mVertices[j].dot(n);
+ if (d < minCD) minCD = d;
+ if (d > maxCD) maxCD = d;
+ }
+ if (maxVD < maxCD - eps) {
+ cut(n, maxVD, cutEmpty, false);
+ if (cutEmpty)
+ return;
+ }
+ if (minVD > minCD + eps) {
+ cut(-n, -minVD - eps, cutEmpty, false);
+ if (cutEmpty)
+ return;
+ }
+ }
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+float Convex::getVolume() const
+{
+ if (!mVolumeDirty)
+ return mVolume;
+
+ mVolume = 0.0f;
+ for (uint32_t i = 0; i < mFaces.size(); i++) {
+ const Face &f = mFaces[i];
+ if (f.numIndices < 3)
+ continue;
+ const int *ids = &mIndices[(uint32_t)f.firstIndex];
+ const PxVec3 &p0 = mVertices[(uint32_t)ids[0]];
+ for (int j = 1; j < f.numIndices-1; j++) {
+ const PxVec3 &p1 = mVertices[(uint32_t)ids[(uint32_t)j]];
+ const PxVec3 &p2 = mVertices[(uint32_t)ids[(uint32_t)j+1]];
+ mVolume += p0.cross(p1).dot(p2);
+ }
+ }
+ mVolume *= (1.0f / 6.0f);
+ mVolumeDirty = false;
+ return mVolume;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::removeInvisibleFacesFlags()
+{
+ for (uint32_t i = 0; i < mFaces.size(); i++)
+ mFaces[i].flags &= ~CompoundGeometry::FF_INVISIBLE;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::updateFaceVisibility(const float *faceCoverage)
+{
+ for (uint32_t i = 0; i < mFaces.size(); i++) {
+ if (faceCoverage[i] > 0.95f)
+ mFaces[i].flags |= CompoundGeometry::FF_INVISIBLE;
+ else
+ mFaces[i].flags &= ~CompoundGeometry::FF_INVISIBLE;
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::clearFraceFlags(unsigned int flag)
+{
+ for (uint32_t i = 0; i < mFaces.size(); i++)
+ mFaces[i].flags &= ~flag;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::insideFattened(const PxVec3 &pos, float r) const
+{
+ // early out with bounding box
+ if (pos.x < mBounds.minimum.x - r || pos.x > mBounds.maximum.x + r)
+ return false;
+ if (pos.y < mBounds.minimum.y - r || pos.y > mBounds.maximum.y + r)
+ return false;
+ if (pos.z < mBounds.minimum.z - r || pos.z > mBounds.maximum.z + r)
+ return false;
+
+ // planes
+ for (uint32_t i = 0; i < mPlanes.size(); i++) {
+ if (mPlanes[i].n.dot(pos) > mPlanes[i].d + r)
+ return false;
+ }
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::check() {
+ PxVec3 center = getCenter();
+
+ for (uint32_t i = 0; i < mFaces.size(); i++) {
+ Face &f = mFaces[i];
+ if (f.numIndices < 3)
+ return false;
+
+ PxVec3 &p0 = mVertices[(uint32_t)mIndices[(uint32_t)f.firstIndex]];
+ float A = 0.0f;
+ PxVec3 n(0.0, 0.0, 0.0);
+
+ for (int j = 1; j < f.numIndices-1; j++) {
+ PxVec3 &p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]];
+ PxVec3 &p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j+1)]];
+ PxVec3 nj = (p1-p0).cross(p2-p0);
+ A += nj.magnitude();
+ n += nj;
+ }
+ if (A < 1e-6)
+ return false;
+
+ float d = n.dot(p0);
+ if (n.dot(center) > d)
+ return false;
+ }
+ return true;
+}
+
+bool Convex::isOnConvexSurface(const PxVec3 pts) const {
+ const float EPSILON = 1e-6f;
+ uint32_t numF = mFaces.size();
+ for (uint32_t i = 0; i < numF; i++) {
+
+ const Face& f = mFaces[i];
+ int nv = f.numIndices;
+
+ float areaFan = 0.0f;
+ // Compute face area
+ for (int j = 1; j < nv-1; j++) {
+ const PxVec3& p0 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex)]];
+ const PxVec3& p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]];
+ const PxVec3& p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+(j+1))]];
+ areaFan += 0.5f* (((p1-p0).cross(p2-p0))).magnitude();
+ }
+ float areaP = 0.0f;
+
+ for (int j = 0; j < nv; j++) {
+
+ const PxVec3& p1 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+j)]];
+ const PxVec3& p2 = mVertices[(uint32_t)mIndices[uint32_t(f.firstIndex+(j+1) % nv)]];
+ areaP += 0.5f*(((p1-pts).cross(p2-pts))).magnitude();
+ }
+ if ((areaP - areaFan)/areaFan < EPSILON) {
+ return true;
+ }
+ }
+ return false;
+
+}
+
+}
+}
+}
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/ConvexBase.h b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.h
new file mode 100644
index 00000000..98b44af2
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/ConvexBase.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef CONVEX_BASE
+#define CONVEX_BASE
+
+#include <PxPhysics.h>
+#include <PxCooking.h>
+#include <PxVec3.h>
+#include <PxPlane.h>
+#include <PxBounds3.h>
+#include <PxTransform.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+
+namespace nvidia
+{
+
+namespace fracture
+{
+namespace base
+{
+
+class Compound;
+class CompoundGeometry;
+class MeshClipper;
+class SimScene;
+
+// ----------------------------------------------------------------------------
+class Convex : public UserAllocated
+{
+ friend class SimScene;
+protected:
+ Convex(SimScene* scene);
+public:
+ virtual ~Convex();
+
+ void createFromConvex(const Convex *convex, const PxTransform *trans = NULL);
+ void createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans = NULL);
+ //bool createFromXml(XMLParser *p, float scale, bool ignoreVisualMesh = false);
+
+ void transform(const PxMat44 &trans);
+ PxVec3 centerAtZero();
+ PxVec3 getCenter() const;
+ void setTexScale(float texScale) { mTexScale = texScale; }
+ void increaseRefCounter() { mRefCounter++; }
+ int decreaseRefCounter() { mRefCounter--; return mRefCounter; }
+
+ bool rayCast(const PxVec3 &ray, const PxVec3 &dir, float &dist, PxVec3 &normal) const;
+ bool collide(const PxVec3 &pos, float r, float &penetration, PxVec3 &surfaceNormal, PxVec3 &surfaceVel) const;
+
+ void intersectWithConvex(const PxPlane *planes, int numPlanes, const PxMat44 &trans, bool &empty);
+
+ virtual void draw(bool /*debug*/ = false) {}
+
+ PxConvexMesh* createPxConvexMesh(Compound *parent, PxPhysics *pxPhysics, PxCooking *pxCooking);
+ void setPxActor(PxRigidActor *actor);
+ void setLocalPose(const PxTransform &pose);
+
+ // accessors
+ Compound *getParent() { return mParent; }
+ const Compound *getParent() const { return mParent; }
+ const PxConvexMesh *getPxConvexMesh() const { return mPxConvexMesh; }
+ PxConvexMesh *getPxConvexMesh() { return mPxConvexMesh; }
+
+ const nvidia::Array<PxPlane> &getPlanes() const { return mPlanes; };
+ const PxBounds3 &getBounds() const { return mBounds; }
+ void getWorldBounds(PxBounds3 &bounds) const;
+ void getLocalBounds(PxBounds3 &bounds) const;
+ float getVolume() const;
+ void removeInvisibleFacesFlags();
+ void updateFaceVisibility(const float *faceCoverage);
+ void clearFraceFlags(unsigned int flag);
+
+ struct Face {
+ void init() {
+ firstIndex = 0; numIndices = 0; flags = 0; firstNormal = 0;
+ }
+ int firstIndex;
+ int numIndices;
+ int flags;
+ int firstNormal;
+
+
+ };
+
+ const nvidia::Array<Face> &getFaces() const { return mFaces; }
+ const nvidia::Array<int> &getIndices() const { return mIndices; }
+ const nvidia::Array<PxVec3> &getVertices() const { return mVertices; }
+
+ const nvidia::Array<PxVec3> &getVisVertices() const { return mVisVertices; }
+ const nvidia::Array<PxVec3> &getVisNormals() const { return mVisNormals; }
+ const nvidia::Array<PxVec3> &getVisTangents() const { return mVisTangents; }
+ const nvidia::Array<float> &getVisTexCoords() const { return mVisTexCoords; }
+ const nvidia::Array<int> &getVisTriIndices() const { return mVisTriIndices; }
+
+ const nvidia::Array<int> &getVisPolyStarts() const { return mVisPolyStarts; }
+ const nvidia::Array<int> &getVisPolyIndices() const { return mVisPolyIndices; }
+ const nvidia::Array<int> &getVisPolyNeighbors() const { return mVisPolyNeighbors; }
+
+ PxVec3 getMaterialOffset() const { return mMaterialOffset; }
+ void setMaterialOffset(const PxVec3 &offset);
+ PxTransform getGlobalPose() const;
+ PxTransform getLocalPose() const;
+
+ bool isGhostConvex() const { return mIsGhostConvex; }
+
+ // explicit visual mesh
+ bool hasExplicitVisMesh() const { return mHasExplicitVisMesh; }
+ bool setExplicitVisMeshFromTriangles(int numVertices, const PxVec3 *vertices, const PxVec3 *normals, const PxVec2 *texcoords,
+ int numIndices, const uint32_t *indices, PxTransform *trans = NULL, const PxVec3* scale = NULL);
+ bool setExplicitVisMeshFromPolygons(int numVertices, const PxVec3 *vertices, const PxVec3 *normals,
+ const PxVec3 *tangents, const float *texCoords,
+ int numPolygons, const int *polyStarts, // numPolygons+1 entries
+ int numIndices, const int *indices, PxTransform *trans = NULL, const PxVec3* scale = NULL);
+ void createVisTrisFromPolys();
+ void createVisMeshFromConvex();
+ void transformVisualMesh(const PxTransform &trans);
+ bool insideVisualMesh(const PxVec3 &pos) const;
+
+ bool clipVisualMesh(MeshClipper *clipper, const PxTransform &trans, nvidia::Array<Convex*> &newConvexes);
+ void fitToVisualMesh(bool &cutEmpty, int numFitDirections = 3);
+
+ bool isOnConvexSurface(const PxVec3 pts) const;
+ bool check();
+
+ PxActor* getActor();
+ bool insideFattened(const PxVec3 &pos, float r) const;
+
+ bool use2dTexture() const { return mUse2dTexture; }
+ bool isIndestructible() const { return mIndestructible; }
+ int getMaterialId() const { return mMaterialId; }
+ int getSurfaceMaterialId() const { return mSurfaceMaterialId; }
+ void setSurfaceMaterialId(int id) { mSurfaceMaterialId = id; }
+
+ void setModelIslandNr(int nr) { mModelIslandNr = nr; }
+ int getModelIslandNr() const { return mModelIslandNr; }
+
+ void setConvexRendererInfo(int groupNr, int groupPos) const { mConvexRendererGroupNr = groupNr; mConvexRendererGroupPos = groupPos; }
+ int getConvexRendererGroupNr() const { return mConvexRendererGroupNr; }
+ int getConvexRendererGroupPos() const { return mConvexRendererGroupPos; }
+
+ void setIsFarConvex(bool v) { mIsFarConvex = v; }
+ bool getIsFarConvex() { return mIsFarConvex; }
+
+protected:
+ void clear();
+ void finalize();
+ void updateBounds();
+ void updatePlanes();
+
+ bool computeVisMeshNeighbors();
+ void computeVisTangentsFromPoly();
+ bool cutVisMesh(const PxVec3 &localPlaneN, float localPlaneD, bool &cutEmpty);
+ bool cut(const PxVec3 &localPlaneN, float localPlaneD, bool &cutEmpty, bool setNewFaceFlag = true);
+
+ bool rayCastConvex(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const;
+ bool rayCastVisMesh(const PxVec3 &orig, const PxVec3 &dir, float &dist, PxVec3 &normal) const;
+
+ SimScene* mScene;
+
+ nvidia::Array<Face> mFaces;
+ nvidia::Array<int> mIndices;
+ nvidia::Array<PxVec3> mVertices;
+ nvidia::Array<PxVec3> mNormals;
+ nvidia::Array<PxPlane> mPlanes;
+
+ nvidia::Array<PxVec3> mVisVertices;
+ nvidia::Array<PxVec3> mVisNormals;
+ nvidia::Array<PxVec3> mVisTangents;
+ nvidia::Array<float> mVisTexCoords;
+ nvidia::Array<int> mVisTriIndices;
+
+ int mRefCounter;
+ bool mHasExplicitVisMesh;
+ bool mIsGhostConvex;
+ nvidia::Array<int> mVisPolyStarts; // for explicit mesh only
+ nvidia::Array<int> mVisPolyIndices;
+ nvidia::Array<int> mVisPolyNeighbors;
+
+ Convex *mNewConvex; // temporary buffer for cut operations
+
+ Compound *mParent;
+ PxRigidActor *mPxActor;
+ PxTransform mLocalPose;
+ PxConvexMesh *mPxConvexMesh;
+
+ PxBounds3 mBounds;
+ mutable float mVolume;
+ mutable bool mVolumeDirty;
+ PxVec3 mMaterialOffset;
+ float mTexScale;
+ int mModelIslandNr;
+
+ // material
+ bool mUse2dTexture;
+ bool mIndestructible;
+ int mMaterialId;
+ int mSurfaceMaterialId;
+
+ bool mIsFarConvex;
+
+ mutable int mConvexRendererGroupNr;
+ mutable int mConvexRendererGroupPos;
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.cpp b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.cpp
new file mode 100644
index 00000000..a4aa0f1e
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "Delaunay2dBase.h"
+#include "PxBounds3.h"
+#include <PxMath.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+// -------------------------------------------------------------------------------------
+Delaunay2d::Delaunay2d(SimScene* scene):
+ mScene(scene)
+{
+}
+
+// -------------------------------------------------------------------------------------
+Delaunay2d::~Delaunay2d()
+{
+}
+
+// -------------------------------------------------------------------------------------
+void Delaunay2d::clear()
+{
+ mVertices.clear();
+ mIndices.clear();
+ mTriangles.clear();
+ mFirstFarVertex = 0;
+
+ mConvexVerts.clear();
+ mConvexes.clear();
+ mConvexNeighbors.clear();
+}
+
+// -------------------------------------------------------------------------------------
+void Delaunay2d::triangulate(const PxVec3 *vertices, int numVerts, int byteStride, bool removeFarVertices)
+{
+ clear();
+
+ uint8_t *vp = (uint8_t*)vertices;
+ mVertices.resize((uint32_t)numVerts);
+ for (uint32_t i = 0; i < (uint32_t)numVerts; i++) {
+ mVertices[i] = (*(PxVec3*)vp);
+ mVertices[i].z = 0.0f;
+ vp += byteStride;
+ }
+
+ delaunayTriangulation();
+
+ for (uint32_t i = 0; i < mTriangles.size(); i++) {
+ Triangle &t = mTriangles[i];
+ if (!removeFarVertices || (t.p0 < mFirstFarVertex && t.p1 < mFirstFarVertex && t.p2 < mFirstFarVertex)) {
+ mIndices.pushBack(t.p0);
+ mIndices.pushBack(t.p1);
+ mIndices.pushBack(t.p2);
+ }
+ }
+
+ if (removeFarVertices)
+ mVertices.resize((uint32_t)mFirstFarVertex);
+}
+
+
+// -------------------------------------------------------------------------------------
+void Delaunay2d::delaunayTriangulation()
+{
+ PxBounds3 bounds;
+ bounds.setEmpty();
+
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ bounds.include(mVertices[i]);
+
+ bounds.fattenSafe(bounds.getDimensions().magnitude());
+
+ // start with two triangles
+ //float scale = 10.0f;
+ PxVec3 p0(bounds.minimum.x, bounds.minimum.y, 0.0f);
+ PxVec3 p1(bounds.maximum.x, bounds.minimum.y, 0.0f);
+ PxVec3 p2(bounds.maximum.x, bounds.maximum.y, 0.0f);
+ PxVec3 p3(bounds.minimum.x, bounds.maximum.y, 0.0f);
+
+ mFirstFarVertex = (int32_t)mVertices.size();
+ mVertices.pushBack(p0);
+ mVertices.pushBack(p1);
+ mVertices.pushBack(p2);
+ mVertices.pushBack(p3);
+
+ mTriangles.clear();
+ addTriangle(mFirstFarVertex, mFirstFarVertex+1, mFirstFarVertex+2);
+ addTriangle(mFirstFarVertex, mFirstFarVertex+2, mFirstFarVertex+3);
+
+ // insert other points
+ for (uint32_t i = 0; i < (uint32_t)mFirstFarVertex; i++) {
+ mEdges.clear();
+ uint32_t j = 0;
+ while (j < mTriangles.size()) {
+ Triangle &t = mTriangles[j];
+ if ((t.center - mVertices[i]).magnitudeSquared() > t.circumRadiusSquared) {
+ j++;
+ continue;
+ }
+ Edge e0(t.p0, t.p1);
+ Edge e1(t.p1, t.p2);
+ Edge e2(t.p2, t.p0);
+ bool found0 = false;
+ bool found1 = false;
+ bool found2 = false;
+
+ uint32_t k = 0;
+ while (k < mEdges.size()) {
+ Edge &e = mEdges[k];
+ bool found = false;
+ if (e == e0) { found0 = true; found = true; }
+ if (e == e1) { found1 = true; found = true; }
+ if (e == e2) { found2 = true; found = true; }
+ if (found) {
+ mEdges[k] = mEdges[mEdges.size()-1];
+ mEdges.popBack();
+ }
+ else k++;
+ }
+ if (!found0) mEdges.pushBack(e0);
+ if (!found1) mEdges.pushBack(e1);
+ if (!found2) mEdges.pushBack(e2);
+ mTriangles[j] = mTriangles[mTriangles.size()-1];
+ mTriangles.popBack();
+ }
+ for (j = 0; j < mEdges.size(); j++) {
+ Edge &e = mEdges[j];
+ addTriangle(e.p0, e.p1, (int32_t)i);
+ }
+ }
+}
+
+// -------------------------------------------------------------------------------------
+void Delaunay2d::addTriangle(int p0, int p1, int p2)
+{
+ Triangle triangle;
+ triangle.p0 = p0;
+ triangle.p1 = p1;
+ triangle.p2 = p2;
+ getCircumSphere(mVertices[(uint32_t)p0], mVertices[(uint32_t)p1], mVertices[(uint32_t)p2], triangle.center, triangle.circumRadiusSquared);
+ mTriangles.pushBack(triangle);
+}
+
+// -------------------------------------------------------------------------------------
+void Delaunay2d::getCircumSphere(const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2,
+ PxVec3 &center, float &radiusSquared)
+{
+ float x1 = p1.x - p0.x;
+ float y1 = p1.y - p0.y;
+ float x2 = p2.x - p0.x;
+ float y2 = p2.y - p0.y;
+
+ float det = x1 * y2 - x2 * y1;
+ if (det == 0.0f) {
+ center = p0; radiusSquared = 0.0f;
+ return;
+ }
+ det = 0.5f / det;
+ float len1 = x1*x1 + y1*y1;
+ float len2 = x2*x2 + y2*y2;
+ float cx = (len1 * y2 - len2 * y1) * det;
+ float cy = (len2 * x1 - len1 * x2) * det;
+ center.x = p0.x + cx;
+ center.y = p0.y + cy;
+ center.z = 0.0f;
+ radiusSquared = cx * cx + cy * cy;
+}
+
+// -------------------------------------------------------------------------------------
+void Delaunay2d::computeVoronoiMesh()
+{
+ mConvexes.clear();
+ mConvexVerts.clear();
+ mConvexNeighbors.clear();
+
+ uint32_t numVerts = mVertices.size();
+ uint32_t numTris = mIndices.size() / 3;
+
+ // center positions
+ nvidia::Array<PxVec3> centers(numTris);
+ for (uint32_t i = 0; i < numTris; i++) {
+ PxVec3 &p0 = mVertices[(uint32_t)mIndices[3*i]];
+ PxVec3 &p1 = mVertices[(uint32_t)mIndices[3*i+1]];
+ PxVec3 &p2 = mVertices[(uint32_t)mIndices[3*i+2]];
+ float r2;
+ getCircumSphere(p0,p1,p2, centers[i], r2);
+ }
+
+ // vertex -> triangles links
+ nvidia::Array<int> firstVertTri(numVerts+1, 0);
+ nvidia::Array<int> vertTris;
+
+ for (uint32_t i = 0; i < numTris; i++) {
+ firstVertTri[(uint32_t)mIndices[3*i]]++;
+ firstVertTri[(uint32_t)mIndices[3*i+1]]++;
+ firstVertTri[(uint32_t)mIndices[3*i+2]]++;
+ }
+
+ int numLinks = 0;
+ for (uint32_t i = 0; i < numVerts; i++) {
+ numLinks += firstVertTri[i];
+ firstVertTri[i] = numLinks;
+ }
+ firstVertTri[numVerts] = numLinks;
+ vertTris.resize((uint32_t)numLinks);
+
+ for (uint32_t i = 0; i < numTris; i++) {
+ uint32_t &i0 = (uint32_t&)firstVertTri[(uint32_t)mIndices[3*i]];
+ uint32_t &i1 = (uint32_t&)firstVertTri[(uint32_t)mIndices[3*i+1]];
+ uint32_t &i2 = (uint32_t&)firstVertTri[(uint32_t)mIndices[3*i+2]];
+ i0--; vertTris[i0] = (int32_t)i;
+ i1--; vertTris[i1] = (int32_t)i;
+ i2--; vertTris[i2] = (int32_t)i;
+ }
+
+ // convexes
+ Convex c;
+ nvidia::Array<int> nextVert(numVerts, -1);
+ nvidia::Array<int> vertVisited(numVerts, -1);
+ nvidia::Array<int> triOfVert(numVerts, -1);
+ nvidia::Array<int> convexOfVert(numVerts, -1);
+
+ for (uint32_t i = 0; i < numVerts; i++) {
+ int first = firstVertTri[i];
+ int last = firstVertTri[i+1];
+ int num = last - first;
+ if (num < 3)
+ continue;
+
+ int start = -1;
+
+ for (int j = first; j < last; j++) {
+ int triNr = vertTris[(uint32_t)j];
+
+ int k = 0;
+ while (k < 3 && mIndices[uint32_t(3*triNr+k)] != (int32_t)i)
+ k++;
+
+ int j0 = mIndices[uint32_t(3*triNr + (k+1)%3)];
+ int j1 = mIndices[uint32_t(3*triNr + (k+2)%3)];
+
+ if (j == first)
+ start = j0;
+
+ nextVert[(uint32_t)j0] = j1;
+ vertVisited[(uint32_t)j0] = 2*(int32_t)i;
+ triOfVert[(uint32_t)j0] = triNr;
+ }
+
+ c.firstNeighbor = (int32_t)mConvexNeighbors.size();
+ c.firstVert = (int32_t)mConvexVerts.size();
+ c.numVerts = num;
+ bool rollback = false;
+ int id = start;
+ do {
+ if (vertVisited[(uint32_t)id] != 2*(int32_t)i) {
+ rollback = true;
+ break;
+ }
+ vertVisited[(uint32_t)id] = 2*(int32_t)i+1;
+
+ mConvexVerts.pushBack(centers[(uint32_t)triOfVert[(uint32_t)id]]);
+ mConvexNeighbors.pushBack(id);
+ id = nextVert[(uint32_t)id];
+ } while (id != start);
+
+ if (rollback) {
+ mConvexVerts.resize((uint32_t)c.firstVert);
+ mConvexNeighbors.resize((uint32_t)c.firstNeighbor);
+ continue;
+ }
+
+ c.numVerts = (int32_t)mConvexVerts.size() - c.firstVert;
+ c.numNeighbors = (int32_t)mConvexNeighbors.size() - c.firstNeighbor;
+ convexOfVert[i] = (int32_t)mConvexes.size();
+ mConvexes.pushBack(c);
+ }
+
+ // compute neighbors
+ uint32_t newPos = 0;
+ for (uint32_t i = 0; i < mConvexes.size(); i++) {
+ Convex &c = mConvexes[i];
+ uint32_t pos = (uint32_t)c.firstNeighbor;
+ uint32_t num = (uint32_t)c.numNeighbors;
+ c.firstNeighbor = (int32_t)newPos;
+ c.numNeighbors = 0;
+ for (uint32_t j = 0; j < num; j++) {
+ int n = convexOfVert[(uint32_t)mConvexNeighbors[pos+j]];
+ if (n >= 0) {
+ mConvexNeighbors[newPos] = n;
+ newPos++;
+ c.numNeighbors++;
+ }
+ }
+ }
+ mConvexNeighbors.resize(newPos);
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.h b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.h
new file mode 100644
index 00000000..2d477c14
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay2dBase.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef DELAUNAY_2D_BASE_H
+#define DELAUNAY_2D_BASE_H
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+// ------------------------------------------------------------------------------
+
+struct Point;
+struct Edge;
+struct Triangle;
+class SimScene;
+
+// ------------------------------------------------------------------------------
+
+class Delaunay2d : public UserAllocated {
+ friend class SimScene;
+public:
+ // singleton pattern
+ //static Delaunay2d* getInstance();
+ //static void destroyInstance();
+
+ void triangulate(const PxVec3 *vertices, int numVerts, int byteStride, bool removeFarVertices = true);
+ const nvidia::Array<int> getIndices() const { return mIndices; }
+
+ // voronoi mesh, needs triangle mesh
+ void computeVoronoiMesh();
+
+ struct Convex {
+ int firstVert;
+ int numVerts;
+ int firstNeighbor;
+ int numNeighbors;
+ };
+
+ const nvidia::Array<Convex> getConvexes() const { return mConvexes; }
+ const nvidia::Array<PxVec3> getConvexVerts() const { return mConvexVerts; }
+ const nvidia::Array<int> getConvexNeighbors() const { return mConvexNeighbors; }
+
+protected:
+ Delaunay2d(SimScene* scene);
+ virtual ~Delaunay2d();
+
+ void clear();
+ void delaunayTriangulation();
+
+ struct Edge {
+ Edge() {}
+ Edge(int np0, int np1) { p0 = np0; p1 = np1; }
+ bool operator == (const Edge &e) {
+ return (p0 == e.p0 && p1 == e.p1) || (p0 == e.p1 && p1 == e.p0);
+ }
+ int p0, p1;
+ };
+
+ struct Triangle {
+ int p0, p1, p2;
+ PxVec3 center;
+ float circumRadiusSquared;
+ };
+
+ void addTriangle(int p0, int p1, int p2);
+ void getCircumSphere(const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2,
+ PxVec3 &center, float &radiusSquared);
+
+ SimScene* mScene;
+
+ nvidia::Array<PxVec3> mVertices;
+ nvidia::Array<int> mIndices;
+
+ nvidia::Array<Triangle> mTriangles;
+ nvidia::Array<Edge> mEdges;
+
+ nvidia::Array<Convex> mConvexes;
+ nvidia::Array<PxVec3> mConvexVerts;
+ nvidia::Array<int> mConvexNeighbors;
+
+ int mFirstFarVertex;
+};
+
+}
+}
+}
+
+// ------------------------------------------------------------------------------
+
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.cpp b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.cpp
new file mode 100644
index 00000000..4af95e65
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.cpp
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "Delaunay3dBase.h"
+#include "PsSort.h"
+#include <PxAssert.h>
+
+#include "PxBounds3.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+// side orientation points outwards
+const int Delaunay3d::Tetra::sideIndices[4][3] = {{1,2,3},{2,0,3},{0,1,3},{2,1,0}};
+
+// ------ singleton pattern -----------------------------------------------------------
+//
+//static Delaunay3d *gDelaunay3d = NULL;
+//
+//Delaunay3d* Delaunay3d::getInstance()
+//{
+// if (gDelaunay3d == NULL) {
+// gDelaunay3d = PX_NEW(Delaunay3d)();
+// }
+// return gDelaunay3d;
+//}
+//
+//void Delaunay3d::destroyInstance()
+//{
+// if (gDelaunay3d != NULL) {
+// PX_DELETE(gDelaunay3d);
+// }
+// gDelaunay3d = NULL;
+//}
+
+// -----------------------------------------------------------------------------
+void Delaunay3d::tetrahedralize(const PxVec3 *vertices, int numVerts, int byteStride, bool removeExtraVerts)
+{
+ clear();
+
+ uint8_t *vp = (uint8_t*)vertices;
+ for (int i = 0; i < numVerts; i++) {
+ mVertices.pushBack(*(PxVec3*)vp);
+ vp += byteStride;
+ }
+
+ delaunayTetrahedralization();
+
+ compressTetrahedra(removeExtraVerts);
+ if (removeExtraVerts) {
+ mVertices.resize((uint32_t)mFirstFarVertex);
+ }
+
+ for (uint32_t i = 0; i < mTetras.size(); i++) {
+ Tetra &t = mTetras[i];
+ mIndices.pushBack(t.ids[0]);
+ mIndices.pushBack(t.ids[1]);
+ mIndices.pushBack(t.ids[2]);
+ mIndices.pushBack(t.ids[3]);
+ }
+}
+
+// -----------------------------------------------------------------------------
+void Delaunay3d::clear()
+{
+ mVertices.clear();
+ mIndices.clear();
+ mTetras.clear();
+ mFirstFarVertex = 0;
+ mLastFarVertex = 0;
+
+ mGeom.clear();
+
+ mTetMarked.clear();
+ mTetMark = 0;
+}
+
+// -----------------------------------------------------------------------------
+void Delaunay3d::delaunayTetrahedralization()
+{
+ int i,j;
+
+ nvidia::Array<Edge> edges;
+ Edge edge;
+
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ bounds.include(mVertices[i]);
+
+ // start with large tetrahedron
+ mTetras.clear();
+ float a = 3.0f * bounds.getDimensions().magnitude();
+ float x = 0.5f * a;
+ float y0 = x / sqrtf(3.0f);
+ float y1 = x * sqrtf(3.0f) - y0;
+ float z0 = 0.25f * sqrtf(6.0f) * a;
+ float z1 = a * sqrtf(6.0f) / 3.0f - z0;
+
+ PxVec3 center = bounds.getCenter();
+
+ mFirstFarVertex = (int32_t)mVertices.size();
+ PxVec3 p0(-x,-y0,-z1); mVertices.pushBack(center + p0);
+ PxVec3 p1( x,-y0,-z1); mVertices.pushBack(center + p1);
+ PxVec3 p2( 0, y1,-z1); mVertices.pushBack(center + p2);
+ PxVec3 p3( 0, 0, z0); mVertices.pushBack(center + p3);
+ mLastFarVertex = (int32_t)mVertices.size()-1;
+
+ Tetra tetra;
+ tetra.init(mFirstFarVertex, mFirstFarVertex+1, mFirstFarVertex+2, mFirstFarVertex+3);
+ mTetras.pushBack(tetra);
+
+ // build Delaunay triangulation iteratively
+
+ int lastVertex = (int)mVertices.size()-4;
+ for (i = 0; i < lastVertex; i++) {
+ PxVec3 &v = mVertices[(uint32_t)i];
+
+ int tNr = findSurroundingTetra((int32_t)mTetras.size()-1, v); // fast walk
+ if (tNr < 0)
+ continue;
+ // assert(tNr >= 0);
+
+ int newTetraNr = (int32_t)mTetras.size();
+ retriangulate(tNr, i);
+ edges.clear();
+ for (j = newTetraNr; j < (int)mTetras.size(); j++) {
+ Tetra &newTet = mTetras[(uint32_t)j];
+ edge.init(newTet.ids[2], newTet.ids[3], j,1);
+ edges.pushBack(edge);
+ edge.init(newTet.ids[3], newTet.ids[1], j,2);
+ edges.pushBack(edge);
+ edge.init(newTet.ids[1], newTet.ids[2], j,3);
+ edges.pushBack(edge);
+ }
+ shdfnd::sort(edges.begin(), edges.size());
+ for (j = 0; j < (int)edges.size(); j += 2) {
+ Edge &edge0 = edges[(uint32_t)j];
+ Edge &edge1 = edges[(uint32_t)j+1];
+ PX_ASSERT(edge0 == edge1);
+ mTetras[(uint32_t)edge0.tetraNr].neighborNrs[(uint32_t)edge0.neighborNr] = edge1.tetraNr;
+ mTetras[(uint32_t)edge1.tetraNr].neighborNrs[(uint32_t)edge1.neighborNr] = edge0.tetraNr;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+int Delaunay3d::findSurroundingTetra(int startTetra, const PxVec3 &p) const
+{
+ // find the tetrahedra which contains the vertex
+ // by walking through mesh O(n ^ (1/3))
+
+ mTetMark++;
+
+ if (mTetras.size() == 0) return -1;
+ int tetNr = startTetra;
+ PX_ASSERT(!mTetras[(uint32_t)startTetra].deleted);
+
+ if (mTetMarked.size() < mTetras.size())
+ mTetMarked.resize(mTetras.size(), -1);
+
+ bool loop = false;
+
+ while (tetNr >= 0) {
+ if (mTetMarked[(uint32_t)tetNr] == mTetMark) {
+ loop = true;
+ break;
+ }
+ mTetMarked[(uint32_t)tetNr] = mTetMark;
+
+ const Tetra &tetra = mTetras[(uint32_t)tetNr];
+ const PxVec3 &p0 = mVertices[(uint32_t)tetra.ids[0]];
+ PxVec3 q = p-p0;
+ PxVec3 q0 = mVertices[(uint32_t)tetra.ids[1]] - p0;
+ PxVec3 q1 = mVertices[(uint32_t)tetra.ids[2]] - p0;
+ PxVec3 q2 = mVertices[(uint32_t)tetra.ids[3]] - p0;
+ PxMat33 m;
+ m.column0 = q0;
+ m.column1 = q1;
+ m.column2 = q2;
+ float det = m.getDeterminant();
+ m.column0 = q;
+ float x = m.getDeterminant();
+ if (x < 0.0f && tetra.neighborNrs[1] >= 0) {
+ tetNr = tetra.neighborNrs[1];
+ continue;
+ }
+ m.column0 = q0; m.column1 = q;
+ float y = m.getDeterminant();
+ if (y < 0.0f && tetra.neighborNrs[2] >= 0) {
+ tetNr = tetra.neighborNrs[2];
+ continue;
+ }
+ m.column1 = q1; m.column2 = q;
+ float z = m.getDeterminant();
+ if (z < 0.0f && tetra.neighborNrs[3] >= 0) {
+ tetNr = tetra.neighborNrs[3];
+ continue;
+ }
+ if (x + y + z > det && tetra.neighborNrs[0] >= 0) {
+ tetNr = tetra.neighborNrs[0];
+ continue;
+ }
+ return tetNr;
+ }
+ if (loop) { // search failed, brute force:
+ for (uint32_t i = 0; i < mTetras.size(); i++) {
+ const Tetra &tetra = mTetras[i];
+ if (tetra.deleted)
+ continue;
+
+ const PxVec3 &p0 = mVertices[(uint32_t)tetra.ids[0]];
+ const PxVec3 &p1 = mVertices[(uint32_t)tetra.ids[1]];
+ const PxVec3 &p2 = mVertices[(uint32_t)tetra.ids[2]];
+ const PxVec3 &p3 = mVertices[(uint32_t)tetra.ids[3]];
+
+ PxVec3 n;
+ n = (p1-p0).cross(p2-p0);
+ if (n.dot(p) < n.dot(p0)) continue;
+ n = (p2-p0).cross(p3-p0);
+ if (n.dot(p) < n.dot(p0)) continue;
+ n = (p3-p0).cross(p1-p0);
+ if (n.dot(p) < n.dot(p0)) continue;
+ n = (p3-p1).cross(p2-p1);
+ if (n.dot(p) < n.dot(p1)) continue;
+ return (int32_t)i;
+ }
+ return -1;
+ }
+ else
+ return -1;
+}
+
+// -----------------------------------------------------------------------------
+void Delaunay3d::updateCircumSphere(Tetra &tetra)
+{
+ if (!tetra.circumsphereDirty)
+ return;
+ PxVec3 p0 = mVertices[(uint32_t)tetra.ids[0]];
+ PxVec3 b = mVertices[(uint32_t)tetra.ids[1]] - p0;
+ PxVec3 c = mVertices[(uint32_t)tetra.ids[2]] - p0;
+ PxVec3 d = mVertices[(uint32_t)tetra.ids[3]] - p0;
+ float det = b.x*(c.y*d.z - c.z*d.y) - b.y*(c.x*d.z - c.z*d.x) + b.z*(c.x*d.y-c.y*d.x);
+ if (det == 0.0f) {
+ tetra.center = p0; tetra.radiusSquared = 0.0f;
+ return; // singular case
+ }
+ det *= 2.0f;
+ PxVec3 v = c.cross(d)*b.dot(b) + d.cross(b)*c.dot(c) + b.cross(c)*d.dot(d);
+ v /= det;
+ tetra.radiusSquared = v.magnitudeSquared();
+ tetra.center = p0 + v;
+ tetra.circumsphereDirty = false;
+}
+
+// -----------------------------------------------------------------------------
+bool Delaunay3d::pointInCircumSphere(Tetra &tetra, const PxVec3 &p)
+{
+ updateCircumSphere(tetra);
+ return (tetra.center - p).magnitudeSquared() < tetra.radiusSquared;
+}
+
+// -----------------------------------------------------------------------------
+void Delaunay3d::retriangulate(int tetraNr, int vertNr)
+{
+ Tetra &tetra = mTetras[(uint32_t)tetraNr];
+ if (tetra.deleted) return;
+ Tetra tNew;
+ PxVec3 &v = mVertices[(uint32_t)vertNr];
+ tetra.deleted = true;
+ for (uint32_t i = 0; i < 4; i++) {
+ int n = mTetras[(uint32_t)tetraNr].neighborNrs[i];
+ if (n >= 0 && mTetras[(uint32_t)n].deleted)
+ continue;
+ if (n >= 0 && pointInCircumSphere(mTetras[(uint32_t)n],v))
+ retriangulate(n, vertNr);
+ else {
+ Tetra &t = mTetras[(uint32_t)tetraNr];
+ tNew.init(vertNr,
+ t.ids[(uint32_t)Tetra::sideIndices[i][0]],
+ t.ids[(uint32_t)Tetra::sideIndices[i][1]],
+ t.ids[(uint32_t)Tetra::sideIndices[i][2]]
+ );
+ tNew.neighborNrs[0] = n;
+ if (n >= 0) {
+ mTetras[(uint32_t)n].neighborOf(
+ tNew.ids[1], tNew.ids[2], tNew.ids[3])
+ = (int32_t)mTetras.size();
+ }
+ mTetras.pushBack(tNew);
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+void Delaunay3d::compressTetrahedra(bool removeExtraVerts)
+{
+ nvidia::Array<int> oldToNew(mTetras.size(), -1);
+
+ uint32_t num = 0;
+ for (uint32_t i = 0; i < mTetras.size(); i++) {
+ Tetra &t = mTetras[i];
+
+ if (removeExtraVerts) {
+ if (t.ids[0] >= mFirstFarVertex ||
+ t.ids[1] >= mFirstFarVertex ||
+ t.ids[2] >= mFirstFarVertex ||
+ t.ids[3] >= mFirstFarVertex)
+ continue;
+ }
+
+ if (t.deleted)
+ continue;
+
+ oldToNew[i] = (int32_t)num;
+ mTetras[num] = t;
+ num++;
+ }
+ mTetras.resize(num);
+
+ for (uint32_t i = 0; i < num; i++) {
+ Tetra &t = mTetras[i];
+ for (uint32_t j = 0; j < 4; j++) {
+ if (t.neighborNrs[j] >= 0)
+ t.neighborNrs[j] = oldToNew[(uint32_t)t.neighborNrs[j]];
+ }
+ }
+}
+
+// ----------------------------------------------------------------------
+void Delaunay3d::computeVoronoiMesh()
+{
+ mGeom.clear();
+
+ if (mTetras.empty())
+ return;
+
+ // vertex -> tetras links
+ uint32_t numVerts = mVertices.size();
+
+ nvidia::Array<int> firstVertTet(numVerts+1, 0);
+ nvidia::Array<int> vertTets;
+
+ nvidia::Array<int> tetMarks(mTetras.size(), -1);
+ int tetMark = 0;
+
+ for (uint32_t i = 0; i < mTetras.size(); i++) {
+ Tetra &t = mTetras[i];
+ firstVertTet[(uint32_t)t.ids[0]]++;
+ firstVertTet[(uint32_t)t.ids[1]]++;
+ firstVertTet[(uint32_t)t.ids[2]]++;
+ firstVertTet[(uint32_t)t.ids[3]]++;
+ }
+
+ int numLinks = 0;
+ for (uint32_t i = 0; i < numVerts; i++) {
+ numLinks += firstVertTet[i];
+ firstVertTet[i] = numLinks;
+ }
+ firstVertTet[numVerts] = numLinks;
+ vertTets.resize((uint32_t)numLinks);
+
+ for (uint32_t i = 0; i < mTetras.size(); i++) {
+ Tetra &t = mTetras[i];
+ uint32_t &i0 = (uint32_t&)firstVertTet[(uint32_t)t.ids[0]];
+ uint32_t &i1 = (uint32_t&)firstVertTet[(uint32_t)t.ids[1]];
+ uint32_t &i2 = (uint32_t&)firstVertTet[(uint32_t)t.ids[2]];
+ uint32_t &i3 = (uint32_t&)firstVertTet[(uint32_t)t.ids[3]];
+ i0--; vertTets[i0] = (int32_t)i;
+ i1--; vertTets[i1] = (int32_t)i;
+ i2--; vertTets[i2] = (int32_t)i;
+ i3--; vertTets[i3] = (int32_t)i;
+ }
+
+ nvidia::Array<int> convexOfFace(numVerts, -1);
+ nvidia::Array<int> vertOfTet(mTetras.size(), -1);
+ nvidia::Array<int> convexOfVert(numVerts, -1);
+
+ for (uint32_t i = 0; i < numVerts; i++) {
+ int i0 = (int32_t)i;
+
+ int firstTet = firstVertTet[i];
+ int lastTet = firstVertTet[i+1];
+
+ // debug
+ //bool ok = true;
+ //for (int j = firstTet; j < lastTet; j++) {
+ // int tetNr = vertTets[j];
+ // Tetra &t = mTetras[tetNr];
+ // int num = 0;
+ // for (int k = 0; k < 4; k++) {
+ // int n = t.neighborNrs[k];
+ // bool in = false;
+ // for (int l = firstTet; l < lastTet; l++) {
+ // if (vertTets[l] == n)
+ // in = true;
+ // }
+ // if (in)
+ // num++;
+ // }
+ // if (num != 3)
+ // ok = false;
+ //}
+ //if (ok)
+ // int foo = 0;
+
+
+ // new convex
+ int convexNr = (int32_t)i;
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+ c.numVerts = lastTet - firstTet;
+
+ bool rollBack = false;
+
+ // create vertices
+ for (int j = firstTet; j < lastTet; j++) {
+ int tetNr = vertTets[(uint32_t)j];
+ vertOfTet[(uint32_t)tetNr] = j - firstTet;
+ updateCircumSphere(mTetras[(uint32_t)tetNr]);
+ mGeom.vertices.pushBack(mTetras[(uint32_t)tetNr].center);
+ }
+
+ // create indices
+ for (int j = firstTet; j < lastTet; j++) {
+ int tetNr = vertTets[(uint32_t)j];
+ Tetra &t = mTetras[(uint32_t)tetNr];
+
+ for (uint32_t k = 0; k < 4; k++) {
+ int i1 = t.ids[k];
+ if (i1 == i0)
+ continue;
+ if (convexOfFace[(uint32_t)i1] == convexNr)
+ continue;
+ convexOfFace[(uint32_t)i1] = convexNr;
+ mGeom.neighbors.pushBack(i1);
+ c.numNeighbors++;
+
+ // new face
+ c.numFaces++;
+ int faceStart = (int32_t)mGeom.indices.size();
+ mGeom.indices.pushBack(0);
+ mGeom.indices.pushBack(0); // face attrib
+
+ int faceSize = 0;
+ int currNr = tetNr;
+ int prevNr = -1;
+ tetMark++;
+
+ do {
+ mGeom.indices.pushBack(vertOfTet[(uint32_t)currNr]);
+ faceSize++;
+
+ if (tetMarks[(uint32_t)currNr] == tetMark) { // safety
+ rollBack = true;
+ break;
+ }
+ tetMarks[(uint32_t)currNr] = tetMark;
+
+ // find proper neighbor tet
+ int nextTet = -1;
+ for (uint32_t l = 0; l < 4; l++) {
+ int nr = mTetras[(uint32_t)currNr].neighborNrs[l];
+ if (nr < 0)
+ continue;
+ if (nr == prevNr)
+ continue;
+
+ Tetra &tn = mTetras[(uint32_t)nr];
+ bool hasEdge =
+ (tn.ids[0] == i0 || tn.ids[1] == i0 || tn.ids[2] == i0 || tn.ids[3] == i0) &&
+ (tn.ids[0] == i1 || tn.ids[1] == i1 || tn.ids[2] == i1 || tn.ids[3] == i1);
+ if (!hasEdge)
+ continue;
+
+ //if (prevNr < 0) { // correct winding
+ // if ((t.center - faceC).cross(tn.center - faceC).dot(faceN) < 0.0f)
+ // continue;
+ //}
+ nextTet = nr;
+ break;
+ }
+
+ if (nextTet < 0) { // not proper convex, roll back
+ rollBack = true;
+ break;
+ }
+
+ prevNr = currNr;
+ currNr = nextTet;
+
+ } while (currNr != tetNr);
+
+ if (rollBack)
+ break;
+
+ mGeom.indices[(uint32_t)faceStart] = faceSize;
+ }
+ if (rollBack)
+ break;
+ }
+ if (rollBack) {
+ mGeom.indices.resize((uint32_t)c.firstIndex);
+ mGeom.vertices.resize((uint32_t)c.firstVert);
+ }
+ else {
+ convexOfVert[(uint32_t)i] = (int32_t)mGeom.convexes.size();
+ mGeom.convexes.pushBack(c);
+ }
+ }
+
+ // fix face orientations
+ for (uint32_t i = 0; i < mGeom.convexes.size(); i++) {
+ CompoundGeometry::Convex &c = mGeom.convexes[i];
+ int *ids = &mGeom.indices[(uint32_t)c.firstIndex];
+ PxVec3 *vertices = &mGeom.vertices[(uint32_t)c.firstVert];
+ PxVec3 cc(0.0f, 0.0f, 0.0f);
+ for (uint32_t j = 0; j < (uint32_t)c.numVerts; j++)
+ cc += vertices[j];
+ cc /= (float)c.numVerts;
+
+ uint32_t *faceIds = (uint32_t*)ids;
+ for (int j = 0; j < c.numFaces; j++) {
+ uint32_t faceSize = *faceIds++;
+ faceIds++; //int faceAttr = *faceIds++;
+ PxVec3 fc(0.0f, 0.0f, 0.0f);
+ for (uint32_t k = 0; k < faceSize; k++)
+ fc += vertices[faceIds[k]];
+ fc /= (float)faceSize;
+ PxVec3 n = fc - cc;
+ if ((vertices[faceIds[1]] - vertices[faceIds[0]]).cross(vertices[faceIds[2]] - vertices[faceIds[0]]).dot(n) < 0.0f) {
+ for (uint32_t k = 0; k < faceSize/2; k++) {
+ uint32_t d = faceIds[k]; faceIds[k] = faceIds[faceSize-1-k]; faceIds[faceSize-1-k] = d;
+ }
+ }
+ faceIds += faceSize;
+ }
+ }
+
+ // fix neighbors
+ for (uint32_t i = 0; i < mGeom.neighbors.size(); i++) {
+ if (mGeom.neighbors[i] >= 0)
+ mGeom.neighbors[i] = convexOfVert[(uint32_t)mGeom.neighbors[i]];
+ }
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.h b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.h
new file mode 100644
index 00000000..9ffaaa3a
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/Delaunay3dBase.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef DELAUNAY_3D_BASE_H
+#define DELAUNAY_3D_BASE_H
+
+// Matthias Muller-Fischer
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+using namespace nvidia;
+
+#include "CompoundGeometryBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+ class SimScene;
+
+// ---------------------------------------------------------------------------------------
+class Delaunay3d : public UserAllocated {
+ friend class SimScene;
+public:
+ // singleton pattern
+ //static Delaunay3d* getInstance();
+ //static void destroyInstance();
+
+ // tetra mesh
+ void tetrahedralize(const PxVec3 *vertices, int numVerts, int byteStride, bool removeExtraVerts = true);
+ const nvidia::Array<int> getTetras() const { return mIndices; }
+
+ // voronoi mesh, needs tetra mesh
+ void computeVoronoiMesh();
+
+ const CompoundGeometry &getGeometry() { return mGeom; }
+
+protected:
+ Delaunay3d(SimScene* scene): mScene(scene) {}
+ virtual ~Delaunay3d() {}
+
+ // ------------------------------------------------------
+ struct Edge
+ {
+ void init(int i0, int i1, int tetraNr, int neighborNr = -1) {
+ this->tetraNr = tetraNr;
+ this->neighborNr = neighborNr;
+ if (i0 > i1) { this->i0 = i0; this->i1 = i1; }
+ else { this->i0 = i1; this->i1 = i0; }
+ }
+ bool operator <(const Edge &e) const {
+ if (i0 < e.i0) return true;
+ if (i0 > e.i0) return false;
+ if (i1 < e.i1) return true;
+ if (i1 > e.i1) return false;
+ return (neighborNr < e.neighborNr);
+ }
+ bool operator ==(Edge &e) const {
+ return i0 == e.i0 && i1 == e.i1;
+ }
+ int i0, i1;
+ int tetraNr;
+ int neighborNr;
+ };
+
+ // ------------------------------------------------------
+ struct Tetra
+ {
+ void init(int i0, int i1, int i2, int i3) {
+ ids[0] = i0; ids[1] = i1; ids[2] = i2; ids[3] = i3;
+ neighborNrs[0] = neighborNrs[1] = neighborNrs[2] = neighborNrs[3] = -1;
+ circumsphereDirty = true;
+ center = PxVec3(0.0f, 0.0f, 0.0f);
+ radiusSquared = 0.0f;
+ deleted = false;
+ }
+ inline int& neighborOf(int i0, int i1, int i2) {
+ if (ids[0] != i0 && ids[0] != i1 && ids[0] != i2) return neighborNrs[0];
+ if (ids[1] != i0 && ids[1] != i1 && ids[1] != i2) return neighborNrs[1];
+ if (ids[2] != i0 && ids[2] != i1 && ids[2] != i2) return neighborNrs[2];
+ if (ids[3] != i0 && ids[3] != i1 && ids[3] != i2) return neighborNrs[3];
+ return neighborNrs[0];
+ }
+
+ int ids[4];
+ int neighborNrs[4];
+ bool circumsphereDirty;
+ PxVec3 center;
+ float radiusSquared;
+ bool deleted;
+
+ static const int sideIndices[4][3];
+ };
+
+ // ------------------------------------------------------
+ void clear();
+ void delaunayTetrahedralization();
+
+ int findSurroundingTetra(int startTetra, const PxVec3 &p) const;
+ void updateCircumSphere(Tetra &tetra);
+ bool pointInCircumSphere(Tetra &tetra, const PxVec3 &p);
+ void retriangulate(int tetraNr, int vertNr);
+ void compressTetrahedra(bool removeExtraVerts);
+
+ SimScene* mScene;
+
+ int mFirstFarVertex;
+ int mLastFarVertex;
+ nvidia::Array<PxVec3> mVertices;
+ nvidia::Array<Tetra> mTetras;
+ nvidia::Array<int> mIndices;
+
+ CompoundGeometry mGeom;
+
+ mutable nvidia::Array<int> mTetMarked;
+ mutable int mTetMark;
+
+};
+
+}
+}
+}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.cpp b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.cpp
new file mode 100644
index 00000000..f4a87b27
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.cpp
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "PxMath.h"
+#include "PxMat44.h"
+#include "PsMathUtils.h"
+
+#include "FracturePatternBase.h"
+#include "ConvexBase.h"
+#include "CompoundBase.h"
+#include "MeshClipperBase.h"
+#include "IslandDetectorBase.h"
+#include "SimSceneBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+#define HIDE_INVISIBLE_FACES 1
+
+// --------------------------------------------------------------------------------------------
+FracturePattern::FracturePattern(SimScene* scene):
+ mScene(scene)
+{
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::clear()
+{
+ mGeom.clear();
+ mFirstConvexOfCell.clear();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::finalize()
+{
+ mFirstPiece.resize(mGeom.convexes.size(), -1);
+ mSplitPiece.resize(mGeom.convexes.size(), false);
+ mPieces.clear();
+
+ // compute volumes of convexes
+ mConvexVolumes.resize(mGeom.convexes.size(), 0.0f);
+ Convex* c = mScene->createConvex();
+ for (uint32_t i = 0; i < mGeom.convexes.size(); i++) {
+ c->createFromGeometry(mGeom, (int32_t)i);
+ mConvexVolumes[i] = c->getVolume();
+ }
+ mGeom.derivePlanes();
+ PX_DELETE(c);
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::create3dVoronoi(const PxVec3 &dims, int numCells, float biasExp, float maxDist)
+{
+ using namespace physx::shdfnd;
+ clear();
+ nvidia::Array<PxVec3> points((uint32_t)numCells);
+ float r = PxPow(dims.magnitude(), 1.0f/biasExp);
+ float max2 = maxDist * maxDist;
+
+ mBounds.minimum = -dims;
+ mBounds.maximum = dims;
+
+ for (int i = 0; i < numCells; i++) {
+ PxVec3 &p = points[(uint32_t)i];
+ do {
+ p = PxVec3(rand(-r,r), rand(-r,r), rand(-r,r));
+ float len = p.normalize();
+ p *= PxPow(len, biasExp);
+ } while (!mBounds.contains(p) || (maxDist < PX_MAX_F32 && p.magnitudeSquared() > max2));
+ }
+ // avoid numerical problems with flat quads!
+ float eps = 0.001f * mBounds.getDimensions().magnitude();
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+
+ Delaunay3d *d = mScene->getDelaunay3d();
+ d->tetrahedralize(&points[0], (int32_t)points.size(), sizeof(PxVec3), true);
+ d->computeVoronoiMesh();
+ mGeom = d->getGeometry();
+
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::createLocal3dVoronoi(const PxVec3 &dims, int numCells, float radius)
+{
+ using namespace physx::shdfnd;
+
+ clear();
+ nvidia::Array<PxVec3> points((uint32_t)numCells);
+ float r = radius;
+ float r2 = r*r;
+
+ mBounds.minimum = -dims;
+ mBounds.maximum = dims;
+
+ for (int i = 0; i < numCells; i++) {
+ PxVec3 &p = points[(uint32_t)i];
+ do {
+ p = PxVec3(rand(-r,r), rand(-r,r), rand(-r,r));
+ } while (!mBounds.contains(p) || p.magnitudeSquared() > r2);
+ }
+ // avoid numerical problems with flat quads!
+ float eps = 0.001f * mBounds.getDimensions().magnitude();
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), -dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), -dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3( dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+ points.pushBack(PxVec3(-dims.x + rand(-eps, eps), dims.y + rand(-eps, eps), dims.z + rand(-eps, eps)));
+
+ Delaunay3d *d = mScene->getDelaunay3d();
+ d->tetrahedralize(&points[0], (int32_t)points.size(), sizeof(PxVec3), true);
+ d->computeVoronoiMesh();
+ mGeom = d->getGeometry();
+
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::createRegular3dVoronoi(const PxVec3 &dims, float pieceSize, float relRandOffset)
+{
+ clear();
+ mBounds.minimum= -dims;
+ mBounds.maximum= dims;
+ nvidia::Array<PxVec3> points;
+
+ float rel = relRandOffset;
+ if (rel < 1e-4f)
+ rel = 1e-4f; // avoid singular cases
+
+ float off = rel * pieceSize;
+
+ int numX = (int)(2.0f*dims.x / pieceSize) + 1;
+ int numY = (int)(2.0f*dims.y / pieceSize) + 1;
+ int numZ = (int)(2.0f*dims.z / pieceSize) + 1;
+
+ for (int xi = 0; xi < numX; xi++) {
+ for (int yi = 0; yi < numY; yi++) {
+ for (int zi = 0; zi < numZ; zi++) {
+ points.pushBack(PxVec3(
+ mBounds.minimum.x + xi * pieceSize + physx::shdfnd::rand(-off, off),
+ mBounds.minimum.y + yi * pieceSize + physx::shdfnd::rand(-off, off),
+ mBounds.minimum.z + zi * pieceSize + physx::shdfnd::rand(-off, off)));
+ }
+ }
+ }
+
+ Delaunay3d *d = mScene->getDelaunay3d();
+ d->tetrahedralize(&points[0], (int32_t)points.size(), sizeof(PxVec3), true);
+ d->computeVoronoiMesh();
+ mGeom = d->getGeometry();
+
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::addBox(const PxBounds3 &bounds)
+{
+ static int boxFaces[6][4] = {{0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7}, {0,3,2,1}, {4,5,6,7}};
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+
+ c.numVerts = 8;
+ mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.minimum.y, bounds.minimum.z));
+ mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.minimum.y, bounds.minimum.z));
+ mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.maximum.y, bounds.minimum.z));
+ mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.maximum.y, bounds.minimum.z));
+ mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.minimum.y, bounds.maximum.z));
+ mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.minimum.y, bounds.maximum.z));
+ mGeom.vertices.pushBack(PxVec3(bounds.maximum.x, bounds.maximum.y, bounds.maximum.z));
+ mGeom.vertices.pushBack(PxVec3(bounds.minimum.x, bounds.maximum.y, bounds.maximum.z));
+
+ c.numFaces = 6;
+ for (int i = 0; i < 6; i++) {
+ mGeom.indices.pushBack(4); // size
+ mGeom.indices.pushBack(0); // flags
+ for (int j = 0; j < 4; j++)
+ mGeom.indices.pushBack(boxFaces[i][j]);
+ }
+ mGeom.convexes.pushBack(c);
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::createCrack(const PxVec3 &dims, float spacing, float zRand)
+{
+ clear();
+
+ float minZ = -1.2f * zRand;
+ float maxZ = 1.2f * zRand;
+
+ PxBounds3 bounds;
+ bounds.minimum = PxVec3(-dims.x, -dims.y, -dims.z);
+ bounds.maximum = PxVec3( dims.x, dims.y, minZ);
+ addBox(bounds);
+
+ nvidia::Array<PxVec3> points;
+
+ mBounds.minimum = -dims;
+ mBounds.maximum = dims;
+
+ float area = 4.0f * dims.x * dims.y;
+ int numCells = (int)(area / (spacing * spacing));
+
+ for (int i = 0; i < numCells; i++) {
+ PxVec3 p = PxVec3(physx::shdfnd::rand(-dims.x, dims.x), physx::shdfnd::rand(-dims.y,dims.y), 0.0f);
+ points.pushBack(p);
+ }
+
+ Delaunay2d *d = mScene->getDelaunay2d();
+ d->triangulate(&points[0], (int32_t)points.size(), sizeof(PxVec3), true);
+ d->computeVoronoiMesh();
+
+ // convert to 3d
+ const nvidia::Array<Delaunay2d::Convex> &convexes = d->getConvexes();
+ nvidia::Array<PxVec3> verts = d->getConvexVerts();
+ for (uint32_t i = 0; i < verts.size(); i++)
+ verts[i].z += physx::shdfnd::rand(-zRand, zRand);
+
+ int numConvexes = (int32_t)convexes.size();
+
+ const nvidia::Array<int> &neighbors = d->getConvexNeighbors();
+
+ for (int side = 0; side < 2; side++) {
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ const Delaunay2d::Convex &c2 = convexes[i];
+
+ CompoundGeometry::Convex c3;
+ mGeom.initConvex(c3);
+
+ // neighbors
+ c3.numNeighbors = c2.numNeighbors + 2;
+ for (int j = 0; j < c2.numNeighbors; j++) {
+ int n = neighbors[uint32_t(c2.firstNeighbor + j)] + 1;
+ if (side == 0)
+ mGeom.neighbors.pushBack(n);
+ else
+ mGeom.neighbors.pushBack(numConvexes + n);
+ }
+ if (side == 0) {
+ mGeom.neighbors.pushBack(1 + numConvexes + (int32_t)i);
+ mGeom.neighbors.pushBack(0);
+ }
+ else {
+ mGeom.neighbors.pushBack(1 + (int32_t)i);
+ mGeom.neighbors.pushBack(1 + 2*numConvexes);
+ }
+
+ // vertices
+ c3.numVerts = 2 * c2.numVerts;
+ for (int j = 0; j < c2.numVerts; j++) {
+ PxVec3 p = verts[uint32_t(c2.firstVert+j)];
+ if (side == 0) {
+ mGeom.vertices.pushBack(PxVec3(p.x, p.y, minZ));
+ mGeom.vertices.pushBack(p);
+ }
+ else {
+ mGeom.vertices.pushBack(p);
+ mGeom.vertices.pushBack(PxVec3(p.x, p.y, maxZ));
+ }
+ }
+
+ // faces
+ c3.numFaces = c2.numVerts + 2;
+ mGeom.indices.pushBack(c2.numVerts);
+ mGeom.indices.pushBack(0); // flags
+ for (int j = 0; j < c2.numVerts; j++)
+ mGeom.indices.pushBack(2*j+1);
+ mGeom.indices.pushBack(c2.numVerts);
+ mGeom.indices.pushBack(0); // flags
+ for (int j = c2.numVerts-1; j >= 0; j--)
+ mGeom.indices.pushBack(2*j);
+ for (int j = 0; j < c2.numVerts; j++) {
+ mGeom.indices.pushBack(4); // size
+ mGeom.indices.pushBack(0); // flags
+ int k = (j+1)%c2.numVerts;
+ mGeom.indices.pushBack(2*j);
+ mGeom.indices.pushBack(2*k);
+ mGeom.indices.pushBack(2*k+1);
+ mGeom.indices.pushBack(2*j+1);
+ }
+
+ mGeom.convexes.pushBack(c3);
+ }
+ }
+
+ bounds.minimum = PxVec3(-dims.x, -dims.y, maxZ);
+ bounds.maximum = PxVec3( dims.x, dims.y, dims.z);
+ addBox(bounds);
+
+ // two cells
+ mFirstConvexOfCell.pushBack(0);
+ mFirstConvexOfCell.pushBack(1 + numConvexes);
+ mFirstConvexOfCell.pushBack(1 + 2*numConvexes + 1);
+
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::create2dVoronoi(const PxVec3 &dims, int numCells, float biasExp, int numRays)
+{
+ clear();
+ nvidia::Array<PxVec3> points;
+ float r0 = dims.magnitude();
+ float r = physx::shdfnd::pow(r0, 1.0f/biasExp);
+
+ mBounds.minimum= -dims;
+ mBounds.maximum= dims;
+
+ if (numRays == 0) {
+ for (int i = 0; i < numCells; i++) {
+ PxVec3 p;
+ do {
+ p = PxVec3(physx::shdfnd::rand(-r,r), physx::shdfnd::rand(-r,r), 0.0f);
+ float len = p.normalize();
+ p *= physx::shdfnd::pow(len, biasExp);
+ } while (!mBounds.contains(p));
+ points.pushBack(p);
+ }
+ }
+ else {
+ float diag = mBounds.getDimensions().magnitude();
+ float eps = 0.0025f * diag;
+
+ int cellsPerRay = numCells / numRays + 1;
+ float dr = 0.05f * diag / cellsPerRay;
+ float dphi = PxTwoPi / numRays;
+
+ for (int i = 0; i < numRays; i++) {
+ float phi = i * dphi;
+ PxVec3 n(PxCos(phi), PxSin(phi), 0.0f);
+
+ for (int j = 0; j < cellsPerRay; j++) {
+ float rj = dr * physx::shdfnd::pow((float)(j+1), biasExp);
+ PxVec3 p = n * rj;
+ p.x += physx::shdfnd::rand(-rj * eps, rj * eps);
+ p.y += physx::shdfnd::rand(-rj * eps, rj * eps);
+ if (!mBounds.contains(p))
+ break;
+ points.pushBack(p);
+ }
+ }
+ }
+
+ float s = 1.2f;
+ points.pushBack(PxVec3(-s*dims.x, -s*dims.y, 0.0f));
+ points.pushBack(PxVec3( s*dims.x, -s*dims.y, 0.0f));
+ points.pushBack(PxVec3( s*dims.x, s*dims.y, 0.0f));
+ points.pushBack(PxVec3(-s*dims.x, s*dims.y, 0.0f));
+
+ Delaunay2d *d = mScene->getDelaunay2d();
+ d->triangulate(&points[0], (int32_t)points.size(), sizeof(PxVec3), true);
+ d->computeVoronoiMesh();
+
+ // convert to 3d
+ const nvidia::Array<Delaunay2d::Convex> &convexes = d->getConvexes();
+ const nvidia::Array<PxVec3> &verts = d->getConvexVerts();
+ mGeom.neighbors = d->getConvexNeighbors();
+
+ mGeom.convexes.resize(convexes.size());
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ CompoundGeometry::Convex &c3 = mGeom.convexes[i];
+ const Delaunay2d::Convex &c2 = convexes[i];
+
+ c3.firstNeighbor = c2.firstNeighbor;
+ c3.numNeighbors = c2.numNeighbors;
+
+ c3.firstVert = (int32_t)mGeom.vertices.size();
+ c3.numVerts = 2 * c2.numVerts;
+ for (int j = 0; j < c2.numVerts; j++) {
+ PxVec3 p = verts[uint32_t(c2.firstVert+j)];
+ p.z = mBounds.minimum.z;
+ mGeom.vertices.pushBack(p);
+ p.z = mBounds.maximum.z;
+ mGeom.vertices.pushBack(p);
+ }
+
+ c3.firstIndex = (int32_t)mGeom.indices.size();
+ c3.numFaces = c2.numVerts + 2;
+ mGeom.indices.pushBack(c2.numVerts);
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE);
+ for (int j = 0; j < c2.numVerts; j++)
+ mGeom.indices.pushBack(2*j+1);
+ mGeom.indices.pushBack(c2.numVerts);
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE);
+ for (int j = c2.numVerts-1; j >= 0; j--)
+ mGeom.indices.pushBack(2*j);
+ for (int j = 0; j < c2.numVerts; j++) {
+ mGeom.indices.pushBack(4);
+ mGeom.indices.pushBack(0);
+ int k = (j+1)%c2.numVerts;
+ mGeom.indices.pushBack(2*j);
+ mGeom.indices.pushBack(2*k);
+ mGeom.indices.pushBack(2*k+1);
+ mGeom.indices.pushBack(2*j+1);
+ }
+ }
+
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::createGlass(float radius, float thickness, int numSectors, float sectorRand, float firstSegmentSize, float segmentScale, float segmentRand)
+{
+ clear();
+ CompoundGeometry::Convex c;
+ static int faces[6][4] = {{0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7}, {3,2,1,0}, {4,5,6,7}};
+
+ nvidia::Array<float> secAngles((uint32_t)numSectors);
+ float dSec = PxTwoPi / (float)numSectors;
+ for (uint32_t i = 0; i < (uint32_t)numSectors; i++)
+ secAngles[i] = i * dSec + physx::shdfnd::rand(-sectorRand, sectorRand) * dSec;
+
+ // how many segments?
+ float segSize = firstSegmentSize;
+ float d = 0.0f;
+ int numSegs = 0;
+ while (d < radius) {
+ numSegs++;
+ d += segSize;
+ segSize *= segmentScale;
+ }
+
+ for (uint32_t i = 0; i < (uint32_t)numSectors; i++) {
+ float segSize = firstSegmentSize;
+ float d = 0.0f;
+ float r0 = 0.0f;
+ float r1 = 0.0f;
+ float p0, p1;
+
+ float a0 = secAngles[i];
+ float a1 = secAngles[(i + 1) % numSectors];
+
+ for (int j = 0; j < numSegs; j++) {
+ d += segSize;
+ p0 = r0;
+ p1 = r1;
+ r0 = d + physx::shdfnd::rand(-segmentRand, segmentRand) * segSize;
+ r1 = d + physx::shdfnd::rand(-segmentRand, segmentRand) * segSize;
+ segSize *= segmentScale;
+
+ mGeom.initConvex(c);
+ c.numFaces = 6;
+ c.numNeighbors = 6;
+ c.numVerts = 8;
+ c.firstPlane = 0;
+ mGeom.convexes.pushBack(c);
+
+ float sin0 = PxSin(a0);
+ float sin1 = PxSin(a1);
+ float cos0 = PxCos(a0);
+ float cos1 = PxCos(a1);
+
+ mGeom.vertices.pushBack(PxVec3(p0 * cos0, p0 * sin0, -thickness));
+ mGeom.vertices.pushBack(PxVec3(r0 * cos0, r0 * sin0, -thickness));
+ mGeom.vertices.pushBack(PxVec3(r1 * cos1, r1 * sin1, -thickness));
+ mGeom.vertices.pushBack(PxVec3(p1 * cos1, p1 * sin1, -thickness));
+ mGeom.vertices.pushBack(PxVec3(p0 * cos0, p0 * sin0, thickness));
+ mGeom.vertices.pushBack(PxVec3(r0 * cos0, r0 * sin0, thickness));
+ mGeom.vertices.pushBack(PxVec3(r1 * cos1, r1 * sin1, thickness));
+ mGeom.vertices.pushBack(PxVec3(p1 * cos1, p1 * sin1, thickness));
+
+ for (uint32_t k = 0; k < 6; k++) {
+ mGeom.indices.pushBack(4); // face size
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); // flags
+ mGeom.indices.pushBack(faces[k][0]);
+ mGeom.indices.pushBack(faces[k][1]);
+ mGeom.indices.pushBack(faces[k][2]);
+ mGeom.indices.pushBack(faces[k][3]);
+ }
+ mGeom.neighbors.pushBack(i > 0 ? ((int32_t)i-1) * numSegs + j : (numSectors-1) * numSegs + j);
+ mGeom.neighbors.pushBack(j < numSegs-1 ? (int32_t)i * numSegs + j+1 : -1);
+ mGeom.neighbors.pushBack((int32_t)i < numSectors-1 ? ((int32_t)i+1) * numSegs + j : j);
+ mGeom.neighbors.pushBack(j > 0 ? (int32_t)i * numSegs + j-1 : -1);
+ mGeom.neighbors.pushBack(-1);
+ mGeom.neighbors.pushBack(-1);
+ }
+ }
+ finalize();
+}
+// --------------------------------------------------------------------------------------------
+void FracturePattern::createRegularCubeMesh(const PxVec3 &extents, float cubeSize)
+{
+ clear();
+ int numX = (int)(2.0f*extents.x / cubeSize) + 1;
+ int numY = (int)(2.0f*extents.y / cubeSize) + 1;
+ int numZ = (int)(2.0f*extents.z / cubeSize) + 1;
+
+ CompoundGeometry::Convex c;
+ static int faces[6][4] = {{0,1,5,4}, {1,2,6,5}, {2,3,7,6}, {3,0,4,7}, {3,2,1,0}, {4,5,6,7}};
+
+ for (int xi = 0; xi < numX; xi++) {
+ for (int yi = 0; yi < numY; yi++) {
+ for (int zi = 0; zi < numZ; zi++) {
+ mGeom.initConvex(c);
+ c.numFaces = 6;
+ c.numNeighbors = 6;
+ c.numVerts = 8;
+ c.firstPlane = 0;
+ mGeom.convexes.pushBack(c);
+
+ PxVec3 p0(-extents.x + xi*cubeSize, -extents.y + yi*cubeSize, -extents.z + zi*cubeSize);
+ PxVec3 p1 = p0 + PxVec3(cubeSize, cubeSize, cubeSize);
+ mGeom.vertices.pushBack(PxVec3(p0.x, p0.y, p0.z));
+ mGeom.vertices.pushBack(PxVec3(p1.x, p0.y, p0.z));
+ mGeom.vertices.pushBack(PxVec3(p1.x, p1.y, p0.z));
+ mGeom.vertices.pushBack(PxVec3(p0.x, p1.y, p0.z));
+ mGeom.vertices.pushBack(PxVec3(p0.x, p0.y, p1.z));
+ mGeom.vertices.pushBack(PxVec3(p1.x, p0.y, p1.z));
+ mGeom.vertices.pushBack(PxVec3(p1.x, p1.y, p1.z));
+ mGeom.vertices.pushBack(PxVec3(p0.x, p1.y, p1.z));
+ for (int i = 0; i < 6; i++) {
+ mGeom.indices.pushBack(4); // face size
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE); // flags
+ mGeom.indices.pushBack(faces[i][0]);
+ mGeom.indices.pushBack(faces[i][1]);
+ mGeom.indices.pushBack(faces[i][2]);
+ mGeom.indices.pushBack(faces[i][3]);
+ }
+ mGeom.neighbors.pushBack(yi > 0 ? (xi * numY + yi-1) * numZ + zi : -1);
+ mGeom.neighbors.pushBack(xi < numX-1 ? ((xi+1) * numY + yi) * numZ + zi : -1);
+ mGeom.neighbors.pushBack(yi < numY-1 ? (xi * numY + yi+1) * numZ + zi : -1);
+ mGeom.neighbors.pushBack(xi > 0 ? ((xi-1) * numY + yi) * numZ + zi : -1);
+ mGeom.neighbors.pushBack(zi > 0 ? (xi * numY + yi) * numZ + zi-1 : -1);
+ mGeom.neighbors.pushBack(zi < numZ-1 ? (xi * numY + yi) * numZ + zi+1 : -1);
+ }
+ }
+ }
+
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::createCrosses(const PxVec3 &dims, float spacing)
+{
+ clear();
+
+ int numX = (int)floorf(2.0f * dims.x / spacing) + 1;
+ int numY = (int)floorf(2.0f * dims.y / spacing) + 1;
+ int numZ = (int)floorf(2.0f * dims.z / spacing) + 1;
+
+ static int offset[5] = {0,3,1,4,2};
+ static int cross[5][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}, {0,0}};
+ PxBounds3 bounds;
+
+ for (int zi = 0; zi < numZ; zi++) {
+ for (int yi = 0; yi < numY; yi++) {
+ for (int xi = 0; xi < numX; xi += 5) {
+ float z = -dims.z + (zi + xi % 2 + yi % 2) * spacing;
+ float y = -dims.y + yi * spacing;
+ float x = -dims.x + (xi + offset[yi % 5]) * spacing;
+
+ mFirstConvexOfCell.pushBack((int32_t)mGeom.convexes.size());
+
+ for (int i = 0; i < 5; i++) {
+ bounds.minimum.x = x + cross[i][0] * spacing;
+ bounds.minimum.y = y + cross[i][1] * spacing;
+ bounds.minimum.z = z;
+ bounds.maximum = bounds.minimum + PxVec3(spacing, spacing, spacing);
+ addBox(bounds);
+ }
+ }
+ }
+ }
+
+ mFirstConvexOfCell.pushBack((int32_t)mGeom.convexes.size());
+
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::getConvexIntersection(const Convex *convex, const PxMat44 &trans, float minConvexSize, int /*numFitDirections*/) const
+{
+ PxTransform localPose = convex->getLocalPose();
+ const nvidia::Array<PxPlane> convexPlanes = convex->getPlanes();
+
+ mScene->profileBegin("find pattern candidates");
+
+ // cull outside convexes
+ nvidia::Array<int> candidates(mGeom.convexes.size());
+ for (uint32_t i = 0; i < candidates.size(); i++)
+ candidates[i] = (int32_t)i;
+
+ for (uint32_t i = 0; i < convexPlanes.size(); i++) {
+ PxPlane plane = convexPlanes[i];
+ plane.n = localPose.rotate(plane.n); // only valid for rigid transforms!
+ plane.d = plane.d + localPose.p.dot(plane.n);
+
+ uint32_t num = 0;
+ for (uint32_t j = 0; j < candidates.size(); j++) {
+ const CompoundGeometry::Convex &c = mGeom.convexes[(uint32_t)candidates[j]];
+ bool inside = false;
+ for (int k = 0; k < c.numVerts; k++) {
+ PxVec3 p = trans.transform(mGeom.vertices[uint32_t(c.firstVert + k)]);
+ if (p.dot(plane.n) < plane.d) {
+ inside = true;
+ break;
+ }
+ }
+ if (inside) {
+ candidates[num] = candidates[j];
+ num++;
+ }
+ }
+ candidates.resize(num);
+ }
+
+ mScene->profileEnd("find pattern candidates");
+
+ // retreive convexes
+ Piece piece;
+ nvidia::Array<Convex*> newConvexes;
+
+ mScene->profileBegin("clip all");
+
+ mScene->profileBegin("clipper init");
+ MeshClipper *clipper = mScene->getMeshClipper();
+ clipper->init(convex);
+ mScene->profileEnd("clipper init");
+
+ mScene->profileBegin("clipper clip");
+
+ for (uint32_t i = 0; i < candidates.size(); i++) {
+ uint32_t convexNr = (uint32_t)candidates[i];
+ Convex *c = mScene->createConvex();
+ const PxTransform transformTemp = convex->getLocalPose();
+ c->createFromConvex(convex, &transformTemp);
+ const CompoundGeometry::Convex &gc = mGeom.convexes[convexNr];
+
+ bool empty = true;
+ c->intersectWithConvex(&mGeom.planes[(uint32_t)gc.firstPlane], gc.numFaces, trans, empty);
+
+ if (empty) {
+ PX_DELETE(c);
+ continue;
+ }
+
+ const PxBounds3 &bounds = c->getBounds();
+ PxVec3 dim = bounds.getDimensions();
+ if (!c->isGhostConvex() && (dim.x < minConvexSize || dim.y < minConvexSize || dim.z < minConvexSize)) {
+ PX_DELETE(c);
+ continue;
+ }
+
+ empty = false;
+ newConvexes.clear();
+
+ if (convex->hasExplicitVisMesh()) {
+ if (!c->clipVisualMesh(clipper, convex->getLocalPose(), newConvexes)) {
+ PX_DELETE(c);
+ continue;
+ }
+ if (newConvexes.size() > 0)
+ mSplitPiece[convexNr] = true;
+ }
+
+ c->setModelIslandNr(convex->getModelIslandNr());
+ c->setSurfaceMaterialId(convex->getSurfaceMaterialId());
+ newConvexes.pushBack(c);
+
+ for (uint32_t i = 0; i < newConvexes.size(); i++) {
+ Convex *c = newConvexes[i];
+ const PxBounds3 &bounds = c->getBounds();
+ PxVec3 dim = bounds.getDimensions();
+ if (!c->isGhostConvex() && (dim.x < minConvexSize || dim.y < minConvexSize || dim.z < minConvexSize)) {
+ // TODO: Spawn debris?
+ PX_DELETE(c);
+ continue;
+ }
+ piece.convex = newConvexes[i];
+ piece.next = mFirstPiece[convexNr];
+ mFirstPiece[convexNr] = (int32_t)mPieces.size();
+ mPieces.pushBack(piece);
+ }
+ }
+ mScene->profileBegin("clipper clip");
+
+ mScene->profileEnd("clip all");
+
+}
+
+// --------------------------------------------------------------------------------------------
+void FracturePattern::getCompoundIntersection(const Compound *compound, const PxMat44 &trans, float radius, float minConvexSize,
+ nvidia::Array<int> &compoundSizes, nvidia::Array<Convex*> &newConvexes) const
+{
+ // radius = 0.0f : complete fracture
+ // radius > 0.0f : partial (local) fracture
+
+ //{
+
+ // IslandDetector *id = IslandDetector::getInstance();
+ // id->detect(&convexes[0], convexes.size(), true);
+ //}
+
+ const nvidia::Array<Convex*> &convexes = compound->getConvexes();
+ //const nvidia::Array<PxBounds3>& attachmentBounds = compound->getAttachmentBounds();
+
+ PxMat33 m(trans.getBasis(0), trans.getBasis(1), trans.getBasis(2));
+ float transScale = m.getDeterminant();
+
+ newConvexes.clear();
+ compoundSizes.clear();
+
+ PxVec3 fractureCenter = trans.getPosition();
+
+ for (uint32_t i = 0; i < mGeom.convexes.size(); i++) {
+ mFirstPiece[i] = -1;
+ mSplitPiece[i] = false;
+ }
+ mPieces.clear();
+
+ nvidia::Array<Convex*> farConvexes;
+ nvidia::Array<Convex*> cellConvexes;
+
+ // fracture convexes
+ int numFitDirections = 7;
+
+ // complete fracture
+ if (radius == 0.0f) {
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ Convex *c = convexes[i];
+ //if (c->isGhostConvex())
+ // /*int foo = 0*/;
+ getConvexIntersection(c, trans, minConvexSize, numFitDirections);
+ }
+ }
+ else { // partial fracture
+
+ // fracture non-ghost convexes and determine furthest fractured vertex
+ float maxGhostRadius2 = 0.0f;
+
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ Convex *c = convexes[i];
+ if (c->isGhostConvex())
+ continue;
+
+ PxTransform localPose = c->getLocalPose();
+ PxVec3 localCenter = localPose.transformInv(fractureCenter);
+
+ // is the convex outside of the fracture sphere?
+ if (c->insideFattened(localCenter, radius)) {
+ getConvexIntersection(c, trans, minConvexSize, numFitDirections);
+
+ const nvidia::Array<PxVec3> &verts = c->getVertices();
+ for (uint32_t j = 0; j < verts.size(); j++) {
+ float r2 = (verts[j] - localCenter).magnitudeSquared();
+ if (r2 > maxGhostRadius2)
+ maxGhostRadius2 = r2;
+ }
+ }
+ else {
+ c->transform(localPose);
+ c->clearFraceFlags(CompoundGeometry::FF_NEW);
+ c->setIsFarConvex(true);
+ farConvexes.pushBack(c); // double use -> that is why we need reference counters for convexes!
+ }
+ }
+
+ // added overlap test in island detector, no need for ghost anymore!
+
+// // fracture ghost convexes using the maxGhostRadius
+// float maxGhostRadius = PxSqrt(maxGhostRadius2);
+//
+// for (int i = 0; i < (int)convexes.size(); i++) {
+// Convex *c = convexes[i];
+// if (!c->isGhostConvex())
+// continue;
+// PxTransform localPose = c->getLocalPose();
+// PxVec3 localCenter = localPose.transformInv(fractureCenter);
+//
+// // is the convex outside of the fracture sphere?
+// if (c->insideFattened(localCenter, maxGhostRadius)) {
+//// if (c->insideFattened(localCenter, radius)) { // foo
+// getConvexIntersection(c, trans, minConvexSize, numFitDirections);
+// }
+// else {
+// c->transform(localPose);
+// farConvexes.pushBack(c); // double use -> that is why we need reference counters for convexes!
+// }
+// }
+ }
+
+ // collect pieces
+ bool complexCells = !mFirstConvexOfCell.empty();
+ uint32_t numCells = complexCells ? mFirstConvexOfCell.size()-1 : mGeom.convexes.size();
+
+ for (uint32_t i = 0; i < numCells; i++) {
+ uint32_t numConvexes = uint32_t(complexCells ? mFirstConvexOfCell[i+1] - mFirstConvexOfCell[i] : 1);
+
+ cellConvexes.clear();
+ PxVec3 matOff = PxVec3(0.0f, 0.0f, 0.0f);
+ bool hasGhosts = false;
+ bool splitCell = false;
+
+
+ for (uint32_t k = 0; k < numConvexes; k++) {
+ uint32_t convexNr = complexCells ? (uint32_t)mFirstConvexOfCell[i] + k : i;
+
+ if (mSplitPiece[convexNr])
+ splitCell = true;
+
+ if (mFirstPiece[convexNr] < 0)
+ continue;
+
+ int nr = mFirstPiece[convexNr];
+ while (nr >= 0) {
+ Convex *c = mPieces[(uint32_t)nr].convex;
+ if (c->isGhostConvex())
+ hasGhosts = true;
+ else
+ matOff = c->getMaterialOffset();
+ cellConvexes.pushBack(c);
+ nr = mPieces[(uint32_t)nr].next;
+ }
+ }
+
+ // fit to visual mesh, only if there are no ghost convexes, otherwise the faces do to match anymore
+ if (!hasGhosts) {
+ uint32_t num = 0;
+ for (uint32_t j = 0; j < cellConvexes.size(); j++) {
+ Convex *c = cellConvexes[j];
+ if (c->hasExplicitVisMesh()) {
+ bool empty = false;
+ c->fitToVisualMesh(empty, numFitDirections);
+ if (empty) {
+ PX_DELETE(c);
+ continue;
+ }
+ }
+ cellConvexes[num] = c;
+ num++;
+ }
+ cellConvexes.resize(num);
+ }
+
+ if (cellConvexes.size() == 1) {
+ newConvexes.pushBack(cellConvexes[0]);
+ compoundSizes.pushBack(1);
+ continue;
+ }
+
+ // all volume covered with new pieces?
+ bool hasExplicitMesh = false;
+
+ float volumeFraction = 0.0f;
+ for (uint32_t j = 0; j < cellConvexes.size(); j++) {
+ const Convex *c = cellConvexes[j];
+ float vol = c->isGhostConvex() ? -c->getVolume() : c->getVolume();
+ volumeFraction += vol;
+ if (c->hasExplicitVisMesh())
+ hasExplicitMesh = true;
+ }
+
+ float vol = mConvexVolumes[i] * transScale;
+ float volDiff = fabsf(vol - volumeFraction) / vol;
+
+ if (splitCell) { // each convex piece within the pattern piece becomes a separate compound
+ for (uint32_t j = 0; j < cellConvexes.size(); j++) {
+ newConvexes.pushBack(cellConvexes[j]);
+ compoundSizes.pushBack(1);
+ }
+ }
+ else if (!complexCells && !hasExplicitMesh && volDiff < 0.01f) { // the entire pattern piece becomes a convex
+ // delete parts
+ for (uint32_t j = 0; j < cellConvexes.size(); j++)
+ PX_DELETE(cellConvexes[j]);
+
+ // create single piece
+ Convex *c = mScene->createConvex();
+ c->createFromGeometry(mGeom, (int32_t)i, &trans);
+ newConvexes.pushBack(c);
+ c->setMaterialOffset(matOff);
+ compoundSizes.pushBack(1);
+ }
+ else { // all connected convex pieces within the pattern cell become one compound
+ IslandDetector *id = mScene->getIslandDetector();
+ id->detect(cellConvexes, false);
+ const nvidia::Array<IslandDetector::Island> &islands = id->getIslands();
+ const nvidia::Array<int> &islandConvexes = id->getIslandConvexes();
+
+ for (uint32_t j = 0; j < islands.size(); j++) {
+ const IslandDetector::Island &is = islands[j];
+ for (int k = 0; k < is.size; k++)
+ newConvexes.pushBack(cellConvexes[(uint32_t)islandConvexes[uint32_t(is.firstNr+k)]]);
+ compoundSizes.pushBack(is.size);
+ }
+ }
+ }
+
+ // merge far convexes for local fracture
+ if (radius > 0.0f) {
+ farConvexes.reserve(farConvexes.size() + newConvexes.size());
+
+ uint32_t oldConvexNr = 0;
+ uint32_t newConvexNr = 0;
+ uint32_t numNewCompounds = 0;
+
+ for (uint32_t i = 0; i < compoundSizes.size(); i++) {
+ uint32_t oldCompoundSize = (uint32_t)compoundSizes[i];
+ uint32_t newCompoundSize = 0;
+ bool onlyGhosts = true;
+ for (uint32_t j = 0; j < oldCompoundSize; j++) {
+ Convex *c = newConvexes[oldConvexNr + j];
+ if (!c->insideFattened(fractureCenter, radius)) {
+ c->clearFraceFlags(CompoundGeometry::FF_NEW);
+ c->setIsFarConvex(true);
+ farConvexes.pushBack(c);
+ }
+ else {
+ if (!c->isGhostConvex())
+ onlyGhosts = false;
+ newConvexes[newConvexNr] = c;
+ newConvexNr++;
+ newCompoundSize++;
+ }
+ }
+ if (newCompoundSize > 0) {
+ if (onlyGhosts) { // remove compounds that contain only ghost convexes
+ for (uint32_t j = 0; j < newCompoundSize; j++) {
+ newConvexNr--;
+ PX_DELETE(newConvexes[newConvexNr]);
+ }
+ }
+ else {
+ compoundSizes[numNewCompounds] = (int32_t)newCompoundSize;
+ numNewCompounds++;
+ }
+ }
+ oldConvexNr += oldCompoundSize;
+ }
+ newConvexes.resize(newConvexNr);
+ compoundSizes.resize(numNewCompounds);
+ }
+
+ if (farConvexes.size() > 0) {
+ IslandDetector *id = mScene->getIslandDetector();
+
+ mScene->profileBegin("island detection");
+
+ id->detect(farConvexes, true);
+
+ mScene->profileEnd("island detection");
+
+ const nvidia::Array<IslandDetector::Island> &islands = id->getIslands();
+ const nvidia::Array<int> &islandConvexes = id->getIslandConvexes();
+
+ for (uint32_t i = 0; i < islands.size(); i++) {
+ const IslandDetector::Island &island = islands[i];
+ compoundSizes.pushBack(island.size);
+ for (int j = 0; j < island.size; j++) {
+ int nr = islandConvexes[uint32_t(island.firstNr + j)];
+ newConvexes.pushBack(farConvexes[(uint32_t)nr]);
+ }
+ }
+
+ //const nvidia::Array<int> &pairs = id->getNeighborEdges();
+ //FILE *f = fopen("c:\\test.txt", "a");
+ //fprintf(f, "convexes %i, edges %i\n", farConvexes.size(), pairs.size()/2);
+ //fclose(f);
+
+ //StaticTester::getInstance()->setStretchThreshold(1.0f); // 1 newton / m^2
+ //StaticTester::getInstance()->setCompressionThreshold(10.0f); // 10 newton / m^2
+ //StaticTester::getInstance()->setTorqueThreshold(2.0f); // 2 newton / m
+ //StaticTester::getInstance()->analyse(farConvexes, attachmentBounds, id->getNeighborEdges());
+
+#if HIDE_INVISIBLE_FACES
+ if (radius != 0.0f) {
+ // invisible faces may open up with partial fracturing
+ const nvidia::Array<float> faceCoverage = mScene->getIslandDetector()->getFaceCoverage();
+ uint32_t globalFaceNr = 0;
+ for (uint32_t i = 0; i < farConvexes.size(); i++) {
+ Convex *c = farConvexes[i];
+ c->updateFaceVisibility(&faceCoverage[globalFaceNr]);
+ globalFaceNr += c->getFaces().size();
+ }
+ // brute force
+ //for (int i = 0; i < (int)newConvexes.size(); i++) {
+ // newConvexes[i]->updateFaceVisibility
+ // newConvexes[i]->removeInvisibleFacesFlags();
+ //}
+ }
+#endif
+ }
+
+ //if (farConvexes.size() > 0) {
+ // compoundSizes.pushBack(farConvexes.size());
+ // for (int i = 0; i < (int)farConvexes.size(); i++)
+ // newConvexes.pushBack(farConvexes[i]);
+ //}
+
+// printf("%i new convexes, %i new compounds\n", newConvexes.size(), compoundSizes.size());
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.h b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.h
new file mode 100644
index 00000000..425efd22
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/FracturePatternBase.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef FRACTURE_PATTERN_BASE
+#define FRACTURE_PATTERN_BASE
+
+#include "Delaunay3dBase.h"
+#include "Delaunay2dBase.h"
+#include "CompoundGeometryBase.h"
+#include "PxTransform.h"
+#include "PxBounds3.h"
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+class Convex;
+class Compound;
+class CompoundGeometry;
+
+//------------------------------------------------------------------------------------------
+class FracturePattern : public UserAllocated
+{
+ friend class SimScene;
+protected:
+ FracturePattern(SimScene* scene);
+public:
+ virtual ~FracturePattern() {}
+
+ void create3dVoronoi(const PxVec3 &dims, int numCells, float biasExp = 1.0f, float maxDist = PX_MAX_F32);
+ void create2dVoronoi(const PxVec3 &dims, int numCells, float biasExp = 1.0f, int numRays = 0);
+
+ void createRegularCubeMesh(const PxVec3 &dims, float cubeSize);
+ void createRegular3dVoronoi(const PxVec3 &dims, float pieceSize, float relRandOffset = 0.1f);
+ void createLocal3dVoronoi(const PxVec3 &dims, int numCells, float radius);
+ void createGlass(float radius, float thickness, int numSectors, float sectorRand, float firstSegmentSize, float segmentScale, float segmentRand);
+ void createCrack(const PxVec3 &dims, float spacing, float zRand);
+ void createCrosses(const PxVec3 &dims, float spacing);
+
+ // radius = 0.0f : complete fracture
+ // radius > 0.0f : partial (local) fracture
+ void getCompoundIntersection(const Compound *compound, const PxMat44 &trans, float radius, float minConvexSize,
+ nvidia::Array<int> &compoundSizes, nvidia::Array<Convex*> &newConvexes) const;
+
+ const CompoundGeometry &getGeometry() { return mGeom; }
+
+protected:
+ void addBox(const PxBounds3 &bounds);
+ void clear();
+ void finalize();
+
+ void getConvexIntersection(const Convex *convex, const PxMat44 &trans, float minConvexSize, int numFitDirections = 3) const;
+
+ SimScene* mScene;
+
+ CompoundGeometry mGeom;
+
+ // cells can have multiple connected convexes
+ // if this array is empty, each convex is a separate cell
+ // size of array must be num cells + 1
+ nvidia::Array<int> mFirstConvexOfCell;
+
+ PxBounds3 mBounds;
+ nvidia::Array<float> mConvexVolumes;
+
+ // temporary for intersection computation
+ mutable nvidia::Array<int> mFirstPiece;
+ mutable nvidia::Array<bool> mSplitPiece;
+ struct Piece {
+ Convex* convex;
+ int next;
+ };
+ mutable nvidia::Array<Piece> mPieces;
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.cpp b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.cpp
new file mode 100644
index 00000000..774d0049
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.cpp
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Contains code for box pruning.
+ * \file IceBoxPruning.cpp
+ * \author Pierre Terdiman
+ * \date January, 29, 2000
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ You could use a complex sweep-and-prune as implemented in I-Collide.
+ You could use a complex hashing scheme as implemented in V-Clip or recently in ODE it seems.
+ You could use a "Recursive Dimensional Clustering" algorithm as implemented in GPG2.
+
+ Or you could use this.
+ Faster ? I don't know. Probably not. It would be a shame. But who knows ?
+ Easier ? Definitely. Enjoy the sheer simplicity.
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+*/
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "IceBoxPruningBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
+ * \param nb0 [in] number of boxes in the first set
+ * \param bounds0 [in] list of boxes for the first set
+ * \param nb1 [in] number of boxes in the second set
+ * \param bounds1 [in] list of boxes for the second set
+ * \param pairs [out] list of overlapping pairs
+ * \param axes [in] projection order (0,2,1 is often best)
+ * \return true if success.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool BoxPruning::bipartiteBoxPruning(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& axes)
+{
+ uint32_t nb0 = bounds0.size();
+ uint32_t nb1 = bounds1.size();
+ pairs.clear();
+ // Checkings
+ if(nb0 == 0 || nb1 == 0) return false;
+
+ // Catch axes
+ uint32_t Axis0 = axes.Axis0;
+ //uint32_t Axis1 = axes.Axis1;
+ //uint32_t Axis2 = axes.Axis2;
+
+ // Allocate some temporary data
+ if (mMinPosBounds0.size() < nb0)
+ mMinPosBounds0.resize(nb0);
+ if (mMinPosBounds1.size() < nb1)
+ mMinPosBounds1.resize(nb1);
+
+ // 1) Build main lists using the primary axis
+ for(uint32_t i=0;i<nb0;i++) mMinPosBounds0[i] = bounds0[i].minimum[Axis0];
+ for(uint32_t i=0;i<nb1;i++) mMinPosBounds1[i] = bounds1[i].minimum[Axis0];
+
+ // 2) Sort the lists
+ uint32_t* Sorted0 = mRS0.Sort(&mMinPosBounds0[0], nb0).GetRanks();
+ uint32_t* Sorted1 = mRS1.Sort(&mMinPosBounds1[0], nb1).GetRanks();
+
+ // 3) Prune the lists
+ uint32_t Index0, Index1;
+
+ const uint32_t* const LastSorted0 = &Sorted0[nb0];
+ const uint32_t* const LastSorted1 = &Sorted1[nb1];
+ const uint32_t* RunningAddress0 = Sorted0;
+ const uint32_t* RunningAddress1 = Sorted1;
+
+ while(RunningAddress1<LastSorted1 && Sorted0<LastSorted0)
+ {
+ Index0 = *Sorted0++;
+
+ while(RunningAddress1<LastSorted1 && mMinPosBounds1[*RunningAddress1]<mMinPosBounds0[Index0]) RunningAddress1++;
+
+ const uint32_t* RunningAddress2_1 = RunningAddress1;
+
+ while(RunningAddress2_1<LastSorted1 && mMinPosBounds1[Index1 = *RunningAddress2_1++]<=bounds0[Index0].maximum[Axis0])
+ {
+ if(bounds0[Index0].intersects(bounds1[Index1]))
+ {
+ pairs.pushBack(Index0);
+ pairs.pushBack(Index1);
+ }
+ }
+ }
+
+ ////
+
+ while(RunningAddress0<LastSorted0 && Sorted1<LastSorted1)
+ {
+ Index0 = *Sorted1++;
+
+ while(RunningAddress0<LastSorted0 && mMinPosBounds0[*RunningAddress0]<=mMinPosBounds1[Index0]) RunningAddress0++;
+
+ const uint32_t* RunningAddress2_0 = RunningAddress0;
+
+ while(RunningAddress2_0<LastSorted0 && mMinPosBounds0[Index1 = *RunningAddress2_0++]<=bounds1[Index0].maximum[Axis0])
+ {
+ if(bounds0[Index1].intersects(bounds1[Index0]))
+ {
+ pairs.pushBack(Index1);
+ pairs.pushBack(Index0);
+ }
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
+ * \param nb [in] number of boxes
+ * \param list [in] list of boxes
+ * \param pairs [out] list of overlapping pairs
+ * \param axes [in] projection order (0,2,1 is often best)
+ * \return true if success.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool BoxPruning::completeBoxPruning(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& axes)
+{
+ uint32_t nb = bounds.size();
+ pairs.clear();
+
+ // Checkings
+ if(!nb) return false;
+
+ // Catch axes
+ uint32_t Axis0 = axes.Axis0;
+ //uint32_t Axis1 = axes.Axis1;
+ //uint32_t Axis2 = axes.Axis2;
+
+ // Allocate some temporary data
+ if (mPosList.size() < nb)
+ mPosList.resize(nb);
+
+ // 1) Build main list using the primary axis
+ for(uint32_t i=0;i<nb;i++) mPosList[i] = bounds[i].minimum[Axis0];
+
+ // 2) Sort the list
+ uint32_t* Sorted = mRS.Sort(&mPosList[0], nb).GetRanks();
+
+ // 3) Prune the list
+ const uint32_t* const LastSorted = &Sorted[nb];
+ const uint32_t* RunningAddress = Sorted;
+ uint32_t Index0, Index1;
+ while(RunningAddress<LastSorted && Sorted<LastSorted)
+ {
+ Index0 = *Sorted++;
+
+ while(RunningAddress<LastSorted && mPosList[*RunningAddress++]<mPosList[Index0]);
+
+ const uint32_t* RunningAddress2 = RunningAddress;
+
+ while(RunningAddress2<LastSorted && mPosList[Index1 = *RunningAddress2++]<=bounds[Index0].maximum[Axis0])
+ {
+ if(Index0!=Index1)
+ {
+ if(bounds[Index0].intersects(bounds[Index1]))
+ {
+ pairs.pushBack(Index0);
+ pairs.pushBack(Index1);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Brute-force versions are kept:
+// - to check the optimized versions return the correct list of intersections
+// - to check the speed of the optimized code against the brute-force one
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Brute-force bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
+ * \param nb0 [in] number of boxes in the first set
+ * \param bounds0 [in] list of boxes for the first set
+ * \param nb1 [in] number of boxes in the second set
+ * \param bounds1 [in] list of boxes for the second set
+ * \param pairs [out] list of overlapping pairs
+ * \return true if success.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool BoxPruning::bruteForceBipartiteBoxTest(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& /*axes*/)
+{
+ uint32_t nb0 = bounds0.size();
+ uint32_t nb1 = bounds1.size();
+ pairs.clear();
+
+ // Checkings
+ if(!nb0 || !nb1) return false;
+
+ // Brute-force nb0*nb1 overlap tests
+ for(uint32_t i=0;i<nb0;i++)
+ {
+ for(uint32_t j=0;j<nb1;j++)
+ {
+ if(bounds0[i].intersects(bounds1[j])) {
+ pairs.pushBack(i);
+ pairs.pushBack(j);
+ }
+ }
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
+ * \param nb [in] number of boxes
+ * \param list [in] list of boxes
+ * \param pairs [out] list of overlapping pairs
+ * \return true if success.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool BoxPruning::bruteForceCompleteBoxTest(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& /*axes*/)
+{
+ uint32_t nb = bounds.size();
+ pairs.clear();
+
+ // Checkings
+ if(!nb) return false;
+
+ // Brute-force n(n-1)/2 overlap tests
+ for(uint32_t i=0;i<nb;i++)
+ {
+ for(uint32_t j=i+1;j<nb;j++)
+ {
+ if(bounds[i].intersects(bounds[j]))
+ {
+ pairs.pushBack(i);
+ pairs.pushBack(j);
+ }
+ }
+ }
+ return true;
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.h b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.h
new file mode 100644
index 00000000..b7bb9119
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/IceBoxPruningBase.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Contains code for box pruning.
+ * \file IceBoxPruning.h
+ * \author Pierre Terdiman
+ * \date January, 29, 2000
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Include Guard
+#ifndef __ICEBOXPRUNING_BASE_H__
+#define __ICEBOXPRUNING_BASE_H__
+
+//#include "vector"
+#include <PsArray.h>
+#include "IceRevisitedRadixBase.h"
+#include "PxVec3.h"
+#include "PxBounds3.h"
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+ struct Axes
+ {
+ void set(uint32_t a0, uint32_t a1, uint32_t a2) {
+ Axis0 = a0; Axis1 = a1; Axis2 = a2;
+ }
+ uint32_t Axis0;
+ uint32_t Axis1;
+ uint32_t Axis2;
+ };
+
+ class BoxPruning : public UserAllocated
+ {
+ public:
+ // Optimized versions
+ bool completeBoxPruning(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& axes);
+ bool bipartiteBoxPruning(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& axes);
+
+ // Brute-force versions
+ bool bruteForceCompleteBoxTest(const nvidia::Array<PxBounds3> &bounds, nvidia::Array<uint32_t> &pairs, const Axes& axes);
+ bool bruteForceBipartiteBoxTest(const nvidia::Array<PxBounds3> &bounds0, const nvidia::Array<PxBounds3> &bounds1, nvidia::Array<uint32_t>& pairs, const Axes& axes);
+
+ protected:
+ nvidia::Array<float> mMinPosBounds0;
+ nvidia::Array<float> mMinPosBounds1;
+ nvidia::Array<float> mPosList;
+ RadixSort mRS0, mRS1;
+ RadixSort mRS;
+ };
+
+}
+}
+}
+
+#endif // __ICEBOXPRUNING_H__
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.cpp b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.cpp
new file mode 100644
index 00000000..116ea2c4
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Contains source code from the article "Radix Sort Revisited".
+ * \file IceRevisitedRadix.cpp
+ * \author Pierre Terdiman
+ * \date April, 4, 2000
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Revisited Radix Sort.
+ * This is my new radix routine:
+ * - it uses indices and doesn't recopy the values anymore, hence wasting less ram
+ * - it creates all the histograms in one run instead of four
+ * - it sorts words faster than dwords and bytes faster than words
+ * - it correctly sorts negative floating-point values by patching the offsets
+ * - it automatically takes advantage of temporal coherence
+ * - multiple keys support is a side effect of temporal coherence
+ * - it may be worth recoding in asm... (mainly to use FCOMI, FCMOV, etc) [it's probably memory-bound anyway]
+ *
+ * History:
+ * - 08.15.98: very first version
+ * - 04.04.00: recoded for the radix article
+ * - 12.xx.00: code lifting
+ * - 09.18.01: faster CHECK_PASS_VALIDITY thanks to Mark D. Shattuck (who provided other tips, not included here)
+ * - 10.11.01: added local ram support
+ * - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting......
+ * - 01.02.02: - "mIndices" renamed => "mRanks". That's a rank sorter after all.
+ * - ranks are not "reset" anymore, but implicit on first calls
+ *
+ * \class RadixSort
+ * \author Pierre Terdiman
+ * \version 1.4
+ * \date August, 15, 1998
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+To do:
+ - add an offset parameter between two input values (avoid some data recopy sometimes)
+ - unroll ? asm ?
+ - 11 bits trick & 3 passes as Michael did
+ - prefetch stuff the day I have a P3
+*/
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Precompiled Header
+#include "IceRevisitedRadixBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+#define INVALIDATE_RANKS mCurrentSize|=0x80000000
+#define VALIDATE_RANKS mCurrentSize&=0x7fffffff
+#define CURRENT_SIZE (mCurrentSize&0x7fffffff)
+#define INVALID_RANKS (mCurrentSize&0x80000000)
+
+#define CHECK_RESIZE(n) \
+ if(n!=mPreviousSize) \
+ { \
+ if(n>mCurrentSize) Resize(n); \
+ else ResetRanks(); \
+ mPreviousSize = n; \
+ }
+
+#define CREATE_HISTOGRAMS(type, buffer) \
+ /* Clear counters/histograms */ \
+ \
+ memset(mHistogram, 0, 256*4*sizeof(uint32_t)); \
+ \
+ /* Prepare to count */ \
+ uint8_t* p = (uint8_t*)input; \
+ uint8_t* pe = &p[nb*4]; \
+ uint32_t* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \
+ uint32_t* h1= &mHistogram[256]; /* Histogram for second pass */ \
+ uint32_t* h2= &mHistogram[512]; /* Histogram for third pass */ \
+ uint32_t* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \
+ \
+ bool AlreadySorted = true; /* Optimism... */ \
+ \
+ if(INVALID_RANKS) \
+ { \
+ /* Prepare for temporal coherence */ \
+ type* Running = (type*)buffer; \
+ type PrevVal = *Running; \
+ \
+ while(p!=pe) \
+ { \
+ /* Read input buffer in previous sorted order */ \
+ type Val = *Running++;; \
+ /* Check whether already sorted or not */ \
+ if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \
+ /* Update for next iteration */ \
+ PrevVal = Val; \
+ \
+ /* Create histograms */ \
+ h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
+ } \
+ \
+ /* If all input values are already sorted, we just have to return and leave the */ \
+ /* previous list unchanged. That way the routine may take advantage of temporal */ \
+ /* coherence, for example when used to sort transparent faces. */ \
+ if(AlreadySorted) \
+ { \
+ mNbHits++; \
+ for(uint32_t i=0;i<nb;i++) mRanks[i] = i; \
+ return *this; \
+ } \
+ } \
+ else \
+ { \
+ /* Prepare for temporal coherence */ \
+ uint32_t* Indices = mRanks; \
+ type PrevVal = (type)buffer[*Indices]; \
+ \
+ while(p!=pe) \
+ { \
+ /* Read input buffer in previous sorted order */ \
+ type Val = (type)buffer[*Indices++]; \
+ /* Check whether already sorted or not */ \
+ if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \
+ /* Update for next iteration */ \
+ PrevVal = Val; \
+ \
+ /* Create histograms */ \
+ h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
+ } \
+ \
+ /* If all input values are already sorted, we just have to return and leave the */ \
+ /* previous list unchanged. That way the routine may take advantage of temporal */ \
+ /* coherence, for example when used to sort transparent faces. */ \
+ if(AlreadySorted) { mNbHits++; return *this; } \
+ } \
+ \
+ /* Else there has been an early out and we must finish computing the histograms */ \
+ while(p!=pe) \
+ { \
+ /* Create histograms without the previous overhead */ \
+ h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
+ }
+
+#define CHECK_PASS_VALIDITY(pass) \
+ /* Shortcut to current counters */ \
+ uint32_t* CurCount = &mHistogram[pass<<8]; \
+ \
+ /* Reset flag. The sorting pass is supposed to be performed. (default) */ \
+ bool PerformPass = true; \
+ \
+ /* Check pass validity */ \
+ \
+ /* If all values have the same byte, sorting is useless. */ \
+ /* It may happen when sorting bytes or words instead of dwords. */ \
+ /* This routine actually sorts words faster than dwords, and bytes */ \
+ /* faster than words. Standard running time (O(4*n))is reduced to O(2*n) */ \
+ /* for words and O(n) for bytes. Running time for floats depends on actual values... */ \
+ \
+ /* Get first byte */ \
+ uint8_t UniqueVal = *(((uint8_t*)input)+pass); \
+ \
+ /* Check that byte's counter */ \
+ if(CurCount[UniqueVal]==nb) PerformPass=false;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+RadixSort::RadixSort() : mCurrentSize(0), mRanks(NULL), mRanks2(NULL), mTotalCalls(0), mNbHits(0)
+{
+ // Initialize indices
+ mRanksSize = 0;
+ INVALIDATE_RANKS;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Destructor.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+RadixSort::~RadixSort()
+{
+ // Release everything
+ PX_FREE(mRanks2);
+ PX_FREE(mRanks);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Resizes the inner lists.
+ * \param nb [in] new size (number of dwords)
+ * \return true if success
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool RadixSort::Resize(uint32_t nb)
+{
+ if (mRanksSize >= nb)
+ return true;
+
+ // Free previously used ram
+ PX_FREE(mRanks2);
+ PX_FREE(mRanks);
+
+ // Get some fresh one
+ mRanks = (uint32_t*) PX_ALLOC(sizeof(uint32_t)*nb,PX_DEBUG_EXP("RT_FRACTURE"));
+ mRanks2 = (uint32_t*) PX_ALLOC(sizeof(uint32_t)*nb,PX_DEBUG_EXP("RT_FRACTURE"));
+
+ mRanksSize = nb;
+
+ return true;
+}
+
+inline void RadixSort::CheckResize(uint32_t nb)
+{
+ uint32_t CurSize = CURRENT_SIZE;
+ if(nb!=CurSize)
+ {
+ if(nb>CurSize) Resize(nb);
+ mCurrentSize = nb;
+ INVALIDATE_RANKS;
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Main sort routine.
+ * This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.
+ * \param input [in] a list of integer values to sort
+ * \param nb [in] number of values to sort, must be < 2^31
+ * \param signedvalues [in] true to handle negative values, false if you know your input buffer only contains positive values
+ * \return Self-Reference
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+RadixSort& RadixSort::Sort(const uint32_t* input, uint32_t nb, bool signedvalues)
+{
+ // Checkings
+ if(!input || !nb || nb&0x80000000) return *this;
+
+ // Stats
+ mTotalCalls++;
+
+ // Resize lists if needed
+ CheckResize(nb);
+
+ // Create histograms (counters). Counters for all passes are created in one run.
+ // Pros: read input buffer once instead of four times
+ // Cons: mHistogram is 4Kb instead of 1Kb
+ // We must take care of signed/unsigned values for temporal coherence.... I just
+ // have 2 code paths even if just a single opcode changes. Self-modifying code, someone?
+ if(!signedvalues) { CREATE_HISTOGRAMS(uint32_t, input); }
+ else { CREATE_HISTOGRAMS(int32_t, input); }
+
+ // Compute #negative values involved if needed
+ uint32_t NbNegativeValues = 0;
+ if(signedvalues)
+ {
+ // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
+ // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
+ // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
+ uint32_t* h3= &mHistogram[768];
+ for(uint32_t i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
+ }
+
+ // Radix sort, j is the pass number (0=LSB, 3=MSB)
+ for(uint32_t j=0;j<4;j++)
+ {
+ CHECK_PASS_VALIDITY(j);
+
+ // Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is
+ // not a problem, numbers are correctly sorted anyway.
+ if(PerformPass)
+ {
+ // Should we care about negative values?
+ if(j!=3 || !signedvalues)
+ {
+ // Here we deal with positive values only
+
+ // Create offsets
+ mOffset[0] = 0;
+ for(uint32_t i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
+ }
+ else
+ {
+ // This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place.
+
+ // Create biased offsets, in order for negative numbers to be sorted as well
+ mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
+ for(uint32_t i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
+
+ // Fixing the wrong place for negative values
+ mOffset[128] = 0;
+ for(uint32_t i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
+ }
+
+ // Perform Radix Sort
+ uint8_t* InputBytes = (uint8_t*)input;
+ InputBytes += j;
+ if(INVALID_RANKS)
+ {
+ for(uint32_t i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
+ VALIDATE_RANKS;
+ }
+ else
+ {
+ uint32_t* Indices = mRanks;
+ uint32_t* IndicesEnd = &mRanks[nb];
+ while(Indices!=IndicesEnd)
+ {
+ uint32_t id = *Indices++;
+ mRanks2[mOffset[InputBytes[id<<2]]++] = id;
+ }
+ }
+
+ // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
+ uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
+ }
+ }
+ return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Main sort routine.
+ * This one is for floating-point values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data.
+ * \param input [in] a list of floating-point values to sort
+ * \param nb [in] number of values to sort, must be < 2^31
+ * \return Self-Reference
+ * \warning only sorts IEEE floating-point values
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+RadixSort& RadixSort::Sort(const float* input2, uint32_t nb)
+{
+ // Checkings
+ if(!input2 || !nb || nb&0x80000000) return *this;
+
+ // Stats
+ mTotalCalls++;
+
+ uint32_t* input = (uint32_t*)input2;
+
+ // Resize lists if needed
+ CheckResize(nb);
+
+ // Create histograms (counters). Counters for all passes are created in one run.
+ // Pros: read input buffer once instead of four times
+ // Cons: mHistogram is 4Kb instead of 1Kb
+ // Floating-point values are always supposed to be signed values, so there's only one code path there.
+ // Please note the floating point comparison needed for temporal coherence! Although the resulting asm code
+ // is dreadful, this is surprisingly not such a performance hit - well, I suppose that's a big one on first
+ // generation Pentiums....We can't make comparison on integer representations because, as Chris said, it just
+ // wouldn't work with mixed positive/negative values....
+ { CREATE_HISTOGRAMS(float, input2); }
+
+ // Compute #negative values involved if needed
+ uint32_t NbNegativeValues = 0;
+ // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
+ // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
+ // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
+ uint32_t* h3= &mHistogram[768];
+ for(uint32_t i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
+
+ // Radix sort, j is the pass number (0=LSB, 3=MSB)
+ for(uint32_t j=0;j<4;j++)
+ {
+ // Should we care about negative values?
+ if(j!=3)
+ {
+ // Here we deal with positive values only
+ CHECK_PASS_VALIDITY(j);
+
+ if(PerformPass)
+ {
+ // Create offsets
+ mOffset[0] = 0;
+ for(uint32_t i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
+
+ // Perform Radix Sort
+ uint8_t* InputBytes = (uint8_t*)input;
+ InputBytes += j;
+ if(INVALID_RANKS)
+ {
+ for(uint32_t i=0;i<nb;i++) mRanks2[mOffset[InputBytes[i<<2]]++] = i;
+ VALIDATE_RANKS;
+ }
+ else
+ {
+ uint32_t* Indices = mRanks;
+ uint32_t* IndicesEnd = &mRanks[nb];
+ while(Indices!=IndicesEnd)
+ {
+ uint32_t id = *Indices++;
+ mRanks2[mOffset[InputBytes[id<<2]]++] = id;
+ }
+ }
+
+ // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
+ uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
+ }
+ }
+ else
+ {
+ // This is a special case to correctly handle negative values
+ CHECK_PASS_VALIDITY(j);
+
+ if(PerformPass)
+ {
+ // Create biased offsets, in order for negative numbers to be sorted as well
+ mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
+ for(uint32_t i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
+
+ // We must reverse the sorting order for negative numbers!
+ mOffset[255] = 0;
+ for(uint32_t i=0;i<127;i++) mOffset[254-i] = mOffset[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
+ for(uint32_t i=128;i<256;i++) mOffset[i] += CurCount[i]; // Fixing the wrong place for negative values
+
+ // Perform Radix Sort
+ if(INVALID_RANKS)
+ {
+ for(uint32_t i=0;i<nb;i++)
+ {
+ uint32_t Radix = input[i]>>24; // Radix byte, same as above. AND is useless here (uint32_t).
+ // ### cmp to be killed. Not good. Later.
+ if(Radix<128) mRanks2[mOffset[Radix]++] = i; // Number is positive, same as above
+ else mRanks2[--mOffset[Radix]] = i; // Number is negative, flip the sorting order
+ }
+ VALIDATE_RANKS;
+ }
+ else
+ {
+ for(uint32_t i=0;i<nb;i++)
+ {
+ uint32_t Radix = input[mRanks[i]]>>24; // Radix byte, same as above. AND is useless here (uint32_t).
+ // ### cmp to be killed. Not good. Later.
+ if(Radix<128) mRanks2[mOffset[Radix]++] = mRanks[i]; // Number is positive, same as above
+ else mRanks2[--mOffset[Radix]] = mRanks[i]; // Number is negative, flip the sorting order
+ }
+ }
+ // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
+ uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
+ }
+ else
+ {
+ // The pass is useless, yet we still have to reverse the order of current list if all values are negative.
+ if(UniqueVal>=128)
+ {
+ if(INVALID_RANKS)
+ {
+ // ###Possible?
+ for(uint32_t i=0;i<nb;i++) mRanks2[i] = nb-i-1;
+ VALIDATE_RANKS;
+ }
+ else
+ {
+ for(uint32_t i=0;i<nb;i++) mRanks2[i] = mRanks[nb-i-1];
+ }
+
+ // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap.
+ uint32_t* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp;
+ }
+ }
+ }
+ }
+ return *this;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Gets the ram used.
+ * \return memory used in bytes
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+uint32_t RadixSort::GetUsedRam() const
+{
+ uint32_t UsedRam = sizeof(RadixSort);
+
+ UsedRam += 2*CURRENT_SIZE*sizeof(uint32_t); // 2 lists of indices
+ return UsedRam;
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.h b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.h
new file mode 100644
index 00000000..a7e9dede
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/IceRevisitedRadixBase.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Contains source code from the article "Radix Sort Revisited".
+ * \file IceRevisitedRadix.h
+ * \author Pierre Terdiman
+ * \date April, 4, 2000
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Include Guard
+#ifndef __ICERADIXSORT_BASE_H__
+#define __ICERADIXSORT_BASE_H__
+
+#include "PxSimpleTypes.h"
+#include "ApexUsingNamespace.h"
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+ class RadixSort : public UserAllocated
+ {
+ public:
+ // Constructor/Destructor
+ RadixSort();
+ virtual ~RadixSort();
+ // Sorting methods
+ RadixSort& Sort(const uint32_t* input, uint32_t nb, bool signedvalues=true);
+ RadixSort& Sort(const float* input, uint32_t nb);
+
+ //! Access to results. mRanks is a list of indices in sorted order, i.e. in the order you may further process your data
+ inline uint32_t* GetRanks() const { return mRanks; }
+
+ //! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want.
+ inline uint32_t* GetRecyclable() const { return mRanks2; }
+
+ // Stats
+ uint32_t GetUsedRam() const;
+ //! Returns the total number of calls to the radix sorter.
+ inline uint32_t GetNbTotalCalls() const { return mTotalCalls; }
+ //! Returns the number of premature exits due to temporal coherence.
+ inline uint32_t GetNbHits() const { return mNbHits; }
+
+ private:
+
+ uint32_t mHistogram[256*4]; //!< Counters for each byte
+ uint32_t mOffset[256]; //!< Offsets (nearly a cumulative distribution function)
+ uint32_t mCurrentSize; //!< Current size of the indices list
+
+ uint32_t mRanksSize;
+ uint32_t* mRanks; //!< Two lists, swapped each pass
+ uint32_t* mRanks2;
+ // Stats
+ uint32_t mTotalCalls;
+ uint32_t mNbHits;
+ // Internal methods
+ void CheckResize(uint32_t nb);
+ bool Resize(uint32_t nb);
+ };
+
+}
+}
+}
+
+#endif // __ICERADIXSORT_H__
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.cpp
new file mode 100644
index 00000000..387d5734
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.cpp
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "IslandDetectorBase.h"
+#include "ConvexBase.h"
+#include "CompoundGeometryBase.h"
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+// -----------------------------------------------------------------------------
+IslandDetector::IslandDetector(SimScene* scene):
+ mScene(scene)
+{
+ mNeigborPairsDirty = true;
+}
+
+// -----------------------------------------------------------------------------
+void IslandDetector::detect(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage)
+{
+ createConnectivity(convexes, computeFaceCoverage);
+ addOverlapConnectivity(convexes);
+ createIslands();
+ mNeigborPairsDirty = true;
+}
+
+// -----------------------------------------------------------------------------
+bool IslandDetector::touching(const Convex *c0, int faceNr, const Convex *c1, float eps)
+{
+ const Convex::Face &face = c0->getFaces()[(uint32_t)faceNr];
+ const nvidia::Array<int> &indices = c0->getIndices();
+ const nvidia::Array<PxVec3> &verts = c0->getVertices();
+ const nvidia::Array<PxPlane> &planes = c1->getPlanes();
+
+ for (int i = 0; i < face.numIndices; i++) {
+ PxVec3 v = verts[(uint32_t)indices[uint32_t(face.firstIndex + i)]];
+ v = v + c0->getMaterialOffset() - c1->getMaterialOffset(); // transform to c1
+ bool inside = true;
+ for (uint32_t j = 0; j < planes.size(); j++) {
+ const PxPlane &p = planes[j];
+ if (p.n.dot(v) - p.d > eps) {
+ inside = false;
+ break;
+ }
+ }
+ if (inside)
+ return true;
+ }
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+void IslandDetector::createConnectivity(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage)
+{
+ mFaces.clear();
+ Face face;
+ int globalNr = 0;
+
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ const Convex *c = convexes[i];
+ face.convexNr = (int32_t)i;
+ const nvidia::Array<PxPlane> &planes = c->getPlanes();
+ for (uint32_t j = 0; j < planes.size(); j++) {
+ globalNr++;
+ if (c->getFaces()[j].flags & CompoundGeometry::FF_OBJECT_SURFACE)
+ continue;
+ face.faceNr = (int32_t)j;
+ face.globalNr = globalNr-1;
+ float d = planes[j].d;
+ d = d + c->getMaterialOffset().dot(planes[j].n); // transform to global
+ face.orderVal = fabsf(d);
+ mFaces.pushBack(face);
+ }
+ }
+ mFaceCoverage.clear();
+
+ if (computeFaceCoverage) {
+ mFaceCoverage.resize((uint32_t)globalNr, 0.0f);
+ }
+
+ shdfnd::sort(mFaces.begin(), mFaces.size());
+
+ float eps = 1e-3f;
+ mFirstNeighbor.clear();
+ mFirstNeighbor.resize(convexes.size(), -1);
+ mNeighbors.clear();
+ Neighbor n;
+
+ for (uint32_t i = 0; i < mFaces.size(); i++) {
+ Face &fi = mFaces[i];
+ uint32_t j = i+1;
+ while (j < mFaces.size() && mFaces[j].orderVal - fi.orderVal < eps) {
+ Face &fj = mFaces[j];
+ j++;
+
+ if (fi.convexNr == fj.convexNr)
+ continue;
+
+ PxPlane pi = convexes[(uint32_t)fi.convexNr]->getPlanes()[(uint32_t)fi.faceNr];
+ if (convexes[(uint32_t)fi.convexNr]->isGhostConvex())
+ pi.n = -pi.n;
+
+ PxPlane pj = convexes[(uint32_t)fj.convexNr]->getPlanes()[(uint32_t)fj.faceNr];
+ if (convexes[(uint32_t)fj.convexNr]->isGhostConvex())
+ pj.n = -pj.n;
+
+ if (pi.n.dot(pj.n) > -1.0f + eps)
+ continue; // need to be opposite
+
+ if (
+ touching(convexes[(uint32_t)fi.convexNr], fi.faceNr, convexes[(uint32_t)fj.convexNr], eps) ||
+ touching(convexes[(uint32_t)fj.convexNr], fj.faceNr, convexes[(uint32_t)fi.convexNr], eps))
+ {
+ n.area = 0.5f*( fabsf(faceArea(convexes[(uint32_t)fi.convexNr], fi.faceNr)) + fabsf(faceArea(convexes[(uint32_t)fj.convexNr], fj.faceNr)));
+ if (computeFaceCoverage) {
+ float area = faceIntersectionArea(convexes[(uint32_t)fi.convexNr], fi.faceNr, convexes[(uint32_t)fj.convexNr], fj.faceNr);
+ mFaceCoverage[(uint32_t)fi.globalNr] += area;
+ mFaceCoverage[(uint32_t)fj.globalNr] += area;
+ }
+
+ n.convexNr = fj.convexNr;
+ n.next = mFirstNeighbor[(uint32_t)fi.convexNr];
+ mFirstNeighbor[(uint32_t)fi.convexNr] = (int32_t)mNeighbors.size();
+ mNeighbors.pushBack(n);
+
+ n.convexNr = fi.convexNr;
+ n.next = mFirstNeighbor[(uint32_t)fj.convexNr];
+ mFirstNeighbor[(uint32_t)fj.convexNr] = (int32_t)mNeighbors.size();
+ mNeighbors.pushBack(n);
+ }
+ }
+ }
+
+ if (computeFaceCoverage) {
+ uint32_t globalNr = 0;
+
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ const Convex *c = convexes[i];
+ int numFaces = (int32_t)c->getPlanes().size();
+ for (int j = 0; j < numFaces; j++) {
+ float total = faceArea(c, j);
+ if (total != 0.0f)
+ mFaceCoverage[globalNr] /= total;
+ globalNr++;
+ }
+ }
+ }
+
+ mNeigborPairsDirty = true;
+}
+
+// -----------------------------------------------------------------------------
+bool IslandDetector::axisOverlap(const Convex* c0, const Convex* c1, PxVec3 &dir)
+{
+ float off0 = c0->getMaterialOffset().dot(dir);
+ float off1 = c1->getMaterialOffset().dot(dir);
+ const nvidia::Array<PxVec3> &verts0 = c0->getVertices();
+ const nvidia::Array<PxVec3> &verts1 = c1->getVertices();
+ if (verts0.empty() || verts1.empty())
+ return false;
+
+ float d0 = dir.dot(verts0[0]) + off0;
+ float d1 = dir.dot(verts1[0]) + off1;
+ if (d0 < d1) {
+ float max0 = d0;
+ for (uint32_t i = 1; i < verts0.size(); i++) {
+ float d = verts0[i].dot(dir) + off0;
+ if (d > max0) max0 = d;
+ }
+ for (uint32_t i = 0; i < verts1.size(); i++) {
+ float d = verts1[i].dot(dir) + off1;
+ if (d < max0)
+ return true;
+ }
+ }
+ else {
+ float max1 = d1;
+ for (uint32_t i = 1; i < verts1.size(); i++) {
+ float d = verts1[i].dot(dir) + off1;
+ if (d > max1) max1 = d;
+ }
+ for (uint32_t i = 0; i < verts0.size(); i++) {
+ float d = verts0[i].dot(dir) + off0;
+ if (d < max1)
+ return true;
+ }
+ }
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+bool IslandDetector::overlap(const Convex* c0, const Convex* c1)
+{
+ PxVec3 off0 = c0->getMaterialOffset();
+ PxVec3 off1 = c1->getMaterialOffset();
+ PxVec3 center0 = c0->getCenter() + off0;
+ PxVec3 center1 = c1->getCenter() + off1;
+ PxVec3 dir = center1 - center0;
+
+ if (!axisOverlap(c0, c1, dir))
+ return false;
+
+ // todo: test other axes
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+void IslandDetector::addOverlapConnectivity(const nvidia::Array<Convex*> &convexes)
+{
+ mBounds.resize(convexes.size());
+ PxVec3 off;
+
+ for (uint32_t i = 0; i < convexes.size(); i++) {
+ const Convex *c = convexes[i];
+ const PxBounds3 &cb = c->getBounds();
+ off = c->getMaterialOffset();
+
+ PxBounds3 &b = mBounds[i];
+ b.minimum = cb.minimum + off;
+ b.maximum = cb.maximum + off;
+ }
+
+ // broad phase with AABBs
+ Axes axes;
+ axes.set(0,2,1);
+ mBoxPruning.completeBoxPruning(mBounds, mPairs, axes);
+
+ for (uint32_t i = 0; i < mPairs.size(); i += 2) {
+ uint32_t i0 = mPairs[i];
+ uint32_t i1 = mPairs[i+1];
+
+ if (convexes[i0]->getModelIslandNr() == convexes[i1]->getModelIslandNr())
+ continue;
+
+ // already detected?
+ bool found = false;
+ int nr = mFirstNeighbor[i0];
+ while (nr >= 0) {
+ Neighbor &n = mNeighbors[(uint32_t)nr];
+ nr = n.next;
+ if (n.convexNr == (int32_t)i1) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+
+ if (overlap(convexes[i0], convexes[i1])) {
+ Neighbor n;
+
+ // add link
+ n.convexNr = (int32_t)i0;
+ n.next = mFirstNeighbor[i1];
+ mFirstNeighbor[i1] = (int32_t)mNeighbors.size();
+ mNeighbors.pushBack(n);
+
+ n.convexNr = (int32_t)i1;
+ n.next = mFirstNeighbor[i0];
+ mFirstNeighbor[i0] = (int32_t)mNeighbors.size();
+ mNeighbors.pushBack(n);
+ }
+
+ }
+}
+
+// -----------------------------------------------------------------------------
+void IslandDetector::createIslands()
+{
+ uint32_t numConvexes = mFirstNeighbor.size();
+ mIslands.clear();
+ mIslandConvexes.clear();
+
+ Island island;
+
+ // color convexes
+ mColors.clear();
+ mColors.resize(numConvexes,-1);
+ int color = -1;
+
+ for (uint32_t i = 0; i < numConvexes; i++) {
+ if (mColors[i] >= 0)
+ continue;
+ mQueue.clear();
+ mQueue.pushBack((int32_t)i);
+ color++;
+ island.firstNr = (int32_t)mIslandConvexes.size();
+ island.size = 0;
+
+ while (mQueue.size() > 0) {
+ int convexNr = mQueue[mQueue.size()-1];
+ mQueue.popBack();
+ if (mColors[(uint32_t)convexNr] >= 0)
+ continue;
+ mColors[(uint32_t)convexNr] = color;
+ mIslandConvexes.pushBack(convexNr);
+ island.size++;
+
+ int nr = mFirstNeighbor[(uint32_t)convexNr];
+ while (nr >= 0) {
+ int adj = mNeighbors[(uint32_t)nr].convexNr;
+ nr = mNeighbors[(uint32_t)nr].next;
+ if (mColors[(uint32_t)adj] < 0)
+ mQueue.pushBack(adj);
+ }
+ }
+ mIslands.pushBack(island);
+ }
+}
+
+// -----------------------------------------------------------------------------
+float IslandDetector::faceArea(const Convex *c, int faceNr)
+{
+ const Convex::Face &face = c->getFaces()[(uint32_t)faceNr];
+ const nvidia::Array<PxVec3> &verts = c->getVertices();
+ const nvidia::Array<int> &indices = c->getIndices();
+
+ float area = 0.0f;
+ PxVec3 p0 = verts[(uint32_t)indices[(uint32_t)face.firstIndex]];
+ for (int i = 1; i < face.numIndices-1; i++) {
+ PxVec3 p1 = verts[(uint32_t)indices[uint32_t(face.firstIndex+i)]];
+ PxVec3 p2 = verts[(uint32_t)indices[uint32_t(face.firstIndex+i+1)]];
+ area += (p1-p0).cross(p2-p0).magnitude();
+ }
+ return 0.5f * area;
+}
+
+// -----------------------------------------------------------------------------
+float IslandDetector::faceIntersectionArea(const Convex *c0, int faceNr0, const Convex *c1, int faceNr1)
+{
+ // vertices of the first face
+ mCutPolys[0].clear();
+ mCutPolys[1].clear();
+
+ const Convex::Face &face0 = c0->getFaces()[(uint32_t)faceNr0];
+ const nvidia::Array<PxVec3> &verts0 = c0->getVertices();
+ const nvidia::Array<int> &indices0 = c0->getIndices();
+
+ const Convex::Face &face1 = c1->getFaces()[(uint32_t)faceNr1];
+ const nvidia::Array<PxVec3> &verts1 = c1->getVertices();
+ const nvidia::Array<int> &indices1 = c1->getIndices();
+
+ for (int i = 0; i < face0.numIndices; i++)
+ mCutPolys[0].pushBack(verts0[(uint32_t)indices0[uint32_t(face0.firstIndex + i)]]);
+
+ const PxVec3 &n0 = c0->getPlanes()[(uint32_t)faceNr0].n;
+
+ // cut face 0 polygon with face 1 polygon
+ for (int i = 0; i < face1.numIndices; i++) {
+ const PxVec3 &p0 = verts1[(uint32_t)indices1[uint32_t(face1.firstIndex + (i+1)%face1.numIndices)]];
+ const PxVec3 &p1 = verts1[(uint32_t)indices1[uint32_t(face1.firstIndex + i)]];
+ PxVec3 n = (p1-p0).cross(n0);
+ float d = n.dot(p0);
+
+ nvidia::Array<PxVec3> &currPoly = mCutPolys[uint32_t(i%2)];
+ nvidia::Array<PxVec3> &newPoly = mCutPolys[uint32_t(1 - (i%2))];
+ newPoly.clear();
+
+ uint32_t num = currPoly.size();
+ for (uint32_t j = 0; j < num; j++) {
+ PxVec3 &q0 = currPoly[j];
+ PxVec3 &q1 = currPoly[(j+1) % num];
+
+ bool inside0 = q0.dot(n) < d;
+ bool inside1 = q1.dot(n) < d;
+
+ if (inside0)
+ newPoly.pushBack(currPoly[j]); // point inside -> keep
+
+ if (inside0 != inside1) { // intersection
+ float s = (d - q0.dot(n)) / (q1-q0).dot(n);
+ PxVec3 ps = q0 + s*(q1-q0);
+ newPoly.pushBack(ps);
+ }
+ }
+ }
+
+ // measure area
+ float area = 0.0f;
+ nvidia::Array<PxVec3> &currPoly = mCutPolys[face1.numIndices%2];
+ if (currPoly.size() < 3)
+ return 0.0f;
+
+ PxVec3 &p0 = currPoly[0];
+ for (uint32_t i = 1; i < currPoly.size()-1; i++) {
+ PxVec3 &p1 = currPoly[i];
+ PxVec3 &p2 = currPoly[i+1];
+ area += (p1-p0).cross(p2-p0).magnitude();
+ }
+ return 0.5f * area;
+}
+
+// -----------------------------------------------------------------------------
+const nvidia::Array<IslandDetector::Edge> &IslandDetector::getNeighborEdges()
+{
+ if (mNeigborPairsDirty) {
+ Edge e;
+ mNeighborPairs.clear();
+ for (uint32_t i = 0; i < mFirstNeighbor.size(); i++) {
+ int nr = mFirstNeighbor[i];
+ e.n0 = (int32_t)i;
+ while (nr >= 0) {
+ Neighbor &n = mNeighbors[(uint32_t)nr];
+ nr = n.next;
+ if (n.convexNr > (int32_t)i) {
+ e.n1 = n.convexNr;
+ e.area = n.area;
+ mNeighborPairs.pushBack(e);
+ //mNeighborPairs.pushBack(i);
+ //mNeighborPairs.pushBack(n.convexNr);
+ }
+ }
+ }
+ mNeigborPairsDirty = false;
+ }
+ return mNeighborPairs;
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.h b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.h
new file mode 100644
index 00000000..d13ed849
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/IslandDetectorBase.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef ISLAND_DETECTOR_BASE_H
+#define ISLAND_DETECTOR_BASE_H
+
+// Matthias Muller-Fischer
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include "IceBoxPruningBase.h"
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+class SimScene;
+class Convex;
+
+// ---------------------------------------------------------------------------------------
+class IslandDetector : public UserAllocated {
+ friend class SimScene;
+public:
+ // singleton pattern
+ //static IslandDetector* getInstance();
+ //static void destroyInstance();
+
+ void detect(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage);
+
+ struct Island {
+ int size;
+ int firstNr;
+ };
+ const nvidia::Array<Island> &getIslands() { return mIslands; }
+ const nvidia::Array<int> &getIslandConvexes() { return mIslandConvexes; }
+
+ const nvidia::Array<float> &getFaceCoverage() { return mFaceCoverage; }
+
+ class Edge{
+ public:
+ int n0, n1;
+ float area;
+ };
+ const nvidia::Array<Edge> &getNeighborEdges();
+
+protected:
+ IslandDetector(SimScene* scene);
+ virtual ~IslandDetector(){}
+
+ void createConnectivity(const nvidia::Array<Convex*> &convexes, bool computeFaceCoverage);
+ static bool touching(const Convex *c0, int faceNr, const Convex *c1, float eps);
+ void createIslands();
+
+ float faceArea(const Convex *c, int faceNr);
+ float faceIntersectionArea(const Convex *c0, int faceNr0, const Convex *c1, int faceNr1);
+
+ bool axisOverlap(const Convex* c0, const Convex* c1, PxVec3 &dir);
+ bool overlap(const Convex* c0, const Convex* c1);
+
+ void addOverlapConnectivity(const nvidia::Array<Convex*> &convexes);
+
+ SimScene* mScene;
+
+ // auxiliary
+ nvidia::Array<int> mFirstNeighbor;
+ struct Neighbor {
+ int convexNr;
+ int next;
+ float area;
+ };
+ nvidia::Array<Neighbor> mNeighbors;
+ struct Face {
+ int convexNr;
+ int faceNr;
+ float orderVal;
+ int globalNr;
+ bool operator < (const Face &f) const { return orderVal < f.orderVal; }
+ };
+ bool mNeigborPairsDirty;
+ nvidia::Array<Edge> mNeighborPairs;
+ nvidia::Array<float> mNeighborAreaPairs;
+ nvidia::Array<Face> mFaces;
+ nvidia::Array<int> mColors;
+ nvidia::Array<int> mQueue;
+
+ nvidia::Array<PxVec3> mCutPolys[2];
+
+ // overlaps
+ BoxPruning mBoxPruning;
+ nvidia::Array<PxBounds3> mBounds;
+ nvidia::Array<uint32_t> mPairs;
+
+ // output
+ nvidia::Array<Island> mIslands;
+ nvidia::Array<int> mIslandConvexes;
+ nvidia::Array<float> mFaceCoverage;
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshBase.cpp b/APEX_1.4/module/destructible/fracture/Core/MeshBase.cpp
new file mode 100644
index 00000000..fecbd5d2
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/MeshBase.cpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include <PxBounds3.h>
+
+#include "MeshBase.h"
+#include <algorithm>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+// ----------------------------------------------------------------------
+void Mesh::updateNormals()
+{
+ if (mVertices.empty())
+ return;
+
+ PxVec3 zero(0.0f, 0.0f, 0.0f);
+
+ mNormals.resize(mVertices.size());
+ for (uint32_t i = 0; i < mNormals.size(); i++)
+ mNormals[i] = zero;
+ PxVec3 n;
+
+ uint32_t *idx = &mIndices[0];
+ uint32_t numTriangles = mIndices.size() / 3;
+ for (uint32_t i = 0; i < numTriangles; i++) {
+ uint32_t i0 = *idx++;
+ uint32_t i1 = *idx++;
+ uint32_t i2 = *idx++;
+ n = (mVertices[i1] - mVertices[i0]).cross(mVertices[i2] - mVertices[i0]);
+ mNormals[i0] += n;
+ mNormals[i1] += n;
+ mNormals[i2] += n;
+ }
+ for (uint32_t i = 0; i < mNormals.size(); i++) {
+ if (!mNormals[i].isZero())
+ mNormals[i].normalize();
+ }
+}
+
+// ------------------------------------------------------------------------------
+void Mesh::getBounds(PxBounds3 &bounds, int subMeshNr) const
+{
+ bounds.setEmpty();
+ if (subMeshNr < 0 || subMeshNr >= (int)mSubMeshes.size()) {
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ bounds.include(mVertices[i]);
+ }
+ else {
+ const SubMesh &sm = mSubMeshes[(uint32_t)subMeshNr];
+ for (int i = 0; i < sm.numIndices; i++) {
+ bounds.include(mVertices[(uint32_t)mIndices[uint32_t(sm.firstIndex + i)]]);
+ }
+ }
+}
+
+// ------------------------------------------------------------------------------
+void Mesh::normalize(const PxVec3 &center, float diagonal)
+{
+ if (mVertices.size() < 3)
+ return;
+
+ PxBounds3 bounds;
+ getBounds(bounds);
+
+ float s = diagonal / bounds.getDimensions().magnitude();
+ PxVec3 c = 0.5f * (bounds.minimum + bounds.maximum);
+
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ mVertices[i] = center + (mVertices[i] - c) * s;
+}
+
+// ------------------------------------------------------------------------------
+void Mesh::scale(float diagonal)
+{
+ if (mVertices.size() < 3)
+ return;
+
+ PxBounds3 bounds;
+ getBounds(bounds);
+
+ float s = diagonal / bounds.getDimensions().magnitude();
+ for (uint32_t i = 0; i < mVertices.size(); i++)
+ mVertices[i] *= s;
+}
+
+// --------------------------------------------------------------------------------------------
+struct IdEdge {
+ void set(uint32_t &i0, uint32_t &i1, int faceNr, int edgeNr) {
+ if (i0 < i1) { this->i0 = i0; this->i1 = i1; }
+ else { this->i0 = i1; this->i1 = i0; }
+ this->faceNr = faceNr; this->edgeNr = edgeNr;
+ }
+ bool operator < (const IdEdge &e) const {
+ if (i0 < e.i0) return true;
+ if (i0 == e.i0 && i1 < e.i1) return true;
+ return false;
+ }
+ bool operator == (const IdEdge &e) const { return i0 == e.i0 && i1 == e.i1; }
+ uint32_t i0,i1;
+ int faceNr, edgeNr;
+};
+
+// ------------------------------------------------------------------------------
+bool Mesh::computeNeighbors()
+{
+ uint32_t numTris = mIndices.size() / 3;
+
+ nvidia::Array<IdEdge> edges(3*numTris);
+
+ for (uint32_t i = 0; i < numTris; i++) {
+ for (uint32_t j = 0; j < 3; j++)
+ edges[3*i+j].set(mIndices[3*i+j], mIndices[3*i + (j+1)%3], (int32_t)i, (int32_t)j);
+ }
+ std::sort(edges.begin(), edges.end());
+
+ mNeighbors.clear();
+ mNeighbors.resize(mIndices.size(), -1);
+ bool manifold = true;
+ uint32_t i = 0;
+ while (i < edges.size()) {
+ IdEdge &e0 = edges[i];
+ i++;
+ if (i < edges.size() && edges[i] == e0) {
+ IdEdge &e1 = edges[i];
+ mNeighbors[uint32_t(3* e0.faceNr + e0.edgeNr)] = e1.faceNr;
+ mNeighbors[uint32_t(3* e1.faceNr + e1.edgeNr)] = e0.faceNr;
+ i++;
+ }
+ while (i < edges.size() && edges[i] == e0) {
+ manifold = false;
+ i++;
+ }
+ }
+ return manifold;
+}
+
+// --------------------------------------------------------------------------------------------
+struct PosEdge {
+ // not using indices for edge match but positions
+ // so duplicated vertices are handled as one vertex
+ static bool smaller(const PxVec3 &v0, const PxVec3 &v1) {
+ if (v0.x < v1.x) return true;
+ if (v0.x > v1.x) return false;
+ if (v0.y < v1.y) return true;
+ if (v0.y > v1.y) return false;
+ return (v0.z < v1.z);
+ }
+ void set(const PxVec3 &v0, const PxVec3 &v1, int faceNr, int edgeNr) {
+ if (smaller(v0,v1)) { this->v0 = v0; this->v1 = v1; }
+ else { this->v0 = v1; this->v1 = v0; }
+ this->faceNr = faceNr; this->edgeNr = edgeNr;
+ }
+ bool operator < (const PosEdge &e) const {
+ if (smaller(v0, e.v0)) return true;
+ if (v0 == e.v0 && smaller(v1, e.v1)) return true;
+ return false;
+ }
+ bool operator == (const PosEdge &e) const { return v0 == e.v0 && v1 == e.v1; }
+ PxVec3 v0,v1;
+ int faceNr, edgeNr;
+};
+
+// ------------------------------------------------------------------------------
+bool Mesh::computeWeldedNeighbors()
+{
+ uint32_t numTris = mIndices.size() / 3;
+ nvidia::Array<PosEdge> edges(3*numTris);
+
+ for (uint32_t i = 0; i < numTris; i++) {
+ for (uint32_t j = 0; j < 3; j++)
+ edges[3*i+j].set(mVertices[(uint32_t)mIndices[3*i+j]], mVertices[(uint32_t)mIndices[3*i + (j+1)%3]], (int32_t)i, (int32_t)j);
+ }
+ std::sort(edges.begin(), edges.end());
+
+ mNeighbors.clear();
+ mNeighbors.resize(mIndices.size(), -1);
+ bool manifold = true;
+ uint32_t i = 0;
+ while (i < edges.size()) {
+ PosEdge &e0 = edges[i];
+ i++;
+ if (i < edges.size() && edges[i] == e0) {
+ PosEdge &e1 = edges[i];
+ mNeighbors[uint32_t(3* e0.faceNr + e0.edgeNr)] = e1.faceNr;
+ mNeighbors[uint32_t(3* e1.faceNr + e1.edgeNr)] = e0.faceNr;
+ i++;
+ }
+ while (i < edges.size() && edges[i] == e0) {
+ manifold = false;
+ i++;
+ }
+ }
+ return manifold;
+}
+
+void Mesh::flipV()
+{
+ for(uint32_t i = 0; i < mTexCoords.size(); i++)
+ {
+ mTexCoords[i].y = 1.0f - mTexCoords[i].y;
+ }
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshBase.h b/APEX_1.4/module/destructible/fracture/Core/MeshBase.h
new file mode 100644
index 00000000..db4617c4
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/MeshBase.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef MESH_BASE
+#define MESH_BASE
+
+#include <PxVec3.h>
+#include <PxVec2.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+// -----------------------------------------------------------------------------------
+class Mesh : public UserAllocated
+{
+public:
+ Mesh() {};
+ virtual ~Mesh() {};
+
+ const nvidia::Array<PxVec3> &getVertices() const { return mVertices; }
+ const nvidia::Array<PxVec3> &getNormals() const { return mNormals; }
+ const nvidia::Array<PxVec2> &getTexCoords() const { return mTexCoords; }
+ const nvidia::Array<uint32_t> &getIndices() const { return mIndices; }
+ const nvidia::Array<int> &getNeighbors() const { return mNeighbors; }
+
+ struct SubMesh {
+ void init() { /*name = "";*/ firstIndex = -1; numIndices = 0; }
+ //std::string name;
+ int firstIndex;
+ int numIndices;
+ };
+
+ const nvidia::Array<SubMesh> &getSubMeshes() const { return mSubMeshes; }
+
+ void normalize(const PxVec3 &center, float diagonal);
+ void scale(float diagonal);
+ void getBounds(PxBounds3 &bounds, int subMeshNr = -1) const;
+
+ void flipV(); // flips v values to hand coordinate system change (Assumes normalized coordinates)
+
+ bool computeNeighbors();
+ bool computeWeldedNeighbors();
+
+protected:
+ void clear();
+ void updateNormals();
+
+ nvidia::Array<PxVec3> mVertices;
+ nvidia::Array<PxVec3> mNormals;
+ nvidia::Array<PxVec2> mTexCoords;
+
+ nvidia::Array<SubMesh> mSubMeshes;
+ nvidia::Array<uint32_t> mIndices;
+ nvidia::Array<int> mNeighbors;
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.cpp b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.cpp
new file mode 100644
index 00000000..cccbb023
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.cpp
@@ -0,0 +1,1439 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "MeshClipperBase.h"
+#include "PsSort.h"
+#include "ConvexBase.h"
+#include <PxAssert.h>
+
+#define DEBUG 0
+#if DEBUG
+#include <stdio.h>
+#else
+#define printf(...)
+#define fwrite(...)
+#define fread(...)
+#define fopen(...)
+#define fclose(...)
+#endif
+
+#include "SimSceneBase.h"
+
+#pragma warning(disable:4127)
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+int vecFloor(float f ) { return (int)::floorf(f); }
+
+#define DUMP_PATH "c:\\meshClipDump.bin"
+
+// -----------------------------------------------------------------------------
+MeshClipper::MeshClipper(SimScene* scene)
+{
+ mScene = scene;
+ mMeshConvex = NULL;
+ mClipConvex = NULL;
+ mDumpOnError = false;
+}
+
+// -----------------------------------------------------------------------------
+void MeshClipper::Mesh::clear()
+{
+ vertices.clear();
+ normals.clear();
+ tangents.clear();
+ texCoords.clear();
+ polyStarts.resize(1, 0);
+ polyIndices.clear();
+ polyNeighbors.clear();
+}
+
+// -----------------------------------------------------------------------------
+//PxVec3 MeshClipper::conv(const Vec3 &v)
+//{
+// return PxVec3((float)v.x, (float)v.y, (float)v.z);
+//}
+//
+//Vec3 MeshClipper::conv(const PxVec3 &v)
+//{
+// return Vec3((VecReal)v.x, (VecReal)v.y, (VecReal)v.z);
+//}
+//
+//Plane MeshClipper::conv(const PxPlane &p)
+//{
+// return Plane(conv(p.n), VecReal(p.d));
+//}
+//
+//Transform MeshClipper::conv(const PxTransform &t)
+//{
+// return Transform(conv(t.p), Quat(t.q.x, t.q.y, t.q.z, t.q.w));
+//}
+
+// -----------------------------------------------------------------------------
+int MeshClipper::getNumMeshes()
+{
+ if (mOutMeshes.size() == 1) // no islands
+ return 1;
+ else
+ return (int32_t)mOutMeshes.size()-1;
+}
+
+// -----------------------------------------------------------------------------
+const MeshClipper::Mesh& MeshClipper::getMesh(int meshNr)
+{
+ if (mOutMeshes.size() == 1) // no islands
+ return mOutMeshes[0];
+ else
+ return mOutMeshes[1 + (uint32_t)meshNr];
+}
+
+// -----------------------------------------------------------------------------
+void MeshClipper::init(const Convex *meshConvex)
+{
+ if (!meshConvex->hasExplicitVisMesh()) {
+ mMeshConvex = NULL;
+ return;
+ }
+
+ mMeshConvex = meshConvex;
+ const nvidia::Array<PxVec3> &verts = mMeshConvex->getVisVertices();
+ mMeshVertices.resize(verts.size());
+ for (uint32_t i = 0; i < verts.size(); i++)
+ mMeshVertices[i] = verts[i];
+
+ PxVec3 center(0.0, 0.0, 0.0);
+ for (uint32_t i = 0; i < mMeshVertices.size(); i++)
+ center += mMeshVertices[i];
+ center /= (float)mMeshVertices.size();
+
+ for (uint32_t i = 0; i < mMeshVertices.size(); i++) {
+ mMeshVertices[i] = center + (mMeshVertices[i] - center) * 1.001f;
+ }
+
+ const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts();
+ const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices();
+ uint32_t numPolys = meshPolyStarts.size()-1;
+
+ mPolyBounds.resize(numPolys);
+ for (uint32_t i = 0; i < numPolys; i++) {
+ int first = meshPolyStarts[i];
+ int last = meshPolyStarts[i+1];
+ mPolyBounds[i].setEmpty();
+ for (int k = first; k < last; k++)
+ mPolyBounds[i].include(mMeshVertices[(uint32_t)meshPolyIndices[(uint32_t)k]]);
+ }
+
+ createGrid();
+}
+
+// --------------------------------------------------------------------------------------------
+void MeshClipper::createGrid()
+{
+ const uint32_t minGridPolys = 1000;
+
+ uint32_t numPolys = mPolyBounds.size();
+ mGridFirstPoly.clear();
+
+ if (numPolys < minGridPolys)
+ return;
+
+ // determine grid dimensions
+ PxBounds3 meshBounds;
+ meshBounds.setEmpty();
+ for (uint32_t i = 0; i < mMeshVertices.size(); i++)
+ meshBounds.include(mMeshVertices[i]);
+ PxVec3 meshExtent = meshBounds.maximum - meshBounds.minimum;
+
+ // number of cells in the order of num polygons
+// int targetNumCells = numPolys;
+ float targetNumCells = 10000;
+ float s3 = meshExtent.x * meshExtent.y * meshExtent.z / (float)targetNumCells;
+ mGridSpacing = PxPow((float)s3, 1.0f/3.0f);
+
+ mGridBounds.minimum = meshBounds.minimum;
+ mGridNumX = vecFloor(meshExtent.x / mGridSpacing) + 1;
+ mGridNumY = vecFloor(meshExtent.y / mGridSpacing) + 1;
+ mGridNumZ = vecFloor(meshExtent.z / mGridSpacing) + 1;
+ uint32_t numCells = uint32_t(mGridNumX * mGridNumY * mGridNumZ);
+ mGridBounds.maximum = mGridBounds.minimum +
+ PxVec3(mGridNumX * mGridSpacing, mGridNumY * mGridSpacing, mGridNumZ * mGridSpacing);
+
+ mGridFirstPoly.resize(numCells+1, -0);
+ mGridPolys.clear();
+
+ // histogram
+ //float h = mGridSpacing;
+ float h1 = 1.0f / mGridSpacing;
+ PxBounds3 polyBounds;
+ for (uint32_t i = 0; i < numPolys; i++) {
+ PxBounds3 &polyBounds = mPolyBounds[i];
+ int x0 = (int)((polyBounds.minimum.x - mGridBounds.minimum.x) * h1);
+ int y0 = (int)((polyBounds.minimum.y - mGridBounds.minimum.y) * h1);
+ int z0 = (int)((polyBounds.minimum.z - mGridBounds.minimum.z) * h1);
+ int x1 = (int)((polyBounds.maximum.x - mGridBounds.minimum.x) * h1);
+ int y1 = (int)((polyBounds.maximum.y - mGridBounds.minimum.y) * h1);
+ int z1 = (int)((polyBounds.maximum.z - mGridBounds.minimum.z) * h1);
+ for (int xi = x0; xi <= x1; xi++) {
+ for (int yi = y0; yi <= y1; yi++) {
+ for (int zi = z0; zi <= z1; zi++) {
+ int nr = (xi * mGridNumY + yi) * mGridNumZ + zi;
+ mGridFirstPoly[(uint32_t)nr]++;
+ }
+ }
+ }
+ }
+ int first = 0;
+ for (uint32_t i = 0; i < numCells; i++) {
+ first += mGridFirstPoly[i];
+ mGridFirstPoly[i] = first;
+ }
+ mGridFirstPoly[numCells] = first;
+ mGridPolys.resize((uint32_t)first);
+
+ // fill in
+ for (uint32_t i = 0; i < numPolys; i++) {
+ PxBounds3 &polyBounds = mPolyBounds[i];
+ int x0 = (int)((polyBounds.minimum.x - mGridBounds.minimum.x) * h1);
+ int y0 = (int)((polyBounds.minimum.y - mGridBounds.minimum.y) * h1);
+ int z0 = (int)((polyBounds.minimum.z - mGridBounds.minimum.z) * h1);
+ int x1 = (int)((polyBounds.maximum.x - mGridBounds.minimum.x) * h1);
+ int y1 = (int)((polyBounds.maximum.y - mGridBounds.minimum.y) * h1);
+ int z1 = (int)((polyBounds.maximum.z - mGridBounds.minimum.z) * h1);
+ for (int xi = x0; xi <= x1; xi++) {
+ for (int yi = y0; yi <= y1; yi++) {
+ for (int zi = z0; zi <= z1; zi++) {
+ int nr = (xi * mGridNumY + yi) * mGridNumZ + zi;
+ mGridFirstPoly[(uint32_t)nr]--;
+ mGridPolys[(uint32_t)mGridFirstPoly[(uint32_t)nr]] = (int32_t)i;
+ }
+ }
+ }
+ }
+ mGridPolyMarks.clear();
+ mGridPolyMarks.resize(numPolys, 0);
+ mGridCurrentMark = 1;
+}
+
+// --------------------------------------------------------------------------------------------
+void MeshClipper::computeClipFaceNeighbors()
+{
+ const nvidia::Array<int> &indices = mClipConvex->getIndices();
+ const nvidia::Array<Convex::Face> &faces = mClipConvex->getFaces();
+
+ mClipFaceNeighbors.clear();
+ mClipFaceNeighbors.resize(indices.size(), -1);
+
+ mEdges.resize(indices.size());
+ //int edgeNr = 0;
+ for (uint32_t i = 0; i < faces.size(); i++) {
+ const Convex::Face &f = faces[i];
+ for (int j = 0; j < f.numIndices; j++) {
+ int edgeNr = f.firstIndex + j;
+ mEdges[(uint32_t)edgeNr].init(indices[uint32_t(f.firstIndex + j)], indices[uint32_t(f.firstIndex + (j+1)%f.numIndices)], edgeNr, (int32_t)i);
+ }
+ }
+ shdfnd::sort(mEdges.begin(), mEdges.size());
+ uint32_t i = 0;
+ while (i < mEdges.size()) {
+ Edge &e0 = mEdges[i];
+ i++;
+ if (i < mEdges.size() && mEdges[i] == e0) {
+ Edge &e1 = mEdges[i];
+ mClipFaceNeighbors[(uint32_t)e0.edgeNr] = e1.faceNr;
+ mClipFaceNeighbors[(uint32_t)e1.edgeNr] = e0.faceNr;
+ i++;
+ }
+ while (i < mEdges.size() && mEdges[i] == e0)
+ i++;
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+bool MeshClipper::getGridCandidates(const PxBounds3 &bounds)
+{
+ if (mGridFirstPoly.empty())
+ return false; // too few mesh polygons, no grid created
+
+ float h1 = 1.0f / mGridSpacing;
+ mGridCurrentMark++; // make sure we return any poligon only once
+
+ int x0 = vecFloor((bounds.minimum.x - mGridBounds.minimum.x) * h1);
+ int y0 = vecFloor((bounds.minimum.y - mGridBounds.minimum.y) * h1);
+ int z0 = vecFloor((bounds.minimum.z - mGridBounds.minimum.z) * h1);
+ int x1 = vecFloor((bounds.maximum.x - mGridBounds.minimum.x) * h1);
+ int y1 = vecFloor((bounds.maximum.y - mGridBounds.minimum.y) * h1);
+ int z1 = vecFloor((bounds.maximum.z - mGridBounds.minimum.z) * h1);
+
+ if (x0 < 0) x0 = 0;
+ if (y0 < 0) y0 = 0;
+ if (z0 < 0) z0 = 0;
+ if (x1 >= mGridNumX) x1 = mGridNumX-1;
+ if (y1 >= mGridNumY) y1 = mGridNumY-1;
+ if (z1 >= mGridNumZ) z1 = mGridNumZ-1;
+
+
+ mPolyCandidates.clear();
+
+ for (int xi = x0; xi <= x1; xi++) {
+ for (int yi = y0; yi <= y1; yi++) {
+ for (int zi = z0; zi <= z1; zi++) {
+ int nr = (xi * mGridNumY + yi) * mGridNumZ + zi;
+ int first = mGridFirstPoly[(uint32_t)nr];
+ int last = mGridFirstPoly[(uint32_t)nr+1];
+ for (int i = first; i < last; i++) {
+ int polyNr = mGridPolys[(uint32_t)i];
+ if (mGridPolyMarks[(uint32_t)polyNr] != mGridCurrentMark) {
+ mGridPolyMarks[(uint32_t)polyNr] = mGridCurrentMark;
+ mPolyCandidates.pushBack(polyNr);
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+void MeshClipper::generateCandidates(const PxTransform &pxTrans)
+{
+ // cull polys that are completely outside of at least one convex plane
+ // determine polys that are completely inside of all convex planes
+
+ const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts();
+ const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices();
+
+ const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes();
+ const nvidia::Array<PxVec3> &clipConvexVertices = mClipConvex->getVertices();
+
+ PxTransform trans = (pxTrans);
+ PxTransform invTrans = trans.getInverse();
+
+ PxBounds3 clipBounds;
+ clipBounds.setEmpty();
+ for (uint32_t i = 0; i < clipConvexVertices.size(); i++)
+ clipBounds.include(invTrans.transform((clipConvexVertices[i])));
+
+ uint32_t numPolys = meshPolyStarts.size()-1;
+
+ // use grid for initial culling
+ if (!getGridCandidates(clipBounds)) {
+ mPolyCandidates.resize(numPolys); // no grid, start with all polys
+ for (uint32_t i = 0; i < numPolys; i++)
+ mPolyCandidates[i] = (int32_t)i;
+ }
+
+ // use bounding boxes for further culling
+ PxBounds3 polyBounds;
+ uint32_t numCandidates = 0;
+ for (uint32_t i = 0; i < mPolyCandidates.size(); i++) {
+ int polyNr = mPolyCandidates[i];
+ PxBounds3 &polyBounds = mPolyBounds[(uint32_t)polyNr];
+ if (polyBounds.intersects(clipBounds)) {
+ mPolyCandidates[numCandidates] = polyNr;
+ numCandidates++;
+ }
+ }
+ mPolyCandidates.resize(numCandidates);
+
+ // use clip planes for further culling
+ mPolyInside.resize(0);
+ mPolyInside.resize(numPolys, true);
+
+ for (uint32_t i = 0; i < clipPlanes.size(); i++) {
+ PxPlane plane = (clipPlanes[i]);
+ plane.n = invTrans.rotate(plane.n);
+ plane.d = plane.d + invTrans.p.dot(plane.n);
+
+ uint32_t numCandidates = 0;
+ for (uint32_t j = 0; j < mPolyCandidates.size(); j++) {
+ uint32_t polyNr = (uint32_t)mPolyCandidates[j];
+ int first = meshPolyStarts[polyNr];
+ int last = meshPolyStarts[polyNr+1];
+ bool outside = true;
+ for (int k = first; k < last; k++) {
+ PxVec3 &p = mMeshVertices[(uint32_t)meshPolyIndices[(uint32_t)k]];
+ float dot = plane.n.dot(p);
+ if (dot > plane.d)
+ mPolyInside[polyNr] = false;
+ if (dot < plane.d)
+ outside = false;
+ if (!mPolyInside[polyNr] && !outside)
+ break;
+ }
+ if (!outside) {
+ mPolyCandidates[numCandidates] = (int32_t)polyNr;
+ numCandidates++;
+ }
+ }
+ mPolyCandidates.resize(numCandidates);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+bool MeshClipper::createInternalPolygons(const PxTransform &pxTrans)
+{
+#if VEC3_DOUBLE
+ const float eps = 1e-8f;
+#else
+ const float eps = 1e-4f;
+#endif
+
+ PxTransform trans = (pxTrans);
+
+ const nvidia::Array<PxVec3> &meshNormals = mMeshConvex->getVisNormals();
+ const nvidia::Array<PxVec3> &meshTangents = mMeshConvex->getVisTangents();
+ const nvidia::Array<float> &meshTexCoords = mMeshConvex->getVisTexCoords();
+
+ const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts();
+ const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices();
+ const nvidia::Array<int> &meshPolyNeighbors = mMeshConvex->getVisPolyNeighbors();
+
+ const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes();
+ //const nvidia::Array<Convex::Face> &clipConvexFaces = mClipConvex->getFaces();
+
+ uint32_t current = 0;
+ Mesh &out = mOutMeshes[0];
+
+ for (uint32_t i = 0; i < mPolyCandidates.size(); i++) {
+ uint32_t polyNr = (uint32_t)mPolyCandidates[i];
+
+ int first = meshPolyStarts[polyNr];
+ int last = meshPolyStarts[polyNr+1];
+ int polySize = last - first;
+ PX_ASSERT(polySize >= 3);
+
+ // initialize working poly with original poly
+ // todo: fast poly for insides
+
+ mClipPolyStarts[current].resize(2, 0);
+ mClipPolyStarts[current][1] = polySize;
+
+ mClipPolyVerts[current].resize((uint32_t)polySize);
+
+ if (mPolyInside[polyNr]) { // fast path for polygons completely inside convex
+
+ mFirstOutPoly[polyNr] = (int32_t)out.polyStarts.size()-1;
+ mNumOutPolys[polyNr] = 1;
+
+ for (int j = 0; j < polySize; j++) {
+ uint32_t id = (uint32_t)meshPolyIndices[uint32_t(first + j)];
+ if (mOutVertNr[id] < 0) {
+ mOutVertNr[id] = (int32_t)out.vertices.size();
+ out.vertices.pushBack((trans.transform(mMeshVertices[id])));
+ out.normals.pushBack(pxTrans.rotate(meshNormals[id]));
+ out.tangents.pushBack(pxTrans.rotate(meshTangents[id]));
+ out.texCoords.pushBack(meshTexCoords[2*id]);
+ out.texCoords.pushBack(meshTexCoords[2*id+1]);
+ }
+ out.polyIndices.pushBack(mOutVertNr[id]);
+ out.polyNeighbors.pushBack(meshPolyNeighbors[uint32_t(first + j)]);
+ }
+ out.polyStarts.pushBack((int32_t)out.polyIndices.size());
+ continue;
+ }
+
+ for (int j = 0; j < polySize; j++) {
+ PolyVert &pv = mClipPolyVerts[current][(uint32_t)j];
+ pv.init();
+ pv.id = meshPolyIndices[uint32_t(first + j)];
+ pv.pos = trans.transform(mMeshVertices[(uint32_t)pv.id]);
+ pv.normal = trans.rotate((meshNormals[(uint32_t)pv.id]));
+ pv.tangent = trans.rotate((meshTangents[(uint32_t)pv.id]));
+ pv.u = meshTexCoords[2 * (uint32_t)pv.id];
+ pv.v = meshTexCoords[2 * (uint32_t)pv.id + 1];
+ pv.edgeNeighbor = meshPolyNeighbors[uint32_t(first + j)];
+ pv.edgeOnFace = false;
+ }
+
+ // determine face normal
+ PxVec3 faceNormal(0.0, 0.0, 0.0);
+ PxVec3 &p0 = mClipPolyVerts[current][0].pos;
+ for (int j = 1; j < polySize-1; j++) {
+ PxVec3 &p1 = mClipPolyVerts[current][(uint32_t)j].pos;
+ PxVec3 &p2 = mClipPolyVerts[current][(uint32_t)j+1].pos;
+ faceNormal += (p1-p0).cross(p2-p0);
+ }
+ faceNormal.normalize();
+
+ // clip working poly against all planes
+ for (uint32_t j = 0; j < clipPlanes.size(); j++) {
+
+ const PxPlane plane = (clipPlanes[j]);
+ PxVec3 cutNormal = faceNormal.cross(plane.n);
+ if (cutNormal.magnitudeSquared() < eps * eps)
+ continue;
+
+ uint32_t prev = current;
+ current = 1-current;
+
+ mClipPolyStarts[current].clear();
+ mClipPolyStarts[current].pushBack(0);
+ mClipPolyVerts[current].clear();
+
+ uint32_t numPrevPolys = mClipPolyStarts[prev].size()-1;
+ if (numPrevPolys == 0)
+ break;
+
+ for (uint32_t k = 0; k < numPrevPolys; k++) {
+ int prevFirst = mClipPolyStarts[prev][k];
+ int prevLast = mClipPolyStarts[prev][k+1];
+ int prevNum = prevLast - prevFirst;
+
+ // determine cuts
+ mCuts.clear();
+ bool anyIn = false;
+
+ for (int l = 0; l < prevNum; l++) {
+ PolyVert &pv0 = mClipPolyVerts[prev][uint32_t(prevFirst + l)];
+ PolyVert &pv1 = mClipPolyVerts[prev][uint32_t(prevFirst + (l+1)%prevNum)];
+ pv0.nextVert = -1;
+
+ bool sign0 = plane.n.dot(pv0.pos) > plane.d;
+ bool sign1 = plane.n.dot(pv1.pos) > plane.d;
+
+ if (!sign0 || !sign1)
+ anyIn = true;
+
+ if (sign0 == sign1)
+ continue;
+
+ PxVec3 p0 = pv0.pos;
+ PxVec3 p1 = pv1.pos;
+
+ // compute in unique order such that cut positions are identical on shared edges
+ bool smaller =
+ (p0.x < p1.x) ||
+ (p0.x == p1.x && p0.y < p1.y) ||
+ (p0.x == p1.x && p0.y == p1.y && p0.z < p1.z);
+ if (smaller) {
+ p0 = pv1.pos;
+ p1 = pv0.pos;
+ }
+
+ float t = (p1 - p0).dot(plane.n);
+ if (t == 0.0)
+ continue;
+ t = (plane.d - p0.dot(plane.n)) / t;
+
+ PolyVert cut;
+ cut.init();
+ cut.pos = p0 + (p1 - p0) * t;
+ if (smaller) {
+ cut.normal = pv1.normal + (pv0.normal - pv1.normal) * t;
+ cut.tangent = pv1.tangent + (pv0.tangent - pv1.tangent) * t;
+ cut.u = pv1.u + (pv0.u - pv1.u) * t;
+ cut.v = pv1.v + (pv0.v - pv1.v) * t;
+ }
+ else {
+ cut.normal = pv0.normal + (pv1.normal - pv0.normal) * t;
+ cut.tangent = pv0.tangent + (pv1.tangent - pv0.tangent) * t;
+ cut.u = pv0.u + (pv1.u - pv0.u) * t;
+ cut.v = pv0.v + (pv1.v - pv0.v) * t;
+ }
+ cut.normal.normalize();
+ cut.tangent.normalize();
+ cut.id = -1;
+
+ // vertex following this cut
+ if (sign1) {
+ cut.edgeOnFace = true;
+ cut.edgeNeighbor = (int32_t)j; // planeNr
+ cut.nextVert = -1; // exit convex
+ }
+ else {
+ cut.edgeOnFace = pv0.edgeOnFace;
+ cut.edgeNeighbor = pv0.edgeNeighbor;
+ cut.nextVert = (l+1)%prevNum; // enter convex
+ }
+
+ pv0.nextVert = (int32_t)mCuts.size();
+ mCuts.pushBack(cut);
+ }
+ if (!anyIn)
+ continue;
+
+ // poly not cut, copy 1:1
+ if (mCuts.empty()) {
+ for (int l = 0; l < prevNum; l++) {
+ PolyVert &pv = mClipPolyVerts[prev][uint32_t(prevFirst + l)];
+ mClipPolyVerts[current].pushBack(pv);
+ }
+ mClipPolyStarts[current].pushBack((int32_t)mClipPolyVerts[current].size());
+ continue;
+ }
+
+ // construct new polygon(s)
+ for (uint32_t l = 0; l < mCuts.size(); l++)
+ {
+ if (mCuts[l].nextVert < 0) // exit polygon
+ continue;
+
+ // start a polygon from this cut
+ int nr = mCuts[l].nextVert;
+ mCuts[l].nextVert = -1; // visited
+ mClipPolyVerts[current].pushBack(mCuts[l]);
+
+ int safetyCnt = 0;
+
+ while ( true )
+ {
+ if (!check(safetyCnt < prevNum + (int)mCuts.size(), "construct new polygons infinite loop"))
+ return false;
+ safetyCnt++;
+
+ if (!check(nr >= 0, "construct new polygons loop not closed"))
+ return false;
+
+ if(nr >= (int)mClipPolyVerts[prev].size()) // prevents a crash
+ return false;
+
+ mClipPolyVerts[current].pushBack(mClipPolyVerts[prev][(uint32_t)nr]);
+ int cutNr = mClipPolyVerts[prev][(uint32_t)nr].nextVert;
+ if (cutNr < 0) {
+ nr = (nr+1) % prevNum;
+ continue;
+ }
+ // we reached the next cut
+ mClipPolyVerts[current].pushBack(mCuts[(uint32_t)cutNr]);
+
+ // find the closest cut to the left
+ float s0 = mCuts[(uint32_t)cutNr].pos.dot(cutNormal);
+ float sMax = -FLT_MAX;
+ float sMin = FLT_MAX;
+ int minNr = -1;
+ int maxNr = -1;
+ for (int m = 0; m < (int)mCuts.size(); m++) {
+ float s = mCuts[(uint32_t)m].pos.dot(cutNormal);
+ if (s > s0 && s < sMin) {
+ sMin = s;
+ minNr = m;
+ }
+ if (s > sMax) {
+ sMax = s;
+ maxNr = m;
+ }
+ }
+ uint32_t nextCutNr = uint32_t((minNr >= 0) ? minNr : maxNr);
+
+ if (nextCutNr == l)
+ break; // loop closed
+
+ PolyVert &nextCut = mCuts[nextCutNr];
+ nr = nextCut.nextVert;
+ nextCut.nextVert = -1; // visited
+ mClipPolyVerts[current].pushBack(nextCut);
+ }
+ // close poly
+ mClipPolyStarts[current].pushBack((int32_t)mClipPolyVerts[current].size());
+ }
+ }
+ } // next plane
+
+ // map from old to new poly numbers
+ mFirstOutPoly[polyNr] = (int32_t)out.polyStarts.size()-1;
+ mNumOutPolys[polyNr] = (int32_t)mClipPolyStarts[current].size()-1;
+ // separate num needed because we do not process the polys with candidate list, not in order
+
+ // clipped poly empty?
+ if (mNumOutPolys[polyNr] <= 0)
+ continue;
+
+ // create visual polygon(s)
+ for (uint32_t j = 0; j < mClipPolyStarts[current].size()-1; j++) {
+ int first = mClipPolyStarts[current][j];
+ int last = mClipPolyStarts[current][j+1];
+ int num = last - first;
+ for (int k = 0; k < num; k++) {
+ PolyVert &pv0 = mClipPolyVerts[current][uint32_t(first + k)];
+ PolyVert &pv1 = mClipPolyVerts[current][uint32_t(first + (k+1)%num)];
+
+ int id = -1;
+ int faceId = -1;
+
+ if (!pv0.edgeOnFace && !pv1.edgeOnFace) { // existing vertex, duplicate
+ if (!check(pv1.id >= 0, "internal vertex with id < 0"))
+ return false;
+
+ if (mOutVertNr[(uint32_t)pv1.id] < 0) {
+ mOutVertNr[(uint32_t)pv1.id] = (int32_t)out.vertices.size();
+ out.vertices.pushBack((pv1.pos));
+ out.normals.pushBack((pv1.normal));
+ out.tangents.pushBack((pv1.tangent));
+ out.texCoords.pushBack((float)pv1.u);
+ out.texCoords.pushBack((float)pv1.v);
+ }
+ id = mOutVertNr[(uint32_t)pv1.id];
+ faceId = -1;
+ }
+ else if (pv0.edgeOnFace && pv1.edgeOnFace) { // new, non shared
+ id = (int32_t)out.vertices.size();
+ out.vertices.pushBack((pv1.pos));
+ out.normals.pushBack((pv1.normal));
+ out.tangents.pushBack((pv1.tangent));
+ out.texCoords.pushBack((float)pv1.u);
+ out.texCoords.pushBack((float)pv1.v);
+ faceId = id;
+ }
+ else { // new, shared
+ int edgeNeighbor = pv0.edgeOnFace ? pv1.edgeNeighbor : pv0.edgeNeighbor;
+ int sharedId = -1;
+ int numPolys = mNumOutPolys[(uint32_t)edgeNeighbor];
+
+ // new neighbor exists, search shared vertex
+ if (numPolys > 0) {
+ int firstPoly = mFirstOutPoly[(uint32_t)edgeNeighbor];
+ for (int l = 0; l < numPolys; l++) {
+ int newPolyNr = firstPoly + l;
+ int first = out.polyStarts[(uint32_t)newPolyNr];
+ int last = out.polyStarts[(uint32_t)newPolyNr+1];
+ for (int m = first; m < last; m++) {
+ int testId = out.polyIndices[(uint32_t)m];
+ if (out.vertices[(uint32_t)testId] == (pv1.pos)) {
+ sharedId = testId;
+ break;
+ }
+ }
+ if (sharedId >= 0)
+ break;
+ }
+ }
+ if (sharedId >= 0 && out.normals[(uint32_t)sharedId] == (pv1.normal)) // share it
+ id = sharedId;
+ else {
+ id = (int32_t)out.vertices.size(); // create new
+ out.vertices.pushBack((pv1.pos));
+ out.normals.pushBack((pv1.normal));
+ out.tangents.pushBack((pv1.tangent));
+ out.texCoords.pushBack((float)pv1.u);
+ out.texCoords.pushBack((float)pv1.v);
+ }
+ if (sharedId >= 0)
+ faceId = sharedId; // on the convex surface we need the shared id to make the surface poly connected
+ else
+ faceId = id;
+ }
+ out.polyIndices.pushBack(id);
+ out.polyNeighbors.pushBack(pv1.edgeOnFace ? -1 : pv1.edgeNeighbor);
+ pv1.id = faceId;
+ }
+ out.polyStarts.pushBack((int32_t)out.polyIndices.size()); // close poly
+
+ // create face vertices
+ for (int k = 0; k < num; k++) {
+ PolyVert &pv0 = mClipPolyVerts[current][uint32_t(first + k)];
+ PolyVert &pv1 = mClipPolyVerts[current][uint32_t(first + (k+1)%num)];
+ if (!pv0.edgeOnFace && !pv1.edgeOnFace)
+ continue;
+
+ if (pv1.id >= (int)mFaceVertNrs.size())
+ mFaceVertNrs.resize((uint32_t)pv1.id + 1, -1);
+
+ int &vertNr = mFaceVertNrs[(uint32_t)pv1.id];
+ if (vertNr < 0) {
+ FaceVert newSv;
+ newSv.init();
+ vertNr = (int32_t)mFaceVerts.size();
+ mFaceVerts.pushBack(newSv);
+ }
+ FaceVert &sv = mFaceVerts[(uint32_t)vertNr];
+ sv.id = pv1.id;
+ }
+
+ // create face polyline
+ for (int k = 0; k < num; k++) {
+ PolyVert &pv0 = mClipPolyVerts[current][uint32_t(first + k)];
+ PolyVert &pv1 = mClipPolyVerts[current][uint32_t(first + (k+1)%num)];
+
+ if (pv1.id < 0) // not on surface
+ continue;
+
+ FaceVert &sv = mFaceVerts[(uint32_t)mFaceVertNrs[(uint32_t)pv1.id]];
+ if (pv0.edgeOnFace) {
+ sv.nextFaceNr = pv0.edgeNeighbor;
+ sv.neighborPos = out.polyStarts[out.polyStarts.size()-2] + (k+num-1)%num;
+ sv.neighborPolyNr = (int32_t)out.polyStarts.size()-2;
+ sv.nextVert = mFaceVertNrs[(uint32_t)pv0.id];
+ }
+ if (pv1.edgeOnFace) {
+ sv.prevFaceNr = pv1.edgeNeighbor;
+ }
+ }
+ }
+ } // next polygon candidate
+
+ // fix neighbors
+ for (int i = 0; i < (int)out.polyStarts.size()-1; i++) {
+ int first = out.polyStarts[(uint32_t)i];
+ int num = out.polyStarts[(uint32_t)i+1] - first;
+ for (int j = 0; j < num; j++) {
+ int oldNr = out.polyNeighbors[uint32_t(first + j)];
+ if (oldNr < 0)
+ continue;
+
+ int numNew = mNumOutPolys[(uint32_t)oldNr];
+ if (!check(numNew > 0, "fix internal neighbors, no new polygond created"))
+ return false;
+
+ if (numNew == 1) { // simple mapping
+ out.polyNeighbors[uint32_t(first + j)] = mFirstOutPoly[(uint32_t)oldNr];
+ }
+ else { // find correct new poly
+ PxVec3 v1 = out.vertices[(uint32_t)out.polyIndices[uint32_t(first + (j+1)%num)]];
+ float minD2 = PX_MAX_F32;
+ int minNr = -1;
+
+ for (int k = 0; k < numNew; k++) {
+ int newNr = mFirstOutPoly[(uint32_t)oldNr] + k;
+ int firstNew = out.polyStarts[(uint32_t)newNr];
+ int lastNew = out.polyStarts[(uint32_t)newNr+1];
+ for (int l = firstNew; l < lastNew; l++) {
+ PxVec3 v0 = out.vertices[(uint32_t)out.polyIndices[(uint32_t)l]];
+ float d2 = (v1-v0).magnitudeSquared();
+ if (d2 < minD2) {
+ minD2 = d2;
+ minNr = newNr;
+ }
+ }
+ }
+ out.polyNeighbors[uint32_t(first + j)] = minNr;
+ }
+ }
+ }
+
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+bool MeshClipper::createFacePolys()
+{
+ const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes();
+ const nvidia::Array<Convex::Face> &clipConvexFaces = mClipConvex->getFaces();
+ const nvidia::Array<PxVec3> &clipConvexVertices = mClipConvex->getVertices();
+ const nvidia::Array<int> &clipConvexIndices = mClipConvex->getIndices();
+
+ mFaceTypes.clear();
+ mFaceTypes.resize(clipConvexFaces.size(), 0);
+ mFaceOfPoly.clear();
+
+ Mesh &out = mOutMeshes[0];
+ int firstFacePoly = (int32_t)out.polyStarts.size()-1;
+
+
+ // create face polys
+ for (uint32_t i = 0; i < mFaceVerts.size(); i++) {
+ FaceVert &startSv = mFaceVerts[i];
+ if (startSv.visited)
+ continue;
+
+ int faceNr = startSv.nextFaceNr;
+ if (!check(faceNr >= 0, "create face polygons, loop interrupted"))
+ return false;
+
+ mFaceTypes[(uint32_t)faceNr] = 1; // has visual mesh
+
+ PxVec3 faceNormal = clipPlanes[(uint32_t)faceNr].n;
+ PxVec3 t0,t1;
+ // tangents
+ if (fabs(faceNormal.x) < fabs(faceNormal.y) && fabs(faceNormal.x) < fabs(faceNormal.z))
+ t0 = PxVec3(1.0f, 0.0f, 0.0f);
+ else if (fabs(faceNormal.y) < fabs(faceNormal.z))
+ t0 = PxVec3(0.0f, 1.0f, 0.0);
+ else
+ t0 = PxVec3(0.0f, 0.0f, 1.0f);
+ t1 = faceNormal.cross(t0);
+ t1.normalize();
+ t0 = t1.cross(faceNormal);
+
+ const Convex::Face &face = clipConvexFaces[(uint32_t)faceNr];
+ int thisPolyNr = (int32_t)out.polyStarts.size()-1;
+
+ int vertNr = (int32_t)i;
+ int safetyCnt = 0;
+
+ while (true) {
+ if (!check(safetyCnt <= (int)mFaceVerts.size() + (int)clipConvexVertices.size(), "create face polygons infinite loop"))
+ return false;
+ safetyCnt++;
+
+ if (!check(vertNr >= 0, "create face polygons loop interrupted"))
+ return false;
+
+ FaceVert &sv = mFaceVerts[(uint32_t)vertNr];
+
+ out.polyIndices.pushBack((int32_t)out.vertices.size());
+ PxVec3 temp = out.vertices[(uint32_t)sv.id];
+ out.vertices.pushBack(temp);
+ out.normals.pushBack(faceNormal);
+ out.tangents.pushBack(t0);
+ out.texCoords.pushBack(out.vertices[(uint32_t)sv.id].dot(t0) * mTexScale);
+ out.texCoords.pushBack(out.vertices[(uint32_t)sv.id].dot(t1) * mTexScale);
+
+ if (sv.nextFaceNr == faceNr) { // continues on this face
+ sv.visited = true;
+ out.polyNeighbors.pushBack(sv.neighborPolyNr);
+ out.polyNeighbors[(uint32_t)sv.neighborPos] = thisPolyNr;
+ vertNr = sv.nextVert;
+ if (vertNr == (int32_t)i)
+ break; // start reached
+ else
+ continue;
+ }
+
+ // on convex edge, find next entry vert
+ int edgeNr = 0;
+ while (edgeNr < face.numIndices && mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)] != sv.nextFaceNr)
+ edgeNr++;
+ if (!check(edgeNr < face.numIndices, "create face polys, find next entry vert not successfull"))
+ return false;
+
+ vertNr = -1;
+ int numCorners = 0;
+
+ for (int j = 0; j <= face.numIndices; j++) {
+ int adjFaceNr = mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)];
+ out.polyNeighbors.pushBack(-1-adjFaceNr);
+
+ PxVec3 edgeDir = clipPlanes[(uint32_t)faceNr].n.cross(clipPlanes[(uint32_t)adjFaceNr].n);
+ float s0 = out.vertices[out.vertices.size()-1].dot(edgeDir);
+ float minS = PX_MAX_F32;
+ int minK = -1;
+ for (uint32_t k = 0; k < mFaceVerts.size(); k++) { // todo: create edge face vert list to speed up
+ FaceVert &vk = mFaceVerts[k];
+// if (vk.id < 0) continue;
+ if (vk.nextFaceNr != faceNr || vk.prevFaceNr != adjFaceNr)
+ continue;
+ float si = out.vertices[(uint32_t)vk.id].dot(edgeDir);
+ if (si > s0 && si < minS) {
+ minS = si;
+ minK = (int32_t)k;
+ }
+ }
+
+ if (minK >= 0) {
+ vertNr = minK;
+ break;
+ }
+
+ // no entry found, add corner of convex
+ PxVec3 pos = clipConvexVertices[(uint32_t)clipConvexIndices[uint32_t(face.firstIndex + (edgeNr+1)%face.numIndices)]];
+ out.vertices.pushBack(pos);
+ out.normals.pushBack(faceNormal);
+ out.tangents.pushBack(t0);
+ out.texCoords.pushBack(pos.dot(t0) * mTexScale);
+ out.texCoords.pushBack(pos.dot(t1) * mTexScale);
+
+ out.polyIndices.pushBack((int32_t)out.vertices.size()-1);
+ if (numCorners > 0) {
+ if (mFaceTypes[(uint32_t)mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)]] == 0)
+ mFaceTypes[(uint32_t)mClipFaceNeighbors[uint32_t(face.firstIndex + edgeNr)]] = 2; // inside visual mesh
+ }
+
+ numCorners++;
+ edgeNr = (edgeNr+1) % face.numIndices;
+ }
+ if (vertNr == (int32_t)i)
+ break; // loop closed
+ }
+
+ mFaceOfPoly.pushBack(faceNr);
+ out.polyStarts.pushBack((int32_t)out.polyIndices.size()); // close face poly
+ }
+
+ // determine faces completely inside the visual mesh via flood fill
+ // start at faces of type 2 and fill all faces of type 0
+ // reagion is bounded by faces of type 1 containing the visual mesh
+ for (uint32_t i = 0; i < mFaceTypes.size(); i++) {
+ if (mFaceTypes[i] != 2)
+ continue;
+ mFaceTypes[i] = 0;
+ mFaceQueue.resize(1, (int32_t)i);
+ while (mFaceQueue.size() > 0) {
+ uint32_t faceNr = (uint32_t)mFaceQueue[mFaceQueue.size()-1];
+ mFaceQueue.popBack();
+ if (mFaceTypes[faceNr] != 0)
+ continue;
+ mFaceTypes[faceNr] = 2;
+ const Convex::Face &face = clipConvexFaces[faceNr];
+ for (int j = 0; j < face.numIndices; j++) {
+ int adjFaceNr = mClipFaceNeighbors[uint32_t(face.firstIndex + j)];
+ if (mFaceTypes[(uint32_t)adjFaceNr] == 0)
+ mFaceQueue.pushBack(adjFaceNr);
+ }
+ }
+ }
+
+ // create a polygon for each complete face inside the mesh
+ for (uint32_t i = 0; i < clipConvexFaces.size(); i++) {
+ if (mFaceTypes[i] != 2)
+ continue;
+ const Convex::Face &face = clipConvexFaces[i];
+ PxVec3 faceNormal = clipPlanes[i].n;
+
+ // tangents
+ PxVec3 t0,t1;
+ if (fabs(faceNormal.x) < fabs(faceNormal.y) && fabs(faceNormal.x) < fabs(faceNormal.z))
+ t0 = PxVec3(1.0f, 0.0f, 0.0f);
+ else if (fabs(faceNormal.y) < fabs(faceNormal.z))
+ t0 = PxVec3(0.0f, 1.0f, 0.0);
+ else
+ t0 = PxVec3(0.0f, 0.0f, 1.0f);
+ t1 = faceNormal.cross(t0);
+ t1.normalize();
+ t0 = t1.cross(faceNormal);
+
+ for (int j = 0; j < (int)face.numIndices; j++) {
+ PxVec3 pos = clipConvexVertices[(uint32_t)clipConvexIndices[uint32_t(face.firstIndex + j)]];
+ out.vertices.pushBack(pos);
+ out.normals.pushBack(faceNormal);
+ out.tangents.pushBack(t0);
+ out.texCoords.pushBack(pos.dot(t0) * mTexScale);
+ out.texCoords.pushBack(pos.dot(t1) * mTexScale);
+
+ out.polyIndices.pushBack((int32_t)out.vertices.size()-1);
+ out.polyNeighbors.pushBack(-1-mClipFaceNeighbors[uint32_t(face.firstIndex+j)]);
+ }
+ mFaceOfPoly.pushBack((int32_t)i);
+ out.polyStarts.pushBack((int32_t)out.polyIndices.size());
+ }
+
+ // fix face polygon neighbors
+ for (uint32_t i = (uint32_t)firstFacePoly; i < out.polyStarts.size()-1; i++) {
+ int first = out.polyStarts[i];
+ int num = out.polyStarts[i+1] - first;
+ for (int j = 0; j < num; j++) {
+ int adjFaceNr = out.polyNeighbors[uint32_t(first + j)];
+ if (adjFaceNr >= 0)
+ continue;
+ adjFaceNr = -1 - adjFaceNr;
+ PxVec3 &p0 = out.vertices[(uint32_t)out.polyIndices[uint32_t(first + (j+1)%num)]];
+ float minD2 = PX_MAX_F32;
+ int minAdjPolyNr = -1;
+
+ for (uint32_t k = 0; k < mFaceOfPoly.size(); k++) {
+ if (mFaceOfPoly[k] != adjFaceNr)
+ continue;
+ int adjPolyNr = firstFacePoly + (int32_t)k;
+ int adjFirst = out.polyStarts[(uint32_t)adjPolyNr];
+ int adjLast = out.polyStarts[(uint32_t)adjPolyNr+1];
+ for (int l = adjFirst; l < adjLast; l++) {
+ PxVec3 &p1 = out.vertices[(uint32_t)out.polyIndices[(uint32_t)l]];
+ float d2 = (p0 - p1).magnitudeSquared();
+ if (d2 < minD2) {
+ minD2 = d2;
+ minAdjPolyNr = adjPolyNr;
+ }
+ }
+ }
+ if (!check(minAdjPolyNr >= 0, "create face polys, fix neighbors"))
+ return false;
+
+ out.polyNeighbors[uint32_t(first + j)] = minAdjPolyNr;
+ }
+ }
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+bool MeshClipper::clip(const Convex *clipConvex, const PxTransform &trans, float texScale, bool splitIslands,
+ bool &empty, bool &completelyInside)
+{
+ if (mMeshConvex == NULL)
+ return false;
+
+ mTexScale = texScale;
+
+ mClipConvex = clipConvex;
+ computeClipFaceNeighbors();
+
+ empty = true;
+ completelyInside = false;
+
+ mOutMeshes.resize(1);
+ Mesh &out = mOutMeshes[0];
+ mOutMeshes[0].clear();
+
+ mFaceVertNrs.clear(); // necessary?
+ mFaceVerts.clear();
+
+ const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts();
+ //const nvidia::Array<PxPlane> &clipPlanes = mClipConvex->getPlanes();
+ const nvidia::Array<Convex::Face> &clipConvexFaces = mClipConvex->getFaces();
+ const nvidia::Array<PxVec3> &clipConvexVertices = mClipConvex->getVertices();
+
+ int numPolys = (int32_t)meshPolyStarts.size()-1;
+
+ mScene->profileBegin("generate poly candidates");
+ generateCandidates(trans);
+ mScene->profileEnd("generate poly candidates");
+
+ mFirstOutPoly.clear(); // speed up, use only local mesh part
+ mFirstOutPoly.resize((uint32_t)numPolys, -1);
+ mNumOutPolys.clear();
+ mNumOutPolys.resize((uint32_t)numPolys, 0);
+
+ mOutVertNr.clear();
+ mOutVertNr.resize(mMeshVertices.size(), -1);
+ mFirstOutFacePoly.clear();
+ mFirstOutFacePoly.resize(clipConvexFaces.size(), -1);
+ mNumOutFacePolys.clear();
+ mNumOutFacePolys.resize(clipConvexFaces.size(), 0);
+
+ mScene->profileBegin("create internal polygons");
+ if (!createInternalPolygons(trans)) {
+ empty = true;
+ mScene->profileEnd("create internal polygons");
+ return false;
+ }
+ mScene->profileEnd("create internal polygons");
+
+ if (out.polyStarts.size() <= 1) { // cut empty
+
+ // inside visual mesh?
+
+ PxVec3 center(0.0f, 0.0f, 0.0f);
+ for (uint32_t i = 0; i < clipConvexVertices.size(); i++)
+ center += clipConvexVertices[i];
+ center /= (float)clipConvexVertices.size();
+ if (mMeshConvex->insideVisualMesh(trans.transformInv(center))) {
+ empty = false;
+ completelyInside = true;
+ return true;
+ }
+ else {
+ empty = true;
+ completelyInside = false;
+ return true;
+ }
+ }
+
+ empty = true;
+
+ mScene->profileBegin("create face polys");
+ bool OK = createFacePolys();
+ mScene->profileEnd("create face polys");
+ if (!OK)
+ return false;
+
+ //if (!testNeighbors())
+ // return false;
+
+ if (splitIslands)
+ this->splitIslands();
+
+ empty = false;
+ return true;
+}
+
+
+
+// --------------------------------------------------------------------------------------------
+bool MeshClipper::splitIslands()
+{
+ if (mOutMeshes.size() < 1)
+ return false;
+
+ uint32_t numPolys = mOutMeshes[0].polyStarts.size()-1;
+ mColors.clear();
+ mColors.resize(numPolys, -1);
+ mQueue.clear();
+
+ int numIslands = 0;
+
+ // color islands
+ for (uint32_t i = 0; i < numPolys; i++) {
+ if (mColors[i] >= 0)
+ continue;
+ numIslands++;
+ mQueue.clear();
+ mQueue.pushBack((int32_t)i);
+ while (!mQueue.empty()) {
+ uint32_t polyNr = (uint32_t)mQueue[mQueue.size()-1];
+ mQueue.popBack();
+ if (mColors[polyNr] >= 0)
+ continue;
+ mColors[polyNr] = numIslands-1;
+ int first = mOutMeshes[0].polyStarts[polyNr];
+ int last = mOutMeshes[0].polyStarts[polyNr+1];
+ for (int j = first; j < last; j++) {
+ int neighborNr = mOutMeshes[0].polyNeighbors[(uint32_t)j];
+ if (mColors[(uint32_t)neighborNr] >= 0)
+ continue;
+ mQueue.pushBack(neighborNr);
+ }
+ }
+ }
+
+ // only one island?
+ if (numIslands <= 1)
+ return false;
+
+ // create child meshes
+ mOutMeshes.resize((uint32_t)numIslands+1);
+ for (uint32_t i = 0; i < (uint32_t)numIslands; i++) {
+ mOutMeshes[1+i].clear();
+ }
+
+ // distribute visual mesh
+ mNewVertNr.clear();
+ mNewVertNr.resize(mOutMeshes[0].vertices.size(), -1);
+ mNewPolyNr.clear();
+ mNewPolyNr.resize(numPolys, -1);
+
+ for (uint32_t i = 0; i < numPolys; i++) {
+ int meshNr = mColors[i];
+ Mesh &parent = mOutMeshes[0];
+ Mesh &child = mOutMeshes[(uint32_t)meshNr+1];
+ int first = parent.polyStarts[i];
+ int last = parent.polyStarts[i+1];
+ for (int j = first; j < last; j++) {
+ uint32_t id = (uint32_t)parent.polyIndices[(uint32_t)j];
+ if (mNewVertNr[id] < 0) {
+ mNewVertNr[id] = (int32_t)child.vertices.size();
+ child.vertices.pushBack(parent.vertices[id]);
+ child.normals.pushBack(parent.normals[id]);
+ child.tangents.pushBack(parent.tangents[id]);
+ child.texCoords.pushBack(parent.texCoords[2*id]);
+ child.texCoords.pushBack(parent.texCoords[2*id+1]);
+ }
+ child.polyIndices.pushBack(mNewVertNr[id]);
+ child.polyNeighbors.pushBack(parent.polyNeighbors[(uint32_t)j]); // cannot adjust neighbor number yet
+ }
+ mNewPolyNr[i] = (int32_t)child.polyStarts.size()-1;
+ child.polyStarts.pushBack((int32_t)child.polyIndices.size());
+ }
+
+ // adjust neighbor numbers
+ //int num = 0;
+ for (int i = 0; i < numIslands; i++) {
+ Mesh &child = mOutMeshes[1+(uint32_t)i];
+ for (int j = 0; j < (int)child.polyStarts.size()-1; j++) {
+ int first = child.polyStarts[(uint32_t)j];
+ int last = child.polyStarts[(uint32_t)j+1];
+ for (int k = first; k < last; k++) {
+ child.polyNeighbors[(uint32_t)k] = mNewPolyNr[(uint32_t)child.polyNeighbors[(uint32_t)k]];
+ }
+ }
+ }
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+bool MeshClipper::insideVisualMesh(const PxVec3 & /*pos*/) const
+{
+ //if (mMeshConvex == NULL)
+ // return false;
+
+ //const nvidia::Array<PxVec3> &meshNormals = mMeshConvex->getVisNormals();
+ //const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts();
+ //const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices();
+ //const nvidia::Array<int> &meshPolyNeighbors = mMeshConvex->getVisPolyNeighbors();
+
+ //int num[6] = {0,0,0,0,0,0};
+ //const int numAxes = 2; // max 3: the nigher the more robust but slower
+
+ //for (int i = 0; i < (int)mVisTriIndices.size(); i += 3) {
+ // const PxVec3 &p0 = mVisVertices[mVisTriIndices[i]];
+ // const PxVec3 &p1 = mVisVertices[mVisTriIndices[i+1]];
+ // const PxVec3 &p2 = mVisVertices[mVisTriIndices[i+2]];
+ // PxVec3 n = (p1-p0).cross(p2-p0);
+ // float d = n.dot(p0);
+ // float ds = d - pos.dot(n);
+
+ // // for all axes, cound the hits of the ray starting from pos with the mesh
+ // for (int j = 0; j < numAxes; j++) {
+ // if (n[j] == 0.0f)
+ // continue;
+
+ // int j0 = (j+1)%3;
+ // int j1 = (j+2)%3;
+ // float x0 = p0[j0];
+ // float y0 = p0[j1];
+ // float x1 = p1[j0];
+ // float y1 = p1[j1];
+ // float x2 = p2[j0];
+ // float y2 = p2[j1];
+
+ // float px = pos[j0];
+ // float py = pos[j1];
+
+ // // inside triangle?
+ // float d0 = (x1-x0) * (py-y0) - (y1-y0) * (px-x0);
+ // float d1 = (x2-x1) * (py-y1) - (y2-y1) * (px-x1);
+ // float d2 = (x0-x2) * (py-y2) - (y0-y2) * (px-x2);
+ // bool inside =
+ // (d0 <= 0.0f && d1 <= 0.0f && d2 <= 0.0f) ||
+ // (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f);
+ // if (!inside)
+ // continue;
+
+ // float s = ds / n[j];
+ // if (s > 0.0f)
+ // num[2*j] += (n[j] > 0.0f) ? +1 : -1;
+ // else
+ // num[2*j+1] += (n[j] < 0.0f) ? +1 : -1;
+ // }
+ //}
+ //int numVotes = 0;
+ //for (int i = 0; i < 6; i++) {
+ // if (num[i] > 0)
+ // numVotes++;
+ //}
+ //return numVotes > numAxes;
+ return false;
+}
+
+// --------------------------------------------------------------------------------------------
+bool MeshClipper::testNeighbors(int meshNr)
+{
+ if (meshNr >= (int)mOutMeshes.size())
+ return false;
+ Mesh &mesh = mOutMeshes[(uint32_t)meshNr];
+
+ for (int i = 0; i < (int)mesh.polyStarts.size()-1; i++) {
+ int first = mesh.polyStarts[(uint32_t)i];
+ int num = mesh.polyStarts[(uint32_t)i+1] - first;
+ for (int j = 0; j < num; j++) {
+ uint32_t i0 = (uint32_t)mesh.polyIndices[uint32_t(first+j)];
+ uint32_t i1 = (uint32_t)mesh.polyIndices[uint32_t(first + (j+1)%num)];
+ PxVec3 p0 = mesh.vertices[i0];
+ PxVec3 p1 = mesh.vertices[i1];
+
+ int adj = mesh.polyNeighbors[uint32_t(first + j)];
+ if (adj < 0)
+ return false;
+
+ int adjFirst = mesh.polyStarts[(uint32_t)adj];
+ int adjNum = mesh.polyStarts[(uint32_t)adj+1] - adjFirst;
+ bool found = false;
+ for (int k = 0; k < adjNum; k++) {
+ if (mesh.polyNeighbors[uint32_t(adjFirst+k)] == i) {
+ uint32_t j0 = (uint32_t)mesh.polyIndices[uint32_t(adjFirst+k)];
+ uint32_t j1 = (uint32_t)mesh.polyIndices[uint32_t(adjFirst + (k+1)%adjNum)];
+ PxVec3 q0 = mesh.vertices[j0];
+ PxVec3 q1 = mesh.vertices[j1];
+ if (p0 == q1 && p1 == q0)
+ found = true;
+ }
+ }
+ if (!found)
+ return false;
+ }
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+bool MeshClipper::check(bool test, const char* /*message*/)
+{
+#ifndef _DEBUG
+ return test;
+#else
+
+ if (test)
+ return true;
+
+ printf("\nerror in MeshClipper.cpp: %s\n", message);
+
+ if (!mDumpOnError)
+ return test;
+#endif
+
+#if DEBUG
+ FILE *f = fopen(DUMP_PATH, "wb");
+ if (f == NULL)
+ return test;
+#endif
+
+#ifdef _DEBUG
+
+ printf("dump file saved: %s\n", DUMP_PATH);
+
+ const nvidia::Array<PxVec3> &meshVertices = mMeshConvex->getVisVertices();
+ //const nvidia::Array<PxVec3> &meshNormals = mMeshConvex->getVisNormals();
+ const nvidia::Array<int> &meshPolyStarts = mMeshConvex->getVisPolyStarts();
+ const nvidia::Array<int> &meshPolyIndices = mMeshConvex->getVisPolyIndices();
+ //const nvidia::Array<int> &meshPolyNeighbors = mMeshConvex->getVisPolyNeighbors();
+
+ int cnt = (int)meshVertices.size();
+ fwrite(&cnt, sizeof(int), 1, f);
+ fwrite(&meshVertices[0], sizeof(PxVec3), meshVertices.size(), f);
+ fwrite(&meshNormals[0], sizeof(PxVec3), meshNormals.size(), f);
+
+ cnt = (int)meshPolyStarts.size();
+ fwrite(&cnt, sizeof(int), 1, f);
+ fwrite(&meshPolyStarts[0], sizeof(int), meshPolyStarts.size(), f);
+
+ cnt = (int)meshPolyIndices.size();
+ fwrite(&cnt, sizeof(int), 1, f);
+ fwrite(&meshPolyIndices[0], sizeof(int), meshPolyIndices.size(), f);
+
+ fclose(f);
+ return false;
+#endif
+}
+
+// -----------------------------------------------------------------------------
+bool MeshClipper::loadDump()
+{
+#if DEBUG
+ FILE *f = fopen(DUMP_PATH, "rb");
+ if (f == NULL)
+ return false;
+#endif
+
+ nvidia::Array<PxVec3> vertices;
+ nvidia::Array<PxVec3> normals;
+ nvidia::Array<int> polyStarts;
+ nvidia::Array<int> polyIndices;
+ nvidia::Array<int> polyNeighbors;
+
+ uint32_t cnt = 0;
+ fread(&cnt, sizeof(int), 1, f);
+ vertices.resize(cnt);
+ fread(&vertices[0], sizeof(PxVec3), vertices.size(), f);
+ normals.resize(cnt);
+ fread(&normals[0], sizeof(PxVec3), normals.size(), f);
+
+ fread(&cnt, sizeof(int), 1, f);
+ polyStarts.resize(cnt);
+ fread(&polyStarts[0], sizeof(int), polyStarts.size(), f);
+
+ fread(&cnt, sizeof(int), 1, f);
+ polyIndices.resize(cnt);
+ fread(&polyIndices[0], sizeof(int), polyIndices.size(), f);
+
+ fclose(f);
+
+ Convex *c = mScene->createConvex();
+
+ bool isManifold = c->setExplicitVisMeshFromPolygons(
+ (int32_t)vertices.size(), &vertices[0], &normals[0], NULL, NULL, // todo, save as well
+ (int32_t)polyStarts.size()-1, &polyStarts[0],
+ (int32_t)polyIndices.size(), &polyIndices[0]);
+
+ mMeshConvex = c;
+
+ return isManifold;
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.h b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.h
new file mode 100644
index 00000000..70cd8d03
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/MeshClipperBase.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef MESH_CLIPPER_BASE_H
+#define MESH_CLIPPER_BASE_H
+
+// Matthias Muller-Fischer
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include <PxTransform.h>
+#include <PxBounds3.h>
+#include <PsUserAllocated.h>
+
+//#include "Vec3.h"
+//#include "Bounds3.h"
+//#include "Transform.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+//using namespace ::M;
+class Convex;
+class SimScene;
+
+// ---------------------------------------------------------------------------------------
+class MeshClipper : public UserAllocated {
+ friend class SimScene;
+public:
+ // singleton pattern
+ //static MeshClipper* getInstance();
+ //static void destroyInstance();
+
+ void init(const Convex *meshConvex);
+ bool clip(const Convex *clipConvex, const PxTransform &pxTrans, float texScale, bool splitIslands,
+ bool &empty, bool &completelyInside);
+
+ struct Mesh {
+ void clear();
+ nvidia::Array<PxVec3> vertices;
+ nvidia::Array<PxVec3> normals;
+ nvidia::Array<PxVec3> tangents;
+ nvidia::Array<float> texCoords;
+ nvidia::Array<int> polyStarts;
+ nvidia::Array<int> polyIndices;
+ nvidia::Array<int> polyNeighbors;
+ };
+
+ int getNumMeshes();
+ const Mesh &getMesh(int meshNr);
+
+ bool loadDump();
+
+protected:
+ MeshClipper(SimScene* scene);
+ virtual ~MeshClipper() {}
+
+ //static PxVec3 conv(const Vec3 &v);
+ //static Vec3 conv(const PxVec3 &v);
+ //static Transform conv(const PxTransform &t);
+ //static Plane conv(const PxPlane &p);
+
+ void createGrid();
+ bool getGridCandidates(const PxBounds3 &bounds);
+
+ void generateCandidates(const PxTransform &pxTrans);
+ bool createInternalPolygons(const PxTransform &pxTrans);
+ bool createFacePolys();
+ bool testNeighbors(int meshNr);
+
+ bool splitIslands();
+
+ bool insideVisualMesh(const PxVec3 &pos) const;
+
+ void computeClipFaceNeighbors();
+
+ SimScene* mScene;
+
+ // input
+ const Convex *mMeshConvex;
+ const Convex *mClipConvex;
+ nvidia::Array<int> mClipFaceNeighbors;
+ float mTexScale;
+
+ // output
+ nvidia::Array<Mesh> mOutMeshes;
+
+ // auxiliaries
+ struct PolyVert {
+ void init() {
+ pos = normal = tangent = PxVec3(0.0, 0.0, 0.0); u = 0.0f; v = 0.0f;
+ id = -1; edgeNeighbor = -1; edgeOnFace = false; nextVert = -1;
+ }
+ PxVec3 pos;
+ PxVec3 normal;
+ PxVec3 tangent;
+ double u, v;
+ int id;
+ int edgeNeighbor;
+ bool edgeOnFace;
+ int nextVert;
+ };
+
+ struct FaceVert {
+ void init() {
+ id = -1; prevFaceNr = -1; nextFaceNr = -1; neighborPolyNr = -1; neighborPos = -1;
+ nextVert = -1; visited = false;
+ }
+ int id;
+ int prevFaceNr, nextFaceNr;
+ int neighborPolyNr;
+ int neighborPos;
+ int nextVert;
+ bool visited;
+ };
+
+ nvidia::Array<PxVec3> mMeshVertices;
+ nvidia::Array<bool> mPolyInside;
+ nvidia::Array<int> mPolyCandidates;
+
+ nvidia::Array<PolyVert> mClipPolyVerts[2];
+ nvidia::Array<int> mClipPolyStarts[2];
+ nvidia::Array<PolyVert> mCuts;
+ nvidia::Array<int> mFaceVertNrs;
+ nvidia::Array<FaceVert> mFaceVerts;
+ nvidia::Array<PxBounds3> mPolyBounds;
+
+ struct Edge {
+ void init(int i0, int i1, int edgeNr, int faceNr) {
+ if (i0 < i1) { this->i0 = i0; this->i1 = i1; }
+ else { this->i0 = i1; this->i1 = i0; }
+ this->edgeNr = edgeNr; this->faceNr = faceNr;
+ }
+ bool operator == (const Edge &e) const { return i0 == e.i0 && i1 == e.i1; }
+ bool operator < (const Edge &e) const { return i0 < e.i0 || (i0 == e.i0 && i1 < e.i1); }
+ int i0, i1;
+ int edgeNr, faceNr;
+ };
+ nvidia::Array<Edge> mEdges;
+
+ // map from int to out mesh
+ nvidia::Array<int> mFirstOutPoly;
+ nvidia::Array<int> mNumOutPolys;
+ nvidia::Array<int> mOutVertNr;
+ nvidia::Array<int> mFirstOutFacePoly;
+ nvidia::Array<int> mNumOutFacePolys;
+
+ nvidia::Array<int> mFaceTypes;
+ nvidia::Array<int> mFaceOfPoly;
+ nvidia::Array<int> mFaceQueue;
+
+ // split islands
+ nvidia::Array<int> mColors;
+ nvidia::Array<int> mQueue;
+ nvidia::Array<int> mNewVertNr;
+ nvidia::Array<int> mNewPolyNr;
+
+ // grid
+ nvidia::Array<int> mGridFirstPoly;
+ nvidia::Array<int> mGridPolys;
+ int mGridNumX, mGridNumY, mGridNumZ;
+ float mGridSpacing;
+ PxBounds3 mGridBounds;
+ nvidia::Array<int> mGridPolyMarks;
+ int mGridCurrentMark;
+
+ // error handling
+ bool check(bool test, const char *message);
+ bool mDumpOnError;
+};
+
+}
+}
+}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.cpp b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.cpp
new file mode 100644
index 00000000..5a1d892b
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.cpp
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "PolygonTriangulatorBase.h"
+#include <PxAssert.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace nvidia;
+
+// ------ singleton pattern -----------------------------------------------------------
+
+//static PolygonTriangulator *gPolygonTriangulator = NULL;
+//
+//PolygonTriangulator* PolygonTriangulator::getInstance()
+//{
+// if (gPolygonTriangulator == NULL) {
+// gPolygonTriangulator = PX_NEW(PolygonTriangulator)();
+// }
+// return gPolygonTriangulator;
+//}
+//
+//void PolygonTriangulator::destroyInstance()
+//{
+// if (gPolygonTriangulator != NULL) {
+// PX_DELETE(gPolygonTriangulator);
+// }
+// gPolygonTriangulator = NULL;
+//}
+
+// -------------------------------------------------------------------------------------
+PolygonTriangulator::PolygonTriangulator(SimScene* scene):
+ mScene(scene)
+{
+}
+
+// -------------------------------------------------------------------------------------
+PolygonTriangulator::~PolygonTriangulator()
+{
+}
+
+// -------------------------------------------------------------------------------------
+float PolygonTriangulator::cross(const PxVec3 &p0, const PxVec3 &p1)
+{
+ return p0.x * p1.y - p0.y * p1.x;
+}
+
+// -------------------------------------------------------------------------------------
+bool PolygonTriangulator::inTriangle(const PxVec3 &p, const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2)
+{
+ float d0 = cross(p1 - p0, p - p0);
+ float d1 = cross(p2 - p1, p - p1);
+ float d2 = cross(p0 - p2, p - p2);
+ return (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f) ||
+ (d0 <= 0.0f && d1 <= 0.0f && d2 <= 0.0f);
+}
+
+// -------------------------------------------------------------------------------------
+void PolygonTriangulator::triangulate(const PxVec3 *points, int numPoints, const int *indices, PxVec3 *planeNormal)
+{
+ mIndices.clear();
+
+ if (numPoints < 3)
+ return;
+ if (numPoints == 3) {
+ if (indices == NULL) {
+ mIndices.pushBack(0);
+ mIndices.pushBack(1);
+ mIndices.pushBack(2);
+ }
+ else {
+ mIndices.pushBack(indices[0]);
+ mIndices.pushBack(indices[1]);
+ mIndices.pushBack(indices[2]);
+ }
+ return;
+ }
+
+ bool isConvex;
+ importPoints(points, numPoints, indices, planeNormal, isConvex);
+
+ if (isConvex) { // fast path
+ mIndices.resize(3*((uint32_t)numPoints-2));
+ for (int i = 0; i < numPoints-2; i++) {
+ mIndices[3*(uint32_t)i] = 0;
+ mIndices[3*(uint32_t)i+1] = i+1;
+ mIndices[3*(uint32_t)i+2] = i+2;
+ }
+ }
+ else
+ clipEars();
+
+ if (indices != NULL) {
+ for (uint32_t i = 0; i < mIndices.size(); i++) {
+ mIndices[i] = indices[(uint32_t)mIndices[i]];
+ }
+ }
+}
+
+// -------------------------------------------------------------------------------------
+void PolygonTriangulator::importPoints(const PxVec3 *points, int numPoints, const int *indices, PxVec3 *planeNormal, bool &isConvex)
+{
+ // find projection 3d -> 2d;
+ PxVec3 n;
+
+ isConvex = true;
+
+ if (planeNormal)
+ n = *planeNormal;
+ else {
+ PX_ASSERT(numPoints >= 3);
+ n = PxVec3(0.0f, 0.0f, 0.0f);
+
+ for (int i = 1; i < numPoints-1; i++) {
+ int i0 = 0;
+ int i1 = i;
+ int i2 = i+1;
+ if (indices) {
+ i0 = indices[i0];
+ i1 = indices[i1];
+ i2 = indices[i2];
+ }
+ const PxVec3 &p0 = points[i0];
+ const PxVec3 &p1 = points[i1];
+ const PxVec3 &p2 = points[i2];
+ PxVec3 ni = (p1-p0).cross(p2-p0);
+ if (i > 1 && ni.dot(n) < 0.0f)
+ isConvex = false;
+ n += ni;
+ }
+ }
+
+ n.normalize();
+ PxVec3 t0,t1;
+
+ if (fabs(n.x) < fabs(n.y) && fabs(n.x) < fabs(n.z))
+ t0 = PxVec3(1.0f, 0.0f, 0.0f);
+ else if (fabs(n.y) < fabs(n.z))
+ t0 = PxVec3(0.0f, 1.0f, 0.0f);
+ else
+ t0 = PxVec3(0.0f, 0.0f, 1.0f);
+ t1 = n.cross(t0);
+ t1.normalize();
+ t0 = t1.cross(n);
+
+ mPoints.resize((uint32_t)numPoints);
+ if (indices == NULL) {
+ for (uint32_t i = 0; i < (uint32_t)numPoints; i++)
+ mPoints[i] = PxVec3(points[i].dot(t0), points[i].dot(t1), 0.0f);
+ }
+ else {
+ for (uint32_t i = 0; i < (uint32_t)numPoints; i++) {
+ const PxVec3 &p = points[(uint32_t)indices[i]];
+ mPoints[i] = PxVec3(p.dot(t0), p.dot(t1), 0.0f);
+ }
+ }
+}
+
+// -------------------------------------------------------------------------------------
+void PolygonTriangulator::clipEars()
+{
+ // init
+ int32_t num = (int32_t)mPoints.size();
+
+ mCorners.resize((uint32_t)num);
+
+ for (int i = 0; i < num; i++) {
+ Corner &c = mCorners[(uint32_t)i];
+ c.prev = (i > 0) ? i-1 : num-1;
+ c.next = (i < num-1) ? i + 1 : 0;
+ c.isEar = false;
+ c.angle = 0.0f;
+ PxVec3 &p0 = mPoints[(uint32_t)c.prev];
+ PxVec3 &p1 = mPoints[(uint32_t)i];
+ PxVec3 &p2 = mPoints[(uint32_t)c.next];
+ PxVec3 n1 = p1-p0;
+ PxVec3 n2 = p2-p1;
+ if (cross(n1, n2) > 0.0f) {
+ n1.normalize();
+ n2.normalize();
+ c.angle = n1.dot(n2);
+
+ c.isEar = true;
+ int nr = (i+2) % num;
+ for (int j = 0; j < num-3; j++) {
+ if (inTriangle(mPoints[(uint32_t)nr], p0,p1,p2)) {
+ c.isEar = false;
+ break;
+ }
+ nr = (nr+1) % num;
+ }
+ }
+ }
+
+ int firstCorner = 0;
+ int numCorners = num;
+
+ while (numCorners > 3) {
+
+ // find best ear
+ float minAng = FLT_MAX;
+ int minNr = -1;
+
+ int nr = firstCorner;
+ for (int i = 0; i < numCorners; i++) {
+ Corner &c = mCorners[(uint32_t)nr];
+ if (c.isEar && c.angle < minAng) {
+ minAng = c.angle;
+ minNr = nr;
+ }
+ nr = c.next;
+ }
+
+ // cut ear
+// assert(minNr >= 0);
+if (minNr < 0)
+break;
+ Corner &cmin = mCorners[(uint32_t)minNr];
+ mIndices.pushBack(cmin.prev);
+ mIndices.pushBack(minNr);
+ mIndices.pushBack(cmin.next);
+ mCorners[(uint32_t)cmin.prev].next = cmin.next;
+ mCorners[(uint32_t)cmin.next].prev = cmin.prev;
+
+ if (firstCorner == minNr)
+ firstCorner = cmin.next;
+ numCorners--;
+ if (numCorners == 3)
+ break;
+
+ // new ears?
+ for (int i = 0; i < 2; i++) {
+ uint32_t i1 = uint32_t((i == 0) ? cmin.prev : cmin.next);
+ uint32_t i0 = (uint32_t)mCorners[i1].prev;
+ uint32_t i2 = (uint32_t)mCorners[i1].next;
+
+ PxVec3 &p0 = mPoints[i0];
+ PxVec3 &p1 = mPoints[i1];
+ PxVec3 &p2 = mPoints[i2];
+ PxVec3 n1 = p1-p0;
+ PxVec3 n2 = p2-p1;
+ if (cross(n1, n2) > 0.0f) {
+ n1.normalize();
+ n2.normalize();
+ mCorners[i1].angle = n1.dot(n2);
+
+ mCorners[i1].isEar = true;
+ int nr = mCorners[i2].next;
+ for (int j = 0; j < numCorners-3; j++) {
+ if (inTriangle(mPoints[(uint32_t)nr], p0,p1,p2)) {
+ mCorners[i1].isEar = false;
+ break;
+ }
+ nr = mCorners[(uint32_t)nr].next;
+ }
+ }
+ }
+ }
+ int id = firstCorner;
+ mIndices.pushBack(id);
+ id = mCorners[(uint32_t)id].next;
+ mIndices.pushBack(id);
+ id = mCorners[(uint32_t)id].next;
+ mIndices.pushBack(id);
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.h b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.h
new file mode 100644
index 00000000..b6441ff2
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/PolygonTriangulatorBase.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef POLYGON_TRIANGULATOR_BASE_H
+#define POLYGON_TRIANGULATOR_BASE_H
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+#include <PxMath.h>
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+ class SimScene;
+
+// ------------------------------------------------------------------------------
+
+class PolygonTriangulator : public UserAllocated {
+ friend class SimScene;
+public:
+ // singleton pattern
+ //static PolygonTriangulator* getInstance();
+ //static void destroyInstance();
+
+ void triangulate(const PxVec3 *points, int numPoints, const int *indices = NULL, PxVec3 *planeNormal = NULL);
+ const nvidia::Array<int> &getIndices() const { return mIndices; }
+
+protected:
+ void importPoints(const PxVec3 *points, int numPoints, const int *indices, PxVec3 *planeNormal, bool &isConvex);
+ void clipEars();
+
+ inline float cross(const PxVec3 &p0, const PxVec3 &p1);
+ bool inTriangle(const PxVec3 &p, const PxVec3 &p0, const PxVec3 &p1, const PxVec3 &p2);
+
+ PolygonTriangulator(SimScene* scene);
+ virtual ~PolygonTriangulator();
+
+ SimScene* mScene;
+
+ nvidia::Array<PxVec3> mPoints;
+ nvidia::Array<int> mIndices;
+
+ struct Corner {
+ int prev;
+ int next;
+ bool isEar;
+ float angle;
+ };
+ nvidia::Array<Corner> mCorners;
+};
+
+}
+}
+}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.cpp b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.cpp
new file mode 100644
index 00000000..e8b1a7be
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.cpp
@@ -0,0 +1,654 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "SimSceneBase.h"
+#include <PxMat44.h>
+#include "PxRigidBodyExt.h"
+#include "PxPhysics.h"
+#include "PxCooking.h"
+#include "PxShape.h"
+#include "PxScene.h"
+#include "PxMaterial.h"
+
+#include "ActorBase.h"
+#include "CompoundBase.h"
+#include "ConvexBase.h"
+#include "CompoundCreatorBase.h"
+#include "Delaunay2dBase.h"
+#include "Delaunay3dBase.h"
+#include "PolygonTriangulatorBase.h"
+#include "IslandDetectorBase.h"
+#include "MeshClipperBase.h"
+#include "FracturePatternBase.h"
+
+#include "RTdef.h"
+
+#define USE_CONVEX_RENDERER 1
+#define NUM_NO_SOUND_FRAMES 1
+
+//#define REL_VEL_FRACTURE_THRESHOLD 5.0f
+#define REL_VEL_FRACTURE_THRESHOLD 0.1f
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+using namespace physx;
+
+SimScene* SimScene::createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath)
+{
+ SimScene* s = PX_NEW(SimScene)(pxPhysics,pxCooking,scene,minConvexSize,defaultMat,resourcePath);
+ s->createSingletons();
+ return s;
+}
+
+void SimScene::createSingletons()
+{
+ mCompoundCreator = PX_NEW(CompoundCreator)(this);
+ mDelaunay2d = PX_NEW(Delaunay2d)(this);
+ mDelaunay3d = PX_NEW(Delaunay3d)(this);
+ mPolygonTriangulator = PX_NEW(PolygonTriangulator)(this);
+ mIslandDetector = PX_NEW(IslandDetector)(this);
+ mMeshClipper = PX_NEW(MeshClipper)(this);
+ addActor(createActor()); // make default actor
+}
+
+Convex* SimScene::createConvex()
+{
+ return PX_NEW(Convex)(this);
+}
+
+Compound* SimScene::createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern, float contactOffset, float restOffset)
+{
+ return PX_NEW(Compound)(this,pattern,secondaryPattern,contactOffset,restOffset);
+}
+
+FracturePattern* SimScene::createFracturePattern()
+{
+ return PX_NEW(FracturePattern)(this);
+}
+
+Actor* SimScene::createActor()
+{
+ return PX_NEW(Actor)(this);
+}
+
+nvidia::Array<Compound*> SimScene::getCompounds()
+{
+ return mActors[0]->getCompounds();
+}
+
+///*extern*/ std::vector<Compound*> delCompoundList;
+
+// --------------------------------------------------------------------------------------------
+SimScene::SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath)
+{
+ mPxPhysics = pxPhysics; // used for cooking
+ mPxCooking = pxCooking;
+ mScene = scene;
+ mPxDefaultMaterial = defaultMat;
+ if (mPxDefaultMaterial != NULL)
+ {
+ mPxDefaultMaterial->acquireReference();
+ }
+ else
+ {
+ mPxDefaultMaterial = pxPhysics->createMaterial(0.5f, 0.5f, 0.1f);
+ }
+ mResourcePath = resourcePath;
+
+ clear();
+ mRenderBuffers.init();
+ mSceneVersion = 1;
+ mRenderBufferVersion = 0;
+ mOptixBufferVersion = 0;
+
+ //create3dTexture();
+
+ mFractureForceThreshold = 500.0f;
+ mContactImpactRadius = 0.5f;
+
+ mNoFractureFrames = 0;
+ mNoSoundFrames = 0;
+ mFrameNr = 0;
+ mDebugDraw = false;
+// mDebugDraw = true; // foo
+
+ mPickDepth = 0.0f;
+ mPickActor = NULL;
+ mPickPos = mPickLocalPos = PxVec3(0.0f, 0.0f, 0.0f);
+
+ mMinConvexSize = minConvexSize;
+ mNumNoFractureFrames = 2;
+
+ bumpTextureUVScale = 0.1f;
+ roughnessScale = 0.2f;
+ extraNoiseScale = 2.0f;
+
+ particleBumpTextureUVScale = 0.2f;
+ particleRoughnessScale = 0.8f;
+ particleExtraNoiseScale = 2.0f;
+
+
+ mPlaySounds = false;
+ mRenderDebris = true;
+
+ mCompoundCreator = NULL;
+ mDelaunay2d = NULL;
+ mDelaunay3d = NULL;
+ mPolygonTriangulator = NULL;
+ mIslandDetector = NULL;
+
+ mAppNotify = NULL;
+
+ //SDLWrapper::init();
+}
+
+// --------------------------------------------------------------------------------------------
+SimScene::~SimScene()
+{
+ clear();
+
+ if (mPxDefaultMaterial)
+ {
+ mPxDefaultMaterial->release();
+ mPxDefaultMaterial = NULL;
+ }
+
+ // Delete actors if not already deleted
+ for(int i = ((int)mActors.size() - 1) ; i >= 0; i--)
+ {
+ PX_DELETE(mActors[(uint32_t)i]);
+ }
+
+ PX_DELETE(mCompoundCreator);
+ PX_DELETE(mDelaunay2d);
+ PX_DELETE(mDelaunay3d);
+ PX_DELETE(mPolygonTriangulator);
+ PX_DELETE(mIslandDetector);
+ PX_DELETE(mMeshClipper);
+
+ mCompoundCreator = NULL;
+ mDelaunay2d = NULL;
+ mDelaunay3d = NULL;
+ mPolygonTriangulator = NULL;
+ mIslandDetector = NULL;
+ mMeshClipper = NULL;
+
+ //SDLWrapper::done();
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::restoreUserCallbacks()
+{
+ if (mScene != NULL)
+ {
+ // restore user callbacks
+ mScene->lockWrite();
+ mScene->setSimulationEventCallback(mAppNotify);
+ mScene->unlockWrite();
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::clear()
+{
+ for(uint32_t i = 0 ; i < mActors.size(); i++)
+ {
+ mActors[i]->clear();
+ }
+ deleteCompounds();
+ mPickActor = NULL;
+
+ ++mSceneVersion;
+}
+
+void SimScene::addActor(Actor* a)
+{
+ mActors.pushBack(a);
+}
+
+void SimScene::removeActor(Actor* a)
+{
+ for(uint32_t i = 0; i < mActors.size(); i++)
+ {
+ if( a == mActors[i] )
+ {
+ mActors[i] = mActors[mActors.size()-1];
+ mActors.popBack();
+ }
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::addCompound(Compound *c)
+{
+ mActors[0]->addCompound(c);
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::removeCompound(Compound *c)
+{
+ mActors[0]->removeCompound(c);
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::deleteCompounds()
+{
+ for (uint32_t i = 0; i < delCompoundList.size(); i++)
+ {
+ PX_DELETE(delCompoundList[i]);
+ }
+ delCompoundList.clear();
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::preSim(float dt)
+{
+ const float pickStiffness = 2.0f;
+
+ if (mPickActor != NULL) {
+ PxVec3 pos = mPickActor->getGlobalPose().transform(mPickLocalPos);
+ float m = mPickActor->getMass();
+
+ PxRigidBodyExt::addForceAtPos(*mPickActor, (mPickPos - pos) * pickStiffness * m, pos, PxForceMode::eIMPULSE);
+ }
+
+ for(uint32_t i = 0 ; i < mActors.size(); i++)
+ {
+ mActors[i]->preSim(dt);
+ }
+
+ mFractureEvents.clear();
+
+ // make sure we use the apex user notify... if the application
+ // changes their custom one make sure we map to it.
+ if (mScene != NULL)
+ {
+ mScene->lockWrite();
+ PxSimulationEventCallback* userNotify = mScene->getSimulationEventCallback();
+ if (userNotify != this)
+ {
+ mAppNotify = userNotify;
+ mScene->setSimulationEventCallback(this);
+ }
+ mScene->unlockWrite();
+ }
+}
+
+//float4* posVelG = 0;
+//int numPosVelG = 0;
+// --------------------------------------------------------------------------------------------
+void SimScene::postSim(float dt)
+{
+// Profiler *p = Profiler::getInstance();
+
+ //processFractureEvents(fluidSim);
+ for(uint32_t i = 0 ; i < mActors.size(); i++)
+ {
+ mActors[i]->postSim(dt);
+ }
+ //posVelG = &posVel[0];
+ //numPosVelG = posVel.size();
+// mFractureEvents.clear(); // foo
+
+ mFrameNr++;
+ mNoFractureFrames--;
+ mNoSoundFrames--;
+}
+
+// --------------------------------------------------------------------------------------------
+bool SimScene::rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &actorNr , int &compoundNr, int &convexNr, PxVec3 &normal) const
+{
+ dist = PX_MAX_F32;
+ actorNr = -1;
+ compoundNr = -1;
+ convexNr = -1;
+
+ for (int i = 0; i < (int)mActors.size(); i++)
+ {
+ float d;
+ int comNr;
+ int conNr;
+ PxVec3 n;
+ if (mActors[(uint32_t)i]->rayCast(orig,dir,d,comNr,conNr,n))
+ {
+ if( d < dist )
+ {
+ dist = d;
+ actorNr = i;
+ compoundNr = comNr;
+ convexNr = conNr;
+ normal = n;
+ }
+ }
+ }
+
+ return actorNr >= 0;
+}
+
+//-----------------------------------------------------------------------------
+bool SimScene::pickStart(const PxVec3 &orig, const PxVec3 &dir)
+{
+ float dist;
+ int actorNr, compoundNr, convexNr;
+ PxVec3 normal;
+
+ if (!rayCast(orig, dir, dist, actorNr, compoundNr, convexNr, normal))
+ return false;
+
+ mPickActor = mActors[(uint32_t)actorNr]->mCompounds[(uint32_t)compoundNr]->getPxActor();
+ mPickPos = orig + dir * dist;
+ mPickLocalPos = mPickActor->getGlobalPose().transformInv(mPickPos);
+ mPickDepth = dist;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void SimScene::pickMove(const PxVec3 &orig, const PxVec3 &dir)
+{
+ if (mPickActor == NULL)
+ return;
+
+ mPickPos = orig + dir * mPickDepth;
+}
+
+//-----------------------------------------------------------------------------
+void SimScene::pickRelease()
+{
+ mPickActor = NULL;
+}
+
+// --------------------------------------------------------------------------------------------
+bool SimScene::patternFracture(const PxVec3 &orig, const PxVec3 &dir, const PxMat33 patternTransform, float impactRadius, float radialImpulse, float directionalImpulse)
+{
+ float dist;
+ //float objectSize = 0.0f;
+ int actorNr;
+ int compoundNr;
+ int convexNr;
+ PxVec3 normal;
+
+ if (!rayCast(orig, dir, dist, actorNr, compoundNr, convexNr, normal))
+ return false;
+
+ return mActors[(uint32_t)actorNr]->patternFracture(orig+dist*dir,normal,compoundNr,patternTransform,impactRadius,radialImpulse,directionalImpulse);
+}
+
+bool SimScene::findCompound(const Compound* c, int& actorNr, int& compoundNr)
+{
+ actorNr = -1;
+ compoundNr = -1;
+ for(uint32_t i = 0; i < mActors.size(); i++)
+ {
+ if (mActors[i]->findCompound(c,compoundNr))
+ {
+ actorNr = (int32_t)i;
+ return true;
+ }
+ }
+ return false;
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::processFractureEvents(bool& valid,bool* addFireDustP)
+{
+ valid = false;
+ debugPoints.clear();
+ int numPieces = 0;
+
+ if (mFractureEvents.size() <= 0)
+ return;
+
+ nvidia::Array<Compound*> compounds;
+ ++mSceneVersion;
+
+ float objectSize = 0.0f;
+
+ // here the fracture pattern could be randomized
+ float scale = 1.0f;
+ PxMat33 fractureTransform;
+ fractureTransform = PxMat33(PxIdentity);
+ fractureTransform *= scale;
+
+ bool addFireDust = false;
+
+ for (uint32_t i = 0; i < mFractureEvents.size(); i++) {
+ const FractureEvent &e = mFractureEvents[i];
+
+ if (!e.compound->patternFracture(e.pos, mMinConvexSize, compounds, fractureTransform, debugPoints, mContactImpactRadius,
+ e.additionalRadialImpulse, -e.normal * e.additionalNormalImpulse))
+ continue;
+
+ if (e.additionalNormalImpulse > 0.0f || e.additionalRadialImpulse > 0.0f) {
+ addFireDust = true;
+ playSound("explosion", 1);
+ }
+ else {
+// playSound("explosion", 1);
+ }
+
+ if (compounds.empty())
+ continue;
+
+ PxBounds3 bounds;
+ e.compound->getWorldBounds(bounds);
+ float size = bounds.getDimensions().magnitude();
+ if (size > objectSize)
+ objectSize = size;
+
+ for (uint32_t j = 0; j < compounds.size(); j++) {
+ PxRigidDynamic *a = compounds[j]->getPxActor();
+// a->setContactReportFlags(Px_NOTIFY_ON_TOUCH_FORCE_THRESHOLD);
+ a->setContactReportThreshold(mFractureForceThreshold);
+ }
+
+ //int compoundNr = 0;
+ //while (compoundNr < (int)mCompounds.size() && mCompounds[compoundNr] != e.compound)
+ // compoundNr++;
+
+ //int first = 0;
+ //if (compoundNr < (int)mCompounds.size()) {
+ // mCompounds[compoundNr] = compounds[0];
+ // first++;
+ //}
+
+ int first = 0;
+ int actorNr = 0;
+ int compoundNr = 0;
+ if (findCompound(e.compound,actorNr,compoundNr) )
+ {
+ mActors[(uint32_t)actorNr]->mCompounds[(uint32_t)compoundNr] = compounds[0];
+ first++;
+ }
+
+ if (e.compound->getPxActor() == mPickActor)
+ mPickActor = NULL;
+
+ e.compound->clear();
+ //delCompoundList.push_back(e.compound);
+ delCompoundList.pushBack(e.compound);
+
+ //delete e.compound;
+
+ for (int j = first; j < (int)compounds.size(); j++)
+ mActors[(uint32_t)actorNr]->mCompounds.pushBack(compounds[(uint32_t)j]);
+
+ numPieces += compounds.size();
+ }
+
+ mFractureEvents.clear();
+
+ if (objectSize > 0.0f) {
+ // playShatterSound(objectSize);
+ mNoFractureFrames = mNumNoFractureFrames;
+ }
+ if(addFireDustP)
+ {
+ *addFireDustP = addFireDust;
+ }
+ valid = true;
+ return;
+}
+
+void SimScene::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, uint32_t nbPairs)
+{
+ // Pass along to application's callback, if defined
+ if (mAppNotify != NULL)
+ {
+ mAppNotify->onContact(pairHeader, pairs, nbPairs);
+ }
+
+ if (mNoFractureFrames > 0)
+ return;
+
+ for (int i = 0; i < (int)nbPairs; i++) {
+
+ const PxContactPair &pair = pairs[i];
+ uint32_t num = pair.contactCount;
+ if (num == 0)
+ continue;
+
+ mContactPoints.resize(num);
+ pairs[i].extractContacts(&mContactPoints[0], num);
+
+ // pick first point (arbitrary)
+ Convex* convexes[2];
+ convexes[0] = findConvexForShape(*pair.shapes[0]);
+ convexes[1] = findConvexForShape(*pair.shapes[1]);
+
+ PxVec3 &pos = mContactPoints[0].position;
+ PxVec3 &normal = mContactPoints[0].normal;
+
+ PxVec3 relVel(0.0f, 0.0f, 0.0f);
+
+ for (int j = 0; j < 2; j++) {
+ if (convexes[j] == NULL)
+ continue;
+ PxRigidDynamic *a = convexes[j]->getParent()->getPxActor();
+ PxVec3 v = PxRigidBodyExt::getVelocityAtPos(*a, pos);
+ relVel += (j == 0) ? v : -v;
+ }
+
+ float normalImpulse = 0;
+ float radialImpulse = 0;
+ for (int j = 0; j < 2; j++) {
+ if (convexes[j] != NULL) {
+ normalImpulse = PxMax(normalImpulse, convexes[j]->getParent()->getAdditionalImpactNormalImpulse());
+ radialImpulse = PxMax(radialImpulse, convexes[j]->getParent()->getAdditionalImpactRadialImpulse());
+ }
+ }
+
+ for (int j = 0; j < 2; j++) {
+ Convex *c = convexes[j];
+ if (c == NULL)
+ continue;
+ if (relVel.magnitude() < REL_VEL_FRACTURE_THRESHOLD)
+ continue;
+
+ Compound *compound = c->getParent();
+
+ FractureEvent e;
+ e.init();
+ e.compound = compound;
+ e.pos = pos;
+ e.normal = normal;
+ e.withStatic = (convexes[1-j] == NULL);
+ e.additionalNormalImpulse = normalImpulse;
+ e.additionalRadialImpulse = radialImpulse;
+
+ uint32_t k = 0;
+ while (k < mFractureEvents.size() && mFractureEvents[k].compound != compound)
+ k++;
+
+ if (k < mFractureEvents.size()) {
+ if (mFractureEvents[k].withStatic && !e.withStatic) // prioritize dynamic collisions
+ mFractureEvents[k] = e;
+ }
+ else
+ mFractureEvents.pushBack(e);
+ }
+ }
+}
+
+void SimScene::onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count)
+{
+ PX_UNUSED(bodyBuffer);
+ PX_UNUSED(poseBuffer);
+ PX_UNUSED(count);
+}
+
+void SimScene::onTrigger(PxTriggerPair* pairs, uint32_t count)
+{
+ // Pass along to application's callback, if defined
+ if (mAppNotify != NULL)
+ {
+ mAppNotify->onTrigger(pairs, count);
+ }
+}
+
+void SimScene::onWake(PxActor** actors, uint32_t count)
+{
+ // Pass along to application's callback, if defined
+ if (mAppNotify != NULL)
+ {
+ mAppNotify->onWake(actors, count);
+ }
+}
+
+void SimScene::onSleep(PxActor** actors, uint32_t count)
+{
+ // Pass along to application's callback, if defined
+ if (mAppNotify != NULL)
+ {
+ mAppNotify->onSleep(actors, count);
+ }
+}
+
+void SimScene::onConstraintBreak(physx::PxConstraintInfo* constraints, uint32_t count)
+{
+ // Pass along to application's callback, if defined
+ if (mAppNotify != NULL)
+ {
+ mAppNotify->onConstraintBreak(constraints, count);
+ }
+}
+
+nvidia::Array<PxVec3>& SimScene::getDebugPoints() {
+ return debugPoints;
+}
+
+bool SimScene::mapShapeToConvex(const PxShape& shape, Convex& convex)
+{
+ return mShapeMap.insert(&shape, &convex);
+}
+
+bool SimScene::unmapShape(const PxShape& shape)
+{
+ return mShapeMap.erase(&shape);
+}
+
+Convex* SimScene::findConvexForShape(const PxShape& shape)
+{
+ const shdfnd::HashMap<const PxShape*, Convex*>::Entry* entry = mShapeMap.find(&shape);
+ return entry != NULL ? entry->second : NULL; // Since we don't expect *entry to be NULL, we shouldn't lose information here
+}
+
+}
+}
+}
+
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.h b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.h
new file mode 100644
index 00000000..2170c19e
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Core/SimSceneBase.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef SIM_SCENE_BASE
+#define SIM_SCENE_BASE
+
+#include "PxSimulationEventCallback.h"
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+#include <PsHashMap.h>
+
+#include "RTdef.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+namespace base
+{
+
+class Actor;
+class Compound;
+class Convex;
+class FracturePattern;
+class CompoundCreator;
+class Delaunay2d;
+class Delaunay3d;
+class PolygonTriangulator;
+class IslandDetector;
+class MeshClipper;
+
+// -----------------------------------------------------------------------------------
+class SimScene :
+ public PxSimulationEventCallback, public UserAllocated
+{
+ friend class Actor;
+public:
+ static SimScene* createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath);
+protected:
+ SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath);
+public:
+ // Allow the Destructible module to release things in a proper order
+ void restoreUserCallbacks();
+ virtual ~SimScene();
+
+ // Creates Scene Level Singletons
+ virtual void createSingletons();
+ // Access singletons
+ CompoundCreator* getCompoundCreator() {return mCompoundCreator;}
+ Delaunay2d* getDelaunay2d() {return mDelaunay2d;}
+ Delaunay3d* getDelaunay3d() {return mDelaunay3d;}
+ PolygonTriangulator* getPolygonTriangulator() {return mPolygonTriangulator;}
+ IslandDetector* getIslandDetector() {return mIslandDetector;}
+ MeshClipper* getMeshClipper() {return mMeshClipper;}
+
+ // Create non-Singletons
+ virtual Actor* createActor();
+ virtual Convex* createConvex();
+ virtual Compound* createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f);
+ virtual FracturePattern* createFracturePattern();
+ virtual void clear();
+ void addCompound(Compound *m);
+ void removeCompound(Compound *m);
+ // perform deferred deletion
+ void deleteCompounds();
+ //
+ bool findCompound(const Compound* c, int& actorNr, int& compoundNr);
+
+ void removeActor(Actor* a);
+
+ // Profiler hooks
+ virtual void profileBegin(const char* /*name*/) {}
+ virtual void profileEnd(const char* /*name*/) {}
+
+ bool rayCast(const PxVec3 &orig, const PxVec3 &dir, float &dist, int &actorNr, int &compoundNr, int &convexNr, PxVec3 &normal) const;
+
+ bool patternFracture(const PxVec3 &orig, const PxVec3 &dir,
+ const PxMat33 patternTransform, float impactRadius = 0.0f, float radialImpulse = 0.0f, float directionalImpulse = 0.0f);
+
+ virtual void playSound(const char * /*name*/, int /*nr*/ = -1) {}
+
+ // accessors
+ nvidia::Array<Compound*> getCompounds(); //{ return mCompounds; }
+ nvidia::Array<Actor*> getActors() { return mActors; }
+ PxPhysics* getPxPhysics() { return mPxPhysics; }
+ PxCooking* getPxCooking() { return mPxCooking; }
+ PxScene* getScene() { return mScene; }
+
+ //ConvexRenderer &getConvexRenderer() { return mConvexRenderer; }
+
+ void preSim(float dt);
+ void postSim(float dt); //, RegularCell3D* fluidSim);
+
+ void setPlaySounds(bool play) { mPlaySounds = play; }
+ void setContactImpactRadius(float radius) { mContactImpactRadius = radius; }
+ void setNumNoFractureFrames(int num) { mNumNoFractureFrames = num; }
+
+ void setCamera(const PxVec3 &pos, const PxVec3 &dir, const PxVec3 &up, float fov ) {
+ mCameraPos = pos; mCameraDir = dir; mCameraUp = up; mCameraFov = fov;
+ }
+
+ //void draw(bool useShader, Shader* particleShader = NULL) {}
+ //void setShaderMaterial(Shader* shader, const ShaderMaterial& mat) {this->mShader = shader; this->mShaderMat = mat;}
+ //void setFractureForceThreshold(float threshold) { mFractureForceThreshold = threshold; }
+
+ PxMaterial *getPxDefaultMaterial() { return mPxDefaultMaterial; }
+
+ void toggleDebugDrawing() { mDebugDraw = !mDebugDraw; }
+
+ virtual bool pickStart(const PxVec3 &orig, const PxVec3 &dir);
+ virtual void pickMove(const PxVec3 &orig, const PxVec3 &dir);
+ virtual void pickRelease();
+ PxRigidDynamic* getPickActor() { return mPickActor; }
+ const PxVec3 &getPickPos() { return mPickPos; }
+ const PxVec3 &getPickLocalPos() { return mPickLocalPos; }
+
+ // callback interface
+
+ void onContactNotify(unsigned int arraySizes, void ** shape0Array, void ** shape1Array, void ** actor0Array, void ** actor1Array, float * positionArray, float * normalArray);
+ void onConstraintBreak(physx::PxConstraintInfo* constraints, uint32_t count);
+ void onWake(PxActor** actors, uint32_t count);
+ void onSleep(PxActor** actors, uint32_t count);
+ void onTrigger(physx::PxTriggerPair* pairs, uint32_t count);
+ void onContact(const physx::PxContactPairHeader& pairHeader, const physx::PxContactPair* pairs, uint32_t nbPairs);
+ void onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count);
+
+ void toggleRenderDebris() {mRenderDebris = !mRenderDebris;}
+ bool getRenderDebrs() {return mRenderDebris;}
+ //virtual void dumpSceneGeometry() {}
+ nvidia::Array<PxVec3>& getDebugPoints();
+ //virtual void createRenderBuffers() {}
+ //void loadAndCreateTextureArrays();
+
+ nvidia::Array<PxVec3>& getCrackNormals() {return crackNormals;}
+ nvidia::Array<PxVec3>& getTmpPoints() {return tmpPoints;}
+
+ bool mapShapeToConvex(const PxShape& shape, Convex& convex);
+ bool unmapShape(const PxShape& shape);
+ Convex* findConvexForShape(const PxShape& shape);
+ bool owns(const PxShape& shape) {return NULL != findConvexForShape(shape);}
+
+protected:
+ //virtual void create3dTexture() {}
+ //virtual void updateConvexesTex() {}
+ //void playShatterSound(float objectSize);
+
+ void addActor(Actor* a); // done internally upon creation
+
+ PxPhysics *mPxPhysics;
+ PxCooking *mPxCooking;
+ PxScene *mScene;
+ const char *mResourcePath;
+ bool mPlaySounds;
+
+ //nvidia::Array<Compound*> mCompounds;
+ nvidia::Array<Actor*> mActors;
+
+ float mFractureForceThreshold;
+ float mContactImpactRadius;
+
+ nvidia::Array<physx::PxContactPairPoint> mContactPoints;
+ struct FractureEvent {
+ void init() {
+ compound = NULL;
+ pos = normal = PxVec3(0.0f, 0.0f, 0.0f);
+ additionalRadialImpulse = additionalNormalImpulse = 0.0f;
+ withStatic = false;
+ }
+ Compound *compound;
+ PxVec3 pos;
+ PxVec3 normal;
+ float additionalRadialImpulse;
+ float additionalNormalImpulse;
+ bool withStatic;
+ };
+ nvidia::Array<FractureEvent> mFractureEvents;
+ void processFractureEvents(bool& valid,bool* addFireDust = NULL);
+
+ struct RenderBuffers {
+ void init() {
+ numVertices = 0; numIndices = 0;
+ VBO = 0; IBO = 0; matTex = 0; volTex = 0;
+ texSize = 0; numConvexes = -1;
+ }
+ nvidia::Array<float> tmpVertices;
+ nvidia::Array<unsigned int> tmpIndices;
+ nvidia::Array<float> tmpTexCoords;
+ int numVertices, numIndices;
+ unsigned int VBO;
+ unsigned int IBO;
+ unsigned int volTex;
+ unsigned int matTex;
+ int texSize;
+ int numConvexes;
+ };
+ RenderBuffers mRenderBuffers;
+ unsigned int mSceneVersion; // changed on each update
+ unsigned int mRenderBufferVersion; // to handle updates
+ unsigned int mOptixBufferVersion; // to handle updates
+
+ PxMaterial *mPxDefaultMaterial;
+
+ //ConvexRenderer mConvexRenderer;
+
+ int mNoFractureFrames;
+ int mNoSoundFrames;
+ int mFrameNr;
+ bool mDebugDraw;
+
+ float mPickDepth;
+ PxRigidDynamic *mPickActor;
+ PxVec3 mPickPos;
+ PxVec3 mPickLocalPos;
+
+ float mMinConvexSize;
+ int mNumNoFractureFrames; // > 1 to prevent a slow down by too many fracture events
+
+ PxVec3 mCameraPos, mCameraDir, mCameraUp;
+ float mCameraFov;
+
+ float bumpTextureUVScale;
+ float extraNoiseScale;
+ float roughnessScale;
+
+ float particleBumpTextureUVScale;
+ float particleRoughnessScale;
+ float particleExtraNoiseScale;
+ nvidia::Array<PxVec3> debugPoints;
+ bool mRenderDebris;
+
+ PxSimulationEventCallback* mAppNotify;
+
+ //GLuint diffuseTexArray, bumpTexArray, specularTexArray, emissiveReflectSpecPowerTexArray;
+
+ //GLuint loadTextureArray(std::vector<std::string>& names);
+
+ //Singletons
+ CompoundCreator* mCompoundCreator;
+ Delaunay2d* mDelaunay2d;
+ Delaunay3d* mDelaunay3d;
+ PolygonTriangulator* mPolygonTriangulator;
+ IslandDetector* mIslandDetector;
+ MeshClipper* mMeshClipper;
+
+ //Array for use by Compound (effectively static)
+ nvidia::Array<PxVec3> crackNormals;
+ nvidia::Array<PxVec3> tmpPoints;
+
+ // Deferred Deletion list
+ nvidia::Array<Compound*> delCompoundList;
+
+ // Map used to determine SimScene ownership of shape
+ shdfnd::HashMap<const PxShape*,Convex*> mShapeMap;
+};
+
+}
+}
+}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Delaunay2d.cpp b/APEX_1.4/module/destructible/fracture/Delaunay2d.cpp
new file mode 100644
index 00000000..efa26e4d
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Delaunay2d.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "Delaunay2d.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Delaunay2d.h b/APEX_1.4/module/destructible/fracture/Delaunay2d.h
new file mode 100644
index 00000000..7776214e
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Delaunay2d.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef DELAUNAY_2D_H
+#define DELAUNAY_2D_H
+
+#include <PxVec3.h>
+#include <PsArray.h>
+
+#include "Delaunay2dBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class Delaunay2d : public base::Delaunay2d
+{
+ friend class SimScene;
+protected:
+ Delaunay2d(base::SimScene* scene): base::Delaunay2d((base::SimScene*)scene) {}
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Delaunay3d.cpp b/APEX_1.4/module/destructible/fracture/Delaunay3d.cpp
new file mode 100644
index 00000000..2ab81157
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Delaunay3d.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "Delaunay3d.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Delaunay3d.h b/APEX_1.4/module/destructible/fracture/Delaunay3d.h
new file mode 100644
index 00000000..628e071d
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Delaunay3d.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef DELAUNAY_3D_H
+#define DELAUNAY_3D_H
+
+#include <PxVec3.h>
+#include <PsArray.h>
+
+#include "CompoundGeometry.h"
+
+#include "Delaunay3dBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class Delaunay3d : public base::Delaunay3d
+{
+ friend class SimScene;
+protected:
+ Delaunay3d(base::SimScene* scene): base::Delaunay3d((base::SimScene*)scene) {}
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/FracturePattern.cpp b/APEX_1.4/module/destructible/fracture/FracturePattern.cpp
new file mode 100644
index 00000000..08133f41
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/FracturePattern.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "FracturePattern.h"
+
+// Empty until base has code proven to be non-portable
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/FracturePattern.h b/APEX_1.4/module/destructible/fracture/FracturePattern.h
new file mode 100644
index 00000000..ddf9911b
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/FracturePattern.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef FRACTURE_PATTERN
+#define FRACTURE_PATTERN
+
+#include "Delaunay3d.h"
+#include "Delaunay2d.h"
+#include "CompoundGeometry.h"
+#include "PxTransform.h"
+#include "PxBounds3.h"
+
+#include "FracturePatternBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class Convex;
+class Compound;
+class CompoundGeometry;
+
+class FracturePattern : public base::FracturePattern
+{
+ friend class SimScene;
+protected:
+ FracturePattern(base::SimScene* scene): base::FracturePattern((base::SimScene*)scene) {}
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/IceBoxPruning.cpp b/APEX_1.4/module/destructible/fracture/IceBoxPruning.cpp
new file mode 100644
index 00000000..65ecc1b6
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/IceBoxPruning.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "IceBoxPruning.h"
+
+// Empty until base has code proven to be non-portable
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/IceBoxPruning.h b/APEX_1.4/module/destructible/fracture/IceBoxPruning.h
new file mode 100644
index 00000000..b5d2f0f1
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/IceBoxPruning.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef ICEBOXPRUNING_H
+#define ICEBOXPRUNING_H
+
+#include "IceRevisitedRadix.h"
+#include "PxVec3.h"
+#include "PxBounds3.h"
+
+#include "IceBoxPruningBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+struct Axes : public base::Axes
+{
+};
+
+class BoxPruning : public base::BoxPruning
+{
+
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.cpp b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.cpp
new file mode 100644
index 00000000..331c7ee6
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "IceRevisitedRadix.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.h b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.h
new file mode 100644
index 00000000..19bc8d25
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/IceRevisitedRadix.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef ICERADIXSORT_H
+#define ICERADIXSORT_H
+
+#include "IceRevisitedRadixBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class RadixSort : public nvidia::fracture::base::RadixSort
+{
+};
+
+}
+}
+
+#endif // __ICERADIXSORT_H__
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/IslandDetector.cpp b/APEX_1.4/module/destructible/fracture/IslandDetector.cpp
new file mode 100644
index 00000000..c09dfa80
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/IslandDetector.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "IslandDetector.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/IslandDetector.h b/APEX_1.4/module/destructible/fracture/IslandDetector.h
new file mode 100644
index 00000000..889e5050
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/IslandDetector.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef ISLAND_DETECTOR_H
+#define ISLAND_DETECTOR_H
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include "IceBoxPruning.h"
+
+#include "IslandDetectorBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class IslandDetector : public base::IslandDetector
+{
+ friend class SimScene;
+protected:
+ IslandDetector(base::SimScene* scene): base::IslandDetector((base::SimScene*)scene) {}
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/Mesh.cpp b/APEX_1.4/module/destructible/fracture/Mesh.cpp
new file mode 100644
index 00000000..04ffbbd8
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Mesh.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include <RenderMeshAsset.h>
+
+#include "Mesh.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+void Mesh::gatherPartMesh(Array<PxVec3>& vertices,
+ nvidia::Array<uint32_t>& indices,
+ nvidia::Array<PxVec3>& normals,
+ nvidia::Array<PxVec2>& texcoords,
+ nvidia::Array<SubMesh>& subMeshes,
+ const RenderMeshAsset& renderMeshAsset,
+ uint32_t partIndex)
+
+{
+ if (partIndex >= renderMeshAsset.getPartCount())
+ {
+ vertices.resize(0);
+ indices.resize(0);
+ normals.resize(0);
+ texcoords.resize(0);
+ subMeshes.resize(0);
+ return;
+ }
+
+ subMeshes.resize(renderMeshAsset.getSubmeshCount());
+
+ // Pre-count vertices and indices so we can allocate once
+ uint32_t vertexCount = 0;
+ uint32_t indexCount = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAsset.getSubmeshCount(); ++submeshIndex)
+ {
+ const RenderSubmesh& submesh = renderMeshAsset.getSubmesh(submeshIndex);
+ vertexCount += submesh.getVertexCount(partIndex);
+ indexCount += submesh.getIndexCount(partIndex);
+ }
+
+ vertices.resize(vertexCount);
+ normals.resize(vertexCount);
+ texcoords.resize(vertexCount);
+ indices.resize(indexCount);
+
+ vertexCount = 0;
+ indexCount = 0;
+ for (uint32_t submeshIndex = 0; submeshIndex < renderMeshAsset.getSubmeshCount(); ++submeshIndex)
+ {
+ const RenderSubmesh& submesh = renderMeshAsset.getSubmesh(submeshIndex);
+ const uint32_t submeshVertexCount = submesh.getVertexCount(partIndex);
+ if (submeshVertexCount > 0)
+ {
+ const VertexBuffer& vertexBuffer = submesh.getVertexBuffer();
+ const VertexFormat& vertexFormat = vertexBuffer.getFormat();
+
+ enum { MESH_SEMANTIC_COUNT = 3 };
+ struct {
+ RenderVertexSemantic::Enum semantic;
+ RenderDataFormat::Enum format;
+ uint32_t sizeInBytes;
+ void* dstBuffer;
+ } semanticData[MESH_SEMANTIC_COUNT] = {
+ { RenderVertexSemantic::POSITION, RenderDataFormat::FLOAT3, sizeof(PxVec3), &vertices[vertexCount] },
+ { RenderVertexSemantic::NORMAL, RenderDataFormat::FLOAT3, sizeof(PxVec3), &normals[vertexCount] },
+ { RenderVertexSemantic::TEXCOORD0, RenderDataFormat::FLOAT2, sizeof(PxVec2), &texcoords[vertexCount] }
+ };
+
+ for (uint32_t i = 0; i < MESH_SEMANTIC_COUNT; ++i)
+ {
+ const int32_t bufferIndex = vertexFormat.getBufferIndexFromID(vertexFormat.getSemanticID(semanticData[i].semantic));
+ if (bufferIndex >= 0)
+ vertexBuffer.getBufferData(semanticData[i].dstBuffer,
+ semanticData[i].format,
+ semanticData[i].sizeInBytes,
+ (uint32_t)bufferIndex,
+ submesh.getFirstVertexIndex(partIndex),
+ submesh.getVertexCount(partIndex));
+ else
+ memset(semanticData[i].dstBuffer, 0, submesh.getVertexCount(partIndex)*semanticData[i].sizeInBytes);
+ }
+
+ /*
+ const uint32_t firstVertexIndex = submesh.getFirstVertexIndex(partIndex);
+ fillBuffer<PxVec3>(vertexBuffer, vertexFormat, RenderVertexSemantic::POSITION, RenderDataFormat::FLOAT3,
+ firstVertexIndex, submeshVertexCount, &vertices[vertexCount]);
+ fillBuffer<PxVec3>(vertexBuffer, vertexFormat, RenderVertexSemantic::NORMAL, RenderDataFormat::FLOAT3,
+ firstVertexIndex, submeshVertexCount, &normals[vertexCount]);
+ fillBuffer<PxVec2>(vertexBuffer, vertexFormat, RenderVertexSemantic::TEXCOORD0, RenderDataFormat::FLOAT2,
+ firstVertexIndex, submeshVertexCount, &texcoords[vertexCount]);*/
+
+ const uint32_t* partIndexBuffer = submesh.getIndexBuffer(partIndex);
+ const uint32_t partIndexCount = submesh.getIndexCount(partIndex);
+ subMeshes[submeshIndex].firstIndex = (int32_t)partIndexCount;
+ for (uint32_t indexNum = 0; indexNum < partIndexCount; ++indexNum)
+ {
+ indices[indexCount++] = partIndexBuffer[indexNum] + vertexCount - submesh.getFirstVertexIndex(partIndex);
+ }
+ vertexCount += submeshVertexCount;
+ }
+ }
+}
+
+
+void Mesh::loadFromRenderMesh(const RenderMeshAsset& mesh, uint32_t partIndex)
+{
+ gatherPartMesh(mVertices, mIndices, mNormals, mTexCoords, mSubMeshes, mesh, partIndex);
+}
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Mesh.h b/APEX_1.4/module/destructible/fracture/Mesh.h
new file mode 100644
index 00000000..59231566
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Mesh.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef MESH
+#define MESH
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include <PsAllocator.h>
+
+#include "MeshBase.h"
+
+namespace nvidia
+{
+namespace apex
+{
+ class RenderMeshAsset;
+}
+}
+
+namespace nvidia
+{
+namespace fracture
+{
+
+using namespace ::nvidia::shdfnd;
+
+class Mesh : public base::Mesh
+{
+public:
+ void loadFromRenderMesh(const apex::RenderMeshAsset& mesh, uint32_t partIndex);
+protected:
+ static void gatherPartMesh(Array<PxVec3>& vertices, Array<uint32_t>& indices, Array<PxVec3>& normals,
+ Array<PxVec2>& texcoords, nvidia::Array<SubMesh>& subMeshes, const apex::RenderMeshAsset& renderMeshAsset, uint32_t partIndex);
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/MeshClipper.cpp b/APEX_1.4/module/destructible/fracture/MeshClipper.cpp
new file mode 100644
index 00000000..b5e42b7a
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/MeshClipper.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "MeshClipper.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/MeshClipper.h b/APEX_1.4/module/destructible/fracture/MeshClipper.h
new file mode 100644
index 00000000..e52d5f3d
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/MeshClipper.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef MESH_CLIPPER_H
+#define MESH_CLIPPER_H
+
+#include <PxVec3.h>
+#include <PsArray.h>
+#include <PxTransform.h>
+#include <PxBounds3.h>
+
+#include "MeshClipperBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class MeshClipper : public base::MeshClipper
+{
+ friend class SimScene;
+protected:
+ MeshClipper(base::SimScene* scene): base::MeshClipper((base::SimScene*)scene) {}
+};
+
+}
+}
+
+#endif
+#endif
diff --git a/APEX_1.4/module/destructible/fracture/PolygonTriangulator.cpp b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.cpp
new file mode 100644
index 00000000..c8012cdd
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "PolygonTriangulator.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/PolygonTriangulator.h b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.h
new file mode 100644
index 00000000..3d142351
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/PolygonTriangulator.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef POLYGON_TRIANGULATOR_H
+#define POLYGON_TRIANGULATOR_H
+
+#include <PxVec3.h>
+#include <PsArray.h>
+
+#include "PolygonTriangulatorBase.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+class PolygonTriangulator : public base::PolygonTriangulator
+{
+ friend class SimScene;
+protected:
+ PolygonTriangulator(base::SimScene* scene): base::PolygonTriangulator((base::SimScene*)scene) {}
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/RTdef.h b/APEX_1.4/module/destructible/fracture/RTdef.h
new file mode 100644
index 00000000..0a8b9561
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/RTdef.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+// This file exists primarily for APEX integration
+
+#ifndef RT_DEF_H
+#define RT_DEF_H
+
+#include "ApexDefs.h"
+#include "ModuleDestructible.h"
+
+#if APEX_RUNTIME_FRACTURE
+#define RT_COMPILE 1
+#else
+#define RT_COMPILE 0
+#endif
+
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Renderable.cpp b/APEX_1.4/module/destructible/fracture/Renderable.cpp
new file mode 100644
index 00000000..5e8ba01b
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Renderable.cpp
@@ -0,0 +1,467 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include "DestructibleActorImpl.h"
+
+#include "Actor.h"
+#include "Compound.h"
+#include "Convex.h"
+
+#include "../fracture/Renderable.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+Renderable::Renderable():
+ mVertexBuffer(NULL),
+ mIndexBuffer(NULL),
+ mBoneBuffer(NULL),
+ mVertexBufferSize(0),
+ mIndexBufferSize(0),
+ mBoneBufferSize(0),
+ mVertexBufferSizeLast(0),
+ mIndexBufferSizeLast(0),
+ mBoneBufferSizeLast(0),
+ mFullBufferDirty(true),
+ valid(false)
+{
+
+}
+
+Renderable::~Renderable()
+{
+ UserRenderResourceManager* rrm = GetInternalApexSDK()->getUserRenderResourceManager();
+ if (mVertexBuffer != NULL )
+ {
+ rrm->releaseVertexBuffer(*mVertexBuffer);
+ }
+ if (mIndexBuffer != NULL )
+ {
+ rrm->releaseIndexBuffer(*mIndexBuffer);
+ }
+ if (mBoneBuffer != NULL)
+ {
+ rrm->releaseBoneBuffer(*mBoneBuffer);
+ }
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ ConvexGroup& g = mConvexGroups[k];
+ for (uint32_t j = 0; j < g.mSubMeshes.size(); j++)
+ {
+ SubMesh& s = g.mSubMeshes[j];
+ if(s.renderResource != NULL)
+ {
+ rrm->releaseResource(*s.renderResource);
+ s.renderResource = NULL;
+ }
+ }
+ }
+}
+
+void Renderable::updateRenderResources(bool rewriteBuffers, void* userRenderData)
+{
+ UserRenderResourceManager* rrm = GetInternalApexSDK()->getUserRenderResourceManager();
+ ResourceProviderIntl* nrp = GetInternalApexSDK()->getInternalResourceProvider();
+
+ PX_ASSERT(rrm != NULL && nrp != NULL);
+ if (rrm == NULL || nrp == NULL || mConvexGroups.empty())
+ {
+ valid = false;
+ return;
+ }
+
+ if (rewriteBuffers)
+ {
+ mFullBufferDirty = true;
+ }
+
+ // Resize buffers if necessary: TODO: intelligently oversize
+ // vertex buffer
+ if (mVertexBufferSize > mVertexBufferSizeLast)
+ {
+ if (mVertexBuffer != NULL )
+ {
+ rrm->releaseVertexBuffer(*mVertexBuffer);
+ }
+ {
+ UserRenderVertexBufferDesc desc;
+ desc.uvOrigin = nvidia::apex::TextureUVOrigin::ORIGIN_BOTTOM_LEFT;
+ desc.hint = RenderBufferHint::DYNAMIC;
+ desc.maxVerts = mVertexBufferSize;
+ desc.buffersRequest[RenderVertexSemantic::POSITION] = RenderDataFormat::FLOAT3;
+ desc.buffersRequest[RenderVertexSemantic::NORMAL] = RenderDataFormat::FLOAT3;
+ desc.buffersRequest[RenderVertexSemantic::TEXCOORD0] = RenderDataFormat::FLOAT2;
+ desc.buffersRequest[RenderVertexSemantic::BONE_INDEX] = RenderDataFormat::USHORT1;
+ mVertexBuffer = rrm->createVertexBuffer(desc);
+ PX_ASSERT(mVertexBuffer);
+ }
+ mFullBufferDirty = true;
+ }
+ // index buffer
+ if (mIndexBufferSize > mIndexBufferSizeLast)
+ {
+ if (mIndexBuffer != NULL )
+ {
+ rrm->releaseIndexBuffer(*mIndexBuffer);
+ }
+ UserRenderIndexBufferDesc desc;
+ desc.hint = RenderBufferHint::DYNAMIC;
+ desc.maxIndices = mIndexBufferSize;
+ desc.format = RenderDataFormat::UINT1;
+ mIndexBuffer = rrm->createIndexBuffer(desc);
+ PX_ASSERT(mIndexBuffer);
+ mFullBufferDirty = true;
+ }
+ // bone buffer
+ if (mBoneBufferSize > mBoneBufferSizeLast)
+ {
+ if (mBoneBuffer != NULL)
+ {
+ rrm->releaseBoneBuffer(*mBoneBuffer);
+ }
+ UserRenderBoneBufferDesc desc;
+ desc.hint = RenderBufferHint::DYNAMIC;
+ desc.maxBones = mBoneBufferSize;
+ desc.buffersRequest[RenderBoneSemantic::POSE] = RenderDataFormat::FLOAT3x4;
+ mBoneBuffer = rrm->createBoneBuffer(desc);
+ PX_ASSERT(mBoneBuffer);
+ mFullBufferDirty = true;
+ }
+ // Fill buffers
+ if (mFullBufferDirty)
+ {
+ uint32_t vertexIdx = 0;
+ uint32_t indexIdx = 0;
+ uint32_t boneIdx = 0;
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ ConvexGroup& g = mConvexGroups[k];
+ for (uint32_t j = 0; j < g.mSubMeshes.size(); j++)
+ {
+ SubMesh& s = g.mSubMeshes[j];
+ if(s.renderResource != NULL)
+ {
+ rrm->releaseResource(*s.renderResource);
+ s.renderResource = NULL;
+ }
+ UserRenderResourceDesc desc;
+ desc.primitives = RenderPrimitiveType::TRIANGLES;
+ // configure vertices
+ desc.vertexBuffers = &mVertexBuffer;
+ desc.numVertexBuffers = 1;
+ desc.numVerts = g.mVertexCache.size();
+ desc.firstVertex = vertexIdx;
+ // configure indices;
+ desc.indexBuffer = mIndexBuffer;
+ desc.firstIndex = indexIdx;
+ desc.numIndices = s.mIndexCache.size();
+ // configure bones;
+ desc.boneBuffer = mBoneBuffer;
+ desc.numBones = g.mBoneCache.size();
+ desc.firstBone = boneIdx;
+ // configure other info
+ desc.material = nrp->getResource(mMaterialInfo[j].mMaterialID);
+ desc.submeshIndex = j;
+ desc.userRenderData = userRenderData;
+ // create
+ s.renderResource = rrm->createResource(desc);
+ PX_ASSERT(s.renderResource);
+ // copy indices into buffer
+ PX_ASSERT(indexIdx+s.mIndexCache.size() <= mIndexBufferSize);
+ mIndexBuffer->writeBuffer(s.mIndexCache.begin(),sizeof(*s.mIndexCache.begin()),indexIdx,s.mIndexCache.size());
+ indexIdx += s.mIndexCache.size();
+ }
+ // copy vertices and bones
+ {
+ RenderVertexBufferData data;
+ data.setSemanticData(RenderVertexSemantic::POSITION, g.mVertexCache.begin(), sizeof(*g.mVertexCache.begin()), RenderDataFormat::FLOAT3);
+ data.setSemanticData(RenderVertexSemantic::NORMAL, g.mNormalCache.begin(), sizeof(*g.mNormalCache.begin()), RenderDataFormat::FLOAT3);
+ data.setSemanticData(RenderVertexSemantic::TEXCOORD0, g.mTexcoordCache.begin(), sizeof(*g.mTexcoordCache.begin()), RenderDataFormat::FLOAT2);
+ data.setSemanticData(RenderVertexSemantic::BONE_INDEX,g.mBoneIndexCache.begin(),sizeof(*g.mBoneIndexCache.begin()),RenderDataFormat::USHORT1);
+ PX_ASSERT(vertexIdx + g.mVertexCache.size() <= mVertexBufferSize);
+ mVertexBuffer->writeBuffer(data,vertexIdx,g.mVertexCache.size());
+ }
+ {
+ RenderBoneBufferData data;
+ data.setSemanticData(RenderBoneSemantic::POSE,g.mBoneCache.begin(),sizeof(*g.mBoneCache.begin()),RenderDataFormat::FLOAT4x4);
+ PX_ASSERT(boneIdx + g.mBoneCache.size() <= mBoneBufferSize);
+ mBoneBuffer->writeBuffer(data,boneIdx,g.mBoneCache.size());
+ }
+ vertexIdx += g.mVertexCache.size();
+ boneIdx += g.mBoneCache.size();
+ }
+ mFullBufferDirty = false;
+ }
+ else // Bones only
+ {
+ uint32_t boneIdx = 0;
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ ConvexGroup& g = mConvexGroups[k];
+ {
+ RenderBoneBufferData data;
+ data.setSemanticData(RenderBoneSemantic::POSE,g.mBoneCache.begin(),sizeof(*g.mBoneCache.begin()),RenderDataFormat::FLOAT4x4);
+ mBoneBuffer->writeBuffer(data,boneIdx,g.mBoneCache.size());
+ }
+ boneIdx += g.mBoneCache.size();
+ }
+ }
+ mVertexBufferSizeLast = mVertexBufferSize;
+ mIndexBufferSizeLast = mIndexBufferSize;
+ mBoneBufferSizeLast = mBoneBufferSize;
+ valid = true;
+}
+
+void Renderable::dispatchRenderResources(UserRenderer& api)
+{
+ if (!valid)
+ {
+ return;
+ }
+ RenderContext ctx;
+ ctx.local2world = PxMat44(PxIdentity);
+ ctx.world2local = PxMat44(PxIdentity);
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ ConvexGroup& g = mConvexGroups[k];
+ for (uint32_t j = 0; j < g.mSubMeshes.size(); j++)
+ {
+ SubMesh& s = g.mSubMeshes[j];
+ if(s.renderResource && !s.mIndexCache.empty())
+ {
+ ctx.renderResource = s.renderResource;
+ api.renderResource(ctx);
+ }
+ }
+ }
+}
+
+// -----------------------Cache Update-----------------------------------
+void Renderable::updateRenderCacheFull(Actor* actor)
+{
+ mVertexBufferSize = 0;
+ mIndexBufferSize = 0;
+ mBoneBufferSize = 0;
+ // Resize SubMeshes if necessary
+ const uint32_t numSubMeshes = actor->mActor->getRenderSubmeshCount();
+ if( numSubMeshes == 0 )
+ {
+ return;
+ }
+ if( numSubMeshes != mMaterialInfo.size() )
+ {
+ mMaterialInfo.resize(numSubMeshes);
+ }
+ // grab material information
+ if (ResourceProviderIntl* nrp = GetInternalApexSDK()->getInternalResourceProvider())
+ {
+ if (UserRenderResourceManager* rrm = GetInternalApexSDK()->getUserRenderResourceManager())
+ {
+ ResID materialNS = GetInternalApexSDK()->getMaterialNameSpace();
+ for(uint32_t i = 0; i < numSubMeshes; i++)
+ {
+ if(mMaterialInfo[i].mMaxBones == 0)
+ {
+ mMaterialInfo[i].mMaterialID = nrp->createResource(materialNS,actor->mActor->getDestructibleAsset()->getRenderMeshAsset()->getMaterialName(i),false);
+ mMaterialInfo[i].mMaxBones = rrm->getMaxBonesForMaterial(nrp->getResource(mMaterialInfo[i].mMaterialID));
+ }
+ }
+ }
+ }
+ // Find bone limit
+ uint32_t maxBones = mMaterialInfo[0].mMaxBones;
+ for (uint32_t i = 1; i < mMaterialInfo.size(); i++)
+ {
+ if (mMaterialInfo[i].mMaxBones < maxBones)
+ {
+ maxBones = mMaterialInfo[i].mMaxBones;
+ }
+ }
+ //maxBones = 1; // TEMPORARY: FIXES TEXTURE MAPPING PROBLEM
+ //maxBones = rand(1,maxBones-1);
+ // Count Convexes
+ uint32_t numConvexes = 0;
+ const Array<base::Compound*>& compounds = actor->getCompounds();
+ for (uint32_t k = 0; k < compounds.size(); k++)
+ {
+ const Array<base::Convex*>& convexes = compounds[k]->getConvexes();
+ numConvexes += convexes.size();
+ }
+ mBoneBufferSize += numConvexes;
+
+ //maxBones is 0 when VTF rendering method is used for destructible(only)
+ if(maxBones == 0)
+ maxBones = mBoneBufferSize;
+
+ // Create more groups if necessary
+ uint32_t numGroups = numConvexes/maxBones + ((numConvexes%maxBones)?1:0);
+ if (numGroups != mConvexGroups.size())
+ {
+ mConvexGroups.resize(numGroups);
+ }
+ // Resize convex caches and subMeshes if necessary
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ ConvexGroup& g = mConvexGroups[k];
+ g.mConvexCache.clear();
+ if( g.mConvexCache.capacity() <= maxBones )
+ {
+ g.mConvexCache.reserve(maxBones);
+ }
+ if( g.mSubMeshes.size() != mMaterialInfo.size())
+ {
+ g.mSubMeshes.resize(mMaterialInfo.size());
+ }
+ }
+ // Populate convex cache
+ {
+ uint32_t idx = 0;
+ const Array<base::Compound*>& compounds = actor->getCompounds();
+ for (uint32_t k = 0; k < compounds.size(); k++)
+ {
+ const Array<base::Convex*>& convexes = compounds[k]->getConvexes();
+ for (uint32_t j = 0; j < convexes.size(); j++)
+ {
+ mConvexGroups[idx/maxBones].mConvexCache.pushBack((Convex*)convexes[j]);
+ idx++;
+ }
+ }
+ }
+ // Fill other caches
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ ConvexGroup& g = mConvexGroups[k];
+ // Calculate number of vertices
+ uint32_t numVertices = 0;
+ for (uint32_t j = 0; j < g.mConvexCache.size(); j++)
+ {
+ numVertices += g.mConvexCache[j]->getVisVertices().size();
+ }
+ mVertexBufferSize += numVertices;
+ // Resize if necessary
+ g.mVertexCache.clear();
+ g.mNormalCache.clear();
+ g.mTexcoordCache.clear();
+ g.mBoneIndexCache.clear();
+ if (numVertices >= g.mVertexCache.capacity())
+ {
+ g.mVertexCache.reserve(numVertices);
+ g.mNormalCache.reserve(numVertices);
+ g.mBoneIndexCache.reserve(numVertices);
+ g.mTexcoordCache.reserve(numVertices);
+ }
+ g.mBoneCache.clear();
+ if (maxBones >= g.mBoneCache.capacity())
+ {
+ g.mBoneCache.reserve(maxBones);
+ }
+ // Calculate index buffer sizes
+ for (uint32_t i = 0; i < g.mSubMeshes.size(); i++)
+ {
+ uint32_t numIndices = 0;
+ for (uint32_t j = 0; j < g.mConvexCache.size(); j++)
+ {
+ numIndices += g.mConvexCache[j]->getVisTriIndices().size();
+ }
+ g.mSubMeshes[i].mIndexCache.clear();
+ if (numIndices >= g.mSubMeshes[i].mIndexCache.capacity())
+ {
+ g.mSubMeshes[i].mIndexCache.reserve(numIndices);
+ }
+ mIndexBufferSize += numIndices;
+ }
+ // Fill for each convex
+ for (uint32_t j = 0; j < g.mConvexCache.size(); j++)
+ {
+ Convex* c = g.mConvexCache[j];
+ uint32_t off = g.mVertexCache.size();
+ // fill vertices
+ const Array<PxVec3>& verts = c->getVisVertices();
+ const Array<PxVec3>& norms = c->getVisNormals();
+ const Array<float>& texcs = c->getVisTexCoords();
+ PX_ASSERT(verts.size() == norms.size() && verts.size() == (texcs.size()/2));
+ for (uint32_t i = 0; i < verts.size(); i++)
+ {
+ g.mVertexCache.pushBack(verts[i]);
+ g.mNormalCache.pushBack(norms[i]);
+ g.mTexcoordCache.pushBack(PxVec2(texcs[2*i],texcs[2*i+1]));
+ g.mBoneIndexCache.pushBack((uint16_t)j);
+ }
+ // fill indicies for each submesh
+ for (uint32_t i = 0; i < g.mSubMeshes.size(); i++)
+ {
+ const Array<int32_t>& indices = c->getVisTriIndices();
+ PX_ASSERT(indices.size()%3 == 0);
+ for (uint32_t a = 0; a < indices.size()/3; a++)
+ {
+ uint32_t subMeshID = 0; // <<<--- TODO: acquire subMeshID for triangle
+ if (subMeshID == i)
+ {
+ g.mSubMeshes[i].mIndexCache.pushBack(indices[3*a+0]+off);
+ g.mSubMeshes[i].mIndexCache.pushBack(indices[3*a+1]+off);
+ g.mSubMeshes[i].mIndexCache.pushBack(indices[3*a+2]+off);
+ }
+ }
+ }
+ g.mBoneCache.pushBack(c->getGlobalPose());
+ }
+ }
+}
+
+void Renderable::updateRenderCache(Actor* actor)
+{
+ if( actor == NULL ) return;
+ actor->mScene->getScene()->lockRead();
+ //actor->mRenderResourcesDirty = true;
+ if( actor->mRenderResourcesDirty)
+ {
+ updateRenderCacheFull(actor);
+ mFullBufferDirty = true;
+ actor->mRenderResourcesDirty = false;
+ }
+ // Fill other caches
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ ConvexGroup& g = mConvexGroups[k];
+ g.mBoneCache.clear();
+ // Fill bones for each convex
+ for (uint32_t j = 0; j < g.mConvexCache.size(); j++)
+ {
+ Convex* c = g.mConvexCache[j];
+ g.mBoneCache.pushBack(c->getGlobalPose());
+ }
+ }
+ actor->mScene->getScene()->unlockRead();
+}
+
+PxBounds3 Renderable::getBounds() const
+{
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ for (uint32_t k = 0; k < mConvexGroups.size(); k++)
+ {
+ const ConvexGroup& g = mConvexGroups[k];
+ for (uint32_t j = 0; j < g.mConvexCache.size(); j++)
+ {
+ const Convex* c = g.mConvexCache[j];
+ bounds.include(c->getBounds());
+ }
+ }
+ return bounds;
+}
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/Renderable.h b/APEX_1.4/module/destructible/fracture/Renderable.h
new file mode 100644
index 00000000..9a2af07c
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/Renderable.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef RT_RENDERABLE_H
+#define RT_RENDERABLE_H
+
+#include "PsArray.h"
+#include "PsUserAllocated.h"
+#include "PxVec2.h"
+
+namespace nvidia
+{
+namespace apex
+{
+ class UserRenderer;
+ class UserRenderVertexBuffer;
+ class UserRenderIndexBuffer;
+ class UserRenderBoneBuffer;
+ class UserRenderResource;
+}
+using namespace shdfnd;
+
+namespace fracture
+{
+
+class Actor;
+class Convex;
+
+class Renderable : public UserAllocated
+{
+public:
+ Renderable();
+ ~Renderable();
+
+ // Called by rendering thread
+ void updateRenderResources(bool rewriteBuffers, void* userRenderData);
+ void dispatchRenderResources(UserRenderer& api);
+
+ // Per tick bone update, unless Actor is dirty
+ void updateRenderCache(Actor* actor);
+
+ // Returns the bounds of all of the convexes
+ PxBounds3 getBounds() const;
+
+private:
+ // Called by actor after a patternFracture (On Game Thread)
+ void updateRenderCacheFull(Actor* actor);
+
+ // To Handle Multiple Materials
+ struct SubMesh
+ {
+ SubMesh(): renderResource(NULL) {}
+
+ Array<uint32_t> mIndexCache;
+ UserRenderResource* renderResource;
+ };
+ // To Handle Bone Limit
+ struct ConvexGroup
+ {
+ Array<SubMesh> mSubMeshes;
+ Array<Convex*> mConvexCache;
+ Array<PxVec3> mVertexCache;
+ Array<PxVec3> mNormalCache;
+ Array<PxVec2> mTexcoordCache;
+ Array<uint16_t> mBoneIndexCache;
+ Array<PxMat44> mBoneCache;
+ };
+ // Shared by SubMeshes
+ struct MaterialInfo
+ {
+ MaterialInfo(): mMaxBones(0), mMaterialID(0) {}
+
+ uint32_t mMaxBones;
+ ResID mMaterialID;
+ };
+ //
+ Array<ConvexGroup> mConvexGroups;
+ Array<MaterialInfo> mMaterialInfo;
+
+ UserRenderVertexBuffer* mVertexBuffer;
+ UserRenderIndexBuffer* mIndexBuffer;
+ UserRenderBoneBuffer* mBoneBuffer;
+ uint32_t mVertexBufferSize;
+ uint32_t mIndexBufferSize;
+ uint32_t mBoneBufferSize;
+ uint32_t mVertexBufferSizeLast;
+ uint32_t mIndexBufferSizeLast;
+ uint32_t mBoneBufferSizeLast;
+ bool mFullBufferDirty;
+ bool valid;
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/SimScene.cpp b/APEX_1.4/module/destructible/fracture/SimScene.cpp
new file mode 100644
index 00000000..9d651093
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/SimScene.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#include <PsUserAllocated.h>
+
+#include "DestructibleActorImpl.h"
+
+#include "Actor.h"
+#include "Compound.h"
+#include "Convex.h"
+#include "CompoundCreator.h"
+#include "Delaunay2d.h"
+#include "Delaunay3d.h"
+#include "PolygonTriangulator.h"
+#include "IslandDetector.h"
+#include "MeshClipper.h"
+#include "FracturePattern.h"
+
+#include "SimScene.h"
+
+namespace nvidia
+{
+namespace fracture
+{
+
+void SimScene::onWake(PxActor** actors, uint32_t count){
+ if(mAppNotify != NULL)
+ mAppNotify->onWake(actors,count);
+
+ for(uint32_t i = 0; i < count; i++)
+ {
+ PxActor* actor = actors[i];
+ if(actor != NULL && actor->is<physx::PxRigidDynamic>())
+ {
+ uint32_t shapeCount = actor->is<physx::PxRigidDynamic>()->getNbShapes();
+ PxShape** shapes = (PxShape**)PX_ALLOC(sizeof(PxShape*)*shapeCount,"onWake Shapes Temp Buffer");
+ actor->is<physx::PxRigidDynamic>()->getShapes(shapes,sizeof(PxShape*)*shapeCount,0);
+ ::nvidia::destructible::DestructibleActorImpl* prevActor = NULL;
+ for(uint32_t j = 0; j < shapeCount; j++)
+ {
+ nvidia::fracture::base::Convex* convex = findConvexForShape(*shapes[j]);
+ if(convex == NULL || convex->getParent() == NULL)
+ continue;
+ nvidia::fracture::Compound* parent = (nvidia::fracture::Compound*)convex->getParent();
+ ::nvidia::destructible::DestructibleActorImpl* curActor = parent->getDestructibleActor();
+ if(convex && convex->getParent() && curActor != prevActor && curActor)
+ {
+ curActor->incrementWakeCount();
+ prevActor = curActor;
+ }
+
+ }
+ PX_FREE(shapes);
+ }
+ }
+}
+
+void SimScene::onSleep(PxActor** actors, uint32_t count){
+ if(mAppNotify != NULL)
+ mAppNotify->onSleep(actors,count);
+
+ for(uint32_t i = 0; i < count; i++)
+ {
+ PxActor* actor = actors[i];
+ if(actor != NULL && actor->is<physx::PxRigidDynamic>())
+ {
+ uint32_t shapeCount = actor->is<physx::PxRigidDynamic>()->getNbShapes();
+ PxShape** shapes = (PxShape**)PX_ALLOC(sizeof(PxShape*)*shapeCount,"onSleep Shapes Temp Buffer");
+ actor->is<physx::PxRigidDynamic>()->getShapes(shapes,sizeof(PxShape*)*shapeCount,0);
+ ::nvidia::destructible::DestructibleActorImpl* prevActor = NULL;
+ for(uint32_t j = 0; j < shapeCount; j++)
+ {
+ nvidia::fracture::base::Convex* convex = findConvexForShape(*shapes[j]);
+ if(convex == NULL || convex->getParent() == NULL)
+ continue;
+ nvidia::fracture::Compound* parent = (nvidia::fracture::Compound*)convex->getParent();
+ ::nvidia::destructible::DestructibleActorImpl* curActor = parent->getDestructibleActor();
+ if(convex && convex->getParent() && curActor != prevActor && curActor)
+ {
+ curActor->decrementWakeCount();;
+ prevActor = curActor;
+ }
+
+ }
+ PX_FREE(shapes);
+ }
+ }
+}
+SimScene* SimScene::createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath)
+{
+ SimScene* s = PX_NEW(SimScene)(pxPhysics,pxCooking,scene,minConvexSize,defaultMat,resourcePath);
+ s->createSingletons();
+ return s;
+}
+
+void SimScene::createSingletons()
+{
+ mCompoundCreator = PX_NEW(CompoundCreator)(this);
+ mDelaunay2d = PX_NEW(Delaunay2d)(this);
+ mDelaunay3d = PX_NEW(Delaunay3d)(this);
+ mPolygonTriangulator = PX_NEW(PolygonTriangulator)(this);
+ mIslandDetector = PX_NEW(IslandDetector)(this);
+ mMeshClipper = PX_NEW(MeshClipper)(this);
+ mDefaultGlass = PX_NEW(FracturePattern)(this);
+ mDefaultGlass->createGlass(10.0f,0.25f,30,0.3f,0.03f,1.4f,0.3f);
+ //mDefaultGlass->create3dVoronoi(PxVec3(10.0f, 10.0f, 10.0f), 50, 10.0f);
+ addActor(createActor(NULL));
+}
+
+base::Actor* SimScene::createActor(::nvidia::destructible::DestructibleActorImpl* actor)
+{
+ return (base::Actor*)PX_NEW(Actor)(this,actor);
+}
+
+base::Convex* SimScene::createConvex()
+{
+ return (base::Convex*)PX_NEW(Convex)(this);
+}
+
+base::Compound* SimScene::createCompound(const base::FracturePattern *pattern, const base::FracturePattern *secondaryPattern, float contactOffset, float restOffset)
+{
+ return (base::Compound*)PX_NEW(Compound)(this,pattern,secondaryPattern,contactOffset,restOffset);
+}
+
+base::FracturePattern* SimScene::createFracturePattern()
+{
+ return (base::FracturePattern*)PX_NEW(FracturePattern)(this);
+}
+
+SimScene::SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath):
+ base::SimScene(pxPhysics,pxCooking,scene,minConvexSize,defaultMat,resourcePath)
+{
+}
+
+// --------------------------------------------------------------------------------------------
+SimScene::~SimScene()
+{
+ PX_DELETE(mDefaultGlass);
+
+ mDefaultGlass = NULL;
+}
+
+}
+}
+#endif \ No newline at end of file
diff --git a/APEX_1.4/module/destructible/fracture/SimScene.h b/APEX_1.4/module/destructible/fracture/SimScene.h
new file mode 100644
index 00000000..fd0e82e6
--- /dev/null
+++ b/APEX_1.4/module/destructible/fracture/SimScene.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef SIM_SCENE
+#define SIM_SCENE
+
+#include "SimSceneBase.h"
+
+namespace nvidia
+{
+namespace destructible
+{
+ class DestructibleActorImpl;
+}
+
+namespace fracture
+{
+
+class FracturePattern;
+class Actor;
+
+class SimScene : public base::SimScene
+{
+public:
+ static SimScene* createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath);
+protected:
+ SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, PxScene *scene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath);
+public:
+ virtual ~SimScene();
+
+ virtual void createSingletons();
+
+ virtual base::Actor* createActor(nvidia::destructible::DestructibleActorImpl* actor);
+ virtual base::Convex* createConvex();
+ virtual base::Compound* createCompound(const base::FracturePattern *pattern, const base::FracturePattern *secondaryPattern = NULL, float contactOffset = 0.005f, float restOffset = -0.001f);
+ virtual base::FracturePattern* createFracturePattern();
+ virtual void onWake(PxActor** actors, uint32_t count);
+ virtual void onSleep(PxActor** actors, uint32_t count);
+
+ FracturePattern* getDefaultGlass() {return mDefaultGlass;}
+
+protected:
+ FracturePattern* mDefaultGlass;
+};
+
+}
+}
+
+#endif
+#endif \ No newline at end of file