aboutsummaryrefslogtreecommitdiff
path: root/extensions/flexExtContainer.cpp
diff options
context:
space:
mode:
authorMiles Macklin <[email protected]>2017-03-10 14:51:31 +1300
committerMiles Macklin <[email protected]>2017-03-10 14:51:31 +1300
commitad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f (patch)
tree4cc6f3288363889d7342f7f8407c0251e6904819 /extensions/flexExtContainer.cpp
downloadflex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.tar.xz
flex-ad3d90fafe5ee79964bdfe1f1e0704c3ffcdfd5f.zip
Initial 1.1.0 binary release
Diffstat (limited to 'extensions/flexExtContainer.cpp')
-rw-r--r--extensions/flexExtContainer.cpp807
1 files changed, 807 insertions, 0 deletions
diff --git a/extensions/flexExtContainer.cpp b/extensions/flexExtContainer.cpp
new file mode 100644
index 0000000..92cb958
--- /dev/null
+++ b/extensions/flexExtContainer.cpp
@@ -0,0 +1,807 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2013-2017 NVIDIA Corporation. All rights reserved.
+
+#include <vector>
+#include <limits>
+#include <algorithm>
+
+#include "../core/core.h"
+#include "../core/maths.h"
+
+#include "../include/NvFlex.h"
+#include "../include/NvFlexExt.h"
+
+class Bitmap
+{
+public:
+
+ typedef unsigned int Word;
+
+ static const int kWordSize = sizeof(Word)*8;
+
+ Bitmap(int numBits) : mBits((numBits+kWordSize-1)/kWordSize)
+ {
+ }
+
+ inline void Set(int bit)
+ {
+ const int wordIndex = bit/kWordSize;
+ const int bitIndex = bit&(kWordSize-1);
+
+ const Word word = mBits[wordIndex];
+
+ mBits[wordIndex] = word|(1<<bitIndex);
+ }
+
+ inline void Reset(int bit)
+ {
+ const int wordIndex = bit/kWordSize;
+ const int bitIndex = bit&(kWordSize-1);
+
+ const Word word = mBits[wordIndex];
+
+ mBits[wordIndex] = word&~(1<<bitIndex);
+ }
+
+ inline bool IsSet(int bit)
+ {
+ const int wordIndex = bit/kWordSize;
+ const int bitIndex = bit&(kWordSize-1);
+
+ const Word word = mBits[wordIndex];
+
+ return (word & (1<<bitIndex)) != 0;
+ }
+
+private:
+
+ std::vector<Word> mBits;
+};
+
+
+struct NvFlexExtContainer
+{
+ int mMaxParticles;
+
+ NvFlexSolver* mSolver;
+ NvFlexLibrary* mFlexLib;
+
+ // first n indices
+ NvFlexVector<int> mActiveList;
+
+ std::vector<int> mFreeList;
+ std::vector<NvFlexExtInstance*> mInstances;
+
+ // particles
+ NvFlexVector<Vec4> mParticles;
+ NvFlexVector<Vec4> mParticlesRest;
+ NvFlexVector<Vec3> mVelocities;
+ NvFlexVector<int> mPhases;
+ NvFlexVector<Vec4> mNormals;
+
+ // shapes
+ NvFlexVector<int> mShapeOffsets;
+ NvFlexVector<int> mShapeIndices;
+ NvFlexVector<float> mShapeCoefficients;
+ NvFlexVector<Quat> mShapeRotations;
+ NvFlexVector<Vec3> mShapeTranslations;
+ NvFlexVector<Vec3> mShapeRestPositions;
+
+ // springs
+ NvFlexVector<int> mSpringIndices;
+ NvFlexVector<float> mSpringLengths;
+ NvFlexVector<float> mSpringCoefficients;
+
+ // cloth
+ NvFlexVector<int> mTriangleIndices;
+ NvFlexVector<Vec3> mTriangleNormals;
+
+ NvFlexVector<int> mInflatableStarts;
+ NvFlexVector<int> mInflatableCounts;
+ NvFlexVector<float> mInflatableRestVolumes;
+ NvFlexVector<float> mInflatableCoefficients;
+ NvFlexVector<float> mInflatableOverPressures;
+
+ // bounds (CPU), stored in a vector to ensure transfers can happen asynchronously
+ NvFlexVector<Vec3> mBoundsLower;
+ NvFlexVector<Vec3> mBoundsUpper;
+
+ // needs compact
+ bool mNeedsCompact;
+ // needs to update active list
+ bool mNeedsActiveListRebuild;
+
+ NvFlexExtContainer(NvFlexLibrary* l) :
+ mMaxParticles(0), mSolver(NULL), mFlexLib(l),
+ mActiveList(l),mParticles(l),mParticlesRest(l),mVelocities(l),
+ mPhases(l),mNormals(l),mShapeOffsets(l),mShapeIndices(l),
+ mShapeCoefficients(l),mShapeRotations(l),mShapeTranslations(l),
+ mShapeRestPositions(l),mSpringIndices(l),mSpringLengths(l),
+ mSpringCoefficients(l),mTriangleIndices(l),mTriangleNormals(l),
+ mInflatableStarts(l),mInflatableCounts(l),mInflatableRestVolumes(l),
+ mInflatableCoefficients(l),mInflatableOverPressures(l), mBoundsLower(l), mBoundsUpper(l),
+ mNeedsCompact(false), mNeedsActiveListRebuild(false)
+ {}
+};
+
+
+
+namespace
+{
+
+// compacts all constraints into linear arrays
+void CompactObjects(NvFlexExtContainer* c)
+{
+ int totalNumSprings = 0;
+ int totalNumTris = 0;
+ int totalNumShapes = 0;
+ int totalNumShapeIndices = 0;
+
+ // pre-calculate array sizes
+ for (size_t i = 0; i < c->mInstances.size(); ++i)
+ {
+ NvFlexExtInstance* inst = c->mInstances[i];
+
+ const NvFlexExtAsset* asset = inst->asset;
+
+ // index into the triangle array for this instance
+ inst->triangleIndex = totalNumTris;
+
+ totalNumSprings += asset->numSprings;
+ totalNumTris += asset->numTriangles;
+
+ totalNumShapeIndices += asset->numShapeIndices;
+ totalNumShapes += asset->numShapes;
+ }
+
+ //----------------------
+ // map buffers
+
+ // springs
+ c->mSpringIndices.map();
+ c->mSpringLengths.map();
+ c->mSpringCoefficients.map();
+
+ // cloth
+ c->mTriangleIndices.map();
+ c->mTriangleNormals.map();
+
+ // inflatables
+ c->mInflatableStarts.map();
+ c->mInflatableCounts.map();
+ c->mInflatableRestVolumes.map();
+ c->mInflatableCoefficients.map();
+ c->mInflatableOverPressures.map();
+
+ // shapes
+ c->mShapeIndices.map();
+ c->mShapeRestPositions.map();
+ c->mShapeOffsets.map();
+ c->mShapeCoefficients.map();
+
+ c->mShapeTranslations.map();
+ c->mShapeRotations.map();
+
+ //----------------------
+ // resize buffers
+
+ // springs
+ c->mSpringIndices.resize(totalNumSprings * 2);
+ c->mSpringLengths.resize(totalNumSprings);
+ c->mSpringCoefficients.resize(totalNumSprings);
+
+ // cloth
+ c->mTriangleIndices.resize(totalNumTris * 3);
+ c->mTriangleNormals.resize(totalNumTris);
+
+ // inflatables
+ c->mInflatableStarts.resize(0);
+ c->mInflatableCounts.resize(0);
+ c->mInflatableRestVolumes.resize(0);
+ c->mInflatableCoefficients.resize(0);
+ c->mInflatableOverPressures.resize(0);
+
+ // shapes
+ c->mShapeIndices.resize(totalNumShapeIndices);
+ c->mShapeRestPositions.resize(totalNumShapeIndices);
+ c->mShapeOffsets.resize(1 + totalNumShapes);
+ c->mShapeCoefficients.resize(totalNumShapes);
+
+ c->mShapeTranslations.resize(totalNumShapes);
+ c->mShapeRotations.resize(totalNumShapes);
+
+ int* __restrict dstSpringIndices = (totalNumSprings) ? &c->mSpringIndices[0] : NULL;
+ float* __restrict dstSpringLengths = (totalNumSprings) ? &c->mSpringLengths[0] : NULL;
+ float* __restrict dstSpringCoefficients = (totalNumSprings) ? &c->mSpringCoefficients[0] : NULL;
+
+ int* __restrict dstTriangleIndices = (totalNumTris) ? &c->mTriangleIndices[0] : NULL;
+
+ int* __restrict dstShapeIndices = (totalNumShapeIndices) ? &c->mShapeIndices[0] : NULL;
+ Vec3* __restrict dstShapeRestPositions = (totalNumShapeIndices) ? &c->mShapeRestPositions[0] : NULL;
+ int* __restrict dstShapeOffsets = (totalNumShapes) ? &c->mShapeOffsets[0] : NULL;
+ float* __restrict dstShapeCoefficients = (totalNumShapes) ? &c->mShapeCoefficients[0] : NULL;
+ Vec3* __restrict dstShapeTranslations = (totalNumShapes) ? &c->mShapeTranslations[0] : NULL;
+ Quat* __restrict dstShapeRotations = (totalNumShapes) ? &c->mShapeRotations[0] : NULL;
+
+ // push leading zero if necessary
+ if (totalNumShapes != 0)
+ {
+ *dstShapeOffsets = 0;
+ ++dstShapeOffsets;
+ }
+
+ int shapeIndexOffset = 0;
+ int shapeIndex = 0;
+
+ // go through each instance and update springs, shapes, etc
+ for (size_t i = 0; i < c->mInstances.size(); ++i)
+ {
+ NvFlexExtInstance* inst = c->mInstances[i];
+
+ const NvFlexExtAsset* asset = inst->asset;
+
+ // map indices from the asset to the instance
+ const int* __restrict remap = &inst->particleIndices[0];
+
+ // flatten spring data
+ int numSprings = asset->numSprings;
+ const int numSpringIndices = asset->numSprings * 2;
+ const int* __restrict srcSpringIndices = asset->springIndices;
+
+ for (int i = 0; i < numSpringIndices; ++i)
+ {
+ *dstSpringIndices = remap[*srcSpringIndices];
+
+ ++dstSpringIndices;
+ ++srcSpringIndices;
+ }
+
+ memcpy(dstSpringLengths, asset->springRestLengths, numSprings*sizeof(float));
+ memcpy(dstSpringCoefficients, asset->springCoefficients, numSprings*sizeof(float));
+
+ dstSpringLengths += numSprings;
+ dstSpringCoefficients += numSprings;
+
+ // shapes
+ if (asset->numShapes)
+ {
+ const int indexOffset = shapeIndexOffset;
+
+ // store start index into shape array
+ inst->shapeIndex = shapeIndex;
+
+ int shapeStart = 0;
+
+ for (int s=0; s < asset->numShapes; ++s)
+ {
+ dstShapeOffsets[shapeIndex] = asset->shapeOffsets[s] + indexOffset;
+ dstShapeCoefficients[shapeIndex] = asset->shapeCoefficients[s];
+ dstShapeTranslations[shapeIndex] = Vec3(&inst->shapeTranslations[s*3]);
+ dstShapeRotations[shapeIndex] = Quat(&inst->shapeRotations[s*4]);
+
+ ++shapeIndex;
+
+ const int shapeEnd = asset->shapeOffsets[s];
+
+ for (int i=shapeStart; i < shapeEnd; ++i)
+ {
+ const int firstParticle = asset->shapeIndices[0];
+ const int currentParticle = asset->shapeIndices[i];
+
+ // remap indices and create local space positions for each shape
+ // To make this calculation more robust, subtract the position of the first particle from both, the positions of the current
+ // particle and the shapeCenter. Without this one would subtract two very similar floating point values, which can lead to ghost forces.
+ dstShapeRestPositions[shapeIndexOffset] = (Vec3(&asset->particles[currentParticle*4]) - Vec3(&asset->particles[firstParticle]))
+ - (Vec3(&asset->shapeCenters[s*3]) - Vec3(&asset->particles[firstParticle]));
+
+ dstShapeIndices[shapeIndexOffset] = remap[asset->shapeIndices[i]];
+
+ ++shapeIndexOffset;
+ }
+
+ shapeStart = shapeEnd;
+ }
+ }
+
+ if (asset->numTriangles)
+ {
+ // triangles
+ const int numTriIndices = asset->numTriangles * 3;
+ const int* __restrict srcTriIndices = asset->triangleIndices;
+
+ for (int i = 0; i < numTriIndices; ++i)
+ {
+ *dstTriangleIndices = remap[*srcTriIndices];
+
+ ++dstTriangleIndices;
+ ++srcTriIndices;
+ }
+
+ if (asset->inflatable)
+ {
+ c->mInflatableStarts.push_back(inst->triangleIndex);
+ c->mInflatableCounts.push_back(asset->numTriangles);
+ c->mInflatableRestVolumes.push_back(asset->inflatableVolume);
+ c->mInflatableCoefficients.push_back(asset->inflatableStiffness);
+ c->mInflatableOverPressures.push_back(asset->inflatablePressure);
+ }
+ }
+ }
+
+
+ //----------------------
+ // unmap buffers
+
+ // springs
+ c->mSpringIndices.unmap();
+ c->mSpringLengths.unmap();
+ c->mSpringCoefficients.unmap();
+
+ // cloth
+ c->mTriangleIndices.unmap();
+ c->mTriangleNormals.unmap();
+
+ // inflatables
+ c->mInflatableStarts.unmap();
+ c->mInflatableCounts.unmap();
+ c->mInflatableRestVolumes.unmap();
+ c->mInflatableCoefficients.unmap();
+ c->mInflatableOverPressures.unmap();
+
+ // shapes
+ c->mShapeIndices.unmap();
+ c->mShapeRestPositions.unmap();
+ c->mShapeOffsets.unmap();
+ c->mShapeCoefficients.unmap();
+
+ c->mShapeTranslations.unmap();
+ c->mShapeRotations.unmap();
+
+ // ----------------------
+ // Flex update
+
+ // springs
+ if (c->mSpringLengths.size())
+ NvFlexSetSprings(c->mSolver, c->mSpringIndices.buffer, c->mSpringLengths.buffer, c->mSpringCoefficients.buffer, int(c->mSpringLengths.size()));
+ else
+ NvFlexSetSprings(c->mSolver, NULL, NULL, NULL, 0);
+
+ // shapes
+ if (c->mShapeCoefficients.size())
+ {
+ NvFlexSetRigids(c->mSolver, c->mShapeOffsets.buffer, c->mShapeIndices.buffer, c->mShapeRestPositions.buffer, NULL, c->mShapeCoefficients.buffer, c->mShapeRotations.buffer, c->mShapeTranslations.buffer, int(c->mShapeCoefficients.size()), c->mShapeIndices.size());
+ }
+ else
+ {
+ c->mShapeRotations.resize(0);
+ c->mShapeTranslations.resize(0);
+
+ NvFlexSetRigids(c->mSolver, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0);
+ }
+
+ // triangles
+ if (c->mTriangleIndices.size())
+ NvFlexSetDynamicTriangles(c->mSolver, c->mTriangleIndices.buffer, NULL, int(c->mTriangleIndices.size()/3));
+ else
+ NvFlexSetDynamicTriangles(c->mSolver, NULL, NULL, 0);
+
+ // inflatables
+ if (c->mInflatableCounts.size())
+ NvFlexSetInflatables(c->mSolver, c->mInflatableStarts.buffer, c->mInflatableCounts.buffer, c->mInflatableRestVolumes.buffer, c->mInflatableOverPressures.buffer, c->mInflatableCoefficients.buffer, int(c->mInflatableCounts.size()));
+ else
+ NvFlexSetInflatables(c->mSolver, NULL, NULL, NULL, NULL, NULL, 0);
+
+ c->mNeedsCompact = false;
+
+}
+
+} // anonymous namespace
+
+
+NvFlexExtContainer* NvFlexExtCreateContainer(NvFlexLibrary* flexLib, NvFlexSolver* solver, int maxParticles)
+{
+ NvFlexExtContainer* c = new NvFlexExtContainer(flexLib);
+
+ c->mSolver = solver;
+ c->mFlexLib = flexLib;
+ c->mMaxParticles = maxParticles;
+
+ // initialize free list
+ c->mFreeList.resize(maxParticles);
+ for (int i=0; i < maxParticles; ++i)
+ c->mFreeList[i] = i;
+
+ c->mActiveList.init(maxParticles);
+ c->mParticles.init(maxParticles);
+ c->mParticlesRest.init(maxParticles);
+ c->mVelocities.init(maxParticles);
+ c->mPhases.init(maxParticles);
+ c->mNormals.init(maxParticles);
+
+
+ // ensure we have the corerct CUDA context set
+ NvFlexAcquireContext(flexLib);
+
+ c->mBoundsLower.init(1);
+ c->mBoundsUpper.init(1);
+
+ NvFlexRestoreContext(flexLib);
+
+ c->mNeedsCompact = false;
+
+ return c;
+}
+
+void NvFlexExtDestroyContainer(NvFlexExtContainer* c)
+{
+ // ensure we have the corerct CUDA context set
+ NvFlexLibrary* lib = c->mFlexLib;
+
+ NvFlexAcquireContext(lib);
+
+ delete c;
+
+ NvFlexRestoreContext(lib);
+
+}
+
+int NvFlexExtAllocParticles(NvFlexExtContainer* c, int n, int* indices)
+{
+ const int numToAlloc = Min(int(c->mFreeList.size()), n);
+ const int start = int(c->mFreeList.size())-numToAlloc;
+
+ if (numToAlloc)
+ {
+ memcpy(indices, &c->mFreeList[start], numToAlloc*sizeof(int));
+ c->mFreeList.resize(start);
+ }
+
+ c->mNeedsActiveListRebuild = true;
+
+ return numToAlloc;
+}
+
+void NvFlexExtFreeParticles(NvFlexExtContainer* c, int n, const int* indices)
+{
+#if _DEBUG
+ for (int i=0; i < n; ++i)
+ {
+ // check valid values
+ assert(indices[i] >= 0 && indices[i] < int(c->mFreeList.capacity()));
+
+ // check for double delete
+ assert(std::find(c->mFreeList.begin(), c->mFreeList.end(), indices[i]) == c->mFreeList.end());
+ }
+#endif
+
+ c->mFreeList.insert(c->mFreeList.end(), indices, indices+n);
+
+ c->mNeedsActiveListRebuild = true;
+}
+
+int NvFlexExtGetActiveList(NvFlexExtContainer* c, int* indices)
+{
+ int count = 0;
+
+ Bitmap inactive(c->mMaxParticles);
+
+ // create bitmap
+ for (size_t i=0; i < c->mFreeList.size(); ++i)
+ {
+ // if this fires then somehow a duplicate has ended up in the free list (double delete)
+ assert(!inactive.IsSet(c->mFreeList[i]));
+
+ inactive.Set(c->mFreeList[i]);
+ }
+
+ // iterate bitmap to find active elements
+ for (int i=0; i < c->mMaxParticles; ++i)
+ if (inactive.IsSet(i) == false)
+ indices[count++] = i;
+
+ return count;
+}
+
+NvFlexExtParticleData NvFlexExtMapParticleData(NvFlexExtContainer* c)
+{
+ NvFlexExtParticleData data;
+
+ c->mParticles.map();
+ c->mParticlesRest.map();
+ c->mVelocities.map();
+ c->mPhases.map();
+ c->mNormals.map();
+
+ c->mBoundsLower.map();
+ c->mBoundsUpper.map();
+
+ if (c->mParticles.size())
+ data.particles = (float*)&c->mParticles[0];
+
+ if (c->mParticlesRest.size())
+ data.restParticles = (float*)&c->mParticlesRest[0];
+
+ if (c->mVelocities.size())
+ data.velocities = (float*)&c->mVelocities[0];
+
+ if (c->mPhases.size())
+ data.phases = (int*)&c->mPhases[0];
+
+ if (c->mNormals.size())
+ data.normals = (float*)&c->mNormals[0];
+
+ data.lower = c->mBoundsLower[0];
+ data.upper = c->mBoundsUpper[0];
+
+ return data;
+}
+
+void NvFlexExtUnmapParticleData(NvFlexExtContainer*c)
+{
+ c->mParticles.unmap();
+ c->mParticlesRest.unmap();
+ c->mVelocities.unmap();
+ c->mPhases.unmap();
+ c->mNormals.unmap();
+
+ c->mBoundsLower.unmap();
+ c->mBoundsUpper.unmap();
+}
+
+NvFlexExtTriangleData NvFlexExtMapTriangleData(NvFlexExtContainer* c)
+{
+ NvFlexExtTriangleData data;
+
+ c->mTriangleIndices.map();
+ c->mTriangleNormals.map();
+
+ if (c->mTriangleIndices.size())
+ data.indices = &c->mTriangleIndices[0];
+
+ if (c->mTriangleNormals.size())
+ data.normals = (float*)&c->mTriangleNormals[0];
+
+ return data;
+}
+
+void NvFlexExtUnmapTriangleData(NvFlexExtContainer* c)
+{
+ c->mTriangleIndices.unmap();
+ c->mTriangleNormals.unmap();
+}
+
+NvFlexExtShapeData NvFlexExtMapShapeData(NvFlexExtContainer* c)
+{
+ NvFlexExtShapeData data;
+
+ c->mShapeRotations.map();
+ c->mShapeTranslations.map();
+
+ if (c->mShapeRotations.size())
+ data.rotations = (float*)&c->mShapeRotations[0];
+
+ if (c->mShapeTranslations.size())
+ data.positions = (float*)&c->mShapeTranslations[0];
+
+ return data;
+}
+
+void NvFlexExtUnmapShapeData(NvFlexExtContainer* c)
+{
+ c->mShapeRotations.unmap();
+ c->mShapeTranslations.unmap();
+}
+
+
+NvFlexExtInstance* NvFlexExtCreateInstance(NvFlexExtContainer* c, NvFlexExtParticleData* particleData, const NvFlexExtAsset* asset, const float* transform, float vx, float vy, float vz, int phase, float invMassScale)
+{
+ const int numParticles = asset->numParticles;
+
+ // check if asset will fit
+ if (int(c->mFreeList.size()) < numParticles)
+ return NULL;
+
+ NvFlexExtInstance* inst = new NvFlexExtInstance();
+
+ inst->asset = asset;
+ inst->triangleIndex = -1;
+ inst->shapeIndex = -1;
+ inst->inflatableIndex = -1;
+ inst->userData = NULL;
+ inst->numParticles = numParticles;
+
+ assert(inst->numParticles <= asset->maxParticles);
+
+ // allocate particles for instance
+ inst->particleIndices = new int[asset->maxParticles];
+ int n = NvFlexExtAllocParticles(c, numParticles, &inst->particleIndices[0]);
+ assert(n == numParticles);
+ (void)n;
+
+ c->mInstances.push_back(inst);
+
+ const Matrix44 xform(transform);
+
+ for (int i=0; i < numParticles; ++i)
+ {
+ const int index = inst->particleIndices[i];
+
+ // add transformed particles to the locked particle data
+ ((Vec4*)(particleData->particles))[index] = xform*Vec4(Vec3(&asset->particles[i*4]), 1.0f);
+ ((Vec4*)(particleData->particles))[index].w = asset->particles[i*4+3]*invMassScale;
+ ((Vec4*)(particleData->restParticles))[index] = Vec4(&asset->particles[i*4]);
+
+ ((Vec3*)(particleData->velocities))[index] = Vec3(vx, vy, vz);
+ ((int*)(particleData->phases))[index] = phase;
+ ((Vec4*)(particleData->normals))[index] = Vec4(0.0f);
+ }
+
+ const int numShapes = asset->numShapes;
+
+ // allocate memory for shape transforms
+ Vec3* shapeTranslations = new Vec3[numShapes];
+ Quat* shapeRotations = new Quat[numShapes];
+
+ Quat rotation = Quat(Matrix33(xform.GetAxis(0), xform.GetAxis(1), xform.GetAxis(2)));
+
+ for (int i=0; i < numShapes; ++i)
+ {
+ shapeTranslations[i] = Vec3(xform*Vec4(asset->shapeCenters[i*3+0], asset->shapeCenters[i*3+1], asset->shapeCenters[i*3+2], 1.0));
+ shapeRotations[i] = rotation;
+ }
+
+ inst->shapeTranslations = (float*)shapeTranslations;
+ inst->shapeRotations = (float*)shapeRotations;
+
+ // mark container as dirty
+ c->mNeedsCompact = true;
+ c->mNeedsActiveListRebuild = true;
+
+ return inst;
+}
+
+void NvFlexExtDestroyInstance(NvFlexExtContainer* c, const NvFlexExtInstance* inst)
+{
+ NvFlexExtFreeParticles(c, inst->numParticles, &inst->particleIndices[0]);
+ delete[] inst->particleIndices;
+
+ delete[] inst->shapeRotations;
+ delete[] inst->shapeTranslations;
+
+ // TODO: O(N) remove
+ std::vector<NvFlexExtInstance*>::iterator iter = std::find(c->mInstances.begin(), c->mInstances.end(), inst);
+ assert(iter != c->mInstances.end());
+ c->mInstances.erase(iter);
+
+ c->mNeedsCompact = true;
+ c->mNeedsActiveListRebuild = true;
+
+ delete inst;
+}
+
+void NvFlexExtTickContainer(NvFlexExtContainer* c, float dt, int substeps, bool enableTiming)
+{
+ // update the device
+ NvFlexExtPushToDevice(c);
+
+ // update solver
+ NvFlexUpdateSolver(c->mSolver, dt, substeps, enableTiming);
+
+ // update host
+ NvFlexExtPullFromDevice(c);
+}
+
+void NvFlexExtNotifyAssetChanged(NvFlexExtContainer* c, const NvFlexExtAsset* asset)
+{
+ c->mNeedsCompact = true;
+}
+
+void NvFlexExtPushToDevice(NvFlexExtContainer* c)
+{
+ if (c->mNeedsActiveListRebuild)
+ {
+ // update active list
+ c->mActiveList.map();
+ int n = NvFlexExtGetActiveList(c, &c->mActiveList[0]);
+ c->mActiveList.unmap();
+
+ NvFlexSetActive(c->mSolver, c->mActiveList.buffer, n);
+
+ c->mNeedsActiveListRebuild = false;
+ }
+
+ // push any changes to solver
+ NvFlexSetParticles(c->mSolver, c->mParticles.buffer, int(c->mParticles.size()));
+ NvFlexSetRestParticles(c->mSolver, c->mParticlesRest.buffer, int(c->mParticlesRest.size()));
+
+ NvFlexSetVelocities(c->mSolver, c->mVelocities.buffer, int(c->mVelocities.size()));
+ NvFlexSetPhases(c->mSolver, c->mPhases.buffer, int(c->mPhases.size()));
+ NvFlexSetNormals(c->mSolver, c->mNormals.buffer, int(c->mNormals.size()));
+
+ if (c->mNeedsCompact)
+ CompactObjects(c);
+}
+
+void NvFlexExtPullFromDevice(NvFlexExtContainer* c)
+{
+
+ // read back particle data
+ NvFlexGetParticles(c->mSolver, c->mParticles.buffer, int(c->mParticles.size()));
+ NvFlexGetVelocities(c->mSolver, c->mVelocities.buffer, int(c->mVelocities.size()));
+ NvFlexGetPhases(c->mSolver, c->mPhases.buffer, int(c->mPhases.size()));
+ NvFlexGetNormals(c->mSolver, c->mNormals.buffer, int(c->mNormals.size()));
+ NvFlexGetBounds(c->mSolver, c->mBoundsLower.buffer, c->mBoundsUpper.buffer);
+
+ // read back shape transforms
+ if (c->mShapeCoefficients.size())
+ NvFlexGetRigidTransforms(c->mSolver, c->mShapeRotations.buffer, c->mShapeTranslations.buffer);
+
+}
+
+void NvFlexExtUpdateInstances(NvFlexExtContainer* c)
+{
+ c->mShapeTranslations.map();
+ c->mShapeRotations.map();
+
+ for (int i=0; i < int(c->mInstances.size()); ++i)
+ {
+ NvFlexExtInstance* inst = c->mInstances[i];
+
+ // copy data back to per-instance memory from the container's memory
+ const int numShapes = inst->asset->numShapes;
+ const int shapeStart = inst->shapeIndex;
+
+ if (shapeStart == -1)
+ continue;
+
+ for (int s=0; s < numShapes; ++s)
+ {
+ ((Vec3*)inst->shapeTranslations)[s] = c->mShapeTranslations[shapeStart + s];
+ ((Quat*)inst->shapeRotations)[s] = c->mShapeRotations[shapeStart + s];
+ }
+ }
+
+ c->mShapeTranslations.unmap();
+ c->mShapeRotations.unmap();
+}
+
+void NvFlexExtDestroyAsset(NvFlexExtAsset* asset)
+{
+ delete[] asset->particles;
+ delete[] asset->springIndices;
+ delete[] asset->springCoefficients;
+ delete[] asset->springRestLengths;
+ delete[] asset->triangleIndices;
+ delete[] asset->shapeIndices;
+ delete[] asset->shapeOffsets;
+ delete[] asset->shapeCenters;
+ delete[] asset->shapeCoefficients;
+
+ delete asset;
+}
+
+