PhysicsWorld.hx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package arm.plugin;
  2. #if arm_physics
  3. import iron.system.Time;
  4. import iron.math.Vec4;
  5. import iron.math.RayCaster;
  6. @:access(arm.plugin.PhysicsBody)
  7. class PhysicsWorld extends iron.Trait {
  8. public static var active: PhysicsWorld = null;
  9. static var vec1: Bt.Vector3 = null;
  10. static var vec2: Bt.Vector3 = null;
  11. static var v1 = new iron.math.Vec4();
  12. static var v2 = new iron.math.Vec4();
  13. var world: Bt.DiscreteDynamicsWorld;
  14. var dispatcher: Bt.CollisionDispatcher;
  15. var contacts: Array<TPair> = [];
  16. var bodyMap = new Map<Int, PhysicsBody>();
  17. var timeScale = 1.0;
  18. var timeStep = 1 / 60;
  19. var maxSteps = 1;
  20. @:access(Main)
  21. public static function load(done: Void->Void) {
  22. var b = haxe.io.Bytes.ofData(Krom.loadBlob("data/plugins/ammo.wasm.js"));
  23. var print = function(s: String) { trace(s); };
  24. js.Syntax.code("(1, eval)({0})", b.toString());
  25. var instantiateWasm = function(imports, successCallback) {
  26. var wasmbin = Krom.loadBlob("data/plugins/ammo.wasm.wasm");
  27. var module = new js.lib.webassembly.Module(wasmbin);
  28. var inst = new js.lib.webassembly.Instance(module, imports);
  29. successCallback(inst);
  30. return inst.exports;
  31. };
  32. js.Syntax.code("Ammo({print: {0}, instantiateWasm: {1}}).then({2})", print, instantiateWasm, done);
  33. }
  34. public function new() {
  35. super();
  36. active = this;
  37. vec1 = new Bt.Vector3(0, 0, 0);
  38. vec2 = new Bt.Vector3(0, 0, 0);
  39. init();
  40. }
  41. public function reset() {
  42. for (body in bodyMap) removeBody(body);
  43. }
  44. function init() {
  45. var broadphase = new Bt.DbvtBroadphase();
  46. var collisionConfiguration = new Bt.DefaultCollisionConfiguration();
  47. dispatcher = new Bt.CollisionDispatcher(collisionConfiguration);
  48. var solver = new Bt.SequentialImpulseConstraintSolver();
  49. world = new Bt.DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
  50. setGravity(new Vec4(0, 0, -9.81));
  51. }
  52. public function setGravity(v: Vec4) {
  53. vec1.setValue(v.x, v.y, v.z);
  54. world.setGravity(vec1);
  55. }
  56. public function addBody(pb: PhysicsBody) {
  57. world.addRigidBodyToGroup(pb.body, pb.group, pb.mask);
  58. bodyMap.set(pb.id, pb);
  59. }
  60. public function removeBody(pb: PhysicsBody) {
  61. if (pb.destroyed) return;
  62. pb.destroyed = true;
  63. if (world != null) world.removeRigidBody(pb.body);
  64. bodyMap.remove(pb.id);
  65. pb.delete();
  66. }
  67. public function getContacts(pb: PhysicsBody): Array<PhysicsBody> {
  68. if (contacts.length == 0) return null;
  69. var res: Array<PhysicsBody> = [];
  70. for (i in 0...contacts.length) {
  71. var c = contacts[i];
  72. var pb: PhysicsBody = null;
  73. if (c.a == untyped pb.body.userIndex) pb = bodyMap.get(c.b);
  74. else if (c.b == untyped pb.body.userIndex) pb = bodyMap.get(c.a);
  75. if (pb != null && res.indexOf(pb) == -1) res.push(pb);
  76. }
  77. return res;
  78. }
  79. public function getContactPairs(pb: PhysicsBody): Array<TPair> {
  80. if (contacts.length == 0) return null;
  81. var res: Array<TPair> = [];
  82. for (i in 0...contacts.length) {
  83. var c = contacts[i];
  84. if (c.a == untyped pb.body.userIndex) res.push(c);
  85. else if (c.b == untyped pb.body.userIndex) res.push(c);
  86. }
  87. return res;
  88. }
  89. public function lateUpdate() {
  90. var t = Time.delta * timeScale;
  91. if (t == 0.0) return; // Simulation paused
  92. world.stepSimulation(timeStep, maxSteps, t);
  93. updateContacts();
  94. for (body in bodyMap) @:privateAccess body.physicsUpdate();
  95. }
  96. function updateContacts() {
  97. contacts = [];
  98. var disp: Bt.Dispatcher = dispatcher;
  99. var numManifolds = disp.getNumManifolds();
  100. for (i in 0...numManifolds) {
  101. var contactManifold = disp.getManifoldByIndexInternal(i);
  102. var body0 = untyped Bt.Ammo.btRigidBody.prototype.upcast(contactManifold.getBody0());
  103. var body1 = untyped Bt.Ammo.btRigidBody.prototype.upcast(contactManifold.getBody1());
  104. var numContacts = contactManifold.getNumContacts();
  105. var pt: Bt.ManifoldPoint = null;
  106. var posA: Bt.Vector3 = null;
  107. var posB: Bt.Vector3 = null;
  108. var nor: Bt.Vector3 = null;
  109. for (j in 0...numContacts) {
  110. pt = contactManifold.getContactPoint(j);
  111. posA = pt.get_m_positionWorldOnA();
  112. posB = pt.get_m_positionWorldOnB();
  113. nor = pt.get_m_normalWorldOnB();
  114. var cp: TPair = {
  115. a: untyped body0.userIndex,
  116. b: untyped body1.userIndex,
  117. posA: new Vec4(posA.x(), posA.y(), posA.z()),
  118. posB: new Vec4(posB.x(), posB.y(), posB.z()),
  119. normOnB: new Vec4(nor.x(), nor.y(), nor.z()),
  120. impulse: pt.getAppliedImpulse(),
  121. distance: pt.getDistance()
  122. };
  123. contacts.push(cp);
  124. }
  125. }
  126. }
  127. public function pickClosest(inputX: Float, inputY: Float): PhysicsBody {
  128. var camera = iron.Scene.active.camera;
  129. var start = new Vec4();
  130. var end = new Vec4();
  131. RayCaster.getDirection(start, end, inputX, inputY, camera);
  132. var hit = rayCast(camera.transform.world.getLoc(), end);
  133. var body = (hit != null) ? hit.body : null;
  134. return body;
  135. }
  136. public function rayCast(from: Vec4, to: Vec4, group: Int = 0x00000001, mask = 0xffffffff): THit {
  137. var rayFrom = vec1;
  138. var rayTo = vec2;
  139. rayFrom.setValue(from.x, from.y, from.z);
  140. rayTo.setValue(to.x, to.y, to.z);
  141. var rayCallback = new Bt.ClosestRayResultCallback(rayFrom, rayTo);
  142. rayCallback.set_m_collisionFilterGroup(group);
  143. rayCallback.set_m_collisionFilterMask(mask);
  144. var worldDyn: Bt.DynamicsWorld = world;
  145. var worldCol: Bt.CollisionWorld = worldDyn;
  146. worldCol.rayTest(rayFrom, rayTo, rayCallback);
  147. var pb: PhysicsBody = null;
  148. var hitInfo: THit = null;
  149. var rc: Bt.RayResultCallback = rayCallback;
  150. if (rc.hasHit()) {
  151. var co = rayCallback.get_m_collisionObject();
  152. var body = untyped Bt.Ammo.btRigidBody.prototype.upcast(co);
  153. var hit = rayCallback.get_m_hitPointWorld();
  154. v1.set(hit.x(), hit.y(), hit.z());
  155. var norm = rayCallback.get_m_hitNormalWorld();
  156. v2.set(norm.x(), norm.y(), norm.z());
  157. pb = bodyMap.get(untyped body.userIndex);
  158. hitInfo = {
  159. body: pb,
  160. pos: v1,
  161. normal: v2
  162. };
  163. }
  164. Bt.Ammo.destroy(rayCallback);
  165. return hitInfo;
  166. }
  167. }
  168. typedef THit = {
  169. public var body: PhysicsBody;
  170. public var pos: Vec4;
  171. public var normal: Vec4;
  172. }
  173. typedef TPair = {
  174. public var a: Int;
  175. public var b: Int;
  176. public var posA: Vec4;
  177. public var posB: Vec4;
  178. public var normOnB: Vec4;
  179. public var impulse: Float;
  180. public var distance: Float;
  181. }
  182. #end