Home | History | Annotate | Download | only in BulletSoftBody
      1 /*
      2 Bullet Continuous Collision Detection and Physics Library
      3 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
      4 
      5 This software is provided 'as-is', without any express or implied warranty.
      6 In no event will the authors be held liable for any damages arising from the use of this software.
      7 Permission is granted to anyone to use this software for any purpose,
      8 including commercial applications, and to alter it and redistribute it freely,
      9 subject to the following restrictions:
     10 
     11 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.
     12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
     13 3. This notice may not be removed or altered from any source distribution.
     14 */
     15 ///btSoftBodyHelpers.cpp by Nathanael Presson
     16 
     17 #include "btSoftBodyInternals.h"
     18 #include <stdio.h>
     19 #include <string.h>
     20 #include "btSoftBodyHelpers.h"
     21 #include "LinearMath/btConvexHull.h"
     22 #include "LinearMath/btConvexHullComputer.h"
     23 
     24 
     25 //
     26 static void				drawVertex(	btIDebugDraw* idraw,
     27 								   const btVector3& x,btScalar s,const btVector3& c)
     28 {
     29 	idraw->drawLine(x-btVector3(s,0,0),x+btVector3(s,0,0),c);
     30 	idraw->drawLine(x-btVector3(0,s,0),x+btVector3(0,s,0),c);
     31 	idraw->drawLine(x-btVector3(0,0,s),x+btVector3(0,0,s),c);
     32 }
     33 
     34 //
     35 static void				drawBox(	btIDebugDraw* idraw,
     36 								const btVector3& mins,
     37 								const btVector3& maxs,
     38 								const btVector3& color)
     39 {
     40 	const btVector3	c[]={	btVector3(mins.x(),mins.y(),mins.z()),
     41 		btVector3(maxs.x(),mins.y(),mins.z()),
     42 		btVector3(maxs.x(),maxs.y(),mins.z()),
     43 		btVector3(mins.x(),maxs.y(),mins.z()),
     44 		btVector3(mins.x(),mins.y(),maxs.z()),
     45 		btVector3(maxs.x(),mins.y(),maxs.z()),
     46 		btVector3(maxs.x(),maxs.y(),maxs.z()),
     47 		btVector3(mins.x(),maxs.y(),maxs.z())};
     48 	idraw->drawLine(c[0],c[1],color);idraw->drawLine(c[1],c[2],color);
     49 	idraw->drawLine(c[2],c[3],color);idraw->drawLine(c[3],c[0],color);
     50 	idraw->drawLine(c[4],c[5],color);idraw->drawLine(c[5],c[6],color);
     51 	idraw->drawLine(c[6],c[7],color);idraw->drawLine(c[7],c[4],color);
     52 	idraw->drawLine(c[0],c[4],color);idraw->drawLine(c[1],c[5],color);
     53 	idraw->drawLine(c[2],c[6],color);idraw->drawLine(c[3],c[7],color);
     54 }
     55 
     56 //
     57 static void				drawTree(	btIDebugDraw* idraw,
     58 								 const btDbvtNode* node,
     59 								 int depth,
     60 								 const btVector3& ncolor,
     61 								 const btVector3& lcolor,
     62 								 int mindepth,
     63 								 int maxdepth)
     64 {
     65 	if(node)
     66 	{
     67 		if(node->isinternal()&&((depth<maxdepth)||(maxdepth<0)))
     68 		{
     69 			drawTree(idraw,node->childs[0],depth+1,ncolor,lcolor,mindepth,maxdepth);
     70 			drawTree(idraw,node->childs[1],depth+1,ncolor,lcolor,mindepth,maxdepth);
     71 		}
     72 		if(depth>=mindepth)
     73 		{
     74 			const btScalar	scl=(btScalar)(node->isinternal()?1:1);
     75 			const btVector3	mi=node->volume.Center()-node->volume.Extents()*scl;
     76 			const btVector3	mx=node->volume.Center()+node->volume.Extents()*scl;
     77 			drawBox(idraw,mi,mx,node->isleaf()?lcolor:ncolor);
     78 		}
     79 	}
     80 }
     81 
     82 //
     83 template <typename T>
     84 static inline T				sum(const btAlignedObjectArray<T>& items)
     85 {
     86 	T	v;
     87 	if(items.size())
     88 	{
     89 		v=items[0];
     90 		for(int i=1,ni=items.size();i<ni;++i)
     91 		{
     92 			v+=items[i];
     93 		}
     94 	}
     95 	return(v);
     96 }
     97 
     98 //
     99 template <typename T,typename Q>
    100 static inline void			add(btAlignedObjectArray<T>& items,const Q& value)
    101 {
    102 	for(int i=0,ni=items.size();i<ni;++i)
    103 	{
    104 		items[i]+=value;
    105 	}
    106 }
    107 
    108 //
    109 template <typename T,typename Q>
    110 static inline void			mul(btAlignedObjectArray<T>& items,const Q& value)
    111 {
    112 	for(int i=0,ni=items.size();i<ni;++i)
    113 	{
    114 		items[i]*=value;
    115 	}
    116 }
    117 
    118 //
    119 template <typename T>
    120 static inline T				average(const btAlignedObjectArray<T>& items)
    121 {
    122 	const btScalar	n=(btScalar)(items.size()>0?items.size():1);
    123 	return(sum(items)/n);
    124 }
    125 
    126 //
    127 static inline btScalar		tetravolume(const btVector3& x0,
    128 										const btVector3& x1,
    129 										const btVector3& x2,
    130 										const btVector3& x3)
    131 {
    132 	const btVector3	a=x1-x0;
    133 	const btVector3	b=x2-x0;
    134 	const btVector3	c=x3-x0;
    135 	return(btDot(a,btCross(b,c)));
    136 }
    137 
    138 //
    139 #if 0
    140 static btVector3		stresscolor(btScalar stress)
    141 {
    142 	static const btVector3	spectrum[]=	{	btVector3(1,0,1),
    143 		btVector3(0,0,1),
    144 		btVector3(0,1,1),
    145 		btVector3(0,1,0),
    146 		btVector3(1,1,0),
    147 		btVector3(1,0,0),
    148 		btVector3(1,0,0)};
    149 	static const int		ncolors=sizeof(spectrum)/sizeof(spectrum[0])-1;
    150 	static const btScalar	one=1;
    151 	stress=btMax<btScalar>(0,btMin<btScalar>(1,stress))*ncolors;
    152 	const int				sel=(int)stress;
    153 	const btScalar			frc=stress-sel;
    154 	return(spectrum[sel]+(spectrum[sel+1]-spectrum[sel])*frc);
    155 }
    156 #endif
    157 
    158 //
    159 void			btSoftBodyHelpers::Draw(	btSoftBody* psb,
    160 										btIDebugDraw* idraw,
    161 										int drawflags)
    162 {
    163 	const btScalar		scl=(btScalar)0.1;
    164 	const btScalar		nscl=scl*5;
    165 	const btVector3		lcolor=btVector3(0,0,0);
    166 	const btVector3		ncolor=btVector3(1,1,1);
    167 	const btVector3		ccolor=btVector3(1,0,0);
    168 	int i,j,nj;
    169 
    170 		/* Clusters	*/
    171 	if(0!=(drawflags&fDrawFlags::Clusters))
    172 	{
    173 		srand(1806);
    174 		for(i=0;i<psb->m_clusters.size();++i)
    175 		{
    176 			if(psb->m_clusters[i]->m_collide)
    177 			{
    178 				btVector3						color(	rand()/(btScalar)RAND_MAX,
    179 					rand()/(btScalar)RAND_MAX,
    180 					rand()/(btScalar)RAND_MAX);
    181 				color=color.normalized()*0.75;
    182 				btAlignedObjectArray<btVector3>	vertices;
    183 				vertices.resize(psb->m_clusters[i]->m_nodes.size());
    184 				for(j=0,nj=vertices.size();j<nj;++j)
    185 				{
    186 					vertices[j]=psb->m_clusters[i]->m_nodes[j]->m_x;
    187 				}
    188 #define USE_NEW_CONVEX_HULL_COMPUTER
    189 #ifdef USE_NEW_CONVEX_HULL_COMPUTER
    190 				btConvexHullComputer	computer;
    191 				int stride = sizeof(btVector3);
    192 				int count = vertices.size();
    193 				btScalar shrink=0.f;
    194 				btScalar shrinkClamp=0.f;
    195 				computer.compute(&vertices[0].getX(),stride,count,shrink,shrinkClamp);
    196 				for (int i=0;i<computer.faces.size();i++)
    197 				{
    198 
    199 					int face = computer.faces[i];
    200 					//printf("face=%d\n",face);
    201 					const btConvexHullComputer::Edge*  firstEdge = &computer.edges[face];
    202 					const btConvexHullComputer::Edge*  edge = firstEdge->getNextEdgeOfFace();
    203 
    204 					int v0 = firstEdge->getSourceVertex();
    205 					int v1 = firstEdge->getTargetVertex();
    206 					while (edge!=firstEdge)
    207 					{
    208 						int v2 = edge->getTargetVertex();
    209 						idraw->drawTriangle(computer.vertices[v0],computer.vertices[v1],computer.vertices[v2],color,1);
    210 						edge = edge->getNextEdgeOfFace();
    211 						v0=v1;
    212 						v1=v2;
    213 					};
    214 				}
    215 #else
    216 
    217 				HullDesc		hdsc(QF_TRIANGLES,vertices.size(),&vertices[0]);
    218 				HullResult		hres;
    219 				HullLibrary		hlib;
    220 				hdsc.mMaxVertices=vertices.size();
    221 				hlib.CreateConvexHull(hdsc,hres);
    222 				const btVector3	center=average(hres.m_OutputVertices);
    223 				add(hres.m_OutputVertices,-center);
    224 				mul(hres.m_OutputVertices,(btScalar)1);
    225 				add(hres.m_OutputVertices,center);
    226 				for(j=0;j<(int)hres.mNumFaces;++j)
    227 				{
    228 					const int idx[]={hres.m_Indices[j*3+0],hres.m_Indices[j*3+1],hres.m_Indices[j*3+2]};
    229 					idraw->drawTriangle(hres.m_OutputVertices[idx[0]],
    230 						hres.m_OutputVertices[idx[1]],
    231 						hres.m_OutputVertices[idx[2]],
    232 						color,1);
    233 				}
    234 				hlib.ReleaseResult(hres);
    235 #endif
    236 
    237 			}
    238 			/* Velocities	*/
    239 #if 0
    240 			for(int j=0;j<psb->m_clusters[i].m_nodes.size();++j)
    241 			{
    242 				const btSoftBody::Cluster&	c=psb->m_clusters[i];
    243 				const btVector3				r=c.m_nodes[j]->m_x-c.m_com;
    244 				const btVector3				v=c.m_lv+btCross(c.m_av,r);
    245 				idraw->drawLine(c.m_nodes[j]->m_x,c.m_nodes[j]->m_x+v,btVector3(1,0,0));
    246 			}
    247 #endif
    248 			/* Frame		*/
    249 	//		btSoftBody::Cluster& c=*psb->m_clusters[i];
    250 	//		idraw->drawLine(c.m_com,c.m_framexform*btVector3(10,0,0),btVector3(1,0,0));
    251 	//		idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,10,0),btVector3(0,1,0));
    252 	//		idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,0,10),btVector3(0,0,1));
    253 		}
    254 	}
    255 	else
    256 	{
    257 		/* Nodes	*/
    258 		if(0!=(drawflags&fDrawFlags::Nodes))
    259 		{
    260 			for(i=0;i<psb->m_nodes.size();++i)
    261 			{
    262 				const btSoftBody::Node&	n=psb->m_nodes[i];
    263 				if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
    264 				idraw->drawLine(n.m_x-btVector3(scl,0,0),n.m_x+btVector3(scl,0,0),btVector3(1,0,0));
    265 				idraw->drawLine(n.m_x-btVector3(0,scl,0),n.m_x+btVector3(0,scl,0),btVector3(0,1,0));
    266 				idraw->drawLine(n.m_x-btVector3(0,0,scl),n.m_x+btVector3(0,0,scl),btVector3(0,0,1));
    267 			}
    268 		}
    269 		/* Links	*/
    270 		if(0!=(drawflags&fDrawFlags::Links))
    271 		{
    272 			for(i=0;i<psb->m_links.size();++i)
    273 			{
    274 				const btSoftBody::Link&	l=psb->m_links[i];
    275 				if(0==(l.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
    276 				idraw->drawLine(l.m_n[0]->m_x,l.m_n[1]->m_x,lcolor);
    277 			}
    278 		}
    279 		/* Normals	*/
    280 		if(0!=(drawflags&fDrawFlags::Normals))
    281 		{
    282 			for(i=0;i<psb->m_nodes.size();++i)
    283 			{
    284 				const btSoftBody::Node&	n=psb->m_nodes[i];
    285 				if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
    286 				const btVector3			d=n.m_n*nscl;
    287 				idraw->drawLine(n.m_x,n.m_x+d,ncolor);
    288 				idraw->drawLine(n.m_x,n.m_x-d,ncolor*0.5);
    289 			}
    290 		}
    291 		/* Contacts	*/
    292 		if(0!=(drawflags&fDrawFlags::Contacts))
    293 		{
    294 			static const btVector3		axis[]={btVector3(1,0,0),
    295 				btVector3(0,1,0),
    296 				btVector3(0,0,1)};
    297 			for(i=0;i<psb->m_rcontacts.size();++i)
    298 			{
    299 				const btSoftBody::RContact&	c=psb->m_rcontacts[i];
    300 				const btVector3				o=	c.m_node->m_x-c.m_cti.m_normal*
    301 					(btDot(c.m_node->m_x,c.m_cti.m_normal)+c.m_cti.m_offset);
    302 				const btVector3				x=btCross(c.m_cti.m_normal,axis[c.m_cti.m_normal.minAxis()]).normalized();
    303 				const btVector3				y=btCross(x,c.m_cti.m_normal).normalized();
    304 				idraw->drawLine(o-x*nscl,o+x*nscl,ccolor);
    305 				idraw->drawLine(o-y*nscl,o+y*nscl,ccolor);
    306 				idraw->drawLine(o,o+c.m_cti.m_normal*nscl*3,btVector3(1,1,0));
    307 			}
    308 		}
    309 		/* Faces	*/
    310 	if(0!=(drawflags&fDrawFlags::Faces))
    311 	{
    312 		const btScalar	scl=(btScalar)0.8;
    313 		const btScalar	alp=(btScalar)1;
    314 		const btVector3	col(0,(btScalar)0.7,0);
    315 		for(i=0;i<psb->m_faces.size();++i)
    316 		{
    317 			const btSoftBody::Face&	f=psb->m_faces[i];
    318 			if(0==(f.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
    319 			const btVector3			x[]={f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x};
    320 			const btVector3			c=(x[0]+x[1]+x[2])/3;
    321 			idraw->drawTriangle((x[0]-c)*scl+c,
    322 				(x[1]-c)*scl+c,
    323 				(x[2]-c)*scl+c,
    324 				col,alp);
    325 		}
    326 	}
    327 	/* Tetras	*/
    328 	if(0!=(drawflags&fDrawFlags::Tetras))
    329 	{
    330 		const btScalar	scl=(btScalar)0.8;
    331 		const btScalar	alp=(btScalar)1;
    332 		const btVector3	col((btScalar)0.3,(btScalar)0.3,(btScalar)0.7);
    333 		for(int i=0;i<psb->m_tetras.size();++i)
    334 		{
    335 			const btSoftBody::Tetra&	t=psb->m_tetras[i];
    336 			if(0==(t.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
    337 			const btVector3				x[]={t.m_n[0]->m_x,t.m_n[1]->m_x,t.m_n[2]->m_x,t.m_n[3]->m_x};
    338 			const btVector3				c=(x[0]+x[1]+x[2]+x[3])/4;
    339 			idraw->drawTriangle((x[0]-c)*scl+c,(x[1]-c)*scl+c,(x[2]-c)*scl+c,col,alp);
    340 			idraw->drawTriangle((x[0]-c)*scl+c,(x[1]-c)*scl+c,(x[3]-c)*scl+c,col,alp);
    341 			idraw->drawTriangle((x[1]-c)*scl+c,(x[2]-c)*scl+c,(x[3]-c)*scl+c,col,alp);
    342 			idraw->drawTriangle((x[2]-c)*scl+c,(x[0]-c)*scl+c,(x[3]-c)*scl+c,col,alp);
    343 		}
    344 	}
    345 	}
    346 	/* Anchors	*/
    347 	if(0!=(drawflags&fDrawFlags::Anchors))
    348 	{
    349 		for(i=0;i<psb->m_anchors.size();++i)
    350 		{
    351 			const btSoftBody::Anchor&	a=psb->m_anchors[i];
    352 			const btVector3				q=a.m_body->getWorldTransform()*a.m_local;
    353 			drawVertex(idraw,a.m_node->m_x,0.25,btVector3(1,0,0));
    354 			drawVertex(idraw,q,0.25,btVector3(0,1,0));
    355 			idraw->drawLine(a.m_node->m_x,q,btVector3(1,1,1));
    356 		}
    357 		for(i=0;i<psb->m_nodes.size();++i)
    358 		{
    359 			const btSoftBody::Node&	n=psb->m_nodes[i];
    360 			if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue;
    361 			if(n.m_im<=0)
    362 			{
    363 				drawVertex(idraw,n.m_x,0.25,btVector3(1,0,0));
    364 			}
    365 		}
    366 	}
    367 
    368 
    369 	/* Notes	*/
    370 	if(0!=(drawflags&fDrawFlags::Notes))
    371 	{
    372 		for(i=0;i<psb->m_notes.size();++i)
    373 		{
    374 			const btSoftBody::Note&	n=psb->m_notes[i];
    375 			btVector3				p=n.m_offset;
    376 			for(int j=0;j<n.m_rank;++j)
    377 			{
    378 				p+=n.m_nodes[j]->m_x*n.m_coords[j];
    379 			}
    380 			idraw->draw3dText(p,n.m_text);
    381 		}
    382 	}
    383 	/* Node tree	*/
    384 	if(0!=(drawflags&fDrawFlags::NodeTree))		DrawNodeTree(psb,idraw);
    385 	/* Face tree	*/
    386 	if(0!=(drawflags&fDrawFlags::FaceTree))		DrawFaceTree(psb,idraw);
    387 	/* Cluster tree	*/
    388 	if(0!=(drawflags&fDrawFlags::ClusterTree))	DrawClusterTree(psb,idraw);
    389 	/* Joints		*/
    390 	if(0!=(drawflags&fDrawFlags::Joints))
    391 	{
    392 		for(i=0;i<psb->m_joints.size();++i)
    393 		{
    394 			const btSoftBody::Joint*	pj=psb->m_joints[i];
    395 			switch(pj->Type())
    396 			{
    397 			case	btSoftBody::Joint::eType::Linear:
    398 				{
    399 					const btSoftBody::LJoint*	pjl=(const btSoftBody::LJoint*)pj;
    400 					const btVector3	a0=pj->m_bodies[0].xform()*pjl->m_refs[0];
    401 					const btVector3	a1=pj->m_bodies[1].xform()*pjl->m_refs[1];
    402 					idraw->drawLine(pj->m_bodies[0].xform().getOrigin(),a0,btVector3(1,1,0));
    403 					idraw->drawLine(pj->m_bodies[1].xform().getOrigin(),a1,btVector3(0,1,1));
    404 					drawVertex(idraw,a0,0.25,btVector3(1,1,0));
    405 					drawVertex(idraw,a1,0.25,btVector3(0,1,1));
    406 				}
    407 				break;
    408 			case	btSoftBody::Joint::eType::Angular:
    409 				{
    410 					//const btSoftBody::AJoint*	pja=(const btSoftBody::AJoint*)pj;
    411 					const btVector3	o0=pj->m_bodies[0].xform().getOrigin();
    412 					const btVector3	o1=pj->m_bodies[1].xform().getOrigin();
    413 					const btVector3	a0=pj->m_bodies[0].xform().getBasis()*pj->m_refs[0];
    414 					const btVector3	a1=pj->m_bodies[1].xform().getBasis()*pj->m_refs[1];
    415 					idraw->drawLine(o0,o0+a0*10,btVector3(1,1,0));
    416 					idraw->drawLine(o0,o0+a1*10,btVector3(1,1,0));
    417 					idraw->drawLine(o1,o1+a0*10,btVector3(0,1,1));
    418 					idraw->drawLine(o1,o1+a1*10,btVector3(0,1,1));
    419 					break;
    420 				}
    421 				default:
    422 				{
    423 				}
    424 
    425 			}
    426 		}
    427 	}
    428 }
    429 
    430 //
    431 void			btSoftBodyHelpers::DrawInfos(		btSoftBody* psb,
    432 											 btIDebugDraw* idraw,
    433 											 bool masses,
    434 											 bool areas,
    435 											 bool /*stress*/)
    436 {
    437 	for(int i=0;i<psb->m_nodes.size();++i)
    438 	{
    439 		const btSoftBody::Node&	n=psb->m_nodes[i];
    440 		char					text[2048]={0};
    441 		char					buff[1024];
    442 		if(masses)
    443 		{
    444 			sprintf(buff," M(%.2f)",1/n.m_im);
    445 			strcat(text,buff);
    446 		}
    447 		if(areas)
    448 		{
    449 			sprintf(buff," A(%.2f)",n.m_area);
    450 			strcat(text,buff);
    451 		}
    452 		if(text[0]) idraw->draw3dText(n.m_x,text);
    453 	}
    454 }
    455 
    456 //
    457 void			btSoftBodyHelpers::DrawNodeTree(	btSoftBody* psb,
    458 												btIDebugDraw* idraw,
    459 												int mindepth,
    460 												int maxdepth)
    461 {
    462 	drawTree(idraw,psb->m_ndbvt.m_root,0,btVector3(1,0,1),btVector3(1,1,1),mindepth,maxdepth);
    463 }
    464 
    465 //
    466 void			btSoftBodyHelpers::DrawFaceTree(	btSoftBody* psb,
    467 												btIDebugDraw* idraw,
    468 												int mindepth,
    469 												int maxdepth)
    470 {
    471 	drawTree(idraw,psb->m_fdbvt.m_root,0,btVector3(0,1,0),btVector3(1,0,0),mindepth,maxdepth);
    472 }
    473 
    474 //
    475 void			btSoftBodyHelpers::DrawClusterTree(	btSoftBody* psb,
    476 												   btIDebugDraw* idraw,
    477 												   int mindepth,
    478 												   int maxdepth)
    479 {
    480 	drawTree(idraw,psb->m_cdbvt.m_root,0,btVector3(0,1,1),btVector3(1,0,0),mindepth,maxdepth);
    481 }
    482 
    483 
    484 //The btSoftBody object from the BulletSDK includes an array of Nodes and Links. These links appear
    485 // to be first set up to connect a node to between 5 and 6 of its neighbors [480 links],
    486 //and then to the rest of the nodes after the execution of the Floyd-Warshall graph algorithm
    487 //[another 930 links].
    488 //The way the links are stored by default, we have a number of cases where adjacent links share a node in common
    489 // - this leads to the creation of a data dependency through memory.
    490 //The PSolve_Links() function reads and writes nodes as it iterates over each link.
    491 //So, we now have the possibility of a data dependency between iteration X
    492 //that processes link L with iteration X+1 that processes link L+1
    493 //because L and L+1 have one node in common, and iteration X updates the positions of that node,
    494 //and iteration X+1 reads in the position of that shared node.
    495 //
    496 //Such a memory dependency limits the ability of a modern CPU to speculate beyond
    497 //a certain point because it has to respect a possible dependency
    498 //- this prevents the CPU from making full use of its out-of-order resources.
    499 //If we re-order the links such that we minimize the cases where a link L and L+1 share a common node,
    500 //we create a temporal gap between when the node position is written,
    501 //and when it is subsequently read. This in turn allows the CPU to continue execution without
    502 //risking a dependency violation. Such a reordering would result in significant speedups on
    503 //modern CPUs with lots of execution resources.
    504 //In our testing, we see it have a tremendous impact not only on the A7,
    505 //but also on all x86 cores that ship with modern Macs.
    506 //The attached source file includes a single function (ReoptimizeLinkOrder) which can be called on a
    507 //btSoftBody object in the solveConstraints() function before the actual solver is invoked,
    508 //or right after generateBendingConstraints() once we have all 1410 links.
    509 
    510 
    511 //===================================================================
    512 //
    513 //
    514 // This function takes in a list of interdependent Links and tries
    515 // to maximize the distance between calculation
    516 // of dependent links.  This increases the amount of parallelism that can
    517 // be exploited by out-of-order instruction processors with large but
    518 // (inevitably) finite instruction windows.
    519 //
    520 //===================================================================
    521 
    522 // A small structure to track lists of dependent link calculations
    523 class LinkDeps_t {
    524 	public:
    525 	int value;			// A link calculation that is dependent on this one
    526 		// Positive values = "input A" while negative values = "input B"
    527 	LinkDeps_t *next;	// Next dependence in the list
    528 };
    529 typedef LinkDeps_t *LinkDepsPtr_t;
    530 
    531 // Dependency list constants
    532 #define REOP_NOT_DEPENDENT	-1
    533 #define REOP_NODE_COMPLETE	-2	// Must be less than REOP_NOT_DEPENDENT
    534 
    535 
    536 void btSoftBodyHelpers::ReoptimizeLinkOrder(btSoftBody *psb /* This can be replaced by a btSoftBody pointer */)
    537 {
    538 	int i, nLinks=psb->m_links.size(), nNodes=psb->m_nodes.size();
    539 	btSoftBody::Link *lr;
    540 	int ar, br;
    541 	btSoftBody::Node *node0 = &(psb->m_nodes[0]);
    542 	btSoftBody::Node *node1 = &(psb->m_nodes[1]);
    543 	LinkDepsPtr_t linkDep;
    544 	int readyListHead, readyListTail, linkNum, linkDepFrees, depLink;
    545 
    546 	// Allocate temporary buffers
    547 	int *nodeWrittenAt = new int[nNodes+1];	// What link calculation produced this node's current values?
    548 	int *linkDepA = new int[nLinks];			// Link calculation input is dependent upon prior calculation #N
    549 	int *linkDepB = new int[nLinks];
    550 	int *readyList = new int[nLinks];		// List of ready-to-process link calculations (# of links, maximum)
    551 	LinkDeps_t *linkDepFreeList = new LinkDeps_t[2*nLinks];		// Dependent-on-me list elements (2x# of links, maximum)
    552 	LinkDepsPtr_t *linkDepListStarts = new LinkDepsPtr_t[nLinks];	// Start nodes of dependent-on-me lists, one for each link
    553 
    554 	// Copy the original, unsorted links to a side buffer
    555 	btSoftBody::Link *linkBuffer = new btSoftBody::Link[nLinks];
    556 	memcpy(linkBuffer, &(psb->m_links[0]), sizeof(btSoftBody::Link)*nLinks);
    557 
    558 	// Clear out the node setup and ready list
    559 	for (i=0; i < nNodes+1; i++) {
    560 		nodeWrittenAt[i] = REOP_NOT_DEPENDENT;
    561 	}
    562 	for (i=0; i < nLinks; i++) {
    563 		linkDepListStarts[i] = NULL;
    564 	}
    565 	readyListHead = readyListTail = linkDepFrees = 0;
    566 
    567 	// Initial link analysis to set up data structures
    568 	for (i=0; i < nLinks; i++) {
    569 
    570 		// Note which prior link calculations we are dependent upon & build up dependence lists
    571 		lr = &(psb->m_links[i]);
    572 		ar = (lr->m_n[0] - node0)/(node1 - node0);
    573 		br = (lr->m_n[1] - node0)/(node1 - node0);
    574 		if (nodeWrittenAt[ar] > REOP_NOT_DEPENDENT) {
    575 			linkDepA[i] = nodeWrittenAt[ar];
    576 			linkDep = &linkDepFreeList[linkDepFrees++];
    577 			linkDep->value = i;
    578 			linkDep->next = linkDepListStarts[nodeWrittenAt[ar]];
    579 			linkDepListStarts[nodeWrittenAt[ar]] = linkDep;
    580 		} else {
    581 			linkDepA[i] = REOP_NOT_DEPENDENT;
    582 		}
    583 		if (nodeWrittenAt[br] > REOP_NOT_DEPENDENT) {
    584 			linkDepB[i] = nodeWrittenAt[br];
    585 			linkDep = &linkDepFreeList[linkDepFrees++];
    586 			linkDep->value = -(i+1);
    587 			linkDep->next = linkDepListStarts[nodeWrittenAt[br]];
    588 			linkDepListStarts[nodeWrittenAt[br]] = linkDep;
    589 		} else {
    590 			linkDepB[i] = REOP_NOT_DEPENDENT;
    591 		}
    592 
    593 		// Add this link to the initial ready list, if it is not dependent on any other links
    594 		if ((linkDepA[i] == REOP_NOT_DEPENDENT) && (linkDepB[i] == REOP_NOT_DEPENDENT)) {
    595 			readyList[readyListTail++] = i;
    596 			linkDepA[i] = linkDepB[i] = REOP_NODE_COMPLETE;	// Probably not needed now
    597 		}
    598 
    599 		// Update the nodes to mark which ones are calculated by this link
    600 		nodeWrittenAt[ar] = nodeWrittenAt[br] = i;
    601 	}
    602 
    603 	// Process the ready list and create the sorted list of links
    604 	// -- By treating the ready list as a queue, we maximize the distance between any
    605 	//    inter-dependent node calculations
    606 	// -- All other (non-related) nodes in the ready list will automatically be inserted
    607 	//    in between each set of inter-dependent link calculations by this loop
    608 	i = 0;
    609 	while (readyListHead != readyListTail) {
    610 		// Use ready list to select the next link to process
    611 		linkNum = readyList[readyListHead++];
    612 		// Copy the next-to-calculate link back into the original link array
    613 		psb->m_links[i++] = linkBuffer[linkNum];
    614 
    615 		// Free up any link inputs that are dependent on this one
    616 		linkDep = linkDepListStarts[linkNum];
    617 		while (linkDep) {
    618 			depLink = linkDep->value;
    619 			if (depLink >= 0) {
    620 				linkDepA[depLink] = REOP_NOT_DEPENDENT;
    621 			} else {
    622 				depLink = -depLink - 1;
    623 				linkDepB[depLink] = REOP_NOT_DEPENDENT;
    624 			}
    625 			// Add this dependent link calculation to the ready list if *both* inputs are clear
    626 			if ((linkDepA[depLink] == REOP_NOT_DEPENDENT) && (linkDepB[depLink] == REOP_NOT_DEPENDENT)) {
    627 				readyList[readyListTail++] = depLink;
    628 				linkDepA[depLink] = linkDepB[depLink] = REOP_NODE_COMPLETE;	// Probably not needed now
    629 			}
    630 			linkDep = linkDep->next;
    631 		}
    632 	}
    633 
    634 	// Delete the temporary buffers
    635 	delete [] nodeWrittenAt;
    636 	delete [] linkDepA;
    637 	delete [] linkDepB;
    638 	delete [] readyList;
    639 	delete [] linkDepFreeList;
    640 	delete [] linkDepListStarts;
    641 	delete [] linkBuffer;
    642 }
    643 
    644 
    645 //
    646 void			btSoftBodyHelpers::DrawFrame(		btSoftBody* psb,
    647 											 btIDebugDraw* idraw)
    648 {
    649 	if(psb->m_pose.m_bframe)
    650 	{
    651 		static const btScalar	ascl=10;
    652 		static const btScalar	nscl=(btScalar)0.1;
    653 		const btVector3			com=psb->m_pose.m_com;
    654 		const btMatrix3x3		trs=psb->m_pose.m_rot*psb->m_pose.m_scl;
    655 		const btVector3			Xaxis=(trs*btVector3(1,0,0)).normalized();
    656 		const btVector3			Yaxis=(trs*btVector3(0,1,0)).normalized();
    657 		const btVector3			Zaxis=(trs*btVector3(0,0,1)).normalized();
    658 		idraw->drawLine(com,com+Xaxis*ascl,btVector3(1,0,0));
    659 		idraw->drawLine(com,com+Yaxis*ascl,btVector3(0,1,0));
    660 		idraw->drawLine(com,com+Zaxis*ascl,btVector3(0,0,1));
    661 		for(int i=0;i<psb->m_pose.m_pos.size();++i)
    662 		{
    663 			const btVector3	x=com+trs*psb->m_pose.m_pos[i];
    664 			drawVertex(idraw,x,nscl,btVector3(1,0,1));
    665 		}
    666 	}
    667 }
    668 
    669 //
    670 btSoftBody*		btSoftBodyHelpers::CreateRope(	btSoftBodyWorldInfo& worldInfo, const btVector3& from,
    671 											  const btVector3& to,
    672 											  int res,
    673 											  int fixeds)
    674 {
    675 	/* Create nodes	*/
    676 	const int		r=res+2;
    677 	btVector3*		x=new btVector3[r];
    678 	btScalar*		m=new btScalar[r];
    679 	int i;
    680 
    681 	for(i=0;i<r;++i)
    682 	{
    683 		const btScalar	t=i/(btScalar)(r-1);
    684 		x[i]=lerp(from,to,t);
    685 		m[i]=1;
    686 	}
    687 	btSoftBody*		psb= new btSoftBody(&worldInfo,r,x,m);
    688 	if(fixeds&1) psb->setMass(0,0);
    689 	if(fixeds&2) psb->setMass(r-1,0);
    690 	delete[] x;
    691 	delete[] m;
    692 	/* Create links	*/
    693 	for(i=1;i<r;++i)
    694 	{
    695 		psb->appendLink(i-1,i);
    696 	}
    697 	/* Finished		*/
    698 	return(psb);
    699 }
    700 
    701 //
    702 btSoftBody*		btSoftBodyHelpers::CreatePatch(btSoftBodyWorldInfo& worldInfo,const btVector3& corner00,
    703 											   const btVector3& corner10,
    704 											   const btVector3& corner01,
    705 											   const btVector3& corner11,
    706 											   int resx,
    707 											   int resy,
    708 											   int fixeds,
    709 											   bool gendiags)
    710 {
    711 #define IDX(_x_,_y_)	((_y_)*rx+(_x_))
    712 	/* Create nodes	*/
    713 	if((resx<2)||(resy<2)) return(0);
    714 	const int	rx=resx;
    715 	const int	ry=resy;
    716 	const int	tot=rx*ry;
    717 	btVector3*	x=new btVector3[tot];
    718 	btScalar*	m=new btScalar[tot];
    719 	int iy;
    720 
    721 	for(iy=0;iy<ry;++iy)
    722 	{
    723 		const btScalar	ty=iy/(btScalar)(ry-1);
    724 		const btVector3	py0=lerp(corner00,corner01,ty);
    725 		const btVector3	py1=lerp(corner10,corner11,ty);
    726 		for(int ix=0;ix<rx;++ix)
    727 		{
    728 			const btScalar	tx=ix/(btScalar)(rx-1);
    729 			x[IDX(ix,iy)]=lerp(py0,py1,tx);
    730 			m[IDX(ix,iy)]=1;
    731 		}
    732 	}
    733 	btSoftBody*		psb=new btSoftBody(&worldInfo,tot,x,m);
    734 	if(fixeds&1)	psb->setMass(IDX(0,0),0);
    735 	if(fixeds&2)	psb->setMass(IDX(rx-1,0),0);
    736 	if(fixeds&4)	psb->setMass(IDX(0,ry-1),0);
    737 	if(fixeds&8)	psb->setMass(IDX(rx-1,ry-1),0);
    738 	delete[] x;
    739 	delete[] m;
    740 	/* Create links	and faces */
    741 	for(iy=0;iy<ry;++iy)
    742 	{
    743 		for(int ix=0;ix<rx;++ix)
    744 		{
    745 			const int	idx=IDX(ix,iy);
    746 			const bool	mdx=(ix+1)<rx;
    747 			const bool	mdy=(iy+1)<ry;
    748 			if(mdx) psb->appendLink(idx,IDX(ix+1,iy));
    749 			if(mdy) psb->appendLink(idx,IDX(ix,iy+1));
    750 			if(mdx&&mdy)
    751 			{
    752 				if((ix+iy)&1)
    753 				{
    754 					psb->appendFace(IDX(ix,iy),IDX(ix+1,iy),IDX(ix+1,iy+1));
    755 					psb->appendFace(IDX(ix,iy),IDX(ix+1,iy+1),IDX(ix,iy+1));
    756 					if(gendiags)
    757 					{
    758 						psb->appendLink(IDX(ix,iy),IDX(ix+1,iy+1));
    759 					}
    760 				}
    761 				else
    762 				{
    763 					psb->appendFace(IDX(ix,iy+1),IDX(ix,iy),IDX(ix+1,iy));
    764 					psb->appendFace(IDX(ix,iy+1),IDX(ix+1,iy),IDX(ix+1,iy+1));
    765 					if(gendiags)
    766 					{
    767 						psb->appendLink(IDX(ix+1,iy),IDX(ix,iy+1));
    768 					}
    769 				}
    770 			}
    771 		}
    772 	}
    773 	/* Finished		*/
    774 #undef IDX
    775 	return(psb);
    776 }
    777 
    778 //
    779 btSoftBody*		btSoftBodyHelpers::CreatePatchUV(btSoftBodyWorldInfo& worldInfo,
    780 												 const btVector3& corner00,
    781 												 const btVector3& corner10,
    782 												 const btVector3& corner01,
    783 												 const btVector3& corner11,
    784 												 int resx,
    785 												 int resy,
    786 												 int fixeds,
    787 												 bool gendiags,
    788 												 float* tex_coords)
    789 {
    790 
    791 	/*
    792 	*
    793 	*  corners:
    794 	*
    795 	*  [0][0]     corner00 ------- corner01   [resx][0]
    796 	*                |                |
    797 	*                |                |
    798 	*  [0][resy]  corner10 -------- corner11  [resx][resy]
    799 	*
    800 	*
    801 	*
    802 	*
    803 	*
    804 	*
    805 	*   "fixedgs" map:
    806 	*
    807 	*  corner00     -->   +1
    808 	*  corner01     -->   +2
    809 	*  corner10     -->   +4
    810 	*  corner11     -->   +8
    811 	*  upper middle -->  +16
    812 	*  left middle  -->  +32
    813 	*  right middle -->  +64
    814 	*  lower middle --> +128
    815 	*  center       --> +256
    816 	*
    817 	*
    818 	*   tex_coords size   (resx-1)*(resy-1)*12
    819 	*
    820 	*
    821 	*
    822 	*     SINGLE QUAD INTERNALS
    823 	*
    824 	*  1) btSoftBody's nodes and links,
    825 	*     diagonal link is optional ("gendiags")
    826 	*
    827 	*
    828 	*    node00 ------ node01
    829 	*      | .
    830 	*      |   .
    831 	*      |     .
    832 	*      |       .
    833 	*      |         .
    834 	*    node10        node11
    835 	*
    836 	*
    837 	*
    838 	*   2) Faces:
    839 	*      two triangles,
    840 	*      UV Coordinates (hier example for single quad)
    841 	*
    842 	*     (0,1)          (0,1)  (1,1)
    843 	*     1 |\            3 \-----| 2
    844 	*       | \              \    |
    845 	*       |  \              \   |
    846 	*       |   \              \  |
    847 	*       |    \              \ |
    848 	*     2 |-----\ 3            \| 1
    849 	*     (0,0)    (1,0)       (1,0)
    850 	*
    851 	*
    852 	*
    853 	*
    854 	*
    855 	*
    856 	*/
    857 
    858 #define IDX(_x_,_y_)	((_y_)*rx+(_x_))
    859 	/* Create nodes		*/
    860 	if((resx<2)||(resy<2)) return(0);
    861 	const int	rx=resx;
    862 	const int	ry=resy;
    863 	const int	tot=rx*ry;
    864 	btVector3*	x=new btVector3[tot];
    865 	btScalar*	m=new btScalar[tot];
    866 
    867 	int iy;
    868 
    869 	for(iy=0;iy<ry;++iy)
    870 	{
    871 		const btScalar	ty=iy/(btScalar)(ry-1);
    872 		const btVector3	py0=lerp(corner00,corner01,ty);
    873 		const btVector3	py1=lerp(corner10,corner11,ty);
    874 		for(int ix=0;ix<rx;++ix)
    875 		{
    876 			const btScalar	tx=ix/(btScalar)(rx-1);
    877 			x[IDX(ix,iy)]=lerp(py0,py1,tx);
    878 			m[IDX(ix,iy)]=1;
    879 		}
    880 	}
    881 	btSoftBody*	psb=new btSoftBody(&worldInfo,tot,x,m);
    882 	if(fixeds&1)		psb->setMass(IDX(0,0),0);
    883 	if(fixeds&2)		psb->setMass(IDX(rx-1,0),0);
    884 	if(fixeds&4)		psb->setMass(IDX(0,ry-1),0);
    885 	if(fixeds&8)		psb->setMass(IDX(rx-1,ry-1),0);
    886 	if(fixeds&16)		psb->setMass(IDX((rx-1)/2,0),0);
    887 	if(fixeds&32)		psb->setMass(IDX(0,(ry-1)/2),0);
    888 	if(fixeds&64)		psb->setMass(IDX(rx-1,(ry-1)/2),0);
    889 	if(fixeds&128)		psb->setMass(IDX((rx-1)/2,ry-1),0);
    890 	if(fixeds&256)		psb->setMass(IDX((rx-1)/2,(ry-1)/2),0);
    891 	delete[] x;
    892 	delete[] m;
    893 
    894 
    895 	int z = 0;
    896 	/* Create links	and faces	*/
    897 	for(iy=0;iy<ry;++iy)
    898 	{
    899 		for(int ix=0;ix<rx;++ix)
    900 		{
    901 			const bool	mdx=(ix+1)<rx;
    902 			const bool	mdy=(iy+1)<ry;
    903 
    904 			int node00=IDX(ix,iy);
    905 			int node01=IDX(ix+1,iy);
    906 			int node10=IDX(ix,iy+1);
    907 			int node11=IDX(ix+1,iy+1);
    908 
    909 			if(mdx) psb->appendLink(node00,node01);
    910 			if(mdy) psb->appendLink(node00,node10);
    911 			if(mdx&&mdy)
    912 			{
    913 				psb->appendFace(node00,node10,node11);
    914 				if (tex_coords) {
    915 					tex_coords[z+0]=CalculateUV(resx,resy,ix,iy,0);
    916 					tex_coords[z+1]=CalculateUV(resx,resy,ix,iy,1);
    917 					tex_coords[z+2]=CalculateUV(resx,resy,ix,iy,0);
    918 					tex_coords[z+3]=CalculateUV(resx,resy,ix,iy,2);
    919 					tex_coords[z+4]=CalculateUV(resx,resy,ix,iy,3);
    920 					tex_coords[z+5]=CalculateUV(resx,resy,ix,iy,2);
    921 				}
    922 				psb->appendFace(node11,node01,node00);
    923 				if (tex_coords) {
    924 					tex_coords[z+6 ]=CalculateUV(resx,resy,ix,iy,3);
    925 					tex_coords[z+7 ]=CalculateUV(resx,resy,ix,iy,2);
    926 					tex_coords[z+8 ]=CalculateUV(resx,resy,ix,iy,3);
    927 					tex_coords[z+9 ]=CalculateUV(resx,resy,ix,iy,1);
    928 					tex_coords[z+10]=CalculateUV(resx,resy,ix,iy,0);
    929 					tex_coords[z+11]=CalculateUV(resx,resy,ix,iy,1);
    930 				}
    931 				if (gendiags) psb->appendLink(node00,node11);
    932 				z += 12;
    933 			}
    934 		}
    935 	}
    936 	/* Finished	*/
    937 #undef IDX
    938 	return(psb);
    939 }
    940 
    941 float   btSoftBodyHelpers::CalculateUV(int resx,int resy,int ix,int iy,int id)
    942 {
    943 
    944 	/*
    945 	*
    946 	*
    947 	*    node00 --- node01
    948 	*      |          |
    949 	*    node10 --- node11
    950 	*
    951 	*
    952 	*   ID map:
    953 	*
    954 	*   node00 s --> 0
    955 	*   node00 t --> 1
    956 	*
    957 	*   node01 s --> 3
    958 	*   node01 t --> 1
    959 	*
    960 	*   node10 s --> 0
    961 	*   node10 t --> 2
    962 	*
    963 	*   node11 s --> 3
    964 	*   node11 t --> 2
    965 	*
    966 	*
    967 	*/
    968 
    969 	float tc=0.0f;
    970 	if (id == 0) {
    971 		tc = (1.0f/((resx-1))*ix);
    972 	}
    973 	else if (id==1) {
    974 		tc = (1.0f/((resy-1))*(resy-1-iy));
    975 	}
    976 	else if (id==2) {
    977 		tc = (1.0f/((resy-1))*(resy-1-iy-1));
    978 	}
    979 	else if (id==3) {
    980 		tc = (1.0f/((resx-1))*(ix+1));
    981 	}
    982 	return tc;
    983 }
    984 //
    985 btSoftBody*		btSoftBodyHelpers::CreateEllipsoid(btSoftBodyWorldInfo& worldInfo,const btVector3& center,
    986 												   const btVector3& radius,
    987 												   int res)
    988 {
    989 	struct	Hammersley
    990 	{
    991 		static void	Generate(btVector3* x,int n)
    992 		{
    993 			for(int i=0;i<n;i++)
    994 			{
    995 				btScalar	p=0.5,t=0;
    996 				for(int j=i;j;p*=0.5,j>>=1) if(j&1) t+=p;
    997 				btScalar	w=2*t-1;
    998 				btScalar	a=(SIMD_PI+2*i*SIMD_PI)/n;
    999 				btScalar	s=btSqrt(1-w*w);
   1000 				*x++=btVector3(s*btCos(a),s*btSin(a),w);
   1001 			}
   1002 		}
   1003 	};
   1004 	btAlignedObjectArray<btVector3>	vtx;
   1005 	vtx.resize(3+res);
   1006 	Hammersley::Generate(&vtx[0],vtx.size());
   1007 	for(int i=0;i<vtx.size();++i)
   1008 	{
   1009 		vtx[i]=vtx[i]*radius+center;
   1010 	}
   1011 	return(CreateFromConvexHull(worldInfo,&vtx[0],vtx.size()));
   1012 }
   1013 
   1014 
   1015 
   1016 //
   1017 btSoftBody*		btSoftBodyHelpers::CreateFromTriMesh(btSoftBodyWorldInfo& worldInfo,const btScalar*	vertices,
   1018 													 const int* triangles,
   1019 													 int ntriangles, bool randomizeConstraints)
   1020 {
   1021 	int		maxidx=0;
   1022 	int i,j,ni;
   1023 
   1024 	for(i=0,ni=ntriangles*3;i<ni;++i)
   1025 	{
   1026 		maxidx=btMax(triangles[i],maxidx);
   1027 	}
   1028 	++maxidx;
   1029 	btAlignedObjectArray<bool>		chks;
   1030 	btAlignedObjectArray<btVector3>	vtx;
   1031 	chks.resize(maxidx*maxidx,false);
   1032 	vtx.resize(maxidx);
   1033 	for(i=0,j=0,ni=maxidx*3;i<ni;++j,i+=3)
   1034 	{
   1035 		vtx[j]=btVector3(vertices[i],vertices[i+1],vertices[i+2]);
   1036 	}
   1037 	btSoftBody*		psb=new btSoftBody(&worldInfo,vtx.size(),&vtx[0],0);
   1038 	for( i=0,ni=ntriangles*3;i<ni;i+=3)
   1039 	{
   1040 		const int idx[]={triangles[i],triangles[i+1],triangles[i+2]};
   1041 #define IDX(_x_,_y_) ((_y_)*maxidx+(_x_))
   1042 		for(int j=2,k=0;k<3;j=k++)
   1043 		{
   1044 			if(!chks[IDX(idx[j],idx[k])])
   1045 			{
   1046 				chks[IDX(idx[j],idx[k])]=true;
   1047 				chks[IDX(idx[k],idx[j])]=true;
   1048 				psb->appendLink(idx[j],idx[k]);
   1049 			}
   1050 		}
   1051 #undef IDX
   1052 		psb->appendFace(idx[0],idx[1],idx[2]);
   1053 	}
   1054 
   1055 	if (randomizeConstraints)
   1056 	{
   1057 		psb->randomizeConstraints();
   1058 	}
   1059 
   1060 	return(psb);
   1061 }
   1062 
   1063 //
   1064 btSoftBody*		btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldInfo,	const btVector3* vertices,
   1065 														int nvertices, bool randomizeConstraints)
   1066 {
   1067 	HullDesc		hdsc(QF_TRIANGLES,nvertices,vertices);
   1068 	HullResult		hres;
   1069 	HullLibrary		hlib;/*??*/
   1070 	hdsc.mMaxVertices=nvertices;
   1071 	hlib.CreateConvexHull(hdsc,hres);
   1072 	btSoftBody*		psb=new btSoftBody(&worldInfo,(int)hres.mNumOutputVertices,
   1073 		&hres.m_OutputVertices[0],0);
   1074 	for(int i=0;i<(int)hres.mNumFaces;++i)
   1075 	{
   1076 		const int idx[]={	static_cast<int>(hres.m_Indices[i*3+0]),
   1077 							static_cast<int>(hres.m_Indices[i*3+1]),
   1078 							static_cast<int>(hres.m_Indices[i*3+2])};
   1079 		if(idx[0]<idx[1]) psb->appendLink(	idx[0],idx[1]);
   1080 		if(idx[1]<idx[2]) psb->appendLink(	idx[1],idx[2]);
   1081 		if(idx[2]<idx[0]) psb->appendLink(	idx[2],idx[0]);
   1082 		psb->appendFace(idx[0],idx[1],idx[2]);
   1083 	}
   1084 	hlib.ReleaseResult(hres);
   1085 	if (randomizeConstraints)
   1086 	{
   1087 		psb->randomizeConstraints();
   1088 	}
   1089 	return(psb);
   1090 }
   1091 
   1092 
   1093 
   1094 
   1095 static int nextLine(const char* buffer)
   1096 {
   1097 	int numBytesRead=0;
   1098 
   1099 	while (*buffer != '\n')
   1100 	{
   1101 		buffer++;
   1102 		numBytesRead++;
   1103 	}
   1104 
   1105 
   1106 	if (buffer[0]==0x0a)
   1107 	{
   1108 		buffer++;
   1109 		numBytesRead++;
   1110 	}
   1111 	return numBytesRead;
   1112 }
   1113 
   1114 /* Create from TetGen .ele, .face, .node data							*/
   1115 btSoftBody*	btSoftBodyHelpers::CreateFromTetGenData(btSoftBodyWorldInfo& worldInfo,
   1116 													const char* ele,
   1117 													const char* face,
   1118 													const char* node,
   1119 													bool bfacelinks,
   1120 													bool btetralinks,
   1121 													bool bfacesfromtetras)
   1122 {
   1123 btAlignedObjectArray<btVector3>	pos;
   1124 int								nnode=0;
   1125 int								ndims=0;
   1126 int								nattrb=0;
   1127 int								hasbounds=0;
   1128 int result = sscanf(node,"%d %d %d %d",&nnode,&ndims,&nattrb,&hasbounds);
   1129 result = sscanf(node,"%d %d %d %d",&nnode,&ndims,&nattrb,&hasbounds);
   1130 node += nextLine(node);
   1131 
   1132 pos.resize(nnode);
   1133 for(int i=0;i<pos.size();++i)
   1134 	{
   1135 	int			index=0;
   1136 	//int			bound=0;
   1137 	float	x,y,z;
   1138 	sscanf(node,"%d %f %f %f",&index,&x,&y,&z);
   1139 
   1140 //	sn>>index;
   1141 //	sn>>x;sn>>y;sn>>z;
   1142 	node += nextLine(node);
   1143 
   1144 	//for(int j=0;j<nattrb;++j)
   1145 	//	sn>>a;
   1146 
   1147 	//if(hasbounds)
   1148 	//	sn>>bound;
   1149 
   1150 	pos[index].setX(btScalar(x));
   1151 	pos[index].setY(btScalar(y));
   1152 	pos[index].setZ(btScalar(z));
   1153 	}
   1154 btSoftBody*						psb=new btSoftBody(&worldInfo,nnode,&pos[0],0);
   1155 #if 0
   1156 if(face&&face[0])
   1157 	{
   1158 	int								nface=0;
   1159 	sf>>nface;sf>>hasbounds;
   1160 	for(int i=0;i<nface;++i)
   1161 		{
   1162 		int			index=0;
   1163 		int			bound=0;
   1164 		int			ni[3];
   1165 		sf>>index;
   1166 		sf>>ni[0];sf>>ni[1];sf>>ni[2];
   1167 		sf>>bound;
   1168 		psb->appendFace(ni[0],ni[1],ni[2]);
   1169 		if(btetralinks)
   1170 			{
   1171 			psb->appendLink(ni[0],ni[1],0,true);
   1172 			psb->appendLink(ni[1],ni[2],0,true);
   1173 			psb->appendLink(ni[2],ni[0],0,true);
   1174 			}
   1175 		}
   1176 	}
   1177 #endif
   1178 
   1179 if(ele&&ele[0])
   1180 	{
   1181 	int								ntetra=0;
   1182 	int								ncorner=0;
   1183 	int								neattrb=0;
   1184 	sscanf(ele,"%d %d %d",&ntetra,&ncorner,&neattrb);
   1185 	ele += nextLine(ele);
   1186 
   1187 	//se>>ntetra;se>>ncorner;se>>neattrb;
   1188 	for(int i=0;i<ntetra;++i)
   1189 		{
   1190 		int			index=0;
   1191 		int			ni[4];
   1192 
   1193 		//se>>index;
   1194 		//se>>ni[0];se>>ni[1];se>>ni[2];se>>ni[3];
   1195 		sscanf(ele,"%d %d %d %d %d",&index,&ni[0],&ni[1],&ni[2],&ni[3]);
   1196 		ele+=nextLine(ele);
   1197 		//for(int j=0;j<neattrb;++j)
   1198 		//	se>>a;
   1199 		psb->appendTetra(ni[0],ni[1],ni[2],ni[3]);
   1200 		if(btetralinks)
   1201 			{
   1202 			psb->appendLink(ni[0],ni[1],0,true);
   1203 			psb->appendLink(ni[1],ni[2],0,true);
   1204 			psb->appendLink(ni[2],ni[0],0,true);
   1205 			psb->appendLink(ni[0],ni[3],0,true);
   1206 			psb->appendLink(ni[1],ni[3],0,true);
   1207 			psb->appendLink(ni[2],ni[3],0,true);
   1208 			}
   1209 		}
   1210 	}
   1211 printf("Nodes:  %u\r\n",psb->m_nodes.size());
   1212 printf("Links:  %u\r\n",psb->m_links.size());
   1213 printf("Faces:  %u\r\n",psb->m_faces.size());
   1214 printf("Tetras: %u\r\n",psb->m_tetras.size());
   1215 return(psb);
   1216 }
   1217 
   1218