Actor Create.cpp 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. #define TUBE_RES 4
  5. #define TUBE_MASS_FACTOR (1.5708f/TUBE_RES) // because we operate on boxes we need to adjust for tube/box volume factor, calculated comparing Boxed Actor mass to desired Tube volume
  6. static Flt Density(Flt density, Bool kinematic) {return (kinematic && density<=0) ? 1 : Max(0, density);}
  7. /******************************************************************************/
  8. #if PHYSX
  9. /******************************************************************************/
  10. static Bool Add(PxRigidActor &actor, C Plane &plane)
  11. {
  12. if(PxShape *shape=actor.createShape(PxPlaneGeometry(), *Physics.mtrl_default._m))
  13. {
  14. shape->setLocalPose(Physx.matrix(Matrix().setPosRight(plane.pos, plane.normal)));
  15. shape->setContactOffset(Physics.skin());
  16. return true;
  17. }
  18. return false;
  19. }
  20. static Bool Add(PxRigidActor &actor, C Box &box, C Vec *local_pos)
  21. {
  22. if(PxShape *shape=actor.createShape(PxBoxGeometry(box.w()*0.5f, box.h()*0.5f, box.d()*0.5f), *Physics.mtrl_default._m))
  23. {
  24. Matrix local_matrix; if(local_pos)local_matrix.pos=*local_pos;else local_matrix.pos.zero(); local_matrix.orn().identity();
  25. shape->setLocalPose(Physx.matrix(local_matrix));
  26. shape->setContactOffset(Physics.skin());
  27. return true;
  28. }
  29. return false;
  30. }
  31. static Bool Add(PxRigidActor &actor, C OBox &obox, C Vec *local_pos)
  32. {
  33. if(PxShape *shape=actor.createShape(PxBoxGeometry(obox.box.w()*0.5f, obox.box.h()*0.5f, obox.box.d()*0.5f), *Physics.mtrl_default._m))
  34. {
  35. Matrix local_matrix; if(local_pos)local_matrix.pos=*local_pos;else local_matrix.pos.zero(); local_matrix.orn()=obox.matrix.orn();
  36. shape->setLocalPose(Physx.matrix(local_matrix));
  37. shape->setContactOffset(Physics.skin());
  38. return true;
  39. }
  40. return false;
  41. }
  42. static Bool Add(PxRigidActor &actor, C Extent &ext, C Vec *local_pos)
  43. {
  44. if(PxShape *shape=actor.createShape(PxBoxGeometry(Physx.vec(ext.ext)), *Physics.mtrl_default._m))
  45. {
  46. Matrix local_matrix; if(local_pos)local_matrix.pos=*local_pos;else local_matrix.pos.zero(); local_matrix.orn().identity();
  47. shape->setLocalPose(Physx.matrix(local_matrix));
  48. shape->setContactOffset(Physics.skin());
  49. return true;
  50. }
  51. return false;
  52. }
  53. static Bool Add(PxRigidActor &actor, C Ball &ball, C Vec *local_pos)
  54. {
  55. if(PxShape *shape=actor.createShape(PxSphereGeometry(ball.r), *Physics.mtrl_default._m))
  56. {
  57. Matrix local_matrix; if(local_pos)local_matrix.pos=*local_pos;else local_matrix.pos.zero(); local_matrix.orn().identity();
  58. shape->setLocalPose(Physx.matrix(local_matrix));
  59. shape->setContactOffset(Physics.skin());
  60. return true;
  61. }
  62. return false;
  63. }
  64. static Bool Add(PxRigidActor &actor, C Capsule &capsule, C Vec *local_pos)
  65. {
  66. if(PxShape *shape=actor.createShape(PxCapsuleGeometry(capsule.r, capsule.h*0.5f-capsule.r), *Physics.mtrl_default._m))
  67. {
  68. Matrix local_matrix; if(local_pos)local_matrix.pos=*local_pos;else local_matrix.pos.zero(); local_matrix.orn().setRight(capsule.up);
  69. shape->setLocalPose(Physx.matrix(local_matrix));
  70. shape->setContactOffset(Physics.skin());
  71. return true;
  72. }
  73. return false;
  74. }
  75. static Bool Add(PxRigidActor &actor, PxConvexMesh &mesh, C Vec &scale)
  76. {
  77. if(PxShape *shape=actor.createShape(PxConvexMeshGeometry(&mesh, PxMeshScale(Physx.vec(scale), PxQuat(PxIdentity))), *Physics.mtrl_default._m))
  78. {
  79. shape->setContactOffset(Physics.skin());
  80. return true;
  81. }
  82. return false;
  83. }
  84. static Bool Add(PxRigidActor &actor, PxTriangleMesh &mesh, C Vec &scale)
  85. {
  86. if(PxShape *shape=actor.createShape(PxTriangleMeshGeometry(&mesh, PxMeshScale(Physx.vec(scale), PxQuat(PxIdentity))), *Physics.mtrl_default._m))
  87. {
  88. shape->setContactOffset(Physics.skin());
  89. return true;
  90. }
  91. return false;
  92. }
  93. static inline Bool Create(Actor &actor, Bool dynamic, Bool kinematic, C Vec &pos=VecZero)
  94. {
  95. if(dynamic || kinematic)actor._actor=actor._dynamic=Physx.physics->createRigidDynamic(Physx.matrix(pos));
  96. else actor._actor= Physx.physics->createRigidStatic (Physx.matrix(pos));
  97. if( kinematic)actor.kinematic(true);
  98. return actor._actor!=null;
  99. }
  100. /******************************************************************************/
  101. ActorShapes& ActorShapes::add(C Plane &plane ) {_as->shape.New().set(0 , plane ); return T;}
  102. ActorShapes& ActorShapes::add(C Box &box , Flt density) {_as->shape.New().set(density, box ); return T;}
  103. ActorShapes& ActorShapes::add(C OBox &obox , Flt density) {_as->shape.New().set(density, obox ); return T;}
  104. ActorShapes& ActorShapes::add(C Extent &ext , Flt density) {_as->shape.New().set(density, ext ); return T;}
  105. ActorShapes& ActorShapes::add(C Ball &ball , Flt density) {_as->shape.New().set(density, ball ); return T;}
  106. ActorShapes& ActorShapes::add(C Capsule &capsule, Flt density) {_as->shape.New().set(density, capsule); return T;}
  107. ActorShapes& ActorShapes::add(C Tube &tube , Flt density)
  108. {
  109. density*=TUBE_MASS_FACTOR;
  110. Matrix matrix; matrix.setPosUp(tube.pos, tube.up);
  111. OBox obox(Box(tube.r*SQRT2, tube.h, tube.r*SQRT2), matrix);
  112. matrix.orn().setRotate(tube.up, PI_2/TUBE_RES); REP(TUBE_RES)
  113. {
  114. add(obox, density);
  115. if(i)obox.matrix.orn()*=matrix.orn();
  116. }
  117. return T;
  118. }
  119. ActorShapes& ActorShapes::add(C PhysPart &const_part, Flt density, C Vec &scale)
  120. {
  121. PhysPart &part=ConstCast(const_part);
  122. density=Density(part.density, false)*Density(density, false);
  123. switch(part.type())
  124. {
  125. case PHYS_SHAPE : add(Equal(scale, VecOne) ? part.shape : part.shape*scale, density); break;
  126. case PHYS_CONVEX: part.setPhysMesh(); if(part._pm && part._pm->_convex){_as->convex.New().set(density, scale, part._pm->_convex); IncRef(_as->pm.New()=part._pm);} break;
  127. case PHYS_MESH : part.setPhysMesh(); if(part._pm && part._pm->_mesh ){_as->mesh .New().set(density, scale, part._pm->_mesh ); IncRef(_as->pm.New()=part._pm);} break;
  128. }
  129. return T;
  130. }
  131. /******************************************************************************/
  132. Actor& Actor::del()
  133. {
  134. if(_actor)
  135. {
  136. SafeWriteLock lock(Physics._rws);
  137. if(_actor)
  138. {
  139. if(Physx.physics)_actor->release();
  140. _actor=_dynamic=null;
  141. if(_ignore_id)
  142. {
  143. if(Physx.ignore_map.elms())REP(MAX_ACTOR_IGNORE) // disable all possible ignores (check for 'ignore_map' existence in case it was already deleted)
  144. {
  145. FlagDisable(Physx.ignoreMap(i, _ignore_id), 1<<(_ignore_id&7));
  146. FlagDisable(Physx.ignoreMap(_ignore_id, i), 1<<( i&7));
  147. }
  148. Physx.ignore_id_gen.Return(_ignore_id); _ignore_id=0;
  149. }
  150. }
  151. }
  152. REPA(_pm)DecRef(_pm[i]); _pm.del();
  153. return T;
  154. }
  155. Bool Actor::createTry(C ActorShapes &shapes, Flt density, Bool kinematic)
  156. {
  157. WriteLock lock(Physics._rws);
  158. del();
  159. _ActorShapes &as=*shapes._as;
  160. if(!as.shape.elms() && !as.convex.elms() && !as.mesh.elms())return true;
  161. if(Physx.world)
  162. {
  163. Bool dynamic=(density>0 && !as.mesh.elms()); // must be false for triangle meshes
  164. if( dynamic) // if at least one shape is static, then we can't create dynamic
  165. {
  166. REPA(as.shape )if(as.shape [i].density<=0){dynamic=false; break;}
  167. REPA(as.convex)if(as.convex[i].density<=0){dynamic=false; break;}
  168. REPA(as.mesh )if(as.mesh [i].density<=0){dynamic=false; break;}
  169. }
  170. if(Create(T, dynamic, kinematic))
  171. {
  172. Memt<Flt> densities;
  173. density=Density(density, kinematic);
  174. FREPA(as.shape)
  175. {
  176. _ActorShapes::Shape &s=as.shape[i];
  177. switch(s.shape.type)
  178. {
  179. case SHAPE_PLANE : if(!Add(*_actor, s.shape.plane ))goto error; densities.add(Density(s.density, kinematic)*density); break;
  180. case SHAPE_BOX : if(!Add(*_actor, s.shape.box , &s.shape.box .center()))goto error; densities.add(Density(s.density, kinematic)*density); break;
  181. case SHAPE_OBOX : if(!Add(*_actor, s.shape.obox , &s.shape.obox .center()))goto error; densities.add(Density(s.density, kinematic)*density); break;
  182. case SHAPE_BALL : if(!Add(*_actor, s.shape.ball , &s.shape.ball .pos ))goto error; densities.add(Density(s.density, kinematic)*density); break;
  183. case SHAPE_CAPSULE: if(!Add(*_actor, s.shape.capsule, &s.shape.capsule.pos ))goto error; densities.add(Density(s.density, kinematic)*density); break;
  184. }
  185. }
  186. FREPA(as.convex){_ActorShapes::Convex &convex=as.convex[i]; if(!Add(*_actor, *convex.convex, convex.scale))goto error; densities.add(Density(convex.density, kinematic)*density);}
  187. FREPA(as.mesh ){_ActorShapes::Mesh &mesh =as.mesh [i]; if(!Add(*_actor, *mesh .mesh , mesh .scale))goto error; densities.add(Density(mesh .density, kinematic)*density);}
  188. _pm=as.pm; REPA(_pm)IncRef(_pm[i]);
  189. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, densities.data(), densities.elms(), null);
  190. group(0).materialForce(shapes._mtrl);
  191. Physx.world->addActor(*_actor);
  192. return true;
  193. }
  194. }
  195. error:
  196. del(); return false;
  197. }
  198. Bool Actor::createTry(C Plane &plane)
  199. {
  200. WriteLock lock(Physics._rws); del();
  201. if(Physx.world)
  202. if(Create(T, false, false))
  203. {
  204. if(Add(*_actor, plane))
  205. {
  206. //if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, Density(density, kinematic), null);
  207. group(0).materialForce(null);
  208. Physx.world->addActor(*_actor);
  209. return true;
  210. }
  211. del();
  212. }
  213. return false;
  214. }
  215. Bool Actor::createTry(C Box &box, Flt density, C Vec *anchor, Bool kinematic)
  216. {
  217. WriteLock lock(Physics._rws); del();
  218. if(Physx.world)
  219. {
  220. Vec pos=box.center();
  221. if(Create(T, density>0, kinematic, anchor ? *anchor : pos))
  222. {
  223. if(Add(*_actor, box, anchor ? &(pos-*anchor) : null))
  224. {
  225. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, Density(density, kinematic), null);
  226. group(0).materialForce(null);
  227. Physx.world->addActor(*_actor);
  228. return true;
  229. }
  230. del();
  231. }
  232. }
  233. return false;
  234. }
  235. Bool Actor::createTry(C OBox &obox, Flt density, C Vec *anchor, Bool kinematic)
  236. {
  237. WriteLock lock(Physics._rws); del();
  238. if(Physx.world)
  239. {
  240. Vec pos=obox.center();
  241. if(Create(T, density>0, kinematic, anchor ? *anchor : pos))
  242. {
  243. if(Add(*_actor, obox, anchor ? &(pos-*anchor) : null))
  244. {
  245. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, Density(density, kinematic), null);
  246. group(0).materialForce(null);
  247. Physx.world->addActor(*_actor);
  248. return true;
  249. }
  250. del();
  251. }
  252. }
  253. return false;
  254. }
  255. Bool Actor::createTry(C Extent &ext, Flt density, C Vec *anchor, Bool kinematic)
  256. {
  257. WriteLock lock(Physics._rws); del();
  258. if(Physx.world)
  259. {
  260. if(Create(T, density>0, kinematic, anchor ? *anchor : ext.pos))
  261. {
  262. if(Add(*_actor, ext, anchor ? &(ext.pos-*anchor) : null))
  263. {
  264. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, Density(density, kinematic), null);
  265. group(0).materialForce(null);
  266. Physx.world->addActor(*_actor);
  267. return true;
  268. }
  269. del();
  270. }
  271. }
  272. return false;
  273. }
  274. Bool Actor::createTry(C Ball &ball, Flt density, C Vec *anchor, Bool kinematic)
  275. {
  276. WriteLock lock(Physics._rws); del();
  277. if(Physx.world)
  278. {
  279. if(Create(T, density>0, kinematic, anchor ? *anchor : ball.pos))
  280. {
  281. if(Add(*_actor, ball, anchor ? &(ball.pos-*anchor) : null))
  282. {
  283. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, Density(density, kinematic), null);
  284. group(0).materialForce(null);
  285. Physx.world->addActor(*_actor);
  286. return true;
  287. }
  288. del();
  289. }
  290. }
  291. return false;
  292. }
  293. Bool Actor::createTry(C Capsule &capsule, Flt density, C Vec *anchor, Bool kinematic)
  294. {
  295. WriteLock lock(Physics._rws); del();
  296. if(Physx.world)
  297. {
  298. if(Create(T, density>0, kinematic, anchor ? *anchor : capsule.pos))
  299. {
  300. if(Add(*_actor, capsule, anchor ? &(capsule.pos-*anchor) : null))
  301. {
  302. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, Density(density, kinematic), null);
  303. group(0).materialForce(null);
  304. Physx.world->addActor(*_actor);
  305. return true;
  306. }
  307. del();
  308. }
  309. }
  310. return false;
  311. }
  312. Bool Actor::createTry(C Tube &tube, Flt density, C Vec *anchor, Bool kinematic)
  313. {
  314. Vec dest=(anchor ? *anchor : tube.pos);
  315. if(createTry(ActorShapes().add(tube-dest), density, kinematic))
  316. {
  317. pos(dest);
  318. return true;
  319. }
  320. return false;
  321. }
  322. Bool Actor::createTry(C PhysPart &const_part, Flt density, C Vec &scale, Bool kinematic)
  323. {
  324. PhysPart &part=ConstCast(const_part);
  325. density=Density(part.density, kinematic)*Density(density, kinematic);
  326. switch(part.type())
  327. {
  328. case PHYS_SHAPE: return createTry(Equal(scale, VecOne) ? part.shape : part.shape*scale, density, &VecZero, kinematic);
  329. case PHYS_CONVEX:
  330. {
  331. WriteLock lock(Physics._rws);
  332. del();
  333. part.setPhysMesh(); // creating in background thread sometimes doesn't succeed, so let's try again
  334. if(Physx.world && part._pm && part._pm->_convex)
  335. if(Create(T, density>0, kinematic))
  336. {
  337. if(Add(*_actor, *part._pm->_convex, scale))
  338. {
  339. IncRef(_pm.New()=part._pm);
  340. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, density, null);
  341. group(0).materialForce(null);
  342. Physx.world->addActor(*_actor);
  343. return true;
  344. }
  345. del();
  346. }
  347. }return false;
  348. case PHYS_MESH:
  349. {
  350. WriteLock lock(Physics._rws);
  351. del();
  352. part.setPhysMesh(); // creating in background thread sometimes doesn't succeed, so let's try again
  353. if(Physx.world && part._pm && part._pm->_mesh)
  354. if(Create(T, false, kinematic)) // must be false for triangle meshes
  355. {
  356. if(Add(*_actor, *part._pm->_mesh, scale))
  357. {
  358. IncRef(_pm.New()=part._pm);
  359. if(_dynamic)PxRigidBodyExt::updateMassAndInertia(*_dynamic, density, null);
  360. group(0).materialForce(null);
  361. Physx.world->addActor(*_actor);
  362. return true;
  363. }
  364. del();
  365. }
  366. }return false;
  367. default: del(); return true;
  368. }
  369. }
  370. /******************************************************************************/
  371. #else // BULLET
  372. /******************************************************************************/
  373. static void DelActorShapes(btCollisionShape *shape)
  374. {
  375. if(shape)
  376. {
  377. if(btCompoundShape *compound=CAST(btCompoundShape, shape))
  378. {
  379. REP(compound->getNumChildShapes())DelActorShapes(compound->getChildShape(i)); // delete children
  380. }else
  381. if(btScaledBvhTriangleMeshShape *mesh=CAST(btScaledBvhTriangleMeshShape, shape))
  382. {
  383. DelActorShapes(mesh->getChildShape());
  384. }else
  385. if(btUniformScalingShape *uni=CAST(btUniformScalingShape, shape))
  386. {
  387. DelActorShapes(uni->getChildShape());
  388. }
  389. DecRef(shape);
  390. }
  391. }
  392. /******************************************************************************/
  393. btStaticPlaneShape* NewShape(C Plane &plane ) { btStaticPlaneShape *shape=new btStaticPlaneShape (Bullet.vec(plane.normal), Dot(plane.pos, plane.normal) ); shape->setMargin(Physics.skin()); return shape;}
  394. btBoxShape * NewShape(C Box &box ) { btBoxShape *shape=new btBoxShape (btVector3(box.w()*0.5f, box.h()*0.5f, box.d()*0.5f) ); shape->setMargin(Physics.skin()); return shape;}
  395. btBoxShape * NewShape(C OBox &obox ) { btBoxShape *shape=new btBoxShape (btVector3(obox.box.w()*0.5f, obox.box.h()*0.5f, obox.box.d()*0.5f)); shape->setMargin(Physics.skin()); return shape;}
  396. btBoxShape * NewShape(C Extent &ext ) { btBoxShape *shape=new btBoxShape (Bullet.vec(ext.ext) ); shape->setMargin(Physics.skin()); return shape;}
  397. btSphereShape * NewShape(C Ball &ball ) { btSphereShape *shape=new btSphereShape (ball.r ); shape->setMargin(Physics.skin()); return shape;}
  398. btCapsuleShape * NewShape(C Capsule &capsule ) { btCapsuleShape *shape=new btCapsuleShape (capsule.r, capsule.h-capsule.r*2 ); shape->setMargin(Physics.skin()); return shape;}
  399. btCylinderShape * NewShape(C Tube &tube ) { btCylinderShape *shape=new btCylinderShape (btVector3(tube.r, tube.h*0.5f, tube.r) ); shape->setMargin(Physics.skin()); return shape;}
  400. btCollisionShape * NewShape(btConvexHullShape *convex, C Vec &scale) {IncRef(convex); if(Equal(scale, VecOne))return convex; btCollisionShape *shape=new btUniformScalingShape (convex, scale.max() ); shape->setMargin(Physics.skin()); return shape;} // always IncRef 'convex' because either it's returned or it's used by 'btUniformScalingShape'
  401. btCollisionShape * NewShape(btBvhTriangleMeshShape *mesh , C Vec &scale) {IncRef(mesh ); if(Equal(scale, VecOne))return mesh ; btCollisionShape *shape=new btScaledBvhTriangleMeshShape(mesh , Bullet.vec(scale) ); shape->setMargin(Physics.skin()); return shape;} // always IncRef 'mesh ' because either it's returned or it's used by 'btScaledBvhTriangleMeshShape'
  402. btCompoundShape * NewShape( ) { btCompoundShape *shape=new btCompoundShape ; shape->setMargin(Physics.skin()); return shape;}
  403. /******************************************************************************/
  404. ActorShapes& ActorShapes::add(C Plane &plane ) {_as->shape.New().set(0 , plane ); return T;}
  405. ActorShapes& ActorShapes::add(C Box &box , Flt density) {_as->shape.New().set(density, box ); return T;}
  406. ActorShapes& ActorShapes::add(C OBox &obox , Flt density) {_as->shape.New().set(density, obox ); return T;}
  407. ActorShapes& ActorShapes::add(C Extent &ext , Flt density) {_as->shape.New().set(density, ext ); return T;}
  408. ActorShapes& ActorShapes::add(C Ball &ball , Flt density) {_as->shape.New().set(density, ball ); return T;}
  409. ActorShapes& ActorShapes::add(C Capsule &capsule , Flt density) {_as->shape.New().set(density, capsule); return T;}
  410. ActorShapes& ActorShapes::add(C Tube &tube , Flt density) {_as->shape.New().set(density, tube ); return T;}
  411. ActorShapes& ActorShapes::add(C PhysPart &const_part, Flt density, C Vec &scale)
  412. {
  413. PhysPart &part=ConstCast(const_part);
  414. density=Density(part.density, false)*Density(density, false);
  415. switch(part.type())
  416. {
  417. case PHYS_SHAPE : add(Equal(scale, VecOne) ? part.shape : part.shape*scale, density); break;
  418. case PHYS_CONVEX: part.setPhysMesh(); if(part._pm && part._pm->_convex){_as->convex.New().set(density, part._pm->volume(), scale, part._pm->_convex); IncRef(_as->pm.New()=part._pm);} break; // here 'IncRef' for '_convex' is not needed because there's an 'IncRef' for '_pm' which already holds references to that shape
  419. case PHYS_MESH : part.setPhysMesh(); if(part._pm && part._pm->_mesh ){_as->mesh .New().set(density, scale, part._pm->_mesh ); IncRef(_as->pm.New()=part._pm);} break; // here 'IncRef' for '_mesh ' is not needed because there's an 'IncRef' for '_pm' which already holds references to that shape
  420. }
  421. return T;
  422. }
  423. /******************************************************************************/
  424. Actor& Actor::del()
  425. {
  426. if(_actor)
  427. {
  428. SafeWriteLock lock(Physics._rws);
  429. if(_actor)
  430. {
  431. if(Bullet.world)
  432. {
  433. REP(_actor->getNumConstraintRefs())Bullet.world->removeConstraint(_actor->getConstraintRef(i)); // remove all joints linked with this actor
  434. Bullet.world->removeRigidBody(_actor); // remove from world
  435. }
  436. DelActorShapes(_actor->getCollisionShape()); // delete shapes
  437. if(btMotionState *motion_state=_actor->getMotionState())Delete(motion_state); // delete motion state
  438. Delete(_actor);
  439. }
  440. }
  441. REPA(_pm)DecRef(_pm[i]); _pm.del();
  442. return T;
  443. }
  444. Bool Actor::init(btRigidBody::btRigidBodyConstructionInfo &info, C Vec *anchor, Bool kinematic, PhysMesh *pm, PhysMtrl *material)
  445. {
  446. _actor=new RigidBody(info);
  447. Bullet.world->addRigidBody(_actor);
  448. // desired_matrix = offset * bullet_matrix
  449. // offset = desired_matrix / bullet_matrix
  450. Matrix bullet_matrix=massCenterMatrix(),
  451. desired_matrix(anchor ? *anchor : bullet_matrix.pos);
  452. desired_matrix.divNormalized(bullet_matrix, _actor->offset);
  453. group(0).ray(true).kinematic(kinematic).materialForce(material);
  454. _actor->setCollisionFlags(_actor->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
  455. if(pm)IncRef(T._pm.New()=pm);
  456. return true;
  457. }
  458. /******************************************************************************/
  459. static Matrix GetTransform(C Box &box ) {return Matrix( box.center() );}
  460. static Matrix GetTransform(C OBox &obox ) {return Matrix(obox.matrix.orn(), obox.center() );}
  461. static Matrix GetTransform(C Extent &ext ) {return Matrix( ext.center );}
  462. static Matrix GetTransform(C Ball &ball ) {return Matrix( ball .pos );}
  463. static Matrix GetTransform(C Capsule &capsule) {return Matrix().setPosUp(capsule.pos, capsule.up);}
  464. static Matrix GetTransform(C Tube &tube ) {return Matrix().setPosUp(tube .pos, tube .up);}
  465. /******************************************************************************/
  466. Bool Actor::createTry(C ActorShapes &shapes, Flt density, Bool kinematic)
  467. {
  468. _ActorShapes &as=*shapes._as;
  469. if(as.shape.elms()==0 && as.convex.elms()==0 && as.mesh.elms()==0){del(); return true;}
  470. if(as.shape.elms()==1 && as.convex.elms()==0 && as.mesh.elms()==0){ if(createTry(as.shape .first().shape , as.shape .first().density*density, &VecZero, kinematic)){materialForce(shapes._mtrl); return true;} return false;}
  471. if(as.shape.elms()==0 && as.convex.elms()==1 && as.mesh.elms()==0)return createTry(as.convex.first().convex, as.convex.first().scale, as.convex.first().density*density, kinematic, (as.pm.elms()==1) ? as.pm[0] : null, shapes._mtrl); // here 'IncRef' is not needed because it will be called inside that method if needed
  472. if(as.shape.elms()==0 && as.convex.elms()==0 && as.mesh.elms()==1)return createTry(as.mesh .first().mesh , as.mesh .first().scale , (as.pm.elms()==1) ? as.pm[0] : null, shapes._mtrl); // here 'IncRef' is not needed because it will be called inside that method if needed
  473. WriteLock lock(Physics._rws);
  474. del();
  475. if(Bullet.world)
  476. {
  477. density=Density(density, kinematic);
  478. Flt mass =0;
  479. Vec center=0;
  480. REPA(as.shape ){_ActorShapes::Shape &shape =as.shape [i]; Flt m=shape.shape.volume() *Density( shape.density, kinematic)*density; mass+=m; center+=m*shape.shape.pos();}
  481. REPA(as.convex){_ActorShapes::Convex &convex=as.convex[i]; btVector3 bcenter; btScalar radius; convex.convex->getBoundingSphere(bcenter, radius); Flt m= convex.volume*convex.scale.x*convex.scale.y*convex.scale.z*Density(convex.density, kinematic)*density; mass+=m; center+=m*Bullet.vec(bcenter)*convex.scale;}
  482. if(mass)center/=mass;
  483. btCompoundShape *compound=NewShape();
  484. FREPA(as.shape)
  485. {
  486. _ActorShapes::Shape &s=as.shape[i];
  487. switch(s.shape.type)
  488. {
  489. case SHAPE_PLANE : compound->addChildShape(Bullet.matrix( Matrix(-center)), NewShape(s.shape.plane )); break;
  490. case SHAPE_BOX : compound->addChildShape(Bullet.matrix(GetTransform(s.shape.box ).moveBack(center)), NewShape(s.shape.box )); break;
  491. case SHAPE_OBOX : compound->addChildShape(Bullet.matrix(GetTransform(s.shape.obox ).moveBack(center)), NewShape(s.shape.obox )); break;
  492. case SHAPE_BALL : compound->addChildShape(Bullet.matrix(GetTransform(s.shape.ball ).moveBack(center)), NewShape(s.shape.ball )); break;
  493. case SHAPE_CAPSULE: compound->addChildShape(Bullet.matrix(GetTransform(s.shape.capsule).moveBack(center)), NewShape(s.shape.capsule)); break;
  494. case SHAPE_TUBE : compound->addChildShape(Bullet.matrix(GetTransform(s.shape.tube ).moveBack(center)), NewShape(s.shape.tube )); break;
  495. }
  496. }
  497. FREPA(as.convex){_ActorShapes::Convex &convex=as.convex[i]; compound->addChildShape(Bullet.matrix(Matrix(-center)), NewShape(convex.convex, convex.scale));} // 'NewShape' will call 'IncRef' if needed
  498. FREPA(as.mesh ){_ActorShapes::Mesh &mesh =as.mesh [i]; compound->addChildShape(Bullet.matrix(Matrix(-center)), NewShape(mesh .mesh , mesh .scale));} // 'NewShape' will call 'IncRef' if needed
  499. btVector3 local_inertia(0, 0, 0); if(mass)compound->calculateLocalInertia(mass, local_inertia);
  500. btRigidBody::btRigidBodyConstructionInfo info(mass, null, compound, local_inertia);
  501. if(init(info, &(-center), kinematic, null, shapes._mtrl))
  502. {
  503. _pm=as.pm; REPA(_pm)IncRef(_pm[i]);
  504. return true;
  505. }
  506. }
  507. return false;
  508. }
  509. Bool Actor::createTry(C Plane &plane)
  510. {
  511. WriteLock lock(Physics._rws);
  512. del();
  513. if(Bullet.world)
  514. {
  515. btStaticPlaneShape *shape=NewShape(plane);
  516. btRigidBody::btRigidBodyConstructionInfo info(0, null, shape);
  517. return init(info, null, false, null, null);
  518. }
  519. return false;
  520. }
  521. Bool Actor::createTry(C Box &box, Flt density, C Vec *anchor, Bool kinematic)
  522. {
  523. WriteLock lock(Physics._rws);
  524. del();
  525. if(Bullet.world)
  526. {
  527. btBoxShape *shape=NewShape(box);
  528. Flt mass =box.volume()*Density(density, kinematic);
  529. btVector3 local_inertia(0, 0, 0); if(mass)shape->calculateLocalInertia(mass, local_inertia);
  530. btRigidBody::btRigidBodyConstructionInfo info(mass, null, shape, local_inertia);
  531. info.m_startWorldTransform=Bullet.matrix(GetTransform(box)); // info.m_motionState=new btDefaultMotionState(info.m_startWorldTransform);
  532. return init(info, anchor, kinematic, null, null);
  533. }
  534. return false;
  535. }
  536. Bool Actor::createTry(C OBox &obox, Flt density, C Vec *anchor, Bool kinematic)
  537. {
  538. WriteLock lock(Physics._rws);
  539. del();
  540. if(Bullet.world)
  541. {
  542. btBoxShape *shape=NewShape(obox);
  543. Flt mass =obox.volume()*Density(density, kinematic);
  544. btVector3 local_inertia(0, 0, 0); if(mass)shape->calculateLocalInertia(mass, local_inertia);
  545. btRigidBody::btRigidBodyConstructionInfo info(mass, null, shape, local_inertia);
  546. info.m_startWorldTransform=Bullet.matrix(GetTransform(obox)); // info.m_motionState=new btDefaultMotionState(info.m_startWorldTransform);
  547. return init(info, anchor, kinematic, null, null);
  548. }
  549. return false;
  550. }
  551. Bool Actor::createTry(C Extent &ext, Flt density, C Vec *anchor, Bool kinematic)
  552. {
  553. WriteLock lock(Physics._rws);
  554. del();
  555. if(Bullet.world)
  556. {
  557. btBoxShape *shape=NewShape(ext);
  558. Flt mass =ext.volume()*Density(density, kinematic);
  559. btVector3 local_inertia(0, 0, 0); if(mass)shape->calculateLocalInertia(mass, local_inertia);
  560. btRigidBody::btRigidBodyConstructionInfo info(mass, null, shape, local_inertia);
  561. info.m_startWorldTransform=Bullet.matrix(GetTransform(ext)); // info.m_motionState=new btDefaultMotionState(info.m_startWorldTransform);
  562. return init(info, anchor, kinematic, null, null);
  563. }
  564. return false;
  565. }
  566. Bool Actor::createTry(C Ball &ball, Flt density, C Vec *anchor, Bool kinematic)
  567. {
  568. WriteLock lock(Physics._rws);
  569. del();
  570. if(Bullet.world)
  571. {
  572. btSphereShape *shape=NewShape(ball);
  573. Flt mass =ball.volume()*Density(density, kinematic);
  574. btVector3 local_inertia(0, 0, 0); if(mass)shape->calculateLocalInertia(mass, local_inertia);
  575. btRigidBody::btRigidBodyConstructionInfo info(mass, null, shape, local_inertia);
  576. info.m_startWorldTransform=Bullet.matrix(GetTransform(ball)); // info.m_motionState=new btDefaultMotionState(info.m_startWorldTransform);
  577. return init(info, anchor, kinematic, null, null);
  578. }
  579. return false;
  580. }
  581. Bool Actor::createTry(C Capsule &capsule, Flt density, C Vec *anchor, Bool kinematic)
  582. {
  583. WriteLock lock(Physics._rws);
  584. del();
  585. if(Bullet.world)
  586. {
  587. btCapsuleShape *shape=NewShape(capsule);
  588. Flt mass =capsule.volume()*Density(density, kinematic);
  589. btVector3 local_inertia(0, 0, 0); if(mass)shape->calculateLocalInertia(mass, local_inertia);
  590. btRigidBody::btRigidBodyConstructionInfo info(mass, null, shape, local_inertia);
  591. info.m_startWorldTransform=Bullet.matrix(GetTransform(capsule)); // info.m_motionState=new btDefaultMotionState(info.m_startWorldTransform);
  592. return init(info, anchor, kinematic, null, null);
  593. }
  594. return false;
  595. }
  596. Bool Actor::createTry(C Tube &tube, Flt density, C Vec *anchor, Bool kinematic)
  597. {
  598. WriteLock lock(Physics._rws);
  599. del();
  600. if(Bullet.world)
  601. {
  602. btCylinderShape *shape=NewShape(tube);
  603. Flt mass =tube.volume()*Density(density, kinematic);
  604. btVector3 local_inertia(0, 0, 0); if(mass)shape->calculateLocalInertia(mass, local_inertia);
  605. btRigidBody::btRigidBodyConstructionInfo info(mass, null, shape, local_inertia);
  606. info.m_startWorldTransform=Bullet.matrix(GetTransform(tube)); // info.m_motionState=new btDefaultMotionState(info.m_startWorldTransform);
  607. return init(info, anchor, kinematic, null, null);
  608. }
  609. return false;
  610. }
  611. Bool Actor::createTry(btConvexHullShape *convex, C Vec &scale, Flt density, Bool kinematic, PhysMesh *pm, PhysMtrl *material)
  612. {
  613. WriteLock lock(Physics._rws);
  614. del();
  615. if(Bullet.world && convex)
  616. {
  617. density=Density(density, kinematic);
  618. btVector3 bcenter; btScalar radius; convex->getBoundingSphere(bcenter, radius); Vec center=Bullet.vec(bcenter)*scale;
  619. Flt mass =(pm ? pm->volume() : Ball(radius).volume())*scale.x*scale.y*scale.z*density; // if mesh is unavailable then approximate with a Ball
  620. btCollisionShape *shape =NewShape(convex, scale); // 'NewShape' will call 'IncRef' if needed
  621. if(mass && center.length2()>0.01f*0.01f) // if non-static actor and convex center is not at (0, 0, 0) then offset must be used
  622. {
  623. btCompoundShape *compound=NewShape();
  624. compound->addChildShape(Bullet.matrix(Matrix(-center)), shape);
  625. btVector3 local_inertia(0, 0, 0); if(mass)compound->calculateLocalInertia(mass, local_inertia);
  626. btRigidBody::btRigidBodyConstructionInfo info(mass, null, compound, local_inertia);
  627. return init(info, &(-center), kinematic, pm, material);
  628. }else
  629. {
  630. btVector3 local_inertia(0, 0, 0); if(mass)shape->calculateLocalInertia(mass, local_inertia);
  631. btRigidBody::btRigidBodyConstructionInfo info(mass, null, shape, local_inertia);
  632. return init(info, null, kinematic, pm, material);
  633. }
  634. }
  635. return false;
  636. }
  637. Bool Actor::createTry(btBvhTriangleMeshShape *mesh, C Vec &scale, PhysMesh *pm, PhysMtrl *material)
  638. {
  639. WriteLock lock(Physics._rws);
  640. del();
  641. if(Bullet.world && mesh)
  642. {
  643. btRigidBody::btRigidBodyConstructionInfo info(0, null, NewShape(mesh, scale)); // mass must be 0 to indicate static object, 'NewShape' will call 'IncRef' if needed
  644. return init(info, null, false, pm, material);
  645. }
  646. return false;
  647. }
  648. Bool Actor::createTry(C PhysPart &const_part, Flt density, C Vec &scale, Bool kinematic)
  649. {
  650. PhysPart &part=ConstCast(const_part);
  651. density=Density(part.density, kinematic)*Density(density, kinematic);
  652. switch(part.type())
  653. {
  654. case PHYS_SHAPE : return createTry(Equal(scale, VecOne) ? part.shape : part.shape*scale, density, &VecZero, kinematic );
  655. case PHYS_CONVEX: part.setPhysMesh(); return createTry(part._pm ? part._pm->_convex : null, scale, density, kinematic, part._pm, null); // here 'IncRef' for '_convex' is not needed because if needed then it's called inside that method
  656. case PHYS_MESH : part.setPhysMesh(); return createTry(part._pm ? part._pm->_mesh : null, scale , part._pm, null); // here 'IncRef' for '_mesh ' is not needed because if needed then it's called inside that method
  657. }
  658. del(); return true;
  659. }
  660. /******************************************************************************/
  661. #endif
  662. /******************************************************************************/
  663. _ActorShapes::~_ActorShapes() {REPA(pm)DecRef(pm[i]);}
  664. ActorShapes::~ ActorShapes() {Delete(_as);}
  665. ActorShapes:: ActorShapes() {New (_as); _mtrl=null;}
  666. ActorShapes& ActorShapes::add(C Shape &shape, Flt density)
  667. {
  668. switch(shape.type)
  669. {
  670. case SHAPE_PLANE : add(shape.plane ); break;
  671. case SHAPE_BOX : add(shape.box , density); break;
  672. case SHAPE_OBOX : add(shape.obox , density); break;
  673. case SHAPE_BALL : add(shape.ball , density); break;
  674. case SHAPE_CAPSULE: add(shape.capsule, density); break;
  675. case SHAPE_TUBE : add(shape.tube , density); break;
  676. }
  677. return T;
  678. }
  679. ActorShapes& ActorShapes::add(C PhysPart &part, C Vec &scale)
  680. {
  681. return add(part, 1, scale);
  682. }
  683. ActorShapes& ActorShapes::add(C PhysBody &phys, C Vec &scale)
  684. {
  685. if(!_mtrl && phys.material)_mtrl=phys.material;
  686. Flt density=phys.finalDensity();
  687. FREPA(phys)add(phys.parts[i], density, scale);
  688. return T;
  689. }
  690. /******************************************************************************/
  691. Bool Actor::createTry(C Shape &shape, Flt density, C Vec *anchor, Bool kinematic)
  692. {
  693. switch(shape.type)
  694. {
  695. default : del(); return false;
  696. case SHAPE_NONE : del(); return true ;
  697. case SHAPE_PLANE : return createTry(shape.plane );
  698. case SHAPE_BOX : return createTry(shape.box , density, anchor, kinematic);
  699. case SHAPE_OBOX : return createTry(shape.obox , density, anchor, kinematic);
  700. case SHAPE_BALL : return createTry(shape.ball , density, anchor, kinematic);
  701. case SHAPE_CAPSULE: return createTry(shape.capsule, density, anchor, kinematic);
  702. case SHAPE_TUBE : return createTry(shape.tube , density, anchor, kinematic);
  703. }
  704. }
  705. Bool Actor::createTry(C PhysBody &phys, Flt density, C Vec &scale, Bool kinematic)
  706. {
  707. switch(phys.parts.elms())
  708. {
  709. case 0: del(); return true;
  710. case 1: if(createTry(phys.parts[0], Density(phys.finalDensity(), kinematic)*Density(density, kinematic), scale, kinematic))
  711. {
  712. materialForce(phys.material);
  713. return true;
  714. }return false;
  715. default:
  716. {
  717. ActorShapes shapes; shapes.add(phys, scale); // 'phys.material' and 'phys.density' is passed into 'shapes'
  718. return createTry(shapes, density, kinematic);
  719. }
  720. }
  721. }
  722. /******************************************************************************/
  723. static void CheckPhysics( ) {if(!Physics.created())Exit("Attempting to create an actor without creating Physics first.");}
  724. static void CheckMesh (C PhysPart &part, C PhysBody *owner=null)
  725. {
  726. switch(part.type())
  727. {
  728. case PHYS_CONVEX:
  729. case PHYS_MESH :
  730. {
  731. Str file=PhysBodies.name(owner);
  732. Exit(S+"Can't create actor from "+((part.type()==PHYS_CONVEX) ? "PHYS_CONVEX" : "PHYS_MESH")+" physical body.\n"
  733. "Physics Engine Used: "
  734. #if PHYSX
  735. "PhysX\n"
  736. #else
  737. "Bullet\n"
  738. #endif
  739. "Universal Data Available: "+((part._pm && part._pm-> _base ) ? "Yes\n" : "No\n")+
  740. "PhysX Data Available: " +((part._pm && part._pm-> _physx_cooked_data.elms()) ? "Yes\n" : "No\n")+
  741. "Bullet Data Available: " +((part._pm && part._pm->_bullet_cooked_data ) ? "Yes\n" : "No\n")+
  742. #if PHYSX
  743. "PhysX Mesh Available: " +((part._pm && ((part.type()==PHYS_CONVEX) ? part._pm->_convex!=null : part._pm->_mesh!=null)) ? "Yes\n" : "No\n")+
  744. #else
  745. "Bullet Mesh Available: " +((part._pm && ((part.type()==PHYS_CONVEX) ? part._pm->_convex!=null : part._pm->_mesh!=null)) ? "Yes\n" : "No\n")+
  746. #endif
  747. "PhysBody file: \""+file+"\""
  748. #if !PHYSX
  749. +((part._pm && part._pm->_base) ? "" : "\nPlease recreate the PhysBody file.")
  750. #endif
  751. );
  752. }break;
  753. }
  754. }
  755. static void CheckMesh(C PhysBody &phys) {REPA(phys)CheckMesh(phys.parts[i], &phys);}
  756. /******************************************************************************/
  757. Actor& Actor::create(C ActorShapes &shapes , Flt density, Bool kinematic) {if(!createTry(shapes , density, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C ActorShapes &shapes, Flt density, Bool kinematic);\ndensity = " +density+"\nkinematic = "+kinematic );} return T;}
  758. Actor& Actor::create(C Plane &plane ) {if(!createTry(plane )){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C Plane &plane);\nplane = " +plane .asText( ) );} return T;}
  759. Actor& Actor::create(C Box &box , Flt density, C Vec *anchor, Bool kinematic) {if(!createTry(box , density, anchor, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C Box &box, Flt density, C Vec *anchor, Bool kinematic);\nbox = " +box .asText( )+"\ndensity = "+density+"\nkinematic = "+kinematic );} return T;}
  760. Actor& Actor::create(C OBox &obox , Flt density, C Vec *anchor, Bool kinematic) {if(!createTry(obox , density, anchor, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C OBox &obox, Flt density, C Vec *anchor, Bool kinematic);\nobox = " +obox .asText( )+"\ndensity = "+density+"\nkinematic = "+kinematic );} return T;}
  761. Actor& Actor::create(C Extent &ext , Flt density, C Vec *anchor, Bool kinematic) {if(!createTry(ext , density, anchor, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C Extent &ext, Flt density, C Vec *anchor, Bool kinematic);\next = " +ext .asText( )+"\ndensity = "+density+"\nkinematic = "+kinematic );} return T;}
  762. Actor& Actor::create(C Ball &ball , Flt density, C Vec *anchor, Bool kinematic) {if(!createTry(ball , density, anchor, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C Ball &ball, Flt density, C Vec *anchor, Bool kinematic);\nball = " +ball .asText( )+"\ndensity = "+density+"\nkinematic = "+kinematic );} return T;}
  763. Actor& Actor::create(C Capsule &capsule, Flt density, C Vec *anchor, Bool kinematic) {if(!createTry(capsule, density, anchor, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C Capsule &capsule, Flt density, C Vec *anchor, Bool kinematic);\ncapsule = " +capsule.asText( )+"\ndensity = "+density+"\nkinematic = "+kinematic );} return T;}
  764. Actor& Actor::create(C Tube &tube , Flt density, C Vec *anchor, Bool kinematic) {if(!createTry(tube , density, anchor, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C Tube &tube, Flt density, C Vec *anchor, Bool kinematic);\ntube = " +tube .asText( )+"\ndensity = "+density+"\nkinematic = "+kinematic );} return T;}
  765. Actor& Actor::create(C Shape &shape , Flt density, C Vec *anchor, Bool kinematic) {if(!createTry(shape , density, anchor, kinematic)){CheckPhysics(); Exit(S+"Can't create actor:\nActor.create(C Shape &shape, Flt density, C Vec *anchor, Bool kinematic);\nshape = " +shape .asText(true)+"\ndensity = "+density+"\nkinematic = "+kinematic );} return T;}
  766. Actor& Actor::create(C PhysPart &part , Flt density, C Vec &scale , Bool kinematic) {if(!createTry(part , density, scale , kinematic)){CheckPhysics(); CheckMesh(part); Exit(S+"Can't create actor:\nActor.create(C PhysPart &part, Flt density, C Vec &scale, C Vec *anchor,Bool kinematic);\ndensity = "+density +"\nscale = "+scale +"\nkinematic = "+kinematic );} return T;}
  767. Actor& Actor::create(C PhysBody &phys , Flt density, C Vec &scale , Bool kinematic) {if(!createTry(phys , density, scale , kinematic)){CheckPhysics(); CheckMesh(phys); Exit(S+"Can't create actor:\nActor.create(C PhysBody &phys, Flt density, C Vec &scale, Bool kinematic);\ndensity = " +density +"\nscale = "+scale +"\nkinematic = "+kinematic+"\nphys = \""+PhysBodies.name(&phys)+"\"");} return T;}
  768. /******************************************************************************/
  769. }
  770. /******************************************************************************/