PxU32 PxParticleExt::buildBoundsHash(PxU32* sortedParticleIndices,
									 ParticleBounds* particleBounds,
									 const PxStrideIterator<const PxVec3>& positionBuffer,
									 const PxU32 validParticleRange,
									 const PxU32* validParticleBitmap,
									 const PxU32 hashSize,
									 const PxU32 maxBounds,
									 const PxReal gridSpacing)
{
	// test if hash size is a multiple of 2
	PX_ASSERT((((hashSize - 1) ^ hashSize) + 1) == (2 * hashSize));
	PX_ASSERT(maxBounds <= hashSize);

	PxReal cellSizeInv = 1.0f / gridSpacing;

	Ps::Array<PxU32> particleToCellMap PX_DEBUG_EXP("buildBoundsHashCellMap"); 	
	particleToCellMap.resize(validParticleRange);

	// initialize cells
	Ps::Array<Cell> cells PX_DEBUG_EXP("buildBoundsCells");
	cells.resize(hashSize);
	PxMemSet(cells.begin(), sInvalidIndex, sizeof(Cell) * hashSize);

	// count number of particles per cell
	PxU32 entryCounter = 0;

	if (validParticleRange > 0)
	{
		for (PxU32 w = 0; w <= (validParticleRange-1) >> 5; w++)
			for (PxU32 b = validParticleBitmap[w]; b; b &= b-1)
			{
				PxU32 index = (w<<5|Ps::lowestSetBit(b));
				const PxVec3& position = positionBuffer[index];

				PxU32& cellIndex = particleToCellMap[index];
				cellIndex = sInvalidIndex;	// initialize to invalid in case we reach maxBounds	
				if (entryCounter < maxBounds)
				{
					CellCoords particleCoords;
					particleCoords.set(position, cellSizeInv);
					cellIndex = getEntry(particleCoords, hashSize, cells.begin());
					PX_ASSERT(cellIndex != sInvalidIndex);

					Cell& cell = cells[cellIndex];
					if (cell.size == sInvalidIndex)
					{
						// this is the first particle in this cell
						cell.coords = particleCoords;
						cell.aabb = PxBounds3(position, position);
						cell.size = 1;
						++entryCounter;
					}
					else
					{
						// the cell is already occupied
						cell.aabb.include(position);
						++cell.size;
					}
				}
			}
	}


	// accumulate start indices from cell size histogram and write to the user's particleBounds buffer
	PxU32 numBounds = 0;
	for (PxU32 i = 0, counter = 0; i < cells.size(); i++)
	{
		Cell& cell = cells[i];
		if (cell.size != sInvalidIndex)
		{
			cell.start = counter;
			counter += cell.size;
			
			PxParticleExt::ParticleBounds& cellBounds = particleBounds[numBounds++];
			PX_ASSERT(cell.aabb.isValid());
			cellBounds.bounds = cell.aabb;
			cellBounds.firstParticle = cell.start;
			cellBounds.numParticles = cell.size;
			
			cell.size = 0;
		}
	}

	// sort output particle indices by cell
	if (validParticleRange > 0)
	{
		for (PxU32 w = 0; w <= (validParticleRange-1) >> 5; w++)
			for (PxU32 b = validParticleBitmap[w]; b; b &= b-1)
			{
				PxU32 index = (w<<5|Ps::lowestSetBit(b));
				PxU32 cellIndex = particleToCellMap[index];
				if (cellIndex != sInvalidIndex)
				{
					Cell& cell = cells[cellIndex];
					PX_ASSERT(cell.start != sInvalidIndex && cell.size != sInvalidIndex);
					sortedParticleIndices[cell.start + cell.size] = index;
					++cell.size;
				}
			}
	}
	
	return numBounds;
}
void DeformableMesh::weldMesh()
{
	mVertexToParticleMap.resize(mVertexPositions.size());

	if (mPrimitiveType == PxDeformablePrimitiveType::eTRIANGLE && (mFlags & PxDeformableMeshFlag::eWELD_VERTICES) != 0)
	{
		Ps::Array<int> order PX_DEBUG_EXP("defoMeshOrder");
		order.resize(mVertexPositions.size());
		for (PxU32 i = 0; i < order.size(); i++)
			order[i] = i;

		// sort vertices by their x coordinate
		Ps::sort(order.begin(), order.size(), WeldComparator(mVertexPositions));

		// generate permutation table which welds similar vertices
		for (PxU32 i = 0; i < mVertexPositions.size(); i++)
			mVertexToParticleMap[i] = PX_MAX_U32;

		int newNr = 0;
		PxReal mWeldingDistanceSq = mWeldingDistance * mWeldingDistance;
		for (PxU32 i = 0; i < mVertexPositions.size(); i++) 
		{
			int oldNr = order[i];
			if (mVertexToParticleMap[oldNr] != PX_MAX_U32)
				continue;
			
			mVertexToParticleMap[oldNr] = newNr;
			PxVec3 vi = mVertexPositions[oldNr];
			PxU32 j = i+1;
			while (j < mVertexPositions.size() && PxAbs(vi.x - mVertexPositions[order[j]].x) <= mWeldingDistance) 
			{
				oldNr = order[j];
				if ((vi-mVertexPositions[oldNr]).magnitudeSquared() <= mWeldingDistanceSq) 
				{
					if (mVertexToParticleMap[oldNr] == PX_MAX_U32)
						mVertexToParticleMap[oldNr] = newNr;
				}
				j++;
			}
			newNr++;
		}
		mNumWeldedVertices = newNr;
	}
	else
	{
		// Welding not enabled. We use an identity permutation.
		for (PxU32 i = 0; i < mVertexToParticleMap.size(); i++)
			mVertexToParticleMap[i] = i;

#if 0
		Ps::Array<int> order;
		order.resize(mVertexPositions.size());
		for (PxU32 i = 0; i < order.size(); i++)
			order[i] = i;
		Ps::sort(order.begin(), order.size(), WeldComparator(mVertexPositions));
		for (PxU32 i = 0; i < mVertexToParticleMap.size(); i++)
			mVertexToParticleMap[i] = order[i];
#endif

		mNumWeldedVertices = mVertexPositions.size();
	}

	mWeldedVertices.resize(mNumWeldedVertices);
	for (PxU32 i = 0; i < mVertexPositions.size(); i++)
		mWeldedVertices[mVertexToParticleMap[i]] = mVertexPositions[i];
}