aboutsummaryrefslogtreecommitdiff
path: root/KaplaDemo/samples/sampleViewer3/Fracture/Core
diff options
context:
space:
mode:
Diffstat (limited to 'KaplaDemo/samples/sampleViewer3/Fracture/Core')
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.cpp139
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.h54
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.cpp536
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.h136
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.cpp844
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.h103
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.cpp86
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.h68
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.cpp1316
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.h213
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.cpp212
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.h67
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.cpp272
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.h59
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.cpp337
-rw-r--r--KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.h248
16 files changed, 4690 insertions, 0 deletions
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.cpp
new file mode 100644
index 00000000..4504add8
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.cpp
@@ -0,0 +1,139 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include "ActorBase.h"
+
+#include <foundation/PxMat44.h>
+#include "PxRigidBodyExt.h"
+
+#include "PxScene.h"
+#include "SimSceneBase.h"
+#include "CompoundBase.h"
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+Actor::Actor(SimScene* scene):
+ mScene(scene),
+ mMinConvexSize(scene->mMinConvexSize),
+ mDepthLimit(100),
+ mDestroyIfAtDepthLimit(false)
+{
+
+}
+
+Actor::~Actor()
+{
+ mScene->getScene()->lockWrite();
+ clear();
+ mScene->getScene()->unlockWrite();
+ mScene->removeActor(this);
+}
+
+void Actor::clear()
+{
+ for (int i = 0; i < (int)mCompounds.size(); i++) {
+ PX_DELETE(mCompounds[i]);
+ }
+ mCompounds.clear();
+}
+
+void Actor::addCompound(Compound *c)
+{
+ mCompounds.pushBack(c);
+ PxRigidDynamic *a = c->getPxActor();
+#if 1
+ if (a) {
+// a->setContactReportFlags(Px_NOTIFY_ON_TOUCH_FORCE_THRESHOLD | Px_NOTIFY_ON_START_TOUCH_FORCE_THRESHOLD);
+ a->setContactReportThreshold(mScene->mFractureForceThreshold);
+ }
+#endif
+ c->mActor = this;
+ ++(mScene->mSceneVersion);
+}
+
+void Actor::removeCompound(Compound *c)
+{
+ int num = 0;
+ for (int i = 0; i < (int)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)
+{
+ int num = 0;
+ for (int i = 0; i < (int)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 (int i = 0; i < (int)mCompounds.size(); i++) {
+ float d;
+ int cNr;
+ PxVec3 n;
+ if (mCompounds[i]->rayCast(orig, dir, d, cNr, n)) {
+ if (d < dist) {
+ dist = d;
+ compoundNr = i;
+ convexNr = cNr;
+ normal = n;
+ }
+ }
+ }
+ return compoundNr >= 0;
+}
+
+bool Actor::findCompound(const Compound* c, int& compoundNr)
+{
+ for(int i = 0; i < (int)mCompounds.size(); i++)
+ {
+ if(mCompounds[i] == c)
+ {
+ compoundNr = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.h
new file mode 100644
index 00000000..b268b5f9
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ActorBase.h
@@ -0,0 +1,54 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef ACTOR_BASE_H
+#define ACTOR_BASE_H
+
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+class Compound;
+
+class Actor : public ::physx::shdfnd::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;
+
+ shdfnd::Array<Compound*> getCompounds() { return mCompounds; }
+
+protected:
+ SimScene* mScene;
+ shdfnd::Array<Compound*> mCompounds;
+
+ PxF32 mMinConvexSize;
+ PxU32 mDepthLimit;
+ bool mDestroyIfAtDepthLimit;
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.cpp
new file mode 100644
index 00000000..ac2c4f15
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.cpp
@@ -0,0 +1,536 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include "MeshBase.h"
+#include "CompoundGeometryBase.h"
+#include "CompoundCreatorBase.h"
+#include "PxConvexMeshGeometry.h"
+#include "PxRigidBodyExt.h"
+#include "foundation/PxMat44.h"
+#include "PxScene.h"
+#include "PxShape.h"
+
+#include "SimSceneBase.h"
+#include "CompoundBase.h"
+#include "ActorBase.h"
+#include "ConvexBase.h"
+#include "foundation/PxMathUtils.h"
+
+#include <stdio.h>
+
+#include "MathUtils.h"
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+//vector<PxVec3> tmpPoints;
+void Compound::appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, shdfnd::Array<PxVec3>& samples, shdfnd::Array<PxVec3>* normals) {
+ 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)floor(aa);
+
+ if (randRange(0.0f,1.0f) <= aa-np) np++;
+
+ for (int j = 0; j < np; j++) {
+ float r1 = randRange(0.0f,1.0f);
+ float sr1 = physx::PxSqrt(r1);
+ float r2 = randRange(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, PxReal contactOffset, PxReal restOffset)
+{
+ mScene = scene;
+ mActor = NULL;
+ mPxActor = NULL;
+ 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 physx::PxU32 shapeCount = mPxActor->getNbShapes();
+ physx::PxShape* shapeBuffer[SHAPE_BUFFER_SIZE];
+ for (physx::PxU32 shapeStartIndex = 0; shapeStartIndex < shapeCount; shapeStartIndex += SHAPE_BUFFER_SIZE)
+ {
+ physx::PxU32 shapesRead = mPxActor->getShapes(shapeBuffer, SHAPE_BUFFER_SIZE, shapeStartIndex);
+ for (physx::PxU32 shapeBufferIndex = 0; shapeBufferIndex < shapesRead; ++shapeBufferIndex)
+ {
+ mScene->unmapShape(*shapeBuffer[shapeBufferIndex]);
+ }
+ }
+ // release the actor
+ mPxActor->release();
+ mPxActor = NULL;
+ }
+ for (int i = 0; i < (int)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, int matID, int surfMatID)
+{
+ return createFromConvexes(&convex, 1, pose, vel, omega, copyConvexes, matID, surfMatID);
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::createFromConvexes(Convex** convexes, int numConvexes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes, int matID, int surfMatID)
+{
+ 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;
+
+ shdfnd::Array<PxShape*> shapes;
+
+ for (int i = 0; i < numConvexes; i++) {
+ Convex *c;
+ if (copyConvexes) {
+ c = mScene->createConvex();
+ c->createFromConvex(convexes[i], 0, matID, surfMatID);
+ }
+ 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);
+
+ PxShape *shape = mScene->getPxPhysics()->createShape(
+ PxConvexMeshGeometry(mesh),
+ *mScene->getPxDefaultMaterial(),
+ true
+ );
+ shape->setLocalPose(c->getLocalPose());
+
+ //shape->setContactOffset(mContactOffset);
+ //shape->setRestOffset(mRestOffset);
+
+ if (mContactOffset < mRestOffset || mContactOffset < 0.0f)
+ {
+ printf("WRONG\n");
+ }
+
+ mScene->mapShapeToConvex(*shape, *c);
+
+ shapes.pushBack(shape);
+ }
+
+ if (shapes.empty())
+ {
+ return false;
+ }
+
+ createPxActor(shapes, pose, vel, omega);
+
+
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+
+bool Compound::createFromGeometry(const CompoundGeometry &geom, PxRigidDynamic* body, Shader* myShader, int matID, int surfMatID)
+{
+ clear();
+
+ shdfnd::Array<PxShape*> shapes(body->getNbShapes());
+
+ body->getShapes(shapes.begin(), body->getNbShapes());
+
+ PX_ASSERT(geom.convexes.size() == body->getNbShapes());
+
+ for (int i = 0; i < (int)geom.convexes.size(); i++) {
+ Convex *c = mScene->createConvex();
+ c->createFromGeometry(geom, i, 0, matID, surfMatID);
+ 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;
+
+ if (!reused)
+ convexAdded(c, myShader); //mScene->getConvexRenderer().add(c);
+
+ mScene->mapShapeToConvex(*shapes[i], *c);
+
+ }
+
+ if (shapes.empty())
+ return false;
+
+ mPxActor = body;
+ for (int i = 0; i < (int)mConvexes.size(); i++)
+ mConvexes[i]->setPxActor(mPxActor);
+
+ //createPxActor(shapes, pose, vel, omega);
+ return true;
+
+}
+bool Compound::createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, Shader* myShader, int matID, int surfMatID)
+{
+ clear();
+
+ shdfnd::Array<PxShape*> shapes;
+
+ for (int i = 0; i < (int)geom.convexes.size(); i++) {
+ Convex *c = mScene->createConvex();
+ c->createFromGeometry(geom, i, 0, matID, surfMatID);
+ 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, myShader); //mScene->getConvexRenderer().add(c);
+
+ PxShape *shape;
+ if (geom.convexes[i].isSphere)
+ {
+ shape = mScene->getPxPhysics()->createShape(
+ PxSphereGeometry(geom.convexes[i].radius),
+ *mScene->getPxDefaultMaterial(),
+ true
+ );
+ }
+ else
+ {
+ shape = mScene->getPxPhysics()->createShape(
+ PxConvexMeshGeometry(mesh),
+ *mScene->getPxDefaultMaterial(),
+ true
+ );
+ }
+ shape->setLocalPose(c->getLocalPose());
+
+ //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, int matID, int surfMatID)
+{
+ const shdfnd::Array<PxVec3> &verts = mesh->getVertices();
+ const shdfnd::Array<PxVec3> &normals = mesh->getNormals();
+ const shdfnd::Array<PxVec2> &texcoords = mesh->getTexCoords();
+ const shdfnd::Array<PxU32> &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, NULL, matID, surfMatID);
+ PxTransform trans(-center);
+
+ if (submeshNr < 0)
+ mConvexes[0]->setExplicitVisMeshFromTriangles(verts.size(), &verts[0], &normals[0], &texcoords[0], indices.size(), &indices[0], &trans, &scale);
+ else {
+ const Mesh::SubMesh &sm = mesh->getSubMeshes()[submeshNr];
+ mConvexes[0]->setExplicitVisMeshFromTriangles(verts.size(), &verts[0], &normals[0], &texcoords[0], sm.numIndices, &indices[sm.firstIndex], &trans, &scale);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::createPxActor(shdfnd::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega)
+{
+ if (shapes.empty())
+ return false;
+
+ for(int i = 0; i < (int)shapes.size(); i++)
+ {
+ applyShapeTemplate(shapes[i]);
+ }
+
+ PxRigidDynamic* body = mScene->getPxPhysics()->createRigidDynamic(pose);
+ if (body == NULL)
+ return false;
+
+ //body->setSleepThreshold(getSleepingThresholdRB());
+#if 0
+ body->setWakeCounter(100000000000.f);
+#endif
+
+ mScene->getScene()->addActor(*body);
+
+ for (int i = 0; i < (int)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, 1.0f);
+
+ /*const PxReal maxMass = 50.f;
+ const PxReal minMass = 1.f;
+
+ PxReal mass = PxMax(PxMin(maxMass, body->getMass()), minMass);
+ PxRigidBodyExt::setMassAndUpdateInertia(*body, mass);*/
+
+
+
+ body->setLinearVelocity(vel);
+ body->setAngularVelocity(omega);
+
+ /*if (vel.isZero() && omega.isZero())
+ {
+ body->putToSleep();
+ }*/
+
+ mPxActor = body;
+ for (int i = 0; i < (int)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 (int i = 0; i < (int)mConvexes.size(); i++) {
+ float d;
+ PxVec3 n;
+ if (mConvexes[i]->rayCast(orig, dir, d, n)) {
+ if (d < dist) {
+ dist = d;
+ convexNr = i;
+ normal = n;
+ }
+ }
+ }
+ return convexNr >= 0;
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::getRestBounds(PxBounds3 &bounds) const
+{
+ bounds.setEmpty();
+ PxBounds3 bi;
+ for (int i = 0; i < (int)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 (int i = 0; i < (int)mConvexes.size(); i++) {
+ mConvexes[i]->getWorldBounds(bi);
+ bounds.include(bi);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::getLocalBounds(PxBounds3 &bounds) const
+{
+ bounds.setEmpty();
+ PxBounds3 bi;
+ for (int i = 0; i < (int)mConvexes.size(); i++) {
+ mConvexes[i]->getLocalBounds(bi);
+ bounds.include(bi);
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+bool Compound::isAttached()
+{
+ if (mAttachmentBounds.empty())
+ return false;
+
+ PxBounds3 b;
+ for (int i = 0; i < (int)mConvexes.size(); i++) {
+ Convex *c = mConvexes[i];
+ b = c->getBounds();
+ b.minimum += c->getMaterialOffset();
+ b.maximum += c->getMaterialOffset();
+ for (int j = 0; j < (int)mAttachmentBounds.size(); j++) {
+ if (b.intersects(mAttachmentBounds[j]))
+ return true;
+ }
+ }
+ return false;
+}
+
+// --------------------------------------------------------------------------------------------
+void Compound::attach(const shdfnd::Array<PxBounds3> &bounds)
+{
+ mAttachmentBounds.resize(bounds.size());
+
+ PxTransform t = getPxActor()->getGlobalPose().getInverse();
+ for (int i = 0; i < (int)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 shdfnd::Array<PxBounds3> &bounds)
+{
+ mAttachmentBounds.resize(bounds.size());
+
+ for (int i = 0; i < (int)bounds.size(); i++) {
+ mAttachmentBounds[i] = bounds[i];
+ }
+
+ if (isAttached())
+ mPxActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+}
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.h
new file mode 100644
index 00000000..3ab093a5
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundBase.h
@@ -0,0 +1,136 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUNDBASE
+#define COMPOUNDBASE
+
+#define TECHNICAL_MODE 1
+
+#include <foundation/PxVec3.h>
+#include <foundation/PxPlane.h>
+#include <foundation/PxBounds3.h>
+#include <foundation/PxTransform.h>
+#include <PsArray.h>
+#include <PxRigidDynamic.h>
+#include <PsUserAllocated.h>
+
+
+class Shader;
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+class Convex;
+class Mesh;
+class SimScene;
+class CompoundGeometry;
+
+// -----------------------------------------------------------------------------------
+class Compound : public ::physx::shdfnd::UserAllocated
+{
+ friend class SimScene;
+ friend class Actor;
+protected:
+ Compound(SimScene* scene, PxReal contactOffset = 0.005f, PxReal 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, int matID = 0, int surfMatID = 0);
+ bool createFromConvex(Convex* convex, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, bool copyConvexes = true, int matID = 0, int surfMatID = 0);
+ bool createFromGeometry(const CompoundGeometry &geom, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, Shader* myShader, int matID = 0, int surfMatID = 0);
+ bool createFromGeometry(const CompoundGeometry &geom, PxRigidDynamic* body, Shader* myShader, int matID = 0, int surfMatID = 0);
+ void createFromMesh(const Mesh *mesh, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega, int submeshNr = -1, const PxVec3& scale = PxVec3(1.f), int matID = 0, int surfMatID = 0);
+ //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; }
+
+
+ virtual void convexAdded(Convex* /*c*/, Shader* shader = NULL) {}
+ virtual void convexRemoved(Convex* /*c*/) {}
+
+ void attach(const shdfnd::Array<PxBounds3> &bounds);
+ void attachLocal(const shdfnd::Array<PxBounds3> &bounds);
+
+ const shdfnd::Array<Convex*>& getConvexes() const { return mConvexes; }
+ const shdfnd::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:
+
+ bool isAttached();
+
+ bool createPxActor(shdfnd::Array<PxShape*> &shapes, const PxTransform &pose, const PxVec3 &vel, const PxVec3 &omega);
+
+ static void appendUniformSamplesOfConvexPolygon(PxVec3* vertices, int numV, float area, shdfnd::Array<PxVec3>& samples, shdfnd::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;
+ };
+
+ shdfnd::Array<Convex*> mConvexes;
+ shdfnd::Array<Edge> mEdges;
+
+ SimScene *mScene;
+ Actor *mActor;
+ PxRigidDynamic *mPxActor;
+ PxVec3 mKinematicVel;
+ shdfnd::Array<PxBounds3> mAttachmentBounds;
+
+ //Shader *mShader;
+ //ShaderMaterial mShaderMat;
+
+ PxReal mContactOffset;
+ PxReal mRestOffset;
+
+ int mLifeFrames;
+
+ float mAdditionalImpactNormalImpulse;
+ float mAdditionalImpactRadialImpulse;
+
+ PxU32 mDepth; // fracture depth
+ PxVec3 mNormal; // normal use with mSheetFracture
+};
+
+}}}
+
+#endif
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.cpp
new file mode 100644
index 00000000..f01d0701
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.cpp
@@ -0,0 +1,844 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include "CompoundCreatorBase.h"
+#include <algorithm>
+#include <foundation/PxAssert.h>
+
+#include "PhysXMacros.h"
+#include "PxConvexMeshGeometry.h"
+#include "PxConvexMesh.h"
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+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 = PX_TRANSFORM_ID;
+ if (trans)
+ t = *trans;
+
+ shdfnd::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[i0]);
+ mGeom.normals.pushBack(normals[i1]);
+ mGeom.normals.pushBack(normals[i2]);
+ mGeom.normals.pushBack(normals[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 = PX_TRANSFORM_ID;
+ if (trans)
+ t = *trans;
+
+ mGeom.clear();
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+
+ float dphi = PxTwoPi / (float)numSegs;
+ c.numVerts = 2*numSegs;
+ mGeom.vertices.resize(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*i] = t.transform(p0);
+ mGeom.vertices[2*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, bool clear)
+{
+ PxTransform t = PX_TRANSFORM_ID;
+ if (trans)
+ t = *trans;
+
+ if (clear)
+ mGeom.clear();
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+
+ c.numVerts = 8;
+ 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::createFromConvexMesh(const PxConvexMeshGeometry& convexGeom, PxTransform offset, bool clear)
+{
+
+ if (clear)
+ {
+ mGeom.clear();
+ }
+ CompoundGeometry::Convex c;
+ mGeom.initConvex(c);
+
+ PxConvexMesh* convexMesh = convexGeom.convexMesh;
+ c.numVerts = convexMesh->getNbVertices();
+ c.numFaces = convexMesh->getNbPolygons();
+
+ const PxVec3* verts = convexMesh->getVertices();
+ const PxU8* indexBuff = convexMesh->getIndexBuffer();
+
+
+ for (PxU32 a = 0; a < c.numVerts; ++a)
+ {
+ mGeom.vertices.pushBack(offset.transform(verts[a]));
+ }
+
+
+ for (PxU32 a = 0; a < c.numFaces; ++a)
+ {
+ PxHullPolygon data;
+ convexMesh->getPolygonData(a, data);
+
+ mGeom.indices.pushBack(data.mNbVerts);
+ mGeom.indices.pushBack(CompoundGeometry::FF_OBJECT_SURFACE);
+ const PxU32 indexBase = data.mIndexBase;
+ for (PxU32 b = 0; b < data.mNbVerts; ++b)
+ {
+ PxU32 ind = indexBuff[indexBase + b];
+ mGeom.indices.pushBack(ind);
+ }
+ }
+
+ mGeom.convexes.pushBack(c);
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::createSphere(const PxVec3 &dims, int resolution, const PxTransform *trans)
+{
+ PxTransform t = PX_TRANSFORM_ID;
+ 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);
+
+ if (rx == ry && rx == rz)
+ {
+ c.isSphere = true;
+ c.radius = rx;
+ }
+
+ 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 = mGeom.vertices.size();
+ mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, -rz));
+ int topNr = mGeom.vertices.size();
+ mGeom.vertices.pushBack(PxVec3(0.0f, 0.0f, +rz));
+
+ c.numVerts = 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[i0]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[i1]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[i2]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[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[i0]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[i1]; n.normalize(); mGeom.normals.pushBack(n);
+ n = mGeom.vertices[i2]; n.normalize(); mGeom.normals.pushBack(n);
+ c.numFaces++;
+ }
+ }
+ mGeom.convexes.pushBack(c);
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::fromTetraMesh(const shdfnd::Array<PxVec3> &tetVerts, const shdfnd::Array<int> &tetIndices)
+{
+ mTetVertices = tetVerts;
+ mTetIndices = tetIndices;
+ deleteColors();
+
+ computeTetNeighbors();
+ computeTetEdges();
+ colorTets();
+ colorsToConvexes();
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::computeTetNeighbors()
+{
+ int 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;
+ };
+ shdfnd::Array<TetFace> faces(numTets * 4);
+
+ for (int 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 (int j = 0; j < 4; j++) {
+ int i0 = ids[tetFaceIds[j][0]];
+ int i1 = ids[tetFaceIds[j][1]];
+ int i2 = ids[tetFaceIds[j][2]];
+ faces[4*i+j].init(i0,i1,i2, j, i);
+ }
+ }
+ std::sort(faces.begin(), faces.end());
+
+ mTetNeighbors.clear();
+ mTetNeighbors.resize(numTets * 4, -1);
+ int i = 0;
+ while (i < (int)faces.size()) {
+ TetFace &f0 = faces[i];
+ i++;
+ if (i < (int)faces.size() && faces[i] == f0) {
+ TetFace &f1 = faces[i];
+ mTetNeighbors[4*f0.tetNr + f0.faceNr] = f1.tetNr;
+ mTetNeighbors[4*f1.tetNr + f1.faceNr] = f0.tetNr;
+ while (i < (int)faces.size() && faces[i] == f0)
+ i++;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::computeTetEdges()
+{
+ int 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;
+ };
+ shdfnd::Array<SortEdge> edges(numTets * 6);
+
+ for (int 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 (int j = 0; j < 6; j++) {
+ int i0 = ids[tetEdgeVerts[j][0]];
+ int i1 = ids[tetEdgeVerts[j][1]];
+ edges[6*i + j].init(i0,i1, j, 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;
+ shdfnd::Array<ChainVert> chainVerts(mTetVertices.size(), cv);
+ shdfnd::Array<int> chainVertNrs;
+
+ int mark = 1;
+
+ int i = 0;
+ while (i < (int)edges.size()) {
+ SortEdge &e0 = edges[i];
+ int edgeNr = mTetEdges.size();
+ te.init(e0.i0, e0.i1);
+ te.firstTet = mEdgeTetNrs.size();
+ te.numTets = 0;
+ mark++;
+ chainVertNrs.clear();
+ do {
+ SortEdge &e = edges[i];
+ mTetEdgeNrs[6 * e.tetNr + e.edgeNr] = edgeNr;
+ int i2 = -1;
+ int i3 = -1;
+ for (int j = 0; j < 4; j++) {
+ int id = mTetIndices[4 * 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[e0.i0];
+ PxVec3 &p1 = mTetVertices[e0.i1];
+ PxVec3 &p2 = mTetVertices[i2];
+ PxVec3 &p3 = mTetVertices[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[i2];
+ ChainVert &cv3 = chainVerts[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 < (int)edges.size() && edges[i] == e0);
+
+ te.numTets = chainVertNrs.size() / 2;
+ // find chain start;
+ int startVertNr = -1;
+ for (int j = 0; j < (int)chainVertNrs.size(); j++) {
+ ChainVert &cv = chainVerts[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[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[tetNr];
+ while (nr >= 0) {
+ if (mTetColors[nr].color == color)
+ return true;
+ nr = mTetColors[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[tetNr];
+
+ if (mTetColorsFirstEmpty <= 0) { // new entry
+ mTetFirstColor[tetNr] = mTetColors.size();
+ mTetColors.pushBack(c);
+ }
+ else { // take from empty list
+ int newNr = mTetColorsFirstEmpty;
+ mTetFirstColor[tetNr] = newNr;
+ mTetColorsFirstEmpty = mTetColors[newNr].next;
+ mTetColors[newNr] = c;
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+bool CompoundCreator::tetRemoveColor(int tetNr, int color)
+{
+ int nr = mTetFirstColor[tetNr];
+ int prev = -1;
+ while (nr >= 0) {
+ if (mTetColors[nr].color == color) {
+ if (prev < 0)
+ mTetFirstColor[tetNr] = mTetColors[nr].next;
+ else
+ mTetColors[prev].next = mTetColors[nr].next;
+
+ // add to empty list
+ mTetColors[nr].next = mTetColorsFirstEmpty;
+ mTetColorsFirstEmpty = nr;
+ return true;
+ }
+ prev = nr;
+ nr = mTetColors[nr].next;
+ }
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+int CompoundCreator::tetNumColors(int tetNr)
+{
+ int num = 0;
+ int nr = mTetFirstColor[tetNr];
+ while (nr >= 0) {
+ num++;
+ nr = mTetColors[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[6*tetNr+i]);
+
+ bool failed = false;
+
+ while (mTestEdges.size() > 0) {
+ int edgeNr = mTestEdges[mTestEdges.size()-1];
+ mTestEdges.popBack();
+
+ TetEdge &e = mTetEdges[edgeNr];
+ bool anyOtherCol = false;
+ float sumAng = 0.0f;
+ for (int i = 0; i < e.numTets; i++) {
+ int edgeTetNr = mEdgeTetNrs[e.firstTet + i];
+ if (tetHasColor(edgeTetNr, color))
+ sumAng += mEdgeTetAngles[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[e.firstTet + i];
+ if (!tetHasColor(edgeTetNr, color)) {
+ tetAddColor(edgeTetNr, color);
+ mAddedTets.pushBack(edgeTetNr);
+ for (int j = 0; j < 6; j++)
+ mTestEdges.pushBack(mTetEdgeNrs[6*edgeTetNr+j]);
+ }
+ }
+ }
+ if (failed) {
+ for (int i = 0; i < (int)mAddedTets.size(); i++)
+ tetRemoveColor(mAddedTets[i], color);
+ mAddedTets.clear();
+ return false;
+ }
+
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::colorTets()
+{
+ int numTets = mTetIndices.size() / 4;
+ deleteColors();
+
+ int color = 0;
+ shdfnd::Array<int> edges;
+ shdfnd::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[faceNr];
+
+ if (adjTetNr < 0)
+ continue;
+
+ //if (tetNumColors(adjTetNr) > 0)
+ // continue;
+
+ if (!tryTet(adjTetNr, color))
+ continue;
+
+ for (int j = 0; j < (int)mAddedTets.size(); j++) {
+ int addedTet = mAddedTets[j];
+ for (int k = 0; k < 4; k++) {
+ int adj = mTetNeighbors[4*addedTet+k];
+ if (adj >= 0 && !tetHasColor(adj, color))
+ faces.pushBack(4*addedTet+k);
+ }
+ }
+ }
+ color++;
+ }
+}
+
+// -----------------------------------------------------------------------------
+void CompoundCreator::colorsToConvexes()
+{
+ mGeom.clear();
+
+ int numTets = mTetIndices.size() / 4;
+ int numColors = 0;
+ for (int i = 0; i < (int)mTetColors.size(); i++) {
+ int color = mTetColors[i].color;
+ if (color >= numColors)
+ numColors = color+1;
+ }
+
+ shdfnd::Array<bool> colorVisited(numColors, false);
+ shdfnd::Array<int> queue;
+ shdfnd::Array<int> globalToLocal(mTetVertices.size(), -1);
+
+ shdfnd::Array<int> tetMarks(numTets, 0);
+ shdfnd::Array<int> vertMarks(mTetVertices.size(), 0);
+ int mark = 1;
+
+ shdfnd::Array<int> colorToConvexNr;
+
+ CompoundGeometry::Convex c;
+
+ for (int i = 0; i < numTets; i++) {
+ int nr = mTetFirstColor[i];
+ while (nr >= 0) {
+ int color = mTetColors[nr].color;
+ nr = mTetColors[nr].next;
+
+ if (colorVisited[color])
+ continue;
+ colorVisited[color] = true;
+
+ if ((int)colorToConvexNr.size() <= color)
+ colorToConvexNr.resize(color+1, -1);
+ colorToConvexNr[color] = mGeom.convexes.size();
+
+ queue.clear();
+ queue.pushBack(i);
+
+ mGeom.initConvex(c);
+ mark++;
+ c.numVerts = 0;
+
+ // flood fill
+ while (!queue.empty()) {
+ int tetNr = queue[queue.size()-1];
+ queue.popBack();
+ if (tetMarks[tetNr] == mark)
+ continue;
+ tetMarks[tetNr] = mark;
+
+ for (int j = 0; j < 4; j++) {
+ int adjNr = mTetNeighbors[4*tetNr + j];
+ if (adjNr < 0 || !tetHasColor(adjNr, 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 (int k = 0; k < 3; k++) {
+ int id = 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[adjNr];
+ while (colNr >= 0) {
+ int adjColor = mTetColors[colNr].color;
+ colNr = mTetColors[colNr].next;
+ if (adjColor != color) {
+ bool isNew = true;
+ for (int k = 0; k < c.numNeighbors; k++) {
+ if (mGeom.neighbors[c.firstNeighbor+k] == adjColor) {
+ isNew = false;
+ break;
+ }
+ }
+ if (isNew) {
+ mGeom.neighbors.pushBack(adjColor);
+ c.numNeighbors++;
+ }
+ }
+ }
+ }
+ if (adjNr < 0 || !tetHasColor(adjNr, color) || tetMarks[adjNr] == mark)
+ continue;
+ queue.pushBack(adjNr);
+ }
+ }
+ mGeom.convexes.pushBack(c);
+ }
+ }
+
+ for (int i = 0; i < (int)mGeom.neighbors.size(); i++) {
+ if (mGeom.neighbors[i] >= 0)
+ mGeom.neighbors[i] = colorToConvexNr[mGeom.neighbors[i]];
+ }
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.h
new file mode 100644
index 00000000..cc614672
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundCreatorBase.h
@@ -0,0 +1,103 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUND_CREATOR_BASE_H
+#define COMPOUND_CREATOR_BASE_H
+
+// Matthias M�ller-Fischer
+
+#include <foundation/PxVec3.h>
+#include <foundation/PxTransform.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+#include "CompoundGeometryBase.h"
+
+namespace physx
+{
+ class PxConvexMeshGeometry;
+namespace fracture
+{
+namespace base
+{
+
+ class SimScene;
+// ---------------------------------------------------------------------------------------
+class CompoundCreator : public ::physx::shdfnd::UserAllocated {
+ friend class 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, bool clearShape = true);
+ void createSphere(const PxVec3 &dims, int resolution = 5, const PxTransform *trans = NULL);
+ void fromTetraMesh(const shdfnd::Array<PxVec3> &tetVerts, const shdfnd::Array<int> &tetIndices);
+
+ void createFromConvexMesh(const PxConvexMeshGeometry& convexGeom, PxTransform offset = PxTransform(PxIdentity), bool clear = true);
+
+
+ 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
+ shdfnd::Array<PxVec3> mTetVertices;
+ shdfnd::Array<int> mTetIndices;
+ shdfnd::Array<int> mTetNeighbors;
+
+ shdfnd::Array<int> mTetFirstColor;
+ struct Color {
+ int color;
+ int next;
+ };
+ int mTetColorsFirstEmpty;
+ shdfnd::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;
+ };
+ shdfnd::Array<TetEdge> mTetEdges;
+ shdfnd::Array<int> mTetEdgeNrs;
+ shdfnd::Array<int> mEdgeTetNrs;
+ shdfnd::Array<float> mEdgeTetAngles;
+
+ shdfnd::Array<int> mAddedTets;
+ shdfnd::Array<int> mTestEdges;
+
+ // input
+ shdfnd::Array<PxVec3> mVertices;
+ shdfnd::Array<int> mIndices;
+
+ // output
+ CompoundGeometry mGeom;
+};
+
+}}}
+
+#endif
+#endif
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.cpp
new file mode 100644
index 00000000..7051b72a
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.cpp
@@ -0,0 +1,86 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include "CompoundGeometryBase.h"
+
+namespace physx
+{
+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 = vertices.size();
+ c.numVerts = 0;
+ c.firstNormal = normals.size();
+ c.firstIndex = indices.size();
+ c.numFaces = 0;
+ c.firstPlane = 0;
+ c.firstNeighbor = neighbors.size();
+ c.numNeighbors = 0;
+ c.radius = 0.f;
+ c.isSphere = false;
+}
+
+// -------------------------------------------------------------------------------
+void CompoundGeometry::derivePlanes()
+{
+ planes.clear();
+ PxPlane p;
+
+ for (int i = 0; i < (int)convexes.size(); i++) {
+ Convex &c = convexes[i];
+ c.firstPlane = planes.size();
+ int *ids = &indices[c.firstIndex];
+ PxVec3 *verts = &vertices[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/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.h
new file mode 100644
index 00000000..e5de3787
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/CompoundGeometryBase.h
@@ -0,0 +1,68 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef COMPOUND_GEOMETRY_BASE
+#define COMPOUND_GEOMETRY_BASE
+
+#include <foundation/PxVec3.h>
+#include <foundation/PxPlane.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+// -----------------------------------------------------------------------------------
+class CompoundGeometry : public ::physx::shdfnd::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;
+ float radius;
+ bool isSphere;
+ };
+
+ void initConvex(Convex &c);
+
+ shdfnd::Array<Convex> convexes;
+ shdfnd::Array<PxVec3> vertices;
+ shdfnd::Array<PxVec3> normals; // one per face and vertex!
+ // face size, face flags, id, id, .., face size, face flags, id ..
+ shdfnd::Array<int> indices;
+ shdfnd::Array<int> neighbors;
+
+ shdfnd::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/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.cpp
new file mode 100644
index 00000000..7a6358b6
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.cpp
@@ -0,0 +1,1316 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include "PxPhysics.h"
+#include "PxCooking.h"
+#include "PxDefaultStreams.h"
+#include "PxShape.h"
+#include "foundation/PxMath.h"
+#include "PxRigidDynamic.h"
+#include "PxConvexMesh.h"
+#include "foundation/PxMat44.h"
+#include "foundation/PxMathUtils.h"
+#include "foundation/PxVec2.h"
+
+#include "CompoundGeometryBase.h"
+#include "SimSceneBase.h"
+#include "PolygonTriangulatorBase.h"
+
+#include "ConvexBase.h"
+
+#include "PhysXMacros.h"
+
+class physx::PxPhysics;
+class physx::PxCooking;
+class physx::PxActor;
+class physx::PxScene;
+class physx::PxConvexMesh;
+
+#define COOK_TRIANGLES 1
+
+#include <algorithm>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+// --------------------------------------------------------------------------------------------
+Convex::Convex(SimScene* scene)
+{
+ mScene = scene;
+ mPxConvexMesh = NULL;
+ mPxActor = NULL;
+ mLocalPose = PX_TRANSFORM_ID;
+ 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 = PX_TRANSFORM_ID;
+
+ 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, int matID, int surfMatID)
+{
+ 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;
+ mMaterialId = matID;
+ mSurfaceMaterialId = surfMatID;
+
+ if (trans != NULL) {
+ for (int i = 0; i < (int)mVertices.size(); i++)
+ mVertices[i] = trans->transform(mVertices[i]);
+ for (int i = 0; i < (int)mNormals.size(); i++)
+ mNormals[i] = trans->rotate(mNormals[i]);
+ mMaterialOffset -= trans->p;
+ }
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::transform(const PxMat44 &trans)
+{
+ for (int i = 0; i < (int)mVertices.size(); i++)
+ mVertices[i] = trans.transform(mVertices[i]);
+ for (int i = 0; i < (int)mNormals.size(); i++)
+ mNormals[i] = trans.rotate(mNormals[i]);
+ mMaterialOffset -= trans.getPosition();
+
+ if (mHasExplicitVisMesh) {
+ for (int i = 0; i < (int)mVisVertices.size(); i++)
+ mVisVertices[i] = trans.transform(mVisVertices[i]);
+ for (int i = 0; i < (int)mVisNormals.size(); i++)
+ mVisNormals[i] = trans.rotate(mVisNormals[i]);
+ }
+ finalize();
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans, int matID, int surfMatID)
+{
+ clear();
+ const CompoundGeometry::Convex &c = geom.convexes[convexNr];
+
+ PxMat44 t = PX_MAT44_ID;
+
+ if (trans)
+ t = *trans;
+
+ mVertices.resize(c.numVerts);
+ for (int i = 0; i < c.numVerts; i++)
+ mVertices[i] = t.transform(geom.vertices[c.firstVert + i]);
+
+ mFaces.resize(c.numFaces);
+ int num = 0;
+ const int *id = &geom.indices[c.firstIndex];
+ const PxVec3 *normals = (geom.normals.size() > 0) ? &geom.normals[c.firstNormal] : NULL;
+ mMaterialId = matID;
+ mSurfaceMaterialId = surfMatID;
+
+ for (int i = 0; i < 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 = 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;
+
+ int numVerts = mVertices.size();
+ for (int i = 0; i < numVerts; i++)
+ center += mVertices[i];
+ center /= (float)numVerts;
+
+ return center;
+}
+
+// --------------------------------------------------------------------------------------------
+PxVec3 Convex::centerAtZero()
+{
+ PxVec3 center = getCenter();
+ for (int i = 0; i < (int)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 (int i = 0; i < (int)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 (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 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 = 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 (int i = 0; i < (int)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 = i;
+ }
+ }
+
+ if (minPlane < 0)
+ return false;
+ else {
+ PxPlane plane = mPlanes[minPlane];
+ surfaceNormal = plane.n;
+ penetration = minDist;
+ surfaceVel = PxVec3(0.0f, 0.0f, 0.0f);
+
+ if (mPxActor != NULL)
+ {
+ PxRigidDynamic *actor = mPxActor->is<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 (int i = 0; i < (int)mVertices.size(); i++)
+ mBounds.include(mVertices[i]);
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::updatePlanes()
+{
+ int numFaces = mFaces.size();
+ mPlanes.resize(numFaces);
+
+ for (int 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[mIndices[f.firstIndex]];
+ for (int j = 1; j < f.numIndices-1; j++) {
+ PxVec3 &p1 = mVertices[mIndices[f.firstIndex+j]];
+ PxVec3 &p2 = mVertices[mIndices[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 (int i = 0; i < (int)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 (int i = 0; i < (int)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
+ int numFaces = mFaces.size();
+ shdfnd::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;
+ };
+ shdfnd::Array<Cut> cuts;
+
+ for (int i = 0; i < numFaces; i++) {
+ Face &f = mFaces[i];
+ int *ids = &mIndices[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 = mNewConvex->mIndices.size();
+ bool hasNormals = (f.flags & CompoundGeometry::FF_HAS_NORMALS) != 0;
+ if (hasNormals)
+ newFace.firstNormal = mNewConvex->mNormals.size();
+
+ int cutNrs[2];
+ int 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[i0];
+ PxVec3 &p1 = mVertices[i1];
+ PxVec3 n0,n1;
+ if (hasNormals) {
+ n0 = mNormals[f.firstNormal+j];
+ n1 = mNormals[f.firstNormal+j1];
+ }
+ bool sign0 = p0.dot(pn) >= pd;
+ bool sign1 = p1.dot(pn) >= pd;
+ if (!sign0) {
+ if (newNr[i0] < 0) {
+ newNr[i0] = mNewConvex->mVertices.size();
+ mNewConvex->mVertices.pushBack(p0);
+ }
+ mNewConvex->mIndices.pushBack(newNr[i0]);
+ if (hasNormals)
+ mNewConvex->mNormals.pushBack(n0);
+ if (numCuts == 1)
+ winding = true;
+ }
+
+ // cut?
+ if (sign0 != sign1) {
+ // do we have the cut vertex already?
+ int totalCuts = cuts.size();
+ int 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, 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] = k;
+ numCuts++;
+ }
+ }
+
+ if (numCuts == 1) { // numerical problems!
+ cutEmpty = true;
+ return false;
+ }
+
+ if (numCuts == 2) {
+ Cut &cut0 = cuts[cutNrs[0]];
+ Cut &cut1 = cuts[cutNrs[1]];
+ if (winding) {
+ cut0.next = cutNrs[1];
+ }
+ else {
+ cut1.next = cutNrs[0];
+ }
+ }
+
+ // check whether the new convex got a new face
+
+ newFace.numIndices = 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 = mNewConvex->mIndices.size();
+
+ int nr = 0;
+ for (int i = 0; i < (int)cuts.size(); i++) {
+ mNewConvex->mIndices.pushBack(cuts[nr].newId);
+ closingFace.numIndices++;
+ nr = cuts[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
+ shdfnd::Array<PxU32> 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]);
+ }
+ }
+
+ PxConvexMeshDesc meshDesc;
+ meshDesc.setToDefault();
+ meshDesc.points.count = mVertices.size();
+ meshDesc.points.stride = sizeof(PxVec3);
+ meshDesc.points.data = &mVertices[0];
+
+ meshDesc.flags |= PxConvexFlag::eCOMPUTE_CONVEX;
+#else
+ shdfnd::Array<PxHullPolygon> polygons;
+ polygons.reserve(mFaces.size());
+ if (mPlanes.size() != mFaces.size())
+ updatePlanes();
+
+ for (int i = 0; i < (int)mFaces.size(); i++) {
+ Face &f = mFaces[i];
+ if (f.numIndices < 3)
+ continue;
+ PxHullPolygon p;
+ p.mIndexBase = (physx::PxU16)f.firstIndex;
+ p.mNbVerts = (physx::PxU16)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);
+ }
+
+ PxConvexMeshDesc meshDesc;
+ meshDesc.setToDefault();
+ meshDesc.flags |= PxConvexFlag::eDISABLE_MESH_VALIDATION;
+ 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(PxU32);
+ meshDesc.polygons.count = mFaces.size();
+ meshDesc.polygons.data = &polygons[0];
+ meshDesc.polygons.stride = sizeof(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 (int i = 0; i < (int)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 (int i = 0; i < (int)mFaces.size(); i++) {
+ Face &f = mFaces[i];
+ if (f.flags & CompoundGeometry::FF_INVISIBLE)
+ continue;
+ if (f.numIndices < 3)
+ continue;
+ // normal
+ int *ids = &mIndices[f.firstIndex];
+ if (!(f.flags & CompoundGeometry::FF_HAS_NORMALS)) {
+ n = (mVertices[ids[1]] - mVertices[ids[0]]).cross(mVertices[ids[2]] - mVertices[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 = mVisVertices.size();
+ for (int j = 0; j < f.numIndices; j++) {
+ PxVec3 p = mVertices[ids[j]];
+ mVisVertices.pushBack(p);
+ if (f.flags & CompoundGeometry::FF_HAS_NORMALS) {
+ mVisNormals.pushBack(mNormals[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()
+{
+ int numIndices = mVisPolyIndices.size();
+ int numPolygons = mVisPolyStarts.size()-1;
+
+ shdfnd::Array<Edge> edges(numIndices);
+
+ for (int i = 0; i < numPolygons; i++) {
+ int first = mVisPolyStarts[i];
+ int num = mVisPolyStarts[i+1] - first;
+ for (int j = 0; j < num; j++) {
+ edges[first + j].set(
+ mVisVertices[mVisPolyIndices[first + j]],
+ mVisVertices[mVisPolyIndices[first + (j+1)%num]], i, first + j);
+ }
+ }
+ std::sort(edges.begin(), edges.end());
+
+ mVisPolyNeighbors.resize(numIndices);
+ bool manifold = true;
+ int i = 0;
+ while (i < (int)edges.size()) {
+ Edge &e0 = edges[i];
+ i++;
+ if (i < (int)edges.size() && edges[i] == e0) {
+ Edge &e1 = edges[i];
+ mVisPolyNeighbors[e0.edgeNr] = e1.faceNr;
+ mVisPolyNeighbors[e1.edgeNr] = e0.faceNr;
+ i++;
+ }
+ while (i < (int)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 PxU32 *indices, PxTransform *trans, const PxVec3* scale)
+{
+ mHasExplicitVisMesh = true;
+
+ // reduce to vertices referenced by indices
+ // needed if submesh is provided
+ shdfnd::Array<int> oldToNew(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++) {
+ int id = indices[i];
+ if (oldToNew[id] < 0) {
+ oldToNew[id] = 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);
+ }
+ }
+
+ int numTris = numIndices / 3;
+ mVisPolyStarts.resize(numTris+1);
+ for (int i = 0; i < numTris+1; i++)
+ mVisPolyStarts[i] = 3*i;
+
+ mVisPolyIndices.resize(numIndices);
+ for (int i = 0; i < numIndices; i++)
+ mVisPolyIndices[i] = oldToNew[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(numVertices);
+ mVisNormals.resize(numVertices);
+ mVisTangents.resize(numVertices);
+ mVisTexCoords.resize(2*numVertices);
+
+ const float scaleMagn = scale ? scale->magnitude() : 1.f;
+
+ for (int i = 0; i < 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(numPolygons+1);
+ for (int i = 0; i < numPolygons+1; i++)
+ mVisPolyStarts[i] = polyStarts[i];
+
+ mVisPolyIndices.resize(numIndices);
+ for (int i = 0; i < 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
+
+ int numTris = mVisTriIndices.size() / 3;
+ int* tris = &mVisTriIndices[0];
+ int numV = mVisVertices.size();
+
+ for (int i = 0; i < numTris; i++)
+ {
+ int i0 = tris[0];
+ int i1 = tris[1];
+ int i2 = 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);
+ //NxVec3 b = idet*NxVec3(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 (int 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 (int i = 0; i < (int)mVisPolyStarts.size()-1; i++) {
+ int first = mVisPolyStarts[i];
+ int num = 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], num, &mVisPolyIndices[first]);
+ const shdfnd::Array<int> indices = pt->getIndices();
+
+ int numIds = mVisTriIndices.size();
+ mVisTriIndices.resize(numIds + indices.size());
+ for (int j = 0; j < (int)indices.size(); j++)
+ mVisTriIndices[numIds+j] = indices[j];
+ }
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::transformVisualMesh(const PxTransform &trans)
+{
+ for (int i = 0; i < (int)mVisVertices.size(); i++)
+ mVisVertices[i] = trans.transform(mVisVertices[i]);
+ for (int i = 0; i < (int)mVisNormals.size(); i++)
+ mVisNormals[i] = trans.rotate(mVisNormals[i]);
+ for (int i = 0; i < (int)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 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;
+}
+
+// --------------------------------------------------------------------------------------------
+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 (int j = 0; j < (int)mVisVertices.size(); j++) {
+ float d = mVisVertices[j].dot(n);
+ if (d < minVD) minVD = d;
+ if (d > maxVD) maxVD = d;
+ }
+ for (int j = 0; j < (int)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 (int i = 0; i < (int)mFaces.size(); i++) {
+ const Face &f = mFaces[i];
+ if (f.numIndices < 3)
+ continue;
+ const int *ids = &mIndices[f.firstIndex];
+ const PxVec3 &p0 = mVertices[ids[0]];
+ for (int j = 1; j < f.numIndices-1; j++) {
+ const PxVec3 &p1 = mVertices[ids[j]];
+ const PxVec3 &p2 = mVertices[ids[j+1]];
+ mVolume += p0.cross(p1).dot(p2);
+ }
+ }
+ mVolume *= (1.0f / 6.0f);
+ mVolumeDirty = false;
+ return mVolume;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::removeInvisibleFacesFlags()
+{
+ for (int i = 0; i < (int)mFaces.size(); i++)
+ mFaces[i].flags &= ~CompoundGeometry::FF_INVISIBLE;
+}
+
+// --------------------------------------------------------------------------------------------
+void Convex::updateFaceVisibility(const float *faceCoverage)
+{
+ for (int i = 0; i < (int)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 (int i = 0; i < (int)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 (int i = 0; i < (int)mPlanes.size(); i++) {
+ if (mPlanes[i].n.dot(pos) > mPlanes[i].d + r)
+ return false;
+ }
+ return true;
+}
+
+// --------------------------------------------------------------------------------------------
+bool Convex::check() {
+ PxVec3 center = getCenter();
+
+ for (int i = 0; i < (int)mFaces.size(); i++) {
+ Face &f = mFaces[i];
+ if (f.numIndices < 3)
+ return false;
+
+ PxVec3 &p0 = mVertices[mIndices[f.firstIndex]];
+ PxReal A = 0.0f;
+ PxVec3 n(0.0, 0.0, 0.0);
+
+ for (int j = 1; j < f.numIndices-1; j++) {
+ PxVec3 &p1 = mVertices[mIndices[f.firstIndex+j]];
+ PxVec3 &p2 = mVertices[mIndices[f.firstIndex+j+1]];
+ PxVec3 nj = (p1-p0).cross(p2-p0);
+ A += nj.magnitude();
+ n += nj;
+ }
+ if (A < 1e-6)
+ return false;
+
+ PxReal 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;
+ int numF = mFaces.size();
+ for (int 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[mIndices[f.firstIndex]];
+ const PxVec3& p1 = mVertices[mIndices[f.firstIndex+j]];
+ const PxVec3& p2 = mVertices[mIndices[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[mIndices[f.firstIndex+j]];
+ const PxVec3& p2 = mVertices[mIndices[f.firstIndex+(j+1) % nv]];
+ areaP += 0.5f*(((p1-pts).cross(p2-pts))).magnitude();
+ }
+ if ((areaP - areaFan)/areaFan < EPSILON) {
+ return true;
+ }
+ }
+ return false;
+
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.h
new file mode 100644
index 00000000..ad544867
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/ConvexBase.h
@@ -0,0 +1,213 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef CONVEX_BASE
+#define CONVEX_BASE
+
+#include <PxPhysics.h>
+#include <PxCooking.h>
+#include <foundation/PxVec3.h>
+#include <foundation/PxPlane.h>
+#include <foundation/PxBounds3.h>
+#include <foundation/PxTransform.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+class physx::PxShape;
+class physx::PxActor;
+class physx::PxScene;
+class physx::PxConvexMesh;
+
+class Compound;
+class CompoundGeometry;
+class SimScene;
+
+// ----------------------------------------------------------------------------
+class Convex : public ::physx::shdfnd::UserAllocated
+{
+ friend class SimScene;
+protected:
+ Convex(SimScene* scene);
+public:
+ virtual ~Convex();
+
+ void createFromConvex(const Convex *convex, const PxTransform *trans = NULL, int matID = 0, int surfMatID = 0);
+ void createFromGeometry(const CompoundGeometry &geom, int convexNr, const PxMat44 *trans = NULL, int matID = 0, int surfMatID = 0);
+ //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 shdfnd::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 shdfnd::Array<Face> &getFaces() const { return mFaces; }
+ const shdfnd::Array<int> &getIndices() const { return mIndices; }
+ const shdfnd::Array<PxVec3> &getVertices() const { return mVertices; }
+
+ const shdfnd::Array<PxVec3> &getVisVertices() const { return mVisVertices; }
+ const shdfnd::Array<PxVec3> &getVisNormals() const { return mVisNormals; }
+ const shdfnd::Array<PxVec3> &getVisTangents() const { return mVisTangents; }
+ const shdfnd::Array<float> &getVisTexCoords() const { return mVisTexCoords; }
+ const shdfnd::Array<int> &getVisTriIndices() const { return mVisTriIndices; }
+
+ const shdfnd::Array<int> &getVisPolyStarts() const { return mVisPolyStarts; }
+ const shdfnd::Array<int> &getVisPolyIndices() const { return mVisPolyIndices; }
+ const shdfnd::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 PxU32 *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;
+
+ 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;
+
+ shdfnd::Array<Face> mFaces;
+ shdfnd::Array<int> mIndices;
+ shdfnd::Array<PxVec3> mVertices;
+ shdfnd::Array<PxVec3> mNormals;
+ shdfnd::Array<PxPlane> mPlanes;
+
+ shdfnd::Array<PxVec3> mVisVertices;
+ shdfnd::Array<PxVec3> mVisNormals;
+ shdfnd::Array<PxVec3> mVisTangents;
+ shdfnd::Array<float> mVisTexCoords;
+ shdfnd::Array<int> mVisTriIndices;
+
+ int mRefCounter;
+ bool mHasExplicitVisMesh;
+ bool mIsGhostConvex;
+ shdfnd::Array<int> mVisPolyStarts; // for explicit mesh only
+ shdfnd::Array<int> mVisPolyIndices;
+ shdfnd::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/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.cpp
new file mode 100644
index 00000000..303a2d65
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.cpp
@@ -0,0 +1,212 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include <foundation/PxBounds3.h>
+
+#include "MeshBase.h"
+#include <algorithm>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+// ----------------------------------------------------------------------
+void Mesh::updateNormals()
+{
+ if (mVertices.empty())
+ return;
+
+ PxVec3 zero(0.0f, 0.0f, 0.0f);
+
+ mNormals.resize(mVertices.size());
+ for (int i = 0; i < (int)mNormals.size(); i++)
+ mNormals[i] = zero;
+ PxVec3 n;
+
+ PxU32 *idx = &mIndices[0];
+ int numTriangles = mIndices.size() / 3;
+ for (int i = 0; i < numTriangles; i++) {
+ PxU32 i0 = *idx++;
+ PxU32 i1 = *idx++;
+ PxU32 i2 = *idx++;
+ n = (mVertices[i1] - mVertices[i0]).cross(mVertices[i2] - mVertices[i0]);
+ mNormals[i0] += n;
+ mNormals[i1] += n;
+ mNormals[i2] += n;
+ }
+ for (int i = 0; i < (int)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 (int i = 0; i < (int)mVertices.size(); i++)
+ bounds.include(mVertices[i]);
+ }
+ else {
+ const SubMesh &sm = mSubMeshes[subMeshNr];
+ for (int i = 0; i < sm.numIndices; i++) {
+ bounds.include(mVertices[mIndices[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 (int i = 0; i < (int)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 (int i = 0; i < (int)mVertices.size(); i++)
+ mVertices[i] *= s;
+}
+
+// --------------------------------------------------------------------------------------------
+struct IdEdge {
+ void set(PxU32 &i0, PxU32 &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; }
+ PxU32 i0,i1;
+ int faceNr, edgeNr;
+};
+
+// ------------------------------------------------------------------------------
+bool Mesh::computeNeighbors()
+{
+ int numTris = mIndices.size() / 3;
+
+ shdfnd::Array<IdEdge> edges(3*numTris);
+
+ for (int i = 0; i < numTris; i++) {
+ for (int j = 0; j < 3; j++)
+ edges[3*i+j].set(mIndices[3*i+j], mIndices[3*i + (j+1)%3], i, j);
+ }
+ std::sort(edges.begin(), edges.end());
+
+ mNeighbors.clear();
+ mNeighbors.resize(mIndices.size(), -1);
+ bool manifold = true;
+ int i = 0;
+ while (i < (int)edges.size()) {
+ IdEdge &e0 = edges[i];
+ i++;
+ if (i < (int)edges.size() && edges[i] == e0) {
+ IdEdge &e1 = edges[i];
+ mNeighbors[3* e0.faceNr + e0.edgeNr] = e1.faceNr;
+ mNeighbors[3* e1.faceNr + e1.edgeNr] = e0.faceNr;
+ i++;
+ }
+ while (i < (int)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()
+{
+ int numTris = mIndices.size() / 3;
+ shdfnd::Array<PosEdge> edges(3*numTris);
+
+ for (int i = 0; i < numTris; i++) {
+ for (int j = 0; j < 3; j++)
+ edges[3*i+j].set(mVertices[mIndices[3*i+j]], mVertices[mIndices[3*i + (j+1)%3]], i, j);
+ }
+ std::sort(edges.begin(), edges.end());
+
+ mNeighbors.clear();
+ mNeighbors.resize(mIndices.size(), -1);
+ bool manifold = true;
+ int i = 0;
+ while (i < (int)edges.size()) {
+ PosEdge &e0 = edges[i];
+ i++;
+ if (i < (int)edges.size() && edges[i] == e0) {
+ PosEdge &e1 = edges[i];
+ mNeighbors[3* e0.faceNr + e0.edgeNr] = e1.faceNr;
+ mNeighbors[3* e1.faceNr + e1.edgeNr] = e0.faceNr;
+ i++;
+ }
+ while (i < (int)edges.size() && edges[i] == e0) {
+ manifold = false;
+ i++;
+ }
+ }
+ return manifold;
+}
+
+void Mesh::flipV()
+{
+ for(PxU32 i = 0; i < mTexCoords.size(); i++)
+ {
+ mTexCoords[i].y = 1.0f - mTexCoords[i].y;
+ }
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.h
new file mode 100644
index 00000000..5cde7f17
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/MeshBase.h
@@ -0,0 +1,67 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef MESH_BASE
+#define MESH_BASE
+
+#include <foundation/PxVec3.h>
+#include <foundation/PxVec2.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+// -----------------------------------------------------------------------------------
+class Mesh : public ::physx::shdfnd::UserAllocated
+{
+public:
+ Mesh() {};
+ virtual ~Mesh() {};
+
+ const shdfnd::Array<PxVec3> &getVertices() const { return mVertices; }
+ const shdfnd::Array<PxVec3> &getNormals() const { return mNormals; }
+ const shdfnd::Array<PxVec2> &getTexCoords() const { return mTexCoords; }
+ const shdfnd::Array<PxU32> &getIndices() const { return mIndices; }
+ const shdfnd::Array<int> &getNeighbors() const { return mNeighbors; }
+
+ struct SubMesh {
+ void init() { /*name = "";*/ firstIndex = -1; numIndices = 0; }
+ //std::string name;
+ int firstIndex;
+ int numIndices;
+ };
+
+ const shdfnd::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();
+
+ shdfnd::Array<PxVec3> mVertices;
+ shdfnd::Array<PxVec3> mNormals;
+ shdfnd::Array<PxVec2> mTexCoords;
+
+ shdfnd::Array<SubMesh> mSubMeshes;
+ shdfnd::Array<PxU32> mIndices;
+ shdfnd::Array<int> mNeighbors;
+};
+
+}
+}
+}
+
+#endif
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.cpp
new file mode 100644
index 00000000..9b7f82b3
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.cpp
@@ -0,0 +1,272 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include "PolygonTriangulatorBase.h"
+#include <foundation/PxAssert.h>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+// ------ 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*(numPoints-2));
+ for (int i = 0; i < numPoints-2; i++) {
+ mIndices[3*i] = 0;
+ mIndices[3*i+1] = i+1;
+ mIndices[3*i+2] = i+2;
+ }
+ }
+ else
+ clipEars();
+
+ if (indices != NULL) {
+ for (int i = 0; i < (int)mIndices.size(); i++) {
+ mIndices[i] = indices[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(numPoints);
+ if (indices == NULL) {
+ for (int i = 0; i < numPoints; i++)
+ mPoints[i] = PxVec3(points[i].dot(t0), points[i].dot(t1), 0.0f);
+ }
+ else {
+ for (int i = 0; i < numPoints; i++) {
+ const PxVec3 &p = points[indices[i]];
+ mPoints[i] = PxVec3(p.dot(t0), p.dot(t1), 0.0f);
+ }
+ }
+}
+
+// -------------------------------------------------------------------------------------
+void PolygonTriangulator::clipEars()
+{
+ // init
+ int num = mPoints.size();
+
+ mCorners.resize(num);
+
+ for (int i = 0; i < num; i++) {
+ Corner &c = mCorners[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[c.prev];
+ PxVec3 &p1 = mPoints[i];
+ PxVec3 &p2 = mPoints[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[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[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[minNr];
+ mIndices.pushBack(cmin.prev);
+ mIndices.pushBack(minNr);
+ mIndices.pushBack(cmin.next);
+ mCorners[cmin.prev].next = cmin.next;
+ mCorners[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++) {
+ int i1 = (i == 0) ? cmin.prev : cmin.next;
+ int i0 = mCorners[i1].prev;
+ int i2 = 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[nr], p0,p1,p2)) {
+ mCorners[i1].isEar = false;
+ break;
+ }
+ nr = mCorners[nr].next;
+ }
+ }
+ }
+ }
+ int id = firstCorner;
+ mIndices.pushBack(id);
+ id = mCorners[id].next;
+ mIndices.pushBack(id);
+ id = mCorners[id].next;
+ mIndices.pushBack(id);
+}
+
+}
+}
+}
+#endif \ No newline at end of file
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.h
new file mode 100644
index 00000000..3b1c08be
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/PolygonTriangulatorBase.h
@@ -0,0 +1,59 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#ifndef POLYGON_TRIANGULATOR_BASE_H
+#define POLYGON_TRIANGULATOR_BASE_H
+
+#include <foundation/PxVec3.h>
+#include <foundation/PxMath.h>
+#include <PsArray.h>
+#include <PsUserAllocated.h>
+
+namespace physx
+{
+namespace fracture
+{
+namespace base
+{
+
+// ------------------------------------------------------------------------------
+
+class PolygonTriangulator : public ::physx::shdfnd::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 shdfnd::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;
+
+ shdfnd::Array<PxVec3> mPoints;
+ shdfnd::Array<int> mIndices;
+
+ struct Corner {
+ int prev;
+ int next;
+ bool isEar;
+ float angle;
+ };
+ shdfnd::Array<Corner> mCorners;
+};
+
+}
+}
+}
+
+#endif
+#endif
diff --git a/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.cpp b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.cpp
new file mode 100644
index 00000000..6a1d2931
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.cpp
@@ -0,0 +1,337 @@
+#include "RTdef.h"
+#if RT_COMPILE
+#include "PsHashMap.h"
+#include "SimSceneBase.h"
+#include <foundation/PxMat44.h>
+#include "PxRigidBodyExt.h"
+#include "PxPhysics.h"
+#include "PxCooking.h"
+#include "PxShape.h"
+
+#include "ActorBase.h"
+#include "CompoundBase.h"
+#include "ConvexBase.h"
+#include "CompoundCreatorBase.h"
+#include "PolygonTriangulatorBase.h"
+
+#include "RTdef.h"
+
+#include "PhysXMacros.h"
+#include "PxScene.h"
+#include "PxD6Joint.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 physx
+{
+namespace fracture
+{
+namespace base
+{
+
+SimScene* SimScene::createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath)
+{
+ SimScene* s = PX_NEW(SimScene)(pxPhysics,pxCooking, isGrbScene,minConvexSize,defaultMat,resourcePath);
+ s->createSingletons();
+ return s;
+}
+
+void SimScene::createSingletons()
+{
+ mCompoundCreator = PX_NEW(CompoundCreator)(this);
+ mPolygonTriangulator = PX_NEW(PolygonTriangulator)(this);
+ addActor(createActor()); // make default actor
+}
+
+Convex* SimScene::createConvex()
+{
+ return PX_NEW(Convex)(this);
+}
+
+Compound* SimScene::createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern, PxReal contactOffset, PxReal restOffset)
+{
+ return PX_NEW(Compound)(this,contactOffset,restOffset);
+}
+
+Actor* SimScene::createActor()
+{
+ return PX_NEW(Actor)(this);
+}
+
+shdfnd::Array<Compound*> SimScene::getCompounds()
+{
+ return mActors[0]->getCompounds();
+}
+
+///*extern*/ std::vector<Compound*> delCompoundList;
+
+// --------------------------------------------------------------------------------------------
+SimScene::SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath)
+{
+ mPxPhysics = pxPhysics; // used for cooking
+ mPxCooking = pxCooking;
+ mPxDefaultMaterial = defaultMat;
+ 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;
+ mPickJoint = 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;
+ mPolygonTriangulator = NULL;
+
+ mAppNotify = NULL;
+}
+
+// --------------------------------------------------------------------------------------------
+SimScene::~SimScene()
+{
+ clear();
+
+ // Delete actors if not already deleted
+ for(int i = ((int)mActors.size() - 1) ; i >= 0; i--)
+ {
+ PX_DELETE(mActors[i]);
+ }
+
+ PX_DELETE(mCompoundCreator);
+ PX_DELETE(mPolygonTriangulator);
+
+ mCompoundCreator = NULL;
+ mPolygonTriangulator = NULL;
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::clear()
+{
+ for(int i = 0 ; i < (int)mActors.size(); i++)
+ {
+ mActors[i]->clear();
+ }
+ deleteCompounds();
+ mPickActor = NULL;
+
+ ++mSceneVersion;
+}
+
+void SimScene::addActor(Actor* a)
+{
+ mActors.pushBack(a);
+}
+
+void SimScene::removeActor(Actor* a)
+{
+ for(int i = 0; i < (int)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 (int i = 0; i < (int)delCompoundList.size(); i++)
+ {
+ PX_DELETE(delCompoundList[i]);
+ }
+ delCompoundList.clear();
+}
+
+// --------------------------------------------------------------------------------------------
+void SimScene::preSim(float dt)
+{
+ for(int i = 0 ; i < (int)mActors.size(); i++)
+ {
+ mActors[i]->preSim(dt);
+ }
+
+
+ // make sure we use the apex user notify... if the application
+ // changes their custom one make sure we map to it.
+ 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)
+{
+ for(int i = 0 ; i < (int)mActors.size(); i++)
+ {
+ mActors[i]->postSim(dt);
+ }
+
+ mFrameNr++;
+ mNoFractureFrames--;
+ mNoSoundFrames--;
+}
+
+
+//-----------------------------------------------------------------------------
+bool SimScene::pickStart(const PxVec3 &orig, const PxVec3 &dir)
+{
+ PX_ASSERT(mPickActor == NULL);
+
+ float dist = 1000.f;
+
+ PxRaycastBuffer buffer;
+ if (!getScene()->raycast(orig, dir, dist, buffer, PxHitFlag::eDEFAULT, PxQueryFilterData(PxQueryFlag::eDYNAMIC)))
+ return false;
+
+ PxRigidDynamic* pickedActor = buffer.getAnyHit(0).actor->is<PxRigidDynamic>();
+
+ dist = buffer.getAnyHit(0).distance;
+
+
+
+ //mPickActor = mActors[actorNr]->mCompounds[compoundNr]->getPxActor();
+ mPickPos = orig + dir * dist;
+
+ mPickActor = PxGetPhysics().createRigidDynamic(PxTransform(mPickPos));
+ mPickActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
+
+ getScene()->addActor(*mPickActor);
+
+ mPickLocalPos = PxVec3(0.f);
+
+ mPickJoint = PxD6JointCreate(PxGetPhysics(), mPickActor, PxTransform(PxIdentity), pickedActor, PxTransform(pickedActor->getGlobalPose().transformInv(mPickPos)));
+ mPickJoint->setMotion(PxD6Axis::eSWING1, PxD6Motion::eFREE);
+ mPickJoint->setMotion(PxD6Axis::eSWING2, PxD6Motion::eFREE);
+ mPickJoint->setMotion(PxD6Axis::eTWIST, PxD6Motion::eFREE);
+
+ mPickDepth = dist;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+void SimScene::pickMove(const PxVec3 &orig, const PxVec3 &dir)
+{
+ if (mPickActor == NULL)
+ return;
+
+ mPickPos = orig + dir * mPickDepth;
+ mPickActor->setKinematicTarget(PxTransform(mPickPos));
+}
+
+//-----------------------------------------------------------------------------
+void SimScene::pickRelease()
+{
+ if (mPickJoint)
+ mPickJoint->release();
+ mPickJoint = NULL;
+ if (mPickActor)
+ mPickActor->release();
+ mPickActor = NULL;
+}
+
+bool SimScene::findCompound(const Compound* c, int& actorNr, int& compoundNr)
+{
+ actorNr = -1;
+ compoundNr = -1;
+ for(int i = 0; i < (int)mActors.size(); i++)
+ {
+ if (mActors[i]->findCompound(c,compoundNr))
+ {
+ actorNr = i;
+ return true;
+ }
+ }
+ return false;
+}
+
+// --------------------------------------------------------------------------------------------
+// CPU
+void SimScene::onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs)
+{
+ // Pass along to application's callback, if defined
+ if (mAppNotify != NULL)
+ {
+ mAppNotify->onContact(pairHeader, pairs, nbPairs);
+ }
+}
+
+shdfnd::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 physx::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/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.h b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.h
new file mode 100644
index 00000000..60bd732d
--- /dev/null
+++ b/KaplaDemo/samples/sampleViewer3/Fracture/Core/SimSceneBase.h
@@ -0,0 +1,248 @@
+#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 physx
+{
+class PxPhysics;
+class PxCooking;
+class PxScene;
+class PxRigidDynamic;
+class PxD6Joint;
+namespace fracture
+{
+namespace base
+{
+
+class Actor;
+class Compound;
+class Convex;
+class FracturePattern;
+class CompoundCreator;
+class Delaunay2d;
+class Delaunay3d;
+class PolygonTriangulator;
+
+// -----------------------------------------------------------------------------------
+class SimScene :
+ public PxSimulationEventCallback, public ::physx::shdfnd::UserAllocated
+{
+ friend class Actor;
+public:
+ static SimScene* createSimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath);
+protected:
+ SimScene(PxPhysics *pxPhysics, PxCooking *pxCooking, bool isGrbScene, float minConvexSize, PxMaterial* defaultMat, const char *resourcePath);
+public:
+ virtual ~SimScene();
+
+ // Creates Scene Level Singletons
+ virtual void createSingletons();
+ // Access singletons
+ CompoundCreator* getCompoundCreator() {return mCompoundCreator;}
+ PolygonTriangulator* getPolygonTriangulator() {return mPolygonTriangulator;}
+
+ // Create non-Singletons
+ virtual Actor* createActor();
+ virtual Convex* createConvex();
+ virtual Compound* createCompound(const FracturePattern *pattern, const FracturePattern *secondaryPattern = NULL, PxReal contactOffset = 0.005f, PxReal restOffset = -0.001f);
+ virtual void clear();
+ void addCompound(Compound *m);
+ void removeCompound(Compound *m);
+ // perform deferred deletion
+ void deleteCompounds();
+
+ void setScene(PxScene* scene) { mScene = scene; }
+ //
+ 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*/) {}
+
+ virtual void playSound(const char * /*name*/, int /*nr*/ = -1) {}
+
+ // accessors
+ shdfnd::Array<Compound*> getCompounds(); //{ return mCompounds; }
+ shdfnd::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(PxConstraintInfo* constraints, PxU32 count) { PX_UNUSED((constraints, count)); }
+ void onWake(PxActor** actors, PxU32 count) { PX_UNUSED((actors, count)); }
+ void onSleep(PxActor** actors, PxU32 count) { PX_UNUSED((actors, count)); }
+ void onTrigger(PxTriggerPair* pairs, PxU32 count) { PX_UNUSED((pairs, count)); }
+ void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs);
+ void onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count) { PX_UNUSED(bodyBuffer); PX_UNUSED(poseBuffer); PX_UNUSED(count); }
+
+ void toggleRenderDebris() {mRenderDebris = !mRenderDebris;}
+ bool getRenderDebrs() {return mRenderDebris;}
+ //virtual void dumpSceneGeometry() {}
+ shdfnd::Array<PxVec3>& getDebugPoints();
+ //virtual void createRenderBuffers() {}
+ //void loadAndCreateTextureArrays();
+
+ shdfnd::Array<PxVec3>& getCrackNormals() {return crackNormals;}
+ shdfnd::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;
+
+ //shdfnd::Array<Compound*> mCompounds;
+ shdfnd::Array<Actor*> mActors;
+
+ float mFractureForceThreshold;
+ float mContactImpactRadius;
+
+ shdfnd::Array<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;
+ };
+
+ struct RenderBuffers {
+ void init() {
+ numVertices = 0; numIndices = 0;
+ VBO = 0; IBO = 0; matTex = 0; volTex = 0;
+ texSize = 0; numConvexes = -1;
+ }
+ shdfnd::Array<float> tmpVertices;
+ shdfnd::Array<unsigned int> tmpIndices;
+ shdfnd::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;
+ PxD6Joint* mPickJoint;
+ 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;
+ shdfnd::Array<PxVec3> debugPoints;
+ bool mRenderDebris;
+
+ PxSimulationEventCallback* mAppNotify;
+
+ //GLuint diffuseTexArray, bumpTexArray, specularTexArray, emissiveReflectSpecPowerTexArray;
+
+ //GLuint loadTextureArray(std::vector<std::string>& names);
+
+ //Singletons
+ CompoundCreator* mCompoundCreator;
+ PolygonTriangulator* mPolygonTriangulator;
+
+ //Array for use by Compound (effectively static)
+ shdfnd::Array<PxVec3> crackNormals;
+ shdfnd::Array<PxVec3> tmpPoints;
+
+ // Deferred Deletion list
+ shdfnd::Array<Compound*> delCompoundList;
+
+ // Map used to determine SimScene ownership of shape
+ shdfnd::HashMap<const PxShape*,Convex*> mShapeMap;
+};
+
+}
+}
+}
+
+#endif
+#endif