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;
}
Beispiel #3
0
	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;
	}
Beispiel #4
0
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;
}