forked from LeenkxTeam/LNXSDK
748 lines
21 KiB
Haxe
748 lines
21 KiB
Haxe
package leenkx.trait.physics.jolt;
|
|
|
|
#if lnx_jolt
|
|
|
|
import iron.Trait;
|
|
import iron.math.Vec4;
|
|
import iron.math.Quat;
|
|
import iron.data.SceneFormat;
|
|
import iron.object.Transform;
|
|
import iron.object.MeshObject;
|
|
|
|
@:enum abstract Shape(Int) from Int to Int {
|
|
var Box = 0;
|
|
var Sphere = 1;
|
|
var ConvexHull = 2;
|
|
var Mesh = 3;
|
|
var Cone = 4;
|
|
var Cylinder = 5;
|
|
var Capsule = 6;
|
|
var Terrain = 7;
|
|
}
|
|
|
|
class RigidBody extends Trait {
|
|
public var physics:PhysicsWorld;
|
|
public var transform:Transform = null;
|
|
|
|
public var body:jolt.Jt.Body;
|
|
public var bodyId:jolt.Jt.BodyID;
|
|
|
|
public var id:Int;
|
|
public var destroyed = false;
|
|
public var ready = false;
|
|
|
|
public var shape:Shape;
|
|
public var mass:Float;
|
|
public var friction:Float;
|
|
public var restitution:Float;
|
|
public var group:Int;
|
|
public var mask:Int;
|
|
public var linearDamping:Float;
|
|
public var angularDamping:Float;
|
|
public var animated:Bool;
|
|
public var staticObj:Bool;
|
|
public var trigger:Bool;
|
|
var lockTranslationX:Bool;
|
|
var lockTranslationY:Bool;
|
|
var lockTranslationZ:Bool;
|
|
var lockRotationX:Bool;
|
|
var lockRotationY:Bool;
|
|
var lockRotationZ:Bool;
|
|
var ccd:Bool;
|
|
var useDeactivation:Bool;
|
|
|
|
static var nextId = 0;
|
|
|
|
// Native bindings for complex shape creation (HL only)
|
|
#if hl
|
|
@:hlNative("jolt", "ConvexHullShapeSettings_new")
|
|
static function hlConvexHullShapeSettings_new():Dynamic { return null; }
|
|
|
|
@:hlNative("jolt", "ConvexHullShapeSettings_delete")
|
|
static function hlConvexHullShapeSettings_delete(settings:Dynamic):Void {}
|
|
|
|
@:hlNative("jolt", "ConvexHullShapeSettings_AddPoint")
|
|
static function hlConvexHullShapeSettings_AddPoint(settings:Dynamic, x:Float, y:Float, z:Float):Void {}
|
|
|
|
@:hlNative("jolt", "ConvexHullShapeSettings_Create")
|
|
static function hlConvexHullShapeSettings_Create(settings:Dynamic):Dynamic { return null; }
|
|
|
|
@:hlNative("jolt", "MeshShapeSettings_new")
|
|
static function hlMeshShapeSettings_new():Dynamic { return null; }
|
|
|
|
@:hlNative("jolt", "MeshShapeSettings_delete")
|
|
static function hlMeshShapeSettings_delete(settings:Dynamic):Void {}
|
|
|
|
@:hlNative("jolt", "MeshShapeSettings_AddVertex")
|
|
static function hlMeshShapeSettings_AddVertex(settings:Dynamic, x:Float, y:Float, z:Float):Void {}
|
|
|
|
@:hlNative("jolt", "MeshShapeSettings_AddTriangle")
|
|
static function hlMeshShapeSettings_AddTriangle(settings:Dynamic, i0:Int, i1:Int, i2:Int):Void {}
|
|
|
|
@:hlNative("jolt", "MeshShapeSettings_Create")
|
|
static function hlMeshShapeSettings_Create(settings:Dynamic):Dynamic { return null; }
|
|
#end
|
|
|
|
public function new(shape:Shape = Box, mass:Float = 1.0, friction:Float = 0.5, restitution:Float = 0.0, group:Int = 1, mask:Int = 1,
|
|
params:RigidBodyParams = null, flags:RigidBodyFlags = null) {
|
|
super();
|
|
|
|
if (params == null) params = {
|
|
linearDamping: 0.04,
|
|
angularDamping: 0.1,
|
|
angularFriction: 0.1,
|
|
linearFactorsX: 1.0,
|
|
linearFactorsY: 1.0,
|
|
linearFactorsZ: 1.0,
|
|
angularFactorsX: 1.0,
|
|
angularFactorsY: 1.0,
|
|
angularFactorsZ: 1.0,
|
|
collisionMargin: 0.0,
|
|
linearDeactivationThreshold: 0.0,
|
|
angularDeactivationThreshold: 0.0,
|
|
deactivationTime: 0.0,
|
|
linearVelocityMin: 0.0,
|
|
linearVelocityMax: 0.0,
|
|
angularVelocityMin: 0.0,
|
|
angularVelocityMax: 0.0,
|
|
lockTranslationX: false,
|
|
lockTranslationY: false,
|
|
lockTranslationZ: false,
|
|
lockRotationX: false,
|
|
lockRotationY: false,
|
|
lockRotationZ: false
|
|
};
|
|
|
|
if (flags == null) flags = {
|
|
animated: false,
|
|
trigger: false,
|
|
ccd: false,
|
|
interpolate: false,
|
|
staticObj: false,
|
|
useDeactivation: true
|
|
};
|
|
|
|
this.shape = shape;
|
|
this.mass = mass;
|
|
this.friction = friction;
|
|
this.restitution = restitution;
|
|
this.group = group;
|
|
this.mask = mask;
|
|
this.linearDamping = params.linearDamping;
|
|
this.angularDamping = params.angularDamping;
|
|
this.animated = flags.animated;
|
|
this.trigger = flags.trigger;
|
|
this.ccd = flags.ccd;
|
|
this.staticObj = flags.staticObj || mass == 0.0;
|
|
this.lockTranslationX = params.lockTranslationX;
|
|
this.lockTranslationY = params.lockTranslationY;
|
|
this.lockTranslationZ = params.lockTranslationZ;
|
|
this.lockRotationX = params.lockRotationX;
|
|
this.lockRotationY = params.lockRotationY;
|
|
this.lockRotationZ = params.lockRotationZ;
|
|
this.useDeactivation = flags.useDeactivation;
|
|
this.id = nextId++;
|
|
|
|
notifyOnAdd(init);
|
|
notifyOnRemove(removeFromWorld);
|
|
}
|
|
|
|
function init() {
|
|
if (ready)
|
|
return;
|
|
|
|
transform = object.transform;
|
|
transform.buildMatrix();
|
|
physics = PhysicsWorld.active;
|
|
|
|
if (physics == null) {
|
|
new PhysicsWorld();
|
|
physics = PhysicsWorld.active;
|
|
}
|
|
|
|
#if js
|
|
// Check if Jolt is initialized - defer if not
|
|
if (!physics.physicsReady) {
|
|
// Jolt not ready yet, retry after delay
|
|
haxe.Timer.delay(init, 16);
|
|
return;
|
|
}
|
|
#end
|
|
|
|
ready = true;
|
|
|
|
var t = transform;
|
|
t.buildMatrix();
|
|
var pos = t.world.getLoc();
|
|
var rot = new Quat();
|
|
rot.fromMat(t.world);
|
|
|
|
// Create shape based on type - use transform.dim like Bullet does
|
|
var joltShape = createShape(t);
|
|
|
|
// Determine motion type (0=Static, 1=Kinematic, 2=Dynamic)
|
|
var motionType:Int = staticObj ? 0 : (animated ? 1 : 2);
|
|
|
|
// Jolt uses RVec3 for world positions
|
|
var jPos = new jolt.Jt.RVec3(pos.x, pos.y, pos.z);
|
|
var jRot = new jolt.Jt.Quat(rot.x, rot.y, rot.z, rot.w);
|
|
if (staticObj || animated) mass = 0;
|
|
|
|
var settings = new jolt.Jt.BodyCreationSettings(joltShape, jPos, jRot, motionType, staticObj ? 0 : 1);
|
|
settings.mFriction = friction;
|
|
settings.mRestitution = restitution;
|
|
settings.mIsSensor = trigger;
|
|
|
|
settings.mLinearDamping = linearDamping;
|
|
settings.mAngularDamping = angularDamping;
|
|
|
|
// Match Bullet's deactivation: useDeactivation=false → DISABLE_DEACTIVATION
|
|
if (!useDeactivation) {
|
|
settings.mAllowSleeping = false;
|
|
}
|
|
|
|
// Set mass to match Bullet (CalculateInertia = 1: use provided mass, compute inertia from shape)
|
|
// Use explicit MassProperties object to avoid chained property access issues in HL
|
|
if (mass > 0) {
|
|
settings.mOverrideMassProperties = 1;
|
|
var mp = new jolt.Jt.MassProperties();
|
|
mp.mMass = mass;
|
|
settings.mMassPropertiesOverride = mp;
|
|
#if hl
|
|
mp.delete();
|
|
#end
|
|
}
|
|
|
|
// Set allowed DOFs (matching Bullet's linear/angular factors + lock properties)
|
|
var dofs = 0x3F; // All DOFs by default (0x3F = TranslationX|Y|Z|RotationX|Y|Z)
|
|
if (lockTranslationX) dofs &= ~0x01;
|
|
if (lockTranslationY) dofs &= ~0x02;
|
|
if (lockTranslationZ) dofs &= ~0x04;
|
|
if (lockRotationX) dofs &= ~0x08;
|
|
if (lockRotationY) dofs &= ~0x10;
|
|
if (lockRotationZ) dofs &= ~0x20;
|
|
if (dofs != 0x3F) settings.mAllowedDOFs = dofs;
|
|
|
|
// CCD for fast-moving objects
|
|
if (ccd) settings.mMotionQuality = 1; // LinearCast
|
|
|
|
body = physics.bodyInterface.CreateBody(settings);
|
|
bodyId = body.GetID();
|
|
|
|
#if hl
|
|
settings.delete();
|
|
jPos.delete();
|
|
jRot.delete();
|
|
#end
|
|
|
|
// Add to world (activate dynamic bodies, matching Bullet behavior)
|
|
physics.addRigidBody(this, !staticObj);
|
|
|
|
// Initialize cached position from body creation position
|
|
currentPosX = pos.x;
|
|
currentPosY = pos.y;
|
|
currentPosZ = pos.z;
|
|
currentRotX = rot.x;
|
|
currentRotY = rot.y;
|
|
currentRotZ = rot.z;
|
|
currentRotW = rot.w;
|
|
|
|
// Register visual update callback for non-animated bodies (matching Bullet)
|
|
if (!animated) notifyOnUpdate(update);
|
|
}
|
|
|
|
function createShape(t:Transform):jolt.Jt.Shape {
|
|
// Use transform.dim (mesh bounding box) for shape dimensions, matching Bullet
|
|
var dimX = t.dim.x;
|
|
var dimY = t.dim.y;
|
|
var dimZ = t.dim.z;
|
|
|
|
return switch (shape) {
|
|
case Box:
|
|
var halfExtent = new jolt.Jt.Vec3(dimX / 2, dimY / 2, dimZ / 2);
|
|
cast new jolt.Jt.BoxShape(halfExtent);
|
|
case Sphere:
|
|
var radius = dimX / 2;
|
|
cast new jolt.Jt.SphereShape(radius);
|
|
case Capsule:
|
|
var radius = dimX / 2;
|
|
var halfHeight = dimZ / 2 - radius;
|
|
if (halfHeight < 0) halfHeight = 0.01;
|
|
cast new jolt.Jt.CapsuleShape(halfHeight, radius);
|
|
case Cylinder:
|
|
var radius = Math.max(dimX, dimY) / 2;
|
|
var halfHeight = dimZ / 2;
|
|
cast new jolt.Jt.CylinderShape(halfHeight, radius);
|
|
case Cone:
|
|
var radius = Math.max(dimX, dimY) / 2;
|
|
var halfHeight = dimZ / 2;
|
|
cast new jolt.Jt.CylinderShape(halfHeight, radius);
|
|
case ConvexHull:
|
|
#if hl
|
|
createConvexHullShape(t.scale);
|
|
#else
|
|
createConvexHullShapeJS(t.scale, dimX, dimY, dimZ);
|
|
#end
|
|
case Mesh:
|
|
// Jolt MeshShape only works for static bodies (unlike Bullet's GImpact)
|
|
// Dynamic mesh bodies must use ConvexHullShape instead
|
|
if (staticObj) {
|
|
#if hl
|
|
createMeshShape(t.scale);
|
|
#else
|
|
createMeshShapeJS(t.scale, dimX, dimY, dimZ);
|
|
#end
|
|
} else {
|
|
#if hl
|
|
createConvexHullShape(t.scale);
|
|
#else
|
|
createConvexHullShapeJS(t.scale, dimX, dimY, dimZ);
|
|
#end
|
|
}
|
|
case Terrain:
|
|
#if hl
|
|
createTerrainShape(t.scale);
|
|
#else
|
|
createMeshShapeJS(t.scale, dimX, dimY, dimZ);
|
|
#end
|
|
default:
|
|
var halfExtent = new jolt.Jt.Vec3(dimX / 2, dimY / 2, dimZ / 2);
|
|
cast new jolt.Jt.BoxShape(halfExtent);
|
|
};
|
|
}
|
|
|
|
function createConvexHullShape(scale:Vec4):jolt.Jt.Shape {
|
|
var mo = cast(object, MeshObject);
|
|
if (mo == null || mo.data == null || mo.data.geom == null) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
}
|
|
|
|
var positions = mo.data.geom.positions.values;
|
|
var scalePos = mo.data.scalePos;
|
|
|
|
#if hl
|
|
var settings = hlConvexHullShapeSettings_new();
|
|
var numVerts = Std.int(positions.length / 4);
|
|
for (i in 0...numVerts) {
|
|
var x = (positions[i * 4] / 32767) * scalePos * scale.x;
|
|
var y = (positions[i * 4 + 1] / 32767) * scalePos * scale.y;
|
|
var z = (positions[i * 4 + 2] / 32767) * scalePos * scale.z;
|
|
hlConvexHullShapeSettings_AddPoint(settings, x, y, z);
|
|
}
|
|
var shape = hlConvexHullShapeSettings_Create(settings);
|
|
hlConvexHullShapeSettings_delete(settings);
|
|
if (shape == null) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
}
|
|
return cast shape;
|
|
#else
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
#end
|
|
}
|
|
|
|
function createMeshShape(scale:Vec4):jolt.Jt.Shape {
|
|
var mo = cast(object, MeshObject);
|
|
if (mo == null || mo.data == null || mo.data.geom == null) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
}
|
|
|
|
var positions = mo.data.geom.positions.values;
|
|
var indices = mo.data.geom.indices;
|
|
var scalePos = mo.data.scalePos;
|
|
|
|
#if hl
|
|
var settings = hlMeshShapeSettings_new();
|
|
var numVerts = Std.int(positions.length / 4);
|
|
|
|
for (i in 0...numVerts) {
|
|
var x = (positions[i * 4] / 32767) * scalePos * scale.x;
|
|
var y = (positions[i * 4 + 1] / 32767) * scalePos * scale.y;
|
|
var z = (positions[i * 4 + 2] / 32767) * scalePos * scale.z;
|
|
hlMeshShapeSettings_AddVertex(settings, x, y, z);
|
|
}
|
|
|
|
for (indexArray in indices) {
|
|
var numTris = Std.int(indexArray.length / 3);
|
|
for (i in 0...numTris) {
|
|
hlMeshShapeSettings_AddTriangle(settings, indexArray[i * 3], indexArray[i * 3 + 1], indexArray[i * 3 + 2]);
|
|
}
|
|
}
|
|
|
|
var shape = hlMeshShapeSettings_Create(settings);
|
|
hlMeshShapeSettings_delete(settings);
|
|
if (shape == null) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
}
|
|
return cast shape;
|
|
#else
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
#end
|
|
}
|
|
|
|
function createTerrainShape(scale:Vec4):jolt.Jt.Shape {
|
|
// Terrain/HeightField shape - requires height data from object
|
|
var mo = cast(object, MeshObject);
|
|
if (mo == null) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
}
|
|
|
|
#if js
|
|
// For JS, use HeightFieldShapeSettings or fallback to mesh
|
|
// Terrain meshes are typically treated as mesh shapes in Jolt
|
|
return createMeshShape(scale);
|
|
#elseif hl
|
|
// For HashLink, terrain is also best represented as mesh shape
|
|
// HeightFieldShape requires specific grid data which terrain meshes may not have
|
|
return createMeshShape(scale);
|
|
#else
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(scale.x * 0.5, scale.y * 0.5, scale.z * 0.5));
|
|
#end
|
|
}
|
|
|
|
#if js
|
|
function createConvexHullShapeJS(scale:Vec4, dimX:Float, dimY:Float, dimZ:Float):jolt.Jt.Shape {
|
|
var mo = cast(object, MeshObject);
|
|
if (mo == null || mo.data == null || mo.data.geom == null) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(dimX / 2, dimY / 2, dimZ / 2));
|
|
}
|
|
|
|
var positions = mo.data.geom.positions.values;
|
|
var scalePos = mo.data.scalePos;
|
|
var numVerts = Std.int(positions.length / 4);
|
|
|
|
var settings:Dynamic = untyped __js__("new Jolt.ConvexHullShapeSettings()");
|
|
var points:Dynamic = untyped settings.mPoints;
|
|
points.clear();
|
|
for (i in 0...numVerts) {
|
|
var x:Float = (positions[i * 4] / 32767) * scalePos * scale.x;
|
|
var y:Float = (positions[i * 4 + 1] / 32767) * scalePos * scale.y;
|
|
var z:Float = (positions[i * 4 + 2] / 32767) * scalePos * scale.z;
|
|
var pt:Dynamic = untyped __js__("new Jolt.Vec3({0}, {1}, {2})", x, y, z);
|
|
untyped points.push_back(pt);
|
|
}
|
|
|
|
var result:Dynamic = untyped settings.Create();
|
|
if (untyped result.HasError()) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(dimX / 2, dimY / 2, dimZ / 2));
|
|
}
|
|
return cast untyped result.Get();
|
|
}
|
|
|
|
function createMeshShapeJS(scale:Vec4, dimX:Float, dimY:Float, dimZ:Float):jolt.Jt.Shape {
|
|
var mo = cast(object, MeshObject);
|
|
if (mo == null || mo.data == null || mo.data.geom == null) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(dimX / 2, dimY / 2, dimZ / 2));
|
|
}
|
|
|
|
var positions = mo.data.geom.positions.values;
|
|
var indices = mo.data.geom.indices;
|
|
var scalePos = mo.data.scalePos;
|
|
var numVerts = Std.int(positions.length / 4);
|
|
|
|
var settings:Dynamic = untyped __js__("new Jolt.MeshShapeSettings()");
|
|
var verts:Dynamic = untyped settings.mTriangleVertices;
|
|
var tris:Dynamic = untyped settings.mIndexedTriangles;
|
|
verts.clear();
|
|
tris.clear();
|
|
|
|
for (i in 0...numVerts) {
|
|
var x:Float = (positions[i * 4] / 32767) * scalePos * scale.x;
|
|
var y:Float = (positions[i * 4 + 1] / 32767) * scalePos * scale.y;
|
|
var z:Float = (positions[i * 4 + 2] / 32767) * scalePos * scale.z;
|
|
var v:Dynamic = untyped __js__("new Jolt.Float3({0}, {1}, {2})", x, y, z);
|
|
untyped verts.push_back(v);
|
|
}
|
|
|
|
for (indexArray in indices) {
|
|
var numTris = Std.int(indexArray.length / 3);
|
|
for (i in 0...numTris) {
|
|
var tri:Dynamic = untyped __js__("new Jolt.IndexedTriangle()");
|
|
untyped tri.set_mIdx(0, indexArray[i * 3]);
|
|
untyped tri.set_mIdx(1, indexArray[i * 3 + 1]);
|
|
untyped tri.set_mIdx(2, indexArray[i * 3 + 2]);
|
|
untyped tri.set_mMaterialIndex(0);
|
|
untyped tris.push_back(tri);
|
|
}
|
|
}
|
|
|
|
var result:Dynamic = untyped settings.Create();
|
|
if (untyped result.HasError()) {
|
|
return cast new jolt.Jt.BoxShape(new jolt.Jt.Vec3(dimX / 2, dimY / 2, dimZ / 2));
|
|
}
|
|
return cast untyped result.Get();
|
|
}
|
|
#end
|
|
|
|
// Cached physics state for visual interpolation (matching Bullet pattern)
|
|
var currentPosX:Float = 0;
|
|
var currentPosY:Float = 0;
|
|
var currentPosZ:Float = 0;
|
|
var currentRotX:Float = 0;
|
|
var currentRotY:Float = 0;
|
|
var currentRotZ:Float = 0;
|
|
var currentRotW:Float = 1;
|
|
|
|
public function physicsUpdate() {
|
|
if (!ready)
|
|
return;
|
|
|
|
if (staticObj)
|
|
return;
|
|
|
|
if (animated) {
|
|
syncTransform();
|
|
return;
|
|
}
|
|
|
|
var active = physics.bodyInterface.IsActive(bodyId);
|
|
if (!active)
|
|
return;
|
|
|
|
// Read position and rotation from Jolt into cached state
|
|
var p = physics.bodyInterface.GetPosition(bodyId);
|
|
var q = physics.bodyInterface.GetRotation(bodyId);
|
|
|
|
#if js
|
|
currentPosX = cast p.GetX();
|
|
currentPosY = cast p.GetY();
|
|
currentPosZ = cast p.GetZ();
|
|
currentRotX = cast q.GetX();
|
|
currentRotY = cast q.GetY();
|
|
currentRotZ = cast q.GetZ();
|
|
currentRotW = cast q.GetW();
|
|
// JS: getter return values use internal WASM wrappers - do NOT destroy
|
|
#else
|
|
currentPosX = p.GetX();
|
|
currentPosY = p.GetY();
|
|
currentPosZ = p.GetZ();
|
|
currentRotX = q.GetX();
|
|
currentRotY = q.GetY();
|
|
currentRotZ = q.GetZ();
|
|
currentRotW = q.GetW();
|
|
p.delete();
|
|
q.delete();
|
|
#end
|
|
}
|
|
|
|
function update() {
|
|
transform.loc.set(currentPosX, currentPosY, currentPosZ);
|
|
transform.rot.set(currentRotX, currentRotY, currentRotZ, currentRotW);
|
|
|
|
if (object.parent != null) {
|
|
var ptransform = object.parent.transform;
|
|
transform.loc.x -= ptransform.worldx();
|
|
transform.loc.y -= ptransform.worldy();
|
|
transform.loc.z -= ptransform.worldz();
|
|
}
|
|
|
|
transform.buildMatrix();
|
|
}
|
|
|
|
function removeFromWorld() {
|
|
if (physics != null) {
|
|
physics.removeRigidBody(this);
|
|
}
|
|
}
|
|
|
|
public function delete() {
|
|
// Cleanup handled by physics world
|
|
}
|
|
|
|
// Physics methods
|
|
public function applyForce(force:Vec4, ?loc:Vec4) {
|
|
activate();
|
|
if (loc == null) {
|
|
var f = new jolt.Jt.Vec3(force.x, force.y, force.z);
|
|
physics.bodyInterface.AddForce(bodyId, f);
|
|
#if hl f.delete(); #end
|
|
} else {
|
|
var f = new jolt.Jt.Vec3(force.x, force.y, force.z);
|
|
var l = new jolt.Jt.RVec3(loc.x, loc.y, loc.z);
|
|
physics.bodyInterface.AddForceAtPosition(bodyId, f, l);
|
|
#if hl f.delete(); l.delete(); #end
|
|
}
|
|
}
|
|
|
|
public function applyImpulse(impulse:Vec4, ?loc:Vec4) {
|
|
activate();
|
|
if (loc == null) {
|
|
var i = new jolt.Jt.Vec3(impulse.x, impulse.y, impulse.z);
|
|
physics.bodyInterface.AddImpulse(bodyId, i);
|
|
#if hl i.delete(); #end
|
|
} else {
|
|
var i = new jolt.Jt.Vec3(impulse.x, impulse.y, impulse.z);
|
|
var l = new jolt.Jt.RVec3(loc.x, loc.y, loc.z);
|
|
physics.bodyInterface.AddImpulseAtPosition(bodyId, i, l);
|
|
#if hl i.delete(); l.delete(); #end
|
|
}
|
|
}
|
|
|
|
public function applyTorque(torque:Vec4) {
|
|
activate();
|
|
var t = new jolt.Jt.Vec3(torque.x, torque.y, torque.z);
|
|
physics.bodyInterface.AddTorque(bodyId, t);
|
|
#if hl t.delete(); #end
|
|
}
|
|
|
|
public function applyTorqueImpulse(impulse:Vec4) {
|
|
activate();
|
|
var i = new jolt.Jt.Vec3(impulse.x, impulse.y, impulse.z);
|
|
physics.bodyInterface.AddAngularImpulse(bodyId, i);
|
|
#if hl i.delete(); #end
|
|
}
|
|
|
|
public function setLinearVelocity(v:Vec4) {
|
|
var vel = new jolt.Jt.Vec3(v.x, v.y, v.z);
|
|
physics.bodyInterface.SetLinearVelocity(bodyId, vel);
|
|
#if hl vel.delete(); #end
|
|
}
|
|
|
|
public function getLinearVelocity():Vec4 {
|
|
var v = physics.bodyInterface.GetLinearVelocity(bodyId);
|
|
var result = new Vec4(v.GetX(), v.GetY(), v.GetZ());
|
|
#if hl v.delete(); #end
|
|
return result;
|
|
}
|
|
|
|
public function setAngularVelocity(v:Vec4) {
|
|
var vel = new jolt.Jt.Vec3(v.x, v.y, v.z);
|
|
physics.bodyInterface.SetAngularVelocity(bodyId, vel);
|
|
#if hl vel.delete(); #end
|
|
}
|
|
|
|
public function getAngularVelocity():Vec4 {
|
|
var v = physics.bodyInterface.GetAngularVelocity(bodyId);
|
|
var result = new Vec4(v.GetX(), v.GetY(), v.GetZ());
|
|
#if hl v.delete(); #end
|
|
return result;
|
|
}
|
|
|
|
public function setFriction(f:Float) {
|
|
friction = f;
|
|
physics.bodyInterface.SetFriction(bodyId, f);
|
|
}
|
|
|
|
public function setRestitution(r:Float) {
|
|
restitution = r;
|
|
physics.bodyInterface.SetRestitution(bodyId, r);
|
|
}
|
|
|
|
public function setGravityFactor(f:Float) {
|
|
physics.bodyInterface.SetGravityFactor(bodyId, f);
|
|
}
|
|
|
|
public function activate() {
|
|
physics.bodyInterface.ActivateBody(bodyId);
|
|
}
|
|
|
|
public function disableSimulation() {
|
|
physics.bodyInterface.DeactivateBody(bodyId);
|
|
}
|
|
|
|
public function setPosition(pos:Vec4) {
|
|
var p = new jolt.Jt.RVec3(pos.x, pos.y, pos.z);
|
|
physics.bodyInterface.SetPosition(bodyId, p, 0);
|
|
#if hl p.delete(); #end
|
|
}
|
|
|
|
public function setRotation(rot:Quat) {
|
|
var q = new jolt.Jt.Quat(rot.x, rot.y, rot.z, rot.w);
|
|
physics.bodyInterface.SetRotation(bodyId, q, 0);
|
|
#if hl q.delete(); #end
|
|
}
|
|
|
|
public function syncTransform() {
|
|
var t = transform;
|
|
var pos = t.world.getLoc();
|
|
var rot = new Quat();
|
|
rot.fromMat(t.world);
|
|
setPosition(pos);
|
|
setRotation(rot);
|
|
}
|
|
|
|
public function isActive():Bool {
|
|
return physics.bodyInterface.IsActive(bodyId);
|
|
}
|
|
|
|
public function disableGravity() {
|
|
setGravityFactor(0.0);
|
|
}
|
|
|
|
public function enableGravity() {
|
|
setGravityFactor(1.0);
|
|
}
|
|
|
|
public function getPointVelocity(x:Float, y:Float, z:Float):Vec4 {
|
|
var linear = getLinearVelocity();
|
|
var relativePoint = new Vec4(x, y, z).sub(transform.world.getLoc());
|
|
var angular = getAngularVelocity().cross(relativePoint);
|
|
return linear.add(angular);
|
|
}
|
|
|
|
public function disableCollision() {
|
|
// In Jolt, use SetIsSensor to disable contact response
|
|
body.SetIsSensor(true);
|
|
}
|
|
|
|
public function enableCollision() {
|
|
body.SetIsSensor(false);
|
|
}
|
|
|
|
public function notifyOnContact(f:RigidBody->Void) {
|
|
if (onContact == null)
|
|
onContact = [];
|
|
onContact.push(f);
|
|
}
|
|
|
|
public function removeContact(f:RigidBody->Void) {
|
|
if (onContact != null)
|
|
onContact.remove(f);
|
|
}
|
|
|
|
public var onContact:Array<RigidBody->Void> = null;
|
|
public var onReady:Void->Void = null;
|
|
|
|
public function notifyOnReady(f:Void->Void) {
|
|
onReady = f;
|
|
if (ready)
|
|
onReady();
|
|
}
|
|
}
|
|
|
|
typedef RigidBodyParams = {
|
|
var linearDamping:Float;
|
|
var angularDamping:Float;
|
|
var angularFriction:Float;
|
|
var linearFactorsX:Float;
|
|
var linearFactorsY:Float;
|
|
var linearFactorsZ:Float;
|
|
var angularFactorsX:Float;
|
|
var angularFactorsY:Float;
|
|
var angularFactorsZ:Float;
|
|
var collisionMargin:Float;
|
|
var linearDeactivationThreshold:Float;
|
|
var angularDeactivationThreshold:Float;
|
|
var deactivationTime:Float;
|
|
var linearVelocityMin:Float;
|
|
var linearVelocityMax:Float;
|
|
var angularVelocityMin:Float;
|
|
var angularVelocityMax:Float;
|
|
var lockTranslationX:Bool;
|
|
var lockTranslationY:Bool;
|
|
var lockTranslationZ:Bool;
|
|
var lockRotationX:Bool;
|
|
var lockRotationY:Bool;
|
|
var lockRotationZ:Bool;
|
|
}
|
|
|
|
typedef RigidBodyFlags = {
|
|
var animated:Bool;
|
|
var trigger:Bool;
|
|
var ccd:Bool;
|
|
var interpolate:Bool;
|
|
var staticObj:Bool;
|
|
var useDeactivation:Bool;
|
|
}
|
|
|
|
#end
|