physics_world.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. ///if arm_physics
  2. type physics_world_t = {
  3. world?: Ammo.btDiscreteDynamicsWorld;
  4. dispatcher?: Ammo.btCollisionDispatcher;
  5. contacts?: pair_t[];
  6. body_map?: map_t<i32, physics_body_t>;
  7. time_scale?: f32;
  8. time_step?: f32;
  9. max_steps?: i32;
  10. };
  11. let physics_world_active: physics_world_t = null;
  12. let physics_world_vec1: Ammo.btVector3 = null;
  13. let physics_world_vec2: Ammo.btVector3 = null;
  14. let physics_world_v1: vec4_t = vec4_create();
  15. let physics_world_v2: vec4_t = vec4_create();
  16. function physics_world_load(done: ()=>void) {
  17. let b: buffer_t = krom_load_blob("data/plugins/ammo.js");
  18. js_eval(sys_buffer_to_string(b));
  19. let print: (s: string)=>void = function (s: string) {
  20. krom_log(s);
  21. };
  22. Ammo({print: print}).then(done);
  23. }
  24. function physics_world_create(): physics_world_t {
  25. let pw: physics_world_t = {};
  26. pw.contacts = [];
  27. pw.body_map = map_create();
  28. pw.time_scale = 1.0;
  29. pw.time_step = 1 / 60;
  30. pw.max_steps = 1;
  31. physics_world_active = pw;
  32. physics_world_vec1 = new Ammo.btVector3(0, 0, 0);
  33. physics_world_vec2 = new Ammo.btVector3(0, 0, 0);
  34. physics_world_init(pw);
  35. return pw;
  36. }
  37. function physics_world_reset(pw: physics_world_t) {
  38. let keys: string[] = map_keys(pw.body_map);
  39. for (let i: i32 = 0; i < keys.length; ++i) {
  40. let body: physics_body_t = map_get(pw.body_map, keys[i]);
  41. physics_world_remove_body(pw, body);
  42. }
  43. }
  44. function physics_world_init(pw: physics_world_t) {
  45. let broadphase: Ammo.btDbvtBroadphase = new Ammo.btDbvtBroadphase();
  46. let collision_conf: Ammo.btDefaultCollisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
  47. pw.dispatcher = new Ammo.btCollisionDispatcher(collision_conf);
  48. let solver: Ammo.btSequentialImpulseConstraintSolver = new Ammo.btSequentialImpulseConstraintSolver();
  49. pw.world = new Ammo.btDiscreteDynamicsWorld(pw.dispatcher, broadphase, solver, collision_conf);
  50. physics_world_set_gravity(pw, vec4_create(0, 0, -9.81));
  51. }
  52. function physics_world_set_gravity(pw: physics_world_t, v: vec4_t) {
  53. physics_world_vec1.setValue(v.x, v.y, v.z);
  54. pw.world.setGravity(physics_world_vec1);
  55. }
  56. function physics_world_add_body(pw: physics_world_t, pb: physics_body_t) {
  57. pw.world.addRigidBody(pb.body, pb.group, pb.mask);
  58. map_set(pw.body_map, pb.id, pb);
  59. }
  60. function physics_world_remove_body(pw: physics_world_t, pb: physics_body_t) {
  61. if (pb.destroyed) {
  62. return;
  63. }
  64. pb.destroyed = true;
  65. if (pw.world != null) {
  66. pw.world.removeRigidBody(pb.body);
  67. }
  68. map_delete(pw.body_map, pb.id);
  69. physics_body_delete(pb);
  70. }
  71. function physics_world_get_contacts(pw: physics_world_t, pb: physics_body_t): physics_body_t[] {
  72. if (pw.contacts.length == 0) {
  73. return null;
  74. }
  75. let res: physics_body_t[] = [];
  76. for (let i: i32 = 0; i < pw.contacts.length; ++i) {
  77. let c: pair_t = pw.contacts[i];
  78. let pb: physics_body_t = null;
  79. if (c.a == pb.body.userIndex) {
  80. pb = map_get(pw.body_map, c.b);
  81. }
  82. else if (c.b == pb.body.userIndex) {
  83. pb = map_get(pw.body_map, c.a);
  84. }
  85. if (pb != null && array_index_of(res, pb) == -1) {
  86. array_push(res, pb);
  87. }
  88. }
  89. return res;
  90. }
  91. function physics_world_get_contact_pairs(pw: physics_world_t, pb: physics_body_t): pair_t[] {
  92. if (pw.contacts.length == 0) {
  93. return null;
  94. }
  95. let res: pair_t[] = [];
  96. for (let i: i32 = 0; i < pw.contacts.length; ++i) {
  97. let c: pair_t = pw.contacts[i];
  98. if (c.a == pb.body.userIndex) {
  99. array_push(res, c);
  100. }
  101. else if (c.b == pb.body.userIndex) {
  102. array_push(res, c);
  103. }
  104. }
  105. return res;
  106. }
  107. function physics_world_late_update(pw: physics_world_t) {
  108. let t: f32 = time_delta() * pw.time_scale;
  109. if (t == 0.0) {
  110. return; // Simulation paused
  111. }
  112. pw.world.stepSimulation(pw.time_step, pw.max_steps, t);
  113. physics_world_update_contacts(pw);
  114. let keys: string[] = map_keys(pw.body_map);
  115. for (let i: i32 = 0; i < keys.length; ++i) {
  116. let body: physics_body_t = map_get(pw.body_map, keys[i]);
  117. physics_body_physics_update(body);
  118. }
  119. }
  120. function physics_world_update_contacts(pw: physics_world_t) {
  121. pw.contacts = [];
  122. let disp: Ammo.btDispatcher = pw.dispatcher;
  123. let num_manifolds: i32 = disp.getNumManifolds();
  124. for (let i: i32 = 0; i < num_manifolds; ++i) {
  125. let contact_manifold: Ammo.btPersistentManifold = disp.getManifoldByIndexInternal(i);
  126. let body0: Ammo.btRigidBody = Ammo.btRigidBody.prototype.upcast(contact_manifold.getBody0());
  127. let body1: Ammo.btRigidBody = Ammo.btRigidBody.prototype.upcast(contact_manifold.getBody1());
  128. let num_contacts: i32 = contact_manifold.getNumContacts();
  129. let pt: Ammo.btManifoldPoint = null;
  130. let pos_a: Ammo.btVector3 = null;
  131. let pos_b: Ammo.btVector3 = null;
  132. let nor: Ammo.btVector3 = null;
  133. for (let j: i32 = 0; j < num_contacts; ++j) {
  134. pt = contact_manifold.getContactPoint(j);
  135. pos_a = pt.get_m_positionWorldOnA();
  136. pos_b = pt.get_m_positionWorldOnB();
  137. nor = pt.get_m_normalWorldOnB();
  138. let cp: pair_t = {
  139. a: body0.userIndex,
  140. b: body1.userIndex,
  141. pos_a: vec4_create(pos_a.x(), pos_a.y(), pos_a.z()),
  142. pos_b: vec4_create(pos_b.x(), pos_b.y(), pos_b.z()),
  143. norm_on_b: vec4_create(nor.x(), nor.y(), nor.z()),
  144. impulse: pt.getAppliedImpulse(),
  145. distance: pt.getDistance()
  146. };
  147. array_push(pw.contacts, cp);
  148. }
  149. }
  150. }
  151. function physics_world_pick_closest(pw: physics_world_t, inputX: f32, inputY: f32): physics_body_t {
  152. let camera: camera_object_t = scene_camera;
  153. let start: vec4_t = vec4_create();
  154. let end: vec4_t = vec4_create();
  155. raycast_get_dir(start, end, inputX, inputY, camera);
  156. let hit: hit_t = physics_world_ray_cast(pw, mat4_get_loc(camera.base.transform.world), end);
  157. let body: physics_body_t = (hit != null) ? hit.body : null;
  158. return body;
  159. }
  160. function physics_world_ray_cast(pw: physics_world_t, from: vec4_t, to: vec4_t, group: i32 = 0x00000001, mask: i32 = 0xffffffff): hit_t {
  161. let ray_from: Ammo.btVector3 = physics_world_vec1;
  162. let ray_to: Ammo.btVector3 = physics_world_vec2;
  163. ray_from.setValue(from.x, from.y, from.z);
  164. ray_to.setValue(to.x, to.y, to.z);
  165. let ray_callback: Ammo.ClosestRayResultCallback = new Ammo.ClosestRayResultCallback(ray_from, ray_to);
  166. ray_callback.set_m_collisionFilterGroup(group);
  167. ray_callback.set_m_collisionFilterMask(mask);
  168. let world_dyn: Ammo.btDynamicsWorld = pw.world;
  169. let world_col: Ammo.btCollisionWorld = world_dyn;
  170. world_col.rayTest(ray_from, ray_to, ray_callback);
  171. let pb: physics_body_t = null;
  172. let hit_info: hit_t = null;
  173. let rc: Ammo.RayResultCallback = ray_callback;
  174. if (rc.hasHit()) {
  175. let co: Ammo.btCollisionObject = ray_callback.get_m_collisionObject();
  176. let body: Ammo.btRigidBody = Ammo.btRigidBody.prototype.upcast(co);
  177. let hit: Ammo.btVector3 = ray_callback.get_m_hitPointWorld();
  178. vec4_set(physics_world_v1, hit.x(), hit.y(), hit.z());
  179. let norm: Ammo.btVector3 = ray_callback.get_m_hitNormalWorld();
  180. vec4_set(physics_world_v2, norm.x(), norm.y(), norm.z());
  181. pb = map_get(pw.body_map, body.userIndex);
  182. hit_info = {
  183. body: pb,
  184. pos: physics_world_v1,
  185. normal: physics_world_v2
  186. };
  187. }
  188. Ammo.destroy(ray_callback);
  189. return hit_info;
  190. }
  191. type hit_t = {
  192. body?: physics_body_t;
  193. pos?: vec4_t;
  194. normal?: vec4_t;
  195. };
  196. type pair_t = {
  197. a?: i32;
  198. b?: i32;
  199. pos_a?: vec4_t;
  200. pos_b?: vec4_t;
  201. norm_on_b?: vec4_t;
  202. impulse?: f32;
  203. distance?: f32;
  204. };
  205. ///end