Projekt_Grafika/dependencies/physx-4.1/source/physxcooking/src/Adjacencies.cpp

713 lines
28 KiB
C++

//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2019 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