Physics.cpp 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #define MAX_CONTACTS 32
  4. namespace EE{
  5. #include "PhysX Stream.h"
  6. /******************************************************************************/
  7. PhysicsClass Physics;
  8. #if PHYSX
  9. PhysxClass Physx;
  10. #else
  11. BulletClass Bullet;
  12. #endif
  13. /******************************************************************************/
  14. // CALLBACKS
  15. /******************************************************************************/
  16. static Flt WheelFriction(C PhysMtrl &ground_material, C PhysMtrl &wheel_material, C ActorInfo &vehicle, WHEEL_TYPE wheel)
  17. {
  18. return 1.0f;
  19. }
  20. /******************************************************************************/
  21. #if PHYSX
  22. /******************************************************************************/
  23. PxU32 OutputStream::write(const void* src, PxU32 count)
  24. {
  25. if(pos+count>max)Realloc(data, max=pos+count+8192, pos);
  26. CopyFast(data+pos, src, count); pos+=count;
  27. return count;
  28. }
  29. PxU32 InputStream::read(void* dest, PxU32 count)
  30. {
  31. Int read=Min(count, size-pos);
  32. CopyFast(dest, data+pos, read); pos+=read;
  33. return read;
  34. }
  35. /******************************************************************************/
  36. static struct ErrorCallbackClass : PxErrorCallback
  37. {
  38. virtual void reportError(PxErrorCode::Enum code, const char* message, const char* file, int line)override
  39. {
  40. if(code&PxErrorCode::eABORT)Exit(S+"Physx("+code+"): "+message);
  41. #if DEBUG
  42. if(!Equal(message, "RigidBody::setRigidBodyFlag: kinematic bodies with CCD enabled are not supported! CCD will be ignored.")
  43. )LogN(S+"Physx("+code+"): "+message);
  44. #endif
  45. }
  46. }ErrorCallback;
  47. Ptr PhysxClass::AllocatorCallback::allocate(size_t size, const char *typeName, const char *filename, int line)
  48. {
  49. Ptr ptr=super::allocate(size, typeName, filename, line);
  50. if( ptr)AtomicInc(Physx._mem_leaks);
  51. return ptr;
  52. }
  53. void PhysxClass::AllocatorCallback::deallocate(void *ptr)
  54. {
  55. if(ptr)
  56. {
  57. AtomicDec(Physx._mem_leaks);
  58. super::deallocate(ptr);
  59. }
  60. }
  61. #if !USE_DEFAULT_CPU_DISPATCHER
  62. static struct CpuDispatcherClass : PxCpuDispatcher // !!!!!!!!!!!!! if PhysX crashes here, then most likely invalid data was put into Actors (0, NaN, +-Inf, etc.) or other physics classes !!!!!!!!
  63. {
  64. #if HAS_THREADS
  65. Threads threads;
  66. #endif
  67. ~CpuDispatcherClass() {del();}
  68. void del()
  69. {
  70. #if HAS_THREADS
  71. threads.wait(); // make sure all are processed because we need to release the 'PxBaseTask'
  72. #endif
  73. }
  74. CpuDispatcherClass& create()
  75. {
  76. del();
  77. #if HAS_THREADS
  78. threads.create(false, Cpu.threads()-1, 0, "EE.PhysX #"); // leave 1 thread for the main update, TODO: we could reuse any other 'Threads'
  79. #endif
  80. return T;
  81. }
  82. virtual PxU32 getWorkerCount()C override
  83. {
  84. #if HAS_THREADS
  85. return threads.threads();
  86. #else
  87. return 0;
  88. #endif
  89. }
  90. static void ProcessTask(PxBaseTask &task, Ptr user, Int thread_index) {task.run(); task.release();}
  91. virtual void submitTask(PxBaseTask &task)override
  92. {
  93. #if HAS_THREADS
  94. threads.queue(task, ProcessTask);
  95. #else
  96. task.run(); task.release();
  97. #endif
  98. }
  99. }CpuDispatcher;
  100. #else
  101. static PxDefaultCpuDispatcher *CpuDispatcher;
  102. #endif
  103. static PxFilterFlags FilterFunc(PxFilterObjectAttributes attributes0, PxFilterData filterData0, PxFilterObjectAttributes attributes1, PxFilterData filterData1, PxPairFlags &pairFlags, const void *constantBlock, PxU32 constantBlockSize)
  104. {
  105. // check triggers
  106. if((attributes0 | attributes1) & PxFilterObjectFlag::eTRIGGER)
  107. {
  108. pairFlags=(PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_PERSISTS | PxPairFlag::eNOTIFY_TOUCH_LOST);
  109. return PxFilterFlags();
  110. }
  111. // per-group filtering
  112. if(!Physics.collides(filterData0.word0, filterData1.word0))return PxFilterFlag::eSUPPRESS;
  113. // per-actor filtering
  114. if(filterData0.word1 && filterData1.word1 && (Physx.ignoreMap(filterData0.word1, filterData1.word1)&(1<<(filterData1.word1&7))))return PxFilterFlag::eSUPPRESS;
  115. // set default values
  116. pairFlags=PxPairFlags(PxPairFlag::eCONTACT_DEFAULT | filterData0.word2 | filterData1.word2); // word2 has encoded PxPairFlags (for example 'ccd')
  117. // check for collision reports
  118. if(Physics.reports(filterData0.word0, filterData1.word0))pairFlags|=(PxPairFlag::eNOTIFY_TOUCH_FOUND | PxPairFlag::eNOTIFY_TOUCH_PERSISTS | PxPairFlag::eNOTIFY_TOUCH_LOST | PxPairFlag::eNOTIFY_CONTACT_POINTS);
  119. return PxFilterFlags();
  120. }
  121. static PxQueryHitType::Enum VehicleWheelRaycastFilterFunc(PxFilterData vehicle_susp, PxFilterData shape_fd, const void* constantBlock, PxU32 constantBlockSize, PxHitFlags& filterFlags)
  122. {
  123. return (vehicle_susp.word1==shape_fd.word1) ? PxQueryHitType::eNONE : PxQueryHitType::eBLOCK; // ignore actors of same actor_id
  124. }
  125. struct EventCallbackClass : PxSimulationEventCallback
  126. {
  127. virtual void onConstraintBreak(PxConstraintInfo* constraints, PxU32 count)override {}
  128. virtual void onWake(PxActor** actors, PxU32 count)override {}
  129. virtual void onSleep(PxActor** actors, PxU32 count)override {}
  130. virtual void onAdvance(const PxRigidBody*const* bodyBuffer, const PxTransform* poseBuffer, const PxU32 count)override {}
  131. virtual void onContact(const PxContactPairHeader& pairHeader, const PxContactPair* pairs, PxU32 nbPairs)override
  132. {
  133. void (*func)(ActorInfo &actor_a, ActorInfo &actor_b, C PhysContact *contact, Int contacts)=Physics._report_contact; // assign to temporary variable in order to avoid multi-threading issues
  134. if(func)
  135. if(!(pairHeader.flags&(PxContactPairHeaderFlag::eREMOVED_ACTOR_0 | PxContactPairHeaderFlag::eREMOVED_ACTOR_1))) // if both still exist
  136. if(PxRigidActor *actor0=pairHeader.actors[0]->is<PxRigidActor>())
  137. if(PxRigidActor *actor1=pairHeader.actors[1]->is<PxRigidActor>())
  138. {
  139. PxShape *shape0, *shape1;
  140. if(actor0->getShapes(&shape0, 1))
  141. if(actor1->getShapes(&shape1, 1))
  142. {
  143. ActorInfo actor_a, actor_b; actor_a.set(shape0); actor_b.set(shape1);
  144. PhysContact contact[MAX_CONTACTS]; Int contacts=0;
  145. REP(nbPairs)
  146. {
  147. C PxContactPair &pair=pairs[i];
  148. if(pair.flags&PxContactPairFlag::eINTERNAL_HAS_IMPULSES) // we can ignore 'eREMOVED_SHAPE_0' and 'eREMOVED_SHAPE_1' because we're just collecting pos/normal/force
  149. {
  150. PxContactPairPoint px_contact[MAX_CONTACTS]; Int px_contacts=pair.extractContacts(px_contact, Elms(px_contact));
  151. REP(px_contacts)
  152. {
  153. if(InRange(contacts, contact))
  154. {
  155. contact[contacts].pos =Physx.vec(px_contact[i].position);
  156. contact[contacts].normal=Physx.vec(px_contact[i].normal );
  157. contact[contacts].force =Physx.vec(px_contact[i].impulse ); if(Physics.stepTime())contact[contacts].force/=Physics.stepTime(); // according to PhysX doc, impulse should be divided by simulation step to get force
  158. contacts++;
  159. }
  160. }
  161. }
  162. }
  163. func(actor_a, actor_b, contact, contacts);
  164. }
  165. }
  166. }
  167. virtual void onTrigger(PxTriggerPair* pairs, PxU32 count)override
  168. {
  169. void (*func)(ActorInfo &trigger, ActorInfo &actor, PHYS_CONTACT contact)=Physics._report_trigger; // assign to temporary variable in order to avoid multi-threading issues
  170. if(func)FREP(count)
  171. {
  172. C PxTriggerPair &pair=pairs[i];
  173. if(!(pair.flags&(PxTriggerPairFlag::eREMOVED_SHAPE_TRIGGER | PxTriggerPairFlag::eREMOVED_SHAPE_OTHER))) // if both still exist
  174. {
  175. PHYS_CONTACT contact;
  176. if(pair.status&PxPairFlag::eNOTIFY_TOUCH_LOST )contact=CONTACT_LOST;else
  177. if(pair.status&PxPairFlag::eNOTIFY_TOUCH_FOUND)contact=CONTACT_NEW ;else
  178. contact=CONTACT_KEEP;
  179. ActorInfo trigger, actor; trigger.set(pair.triggerShape); actor.set(pair.otherShape); func(trigger, actor, contact);
  180. }
  181. }
  182. }
  183. }EventCallback;
  184. /******************************************************************************/
  185. #else // BULLET
  186. /******************************************************************************/
  187. static struct OverlapFilterCallbackClass : btOverlapFilterCallback
  188. {
  189. virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1)const override
  190. {
  191. return Physics.collides(proxy0->m_collisionFilterGroup, proxy1->m_collisionFilterGroup);
  192. }
  193. }OverlapFilterCallback;
  194. STRUCT(CollisionDispatcher , btCollisionDispatcher)
  195. //{
  196. bool needsCollision(btCollisionObject* body0, btCollisionObject* body1)
  197. {
  198. if(super::needsCollision(body0, body1))
  199. {
  200. // test pair<->pair
  201. if(RigidBody *rb=(RigidBody*)body0->getUserPointer())if(rb->ignore.has(body1))return false;
  202. return true;
  203. }
  204. return false;
  205. }
  206. CollisionDispatcher(btCollisionConfiguration* collisionConfiguration) : btCollisionDispatcher(collisionConfiguration) {}
  207. };
  208. /******************************************************************************/
  209. #endif
  210. /******************************************************************************/
  211. // PHYSICS
  212. /******************************************************************************/
  213. #if PHYSX
  214. ASSERT(SIZE(Quaternion)==SIZE(PxQuat));
  215. ASSERT(SIZE(Matrix3 )==SIZE(PxMat33));
  216. Matrix3 PhysxClass::orn(C PxQuat &quat)
  217. {
  218. Quaternion q; q.set(quat.x, quat.y, quat.z, -quat.w); return q;
  219. }
  220. Matrix3 PhysxClass::orn(C PxMat33 &mat)
  221. {
  222. return (Matrix3&)mat;
  223. }
  224. PxQuat PhysxClass::orn(C Matrix3 &matrix)
  225. {
  226. PxQuat q; (Quaternion&)q=matrix;
  227. CHS(q.w);
  228. return q;
  229. }
  230. Matrix PhysxClass::matrix(C PxTransform &t)
  231. {
  232. Matrix m; m.pos.set(t.p.x, t.p.y, t.p.z);
  233. Quaternion q; q. set(t.q.x, t.q.y, t.q.z, -t.q.w); m.orn()=q;
  234. return m;
  235. }
  236. PxTransform PhysxClass::matrix(C Matrix &matrix)
  237. {
  238. PxTransform t;
  239. t.p.x=matrix.pos.x;
  240. t.p.y=matrix.pos.y;
  241. t.p.z=matrix.pos.z;
  242. (Quaternion&)t.q=matrix;
  243. CHS(t.q.w);
  244. return t;
  245. }
  246. #else // BULLET
  247. Matrix3 BulletClass::matrix(C btMatrix3x3 &t)
  248. {
  249. Matrix3 m;
  250. m.x=vec(t.getColumn(0));
  251. m.y=vec(t.getColumn(1));
  252. m.z=vec(t.getColumn(2));
  253. return m;
  254. }
  255. Matrix BulletClass::matrix(C btTransform &t)
  256. {
  257. Matrix m;
  258. m.pos=vec(t.getOrigin());
  259. m.x =vec(t.getBasis ().getColumn(0));
  260. m.y =vec(t.getBasis ().getColumn(1));
  261. m.z =vec(t.getBasis ().getColumn(2));
  262. return m;
  263. }
  264. btMatrix3x3 BulletClass::matrix(C Matrix3 &m)
  265. {
  266. btMatrix3x3 t;
  267. t.setValue(m.x.x, m.y.x, m.z.x,
  268. m.x.y, m.y.y, m.z.y,
  269. m.x.z, m.y.z, m.z.z);
  270. return t;
  271. }
  272. btTransform BulletClass::matrix(C Matrix &m)
  273. {
  274. btTransform t;
  275. t.getOrigin()=vec(m.pos);
  276. t.getBasis ().setValue(m.x.x, m.y.x, m.z.x,
  277. m.x.y, m.y.y, m.z.y,
  278. m.x.z, m.y.z, m.z.z);
  279. return t;
  280. }
  281. #endif
  282. /******************************************************************************/
  283. /*PhysicsClass& PhysicsClass::filter(Bool on)
  284. {
  285. if(Physx.world)
  286. {
  287. Physx.world->setFilterOps (NX_FILTEROP_OR, NX_FILTEROP_OR, NX_FILTEROP_AND);
  288. Physx.world->setFilterBool(true);
  289. NxGroupsMask mask; mask.bits0=mask.bits1=mask.bits2=mask.bits3=!on;
  290. Physx.world->setFilterConstant0(mask);
  291. Physx.world->setFilterConstant1(mask);
  292. }
  293. return T;
  294. }*/
  295. UInt PhysicsClass::collisionGroups(Byte group)C
  296. {
  297. return InRange(group, AG_NUM) ? _collision_array[group] : 0;
  298. }
  299. PhysicsClass& PhysicsClass::ignore(Int group_a, Int group_b, Bool ignore)
  300. {
  301. if(created() && InRange(group_a, AG_NUM) && InRange(group_b, AG_NUM))
  302. {
  303. FlagSet(_collision_array[group_a], 1<<group_b, !ignore);
  304. FlagSet(_collision_array[group_b], 1<<group_a, !ignore);
  305. }
  306. return T;
  307. }
  308. PhysicsClass& PhysicsClass::reportContact(Int group_a, Int group_b, Bool report)
  309. {
  310. #if PHYSX
  311. if(created() && InRange(group_a, AG_NUM) && InRange(group_b, AG_NUM))
  312. {
  313. _contact_report[group_a][group_b]=report;
  314. _contact_report[group_b][group_a]=report;
  315. }
  316. #endif
  317. return T;
  318. }
  319. PhysicsClass& PhysicsClass::reportContact(void (*ReportContact)(ActorInfo &actor_a, ActorInfo &actor_b, C PhysContact *contact, Int contacts))
  320. {
  321. T._report_contact=ReportContact;
  322. return T;
  323. }
  324. PhysicsClass& PhysicsClass::reportTrigger(void (*ReportTrigger)(ActorInfo &trigger, ActorInfo &actor, PHYS_CONTACT contact))
  325. {
  326. T._report_trigger=ReportTrigger;
  327. return T;
  328. }
  329. PhysicsClass& PhysicsClass::wheelFriction(Flt (*WheelFriction)(C PhysMtrl &ground_material, C PhysMtrl &wheel_material, C ActorInfo &vehicle, WHEEL_TYPE wheel))
  330. {
  331. T._wheel_friction=(WheelFriction ? WheelFriction : ::WheelFriction);
  332. return T;
  333. }
  334. PhysicsClass& PhysicsClass::dominance(Int dominance_group_a, Int dominance_group_b, Bool a_factor, Bool b_factor)
  335. {
  336. #if PHYSX
  337. if(Physx.world)
  338. {
  339. PxDominanceGroupPair cd(a_factor, b_factor);
  340. Physx.world->setDominanceGroupPair(dominance_group_a, dominance_group_b, cd);
  341. }
  342. #endif
  343. return T;
  344. }
  345. /******************************************************************************/
  346. #if !PHYSX
  347. static Flt joint_impulse_scale;
  348. #endif
  349. PhysicsClass& PhysicsClass::startSimulation(Flt dt)
  350. {
  351. if(!_simulated && created())
  352. {
  353. _simulated =true;
  354. _new_updated =false;
  355. _new_updated_time =0;
  356. _step_time =0;
  357. _new_cpu_time =0;
  358. _accumulated_time+=Max(0, dt); if(_accumulated_time>EPS)
  359. {
  360. const Int max_steps=16;
  361. Dbl time=Time.curTime();
  362. WriteLock lock(_rws);
  363. #if PHYSX
  364. if(timestep()==PHYS_TIMESTEP_ROUND)
  365. {
  366. if(_step_left=Trunc(_accumulated_time/_prec_time))
  367. {
  368. if(_step_left<=max_steps)
  369. {
  370. _step_time =_prec_time;
  371. _new_updated_time =_prec_time*_step_left;
  372. _accumulated_time-=_new_updated_time;
  373. }else
  374. {
  375. _new_updated_time=_accumulated_time;
  376. _step_left = max_steps;
  377. _step_time =_new_updated_time/_step_left;
  378. _accumulated_time=0;
  379. }
  380. }
  381. }else // PHYS_TIMESTEP_VARIABLE
  382. {
  383. _step_left = Mid(RoundPos(_accumulated_time/_prec_time), 1, max_steps);
  384. _step_time =_accumulated_time/_step_left;
  385. _new_updated_time=_accumulated_time;
  386. _accumulated_time=0;
  387. }
  388. if(_step_left){_step_left--; _new_updated=true; Physx.world->simulate(_step_time);}
  389. #else
  390. // remember that calling 'stepSimulation' will internally call '*StepCompleted' functions
  391. if(timestep()==PHYS_TIMESTEP_ROUND)
  392. {
  393. _step_time =_prec_time; // have to set before 'stepSimulation' because it will use 'stepCompleted' callback inside which this is going to be accessed
  394. Int steps=Bullet.world->stepSimulation(_accumulated_time, max_steps, _prec_time); // number of steps processed in this update
  395. _new_updated =(steps>0); // if the number of steps is >0 then it means we've updated physics in this update
  396. _new_updated_time= steps*_prec_time; // actual physics update time is the number of steps * step duration
  397. }else // PHYS_TIMESTEP_VARIABLE
  398. {
  399. Int steps=Mid(RoundPos(_accumulated_time/_prec_time), 1, max_steps); // number of steps in which we want to update physics
  400. _step_time =_accumulated_time/steps; // have to set before 'stepSimulation' because it will use 'stepCompleted' callback inside which this is going to be accessed
  401. Bullet.world->stepSimulation(_accumulated_time, steps, _accumulated_time/(steps+EPSD)); // +EPSD is to make sure Bullet will calculate 'steps' steps when dividing 'dt' by "dt/(steps+EPSD)"
  402. _new_updated = true ; // in variable mode we always update physics
  403. _new_updated_time=_accumulated_time; // always by the total of 'dt' time
  404. }
  405. joint_impulse_scale=Sqrt(_step_time/_accumulated_time)/PI; // Sqrt(fixedTimeStep/timeStep), div by PI to match PhysX scale
  406. _accumulated_time=0; // everything was pushed to Bullet counter
  407. #endif
  408. _new_cpu_time=Time.curTime()-time;
  409. }
  410. }
  411. return T;
  412. }
  413. void PhysicsClass::stepCompleted()
  414. {
  415. // set current 'time' to 'stepTime' as we may access it in vehicles update or custom step callback
  416. _time=stepTime();
  417. // first update vehicles
  418. #if SUPPORT_PHYSX_VEHICLE
  419. Physx.updateVehicles();
  420. #endif
  421. REPAO(_vehicles)->update();
  422. if(void (*step)()=simulation_step_completed)step(); // call custom callback if specified, copy to temp var to avoid multi-threaded issues
  423. // revert the time to the last update time, we have to do it, because on PhysX we may call 'stepCompleted' multiple times across the entire frame (update and draw), and when outside 'stepCompleted' we always want to refer to the last update total time
  424. _time=_last_updated_time;
  425. }
  426. void PhysicsClass::step()
  427. {
  428. #if PHYSX
  429. // TODO: alternatively "SnippetStepper" tutorial from PhysX SDK could be used, however it's possible it would execute codes on secondary threads
  430. if(_step_left>0)
  431. {
  432. WriteLock lock(_rws);
  433. if(_step_left>0 && Physx.world)
  434. if(Physx.world->checkResults(false)) // check if results are ready, don't block
  435. {
  436. Dbl time=Time.curTime();
  437. Physx.world->fetchResults(true);
  438. stepCompleted();
  439. Physx.world->simulate(_step_time);
  440. _step_left--;
  441. _new_cpu_time+=Time.curTime()-time;
  442. }
  443. }
  444. #endif
  445. }
  446. PhysicsClass& PhysicsClass::stopSimulation()
  447. {
  448. if(_simulated)
  449. {
  450. if(_new_updated)
  451. {
  452. Dbl time=Time.curTime();
  453. WriteLock lock(_rws);
  454. #if PHYSX
  455. for(; _step_left>0; _step_left--) // process all steps that are left
  456. {
  457. Physx.world->fetchResults(true);
  458. stepCompleted();
  459. Physx.world->simulate(_step_time);
  460. }
  461. Physx.world->fetchResults(true);
  462. stepCompleted();
  463. #else
  464. REPA(Bullet.breakables)if(btTypedConstraint *joint=Bullet.breakables[i])
  465. {
  466. // Warning: 'getAppliedImpulse' sometimes returns values too big TODO: investigate if it depends on steps/times or is it a bug in Bullet, or should this be called in 'stepCompleted'?
  467. Int force =joint->getUserConstraintId();
  468. Flt impulse=joint->getAppliedImpulse()*joint_impulse_scale; joint->internalSetAppliedImpulse(0);
  469. if(btRigidBody *rb0=&joint->getRigidBodyA())impulse/=rb0->getInvMass();
  470. if(Abs(impulse)>=(Flt&)force)
  471. {
  472. joint->setUserConstraintType(1); // Joint.broken
  473. joint->enableFeedback(false);
  474. Bullet.breakables.remove(i);
  475. Bullet.world->removeConstraint(joint);
  476. }
  477. }
  478. #endif
  479. _new_cpu_time+=Time.curTime()-time;
  480. _update_count++;
  481. }
  482. _last_updated =_updated;
  483. _last_updated_time=_updated_time;
  484. _updated =_new_updated;
  485. _time=_updated_time=_new_updated_time;
  486. _cpu_time=_new_cpu_time;
  487. _simulated=false;
  488. }
  489. return T;
  490. }
  491. /******************************************************************************/
  492. Bool PhysicsClass::createMaterials()
  493. {
  494. WriteLock lock(_rws);
  495. mtrl_default .create().bounciness(0.3f).frictionStatic(1.2f).frictionDynamic(1.0f);
  496. //mtrl_grass .create().bounciness(0.0f).frictionStatic(0.0f).frictionDynamic(0.0f);
  497. //mtrl_ice .create().bounciness(1.0f).frictionStatic(0.0f).frictionDynamic(0.0f);
  498. //mtrl_mud .create().bounciness(0.0f).frictionStatic(3.0f).frictionDynamic(1.0f);
  499. mtrl_ctrl .create().bounciness(0).bouncinessMode(PhysMtrl::MODE_MUL).anisotropicDir(Vec(0, 1, 0));
  500. mtrl_ctrl_stop.create().bounciness(0).bouncinessMode(PhysMtrl::MODE_MUL).frictionMode(PhysMtrl::MODE_MAX);
  501. #if PHYSX
  502. if(_css==CSS_MATERIALS)
  503. {
  504. mtrl_ctrl.frictionStatic(0.0f).frictionDynamic(0.0f).frictionMode(PhysMtrl::MODE_MUL).frictionStaticA(2.5f).frictionDynamicA(0.0f).anisotropic(true);
  505. }else
  506. {
  507. mtrl_ctrl.frictionStatic(2.5f).frictionDynamic(2.5f).frictionStaticA(2.5f).frictionDynamicA(0.0f).anisotropic(true);
  508. }
  509. mtrl_ctrl_stop.frictionStatic(12).frictionDynamic(12);
  510. return mtrl_default._m!=null; // PhysX requires to have default material created (because of actor creation)
  511. #else
  512. if(_css==CSS_MATERIALS)
  513. {
  514. mtrl_ctrl.frictionStatic(0.0f).frictionDynamic(0.0f).frictionMode(PhysMtrl::MODE_MUL).frictionStaticA(2.5f).frictionDynamicA(0.0f).anisotropic(true);
  515. }else
  516. {
  517. mtrl_ctrl.frictionStatic(0.2f).frictionDynamic(0.2f).frictionStaticA(2.5f).frictionDynamicA(0.0f).anisotropic(true);
  518. }
  519. mtrl_ctrl_stop.frictionStatic(1.0f).frictionDynamic(1.0f);
  520. return true;
  521. #endif
  522. }
  523. /******************************************************************************/
  524. Bool PhysicsClass::ignored(PHYS_API(PxRigidActor, RigidBody) &a, PHYS_API(PxRigidActor, RigidBody) &b)
  525. {
  526. if(&a==&b)return true; // collisions are always ignored between the same actor (this is needed for Controller tests)
  527. #if PHYSX
  528. PxShape *as, *bs;
  529. if(a.getShapes(&as, 1))if(UInt ai=as->getSimulationFilterData().word1)
  530. if(b.getShapes(&bs, 1))if(UInt bi=bs->getSimulationFilterData().word1)return FlagTest(Physx.ignoreMap(ai, bi), 1<<(bi&7));
  531. return false;
  532. #else
  533. return a.ignore.has(&b);
  534. #endif
  535. }
  536. /******************************************************************************/
  537. PHYS_ENGINE PhysicsClass::engine()C
  538. {
  539. #if PHYSX
  540. return PHYS_ENGINE_PHYSX;
  541. #else
  542. return PHYS_ENGINE_BULLET;
  543. #endif
  544. }
  545. PhysicsClass::PhysicsClass()
  546. {
  547. simulation_step_completed=null;
  548. _hw=_updated=_new_updated=_last_updated=false; Zero(_contact_report);
  549. _simulated=0;
  550. _precision=_actual_precision=_step_left=0;
  551. _update_count=0; Zero(_collision_array);
  552. _skin=_cpu_time=_new_cpu_time=_updated_time=_new_updated_time=_last_updated_time=_prec_time=_accumulated_time=_step_time=_time=0;
  553. _gravity.zero();
  554. _css=CSS_NONE;
  555. _timestep=PHYS_TIMESTEP_ROUND;
  556. _report_contact=null;
  557. _report_trigger=null;
  558. _wheel_friction=null;
  559. }
  560. Bool PhysicsClass::created()C {return PHYS_API(Physx, Bullet).world!=null;}
  561. void PhysicsClass::del ()
  562. {
  563. SafeWriteLock lock(_rws);
  564. stopSimulation();
  565. #if PHYSX
  566. Physx.del();
  567. #else
  568. Bullet.del();
  569. #endif
  570. PhysBodies.del();
  571. PhysMtrls .del(); mtrl_default.del(); mtrl_ctrl.del(); mtrl_ctrl_stop.del();
  572. _gravity .zero();
  573. _vehicles.del();
  574. }
  575. Bool PhysicsClass::createTry(C Str &physx_dll_path, CONTROLLER_SLOPE_SLIDING_MODE css, Bool hardware)
  576. {
  577. if(created())return true;
  578. WriteLock lock(_rws);
  579. T._css =css;
  580. T._timestep =PHYS_TIMESTEP_ROUND;
  581. T._precision =T._actual_precision=60; T._prec_time=1.0f/_actual_precision;
  582. T._hw =false;
  583. T._wheel_friction=WheelFriction;
  584. T.ctrl_ground_group_force =0;
  585. T.ctrl_ground_group_allow =~IndexToFlag(AG_CONTROLLER);
  586. T.ctrl_slide_group_horizontal= IndexToFlag(AG_CONTROLLER);
  587. T.ctrl_ground_slope = 0.65f;
  588. #if PHYSX
  589. if(Physx.create(physx_dll_path, hardware))
  590. #else
  591. if(Bullet.create())
  592. #endif
  593. {
  594. skin(0.005f);
  595. gravity(Vec(0, -9.8f, 0));
  596. REPAO(_collision_array)=~0;
  597. Zero (_contact_report );
  598. if(createMaterials())return true;
  599. }
  600. del(); return false;
  601. }
  602. PhysicsClass& PhysicsClass::create(C Str &physx_dll_path, CONTROLLER_SLOPE_SLIDING_MODE css, Bool hardware)
  603. {
  604. if(!createTry(physx_dll_path, css, hardware))
  605. Exit("Can't initialize physics."
  606. #if WINDOWS
  607. "\nPlease make sure you have PhysX DLL files in the path specified in 'Physics.create' method."
  608. #elif LINUX
  609. "\nPlease make sure you have PhysX SO files in the application's \"Bin\" folder."
  610. #endif
  611. );
  612. return T;
  613. }
  614. /******************************************************************************/
  615. #if PHYSX
  616. /******************************************************************************/
  617. void PhysxClass::del()
  618. {
  619. #if SUPPORT_PHYSX_VEHICLE
  620. if(world )PxCloseVehicleSDK();
  621. if(batch_query_4){batch_query_4->release(); batch_query_4=null;}
  622. vehicles.del();
  623. #endif
  624. if(world ){world ->release(); world =null;}
  625. #if USE_DEFAULT_CPU_DISPATCHER
  626. if(CpuDispatcher){CpuDispatcher->release(); CpuDispatcher=null;}
  627. #else
  628. CpuDispatcher. del ();
  629. #endif
  630. if(cook[1] ){cook[1] ->release(); cook[1] =null;}
  631. if(cook[0] ){cook[0] ->release(); cook[0] =null;}
  632. if(physics ){physics ->release(); physics =null;}
  633. if(foundation ){foundation ->release(); foundation =null;}
  634. ignore_map .del();
  635. #if PHYSX_DLL_ACTUAL
  636. raycast=null;
  637. PhysXCooking .del();
  638. PhysX3 .del();
  639. PhysXCommon .delForce(); // PhysX has some bug, that it doesn't release the common DLL after interface creation, however we do need to release it in case we're deleting/updating DLL files (for example installer/patcher) TODO: test if this is still needed
  640. PhysXFoundation.del();
  641. #endif
  642. }
  643. Bool PhysxClass::create(Str dll_path, Bool hardware)
  644. {
  645. Bool ok=false;
  646. #if PHYSX_DLL_ACTUAL
  647. #if WINDOWS
  648. dll_path.tailSlash(true);
  649. #if X64
  650. if(PhysXFoundation.createFile(dll_path+"PxFoundation_x64.dll" ))
  651. if(PhysXCommon .createFile(dll_path+"PhysX3Common_x64.dll" ))
  652. if(PhysX3 .createFile(dll_path+"PhysX3_x64.dll" ))
  653. if(PhysXCooking .createFile(dll_path+"PhysX3Cooking_x64.dll"))
  654. if(raycast=PhysXCommon.getFunc("?raycast@PxGeometryQuery@physx@@SAIAEBVPxVec3@2@0AEBVPxGeometry@2@AEBVPxTransform@2@MV?$PxFlags@W4Enum@PxHitFlag@physx@@G@2@IPEIAUPxRaycastHit@2@@Z"))
  655. #else
  656. if(PhysXFoundation.createFile(dll_path+"PxFoundation_x86.dll" ))
  657. if(PhysXCommon .createFile(dll_path+"PhysX3Common_x86.dll" ))
  658. if(PhysX3 .createFile(dll_path+"PhysX3_x86.dll" ))
  659. if(PhysXCooking .createFile(dll_path+"PhysX3Cooking_x86.dll"))
  660. if(raycast=PhysXCommon.getFunc("?raycast@PxGeometryQuery@physx@@SAIABVPxVec3@2@0ABVPxGeometry@2@ABVPxTransform@2@MV?$PxFlags@W4Enum@PxHitFlag@physx@@G@2@IPIAUPxRaycastHit@2@@Z"))
  661. #endif
  662. #elif LINUX // Warning: because of Linux poor DLL search path mechanism, the paths are hardcoded as "Bin" in project settings, therefore we must ignore the 'dll_path' path here
  663. #if X64
  664. if(PhysXFoundation.createFile("libPxFoundation_x64.so" ))
  665. if(PhysXCommon .createFile("libPhysX3Common_x64.so" ))
  666. if(PhysX3 .createFile("libPhysX3_x64.so" )) // warning: this file requires "libPhysX3Common_x64.so" and it will fail, unless we specify "Runtime Search Directories" in NetBeans Project Settings
  667. if(PhysXCooking .createFile("libPhysX3Cooking_x64.so")) // warning: this file requires "libPhysX3Common_x64.so" and it will fail, unless we specify "Runtime Search Directories" in NetBeans Project Settings
  668. if(raycast=PhysXCommon.getFunc(fix me "_ZN5physx15PxGeometryQuery7raycastERKNS_6PxVec3ES3_RKNS_10PxGeometryERKNS_11PxTransformEfNS_7PxFlagsINS_9PxHitFlag4EnumEtEEjPNS_12PxRaycastHitEb")) // name extracted using Total Commander Hex Viewer (look for 'PxGeometryQuery' and copy everything from ' ' to ' ')
  669. #else
  670. if(PhysXFoundation.createFile("libPxFoundation_x86.so" ))
  671. if(PhysXCommon .createFile("libPhysX3Common_x86.so" ))
  672. if(PhysX3 .createFile("libPhysX3_x86.so" )) // warning: this file requires "libPhysX3Common_x86.so" and it will fail, unless we specify "Runtime Search Directories" in NetBeans Project Settings
  673. if(PhysXCooking .createFile("libPhysX3Cooking_x86.so")) // warning: this file requires "libPhysX3Common_x86.so" and it will fail, unless we specify "Runtime Search Directories" in NetBeans Project Settings
  674. if(raycast=PhysXCommon.getFunc(fix me))
  675. #endif
  676. #endif
  677. if(auto _PxCreateFoundation =(decltype(&PxCreateFoundation ))PhysXFoundation.getFunc("PxCreateFoundation"))
  678. #define PxCreateFoundation _PxCreateFoundation
  679. if(auto _PxCreateBasePhysics=(decltype(&PxCreateBasePhysics))PhysX3 .getFunc("PxCreateBasePhysics"))
  680. #define PxCreateBasePhysics _PxCreateBasePhysics
  681. if(auto _PxCreateCooking =(decltype(&PxCreateCooking ))PhysXCooking .getFunc("PxCreateCooking"))
  682. #define PxCreateCooking _PxCreateCooking
  683. if(auto _PxRegisterCloth =(decltype(&PxRegisterCloth ))PhysX3 .getFunc("PxRegisterCloth"))
  684. #define PxRegisterCloth _PxRegisterCloth
  685. if(auto _PxRegisterParticles=(decltype(&PxRegisterParticles))PhysX3 .getFunc("PxRegisterParticles"))
  686. #define PxRegisterParticles _PxRegisterParticles
  687. #endif
  688. if(foundation=PxCreateFoundation (PX_FOUNDATION_VERSION, allocator, ErrorCallback))
  689. if(physics =PxCreateBasePhysics(PX_PHYSICS_VERSION , *foundation, PxTolerancesScale(), false, null))
  690. {
  691. PxCookingParams cook_params(physics->getTolerancesScale());
  692. cook_params.suppressTriangleMeshRemapTable=true; // disable remap
  693. if(cook[0]=PxCreateCooking(PX_PHYSICS_VERSION, *foundation, cook_params))
  694. {
  695. cook_params.suppressTriangleMeshRemapTable=false; // enable remap
  696. if(cook[1]=PxCreateCooking(PX_PHYSICS_VERSION, *foundation, cook_params))
  697. {
  698. PxRegisterCloth (*physics);
  699. PxRegisterParticles(*physics);
  700. PxSceneDesc scene_desc(physics->getTolerancesScale());
  701. scene_desc.flags|=PxSceneFlag::eENABLE_CCD;
  702. #if USE_DEFAULT_CPU_DISPATCHER
  703. if(!scene_desc.cpuDispatcher)scene_desc.cpuDispatcher=CpuDispatcher=PxDefaultCpuDispatcherCreate(Max(0, Cpu.threads()-1)); // leave 1 thread for the main update
  704. #else
  705. if(!scene_desc.cpuDispatcher)scene_desc.cpuDispatcher=&CpuDispatcher.create();
  706. #endif
  707. scene_desc.filterShader=FilterFunc;
  708. scene_desc.simulationEventCallback=&EventCallback;
  709. if(scene_desc.isValid())
  710. if(world=physics->createScene(scene_desc))
  711. {
  712. ignore_map.setNumZero(MAX_ACTOR_IGNORE*Ceil8(MAX_ACTOR_IGNORE)/8); // y's are bit-packed (8-bits per byte)
  713. ignore_id_gen.New(); // create 0 at start because "0" is a special case for turned off
  714. #if SUPPORT_PHYSX_VEHICLE
  715. vehicle_id_gen.New(); // create 0 at start because "0" is a special case for empty
  716. PxInitVehicleSDK(*physics);
  717. MeshBase mesh; mesh.create(Tube(1.0f, 1.0f, VecZero, Vec(1,0,0)), 0, 8); if(wheel_mesh.createConvexTry(mesh))
  718. {
  719. PxBatchQueryDesc desc(Elms(raycast_query_result), 0, 0);
  720. desc.queryMemory.userRaycastResultBuffer=raycast_query_result;
  721. desc.queryMemory.userRaycastTouchBuffer =raycast_hit;
  722. desc.queryMemory.raycastTouchBufferSize =Elms(raycast_hit);
  723. desc.preFilterShader=VehicleWheelRaycastFilterFunc;
  724. if(batch_query_4=world->createBatchQuery(desc))
  725. {
  726. // ok
  727. }
  728. }
  729. #endif
  730. ok=true;
  731. }
  732. }
  733. }
  734. }
  735. if(!ok)del(); return ok;
  736. }
  737. /******************************************************************************/
  738. #else // BULLET
  739. /******************************************************************************/
  740. static Ptr BulletAlloc(size_t size) {return Alloc(size);}
  741. static void BulletFree (Ptr data) {return Free (data);}
  742. void BulletClass::del()
  743. {
  744. if(world)
  745. {
  746. REP(world->getNumConstraints ())world->removeConstraint(world->getConstraint(i));
  747. REP(world->getNumCollisionObjects())
  748. {
  749. if(btCollisionObject *obj=world->getCollisionObjectArray()[i])
  750. {
  751. if(btRigidBody *body=CAST(btRigidBody, obj))if(btMotionState *motion=body->getMotionState())Delete(motion);
  752. world->removeCollisionObject(obj);
  753. }
  754. }
  755. }
  756. Delete(world);
  757. Delete(solver);
  758. Delete(broadphase);
  759. Delete(dispatcher);
  760. Delete(collision_config);
  761. }
  762. static bool MaterialCallback(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1)
  763. {
  764. if(RigidBody *rb0=(RigidBody*)colObj0Wrap->m_collisionObject->getUserPointer())
  765. if(RigidBody *rb1=(RigidBody*)colObj1Wrap->m_collisionObject->getUserPointer())
  766. {
  767. /*// set 'rb0' as dynamic object with biggest mass (most significant dynamic object)
  768. if(!rb1->isStaticOrKinematicObject())
  769. if(rb0->isStaticOrKinematicObject() || rb1->getInvMass()<rb0->getInvMass)
  770. Swap(rb0, rb1);*/
  771. switch(rb0->material->bouncinessMode())
  772. {
  773. case PhysMtrl::MODE_AVG: cp.m_combinedRestitution=Avg(rb0->getRestitution(), rb1->getRestitution()); break;
  774. case PhysMtrl::MODE_MUL: cp.m_combinedRestitution= (rb0->getRestitution()* rb1->getRestitution()); break;
  775. case PhysMtrl::MODE_MIN: cp.m_combinedRestitution=Min(rb0->getRestitution(), rb1->getRestitution()); break;
  776. case PhysMtrl::MODE_MAX: cp.m_combinedRestitution=Max(rb0->getRestitution(), rb1->getRestitution()); break;
  777. }
  778. switch(rb0->material->frictionMode())
  779. {
  780. case PhysMtrl::MODE_AVG: cp.m_combinedFriction=2*Avg(rb0->getFriction(), rb1->getFriction()); break; // 2* to match PhysX scale
  781. case PhysMtrl::MODE_MUL: cp.m_combinedFriction=2* (rb0->getFriction()* rb1->getFriction()); break; // 2* to match PhysX scale
  782. case PhysMtrl::MODE_MIN: cp.m_combinedFriction=2*Min(rb0->getFriction(), rb1->getFriction()); break; // 2* to match PhysX scale
  783. case PhysMtrl::MODE_MAX: cp.m_combinedFriction=2*Max(rb0->getFriction(), rb1->getFriction()); break; // 2* to match PhysX scale
  784. }
  785. }
  786. return true;
  787. }
  788. static void BulletStepCompleted(btDynamicsWorld *world, btScalar timeStep) {Physics.stepCompleted();}
  789. Bool BulletClass::create()
  790. {
  791. btAlignedAllocSetCustom(BulletAlloc, BulletFree);
  792. collision_config=new btDefaultCollisionConfiguration();
  793. dispatcher =new CollisionDispatcher(collision_config);
  794. broadphase =new btDbvtBroadphase();
  795. solver =new btSequentialImpulseConstraintSolver;
  796. world =new btDiscreteDynamicsWorld(dispatcher, broadphase, solver, collision_config);
  797. gDeactivationTime=1;
  798. gContactAddedCallback=MaterialCallback;
  799. world->getPairCache()->setOverlapFilterCallback(&OverlapFilterCallback);
  800. world->setForceUpdateAllAabbs(false); // because of this call, changing pos/orn/matrix of inactive actors must be followed by 'updateSingleAabb'
  801. world->setInternalTickCallback(BulletStepCompleted);
  802. return true;
  803. }
  804. #endif
  805. /******************************************************************************/
  806. #if PHYSX
  807. PhysicsClass& PhysicsClass::skin ( Flt skin ) {if( Physx.world){T._skin =Max(0, skin); } return T;}
  808. PhysicsClass& PhysicsClass::gravity(C Vec &gravity) {if(T._gravity!=gravity && Physx.world){T._gravity=gravity ; Physx.world->setGravity(Physx.vec(T._gravity));} return T;}
  809. #else
  810. PhysicsClass& PhysicsClass::skin ( Flt skin ) {if( Bullet.world){T._skin =Max(0, skin); } return T;}
  811. PhysicsClass& PhysicsClass::gravity(C Vec &gravity) {if(T._gravity!=gravity && Bullet.world){T._gravity=gravity ; Bullet.world->setGravity(Bullet.vec(T._gravity));} return T;}
  812. #endif
  813. /******************************************************************************/
  814. PhysicsClass& PhysicsClass::timestep(PHYS_TIMESTEP_MODE mode)
  815. {
  816. Clamp(mode, PHYS_TIMESTEP_MODE(0), PHYS_TIMESTEP_MODE(PHYS_TIMESTEP_NUM-1));
  817. if(created())_timestep=mode;
  818. return T;
  819. }
  820. /******************************************************************************/
  821. PhysicsClass& PhysicsClass::precision(Int steps_ps)
  822. {
  823. if(created())
  824. {
  825. MAX(steps_ps, 0); T._precision=steps_ps;
  826. if(!steps_ps)
  827. {
  828. steps_ps=D.freq();
  829. if(!steps_ps)steps_ps=60;
  830. }
  831. if(steps_ps!=T._actual_precision)
  832. {
  833. T._actual_precision=steps_ps;
  834. T._prec_time =1.0f/_actual_precision;
  835. }
  836. }
  837. return T;
  838. }
  839. Int PhysicsClass::actorShapes()C
  840. {
  841. #if PHYSX
  842. if(Physx.world)return Physx.world->getNbActors(PxActorTypeFlag::eRIGID_STATIC | PxActorTypeFlag::eRIGID_DYNAMIC);
  843. #else
  844. if(Bullet.world)return Bullet.world->getNumCollisionObjects();
  845. #endif
  846. return 0;
  847. }
  848. /******************************************************************************/
  849. }
  850. /******************************************************************************/