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 //
drawVertex(btIDebugDraw * idraw,const btVector3 & x,btScalar s,const btVector3 & c)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 //
drawBox(btIDebugDraw * idraw,const btVector3 & mins,const btVector3 & maxs,const btVector3 & color)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 //
drawTree(btIDebugDraw * idraw,const btDbvtNode * node,int depth,const btVector3 & ncolor,const btVector3 & lcolor,int mindepth,int maxdepth)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>
sum(const btAlignedObjectArray<T> & items)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>
add(btAlignedObjectArray<T> & items,const Q & value)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>
mul(btAlignedObjectArray<T> & items,const Q & value)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>
average(const btAlignedObjectArray<T> & items)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 //
tetravolume(const btVector3 & x0,const btVector3 & x1,const btVector3 & x2,const btVector3 & x3)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 //
Draw(btSoftBody * psb,btIDebugDraw * idraw,int drawflags)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 //
DrawInfos(btSoftBody * psb,btIDebugDraw * idraw,bool masses,bool areas,bool)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 //
DrawNodeTree(btSoftBody * psb,btIDebugDraw * idraw,int mindepth,int maxdepth)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 //
DrawFaceTree(btSoftBody * psb,btIDebugDraw * idraw,int mindepth,int maxdepth)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 //
DrawClusterTree(btSoftBody * psb,btIDebugDraw * idraw,int mindepth,int maxdepth)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
ReoptimizeLinkOrder(btSoftBody * psb)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 //
DrawFrame(btSoftBody * psb,btIDebugDraw * idraw)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 //
CreateRope(btSoftBodyWorldInfo & worldInfo,const btVector3 & from,const btVector3 & to,int res,int fixeds)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 //
CreatePatch(btSoftBodyWorldInfo & worldInfo,const btVector3 & corner00,const btVector3 & corner10,const btVector3 & corner01,const btVector3 & corner11,int resx,int resy,int fixeds,bool gendiags)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 //
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)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
CalculateUV(int resx,int resy,int ix,int iy,int id)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 //
CreateEllipsoid(btSoftBodyWorldInfo & worldInfo,const btVector3 & center,const btVector3 & radius,int res)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 //
CreateFromTriMesh(btSoftBodyWorldInfo & worldInfo,const btScalar * vertices,const int * triangles,int ntriangles,bool randomizeConstraints)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 //
CreateFromConvexHull(btSoftBodyWorldInfo & worldInfo,const btVector3 * vertices,int nvertices,bool randomizeConstraints)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
nextLine(const char * buffer)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 */
CreateFromTetGenData(btSoftBodyWorldInfo & worldInfo,const char * ele,const char * face,const char * node,bool bfacelinks,bool btetralinks,bool bfacesfromtetras)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