void DeformableMesh::generateConstraintsFromTriangles()
{
	PxU32 numTriangles = mPrimitives.size() / 3;

	DeformableTriEdge e;
	Ps::Array<DeformableTriEdge> edges PX_DEBUG_EXP("defoMeshEdges");
	edges.reserve(numTriangles * 3);
	const PxU32 *i0 = mPrimitives.begin();

	for (PxU32 i = 0; i < numTriangles; i++, i0 += 3) 
	{
		const PxU32 *i1 = i0+1;
		const PxU32 *i2 = i0+2;
		e.set(mVertexToParticleMap[*i0], mVertexToParticleMap[*i1], mVertexToParticleMap[*i2], i); 
		edges.pushBack(e);
		e.set(mVertexToParticleMap[*i1], mVertexToParticleMap[*i2], mVertexToParticleMap[*i0], i); 
		edges.pushBack(e);
		e.set(mVertexToParticleMap[*i2], mVertexToParticleMap[*i0], mVertexToParticleMap[*i1], i); 
		edges.pushBack(e);
	}
	quickSortEdges(edges, 0, edges.size()-1);

	DeformableConstraint constraint;
	constraint.particleId[4] = -1;	// only used when torn
	constraint.particleId[5] = -1;	// only used when torn

	for(PxU32 i=0; i<edges.size(); )
	{
		const DeformableTriEdge &e0 = edges[i];
		PxU32 p0 = constraint.particleId[0] = e0.particleId[0];
		PxU32 p1 = constraint.particleId[1] = e0.particleId[1];
		PxVec3 d0 = mWeldedVertices[p1] - mWeldedVertices[p0]; 

		constraint.stretchingRestLength = d0.magnitude();
		constraint.particleId[2] = e0.third;
		constraint.particleId[3] = -1;			// for border edges -> no bending possible
		constraint.bendingRestLength = 0.0f;
		constraint.flags = 0;
		if (++i < edges.size()) {
			const DeformableTriEdge &e1 = edges[i];
			if (e0 == e1) {
				constraint.particleId[2] = e0.third;
				constraint.particleId[3] = e1.third;
				PxVec3 d1 = mWeldedVertices[e1.third] - mWeldedVertices[e0.third]; 
				constraint.bendingRestLength = d1.magnitude();
			}
			while (i < edges.size() && edges[i] == e0)
				++i;
		}
		mConstraints.pushBack(constraint);
	}
}
void DeformableMesh::generateConstraintsFromTetrahedra()
{
	PxU32 edgeIndices[6][2] = { {0,1}, {0,2}, {0,3}, {1,2}, {1,3}, {2,3} };
	PxU32 *tetIndices;

	// - tetrahedra are assumed to be unique (thus no parent code here)

	PxU32 numTetrahedra = mPrimitives.size() / 4;

	DeformableTetraEdge e;
	Ps::Array<DeformableTetraEdge> edges PX_DEBUG_EXP("defoMeshEdges2");
	edges.reserve(numTetrahedra * 6);
	tetIndices = mPrimitives.begin();
	PxU32 i, j;
	for (i = 0; i < numTetrahedra; i++, tetIndices += 4) 
	{
		for(j = 0; j < 6; j++) 
		{
			PxU32 e0 = mVertexToParticleMap[tetIndices[edgeIndices[j][0]]];
			PxU32 e1 = mVertexToParticleMap[tetIndices[edgeIndices[j][1]]];
			e.set(e0, e1, i); edges.pushBack(e);	
		}
	}
	
	quickSortTetraEdges(edges, 0, edges.size()-1);

	mConstraints.resize(numTetrahedra);

	DeformableConstraint constraint;
	DeformableTetraEdge *tetEdges[6];
	tetIndices = mPrimitives.begin();
	
	bool warningIssued = false;
	for (i = 0; i < numTetrahedra; i++, tetIndices += 4) 
	{
		for (j = 0; j < 6; j++) 
		{
			PxU32 e0 = mVertexToParticleMap[tetIndices[edgeIndices[j][0]]];
			PxU32 e1 = mVertexToParticleMap[tetIndices[edgeIndices[j][1]]];
			DeformableTetraEdge goalEdge;
			goalEdge.set(e0, e1, i);
			tetEdges[j] = binarySearchTetraEdge(edges, goalEdge);
		}

		for (j = 0; j < 4; j++)
			constraint.particleId[j] = mVertexToParticleMap[tetIndices[j]];
		
		PxVec3 groundArea = (mWeldedVertices[tetIndices[1]] - mWeldedVertices[tetIndices[0]]).cross(mWeldedVertices[tetIndices[2]] - mWeldedVertices[tetIndices[0]]);
		constraint.restVolume = groundArea.dot(mWeldedVertices[tetIndices[3]] - mWeldedVertices[tetIndices[0]]);
		constraint.flags = 0;

		if (!warningIssued && constraint.restVolume < 0.0f)
		{
			Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, "Soft body mesh tetrahedron %d has illegal winding order.", i);
			warningIssued = true;
		}

		for (j = 0; j < 6; j++) 
		{
			PxU32 e0 = mVertexToParticleMap[tetIndices[edgeIndices[j][0]]];
			PxU32 e1 = mVertexToParticleMap[tetIndices[edgeIndices[j][1]]];
			PxVec3 edgeVec = mWeldedVertices[e1] - mWeldedVertices[e0];
			if(tetEdges[j]) 
			{
				PX_ASSERT(tetEdges[j]->tetrahedron == i);
				constraint.restEdgeLengths[j] = edgeVec.magnitude();
			} 
			else 
				constraint.restEdgeLengths[j] = -edgeVec.magnitude();
		}

		mConstraints[i] = constraint;
	}
}