3710 lines
		
	
	
		
			92 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			3710 lines
		
	
	
		
			92 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						||
Bullet Continuous Collision Detection and Physics Library
 | 
						||
Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
 | 
						||
 | 
						||
This software is provided 'as-is', without any express or implied warranty.
 | 
						||
In no event will the authors be held liable for any damages arising from the use of this software.
 | 
						||
Permission is granted to anyone to use this software for any purpose,
 | 
						||
including commercial applications, and to alter it and redistribute it freely,
 | 
						||
subject to the following restrictions:
 | 
						||
 | 
						||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
 | 
						||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
 | 
						||
3. This notice may not be removed or altered from any source distribution.
 | 
						||
*/
 | 
						||
///btSoftBody implementation by Nathanael Presson
 | 
						||
 | 
						||
#include "btSoftBodyInternals.h"
 | 
						||
#include "BulletSoftBody/btSoftBodySolvers.h"
 | 
						||
#include "btSoftBodyData.h"
 | 
						||
#include "LinearMath/btSerializer.h"
 | 
						||
#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
 | 
						||
#include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
btSoftBody::btSoftBody(btSoftBodyWorldInfo*	worldInfo,int node_count,  const btVector3* x,  const btScalar* m)
 | 
						||
:m_softBodySolver(0),m_worldInfo(worldInfo)
 | 
						||
{	
 | 
						||
	/* Init		*/ 
 | 
						||
	initDefaults();
 | 
						||
 | 
						||
	/* Default material	*/ 
 | 
						||
	Material*	pm=appendMaterial();
 | 
						||
	pm->m_kLST	=	1;
 | 
						||
	pm->m_kAST	=	1;
 | 
						||
	pm->m_kVST	=	1;
 | 
						||
	pm->m_flags	=	fMaterial::Default;
 | 
						||
 | 
						||
	/* Nodes			*/ 
 | 
						||
	const btScalar		margin=getCollisionShape()->getMargin();
 | 
						||
	m_nodes.resize(node_count);
 | 
						||
	for(int i=0,ni=node_count;i<ni;++i)
 | 
						||
	{	
 | 
						||
		Node&	n=m_nodes[i];
 | 
						||
		ZeroInitialize(n);
 | 
						||
		n.m_x		=	x?*x++:btVector3(0,0,0);
 | 
						||
		n.m_q		=	n.m_x;
 | 
						||
		n.m_im		=	m?*m++:1;
 | 
						||
		n.m_im		=	n.m_im>0?1/n.m_im:0;
 | 
						||
		n.m_leaf	=	m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x,margin),&n);
 | 
						||
		n.m_material=	pm;
 | 
						||
	}
 | 
						||
	updateBounds();	
 | 
						||
 | 
						||
}
 | 
						||
 | 
						||
btSoftBody::btSoftBody(btSoftBodyWorldInfo*	worldInfo)
 | 
						||
