Files
armorpaint/base/Sources/PhysicsWorld.ts
T

201 lines
6.0 KiB
TypeScript
Raw Normal View History

2024-01-17 18:53:31 +01:00
///if arm_physics
2024-01-26 16:50:04 +01:00
class PhysicsWorldRaw {
2024-01-21 09:45:47 +01:00
world: Ammo.btDiscreteDynamicsWorld;
dispatcher: Ammo.btCollisionDispatcher;
2024-01-17 18:53:31 +01:00
contacts: TPair[] = [];
2024-01-26 16:50:04 +01:00
bodyMap = new Map<i32, PhysicsBodyRaw>();
2024-01-17 18:53:31 +01:00
timeScale = 1.0;
timeStep = 1 / 60;
maxSteps = 1;
2024-01-26 16:50:04 +01:00
}
class PhysicsWorld {
static active: PhysicsWorldRaw = null;
static vec1: Ammo.btVector3 = null;
static vec2: Ammo.btVector3 = null;
2024-02-05 20:57:20 +01:00
static v1 = vec4_create();
static v2 = vec4_create();
2024-01-17 18:53:31 +01:00
2024-01-21 09:45:47 +01:00
static load = (done: ()=>void) => {
let b = Krom.loadBlob("data/plugins/ammo.js");
2024-02-05 20:57:20 +01:00
globalThis.eval(sys_buffer_to_string(b));
2024-01-17 18:53:31 +01:00
let print = (s: string) => { Krom.log(s); };
2024-01-21 09:45:47 +01:00
Ammo({print: print}).then(done);
2024-01-17 18:53:31 +01:00
}
2024-01-26 16:50:04 +01:00
static create(): PhysicsWorldRaw {
let pw = new PhysicsWorldRaw();
PhysicsWorld.active = pw;
2024-01-21 09:45:47 +01:00
PhysicsWorld.vec1 = new Ammo.btVector3(0, 0, 0);
PhysicsWorld.vec2 = new Ammo.btVector3(0, 0, 0);
2024-01-26 16:50:04 +01:00
PhysicsWorld.init(pw);
return pw;
2024-01-17 18:53:31 +01:00
}
2024-01-26 16:50:04 +01:00
static reset = (pw: PhysicsWorldRaw) => {
for (let body of pw.bodyMap.values()) PhysicsWorld.removeBody(pw, body);
2024-01-17 18:53:31 +01:00
}
2024-01-26 16:50:04 +01:00
static init = (pw: PhysicsWorldRaw) => {
2024-01-21 09:45:47 +01:00
let broadphase = new Ammo.btDbvtBroadphase();
let collisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
2024-01-26 16:50:04 +01:00
pw.dispatcher = new Ammo.btCollisionDispatcher(collisionConfiguration);
2024-01-21 09:45:47 +01:00
let solver = new Ammo.btSequentialImpulseConstraintSolver();
2024-01-26 16:50:04 +01:00
pw.world = new Ammo.btDiscreteDynamicsWorld(pw.dispatcher, broadphase, solver, collisionConfiguration);
2024-02-05 20:57:20 +01:00
PhysicsWorld.setGravity(pw, vec4_create(0, 0, -9.81));
2024-01-17 18:53:31 +01:00
}
2024-02-05 20:57:20 +01:00
static setGravity = (pw: PhysicsWorldRaw, v: vec4_t) => {
2024-01-21 09:45:47 +01:00
PhysicsWorld.vec1.setValue(v.x, v.y, v.z);
2024-01-26 16:50:04 +01:00
pw.world.setGravity(PhysicsWorld.vec1);
2024-01-17 18:53:31 +01:00
}
2024-01-26 16:50:04 +01:00
static addBody = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw) => {
pw.world.addRigidBody(pb.body, pb.group, pb.mask);
pw.bodyMap.set(pb.id, pb);
2024-01-17 18:53:31 +01:00
}
2024-01-26 16:50:04 +01:00
static removeBody = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw) => {
2024-01-17 18:53:31 +01:00
if (pb.destroyed) return;
pb.destroyed = true;
2024-01-26 16:50:04 +01:00
if (pw.world != null) pw.world.removeRigidBody(pb.body);
pw.bodyMap.delete(pb.id);
PhysicsBody.delete(pb);
2024-01-17 18:53:31 +01:00
}
2024-01-26 16:50:04 +01:00
static getContacts = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw): PhysicsBodyRaw[] => {
if (pw.contacts.length == 0) return null;
let res: PhysicsBodyRaw[] = [];
for (let i = 0; i < pw.contacts.length; ++i) {
let c = pw.contacts[i];
let pb: PhysicsBodyRaw = null;
if (c.a == pb.body.userIndex) pb = pw.bodyMap.get(c.b);
else if (c.b == pb.body.userIndex) pb = pw.bodyMap.get(c.a);
2024-01-17 18:53:31 +01:00
if (pb != null && res.indexOf(pb) == -1) res.push(pb);
}
return res;
}
2024-01-26 16:50:04 +01:00
static getContactPairs = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw): TPair[] => {
if (pw.contacts.length == 0) return null;
2024-01-17 18:53:31 +01:00
let res: TPair[] = [];
2024-01-26 16:50:04 +01:00
for (let i = 0; i < pw.contacts.length; ++i) {
let c = pw.contacts[i];
2024-01-17 18:53:31 +01:00
if (c.a == pb.body.userIndex) res.push(c);
else if (c.b == pb.body.userIndex) res.push(c);
}
return res;
}
2024-01-26 16:50:04 +01:00
static lateUpdate = (pw: PhysicsWorldRaw) => {
2024-02-05 20:57:20 +01:00
let t = time_delta() * pw.timeScale;
2024-01-17 18:53:31 +01:00
if (t == 0.0) return; // Simulation paused
2024-01-26 16:50:04 +01:00
pw.world.stepSimulation(pw.timeStep, pw.maxSteps, t);
PhysicsWorld.updateContacts(pw);
for (let body of pw.bodyMap.values()) PhysicsBody.physicsUpdate(body);
2024-01-17 18:53:31 +01:00
}
2024-01-26 16:50:04 +01:00
static updateContacts = (pw: PhysicsWorldRaw) => {
pw.contacts = [];
let disp: Ammo.btDispatcher = pw.dispatcher;
2024-01-17 18:53:31 +01:00
let numManifolds = disp.getNumManifolds();
for (let i = 0; i < numManifolds; ++i) {
let contactManifold = disp.getManifoldByIndexInternal(i);
2024-01-21 09:45:47 +01:00
let body0 = Ammo.btRigidBody.prototype.upcast(contactManifold.getBody0());
let body1 = Ammo.btRigidBody.prototype.upcast(contactManifold.getBody1());
2024-01-17 18:53:31 +01:00
let numContacts = contactManifold.getNumContacts();
2024-01-21 09:45:47 +01:00
let pt: Ammo.btManifoldPoint = null;
let posA: Ammo.btVector3 = null;
let posB: Ammo.btVector3 = null;
let nor: Ammo.btVector3 = null;
2024-01-17 18:53:31 +01:00
for (let j = 0; j < numContacts; ++j) {
pt = contactManifold.getContactPoint(j);
posA = pt.get_m_positionWorldOnA();
posB = pt.get_m_positionWorldOnB();
nor = pt.get_m_normalWorldOnB();
let cp: TPair = {
a: body0.userIndex,
b: body1.userIndex,
2024-02-05 20:57:20 +01:00
posA: vec4_create(posA.x(), posA.y(), posA.z()),
posB: vec4_create(posB.x(), posB.y(), posB.z()),
normOnB: vec4_create(nor.x(), nor.y(), nor.z()),
2024-01-17 18:53:31 +01:00
impulse: pt.getAppliedImpulse(),
distance: pt.getDistance()
};
2024-01-26 16:50:04 +01:00
pw.contacts.push(cp);
2024-01-17 18:53:31 +01:00
}
}
}
2024-01-26 16:50:04 +01:00
static pickClosest = (pw: PhysicsWorldRaw, inputX: f32, inputY: f32): PhysicsBodyRaw => {
2024-02-05 20:57:20 +01:00
let camera = scene_camera;
let start = vec4_create();
let end = vec4_create();
raycast_get_dir(start, end, inputX, inputY, camera);
let hit = PhysicsWorld.rayCast(pw, mat4_get_loc(camera.base.transform.world), end);
2024-01-17 18:53:31 +01:00
let body = (hit != null) ? hit.body : null;
return body;
}
2024-02-05 20:57:20 +01:00
static rayCast = (pw: PhysicsWorldRaw, from: vec4_t, to: vec4_t, group: i32 = 0x00000001, mask = 0xffffffff): THit => {
2024-01-21 09:45:47 +01:00
let rayFrom = PhysicsWorld.vec1;
let rayTo = PhysicsWorld.vec2;
2024-01-17 18:53:31 +01:00
rayFrom.setValue(from.x, from.y, from.z);
rayTo.setValue(to.x, to.y, to.z);
2024-01-21 09:45:47 +01:00
let rayCallback = new Ammo.ClosestRayResultCallback(rayFrom, rayTo);
2024-01-17 18:53:31 +01:00
rayCallback.set_m_collisionFilterGroup(group);
rayCallback.set_m_collisionFilterMask(mask);
2024-01-26 16:50:04 +01:00
let worldDyn: Ammo.btDynamicsWorld = pw.world;
2024-01-21 09:45:47 +01:00
let worldCol: Ammo.btCollisionWorld = worldDyn;
2024-01-17 18:53:31 +01:00
worldCol.rayTest(rayFrom, rayTo, rayCallback);
2024-01-26 16:50:04 +01:00
let pb: PhysicsBodyRaw = null;
2024-01-17 18:53:31 +01:00
let hitInfo: THit = null;
2024-01-21 09:45:47 +01:00
let rc: Ammo.RayResultCallback = rayCallback;
2024-01-17 18:53:31 +01:00
if (rc.hasHit()) {
let co = rayCallback.get_m_collisionObject();
2024-01-21 09:45:47 +01:00
let body = Ammo.btRigidBody.prototype.upcast(co);
2024-01-17 18:53:31 +01:00
let hit = rayCallback.get_m_hitPointWorld();
2024-02-05 20:57:20 +01:00
vec4_set(PhysicsWorld.v1, hit.x(), hit.y(), hit.z());
2024-01-17 18:53:31 +01:00
let norm = rayCallback.get_m_hitNormalWorld();
2024-02-05 20:57:20 +01:00
vec4_set(PhysicsWorld.v2, norm.x(), norm.y(), norm.z());
2024-01-26 16:50:04 +01:00
pb = pw.bodyMap.get(body.userIndex);
2024-01-17 18:53:31 +01:00
hitInfo = {
body: pb,
2024-01-21 09:45:47 +01:00
pos: PhysicsWorld.v1,
normal: PhysicsWorld.v2
2024-01-17 18:53:31 +01:00
};
}
2024-01-21 09:45:47 +01:00
Ammo.destroy(rayCallback);
2024-01-17 18:53:31 +01:00
return hitInfo;
}
}
type THit = {
2024-01-26 16:50:04 +01:00
body: PhysicsBodyRaw;
2024-02-05 20:57:20 +01:00
pos: vec4_t;
normal: vec4_t;
2024-01-17 18:53:31 +01:00
}
type TPair = {
a: i32;
b: i32;
2024-02-05 20:57:20 +01:00
posA: vec4_t;
posB: vec4_t;
normOnB: vec4_t;
2024-01-17 18:53:31 +01:00
impulse: f32;
distance: f32;
}
///end