const std = @import("std"); pub const zphysics = @import("zphysics"); pub const core = @import("core"); pub const PhysicsCollider = @import("physicsCollider.zig").PhysicsCollider; pub const PhysicsCharacter = @import("physicsCharacter.zig").PhysicsCharacter; pub const ConvexShapeSettings = zphysics.ConvexShapeSettings; pub const BoxShapeSettings = zphysics.BoxShapeSettings; pub const SphereShapeSettings = zphysics.SphereShapeSettings; pub const TriangleShapeSettings = zphysics.TriangleShapeSettings; pub const CapsuleShapeSettings = zphysics.CapsuleShapeSettings; pub const TaperedCapsuleShapeSettings = zphysics.TaperedCapsuleShapeSettings; pub const CylinderShapeSettings = zphysics.CylinderShapeSettings; pub const ConvexHullShapeSettings = zphysics.ConvexHullShapeSettings; pub const HeightFieldShapeSettings = zphysics.HeightFieldShapeSettings; pub const MeshShapeSettings = zphysics.MeshShapeSettings; pub const DecoratedShapeSettings = zphysics.DecoratedShapeSettings; pub const CompoundShapeSettings = zphysics.CompoundShapeSettings; pub const BodyId = zphysics.BodyId; pub const ShapeSettings = runtime.ShapeSettings; pub const BodyCreationSettings = zphysics.BodyCreationSettings; pub const Activation = zphysics.Activation; pub const ObjectLayers = runtime.ObjectLayers; const runtime = @import("physicsSystem.zig"); pub const IgnoreFixedBodiesFilter = runtime.IgnoreFixedBodiesFilter; pub const PrimitiveType = enum { box, sphere, }; pub const ComponentList = struct { pub const _PhysicsCharacter = PhysicsCharacter; pub const _PhysicsCollider = PhysicsCollider; }; // low level helpers - old api pub fn addPrimitiveBody(primitive: PrimitiveType, settings: BodyCreationSettings, activationMode: Activation) !BodyId { const interface = context().system.getBodyInterfaceMut(); var s = settings; switch (primitive) { .box => { s.shape = context().primBoxShape; }, .sphere => { s.shape = context().primSphereShape; }, } return try interface.createAndAddBody(s, activationMode); } pub fn setBodyPosition(id: BodyId, pos: core.Vectorf) void { const interface = context().system.getBodyInterfaceMut(); interface.setPosition(id, pos.toArr3(), .activate); } pub fn setBodyRotation(id: BodyId, rot: core.Rotation) void { const interface = context().system.getBodyInterfaceMut(); interface.setRotation(id, rot.quat, .activate); } pub fn optimizeBroadPhase() void { context().system.optimizeBroadPhase(); } pub const context = core.EngineObject(runtime.PhysicsRuntime).get; pub fn removeShape(name: *core.Name) void { context().removeShape(name); } pub fn addShape(name: []const u8, settings: ShapeSettings) !void { var n = core.MakeName(name); try context().createShape(&n, settings); } pub fn start_module(spec: *core.SpecVariantMap, args: anytype, allocator: std.mem.Allocator) !void { _ = args; _ = spec; core.engine_logs("starting physics"); try core.defineComponentList(ComponentList, allocator); _ = try core.createObject(runtime.PhysicsRuntime, .{ .can_tick = true }); } pub fn setupFromModule() void { core.ecs.patchComponentList(ComponentList); } pub fn shutdown_module(allocator: std.mem.Allocator) void { core.undefineComponentList(ComponentList); _ = allocator; // core.getEngineObject(runtime.PhysicsRuntime).?.system.destroy(); } pub const Module: core.ModuleDescription = .{ .name = "physics", .enabledByDefault = false, }; pub fn releaseShape(name: core.Name) void { var n = name; context().shapes.get(n.handle()).?.shape.release(); } pub const RayCastSettings = struct { entityLookup: bool = false, getNormalsSlow: bool = false, bodyFilter: ?*const anyopaque = null, }; pub const RayCastResult = struct { body: BodyId, point: core.Vectorf, normal: ?core.Vectorf = null, // how to get this? entity: ?core.Entity = null, }; pub fn traceLine(start: core.Vectorf, direction: core.Vectorf, settings: RayCastSettings) ?RayCastResult { const query = context().system.getNarrowPhaseQuery(); const result = query.castRay(.{ .origin = start.toZm(), .direction = direction.toZm(), }, .{ .body_filter = @ptrCast(@alignCast(settings.bodyFilter)), }); if (!result.has_hit) { return null; } var rv: RayCastResult = .{ .body = result.hit.body_id, .point = direction.fmul(result.hit.fraction).add(start), }; if (settings.entityLookup) { rv.entity = context().idToEntity.get(rv.body).?; } // VERY SLOW if (settings.getNormalsSlow) { const lock_interface = context().system.getBodyLockInterfaceNoLock(); var read_lock: zphysics.BodyLockRead = .{}; read_lock.lock(lock_interface, rv.body); defer read_lock.unlock(); if (read_lock.body) |body| { rv.normal = core.Vectorf.fromArr3(body.getWorldSpaceSurfaceNormal(result.hit.sub_shape_id, rv.point.toArr3())); } } return rv; } pub fn applyForce(body: BodyId, impulse: core.Vectorf, position: core.Vectorf) void { const interface = context().system.getBodyInterfaceMut(); interface.addImpulseAtPosition(body, impulse.toArr3(), position.toArr3()); }