diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/PhysXCooking/src/Adjacencies.cpp | |
| download | physx-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.cpp | 712 |
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 |