aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/PhysXCooking/src/Adjacencies.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/PhysXCooking/src/Adjacencies.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/PhysXCooking/src/Adjacencies.cpp')
-rw-r--r--PhysX_3.4/Source/PhysXCooking/src/Adjacencies.cpp712
1 files changed, 712 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/PhysXCooking/src/Adjacencies.cpp b/PhysX_3.4/Source/PhysXCooking/src/Adjacencies.cpp
new file mode 100644
index 00000000..63797c1a
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXCooking/src/Adjacencies.cpp
@@ -0,0 +1,712 @@
+// 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/PxMemory.h"
+#include "EdgeList.h"
+#include "Adjacencies.h"
+#include "CmRadixSortBuffered.h"
+#include "GuSerialize.h"
+#include "PsFoundation.h"
+
+using namespace physx;
+using namespace Gu;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Flips the winding.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void AdjTriangle::Flip()
+{
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ // Call the Triangle method
+ IndexedTriangle::Flip();
+#endif
+
+ // Flip links. We flipped vertex references 1 & 2, i.e. links 0 & 1.
+ physx::shdfnd::swap(mATri[0], mATri[1]);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Computes the number of boundary edges in a triangle.
+ * \return the number of boundary edges. (0 => 3)
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+PxU32 AdjTriangle::ComputeNbBoundaryEdges() const
+{
+ // Look for boundary edges
+ PxU32 Nb = 0;
+ if(IS_BOUNDARY(mATri[0])) Nb++;
+ if(IS_BOUNDARY(mATri[1])) Nb++;
+ if(IS_BOUNDARY(mATri[2])) Nb++;
+ return Nb;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Computes the number of valid neighbors.
+ * \return the number of neighbors. (0 => 3)
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+PxU32 AdjTriangle::ComputeNbNeighbors() const
+{
+ PxU32 Nb = 0;
+ if(!IS_BOUNDARY(mATri[0])) Nb++;
+ if(!IS_BOUNDARY(mATri[1])) Nb++;
+ if(!IS_BOUNDARY(mATri[2])) Nb++;
+ return Nb;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Checks whether the triangle has a particular neighbor or not.
+ * \param tref [in] the triangle reference to look for
+ * \param index [out] the corresponding index in the triangle (NULL if not needed)
+ * \return true if the triangle has the given neighbor
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool AdjTriangle::HasNeighbor(PxU32 tref, PxU32* index) const
+{
+ // ### could be optimized
+ if(!IS_BOUNDARY(mATri[0]) && MAKE_ADJ_TRI(mATri[0])==tref) { if(index) *index = 0; return true; }
+ if(!IS_BOUNDARY(mATri[1]) && MAKE_ADJ_TRI(mATri[1])==tref) { if(index) *index = 1; return true; }
+ if(!IS_BOUNDARY(mATri[2]) && MAKE_ADJ_TRI(mATri[2])==tref) { if(index) *index = 2; return true; }
+ return false;
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Constructor.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+Adjacencies::Adjacencies() : mNbFaces(0), mFaces(NULL)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Destructor.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+Adjacencies::~Adjacencies()
+{
+ PX_DELETE_ARRAY(mFaces);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Computes the number of boundary edges.
+ * \return the number of boundary edges.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+PxU32 Adjacencies::ComputeNbBoundaryEdges() const
+{
+ // Checking
+ if(!mFaces) return 0;
+
+ // Look for boundary edges
+ PxU32 Nb = 0;
+ for(PxU32 i=0;i<mNbFaces;i++)
+ {
+ AdjTriangle* CurTri = &mFaces[i];
+ Nb+=CurTri->ComputeNbBoundaryEdges();
+ }
+ return Nb;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Computes the boundary vertices. A boundary vertex is defined as a vertex shared by at least one boundary edge.
+ * \param nb_verts [in] the number of vertices
+ * \param bound_status [out] a user-provided array of bool
+ * \return true if success. The user-array is filled with true or false (boundary vertex / not boundary vertex)
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+bool Adjacencies::GetBoundaryVertices(PxU32 nb_verts, bool* bound_status) const
+#else
+bool Adjacencies::GetBoundaryVertices(PxU32 nb_verts, bool* bound_status, const Gu::TriangleT<PxU32>* faces) const
+#endif
+{
+ // We need the adjacencies
+ if(!mFaces || !bound_status || !nb_verts)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Adjacencies::GetBoundaryVertices: NULL parameter!");
+ return false;
+ }
+
+#ifndef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ if(!faces)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Adjacencies::GetBoundaryVertices: NULL parameter!");
+ return false;
+ }
+#endif
+
+ // Init
+ PxMemZero(bound_status, nb_verts*sizeof(bool));
+
+ // Loop through faces
+ for(PxU32 i=0;i<mNbFaces;i++)
+ {
+ AdjTriangle* CurTri = &mFaces[i];
+ if(IS_BOUNDARY(CurTri->mATri[0]))
+ {
+ // Two boundary vertices: 0 - 1
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ PxU32 VRef0 = CurTri->v[0]; if(VRef0>=nb_verts) return false; bound_status[VRef0] = true;
+ PxU32 VRef1 = CurTri->v[1]; if(VRef1>=nb_verts) return false; bound_status[VRef1] = true;
+#else
+ PxU32 VRef0 = faces[i].v[0]; if(VRef0>=nb_verts) return false; bound_status[VRef0] = true;
+ PxU32 VRef1 = faces[i].v[1]; if(VRef1>=nb_verts) return false; bound_status[VRef1] = true;
+#endif
+ }
+ if(IS_BOUNDARY(CurTri->mATri[1]))
+ {
+ // Two boundary vertices: 0 - 2
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ PxU32 VRef0 = CurTri->v[0]; if(VRef0>=nb_verts) return false; bound_status[VRef0] = true;
+ PxU32 VRef1 = CurTri->v[2]; if(VRef1>=nb_verts) return false; bound_status[VRef1] = true;
+#else
+ PxU32 VRef0 = faces[i].v[0]; if(VRef0>=nb_verts) return false; bound_status[VRef0] = true;
+ PxU32 VRef1 = faces[i].v[2]; if(VRef1>=nb_verts) return false; bound_status[VRef1] = true;
+#endif
+ }
+ if(IS_BOUNDARY(CurTri->mATri[2]))
+ {
+ // Two boundary vertices: 1 - 2
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ PxU32 VRef0 = CurTri->v[1]; if(VRef0>=nb_verts) return false; bound_status[VRef0] = true;
+ PxU32 VRef1 = CurTri->v[2]; if(VRef1>=nb_verts) return false; bound_status[VRef1] = true;
+#else
+ PxU32 VRef0 = faces[i].v[1]; if(VRef0>=nb_verts) return false; bound_status[VRef0] = true;
+ PxU32 VRef1 = faces[i].v[2]; if(VRef1>=nb_verts) return false; bound_status[VRef1] = true;
+#endif
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Assigns a new edge code to the counterpart link of a given link.
+ * \param link [in] the link to modify - shouldn't be a boundary link
+ * \param edge_nb [in] the new edge number
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+void Adjacencies::AssignNewEdgeCode(PxU32 link, PxU8 edge_nb)
+{
+ if(!IS_BOUNDARY(link))
+ {
+ PxU32 Id = MAKE_ADJ_TRI(link); // Triangle ID
+ PxU32 Edge = GET_EDGE_NB(link); // Counterpart edge ID
+ AdjTriangle* Tri = &mFaces[Id]; // Adjacent triangle
+
+ // Get link whose edge code is invalid
+ PxU32 AdjLink = Tri->mATri[Edge]; // Link to ourself (i.e. to 'link')
+ SET_EDGE_NB(AdjLink, edge_nb); // Assign new edge code
+ Tri->mATri[Edge] = AdjLink; // Put link back
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Modifies the existing database so that reference 'vref' of triangle 'curtri' becomes the last one.
+ * Provided reference must already exist in provided triangle.
+ * \param cur_tri [in] the triangle
+ * \param vref [in] the reference
+ * \return true if success.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+bool Adjacencies::MakeLastRef(AdjTriangle& cur_tri, PxU32 vref)
+#else
+bool Adjacencies::MakeLastRef(AdjTriangle& cur_tri, PxU32 vref, Gu::TriangleT<PxU32>* cur_topo)
+#endif
+{
+#ifndef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ // Checkings
+ if(!cur_topo)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Adjacencies::MakeLastRef: NULL parameter!");
+ return false;
+ }
+#endif
+ // We want pattern (x y vref)
+ // Edge 0-1 is (x y)
+ // Edge 0-2 is (x vref)
+ // Edge 1-2 is (y vref)
+
+ // First thing is to scroll the existing references in order for vref to become the last one. Scrolling assures winding order is conserved.
+
+ // Edge code need fixing as well:
+ // The two MSB for each link encode the counterpart edge in adjacent triangle. We swap the link positions, but adjacent triangles remain the
+ // same. In other words, edge codes are still valid for current triangle since counterpart edges have not been swapped. *BUT* edge codes of
+ // the three possible adjacent triangles *are* now invalid. We need to fix edge codes, but for adjacent triangles...
+
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ if(cur_tri.v[0]==vref)
+#else
+ if(cur_topo->v[0]==vref)
+#endif
+ {
+ // Pattern is (vref x y)
+ // Edge 0-1 is (vref x)
+ // Edge 0-2 is (vref y)
+ // Edge 1-2 is (x y)
+
+ // Catch original data
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ PxU32 Ref0 = cur_tri.v[0]; PxU32 Link01 = cur_tri.mATri[0];
+ PxU32 Ref1 = cur_tri.v[1]; PxU32 Link02 = cur_tri.mATri[1];
+ PxU32 Ref2 = cur_tri.v[2]; PxU32 Link12 = cur_tri.mATri[2];
+
+ // Swap
+ cur_tri.v[0] = Ref1;
+ cur_tri.v[1] = Ref2;
+ cur_tri.v[2] = Ref0;
+#else
+ PxU32 Ref0 = cur_topo->v[0]; PxU32 Link01 = cur_tri.mATri[0];
+ PxU32 Ref1 = cur_topo->v[1]; PxU32 Link02 = cur_tri.mATri[1];
+ PxU32 Ref2 = cur_topo->v[2]; PxU32 Link12 = cur_tri.mATri[2];
+
+ // Swap
+ cur_topo->v[0] = Ref1;
+ cur_topo->v[1] = Ref2;
+ cur_topo->v[2] = Ref0;
+#endif
+ cur_tri.mATri[0] = Link12; // Edge 0-1 now encodes Ref1-Ref2, i.e. previous Link12
+ cur_tri.mATri[1] = Link01; // Edge 0-2 now encodes Ref1-Ref0, i.e. previous Link01
+ cur_tri.mATri[2] = Link02; // Edge 1-2 now encodes Ref2-Ref0, i.e. previous Link02
+
+ // Fix edge codes
+ AssignNewEdgeCode(Link01, 1);
+ AssignNewEdgeCode(Link02, 2);
+ AssignNewEdgeCode(Link12, 0);
+
+ return true;
+ }
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ else if(cur_tri.v[1]==vref)
+#else
+ else if(cur_topo->v[1]==vref)
+#endif
+ {
+ // Pattern is (x vref y)
+ // Edge 0-1 is (x vref)
+ // Edge 0-2 is (x y)
+ // Edge 1-2 is (vref y)
+
+ // Catch original data
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ PxU32 Ref0 = cur_tri.v[0]; PxU32 Link01 = cur_tri.mATri[0];
+ PxU32 Ref1 = cur_tri.v[1]; PxU32 Link02 = cur_tri.mATri[1];
+ PxU32 Ref2 = cur_tri.v[2]; PxU32 Link12 = cur_tri.mATri[2];
+
+ // Swap
+ cur_tri.v[0] = Ref2;
+ cur_tri.v[1] = Ref0;
+ cur_tri.v[2] = Ref1;
+#else
+ PxU32 Ref0 = cur_topo->v[0]; PxU32 Link01 = cur_tri.mATri[0];
+ PxU32 Ref1 = cur_topo->v[1]; PxU32 Link02 = cur_tri.mATri[1];
+ PxU32 Ref2 = cur_topo->v[2]; PxU32 Link12 = cur_tri.mATri[2];
+
+ // Swap
+ cur_topo->v[0] = Ref2;
+ cur_topo->v[1] = Ref0;
+ cur_topo->v[2] = Ref1;
+#endif
+ cur_tri.mATri[0] = Link02; // Edge 0-1 now encodes Ref2-Ref0, i.e. previous Link02
+ cur_tri.mATri[1] = Link12; // Edge 0-2 now encodes Ref2-Ref1, i.e. previous Link12
+ cur_tri.mATri[2] = Link01; // Edge 1-2 now encodes Ref0-Ref1, i.e. previous Link01
+
+ // Fix edge codes
+ AssignNewEdgeCode(Link01, 2);
+ AssignNewEdgeCode(Link02, 0);
+ AssignNewEdgeCode(Link12, 1);
+
+ return true;
+ }
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ else if(cur_tri.v[2]==vref)
+#else
+ else if(cur_topo->v[2]==vref)
+#endif
+ {
+ // Nothing to do, provided reference already is the last one
+ return true;
+ }
+
+ // Here the provided reference doesn't belong to the provided triangle.
+ return false;
+}
+
+bool Adjacencies::Load(PxInputStream& stream)
+{
+ // Import header
+ PxU32 Version;
+ bool Mismatch;
+ if(!ReadHeader('A', 'D', 'J', 'A', Version, Mismatch, stream))
+ return false;
+
+ // Import adjacencies
+ mNbFaces = readDword(Mismatch, stream);
+ mFaces = PX_NEW(AdjTriangle)[mNbFaces];
+ stream.read(mFaces, sizeof(AdjTriangle)*mNbFaces);
+
+ return true;
+}
+
+//#ifdef PX_COOKING
+
+ //! An edge class used to compute the adjacency structures.
+ class AdjEdge : public Gu::EdgeData, public Ps::UserAllocated
+ {
+ public:
+ //! Constructor
+ PX_INLINE AdjEdge() {}
+ //! Destructor
+ PX_INLINE ~AdjEdge() {}
+
+ PxU32 mFaceNb; //!< Owner face
+ };
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /**
+ * Adds a new edge to the database.
+ * \param ref0 [in] vertex reference for the new edge
+ * \param ref1 [in] vertex reference for the new edge
+ * \param face [in] owner face
+ */
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ static void AddEdge(PxU32 ref0, PxU32 ref1, PxU32 face, PxU32& nb_edges, AdjEdge* edges)
+ {
+ // Store edge data
+ edges[nb_edges].Ref0 = ref0;
+ edges[nb_edges].Ref1 = ref1;
+ edges[nb_edges].mFaceNb = face;
+ nb_edges++;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /**
+ * Adds a new triangle to the database.
+ * \param ref0 [in] vertex reference for the new triangle
+ * \param ref1 [in] vertex reference for the new triangle
+ * \param ref2 [in] vertex reference for the new triangle
+ * \param id [in] triangle index
+ */
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ static void AddTriangle(PxU32 ref0, PxU32 ref1, PxU32 ref2, PxU32 id, AdjTriangle* faces, PxU32& nb_edges, AdjEdge* edges)
+ {
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ // Store vertex-references
+ faces[id].v[0] = ref0;
+ faces[id].v[1] = ref1;
+ faces[id].v[2] = ref2;
+#endif
+ // Reset links
+ faces[id].mATri[0] = PX_INVALID_U32;
+ faces[id].mATri[1] = PX_INVALID_U32;
+ faces[id].mATri[2] = PX_INVALID_U32;
+
+ // Add edge 01 to database
+ if(ref0<ref1) AddEdge(ref0, ref1, id, nb_edges, edges);
+ else AddEdge(ref1, ref0, id, nb_edges, edges);
+ // Add edge 02 to database
+ if(ref0<ref2) AddEdge(ref0, ref2, id, nb_edges, edges);
+ else AddEdge(ref2, ref0, id, nb_edges, edges);
+ // Add edge 12 to database
+ if(ref1<ref2) AddEdge(ref1, ref2, id, nb_edges, edges);
+ else AddEdge(ref2, ref1, id, nb_edges, edges);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /**
+ * Updates the links in two adjacent triangles.
+ * \param first_tri [in] index of the first triangle
+ * \param second_tri [in] index of the second triangle
+ * \param ref0 [in] the common edge's first vertex reference
+ * \param ref1 [in] the common edge's second vertex reference
+ * \return true if success.
+ */
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ static bool UpdateLink(PxU32 first_tri, PxU32 second_tri, PxU32 ref0, PxU32 ref1, AdjTriangle* faces)
+#else
+ static bool UpdateLink(PxU32 first_tri, PxU32 second_tri, PxU32 ref0, PxU32 ref1, AdjTriangle* faces, const ADJACENCIESCREATE& create)
+#endif
+ {
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ AdjTriangle& Tri0 = faces[first_tri]; // Catch the first triangle
+ AdjTriangle& Tri1 = faces[second_tri]; // Catch the second triangle
+
+ // Get the edge IDs. 0xff means input references are wrong.
+ PxU8 EdgeNb0 = Tri0.FindEdge(ref0, ref1); if(EdgeNb0==0xff) return SetIceError("Adjacencies::UpdateLink: invalid edge reference in first triangle");
+ PxU8 EdgeNb1 = Tri1.FindEdge(ref0, ref1); if(EdgeNb1==0xff) return SetIceError("Adjacencies::UpdateLink: invalid edge reference in second triangle");
+
+ // Update links. The two most significant bits contain the counterpart edge's ID.
+ Tri0.mATri[EdgeNb0] = second_tri |(PxU32(EdgeNb1)<<30);
+ Tri1.mATri[EdgeNb1] = first_tri |(PxU32(EdgeNb0)<<30);
+#else
+ Gu::TriangleT<PxU32> FirstTri, SecondTri;
+ if(create.DFaces)
+ {
+ FirstTri.v[0] = create.DFaces[first_tri*3+0];
+ FirstTri.v[1] = create.DFaces[first_tri*3+1];
+ FirstTri.v[2] = create.DFaces[first_tri*3+2];
+ SecondTri.v[0] = create.DFaces[second_tri*3+0];
+ SecondTri.v[1] = create.DFaces[second_tri*3+1];
+ SecondTri.v[2] = create.DFaces[second_tri*3+2];
+ }
+ if(create.WFaces)
+ {
+ FirstTri.v[0] = create.WFaces[first_tri*3+0];
+ FirstTri.v[1] = create.WFaces[first_tri*3+1];
+ FirstTri.v[2] = create.WFaces[first_tri*3+2];
+ SecondTri.v[0] = create.WFaces[second_tri*3+0];
+ SecondTri.v[1] = create.WFaces[second_tri*3+1];
+ SecondTri.v[2] = create.WFaces[second_tri*3+2];
+ }
+
+ // Get the edge IDs. 0xff means input references are wrong.
+ const PxU8 EdgeNb0 = FirstTri.findEdge(ref0, ref1);
+ const PxU8 EdgeNb1 = SecondTri.findEdge(ref0, ref1);
+ if(EdgeNb0==0xff || EdgeNb1==0xff)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Adjacencies::UpdateLink: invalid edge reference");
+ return false;
+ }
+
+ // Update links. The two most significant bits contain the counterpart edge's ID.
+ faces[first_tri].mATri[EdgeNb0] = second_tri |(PxU32(EdgeNb1)<<30);
+ faces[second_tri].mATri[EdgeNb1] = first_tri |(PxU32(EdgeNb0)<<30);
+#endif
+ return true;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ /**
+ * Creates the adjacency structures.
+ * \return true if success.
+ */
+ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ static bool CreateDatabase(AdjTriangle* faces, PxU32 nb_edges, const AdjEdge* edges)
+#else
+ static bool CreateDatabase(AdjTriangle* faces, PxU32 nb_edges, const AdjEdge* edges, const ADJACENCIESCREATE& create)
+#endif
+ {
+ Cm::RadixSortBuffered Core;
+ {
+ // Multiple sorts - this rewritten version uses less ram
+ // PT: TTP 2994: the mesh has 343000+ edges, so yeah, sure, allocating more than 1mb on the stack causes overflow...
+ PxU32* VRefs = PX_NEW_TEMP(PxU32)[nb_edges];
+
+ // Sort according to mRef0, then mRef1
+ PxU32 i;
+ for(i=0;i<nb_edges;i++)
+ VRefs[i] = edges[i].Ref0;
+ Core.Sort(VRefs, nb_edges);
+ for(i=0;i<nb_edges;i++)
+ VRefs[i] = edges[i].Ref1;
+ Core.Sort(VRefs, nb_edges);
+
+ PX_DELETE_POD(VRefs);
+ }
+ const PxU32* Sorted = Core.GetRanks();
+
+ // Read the list in sorted order, look for similar edges
+ PxU32 LastRef0 = edges[Sorted[0]].Ref0;
+ PxU32 LastRef1 = edges[Sorted[0]].Ref1;
+ PxU32 Count = 0;
+ PxU32 TmpBuffer[3];
+
+ while(nb_edges--)
+ {
+ PxU32 SortedIndex = *Sorted++;
+ PxU32 Face = edges[SortedIndex].mFaceNb; // Owner face
+ PxU32 Ref0 = edges[SortedIndex].Ref0; // Vertex ref #1
+ PxU32 Ref1 = edges[SortedIndex].Ref1; // Vertex ref #2
+ if(Ref0==LastRef0 && Ref1==LastRef1)
+ {
+ // Current edge is the same as last one
+ TmpBuffer[Count++] = Face; // Store face number
+ // Only works with manifold meshes (i.e. an edge is not shared by more than 2 triangles)
+ if(Count==3)
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "Adjacencies::CreateDatabase: can't work on non-manifold meshes.");
+ return false;
+ }
+ }
+ else
+ {
+ // Here we have a new edge (LastRef0, LastRef1) shared by Count triangles stored in TmpBuffer
+ if(Count==2)
+ {
+ // if Count==1 => edge is a boundary edge: it belongs to a single triangle.
+ // Hence there's no need to update a link to an adjacent triangle.
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ if(!UpdateLink(TmpBuffer[0], TmpBuffer[1], LastRef0, LastRef1, faces)) return false;
+#else
+ if(!UpdateLink(TmpBuffer[0], TmpBuffer[1], LastRef0, LastRef1, faces, create)) return false;
+#endif
+ }
+ // Reset for next edge
+ Count = 0;
+ TmpBuffer[Count++] = Face;
+ LastRef0 = Ref0;
+ LastRef1 = Ref1;
+ }
+ }
+ bool Status = true;
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ if(Count==2) Status = UpdateLink(TmpBuffer[0], TmpBuffer[1], LastRef0, LastRef1, faces);
+#else
+ if(Count==2) Status = UpdateLink(TmpBuffer[0], TmpBuffer[1], LastRef0, LastRef1, faces, create);
+#endif
+ return Status;
+ }
+
+AdjacenciesBuilder::AdjacenciesBuilder()
+{
+}
+
+AdjacenciesBuilder::~AdjacenciesBuilder()
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Initializes the component.
+ * \param create [in] the creation structure
+ * \return true if success.
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+bool AdjacenciesBuilder::Init(const ADJACENCIESCREATE& create)
+{
+ // Checkings
+ if(!create.NbFaces) return false;
+
+ // Get some bytes
+ mNbFaces = create.NbFaces;
+ mFaces = PX_NEW(AdjTriangle)[mNbFaces];
+
+ AdjEdge* Edges = PX_NEW_TEMP(AdjEdge)[mNbFaces*3];
+ PxU32 NbEdges=0;
+
+ // Feed me with triangles.....
+ for(PxU32 i=0;i<mNbFaces;i++)
+ {
+ // Get correct vertex references
+ const PxU32 Ref0 = create.DFaces ? create.DFaces[i*3+0] : create.WFaces ? create.WFaces[i*3+0] : 0;
+ const PxU32 Ref1 = create.DFaces ? create.DFaces[i*3+1] : create.WFaces ? create.WFaces[i*3+1] : 1;
+ const PxU32 Ref2 = create.DFaces ? create.DFaces[i*3+2] : create.WFaces ? create.WFaces[i*3+2] : 2;
+
+ // Add a triangle to the database
+ AddTriangle(Ref0, Ref1, Ref2, i, mFaces, NbEdges, Edges);
+ }
+
+ // At this point of the process we have mFaces & Edges filled with input data. That is:
+ // - a list of triangles with 3 NULL links (i.e. PX_INVALID_U32)
+ // - a list of mNbFaces*3 edges, each edge having 2 vertex references and an owner face.
+
+ // Here NbEdges should be equal to mNbFaces*3.
+ PX_ASSERT(NbEdges==mNbFaces*3);
+
+#ifdef MSH_ADJACENCIES_INCLUDE_TOPOLOGY
+ bool Status = CreateDatabase(mFaces, NbEdges, Edges);
+#else
+ bool Status = CreateDatabase(mFaces, NbEdges, Edges, create);
+#endif
+
+ // We don't need the edges anymore
+ PX_DELETE_ARRAY(Edges);
+
+#ifdef MSH_ADJACENCIES_INCLUDE_CONVEX_BITS
+ // Now create convex information. This creates coupling between adjacencies & edge-list but in this case it's actually the goal:
+ // mixing the two structures to save memory.
+ if(Status && create.Verts)
+ {
+ Gu::EDGELISTCREATE ELC;
+ ELC.NbFaces = create.NbFaces;
+ ELC.DFaces = create.DFaces; // That's where I like having a unified way to do things... We
+ ELC.WFaces = create.WFaces; // can just directly copy the same pointers.
+ ELC.FacesToEdges = true;
+ ELC.Verts = create.Verts;
+ ELC.Epsilon = create.Epsilon;
+
+ Gu::EdgeListBuilder EL;
+ if(EL.init(ELC))
+ {
+ for(PxU32 i=0;i<mNbFaces;i++)
+ {
+ const Gu::EdgeTriangleData& ET = EL.getEdgeTriangle(i);
+ if(Gu::EdgeTriangleAC::HasActiveEdge01(ET)) mFaces[i].mATri[EDGE01] |= 0x20000000;
+ else mFaces[i].mATri[EDGE01] &= ~0x20000000;
+ if(Gu::EdgeTriangleAC::HasActiveEdge20(ET)) mFaces[i].mATri[EDGE02] |= 0x20000000;
+ else mFaces[i].mATri[EDGE02] &= ~0x20000000;
+ if(Gu::EdgeTriangleAC::HasActiveEdge12(ET)) mFaces[i].mATri[EDGE12] |= 0x20000000;
+ else mFaces[i].mATri[EDGE12] &= ~0x20000000;
+
+ PX_ASSERT((Gu::EdgeTriangleAC::HasActiveEdge01(ET) && mFaces[i].HasActiveEdge01()) || (!Gu::EdgeTriangleAC::HasActiveEdge01(ET) && !mFaces[i].HasActiveEdge01()));
+ PX_ASSERT((Gu::EdgeTriangleAC::HasActiveEdge20(ET) && mFaces[i].HasActiveEdge20()) || (!Gu::EdgeTriangleAC::HasActiveEdge20(ET) && !mFaces[i].HasActiveEdge20()));
+ PX_ASSERT((Gu::EdgeTriangleAC::HasActiveEdge12(ET) && mFaces[i].HasActiveEdge12()) || (!Gu::EdgeTriangleAC::HasActiveEdge12(ET) && !mFaces[i].HasActiveEdge12()));
+ }
+ }
+ }
+#endif
+
+ return Status;
+}
+/*
+bool AdjacenciesBuilder::Save(Stream& stream) const
+{
+ bool PlatformMismatch = PxPlatformMismatch();
+
+ // Export header
+ if(!WriteHeader('A', 'D', 'J', 'A', gVersion, PlatformMismatch, stream))
+ return false;
+
+ // Export adjacencies
+// stream.StoreDword(mNbFaces);
+ WriteDword(mNbFaces, PlatformMismatch, stream);
+
+// stream.StoreBuffer(mFaces, sizeof(AdjTriangle)*mNbFaces);
+ WriteDwordBuffer((const PxU32*)mFaces, mNbFaces*3, PlatformMismatch, stream);
+
+ return true;
+}*/
+//#endif