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>
20 #include <iostream>
21 #include <sstream>
22 #include <string.h>
23 #include <algorithm>
24 #include "btSoftBodyHelpers.h"
25 #include "LinearMath/btConvexHull.h"
26 #include "LinearMath/btConvexHullComputer.h"
27 #include <map>
28 #include <vector>
29 
drawVertex(btIDebugDraw * idraw,const btVector3 & x,btScalar s,const btVector3 & c)30 static void drawVertex(btIDebugDraw* idraw,
31 					   const btVector3& x, btScalar s, const btVector3& c)
32 {
33 	idraw->drawLine(x - btVector3(s, 0, 0), x + btVector3(s, 0, 0), c);
34 	idraw->drawLine(x - btVector3(0, s, 0), x + btVector3(0, s, 0), c);
35 	idraw->drawLine(x - btVector3(0, 0, s), x + btVector3(0, 0, s), c);
36 }
37 
38 //
drawBox(btIDebugDraw * idraw,const btVector3 & mins,const btVector3 & maxs,const btVector3 & color)39 static void drawBox(btIDebugDraw* idraw,
40 					const btVector3& mins,
41 					const btVector3& maxs,
42 					const btVector3& color)
43 {
44 	const btVector3 c[] = {btVector3(mins.x(), mins.y(), mins.z()),
45 						   btVector3(maxs.x(), mins.y(), mins.z()),
46 						   btVector3(maxs.x(), maxs.y(), mins.z()),
47 						   btVector3(mins.x(), maxs.y(), mins.z()),
48 						   btVector3(mins.x(), mins.y(), maxs.z()),
49 						   btVector3(maxs.x(), mins.y(), maxs.z()),
50 						   btVector3(maxs.x(), maxs.y(), maxs.z()),
51 						   btVector3(mins.x(), maxs.y(), maxs.z())};
52 	idraw->drawLine(c[0], c[1], color);
53 	idraw->drawLine(c[1], c[2], color);
54 	idraw->drawLine(c[2], c[3], color);
55 	idraw->drawLine(c[3], c[0], color);
56 	idraw->drawLine(c[4], c[5], color);
57 	idraw->drawLine(c[5], c[6], color);
58 	idraw->drawLine(c[6], c[7], color);
59 	idraw->drawLine(c[7], c[4], color);
60 	idraw->drawLine(c[0], c[4], color);
61 	idraw->drawLine(c[1], c[5], color);
62 	idraw->drawLine(c[2], c[6], color);
63 	idraw->drawLine(c[3], c[7], color);
64 }
65 
66 //
drawTree(btIDebugDraw * idraw,const btDbvtNode * node,int depth,const btVector3 & ncolor,const btVector3 & lcolor,int mindepth,int maxdepth)67 static void drawTree(btIDebugDraw* idraw,
68 					 const btDbvtNode* node,
69 					 int depth,
70 					 const btVector3& ncolor,
71 					 const btVector3& lcolor,
72 					 int mindepth,
73 					 int maxdepth)
74 {
75 	if (node)
76 	{
77 		if (node->isinternal() && ((depth < maxdepth) || (maxdepth < 0)))
78 		{
79 			drawTree(idraw, node->childs[0], depth + 1, ncolor, lcolor, mindepth, maxdepth);
80 			drawTree(idraw, node->childs[1], depth + 1, ncolor, lcolor, mindepth, maxdepth);
81 		}
82 		if (depth >= mindepth)
83 		{
84 			const btScalar scl = (btScalar)(node->isinternal() ? 1 : 1);
85 			const btVector3 mi = node->volume.Center() - node->volume.Extents() * scl;
86 			const btVector3 mx = node->volume.Center() + node->volume.Extents() * scl;
87 			drawBox(idraw, mi, mx, node->isleaf() ? lcolor : ncolor);
88 		}
89 	}
90 }
91 
92 //
93 template <typename T>
sum(const btAlignedObjectArray<T> & items)94 static inline T sum(const btAlignedObjectArray<T>& items)
95 {
96 	T v;
97 	if (items.size())
98 	{
99 		v = items[0];
100 		for (int i = 1, ni = items.size(); i < ni; ++i)
101 		{
102 			v += items[i];
103 		}
104 	}
105 	return (v);
106 }
107 
108 //
109 template <typename T, typename Q>
add(btAlignedObjectArray<T> & items,const Q & value)110 static inline void add(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, typename Q>
mul(btAlignedObjectArray<T> & items,const Q & value)120 static inline void mul(btAlignedObjectArray<T>& items, const Q& value)
121 {
122 	for (int i = 0, ni = items.size(); i < ni; ++i)
123 	{
124 		items[i] *= value;
125 	}
126 }
127 
128 //
129 template <typename T>
average(const btAlignedObjectArray<T> & items)130 static inline T average(const btAlignedObjectArray<T>& items)
131 {
132 	const btScalar n = (btScalar)(items.size() > 0 ? items.size() : 1);
133 	return (sum(items) / n);
134 }
135 
136 #if 0
137 //
138  inline static btScalar		tetravolume(const btVector3& x0,
139 										const btVector3& x1,
140 										const btVector3& x2,
141 										const btVector3& x3)
142 {
143 	const btVector3	a=x1-x0;
144 	const btVector3	b=x2-x0;
145 	const btVector3	c=x3-x0;
146 	return(btDot(a,btCross(b,c)));
147 }
148 #endif
149 
150 //
151 #if 0
152 static btVector3		stresscolor(btScalar stress)
153 {
154 	static const btVector3	spectrum[]=	{	btVector3(1,0,1),
155 		btVector3(0,0,1),
156 		btVector3(0,1,1),
157 		btVector3(0,1,0),
158 		btVector3(1,1,0),
159 		btVector3(1,0,0),
160 		btVector3(1,0,0)};
161 	static const int		ncolors=sizeof(spectrum)/sizeof(spectrum[0])-1;
162 	static const btScalar	one=1;
163 	stress=btMax<btScalar>(0,btMin<btScalar>(1,stress))*ncolors;
164 	const int				sel=(int)stress;
165 	const btScalar			frc=stress-sel;
166 	return(spectrum[sel]+(spectrum[sel+1]-spectrum[sel])*frc);
167 }
168 #endif
169 
170 //
Draw(btSoftBody * psb,btIDebugDraw * idraw,int drawflags)171 void btSoftBodyHelpers::Draw(btSoftBody* psb,
172 							 btIDebugDraw* idraw,
173 							 int drawflags)
174 {
175 	const btScalar scl = (btScalar)0.1;
176 	const btScalar nscl = scl * 5;
177 	const btVector3 lcolor = btVector3(0, 0, 0);
178 	const btVector3 ncolor = btVector3(1, 1, 1);
179 	const btVector3 ccolor = btVector3(1, 0, 0);
180 	int i, j, nj;
181 
182 	/* Clusters	*/
183 	if (0 != (drawflags & fDrawFlags::Clusters))
184 	{
185 		srand(1806);
186 		for (i = 0; i < psb->m_clusters.size(); ++i)
187 		{
188 			if (psb->m_clusters[i]->m_collide)
189 			{
190 				btVector3 color(rand() / (btScalar)RAND_MAX,
191 								rand() / (btScalar)RAND_MAX,
192 								rand() / (btScalar)RAND_MAX);
193 				color = color.normalized() * 0.75;
194 				btAlignedObjectArray<btVector3> vertices;
195 				vertices.resize(psb->m_clusters[i]->m_nodes.size());
196 				for (j = 0, nj = vertices.size(); j < nj; ++j)
197 				{
198 					vertices[j] = psb->m_clusters[i]->m_nodes[j]->m_x;
199 				}
200 #define USE_NEW_CONVEX_HULL_COMPUTER
201 #ifdef USE_NEW_CONVEX_HULL_COMPUTER
202 				btConvexHullComputer computer;
203 				int stride = sizeof(btVector3);
204 				int count = vertices.size();
205 				btScalar shrink = 0.f;
206 				btScalar shrinkClamp = 0.f;
207 				computer.compute(&vertices[0].getX(), stride, count, shrink, shrinkClamp);
208 				for (int i = 0; i < computer.faces.size(); i++)
209 				{
210 					int face = computer.faces[i];
211 					//printf("face=%d\n",face);
212 					const btConvexHullComputer::Edge* firstEdge = &computer.edges[face];
213 					const btConvexHullComputer::Edge* edge = firstEdge->getNextEdgeOfFace();
214 
215 					int v0 = firstEdge->getSourceVertex();
216 					int v1 = firstEdge->getTargetVertex();
217 					while (edge != firstEdge)
218 					{
219 						int v2 = edge->getTargetVertex();
220 						idraw->drawTriangle(computer.vertices[v0], computer.vertices[v1], computer.vertices[v2], color, 1);
221 						edge = edge->getNextEdgeOfFace();
222 						v0 = v1;
223 						v1 = v2;
224 					};
225 				}
226 #else
227 
228 				HullDesc hdsc(QF_TRIANGLES, vertices.size(), &vertices[0]);
229 				HullResult hres;
230 				HullLibrary hlib;
231 				hdsc.mMaxVertices = vertices.size();
232 				hlib.CreateConvexHull(hdsc, hres);
233 				const btVector3 center = average(hres.m_OutputVertices);
234 				add(hres.m_OutputVertices, -center);
235 				mul(hres.m_OutputVertices, (btScalar)1);
236 				add(hres.m_OutputVertices, center);
237 				for (j = 0; j < (int)hres.mNumFaces; ++j)
238 				{
239 					const int idx[] = {hres.m_Indices[j * 3 + 0], hres.m_Indices[j * 3 + 1], hres.m_Indices[j * 3 + 2]};
240 					idraw->drawTriangle(hres.m_OutputVertices[idx[0]],
241 										hres.m_OutputVertices[idx[1]],
242 										hres.m_OutputVertices[idx[2]],
243 										color, 1);
244 				}
245 				hlib.ReleaseResult(hres);
246 #endif
247 			}
248 			/* Velocities	*/
249 #if 0
250 			for(int j=0;j<psb->m_clusters[i].m_nodes.size();++j)
251 			{
252 				const btSoftBody::Cluster&	c=psb->m_clusters[i];
253 				const btVector3				r=c.m_nodes[j]->m_x-c.m_com;
254 				const btVector3				v=c.m_lv+btCross(c.m_av,r);
255 				idraw->drawLine(c.m_nodes[j]->m_x,c.m_nodes[j]->m_x+v,btVector3(1,0,0));
256 			}
257 #endif
258 			/* Frame		*/
259 			//		btSoftBody::Cluster& c=*psb->m_clusters[i];
260 			//		idraw->drawLine(c.m_com,c.m_framexform*btVector3(10,0,0),btVector3(1,0,0));
261 			//		idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,10,0),btVector3(0,1,0));
262 			//		idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,0,10),btVector3(0,0,1));
263 		}
264 	}
265 	else
266 	{
267 		/* Nodes	*/
268 		if (0 != (drawflags & fDrawFlags::Nodes))
269 		{
270 			for (i = 0; i < psb->m_nodes.size(); ++i)
271 			{
272 				const btSoftBody::Node& n = psb->m_nodes[i];
273 				if (0 == (n.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
274 				idraw->drawLine(n.m_x - btVector3(scl, 0, 0), n.m_x + btVector3(scl, 0, 0), btVector3(1, 0, 0));
275 				idraw->drawLine(n.m_x - btVector3(0, scl, 0), n.m_x + btVector3(0, scl, 0), btVector3(0, 1, 0));
276 				idraw->drawLine(n.m_x - btVector3(0, 0, scl), n.m_x + btVector3(0, 0, scl), btVector3(0, 0, 1));
277 			}
278 		}
279 		/* Links	*/
280 		if (0 != (drawflags & fDrawFlags::Links))
281 		{
282 			for (i = 0; i < psb->m_links.size(); ++i)
283 			{
284 				const btSoftBody::Link& l = psb->m_links[i];
285 				if (0 == (l.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
286 				idraw->drawLine(l.m_n[0]->m_x, l.m_n[1]->m_x, lcolor);
287 			}
288 		}
289 		/* Normals	*/
290 		if (0 != (drawflags & fDrawFlags::Normals))
291 		{
292 			for (i = 0; i < psb->m_nodes.size(); ++i)
293 			{
294 				const btSoftBody::Node& n = psb->m_nodes[i];
295 				if (0 == (n.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
296 				const btVector3 d = n.m_n * nscl;
297 				idraw->drawLine(n.m_x, n.m_x + d, ncolor);
298 				idraw->drawLine(n.m_x, n.m_x - d, ncolor * 0.5);
299 			}
300 		}
301 		/* Contacts	*/
302 		if (0 != (drawflags & fDrawFlags::Contacts))
303 		{
304 			static const btVector3 axis[] = {btVector3(1, 0, 0),
305 											 btVector3(0, 1, 0),
306 											 btVector3(0, 0, 1)};
307 			for (i = 0; i < psb->m_rcontacts.size(); ++i)
308 			{
309 				const btSoftBody::RContact& c = psb->m_rcontacts[i];
310 				const btVector3 o = c.m_node->m_x - c.m_cti.m_normal *
311 														(btDot(c.m_node->m_x, c.m_cti.m_normal) + c.m_cti.m_offset);
312 				const btVector3 x = btCross(c.m_cti.m_normal, axis[c.m_cti.m_normal.minAxis()]).normalized();
313 				const btVector3 y = btCross(x, c.m_cti.m_normal).normalized();
314 				idraw->drawLine(o - x * nscl, o + x * nscl, ccolor);
315 				idraw->drawLine(o - y * nscl, o + y * nscl, ccolor);
316 				idraw->drawLine(o, o + c.m_cti.m_normal * nscl * 3, btVector3(1, 1, 0));
317 			}
318 		}
319 		/* Faces	*/
320 		if (0 != (drawflags & fDrawFlags::Faces))
321 		{
322 			const btScalar scl = (btScalar)0.8;
323 			const btScalar alp = (btScalar)1;
324 			const btVector3 col(0, (btScalar)0.7, 0);
325 			for (i = 0; i < psb->m_faces.size(); ++i)
326 			{
327 				const btSoftBody::Face& f = psb->m_faces[i];
328 				if (0 == (f.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
329 				const btVector3 x[] = {f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x};
330 				const btVector3 c = (x[0] + x[1] + x[2]) / 3;
331 				idraw->drawTriangle((x[0] - c) * scl + c,
332 									(x[1] - c) * scl + c,
333 									(x[2] - c) * scl + c,
334 									col, alp);
335 			}
336 		}
337 		/* Tetras	*/
338 		if (0 != (drawflags & fDrawFlags::Tetras))
339 		{
340 			const btScalar scl = (btScalar)0.8;
341 			const btScalar alp = (btScalar)1;
342 			const btVector3 col((btScalar)0.3, (btScalar)0.3, (btScalar)0.7);
343 			for (int i = 0; i < psb->m_tetras.size(); ++i)
344 			{
345 				const btSoftBody::Tetra& t = psb->m_tetras[i];
346 				if (0 == (t.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
347 				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};
348 				const btVector3 c = (x[0] + x[1] + x[2] + x[3]) / 4;
349 				idraw->drawTriangle((x[0] - c) * scl + c, (x[1] - c) * scl + c, (x[2] - c) * scl + c, col, alp);
350 				idraw->drawTriangle((x[0] - c) * scl + c, (x[1] - c) * scl + c, (x[3] - c) * scl + c, col, alp);
351 				idraw->drawTriangle((x[1] - c) * scl + c, (x[2] - c) * scl + c, (x[3] - c) * scl + c, col, alp);
352 				idraw->drawTriangle((x[2] - c) * scl + c, (x[0] - c) * scl + c, (x[3] - c) * scl + c, col, alp);
353 			}
354 		}
355 	}
356 	/* Anchors	*/
357 	if (0 != (drawflags & fDrawFlags::Anchors))
358 	{
359 		for (i = 0; i < psb->m_anchors.size(); ++i)
360 		{
361 			const btSoftBody::Anchor& a = psb->m_anchors[i];
362 			const btVector3 q = a.m_body->getWorldTransform() * a.m_local;
363 			drawVertex(idraw, a.m_node->m_x, 0.25, btVector3(1, 0, 0));
364 			drawVertex(idraw, q, 0.25, btVector3(0, 1, 0));
365 			idraw->drawLine(a.m_node->m_x, q, btVector3(1, 1, 1));
366 		}
367 		for (i = 0; i < psb->m_nodes.size(); ++i)
368 		{
369 			const btSoftBody::Node& n = psb->m_nodes[i];
370 			if (0 == (n.m_material->m_flags & btSoftBody::fMaterial::DebugDraw)) continue;
371 			if (n.m_im <= 0)
372 			{
373 				drawVertex(idraw, n.m_x, 0.25, btVector3(1, 0, 0));
374 			}
375 		}
376 	}
377 
378 	/* Notes	*/
379 	if (0 != (drawflags & fDrawFlags::Notes))
380 	{
381 		for (i = 0; i < psb->m_notes.size(); ++i)
382 		{
383 			const btSoftBody::Note& n = psb->m_notes[i];
384 			btVector3 p = n.m_offset;
385 			for (int j = 0; j < n.m_rank; ++j)
386 			{
387 				p += n.m_nodes[j]->m_x * n.m_coords[j];
388 			}
389 			idraw->draw3dText(p, n.m_text);
390 		}
391 	}
392 	/* Node tree	*/
393 	if (0 != (drawflags & fDrawFlags::NodeTree)) DrawNodeTree(psb, idraw);
394 	/* Face tree	*/
395 	if (0 != (drawflags & fDrawFlags::FaceTree)) DrawFaceTree(psb, idraw);
396 	/* Cluster tree	*/
397 	if (0 != (drawflags & fDrawFlags::ClusterTree)) DrawClusterTree(psb, idraw);
398 	/* Joints		*/
399 	if (0 != (drawflags & fDrawFlags::Joints))
400 	{
401 		for (i = 0; i < psb->m_joints.size(); ++i)
402 		{
403 			const btSoftBody::Joint* pj = psb->m_joints[i];
404 			switch (pj->Type())
405 			{
406 				case btSoftBody::Joint::eType::Linear:
407 				{
408 					const btSoftBody::LJoint* pjl = (const btSoftBody::LJoint*)pj;
409 					const btVector3 a0 = pj->m_bodies[0].xform() * pjl->m_refs[0];
410 					const btVector3 a1 = pj->m_bodies[1].xform() * pjl->m_refs[1];
411 					idraw->drawLine(pj->m_bodies[0].xform().getOrigin(), a0, btVector3(1, 1, 0));
412 					idraw->drawLine(pj->m_bodies[1].xform().getOrigin(), a1, btVector3(0, 1, 1));
413 					drawVertex(idraw, a0, 0.25, btVector3(1, 1, 0));
414 					drawVertex(idraw, a1, 0.25, btVector3(0, 1, 1));
415 				}
416 				break;
417 				case btSoftBody::Joint::eType::Angular:
418 				{
419 					//const btSoftBody::AJoint*	pja=(const btSoftBody::AJoint*)pj;
420 					const btVector3 o0 = pj->m_bodies[0].xform().getOrigin();
421 					const btVector3 o1 = pj->m_bodies[1].xform().getOrigin();
422 					const btVector3 a0 = pj->m_bodies[0].xform().getBasis() * pj->m_refs[0];
423 					const btVector3 a1 = pj->m_bodies[1].xform().getBasis() * pj->m_refs[1];
424 					idraw->drawLine(o0, o0 + a0 * 10, btVector3(1, 1, 0));
425 					idraw->drawLine(o0, o0 + a1 * 10, btVector3(1, 1, 0));
426 					idraw->drawLine(o1, o1 + a0 * 10, btVector3(0, 1, 1));
427 					idraw->drawLine(o1, o1 + a1 * 10, btVector3(0, 1, 1));
428 					break;
429 				}
430 				default:
431 				{
432 				}
433 			}
434 		}
435 	}
436 }
437 
438 //
DrawInfos(btSoftBody * psb,btIDebugDraw * idraw,bool masses,bool areas,bool)439 void btSoftBodyHelpers::DrawInfos(btSoftBody* psb,
440 								  btIDebugDraw* idraw,
441 								  bool masses,
442 								  bool areas,
443 								  bool /*stress*/)
444 {
445 	for (int i = 0; i < psb->m_nodes.size(); ++i)
446 	{
447 		const btSoftBody::Node& n = psb->m_nodes[i];
448 		char text[2048] = {0};
449 		char buff[1024];
450 		if (masses)
451 		{
452 			sprintf(buff, " M(%.2f)", 1 / n.m_im);
453 			strcat(text, buff);
454 		}
455 		if (areas)
456 		{
457 			sprintf(buff, " A(%.2f)", n.m_area);
458 			strcat(text, buff);
459 		}
460 		if (text[0]) idraw->draw3dText(n.m_x, text);
461 	}
462 }
463 
464 //
DrawNodeTree(btSoftBody * psb,btIDebugDraw * idraw,int mindepth,int maxdepth)465 void btSoftBodyHelpers::DrawNodeTree(btSoftBody* psb,
466 									 btIDebugDraw* idraw,
467 									 int mindepth,
468 									 int maxdepth)
469 {
470 	drawTree(idraw, psb->m_ndbvt.m_root, 0, btVector3(1, 0, 1), btVector3(1, 1, 1), mindepth, maxdepth);
471 }
472 
473 //
DrawFaceTree(btSoftBody * psb,btIDebugDraw * idraw,int mindepth,int maxdepth)474 void btSoftBodyHelpers::DrawFaceTree(btSoftBody* psb,
475 									 btIDebugDraw* idraw,
476 									 int mindepth,
477 									 int maxdepth)
478 {
479 	drawTree(idraw, psb->m_fdbvt.m_root, 0, btVector3(0, 1, 0), btVector3(1, 0, 0), mindepth, maxdepth);
480 }
481 
482 //
DrawClusterTree(btSoftBody * psb,btIDebugDraw * idraw,int mindepth,int maxdepth)483 void btSoftBodyHelpers::DrawClusterTree(btSoftBody* psb,
484 										btIDebugDraw* idraw,
485 										int mindepth,
486 										int maxdepth)
487 {
488 	drawTree(idraw, psb->m_cdbvt.m_root, 0, btVector3(0, 1, 1), btVector3(1, 0, 0), mindepth, maxdepth);
489 }
490 
491 //The btSoftBody object from the BulletSDK includes an array of Nodes and Links. These links appear
492 // to be first set up to connect a node to between 5 and 6 of its neighbors [480 links],
493 //and then to the rest of the nodes after the execution of the Floyd-Warshall graph algorithm
494 //[another 930 links].
495 //The way the links are stored by default, we have a number of cases where adjacent links share a node in common
496 // - this leads to the creation of a data dependency through memory.
497 //The PSolve_Links() function reads and writes nodes as it iterates over each link.
498 //So, we now have the possibility of a data dependency between iteration X
499 //that processes link L with iteration X+1 that processes link L+1
500 //because L and L+1 have one node in common, and iteration X updates the positions of that node,
501 //and iteration X+1 reads in the position of that shared node.
502 //
503 //Such a memory dependency limits the ability of a modern CPU to speculate beyond
504 //a certain point because it has to respect a possible dependency
505 //- this prevents the CPU from making full use of its out-of-order resources.
506 //If we re-order the links such that we minimize the cases where a link L and L+1 share a common node,
507 //we create a temporal gap between when the node position is written,
508 //and when it is subsequently read. This in turn allows the CPU to continue execution without
509 //risking a dependency violation. Such a reordering would result in significant speedups on
510 //modern CPUs with lots of execution resources.
511 //In our testing, we see it have a tremendous impact not only on the A7,
512 //but also on all x86 cores that ship with modern Macs.
513 //The attached source file includes a single function (ReoptimizeLinkOrder) which can be called on a
514 //btSoftBody object in the solveConstraints() function before the actual solver is invoked,
515 //or right after generateBendingConstraints() once we have all 1410 links.
516 
517 //===================================================================
518 //
519 //
520 // This function takes in a list of interdependent Links and tries
521 // to maximize the distance between calculation
522 // of dependent links.  This increases the amount of parallelism that can
523 // be exploited by out-of-order instruction processors with large but
524 // (inevitably) finite instruction windows.
525 //
526 //===================================================================
527 
528 // A small structure to track lists of dependent link calculations
529 class LinkDeps_t
530 {
531 public:
532 	int value;         // A link calculation that is dependent on this one
533 					   // Positive values = "input A" while negative values = "input B"
534 	LinkDeps_t* next;  // Next dependence in the list
535 };
536 typedef LinkDeps_t* LinkDepsPtr_t;
537 
538 // Dependency list constants
539 #define REOP_NOT_DEPENDENT -1
540 #define REOP_NODE_COMPLETE -2  // Must be less than REOP_NOT_DEPENDENT
541 
ReoptimizeLinkOrder(btSoftBody * psb)542 void btSoftBodyHelpers::ReoptimizeLinkOrder(btSoftBody* psb /* This can be replaced by a btSoftBody pointer */)
543 {
544 	int i, nLinks = psb->m_links.size(), nNodes = psb->m_nodes.size();
545 	btSoftBody::Link* lr;
546 	int ar, br;
547 	btSoftBody::Node* node0 = &(psb->m_nodes[0]);
548 	btSoftBody::Node* node1 = &(psb->m_nodes[1]);
549 	LinkDepsPtr_t linkDep;
550 	int readyListHead, readyListTail, linkNum, linkDepFrees, depLink;
551 
552 	// Allocate temporary buffers
553 	int* nodeWrittenAt = new int[nNodes + 1];  // What link calculation produced this node's current values?
554 	int* linkDepA = new int[nLinks];           // Link calculation input is dependent upon prior calculation #N
555 	int* linkDepB = new int[nLinks];
556 	int* readyList = new int[nLinks];                              // List of ready-to-process link calculations (# of links, maximum)
557 	LinkDeps_t* linkDepFreeList = new LinkDeps_t[2 * nLinks];      // Dependent-on-me list elements (2x# of links, maximum)
558 	LinkDepsPtr_t* linkDepListStarts = new LinkDepsPtr_t[nLinks];  // Start nodes of dependent-on-me lists, one for each link
559 
560 	// Copy the original, unsorted links to a side buffer
561 	btSoftBody::Link* linkBuffer = new btSoftBody::Link[nLinks];
562 	memcpy(linkBuffer, &(psb->m_links[0]), sizeof(btSoftBody::Link) * nLinks);
563 
564 	// Clear out the node setup and ready list
565 	for (i = 0; i < nNodes + 1; i++)
566 	{
567 		nodeWrittenAt[i] = REOP_NOT_DEPENDENT;
568 	}
569 	for (i = 0; i < nLinks; i++)
570 	{
571 		linkDepListStarts[i] = NULL;
572 	}
573 	readyListHead = readyListTail = linkDepFrees = 0;
574 
575 	// Initial link analysis to set up data structures
576 	for (i = 0; i < nLinks; i++)
577 	{
578 		// Note which prior link calculations we are dependent upon & build up dependence lists
579 		lr = &(psb->m_links[i]);
580 		ar = (lr->m_n[0] - node0) / (node1 - node0);
581 		br = (lr->m_n[1] - node0) / (node1 - node0);
582 		if (nodeWrittenAt[ar] > REOP_NOT_DEPENDENT)
583 		{
584 			linkDepA[i] = nodeWrittenAt[ar];
585 			linkDep = &linkDepFreeList[linkDepFrees++];
586 			linkDep->value = i;
587 			linkDep->next = linkDepListStarts[nodeWrittenAt[ar]];
588 			linkDepListStarts[nodeWrittenAt[ar]] = linkDep;
589 		}
590 		else
591 		{
592 			linkDepA[i] = REOP_NOT_DEPENDENT;
593 		}
594 		if (nodeWrittenAt[br] > REOP_NOT_DEPENDENT)
595 		{
596 			linkDepB[i] = nodeWrittenAt[br];
597 			linkDep = &linkDepFreeList[linkDepFrees++];
598 			linkDep->value = -(i + 1);
599 			linkDep->next = linkDepListStarts[nodeWrittenAt[br]];
600 			linkDepListStarts[nodeWrittenAt[br]] = linkDep;
601 		}
602 		else
603 		{
604 			linkDepB[i] = REOP_NOT_DEPENDENT;
605 		}
606 
607 		// Add this link to the initial ready list, if it is not dependent on any other links
608 		if ((linkDepA[i] == REOP_NOT_DEPENDENT) && (linkDepB[i] == REOP_NOT_DEPENDENT))
609 		{
610 			readyList[readyListTail++] = i;
611 			linkDepA[i] = linkDepB[i] = REOP_NODE_COMPLETE;  // Probably not needed now
612 		}
613 
614 		// Update the nodes to mark which ones are calculated by this link
615 		nodeWrittenAt[ar] = nodeWrittenAt[br] = i;
616 	}
617 
618 	// Process the ready list and create the sorted list of links
619 	// -- By treating the ready list as a queue, we maximize the distance between any
620 	//    inter-dependent node calculations
621 	// -- All other (non-related) nodes in the ready list will automatically be inserted
622 	//    in between each set of inter-dependent link calculations by this loop
623 	i = 0;
624 	while (readyListHead != readyListTail)
625 	{
626 		// Use ready list to select the next link to process
627 		linkNum = readyList[readyListHead++];
628 		// Copy the next-to-calculate link back into the original link array
629 		psb->m_links[i++] = linkBuffer[linkNum];
630 
631 		// Free up any link inputs that are dependent on this one
632 		linkDep = linkDepListStarts[linkNum];
633 		while (linkDep)
634 		{
635 			depLink = linkDep->value;
636 			if (depLink >= 0)
637 			{
638 				linkDepA[depLink] = REOP_NOT_DEPENDENT;
639 			}
640 			else
641 			{
642 				depLink = -depLink - 1;
643 				linkDepB[depLink] = REOP_NOT_DEPENDENT;
644 			}
645 			// Add this dependent link calculation to the ready list if *both* inputs are clear
646 			if ((linkDepA[depLink] == REOP_NOT_DEPENDENT) && (linkDepB[depLink] == REOP_NOT_DEPENDENT))
647 			{
648 				readyList[readyListTail++] = depLink;
649 				linkDepA[depLink] = linkDepB[depLink] = REOP_NODE_COMPLETE;  // Probably not needed now
650 			}
651 			linkDep = linkDep->next;
652 		}
653 	}
654 
655 	// Delete the temporary buffers
656 	delete[] nodeWrittenAt;
657 	delete[] linkDepA;
658 	delete[] linkDepB;
659 	delete[] readyList;
660 	delete[] linkDepFreeList;
661 	delete[] linkDepListStarts;
662 	delete[] linkBuffer;
663 }
664 
665 //
DrawFrame(btSoftBody * psb,btIDebugDraw * idraw)666 void btSoftBodyHelpers::DrawFrame(btSoftBody* psb,
667 								  btIDebugDraw* idraw)
668 {
669 	if (psb->m_pose.m_bframe)
670 	{
671 		static const btScalar ascl = 10;
672 		static const btScalar nscl = (btScalar)0.1;
673 		const btVector3 com = psb->m_pose.m_com;
674 		const btMatrix3x3 trs = psb->m_pose.m_rot * psb->m_pose.m_scl;
675 		const btVector3 Xaxis = (trs * btVector3(1, 0, 0)).normalized();
676 		const btVector3 Yaxis = (trs * btVector3(0, 1, 0)).normalized();
677 		const btVector3 Zaxis = (trs * btVector3(0, 0, 1)).normalized();
678 		idraw->drawLine(com, com + Xaxis * ascl, btVector3(1, 0, 0));
679 		idraw->drawLine(com, com + Yaxis * ascl, btVector3(0, 1, 0));
680 		idraw->drawLine(com, com + Zaxis * ascl, btVector3(0, 0, 1));
681 		for (int i = 0; i < psb->m_pose.m_pos.size(); ++i)
682 		{
683 			const btVector3 x = com + trs * psb->m_pose.m_pos[i];
684 			drawVertex(idraw, x, nscl, btVector3(1, 0, 1));
685 		}
686 	}
687 }
688 
689 //
CreateRope(btSoftBodyWorldInfo & worldInfo,const btVector3 & from,const btVector3 & to,int res,int fixeds)690 btSoftBody* btSoftBodyHelpers::CreateRope(btSoftBodyWorldInfo& worldInfo, const btVector3& from,
691 										  const btVector3& to,
692 										  int res,
693 										  int fixeds)
694 {
695 	/* Create nodes	*/
696 	const int r = res + 2;
697 	btVector3* x = new btVector3[r];
698 	btScalar* m = new btScalar[r];
699 	int i;
700 
701 	for (i = 0; i < r; ++i)
702 	{
703 		const btScalar t = i / (btScalar)(r - 1);
704 		x[i] = lerp(from, to, t);
705 		m[i] = 1;
706 	}
707 	btSoftBody* psb = new btSoftBody(&worldInfo, r, x, m);
708 	if (fixeds & 1) psb->setMass(0, 0);
709 	if (fixeds & 2) psb->setMass(r - 1, 0);
710 	delete[] x;
711 	delete[] m;
712 	/* Create links	*/
713 	for (i = 1; i < r; ++i)
714 	{
715 		psb->appendLink(i - 1, i);
716 	}
717 	/* Finished		*/
718 	return (psb);
719 }
720 
721 //
CreatePatch(btSoftBodyWorldInfo & worldInfo,const btVector3 & corner00,const btVector3 & corner10,const btVector3 & corner01,const btVector3 & corner11,int resx,int resy,int fixeds,bool gendiags,btScalar perturbation)722 btSoftBody* btSoftBodyHelpers::CreatePatch(btSoftBodyWorldInfo& worldInfo, const btVector3& corner00,
723 										   const btVector3& corner10,
724 										   const btVector3& corner01,
725 										   const btVector3& corner11,
726 										   int resx,
727 										   int resy,
728 										   int fixeds,
729 										   bool gendiags,
730                                            btScalar perturbation)
731 {
732 #define IDX(_x_, _y_) ((_y_)*rx + (_x_))
733 	/* Create nodes	*/
734 	if ((resx < 2) || (resy < 2)) return (0);
735 	const int rx = resx;
736 	const int ry = resy;
737 	const int tot = rx * ry;
738 	btVector3* x = new btVector3[tot];
739 	btScalar* m = new btScalar[tot];
740 	int iy;
741 
742 	for (iy = 0; iy < ry; ++iy)
743 	{
744 		const btScalar ty = iy / (btScalar)(ry - 1);
745 		const btVector3 py0 = lerp(corner00, corner01, ty);
746 		const btVector3 py1 = lerp(corner10, corner11, ty);
747 		for (int ix = 0; ix < rx; ++ix)
748 		{
749 			const btScalar tx = ix / (btScalar)(rx - 1);
750             btScalar pert = perturbation * btScalar(rand())/RAND_MAX;
751             btVector3 temp1 = py1;
752             temp1.setY(py1.getY() + pert);
753             btVector3 temp = py0;
754             pert = perturbation * btScalar(rand())/RAND_MAX;
755             temp.setY(py0.getY() + pert);
756 			x[IDX(ix, iy)] = lerp(temp, temp1, tx);
757 			m[IDX(ix, iy)] = 1;
758 		}
759 	}
760 	btSoftBody* psb = new btSoftBody(&worldInfo, tot, x, m);
761 	if (fixeds & 1) psb->setMass(IDX(0, 0), 0);
762 	if (fixeds & 2) psb->setMass(IDX(rx - 1, 0), 0);
763 	if (fixeds & 4) psb->setMass(IDX(0, ry - 1), 0);
764 	if (fixeds & 8) psb->setMass(IDX(rx - 1, ry - 1), 0);
765 	delete[] x;
766 	delete[] m;
767 	/* Create links	and faces */
768 	for (iy = 0; iy < ry; ++iy)
769 	{
770 		for (int ix = 0; ix < rx; ++ix)
771 		{
772 			const int idx = IDX(ix, iy);
773 			const bool mdx = (ix + 1) < rx;
774 			const bool mdy = (iy + 1) < ry;
775 			if (mdx) psb->appendLink(idx, IDX(ix + 1, iy));
776 			if (mdy) psb->appendLink(idx, IDX(ix, iy + 1));
777 			if (mdx && mdy)
778 			{
779 				if ((ix + iy) & 1)
780 				{
781 					psb->appendFace(IDX(ix, iy), IDX(ix + 1, iy), IDX(ix + 1, iy + 1));
782 					psb->appendFace(IDX(ix, iy), IDX(ix + 1, iy + 1), IDX(ix, iy + 1));
783 					if (gendiags)
784 					{
785 						psb->appendLink(IDX(ix, iy), IDX(ix + 1, iy + 1));
786 					}
787 				}
788 				else
789 				{
790 					psb->appendFace(IDX(ix, iy + 1), IDX(ix, iy), IDX(ix + 1, iy));
791 					psb->appendFace(IDX(ix, iy + 1), IDX(ix + 1, iy), IDX(ix + 1, iy + 1));
792 					if (gendiags)
793 					{
794 						psb->appendLink(IDX(ix + 1, iy), IDX(ix, iy + 1));
795 					}
796 				}
797 			}
798 		}
799 	}
800 	/* Finished		*/
801 #undef IDX
802 	return (psb);
803 }
804 
805 //
CreatePatchUV(btSoftBodyWorldInfo & worldInfo,const btVector3 & corner00,const btVector3 & corner10,const btVector3 & corner01,const btVector3 & corner11,int resx,int resy,int fixeds,bool gendiags,float * tex_coords)806 btSoftBody* btSoftBodyHelpers::CreatePatchUV(btSoftBodyWorldInfo& worldInfo,
807 											 const btVector3& corner00,
808 											 const btVector3& corner10,
809 											 const btVector3& corner01,
810 											 const btVector3& corner11,
811 											 int resx,
812 											 int resy,
813 											 int fixeds,
814 											 bool gendiags,
815 											 float* tex_coords)
816 {
817 	/*
818 	*
819 	*  corners:
820 	*
821 	*  [0][0]     corner00 ------- corner01   [resx][0]
822 	*                |                |
823 	*                |                |
824 	*  [0][resy]  corner10 -------- corner11  [resx][resy]
825 	*
826 	*
827 	*
828 	*
829 	*
830 	*
831 	*   "fixedgs" map:
832 	*
833 	*  corner00     -->   +1
834 	*  corner01     -->   +2
835 	*  corner10     -->   +4
836 	*  corner11     -->   +8
837 	*  upper middle -->  +16
838 	*  left middle  -->  +32
839 	*  right middle -->  +64
840 	*  lower middle --> +128
841 	*  center       --> +256
842 	*
843 	*
844 	*   tex_coords size   (resx-1)*(resy-1)*12
845 	*
846 	*
847 	*
848 	*     SINGLE QUAD INTERNALS
849 	*
850 	*  1) btSoftBody's nodes and links,
851 	*     diagonal link is optional ("gendiags")
852 	*
853 	*
854 	*    node00 ------ node01
855 	*      | .
856 	*      |   .
857 	*      |     .
858 	*      |       .
859 	*      |         .
860 	*    node10        node11
861 	*
862 	*
863 	*
864 	*   2) Faces:
865 	*      two triangles,
866 	*      UV Coordinates (hier example for single quad)
867 	*
868 	*     (0,1)          (0,1)  (1,1)
869 	*     1 |\            3 \-----| 2
870 	*       | \              \    |
871 	*       |  \              \   |
872 	*       |   \              \  |
873 	*       |    \              \ |
874 	*     2 |-----\ 3            \| 1
875 	*     (0,0)    (1,0)       (1,0)
876 	*
877 	*
878 	*
879 	*
880 	*
881 	*
882 	*/
883 
884 #define IDX(_x_, _y_) ((_y_)*rx + (_x_))
885 	/* Create nodes		*/
886 	if ((resx < 2) || (resy < 2)) return (0);
887 	const int rx = resx;
888 	const int ry = resy;
889 	const int tot = rx * ry;
890 	btVector3* x = new btVector3[tot];
891 	btScalar* m = new btScalar[tot];
892 
893 	int iy;
894 
895 	for (iy = 0; iy < ry; ++iy)
896 	{
897 		const btScalar ty = iy / (btScalar)(ry - 1);
898 		const btVector3 py0 = lerp(corner00, corner01, ty);
899 		const btVector3 py1 = lerp(corner10, corner11, ty);
900 		for (int ix = 0; ix < rx; ++ix)
901 		{
902 			const btScalar tx = ix / (btScalar)(rx - 1);
903 			x[IDX(ix, iy)] = lerp(py0, py1, tx);
904 			m[IDX(ix, iy)] = 1;
905 		}
906 	}
907 	btSoftBody* psb = new btSoftBody(&worldInfo, tot, x, m);
908 	if (fixeds & 1) psb->setMass(IDX(0, 0), 0);
909 	if (fixeds & 2) psb->setMass(IDX(rx - 1, 0), 0);
910 	if (fixeds & 4) psb->setMass(IDX(0, ry - 1), 0);
911 	if (fixeds & 8) psb->setMass(IDX(rx - 1, ry - 1), 0);
912 	if (fixeds & 16) psb->setMass(IDX((rx - 1) / 2, 0), 0);
913 	if (fixeds & 32) psb->setMass(IDX(0, (ry - 1) / 2), 0);
914 	if (fixeds & 64) psb->setMass(IDX(rx - 1, (ry - 1) / 2), 0);
915 	if (fixeds & 128) psb->setMass(IDX((rx - 1) / 2, ry - 1), 0);
916 	if (fixeds & 256) psb->setMass(IDX((rx - 1) / 2, (ry - 1) / 2), 0);
917 	delete[] x;
918 	delete[] m;
919 
920 	int z = 0;
921 	/* Create links	and faces	*/
922 	for (iy = 0; iy < ry; ++iy)
923 	{
924 		for (int ix = 0; ix < rx; ++ix)
925 		{
926 			const bool mdx = (ix + 1) < rx;
927 			const bool mdy = (iy + 1) < ry;
928 
929 			int node00 = IDX(ix, iy);
930 			int node01 = IDX(ix + 1, iy);
931 			int node10 = IDX(ix, iy + 1);
932 			int node11 = IDX(ix + 1, iy + 1);
933 
934 			if (mdx) psb->appendLink(node00, node01);
935 			if (mdy) psb->appendLink(node00, node10);
936 			if (mdx && mdy)
937 			{
938 				psb->appendFace(node00, node10, node11);
939 				if (tex_coords)
940 				{
941 					tex_coords[z + 0] = CalculateUV(resx, resy, ix, iy, 0);
942 					tex_coords[z + 1] = CalculateUV(resx, resy, ix, iy, 1);
943 					tex_coords[z + 2] = CalculateUV(resx, resy, ix, iy, 0);
944 					tex_coords[z + 3] = CalculateUV(resx, resy, ix, iy, 2);
945 					tex_coords[z + 4] = CalculateUV(resx, resy, ix, iy, 3);
946 					tex_coords[z + 5] = CalculateUV(resx, resy, ix, iy, 2);
947 				}
948 				psb->appendFace(node11, node01, node00);
949 				if (tex_coords)
950 				{
951 					tex_coords[z + 6] = CalculateUV(resx, resy, ix, iy, 3);
952 					tex_coords[z + 7] = CalculateUV(resx, resy, ix, iy, 2);
953 					tex_coords[z + 8] = CalculateUV(resx, resy, ix, iy, 3);
954 					tex_coords[z + 9] = CalculateUV(resx, resy, ix, iy, 1);
955 					tex_coords[z + 10] = CalculateUV(resx, resy, ix, iy, 0);
956 					tex_coords[z + 11] = CalculateUV(resx, resy, ix, iy, 1);
957 				}
958 				if (gendiags) psb->appendLink(node00, node11);
959 				z += 12;
960 			}
961 		}
962 	}
963 	/* Finished	*/
964 #undef IDX
965 	return (psb);
966 }
967 
CalculateUV(int resx,int resy,int ix,int iy,int id)968 float btSoftBodyHelpers::CalculateUV(int resx, int resy, int ix, int iy, int id)
969 {
970 	/*
971 	*
972 	*
973 	*    node00 --- node01
974 	*      |          |
975 	*    node10 --- node11
976 	*
977 	*
978 	*   ID map:
979 	*
980 	*   node00 s --> 0
981 	*   node00 t --> 1
982 	*
983 	*   node01 s --> 3
984 	*   node01 t --> 1
985 	*
986 	*   node10 s --> 0
987 	*   node10 t --> 2
988 	*
989 	*   node11 s --> 3
990 	*   node11 t --> 2
991 	*
992 	*
993 	*/
994 
995 	float tc = 0.0f;
996 	if (id == 0)
997 	{
998 		tc = (1.0f / ((resx - 1)) * ix);
999 	}
1000 	else if (id == 1)
1001 	{
1002 		tc = (1.0f / ((resy - 1)) * (resy - 1 - iy));
1003 	}
1004 	else if (id == 2)
1005 	{
1006 		tc = (1.0f / ((resy - 1)) * (resy - 1 - iy - 1));
1007 	}
1008 	else if (id == 3)
1009 	{
1010 		tc = (1.0f / ((resx - 1)) * (ix + 1));
1011 	}
1012 	return tc;
1013 }
1014 //
CreateEllipsoid(btSoftBodyWorldInfo & worldInfo,const btVector3 & center,const btVector3 & radius,int res)1015 btSoftBody* btSoftBodyHelpers::CreateEllipsoid(btSoftBodyWorldInfo& worldInfo, const btVector3& center,
1016 											   const btVector3& radius,
1017 											   int res)
1018 {
1019 	struct Hammersley
1020 	{
1021 		static void Generate(btVector3* x, int n)
1022 		{
1023 			for (int i = 0; i < n; i++)
1024 			{
1025 				btScalar p = 0.5, t = 0;
1026 				for (int j = i; j; p *= 0.5, j >>= 1)
1027 					if (j & 1) t += p;
1028 				btScalar w = 2 * t - 1;
1029 				btScalar a = (SIMD_PI + 2 * i * SIMD_PI) / n;
1030 				btScalar s = btSqrt(1 - w * w);
1031 				*x++ = btVector3(s * btCos(a), s * btSin(a), w);
1032 			}
1033 		}
1034 	};
1035 	btAlignedObjectArray<btVector3> vtx;
1036 	vtx.resize(3 + res);
1037 	Hammersley::Generate(&vtx[0], vtx.size());
1038 	for (int i = 0; i < vtx.size(); ++i)
1039 	{
1040 		vtx[i] = vtx[i] * radius + center;
1041 	}
1042 	return (CreateFromConvexHull(worldInfo, &vtx[0], vtx.size()));
1043 }
1044 
1045 //
CreateFromTriMesh(btSoftBodyWorldInfo & worldInfo,const btScalar * vertices,const int * triangles,int ntriangles,bool randomizeConstraints)1046 btSoftBody* btSoftBodyHelpers::CreateFromTriMesh(btSoftBodyWorldInfo& worldInfo, const btScalar* vertices,
1047 												 const int* triangles,
1048 												 int ntriangles, bool randomizeConstraints)
1049 {
1050 	int maxidx = 0;
1051 	int i, j, ni;
1052 
1053 	for (i = 0, ni = ntriangles * 3; i < ni; ++i)
1054 	{
1055 		maxidx = btMax(triangles[i], maxidx);
1056 	}
1057 	++maxidx;
1058 	btAlignedObjectArray<bool> chks;
1059 	btAlignedObjectArray<btVector3> vtx;
1060 	chks.resize(maxidx * maxidx, false);
1061 	vtx.resize(maxidx);
1062 	for (i = 0, j = 0, ni = maxidx * 3; i < ni; ++j, i += 3)
1063 	{
1064 		vtx[j] = btVector3(vertices[i], vertices[i + 1], vertices[i + 2]);
1065 	}
1066 	btSoftBody* psb = new btSoftBody(&worldInfo, vtx.size(), &vtx[0], 0);
1067 	for (i = 0, ni = ntriangles * 3; i < ni; i += 3)
1068 	{
1069 		const int idx[] = {triangles[i], triangles[i + 1], triangles[i + 2]};
1070 #define IDX(_x_, _y_) ((_y_)*maxidx + (_x_))
1071 		for (int j = 2, k = 0; k < 3; j = k++)
1072 		{
1073 			if (!chks[IDX(idx[j], idx[k])])
1074 			{
1075 				chks[IDX(idx[j], idx[k])] = true;
1076 				chks[IDX(idx[k], idx[j])] = true;
1077 				psb->appendLink(idx[j], idx[k]);
1078 			}
1079 		}
1080 #undef IDX
1081 		psb->appendFace(idx[0], idx[1], idx[2]);
1082 	}
1083 
1084 	if (randomizeConstraints)
1085 	{
1086 		psb->randomizeConstraints();
1087 	}
1088 
1089 	return (psb);
1090 }
1091 
1092 //
CreateFromConvexHull(btSoftBodyWorldInfo & worldInfo,const btVector3 * vertices,int nvertices,bool randomizeConstraints)1093 btSoftBody* btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldInfo, const btVector3* vertices,
1094 													int nvertices, bool randomizeConstraints)
1095 {
1096 	HullDesc hdsc(QF_TRIANGLES, nvertices, vertices);
1097 	HullResult hres;
1098 	HullLibrary hlib; /*??*/
1099 	hdsc.mMaxVertices = nvertices;
1100 	hlib.CreateConvexHull(hdsc, hres);
1101 	btSoftBody* psb = new btSoftBody(&worldInfo, (int)hres.mNumOutputVertices,
1102 									 &hres.m_OutputVertices[0], 0);
1103 	for (int i = 0; i < (int)hres.mNumFaces; ++i)
1104 	{
1105 		const int idx[] = {static_cast<int>(hres.m_Indices[i * 3 + 0]),
1106 						   static_cast<int>(hres.m_Indices[i * 3 + 1]),
1107 						   static_cast<int>(hres.m_Indices[i * 3 + 2])};
1108 		if (idx[0] < idx[1]) psb->appendLink(idx[0], idx[1]);
1109 		if (idx[1] < idx[2]) psb->appendLink(idx[1], idx[2]);
1110 		if (idx[2] < idx[0]) psb->appendLink(idx[2], idx[0]);
1111 		psb->appendFace(idx[0], idx[1], idx[2]);
1112 	}
1113 	hlib.ReleaseResult(hres);
1114 	if (randomizeConstraints)
1115 	{
1116 		psb->randomizeConstraints();
1117 	}
1118 	return (psb);
1119 }
1120 
nextLine(const char * buffer)1121 static int nextLine(const char* buffer)
1122 {
1123 	int numBytesRead = 0;
1124 
1125 	while (*buffer != '\n')
1126 	{
1127 		buffer++;
1128 		numBytesRead++;
1129 	}
1130 
1131 	if (buffer[0] == 0x0a)
1132 	{
1133 		buffer++;
1134 		numBytesRead++;
1135 	}
1136 	return numBytesRead;
1137 }
1138 
1139 /* Create from TetGen .ele, .face, .node data							*/
CreateFromTetGenData(btSoftBodyWorldInfo & worldInfo,const char * ele,const char * face,const char * node,bool bfacelinks,bool btetralinks,bool bfacesfromtetras)1140 btSoftBody* btSoftBodyHelpers::CreateFromTetGenData(btSoftBodyWorldInfo& worldInfo,
1141 													const char* ele,
1142 													const char* face,
1143 													const char* node,
1144 													bool bfacelinks,
1145 													bool btetralinks,
1146 													bool bfacesfromtetras)
1147 {
1148 	btAlignedObjectArray<btVector3> pos;
1149 	int nnode = 0;
1150 	int ndims = 0;
1151 	int nattrb = 0;
1152 	int hasbounds = 0;
1153 	int result = sscanf(node, "%d %d %d %d", &nnode, &ndims, &nattrb, &hasbounds);
1154 	result = sscanf(node, "%d %d %d %d", &nnode, &ndims, &nattrb, &hasbounds);
1155 	node += nextLine(node);
1156 
1157 	pos.resize(nnode);
1158 	for (int i = 0; i < pos.size(); ++i)
1159 	{
1160 		int index = 0;
1161 		//int			bound=0;
1162 		float x, y, z;
1163 		sscanf(node, "%d %f %f %f", &index, &x, &y, &z);
1164 
1165 		//	sn>>index;
1166 		//	sn>>x;sn>>y;sn>>z;
1167 		node += nextLine(node);
1168 
1169 		//for(int j=0;j<nattrb;++j)
1170 		//	sn>>a;
1171 
1172 		//if(hasbounds)
1173 		//	sn>>bound;
1174 
1175 		pos[index].setX(btScalar(x));
1176 		pos[index].setY(btScalar(y));
1177 		pos[index].setZ(btScalar(z));
1178 	}
1179 	btSoftBody* psb = new btSoftBody(&worldInfo, nnode, &pos[0], 0);
1180 #if 0
1181 if(face&&face[0])
1182 	{
1183 	int								nface=0;
1184 	sf>>nface;sf>>hasbounds;
1185 	for(int i=0;i<nface;++i)
1186 		{
1187 		int			index=0;
1188 		int			bound=0;
1189 		int			ni[3];
1190 		sf>>index;
1191 		sf>>ni[0];sf>>ni[1];sf>>ni[2];
1192 		sf>>bound;
1193 		psb->appendFace(ni[0],ni[1],ni[2]);
1194 		if(btetralinks)
1195 			{
1196 			psb->appendLink(ni[0],ni[1],0,true);
1197 			psb->appendLink(ni[1],ni[2],0,true);
1198 			psb->appendLink(ni[2],ni[0],0,true);
1199 			}
1200 		}
1201 	}
1202 #endif
1203 
1204 	if (ele && ele[0])
1205 	{
1206 		int ntetra = 0;
1207 		int ncorner = 0;
1208 		int neattrb = 0;
1209 		sscanf(ele, "%d %d %d", &ntetra, &ncorner, &neattrb);
1210 		ele += nextLine(ele);
1211 
1212 		//se>>ntetra;se>>ncorner;se>>neattrb;
1213 		for (int i = 0; i < ntetra; ++i)
1214 		{
1215 			int index = 0;
1216 			int ni[4];
1217 
1218 			//se>>index;
1219 			//se>>ni[0];se>>ni[1];se>>ni[2];se>>ni[3];
1220 			sscanf(ele, "%d %d %d %d %d", &index, &ni[0], &ni[1], &ni[2], &ni[3]);
1221 			ele += nextLine(ele);
1222 			//for(int j=0;j<neattrb;++j)
1223 			//	se>>a;
1224 			psb->appendTetra(ni[0], ni[1], ni[2], ni[3]);
1225 			if (btetralinks)
1226 			{
1227 				psb->appendLink(ni[0], ni[1], 0, true);
1228 				psb->appendLink(ni[1], ni[2], 0, true);
1229 				psb->appendLink(ni[2], ni[0], 0, true);
1230 				psb->appendLink(ni[0], ni[3], 0, true);
1231 				psb->appendLink(ni[1], ni[3], 0, true);
1232 				psb->appendLink(ni[2], ni[3], 0, true);
1233 			}
1234 		}
1235 	}
1236     psb->initializeDmInverse();
1237     psb->m_tetraScratches.resize(psb->m_tetras.size());
1238     psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
1239 	printf("Nodes:  %u\r\n", psb->m_nodes.size());
1240 	printf("Links:  %u\r\n", psb->m_links.size());
1241 	printf("Faces:  %u\r\n", psb->m_faces.size());
1242 	printf("Tetras: %u\r\n", psb->m_tetras.size());
1243 	return (psb);
1244 }
1245 
CreateFromVtkFile(btSoftBodyWorldInfo & worldInfo,const char * vtk_file)1246 btSoftBody* btSoftBodyHelpers::CreateFromVtkFile(btSoftBodyWorldInfo& worldInfo, const char* vtk_file)
1247 {
1248     std::ifstream fs;
1249     fs.open(vtk_file);
1250     btAssert(fs);
1251 
1252     typedef btAlignedObjectArray<int> Index;
1253     std::string line;
1254     btAlignedObjectArray<btVector3> X;
1255     btVector3 position;
1256     btAlignedObjectArray<Index> indices;
1257     bool reading_points = false;
1258     bool reading_tets = false;
1259     size_t n_points = 0;
1260     size_t n_tets = 0;
1261     size_t x_count = 0;
1262     size_t indices_count = 0;
1263     while (std::getline(fs, line))
1264     {
1265         std::stringstream ss(line);
1266         if (line.size() == (size_t)(0))
1267         {
1268         }
1269         else if (line.substr(0, 6) == "POINTS")
1270         {
1271             reading_points = true;
1272             reading_tets = false;
1273             ss.ignore(128, ' '); // ignore "POINTS"
1274             ss >> n_points;
1275             X.resize(n_points);
1276         }
1277         else if (line.substr(0, 5) == "CELLS")
1278         {
1279             reading_points = false;
1280             reading_tets = true;
1281             ss.ignore(128, ' '); // ignore "CELLS"
1282             ss >> n_tets;
1283             indices.resize(n_tets);
1284         }
1285         else if (line.substr(0, 10) == "CELL_TYPES")
1286         {
1287             reading_points = false;
1288             reading_tets = false;
1289         }
1290         else if (reading_points)
1291         {
1292             btScalar p;
1293             ss >> p;
1294             position.setX(p);
1295             ss >> p;
1296             position.setY(p);
1297             ss >> p;
1298             position.setZ(p);
1299             X[x_count++] = position;
1300         }
1301         else if (reading_tets)
1302         {
1303             ss.ignore(128, ' '); // ignore "4"
1304             Index tet;
1305             tet.resize(4);
1306             for (size_t i = 0; i < 4; i++)
1307             {
1308                 ss >> tet[i];
1309             }
1310             indices[indices_count++] = tet;
1311         }
1312     }
1313     btSoftBody* psb = new btSoftBody(&worldInfo, n_points, &X[0], 0);
1314 
1315     for (int i = 0; i < n_tets; ++i)
1316     {
1317         const Index& ni = indices[i];
1318         psb->appendTetra(ni[0], ni[1], ni[2], ni[3]);
1319         {
1320             psb->appendLink(ni[0], ni[1], 0, true);
1321             psb->appendLink(ni[1], ni[2], 0, true);
1322             psb->appendLink(ni[2], ni[0], 0, true);
1323             psb->appendLink(ni[0], ni[3], 0, true);
1324             psb->appendLink(ni[1], ni[3], 0, true);
1325             psb->appendLink(ni[2], ni[3], 0, true);
1326         }
1327     }
1328 
1329 
1330     generateBoundaryFaces(psb);
1331     psb->initializeDmInverse();
1332     psb->m_tetraScratches.resize(psb->m_tetras.size());
1333     psb->m_tetraScratchesTn.resize(psb->m_tetras.size());
1334     printf("Nodes:  %u\r\n", psb->m_nodes.size());
1335     printf("Links:  %u\r\n", psb->m_links.size());
1336     printf("Faces:  %u\r\n", psb->m_faces.size());
1337     printf("Tetras: %u\r\n", psb->m_tetras.size());
1338 
1339     fs.close();
1340     return psb;
1341 }
1342 
generateBoundaryFaces(btSoftBody * psb)1343 void btSoftBodyHelpers::generateBoundaryFaces(btSoftBody* psb)
1344 {
1345     int counter = 0;
1346     for (int i = 0; i < psb->m_nodes.size(); ++i)
1347     {
1348         psb->m_nodes[i].index = counter++;
1349     }
1350     typedef btAlignedObjectArray<int> Index;
1351     btAlignedObjectArray<Index> indices;
1352     indices.resize(psb->m_tetras.size());
1353     for (int i = 0; i < indices.size(); ++i)
1354     {
1355         Index index;
1356         index.push_back(psb->m_tetras[i].m_n[0]->index);
1357         index.push_back(psb->m_tetras[i].m_n[1]->index);
1358         index.push_back(psb->m_tetras[i].m_n[2]->index);
1359         index.push_back(psb->m_tetras[i].m_n[3]->index);
1360         indices[i] = index;
1361     }
1362 
1363     std::map<std::vector<int>, std::vector<int> > dict;
1364     for (int i = 0; i < indices.size(); ++i)
1365     {
1366         for (int j = 0; j < 4; ++j)
1367         {
1368             std::vector<int> f;
1369             if (j == 0)
1370             {
1371                 f.push_back(indices[i][1]);
1372                 f.push_back(indices[i][0]);
1373                 f.push_back(indices[i][2]);
1374             }
1375             if (j == 1)
1376             {
1377                 f.push_back(indices[i][3]);
1378                 f.push_back(indices[i][0]);
1379                 f.push_back(indices[i][1]);
1380             }
1381             if (j == 2)
1382             {
1383                 f.push_back(indices[i][3]);
1384                 f.push_back(indices[i][1]);
1385                 f.push_back(indices[i][2]);
1386             }
1387             if (j == 3)
1388             {
1389                 f.push_back(indices[i][2]);
1390                 f.push_back(indices[i][0]);
1391                 f.push_back(indices[i][3]);
1392             }
1393             std::vector<int> f_sorted = f;
1394             std::sort(f_sorted.begin(), f_sorted.end());
1395             if (dict.find(f_sorted) != dict.end())
1396             {
1397                 dict.erase(f_sorted);
1398             }
1399             else
1400             {
1401                 dict.insert(std::make_pair(f_sorted, f));
1402             }
1403         }
1404     }
1405 
1406     for (std::map<std::vector<int>, std::vector<int> >::iterator it = dict.begin(); it != dict.end(); ++it)
1407     {
1408         std::vector<int> f = it->second;
1409         psb->appendFace(f[0], f[1], f[2]);
1410     }
1411 }
1412 
writeObj(const char * filename,const btSoftBody * psb)1413 void btSoftBodyHelpers::writeObj(const char* filename, const btSoftBody* psb)
1414 {
1415     std::ofstream fs;
1416     fs.open(filename);
1417     btAssert(fs);
1418     for (int i = 0; i < psb->m_nodes.size(); ++i)
1419     {
1420         fs << "v";
1421         for (int d = 0; d < 3; d++)
1422         {
1423              fs << " " << psb->m_nodes[i].m_x[d];
1424         }
1425         fs << "\n";
1426     }
1427 
1428     for (int i = 0; i < psb->m_faces.size(); ++i)
1429     {
1430         fs << "f";
1431         for (int n = 0; n < 3; n++)
1432         {
1433             fs << " " << psb->m_faces[i].m_n[n]->index + 1;
1434         }
1435         fs << "\n";
1436     }
1437     fs.close();
1438 }
1439 
duplicateFaces(const char * filename,const btSoftBody * psb)1440 void btSoftBodyHelpers::duplicateFaces(const char* filename, const btSoftBody* psb)
1441 {
1442     std::ifstream fs_read;
1443     fs_read.open(filename);
1444     std::string line;
1445     btVector3 pos;
1446     btAlignedObjectArray<btAlignedObjectArray<int> > additional_faces;
1447     while (std::getline(fs_read, line))
1448     {
1449         std::stringstream ss(line);
1450         if (line[0] == 'v')
1451         {
1452         }
1453         else if (line[0] == 'f')
1454         {
1455             ss.ignore();
1456             int id0, id1, id2;
1457             ss >> id0;
1458             ss >> id1;
1459             ss >> id2;
1460             btAlignedObjectArray<int> new_face;
1461             new_face.push_back(id1);
1462             new_face.push_back(id0);
1463             new_face.push_back(id2);
1464             additional_faces.push_back(new_face);
1465         }
1466     }
1467     fs_read.close();
1468 
1469     std::ofstream fs_write;
1470     fs_write.open(filename, std::ios_base::app);
1471     for (int i = 0; i < additional_faces.size(); ++i)
1472     {
1473         fs_write << "f";
1474         for (int n = 0; n < 3; n++)
1475         {
1476             fs_write << " " << additional_faces[i][n];
1477         }
1478         fs_write << "\n";
1479     }
1480     fs_write.close();
1481 }
1482 
1483 // Given a simplex with vertices a,b,c,d, find the barycentric weights of p in this simplex
getBarycentricWeights(const btVector3 & a,const btVector3 & b,const btVector3 & c,const btVector3 & d,const btVector3 & p,btVector4 & bary)1484 void btSoftBodyHelpers::getBarycentricWeights(const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, const btVector3& p, btVector4& bary)
1485 {
1486     btVector3 vap = p - a;
1487     btVector3 vbp = p - b;
1488 
1489     btVector3 vab = b - a;
1490     btVector3 vac = c - a;
1491     btVector3 vad = d - a;
1492 
1493     btVector3 vbc = c - b;
1494     btVector3 vbd = d - b;
1495     btScalar va6 = (vbp.cross(vbd)).dot(vbc);
1496     btScalar vb6 = (vap.cross(vac)).dot(vad);
1497     btScalar vc6 = (vap.cross(vad)).dot(vab);
1498     btScalar vd6 = (vap.cross(vab)).dot(vac);
1499     btScalar v6 = btScalar(1) / (vab.cross(vac).dot(vad));
1500     bary = btVector4(va6*v6, vb6*v6, vc6*v6, vd6*v6);
1501 }
1502 
1503 // Iterate through all render nodes to find the simulation tetrahedron that contains the render node and record the barycentric weights
1504 // If the node is not inside any tetrahedron, assign it to the tetrahedron in which the node has the least negative barycentric weight
interpolateBarycentricWeights(btSoftBody * psb)1505 void btSoftBodyHelpers::interpolateBarycentricWeights(btSoftBody* psb)
1506 {
1507     psb->m_renderNodesInterpolationWeights.resize(psb->m_renderNodes.size());
1508     psb->m_renderNodesParents.resize(psb->m_renderNodes.size());
1509     for (int i = 0; i < psb->m_renderNodes.size(); ++i)
1510     {
1511         const btVector3& p = psb->m_renderNodes[i].m_x;
1512         btVector4 bary;
1513         btVector4 optimal_bary;
1514         btScalar min_bary_weight = -1e3;
1515         btAlignedObjectArray<const btSoftBody::Node*> optimal_parents;
1516         bool found = false;
1517         for (int j = 0; j < psb->m_tetras.size(); ++j)
1518         {
1519             const btSoftBody::Tetra& t = psb->m_tetras[j];
1520             getBarycentricWeights(t.m_n[0]->m_x, t.m_n[1]->m_x, t.m_n[2]->m_x, t.m_n[3]->m_x, p, bary);
1521             btScalar new_min_bary_weight = bary[0];
1522             for (int k = 1; k < 4; ++k)
1523             {
1524                 new_min_bary_weight = btMin(new_min_bary_weight, bary[k]);
1525             }
1526             if (new_min_bary_weight > min_bary_weight)
1527             {
1528                 btAlignedObjectArray<const btSoftBody::Node*> parents;
1529                 parents.push_back(t.m_n[0]);
1530                 parents.push_back(t.m_n[1]);
1531                 parents.push_back(t.m_n[2]);
1532                 parents.push_back(t.m_n[3]);
1533                 optimal_parents = parents;
1534                 optimal_bary = bary;
1535                 min_bary_weight = new_min_bary_weight;
1536                 // stop searching if p is inside the tetrahedron at hand
1537                 if (bary[0]>=0. && bary[1]>=0. && bary[2]>=0. && bary[3]>=0.)
1538                 {
1539                     break;
1540                 }
1541             }
1542         }
1543         psb->m_renderNodesInterpolationWeights[i] = optimal_bary;
1544         psb->m_renderNodesParents[i] = optimal_parents;
1545     }
1546 }
1547