Jolt Patch

This commit is contained in:
2026-07-09 17:25:48 -07:00
parent cb19c9b5b4
commit 9d83c318b6
18 changed files with 2542 additions and 157 deletions

View File

@ -101,6 +101,15 @@ class Starter {
kha.Assets.loadBlobFromPath(name, function(b: kha.Blob) {
js.Syntax.code("(1,eval)({0})", b.toString());
#if kha_krom
#if lnx_jolt_mt
js.Syntax.code("Jolt({print:function(s){iron.log(s);},instantiateWasm:function(imports,successCallback) {
var wasmbin = Krom.loadBlob('jolt.mt.wasm.wasm');
var module = new WebAssembly.Module(wasmbin);
var inst = new WebAssembly.Instance(module,imports);
successCallback(inst,module);
return inst.exports;
}}).then(function(m){ Jolt=m; tasks--; start();})");
#else
js.Syntax.code("Jolt({print:function(s){iron.log(s);},instantiateWasm:function(imports,successCallback) {
var wasmbin = Krom.loadBlob('jolt.wasm.wasm');
var module = new WebAssembly.Module(wasmbin);
@ -108,6 +117,7 @@ class Starter {
successCallback(inst);
return inst.exports;
}}).then(function(m){ Jolt=m; tasks--; start();})");
#end
#else
js.Syntax.code("Jolt({print:function(s){iron.log(s);},locateFile:function(f){return 'jolt.wasm.wasm';}}).then(function(m){ Jolt=m; tasks--; start();})");
#end
@ -147,8 +157,12 @@ class Starter {
#if (js && lnx_jolt)
tasks++;
#if lnx_jolt_mt
loadLibJolt("jolt.mt.wasm.js");
#else
loadLibJolt("jolt.wasm.js");
#end
#end
#if (js && lnx_navigation)
tasks++;

View File

@ -6,14 +6,14 @@ import iron.Trait;
import iron.object.MeshObject;
import iron.data.MeshData;
import iron.data.SceneFormat;
#if (lnx_bullet || lnx_oimo)
#if lnx_physics
import leenkx.trait.physics.RigidBody;
import leenkx.trait.physics.PhysicsWorld;
#end
class PhysicsBreak extends Trait {
#if (!lnx_bullet && !lnx_oimo)
#if (!lnx_physics)
public function new() { super(); }
#else
@ -74,14 +74,16 @@ class PhysicsBreak extends Trait {
impactNormal = p.normOnB;
#elseif lnx_oimo
impactNormal = p.nor;
#else
impactNormal = p.normOnB;
#end
}
}
#if lnx_bullet
var fractureImpulse = 4.0;
#elseif lnx_oimo
#if lnx_oimo
var fractureImpulse = 1.0;
#else
var fractureImpulse = 4.0;
#end
if (maxImpulse > fractureImpulse && impactPoint != null && impactNormal != null) {
var radialIter = 1;

View File

@ -11,25 +11,38 @@ import leenkx.trait.physics.PhysicsWorld;
class PhysicsDrag extends Trait {
#if (!lnx_bullet)
#if (!lnx_physics)
public function new() { super(); }
#else
#if lnx_bullet
@prop public var linearLowerLimit = new Vec3(0,0,0);
@prop public var linearUpperLimit = new Vec3(0,0,0);
@prop public var angularLowerLimit = new Vec3(-10,-10,-10);
@prop public var angularUpperLimit = new Vec3(10,10,10);
var pickConstraint: bullet.Bt.Generic6DofConstraint = null;
var pickDist: Float;
var pickedBody: RigidBody = null;
var rayFrom: bullet.Bt.Vector3;
var rayTo: bullet.Bt.Vector3;
#end
#if lnx_jolt
var pickConstraint:jolt.Jt.TwoBodyConstraint = null;
var anchorBody:jolt.Jt.Body = null;
var anchorBodyId:jolt.Jt.BodyID = null;
var localPivot:Vec4 = null;
#end
var pickDist:Float;
var pickedBody:RigidBody = null;
static var v = new Vec4();
static var m = Mat4.identity();
static var first = true;
static var start = new Vec4();
static var end = new Vec4();
#if lnx_jolt
static var anchorPos:jolt.Jt.RVec3 = null;
static var anchorRot:jolt.Jt.Quat = null;
#end
public function new() {
super();
@ -45,81 +58,135 @@ class PhysicsDrag extends Trait {
var mouse = Input.getMouse();
if (mouse.started()) {
var b = physics.pickClosest(mouse.x, mouse.y);
if (b != null && b.mass > 0 && !b.body.isKinematicObject() && b.object.getTrait(PhysicsDrag) != null) {
setRays();
if (b != null && b.mass > 0 && isDraggable(b) && b.object.getTrait(PhysicsDrag) != null) {
pickedBody = b;
m.getInverse(b.object.transform.world);
var hit = physics.hitPointWorld;
var camera = iron.Scene.active.camera;
var camLoc = camera.transform.world.getLoc();
pickDist = v.set(hit.x - camLoc.x, hit.y - camLoc.y, hit.z - camLoc.z).length();
#if lnx_bullet
setRays();
m.getInverse(b.object.transform.world);
v.setFrom(hit);
v.applymat4(m);
var localPivot = new bullet.Bt.Vector3(v.x, v.y, v.z);
var tr = new bullet.Bt.Transform();
tr.setIdentity();
tr.setOrigin(localPivot);
pickConstraint = new bullet.Bt.Generic6DofConstraint(b.body, tr, false);
pickConstraint.setLinearLowerLimit(new bullet.Bt.Vector3(linearLowerLimit.x, linearLowerLimit.y, linearLowerLimit.z));
pickConstraint.setLinearUpperLimit(new bullet.Bt.Vector3(linearUpperLimit.x, linearUpperLimit.y, linearUpperLimit.z));
pickConstraint.setAngularLowerLimit(new bullet.Bt.Vector3(angularLowerLimit.x, angularLowerLimit.y, angularLowerLimit.z));
pickConstraint.setAngularUpperLimit(new bullet.Bt.Vector3(angularUpperLimit.x, angularUpperLimit.y, angularUpperLimit.z));
physics.world.addConstraint(pickConstraint, false);
#elseif lnx_jolt
// Compute local pivot on the body (world hit -> body local)
m.getInverse(b.object.transform.world);
localPivot = new Vec4();
localPivot.setFrom(hit);
localPivot.applymat4(m);
/*pickConstraint.setParam(4, 0.8, 0);
pickConstraint.setParam(4, 0.8, 1);
pickConstraint.setParam(4, 0.8, 2);
pickConstraint.setParam(4, 0.8, 3);
pickConstraint.setParam(4, 0.8, 4);
pickConstraint.setParam(4, 0.8, 5);
// Create a small kinematic anchor body at the hit point
var aPos = new jolt.Jt.RVec3(hit.x, hit.y, hit.z);
var aRot = new jolt.Jt.Quat(0, 0, 0, 1);
var anchorShape = new jolt.Jt.SphereShape(0.01);
var anchorSettings = new jolt.Jt.BodyCreationSettings(anchorShape, aPos, aRot, jolt.Jt.EMotionType.Kinematic, 0);
anchorSettings.mGravityFactor = 0.0;
anchorBody = physics.bodyInterface.CreateBody(anchorSettings);
anchorBodyId = anchorBody.GetID();
physics.bodyInterface.AddBody(anchorBodyId, jolt.Jt.EActivation.Activate);
#if hl anchorSettings.delete(); aPos.delete(); aRot.delete(); #end
pickConstraint.setParam(1, 0.1, 0);
pickConstraint.setParam(1, 0.1, 1);
pickConstraint.setParam(1, 0.1, 2);
pickConstraint.setParam(1, 0.1, 3);
pickConstraint.setParam(1, 0.1, 4);
pickConstraint.setParam(1, 0.1, 5);*/
pickDist = v.set(hit.x - rayFrom.x(), hit.y - rayFrom.y(), hit.z - rayFrom.z()).length();
// Create SixDOFConstraint: translation locked, rotation free
var sixDof = new jolt.Jt.SixDOFConstraintSettings();
sixDof.mSpace = 0; // LocalToBodyCOM
var p1 = new jolt.Jt.RVec3(localPivot.x, localPivot.y, localPivot.z);
var p2 = new jolt.Jt.RVec3(0, 0, 0);
var ax1 = new jolt.Jt.Vec3(1, 0, 0);
var ay1 = new jolt.Jt.Vec3(0, 1, 0);
var ax2 = new jolt.Jt.Vec3(1, 0, 0);
var ay2 = new jolt.Jt.Vec3(0, 1, 0);
sixDof.mPosition1 = p1;
sixDof.mPosition2 = p2;
sixDof.mAxisX1 = ax1;
sixDof.mAxisY1 = ay1;
sixDof.mAxisX2 = ax2;
sixDof.mAxisY2 = ay2;
sixDof.MakeFixedAxis(0);
sixDof.MakeFixedAxis(1);
sixDof.MakeFixedAxis(2);
sixDof.MakeFreeAxis(3);
sixDof.MakeFreeAxis(4);
sixDof.MakeFreeAxis(5);
pickConstraint = sixDof.Create(b.body, anchorBody);
physics.physicsSystem.AddConstraint(pickConstraint);
#if hl sixDof.delete(); p1.delete(); p2.delete(); ax1.delete(); ay1.delete(); ax2.delete(); ay2.delete(); #end
#end
Input.occupied = true;
}
}
else if (mouse.released()) {
#if lnx_bullet
if (pickConstraint != null) {
physics.world.removeConstraint(pickConstraint);
pickConstraint = null;
pickedBody = null;
}
#elseif lnx_jolt
if (pickConstraint != null) {
physics.physicsSystem.RemoveConstraint(pickConstraint);
pickConstraint = null;
}
if (anchorBodyId != null) {
physics.bodyInterface.RemoveBody(anchorBodyId);
physics.bodyInterface.DestroyBody(anchorBodyId);
anchorBodyId = null;
anchorBody = null;
}
localPivot = null;
#end
pickedBody = null;
Input.occupied = false;
}
else if (mouse.down()) {
if (pickConstraint != null) {
setRays();
// Keep it at the same picking distance
var dir = new bullet.Bt.Vector3(rayTo.x() - rayFrom.x(), rayTo.y() - rayFrom.y(), rayTo.z() - rayFrom.z());
dir.normalize();
dir.setX(dir.x() * pickDist);
dir.setY(dir.y() * pickDist);
dir.setZ(dir.z() * pickDist);
var newPivotB = new bullet.Bt.Vector3(rayFrom.x() + dir.x(), rayFrom.y() + dir.y(), rayFrom.z() + dir.z());
#if (js || hl)
pickConstraint.getFrameOffsetA().setOrigin(newPivotB);
#elseif cpp
pickConstraint.setFrameOffsetAOrigin(newPivotB);
if (pickedBody != null) {
#if lnx_bullet
if (pickConstraint != null) {
setRays();
var dir = new bullet.Bt.Vector3(rayTo.x() - rayFrom.x(), rayTo.y() - rayFrom.y(), rayTo.z() - rayFrom.z());
dir.normalize();
dir.setX(dir.x() * pickDist);
dir.setY(dir.y() * pickDist);
dir.setZ(dir.z() * pickDist);
var newPivotB = new bullet.Bt.Vector3(rayFrom.x() + dir.x(), rayFrom.y() + dir.y(), rayFrom.z() + dir.z());
#if (js || hl)
pickConstraint.getFrameOffsetA().setOrigin(newPivotB);
#elseif cpp
pickConstraint.setFrameOffsetAOrigin(newPivotB);
#end
}
#elseif lnx_jolt
if (pickConstraint != null) {
setAnchorTarget(physics);
}
#end
}
}
}
static var start = new Vec4();
static var end = new Vec4();
inline function isDraggable(b:RigidBody):Bool {
#if lnx_bullet
return !b.body.isKinematicObject();
#elseif lnx_jolt
return !b.staticObj && !b.animated;
#else
return true;
#end
}
#if lnx_bullet
inline function setRays() {
var mouse = Input.getMouse();
var camera = iron.Scene.active.camera;
@ -128,5 +195,37 @@ class PhysicsDrag extends Trait {
RayCaster.getDirection(start, end, mouse.x, mouse.y, camera);
rayTo = new bullet.Bt.Vector3(end.x, end.y, end.z);
}
#end
#if lnx_jolt
inline function setAnchorTarget(physics:PhysicsWorld) {
var mouse = Input.getMouse();
var camera = iron.Scene.active.camera;
var camLoc = camera.transform.world.getLoc();
RayCaster.getDirection(start, end, mouse.x, mouse.y, camera);
var dirX = end.x - camLoc.x;
var dirY = end.y - camLoc.y;
var dirZ = end.z - camLoc.z;
var len = Math.sqrt(dirX * dirX + dirY * dirY + dirZ * dirZ);
if (len > 0) { dirX /= len; dirY /= len; dirZ /= len; }
var targetX = camLoc.x + dirX * pickDist;
var targetY = camLoc.y + dirY * pickDist;
var targetZ = camLoc.z + dirZ * pickDist;
var t = iron.system.Time.fixedStep;
#if hl
RigidBody.hlPos.Set(targetX, targetY, targetZ);
physics.bodyInterface.MoveKinematic(anchorBodyId, RigidBody.hlPos, RigidBody.hlRot, t);
#else
if (anchorPos == null) {
anchorPos = new jolt.Jt.RVec3(0, 0, 0);
anchorRot = new jolt.Jt.Quat(0, 0, 0, 1);
}
anchorPos.Set(targetX, targetY, targetZ);
physics.bodyInterface.MoveKinematic(anchorBodyId, anchorPos, anchorRot, t);
#end
}
#end
#end
}

View File

@ -7,12 +7,17 @@ import iron.object.Transform;
import iron.system.Time;
import leenkx.trait.physics.PhysicsWorld;
class VehicleBody extends Trait {
#if (!lnx_physics)
class VehicleBody extends Trait { public function new() { super(); } }
class VehicleWheel { public function new() {} }
#if (!lnx_bullet)
public function new() { super(); }
#else
#if lnx_bullet
class VehicleBody extends Trait {
@prop var wheel0Name: String = "Wheel0";
@prop var wheel1Name: String = "Wheel1";
@prop var wheel2Name: String = "Wheel2";
@ -232,34 +237,44 @@ class VehicleBody extends Trait {
static inline var keyStrafeUp = "e";
static inline var keyStrafeDown = "q";
#end
#end
}
class VehicleWheel {
#if (!lnx_bullet)
public function new() {}
#else
public var isFrontWheel: Bool;
public var wheelRadius: Float;
public var wheelWidth: Float;
public var isFrontWheel: Bool;
public var wheelRadius: Float;
public var wheelWidth: Float;
var locX: Float;
var locY: Float;
var locZ: Float;
var locX: Float;
var locY: Float;
var locZ: Float;
public function new(id: Int, transform: Transform, vehicleTransform: Transform) {
wheelRadius = transform.dim.z / 2;
wheelWidth = transform.dim.x > transform.dim.y ? transform.dim.y : transform.dim.x;
public function new(id: Int, transform: Transform, vehicleTransform: Transform) {
wheelRadius = transform.dim.z / 2;
wheelWidth = transform.dim.x > transform.dim.y ? transform.dim.y : transform.dim.x;
locX = transform.loc.x;
locY = transform.loc.y;
locZ = vehicleTransform.dim.z / 2 + transform.loc.z;
}
locX = transform.loc.x;
locY = transform.loc.y;
locZ = vehicleTransform.dim.z / 2 + transform.loc.z;
public function getConnectionPoint(): bullet.Bt.Vector3 {
return new bullet.Bt.Vector3(locX, locY, locZ);
}
}
public function getConnectionPoint(): bullet.Bt.Vector3 {
return new bullet.Bt.Vector3(locX, locY, locZ);
}
#end
#elseif lnx_jolt
typedef VehicleBody = leenkx.trait.physics.jolt.VehicleBody;
typedef VehicleWheel = leenkx.trait.physics.jolt.VehicleWheel;
#else
class VehicleBody extends Trait { public function new() { super(); } }
class VehicleWheel { public function new() {} }
#end
#end
}

View File

@ -8,7 +8,7 @@ import iron.math.Quat;
import iron.math.Mat4;
import iron.object.Object;
@:enum abstract ConstraintType(Int) from Int to Int {
enum abstract ConstraintType(Int) from Int to Int {
var Fixed = 0;
var Point = 1;
var Hinge = 2;
@ -396,7 +396,7 @@ class PhysicsConstraint extends Trait {
}
}
@:enum abstract ConstraintAxis(Int) from Int to Int {
enum abstract ConstraintAxis(Int) from Int to Int {
var X = 0;
var Y = 1;
var Z = 2;

View File

@ -59,6 +59,7 @@ class PhysicsWorld extends Trait {
var contacts:Array<ContactPair>;
var preUpdates:Array<Void->Void> = null;
public var rbMap:Map<Int, RigidBody>;
public var bodyIdMap:Map<Int, RigidBody>;
public var conMap:Map<Int, PhysicsConstraint>;
public var constraints:Array<PhysicsConstraint> = [];
public var timeScale = 1.0;
@ -77,6 +78,21 @@ class PhysicsWorld extends Trait {
static var vec2:jolt.Jt.Vec3 = null;
static var quat1:jolt.Jt.Quat = null;
// Cached raycast objects
static var rayOrigin:jolt.Jt.RVec3 = null;
static var rayDir:jolt.Jt.Vec3 = null;
static var cachedRay:jolt.Jt.RRayCast = null;
static var rayResult:jolt.Jt.RayCastResult = null;
static var raySettings:jolt.Jt.RayCastSettings = null;
#if js
static var rayCollector:jolt.Jt.CastRayClosestHitCollisionCollector = null;
#end
static var bpFilter:jolt.Jt.BroadPhaseLayerFilter = null;
static var objFilter:jolt.Jt.ObjectLayerFilter = null;
static var bodyFilter:jolt.Jt.BodyFilter = null;
static var shapeFilter:jolt.Jt.ShapeFilter = null;
static var narrowPhaseQuery:jolt.Jt.NarrowPhaseQuery = null;
#if js
var joltInterface:jolt.Jt.JoltInterface;
static var joltReady = false;
@ -110,6 +126,7 @@ class PhysicsWorld extends Trait {
contacts = [];
rbMap = new Map();
bodyIdMap = new Map();
conMap = new Map();
active = this;
@ -157,6 +174,7 @@ class PhysicsWorld extends Trait {
#if hl
// Must initialize Jolt allocator before ANY Jolt object creation
hlJoltInit();
RigidBody.hlInitVars();
#end
if (nullvec) {
@ -164,6 +182,21 @@ class PhysicsWorld extends Trait {
vec1 = new jolt.Jt.Vec3(0, 0, 0);
vec2 = new jolt.Jt.Vec3(0, 0, 0);
quat1 = new jolt.Jt.Quat(0, 0, 0, 1);
rayOrigin = new jolt.Jt.RVec3(0, 0, 0);
rayDir = new jolt.Jt.Vec3(0, 0, 0);
cachedRay = new jolt.Jt.RRayCast(rayOrigin, rayDir);
rayResult = new jolt.Jt.RayCastResult();
raySettings = new jolt.Jt.RayCastSettings();
#if js
rayCollector = new jolt.Jt.CastRayClosestHitCollisionCollector();
#end
bpFilter = new jolt.Jt.BroadPhaseLayerFilter();
#if hl
objFilter = new jolt.Jt.ObjectLayerFilter();
#end
bodyFilter = new jolt.Jt.BodyFilter();
shapeFilter = new jolt.Jt.ShapeFilter();
narrowPhaseQuery = null;
}
if (!physicsReady) {
@ -220,6 +253,10 @@ class PhysicsWorld extends Trait {
joltInterface = new jolt.Jt.JoltInterface(settings);
physicsSystem = joltInterface.GetPhysicsSystem();
bodyInterface = physicsSystem.GetBodyInterface();
if (objFilter == null) {
objFilter = new jolt.Jt.DefaultObjectLayerFilter(objectLayerPair, 0);
}
#end
physicsReady = true;
@ -243,8 +280,9 @@ class PhysicsWorld extends Trait {
}
public function addRigidBody(body:RigidBody, activate:Bool = true) {
bodyInterface.AddBody(body.bodyId, activate ? 1 : 0);
bodyInterface.AddBody(body.bodyId, activate ? 0 : 1);
rbMap.set(body.id, body);
bodyIdMap.set(body.bodyId.GetIndex(), body);
}
public function addPhysicsConstraint(constraint:PhysicsConstraint) {
@ -262,6 +300,7 @@ class PhysicsWorld extends Trait {
bodyInterface.RemoveBody(body.bodyId);
bodyInterface.DestroyBody(body.bodyId);
rbMap.remove(body.id);
bodyIdMap.remove(body.bodyId.GetIndex());
}
public function removePhysicsConstraint(constraint:PhysicsConstraint) {
@ -354,41 +393,39 @@ class PhysicsWorld extends Trait {
var dirY = to.y - from.y;
var dirZ = to.z - from.z;
var origin = new jolt.Jt.RVec3(from.x, from.y, from.z);
var direction = new jolt.Jt.Vec3(dirX, dirY, dirZ);
var ray = new jolt.Jt.RRayCast(origin, direction);
var result = new jolt.Jt.RayCastResult();
var narrowPhase = physicsSystem.GetNarrowPhaseQuery();
var didHit = narrowPhase.CastRay(ray, result);
// reuse cached objects
rayOrigin.Set(from.x, from.y, from.z);
rayDir.Set(dirX, dirY, dirZ);
cachedRay.mOrigin = rayOrigin;
cachedRay.mDirection = rayDir;
if (narrowPhaseQuery == null){
narrowPhaseQuery = physicsSystem.GetNarrowPhaseQuery();
}
rayResult.mFraction = 1.0;
#if hl
var didHit = narrowPhaseQuery.CastRay(cachedRay, rayResult, raySettings, bpFilter, objFilter, bodyFilter, shapeFilter);
#else
rayCollector.Reset();
narrowPhaseQuery.CastRay(cachedRay, raySettings, rayCollector, bpFilter, objFilter, bodyFilter, shapeFilter);
var didHit = rayCollector.HadHit();
if (didHit) {
var bodyId = result.mBodyID;
var fraction = result.mFraction;
var hit = rayCollector.mHit;
rayResult.mBodyID = hit.mBodyID;
rayResult.mFraction = hit.mFraction;
}
#end
var fraction = rayResult.mFraction;
if (didHit && fraction < 1.0) {
var bodyId = rayResult.mBodyID;
hitPointWorld.set(from.x + dirX * fraction, from.y + dirY * fraction, from.z + dirZ * fraction);
// Find rigid body by ID
for (rb in rbMap) {
if (rb.bodyId.GetIndex() == bodyId.GetIndex()) {
#if hl
origin.delete();
direction.delete();
ray.delete();
result.delete();
#end
return new Hit(rb, hitPointWorld.clone(), hitNormalWorld.clone());
}
var rb = bodyIdMap.get(bodyId.GetIndex());
if (rb != null) {
return new Hit(rb, hitPointWorld.clone(), hitNormalWorld.clone());
}
}
#if hl
origin.delete();
direction.delete();
ray.delete();
result.delete();
#end
return null;
}

View File

@ -9,7 +9,7 @@ import iron.data.SceneFormat;
import iron.object.Transform;
import iron.object.MeshObject;
@:enum abstract Shape(Int) from Int to Int {
enum abstract Shape(Int) from Int to Int {
var Box = 0;
var Sphere = 1;
var ConvexHull = 2;
@ -410,14 +410,14 @@ class RigidBody extends Trait {
var scalePos = mo.data.scalePos;
var numVerts = Std.int(positions.length / 4);
var settings:Dynamic = untyped __js__("new Jolt.ConvexHullShapeSettings()");
var settings:Dynamic = new jolt.Jt.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);
var pt:Dynamic = new jolt.Jt.Vec3(x, y, z);
untyped points.push_back(pt);
}
@ -439,7 +439,7 @@ class RigidBody extends Trait {
var scalePos = mo.data.scalePos;
var numVerts = Std.int(positions.length / 4);
var settings:Dynamic = untyped __js__("new Jolt.MeshShapeSettings()");
var settings:Dynamic = new jolt.Jt.MeshShapeSettings();
var verts:Dynamic = untyped settings.mTriangleVertices;
var tris:Dynamic = untyped settings.mIndexedTriangles;
verts.clear();
@ -449,14 +449,14 @@ class RigidBody extends Trait {
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);
var v:Dynamic = new jolt.Jt.Float3(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()");
var tri:Dynamic = new jolt.Jt.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]);
@ -482,6 +482,25 @@ class RigidBody extends Trait {
var currentRotZ:Float = 0;
var currentRotW:Float = 1;
#if hl
public static var hlPos:jolt.Jt.RVec3 = null;
public static var hlRot:jolt.Jt.Quat = null;
public static var hlVel:jolt.Jt.Vec3 = null;
public static var hlForce:jolt.Jt.Vec3 = null;
public static var hlPosR:jolt.Jt.RVec3 = null;
public static var hlQuat:jolt.Jt.Quat = null;
public static function hlInitVars() {
if (hlPos != null) return;
hlPos = new jolt.Jt.RVec3(0, 0, 0);
hlRot = new jolt.Jt.Quat(0, 0, 0, 1);
hlVel = new jolt.Jt.Vec3(0, 0, 0);
hlForce = new jolt.Jt.Vec3(0, 0, 0);
hlPosR = new jolt.Jt.RVec3(0, 0, 0);
hlQuat = new jolt.Jt.Quat(0, 0, 0, 1);
}
#end
public function physicsUpdate() {
if (!ready)
return;
@ -494,18 +513,26 @@ class RigidBody extends Trait {
return;
}
var active = physics.bodyInterface.IsActive(bodyId);
if (!active) {
// Activate body if sleeping
physics.bodyInterface.ActivateBody(bodyId);
#if hl
if (!body.IsActive())
return;
}
// Read position and rotation from Jolt into cached state
body.GetPositionInto(hlPos);
body.GetRotationInto(hlRot);
currentPosX = hlPos.GetX();
currentPosY = hlPos.GetY();
currentPosZ = hlPos.GetZ();
currentRotX = hlRot.GetX();
currentRotY = hlRot.GetY();
currentRotZ = hlRot.GetZ();
currentRotW = hlRot.GetW();
#else
// JS/WASM: re-activate sleeping bodies (Jolt deactivates even with mAllowSleeping=false in WASM)
if (!physics.bodyInterface.IsActive(bodyId))
physics.bodyInterface.ActivateBody(bodyId);
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();
@ -513,17 +540,6 @@ class RigidBody extends Trait {
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
}
@ -554,50 +570,78 @@ class RigidBody extends Trait {
// Physics methods
public function applyForce(force:Vec4, ?loc:Vec4) {
activate();
#if hl
hlForce.Set(force.x, force.y, force.z);
if (loc == null) {
physics.bodyInterface.AddForce(bodyId, hlForce);
} else {
hlPosR.Set(loc.x, loc.y, loc.z);
physics.bodyInterface.AddForceAtPosition(bodyId, hlForce, hlPosR);
}
#else
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
}
#end
}
public function applyImpulse(impulse:Vec4, ?loc:Vec4) {
activate();
#if hl
hlForce.Set(impulse.x, impulse.y, impulse.z);
if (loc == null) {
physics.bodyInterface.AddImpulse(bodyId, hlForce);
} else {
hlPosR.Set(loc.x, loc.y, loc.z);
physics.bodyInterface.AddImpulseAtPosition(bodyId, hlForce, hlPosR);
}
#else
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
}
#end
}
public function applyTorque(torque:Vec4) {
activate();
#if hl
hlForce.Set(torque.x, torque.y, torque.z);
physics.bodyInterface.AddTorque(bodyId, hlForce);
#else
var t = new jolt.Jt.Vec3(torque.x, torque.y, torque.z);
physics.bodyInterface.AddTorque(bodyId, t);
#if hl t.delete(); #end
#end
}
public function applyTorqueImpulse(impulse:Vec4) {
activate();
#if hl
hlForce.Set(impulse.x, impulse.y, impulse.z);
physics.bodyInterface.AddAngularImpulse(bodyId, hlForce);
#else
var i = new jolt.Jt.Vec3(impulse.x, impulse.y, impulse.z);
physics.bodyInterface.AddAngularImpulse(bodyId, i);
#if hl i.delete(); #end
#end
}
public function setLinearVelocity(v:Vec4) {
#if hl
hlVel.Set(v.x, v.y, v.z);
physics.bodyInterface.SetLinearVelocity(bodyId, hlVel);
#else
var vel = new jolt.Jt.Vec3(v.x, v.y, v.z);
physics.bodyInterface.SetLinearVelocity(bodyId, vel);
#if hl vel.delete(); #end
#end
}
public function getLinearVelocity():Vec4 {
@ -608,9 +652,13 @@ class RigidBody extends Trait {
}
public function setAngularVelocity(v:Vec4) {
#if hl
hlVel.Set(v.x, v.y, v.z);
physics.bodyInterface.SetAngularVelocity(bodyId, hlVel);
#else
var vel = new jolt.Jt.Vec3(v.x, v.y, v.z);
physics.bodyInterface.SetAngularVelocity(bodyId, vel);
#if hl vel.delete(); #end
#end
}
public function getAngularVelocity():Vec4 {
@ -643,15 +691,23 @@ class RigidBody extends Trait {
}
public function setPosition(pos:Vec4) {
#if hl
hlPos.Set(pos.x, pos.y, pos.z);
physics.bodyInterface.SetPosition(bodyId, hlPos, 0);
#else
var p = new jolt.Jt.RVec3(pos.x, pos.y, pos.z);
physics.bodyInterface.SetPosition(bodyId, p, 0);
#if hl p.delete(); #end
#end
}
public function setRotation(rot:Quat) {
#if hl
hlQuat.Set(rot.x, rot.y, rot.z, rot.w);
physics.bodyInterface.SetRotation(bodyId, hlQuat, 0);
#else
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
#end
}
public function syncTransform() {