aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/authoringCommon/source
diff options
context:
space:
mode:
authorbgaldrikian <[email protected]>2018-10-03 17:51:20 -0700
committerbgaldrikian <[email protected]>2018-10-03 17:51:20 -0700
commit6f51c0ad55f3ed33597b8b12391d426fe28a0923 (patch)
treeb132a8cb2485820ff9556dafc8e874bc9d41f255 /sdk/extensions/authoringCommon/source
parentFixes to UnitySample to make it build & run. ( In Unity 2018.2 ) (diff)
downloadblast-1.1.4_rc1.tar.xz
blast-1.1.4_rc1.zip
Blast 1.1.4. See docs/release_notes.txt.v1.1.4_rc1
Diffstat (limited to 'sdk/extensions/authoringCommon/source')
-rw-r--r--sdk/extensions/authoringCommon/source/NvBlastExtAuthoringAccelerator.cpp654
-rw-r--r--sdk/extensions/authoringCommon/source/NvBlastExtAuthoringInternalCommon.h265
-rw-r--r--sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.cpp358
-rw-r--r--sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.h200
4 files changed, 1477 insertions, 0 deletions
diff --git a/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringAccelerator.cpp b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringAccelerator.cpp
new file mode 100644
index 0000000..20ff78b
--- /dev/null
+++ b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringAccelerator.cpp
@@ -0,0 +1,654 @@
+// 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) 2016-2018 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastExtAuthoringAccelerator.h"
+#include "NvBlastExtAuthoringMesh.h"
+#include "NvBlastExtAuthoringInternalCommon.h"
+#include "NvBlastGlobals.h"
+
+using namespace physx;
+
+
+namespace Nv
+{
+namespace Blast
+{
+
+DummyAccelerator::DummyAccelerator(int32_t count) :count(count)
+{
+ current = 0;
+}
+void DummyAccelerator::setState(const Vertex* pos, const Edge* ed, const Facet& fc)
+{
+ current = 0;
+ NV_UNUSED(pos);
+ NV_UNUSED(ed);
+ NV_UNUSED(fc);
+}
+void DummyAccelerator::setState(const physx::PxBounds3* bound) {
+ current = 0;
+ NV_UNUSED(bound);
+}
+
+void DummyAccelerator::setState(const physx::PxVec3& point) {
+ current = 0;
+ NV_UNUSED(point);
+}
+int32_t DummyAccelerator::getNextFacet()
+{
+ if (current < count)
+ {
+ ++current;
+ return current - 1;
+ }
+ else
+ return -1;
+}
+
+Grid::Grid(int32_t resolution) : mResolution(resolution)
+{
+ /**
+ Set up 3d grid
+ */
+ r3 = resolution * resolution * resolution;
+ mSpatialMap.resize(resolution * resolution * resolution);
+}
+
+void Grid::setMesh(const Mesh* m)
+{
+ physx::PxBounds3 bd = m->getBoundingBox();
+ mappedFacetCount = m->getFacetCount();
+ bd.fattenFast(0.001f);
+ spos = bd.minimum;
+ deltas = PxVec3(mResolution / bd.getDimensions().x, mResolution / bd.getDimensions().y, mResolution / bd.getDimensions().z);
+
+ for (int32_t i = 0; i < r3; ++i)
+ mSpatialMap[i].clear();
+
+ const float ofs = 0.001f;
+
+ for (uint32_t fc = 0; fc < m->getFacetCount(); ++fc)
+ {
+ physx::PxBounds3 cfc = *m->getFacetBound(fc);
+
+ int32_t is = std::max(0.f, (cfc.minimum.x - spos.x - ofs) * deltas.x);
+ int32_t ie = std::max(0.f, (cfc.maximum.x - spos.x + ofs) * deltas.x);
+
+ int32_t js = std::max(0.f, (cfc.minimum.y - spos.y - ofs) * deltas.y);
+ int32_t je = std::max(0.f, (cfc.maximum.y - spos.y + ofs) * deltas.y);
+
+ int32_t ks = std::max(0.f, (cfc.minimum.z - spos.z - ofs) * deltas.z);
+ int32_t ke = std::max(0.f, (cfc.maximum.z - spos.z + ofs) * deltas.z);
+
+ for (int32_t i = is; i < mResolution && i <= ie; ++i)
+ {
+ for (int32_t j = js; j < mResolution && j <= je; ++j)
+ {
+ for (int32_t k = ks; k < mResolution && k <= ke; ++k)
+ {
+ mSpatialMap[(i * mResolution + j) * mResolution + k].push_back(fc);
+ }
+ }
+ }
+ }
+}
+
+
+GridWalker::GridWalker(Grid* grd)
+{
+ mGrid = grd;
+ alreadyGotValue = 0;
+ alreadyGotFlag.resize(1 << 12);
+ cellList.resize(1 << 12);
+ pointCmdDir = 0;
+}
+
+void GridWalker::setState(const Vertex* pos, const Edge* ed, const Facet& fc)
+{
+
+ physx::PxBounds3 cfc(PxBounds3::empty());
+
+ for (uint32_t v = 0; v < fc.edgesCount; ++v)
+ {
+ cfc.include(pos[ed[fc.firstEdgeNumber + v].s].p);
+ cfc.include(pos[ed[fc.firstEdgeNumber + v].e].p);
+ }
+ setState(&cfc);
+}
+
+void GridWalker::setState(const PxBounds3* facetBounding)
+{
+ alreadyGotValue++;
+ mIteratorCell = -1;
+ mIteratorFacet = -1;
+ gotCells = 0;
+
+ physx::PxBounds3 cfc = *facetBounding;
+
+
+
+ int32_t is = std::max(0.f, (cfc.minimum.x - mGrid->spos.x - 0.001f) * mGrid->deltas.x);
+ int32_t ie = std::max(0.f, (cfc.maximum.x - mGrid->spos.x + 0.001f) * mGrid->deltas.x);
+
+ int32_t js = std::max(0.f, (cfc.minimum.y - mGrid->spos.y - 0.001f) * mGrid->deltas.y);
+ int32_t je = std::max(0.f, (cfc.maximum.y - mGrid->spos.y + 0.001f) * mGrid->deltas.y);
+
+ int32_t ks = std::max(0.f, (cfc.minimum.z - mGrid->spos.z - 0.001f) * mGrid->deltas.z);
+ int32_t ke = std::max(0.f, (cfc.maximum.z - mGrid->spos.z + 0.001f) * mGrid->deltas.z);
+
+ for (int32_t i = is; i < mGrid->mResolution && i <= ie; ++i)
+ {
+ for (int32_t j = js; j < mGrid->mResolution && j <= je; ++j)
+ {
+ for (int32_t k = ks; k < mGrid->mResolution && k <= ke; ++k)
+ {
+ int32_t id = (i * mGrid->mResolution + j) * mGrid->mResolution + k;
+ if (!mGrid->mSpatialMap[id].empty())
+ {
+ cellList[gotCells++] = id;
+ }
+
+ }
+ }
+ }
+ if (gotCells != 0)
+ {
+ mIteratorFacet = 0;
+ mIteratorCell = cellList[gotCells - 1];
+ gotCells--;
+ }
+}
+
+
+void GridWalker::setPointCmpDirection(int32_t d)
+{
+ pointCmdDir = d;
+}
+
+
+void GridWalker::setState(const physx::PxVec3& point)
+{
+ alreadyGotValue++;
+ mIteratorCell = -1;
+ mIteratorFacet = -1;
+ gotCells = 0;
+
+ int32_t is = std::max(0.f, (point.x - mGrid->spos.x - 0.001f) * mGrid->deltas.x);
+ int32_t ie = std::max(0.f, (point.x - mGrid->spos.x + 0.001f) * mGrid->deltas.x);
+
+ int32_t js = std::max(0.f, (point.y - mGrid->spos.y - 0.001f) * mGrid->deltas.y);
+ int32_t je = std::max(0.f, (point.y - mGrid->spos.y + 0.001f) * mGrid->deltas.y);
+
+ int32_t ks = 0;
+ int32_t ke = mGrid->mResolution;
+ switch (pointCmdDir)
+ {
+ case 1:
+ ks = std::max(0.f, (point.z - mGrid->spos.z - 0.001f) * mGrid->deltas.z);
+ break;
+ case -1:
+ ke = std::max(0.f, (point.z - mGrid->spos.z + 0.001f) * mGrid->deltas.z);
+ }
+
+ for (int32_t i = is; i < mGrid->mResolution && i <= ie; ++i)
+ {
+ for (int32_t j = js; j < mGrid->mResolution && j <= je; ++j)
+ {
+ for (int32_t k = ks; k <= ke && k < mGrid->mResolution; ++k)
+ {
+ int32_t id = (i * mGrid->mResolution + j) * mGrid->mResolution + k;
+ if (!mGrid->mSpatialMap[id].empty())
+ {
+ cellList[gotCells++] = id;
+ }
+ }
+ }
+ }
+
+ if (gotCells != 0)
+ {
+ mIteratorFacet = 0;
+ mIteratorCell = cellList[gotCells - 1];
+ gotCells--;
+ }
+}
+int32_t GridWalker::getNextFacet()
+{
+ int32_t facetId = -1;
+
+ while (mIteratorCell != -1)
+ {
+ if (mIteratorFacet >= (int32_t)mGrid->mSpatialMap[mIteratorCell].size())
+ {
+ if (gotCells != 0)
+ {
+ mIteratorCell = cellList[gotCells - 1];
+ gotCells--;
+ mIteratorFacet = 0;
+ }
+ else
+ {
+ mIteratorCell = -1;
+ break;
+ }
+ }
+ if (alreadyGotFlag[mGrid->mSpatialMap[mIteratorCell][mIteratorFacet]] != alreadyGotValue)
+ {
+ facetId = mGrid->mSpatialMap[mIteratorCell][mIteratorFacet];
+ mIteratorFacet++;
+ break;
+ }
+ else
+ {
+ mIteratorFacet++;
+ }
+ }
+ if (facetId != -1)
+ {
+ alreadyGotFlag[facetId] = alreadyGotValue;
+ }
+ return facetId;
+}
+
+
+
+BBoxBasedAccelerator::BBoxBasedAccelerator(const Mesh* mesh, int32_t resolution) : mResolution(resolution), alreadyGotValue(1)
+{
+ mBounds = mesh->getBoundingBox();
+ mSpatialMap.resize(resolution * resolution * resolution);
+ mCells.resize(resolution * resolution * resolution);
+ int32_t currentCell = 0;
+ PxVec3 incr = (mBounds.maximum - mBounds.minimum) * (1.0f / mResolution);
+ for (int32_t z = 0; z < resolution; ++z)
+ {
+ for (int32_t y = 0; y < resolution; ++y)
+ {
+ for (int32_t x = 0; x < resolution; ++x)
+ {
+ mCells[currentCell].minimum.x = mBounds.minimum.x + x * incr.x;
+ mCells[currentCell].minimum.y = mBounds.minimum.y + y * incr.y;
+ mCells[currentCell].minimum.z = mBounds.minimum.z + z * incr.z;
+
+ mCells[currentCell].maximum.x = mBounds.minimum.x + (x + 1) * incr.x;
+ mCells[currentCell].maximum.y = mBounds.minimum.y + (y + 1) * incr.y;
+ mCells[currentCell].maximum.z = mBounds.minimum.z + (z + 1) * incr.z;
+
+ ++currentCell;
+ }
+ }
+ }
+ cellList.resize(1 << 16);
+ gotCells = 0;
+ buildAccelStructure(mesh->getVertices(), mesh->getEdges(), mesh->getFacetsBuffer(), mesh->getFacetCount());
+}
+
+
+BBoxBasedAccelerator::~BBoxBasedAccelerator()
+{
+ mResolution = 0;
+ mBounds.setEmpty();
+ mSpatialMap.clear();
+ mCells.clear();
+ cellList.clear();
+}
+
+int32_t BBoxBasedAccelerator::getNextFacet()
+{
+ int32_t facetId = -1;
+
+ while (mIteratorCell != -1)
+ {
+ if (mIteratorFacet >= (int32_t)mSpatialMap[mIteratorCell].size())
+ {
+ if (gotCells != 0)
+ {
+ mIteratorCell = cellList[gotCells - 1];
+ gotCells--;
+ mIteratorFacet = 0;
+ }
+ else
+ {
+ mIteratorCell = -1;
+ break;
+ }
+ }
+ if (alreadyGotFlag[mSpatialMap[mIteratorCell][mIteratorFacet]] != alreadyGotValue)
+ {
+ facetId = mSpatialMap[mIteratorCell][mIteratorFacet];
+ mIteratorFacet++;
+ break;
+ }
+ else
+ {
+ mIteratorFacet++;
+ }
+ }
+ if (facetId != -1)
+ {
+ alreadyGotFlag[facetId] = alreadyGotValue;
+ }
+ return facetId;
+}
+
+
+void BBoxBasedAccelerator::setState(const Vertex* pos, const Edge* ed, const Facet& fc)
+{
+
+ physx::PxBounds3 cfc(PxBounds3::empty());
+
+ for (uint32_t v = 0; v < fc.edgesCount; ++v)
+ {
+ cfc.include(pos[ed[fc.firstEdgeNumber + v].s].p);
+ cfc.include(pos[ed[fc.firstEdgeNumber + v].e].p);
+ }
+ setState(&cfc);
+}
+
+void BBoxBasedAccelerator::setState(const PxBounds3* facetBox)
+{
+ alreadyGotValue++;
+ mIteratorCell = -1;
+ mIteratorFacet = -1;
+ gotCells = 0;
+
+ for (uint32_t i = 0; i < mCells.size(); ++i)
+ {
+ if (weakBoundingBoxIntersection(mCells[i], *facetBox))
+ {
+ if (!mSpatialMap[i].empty())
+ cellList[gotCells++] = i;
+ }
+ }
+ if (gotCells != 0)
+ {
+ mIteratorFacet = 0;
+ mIteratorCell = cellList[gotCells - 1];
+ gotCells--;
+ }
+}
+
+
+void BBoxBasedAccelerator::setState(const PxVec3& p)
+{
+ alreadyGotValue++;
+ mIteratorCell = -1;
+ mIteratorFacet = -1;
+ gotCells = 0;
+ int32_t perSlice = mResolution * mResolution;
+ for (uint32_t i = 0; i < mCells.size(); ++i)
+ {
+ if (mCells[i].contains(p))
+ {
+ int32_t xyCellId = i % perSlice;
+ for (int32_t zCell = 0; zCell < mResolution; ++zCell)
+ {
+ int32_t cell = zCell * perSlice + xyCellId;
+ if (!mSpatialMap[cell].empty())
+ cellList[gotCells++] = cell;
+ }
+ }
+ }
+ if (gotCells != 0)
+ {
+ mIteratorFacet = 0;
+ mIteratorCell = cellList[gotCells - 1];
+ gotCells--;
+ }
+}
+
+
+void BBoxBasedAccelerator::buildAccelStructure(const Vertex* pos, const Edge* edges, const Facet* fc, int32_t facetCount)
+{
+ for (int32_t facet = 0; facet < facetCount; ++facet)
+ {
+ PxBounds3 bBox;
+ bBox.setEmpty();
+ const Edge* edge = &edges[0] + fc->firstEdgeNumber;
+ int32_t count = fc->edgesCount;
+ for (int32_t ec = 0; ec < count; ++ec)
+ {
+ bBox.include(pos[edge->s].p);
+ bBox.include(pos[edge->e].p);
+ edge++;
+ }
+
+ for (uint32_t i = 0; i < mCells.size(); ++i)
+ {
+ if (weakBoundingBoxIntersection(mCells[i], bBox))
+ {
+ mSpatialMap[i].push_back(facet);
+ }
+ }
+ fc++;
+ }
+ alreadyGotFlag.resize(facetCount, 0);
+}
+
+#define SWEEP_RESOLUTION 2048
+
+void buildIndex(std::vector<SegmentToIndex>& segm, float offset, float mlt, std::vector<std::vector<uint32_t>>& blocks)
+{
+ std::set<uint32_t> currentEnabled;
+ uint32_t lastBlock = 0;
+ for (uint32_t i = 0; i < segm.size(); ++i)
+ {
+ uint32_t currentBlock = (segm[i].coord - offset) * mlt;
+ if (currentBlock >= SWEEP_RESOLUTION) break;
+ if (currentBlock != lastBlock)
+ {
+ for (uint32_t j = lastBlock + 1; j <= currentBlock; ++j)
+ {
+ for (auto id : currentEnabled)
+ blocks[j].push_back(id);
+ }
+ lastBlock = currentBlock;
+ }
+ if (segm[i].end == false)
+ {
+ blocks[lastBlock].push_back(segm[i].index);
+ currentEnabled.insert(segm[i].index);
+ }
+ else
+ {
+ currentEnabled.erase(segm[i].index);
+ }
+ }
+
+}
+
+
+SweepingAccelerator::SweepingAccelerator(Nv::Blast::Mesh* in)
+{
+ PxBounds3 bnd;
+
+ const Vertex* verts = in->getVertices();
+ const Edge* edges = in->getEdges();
+
+ facetCount = in->getFacetCount();
+
+ foundx.resize(facetCount, 0);
+ foundy.resize(facetCount, 0);
+
+
+ std::vector<SegmentToIndex> xevs;
+ std::vector<SegmentToIndex> yevs;
+ std::vector<SegmentToIndex> zevs;
+
+
+ for (uint32_t i = 0; i < in->getFacetCount(); ++i)
+ {
+ const Facet* fc = in->getFacet(i);
+ bnd.setEmpty();
+ for (uint32_t v = 0; v < fc->edgesCount; ++v)
+ {
+ bnd.include(verts[edges[v + fc->firstEdgeNumber].s].p);
+ }
+ bnd.scaleFast(1.1f);
+ xevs.push_back(SegmentToIndex(bnd.minimum.x, i, false));
+ xevs.push_back(SegmentToIndex(bnd.maximum.x, i, true));
+
+ yevs.push_back(SegmentToIndex(bnd.minimum.y, i, false));
+ yevs.push_back(SegmentToIndex(bnd.maximum.y, i, true));
+
+ zevs.push_back(SegmentToIndex(bnd.minimum.z, i, false));
+ zevs.push_back(SegmentToIndex(bnd.maximum.z, i, true));
+
+ }
+
+ std::sort(xevs.begin(), xevs.end());
+ std::sort(yevs.begin(), yevs.end());
+ std::sort(zevs.begin(), zevs.end());
+
+
+ minimal.x = xevs[0].coord;
+ minimal.y = yevs[0].coord;
+ minimal.z = zevs[0].coord;
+
+
+ maximal.x = xevs.back().coord;
+ maximal.y = yevs.back().coord;
+ maximal.z = zevs.back().coord;
+
+
+ rescale = (maximal - minimal) * 1.01f;
+ rescale.x = 1.0f / rescale.x * SWEEP_RESOLUTION;
+ rescale.y = 1.0f / rescale.y * SWEEP_RESOLUTION;
+ rescale.z = 1.0f / rescale.z * SWEEP_RESOLUTION;
+
+ xSegm.resize(SWEEP_RESOLUTION);
+ ySegm.resize(SWEEP_RESOLUTION);
+ zSegm.resize(SWEEP_RESOLUTION);
+
+
+ buildIndex(xevs, minimal.x, rescale.x, xSegm);
+ buildIndex(yevs, minimal.y, rescale.y, ySegm);
+ buildIndex(zevs, minimal.z, rescale.z, zSegm);
+
+
+ iterId = 1;
+ current = 0;
+}
+
+void SweepingAccelerator::setState(const PxBounds3* facetBounds)
+{
+ current = 0;
+ indices.clear();
+
+ PxBounds3 bnd = *facetBounds;
+
+ bnd.scaleFast(1.1);
+ uint32_t start = (std::max(0.0f, bnd.minimum.x - minimal.x)) * rescale.x;
+ uint32_t end = (std::max(0.0f, bnd.maximum.x - minimal.x)) * rescale.x;
+ for (uint32_t i = start; i <= end && i < SWEEP_RESOLUTION; ++i)
+ {
+ for (auto id : xSegm[i])
+ {
+ foundx[id] = iterId;
+ }
+ }
+ start = (std::max(0.0f, bnd.minimum.y - minimal.y)) * rescale.y;
+ end = (std::max(0.0f, bnd.maximum.y - minimal.y)) * rescale.y;
+ for (uint32_t i = start; i <= end && i < SWEEP_RESOLUTION; ++i)
+ {
+ for (auto id : ySegm[i])
+ {
+ foundy[id] = iterId;
+ }
+ }
+ start = (std::max(0.0f, bnd.minimum.z - minimal.z)) * rescale.z;
+ end = (std::max(0.0f, bnd.maximum.z - minimal.z)) * rescale.z;
+ for (uint32_t i = start; i <= end && i < SWEEP_RESOLUTION; ++i)
+ {
+ for (auto id : zSegm[i])
+ {
+ if (foundy[id] == iterId && foundx[id] == iterId)
+ {
+ foundx[id] = iterId + 1;
+ foundy[id] = iterId + 1;
+ indices.push_back(id);
+ }
+ }
+ }
+
+ iterId += 2;
+}
+
+void SweepingAccelerator::setState(const Vertex* pos, const Edge* ed, const Facet& fc)
+{
+
+ physx::PxBounds3 cfc(PxBounds3::empty());
+
+ for (uint32_t v = 0; v < fc.edgesCount; ++v)
+ {
+ cfc.include(pos[ed[fc.firstEdgeNumber + v].s].p);
+ cfc.include(pos[ed[fc.firstEdgeNumber + v].e].p);
+ }
+ setState(&cfc);
+}
+
+
+void SweepingAccelerator::setState(const physx::PxVec3& point) {
+
+ indices.clear();
+
+ /*for (uint32_t i = 0; i < facetCount; ++i)
+ {
+ indices.push_back(i);
+ }*/
+
+ uint32_t xIndex = (point.x - minimal.x) * rescale.x;
+ uint32_t yIndex = (point.y- minimal.y) * rescale.y;
+
+ for (uint32_t i = 0; i < xSegm[xIndex].size(); ++i)
+ {
+ foundx[xSegm[xIndex][i]] = iterId;
+ }
+ for (uint32_t i = 0; i < ySegm[yIndex].size(); ++i)
+ {
+ if (foundx[ySegm[yIndex][i]] == iterId)
+ {
+ indices.push_back(ySegm[yIndex][i]);
+ }
+ }
+ iterId++;
+ current = 0;
+ NV_UNUSED(point);
+}
+int32_t SweepingAccelerator::getNextFacet()
+{
+ if (static_cast<uint32_t>(current) < indices.size())
+ {
+ ++current;
+ return indices[current - 1];
+ }
+ else
+ return -1;
+}
+
+} // namespace Blast
+} // namespace Nv
diff --git a/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringInternalCommon.h b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringInternalCommon.h
new file mode 100644
index 0000000..28d3349
--- /dev/null
+++ b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringInternalCommon.h
@@ -0,0 +1,265 @@
+// 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) 2018 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTINTERNALCOMMON_H
+#define NVBLASTINTERNALCOMMON_H
+#include "NvBlastExtAuthoringTypes.h"
+#include <algorithm>
+
+using namespace physx;
+
+namespace Nv
+{
+namespace Blast
+{
+
+/**
+Edge representation with index of parent facet
+*/
+struct EdgeWithParent
+{
+ uint32_t s, e; // Starting and ending vertices
+ uint32_t parent; // Parent facet index
+ EdgeWithParent() : s(0), e(0), parent(0) {}
+ EdgeWithParent(uint32_t s, uint32_t e, uint32_t p) : s(s), e(e), parent(p) {}
+};
+
+
+/**
+Comparator for sorting edges according to parent facet number.
+*/
+struct EdgeComparator
+{
+ bool operator()(const EdgeWithParent& a, const EdgeWithParent& b) const
+ {
+ if (a.parent == b.parent)
+ {
+ if (a.s == b.s)
+ {
+ return a.e < b.e;
+ }
+ else
+ {
+ return a.s < b.s;
+ }
+ }
+ else
+ {
+ return a.parent < b.parent;
+ }
+ }
+};
+
+
+/**
+Vertex projection direction flag.
+*/
+enum ProjectionDirections
+{
+ YZ_PLANE = 1 << 1,
+ XY_PLANE = 1 << 2,
+ ZX_PLANE = 1 << 3,
+
+ OPPOSITE_WINDING = 1 << 4
+};
+
+/**
+Computes best direction to project points.
+*/
+NV_FORCE_INLINE ProjectionDirections getProjectionDirection(const physx::PxVec3& normal)
+{
+ float maxv = std::max(std::abs(normal.x), std::max(std::abs(normal.y), std::abs(normal.z)));
+ ProjectionDirections retVal;
+ if (maxv == std::abs(normal.x))
+ {
+ retVal = YZ_PLANE;
+ if (normal.x < 0) retVal = (ProjectionDirections)((int)retVal | (int)OPPOSITE_WINDING);
+ return retVal;
+ }
+ if (maxv == std::abs(normal.y))
+ {
+ retVal = ZX_PLANE;
+ if (normal.y > 0) retVal = (ProjectionDirections)((int)retVal | (int)OPPOSITE_WINDING);
+ return retVal;
+ }
+ retVal = XY_PLANE;
+ if (normal.z < 0) retVal = (ProjectionDirections)((int)retVal | (int)OPPOSITE_WINDING);
+ return retVal;
+}
+
+
+/**
+Computes point projected on given axis aligned plane.
+*/
+NV_FORCE_INLINE physx::PxVec2 getProjectedPoint(const physx::PxVec3& point, ProjectionDirections dir)
+{
+ if (dir & YZ_PLANE)
+ {
+ return physx::PxVec2(point.y, point.z);
+ }
+ if (dir & ZX_PLANE)
+ {
+ return physx::PxVec2(point.x, point.z);
+ }
+ return physx::PxVec2(point.x, point.y);
+}
+
+/**
+Computes point projected on given axis aligned plane, this method is polygon-winding aware.
+*/
+NV_FORCE_INLINE physx::PxVec2 getProjectedPointWithWinding(const physx::PxVec3& point, ProjectionDirections dir)
+{
+ if (dir & YZ_PLANE)
+ {
+ if (dir & OPPOSITE_WINDING)
+ {
+ return physx::PxVec2(point.z, point.y);
+ }
+ else
+ return physx::PxVec2(point.y, point.z);
+ }
+ if (dir & ZX_PLANE)
+ {
+ if (dir & OPPOSITE_WINDING)
+ {
+ return physx::PxVec2(point.z, point.x);
+ }
+ return physx::PxVec2(point.x, point.z);
+ }
+ if (dir & OPPOSITE_WINDING)
+ {
+ return physx::PxVec2(point.y, point.x);
+ }
+ return physx::PxVec2(point.x, point.y);
+}
+
+
+
+#define MAXIMUM_EXTENT 1000 * 1000 * 1000
+#define BBOX_TEST_EPS 1e-5f
+
+/**
+Test fattened bounding box intersetion.
+*/
+NV_INLINE bool weakBoundingBoxIntersection(const physx::PxBounds3& aBox, const physx::PxBounds3& bBox)
+{
+ if (std::max(aBox.minimum.x, bBox.minimum.x) > std::min(aBox.maximum.x, bBox.maximum.x) + BBOX_TEST_EPS)
+ return false;
+ if (std::max(aBox.minimum.y, bBox.minimum.y) > std::min(aBox.maximum.y, bBox.maximum.y) + BBOX_TEST_EPS)
+ return false;
+ if (std::max(aBox.minimum.z, bBox.minimum.z) > std::min(aBox.maximum.z, bBox.maximum.z) + BBOX_TEST_EPS)
+ return false;
+ return true;
+}
+
+
+
+/**
+Test segment vs plane intersection. If segment intersects the plane true is returned. Point of intersection is written into 'result'.
+*/
+NV_INLINE bool getPlaneSegmentIntersection(const PxPlane& pl, const PxVec3& a, const PxVec3& b, PxVec3& result)
+{
+ float div = (b - a).dot(pl.n);
+ if (PxAbs(div) < 0.0001f)
+ {
+ if (pl.contains(a))
+ {
+ result = a;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ float t = (-a.dot(pl.n) - pl.d) / div;
+ if (t < 0.0f || t > 1.0f)
+ {
+ return false;
+ }
+ result = (b - a) * t + a;
+ return true;
+}
+
+
+#define POS_COMPARISON_OFFSET 1e-5f
+#define NORM_COMPARISON_OFFSET 1e-3f
+/**
+Vertex comparator for vertex welding.
+*/
+struct VrtComp
+{
+ bool operator()(const Vertex& a, const Vertex& b) const
+ {
+ if (a.p.x + POS_COMPARISON_OFFSET < b.p.x) return true;
+ if (a.p.x - POS_COMPARISON_OFFSET > b.p.x) return false;
+ if (a.p.y + POS_COMPARISON_OFFSET < b.p.y) return true;
+ if (a.p.y - POS_COMPARISON_OFFSET > b.p.y) return false;
+ if (a.p.z + POS_COMPARISON_OFFSET < b.p.z) return true;
+ if (a.p.z - POS_COMPARISON_OFFSET > b.p.z) return false;
+
+ if (a.n.x + NORM_COMPARISON_OFFSET < b.n.x) return true;
+ if (a.n.x - NORM_COMPARISON_OFFSET > b.n.x) return false;
+ if (a.n.y + NORM_COMPARISON_OFFSET < b.n.y) return true;
+ if (a.n.y - NORM_COMPARISON_OFFSET > b.n.y) return false;
+ if (a.n.z + NORM_COMPARISON_OFFSET < b.n.z) return true;
+ if (a.n.z - NORM_COMPARISON_OFFSET > b.n.z) return false;
+
+
+ if (a.uv[0].x + NORM_COMPARISON_OFFSET < b.uv[0].x) return true;
+ if (a.uv[0].x - NORM_COMPARISON_OFFSET > b.uv[0].x) return false;
+ if (a.uv[0].y + NORM_COMPARISON_OFFSET < b.uv[0].y) return true;
+ return false;
+ };
+};
+
+/**
+Vertex comparator for vertex welding (not accounts normal and uv parameters of vertice).
+*/
+struct VrtPositionComparator
+{
+ bool operator()(const physx::PxVec3& a, const physx::PxVec3& b) const
+ {
+ if (a.x + POS_COMPARISON_OFFSET < b.x) return true;
+ if (a.x - POS_COMPARISON_OFFSET > b.x) return false;
+ if (a.y + POS_COMPARISON_OFFSET < b.y) return true;
+ if (a.y - POS_COMPARISON_OFFSET > b.y) return false;
+ if (a.z + POS_COMPARISON_OFFSET < b.z) return true;
+ if (a.z - POS_COMPARISON_OFFSET > b.z) return false;
+ return false;
+ };
+ bool operator()(const Vertex& a, const Vertex& b) const
+ {
+ return operator()(a.p, b.p);
+ };
+};
+
+} // namespace Blast
+} // namespace Nv
+
+#endif \ No newline at end of file
diff --git a/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.cpp b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.cpp
new file mode 100644
index 0000000..f0c9a84
--- /dev/null
+++ b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.cpp
@@ -0,0 +1,358 @@
+// 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) 2016-2018 NVIDIA Corporation. All rights reserved.
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "NvBlastExtAuthoringMeshImpl.h"
+#include "NvBlastExtAuthoringTypes.h"
+#include <NvBlastAssert.h>
+#include "PxMath.h"
+#include <cmath>
+#include <string.h>
+#include <vector>
+#include <algorithm>
+
+using physx::PxVec2;
+using physx::PxVec3;
+using physx::PxBounds3;
+
+
+namespace Nv
+{
+namespace Blast
+{
+
+MeshImpl::MeshImpl(const PxVec3* position, const PxVec3* normals, const PxVec2* uv, uint32_t verticesCount, const uint32_t* indices, uint32_t indicesCount)
+{
+
+ mVertices.resize(verticesCount);
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mVertices[i].p = position[i];
+ }
+ if (normals != 0)
+ {
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mVertices[i].n = normals[i];
+ }
+
+ }
+ else
+ {
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mVertices[i].n = PxVec3(0, 0, 0);
+ }
+ }
+ if (uv != 0)
+ {
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mVertices[i].uv[0] = uv[i];
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mVertices[i].uv[0] = PxVec2(0, 0);
+ }
+ }
+ mEdges.resize(indicesCount);
+ mFacets.resize(indicesCount / 3);
+
+
+ int32_t facetId = 0;
+ for (uint32_t i = 0; i < indicesCount; i += 3)
+ {
+ mEdges[i].s = indices[i];
+ mEdges[i].e = indices[i + 1];
+
+ mEdges[i + 1].s = indices[i + 1];
+ mEdges[i + 1].e = indices[i + 2];
+
+ mEdges[i + 2].s = indices[i + 2];
+ mEdges[i + 2].e = indices[i];
+ mFacets[facetId].firstEdgeNumber = i;
+ mFacets[facetId].edgesCount = 3;
+ mFacets[facetId].materialId = 0;
+ //Unassigned for now
+ mFacets[facetId].smoothingGroup = -1;
+ facetId++;
+ }
+ recalculateBoundingBox();
+}
+
+MeshImpl::MeshImpl(const Vertex* vertices, const Edge* edges, const Facet* facets, uint32_t posCount, uint32_t edgesCount, uint32_t facetsCount)
+{
+ mVertices.resize(posCount);
+ mEdges.resize(edgesCount);
+ mFacets.resize(facetsCount);
+
+ memcpy(mVertices.data(), vertices, sizeof(Vertex) * posCount);
+ memcpy(mEdges.data(), edges, sizeof(Edge) * edgesCount);
+ memcpy(mFacets.data(), facets, sizeof(Facet) * facetsCount);
+ recalculateBoundingBox();
+}
+
+MeshImpl::MeshImpl(const Vertex* vertices, uint32_t count)
+{
+ mVertices = std::vector<Vertex>(vertices, vertices + count);
+ mEdges.resize(count);
+ mFacets.resize(count / 3);
+ uint32_t vp = 0;
+ for (uint32_t i = 0; i < count; i += 3)
+ {
+ mEdges[i].s = vp;
+ mEdges[i].e = vp + 1;
+
+ mEdges[i + 1].s = vp + 1;
+ mEdges[i + 1].e = vp + 2;
+
+ mEdges[i + 2].s = vp + 2;
+ mEdges[i + 2].e = vp;
+ vp += 3;
+ }
+ for (uint32_t i = 0; i < count / 3; ++i)
+ {
+ mFacets[i].edgesCount = 3;
+ mFacets[i].firstEdgeNumber = i * 3;
+ }
+ recalculateBoundingBox();
+}
+
+MeshImpl::MeshImpl(const Vertex* vertices, uint32_t count, uint32_t* indices, uint32_t indexCount, void* materials, uint32_t materialStride)
+{
+ mVertices = std::vector<Vertex>(vertices, vertices + count);
+ mEdges.resize(indexCount);
+ mFacets.resize(indexCount / 3);
+
+ for (uint32_t i = 0; i < indexCount; i += 3)
+ {
+ mEdges[i].s = indices[i];
+ mEdges[i].e = indices[i + 1];
+
+ mEdges[i + 1].s = indices[i + 1];
+ mEdges[i + 1].e = indices[i + 2];
+
+ mEdges[i + 2].s = indices[i + 2];
+ mEdges[i + 2].e = indices[i];
+ }
+ for (uint32_t i = 0; i < indexCount / 3; ++i)
+ {
+ mFacets[i].edgesCount = 3;
+ mFacets[i].firstEdgeNumber = i * 3;
+ mFacets[i].userData = 0;
+ if (materials != nullptr)
+ {
+ mFacets[i].materialId = *(uint32_t*)((uint8_t*)materials + i * materialStride);
+ }
+ }
+ recalculateBoundingBox();
+}
+
+
+
+float MeshImpl::getMeshVolume()
+{
+ /**
+ Check if mesh boundary consist only of triangles
+ */
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ if (mFacets[i].edgesCount != 3)
+ {
+ return 0.0f;
+ }
+ }
+
+ float volume = 0;
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ int32_t offset = mFacets[i].firstEdgeNumber;
+ PxVec3& a = mVertices[mEdges[offset].s].p;
+ PxVec3& b = mVertices[mEdges[offset + 1].s].p;
+ PxVec3& c = mVertices[mEdges[offset + 2].s].p;
+
+ volume += (a.x * b.y * c.z - a.x * b.z * c.y - a.y * b.x * c.z + a.y * b.z * c.x + a.z * b.x * c.y - a.z * b.y * c.x);
+ }
+ return (1.0f / 6.0f) * std::abs(volume);
+}
+
+
+uint32_t MeshImpl::getFacetCount() const
+{
+ return static_cast<uint32_t>(mFacets.size());
+}
+
+Vertex* MeshImpl::getVerticesWritable()
+{
+ return mVertices.data();
+}
+
+Edge* MeshImpl::getEdgesWritable()
+{
+ return mEdges.data();
+}
+
+const Vertex* MeshImpl::getVertices() const
+{
+ return mVertices.data();
+}
+
+const Edge* MeshImpl::getEdges() const
+{
+ return mEdges.data();
+}
+
+uint32_t MeshImpl::getEdgesCount() const
+{
+ return static_cast<uint32_t>(mEdges.size());
+}
+uint32_t MeshImpl::getVerticesCount() const
+{
+ return static_cast<uint32_t>(mVertices.size());
+}
+Facet* MeshImpl::getFacetsBufferWritable()
+{
+ return mFacets.data();
+}
+const Facet* MeshImpl::getFacetsBuffer() const
+{
+ return mFacets.data();
+}
+Facet* MeshImpl::getFacetWritable(int32_t facet)
+{
+ return &mFacets[facet];
+}
+const Facet* MeshImpl::getFacet(int32_t facet) const
+{
+ return &mFacets[facet];
+}
+
+MeshImpl::~MeshImpl()
+{
+}
+
+void MeshImpl::release()
+{
+ delete this;
+}
+
+const PxBounds3& MeshImpl::getBoundingBox() const
+{
+ return mBounds;
+}
+
+PxBounds3& MeshImpl::getBoundingBoxWritable()
+{
+ return mBounds;
+}
+
+
+void MeshImpl::recalculateBoundingBox()
+{
+ mBounds.setEmpty();
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mBounds.include(mVertices[i].p);
+ }
+ calcPerFacetBounds();
+}
+
+const physx::PxBounds3* MeshImpl::getFacetBound(uint32_t index) const
+{
+ if (mPerFacetBounds.empty())
+ {
+ return nullptr;
+ }
+ return &mPerFacetBounds[index];
+}
+
+void MeshImpl::calcPerFacetBounds()
+{
+ mPerFacetBounds.resize(mFacets.size());
+
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ auto& fb = mPerFacetBounds[i];
+ fb.setEmpty();
+
+ for (uint32_t v = 0; v < mFacets[i].edgesCount; ++v)
+ {
+ fb.include(mVertices[mEdges[mFacets[i].firstEdgeNumber + v].s].p);
+ fb.include(mVertices[mEdges[mFacets[i].firstEdgeNumber + v].e].p);
+ }
+ }
+}
+
+void MeshImpl::setMaterialId(const int32_t* materialId)
+{
+ if (materialId != nullptr)
+ {
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ mFacets[i].materialId = *materialId;
+ ++materialId;
+ }
+ }
+}
+
+bool MeshImpl::isValid() const
+{
+ return mVertices.size() > 0 && mEdges.size() > 0 && mFacets.size() > 0;
+}
+
+
+void MeshImpl::replaceMaterialId(int32_t oldMaterialId, int32_t newMaterialId)
+{
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ if (mFacets[i].materialId == oldMaterialId)
+ {
+ mFacets[i].materialId = newMaterialId;
+ }
+ }
+}
+
+void MeshImpl::setSmoothingGroup(const int32_t* smoothingGroups)
+{
+ if (smoothingGroups != nullptr)
+ {
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ mFacets[i].smoothingGroup = *smoothingGroups;
+ ++smoothingGroups;
+ }
+ }
+}
+
+
+
+} // namespace Blast
+} // namespace Nv
diff --git a/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.h b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.h
new file mode 100644
index 0000000..0f4c339
--- /dev/null
+++ b/sdk/extensions/authoringCommon/source/NvBlastExtAuthoringMeshImpl.h
@@ -0,0 +1,200 @@
+// 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) 2016-2018 NVIDIA Corporation. All rights reserved.
+
+#ifndef NVBLASTAUTHORINGMESHIMPL_H
+#define NVBLASTAUTHORINGMESHIMPL_H
+
+#include "NvBlastExtAuthoringMesh.h"
+#include <vector>
+#include <map>
+#include <set>
+
+namespace Nv
+{
+namespace Blast
+{
+
+/**
+ Class for internal mesh representation
+*/
+class MeshImpl : public Mesh
+{
+public:
+
+ /**
+ Constructs mesh object from array of triangles.
+ \param[in] position Array of vertex positions
+ \param[in] normals Array of vertex normals
+ \param[in] uv Array of vertex uv coordinates
+ \param[in] verticesCount Vertices count
+ \param[in] indices Array of vertex indices. Indices contain vertex index triplets which form a mesh triangle.
+ \param[in] indicesCount Indices count (should be equal to numberOfTriangles * 3)
+ */
+ MeshImpl(const physx::PxVec3* position, const physx::PxVec3* normals, const physx::PxVec2* uv, uint32_t verticesCount, const uint32_t* indices, uint32_t indicesCount);
+
+ /**
+ Constructs mesh object from array of facets.
+ \param[in] vertices Array of vertices
+ \param[in] edges Array of edges
+ \param[in] facets Array of facets
+ \param[in] posCount Vertices count
+ \param[in] edgesCount Edges count
+ \param[in] facetsCount Facets count
+ */
+ MeshImpl(const Vertex* vertices, const Edge* edges, const Facet* facets, uint32_t posCount, uint32_t edgesCount, uint32_t facetsCount);
+
+ MeshImpl(const Vertex* vertices, uint32_t count);
+
+ MeshImpl(const Vertex* vertices, uint32_t count, uint32_t* indices, uint32_t indexCount, void* materials, uint32_t materialStride);
+
+ ~MeshImpl();
+
+ virtual void release() override;
+
+ /**
+ Return true if mesh is valid
+ */
+ bool isValid() const override;
+
+ /**
+ Return pointer on vertices array
+ */
+ Vertex* getVerticesWritable() override;
+
+ /**
+ Return pointer on edges array
+ */
+ Edge* getEdgesWritable() override;
+
+ /**
+ Return pointer on facets array
+ */
+ Facet* getFacetsBufferWritable() override;
+
+ /**
+ Return pointer on vertices array
+ */
+ const Vertex* getVertices() const override;
+
+ /**
+ Return pointer on edges array
+ */
+ const Edge* getEdges() const override;
+
+ /**
+ Return pointer on facets array
+ */
+ const Facet* getFacetsBuffer() const override;
+
+ /**
+ Return writable pointer on specified facet
+ */
+ Facet* getFacetWritable(int32_t facet) override;
+
+ /**
+ Return writable pointer on specified facet
+ */
+ const Facet* getFacet(int32_t facet) const override;
+
+ /**
+ Return edges count
+ */
+ uint32_t getEdgesCount() const override;
+
+ /**
+ Return vertices count
+ */
+ uint32_t getVerticesCount() const override;
+
+ /**
+ Return facet count
+ */
+ uint32_t getFacetCount() const override;
+
+
+ /**
+ Return reference on mesh bounding box.
+ */
+ const physx::PxBounds3& getBoundingBox() const override;
+
+ /**
+ Return writable reference on mesh bounding box.
+ */
+ physx::PxBounds3& getBoundingBoxWritable() override;
+
+ /**
+ Recalculate bounding box
+ */
+ void recalculateBoundingBox() override;
+
+ /**
+ Compute mesh volume. Can be used only for triangulated meshes.
+ Return mesh volume. If mesh is not triangulated return 0.
+ */
+ float getMeshVolume() override;
+
+
+ /**
+ Set per-facet material id.
+ */
+ void setMaterialId(const int32_t* materialIds) override;
+
+ /**
+ Replaces an material id on faces with a new one
+ */
+ void replaceMaterialId(int32_t oldMaterialId, int32_t newMaterialId) override;
+
+ /**
+ Set per-facet smoothing group.
+ */
+ void setSmoothingGroup(const int32_t* smoothingGroups) override;
+
+ /**
+ Calculate per-facet bounding boxes.
+ */
+ virtual void calcPerFacetBounds() override;
+
+ /**
+ Get pointer on facet bounding box, if not calculated return nullptr.
+ */
+ virtual const physx::PxBounds3* getFacetBound(uint32_t index) const override;
+
+private:
+ std::vector<Vertex> mVertices;
+ std::vector<Edge> mEdges;
+ std::vector<Facet> mFacets;
+ physx::PxBounds3 mBounds;
+ std::vector<physx::PxBounds3> mPerFacetBounds;
+};
+
+
+
+} // namespace Blast
+} // namespace Nv
+
+
+#endif // ifndef NVBLASTAUTHORINGMESHIMPL_H