bool 
Character::getFramePose(PxTransform &rootTransform, SampleArray<PxVec3> &positions, SampleArray<PxU32> &indexBuffers)
{
	if (mCurrentMotion == NULL)
		return false;

	PxU32 frameNo = PxU32(mFrameTime);
	if (frameNo >= mCurrentMotion->mNbFrames)
		return false;

	positions.resize(mNbBones+1);

	// copy precomputed bone position in local space
	positions[0] = PxVec3(0.0f); // root position
	for (PxU32 i = 0; i < mNbBones; i++)
		positions[i+1] = mCurrentBoneTransform[i].p;

	// copy capsule index data
	indexBuffers.resize(mASFData->mNbBones * 2);
	for (PxU32 i = 0; i < mASFData->mNbBones; i++)
	{
		Acclaim::Bone& bone = mASFData->mBones[i];
		indexBuffers[i*2] = bone.mID;
		indexBuffers[i*2+1] = (bone.mParent) ? bone.mParent->mID : 0;
	}

	// compute root transform
	rootTransform = mCharacterPose.transform(mCurrentRootTransform);

	return true;
}
bool
Skin::computeNewPositions(Character &character, SampleArray<PxVec3> &particlePositions)
{
	if (character.mCurrentMotion == NULL)
		return false;

	PxTransform t = character.mCurrentBoneTransform[mBoneID];
	particlePositions.resize(mBindPos.size());

	for (PxU32 i = 0; i < mBindPos.size(); i++)
		particlePositions[i] = t.transform(mBindPos[i]);

	return true;
}
void
SampleCharacterCloth::createCape()
{
	// compute root transform and positions of all the bones
	PxTransform rootPose;
	SampleArray<PxVec3> positions;	
	SampleArray<PxU32> indexPairs;
	mCharacter.getFramePose(rootPose, positions, indexPairs);

	// convert bones to collision capsules
	SampleArray<PxClothCollisionSphere> spheres;	
	spheres.resize(positions.size());
	for (PxU32 i = 0; i < positions.size(); i++)
	{
		spheres[i].pos = positions[i];
		spheres[i].radius = gCharacterScale * gSphereRadius[i];
	}

	PxClothCollisionData collisionData;
	collisionData.numSpheres = static_cast<PxU32>(positions.size());
	collisionData.spheres = spheres.begin();
	collisionData.numPairs = static_cast<PxU32>(indexPairs.size()) / 2; // number of capsules
	collisionData.pairIndexBuffer = indexPairs.begin();

	// create the cloth cape mesh from file
	PxClothMeshDesc meshDesc;
	SampleArray<PxVec3> vertices;
	SampleArray<PxU32> primitives;
	SampleArray<PxReal> uvs;
	const char* capeFileName = getSampleMediaFilename("ctdm_cape_m.obj");
	PxReal clothScale = gCharacterScale * 0.3f;
	PxVec3 offset = PxVec3(0,-1.5,0); 
	PxQuat rot = PxQuat(0, PxVec3(0,1,0));
	Test::ClothHelpers::createMeshFromObj(capeFileName, clothScale, &rot, &offset, 
		vertices, primitives, &uvs, meshDesc);

	if (!meshDesc.isValid()) fatalError("Could not load ctdm_cape_m.obj\n");
	// create the cloth
	PxCloth& cloth = *createClothFromMeshDesc(
		meshDesc, rootPose, &collisionData, PxVec3(0,-1,0),
		uvs.begin(), "dummy_cape_d.bmp", PxVec3(0.5f, 0.5f, 0.5f), 0.8f);

	mCape = &cloth;

	// attach top verts
	PxClothReadData* readData = cloth.lockClothReadData();
	PX_ASSERT(readData);
	PxU32 numParticles = cloth.getNbParticles();
	SampleArray<PxClothParticle> particles(numParticles);
	SampleArray<PxVec3> particlePositions(numParticles);
    for(PxU32 i = 0; i < numParticles; i++)
	{
		particles[i].pos = readData->particles[i].pos;
		particles[i].invWeight = (uvs[i*2+1] > 0.85f) ? 0.0f : readData->particles[i].invWeight;
		particlePositions[i] = readData->particles[i].pos;
	}
	readData->unlock();
	cloth.setParticles(particles.begin(), particles.begin());

	// compute initial skin binding to the character
	mSkin.bindToCharacter(mCharacter, particlePositions);

	// set solver settings
	cloth.setSolverFrequency(240);

	// damp global particle velocity to 90% every 0.1 seconds
	cloth.setDampingCoefficient(0.1f); // damp local particle velocity
	cloth.setDragCoefficient(0.1f); // transfer frame velocity

	// reduce effect of local frame acceleration
	cloth.setInertiaScale(0.3f);
	
	const bool useVirtualParticles = true;
	const bool useSweptContact = true;
	const bool useCustomConfig = true;

	// virtual particles
	if (useVirtualParticles)
		Test::ClothHelpers::createVirtualParticles(cloth, meshDesc, 4);

	// ccd
	cloth.setClothFlag(PxClothFlag::eSWEPT_CONTACT, useSweptContact);

	// use GPU or not
#if PX_SUPPORT_GPU_PHYSX
	cloth.setClothFlag(PxClothFlag::eGPU, mUseGPU);
#endif

	// custom fiber configuration
	if (useCustomConfig)
	{
		PxClothPhaseSolverConfig config;

		config = cloth.getPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING);
		config.solverType = PxClothPhaseSolverConfig::eSTIFF;
		config.stiffness = 1.0f;
		cloth.setPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING, config);

		config = cloth.getPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING_HORIZONTAL);
		config.solverType = PxClothPhaseSolverConfig::eFAST;
		config.stiffness = 1.0f;
		cloth.setPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING_HORIZONTAL, config);

		config = cloth.getPhaseSolverConfig(PxClothFabricPhaseType::eSHEARING);
		config.solverType = PxClothPhaseSolverConfig::eFAST;
		config.stiffness = 0.75f;
		cloth.setPhaseSolverConfig(PxClothFabricPhaseType::eSHEARING, config);

		config = cloth.getPhaseSolverConfig(PxClothFabricPhaseType::eBENDING_ANGLE);
		config.solverType = PxClothPhaseSolverConfig::eBENDING;
		config.stiffness = 0.5f;
		cloth.setPhaseSolverConfig(PxClothFabricPhaseType::eBENDING_ANGLE, config);
	}
}