:m_worldInfo(worldInfo)
 | 
						||
{
 | 
						||
	initDefaults();
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
void	btSoftBody::initDefaults()
 | 
						||
{
 | 
						||
	m_internalType		=	CO_SOFT_BODY;
 | 
						||
	m_cfg.aeromodel		=	eAeroModel::V_Point;
 | 
						||
	m_cfg.kVCF			=	1;
 | 
						||
	m_cfg.kDG			=	0;
 | 
						||
	m_cfg.kLF			=	0;
 | 
						||
	m_cfg.kDP			=	0;
 | 
						||
	m_cfg.kPR			=	0;
 | 
						||
	m_cfg.kVC			=	0;
 | 
						||
	m_cfg.kDF			=	(btScalar)0.2;
 | 
						||
	m_cfg.kMT			=	0;
 | 
						||
	m_cfg.kCHR			=	(btScalar)1.0;
 | 
						||
	m_cfg.kKHR			=	(btScalar)0.1;
 | 
						||
	m_cfg.kSHR			=	(btScalar)1.0;
 | 
						||
	m_cfg.kAHR			=	(btScalar)0.7;
 | 
						||
	m_cfg.kSRHR_CL		=	(btScalar)0.1;
 | 
						||
	m_cfg.kSKHR_CL		=	(btScalar)1;
 | 
						||
	m_cfg.kSSHR_CL		=	(btScalar)0.5;
 | 
						||
	m_cfg.kSR_SPLT_CL	=	(btScalar)0.5;
 | 
						||
	m_cfg.kSK_SPLT_CL	=	(btScalar)0.5;
 | 
						||
	m_cfg.kSS_SPLT_CL	=	(btScalar)0.5;
 | 
						||
	m_cfg.maxvolume		=	(btScalar)1;
 | 
						||
	m_cfg.timescale		=	1;
 | 
						||
	m_cfg.viterations	=	0;
 | 
						||
	m_cfg.piterations	=	1;	
 | 
						||
	m_cfg.diterations	=	0;
 | 
						||
	m_cfg.citerations	=	4;
 | 
						||
	m_cfg.collisions	=	fCollision::Default;
 | 
						||
	m_pose.m_bvolume	=	false;
 | 
						||
	m_pose.m_bframe		=	false;
 | 
						||
	m_pose.m_volume		=	0;
 | 
						||
	m_pose.m_com		=	btVector3(0,0,0);
 | 
						||
	m_pose.m_rot.setIdentity();
 | 
						||
	m_pose.m_scl.setIdentity();
 | 
						||
	m_tag				=	0;
 | 
						||
	m_timeacc			=	0;
 | 
						||
	m_bUpdateRtCst		=	true;
 | 
						||
	m_bounds[0]			=	btVector3(0,0,0);
 | 
						||
	m_bounds[1]			=	btVector3(0,0,0);
 | 
						||
	m_worldTransform.setIdentity();
 | 
						||
	setSolver(eSolverPresets::Positions);
 | 
						||
	
 | 
						||
	/* Collision shape	*/ 
 | 
						||
	///for now, create a collision shape internally
 | 
						||
	m_collisionShape = new btSoftBodyCollisionShape(this);
 | 
						||
	m_collisionShape->setMargin(0.25f);
 | 
						||
	
 | 
						||
	m_initialWorldTransform.setIdentity();
 | 
						||
 | 
						||
	m_windVelocity = btVector3(0,0,0);
 | 
						||
	m_restLengthScale = btScalar(1.0);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btSoftBody::~btSoftBody()
 | 
						||
{
 | 
						||
	//for now, delete the internal shape
 | 
						||
	delete m_collisionShape;	
 | 
						||
	int i;
 | 
						||
 | 
						||
	releaseClusters();
 | 
						||
	for(i=0;i<m_materials.size();++i) 
 | 
						||
		btAlignedFree(m_materials[i]);
 | 
						||
	for(i=0;i<m_joints.size();++i) 
 | 
						||
		btAlignedFree(m_joints[i]);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
bool			btSoftBody::checkLink(int node0,int node1) const
 | 
						||
{
 | 
						||
	return(checkLink(&m_nodes[node0],&m_nodes[node1]));
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
bool			btSoftBody::checkLink(const Node* node0,const Node* node1) const
 | 
						||
{
 | 
						||
	const Node*	n[]={node0,node1};
 | 
						||
	for(int i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		const Link&	l=m_links[i];
 | 
						||
		if(	(l.m_n[0]==n[0]&&l.m_n[1]==n[1])||
 | 
						||
			(l.m_n[0]==n[1]&&l.m_n[1]==n[0]))
 | 
						||
		{
 | 
						||
			return(true);
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return(false);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
bool			btSoftBody::checkFace(int node0,int node1,int node2) const
 | 
						||
{
 | 
						||
	const Node*	n[]={	&m_nodes[node0],
 | 
						||
		&m_nodes[node1],
 | 
						||
		&m_nodes[node2]};
 | 
						||
	for(int i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		const Face&	f=m_faces[i];
 | 
						||
		int			c=0;
 | 
						||
		for(int j=0;j<3;++j)
 | 
						||
		{
 | 
						||
			if(	(f.m_n[j]==n[0])||
 | 
						||
				(f.m_n[j]==n[1])||
 | 
						||
				(f.m_n[j]==n[2])) c|=1<<j; else break;
 | 
						||
		}
 | 
						||
		if(c==7) return(true);
 | 
						||
	}
 | 
						||
	return(false);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btSoftBody::Material*		btSoftBody::appendMaterial()
 | 
						||
{
 | 
						||
	Material*	pm=new(btAlignedAlloc(sizeof(Material),16)) Material();
 | 
						||
	if(m_materials.size()>0)
 | 
						||
		*pm=*m_materials[0];
 | 
						||
	else
 | 
						||
		ZeroInitialize(*pm);
 | 
						||
	m_materials.push_back(pm);
 | 
						||
	return(pm);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendNote(	const char* text,
 | 
						||
									   const btVector3& o,
 | 
						||
									   const btVector4& c,
 | 
						||
									   Node* n0,
 | 
						||
									   Node* n1,
 | 
						||
									   Node* n2,
 | 
						||
									   Node* n3)
 | 
						||
{
 | 
						||
	Note	n;
 | 
						||
	ZeroInitialize(n);
 | 
						||
	n.m_rank		=	0;
 | 
						||
	n.m_text		=	text;
 | 
						||
	n.m_offset		=	o;
 | 
						||
	n.m_coords[0]	=	c.x();
 | 
						||
	n.m_coords[1]	=	c.y();
 | 
						||
	n.m_coords[2]	=	c.z();
 | 
						||
	n.m_coords[3]	=	c.w();
 | 
						||
	n.m_nodes[0]	=	n0;n.m_rank+=n0?1:0;
 | 
						||
	n.m_nodes[1]	=	n1;n.m_rank+=n1?1:0;
 | 
						||
	n.m_nodes[2]	=	n2;n.m_rank+=n2?1:0;
 | 
						||
	n.m_nodes[3]	=	n3;n.m_rank+=n3?1:0;
 | 
						||
	m_notes.push_back(n);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendNote(	const char* text,
 | 
						||
									   const btVector3& o,
 | 
						||
									   Node* feature)
 | 
						||
{
 | 
						||
	appendNote(text,o,btVector4(1,0,0,0),feature);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendNote(	const char* text,
 | 
						||
									   const btVector3& o,
 | 
						||
									   Link* feature)
 | 
						||
{
 | 
						||
	static const btScalar	w=1/(btScalar)2;
 | 
						||
	appendNote(text,o,btVector4(w,w,0,0),	feature->m_n[0],
 | 
						||
		feature->m_n[1]);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendNote(	const char* text,
 | 
						||
									   const btVector3& o,
 | 
						||
									   Face* feature)
 | 
						||
{
 | 
						||
	static const btScalar	w=1/(btScalar)3;
 | 
						||
	appendNote(text,o,btVector4(w,w,w,0),	feature->m_n[0],
 | 
						||
		feature->m_n[1],
 | 
						||
		feature->m_n[2]);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendNode(	const btVector3& x,btScalar m)
 | 
						||
{
 | 
						||
	if(m_nodes.capacity()==m_nodes.size())
 | 
						||
	{
 | 
						||
		pointersToIndices();
 | 
						||
		m_nodes.reserve(m_nodes.size()*2+1);
 | 
						||
		indicesToPointers();
 | 
						||
	}
 | 
						||
	const btScalar	margin=getCollisionShape()->getMargin();
 | 
						||
	m_nodes.push_back(Node());
 | 
						||
	Node&			n=m_nodes[m_nodes.size()-1];
 | 
						||
	ZeroInitialize(n);
 | 
						||
	n.m_x			=	x;
 | 
						||
	n.m_q			=	n.m_x;
 | 
						||
	n.m_im			=	m>0?1/m:0;
 | 
						||
	n.m_material	=	m_materials[0];
 | 
						||
	n.m_leaf		=	m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x,margin),&n);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendLink(int model,Material* mat)
 | 
						||
{
 | 
						||
	Link	l;
 | 
						||
	if(model>=0)
 | 
						||
		l=m_links[model];
 | 
						||
	else
 | 
						||
	{ ZeroInitialize(l);l.m_material=mat?mat:m_materials[0]; }
 | 
						||
	m_links.push_back(l);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendLink(	int node0,
 | 
						||
									   int node1,
 | 
						||
									   Material* mat,
 | 
						||
									   bool bcheckexist)
 | 
						||
{
 | 
						||
	appendLink(&m_nodes[node0],&m_nodes[node1],mat,bcheckexist);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendLink(	Node* node0,
 | 
						||
									   Node* node1,
 | 
						||
									   Material* mat,
 | 
						||
									   bool bcheckexist)
 | 
						||
{
 | 
						||
	if((!bcheckexist)||(!checkLink(node0,node1)))
 | 
						||
	{
 | 
						||
		appendLink(-1,mat);
 | 
						||
		Link&	l=m_links[m_links.size()-1];
 | 
						||
		l.m_n[0]		=	node0;
 | 
						||
		l.m_n[1]		=	node1;
 | 
						||
		l.m_rl			=	(l.m_n[0]->m_x-l.m_n[1]->m_x).length();
 | 
						||
		m_bUpdateRtCst=true;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendFace(int model,Material* mat)
 | 
						||
{
 | 
						||
	Face	f;
 | 
						||
	if(model>=0)
 | 
						||
	{ f=m_faces[model]; }
 | 
						||
	else
 | 
						||
	{ ZeroInitialize(f);f.m_material=mat?mat:m_materials[0]; }
 | 
						||
	m_faces.push_back(f);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendFace(int node0,int node1,int node2,Material* mat)
 | 
						||
{
 | 
						||
	if (node0==node1)
 | 
						||
		return;
 | 
						||
	if (node1==node2)
 | 
						||
		return;
 | 
						||
	if (node2==node0)
 | 
						||
		return;
 | 
						||
 | 
						||
	appendFace(-1,mat);
 | 
						||
	Face&	f=m_faces[m_faces.size()-1];
 | 
						||
	btAssert(node0!=node1);
 | 
						||
	btAssert(node1!=node2);
 | 
						||
	btAssert(node2!=node0);
 | 
						||
	f.m_n[0]	=	&m_nodes[node0];
 | 
						||
	f.m_n[1]	=	&m_nodes[node1];
 | 
						||
	f.m_n[2]	=	&m_nodes[node2];
 | 
						||
	f.m_ra		=	AreaOf(	f.m_n[0]->m_x,
 | 
						||
		f.m_n[1]->m_x,
 | 
						||
		f.m_n[2]->m_x);	
 | 
						||
	m_bUpdateRtCst=true;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendTetra(int model,Material* mat)
 | 
						||
{
 | 
						||
Tetra	t;
 | 
						||
if(model>=0)
 | 
						||
	t=m_tetras[model];
 | 
						||
	else
 | 
						||
	{ ZeroInitialize(t);t.m_material=mat?mat:m_materials[0]; }
 | 
						||
m_tetras.push_back(t);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendTetra(int node0,
 | 
						||
										int node1,
 | 
						||
										int node2,
 | 
						||
										int node3,
 | 
						||
										Material* mat)
 | 
						||
{
 | 
						||
	appendTetra(-1,mat);
 | 
						||
	Tetra&	t=m_tetras[m_tetras.size()-1];
 | 
						||
	t.m_n[0]	=	&m_nodes[node0];
 | 
						||
	t.m_n[1]	=	&m_nodes[node1];
 | 
						||
	t.m_n[2]	=	&m_nodes[node2];
 | 
						||
	t.m_n[3]	=	&m_nodes[node3];
 | 
						||
	t.m_rv		=	VolumeOf(t.m_n[0]->m_x,t.m_n[1]->m_x,t.m_n[2]->m_x,t.m_n[3]->m_x);
 | 
						||
	m_bUpdateRtCst=true;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
 | 
						||
void			btSoftBody::appendAnchor(int node,btRigidBody* body, bool disableCollisionBetweenLinkedBodies,btScalar influence)
 | 
						||
{
 | 
						||
	btVector3 local = body->getWorldTransform().inverse()*m_nodes[node].m_x;
 | 
						||
	appendAnchor(node,body,local,disableCollisionBetweenLinkedBodies,influence);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendAnchor(int node,btRigidBody* body, const btVector3& localPivot,bool disableCollisionBetweenLinkedBodies,btScalar influence)
 | 
						||
{
 | 
						||
	if (disableCollisionBetweenLinkedBodies)
 | 
						||
	{
 | 
						||
		if (m_collisionDisabledObjects.findLinearSearch(body)==m_collisionDisabledObjects.size())
 | 
						||
		{
 | 
						||
			m_collisionDisabledObjects.push_back(body);
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	Anchor	a;
 | 
						||
	a.m_node			=	&m_nodes[node];
 | 
						||
	a.m_body			=	body;
 | 
						||
	a.m_local			=	localPivot;
 | 
						||
	a.m_node->m_battach	=	1;
 | 
						||
	a.m_influence = influence;
 | 
						||
	m_anchors.push_back(a);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendLinearJoint(const LJoint::Specs& specs,Cluster* body0,Body body1)
 | 
						||
{
 | 
						||
	LJoint*		pj	=	new(btAlignedAlloc(sizeof(LJoint),16)) LJoint();
 | 
						||
	pj->m_bodies[0]	=	body0;
 | 
						||
	pj->m_bodies[1]	=	body1;
 | 
						||
	pj->m_refs[0]	=	pj->m_bodies[0].xform().inverse()*specs.position;
 | 
						||
	pj->m_refs[1]	=	pj->m_bodies[1].xform().inverse()*specs.position;
 | 
						||
	pj->m_cfm		=	specs.cfm;
 | 
						||
	pj->m_erp		=	specs.erp;
 | 
						||
	pj->m_split		=	specs.split;
 | 
						||
	m_joints.push_back(pj);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendLinearJoint(const LJoint::Specs& specs,Body body)
 | 
						||
{
 | 
						||
	appendLinearJoint(specs,m_clusters[0],body);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendLinearJoint(const LJoint::Specs& specs,btSoftBody* body)
 | 
						||
{
 | 
						||
	appendLinearJoint(specs,m_clusters[0],body->m_clusters[0]);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendAngularJoint(const AJoint::Specs& specs,Cluster* body0,Body body1)
 | 
						||
{
 | 
						||
	AJoint*		pj	=	new(btAlignedAlloc(sizeof(AJoint),16)) AJoint();
 | 
						||
	pj->m_bodies[0]	=	body0;
 | 
						||
	pj->m_bodies[1]	=	body1;
 | 
						||
	pj->m_refs[0]	=	pj->m_bodies[0].xform().inverse().getBasis()*specs.axis;
 | 
						||
	pj->m_refs[1]	=	pj->m_bodies[1].xform().inverse().getBasis()*specs.axis;
 | 
						||
	pj->m_cfm		=	specs.cfm;
 | 
						||
	pj->m_erp		=	specs.erp;
 | 
						||
	pj->m_split		=	specs.split;
 | 
						||
	pj->m_icontrol	=	specs.icontrol;
 | 
						||
	m_joints.push_back(pj);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendAngularJoint(const AJoint::Specs& specs,Body body)
 | 
						||
{
 | 
						||
	appendAngularJoint(specs,m_clusters[0],body);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::appendAngularJoint(const AJoint::Specs& specs,btSoftBody* body)
 | 
						||
{
 | 
						||
	appendAngularJoint(specs,m_clusters[0],body->m_clusters[0]);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::addForce(const btVector3& force)
 | 
						||
{
 | 
						||
	for(int i=0,ni=m_nodes.size();i<ni;++i) addForce(force,i);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::addForce(const btVector3& force,int node)
 | 
						||
{
 | 
						||
	Node&	n=m_nodes[node];
 | 
						||
	if(n.m_im>0)
 | 
						||
	{
 | 
						||
		n.m_f	+=	force;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
void			btSoftBody::addAeroForceToNode(const btVector3& windVelocity,int nodeIndex)
 | 
						||
{
 | 
						||
	btAssert(nodeIndex >= 0 && nodeIndex < m_nodes.size());
 | 
						||
 | 
						||
	const btScalar dt = m_sst.sdt;
 | 
						||
	const btScalar kLF = m_cfg.kLF;
 | 
						||
	const btScalar kDG = m_cfg.kDG;
 | 
						||
	//const btScalar kPR = m_cfg.kPR;
 | 
						||
	//const btScalar kVC = m_cfg.kVC;
 | 
						||
	const bool as_lift = kLF>0;
 | 
						||
	const bool as_drag = kDG>0;
 | 
						||
	const bool as_aero = as_lift || as_drag;
 | 
						||
	const bool as_vaero = as_aero && (m_cfg.aeromodel < btSoftBody::eAeroModel::F_TwoSided);
 | 
						||
 | 
						||
	Node& n = m_nodes[nodeIndex];
 | 
						||
 | 
						||
	if( n.m_im>0 )
 | 
						||
	{
 | 
						||
		btSoftBody::sMedium	medium;
 | 
						||
 | 
						||
		EvaluateMedium(m_worldInfo, n.m_x, medium);
 | 
						||
		medium.m_velocity = windVelocity;
 | 
						||
		medium.m_density = m_worldInfo->air_density;
 | 
						||
 | 
						||
		/* Aerodynamics			*/ 
 | 
						||
		if(as_vaero)
 | 
						||
		{				
 | 
						||
			const btVector3	rel_v = n.m_v - medium.m_velocity;					
 | 
						||
			const btScalar rel_v_len = rel_v.length();
 | 
						||
			const btScalar	rel_v2 = rel_v.length2();
 | 
						||
 | 
						||
			if(rel_v2>SIMD_EPSILON)
 | 
						||
			{
 | 
						||
				const btVector3 rel_v_nrm = rel_v.normalized();
 | 
						||
				btVector3	nrm = n.m_n;						
 | 
						||
 | 
						||
				if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSidedLiftDrag)
 | 
						||
				{
 | 
						||
					nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
 | 
						||
					btVector3 fDrag(0, 0, 0);
 | 
						||
					btVector3 fLift(0, 0, 0);
 | 
						||
 | 
						||
					btScalar n_dot_v = nrm.dot(rel_v_nrm);
 | 
						||
					btScalar tri_area = 0.5f * n.m_area;
 | 
						||
							
 | 
						||
					fDrag = 0.5f * kDG * medium.m_density * rel_v2 * tri_area * n_dot_v * (-rel_v_nrm);
 | 
						||
							
 | 
						||
					// Check angle of attack
 | 
						||
					// cos(10<31>) = 0.98480
 | 
						||
					if ( 0 < n_dot_v && n_dot_v < 0.98480f)
 | 
						||
						fLift = 0.5f * kLF * medium.m_density * rel_v_len * tri_area * btSqrt(1.0f-n_dot_v*n_dot_v) * (nrm.cross(rel_v_nrm).cross(rel_v_nrm));
 | 
						||
 | 
						||
					// Check if the velocity change resulted by aero drag force exceeds the current velocity of the node.
 | 
						||
					btVector3 del_v_by_fDrag = fDrag*n.m_im*m_sst.sdt;										
 | 
						||
					btScalar del_v_by_fDrag_len2 = del_v_by_fDrag.length2();
 | 
						||
					btScalar v_len2 = n.m_v.length2();
 | 
						||
 | 
						||
					if (del_v_by_fDrag_len2 >= v_len2 && del_v_by_fDrag_len2 > 0)
 | 
						||
					{
 | 
						||
						btScalar del_v_by_fDrag_len = del_v_by_fDrag.length();
 | 
						||
						btScalar v_len = n.m_v.length();
 | 
						||
						fDrag *= btScalar(0.8)*(v_len / del_v_by_fDrag_len);
 | 
						||
					}
 | 
						||
 | 
						||
					n.m_f += fDrag;
 | 
						||
					n.m_f += fLift;
 | 
						||
				}
 | 
						||
				else if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_Point || m_cfg.aeromodel == btSoftBody::eAeroModel::V_OneSided || m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSided)
 | 
						||
				{
 | 
						||
					if (m_cfg.aeromodel == btSoftBody::eAeroModel::V_TwoSided)
 | 
						||
						nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
 | 
						||
 | 
						||
					const btScalar dvn = btDot(rel_v,nrm);
 | 
						||
					/* Compute forces	*/ 
 | 
						||
					if(dvn>0)
 | 
						||
					{
 | 
						||
						btVector3		force(0,0,0);
 | 
						||
						const btScalar	c0	=	n.m_area * dvn * rel_v2/2;
 | 
						||
						const btScalar	c1	=	c0 * medium.m_density;
 | 
						||
						force	+=	nrm*(-c1*kLF);
 | 
						||
						force	+=	rel_v.normalized() * (-c1 * kDG);
 | 
						||
						ApplyClampedForce(n, force, dt);
 | 
						||
					}
 | 
						||
				}	
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
void			btSoftBody::addAeroForceToFace(const btVector3& windVelocity,int faceIndex)
 | 
						||
{
 | 
						||
	const btScalar dt = m_sst.sdt;
 | 
						||
	const btScalar kLF = m_cfg.kLF;
 | 
						||
	const btScalar kDG = m_cfg.kDG;
 | 
						||
//	const btScalar kPR = m_cfg.kPR;
 | 
						||
//	const btScalar kVC = m_cfg.kVC;
 | 
						||
	const bool as_lift = kLF>0;
 | 
						||
	const bool as_drag = kDG>0;
 | 
						||
	const bool as_aero = as_lift || as_drag;
 | 
						||
	const bool as_faero = as_aero && (m_cfg.aeromodel >= btSoftBody::eAeroModel::F_TwoSided);
 | 
						||
 | 
						||
	if(as_faero)
 | 
						||
	{
 | 
						||
		btSoftBody::Face&	f=m_faces[faceIndex];
 | 
						||
 | 
						||
		btSoftBody::sMedium	medium;
 | 
						||
		
 | 
						||
		const btVector3	v=(f.m_n[0]->m_v+f.m_n[1]->m_v+f.m_n[2]->m_v)/3;
 | 
						||
		const btVector3	x=(f.m_n[0]->m_x+f.m_n[1]->m_x+f.m_n[2]->m_x)/3;
 | 
						||
		EvaluateMedium(m_worldInfo,x,medium);
 | 
						||
		medium.m_velocity = windVelocity;
 | 
						||
		medium.m_density = m_worldInfo->air_density;
 | 
						||
		const btVector3	rel_v=v-medium.m_velocity;
 | 
						||
		const btScalar rel_v_len = rel_v.length();
 | 
						||
		const btScalar	rel_v2=rel_v.length2();
 | 
						||
 | 
						||
		if(rel_v2>SIMD_EPSILON)
 | 
						||
		{
 | 
						||
			const btVector3 rel_v_nrm = rel_v.normalized();
 | 
						||
			btVector3	nrm = f.m_normal;
 | 
						||
 | 
						||
			if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSidedLiftDrag)
 | 
						||
			{
 | 
						||
				nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
 | 
						||
 | 
						||
				btVector3 fDrag(0, 0, 0);
 | 
						||
				btVector3 fLift(0, 0, 0);
 | 
						||
 | 
						||
				btScalar n_dot_v = nrm.dot(rel_v_nrm);
 | 
						||
				btScalar tri_area = 0.5f * f.m_ra;
 | 
						||
					
 | 
						||
				fDrag = 0.5f * kDG * medium.m_density * rel_v2 * tri_area * n_dot_v * (-rel_v_nrm);
 | 
						||
 | 
						||
				// Check angle of attack
 | 
						||
				// cos(10<31>) = 0.98480
 | 
						||
				if ( 0 < n_dot_v && n_dot_v < 0.98480f)
 | 
						||
					fLift = 0.5f * kLF * medium.m_density * rel_v_len * tri_area * btSqrt(1.0f-n_dot_v*n_dot_v) * (nrm.cross(rel_v_nrm).cross(rel_v_nrm));
 | 
						||
 | 
						||
				fDrag /= 3;
 | 
						||
				fLift /= 3;
 | 
						||
 | 
						||
				for(int j=0;j<3;++j) 
 | 
						||
				{
 | 
						||
					if (f.m_n[j]->m_im>0)
 | 
						||
					{
 | 
						||
						// Check if the velocity change resulted by aero drag force exceeds the current velocity of the node.
 | 
						||
						btVector3 del_v_by_fDrag = fDrag*f.m_n[j]->m_im*m_sst.sdt;										
 | 
						||
						btScalar del_v_by_fDrag_len2 = del_v_by_fDrag.length2();
 | 
						||
						btScalar v_len2 = f.m_n[j]->m_v.length2();
 | 
						||
 | 
						||
						if (del_v_by_fDrag_len2 >= v_len2 && del_v_by_fDrag_len2 > 0)
 | 
						||
						{
 | 
						||
							btScalar del_v_by_fDrag_len = del_v_by_fDrag.length();
 | 
						||
							btScalar v_len = f.m_n[j]->m_v.length();
 | 
						||
							fDrag *= btScalar(0.8)*(v_len / del_v_by_fDrag_len);
 | 
						||
						}
 | 
						||
 | 
						||
						f.m_n[j]->m_f += fDrag; 
 | 
						||
						f.m_n[j]->m_f += fLift;
 | 
						||
					}
 | 
						||
				}
 | 
						||
			}
 | 
						||
			else if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_OneSided || m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSided)
 | 
						||
			{
 | 
						||
				if (m_cfg.aeromodel == btSoftBody::eAeroModel::F_TwoSided)
 | 
						||
					nrm *= (btScalar)( (btDot(nrm,rel_v) < 0) ? -1 : +1);
 | 
						||
 | 
						||
				const btScalar	dvn=btDot(rel_v,nrm);
 | 
						||
				/* Compute forces	*/ 
 | 
						||
				if(dvn>0)
 | 
						||
				{
 | 
						||
					btVector3		force(0,0,0);
 | 
						||
					const btScalar	c0	=	f.m_ra*dvn*rel_v2;
 | 
						||
					const btScalar	c1	=	c0*medium.m_density;
 | 
						||
					force	+=	nrm*(-c1*kLF);
 | 
						||
					force	+=	rel_v.normalized()*(-c1*kDG);
 | 
						||
					force	/=	3;
 | 
						||
					for(int j=0;j<3;++j) ApplyClampedForce(*f.m_n[j],force,dt);
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::addVelocity(const btVector3& velocity)
 | 
						||
{
 | 
						||
	for(int i=0,ni=m_nodes.size();i<ni;++i) addVelocity(velocity,i);
 | 
						||
}
 | 
						||
 | 
						||
/* Set velocity for the entire body										*/ 
 | 
						||
void				btSoftBody::setVelocity(	const btVector3& velocity)
 | 
						||
{
 | 
						||
	for(int i=0,ni=m_nodes.size();i<ni;++i) 
 | 
						||
	{
 | 
						||
		Node&	n=m_nodes[i];
 | 
						||
		if(n.m_im>0)
 | 
						||
		{
 | 
						||
			n.m_v	=	velocity;
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::addVelocity(const btVector3& velocity,int node)
 | 
						||
{
 | 
						||
	Node&	n=m_nodes[node];
 | 
						||
	if(n.m_im>0)
 | 
						||
	{
 | 
						||
		n.m_v	+=	velocity;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::setMass(int node,btScalar mass)
 | 
						||
{
 | 
						||
	m_nodes[node].m_im=mass>0?1/mass:0;
 | 
						||
	m_bUpdateRtCst=true;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btScalar		btSoftBody::getMass(int node) const
 | 
						||
{
 | 
						||
	return(m_nodes[node].m_im>0?1/m_nodes[node].m_im:0);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btScalar		btSoftBody::getTotalMass() const
 | 
						||
{
 | 
						||
	btScalar	mass=0;
 | 
						||
	for(int i=0;i<m_nodes.size();++i)
 | 
						||
	{
 | 
						||
		mass+=getMass(i);
 | 
						||
	}
 | 
						||
	return(mass);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::setTotalMass(btScalar mass,bool fromfaces)
 | 
						||
{
 | 
						||
	int i;
 | 
						||
 | 
						||
	if(fromfaces)
 | 
						||
	{
 | 
						||
 | 
						||
		for(i=0;i<m_nodes.size();++i)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_im=0;
 | 
						||
		}
 | 
						||
		for(i=0;i<m_faces.size();++i)
 | 
						||
		{
 | 
						||
			const Face&		f=m_faces[i];
 | 
						||
			const btScalar	twicearea=AreaOf(	f.m_n[0]->m_x,
 | 
						||
				f.m_n[1]->m_x,
 | 
						||
				f.m_n[2]->m_x);
 | 
						||
			for(int j=0;j<3;++j)
 | 
						||
			{
 | 
						||
				f.m_n[j]->m_im+=twicearea;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		for( i=0;i<m_nodes.size();++i)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_im=1/m_nodes[i].m_im;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	const btScalar	tm=getTotalMass();
 | 
						||
	const btScalar	itm=1/tm;
 | 
						||
	for( i=0;i<m_nodes.size();++i)
 | 
						||
	{
 | 
						||
		m_nodes[i].m_im/=itm*mass;
 | 
						||
	}
 | 
						||
	m_bUpdateRtCst=true;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::setTotalDensity(btScalar density)
 | 
						||
{
 | 
						||
	setTotalMass(getVolume()*density,true);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::setVolumeMass(btScalar mass)
 | 
						||
{
 | 
						||
btAlignedObjectArray<btScalar>	ranks;
 | 
						||
ranks.resize(m_nodes.size(),0);
 | 
						||
int i;
 | 
						||
 | 
						||
for(i=0;i<m_nodes.size();++i)
 | 
						||
	{
 | 
						||
	m_nodes[i].m_im=0;
 | 
						||
	}
 | 
						||
for(i=0;i<m_tetras.size();++i)
 | 
						||
	{
 | 
						||
	const Tetra& t=m_tetras[i];
 | 
						||
	for(int j=0;j<4;++j)
 | 
						||
		{
 | 
						||
		t.m_n[j]->m_im+=btFabs(t.m_rv);
 | 
						||
		ranks[int(t.m_n[j]-&m_nodes[0])]+=1;
 | 
						||
		}
 | 
						||
	}
 | 
						||
for( i=0;i<m_nodes.size();++i)
 | 
						||
	{
 | 
						||
	if(m_nodes[i].m_im>0)
 | 
						||
		{
 | 
						||
		m_nodes[i].m_im=ranks[i]/m_nodes[i].m_im;
 | 
						||
		}
 | 
						||
	}
 | 
						||
setTotalMass(mass,false);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::setVolumeDensity(btScalar density)
 | 
						||
{
 | 
						||
btScalar	volume=0;
 | 
						||
for(int i=0;i<m_tetras.size();++i)
 | 
						||
	{
 | 
						||
	const Tetra& t=m_tetras[i];
 | 
						||
	for(int j=0;j<4;++j)
 | 
						||
		{
 | 
						||
		volume+=btFabs(t.m_rv);
 | 
						||
		}
 | 
						||
	}
 | 
						||
setVolumeMass(volume*density/6);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::transform(const btTransform& trs)
 | 
						||
{
 | 
						||
	const btScalar	margin=getCollisionShape()->getMargin();
 | 
						||
	ATTRIBUTE_ALIGNED16(btDbvtVolume)	vol;
 | 
						||
	
 | 
						||
	for(int i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Node&	n=m_nodes[i];
 | 
						||
		n.m_x=trs*n.m_x;
 | 
						||
		n.m_q=trs*n.m_q;
 | 
						||
		n.m_n=trs.getBasis()*n.m_n;
 | 
						||
		vol = btDbvtVolume::FromCR(n.m_x,margin);
 | 
						||
		
 | 
						||
		m_ndbvt.update(n.m_leaf,vol);
 | 
						||
	}
 | 
						||
	updateNormals();
 | 
						||
	updateBounds();
 | 
						||
	updateConstants();
 | 
						||
	m_initialWorldTransform = trs;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::translate(const btVector3& trs)
 | 
						||
{
 | 
						||
	btTransform	t;
 | 
						||
	t.setIdentity();
 | 
						||
	t.setOrigin(trs);
 | 
						||
	transform(t);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::rotate(	const btQuaternion& rot)
 | 
						||
{
 | 
						||
	btTransform	t;
 | 
						||
	t.setIdentity();
 | 
						||
	t.setRotation(rot);
 | 
						||
	transform(t);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::scale(const btVector3& scl)
 | 
						||
{
 | 
						||
 | 
						||
	const btScalar	margin=getCollisionShape()->getMargin();
 | 
						||
	ATTRIBUTE_ALIGNED16(btDbvtVolume)	vol;
 | 
						||
	
 | 
						||
	for(int i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Node&	n=m_nodes[i];
 | 
						||
		n.m_x*=scl;
 | 
						||
		n.m_q*=scl;
 | 
						||
		vol = btDbvtVolume::FromCR(n.m_x,margin);
 | 
						||
		m_ndbvt.update(n.m_leaf,vol);
 | 
						||
	}
 | 
						||
	updateNormals();
 | 
						||
	updateBounds();
 | 
						||
	updateConstants();
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btScalar btSoftBody::getRestLengthScale()
 | 
						||
{
 | 
						||
	return m_restLengthScale;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void btSoftBody::setRestLengthScale(btScalar restLengthScale)
 | 
						||
{
 | 
						||
	for(int i=0, ni=m_links.size(); i<ni; ++i)
 | 
						||
	{
 | 
						||
		Link&		l=m_links[i];
 | 
						||
		l.m_rl	=	l.m_rl / m_restLengthScale * restLengthScale;
 | 
						||
		l.m_c1	=	l.m_rl*l.m_rl;
 | 
						||
	}
 | 
						||
	m_restLengthScale = restLengthScale;
 | 
						||
	
 | 
						||
	if (getActivationState() == ISLAND_SLEEPING)
 | 
						||
		activate();
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::setPose(bool bvolume,bool bframe)
 | 
						||
{
 | 
						||
	m_pose.m_bvolume	=	bvolume;
 | 
						||
	m_pose.m_bframe		=	bframe;
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	/* Weights		*/ 
 | 
						||
	const btScalar	omass=getTotalMass();
 | 
						||
	const btScalar	kmass=omass*m_nodes.size()*1000;
 | 
						||
	btScalar		tmass=omass;
 | 
						||
	m_pose.m_wgh.resize(m_nodes.size());
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		if(m_nodes[i].m_im<=0) tmass+=kmass;
 | 
						||
	}
 | 
						||
	for( i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Node&	n=m_nodes[i];
 | 
						||
		m_pose.m_wgh[i]=	n.m_im>0					?
 | 
						||
			1/(m_nodes[i].m_im*tmass)	:
 | 
						||
		kmass/tmass;
 | 
						||
	}
 | 
						||
	/* Pos		*/ 
 | 
						||
	const btVector3	com=evaluateCom();
 | 
						||
	m_pose.m_pos.resize(m_nodes.size());
 | 
						||
	for( i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_pose.m_pos[i]=m_nodes[i].m_x-com;
 | 
						||
	}
 | 
						||
	m_pose.m_volume	=	bvolume?getVolume():0;
 | 
						||
	m_pose.m_com	=	com;
 | 
						||
	m_pose.m_rot.setIdentity();
 | 
						||
	m_pose.m_scl.setIdentity();
 | 
						||
	/* Aqq		*/ 
 | 
						||
	m_pose.m_aqq[0]	=
 | 
						||
		m_pose.m_aqq[1]	=
 | 
						||
		m_pose.m_aqq[2]	=	btVector3(0,0,0);
 | 
						||
	for( i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		const btVector3&	q=m_pose.m_pos[i];
 | 
						||
		const btVector3		mq=m_pose.m_wgh[i]*q;
 | 
						||
		m_pose.m_aqq[0]+=mq.x()*q;
 | 
						||
		m_pose.m_aqq[1]+=mq.y()*q;
 | 
						||
		m_pose.m_aqq[2]+=mq.z()*q;
 | 
						||
	}
 | 
						||
	m_pose.m_aqq=m_pose.m_aqq.inverse();
 | 
						||
	
 | 
						||
	updateConstants();
 | 
						||
}
 | 
						||
 | 
						||
void				btSoftBody::resetLinkRestLengths()
 | 
						||
{
 | 
						||
	for(int i=0, ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Link& l =	m_links[i];
 | 
						||
		l.m_rl	=	(l.m_n[0]->m_x-l.m_n[1]->m_x).length();
 | 
						||
		l.m_c1	=	l.m_rl*l.m_rl;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btScalar		btSoftBody::getVolume() const
 | 
						||
{
 | 
						||
	btScalar	vol=0;
 | 
						||
	if(m_nodes.size()>0)
 | 
						||
	{
 | 
						||
		int i,ni;
 | 
						||
 | 
						||
		const btVector3	org=m_nodes[0].m_x;
 | 
						||
		for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			const Face&	f=m_faces[i];
 | 
						||
			vol+=btDot(f.m_n[0]->m_x-org,btCross(f.m_n[1]->m_x-org,f.m_n[2]->m_x-org));
 | 
						||
		}
 | 
						||
		vol/=(btScalar)6;
 | 
						||
	}
 | 
						||
	return(vol);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
int				btSoftBody::clusterCount() const
 | 
						||
{
 | 
						||
	return(m_clusters.size());
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btVector3		btSoftBody::clusterCom(const Cluster* cluster)
 | 
						||
{
 | 
						||
	btVector3		com(0,0,0);
 | 
						||
	for(int i=0,ni=cluster->m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		com+=cluster->m_nodes[i]->m_x*cluster->m_masses[i];
 | 
						||
	}
 | 
						||
	return(com*cluster->m_imass);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btVector3		btSoftBody::clusterCom(int cluster) const
 | 
						||
{
 | 
						||
	return(clusterCom(m_clusters[cluster]));
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btVector3		btSoftBody::clusterVelocity(const Cluster* cluster,const btVector3& rpos)
 | 
						||
{
 | 
						||
	return(cluster->m_lv+btCross(cluster->m_av,rpos));
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::clusterVImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse)
 | 
						||
{
 | 
						||
	const btVector3	li=cluster->m_imass*impulse;
 | 
						||
	const btVector3	ai=cluster->m_invwi*btCross(rpos,impulse);
 | 
						||
	cluster->m_vimpulses[0]+=li;cluster->m_lv+=li;
 | 
						||
	cluster->m_vimpulses[1]+=ai;cluster->m_av+=ai;
 | 
						||
	cluster->m_nvimpulses++;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::clusterDImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse)
 | 
						||
{
 | 
						||
	const btVector3	li=cluster->m_imass*impulse;
 | 
						||
	const btVector3	ai=cluster->m_invwi*btCross(rpos,impulse);
 | 
						||
	cluster->m_dimpulses[0]+=li;
 | 
						||
	cluster->m_dimpulses[1]+=ai;
 | 
						||
	cluster->m_ndimpulses++;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::clusterImpulse(Cluster* cluster,const btVector3& rpos,const Impulse& impulse)
 | 
						||
{
 | 
						||
	if(impulse.m_asVelocity)	clusterVImpulse(cluster,rpos,impulse.m_velocity);
 | 
						||
	if(impulse.m_asDrift)		clusterDImpulse(cluster,rpos,impulse.m_drift);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::clusterVAImpulse(Cluster* cluster,const btVector3& impulse)
 | 
						||
{
 | 
						||
	const btVector3	ai=cluster->m_invwi*impulse;
 | 
						||
	cluster->m_vimpulses[1]+=ai;cluster->m_av+=ai;
 | 
						||
	cluster->m_nvimpulses++;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::clusterDAImpulse(Cluster* cluster,const btVector3& impulse)
 | 
						||
{
 | 
						||
	const btVector3	ai=cluster->m_invwi*impulse;
 | 
						||
	cluster->m_dimpulses[1]+=ai;
 | 
						||
	cluster->m_ndimpulses++;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::clusterAImpulse(Cluster* cluster,const Impulse& impulse)
 | 
						||
{
 | 
						||
	if(impulse.m_asVelocity)	clusterVAImpulse(cluster,impulse.m_velocity);
 | 
						||
	if(impulse.m_asDrift)		clusterDAImpulse(cluster,impulse.m_drift);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::clusterDCImpulse(Cluster* cluster,const btVector3& impulse)
 | 
						||
{
 | 
						||
	cluster->m_dimpulses[0]+=impulse*cluster->m_imass;
 | 
						||
	cluster->m_ndimpulses++;
 | 
						||
}
 | 
						||
 | 
						||
struct NodeLinks
 | 
						||
{
 | 
						||
    btAlignedObjectArray<int> m_links;
 | 
						||
};
 | 
						||
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
int				btSoftBody::generateBendingConstraints(int distance,Material* mat)
 | 
						||
{
 | 
						||
	int i,j;
 | 
						||
 | 
						||
	if(distance>1)
 | 
						||
	{
 | 
						||
		/* Build graph	*/ 
 | 
						||
		const int		n=m_nodes.size();
 | 
						||
		const unsigned	inf=(~(unsigned)0)>>1;
 | 
						||
		unsigned*		adj=new unsigned[n*n];
 | 
						||
		
 | 
						||
 | 
						||
#define IDX(_x_,_y_)	((_y_)*n+(_x_))
 | 
						||
		for(j=0;j<n;++j)
 | 
						||
		{
 | 
						||
			for(i=0;i<n;++i)
 | 
						||
			{
 | 
						||
				if(i!=j)
 | 
						||
				{
 | 
						||
					adj[IDX(i,j)]=adj[IDX(j,i)]=inf;
 | 
						||
				}
 | 
						||
				else
 | 
						||
				{
 | 
						||
					adj[IDX(i,j)]=adj[IDX(j,i)]=0;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		for( i=0;i<m_links.size();++i)
 | 
						||
		{
 | 
						||
			const int	ia=(int)(m_links[i].m_n[0]-&m_nodes[0]);
 | 
						||
			const int	ib=(int)(m_links[i].m_n[1]-&m_nodes[0]);
 | 
						||
			adj[IDX(ia,ib)]=1;
 | 
						||
			adj[IDX(ib,ia)]=1;
 | 
						||
		}
 | 
						||
 | 
						||
 | 
						||
		//special optimized case for distance == 2
 | 
						||
		if (distance == 2)
 | 
						||
		{
 | 
						||
 | 
						||
			btAlignedObjectArray<NodeLinks> nodeLinks;
 | 
						||
 | 
						||
 | 
						||
			/* Build node links */
 | 
						||
			nodeLinks.resize(m_nodes.size());
 | 
						||
 | 
						||
			for( i=0;i<m_links.size();++i)
 | 
						||
			{
 | 
						||
				const int	ia=(int)(m_links[i].m_n[0]-&m_nodes[0]);
 | 
						||
				const int	ib=(int)(m_links[i].m_n[1]-&m_nodes[0]);
 | 
						||
				if (nodeLinks[ia].m_links.findLinearSearch(ib)==nodeLinks[ia].m_links.size())
 | 
						||
					nodeLinks[ia].m_links.push_back(ib);
 | 
						||
 | 
						||
				if (nodeLinks[ib].m_links.findLinearSearch(ia)==nodeLinks[ib].m_links.size())
 | 
						||
					nodeLinks[ib].m_links.push_back(ia);
 | 
						||
			}
 | 
						||
			for (int ii=0;ii<nodeLinks.size();ii++)
 | 
						||
			{
 | 
						||
				int i=ii;
 | 
						||
 | 
						||
				for (int jj=0;jj<nodeLinks[ii].m_links.size();jj++)
 | 
						||
				{
 | 
						||
					int k = nodeLinks[ii].m_links[jj];
 | 
						||
					for (int kk=0;kk<nodeLinks[k].m_links.size();kk++)
 | 
						||
					{
 | 
						||
						int j = nodeLinks[k].m_links[kk];
 | 
						||
						if (i!=j)
 | 
						||
						{
 | 
						||
							const unsigned	sum=adj[IDX(i,k)]+adj[IDX(k,j)];
 | 
						||
							btAssert(sum==2);
 | 
						||
							if(adj[IDX(i,j)]>sum)
 | 
						||
							{
 | 
						||
								adj[IDX(i,j)]=adj[IDX(j,i)]=sum;
 | 
						||
							}
 | 
						||
						}
 | 
						||
 | 
						||
					}
 | 
						||
				}
 | 
						||
			}
 | 
						||
		} else
 | 
						||
		{
 | 
						||
			///generic Floyd's algorithm
 | 
						||
			for(int k=0;k<n;++k)
 | 
						||
			{
 | 
						||
				for(j=0;j<n;++j)
 | 
						||
				{
 | 
						||
					for(i=j+1;i<n;++i)
 | 
						||
					{
 | 
						||
						const unsigned	sum=adj[IDX(i,k)]+adj[IDX(k,j)];
 | 
						||
						if(adj[IDX(i,j)]>sum)
 | 
						||
						{
 | 
						||
							adj[IDX(i,j)]=adj[IDX(j,i)]=sum;
 | 
						||
						}
 | 
						||
					}
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
 | 
						||
		/* Build links	*/ 
 | 
						||
		int	nlinks=0;
 | 
						||
		for(j=0;j<n;++j)
 | 
						||
		{
 | 
						||
			for(i=j+1;i<n;++i)
 | 
						||
			{
 | 
						||
				if(adj[IDX(i,j)]==(unsigned)distance)
 | 
						||
				{
 | 
						||
					appendLink(i,j,mat);
 | 
						||
					m_links[m_links.size()-1].m_bbending=1;
 | 
						||
					++nlinks;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		delete[] adj;		
 | 
						||
		return(nlinks);
 | 
						||
	}
 | 
						||
	return(0);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::randomizeConstraints()
 | 
						||
{
 | 
						||
	unsigned long	seed=243703;
 | 
						||
#define NEXTRAND (seed=(1664525L*seed+1013904223L)&0xffffffff)
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		btSwap(m_links[i],m_links[NEXTRAND%ni]);
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		btSwap(m_faces[i],m_faces[NEXTRAND%ni]);
 | 
						||
	}
 | 
						||
#undef NEXTRAND
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::releaseCluster(int index)
 | 
						||
{
 | 
						||
	Cluster*	c=m_clusters[index];
 | 
						||
	if(c->m_leaf) m_cdbvt.remove(c->m_leaf);
 | 
						||
	c->~Cluster();
 | 
						||
	btAlignedFree(c);
 | 
						||
	m_clusters.remove(c);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::releaseClusters()
 | 
						||
{
 | 
						||
	while(m_clusters.size()>0) releaseCluster(0);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
int				btSoftBody::generateClusters(int k,int maxiterations)
 | 
						||
{
 | 
						||
	int i;
 | 
						||
	releaseClusters();
 | 
						||
	m_clusters.resize(btMin(k,m_nodes.size()));
 | 
						||
	for(i=0;i<m_clusters.size();++i)
 | 
						||
	{
 | 
						||
		m_clusters[i]			=	new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
 | 
						||
		m_clusters[i]->m_collide=	true;
 | 
						||
	}
 | 
						||
	k=m_clusters.size();
 | 
						||
	if(k>0)
 | 
						||
	{
 | 
						||
		/* Initialize		*/ 
 | 
						||
		btAlignedObjectArray<btVector3>	centers;
 | 
						||
		btVector3						cog(0,0,0);
 | 
						||
		int								i;
 | 
						||
		for(i=0;i<m_nodes.size();++i)
 | 
						||
		{
 | 
						||
			cog+=m_nodes[i].m_x;
 | 
						||
			m_clusters[(i*29873)%m_clusters.size()]->m_nodes.push_back(&m_nodes[i]);
 | 
						||
		}
 | 
						||
		cog/=(btScalar)m_nodes.size();
 | 
						||
		centers.resize(k,cog);
 | 
						||
		/* Iterate			*/ 
 | 
						||
		const btScalar	slope=16;
 | 
						||
		bool			changed;
 | 
						||
		int				iterations=0;
 | 
						||
		do	{
 | 
						||
			const btScalar	w=2-btMin<btScalar>(1,iterations/slope);
 | 
						||
			changed=false;
 | 
						||
			iterations++;	
 | 
						||
			int i;
 | 
						||
 | 
						||
			for(i=0;i<k;++i)
 | 
						||
			{
 | 
						||
				btVector3	c(0,0,0);
 | 
						||
				for(int j=0;j<m_clusters[i]->m_nodes.size();++j)
 | 
						||
				{
 | 
						||
					c+=m_clusters[i]->m_nodes[j]->m_x;
 | 
						||
				}
 | 
						||
				if(m_clusters[i]->m_nodes.size())
 | 
						||
				{
 | 
						||
					c			/=	(btScalar)m_clusters[i]->m_nodes.size();
 | 
						||
					c			=	centers[i]+(c-centers[i])*w;
 | 
						||
					changed		|=	((c-centers[i]).length2()>SIMD_EPSILON);
 | 
						||
					centers[i]	=	c;
 | 
						||
					m_clusters[i]->m_nodes.resize(0);
 | 
						||
				}			
 | 
						||
			}
 | 
						||
			for(i=0;i<m_nodes.size();++i)
 | 
						||
			{
 | 
						||
				const btVector3	nx=m_nodes[i].m_x;
 | 
						||
				int				kbest=0;
 | 
						||
				btScalar		kdist=ClusterMetric(centers[0],nx);
 | 
						||
				for(int j=1;j<k;++j)
 | 
						||
				{
 | 
						||
					const btScalar	d=ClusterMetric(centers[j],nx);
 | 
						||
					if(d<kdist)
 | 
						||
					{
 | 
						||
						kbest=j;
 | 
						||
						kdist=d;
 | 
						||
					}
 | 
						||
				}
 | 
						||
				m_clusters[kbest]->m_nodes.push_back(&m_nodes[i]);
 | 
						||
			}		
 | 
						||
		} while(changed&&(iterations<maxiterations));
 | 
						||
		/* Merge		*/ 
 | 
						||
		btAlignedObjectArray<int>	cids;
 | 
						||
		cids.resize(m_nodes.size(),-1);
 | 
						||
		for(i=0;i<m_clusters.size();++i)
 | 
						||
		{
 | 
						||
			for(int j=0;j<m_clusters[i]->m_nodes.size();++j)
 | 
						||
			{
 | 
						||
				cids[int(m_clusters[i]->m_nodes[j]-&m_nodes[0])]=i;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		for(i=0;i<m_faces.size();++i)
 | 
						||
		{
 | 
						||
			const int idx[]={	int(m_faces[i].m_n[0]-&m_nodes[0]),
 | 
						||
				int(m_faces[i].m_n[1]-&m_nodes[0]),
 | 
						||
				int(m_faces[i].m_n[2]-&m_nodes[0])};
 | 
						||
			for(int j=0;j<3;++j)
 | 
						||
			{
 | 
						||
				const int cid=cids[idx[j]];
 | 
						||
				for(int q=1;q<3;++q)
 | 
						||
				{
 | 
						||
					const int kid=idx[(j+q)%3];
 | 
						||
					if(cids[kid]!=cid)
 | 
						||
					{
 | 
						||
						if(m_clusters[cid]->m_nodes.findLinearSearch(&m_nodes[kid])==m_clusters[cid]->m_nodes.size())
 | 
						||
						{
 | 
						||
							m_clusters[cid]->m_nodes.push_back(&m_nodes[kid]);
 | 
						||
						}
 | 
						||
					}
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		/* Master		*/ 
 | 
						||
		if(m_clusters.size()>1)
 | 
						||
		{
 | 
						||
			Cluster*	pmaster=new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
 | 
						||
			pmaster->m_collide	=	false;
 | 
						||
			pmaster->m_nodes.reserve(m_nodes.size());
 | 
						||
			for(int i=0;i<m_nodes.size();++i) pmaster->m_nodes.push_back(&m_nodes[i]);
 | 
						||
			m_clusters.push_back(pmaster);
 | 
						||
			btSwap(m_clusters[0],m_clusters[m_clusters.size()-1]);
 | 
						||
		}
 | 
						||
		/* Terminate	*/ 
 | 
						||
		for(i=0;i<m_clusters.size();++i)
 | 
						||
		{
 | 
						||
			if(m_clusters[i]->m_nodes.size()==0)
 | 
						||
			{
 | 
						||
				releaseCluster(i--);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	} else
 | 
						||
	{
 | 
						||
		//create a cluster for each tetrahedron (if tetrahedra exist) or each face
 | 
						||
		if (m_tetras.size())
 | 
						||
		{
 | 
						||
			m_clusters.resize(m_tetras.size());
 | 
						||
			for(i=0;i<m_clusters.size();++i)
 | 
						||
			{
 | 
						||
				m_clusters[i]			=	new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
 | 
						||
				m_clusters[i]->m_collide=	true;
 | 
						||
			}
 | 
						||
			for (i=0;i<m_tetras.size();i++)
 | 
						||
			{
 | 
						||
				for (int j=0;j<4;j++)
 | 
						||
				{
 | 
						||
					m_clusters[i]->m_nodes.push_back(m_tetras[i].m_n[j]);
 | 
						||
				}
 | 
						||
			}
 | 
						||
 | 
						||
		} else
 | 
						||
		{
 | 
						||
			m_clusters.resize(m_faces.size());
 | 
						||
			for(i=0;i<m_clusters.size();++i)
 | 
						||
			{
 | 
						||
				m_clusters[i]			=	new(btAlignedAlloc(sizeof(Cluster),16)) Cluster();
 | 
						||
				m_clusters[i]->m_collide=	true;
 | 
						||
			}
 | 
						||
 | 
						||
			for(i=0;i<m_faces.size();++i)
 | 
						||
			{
 | 
						||
				for(int j=0;j<3;++j)
 | 
						||
				{
 | 
						||
					m_clusters[i]->m_nodes.push_back(m_faces[i].m_n[j]);
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	if (m_clusters.size())
 | 
						||
	{
 | 
						||
		initializeClusters();
 | 
						||
		updateClusters();
 | 
						||
 | 
						||
 | 
						||
		//for self-collision
 | 
						||
		m_clusterConnectivity.resize(m_clusters.size()*m_clusters.size());
 | 
						||
		{
 | 
						||
			for (int c0=0;c0<m_clusters.size();c0++)
 | 
						||
			{
 | 
						||
				m_clusters[c0]->m_clusterIndex=c0;
 | 
						||
				for (int c1=0;c1<m_clusters.size();c1++)
 | 
						||
				{
 | 
						||
					
 | 
						||
					bool connected=false;
 | 
						||
					Cluster* cla = m_clusters[c0];
 | 
						||
					Cluster* clb = m_clusters[c1];
 | 
						||
					for (int i=0;!connected&&i<cla->m_nodes.size();i++)
 | 
						||
					{
 | 
						||
						for (int j=0;j<clb->m_nodes.size();j++)
 | 
						||
						{
 | 
						||
							if (cla->m_nodes[i] == clb->m_nodes[j])
 | 
						||
							{
 | 
						||
								connected=true;
 | 
						||
								break;
 | 
						||
							}
 | 
						||
						}
 | 
						||
					}
 | 
						||
					m_clusterConnectivity[c0+c1*m_clusters.size()]=connected;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	return(m_clusters.size());
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::refine(ImplicitFn* ifn,btScalar accurary,bool cut)
 | 
						||
{
 | 
						||
	const Node*			nbase = &m_nodes[0];
 | 
						||
	int					ncount = m_nodes.size();
 | 
						||
	btSymMatrix<int>	edges(ncount,-2);
 | 
						||
	int					newnodes=0;
 | 
						||
	int i,j,k,ni;
 | 
						||
 | 
						||
	/* Filter out		*/ 
 | 
						||
	for(i=0;i<m_links.size();++i)
 | 
						||
	{
 | 
						||
		Link&	l=m_links[i];
 | 
						||
		if(l.m_bbending)
 | 
						||
		{
 | 
						||
			if(!SameSign(ifn->Eval(l.m_n[0]->m_x),ifn->Eval(l.m_n[1]->m_x)))
 | 
						||
			{
 | 
						||
				btSwap(m_links[i],m_links[m_links.size()-1]);
 | 
						||
				m_links.pop_back();--i;
 | 
						||
			}
 | 
						||
		}	
 | 
						||
	}
 | 
						||
	/* Fill edges		*/ 
 | 
						||
	for(i=0;i<m_links.size();++i)
 | 
						||
	{
 | 
						||
		Link&	l=m_links[i];
 | 
						||
		edges(int(l.m_n[0]-nbase),int(l.m_n[1]-nbase))=-1;
 | 
						||
	}
 | 
						||
	for(i=0;i<m_faces.size();++i)
 | 
						||
	{	
 | 
						||
		Face&	f=m_faces[i];
 | 
						||
		edges(int(f.m_n[0]-nbase),int(f.m_n[1]-nbase))=-1;
 | 
						||
		edges(int(f.m_n[1]-nbase),int(f.m_n[2]-nbase))=-1;
 | 
						||
		edges(int(f.m_n[2]-nbase),int(f.m_n[0]-nbase))=-1;
 | 
						||
	}
 | 
						||
	/* Intersect		*/ 
 | 
						||
	for(i=0;i<ncount;++i)
 | 
						||
	{
 | 
						||
		for(j=i+1;j<ncount;++j)
 | 
						||
		{
 | 
						||
			if(edges(i,j)==-1)
 | 
						||
			{
 | 
						||
				Node&			a=m_nodes[i];
 | 
						||
				Node&			b=m_nodes[j];
 | 
						||
				const btScalar	t=ImplicitSolve(ifn,a.m_x,b.m_x,accurary);
 | 
						||
				if(t>0)
 | 
						||
				{
 | 
						||
					const btVector3	x=Lerp(a.m_x,b.m_x,t);
 | 
						||
					const btVector3	v=Lerp(a.m_v,b.m_v,t);
 | 
						||
					btScalar		m=0;
 | 
						||
					if(a.m_im>0)
 | 
						||
					{
 | 
						||
						if(b.m_im>0)
 | 
						||
						{
 | 
						||
							const btScalar	ma=1/a.m_im;
 | 
						||
							const btScalar	mb=1/b.m_im;
 | 
						||
							const btScalar	mc=Lerp(ma,mb,t);
 | 
						||
							const btScalar	f=(ma+mb)/(ma+mb+mc);
 | 
						||
							a.m_im=1/(ma*f);
 | 
						||
							b.m_im=1/(mb*f);
 | 
						||
							m=mc*f;
 | 
						||
						}
 | 
						||
						else
 | 
						||
						{ a.m_im/=0.5f;m=1/a.m_im; }
 | 
						||
					}
 | 
						||
					else
 | 
						||
					{
 | 
						||
						if(b.m_im>0)
 | 
						||
						{ b.m_im/=0.5f;m=1/b.m_im; }
 | 
						||
						else
 | 
						||
							m=0;
 | 
						||
					}
 | 
						||
					appendNode(x,m);
 | 
						||
					edges(i,j)=m_nodes.size()-1;
 | 
						||
					m_nodes[edges(i,j)].m_v=v;
 | 
						||
					++newnodes;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	nbase=&m_nodes[0];
 | 
						||
	/* Refine links		*/ 
 | 
						||
	for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Link&		feat=m_links[i];
 | 
						||
		const int	idx[]={	int(feat.m_n[0]-nbase),
 | 
						||
			int(feat.m_n[1]-nbase)};
 | 
						||
		if((idx[0]<ncount)&&(idx[1]<ncount))
 | 
						||
		{
 | 
						||
			const int ni=edges(idx[0],idx[1]);
 | 
						||
			if(ni>0)
 | 
						||
			{
 | 
						||
				appendLink(i);
 | 
						||
				Link*		pft[]={	&m_links[i],
 | 
						||
					&m_links[m_links.size()-1]};			
 | 
						||
				pft[0]->m_n[0]=&m_nodes[idx[0]];
 | 
						||
				pft[0]->m_n[1]=&m_nodes[ni];
 | 
						||
				pft[1]->m_n[0]=&m_nodes[ni];
 | 
						||
				pft[1]->m_n[1]=&m_nodes[idx[1]];
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	/* Refine faces		*/ 
 | 
						||
	for(i=0;i<m_faces.size();++i)
 | 
						||
	{
 | 
						||
		const Face&	feat=m_faces[i];
 | 
						||
		const int	idx[]={	int(feat.m_n[0]-nbase),
 | 
						||
			int(feat.m_n[1]-nbase),
 | 
						||
			int(feat.m_n[2]-nbase)};
 | 
						||
		for(j=2,k=0;k<3;j=k++)
 | 
						||
		{
 | 
						||
			if((idx[j]<ncount)&&(idx[k]<ncount))
 | 
						||
			{
 | 
						||
				const int ni=edges(idx[j],idx[k]);
 | 
						||
				if(ni>0)
 | 
						||
				{
 | 
						||
					appendFace(i);
 | 
						||
					const int	l=(k+1)%3;
 | 
						||
					Face*		pft[]={	&m_faces[i],
 | 
						||
						&m_faces[m_faces.size()-1]};
 | 
						||
					pft[0]->m_n[0]=&m_nodes[idx[l]];
 | 
						||
					pft[0]->m_n[1]=&m_nodes[idx[j]];
 | 
						||
					pft[0]->m_n[2]=&m_nodes[ni];
 | 
						||
					pft[1]->m_n[0]=&m_nodes[ni];
 | 
						||
					pft[1]->m_n[1]=&m_nodes[idx[k]];
 | 
						||
					pft[1]->m_n[2]=&m_nodes[idx[l]];
 | 
						||
					appendLink(ni,idx[l],pft[0]->m_material);
 | 
						||
					--i;break;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	/* Cut				*/ 
 | 
						||
	if(cut)
 | 
						||
	{	
 | 
						||
		btAlignedObjectArray<int>	cnodes;
 | 
						||
		const int					pcount=ncount;
 | 
						||
		int							i;
 | 
						||
		ncount=m_nodes.size();
 | 
						||
		cnodes.resize(ncount,0);
 | 
						||
		/* Nodes		*/ 
 | 
						||
		for(i=0;i<ncount;++i)
 | 
						||
		{
 | 
						||
			const btVector3	x=m_nodes[i].m_x;
 | 
						||
			if((i>=pcount)||(btFabs(ifn->Eval(x))<accurary))
 | 
						||
			{
 | 
						||
				const btVector3	v=m_nodes[i].m_v;
 | 
						||
				btScalar		m=getMass(i);
 | 
						||
				if(m>0) { m*=0.5f;m_nodes[i].m_im/=0.5f; }
 | 
						||
				appendNode(x,m);
 | 
						||
				cnodes[i]=m_nodes.size()-1;
 | 
						||
				m_nodes[cnodes[i]].m_v=v;
 | 
						||
			}
 | 
						||
		}
 | 
						||
		nbase=&m_nodes[0];
 | 
						||
		/* Links		*/ 
 | 
						||
		for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			const int		id[]={	int(m_links[i].m_n[0]-nbase),
 | 
						||
				int(m_links[i].m_n[1]-nbase)};
 | 
						||
			int				todetach=0;
 | 
						||
			if(cnodes[id[0]]&&cnodes[id[1]])
 | 
						||
			{
 | 
						||
				appendLink(i);
 | 
						||
				todetach=m_links.size()-1;
 | 
						||
			}
 | 
						||
			else
 | 
						||
			{
 | 
						||
				if((	(ifn->Eval(m_nodes[id[0]].m_x)<accurary)&&
 | 
						||
					(ifn->Eval(m_nodes[id[1]].m_x)<accurary)))
 | 
						||
					todetach=i;
 | 
						||
			}
 | 
						||
			if(todetach)
 | 
						||
			{
 | 
						||
				Link&	l=m_links[todetach];
 | 
						||
				for(int j=0;j<2;++j)
 | 
						||
				{
 | 
						||
					int cn=cnodes[int(l.m_n[j]-nbase)];
 | 
						||
					if(cn) l.m_n[j]=&m_nodes[cn];
 | 
						||
				}			
 | 
						||
			}
 | 
						||
		}
 | 
						||
		/* Faces		*/ 
 | 
						||
		for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			Node**			n=	m_faces[i].m_n;
 | 
						||
			if(	(ifn->Eval(n[0]->m_x)<accurary)&&
 | 
						||
				(ifn->Eval(n[1]->m_x)<accurary)&&
 | 
						||
				(ifn->Eval(n[2]->m_x)<accurary))
 | 
						||
			{
 | 
						||
				for(int j=0;j<3;++j)
 | 
						||
				{
 | 
						||
					int cn=cnodes[int(n[j]-nbase)];
 | 
						||
					if(cn) n[j]=&m_nodes[cn];
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		/* Clean orphans	*/ 
 | 
						||
		int							nnodes=m_nodes.size();
 | 
						||
		btAlignedObjectArray<int>	ranks;
 | 
						||
		btAlignedObjectArray<int>	todelete;
 | 
						||
		ranks.resize(nnodes,0);
 | 
						||
		for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			for(int j=0;j<2;++j) ranks[int(m_links[i].m_n[j]-nbase)]++;
 | 
						||
		}
 | 
						||
		for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			for(int j=0;j<3;++j) ranks[int(m_faces[i].m_n[j]-nbase)]++;
 | 
						||
		}
 | 
						||
		for(i=0;i<m_links.size();++i)
 | 
						||
		{
 | 
						||
			const int	id[]={	int(m_links[i].m_n[0]-nbase),
 | 
						||
				int(m_links[i].m_n[1]-nbase)};
 | 
						||
			const bool	sg[]={	ranks[id[0]]==1,
 | 
						||
				ranks[id[1]]==1};
 | 
						||
			if(sg[0]||sg[1])
 | 
						||
			{
 | 
						||
				--ranks[id[0]];
 | 
						||
				--ranks[id[1]];
 | 
						||
				btSwap(m_links[i],m_links[m_links.size()-1]);
 | 
						||
				m_links.pop_back();--i;
 | 
						||
			}
 | 
						||
		}
 | 
						||
#if 0	
 | 
						||
		for(i=nnodes-1;i>=0;--i)
 | 
						||
		{
 | 
						||
			if(!ranks[i]) todelete.push_back(i);
 | 
						||
		}	
 | 
						||
		if(todelete.size())
 | 
						||
		{		
 | 
						||
			btAlignedObjectArray<int>&	map=ranks;
 | 
						||
			for(int i=0;i<nnodes;++i) map[i]=i;
 | 
						||
			PointersToIndices(this);
 | 
						||
			for(int i=0,ni=todelete.size();i<ni;++i)
 | 
						||
			{
 | 
						||
				int		j=todelete[i];
 | 
						||
				int&	a=map[j];
 | 
						||
				int&	b=map[--nnodes];
 | 
						||
				m_ndbvt.remove(m_nodes[a].m_leaf);m_nodes[a].m_leaf=0;
 | 
						||
				btSwap(m_nodes[a],m_nodes[b]);
 | 
						||
				j=a;a=b;b=j;			
 | 
						||
			}
 | 
						||
			IndicesToPointers(this,&map[0]);
 | 
						||
			m_nodes.resize(nnodes);
 | 
						||
		}
 | 
						||
#endif
 | 
						||
	}
 | 
						||
	m_bUpdateRtCst=true;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
bool			btSoftBody::cutLink(const Node* node0,const Node* node1,btScalar position)
 | 
						||
{
 | 
						||
	return(cutLink(int(node0-&m_nodes[0]),int(node1-&m_nodes[0]),position));
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
bool			btSoftBody::cutLink(int node0,int node1,btScalar position)
 | 
						||
{
 | 
						||
	bool			done=false;
 | 
						||
	int i,ni;
 | 
						||
//	const btVector3	d=m_nodes[node0].m_x-m_nodes[node1].m_x;
 | 
						||
	const btVector3	x=Lerp(m_nodes[node0].m_x,m_nodes[node1].m_x,position);
 | 
						||
	const btVector3	v=Lerp(m_nodes[node0].m_v,m_nodes[node1].m_v,position);
 | 
						||
	const btScalar	m=1;
 | 
						||
	appendNode(x,m);
 | 
						||
	appendNode(x,m);
 | 
						||
	Node*			pa=&m_nodes[node0];
 | 
						||
	Node*			pb=&m_nodes[node1];
 | 
						||
	Node*			pn[2]={	&m_nodes[m_nodes.size()-2],
 | 
						||
		&m_nodes[m_nodes.size()-1]};
 | 
						||
	pn[0]->m_v=v;
 | 
						||
	pn[1]->m_v=v;
 | 
						||
	for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		const int mtch=MatchEdge(m_links[i].m_n[0],m_links[i].m_n[1],pa,pb);
 | 
						||
		if(mtch!=-1)
 | 
						||
		{
 | 
						||
			appendLink(i);
 | 
						||
			Link*	pft[]={&m_links[i],&m_links[m_links.size()-1]};
 | 
						||
			pft[0]->m_n[1]=pn[mtch];
 | 
						||
			pft[1]->m_n[0]=pn[1-mtch];
 | 
						||
			done=true;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		for(int k=2,l=0;l<3;k=l++)
 | 
						||
		{
 | 
						||
			const int mtch=MatchEdge(m_faces[i].m_n[k],m_faces[i].m_n[l],pa,pb);
 | 
						||
			if(mtch!=-1)
 | 
						||
			{
 | 
						||
				appendFace(i);
 | 
						||
				Face*	pft[]={&m_faces[i],&m_faces[m_faces.size()-1]};
 | 
						||
				pft[0]->m_n[l]=pn[mtch];
 | 
						||
				pft[1]->m_n[k]=pn[1-mtch];
 | 
						||
				appendLink(pn[0],pft[0]->m_n[(l+1)%3],pft[0]->m_material,true);
 | 
						||
				appendLink(pn[1],pft[0]->m_n[(l+1)%3],pft[0]->m_material,true);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	if(!done)
 | 
						||
	{
 | 
						||
		m_ndbvt.remove(pn[0]->m_leaf);
 | 
						||
		m_ndbvt.remove(pn[1]->m_leaf);
 | 
						||
		m_nodes.pop_back();
 | 
						||
		m_nodes.pop_back();
 | 
						||
	}
 | 
						||
	return(done);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
bool			btSoftBody::rayTest(const btVector3& rayFrom,
 | 
						||
									const btVector3& rayTo,
 | 
						||
									sRayCast& results)
 | 
						||
{
 | 
						||
	if(m_faces.size()&&m_fdbvt.empty()) 
 | 
						||
		initializeFaceTree();
 | 
						||
 | 
						||
	results.body	=	this;
 | 
						||
	results.fraction = 1.f;
 | 
						||
	results.feature	=	eFeature::None;
 | 
						||
	results.index	=	-1;
 | 
						||
 | 
						||
	return(rayTest(rayFrom,rayTo,results.fraction,results.feature,results.index,false)!=0);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::setSolver(eSolverPresets::_ preset)
 | 
						||
{
 | 
						||
	m_cfg.m_vsequence.clear();
 | 
						||
	m_cfg.m_psequence.clear();
 | 
						||
	m_cfg.m_dsequence.clear();
 | 
						||
	switch(preset)
 | 
						||
	{
 | 
						||
	case	eSolverPresets::Positions:
 | 
						||
		m_cfg.m_psequence.push_back(ePSolver::Anchors);
 | 
						||
		m_cfg.m_psequence.push_back(ePSolver::RContacts);
 | 
						||
		m_cfg.m_psequence.push_back(ePSolver::SContacts);
 | 
						||
		m_cfg.m_psequence.push_back(ePSolver::Linear);	
 | 
						||
		break;	
 | 
						||
	case	eSolverPresets::Velocities:
 | 
						||
		m_cfg.m_vsequence.push_back(eVSolver::Linear);
 | 
						||
 | 
						||
		m_cfg.m_psequence.push_back(ePSolver::Anchors);
 | 
						||
		m_cfg.m_psequence.push_back(ePSolver::RContacts);
 | 
						||
		m_cfg.m_psequence.push_back(ePSolver::SContacts);
 | 
						||
 | 
						||
		m_cfg.m_dsequence.push_back(ePSolver::Linear);
 | 
						||
		break;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::predictMotion(btScalar dt)
 | 
						||
{
 | 
						||
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	/* Update				*/ 
 | 
						||
	if(m_bUpdateRtCst)
 | 
						||
	{
 | 
						||
		m_bUpdateRtCst=false;
 | 
						||
		updateConstants();
 | 
						||
		m_fdbvt.clear();
 | 
						||
		if(m_cfg.collisions&fCollision::VF_SS)
 | 
						||
		{
 | 
						||
			initializeFaceTree();			
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	/* Prepare				*/ 
 | 
						||
	m_sst.sdt		=	dt*m_cfg.timescale;
 | 
						||
	m_sst.isdt		=	1/m_sst.sdt;
 | 
						||
	m_sst.velmrg	=	m_sst.sdt*3;
 | 
						||
	m_sst.radmrg	=	getCollisionShape()->getMargin();
 | 
						||
	m_sst.updmrg	=	m_sst.radmrg*(btScalar)0.25;
 | 
						||
	/* Forces				*/ 
 | 
						||
	addVelocity(m_worldInfo->m_gravity*m_sst.sdt);
 | 
						||
	applyForces();
 | 
						||
	/* Integrate			*/ 
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Node&	n=m_nodes[i];
 | 
						||
		n.m_q	=	n.m_x;
 | 
						||
		btVector3 deltaV = n.m_f*n.m_im*m_sst.sdt;
 | 
						||
		{
 | 
						||
			btScalar maxDisplacement = m_worldInfo->m_maxDisplacement;
 | 
						||
			btScalar clampDeltaV = maxDisplacement/m_sst.sdt;
 | 
						||
			for (int c=0;c<3;c++)
 | 
						||
			{
 | 
						||
				if (deltaV[c]>clampDeltaV)
 | 
						||
				{
 | 
						||
					deltaV[c] = clampDeltaV;
 | 
						||
				}
 | 
						||
				if (deltaV[c]<-clampDeltaV)
 | 
						||
				{
 | 
						||
					deltaV[c]=-clampDeltaV;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		n.m_v	+=	deltaV;
 | 
						||
		n.m_x	+=	n.m_v*m_sst.sdt;
 | 
						||
		n.m_f	=	btVector3(0,0,0);
 | 
						||
	}
 | 
						||
	/* Clusters				*/ 
 | 
						||
	updateClusters();
 | 
						||
	/* Bounds				*/ 
 | 
						||
	updateBounds();	
 | 
						||
	/* Nodes				*/ 
 | 
						||
	ATTRIBUTE_ALIGNED16(btDbvtVolume)	vol;
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Node&	n=m_nodes[i];
 | 
						||
		vol = btDbvtVolume::FromCR(n.m_x,m_sst.radmrg);
 | 
						||
		m_ndbvt.update(	n.m_leaf,
 | 
						||
			vol,
 | 
						||
			n.m_v*m_sst.velmrg,
 | 
						||
			m_sst.updmrg);
 | 
						||
	}
 | 
						||
	/* Faces				*/ 
 | 
						||
	if(!m_fdbvt.empty())
 | 
						||
	{
 | 
						||
		for(int i=0;i<m_faces.size();++i)
 | 
						||
		{
 | 
						||
			Face&			f=m_faces[i];
 | 
						||
			const btVector3	v=(	f.m_n[0]->m_v+
 | 
						||
				f.m_n[1]->m_v+
 | 
						||
				f.m_n[2]->m_v)/3;
 | 
						||
			vol = VolumeOf(f,m_sst.radmrg);
 | 
						||
			m_fdbvt.update(	f.m_leaf,
 | 
						||
				vol,
 | 
						||
				v*m_sst.velmrg,
 | 
						||
				m_sst.updmrg);
 | 
						||
		}
 | 
						||
	}
 | 
						||
	/* Pose					*/ 
 | 
						||
	updatePose();
 | 
						||
	/* Match				*/ 
 | 
						||
	if(m_pose.m_bframe&&(m_cfg.kMT>0))
 | 
						||
	{
 | 
						||
		const btMatrix3x3	posetrs=m_pose.m_rot;
 | 
						||
		for(int i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			Node&	n=m_nodes[i];
 | 
						||
			if(n.m_im>0)
 | 
						||
			{
 | 
						||
				const btVector3	x=posetrs*m_pose.m_pos[i]+m_pose.m_com;
 | 
						||
				n.m_x=Lerp(n.m_x,x,m_cfg.kMT);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	/* Clear contacts		*/ 
 | 
						||
	m_rcontacts.resize(0);
 | 
						||
	m_scontacts.resize(0);
 | 
						||
	/* Optimize dbvt's		*/ 
 | 
						||
	m_ndbvt.optimizeIncremental(1);
 | 
						||
	m_fdbvt.optimizeIncremental(1);
 | 
						||
	m_cdbvt.optimizeIncremental(1);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::solveConstraints()
 | 
						||
{
 | 
						||
 | 
						||
	/* Apply clusters		*/ 
 | 
						||
	applyClusters(false);
 | 
						||
	/* Prepare links		*/ 
 | 
						||
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Link&	l=m_links[i];
 | 
						||
		l.m_c3		=	l.m_n[1]->m_q-l.m_n[0]->m_q;
 | 
						||
		l.m_c2		=	1/(l.m_c3.length2()*l.m_c0);
 | 
						||
	}
 | 
						||
	/* Prepare anchors		*/ 
 | 
						||
	for(i=0,ni=m_anchors.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Anchor&			a=m_anchors[i];
 | 
						||
		const btVector3	ra=a.m_body->getWorldTransform().getBasis()*a.m_local;
 | 
						||
		a.m_c0	=	ImpulseMatrix(	m_sst.sdt,
 | 
						||
			a.m_node->m_im,
 | 
						||
			a.m_body->getInvMass(),
 | 
						||
			a.m_body->getInvInertiaTensorWorld(),
 | 
						||
			ra);
 | 
						||
		a.m_c1	=	ra;
 | 
						||
		a.m_c2	=	m_sst.sdt*a.m_node->m_im;
 | 
						||
		a.m_body->activate();
 | 
						||
	}
 | 
						||
	/* Solve velocities		*/ 
 | 
						||
	if(m_cfg.viterations>0)
 | 
						||
	{
 | 
						||
		/* Solve			*/ 
 | 
						||
		for(int isolve=0;isolve<m_cfg.viterations;++isolve)
 | 
						||
		{
 | 
						||
			for(int iseq=0;iseq<m_cfg.m_vsequence.size();++iseq)
 | 
						||
			{
 | 
						||
				getSolver(m_cfg.m_vsequence[iseq])(this,1);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		/* Update			*/ 
 | 
						||
		for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			Node&	n=m_nodes[i];
 | 
						||
			n.m_x	=	n.m_q+n.m_v*m_sst.sdt;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	/* Solve positions		*/ 
 | 
						||
	if(m_cfg.piterations>0)
 | 
						||
	{
 | 
						||
		for(int isolve=0;isolve<m_cfg.piterations;++isolve)
 | 
						||
		{
 | 
						||
			const btScalar ti=isolve/(btScalar)m_cfg.piterations;
 | 
						||
			for(int iseq=0;iseq<m_cfg.m_psequence.size();++iseq)
 | 
						||
			{
 | 
						||
				getSolver(m_cfg.m_psequence[iseq])(this,1,ti);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		const btScalar	vc=m_sst.isdt*(1-m_cfg.kDP);
 | 
						||
		for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			Node&	n=m_nodes[i];
 | 
						||
			n.m_v	=	(n.m_x-n.m_q)*vc;
 | 
						||
			n.m_f	=	btVector3(0,0,0);		
 | 
						||
		}
 | 
						||
	}
 | 
						||
	/* Solve drift			*/ 
 | 
						||
	if(m_cfg.diterations>0)
 | 
						||
	{
 | 
						||
		const btScalar	vcf=m_cfg.kVCF*m_sst.isdt;
 | 
						||
		for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			Node&	n=m_nodes[i];
 | 
						||
			n.m_q	=	n.m_x;
 | 
						||
		}
 | 
						||
		for(int idrift=0;idrift<m_cfg.diterations;++idrift)
 | 
						||
		{
 | 
						||
			for(int iseq=0;iseq<m_cfg.m_dsequence.size();++iseq)
 | 
						||
			{
 | 
						||
				getSolver(m_cfg.m_dsequence[iseq])(this,1,0);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		for(int i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			Node&	n=m_nodes[i];
 | 
						||
			n.m_v	+=	(n.m_x-n.m_q)*vcf;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	/* Apply clusters		*/ 
 | 
						||
	dampClusters();
 | 
						||
	applyClusters(true);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::staticSolve(int iterations)
 | 
						||
{
 | 
						||
	for(int isolve=0;isolve<iterations;++isolve)
 | 
						||
	{
 | 
						||
		for(int iseq=0;iseq<m_cfg.m_psequence.size();++iseq)
 | 
						||
		{
 | 
						||
			getSolver(m_cfg.m_psequence[iseq])(this,1,0);
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::solveCommonConstraints(btSoftBody** /*bodies*/,int /*count*/,int /*iterations*/)
 | 
						||
{
 | 
						||
	/// placeholder
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::solveClusters(const btAlignedObjectArray<btSoftBody*>& bodies)
 | 
						||
{
 | 
						||
	const int	nb=bodies.size();
 | 
						||
	int			iterations=0;
 | 
						||
	int i;
 | 
						||
 | 
						||
	for(i=0;i<nb;++i)
 | 
						||
	{
 | 
						||
		iterations=btMax(iterations,bodies[i]->m_cfg.citerations);
 | 
						||
	}
 | 
						||
	for(i=0;i<nb;++i)
 | 
						||
	{
 | 
						||
		bodies[i]->prepareClusters(iterations);
 | 
						||
	}
 | 
						||
	for(i=0;i<iterations;++i)
 | 
						||
	{
 | 
						||
		const btScalar sor=1;
 | 
						||
		for(int j=0;j<nb;++j)
 | 
						||
		{
 | 
						||
			bodies[j]->solveClusters(sor);
 | 
						||
		}
 | 
						||
	}
 | 
						||
	for(i=0;i<nb;++i)
 | 
						||
	{
 | 
						||
		bodies[i]->cleanupClusters();
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::integrateMotion()
 | 
						||
{
 | 
						||
	/* Update			*/ 
 | 
						||
	updateNormals();
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btSoftBody::RayFromToCaster::RayFromToCaster(const btVector3& rayFrom,const btVector3& rayTo,btScalar mxt)
 | 
						||
{
 | 
						||
	m_rayFrom = rayFrom;
 | 
						||
	m_rayNormalizedDirection = (rayTo-rayFrom);
 | 
						||
	m_rayTo = rayTo;
 | 
						||
	m_mint	=	mxt;
 | 
						||
	m_face	=	0;
 | 
						||
	m_tests	=	0;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::RayFromToCaster::Process(const btDbvtNode* leaf)
 | 
						||
{
 | 
						||
	btSoftBody::Face&	f=*(btSoftBody::Face*)leaf->data;
 | 
						||
	const btScalar		t=rayFromToTriangle(	m_rayFrom,m_rayTo,m_rayNormalizedDirection,
 | 
						||
		f.m_n[0]->m_x,
 | 
						||
		f.m_n[1]->m_x,
 | 
						||
		f.m_n[2]->m_x,
 | 
						||
		m_mint);
 | 
						||
	if((t>0)&&(t<m_mint)) 
 | 
						||
	{ 
 | 
						||
		m_mint=t;m_face=&f; 
 | 
						||
	}
 | 
						||
	++m_tests;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btScalar			btSoftBody::RayFromToCaster::rayFromToTriangle(	const btVector3& rayFrom,
 | 
						||
																   const btVector3& rayTo,
 | 
						||
																   const btVector3& rayNormalizedDirection,
 | 
						||
																   const btVector3& a,
 | 
						||
																   const btVector3& b,
 | 
						||
																   const btVector3& c,
 | 
						||
																   btScalar maxt)
 | 
						||
{
 | 
						||
	static const btScalar	ceps=-SIMD_EPSILON*10;
 | 
						||
	static const btScalar	teps=SIMD_EPSILON*10;
 | 
						||
 | 
						||
	const btVector3			n=btCross(b-a,c-a);
 | 
						||
	const btScalar			d=btDot(a,n);
 | 
						||
	const btScalar			den=btDot(rayNormalizedDirection,n);
 | 
						||
	if(!btFuzzyZero(den))
 | 
						||
	{
 | 
						||
		const btScalar		num=btDot(rayFrom,n)-d;
 | 
						||
		const btScalar		t=-num/den;
 | 
						||
		if((t>teps)&&(t<maxt))
 | 
						||
		{
 | 
						||
			const btVector3	hit=rayFrom+rayNormalizedDirection*t;
 | 
						||
			if(	(btDot(n,btCross(a-hit,b-hit))>ceps)	&&			
 | 
						||
				(btDot(n,btCross(b-hit,c-hit))>ceps)	&&
 | 
						||
				(btDot(n,btCross(c-hit,a-hit))>ceps))
 | 
						||
			{
 | 
						||
				return(t);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return(-1);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::pointersToIndices()
 | 
						||
{
 | 
						||
#define	PTR2IDX(_p_,_b_)	reinterpret_cast<btSoftBody::Node*>((_p_)-(_b_))
 | 
						||
	btSoftBody::Node*	base=m_nodes.size() ? &m_nodes[0] : 0;
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		if(m_nodes[i].m_leaf)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_leaf->data=*(void**)&i;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_links[i].m_n[0]=PTR2IDX(m_links[i].m_n[0],base);
 | 
						||
		m_links[i].m_n[1]=PTR2IDX(m_links[i].m_n[1],base);
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_faces[i].m_n[0]=PTR2IDX(m_faces[i].m_n[0],base);
 | 
						||
		m_faces[i].m_n[1]=PTR2IDX(m_faces[i].m_n[1],base);
 | 
						||
		m_faces[i].m_n[2]=PTR2IDX(m_faces[i].m_n[2],base);
 | 
						||
		if(m_faces[i].m_leaf)
 | 
						||
		{
 | 
						||
			m_faces[i].m_leaf->data=*(void**)&i;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_anchors.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_anchors[i].m_node=PTR2IDX(m_anchors[i].m_node,base);
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_notes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		for(int j=0;j<m_notes[i].m_rank;++j)
 | 
						||
		{
 | 
						||
			m_notes[i].m_nodes[j]=PTR2IDX(m_notes[i].m_nodes[j],base);
 | 
						||
		}
 | 
						||
	}
 | 
						||
#undef	PTR2IDX
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::indicesToPointers(const int* map)
 | 
						||
{
 | 
						||
#define	IDX2PTR(_p_,_b_)	map?(&(_b_)[map[(((char*)_p_)-(char*)0)]]):	\
 | 
						||
	(&(_b_)[(((char*)_p_)-(char*)0)])
 | 
						||
	btSoftBody::Node*	base=m_nodes.size() ? &m_nodes[0]:0;
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		if(m_nodes[i].m_leaf)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_leaf->data=&m_nodes[i];
 | 
						||
		}
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_links[i].m_n[0]=IDX2PTR(m_links[i].m_n[0],base);
 | 
						||
		m_links[i].m_n[1]=IDX2PTR(m_links[i].m_n[1],base);
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_faces[i].m_n[0]=IDX2PTR(m_faces[i].m_n[0],base);
 | 
						||
		m_faces[i].m_n[1]=IDX2PTR(m_faces[i].m_n[1],base);
 | 
						||
		m_faces[i].m_n[2]=IDX2PTR(m_faces[i].m_n[2],base);
 | 
						||
		if(m_faces[i].m_leaf)
 | 
						||
		{
 | 
						||
			m_faces[i].m_leaf->data=&m_faces[i];
 | 
						||
		}
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_anchors.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_anchors[i].m_node=IDX2PTR(m_anchors[i].m_node,base);
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_notes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		for(int j=0;j<m_notes[i].m_rank;++j)
 | 
						||
		{
 | 
						||
			m_notes[i].m_nodes[j]=IDX2PTR(m_notes[i].m_nodes[j],base);
 | 
						||
		}
 | 
						||
	}
 | 
						||
#undef	IDX2PTR
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
int					btSoftBody::rayTest(const btVector3& rayFrom,const btVector3& rayTo,
 | 
						||
										btScalar& mint,eFeature::_& feature,int& index,bool bcountonly) const
 | 
						||
{
 | 
						||
	int	cnt=0;
 | 
						||
	btVector3 dir = rayTo-rayFrom;
 | 
						||
	
 | 
						||
 | 
						||
	if(bcountonly||m_fdbvt.empty())
 | 
						||
	{/* Full search	*/ 
 | 
						||
		
 | 
						||
		for(int i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			const btSoftBody::Face&	f=m_faces[i];
 | 
						||
 | 
						||
			const btScalar			t=RayFromToCaster::rayFromToTriangle(	rayFrom,rayTo,dir,
 | 
						||
				f.m_n[0]->m_x,
 | 
						||
				f.m_n[1]->m_x,
 | 
						||
				f.m_n[2]->m_x,
 | 
						||
				mint);
 | 
						||
			if(t>0)
 | 
						||
			{
 | 
						||
				++cnt;
 | 
						||
				if(!bcountonly)
 | 
						||
				{
 | 
						||
					feature=btSoftBody::eFeature::Face;
 | 
						||
					index=i;
 | 
						||
					mint=t;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	else
 | 
						||
	{/* Use dbvt	*/ 
 | 
						||
		RayFromToCaster	collider(rayFrom,rayTo,mint);
 | 
						||
 | 
						||
		btDbvt::rayTest(m_fdbvt.m_root,rayFrom,rayTo,collider);
 | 
						||
		if(collider.m_face)
 | 
						||
		{
 | 
						||
			mint=collider.m_mint;
 | 
						||
			feature=btSoftBody::eFeature::Face;
 | 
						||
			index=(int)(collider.m_face-&m_faces[0]);
 | 
						||
			cnt=1;
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	for (int i=0;i<m_tetras.size();i++)
 | 
						||
	{
 | 
						||
		const btSoftBody::Tetra& tet = m_tetras[i];
 | 
						||
		int tetfaces[4][3] = {{0,1,2},{0,1,3},{1,2,3},{0,2,3}};
 | 
						||
		for (int f=0;f<4;f++)
 | 
						||
		{
 | 
						||
 | 
						||
			int index0=tetfaces[f][0];
 | 
						||
			int index1=tetfaces[f][1];
 | 
						||
			int index2=tetfaces[f][2];
 | 
						||
			btVector3 v0=tet.m_n[index0]->m_x;
 | 
						||
			btVector3 v1=tet.m_n[index1]->m_x;
 | 
						||
			btVector3 v2=tet.m_n[index2]->m_x;
 | 
						||
 | 
						||
 | 
						||
		const btScalar			t=RayFromToCaster::rayFromToTriangle(	rayFrom,rayTo,dir,
 | 
						||
			v0,v1,v2,
 | 
						||
				mint);
 | 
						||
		if(t>0)
 | 
						||
			{
 | 
						||
				++cnt;
 | 
						||
				if(!bcountonly)
 | 
						||
				{
 | 
						||
					feature=btSoftBody::eFeature::Tetra;
 | 
						||
					index=i;
 | 
						||
					mint=t;
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return(cnt);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::initializeFaceTree()
 | 
						||
{
 | 
						||
	m_fdbvt.clear();
 | 
						||
	for(int i=0;i<m_faces.size();++i)
 | 
						||
	{
 | 
						||
		Face&	f=m_faces[i];
 | 
						||
		f.m_leaf=m_fdbvt.insert(VolumeOf(f,0),&f);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btVector3		btSoftBody::evaluateCom() const
 | 
						||
{
 | 
						||
	btVector3	com(0,0,0);
 | 
						||
	if(m_pose.m_bframe)
 | 
						||
	{
 | 
						||
		for(int i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			com+=m_nodes[i].m_x*m_pose.m_wgh[i];
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return(com);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
bool				btSoftBody::checkContact(	const btCollisionObjectWrapper* colObjWrap,
 | 
						||
											 const btVector3& x,
 | 
						||
											 btScalar margin,
 | 
						||
											 btSoftBody::sCti& cti) const
 | 
						||
{
 | 
						||
	btVector3 nrm;
 | 
						||
	const btCollisionShape *shp = colObjWrap->getCollisionShape();
 | 
						||
//	const btRigidBody *tmpRigid = btRigidBody::upcast(colObjWrap->getCollisionObject());
 | 
						||
	//const btTransform &wtr = tmpRigid ? tmpRigid->getWorldTransform() : colObjWrap->getWorldTransform();
 | 
						||
	const btTransform &wtr = colObjWrap->getWorldTransform();
 | 
						||
	//todo: check which transform is needed here
 | 
						||
 | 
						||
	btScalar dst = 
 | 
						||
		m_worldInfo->m_sparsesdf.Evaluate(	
 | 
						||
			wtr.invXform(x),
 | 
						||
			shp,
 | 
						||
			nrm,
 | 
						||
			margin);
 | 
						||
	if(dst<0)
 | 
						||
	{
 | 
						||
		cti.m_colObj = colObjWrap->getCollisionObject();
 | 
						||
		cti.m_normal = wtr.getBasis()*nrm;
 | 
						||
		cti.m_offset = -btDot( cti.m_normal, x - cti.m_normal * dst );
 | 
						||
		return(true);
 | 
						||
	}
 | 
						||
	return(false);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::updateNormals()
 | 
						||
{
 | 
						||
 | 
						||
	const btVector3	zv(0,0,0);
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_nodes[i].m_n=zv;
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		btSoftBody::Face&	f=m_faces[i];
 | 
						||
		const btVector3		n=btCross(f.m_n[1]->m_x-f.m_n[0]->m_x,
 | 
						||
			f.m_n[2]->m_x-f.m_n[0]->m_x);
 | 
						||
		f.m_normal=n.normalized();
 | 
						||
		f.m_n[0]->m_n+=n;
 | 
						||
		f.m_n[1]->m_n+=n;
 | 
						||
		f.m_n[2]->m_n+=n;
 | 
						||
	}
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		btScalar len = m_nodes[i].m_n.length();
 | 
						||
		if (len>SIMD_EPSILON)
 | 
						||
			m_nodes[i].m_n /= len;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::updateBounds()
 | 
						||
{
 | 
						||
	/*if( m_acceleratedSoftBody )
 | 
						||
	{
 | 
						||
		// If we have an accelerated softbody we need to obtain the bounds correctly
 | 
						||
		// For now (slightly hackily) just have a very large AABB
 | 
						||
		// TODO: Write get bounds kernel
 | 
						||
		// If that is updating in place, atomic collisions might be low (when the cloth isn't perfectly aligned to an axis) and we could
 | 
						||
		// probably do a test and exchange reasonably efficiently.
 | 
						||
 | 
						||
		m_bounds[0] = btVector3(-1000, -1000, -1000);
 | 
						||
		m_bounds[1] = btVector3(1000, 1000, 1000);
 | 
						||
 | 
						||
	} else {*/
 | 
						||
		if(m_ndbvt.m_root)
 | 
						||
		{
 | 
						||
			const btVector3&	mins=m_ndbvt.m_root->volume.Mins();
 | 
						||
			const btVector3&	maxs=m_ndbvt.m_root->volume.Maxs();
 | 
						||
			const btScalar		csm=getCollisionShape()->getMargin();
 | 
						||
			const btVector3		mrg=btVector3(	csm,
 | 
						||
				csm,
 | 
						||
				csm)*1; // ??? to investigate...
 | 
						||
			m_bounds[0]=mins-mrg;
 | 
						||
			m_bounds[1]=maxs+mrg;
 | 
						||
			if(0!=getBroadphaseHandle())
 | 
						||
			{					
 | 
						||
				m_worldInfo->m_broadphase->setAabb(	getBroadphaseHandle(),
 | 
						||
					m_bounds[0],
 | 
						||
					m_bounds[1],
 | 
						||
					m_worldInfo->m_dispatcher);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		else
 | 
						||
		{
 | 
						||
			m_bounds[0]=
 | 
						||
				m_bounds[1]=btVector3(0,0,0);
 | 
						||
		}		
 | 
						||
	//}
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::updatePose()
 | 
						||
{
 | 
						||
	if(m_pose.m_bframe)
 | 
						||
	{
 | 
						||
		btSoftBody::Pose&	pose=m_pose;
 | 
						||
		const btVector3		com=evaluateCom();
 | 
						||
		/* Com			*/ 
 | 
						||
		pose.m_com	=	com;
 | 
						||
		/* Rotation		*/ 
 | 
						||
		btMatrix3x3		Apq;
 | 
						||
		const btScalar	eps=SIMD_EPSILON;
 | 
						||
		Apq[0]=Apq[1]=Apq[2]=btVector3(0,0,0);
 | 
						||
		Apq[0].setX(eps);Apq[1].setY(eps*2);Apq[2].setZ(eps*3);
 | 
						||
		for(int i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			const btVector3		a=pose.m_wgh[i]*(m_nodes[i].m_x-com);
 | 
						||
			const btVector3&	b=pose.m_pos[i];
 | 
						||
			Apq[0]+=a.x()*b;
 | 
						||
			Apq[1]+=a.y()*b;
 | 
						||
			Apq[2]+=a.z()*b;
 | 
						||
		}
 | 
						||
		btMatrix3x3		r,s;
 | 
						||
		PolarDecompose(Apq,r,s);
 | 
						||
		pose.m_rot=r;
 | 
						||
		pose.m_scl=pose.m_aqq*r.transpose()*Apq;
 | 
						||
		if(m_cfg.maxvolume>1)
 | 
						||
		{
 | 
						||
			const btScalar	idet=Clamp<btScalar>(	1/pose.m_scl.determinant(),
 | 
						||
				1,m_cfg.maxvolume);
 | 
						||
			pose.m_scl=Mul(pose.m_scl,idet);
 | 
						||
		}
 | 
						||
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::updateArea(bool averageArea)
 | 
						||
{
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	/* Face area		*/ 
 | 
						||
	for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Face&		f=m_faces[i];
 | 
						||
		f.m_ra	=	AreaOf(f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x);
 | 
						||
	}
 | 
						||
	
 | 
						||
	/* Node area		*/ 
 | 
						||
 | 
						||
	if (averageArea)
 | 
						||
	{
 | 
						||
		btAlignedObjectArray<int>	counts;
 | 
						||
		counts.resize(m_nodes.size(),0);
 | 
						||
		for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_area	=	0;
 | 
						||
		}
 | 
						||
		for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			btSoftBody::Face&	f=m_faces[i];
 | 
						||
			for(int j=0;j<3;++j)
 | 
						||
			{
 | 
						||
				const int index=(int)(f.m_n[j]-&m_nodes[0]);
 | 
						||
				counts[index]++;
 | 
						||
				f.m_n[j]->m_area+=btFabs(f.m_ra);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			if(counts[i]>0)
 | 
						||
				m_nodes[i].m_area/=(btScalar)counts[i];
 | 
						||
			else
 | 
						||
				m_nodes[i].m_area=0;
 | 
						||
		}
 | 
						||
	}
 | 
						||
	else
 | 
						||
	{
 | 
						||
		// initialize node area as zero
 | 
						||
		for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_area=0;	
 | 
						||
		}
 | 
						||
 | 
						||
		for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			btSoftBody::Face&	f=m_faces[i];
 | 
						||
 | 
						||
			for(int j=0;j<3;++j)
 | 
						||
			{
 | 
						||
				f.m_n[j]->m_area += f.m_ra;
 | 
						||
			}
 | 
						||
		}
 | 
						||
 | 
						||
		for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_area *= 0.3333333f;
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
void				btSoftBody::updateLinkConstants()
 | 
						||
{	
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	/* Links		*/ 
 | 
						||
	for(i=0,ni=m_links.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		Link&		l=m_links[i];
 | 
						||
		Material&	m=*l.m_material;
 | 
						||
		l.m_c0	=	(l.m_n[0]->m_im+l.m_n[1]->m_im)/m.m_kLST;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
void				btSoftBody::updateConstants()
 | 
						||
{
 | 
						||
	resetLinkRestLengths();
 | 
						||
	updateLinkConstants();
 | 
						||
	updateArea();
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::initializeClusters()
 | 
						||
{
 | 
						||
	int i;
 | 
						||
 | 
						||
	for( i=0;i<m_clusters.size();++i)
 | 
						||
	{
 | 
						||
		Cluster&	c=*m_clusters[i];
 | 
						||
		c.m_imass=0;
 | 
						||
		c.m_masses.resize(c.m_nodes.size());
 | 
						||
		for(int j=0;j<c.m_nodes.size();++j)
 | 
						||
		{
 | 
						||
			if (c.m_nodes[j]->m_im==0)
 | 
						||
			{
 | 
						||
				c.m_containsAnchor = true;
 | 
						||
				c.m_masses[j]	=	BT_LARGE_FLOAT;
 | 
						||
			} else
 | 
						||
			{
 | 
						||
				c.m_masses[j]	=	btScalar(1.)/c.m_nodes[j]->m_im;
 | 
						||
			}
 | 
						||
			c.m_imass		+=	c.m_masses[j];
 | 
						||
		}
 | 
						||
		c.m_imass		=	btScalar(1.)/c.m_imass;
 | 
						||
		c.m_com			=	btSoftBody::clusterCom(&c);
 | 
						||
		c.m_lv			=	btVector3(0,0,0);
 | 
						||
		c.m_av			=	btVector3(0,0,0);
 | 
						||
		c.m_leaf		=	0;
 | 
						||
		/* Inertia	*/ 
 | 
						||
		btMatrix3x3&	ii=c.m_locii;
 | 
						||
		ii[0]=ii[1]=ii[2]=btVector3(0,0,0);
 | 
						||
		{
 | 
						||
			int i,ni;
 | 
						||
 | 
						||
			for(i=0,ni=c.m_nodes.size();i<ni;++i)
 | 
						||
			{
 | 
						||
				const btVector3	k=c.m_nodes[i]->m_x-c.m_com;
 | 
						||
				const btVector3	q=k*k;
 | 
						||
				const btScalar	m=c.m_masses[i];
 | 
						||
				ii[0][0]	+=	m*(q[1]+q[2]);
 | 
						||
				ii[1][1]	+=	m*(q[0]+q[2]);
 | 
						||
				ii[2][2]	+=	m*(q[0]+q[1]);
 | 
						||
				ii[0][1]	-=	m*k[0]*k[1];
 | 
						||
				ii[0][2]	-=	m*k[0]*k[2];
 | 
						||
				ii[1][2]	-=	m*k[1]*k[2];
 | 
						||
			}
 | 
						||
		}
 | 
						||
		ii[1][0]=ii[0][1];
 | 
						||
		ii[2][0]=ii[0][2];
 | 
						||
		ii[2][1]=ii[1][2];
 | 
						||
		
 | 
						||
		ii = ii.inverse();
 | 
						||
 | 
						||
		/* Frame	*/ 
 | 
						||
		c.m_framexform.setIdentity();
 | 
						||
		c.m_framexform.setOrigin(c.m_com);
 | 
						||
		c.m_framerefs.resize(c.m_nodes.size());
 | 
						||
		{
 | 
						||
			int i;
 | 
						||
			for(i=0;i<c.m_framerefs.size();++i)
 | 
						||
			{
 | 
						||
				c.m_framerefs[i]=c.m_nodes[i]->m_x-c.m_com;
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::updateClusters()
 | 
						||
{
 | 
						||
	BT_PROFILE("UpdateClusters");
 | 
						||
	int i;
 | 
						||
 | 
						||
	for(i=0;i<m_clusters.size();++i)
 | 
						||
	{
 | 
						||
		btSoftBody::Cluster&	c=*m_clusters[i];
 | 
						||
		const int				n=c.m_nodes.size();
 | 
						||
		//const btScalar			invn=1/(btScalar)n;
 | 
						||
		if(n)
 | 
						||
		{
 | 
						||
			/* Frame				*/ 
 | 
						||
			const btScalar	eps=btScalar(0.0001);
 | 
						||
			btMatrix3x3		m,r,s;
 | 
						||
			m[0]=m[1]=m[2]=btVector3(0,0,0);
 | 
						||
			m[0][0]=eps*1;
 | 
						||
			m[1][1]=eps*2;
 | 
						||
			m[2][2]=eps*3;
 | 
						||
			c.m_com=clusterCom(&c);
 | 
						||
			for(int i=0;i<c.m_nodes.size();++i)
 | 
						||
			{
 | 
						||
				const btVector3		a=c.m_nodes[i]->m_x-c.m_com;
 | 
						||
				const btVector3&	b=c.m_framerefs[i];
 | 
						||
				m[0]+=a[0]*b;m[1]+=a[1]*b;m[2]+=a[2]*b;
 | 
						||
			}
 | 
						||
			PolarDecompose(m,r,s);
 | 
						||
			c.m_framexform.setOrigin(c.m_com);
 | 
						||
			c.m_framexform.setBasis(r);		
 | 
						||
			/* Inertia			*/ 
 | 
						||
#if 1/* Constant	*/ 
 | 
						||
			c.m_invwi=c.m_framexform.getBasis()*c.m_locii*c.m_framexform.getBasis().transpose();
 | 
						||
#else
 | 
						||
#if 0/* Sphere	*/ 
 | 
						||
			const btScalar	rk=(2*c.m_extents.length2())/(5*c.m_imass);
 | 
						||
			const btVector3	inertia(rk,rk,rk);
 | 
						||
			const btVector3	iin(btFabs(inertia[0])>SIMD_EPSILON?1/inertia[0]:0,
 | 
						||
				btFabs(inertia[1])>SIMD_EPSILON?1/inertia[1]:0,
 | 
						||
				btFabs(inertia[2])>SIMD_EPSILON?1/inertia[2]:0);
 | 
						||
 | 
						||
			c.m_invwi=c.m_xform.getBasis().scaled(iin)*c.m_xform.getBasis().transpose();
 | 
						||
#else/* Actual	*/ 		
 | 
						||
			c.m_invwi[0]=c.m_invwi[1]=c.m_invwi[2]=btVector3(0,0,0);
 | 
						||
			for(int i=0;i<n;++i)
 | 
						||
			{
 | 
						||
				const btVector3	k=c.m_nodes[i]->m_x-c.m_com;
 | 
						||
				const btVector3		q=k*k;
 | 
						||
				const btScalar		m=1/c.m_nodes[i]->m_im;
 | 
						||
				c.m_invwi[0][0]	+=	m*(q[1]+q[2]);
 | 
						||
				c.m_invwi[1][1]	+=	m*(q[0]+q[2]);
 | 
						||
				c.m_invwi[2][2]	+=	m*(q[0]+q[1]);
 | 
						||
				c.m_invwi[0][1]	-=	m*k[0]*k[1];
 | 
						||
				c.m_invwi[0][2]	-=	m*k[0]*k[2];
 | 
						||
				c.m_invwi[1][2]	-=	m*k[1]*k[2];
 | 
						||
			}
 | 
						||
			c.m_invwi[1][0]=c.m_invwi[0][1];
 | 
						||
			c.m_invwi[2][0]=c.m_invwi[0][2];
 | 
						||
			c.m_invwi[2][1]=c.m_invwi[1][2];
 | 
						||
			c.m_invwi=c.m_invwi.inverse();
 | 
						||
#endif
 | 
						||
#endif
 | 
						||
			/* Velocities			*/ 
 | 
						||
			c.m_lv=btVector3(0,0,0);
 | 
						||
			c.m_av=btVector3(0,0,0);
 | 
						||
			{
 | 
						||
				int i;
 | 
						||
 | 
						||
				for(i=0;i<n;++i)
 | 
						||
				{
 | 
						||
					const btVector3	v=c.m_nodes[i]->m_v*c.m_masses[i];
 | 
						||
					c.m_lv	+=	v;
 | 
						||
					c.m_av	+=	btCross(c.m_nodes[i]->m_x-c.m_com,v);
 | 
						||
				}
 | 
						||
			}
 | 
						||
			c.m_lv=c.m_imass*c.m_lv*(1-c.m_ldamping);
 | 
						||
			c.m_av=c.m_invwi*c.m_av*(1-c.m_adamping);
 | 
						||
			c.m_vimpulses[0]	=
 | 
						||
				c.m_vimpulses[1]	= btVector3(0,0,0);
 | 
						||
			c.m_dimpulses[0]	=
 | 
						||
				c.m_dimpulses[1]	= btVector3(0,0,0);
 | 
						||
			c.m_nvimpulses		= 0;
 | 
						||
			c.m_ndimpulses		= 0;
 | 
						||
			/* Matching				*/ 
 | 
						||
			if(c.m_matching>0)
 | 
						||
			{
 | 
						||
				for(int j=0;j<c.m_nodes.size();++j)
 | 
						||
				{
 | 
						||
					Node&			n=*c.m_nodes[j];
 | 
						||
					const btVector3	x=c.m_framexform*c.m_framerefs[j];
 | 
						||
					n.m_x=Lerp(n.m_x,x,c.m_matching);
 | 
						||
				}
 | 
						||
			}			
 | 
						||
			/* Dbvt					*/ 
 | 
						||
			if(c.m_collide)
 | 
						||
			{
 | 
						||
				btVector3	mi=c.m_nodes[0]->m_x;
 | 
						||
				btVector3	mx=mi;
 | 
						||
				for(int j=1;j<n;++j)
 | 
						||
				{
 | 
						||
					mi.setMin(c.m_nodes[j]->m_x);
 | 
						||
					mx.setMax(c.m_nodes[j]->m_x);
 | 
						||
				}			
 | 
						||
				ATTRIBUTE_ALIGNED16(btDbvtVolume)	bounds=btDbvtVolume::FromMM(mi,mx);
 | 
						||
				if(c.m_leaf)
 | 
						||
					m_cdbvt.update(c.m_leaf,bounds,c.m_lv*m_sst.sdt*3,m_sst.radmrg);
 | 
						||
				else
 | 
						||
					c.m_leaf=m_cdbvt.insert(bounds,&c);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::cleanupClusters()
 | 
						||
{
 | 
						||
	for(int i=0;i<m_joints.size();++i)
 | 
						||
	{
 | 
						||
		m_joints[i]->Terminate(m_sst.sdt);
 | 
						||
		if(m_joints[i]->m_delete)
 | 
						||
		{
 | 
						||
			btAlignedFree(m_joints[i]);
 | 
						||
			m_joints.remove(m_joints[i--]);
 | 
						||
		}	
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::prepareClusters(int iterations)
 | 
						||
{
 | 
						||
	for(int i=0;i<m_joints.size();++i)
 | 
						||
	{
 | 
						||
		m_joints[i]->Prepare(m_sst.sdt,iterations);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::solveClusters(btScalar sor)
 | 
						||
{
 | 
						||
	for(int i=0,ni=m_joints.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		m_joints[i]->Solve(m_sst.sdt,sor);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::applyClusters(bool drift)
 | 
						||
{
 | 
						||
	BT_PROFILE("ApplyClusters");
 | 
						||
//	const btScalar					f0=m_sst.sdt;
 | 
						||
	//const btScalar					f1=f0/2;
 | 
						||
	btAlignedObjectArray<btVector3> deltas;
 | 
						||
	btAlignedObjectArray<btScalar> weights;
 | 
						||
	deltas.resize(m_nodes.size(),btVector3(0,0,0));
 | 
						||
	weights.resize(m_nodes.size(),0);
 | 
						||
	int i;
 | 
						||
 | 
						||
	if(drift)
 | 
						||
	{
 | 
						||
		for(i=0;i<m_clusters.size();++i)
 | 
						||
		{
 | 
						||
			Cluster&	c=*m_clusters[i];
 | 
						||
			if(c.m_ndimpulses)
 | 
						||
			{
 | 
						||
				c.m_dimpulses[0]/=(btScalar)c.m_ndimpulses;
 | 
						||
				c.m_dimpulses[1]/=(btScalar)c.m_ndimpulses;
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	
 | 
						||
	for(i=0;i<m_clusters.size();++i)
 | 
						||
	{
 | 
						||
		Cluster&	c=*m_clusters[i];	
 | 
						||
		if(0<(drift?c.m_ndimpulses:c.m_nvimpulses))
 | 
						||
		{
 | 
						||
			const btVector3		v=(drift?c.m_dimpulses[0]:c.m_vimpulses[0])*m_sst.sdt;
 | 
						||
			const btVector3		w=(drift?c.m_dimpulses[1]:c.m_vimpulses[1])*m_sst.sdt;
 | 
						||
			for(int j=0;j<c.m_nodes.size();++j)
 | 
						||
			{
 | 
						||
				const int			idx=int(c.m_nodes[j]-&m_nodes[0]);
 | 
						||
				const btVector3&	x=c.m_nodes[j]->m_x;
 | 
						||
				const btScalar		q=c.m_masses[j];
 | 
						||
				deltas[idx]		+=	(v+btCross(w,x-c.m_com))*q;
 | 
						||
				weights[idx]	+=	q;
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
	for(i=0;i<deltas.size();++i)
 | 
						||
	{
 | 
						||
		if(weights[i]>0) 
 | 
						||
		{
 | 
						||
			m_nodes[i].m_x+=deltas[i]/weights[i];
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void					btSoftBody::dampClusters()
 | 
						||
{
 | 
						||
	int i;
 | 
						||
 | 
						||
	for(i=0;i<m_clusters.size();++i)
 | 
						||
	{
 | 
						||
		Cluster&	c=*m_clusters[i];	
 | 
						||
		if(c.m_ndamping>0)
 | 
						||
		{
 | 
						||
			for(int j=0;j<c.m_nodes.size();++j)
 | 
						||
			{
 | 
						||
				Node&			n=*c.m_nodes[j];
 | 
						||
				if(n.m_im>0)
 | 
						||
				{
 | 
						||
					const btVector3	vx=c.m_lv+btCross(c.m_av,c.m_nodes[j]->m_q-c.m_com);
 | 
						||
					if(vx.length2()<=n.m_v.length2())
 | 
						||
						{
 | 
						||
						n.m_v	+=	c.m_ndamping*(vx-n.m_v);
 | 
						||
						}
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::Joint::Prepare(btScalar dt,int)
 | 
						||
{
 | 
						||
	m_bodies[0].activate();
 | 
						||
	m_bodies[1].activate();
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::LJoint::Prepare(btScalar dt,int iterations)
 | 
						||
{
 | 
						||
	static const btScalar	maxdrift=4;
 | 
						||
	Joint::Prepare(dt,iterations);
 | 
						||
	m_rpos[0]		=	m_bodies[0].xform()*m_refs[0];
 | 
						||
	m_rpos[1]		=	m_bodies[1].xform()*m_refs[1];
 | 
						||
	m_drift			=	Clamp(m_rpos[0]-m_rpos[1],maxdrift)*m_erp/dt;
 | 
						||
	m_rpos[0]		-=	m_bodies[0].xform().getOrigin();
 | 
						||
	m_rpos[1]		-=	m_bodies[1].xform().getOrigin();
 | 
						||
	m_massmatrix	=	ImpulseMatrix(	m_bodies[0].invMass(),m_bodies[0].invWorldInertia(),m_rpos[0],
 | 
						||
		m_bodies[1].invMass(),m_bodies[1].invWorldInertia(),m_rpos[1]);
 | 
						||
	if(m_split>0)
 | 
						||
	{
 | 
						||
		m_sdrift	=	m_massmatrix*(m_drift*m_split);
 | 
						||
		m_drift		*=	1-m_split;
 | 
						||
	}
 | 
						||
	m_drift	/=(btScalar)iterations;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::LJoint::Solve(btScalar dt,btScalar sor)
 | 
						||
{
 | 
						||
	const btVector3		va=m_bodies[0].velocity(m_rpos[0]);
 | 
						||
	const btVector3		vb=m_bodies[1].velocity(m_rpos[1]);
 | 
						||
	const btVector3		vr=va-vb;
 | 
						||
	btSoftBody::Impulse	impulse;
 | 
						||
	impulse.m_asVelocity	=	1;
 | 
						||
	impulse.m_velocity		=	m_massmatrix*(m_drift+vr*m_cfm)*sor;
 | 
						||
	m_bodies[0].applyImpulse(-impulse,m_rpos[0]);
 | 
						||
	m_bodies[1].applyImpulse( impulse,m_rpos[1]);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::LJoint::Terminate(btScalar dt)
 | 
						||
{
 | 
						||
	if(m_split>0)
 | 
						||
	{
 | 
						||
		m_bodies[0].applyDImpulse(-m_sdrift,m_rpos[0]);
 | 
						||
		m_bodies[1].applyDImpulse( m_sdrift,m_rpos[1]);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::AJoint::Prepare(btScalar dt,int iterations)
 | 
						||
{
 | 
						||
	static const btScalar	maxdrift=SIMD_PI/16;
 | 
						||
	m_icontrol->Prepare(this);
 | 
						||
	Joint::Prepare(dt,iterations);
 | 
						||
	m_axis[0]	=	m_bodies[0].xform().getBasis()*m_refs[0];
 | 
						||
	m_axis[1]	=	m_bodies[1].xform().getBasis()*m_refs[1];
 | 
						||
	m_drift		=	NormalizeAny(btCross(m_axis[1],m_axis[0]));
 | 
						||
	m_drift		*=	btMin(maxdrift,btAcos(Clamp<btScalar>(btDot(m_axis[0],m_axis[1]),-1,+1)));
 | 
						||
	m_drift		*=	m_erp/dt;
 | 
						||
	m_massmatrix=	AngularImpulseMatrix(m_bodies[0].invWorldInertia(),m_bodies[1].invWorldInertia());
 | 
						||
	if(m_split>0)
 | 
						||
	{
 | 
						||
		m_sdrift	=	m_massmatrix*(m_drift*m_split);
 | 
						||
		m_drift		*=	1-m_split;
 | 
						||
	}
 | 
						||
	m_drift	/=(btScalar)iterations;
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::AJoint::Solve(btScalar dt,btScalar sor)
 | 
						||
{
 | 
						||
	const btVector3		va=m_bodies[0].angularVelocity();
 | 
						||
	const btVector3		vb=m_bodies[1].angularVelocity();
 | 
						||
	const btVector3		vr=va-vb;
 | 
						||
	const btScalar		sp=btDot(vr,m_axis[0]);
 | 
						||
	const btVector3		vc=vr-m_axis[0]*m_icontrol->Speed(this,sp);
 | 
						||
	btSoftBody::Impulse	impulse;
 | 
						||
	impulse.m_asVelocity	=	1;
 | 
						||
	impulse.m_velocity		=	m_massmatrix*(m_drift+vc*m_cfm)*sor;
 | 
						||
	m_bodies[0].applyAImpulse(-impulse);
 | 
						||
	m_bodies[1].applyAImpulse( impulse);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::AJoint::Terminate(btScalar dt)
 | 
						||
{
 | 
						||
	if(m_split>0)
 | 
						||
	{
 | 
						||
		m_bodies[0].applyDAImpulse(-m_sdrift);
 | 
						||
		m_bodies[1].applyDAImpulse( m_sdrift);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::CJoint::Prepare(btScalar dt,int iterations)
 | 
						||
{
 | 
						||
	Joint::Prepare(dt,iterations);
 | 
						||
	const bool	dodrift=(m_life==0);
 | 
						||
	m_delete=(++m_life)>m_maxlife;
 | 
						||
	if(dodrift)
 | 
						||
	{
 | 
						||
		m_drift=m_drift*m_erp/dt;
 | 
						||
		if(m_split>0)
 | 
						||
		{
 | 
						||
			m_sdrift	=	m_massmatrix*(m_drift*m_split);
 | 
						||
			m_drift		*=	1-m_split;
 | 
						||
		}
 | 
						||
		m_drift/=(btScalar)iterations;
 | 
						||
	}
 | 
						||
	else
 | 
						||
	{
 | 
						||
		m_drift=m_sdrift=btVector3(0,0,0);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::CJoint::Solve(btScalar dt,btScalar sor)
 | 
						||
{
 | 
						||
	const btVector3		va=m_bodies[0].velocity(m_rpos[0]);
 | 
						||
	const btVector3		vb=m_bodies[1].velocity(m_rpos[1]);
 | 
						||
	const btVector3		vrel=va-vb;
 | 
						||
	const btScalar		rvac=btDot(vrel,m_normal);
 | 
						||
	btSoftBody::Impulse	impulse;
 | 
						||
	impulse.m_asVelocity	=	1;
 | 
						||
	impulse.m_velocity		=	m_drift;
 | 
						||
	if(rvac<0)
 | 
						||
	{
 | 
						||
		const btVector3	iv=m_normal*rvac;
 | 
						||
		const btVector3	fv=vrel-iv;
 | 
						||
		impulse.m_velocity	+=	iv+fv*m_friction;
 | 
						||
	}
 | 
						||
	impulse.m_velocity=m_massmatrix*impulse.m_velocity*sor;
 | 
						||
	
 | 
						||
	if (m_bodies[0].m_soft==m_bodies[1].m_soft)
 | 
						||
	{
 | 
						||
		if ((impulse.m_velocity.getX() ==impulse.m_velocity.getX())&&(impulse.m_velocity.getY() ==impulse.m_velocity.getY())&&
 | 
						||
			(impulse.m_velocity.getZ() ==impulse.m_velocity.getZ()))
 | 
						||
		{
 | 
						||
			if (impulse.m_asVelocity)
 | 
						||
			{
 | 
						||
				if (impulse.m_velocity.length() <m_bodies[0].m_soft->m_maxSelfCollisionImpulse)
 | 
						||
				{
 | 
						||
					
 | 
						||
				} else
 | 
						||
				{
 | 
						||
					m_bodies[0].applyImpulse(-impulse*m_bodies[0].m_soft->m_selfCollisionImpulseFactor,m_rpos[0]);
 | 
						||
					m_bodies[1].applyImpulse( impulse*m_bodies[0].m_soft->m_selfCollisionImpulseFactor,m_rpos[1]);
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
	} else
 | 
						||
	{
 | 
						||
		m_bodies[0].applyImpulse(-impulse,m_rpos[0]);
 | 
						||
		m_bodies[1].applyImpulse( impulse,m_rpos[1]);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::CJoint::Terminate(btScalar dt)
 | 
						||
{
 | 
						||
	if(m_split>0)
 | 
						||
	{
 | 
						||
		m_bodies[0].applyDImpulse(-m_sdrift,m_rpos[0]);
 | 
						||
		m_bodies[1].applyDImpulse( m_sdrift,m_rpos[1]);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::applyForces()
 | 
						||
{
 | 
						||
 | 
						||
	BT_PROFILE("SoftBody applyForces");
 | 
						||
//	const btScalar					dt =			m_sst.sdt;
 | 
						||
	const btScalar					kLF =			m_cfg.kLF;
 | 
						||
	const btScalar					kDG =			m_cfg.kDG;
 | 
						||
	const btScalar					kPR =			m_cfg.kPR;
 | 
						||
	const btScalar					kVC =			m_cfg.kVC;
 | 
						||
	const bool						as_lift =		kLF>0;
 | 
						||
	const bool						as_drag =		kDG>0;
 | 
						||
	const bool						as_pressure =	kPR!=0;
 | 
						||
	const bool						as_volume =		kVC>0;
 | 
						||
	const bool						as_aero =		as_lift	||
 | 
						||
													as_drag		;
 | 
						||
	//const bool						as_vaero =		as_aero	&&
 | 
						||
	//												(m_cfg.aeromodel < btSoftBody::eAeroModel::F_TwoSided);
 | 
						||
	//const bool						as_faero =		as_aero	&&
 | 
						||
	//												(m_cfg.aeromodel >= btSoftBody::eAeroModel::F_TwoSided);
 | 
						||
	const bool						use_medium =	as_aero;
 | 
						||
	const bool						use_volume =	as_pressure	||
 | 
						||
		as_volume	;
 | 
						||
	btScalar						volume =		0;
 | 
						||
	btScalar						ivolumetp =		0;
 | 
						||
	btScalar						dvolumetv =		0;
 | 
						||
	btSoftBody::sMedium	medium;
 | 
						||
	if(use_volume)
 | 
						||
	{
 | 
						||
		volume		=	getVolume();
 | 
						||
		ivolumetp	=	1/btFabs(volume)*kPR;
 | 
						||
		dvolumetv	=	(m_pose.m_volume-volume)*kVC;
 | 
						||
	}
 | 
						||
	/* Per vertex forces			*/ 
 | 
						||
	int i,ni;
 | 
						||
 | 
						||
	for(i=0,ni=m_nodes.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		btSoftBody::Node&	n=m_nodes[i];
 | 
						||
		if(n.m_im>0)
 | 
						||
		{
 | 
						||
			if(use_medium)
 | 
						||
			{
 | 
						||
				/* Aerodynamics			*/ 
 | 
						||
				addAeroForceToNode(m_windVelocity, i);
 | 
						||
			}
 | 
						||
			/* Pressure				*/ 
 | 
						||
			if(as_pressure)
 | 
						||
			{
 | 
						||
				n.m_f	+=	n.m_n*(n.m_area*ivolumetp);
 | 
						||
			}
 | 
						||
			/* Volume				*/ 
 | 
						||
			if(as_volume)
 | 
						||
			{
 | 
						||
				n.m_f	+=	n.m_n*(n.m_area*dvolumetv);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	/* Per face forces				*/ 
 | 
						||
	for(i=0,ni=m_faces.size();i<ni;++i)
 | 
						||
	{
 | 
						||
	//	btSoftBody::Face&	f=m_faces[i];
 | 
						||
 | 
						||
		/* Aerodynamics			*/ 
 | 
						||
		addAeroForceToFace(m_windVelocity, i);	
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::PSolve_Anchors(btSoftBody* psb,btScalar kst,btScalar ti)
 | 
						||
{
 | 
						||
	BT_PROFILE("PSolve_Anchors");
 | 
						||
	const btScalar	kAHR=psb->m_cfg.kAHR*kst;
 | 
						||
	const btScalar	dt=psb->m_sst.sdt;
 | 
						||
	for(int i=0,ni=psb->m_anchors.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		const Anchor&		a=psb->m_anchors[i];
 | 
						||
		const btTransform&	t=a.m_body->getWorldTransform();
 | 
						||
		Node&				n=*a.m_node;
 | 
						||
		const btVector3		wa=t*a.m_local;
 | 
						||
		const btVector3		va=a.m_body->getVelocityInLocalPoint(a.m_c1)*dt;
 | 
						||
		const btVector3		vb=n.m_x-n.m_q;
 | 
						||
		const btVector3		vr=(va-vb)+(wa-n.m_x)*kAHR;
 | 
						||
		const btVector3		impulse=a.m_c0*vr*a.m_influence;
 | 
						||
		n.m_x+=impulse*a.m_c2;
 | 
						||
		a.m_body->applyImpulse(-impulse,a.m_c1);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
//
 | 
						||
void btSoftBody::PSolve_RContacts(btSoftBody* psb, btScalar kst, btScalar ti)
 | 
						||
{
 | 
						||
	BT_PROFILE("PSolve_RContacts");
 | 
						||
	const btScalar	dt = psb->m_sst.sdt;
 | 
						||
	const btScalar	mrg = psb->getCollisionShape()->getMargin();
 | 
						||
	btMultiBodyJacobianData jacobianData;
 | 
						||
	for(int i=0,ni=psb->m_rcontacts.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		const RContact&		c = psb->m_rcontacts[i];
 | 
						||
		const sCti&			cti = c.m_cti;	
 | 
						||
		if (cti.m_colObj->hasContactResponse()) 
 | 
						||
		{
 | 
						||
            btVector3 va(0,0,0);
 | 
						||
            btRigidBody* rigidCol=0;
 | 
						||
            btMultiBodyLinkCollider* multibodyLinkCol=0;
 | 
						||
            btScalar* deltaV;
 | 
						||
            
 | 
						||
            if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
 | 
						||
            {
 | 
						||
                rigidCol = (btRigidBody*)btRigidBody::upcast(cti.m_colObj);
 | 
						||
                va = rigidCol ? rigidCol->getVelocityInLocalPoint(c.m_c1)*dt : btVector3(0,0,0);
 | 
						||
            }
 | 
						||
			else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
 | 
						||
            {
 | 
						||
                multibodyLinkCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(cti.m_colObj);
 | 
						||
                if (multibodyLinkCol)
 | 
						||
                {
 | 
						||
                    const int ndof  = multibodyLinkCol->m_multiBody->getNumDofs() + 6;
 | 
						||
                    jacobianData.m_jacobians.resize(ndof);
 | 
						||
                    jacobianData.m_deltaVelocitiesUnitImpulse.resize(ndof);
 | 
						||
                    btScalar* jac=&jacobianData.m_jacobians[0];
 | 
						||
                    
 | 
						||
                    multibodyLinkCol->m_multiBody->fillContactJacobianMultiDof(multibodyLinkCol->m_link, c.m_node->m_x, cti.m_normal, jac, jacobianData.scratch_r, jacobianData.scratch_v, jacobianData.scratch_m);
 | 
						||
                    deltaV = &jacobianData.m_deltaVelocitiesUnitImpulse[0];
 | 
						||
                    multibodyLinkCol->m_multiBody->calcAccelerationDeltasMultiDof(&jacobianData.m_jacobians[0],deltaV,jacobianData.scratch_r, jacobianData.scratch_v);
 | 
						||
                    
 | 
						||
                    btScalar vel = 0.0;
 | 
						||
                    for (int j = 0; j < ndof ; ++j) {
 | 
						||
                        vel += multibodyLinkCol->m_multiBody->getVelocityVector()[j] * jac[j];
 | 
						||
                    }
 | 
						||
                    va = cti.m_normal*vel*dt;
 | 
						||
                }
 | 
						||
            }
 | 
						||
            
 | 
						||
			const btVector3		vb = c.m_node->m_x-c.m_node->m_q;
 | 
						||
			const btVector3		vr = vb-va;
 | 
						||
			const btScalar		dn = btDot(vr, cti.m_normal);		
 | 
						||
			if(dn<=SIMD_EPSILON)
 | 
						||
			{
 | 
						||
				const btScalar		dp = btMin( (btDot(c.m_node->m_x, cti.m_normal) + cti.m_offset), mrg );
 | 
						||
				const btVector3		fv = vr - (cti.m_normal * dn);
 | 
						||
				// c0 is the impulse matrix, c3 is 1 - the friction coefficient or 0, c4 is the contact hardness coefficient
 | 
						||
				const btVector3		impulse = c.m_c0 * ( (vr - (fv * c.m_c3) + (cti.m_normal * (dp * c.m_c4))) * kst );
 | 
						||
				c.m_node->m_x -= impulse * c.m_c2;
 | 
						||
                
 | 
						||
                if (cti.m_colObj->getInternalType() == btCollisionObject::CO_RIGID_BODY)
 | 
						||
                {
 | 
						||
                    if (rigidCol)
 | 
						||
                        rigidCol->applyImpulse(impulse,c.m_c1);
 | 
						||
                }
 | 
						||
                else if (cti.m_colObj->getInternalType() == btCollisionObject::CO_FEATHERSTONE_LINK)
 | 
						||
                {
 | 
						||
                    if (multibodyLinkCol)
 | 
						||
                    {
 | 
						||
                        double multiplier = 0.5;
 | 
						||
                        multibodyLinkCol->m_multiBody->applyDeltaVeeMultiDof(deltaV,-impulse.length()*multiplier);
 | 
						||
                    }
 | 
						||
                }
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::PSolve_SContacts(btSoftBody* psb,btScalar,btScalar ti)
 | 
						||
{
 | 
						||
	BT_PROFILE("PSolve_SContacts");
 | 
						||
	
 | 
						||
	for(int i=0,ni=psb->m_scontacts.size();i<ni;++i)
 | 
						||
	{
 | 
						||
		const SContact&		c=psb->m_scontacts[i];
 | 
						||
		const btVector3&	nr=c.m_normal;
 | 
						||
		Node&				n=*c.m_node;
 | 
						||
		Face&				f=*c.m_face;
 | 
						||
		const btVector3		p=BaryEval(	f.m_n[0]->m_x,
 | 
						||
			f.m_n[1]->m_x,
 | 
						||
			f.m_n[2]->m_x,
 | 
						||
			c.m_weights);
 | 
						||
		const btVector3		q=BaryEval(	f.m_n[0]->m_q,
 | 
						||
			f.m_n[1]->m_q,
 | 
						||
			f.m_n[2]->m_q,
 | 
						||
			c.m_weights);											
 | 
						||
		const btVector3		vr=(n.m_x-n.m_q)-(p-q);
 | 
						||
		btVector3			corr(0,0,0);
 | 
						||
		btScalar dot = btDot(vr,nr);
 | 
						||
		if(dot<0)
 | 
						||
		{
 | 
						||
			const btScalar	j=c.m_margin-(btDot(nr,n.m_x)-btDot(nr,p));
 | 
						||
			corr+=c.m_normal*j;
 | 
						||
		}
 | 
						||
		corr			-=	ProjectOnPlane(vr,nr)*c.m_friction;
 | 
						||
		n.m_x			+=	corr*c.m_cfm[0];
 | 
						||
		f.m_n[0]->m_x	-=	corr*(c.m_cfm[1]*c.m_weights.x());
 | 
						||
		f.m_n[1]->m_x	-=	corr*(c.m_cfm[1]*c.m_weights.y());
 | 
						||
		f.m_n[2]->m_x	-=	corr*(c.m_cfm[1]*c.m_weights.z());
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::PSolve_Links(btSoftBody* psb,btScalar kst,btScalar ti)
 | 
						||
{
 | 
						||
BT_PROFILE("PSolve_Links");
 | 
						||
	for(int i=0,ni=psb->m_links.size();i<ni;++i)
 | 
						||
	{			
 | 
						||
		Link&	l=psb->m_links[i];
 | 
						||
		if(l.m_c0>0)
 | 
						||
		{
 | 
						||
			Node&			a=*l.m_n[0];
 | 
						||
			Node&			b=*l.m_n[1];
 | 
						||
			const btVector3	del=b.m_x-a.m_x;
 | 
						||
			const btScalar	len=del.length2();
 | 
						||
			if (l.m_c1+len > SIMD_EPSILON)
 | 
						||
			{
 | 
						||
				const btScalar	k=((l.m_c1-len)/(l.m_c0*(l.m_c1+len)))*kst;
 | 
						||
				a.m_x-=del*(k*a.m_im);
 | 
						||
				b.m_x+=del*(k*b.m_im);
 | 
						||
			}
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void				btSoftBody::VSolve_Links(btSoftBody* psb,btScalar kst)
 | 
						||
{
 | 
						||
	BT_PROFILE("VSolve_Links");
 | 
						||
	for(int i=0,ni=psb->m_links.size();i<ni;++i)
 | 
						||
	{			
 | 
						||
		Link&			l=psb->m_links[i];
 | 
						||
		Node**			n=l.m_n;
 | 
						||
		const btScalar	j=-btDot(l.m_c3,n[0]->m_v-n[1]->m_v)*l.m_c2*kst;
 | 
						||
		n[0]->m_v+=	l.m_c3*(j*n[0]->m_im);
 | 
						||
		n[1]->m_v-=	l.m_c3*(j*n[1]->m_im);
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btSoftBody::psolver_t	btSoftBody::getSolver(ePSolver::_ solver)
 | 
						||
{
 | 
						||
	switch(solver)
 | 
						||
	{
 | 
						||
	case	ePSolver::Anchors:		
 | 
						||
		return(&btSoftBody::PSolve_Anchors);
 | 
						||
	case	ePSolver::Linear:		
 | 
						||
		return(&btSoftBody::PSolve_Links);
 | 
						||
	case	ePSolver::RContacts:	
 | 
						||
		return(&btSoftBody::PSolve_RContacts);
 | 
						||
	case	ePSolver::SContacts:	
 | 
						||
		return(&btSoftBody::PSolve_SContacts);	
 | 
						||
		default:
 | 
						||
		{
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return(0);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
btSoftBody::vsolver_t	btSoftBody::getSolver(eVSolver::_ solver)
 | 
						||
{
 | 
						||
	switch(solver)
 | 
						||
	{
 | 
						||
	case	eVSolver::Linear:		return(&btSoftBody::VSolve_Links);
 | 
						||
		default:
 | 
						||
		{
 | 
						||
		}
 | 
						||
	}
 | 
						||
	return(0);
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::defaultCollisionHandler(const btCollisionObjectWrapper* pcoWrap)
 | 
						||
{
 | 
						||
 | 
						||
	switch(m_cfg.collisions&fCollision::RVSmask)
 | 
						||
	{
 | 
						||
	case	fCollision::SDF_RS:
 | 
						||
		{
 | 
						||
			btSoftColliders::CollideSDF_RS	docollide;		
 | 
						||
			btRigidBody*		prb1=(btRigidBody*) btRigidBody::upcast(pcoWrap->getCollisionObject());
 | 
						||
			btTransform	wtr=pcoWrap->getWorldTransform();
 | 
						||
 | 
						||
			const btTransform	ctr=pcoWrap->getWorldTransform();
 | 
						||
			const btScalar		timemargin=(wtr.getOrigin()-ctr.getOrigin()).length();
 | 
						||
			const btScalar		basemargin=getCollisionShape()->getMargin();
 | 
						||
			btVector3			mins;
 | 
						||
			btVector3			maxs;
 | 
						||
			ATTRIBUTE_ALIGNED16(btDbvtVolume)		volume;
 | 
						||
			pcoWrap->getCollisionShape()->getAabb(	pcoWrap->getWorldTransform(),
 | 
						||
				mins,
 | 
						||
				maxs);
 | 
						||
			volume=btDbvtVolume::FromMM(mins,maxs);
 | 
						||
			volume.Expand(btVector3(basemargin,basemargin,basemargin));		
 | 
						||
			docollide.psb		=	this;
 | 
						||
			docollide.m_colObj1Wrap = pcoWrap;
 | 
						||
			docollide.m_rigidBody = prb1;
 | 
						||
 | 
						||
			docollide.dynmargin	=	basemargin+timemargin;
 | 
						||
			docollide.stamargin	=	basemargin;
 | 
						||
			m_ndbvt.collideTV(m_ndbvt.m_root,volume,docollide);
 | 
						||
		}
 | 
						||
		break;
 | 
						||
	case	fCollision::CL_RS:
 | 
						||
		{
 | 
						||
			btSoftColliders::CollideCL_RS	collider;
 | 
						||
			collider.ProcessColObj(this,pcoWrap);
 | 
						||
		}
 | 
						||
		break;
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
//
 | 
						||
void			btSoftBody::defaultCollisionHandler(btSoftBody* psb)
 | 
						||
{
 | 
						||
	const int cf=m_cfg.collisions&psb->m_cfg.collisions;
 | 
						||
	switch(cf&fCollision::SVSmask)
 | 
						||
	{
 | 
						||
	case	fCollision::CL_SS:
 | 
						||
		{
 | 
						||
			
 | 
						||
			//support self-collision if CL_SELF flag set
 | 
						||
			if (this!=psb || psb->m_cfg.collisions&fCollision::CL_SELF)
 | 
						||
			{
 | 
						||
				btSoftColliders::CollideCL_SS	docollide;
 | 
						||
				docollide.ProcessSoftSoft(this,psb);
 | 
						||
			}
 | 
						||
			
 | 
						||
		}
 | 
						||
		break;
 | 
						||
	case	fCollision::VF_SS:
 | 
						||
		{
 | 
						||
			//only self-collision for Cluster, not Vertex-Face yet
 | 
						||
			if (this!=psb)
 | 
						||
			{
 | 
						||
				btSoftColliders::CollideVF_SS	docollide;
 | 
						||
				/* common					*/ 
 | 
						||
				docollide.mrg=	getCollisionShape()->getMargin()+
 | 
						||
					psb->getCollisionShape()->getMargin();
 | 
						||
				/* psb0 nodes vs psb1 faces	*/ 
 | 
						||
				docollide.psb[0]=this;
 | 
						||
				docollide.psb[1]=psb;
 | 
						||
				docollide.psb[0]->m_ndbvt.collideTT(	docollide.psb[0]->m_ndbvt.m_root,
 | 
						||
					docollide.psb[1]->m_fdbvt.m_root,
 | 
						||
					docollide);
 | 
						||
				/* psb1 nodes vs psb0 faces	*/ 
 | 
						||
				docollide.psb[0]=psb;
 | 
						||
				docollide.psb[1]=this;
 | 
						||
				docollide.psb[0]->m_ndbvt.collideTT(	docollide.psb[0]->m_ndbvt.m_root,
 | 
						||
					docollide.psb[1]->m_fdbvt.m_root,
 | 
						||
					docollide);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		break;
 | 
						||
	default:
 | 
						||
		{
 | 
						||
			
 | 
						||
		}
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
void btSoftBody::setWindVelocity( const btVector3 &velocity )
 | 
						||
{
 | 
						||
	m_windVelocity = velocity;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
const btVector3& btSoftBody::getWindVelocity()
 | 
						||
{
 | 
						||
	return m_windVelocity;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
 | 
						||
int	btSoftBody::calculateSerializeBufferSize()	const
 | 
						||
{
 | 
						||
	int sz = sizeof(btSoftBodyData);
 | 
						||
	return sz;
 | 
						||
}
 | 
						||
 | 
						||
	///fills the dataBuffer and returns the struct name (and 0 on failure)
 | 
						||
const char*	btSoftBody::serialize(void* dataBuffer, class btSerializer* serializer) const
 | 
						||
{
 | 
						||
	btSoftBodyData* sbd = (btSoftBodyData*) dataBuffer;
 | 
						||
 | 
						||
	btCollisionObject::serialize(&sbd->m_collisionObjectData, serializer);
 | 
						||
 | 
						||
	btHashMap<btHashPtr,int>	m_nodeIndexMap;
 | 
						||
 | 
						||
	sbd->m_numMaterials = m_materials.size();
 | 
						||
	sbd->m_materials = sbd->m_numMaterials? (SoftBodyMaterialData**) serializer->getUniquePointer((void*)&m_materials): 0;
 | 
						||
 | 
						||
	if (sbd->m_materials)
 | 
						||
	{
 | 
						||
		int sz = sizeof(SoftBodyMaterialData*);
 | 
						||
		int numElem = sbd->m_numMaterials;
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		//SoftBodyMaterialData** memPtr = chunk->m_oldPtr;
 | 
						||
		SoftBodyMaterialData** memPtr = (SoftBodyMaterialData**)chunk->m_oldPtr;
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			btSoftBody::Material* mat = m_materials[i];
 | 
						||
			*memPtr = mat ? (SoftBodyMaterialData*)serializer->getUniquePointer((void*)mat) : 0;
 | 
						||
			if (!serializer->findPointer(mat))
 | 
						||
			{
 | 
						||
				//serialize it here
 | 
						||
				btChunk* chunk = serializer->allocate(sizeof(SoftBodyMaterialData),1);
 | 
						||
				SoftBodyMaterialData* memPtr = (SoftBodyMaterialData*)chunk->m_oldPtr;
 | 
						||
				memPtr->m_flags = mat->m_flags;
 | 
						||
				memPtr->m_angularStiffness = mat->m_kAST;
 | 
						||
				memPtr->m_linearStiffness = mat->m_kLST;
 | 
						||
				memPtr->m_volumeStiffness = mat->m_kVST;
 | 
						||
				serializer->finalizeChunk(chunk,"SoftBodyMaterialData",BT_SBMATERIAL_CODE,mat);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"SoftBodyMaterialData",BT_ARRAY_CODE,(void*) &m_materials);
 | 
						||
	}
 | 
						||
 | 
						||
 | 
						||
	
 | 
						||
 | 
						||
	sbd->m_numNodes = m_nodes.size();
 | 
						||
	sbd->m_nodes = sbd->m_numNodes ? (SoftBodyNodeData*)serializer->getUniquePointer((void*)&m_nodes): 0;
 | 
						||
	if (sbd->m_nodes)
 | 
						||
	{
 | 
						||
		int sz = sizeof(SoftBodyNodeData);
 | 
						||
		int numElem = sbd->m_numNodes;
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		SoftBodyNodeData* memPtr = (SoftBodyNodeData*)chunk->m_oldPtr;
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			m_nodes[i].m_f.serializeFloat( memPtr->m_accumulatedForce);
 | 
						||
			memPtr->m_area = m_nodes[i].m_area;
 | 
						||
			memPtr->m_attach = m_nodes[i].m_battach;
 | 
						||
			memPtr->m_inverseMass = m_nodes[i].m_im;
 | 
						||
			memPtr->m_material = m_nodes[i].m_material? (SoftBodyMaterialData*)serializer->getUniquePointer((void*) m_nodes[i].m_material):0;
 | 
						||
			m_nodes[i].m_n.serializeFloat(memPtr->m_normal);
 | 
						||
			m_nodes[i].m_x.serializeFloat(memPtr->m_position);
 | 
						||
			m_nodes[i].m_q.serializeFloat(memPtr->m_previousPosition);
 | 
						||
			m_nodes[i].m_v.serializeFloat(memPtr->m_velocity);
 | 
						||
			m_nodeIndexMap.insert(&m_nodes[i],i);
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"SoftBodyNodeData",BT_SBNODE_CODE,(void*) &m_nodes);
 | 
						||
	}
 | 
						||
 | 
						||
	sbd->m_numLinks = m_links.size();
 | 
						||
	sbd->m_links = sbd->m_numLinks? (SoftBodyLinkData*) serializer->getUniquePointer((void*)&m_links[0]):0;
 | 
						||
	if (sbd->m_links)
 | 
						||
	{
 | 
						||
		int sz = sizeof(SoftBodyLinkData);
 | 
						||
		int numElem = sbd->m_numLinks;
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		SoftBodyLinkData* memPtr = (SoftBodyLinkData*)chunk->m_oldPtr;
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			memPtr->m_bbending = m_links[i].m_bbending;
 | 
						||
			memPtr->m_material = m_links[i].m_material? (SoftBodyMaterialData*)serializer->getUniquePointer((void*) m_links[i].m_material):0;
 | 
						||
			memPtr->m_nodeIndices[0] = m_links[i].m_n[0] ? m_links[i].m_n[0] - &m_nodes[0]: -1;
 | 
						||
			memPtr->m_nodeIndices[1] = m_links[i].m_n[1] ? m_links[i].m_n[1] - &m_nodes[0]: -1;
 | 
						||
			btAssert(memPtr->m_nodeIndices[0]<m_nodes.size());
 | 
						||
			btAssert(memPtr->m_nodeIndices[1]<m_nodes.size());
 | 
						||
			memPtr->m_restLength = m_links[i].m_rl;
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"SoftBodyLinkData",BT_ARRAY_CODE,(void*) &m_links[0]);
 | 
						||
 | 
						||
	}
 | 
						||
 | 
						||
 | 
						||
	sbd->m_numFaces = m_faces.size();
 | 
						||
	sbd->m_faces = sbd->m_numFaces? (SoftBodyFaceData*) serializer->getUniquePointer((void*)&m_faces[0]):0;
 | 
						||
	if (sbd->m_faces)
 | 
						||
	{
 | 
						||
		int sz = sizeof(SoftBodyFaceData);
 | 
						||
		int numElem = sbd->m_numFaces;
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		SoftBodyFaceData* memPtr = (SoftBodyFaceData*)chunk->m_oldPtr;
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			memPtr->m_material = m_faces[i].m_material ?  (SoftBodyMaterialData*) serializer->getUniquePointer((void*)m_faces[i].m_material): 0;
 | 
						||
			m_faces[i].m_normal.serializeFloat(	memPtr->m_normal);
 | 
						||
			for (int j=0;j<3;j++)
 | 
						||
			{
 | 
						||
				memPtr->m_nodeIndices[j] = m_faces[i].m_n[j]? m_faces[i].m_n[j] - &m_nodes[0]: -1;
 | 
						||
			}
 | 
						||
			memPtr->m_restArea = m_faces[i].m_ra;
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"SoftBodyFaceData",BT_ARRAY_CODE,(void*) &m_faces[0]);
 | 
						||
	}
 | 
						||
 | 
						||
 | 
						||
	sbd->m_numTetrahedra = m_tetras.size();
 | 
						||
	sbd->m_tetrahedra = sbd->m_numTetrahedra ? (SoftBodyTetraData*) serializer->getUniquePointer((void*)&m_tetras[0]):0;
 | 
						||
	if (sbd->m_tetrahedra)
 | 
						||
	{
 | 
						||
		int sz = sizeof(SoftBodyTetraData);
 | 
						||
		int numElem = sbd->m_numTetrahedra;
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		SoftBodyTetraData* memPtr = (SoftBodyTetraData*)chunk->m_oldPtr;
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			for (int j=0;j<4;j++)
 | 
						||
			{
 | 
						||
				m_tetras[i].m_c0[j].serializeFloat(	memPtr->m_c0[j] );
 | 
						||
				memPtr->m_nodeIndices[j] = m_tetras[j].m_n[j]? m_tetras[j].m_n[j]-&m_nodes[0] : -1;
 | 
						||
			}
 | 
						||
			memPtr->m_c1 = m_tetras[i].m_c1;
 | 
						||
			memPtr->m_c2 = m_tetras[i].m_c2;
 | 
						||
			memPtr->m_material = m_tetras[i].m_material ? (SoftBodyMaterialData*)serializer->getUniquePointer((void*) m_tetras[i].m_material): 0;
 | 
						||
			memPtr->m_restVolume = m_tetras[i].m_rv;
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"SoftBodyTetraData",BT_ARRAY_CODE,(void*) &m_tetras[0]);
 | 
						||
	}
 | 
						||
 | 
						||
	sbd->m_numAnchors = m_anchors.size();
 | 
						||
	sbd->m_anchors = sbd->m_numAnchors ? (SoftRigidAnchorData*) serializer->getUniquePointer((void*)&m_anchors[0]):0;
 | 
						||
	if (sbd->m_anchors)
 | 
						||
	{
 | 
						||
		int sz = sizeof(SoftRigidAnchorData);
 | 
						||
		int numElem = sbd->m_numAnchors;
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		SoftRigidAnchorData* memPtr = (SoftRigidAnchorData*)chunk->m_oldPtr;
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			m_anchors[i].m_c0.serializeFloat(memPtr->m_c0);
 | 
						||
			m_anchors[i].m_c1.serializeFloat(memPtr->m_c1);
 | 
						||
			memPtr->m_c2 = m_anchors[i].m_c2;
 | 
						||
			m_anchors[i].m_local.serializeFloat(memPtr->m_localFrame);
 | 
						||
			memPtr->m_nodeIndex = m_anchors[i].m_node? m_anchors[i].m_node-&m_nodes[0]: -1;
 | 
						||
			
 | 
						||
			memPtr->m_rigidBody = m_anchors[i].m_body? (btRigidBodyData*)  serializer->getUniquePointer((void*)m_anchors[i].m_body): 0;
 | 
						||
			btAssert(memPtr->m_nodeIndex < m_nodes.size());
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"SoftRigidAnchorData",BT_ARRAY_CODE,(void*) &m_anchors[0]);
 | 
						||
	}
 | 
						||
	
 | 
						||
 | 
						||
	sbd->m_config.m_dynamicFriction = m_cfg.kDF;
 | 
						||
	sbd->m_config.m_baumgarte = m_cfg.kVCF;
 | 
						||
	sbd->m_config.m_pressure = m_cfg.kPR;
 | 
						||
	sbd->m_config.m_aeroModel = this->m_cfg.aeromodel;
 | 
						||
	sbd->m_config.m_lift = m_cfg.kLF;
 | 
						||
	sbd->m_config.m_drag = m_cfg.kDG;
 | 
						||
	sbd->m_config.m_positionIterations = m_cfg.piterations;
 | 
						||
	sbd->m_config.m_driftIterations = m_cfg.diterations;
 | 
						||
	sbd->m_config.m_clusterIterations = m_cfg.citerations;
 | 
						||
	sbd->m_config.m_velocityIterations = m_cfg.viterations;
 | 
						||
	sbd->m_config.m_maxVolume = m_cfg.maxvolume;
 | 
						||
	sbd->m_config.m_damping = m_cfg.kDP;
 | 
						||
	sbd->m_config.m_poseMatch = m_cfg.kMT;
 | 
						||
	sbd->m_config.m_collisionFlags = m_cfg.collisions;
 | 
						||
	sbd->m_config.m_volume = m_cfg.kVC;
 | 
						||
	sbd->m_config.m_rigidContactHardness = m_cfg.kCHR;
 | 
						||
	sbd->m_config.m_kineticContactHardness = m_cfg.kKHR;
 | 
						||
	sbd->m_config.m_softContactHardness = m_cfg.kSHR;
 | 
						||
	sbd->m_config.m_anchorHardness = m_cfg.kAHR;
 | 
						||
	sbd->m_config.m_timeScale = m_cfg.timescale;
 | 
						||
	sbd->m_config.m_maxVolume = m_cfg.maxvolume;
 | 
						||
	sbd->m_config.m_softRigidClusterHardness = m_cfg.kSRHR_CL;
 | 
						||
	sbd->m_config.m_softKineticClusterHardness = m_cfg.kSKHR_CL;
 | 
						||
	sbd->m_config.m_softSoftClusterHardness = m_cfg.kSSHR_CL;
 | 
						||
	sbd->m_config.m_softRigidClusterImpulseSplit = m_cfg.kSR_SPLT_CL;
 | 
						||
	sbd->m_config.m_softKineticClusterImpulseSplit = m_cfg.kSK_SPLT_CL;
 | 
						||
	sbd->m_config.m_softSoftClusterImpulseSplit = m_cfg.kSS_SPLT_CL;
 | 
						||
 | 
						||
	//pose for shape matching
 | 
						||
	{
 | 
						||
		sbd->m_pose = (SoftBodyPoseData*)serializer->getUniquePointer((void*)&m_pose);
 | 
						||
 | 
						||
		int sz = sizeof(SoftBodyPoseData);
 | 
						||
		btChunk* chunk = serializer->allocate(sz,1);
 | 
						||
		SoftBodyPoseData* memPtr = (SoftBodyPoseData*)chunk->m_oldPtr;
 | 
						||
		
 | 
						||
		m_pose.m_aqq.serializeFloat(memPtr->m_aqq);
 | 
						||
		memPtr->m_bframe = m_pose.m_bframe;
 | 
						||
		memPtr->m_bvolume = m_pose.m_bvolume;
 | 
						||
		m_pose.m_com.serializeFloat(memPtr->m_com);
 | 
						||
		
 | 
						||
		memPtr->m_numPositions = m_pose.m_pos.size();
 | 
						||
		memPtr->m_positions = memPtr->m_numPositions ? (btVector3FloatData*)serializer->getUniquePointer((void*)&m_pose.m_pos[0]): 0;
 | 
						||
		if (memPtr->m_numPositions)
 | 
						||
		{
 | 
						||
			int numElem = memPtr->m_numPositions;
 | 
						||
			int sz = sizeof(btVector3Data);
 | 
						||
			btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
			btVector3FloatData* memPtr = (btVector3FloatData*)chunk->m_oldPtr;
 | 
						||
			for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
			{
 | 
						||
				m_pose.m_pos[i].serializeFloat(*memPtr);
 | 
						||
			}
 | 
						||
			serializer->finalizeChunk(chunk,"btVector3FloatData",BT_ARRAY_CODE,(void*)&m_pose.m_pos[0]);
 | 
						||
		}
 | 
						||
		memPtr->m_restVolume = m_pose.m_volume;
 | 
						||
		m_pose.m_rot.serializeFloat(memPtr->m_rot);
 | 
						||
		m_pose.m_scl.serializeFloat(memPtr->m_scale);
 | 
						||
 | 
						||
		memPtr->m_numWeigts = m_pose.m_wgh.size();
 | 
						||
		memPtr->m_weights = memPtr->m_numWeigts? (float*) serializer->getUniquePointer((void*) &m_pose.m_wgh[0]) : 0;
 | 
						||
		if (memPtr->m_numWeigts)
 | 
						||
		{
 | 
						||
			
 | 
						||
			int numElem = memPtr->m_numWeigts;
 | 
						||
			int sz = sizeof(float);
 | 
						||
			btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
			float* memPtr = (float*) chunk->m_oldPtr;
 | 
						||
			for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
			{
 | 
						||
				*memPtr = m_pose.m_wgh[i];
 | 
						||
			}
 | 
						||
			serializer->finalizeChunk(chunk,"float",BT_ARRAY_CODE,(void*)&m_pose.m_wgh[0]);
 | 
						||
		}
 | 
						||
 | 
						||
		serializer->finalizeChunk(chunk,"SoftBodyPoseData",BT_ARRAY_CODE,(void*)&m_pose);
 | 
						||
	}
 | 
						||
 | 
						||
	//clusters for convex-cluster collision detection
 | 
						||
 | 
						||
	sbd->m_numClusters = m_clusters.size();
 | 
						||
	sbd->m_clusters = sbd->m_numClusters? (SoftBodyClusterData*) serializer->getUniquePointer((void*)m_clusters[0]) : 0;
 | 
						||
	if (sbd->m_numClusters)
 | 
						||
	{
 | 
						||
		int numElem = sbd->m_numClusters;
 | 
						||
		int sz = sizeof(SoftBodyClusterData);
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		SoftBodyClusterData* memPtr = (SoftBodyClusterData*) chunk->m_oldPtr;
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			memPtr->m_adamping= m_clusters[i]->m_adamping;
 | 
						||
			m_clusters[i]->m_av.serializeFloat(memPtr->m_av);
 | 
						||
			memPtr->m_clusterIndex = m_clusters[i]->m_clusterIndex;
 | 
						||
			memPtr->m_collide = m_clusters[i]->m_collide;
 | 
						||
			m_clusters[i]->m_com.serializeFloat(memPtr->m_com);
 | 
						||
			memPtr->m_containsAnchor = m_clusters[i]->m_containsAnchor;
 | 
						||
			m_clusters[i]->m_dimpulses[0].serializeFloat(memPtr->m_dimpulses[0]);
 | 
						||
			m_clusters[i]->m_dimpulses[1].serializeFloat(memPtr->m_dimpulses[1]);
 | 
						||
			m_clusters[i]->m_framexform.serializeFloat(memPtr->m_framexform);
 | 
						||
			memPtr->m_idmass = m_clusters[i]->m_idmass;
 | 
						||
			memPtr->m_imass = m_clusters[i]->m_imass;
 | 
						||
			m_clusters[i]->m_invwi.serializeFloat(memPtr->m_invwi);
 | 
						||
			memPtr->m_ldamping = m_clusters[i]->m_ldamping;
 | 
						||
			m_clusters[i]->m_locii.serializeFloat(memPtr->m_locii);
 | 
						||
			m_clusters[i]->m_lv.serializeFloat(memPtr->m_lv);
 | 
						||
			memPtr->m_matching = m_clusters[i]->m_matching;
 | 
						||
			memPtr->m_maxSelfCollisionImpulse = m_clusters[i]->m_maxSelfCollisionImpulse;
 | 
						||
			memPtr->m_ndamping = m_clusters[i]->m_ndamping;
 | 
						||
			memPtr->m_ldamping = m_clusters[i]->m_ldamping;
 | 
						||
			memPtr->m_adamping = m_clusters[i]->m_adamping;
 | 
						||
			memPtr->m_selfCollisionImpulseFactor = m_clusters[i]->m_selfCollisionImpulseFactor;
 | 
						||
 | 
						||
			memPtr->m_numFrameRefs = m_clusters[i]->m_framerefs.size();
 | 
						||
			memPtr->m_numMasses = m_clusters[i]->m_masses.size();
 | 
						||
			memPtr->m_numNodes = m_clusters[i]->m_nodes.size();
 | 
						||
 | 
						||
			memPtr->m_nvimpulses = m_clusters[i]->m_nvimpulses;
 | 
						||
			m_clusters[i]->m_vimpulses[0].serializeFloat(memPtr->m_vimpulses[0]);
 | 
						||
			m_clusters[i]->m_vimpulses[1].serializeFloat(memPtr->m_vimpulses[1]);
 | 
						||
			memPtr->m_ndimpulses = m_clusters[i]->m_ndimpulses;
 | 
						||
 | 
						||
			
 | 
						||
 | 
						||
			memPtr->m_framerefs = memPtr->m_numFrameRefs? (btVector3FloatData*)serializer->getUniquePointer((void*)&m_clusters[i]->m_framerefs[0]) : 0;
 | 
						||
			if (memPtr->m_framerefs)
 | 
						||
			{
 | 
						||
				int numElem = memPtr->m_numFrameRefs;
 | 
						||
				int sz = sizeof(btVector3FloatData);
 | 
						||
				btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
				btVector3FloatData* memPtr = (btVector3FloatData*) chunk->m_oldPtr;
 | 
						||
				for (int j=0;j<numElem;j++,memPtr++)
 | 
						||
				{
 | 
						||
					m_clusters[i]->m_framerefs[j].serializeFloat(*memPtr);
 | 
						||
				}
 | 
						||
				serializer->finalizeChunk(chunk,"btVector3FloatData",BT_ARRAY_CODE,(void*)&m_clusters[i]->m_framerefs[0]);
 | 
						||
			}
 | 
						||
			
 | 
						||
			memPtr->m_masses = memPtr->m_numMasses ? (float*) serializer->getUniquePointer((void*)&m_clusters[i]->m_masses[0]): 0;
 | 
						||
			if (memPtr->m_masses)
 | 
						||
			{
 | 
						||
				int numElem = memPtr->m_numMasses;
 | 
						||
				int sz = sizeof(float);
 | 
						||
				btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
				float* memPtr = (float*) chunk->m_oldPtr;
 | 
						||
				for (int j=0;j<numElem;j++,memPtr++)
 | 
						||
				{
 | 
						||
					*memPtr = m_clusters[i]->m_masses[j];
 | 
						||
				}
 | 
						||
				serializer->finalizeChunk(chunk,"float",BT_ARRAY_CODE,(void*)&m_clusters[i]->m_masses[0]);
 | 
						||
			}
 | 
						||
 | 
						||
			memPtr->m_nodeIndices  = memPtr->m_numNodes ? (int*) serializer->getUniquePointer((void*) &m_clusters[i]->m_nodes) : 0;
 | 
						||
			if (memPtr->m_nodeIndices )
 | 
						||
			{
 | 
						||
				int numElem = memPtr->m_numMasses;
 | 
						||
				int sz = sizeof(int);
 | 
						||
				btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
				int* memPtr = (int*) chunk->m_oldPtr;
 | 
						||
				for (int j=0;j<numElem;j++,memPtr++)
 | 
						||
				{
 | 
						||
					int* indexPtr = m_nodeIndexMap.find(m_clusters[i]->m_nodes[j]);
 | 
						||
					btAssert(indexPtr);
 | 
						||
					*memPtr = *indexPtr;
 | 
						||
				}
 | 
						||
				serializer->finalizeChunk(chunk,"int",BT_ARRAY_CODE,(void*)&m_clusters[i]->m_nodes);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"SoftBodyClusterData",BT_ARRAY_CODE,(void*)m_clusters[0]);
 | 
						||
 | 
						||
	}
 | 
						||
	
 | 
						||
 | 
						||
	
 | 
						||
	sbd->m_numJoints = m_joints.size();
 | 
						||
	sbd->m_joints = m_joints.size()? (btSoftBodyJointData*) serializer->getUniquePointer((void*)&m_joints[0]) : 0;
 | 
						||
 | 
						||
	if (sbd->m_joints)
 | 
						||
	{
 | 
						||
		int sz = sizeof(btSoftBodyJointData);
 | 
						||
		int numElem = m_joints.size();
 | 
						||
		btChunk* chunk = serializer->allocate(sz,numElem);
 | 
						||
		btSoftBodyJointData* memPtr = (btSoftBodyJointData*)chunk->m_oldPtr;
 | 
						||
 | 
						||
		for (int i=0;i<numElem;i++,memPtr++)
 | 
						||
		{
 | 
						||
			memPtr->m_jointType = (int)m_joints[i]->Type();
 | 
						||
			m_joints[i]->m_refs[0].serializeFloat(memPtr->m_refs[0]);
 | 
						||
			m_joints[i]->m_refs[1].serializeFloat(memPtr->m_refs[1]);
 | 
						||
			memPtr->m_cfm = m_joints[i]->m_cfm;
 | 
						||
			memPtr->m_erp = float(m_joints[i]->m_erp);
 | 
						||
			memPtr->m_split = float(m_joints[i]->m_split);
 | 
						||
			memPtr->m_delete = m_joints[i]->m_delete;
 | 
						||
			
 | 
						||
			for (int j=0;j<4;j++)
 | 
						||
			{
 | 
						||
				memPtr->m_relPosition[0].m_floats[j] = 0.f;
 | 
						||
				memPtr->m_relPosition[1].m_floats[j] = 0.f;
 | 
						||
			}
 | 
						||
			memPtr->m_bodyA = 0;
 | 
						||
			memPtr->m_bodyB = 0;
 | 
						||
			if (m_joints[i]->m_bodies[0].m_soft)
 | 
						||
			{
 | 
						||
				memPtr->m_bodyAtype = BT_JOINT_SOFT_BODY_CLUSTER;
 | 
						||
				memPtr->m_bodyA = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[0].m_soft);
 | 
						||
			}
 | 
						||
			if (m_joints[i]->m_bodies[0].m_collisionObject)
 | 
						||
			{
 | 
						||
				memPtr->m_bodyAtype = BT_JOINT_COLLISION_OBJECT;
 | 
						||
				memPtr->m_bodyA = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[0].m_collisionObject);
 | 
						||
			}
 | 
						||
			if (m_joints[i]->m_bodies[0].m_rigid)
 | 
						||
			{
 | 
						||
				memPtr->m_bodyAtype = BT_JOINT_RIGID_BODY;
 | 
						||
				memPtr->m_bodyA = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[0].m_rigid);
 | 
						||
			}
 | 
						||
 | 
						||
			if (m_joints[i]->m_bodies[1].m_soft)
 | 
						||
			{
 | 
						||
				memPtr->m_bodyBtype = BT_JOINT_SOFT_BODY_CLUSTER;
 | 
						||
				memPtr->m_bodyB = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[1].m_soft);
 | 
						||
			}
 | 
						||
			if (m_joints[i]->m_bodies[1].m_collisionObject)
 | 
						||
			{
 | 
						||
				memPtr->m_bodyBtype = BT_JOINT_COLLISION_OBJECT;
 | 
						||
				memPtr->m_bodyB = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[1].m_collisionObject);
 | 
						||
			}
 | 
						||
			if (m_joints[i]->m_bodies[1].m_rigid)
 | 
						||
			{
 | 
						||
				memPtr->m_bodyBtype = BT_JOINT_RIGID_BODY;
 | 
						||
				memPtr->m_bodyB = serializer->getUniquePointer((void*)m_joints[i]->m_bodies[1].m_rigid);
 | 
						||
			}
 | 
						||
		}
 | 
						||
		serializer->finalizeChunk(chunk,"btSoftBodyJointData",BT_ARRAY_CODE,(void*) &m_joints[0]);
 | 
						||
	}
 | 
						||
 | 
						||
 | 
						||
	return btSoftBodyDataName;
 | 
						||
}
 | 
						||
 |