aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV32Build.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 /PhysX_3.4/Source/GeomUtils/src/mesh/GuBV32Build.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 'PhysX_3.4/Source/GeomUtils/src/mesh/GuBV32Build.cpp')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/mesh/GuBV32Build.cpp530
1 files changed, 530 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV32Build.cpp b/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV32Build.cpp
new file mode 100644
index 00000000..da62280f
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/mesh/GuBV32Build.cpp
@@ -0,0 +1,530 @@
+// 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) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+#include "foundation/PxVec4.h"
+#include "GuBV32Build.h"
+#include "GuBV32.h"
+#include "PxTriangle.h"
+#include "CmPhysXCommon.h"
+#include "PsBasicTemplates.h"
+#include "GuCenterExtents.h"
+#include "GuBV4Build.h"
+#include "PsAllocator.h"
+
+using namespace physx;
+using namespace Gu;
+
+#include "PsVecMath.h"
+using namespace physx::shdfnd::aos;
+
+#define DELETESINGLE(x) if (x) { delete x; x = NULL; }
+#define DELETEARRAY(x) if (x) { delete []x; x = NULL; }
+
+struct BV32Node : public physx::shdfnd::UserAllocated
+{
+ BV32Node() : mNbChildBVNodes(0)
+ {}
+
+ BV32Data mBVData[32];
+ PxU32 mNbChildBVNodes;
+
+ PX_FORCE_INLINE size_t isLeaf(PxU32 i) const { return mBVData[i].mData & 1; }
+ PX_FORCE_INLINE PxU32 getPrimitive(PxU32 i) const { return PxU32(mBVData[i].mData >> 1); }
+ PX_FORCE_INLINE const BV32Node* getChild(PxU32 i) const { return reinterpret_cast<BV32Node*>(mBVData[i].mData); }
+
+
+ PxU32 getSize() const
+ {
+ return sizeof(BV32Data)*mNbChildBVNodes;
+ }
+};
+
+
+static void fillInNodes(const AABBTreeNode* current_node, const PxU32 startIndex, const PxU32 endIndex, const AABBTreeNode** NODES, PxU32& stat)
+{
+
+ if (startIndex + 1 == endIndex)
+ {
+ //fill in nodes
+ const AABBTreeNode* P = current_node->getPos();
+ const AABBTreeNode* N = current_node->getNeg();
+ NODES[startIndex] = P;
+ NODES[endIndex] = N;
+ stat += 2;
+ }
+ else
+ {
+ const AABBTreeNode* P = current_node->getPos();
+ const AABBTreeNode* N = current_node->getNeg();
+ const PxU32 midIndex = startIndex + ((endIndex - startIndex) / 2);
+ if (!P->isLeaf())
+ fillInNodes(P, startIndex, midIndex, NODES, stat);
+ else
+ {
+ NODES[startIndex] = P;
+ stat++;
+ }
+
+ if (!N->isLeaf())
+ fillInNodes(N, midIndex + 1, endIndex, NODES, stat);
+ else
+ {
+ NODES[midIndex + 1] = N;
+ stat++;
+ }
+ }
+}
+
+
+
+static void setPrimitive(const AABBTree& source, BV32Node* node32, PxU32 i, const AABBTreeNode* node, float epsilon)
+{
+ const PxU32 nbPrims = node->getNbPrimitives();
+ PX_ASSERT(nbPrims<=32);
+ const PxU32* indexBase = source.getIndices();
+ const PxU32* prims = node->getPrimitives();
+ const PxU32 offset = PxU32(prims - indexBase);
+
+#if BV32_VALIDATE
+ for (PxU32 j = 0; j<nbPrims; j++)
+ {
+ PX_ASSERT(prims[j] == offset + j);
+ }
+#endif
+ const PxU32 primitiveIndex = (offset << 6) | (nbPrims & 63);
+
+ node32->mBVData[i].mCenter = node->getAABB().getCenter();
+ node32->mBVData[i].mExtents = node->getAABB().getExtents();
+ if (epsilon != 0.0f)
+ node32->mBVData[i].mExtents += PxVec3(epsilon, epsilon, epsilon);
+ node32->mBVData[i].mData = (primitiveIndex << 1) | 1;
+}
+
+static BV32Node* setNode(const AABBTree& source, BV32Node* node32, PxU32 i, const AABBTreeNode* node, float epsilon)
+{
+ BV32Node* child = NULL;
+
+ if (node)
+ {
+ if (node->isLeaf())
+ {
+ setPrimitive(source, node32, i, node, epsilon);
+ }
+ else
+ {
+ node32->mBVData[i].mCenter = node->getAABB().getCenter();
+ node32->mBVData[i].mExtents = node->getAABB().getExtents();
+ if (epsilon != 0.0f)
+ node32->mBVData[i].mExtents += PxVec3(epsilon, epsilon, epsilon);
+
+ child = PX_NEW(BV32Node);
+ node32->mBVData[i].mData = size_t(child);
+ }
+ }
+
+ return child;
+}
+
+
+static void _BuildBV32(const AABBTree& source, BV32Node* tmp, const AABBTreeNode* current_node, float epsilon, PxU32& nbNodes)
+{
+ PX_ASSERT(!current_node->isLeaf());
+
+ const AABBTreeNode* NODES[32];
+ memset(NODES, 0, sizeof(AABBTreeNode*) * 32);
+
+ fillInNodes(current_node, 0, 31, NODES, tmp->mNbChildBVNodes);
+
+ PxU32 left = 0;
+ PxU32 right = 31;
+
+ while (left < right)
+ {
+
+ //sweep from the front
+ while (left<right)
+ {
+ //found a hole
+ if (NODES[left] == NULL)
+ break;
+ left++;
+ }
+
+ //sweep from the back
+ while (left < right)
+ {
+ //found a node
+ if (NODES[right])
+ break;
+ right--;
+ }
+
+ if (left != right)
+ {
+ //swap left and right
+ const AABBTreeNode* node = NODES[right];
+ NODES[right] = NODES[left];
+ NODES[left] = node;
+ }
+
+ }
+
+ nbNodes += tmp->mNbChildBVNodes;
+
+ for (PxU32 i = 0; i < tmp->mNbChildBVNodes; ++i)
+ {
+ const AABBTreeNode* tempNode = NODES[i];
+ BV32Node* Child = setNode(source, tmp, i, tempNode, epsilon);
+ if (Child)
+ {
+ _BuildBV32(source, Child, tempNode, epsilon, nbNodes);
+ }
+ }
+
+}
+
+//
+//static void validateTree(const AABBTree& Source, const AABBTreeNode* currentNode)
+//{
+// if (currentNode->isLeaf())
+// {
+// const PxU32* indexBase = Source.getIndices();
+// const PxU32* prims = currentNode->getPrimitives();
+// const PxU32 offset = PxU32(prims - indexBase);
+// const PxU32 nbPrims = currentNode->getNbPrimitives();
+// for (PxU32 j = 0; j<nbPrims; j++)
+// {
+// PX_ASSERT(prims[j] == offset + j);
+// }
+// }
+// else
+// {
+// const AABBTreeNode* pos = currentNode->getPos();
+// validateTree(Source, pos);
+// const AABBTreeNode* neg = currentNode->getNeg();
+// validateTree(Source, neg);
+// }
+//}
+
+#if BV32_VALIDATE
+static void validateNodeBound(const BV32Node* currentNode, SourceMesh* mesh)
+{
+ const PxU32 nbNodes = currentNode->mNbChildBVNodes;
+ for (PxU32 i = 0; i < nbNodes; ++i)
+ {
+ const BV32Node* node = currentNode->getChild(i);
+ if (currentNode->isLeaf(i))
+ {
+ BV32Data data = currentNode->mBVData[i];
+ PxU32 nbTriangles = data.getNbReferencedTriangles();
+ PxU32 startIndex = data.getTriangleStartIndex();
+ const IndTri32* triIndices = mesh->getTris32();
+ const PxVec3* verts = mesh->getVerts();
+ PxVec3 min(PX_MAX_F32, PX_MAX_F32, PX_MAX_F32);
+ PxVec3 max(-PX_MAX_F32, -PX_MAX_F32, -PX_MAX_F32);
+ for (PxU32 j = 0; j < nbTriangles; ++j)
+ {
+ IndTri32 index = triIndices[startIndex + j];
+
+ for (PxU32 k = 0; k < 3; ++k)
+ {
+ const PxVec3& v = verts[index.mRef[k]];
+
+ min.x = (min.x > v.x) ? v.x : min.x;
+ min.y = (min.y > v.y) ? v.y : min.y;
+ min.z = (min.z > v.z) ? v.z : min.z;
+
+ max.x = (max.x < v.x) ? v.x : max.x;
+ max.y = (max.y > v.y) ? v.y : max.y;
+ max.z = (max.z > v.z) ? v.z : max.z;
+ }
+ }
+
+ PxVec3 dMin, dMax;
+ data.getMinMax(dMin, dMax);
+ PX_ASSERT(dMin.x <= min.x && dMin.y <= min.y && dMin.z <= min.z);
+ PX_ASSERT(dMax.x >= max.x && dMax.y >= max.y && dMax.z >= min.z);
+
+ }
+ else
+ {
+ validateNodeBound(node, mesh);
+ }
+ }
+}
+#endif
+
+static bool BuildBV32Internal(BV32Tree& bv32Tree, const AABBTree& Source, SourceMesh* mesh, float epsilon)
+{
+ if (mesh->getNbTriangles() <= 32)
+ {
+ bv32Tree.mNbPackedNodes = 1;
+ bv32Tree.mPackedNodes = reinterpret_cast<BV32DataPacked*>(PX_ALLOC(sizeof(BV32DataPacked), "BV32DataPacked"));
+ BV32DataPacked& packedData = bv32Tree.mPackedNodes[0];
+ packedData.mNbNodes = 1;
+ packedData.mCenter[0] = PxVec4(Source.getBV().getCenter(), 0.f);
+ packedData.mExtents[0] = PxVec4(Source.getBV().getExtents(), 0.f);
+ packedData.mData[0] = (mesh->getNbTriangles() << 1) | 1;
+ return bv32Tree.init(mesh, Source.getBV());
+ }
+
+ {
+ struct Local
+ {
+ static void _CheckMD(const AABBTreeNode* current_node, PxU32& md, PxU32& cd)
+ {
+ cd++;
+ md = PxMax(md, cd);
+
+ if (current_node->getPos()) { _CheckMD(current_node->getPos(), md, cd); cd--; }
+ if (current_node->getNeg()) { _CheckMD(current_node->getNeg(), md, cd); cd--; }
+ }
+
+ static void _Check(AABBTreeNode* current_node)
+ {
+ if (current_node->isLeaf())
+ return;
+
+ AABBTreeNode* P = const_cast<AABBTreeNode*>(current_node->getPos());
+ AABBTreeNode* N = const_cast<AABBTreeNode*>(current_node->getNeg());
+ {
+ PxU32 MDP = 0; PxU32 CDP = 0; _CheckMD(P, MDP, CDP);
+ PxU32 MDN = 0; PxU32 CDN = 0; _CheckMD(N, MDN, CDN);
+
+ if (MDP>MDN)
+ // if(MDP<MDN)
+ {
+ Ps::swap(*P, *N);
+ Ps::swap(P, N);
+ }
+ }
+ _Check(P);
+ _Check(N);
+ }
+ };
+ Local::_Check(const_cast<AABBTreeNode*>(Source.getNodes()));
+ }
+
+
+ PxU32 nbNodes = 1;
+ BV32Node* Root32 = PX_NEW(BV32Node);
+
+
+ _BuildBV32(Source, Root32, Source.getNodes(), epsilon, nbNodes);
+
+#if BV32_VALIDATE
+ validateNodeBound(Root32, mesh);
+#endif
+
+ if (!bv32Tree.init(mesh, Source.getBV()))
+ return false;
+ BV32Tree* T = &bv32Tree;
+
+ // Version with variable-sized nodes in single stream
+ {
+ struct Local
+ {
+ static void _Flatten(BV32Data* const dest, const PxU32 box_id, PxU32& current_id, const BV32Node* current, PxU32& max_depth, PxU32& current_depth, const PxU32 nb_nodes)
+ {
+ // Entering a new node => increase depth
+ current_depth++;
+ // Keep track of max depth
+ if (current_depth>max_depth)
+ max_depth = current_depth;
+
+ for (PxU32 i = 0; i<current->mNbChildBVNodes; i++)
+ {
+ dest[box_id + i].mCenter = current->mBVData[i].mCenter;
+ dest[box_id + i].mExtents = current->mBVData[i].mExtents;
+ dest[box_id + i].mData = PxU32(current->mBVData[i].mData);
+
+ PX_ASSERT(box_id + i < nb_nodes);
+ }
+
+ PxU32 NbToGo = 0;
+ PxU32 NextIDs[32];
+ memset(NextIDs, PX_INVALID_U32, sizeof(PxU32)*32);
+ const BV32Node* ChildNodes[32];
+ memset(ChildNodes, 0, sizeof(BV32Node*)*32);
+
+ BV32Data* data = dest + box_id;
+ for (PxU32 i = 0; i<current->mNbChildBVNodes; i++)
+ {
+ PX_ASSERT(current->mBVData[i].mData != PX_INVALID_U32);
+
+ if (!current->isLeaf(i))
+ {
+
+ const BV32Node* ChildNode = current->getChild(i);
+
+ const PxU32 NextID = current_id;
+
+ const PxU32 ChildSize = ChildNode->mNbChildBVNodes;
+ current_id += ChildSize;
+
+ const PxU32 ChildType = ChildNode->mNbChildBVNodes << 1;
+ data[i].mData = size_t(ChildType + (NextID << GU_BV4_CHILD_OFFSET_SHIFT_COUNT));
+ //PX_ASSERT(data[i].mData == size_t(ChildType+(NextID<<3)));
+
+ PX_ASSERT(box_id + i < nb_nodes);
+
+ NextIDs[NbToGo] = NextID;
+ ChildNodes[NbToGo] = ChildNode;
+ NbToGo++;
+ }
+ }
+
+
+
+ for (PxU32 i = 0; i<NbToGo; i++)
+ {
+ _Flatten(dest, NextIDs[i], current_id, ChildNodes[i], max_depth, current_depth, nb_nodes);
+ current_depth--;
+ }
+
+ DELETESINGLE(current);
+ }
+ };
+
+
+ PxU32 CurID = Root32->mNbChildBVNodes+1;
+
+ BV32Data* Nodes = PX_NEW(BV32Data)[nbNodes];
+ Nodes[0].mCenter = Source.getBV().getCenter();
+ Nodes[0].mExtents = Source.getBV().getExtents();
+
+ const PxU32 ChildType = Root32->mNbChildBVNodes << 1;
+ Nodes[0].mData = size_t(ChildType + (1 << GU_BV4_CHILD_OFFSET_SHIFT_COUNT));
+
+ const PxU32 nbChilden = Nodes[0].getNbChildren();
+
+ PX_UNUSED(nbChilden);
+
+
+ T->mInitData = CurID;
+ PxU32 MaxDepth = 0;
+ PxU32 CurrentDepth = 0;
+
+ Local::_Flatten(Nodes, 1, CurID, Root32, MaxDepth, CurrentDepth, nbNodes);
+
+ PX_ASSERT(CurID == nbNodes);
+
+ T->mNbNodes = nbNodes;
+
+ T->mNodes = Nodes;
+ }
+
+
+ bv32Tree.calculateLeafNode(bv32Tree.mNodes[0]);
+
+ bv32Tree.mPackedNodes = reinterpret_cast<BV32DataPacked*>(PX_ALLOC(sizeof(BV32DataPacked)*nbNodes, "BV32DataPacked"));
+ bv32Tree.mNbPackedNodes = nbNodes;
+
+ PxU32 nbPackedNodes = 1;
+ PxU32 currentIndex = bv32Tree.mNodes[0].getNbChildren() - bv32Tree.mNodes[0].mNbLeafNodes + 1;
+ BV32DataPacked& packedData = bv32Tree.mPackedNodes[0];
+ bv32Tree.createSOAformatNode(packedData, bv32Tree.mNodes[0], 1, currentIndex, nbPackedNodes);
+
+ bv32Tree.mNbPackedNodes = nbPackedNodes;
+
+ PX_ASSERT(nbPackedNodes == currentIndex);
+ PX_ASSERT(nbPackedNodes > 0);
+
+ return true;
+}
+
+/////
+
+struct ReorderData32
+{
+ const SourceMesh* mMesh;
+ PxU32* mOrder;
+ PxU32 mNbTrisPerLeaf;
+ PxU32 mIndex;
+ PxU32 mNbTris;
+ PxU32 mStats[32];
+};
+
+static bool gReorderCallback(const AABBTreeNode* current, PxU32 /*depth*/, void* userData)
+{
+ ReorderData32* Data = reinterpret_cast<ReorderData32*>(userData);
+ if (current->isLeaf())
+ {
+ const PxU32 n = current->getNbPrimitives();
+ PX_ASSERT(n > 0);
+ PX_ASSERT(n <= Data->mNbTrisPerLeaf);
+ Data->mStats[n-1]++;
+ PxU32* Prims = const_cast<PxU32*>(current->getPrimitives());
+
+ for (PxU32 i = 0; i<n; i++)
+ {
+ PX_ASSERT(Prims[i]<Data->mNbTris);
+ Data->mOrder[Data->mIndex] = Prims[i];
+ PX_ASSERT(Data->mIndex<Data->mNbTris);
+ Prims[i] = Data->mIndex;
+ Data->mIndex++;
+ }
+ }
+ return true;
+}
+
+
+bool physx::Gu::BuildBV32Ex(BV32Tree& tree, SourceMesh& mesh, float epsilon, PxU32 nbTrisPerLeaf)
+{
+ const PxU32 nbTris = mesh.mNbTris;
+
+ AABBTree Source;
+ if (!Source.buildFromMesh(mesh, nbTrisPerLeaf))
+ return false;
+
+
+ {
+ PxU32* order = reinterpret_cast<PxU32*>(PX_ALLOC(sizeof(PxU32)*nbTris, "BV32"));
+ ReorderData32 RD;
+ RD.mMesh = &mesh;
+ RD.mOrder = order;
+ RD.mNbTrisPerLeaf = nbTrisPerLeaf;
+ RD.mIndex = 0;
+ RD.mNbTris = nbTris;
+ for (PxU32 i = 0; i<32; i++)
+ RD.mStats[i] = 0;
+ Source.walk(gReorderCallback, &RD);
+ PX_ASSERT(RD.mIndex == nbTris);
+ mesh.remapTopology(order);
+ PX_FREE(order);
+ // for(PxU32 i=0;i<16;i++)
+ // printf("%d: %d\n", i, RD.mStats[i]);
+ }
+
+
+ //if (mesh.getNbTriangles() <= nbTrisPerLeaf)
+ // return tree.init(&mesh, Source.getBV());
+
+ return BuildBV32Internal(tree, Source, &mesh, epsilon);
+}