aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp')
-rw-r--r--APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp1222
1 files changed, 1222 insertions, 0 deletions
diff --git a/APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp b/APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp
new file mode 100644
index 00000000..b2f8b1e3
--- /dev/null
+++ b/APEX_1.4/common/src/ApexGeneralizedMarchingCubes.cpp
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+
+#include "ApexGeneralizedMarchingCubes.h"
+
+#include "ApexGeneralizedCubeTemplates.h"
+
+#include "PxMath.h"
+
+#include "ApexSharedUtils.h"
+
+#include "PsSort.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+struct TriangleEdge
+{
+ void init(int32_t v0, int32_t v1, int32_t edgeNr, int32_t triNr)
+ {
+ this->v0 = PxMin(v0, v1);
+ this->v1 = PxMax(v0, v1);
+ this->edgeNr = edgeNr;
+ this->triNr = triNr;
+ }
+ bool operator == (const TriangleEdge& e) const
+ {
+ if (v0 == e.v0 && v1 == e.v1)
+ {
+ return true;
+ }
+ if (v0 == e.v1 && v1 == e.v0)
+ {
+ return true;
+ }
+ return false;
+ }
+ bool operator()(const TriangleEdge& a, const TriangleEdge& b) const
+ {
+ if (a.v0 < b.v0)
+ {
+ return true;
+ }
+ if (a.v0 > b.v0)
+ {
+ return false;
+ }
+ if (a.v1 < b.v1)
+ {
+ return true;
+ }
+ if (a.v1 > b.v1)
+ {
+ return false;
+ }
+ return a.triNr < b.triNr;
+ }
+ int32_t v0, v1;
+ int32_t edgeNr;
+ int32_t triNr;
+};
+
+
+
+struct BorderEdge
+{
+ void set(int vertNr, int prev = -1, int depth = 0)
+ {
+ this->vertNr = vertNr;
+ this->prev = prev;
+ this->depth = depth;
+ }
+ int32_t vertNr;
+ int32_t prev;
+ int32_t depth;
+};
+
+
+
+
+ApexGeneralizedMarchingCubes::ApexGeneralizedMarchingCubes(const PxBounds3& bound, uint32_t subdivision) :
+ mTemplates(NULL)
+{
+ mCubes.clear();
+ mBound = bound;
+ PX_ASSERT(subdivision > 0);
+ mSpacing = (bound.maximum - bound.minimum).magnitude() / (float)subdivision;
+ mInvSpacing = 1.0f / mSpacing;
+
+ memset(mFirstCube, -1, sizeof(int32_t) * HASH_INDEX_SIZE);
+
+ mVertices.clear();
+ mIndices.clear();
+}
+
+
+ApexGeneralizedMarchingCubes::~ApexGeneralizedMarchingCubes()
+{
+ if (mTemplates != NULL)
+ {
+ delete mTemplates;
+ mTemplates = NULL;
+ }
+}
+
+
+
+
+
+void ApexGeneralizedMarchingCubes::registerTriangle(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2)
+{
+ PxBounds3 bounds;
+ bounds.setEmpty();
+ bounds.include(p0);
+ bounds.include(p1);
+ bounds.include(p2);
+ PX_ASSERT(!bounds.isEmpty());
+ bounds.fattenFast(0.001f * mSpacing);
+ PxVec3 n, vertPos, q0, q1, qt;
+ n = (p1 - p0).cross(p2 - p0);
+ float d = n.dot(p0);
+
+ int32_t min[3] = { (int32_t)PxFloor(bounds.minimum.x* mInvSpacing), (int32_t)PxFloor(bounds.minimum.y* mInvSpacing), (int32_t)PxFloor(bounds.minimum.z* mInvSpacing) };
+ int32_t max[3] = { (int32_t)PxFloor(bounds.maximum.x* mInvSpacing) + 1, (int32_t)PxFloor(bounds.maximum.y* mInvSpacing) + 1, (int32_t)PxFloor(bounds.maximum.z* mInvSpacing) + 1 };
+
+ int32_t coord[3];
+
+ for (uint32_t dim0 = 0; dim0 < 3; dim0++)
+ {
+ if (n[dim0] == 0.0f)
+ {
+ continue; // singular case
+ }
+
+ const uint32_t dim1 = (dim0 + 1) % 3;
+ const uint32_t dim2 = (dim1 + 1) % 3;
+
+ for (coord[dim1] = min[dim1]; coord[dim1] <= max[dim1]; coord[dim1]++)
+ {
+ for (coord[dim2] = min[dim2]; coord[dim2] <= max[dim2]; coord[dim2]++)
+ {
+ //const float axis0 = coord[dim0] * mSpacing;
+ const float axis1 = coord[dim1] * mSpacing;
+ const float axis2 = coord[dim2] * mSpacing;
+
+ // does the ray go through the triangle?
+ bool intersection = true;
+ if (n[dim0] > 0.0f)
+ {
+ if ((p1[dim1] - p0[dim1]) * (axis2 - p0[dim2]) - (axis1 - p0[dim1]) * (p1[dim2] - p0[dim2]) < 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p2[dim1] - p1[dim1]) * (axis2 - p1[dim2]) - (axis1 - p1[dim1]) * (p2[dim2] - p1[dim2]) < 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p0[dim1] - p2[dim1]) * (axis2 - p2[dim2]) - (axis1 - p2[dim1]) * (p0[dim2] - p2[dim2]) < 0.0f)
+ {
+ intersection = false;
+ }
+ }
+ else
+ {
+ if ((p1[dim1] - p0[dim1]) * (axis2 - p0[dim2]) - (axis1 - p0[dim1]) * (p1[dim2] - p0[dim2]) > 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p2[dim1] - p1[dim1]) * (axis2 - p1[dim2]) - (axis1 - p1[dim1]) * (p2[dim2] - p1[dim2]) > 0.0f)
+ {
+ intersection = false;
+ }
+ if ((p0[dim1] - p2[dim1]) * (axis2 - p2[dim2]) - (axis1 - p2[dim1]) * (p0[dim2] - p2[dim2]) > 0.0f)
+ {
+ intersection = false;
+ }
+ }
+
+ if (intersection)
+ {
+ const float pos = (d - axis1 * n[dim1] - axis2 * n[dim2]) / n[dim0];
+ coord[dim0] = (int32_t)PxFloor(pos * mInvSpacing);
+
+ uint32_t nr = (uint32_t)createCube(coord[0], coord[1], coord[2]);
+ GeneralizedCube& cube = mCubes[nr];
+
+ if (cube.vertRefs[dim0].vertNr < 0)
+ {
+ vertPos = PxVec3(coord[0] * mSpacing, coord[1] * mSpacing, coord[2] * mSpacing);
+ vertPos[dim0] = pos;
+ cube.vertRefs[dim0].vertNr = (int32_t)mVertices.size();
+ mVertices.pushBack(vertPos);
+ }
+ }
+ }
+ }
+ }
+
+ // does a triangle edge cut a cube face?
+ PxBounds3 cellBounds;
+ for (int32_t xi = min[0]; xi <= max[0]; xi++)
+ {
+ for (int32_t yi = min[1]; yi <= max[1]; yi++)
+ {
+ for (int32_t zi = min[2]; zi <= max[2]; zi++)
+ {
+ cellBounds.minimum = PxVec3(xi * mSpacing, yi * mSpacing, zi * mSpacing);
+ cellBounds.maximum = PxVec3((xi + 1) * mSpacing, (yi + 1) * mSpacing, (zi + 1) * mSpacing);
+
+ for (uint32_t i = 0; i < 3; i++)
+ {
+ switch (i)
+ {
+ case 0 :
+ q0 = p0;
+ q1 = p1;
+ break;
+ case 1 :
+ q0 = p1;
+ q1 = p2;
+ break;
+ case 2 :
+ q0 = p2;
+ q1 = p0;
+ break;
+ default: // Make compiler happy
+ q0 = q1 = PxVec3(0.0f);
+ break;
+ }
+
+ if (q0.x != q1.x)
+ {
+ const float t = (cellBounds.minimum.x - q0.x) / (q1.x - q0.x);
+ if (0.0f <= t && t <= 1.0f)
+ {
+ qt = q0 + (q1 - q0) * t;
+ if (cellBounds.minimum.y <= qt.y && qt.y <= cellBounds.maximum.y && cellBounds.minimum.z <= qt.z && qt.z <= cellBounds.maximum.z)
+ {
+ GeneralizedCube& cube = mCubes[(uint32_t)createCube(xi, yi, zi)];
+ cube.sideBounds[0].include(qt);
+ }
+ }
+ }
+ if (q0.y != q1.y)
+ {
+ const float t = (cellBounds.minimum.y - q0.y) / (q1.y - q0.y);
+ if (0.0f <= t && t <= 1.0f)
+ {
+ qt = q0 + (q1 - q0) * t;
+ if (cellBounds.minimum.z <= qt.z && qt.z <= cellBounds.maximum.z && cellBounds.minimum.x <= qt.x && qt.x <= cellBounds.maximum.x)
+ {
+ GeneralizedCube& cube = mCubes[(uint32_t)createCube(xi, yi, zi)];
+ cube.sideBounds[1].include(qt);
+ }
+ }
+ }
+ if (q0.z != q1.z)
+ {
+ const float t = (cellBounds.minimum.z - q0.z) / (q1.z - q0.z);
+ if (0.0f <= t && t <= 1.0f)
+ {
+ qt = q0 + (q1 - q0) * t;
+ if (cellBounds.minimum.x <= qt.x && qt.x <= cellBounds.maximum.x && cellBounds.minimum.y <= qt.y && qt.y <= cellBounds.maximum.y)
+ {
+ GeneralizedCube& cube = mCubes[(uint32_t)createCube(xi, yi, zi)];
+ cube.sideBounds[2].include(qt);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+bool ApexGeneralizedMarchingCubes::endRegistration(uint32_t bubleSizeToRemove, IProgressListener* progressListener)
+{
+ HierarchicalProgressListener progress(100, progressListener);
+
+ progress.setSubtaskWork(20, "Complete Cells");
+ completeCells();
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(20, "Create Triangles");
+ for (int i = 0; i < (int)mCubes.size(); i++)
+ {
+ createTrianglesForCube(i);
+ }
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(20, "Create Neighbor Info");
+ createNeighbourInfo();
+ progress.completeSubtask();
+
+ uint32_t numTris = mIndices.size() / 3;
+
+ mTriangleDeleted.resize(numTris);
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ mTriangleDeleted[i] = 0;
+ }
+
+ if (bubleSizeToRemove > 0)
+ {
+ progress.setSubtaskWork(10, "Remove Bubbles");
+ determineGroups();
+ removeBubbles((int32_t)bubleSizeToRemove);
+ progress.completeSubtask();
+ }
+ progress.setSubtaskWork(20, "Fix Orientation");
+ determineGroups();
+ fixOrientations();
+ progress.completeSubtask();
+
+ progress.setSubtaskWork(-1, "Compress");
+ compress();
+ progress.completeSubtask();
+
+ return true;
+}
+
+
+int32_t ApexGeneralizedMarchingCubes::createCube(int32_t xi, int32_t yi, int32_t zi)
+{
+ int32_t nr = findCube(xi, yi, zi);
+ if (nr >= 0)
+ {
+ return nr;
+ }
+
+ GeneralizedCube newCube;
+ newCube.init(xi, yi, zi);
+ int32_t h = hashFunction(xi, yi, zi);
+ newCube.next = mFirstCube[h];
+ mFirstCube[h] = (int32_t)mCubes.size();
+ nr = (int32_t)mCubes.size();
+ mCubes.pushBack(newCube);
+ return nr;
+}
+
+
+
+int32_t ApexGeneralizedMarchingCubes::findCube(int32_t xi, int32_t yi, int32_t zi)
+{
+ int32_t h = hashFunction(xi, yi, zi);
+ int32_t i = mFirstCube[h];
+
+ while (i >= 0)
+ {
+ GeneralizedCube& c = mCubes[(uint32_t)i];
+ if (!c.deleted && c.xi == xi && c.yi == yi && c.zi == zi)
+ {
+ return i;
+ }
+ i = mCubes[(uint32_t)i].next;
+ }
+ return -1;
+}
+
+
+
+void ApexGeneralizedMarchingCubes::completeCells()
+{
+ // make sure we have the boarder cells as well
+ uint32_t numCubes = mCubes.size();
+ for (uint32_t i = 0; i < numCubes; i++)
+ {
+ int32_t xi = mCubes[i].xi;
+ int32_t yi = mCubes[i].yi;
+ int32_t zi = mCubes[i].zi;
+ //createCube(xi-1,yi, zi);
+ //createCube(xi, yi-1,zi);
+ //createCube(xi, yi, zi-1);
+
+ createCube(xi - 1, yi, zi);
+ createCube(xi - 1, yi - 1, zi);
+ createCube(xi, yi - 1, zi);
+ createCube(xi, yi, zi - 1);
+ createCube(xi - 1, yi, zi - 1);
+ createCube(xi - 1, yi - 1, zi - 1);
+ createCube(xi, yi - 1, zi - 1);
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::createTrianglesForCube(int32_t cellNr)
+{
+ const int sideEdges[6][4] =
+ {
+ {3, 7, 8, 11}, {1, 5, 9, 10}, {0, 4, 8, 9}, {2, 6, 10, 11}, {0, 1, 2, 3}, {4, 5, 6, 7}
+ };
+ const int adjVerts[12][8] =
+ {
+ {16, 1, 2, 3, 14, 4, 8, 9}, {16, 0, 2, 3, 13, 5, 9, 10}, {16, 0, 1, 3, 15, 6, 10, 11}, {16, 0, 1, 2, 12, 7, 8, 11},
+ {17, 5, 6, 7, 14, 0, 8, 9}, {17, 4, 6, 7, 13, 1, 9, 10}, {17, 4, 5, 7, 15, 2, 10, 11}, {17, 4, 5, 6, 12, 3, 8, 11},
+ {12, 3, 7, 11, 14, 0, 4, 9}, {14, 0, 4, 8, 13, 1, 5, 10}, {13, 1, 5, 9, 15, 2, 6, 11}, {15, 2, 6, 10, 12, 3, 7, 8}
+ };
+
+ int32_t groups[8];
+ int32_t vertNrs[19];
+
+ memset(vertNrs, -1, sizeof(int32_t) * 19);
+
+ // get edge vertices
+ GeneralizedVertRef* vertRefs[12];
+ getCubeEdgesAndGroups(cellNr, vertRefs, groups);
+
+ uint32_t numCuts = 0;
+ for (uint32_t i = 0; i < 12; i++)
+ {
+ if (vertRefs[i] != NULL)
+ {
+ vertNrs[i] = vertRefs[i]->vertNr;
+ if (vertNrs[i] >= 0)
+ {
+ numCuts++;
+ }
+ }
+ }
+
+ if (numCuts == 0)
+ {
+ return;
+ }
+
+ GeneralizedCube& c = mCubes[(uint32_t)cellNr];
+
+ int startFace = -1, endFace = -1;
+
+ PX_UNUSED(endFace); // Make compiler happy
+
+ // create side vertices if necessary
+ for (uint32_t i = 0; i < 6; i++)
+ {
+ uint32_t faceNr = 12 + i;
+ int32_t* faceVertNr = NULL;
+ PxBounds3* b = NULL;
+ switch (faceNr)
+ {
+ case 12:
+ faceVertNr = &c.sideVertexNr[0];
+ b = &c.sideBounds[0];
+ break;
+ case 13:
+ {
+ int32_t nr = findCube(c.xi + 1, c.yi, c.zi);
+ if (nr >= 0)
+ {
+ faceVertNr = &mCubes[(uint32_t)nr].sideVertexNr[0];
+ b = &mCubes[(uint32_t)nr].sideBounds[0];
+ }
+ }
+ break;
+ case 14:
+ faceVertNr = &c.sideVertexNr[1];
+ b = &c.sideBounds[1];
+ break;
+ case 15:
+ {
+ int32_t nr = findCube(c.xi, c.yi + 1, c.zi);
+ if (nr >= 0)
+ {
+ faceVertNr = &mCubes[(uint32_t)nr].sideVertexNr[1];
+ b = &mCubes[(uint32_t)nr].sideBounds[1];
+ }
+ }
+ break;
+ case 16:
+ faceVertNr = &c.sideVertexNr[2];
+ b = &c.sideBounds[2];
+ break;
+ case 17:
+ {
+ int32_t nr = findCube(c.xi, c.yi, c.zi + 1);
+ if (nr >= 0)
+ {
+ faceVertNr = &mCubes[(uint32_t)nr].sideVertexNr[2];
+ b = &mCubes[(uint32_t)nr].sideBounds[2];
+ }
+ }
+ break;
+ }
+
+ PxVec3 pos(0.0f, 0.0f, 0.0f);
+ uint32_t num = 0;
+
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ int32_t edgeVertNr = vertNrs[sideEdges[i][j]];
+ if (edgeVertNr < 0)
+ {
+ continue;
+ }
+
+ pos += mVertices[(uint32_t)edgeVertNr];
+ num++;
+ }
+
+ if (num == 0 || num == 2)
+ {
+ continue;
+ }
+
+ pos = pos / (float)num;
+
+ if (num == 1)
+ {
+ if (startFace < 0)
+ {
+ startFace = (int32_t)faceNr;
+ }
+ else
+ {
+ endFace = (int32_t)faceNr;
+ }
+
+ if (!(b->isEmpty()))
+ {
+ if (PxAbs(pos.x - b->minimum.x) > PxAbs(pos.x - b->maximum.x))
+ {
+ pos.x = b->minimum.x;
+ }
+ else
+ {
+ pos.x = b->maximum.x;
+ }
+ if (PxAbs(pos.y - b->minimum.y) > PxAbs(pos.y - b->maximum.y))
+ {
+ pos.y = b->minimum.y;
+ }
+ else
+ {
+ pos.y = b->maximum.y;
+ }
+ if (PxAbs(pos.z - b->minimum.z) > PxAbs(pos.z - b->maximum.z))
+ {
+ pos.z = b->minimum.z;
+ }
+ else
+ {
+ pos.z = b->maximum.z;
+ }
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ if (*faceVertNr < 0)
+ {
+ *faceVertNr = (int32_t)mVertices.size();
+ mVertices.pushBack(pos);
+ }
+ vertNrs[faceNr] = *faceVertNr;
+ }
+
+ int32_t maxGroup = groups[0];
+ for (uint32_t i = 1; i < 8; i++)
+ {
+ if (groups[i] > maxGroup)
+ {
+ maxGroup = groups[i];
+ }
+ }
+
+ // boundary cell
+ physx::Array<BorderEdge> queue;
+ if (startFace >= 0)
+ {
+ BorderEdge edge;
+ queue.clear();
+ if (queue.capacity() < 20)
+ {
+ queue.reserve(20);
+ }
+
+ int32_t prev[19];
+ bool visited[19];
+ for (uint32_t i = 0; i < 19; i++)
+ {
+ prev[i] = -1;
+ visited[i] = false;
+ }
+
+ edge.set(startFace);
+ queue.pushBack(edge);
+
+ int32_t maxVert = -1;
+ int32_t maxDepth = -1;
+
+ while (!queue.empty())
+ {
+ edge = queue[queue.size() - 1];
+ queue.popBack();
+
+ int32_t v = edge.vertNr;
+ if (visited[v])
+ {
+ continue;
+ }
+
+ visited[v] = true;
+ prev[v] = edge.prev;
+ edge.prev = v;
+ edge.depth++;
+
+ if (edge.depth > maxDepth)
+ {
+ maxDepth = edge.depth;
+ maxVert = v;
+ }
+ // if (v == endFace) break;
+
+ if (v < 12)
+ {
+ for (uint32_t i = 0; i < 8; i += 4)
+ {
+ edge.vertNr = adjVerts[v][i];
+ if (vertNrs[edge.vertNr] >= 0)
+ {
+ if (!visited[edge.vertNr])
+ {
+ queue.pushBack(edge);
+ }
+ }
+ else
+ {
+ for (uint32_t j = i + 1; j < i + 4; j++)
+ {
+ edge.vertNr = adjVerts[v][j];
+ if (vertNrs[edge.vertNr] >= 0 && !visited[edge.vertNr])
+ {
+ queue.pushBack(edge);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t i = 0; i < 4; i++)
+ {
+ edge.vertNr = sideEdges[v - 12][i];
+ if (!visited[edge.vertNr] && vertNrs[edge.vertNr] >= 0)
+ {
+ queue.pushBack(edge);
+ }
+ }
+ }
+ }
+
+ int32_t chain[14];
+ uint32_t chainLen = 0;
+ int32_t v = maxVert;
+
+ if (vertNrs[v] >= 0)
+ {
+ chain[chainLen++] = v;
+ }
+
+ v = prev[v];
+ while (v >= 0)
+ {
+ if (vertNrs[v] >= 0)
+ {
+ chain[chainLen++] = v;
+ }
+ v = prev[v];
+ }
+
+ int32_t numTris = (int32_t)chainLen - 2;
+
+ c.firstTriangle = (int32_t)mIndices.size() / 3;
+ for (int i = 0; i < numTris; i++)
+ {
+ mIndices.pushBack((uint32_t)vertNrs[(uint32_t)chain[0]]);
+ mIndices.pushBack((uint32_t)vertNrs[(uint32_t)chain[i + 1]]);
+ mIndices.pushBack((uint32_t)vertNrs[(uint32_t)chain[i + 2]]);
+ c.numTriangles++;
+ }
+ return;
+ }
+
+ // inner cell
+ if (mTemplates == NULL)
+ {
+ mTemplates = PX_NEW(ApexGeneralizedCubeTemplates)();
+ }
+ mTemplates->getTriangles(groups, mGeneralizedTriangles);
+
+ // create face and inner vertices if necessary
+ for (uint32_t i = 0; i < mGeneralizedTriangles.size(); i++)
+ {
+ int32_t localNr = mGeneralizedTriangles[i];
+
+ if (vertNrs[localNr] < 0)
+ {
+ if (localNr < 12)
+ {
+ return; // impossible to create triangles, border cube
+ }
+
+ if (localNr == 18 && vertNrs[18] < 0)
+ {
+ // center vertex, not shared with other cells
+ vertNrs[18] = (int32_t)mVertices.size();
+ PxVec3 pos(0.0f);
+ float num = 0.0f;
+ for (int j = 0; j < 12; j++)
+ {
+ if (vertNrs[j] >= 0)
+ {
+ pos += mVertices[(uint32_t)vertNrs[j]];
+ num = num + 1.0f;
+ }
+ }
+ mVertices.pushBack(pos / num);
+ }
+ }
+ }
+
+ c.firstTriangle = (int32_t)mIndices.size() / 3;
+ const uint32_t numTris = mGeneralizedTriangles.size() / 3;
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ PX_ASSERT(vertNrs[mGeneralizedTriangles[3 * i + 0]] != vertNrs[mGeneralizedTriangles[3 * i + 1]]);
+ PX_ASSERT(vertNrs[mGeneralizedTriangles[3 * i + 0]] != vertNrs[mGeneralizedTriangles[3 * i + 2]]);
+ PX_ASSERT(vertNrs[mGeneralizedTriangles[3 * i + 1]] != vertNrs[mGeneralizedTriangles[3 * i + 2]]);
+ mIndices.pushBack((uint32_t)vertNrs[mGeneralizedTriangles[3 * i + 0]]);
+ mIndices.pushBack((uint32_t)vertNrs[mGeneralizedTriangles[3 * i + 1]]);
+ mIndices.pushBack((uint32_t)vertNrs[mGeneralizedTriangles[3 * i + 2]]);
+ c.numTriangles++;
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::createNeighbourInfo()
+{
+ physx::Array<TriangleEdge> edges;
+ edges.reserve(mIndices.size());
+
+ mFirstNeighbour.resize(mIndices.size());
+ for (uint32_t i = 0; i < mFirstNeighbour.size(); i++)
+ {
+ mFirstNeighbour[i] = -1;
+ }
+
+ mNeighbours.clear();
+
+ const uint32_t numTriangles = mIndices.size() / 3;
+ for (uint32_t i = 0; i < numTriangles; i++)
+ {
+ TriangleEdge edge;
+ int32_t i0 = (int32_t)mIndices[3 * i];
+ int32_t i1 = (int32_t)mIndices[3 * i + 1];
+ int32_t i2 = (int32_t)mIndices[3 * i + 2];
+ PX_ASSERT(i0 != i1);
+ PX_ASSERT(i0 != i2);
+ PX_ASSERT(i1 != i2);
+ edge.init(i0, i1, 0, (int32_t)i);
+ edges.pushBack(edge);
+ edge.init(i1, i2, 1, (int32_t)i);
+ edges.pushBack(edge);
+ edge.init(i2, i0, 2, (int32_t)i);
+ edges.pushBack(edge);
+ }
+ shdfnd::sort(edges.begin(), edges.size(), TriangleEdge());
+
+ uint32_t i = 0;
+ const uint32_t numEdges = edges.size();
+ while (i < numEdges)
+ {
+ const TriangleEdge& e0 = edges[i];
+ const int32_t first = (int32_t)mNeighbours.size();
+ PX_ASSERT(mFirstNeighbour[(uint32_t)(e0.triNr * 3 + e0.edgeNr)] == -1);
+ mFirstNeighbour[(uint32_t)(e0.triNr * 3 + e0.edgeNr)] = first;
+ mNeighbours.pushBack(e0.triNr);
+ i++;
+
+ while (i < numEdges && edges[i] == e0)
+ {
+ const TriangleEdge& e1 = edges[i];
+ PX_ASSERT(mFirstNeighbour[(uint32_t)(e1.triNr * 3 + e1.edgeNr)] == -1);
+ mFirstNeighbour[(uint32_t)(e1.triNr * 3 + e1.edgeNr)] = first;
+ mNeighbours.pushBack(e1.triNr);
+ i++;
+ }
+ mNeighbours.pushBack(-1); // end marker
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::getCubeEdgesAndGroups(int32_t cellNr, GeneralizedVertRef* vertRefs[12], int32_t groups[8])
+{
+ const int32_t adjCorners[8][3] =
+ {
+ {1, 3, 4}, {0, 2, 5}, {1, 3, 6}, {0, 2, 7}, {0, 5, 7}, {1, 4, 6}, {2, 5, 7}, {3, 4, 6}
+ };
+
+ const int32_t adjEdges[8][3] =
+ {
+ {0, 3, 8}, {0, 1, 9}, {1, 2, 10}, {3, 2, 11}, {8, 4, 7}, {9, 4, 5}, {10, 5, 6}, {11, 7, 6}
+ };
+
+ // collect edge vertices
+ GeneralizedCube& c = mCubes[(uint32_t)cellNr];
+ for (uint32_t i = 0; i < 12; i++)
+ {
+ vertRefs[i] = NULL;
+ }
+
+ vertRefs[0] = &c.vertRefs[0];
+ vertRefs[3] = &c.vertRefs[1];
+ vertRefs[8] = &c.vertRefs[2];
+
+ int32_t nr = findCube(c.xi + 1, c.yi, c.zi);
+ if (nr >= 0)
+ {
+ vertRefs[1] = &mCubes[(uint32_t)nr].vertRefs[1];
+ vertRefs[9] = &mCubes[(uint32_t)nr].vertRefs[2];
+ }
+ nr = findCube(c.xi, c.yi + 1, c.zi);
+ if (nr >= 0)
+ {
+ vertRefs[2] = &mCubes[(uint32_t)nr].vertRefs[0];
+ vertRefs[11] = &mCubes[(uint32_t)nr].vertRefs[2];
+ }
+ nr = findCube(c.xi, c.yi, c.zi + 1);
+ if (nr >= 0)
+ {
+ vertRefs[4] = &mCubes[(uint32_t)nr].vertRefs[0];
+ vertRefs[7] = &mCubes[(uint32_t)nr].vertRefs[1];
+ }
+ nr = findCube(c.xi + 1, c.yi + 1, c.zi);
+ if (nr >= 0)
+ {
+ vertRefs[10] = &mCubes[(uint32_t)nr].vertRefs[2];
+ }
+ nr = findCube(c.xi, c.yi + 1, c.zi + 1);
+ if (nr >= 0)
+ {
+ vertRefs[6] = &mCubes[(uint32_t)nr].vertRefs[0];
+ }
+ nr = findCube(c.xi + 1, c.yi, c.zi + 1);
+ if (nr >= 0)
+ {
+ vertRefs[5] = &mCubes[(uint32_t)nr].vertRefs[1];
+ }
+
+ // assign groups using flood fill on the cube edges
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ groups[i] = -1;
+ }
+
+ int groupNr = -1;
+ for (uint32_t i = 0; i < 8; i++)
+ {
+ if (groups[i] >= 0)
+ {
+ continue;
+ }
+
+ groupNr++;
+ mCubeQueue.clear();
+ mCubeQueue.pushBack((int32_t)i);
+ while (!mCubeQueue.empty())
+ {
+ int32_t cornerNr = mCubeQueue[mCubeQueue.size() - 1];
+ mCubeQueue.popBack();
+
+ if (groups[cornerNr] >= 0)
+ {
+ continue;
+ }
+
+ groups[cornerNr] = groupNr;
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ int32_t adjCorner = adjCorners[cornerNr][j];
+ int32_t adjEdge = adjEdges[cornerNr][j];
+ if (vertRefs[adjEdge] != NULL && vertRefs[adjEdge]->vertNr >= 0) // edge blocked by vertex
+ {
+ continue;
+ }
+
+ if (groups[adjCorner] < 0)
+ {
+ mCubeQueue.pushBack(adjCorner);
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::determineGroups()
+{
+ const uint32_t numTris = mIndices.size() / 3;
+
+ mTriangleGroup.resize(numTris);
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ mTriangleGroup[i] = -1;
+ }
+
+ mGroupFirstTriangle.clear();
+ mGroupTriangles.clear();
+
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ if (mTriangleDeleted[i])
+ {
+ continue;
+ }
+ if (mTriangleGroup[i] >= 0)
+ {
+ continue;
+ }
+
+ int32_t group = (int32_t)mGroupFirstTriangle.size();
+ mGroupFirstTriangle.pushBack((int32_t)mGroupTriangles.size());
+
+ mCubeQueue.clear();
+ mCubeQueue.pushBack((int32_t)i);
+ while (!mCubeQueue.empty())
+ {
+ const uint32_t t = (uint32_t)mCubeQueue[mCubeQueue.size() - 1];
+ mCubeQueue.popBack();
+
+ if (mTriangleGroup[t] >= 0)
+ {
+ continue;
+ }
+
+ mTriangleGroup[t] = group;
+ mGroupTriangles.pushBack((int32_t)t);
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * t + j];
+ uint32_t num = 0;
+ int32_t n = -1;
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] != (int32_t)t)
+ {
+ n = mNeighbours[first];
+ }
+
+ first++;
+ num++;
+ }
+ if (num == 2 && n >= 0 && mTriangleGroup[(uint32_t)n] < 0)
+ {
+ if (!mTriangleDeleted[(uint32_t)n])
+ {
+ mCubeQueue.pushBack(n);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::removeBubbles(int32_t minGroupSize)
+{
+ const uint32_t numGroups = mGroupFirstTriangle.size();
+ for (uint32_t i = 0; i < numGroups; i++)
+ {
+ int32_t firstTri = mGroupFirstTriangle[i];
+ int32_t lastTri = i < numGroups - 1 ? mGroupFirstTriangle[i + 1] : (int32_t)mGroupTriangles.size();
+
+ if (lastTri - firstTri > minGroupSize)
+ {
+ continue;
+ }
+
+ bool OK = true;
+
+ for (int32_t j = firstTri; j < lastTri; j++)
+ {
+ int32_t t = mGroupTriangles[(uint32_t)j];
+ for (uint32_t k = 0; k < 3; k++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * t + k];
+ uint32_t num = 0;
+ int32_t n = -1;
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] != t)
+ {
+ n = mNeighbours[first];
+ }
+
+ num++;
+ first++;
+ }
+ if (num == 2 && mTriangleGroup[(uint32_t)n] != (int32_t)i)
+ {
+ OK = false;
+ break;
+ }
+ }
+ if (!OK)
+ {
+ break;
+ }
+ }
+
+
+ if (!OK)
+ {
+ continue;
+ }
+
+ for (int32_t j = firstTri; j < lastTri; j++)
+ {
+ uint32_t t = (uint32_t)mGroupTriangles[(uint32_t)j];
+ // remove neighbor info
+ for (int k = 0; k < 3; k++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * t + k];
+ int32_t pos = -1;
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] == (int32_t)t)
+ {
+ PX_ASSERT(pos == -1);
+ pos = (int32_t)first;
+ }
+
+ first++;
+ }
+ if (pos >= 0)
+ {
+ mNeighbours[(uint32_t)pos] = mNeighbours[first - 1];
+ mNeighbours[first - 1] = -1;
+ }
+ }
+ // remove triangle
+ mTriangleDeleted[t] = true;
+
+ /*
+ // debugging only
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 0]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 1]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 1]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 2]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 2]]);
+ mDebugLines.pushBack(mVertices[mIndices[t * 3 + 0]]);
+ */
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::fixOrientations()
+{
+ if (mIndices.size() == 0)
+ {
+ return;
+ }
+
+ const uint32_t numTris = mIndices.size() / 3;
+
+ physx::Array<uint8_t> marks;
+ marks.resize(numTris);
+
+ // 0 = non visited, 1 = visited, 2 = visited, to be flipped
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ marks[i] = 0;
+ }
+
+ physx::Array<int32_t> queue;
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ if (mTriangleDeleted[i])
+ {
+ continue;
+ }
+
+ if (marks[i] != 0)
+ {
+ continue;
+ }
+
+ queue.clear();
+
+ marks[i] = 1;
+ queue.pushBack((int32_t)i);
+ while (!queue.empty())
+ {
+ uint32_t triNr = (uint32_t)queue[queue.size() - 1];
+ queue.popBack();
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ uint32_t first = (uint32_t)mFirstNeighbour[3 * triNr + j];
+ uint32_t num = 0;
+ int32_t adjNr = -1;
+
+ while (mNeighbours[first] >= 0)
+ {
+ if (mNeighbours[first] != (int32_t)triNr)
+ {
+ adjNr = mNeighbours[first];
+ }
+
+ first++;
+ num++;
+ }
+
+ if (num != 2)
+ {
+ continue;
+ }
+ if (marks[(uint32_t)adjNr] != 0)
+ {
+ continue;
+ }
+
+ queue.pushBack(adjNr);
+
+ uint32_t i0, i1;
+ if (marks[(uint32_t)triNr] == 1)
+ {
+ i0 = mIndices[3 * triNr + j];
+ i1 = mIndices[3 * triNr + ((j + 1) % 3)];
+ }
+ else
+ {
+ i1 = mIndices[3 * triNr + j];
+ i0 = mIndices[3 * triNr + ((j + 1) % 3)];
+ }
+
+ // don't swap here because this would corrupt the neighbor information
+ marks[(uint32_t)adjNr] = 1;
+ if (mIndices[3 * (uint32_t)adjNr + 0] == i0 && mIndices[3 * (uint32_t)adjNr + 1] == i1)
+ {
+ marks[(uint32_t)adjNr] = 2;
+ }
+ if (mIndices[3 * (uint32_t)adjNr + 1] == i0 && mIndices[3 * (uint32_t)adjNr + 2] == i1)
+ {
+ marks[(uint32_t)adjNr] = 2;
+ }
+ if (mIndices[3 * (uint32_t)adjNr + 2] == i0 && mIndices[3 * (uint32_t)adjNr + 0] == i1)
+ {
+ marks[(uint32_t)adjNr] = 2;
+ }
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < numTris; i++)
+ {
+ if (marks[i] == 2)
+ {
+ uint32_t i0 = mIndices[3 * i];
+ mIndices[3 * i] = mIndices[3 * i + 1];
+ mIndices[3 * i + 1] = i0;
+ }
+ }
+}
+
+
+
+void ApexGeneralizedMarchingCubes::compress()
+{
+ PX_ASSERT(mTriangleDeleted.size() * 3 == mIndices.size());
+
+ uint32_t writePos = 0;
+
+ for (uint32_t i = 0; i < mTriangleDeleted.size(); i++)
+ {
+ if (mTriangleDeleted[i] == 1)
+ {
+ continue;
+ }
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ mIndices[3 * writePos + j] = mIndices[3 * i + j];
+ }
+ writePos++;
+ }
+
+ mIndices.resize(3 * writePos);
+
+ mTriangleDeleted.clear();
+ mTriangleDeleted.reset();
+
+ mNeighbours.clear();
+ mNeighbours.reset();
+
+ mFirstNeighbour.clear();
+ mFirstNeighbour.reset();
+}
+
+}
+} // end namespace nvidia::apex