bool Cm::CompleteBoxPruning(const PxBounds3* bounds, PxU32 nb, Ps::Array<PxU32>& pairs, const Axes& axes) { pairs.clear(); // Checkings if(!nb) return false; // Catch axes const PxU32 Axis0 = axes.mAxis0; const PxU32 Axis1 = axes.mAxis1; const PxU32 Axis2 = axes.mAxis2; PX_UNUSED(Axis1); PX_UNUSED(Axis2); // Allocate some temporary data float* PosList = reinterpret_cast<float*>(PX_ALLOC_TEMP(sizeof(float)*nb, "Cm::CompleteBoxPruning")); // 1) Build main list using the primary axis for(PxU32 i=0;i<nb;i++) PosList[i] = bounds[i].minimum[Axis0]; // 2) Sort the list /*static*/ RadixSortBuffered RS; // Static for coherence const PxU32* Sorted = RS.Sort(PosList, nb).GetRanks(); // 3) Prune the list const PxU32* const LastSorted = &Sorted[nb]; const PxU32* RunningAddress = Sorted; PxU32 Index0, Index1; while(RunningAddress<LastSorted && Sorted<LastSorted) { Index0 = *Sorted++; while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]); const PxU32* RunningAddress2 = RunningAddress; while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=bounds[Index0].maximum[Axis0]) { if(Index0!=Index1) { if(bounds[Index0].intersects(bounds[Index1])) { pairs.pushBack(Index0); pairs.pushBack(Index1); } } } } PX_FREE(PosList); return true; }
bool ReducedVertexCloud::Reduce(REDUCEDCLOUD* rc) { Clean(); mXRef = PX_NEW(PxU32)[mNbVerts]; float* f = PX_NEW_TEMP(float)[mNbVerts]; for(PxU32 i=0;i<mNbVerts;i++) f[i] = mVerts[i].x; RadixSortBuffered Radix; Radix.Sort(reinterpret_cast<const PxU32*>(f), mNbVerts, RADIX_UNSIGNED); for(PxU32 i=0;i<mNbVerts;i++) f[i] = mVerts[i].y; Radix.Sort(reinterpret_cast<const PxU32*>(f), mNbVerts, RADIX_UNSIGNED); for(PxU32 i=0;i<mNbVerts;i++) f[i] = mVerts[i].z; const PxU32* Sorted = Radix.Sort(reinterpret_cast<const PxU32*>(f), mNbVerts, RADIX_UNSIGNED).GetRanks(); PX_DELETE_POD(f); mNbRVerts = 0; const PxU32 Junk[] = {PX_INVALID_U32, PX_INVALID_U32, PX_INVALID_U32}; const PxU32* Previous = Junk; mRVerts = reinterpret_cast<PxVec3*>(PX_ALLOC(sizeof(PxVec3) * mNbVerts, "PxVec3")); PxU32 Nb = mNbVerts; while(Nb--) { const PxU32 Vertex = *Sorted++; // Vertex number const PxU32* current = reinterpret_cast<const PxU32*>(&mVerts[Vertex]); if(current[0]!=Previous[0] || current[1]!=Previous[1] || current[2]!=Previous[2]) mRVerts[mNbRVerts++] = mVerts[Vertex]; Previous = current; mXRef[Vertex] = mNbRVerts-1; } if(rc) { rc->CrossRef = mXRef; rc->NbRVerts = mNbRVerts; rc->RVerts = mRVerts; } return true; }
static bool CreateDatabase(AdjTriangle* faces, PxU32 nb_edges, const AdjEdge* edges, const ADJACENCIESCREATE& create) #endif { RadixSortBuffered Core; { // Multiple sorts - this rewritten version uses less ram // PT: TTP 2994: the stupid mesh has 343000+ edges, so yeah, sure, allocating more than 1mb on the stack causes overflow. Sigh. 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) { PX_ASSERT(!"Adjacencies: found non-manifold mesh!"); 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; }
bool Gu::EdgeListBuilder::CreateFacesToEdges(PxU32 nb_faces, const PxU32* dfaces, const PxU16* wfaces) { // Checkings if(!nb_faces || (!dfaces && !wfaces)) { Ps::getFoundation().error(PxErrorCode::eINVALID_OPERATION, __FILE__, __LINE__, "EdgeList::CreateFacesToEdges: NULL parameter!"); return false; } if(mData.mEdgeFaces) return true; // Already computed! // 1) Get some bytes: I need one EdgesRefs for each face, and some temp buffers mData.mEdgeFaces = PX_NEW(Gu::EdgeTriangleData)[nb_faces]; // Link faces to edges PxU32* VRefs0 = PX_NEW_TEMP(PxU32)[nb_faces*3]; // Temp storage PxU32* VRefs1 = PX_NEW_TEMP(PxU32)[nb_faces*3]; // Temp storage Gu::EdgeData* Buffer = PX_NEW_TEMP(Gu::EdgeData)[nb_faces*3]; // Temp storage // 2) Create a full redundant list of 3 edges / face. for(PxU32 i=0;i<nb_faces;i++) { // Get right vertex-references const PxU32 Ref0 = dfaces ? dfaces[i*3+0] : wfaces ? wfaces[i*3+0] : 0; const PxU32 Ref1 = dfaces ? dfaces[i*3+1] : wfaces ? wfaces[i*3+1] : 1; const PxU32 Ref2 = dfaces ? dfaces[i*3+2] : wfaces ? wfaces[i*3+2] : 2; // Pre-Sort vertex-references and put them in the lists if(Ref0<Ref1) { VRefs0[i*3+0] = Ref0; VRefs1[i*3+0] = Ref1; } // Edge 0-1 maps (i%3) else { VRefs0[i*3+0] = Ref1; VRefs1[i*3+0] = Ref0; } // Edge 0-1 maps (i%3) if(Ref1<Ref2) { VRefs0[i*3+1] = Ref1; VRefs1[i*3+1] = Ref2; } // Edge 1-2 maps (i%3)+1 else { VRefs0[i*3+1] = Ref2; VRefs1[i*3+1] = Ref1; } // Edge 1-2 maps (i%3)+1 if(Ref2<Ref0) { VRefs0[i*3+2] = Ref2; VRefs1[i*3+2] = Ref0; } // Edge 2-0 maps (i%3)+2 else { VRefs0[i*3+2] = Ref0; VRefs1[i*3+2] = Ref2; } // Edge 2-0 maps (i%3)+2 } // 3) Sort the list according to both keys (VRefs0 and VRefs1) RadixSortBuffered Sorter; const PxU32* Sorted = Sorter.Sort(VRefs1, nb_faces*3).Sort(VRefs0, nb_faces*3).GetRanks(); // 4) Loop through all possible edges // - clean edges list by removing redundant edges // - create EdgesRef list mData.mNbEdges = 0; // #non-redundant edges mData.mNbFaces = nb_faces; PxU32 PreviousRef0 = PX_INVALID_U32; PxU32 PreviousRef1 = PX_INVALID_U32; for(PxU32 i=0;i<nb_faces*3;i++) { PxU32 Face = Sorted[i]; // Between 0 and nbfaces*3 PxU32 ID = Face % 3; // Get edge ID back. PxU32 SortedRef0 = VRefs0[Face]; // (SortedRef0, SortedRef1) is the sorted edge PxU32 SortedRef1 = VRefs1[Face]; if(SortedRef0!=PreviousRef0 || SortedRef1!=PreviousRef1) { // New edge found! => stored in temp buffer Buffer[mData.mNbEdges].Ref0 = SortedRef0; Buffer[mData.mNbEdges].Ref1 = SortedRef1; mData.mNbEdges++; } PreviousRef0 = SortedRef0; PreviousRef1 = SortedRef1; // Create mEdgesRef on the fly mData.mEdgeFaces[Face/3].mLink[ID] = mData.mNbEdges-1; } // 5) Here, mNbEdges==#non redundant edges mData.mEdges = (Gu::EdgeData*)PX_ALLOC(sizeof(Gu::EdgeData)*mData.mNbEdges); // Create real edges-list. Ps::memCopy(mData.mEdges, Buffer, mData.mNbEdges*sizeof(Gu::EdgeData)); // 6) Free ram and exit PX_DELETE_POD(Buffer); PX_DELETE_POD(VRefs1); PX_DELETE_POD(VRefs0); return true; }