4500 lines
175 KiB
Zig
4500 lines
175 KiB
Zig
const builtin = @import("builtin");
|
|
const std = @import("std");
|
|
const assert = std.debug.assert;
|
|
const options = @import("zphysics_options");
|
|
const c = @cImport({
|
|
if (options.use_double_precision) @cDefine("JPH_DOUBLE_PRECISION", "");
|
|
if (options.enable_asserts) @cDefine("JPH_ENABLE_ASSERTS", "");
|
|
if (options.enable_cross_platform_determinism) @cDefine("JPH_CROSS_PLATFORM_DETERMINISTIC", "");
|
|
if (options.enable_debug_renderer) @cDefine("JPH_DEBUG_RENDERER", "");
|
|
@cInclude("JoltPhysicsC.h");
|
|
});
|
|
|
|
pub const Real = c.JPC_Real;
|
|
comptime {
|
|
assert(if (options.use_double_precision) Real == f64 else Real == f32);
|
|
}
|
|
|
|
pub const rvec_align = if (Real == f64) 32 else 16;
|
|
|
|
pub const flt_epsilon = c.JPC_FLT_EPSILON;
|
|
|
|
pub const Material = opaque {};
|
|
pub const GroupFilter = opaque {};
|
|
pub const BodyLockInterface = opaque {};
|
|
pub const SharedMutex = opaque {};
|
|
|
|
pub const BroadPhaseLayer = c.JPC_BroadPhaseLayer;
|
|
pub const ObjectLayer = c.JPC_ObjectLayer;
|
|
pub const BodyId = c.JPC_BodyID;
|
|
pub const SubShapeId = c.JPC_SubShapeID;
|
|
|
|
pub const max_physics_jobs = c.JPC_MAX_PHYSICS_JOBS;
|
|
pub const max_physics_barriers = c.JPC_MAX_PHYSICS_BARRIERS;
|
|
|
|
pub const body_id_invalid: BodyId = c.JPC_BODY_ID_INVALID;
|
|
pub const body_id_index_bits: BodyId = c.JPC_BODY_ID_INDEX_BITS;
|
|
pub const body_id_sequence_bits: BodyId = c.JPC_BODY_ID_SEQUENCE_BITS;
|
|
pub const body_id_sequence_shift: BodyId = c.JPC_BODY_ID_SEQUENCE_SHIFT;
|
|
|
|
pub const sub_shape_id_empty: SubShapeId = c.JPC_SUB_SHAPE_ID_EMPTY;
|
|
|
|
pub const debug_renderer_enabled = options.enable_debug_renderer;
|
|
comptime {
|
|
assert(if (debug_renderer_enabled) c.JPC_DEBUG_RENDERER == 1 else c.JPC_DEBUG_RENDERER == 0);
|
|
}
|
|
|
|
const TempAllocator = opaque {};
|
|
const JobSystem = opaque {};
|
|
|
|
/// Check if this is a valid body pointer.
|
|
/// When a body is freed the memory that the pointer occupies is reused to store a freelist.
|
|
/// NOTE: This function is *not* protected by a lock, use with care!
|
|
pub inline fn isValidBodyPointer(body: *const Body) bool {
|
|
return (@intFromPtr(body) & c._JPC_IS_FREED_BODY_BIT) == 0;
|
|
}
|
|
|
|
/// Access a body, will return a `null` if the `body_id` is no longer valid.
|
|
/// Use `PhysicsSystem.getBodies()` to get all the bodies.
|
|
/// NOTE: This function is *not* protected by a lock, use with care!
|
|
pub inline fn tryGetBody(all_bodies: []const *const Body, body_id: BodyId) ?*const Body {
|
|
const body = all_bodies[body_id & body_id_index_bits];
|
|
return if (isValidBodyPointer(body) and body.id == body_id) body else null;
|
|
}
|
|
/// Access a body, will return a `null` if the `body_id` is no longer valid.
|
|
/// Use `PhysicsSystem.getBodiesMut()` to get all the bodies.
|
|
/// NOTE: This function is *not* protected by a lock, use with care!
|
|
pub inline fn tryGetBodyMut(all_bodies: []const *Body, body_id: BodyId) ?*Body {
|
|
const body = all_bodies[body_id & body_id_index_bits];
|
|
return if (isValidBodyPointer(body) and body.id == body_id) body else null;
|
|
}
|
|
|
|
pub const VTableHeader = switch (@import("builtin").abi) {
|
|
.msvc => extern struct {
|
|
__header: ?*const anyopaque = null,
|
|
},
|
|
else => extern struct {
|
|
__header: [2]?*const anyopaque = [_]?*const anyopaque{null} ** 2,
|
|
},
|
|
};
|
|
|
|
pub const BroadPhaseLayerInterface = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn getNumBroadPhaseLayers(self: *const T) u32 {
|
|
return @as(*const BroadPhaseLayerInterface.VTable, @ptrCast(self.__v))
|
|
.getNumBroadPhaseLayers(@as(*const BroadPhaseLayerInterface, @ptrCast(self)));
|
|
}
|
|
pub inline fn getBroadPhaseLayer(self: *const T, layer: ObjectLayer) u32 {
|
|
return @as(*const BroadPhaseLayerInterface.VTable, @ptrCast(self.__v))
|
|
.getBroadPhaseLayer(@as(*const BroadPhaseLayerInterface, @ptrCast(self)), layer);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
getNumBroadPhaseLayers: *const fn (self: *const BroadPhaseLayerInterface) callconv(.C) u32,
|
|
getBroadPhaseLayer: if (@import("builtin").abi == .msvc)
|
|
*const fn (
|
|
self: *const BroadPhaseLayerInterface,
|
|
out_layer: *BroadPhaseLayer,
|
|
layer: ObjectLayer,
|
|
) callconv(.C) *const BroadPhaseLayer
|
|
else
|
|
*const fn (
|
|
self: *const BroadPhaseLayerInterface,
|
|
layer: ObjectLayer,
|
|
) callconv(.C) BroadPhaseLayer,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_BroadPhaseLayerInterfaceVTable));
|
|
assert(@offsetOf(VTable, "getBroadPhaseLayer") == @offsetOf(
|
|
c.JPC_BroadPhaseLayerInterfaceVTable,
|
|
"GetBroadPhaseLayer",
|
|
));
|
|
}
|
|
};
|
|
|
|
pub const ObjectVsBroadPhaseLayerFilter = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn shouldCollide(self: *const T, layer1: ObjectLayer, layer2: BroadPhaseLayer) bool {
|
|
return @as(*const ObjectVsBroadPhaseLayerFilter.VTable, @ptrCast(self.__v))
|
|
.shouldCollide(@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(self)), layer1, layer2);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
shouldCollide: *const fn (
|
|
self: *const ObjectVsBroadPhaseLayerFilter,
|
|
layer1: ObjectLayer,
|
|
layer2: BroadPhaseLayer,
|
|
) callconv(.C) bool,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_ObjectVsBroadPhaseLayerFilterVTable));
|
|
assert(@offsetOf(VTable, "shouldCollide") == @offsetOf(
|
|
c.JPC_ObjectVsBroadPhaseLayerFilterVTable,
|
|
"ShouldCollide",
|
|
));
|
|
}
|
|
};
|
|
|
|
pub const BroadPhaseLayerFilter = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn shouldCollide(self: *const T, layer: BroadPhaseLayer) bool {
|
|
return @as(*const BroadPhaseLayerFilter.VTable, @ptrCast(self.__v))
|
|
.shouldCollide(@as(*const BroadPhaseLayerFilter, @ptrCast(self)), layer);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
shouldCollide: *const fn (
|
|
self: *const BroadPhaseLayerFilter,
|
|
layer: BroadPhaseLayer,
|
|
) callconv(.C) bool,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_BroadPhaseLayerFilterVTable));
|
|
assert(
|
|
@offsetOf(VTable, "shouldCollide") == @offsetOf(c.JPC_BroadPhaseLayerFilterVTable, "ShouldCollide"),
|
|
);
|
|
}
|
|
};
|
|
|
|
pub const ObjectLayerPairFilter = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn shouldCollide(self: *const T, layer1: ObjectLayer, layer2: ObjectLayer) bool {
|
|
return @as(*const ObjectLayerPairFilter.VTable, @ptrCast(self.__v))
|
|
.shouldCollide(@as(*const ObjectLayerPairFilter, @ptrCast(self)), layer1, layer2);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
shouldCollide: *const fn (self: *const ObjectLayerPairFilter, ObjectLayer, ObjectLayer) callconv(.C) bool,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_ObjectLayerPairFilterVTable));
|
|
assert(
|
|
@offsetOf(VTable, "shouldCollide") == @offsetOf(c.JPC_ObjectLayerPairFilterVTable, "ShouldCollide"),
|
|
);
|
|
}
|
|
};
|
|
|
|
pub const ObjectLayerFilter = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn shouldCollide(self: *const T, layer: ObjectLayer) bool {
|
|
return @as(*const ObjectLayerFilter.VTable, @ptrCast(self.__v))
|
|
.shouldCollide(@as(*const ObjectLayerFilter, @ptrCast(self)), layer);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
shouldCollide: *const fn (self: *const ObjectLayerFilter, ObjectLayer) callconv(.C) bool,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_ObjectLayerFilterVTable));
|
|
assert(@offsetOf(VTable, "shouldCollide") == @offsetOf(c.JPC_ObjectLayerFilterVTable, "ShouldCollide"));
|
|
}
|
|
};
|
|
|
|
pub const PhysicsStepListener = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn onStep(self: *const T, delta_time: f32, physics_system: *PhysicsSystem) void {
|
|
return @as(*const PhysicsStepListener.VTable, @ptrCast(self.__v))
|
|
.onStep(@as(*PhysicsStepListener, @ptrCast(self)), delta_time, physics_system);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
onStep: *const fn (self: *PhysicsStepListener, f32, *PhysicsSystem) callconv(.C) void,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_PhysicsStepListenerVTable));
|
|
assert(@offsetOf(VTable, "onStep") == @offsetOf(c.JPC_PhysicsStepListenerVTable, "OnStep"));
|
|
}
|
|
};
|
|
|
|
pub const BodyActivationListener = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn onBodyActivated(
|
|
self: *T,
|
|
body_id: *const BodyId,
|
|
user_data: u64,
|
|
) void {
|
|
@as(*const BodyActivationListener.VTable, @ptrCast(self.__v))
|
|
.onBodyActivated(@as(*const BodyActivationListener, @ptrCast(self)), body_id, user_data);
|
|
}
|
|
pub inline fn onBodyDeactivated(
|
|
self: *T,
|
|
body_id: *const BodyId,
|
|
user_data: u64,
|
|
) void {
|
|
@as(*const BodyActivationListener.VTable, @ptrCast(self.__v))
|
|
.onBodyDeactivated(@as(*const BodyActivationListener, @ptrCast(self)), body_id, user_data);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
onBodyActivated: *const fn (
|
|
self: *BodyActivationListener,
|
|
body_id: *const BodyId,
|
|
user_data: u64,
|
|
) callconv(.C) void,
|
|
onBodyDeactivated: *const fn (
|
|
self: *BodyActivationListener,
|
|
body_id: *const BodyId,
|
|
user_data: u64,
|
|
) callconv(.C) void,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_BodyActivationListenerVTable));
|
|
assert(@offsetOf(VTable, "onBodyDeactivated") == @offsetOf(
|
|
c.JPC_BodyActivationListenerVTable,
|
|
"OnBodyDeactivated",
|
|
));
|
|
}
|
|
};
|
|
|
|
pub const CharacterContactListener = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn OnAdjustBodyVelocity(
|
|
self: *const T,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
io_linear_velocity: *[3]f32,
|
|
io_angular_velocity: *[3]f32,
|
|
) void {
|
|
return @as(*const CharacterContactListener.VTable, @ptrCast(self.__v)).OnAdjustBodyVelocity(
|
|
@as(*CharacterContactListener, @ptrCast(self)),
|
|
character,
|
|
body,
|
|
io_linear_velocity,
|
|
io_angular_velocity,
|
|
);
|
|
}
|
|
pub inline fn OnContactValidate(
|
|
self: *const T,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
sub_shape_id: *const SubShapeId,
|
|
) bool {
|
|
return @as(*const CharacterContactListener.VTable, @ptrCast(self.__v)).OnContactValidate(
|
|
@as(*CharacterContactListener, @ptrCast(self)),
|
|
character,
|
|
body,
|
|
sub_shape_id,
|
|
);
|
|
}
|
|
pub inline fn OnContactAdded(
|
|
self: *const T,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
sub_shape_id: *const SubShapeId,
|
|
contact_position: *const [3]Real,
|
|
contact_normal: *const [3]f32,
|
|
io_settings: *CharacterContactSettings,
|
|
) void {
|
|
return @as(*const CharacterContactListener.VTable, @ptrCast(self.__v)).OnContactAdded(
|
|
@as(*CharacterContactListener, @ptrCast(self)),
|
|
character,
|
|
body,
|
|
sub_shape_id,
|
|
contact_position,
|
|
contact_normal,
|
|
io_settings,
|
|
);
|
|
}
|
|
pub inline fn OnContactSolve(
|
|
self: *const T,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
sub_shape_id: *const SubShapeId,
|
|
contact_position: *const [3]Real,
|
|
contact_normal: *const [3]f32,
|
|
contact_velocity: *const [3]f32,
|
|
contact_material: *const Material,
|
|
character_velocity: *const [3]f32,
|
|
character_velocity_out: *[3]f32,
|
|
) void {
|
|
return @as(*const CharacterContactListener.VTable, @ptrCast(self.__v)).OnContactSolve(
|
|
@as(*CharacterContactListener, @ptrCast(self)),
|
|
character,
|
|
body,
|
|
sub_shape_id,
|
|
contact_position,
|
|
contact_normal,
|
|
contact_velocity,
|
|
contact_material,
|
|
character_velocity,
|
|
character_velocity_out,
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
OnAdjustBodyVelocity: *const fn (
|
|
self: *CharacterContactListener,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
io_linear_velocity: *[3]f32,
|
|
io_angular_velocity: *[3]f32,
|
|
) callconv(.C) void,
|
|
OnContactValidate: *const fn (
|
|
self: *CharacterContactListener,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
sub_shape_id: *const SubShapeId,
|
|
) callconv(.C) bool,
|
|
OnContactAdded: *const fn (
|
|
self: *CharacterContactListener,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
sub_shape_id: *const SubShapeId,
|
|
contact_position: *const [3]Real,
|
|
contact_normal: *const [3]f32,
|
|
io_settings: *CharacterContactSettings,
|
|
) callconv(.C) void,
|
|
OnContactSolve: *const fn (
|
|
self: *CharacterContactListener,
|
|
character: *const CharacterVirtual,
|
|
body: *const Body,
|
|
sub_shape_id: *const SubShapeId,
|
|
contact_position: *const [3]Real,
|
|
contact_normal: *const [3]f32,
|
|
contact_velocity: *const [3]f32,
|
|
contact_material: *const Material,
|
|
character_velocity: *const [3]f32,
|
|
character_velocity_out: *[3]f32,
|
|
) callconv(.C) void,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_CharacterContactListenerVTable));
|
|
assert(@offsetOf(VTable, "OnAdjustBodyVelocity") == @offsetOf(c.JPC_CharacterContactListenerVTable, "OnAdjustBodyVelocity"));
|
|
assert(@offsetOf(VTable, "OnContactSolve") == @offsetOf(c.JPC_CharacterContactListenerVTable, "OnContactSolve"));
|
|
}
|
|
};
|
|
|
|
pub const ContactListener = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn onContactValidate(
|
|
self: *T,
|
|
body1: *const Body,
|
|
body2: *const Body,
|
|
base_offset: *const [3]Real,
|
|
collision_result: *const CollideShapeResult,
|
|
) ValidateResult {
|
|
return @as(*const ContactListener.VTable, @ptrCast(self.__v))
|
|
.onContactValidate(
|
|
@as(*const ContactListener, @ptrCast(self)),
|
|
body1,
|
|
body2,
|
|
base_offset,
|
|
collision_result,
|
|
);
|
|
}
|
|
pub inline fn onContactAdded(
|
|
self: *T,
|
|
body1: *const Body,
|
|
body2: *const Body,
|
|
manifold: *const ContactManifold,
|
|
settings: *ContactSettings,
|
|
) void {
|
|
@as(*const ContactListener.VTable, @ptrCast(self.__v))
|
|
.onContactAdded(@as(*const ContactListener, @ptrCast(self)), body1, body2, manifold, settings);
|
|
}
|
|
pub inline fn onContactPersisted(
|
|
self: *T,
|
|
body1: *const Body,
|
|
body2: *const Body,
|
|
manifold: *const ContactManifold,
|
|
settings: *ContactSettings,
|
|
) void {
|
|
@as(*const ContactListener.VTable, @ptrCast(self.__v))
|
|
.onContactPersisted(@as(*const ContactListener, @ptrCast(self)), body1, body2, manifold, settings);
|
|
}
|
|
pub inline fn onContactRemoved(
|
|
self: *T,
|
|
sub_shape_pair: *const SubShapeIdPair,
|
|
) void {
|
|
@as(*const ContactListener.VTable, @ptrCast(self.__v))
|
|
.onContactRemoved(@as(*const ContactListener, @ptrCast(self)), sub_shape_pair);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
onContactValidate: ?*const fn (
|
|
self: *ContactListener,
|
|
body1: *const Body,
|
|
body2: *const Body,
|
|
base_offset: *const [3]Real,
|
|
collision_result: *const CollideShapeResult,
|
|
) callconv(.C) ValidateResult = null,
|
|
|
|
onContactAdded: ?*const fn (
|
|
self: *ContactListener,
|
|
body1: *const Body,
|
|
body2: *const Body,
|
|
manifold: *const ContactManifold,
|
|
settings: *ContactSettings,
|
|
) callconv(.C) void = null,
|
|
|
|
onContactPersisted: ?*const fn (
|
|
self: *ContactListener,
|
|
body1: *const Body,
|
|
body2: *const Body,
|
|
manifold: *const ContactManifold,
|
|
settings: *ContactSettings,
|
|
) callconv(.C) void = null,
|
|
|
|
onContactRemoved: ?*const fn (
|
|
self: *ContactListener,
|
|
sub_shape_pair: *const SubShapeIdPair,
|
|
) callconv(.C) void = null,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_ContactListenerVTable));
|
|
assert(@offsetOf(VTable, "onContactAdded") == @offsetOf(
|
|
c.JPC_ContactListenerVTable,
|
|
"OnContactAdded",
|
|
));
|
|
assert(
|
|
@offsetOf(VTable, "onContactRemoved") == @offsetOf(c.JPC_ContactListenerVTable, "OnContactRemoved"),
|
|
);
|
|
}
|
|
};
|
|
|
|
pub const BodyFilter = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn shouldCollide(self: *const T, body_id: *const BodyId) bool {
|
|
return @as(*const BodyFilter.VTable, @ptrCast(self.__v))
|
|
.shouldCollide(@as(*const BodyFilter, @ptrCast(self)), body_id);
|
|
}
|
|
pub inline fn shouldCollideLocked(self: *const T, body: *const Body) bool {
|
|
return @as(*const BodyFilter.VTable, @ptrCast(self.__v))
|
|
.shouldCollideLocked(@as(*const BodyFilter, @ptrCast(self)), body);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
shouldCollide: *const fn (self: *const BodyFilter, body_id: *const BodyId) callconv(.C) bool,
|
|
shouldCollideLocked: *const fn (self: *const BodyFilter, body: *const Body) callconv(.C) bool,
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_BodyFilterVTable));
|
|
assert(@offsetOf(VTable, "shouldCollide") == @offsetOf(c.JPC_BodyFilterVTable, "ShouldCollide"));
|
|
assert(
|
|
@offsetOf(VTable, "shouldCollideLocked") == @offsetOf(c.JPC_BodyFilterVTable, "ShouldCollideLocked"),
|
|
);
|
|
}
|
|
};
|
|
|
|
pub const ShapeFilter = extern struct {
|
|
__v: *const VTable,
|
|
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn shouldCollide(
|
|
self: *const T,
|
|
receiving_body_id: u32,
|
|
shape: *const Shape,
|
|
sub_shape_id: *const SubShapeId,
|
|
) bool {
|
|
_ = receiving_body_id;
|
|
return @as(*const ShapeFilter.VTable, @ptrCast(self.__v)).shouldCollide(
|
|
@as(*const ShapeFilter, @ptrCast(self)),
|
|
@as(*const ShapeFilter.VTable, @ptrCast(self.__v)).receiving_body_id,
|
|
shape,
|
|
sub_shape_id,
|
|
);
|
|
}
|
|
pub inline fn pairShouldCollide(
|
|
self: *const T,
|
|
receiving_body_id: u32,
|
|
shape1: *const Shape,
|
|
sub_shape_id1: *const SubShapeId,
|
|
shape2: *const Shape,
|
|
sub_shape_id2: *const SubShapeId,
|
|
) bool {
|
|
_ = receiving_body_id;
|
|
return @as(*const ShapeFilter.VTable, @ptrCast(self.__v)).pairShouldCollide(@as(*const ShapeFilter, @ptrCast(self)), @as(*const ShapeFilter.VTable, @ptrCast(self.__v)).receiving_body_id, shape1, sub_shape_id1, shape2, sub_shape_id2);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub const VTable = extern struct {
|
|
__header: VTableHeader = .{},
|
|
shouldCollide: *const fn (
|
|
self: *const ShapeFilter,
|
|
shape: *const Shape,
|
|
sub_shape_id: *const SubShapeId,
|
|
) callconv(.C) bool,
|
|
pairShouldCollide: *const fn (
|
|
self: *const ShapeFilter,
|
|
shape1: *const Shape,
|
|
sub_shape_id1: *const SubShapeId,
|
|
shape2: *const Shape,
|
|
sub_shape_id2: *const SubShapeId,
|
|
) callconv(.C) bool,
|
|
receiving_body_id: u32 = body_id_invalid, // set by jolt before each call to either of the functions above
|
|
};
|
|
|
|
comptime {
|
|
assert(@sizeOf(VTable) == @sizeOf(c.JPC_ShapeFilterVTable));
|
|
assert(@offsetOf(VTable, "shouldCollide") == @offsetOf(c.JPC_ShapeFilterVTable, "ShouldCollide"));
|
|
assert(@offsetOf(VTable, "receiving_body_id") == @offsetOf(c.JPC_ShapeFilterVTable, "bodyId2"));
|
|
}
|
|
};
|
|
|
|
pub const ContactSettings = extern struct {
|
|
combined_friction: f32,
|
|
combined_restitution: f32,
|
|
is_sensor: bool,
|
|
|
|
comptime {
|
|
assert(@sizeOf(ContactSettings) == @sizeOf(c.JPC_ContactSettings));
|
|
assert(@offsetOf(ContactSettings, "combined_restitution") == @offsetOf(
|
|
c.JPC_ContactSettings,
|
|
"combined_restitution",
|
|
));
|
|
}
|
|
};
|
|
|
|
pub const MassProperties = extern struct {
|
|
mass: f32 = 0.0,
|
|
inertia: [16]f32 align(16) = [_]f32{0} ** 16,
|
|
|
|
comptime {
|
|
assert(@sizeOf(MassProperties) == @sizeOf(c.JPC_MassProperties));
|
|
assert(@offsetOf(MassProperties, "inertia") == @offsetOf(c.JPC_MassProperties, "inertia"));
|
|
}
|
|
};
|
|
|
|
pub const SubShapeIdPair = extern struct {
|
|
first: extern struct {
|
|
body_id: BodyId,
|
|
sub_shape_id: SubShapeId,
|
|
},
|
|
second: extern struct {
|
|
body_id: BodyId,
|
|
sub_shape_id: SubShapeId,
|
|
},
|
|
|
|
comptime {
|
|
assert(@sizeOf(SubShapeIdPair) == @sizeOf(c.JPC_SubShapeIDPair));
|
|
assert(@offsetOf(SubShapeIdPair, "second") == @offsetOf(c.JPC_SubShapeIDPair, "second"));
|
|
}
|
|
};
|
|
|
|
pub const CollideShapeResult = extern struct {
|
|
shape1_contact_point: [4]f32 align(16), // 4th element is ignored; world space
|
|
shape2_contact_point: [4]f32 align(16), // 4th element is ignored; world space
|
|
penetration_axis: [4]f32 align(16), // 4th element is ignored; world space
|
|
penetration_depth: f32,
|
|
shape1_sub_shape_id: SubShapeId,
|
|
shape2_sub_shape_id: SubShapeId,
|
|
body2_id: BodyId,
|
|
shape1_face: extern struct {
|
|
num_points: u32 align(16),
|
|
points: [32][4]f32 align(16), // 4th element is ignored; world space
|
|
},
|
|
shape2_face: extern struct {
|
|
num_points: u32 align(16),
|
|
points: [32][4]f32 align(16), // 4th element is ignored; world space
|
|
},
|
|
|
|
comptime {
|
|
assert(@sizeOf(CollideShapeResult) == @sizeOf(c.JPC_CollideShapeResult));
|
|
assert(@offsetOf(CollideShapeResult, "shape2_face") == @offsetOf(c.JPC_CollideShapeResult, "shape2_face"));
|
|
}
|
|
};
|
|
|
|
pub const ContactManifold = extern struct {
|
|
base_offset: [4]Real align(rvec_align), // 4th element is ignored; world space
|
|
normal: [4]f32 align(16), // 4th element is ignored; world space
|
|
penetration_depth: f32,
|
|
shape1_sub_shape_id: SubShapeId,
|
|
shape2_sub_shape_id: SubShapeId,
|
|
shape1_relative_contact: extern struct {
|
|
num_points: u32 align(16),
|
|
points: [64][4]f32 align(16), // 4th element is ignored; world space
|
|
},
|
|
shape2_relative_contact: extern struct {
|
|
num_points: u32 align(16),
|
|
points: [64][4]f32 align(16), // 4th element is ignored; world space
|
|
},
|
|
|
|
comptime {
|
|
assert(@sizeOf(ContactManifold) == @sizeOf(c.JPC_ContactManifold));
|
|
assert(@offsetOf(ContactManifold, "shape2_relative_contact") ==
|
|
@offsetOf(c.JPC_ContactManifold, "shape2_relative_contact"));
|
|
}
|
|
};
|
|
|
|
pub const CollisionGroup = extern struct {
|
|
filter: ?*GroupFilter = null,
|
|
group_id: GroupId = invalid_group,
|
|
sub_group_id: SubGroupId = invalid_sub_group,
|
|
|
|
pub const GroupId = c.JPC_CollisionGroupID;
|
|
pub const SubGroupId = c.JPC_CollisionSubGroupID;
|
|
|
|
const invalid_group = @as(GroupId, c.JPC_COLLISION_GROUP_INVALID_GROUP);
|
|
const invalid_sub_group = @as(SubGroupId, c.JPC_COLLISION_GROUP_INVALID_SUB_GROUP);
|
|
|
|
comptime {
|
|
assert(@sizeOf(CollisionGroup) == @sizeOf(c.JPC_CollisionGroup));
|
|
}
|
|
};
|
|
|
|
pub const Activation = enum(c.JPC_Activation) {
|
|
activate = c.JPC_ACTIVATION_ACTIVATE,
|
|
dont_activate = c.JPC_ACTIVATION_DONT_ACTIVATE,
|
|
};
|
|
|
|
pub const ValidateResult = enum(c.JPC_ValidateResult) {
|
|
accept_all_contacts = c.JPC_VALIDATE_RESULT_ACCEPT_ALL_CONTACTS,
|
|
accept_contact = c.JPC_VALIDATE_RESULT_ACCEPT_CONTACT,
|
|
reject_contact = c.JPC_VALIDATE_RESULT_REJECT_CONTACT,
|
|
reject_all_contacts = c.JPC_VALIDATE_RESULT_REJECT_ALL_CONTACTS,
|
|
};
|
|
|
|
pub const MotionType = enum(c.JPC_MotionType) {
|
|
static = c.JPC_MOTION_TYPE_STATIC,
|
|
kinematic = c.JPC_MOTION_TYPE_KINEMATIC,
|
|
dynamic = c.JPC_MOTION_TYPE_DYNAMIC,
|
|
};
|
|
|
|
pub const MotionQuality = enum(c.JPC_MotionQuality) {
|
|
discrete = c.JPC_MOTION_QUALITY_DISCRETE,
|
|
linear_cast = c.JPC_MOTION_QUALITY_LINEAR_CAST,
|
|
};
|
|
|
|
pub const OverrideMassProperties = enum(c.JPC_OverrideMassProperties) {
|
|
calc_mass_inertia = c.JPC_OVERRIDE_MASS_PROPS_CALC_MASS_INERTIA,
|
|
calc_inertia = c.JPC_OVERRIDE_MASS_PROPS_CALC_INERTIA,
|
|
mass_inertia_provided = c.JPC_OVERRIDE_MASS_PROPS_MASS_INERTIA_PROVIDED,
|
|
};
|
|
|
|
pub const CharacterGroundState = enum(c.JPC_CharacterGroundState) {
|
|
on_ground = c.JPC_CHARACTER_GROUND_STATE_ON_GROUND,
|
|
on_steep_ground = c.JPC_CHARACTER_GROUND_STATE_ON_STEEP_GROUND,
|
|
not_supported = c.JPC_CHARACTER_GROUND_STATE_NOT_SUPPORTED,
|
|
in_air = c.JPC_CHARACTER_GROUND_STATE_IN_AIR,
|
|
};
|
|
|
|
pub const BodyCreationSettings = extern struct {
|
|
position: [4]Real align(rvec_align) = .{ 0, 0, 0, 0 }, // 4th element is ignored, also ignored in setupByShape
|
|
rotation: [4]f32 align(16) = .{ 0, 0, 0, 1 }, // ignored in setupByShape
|
|
linear_velocity: [4]f32 align(16) = .{ 0, 0, 0, 0 }, // 4th element is ignored // ignored in SetupByShape
|
|
angular_velocity: [4]f32 align(16) = .{ 0, 0, 0, 0 }, // 4th element is ignored // ignored in SetupByShape
|
|
user_data: u64 = 0,
|
|
object_layer: ObjectLayer = 0,
|
|
collision_group: CollisionGroup = .{},
|
|
motion_type: MotionType = .dynamic,
|
|
allow_dynamic_or_kinematic: bool = false,
|
|
is_sensor: bool = false,
|
|
use_manifold_reduction: bool = true,
|
|
motion_quality: MotionQuality = .discrete,
|
|
allow_sleeping: bool = true,
|
|
friction: f32 = 0.2,
|
|
restitution: f32 = 0.0,
|
|
linear_damping: f32 = 0.05,
|
|
angular_damping: f32 = 0.05,
|
|
max_linear_velocity: f32 = 500.0,
|
|
max_angular_velocity: f32 = 0.25 * c.JPC_PI * 60.0,
|
|
gravity_factor: f32 = 1.0,
|
|
override_mass_properties: OverrideMassProperties = .calc_mass_inertia,
|
|
inertia_multiplier: f32 = 1.0,
|
|
mass_properties_override: MassProperties = .{},
|
|
reserved: ?*const anyopaque = null,
|
|
shape: ?*const Shape = null, // ignored in SetupByShape
|
|
|
|
comptime {
|
|
assert(@sizeOf(BodyCreationSettings) == @sizeOf(c.JPC_BodyCreationSettings));
|
|
assert(@offsetOf(BodyCreationSettings, "is_sensor") == @offsetOf(c.JPC_BodyCreationSettings, "is_sensor"));
|
|
assert(@offsetOf(BodyCreationSettings, "shape") == @offsetOf(c.JPC_BodyCreationSettings, "shape"));
|
|
assert(@offsetOf(BodyCreationSettings, "user_data") == @offsetOf(c.JPC_BodyCreationSettings, "user_data"));
|
|
assert(@offsetOf(BodyCreationSettings, "motion_quality") ==
|
|
@offsetOf(c.JPC_BodyCreationSettings, "motion_quality"));
|
|
}
|
|
};
|
|
|
|
pub const CharacterContactSettings = extern struct {
|
|
can_push_character: bool = true,
|
|
can_receive_impulses: bool = true,
|
|
};
|
|
|
|
pub const CharacterBaseSettings = extern struct {
|
|
__header: VTableHeader = .{},
|
|
up: [4]f32 align(16), // 4th element is ignored
|
|
supporting_volume: [4]f32 align(16), // JPH::Plane - 4th element is used
|
|
max_slope_angle: f32,
|
|
shape: *Shape, // must provide valid shape (such as the typical capsule)
|
|
|
|
comptime {
|
|
assert(@sizeOf(CharacterBaseSettings) == @sizeOf(c.JPC_CharacterBaseSettings));
|
|
assert(@offsetOf(CharacterBaseSettings, "up") == @offsetOf(c.JPC_CharacterBaseSettings, "up"));
|
|
assert(@offsetOf(CharacterBaseSettings, "shape") == @offsetOf(c.JPC_CharacterBaseSettings, "shape"));
|
|
}
|
|
};
|
|
|
|
pub const CharacterSettings = extern struct {
|
|
pub fn create() !*CharacterSettings {
|
|
const settings = c.JPC_CharacterSettings_Create();
|
|
if (settings == null) return error.FailedToCreateCharacterSettings;
|
|
return @as(*CharacterSettings, @ptrCast(settings));
|
|
}
|
|
pub fn release(settings: *CharacterSettings) void {
|
|
c.JPC_CharacterSettings_Release(@as(*c.JPC_CharacterSettings, @ptrCast(settings)));
|
|
}
|
|
pub fn addRef(settings: *CharacterSettings) void {
|
|
c.JPC_CharacterSettings_AddRef(@as(*c.JPC_CharacterSettings, @ptrCast(settings)));
|
|
}
|
|
|
|
base: CharacterBaseSettings,
|
|
layer: ObjectLayer,
|
|
mass: f32,
|
|
friction: f32,
|
|
gravity_factor: f32,
|
|
|
|
comptime {
|
|
assert(@sizeOf(CharacterSettings) == @sizeOf(c.JPC_CharacterSettings));
|
|
assert(@offsetOf(CharacterSettings, "base") == @offsetOf(c.JPC_CharacterSettings, "base"));
|
|
assert(@offsetOf(CharacterSettings, "layer") == @offsetOf(c.JPC_CharacterSettings, "layer"));
|
|
assert(@offsetOf(CharacterSettings, "friction") == @offsetOf(c.JPC_CharacterSettings, "friction"));
|
|
}
|
|
};
|
|
|
|
pub const CharacterVirtualSettings = extern struct {
|
|
pub fn create() !*CharacterVirtualSettings {
|
|
const settings = c.JPC_CharacterVirtualSettings_Create();
|
|
if (settings == null) return error.FailedToCreateCharacterVirtualSettings;
|
|
return @as(*CharacterVirtualSettings, @ptrCast(settings));
|
|
}
|
|
pub fn release(settings: *CharacterVirtualSettings) void {
|
|
c.JPC_CharacterVirtualSettings_Release(@as(*c.JPC_CharacterVirtualSettings, @ptrCast(settings)));
|
|
}
|
|
|
|
base: CharacterBaseSettings,
|
|
mass: f32,
|
|
max_strength: f32,
|
|
shape_offset: [4]f32 align(16), // 4th element is ignored
|
|
back_face_mode: BackFaceMode,
|
|
predictive_contact_distance: f32,
|
|
max_collision_iterations: u32,
|
|
max_constraint_iterations: u32,
|
|
min_time_remaining: f32,
|
|
collision_tolerance: f32,
|
|
character_padding: f32,
|
|
max_num_hits: u32,
|
|
hit_reduction_cos_max_angle: f32,
|
|
penetration_recovery_speed: f32,
|
|
|
|
comptime {
|
|
assert(@sizeOf(CharacterVirtualSettings) == @sizeOf(c.JPC_CharacterVirtualSettings));
|
|
assert(@offsetOf(CharacterVirtualSettings, "base") == @offsetOf(c.JPC_CharacterVirtualSettings, "base"));
|
|
assert(@offsetOf(CharacterVirtualSettings, "mass") == @offsetOf(c.JPC_CharacterVirtualSettings, "mass"));
|
|
assert(@offsetOf(CharacterVirtualSettings, "max_num_hits") ==
|
|
@offsetOf(c.JPC_CharacterVirtualSettings, "max_num_hits"));
|
|
assert(@offsetOf(CharacterVirtualSettings, "penetration_recovery_speed") ==
|
|
@offsetOf(c.JPC_CharacterVirtualSettings, "penetration_recovery_speed"));
|
|
}
|
|
};
|
|
|
|
pub const RRayCast = extern struct {
|
|
origin: [4]Real align(rvec_align), // 4th element is ignored
|
|
direction: [4]f32 align(16), // 4th element is ignored
|
|
|
|
pub fn getPointOnRay(self: RRayCast, fraction: Real) [3]Real {
|
|
return .{
|
|
self.origin[0] + self.direction[0] * fraction,
|
|
self.origin[1] + self.direction[1] * fraction,
|
|
self.origin[2] + self.direction[2] * fraction,
|
|
};
|
|
}
|
|
|
|
comptime {
|
|
assert(@sizeOf(RRayCast) == @sizeOf(c.JPC_RRayCast));
|
|
assert(@offsetOf(RRayCast, "origin") == @offsetOf(c.JPC_RRayCast, "origin"));
|
|
assert(@offsetOf(RRayCast, "direction") == @offsetOf(c.JPC_RRayCast, "direction"));
|
|
}
|
|
};
|
|
|
|
pub const RayCastResult = extern struct {
|
|
body_id: BodyId = body_id_invalid,
|
|
fraction: f32 = 1.0 + flt_epsilon,
|
|
sub_shape_id: SubShapeId = undefined,
|
|
|
|
comptime {
|
|
assert(@sizeOf(RayCastResult) == @sizeOf(c.JPC_RayCastResult));
|
|
assert(@offsetOf(RayCastResult, "body_id") == @offsetOf(c.JPC_RayCastResult, "body_id"));
|
|
assert(@offsetOf(RayCastResult, "fraction") == @offsetOf(c.JPC_RayCastResult, "fraction"));
|
|
assert(@offsetOf(RayCastResult, "sub_shape_id") == @offsetOf(c.JPC_RayCastResult, "sub_shape_id"));
|
|
}
|
|
};
|
|
|
|
pub const BackFaceMode = enum(c.JPC_BackFaceMode) {
|
|
ignore_back_faces = c.JPC_BACK_FACE_IGNORE,
|
|
collide_with_back_faces = c.JPC_BACK_FACE_COLLIDE,
|
|
};
|
|
|
|
pub const RayCastSettings = extern struct {
|
|
back_face_mode: BackFaceMode,
|
|
treat_convex_as_solid: bool,
|
|
|
|
comptime {
|
|
assert(@sizeOf(RayCastSettings) == @sizeOf(c.JPC_RayCastSettings));
|
|
assert(
|
|
@offsetOf(RayCastSettings, "back_face_mode") == @offsetOf(c.JPC_RayCastSettings, "back_face_mode"),
|
|
);
|
|
assert(@offsetOf(RayCastSettings, "treat_convex_as_solid") ==
|
|
@offsetOf(c.JPC_RayCastSettings, "treat_convex_as_solid"));
|
|
}
|
|
};
|
|
|
|
pub const DebugRenderer = if (!debug_renderer_enabled) extern struct {} else extern struct {
|
|
pub fn createSingleton(debug_renderer_impl: *anyopaque) !void {
|
|
switch (@as(DebugRendererResult, @enumFromInt(c.JPC_CreateDebugRendererSingleton(debug_renderer_impl)))) {
|
|
.success => {
|
|
return;
|
|
},
|
|
.duplicate_singleton => {
|
|
return error.DebugRendererDuplicateSingleton;
|
|
},
|
|
.missing_singleton => {
|
|
return error.DebugRendererMissingSingleton;
|
|
},
|
|
.incomplete_impl => {
|
|
return error.DebugRendererIncompleteImplementation;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn destroySingleton() void {
|
|
_ = c.JPC_DestroyDebugRendererSingleton(); // For Zig API, don't care if one actually existed, discard error.
|
|
|
|
}
|
|
|
|
pub fn createTriangleBatch(primitive_in: *const anyopaque) *TriangleBatch {
|
|
return @ptrCast(c.JPC_DebugRenderer_TriangleBatch_Create(primitive_in));
|
|
}
|
|
|
|
pub fn getPrimitiveFromBatch(batch_in: *const TriangleBatch) *const Primitive {
|
|
return @ptrCast(c.JPC_DebugRenderer_TriangleBatch_GetPrimitive(@ptrCast(batch_in)));
|
|
}
|
|
|
|
pub fn createBodyDrawFilter(filter_func: BodyDrawFilterFunc) *BodyDrawFilter {
|
|
return @ptrCast(c.JPC_BodyDrawFilter_Create(@ptrCast(filter_func)));
|
|
}
|
|
|
|
pub fn destroyBodyDrawFilter(filter: *BodyDrawFilter) void {
|
|
c.JPC_BodyDrawFilter_Destroy(@ptrCast(filter));
|
|
}
|
|
|
|
pub fn Methods(comptime T: type) type {
|
|
return extern struct {
|
|
pub inline fn drawLine(self: *T, from: *const [3]Real, to: *const [3]Real, color: *const Color) void {
|
|
return @as(*const DebugRenderer.VTable(T), @ptrCast(self.__v))
|
|
.drawLine(
|
|
@as(*const T, @ptrCast(self)),
|
|
from,
|
|
to,
|
|
color,
|
|
);
|
|
}
|
|
pub inline fn drawTriangle(
|
|
self: *T,
|
|
v1: *const [3]Real,
|
|
v2: *const [3]Real,
|
|
v3: *const [3]Real,
|
|
color: *const Color,
|
|
) void {
|
|
return @as(*const DebugRenderer.VTable(T), @ptrCast(self.__v))
|
|
.drawTriangle(
|
|
@as(*const T, @ptrCast(self)),
|
|
v1,
|
|
v2,
|
|
v3,
|
|
color,
|
|
);
|
|
}
|
|
pub inline fn createTriangleBatch(
|
|
self: *T,
|
|
triangles: []Triangle,
|
|
triangle_count: u32,
|
|
) T.Batch {
|
|
return @as(*const DebugRenderer.VTable(T), @ptrCast(self.__v))
|
|
.createTriangleBatch(
|
|
@as(*const T, @ptrCast(self)),
|
|
triangles,
|
|
triangle_count,
|
|
);
|
|
}
|
|
pub inline fn createTriangleBatchIndexed(
|
|
self: *T,
|
|
vertices: []Vertex,
|
|
vertex_count: u32,
|
|
indices: []u32,
|
|
index_count: u32,
|
|
) T.Batch {
|
|
return @as(*const DebugRenderer.VTable(T), @ptrCast(self.__v))
|
|
.createTriangleBatchIndexed(
|
|
@as(*const T, @ptrCast(self)),
|
|
vertices,
|
|
vertex_count,
|
|
indices,
|
|
index_count,
|
|
);
|
|
}
|
|
pub inline fn drawGeometry(
|
|
self: *T,
|
|
model_matrix: *const [16]Real,
|
|
world_space_bound: *const AABox,
|
|
lod_scale_sq: f32,
|
|
color: Color,
|
|
geometry: *const Geometry,
|
|
cull_mode: CullMode,
|
|
cast_shadow: CastShadow,
|
|
draw_mode: DrawMode,
|
|
) void {
|
|
return @as(*const DebugRenderer.VTable(T), @ptrCast(self.__v))
|
|
.drawGeometry(
|
|
@as(*const T, @ptrCast(self)),
|
|
model_matrix,
|
|
world_space_bound,
|
|
lod_scale_sq,
|
|
color,
|
|
geometry,
|
|
cull_mode,
|
|
cast_shadow,
|
|
draw_mode,
|
|
);
|
|
}
|
|
pub inline fn drawText3D(
|
|
self: *T,
|
|
positions: *const [3]Real,
|
|
string: [*:0]const u8,
|
|
color: Color,
|
|
height: f32,
|
|
) void {
|
|
return @as(*const DebugRenderer.VTable(T), @ptrCast(self.__v))
|
|
.drawText3D(
|
|
@as(*const T, @ptrCast(self)),
|
|
positions,
|
|
string,
|
|
color,
|
|
height,
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn VTable(comptime T: type) type {
|
|
return extern struct {
|
|
drawLine: ?*const fn (
|
|
self: *T,
|
|
from: *const [3]Real,
|
|
to: *const [3]Real,
|
|
color: *const Color,
|
|
) callconv(.C) void = null,
|
|
drawTriangle: ?*const fn (
|
|
self: *T,
|
|
v1: *const [3]Real,
|
|
v2: *const [3]Real,
|
|
v3: *const [3]Real,
|
|
color: *const Color,
|
|
) callconv(.C) void = null,
|
|
createTriangleBatch: ?*const fn (
|
|
self: *T,
|
|
triangles: [*]Triangle,
|
|
triangle_count: u32,
|
|
) callconv(.C) *anyopaque = null,
|
|
createTriangleBatchIndexed: ?*const fn (
|
|
self: *T,
|
|
vertices: [*]Vertex,
|
|
vertex_count: u32,
|
|
indices: [*]u32,
|
|
index_count: u32,
|
|
) callconv(.C) *anyopaque = null,
|
|
drawGeometry: ?*const fn (
|
|
self: *T,
|
|
model_matrix: *const [16]Real,
|
|
world_space_bound: *const AABox,
|
|
lod_scale_sq: f32,
|
|
color: Color,
|
|
geometry: *const Geometry,
|
|
cull_mode: CullMode,
|
|
cast_shadow: CastShadow,
|
|
draw_mode: DrawMode,
|
|
) callconv(.C) void = null,
|
|
drawText3D: ?*const fn (
|
|
self: *T,
|
|
positions: *const [3]Real,
|
|
string: [*:0]const u8,
|
|
color: Color,
|
|
height: f32,
|
|
) callconv(.C) void = null,
|
|
};
|
|
}
|
|
|
|
pub const Color = extern union { uint: u32, comp: extern struct {
|
|
r: u8,
|
|
g: u8,
|
|
b: u8,
|
|
a: u8,
|
|
} };
|
|
|
|
pub const Triangle = extern struct {
|
|
v: [3]Vertex,
|
|
};
|
|
|
|
pub const Vertex = extern struct {
|
|
position: [3]f32,
|
|
normal: [3]f32,
|
|
uv: [2]f32,
|
|
color: Color,
|
|
};
|
|
|
|
pub const AABox = extern struct {
|
|
min: [3]f32,
|
|
max: [3]f32,
|
|
};
|
|
|
|
pub const LOD = extern struct {
|
|
batch: *TriangleBatch,
|
|
distance: f32,
|
|
};
|
|
|
|
pub const Geometry = extern struct {
|
|
LODs: [*]LOD,
|
|
num_LODs: u64,
|
|
bounds: *AABox,
|
|
};
|
|
|
|
// zig fmt: off
|
|
pub const BodyDrawSettings = extern struct {
|
|
get_support_func: bool = false, // Draw the GetSupport() function, used for convex collision detection
|
|
get_support_dir: bool = false, // If above true, also draw direction mapped to a specific support point
|
|
get_supporting_face: bool = false, // Draw the faces that were found colliding during collision detection
|
|
shape: bool = true, // Draw the shapes of all bodies
|
|
shape_wireframe: bool = false, // If 'shape' true, the shapes will be drawn in wireframe instead of solid.
|
|
shape_color: ShapeColor = .motion_type_color, // Coloring scheme to use for shapes
|
|
bounding_box: bool = false, // Draw a bounding box per body
|
|
center_of_mass_transform: bool = false, // Draw the center of mass for each body
|
|
world_transform: bool = false, // Draw the world transform (which can be different than CoM) for each body
|
|
velocity: bool = false, // Draw the velocity vector for each body
|
|
mass_and_inertia: bool = false, // Draw the mass and inertia (as the box equivalent) for each body
|
|
sleep_stats: bool = false, // Draw stats regarding the sleeping algorithm of each body
|
|
};
|
|
// zig fmt: on
|
|
|
|
pub const BodyDrawFilterFunc = *const fn (*const Body) callconv(.C) bool;
|
|
pub const BodyDrawFilter = opaque {};
|
|
|
|
pub const TriangleBatch = opaque {};
|
|
pub const Primitive = opaque {};
|
|
|
|
pub const DebugRendererResult = enum(c.JPC_DebugRendererResult) {
|
|
success = c.JPC_DEBUGRENDERER_SUCCESS,
|
|
duplicate_singleton = c.JPC_DEBUGRENDERER_DUPLICATE_SINGLETON,
|
|
missing_singleton = c.JPC_DEBUGRENDERER_MISSING_SINGLETON,
|
|
incomplete_impl = c.JPC_DEBUGRENDERER_INCOMPLETE_IMPL,
|
|
};
|
|
|
|
// zig fmt: off
|
|
pub const ShapeColor = enum(c.JPC_ShapeColor) {
|
|
instance_color = c.JPC_INSTANCE_COLOR, // Random color per instance
|
|
shape_type_color = c.JPC_SHAPE_TYPE_COLOR, // Convex = green, scaled = yellow, compound = orange, mesh = red
|
|
motion_type_color = c.JPC_MOTION_TYPE_COLOR, // Static = grey, keyframed = green, dynamic = random
|
|
sleep_color = c.JPC_SLEEP_COLOR, // Static = grey, keyframed = green, dynamic = yellow, asleep= red
|
|
island_color = c.JPC_ISLAND_COLOR, // Static = grey, active = random per island, sleeping = light grey
|
|
material_color = c.JPC_MATERIAL_COLOR, // Color as defined by the PhysicsMaterial of the shape
|
|
};
|
|
// zig fmt: on
|
|
|
|
pub const CullMode = enum(c.JPC_CullMode) {
|
|
cull_back_face = c.JPC_CULL_BACK_FACE,
|
|
cull_front_face = c.JPC_CULL_FRONT_FACE,
|
|
culling_off = c.JPC_CULLING_OFF,
|
|
};
|
|
|
|
pub const CastShadow = enum(c.JPC_CastShadow) {
|
|
cast_shadow_on = c.JPC_CAST_SHADOW_ON,
|
|
cast_shadow_off = c.JPC_CAST_SHADOW_OFF,
|
|
};
|
|
|
|
pub const DrawMode = enum(c.JPC_DrawMode) {
|
|
draw_mode_solid = c.JPC_DRAW_MODE_SOLID,
|
|
draw_mode_wireframe = c.JPC_DRAW_MODE_WIREFRAME,
|
|
};
|
|
|
|
comptime {
|
|
if (debug_renderer_enabled) {
|
|
assert(@sizeOf(VTable(@This())) == @sizeOf(c.JPC_DebugRendererVTable));
|
|
assert(@offsetOf(VTable(@This()), "drawTriangle") == @offsetOf(c.JPC_DebugRendererVTable, "DrawTriangle"));
|
|
assert(@offsetOf(VTable(@This()), "drawText3D") == @offsetOf(c.JPC_DebugRendererVTable, "DrawText3D"));
|
|
}
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// Init/deinit and global state
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
const SizeAndAlignment = packed struct(u64) {
|
|
size: u48,
|
|
alignment: u16,
|
|
};
|
|
var mem_allocator: ?std.mem.Allocator = null;
|
|
var mem_allocations: ?std.AutoHashMap(usize, SizeAndAlignment) = null;
|
|
var mem_mutex: std.Thread.Mutex = .{};
|
|
const mem_alignment = 16;
|
|
|
|
var temp_allocator: ?*TempAllocator = null;
|
|
var job_system: ?*JobSystem = null;
|
|
|
|
pub fn init(allocator: std.mem.Allocator, args: struct {
|
|
temp_allocator_size: u32 = 16 * 1024 * 1024,
|
|
max_jobs: u32 = max_physics_jobs,
|
|
max_barriers: u32 = max_physics_barriers,
|
|
num_threads: i32 = -1,
|
|
}) !void {
|
|
std.debug.assert(mem_allocator == null and mem_allocations == null);
|
|
|
|
mem_allocator = allocator;
|
|
mem_allocations = std.AutoHashMap(usize, SizeAndAlignment).init(allocator);
|
|
mem_allocations.?.ensureTotalCapacity(32) catch unreachable;
|
|
|
|
c.JPC_RegisterCustomAllocator(zphysicsAlloc, zphysicsFree, zphysicsAlignedAlloc, zphysicsFree);
|
|
|
|
c.JPC_CreateFactory();
|
|
c.JPC_RegisterTypes();
|
|
|
|
assert(temp_allocator == null and job_system == null);
|
|
temp_allocator = @as(*TempAllocator, @ptrCast(c.JPC_TempAllocator_Create(args.temp_allocator_size)));
|
|
job_system = @as(*JobSystem, @ptrCast(c.JPC_JobSystem_Create(args.max_jobs, args.max_barriers, args.num_threads)));
|
|
}
|
|
|
|
pub fn deinit() void {
|
|
c.JPC_JobSystem_Destroy(@as(*c.JPC_JobSystem, @ptrCast(job_system)));
|
|
job_system = null;
|
|
c.JPC_TempAllocator_Destroy(@as(*c.JPC_TempAllocator, @ptrCast(temp_allocator)));
|
|
temp_allocator = null;
|
|
c.JPC_DestroyFactory();
|
|
|
|
mem_allocations.?.deinit();
|
|
mem_allocations = null;
|
|
mem_allocator = null;
|
|
}
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// PhysicsSystem
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const PhysicsSystem = opaque {
|
|
pub fn create(
|
|
broad_phase_layer_interface: *const BroadPhaseLayerInterface,
|
|
object_vs_broad_phase_layer_filter: *const ObjectVsBroadPhaseLayerFilter,
|
|
object_layer_pair_filter: *const ObjectLayerPairFilter,
|
|
args: struct {
|
|
max_bodies: u32 = 1024,
|
|
num_body_mutexes: u32 = 0,
|
|
max_body_pairs: u32 = 1024,
|
|
max_contact_constraints: u32 = 1024,
|
|
},
|
|
) !*PhysicsSystem {
|
|
return @as(*PhysicsSystem, @ptrCast(c.JPC_PhysicsSystem_Create(
|
|
args.max_bodies,
|
|
args.num_body_mutexes,
|
|
args.max_body_pairs,
|
|
args.max_contact_constraints,
|
|
broad_phase_layer_interface,
|
|
object_vs_broad_phase_layer_filter,
|
|
object_layer_pair_filter,
|
|
)));
|
|
}
|
|
|
|
pub fn destroy(physics_system: *PhysicsSystem) void {
|
|
c.JPC_PhysicsSystem_Destroy(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
|
|
pub fn getNumBodies(physics_system: *const PhysicsSystem) u32 {
|
|
return c.JPC_PhysicsSystem_GetNumBodies(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
pub fn getNumActiveBodies(physics_system: *const PhysicsSystem) u32 {
|
|
return c.JPC_PhysicsSystem_GetNumActiveBodies(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
pub fn getMaxBodies(physics_system: *const PhysicsSystem) u32 {
|
|
return c.JPC_PhysicsSystem_GetMaxBodies(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
|
|
pub fn getGravity(physics_system: *const PhysicsSystem) [3]f32 {
|
|
var gravity: [3]f32 = undefined;
|
|
c.JPC_PhysicsSystem_GetGravity(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)), &gravity);
|
|
return gravity;
|
|
}
|
|
pub fn setGravity(physics_system: *PhysicsSystem, gravity: [3]f32) void {
|
|
c.JPC_PhysicsSystem_SetGravity(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)), &gravity);
|
|
}
|
|
|
|
pub fn getBodyInterface(physics_system: *const PhysicsSystem) *const BodyInterface {
|
|
return @as(
|
|
*const BodyInterface,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetBodyInterface(@as(*c.JPC_PhysicsSystem, @ptrFromInt(@intFromPtr(physics_system))))),
|
|
);
|
|
}
|
|
pub fn getBodyInterfaceNoLock(physics_system: *const PhysicsSystem) *const BodyInterface {
|
|
return @as(
|
|
*const BodyInterface,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetBodyInterfaceNoLock(@as(*c.JPC_PhysicsSystem, @ptrFromInt(@intFromPtr(physics_system))))),
|
|
);
|
|
}
|
|
pub fn getBodyInterfaceMut(physics_system: *PhysicsSystem) *BodyInterface {
|
|
return @as(
|
|
*BodyInterface,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetBodyInterface(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)))),
|
|
);
|
|
}
|
|
pub fn getBodyInterfaceMutNoLock(physics_system: *PhysicsSystem) *BodyInterface {
|
|
return @as(
|
|
*BodyInterface,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetBodyInterfaceNoLock(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)))),
|
|
);
|
|
}
|
|
|
|
pub fn getNarrowPhaseQuery(physics_system: *const PhysicsSystem) *const NarrowPhaseQuery {
|
|
return @as(
|
|
*const NarrowPhaseQuery,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetNarrowPhaseQuery(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)))),
|
|
);
|
|
}
|
|
pub fn getNarrowPhaseQueryNoLock(physics_system: *const PhysicsSystem) *const NarrowPhaseQuery {
|
|
return @as(
|
|
*const NarrowPhaseQuery,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetNarrowPhaseQueryNoLock(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)))),
|
|
);
|
|
}
|
|
|
|
pub fn getBodyLockInterface(physics_system: *const PhysicsSystem) *const BodyLockInterface {
|
|
return @as(
|
|
*const BodyLockInterface,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetBodyLockInterface(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)))),
|
|
);
|
|
}
|
|
pub fn getBodyLockInterfaceNoLock(physics_system: *const PhysicsSystem) *const BodyLockInterface {
|
|
return @as(
|
|
*const BodyLockInterface,
|
|
@ptrCast(c.JPC_PhysicsSystem_GetBodyLockInterfaceNoLock(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)))),
|
|
);
|
|
}
|
|
|
|
pub fn setBodyActivationListener(physics_system: *PhysicsSystem, listener: ?*anyopaque) void {
|
|
c.JPC_PhysicsSystem_SetBodyActivationListener(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)), listener);
|
|
}
|
|
pub fn getBodyActivationListener(physics_system: *const PhysicsSystem) ?*anyopaque {
|
|
return c.JPC_PhysicsSystem_GetBodyActivationListener(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
|
|
pub fn setContactListener(physics_system: *PhysicsSystem, listener: ?*anyopaque) void {
|
|
c.JPC_PhysicsSystem_SetContactListener(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)), listener);
|
|
}
|
|
pub fn getContactListener(physics_system: *const PhysicsSystem) ?*anyopaque {
|
|
return c.JPC_PhysicsSystem_GetContactListener(@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
|
|
pub fn optimizeBroadPhase(physics_system: *PhysicsSystem) void {
|
|
c.JPC_PhysicsSystem_OptimizeBroadPhase(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
|
|
pub fn addStepListener(physics_system: *PhysicsSystem, listener: ?*anyopaque) void {
|
|
c.JPC_PhysicsSystem_AddStepListener(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)), listener);
|
|
}
|
|
pub fn removeStepListener(physics_system: *PhysicsSystem, listener: ?*anyopaque) void {
|
|
c.JPC_PhysicsSystem_RemoveStepListener(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)), listener);
|
|
}
|
|
|
|
pub fn addConstraint(physics_system: *PhysicsSystem, two_body_constraint: ?*anyopaque) void {
|
|
c.JPC_PhysicsSystem_AddConstraint(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)), two_body_constraint);
|
|
}
|
|
pub fn removeConstraint(physics_system: *PhysicsSystem, two_body_constraint: ?*anyopaque) void {
|
|
c.JPC_PhysicsSystem_RemoveConstraint(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)), two_body_constraint);
|
|
}
|
|
|
|
pub fn update(
|
|
physics_system: *PhysicsSystem,
|
|
delta_time: f32,
|
|
args: struct {
|
|
collision_steps: i32 = 1,
|
|
integration_sub_steps: i32 = 1,
|
|
},
|
|
) !void {
|
|
const res = c.JPC_PhysicsSystem_Update(
|
|
@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)),
|
|
delta_time,
|
|
args.collision_steps,
|
|
args.integration_sub_steps,
|
|
@as(*c.JPC_TempAllocator, @ptrCast(temp_allocator)),
|
|
@as(*c.JPC_JobSystem, @ptrCast(job_system)),
|
|
);
|
|
|
|
switch (res) {
|
|
c.JPC_PHYSICS_UPDATE_NO_ERROR => {},
|
|
c.JPC_PHYSICS_UPDATE_MANIFOLD_CACHE_FULL => return error.ManifoldCacheFull,
|
|
c.JPC_PHYSICS_UPDATE_BODY_PAIR_CACHE_FULL => return error.BodyPairCacheFull,
|
|
c.JPC_PHYSICS_UPDATE_CONTACT_CONSTRAINTS_FULL => return error.ContactConstraintsFull,
|
|
else => return error.Unknown,
|
|
}
|
|
}
|
|
|
|
pub usingnamespace if (!debug_renderer_enabled) struct {} else struct {
|
|
pub fn drawBodies(
|
|
physics_system: *PhysicsSystem,
|
|
in_draw_settings: *const DebugRenderer.BodyDrawSettings,
|
|
in_draw_filter: ?*const DebugRenderer.BodyDrawFilter,
|
|
) void {
|
|
c.JPC_PhysicsSystem_DrawBodies(
|
|
@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)),
|
|
@as(*const c.JPC_BodyManager_DrawSettings, @ptrCast(in_draw_settings)),
|
|
@as(?*const c.JPC_BodyDrawFilter, @ptrCast(in_draw_filter)),
|
|
);
|
|
}
|
|
|
|
pub fn drawConstraints(physics_system: *PhysicsSystem) void {
|
|
c.JPC_PhysicsSystem_DrawConstraints(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
|
|
pub fn drawConstraintLimits(physics_system: *PhysicsSystem) void {
|
|
c.JPC_PhysicsSystem_DrawConstraintLimits(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
|
|
pub fn drawConstraintReferenceFrame(physics_system: *PhysicsSystem) void {
|
|
c.JPC_PhysicsSystem_DrawConstraintReferenceFrame(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
}
|
|
};
|
|
|
|
pub fn getBodyIds(physics_system: *const PhysicsSystem, body_ids: *std.ArrayList(BodyId)) !void {
|
|
try body_ids.ensureTotalCapacityPrecise(physics_system.getMaxBodies());
|
|
var num_body_ids: u32 = 0;
|
|
c.JPC_PhysicsSystem_GetBodyIDs(
|
|
@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)),
|
|
@as(u32, @intCast(body_ids.capacity)),
|
|
&num_body_ids,
|
|
body_ids.items.ptr,
|
|
);
|
|
body_ids.items.len = num_body_ids;
|
|
}
|
|
|
|
pub fn getActiveBodyIds(physics_system: *const PhysicsSystem, body_ids: *std.ArrayList(BodyId)) !void {
|
|
try body_ids.ensureTotalCapacityPrecise(physics_system.getMaxBodies());
|
|
var num_body_ids: u32 = 0;
|
|
c.JPC_PhysicsSystem_GetActiveBodyIDs(
|
|
@as(*const c.JPC_PhysicsSystem, @ptrCast(physics_system)),
|
|
@as(u32, @intCast(body_ids.capacity)),
|
|
&num_body_ids,
|
|
body_ids.items.ptr,
|
|
);
|
|
body_ids.items.len = num_body_ids;
|
|
}
|
|
|
|
/// NOTE: Advanced. This function is *not* protected by a lock, use with care!
|
|
pub fn getBodiesUnsafe(physics_system: *const PhysicsSystem) []const *const Body {
|
|
const ptr = c.JPC_PhysicsSystem_GetBodiesUnsafe(
|
|
@as(*c.JPC_PhysicsSystem, @ptrFromInt(@intFromPtr(physics_system))),
|
|
);
|
|
return @as([*]const *const Body, @ptrCast(ptr))[0..physics_system.getNumBodies()];
|
|
}
|
|
/// NOTE: Advanced. This function is *not* protected by a lock, use with care!
|
|
pub fn getBodiesMutUnsafe(physics_system: *PhysicsSystem) []const *Body {
|
|
const ptr = c.JPC_PhysicsSystem_GetBodiesUnsafe(@as(*c.JPC_PhysicsSystem, @ptrCast(physics_system)));
|
|
return @as([*]const *Body, @ptrCast(ptr))[0..physics_system.getNumBodies()];
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// BodyLock*
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const BodyLockRead = extern struct {
|
|
lock_interface: *const BodyLockInterface = undefined,
|
|
mutex: ?*SharedMutex = null,
|
|
body: ?*const Body = null,
|
|
|
|
pub fn lock(
|
|
read_lock: *BodyLockRead,
|
|
lock_interface: *const BodyLockInterface,
|
|
body_id: BodyId,
|
|
) void {
|
|
c.JPC_BodyLockInterface_LockRead(
|
|
@as(*const c.JPC_BodyLockInterface, @ptrCast(lock_interface)),
|
|
body_id,
|
|
@as(*c.JPC_BodyLockRead, @ptrCast(read_lock)),
|
|
);
|
|
}
|
|
|
|
pub fn unlock(read_lock: *BodyLockRead) void {
|
|
c.JPC_BodyLockInterface_UnlockRead(
|
|
@as(*const c.JPC_BodyLockInterface, @ptrCast(read_lock.lock_interface)),
|
|
@as(*c.JPC_BodyLockRead, @ptrCast(read_lock)),
|
|
);
|
|
}
|
|
|
|
comptime {
|
|
assert(@sizeOf(BodyLockRead) == @sizeOf(c.JPC_BodyLockRead));
|
|
assert(@offsetOf(BodyLockRead, "mutex") == @offsetOf(c.JPC_BodyLockRead, "mutex"));
|
|
assert(@offsetOf(BodyLockRead, "body") == @offsetOf(c.JPC_BodyLockRead, "body"));
|
|
}
|
|
};
|
|
|
|
pub const BodyLockWrite = extern struct {
|
|
lock_interface: *const BodyLockInterface = undefined,
|
|
mutex: ?*SharedMutex = null,
|
|
body: ?*Body = null,
|
|
|
|
pub fn lock(
|
|
write_lock: *BodyLockWrite,
|
|
lock_interface: *const BodyLockInterface,
|
|
body_id: BodyId,
|
|
) void {
|
|
c.JPC_BodyLockInterface_LockWrite(
|
|
@as(*const c.JPC_BodyLockInterface, @ptrCast(lock_interface)),
|
|
body_id,
|
|
@as(*c.JPC_BodyLockWrite, @ptrCast(write_lock)),
|
|
);
|
|
}
|
|
|
|
pub fn unlock(write_lock: *BodyLockWrite) void {
|
|
c.JPC_BodyLockInterface_UnlockWrite(
|
|
@as(*const c.JPC_BodyLockInterface, @ptrCast(write_lock.lock_interface)),
|
|
@as(*c.JPC_BodyLockWrite, @ptrCast(write_lock)),
|
|
);
|
|
}
|
|
|
|
comptime {
|
|
assert(@sizeOf(BodyLockWrite) == @sizeOf(c.JPC_BodyLockWrite));
|
|
assert(@offsetOf(BodyLockWrite, "mutex") == @offsetOf(c.JPC_BodyLockWrite, "mutex"));
|
|
assert(@offsetOf(BodyLockWrite, "body") == @offsetOf(c.JPC_BodyLockWrite, "body"));
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// BodyInterface
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const BodyInterface = opaque {
|
|
pub fn createBody(body_iface: *BodyInterface, settings: BodyCreationSettings) !*Body {
|
|
const body = c.JPC_BodyInterface_CreateBody(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
@as(*const c.JPC_BodyCreationSettings, @ptrCast(&settings)),
|
|
);
|
|
if (body == null)
|
|
return error.FailedToCreateBody;
|
|
return @as(*Body, @ptrCast(body));
|
|
}
|
|
|
|
pub fn createBodyWithId(body_iface: *BodyInterface, body_id: BodyId, settings: BodyCreationSettings) !*Body {
|
|
const body = c.JPC_BodyInterface_CreateBodyWithID(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
@as(*const c.JPC_BodyCreationSettings, @ptrCast(&settings)),
|
|
);
|
|
if (body == null)
|
|
return error.FailedToCreateBody;
|
|
return @as(*Body, @ptrCast(body));
|
|
}
|
|
|
|
pub fn destroyBody(body_iface: *BodyInterface, body_id: BodyId) void {
|
|
c.JPC_BodyInterface_DestroyBody(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id);
|
|
}
|
|
|
|
pub fn addBody(body_iface: *BodyInterface, body_id: BodyId, mode: Activation) void {
|
|
c.JPC_BodyInterface_AddBody(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id, @intFromEnum(mode));
|
|
}
|
|
|
|
pub fn removeBody(body_iface: *BodyInterface, body_id: BodyId) void {
|
|
c.JPC_BodyInterface_RemoveBody(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id);
|
|
}
|
|
|
|
pub fn createAndAddBody(body_iface: *BodyInterface, settings: BodyCreationSettings, mode: Activation) !BodyId {
|
|
const body_id = c.JPC_BodyInterface_CreateAndAddBody(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
@as(*const c.JPC_BodyCreationSettings, @ptrCast(&settings)),
|
|
@intFromEnum(mode),
|
|
);
|
|
if (body_id == body_id_invalid)
|
|
return error.FailedToCreateBody;
|
|
return body_id;
|
|
}
|
|
|
|
pub fn removeAndDestroyBody(body_iface: *BodyInterface, body_id: BodyId) void {
|
|
body_iface.removeBody(body_id);
|
|
body_iface.destroyBody(body_id);
|
|
}
|
|
|
|
pub fn isAdded(body_iface: *const BodyInterface, body_id: BodyId) bool {
|
|
return c.JPC_BodyInterface_IsAdded(@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)), body_id);
|
|
}
|
|
|
|
pub fn activate(body_iface: *BodyInterface, body_id: BodyId) void {
|
|
return c.JPC_BodyInterface_ActivateBody(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id);
|
|
}
|
|
|
|
pub fn deactivate(body_iface: *BodyInterface, body_id: BodyId) void {
|
|
return c.JPC_BodyInterface_DeactivateBody(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id);
|
|
}
|
|
|
|
pub fn isActive(body_iface: *const BodyInterface, body_id: BodyId) bool {
|
|
return c.JPC_BodyInterface_IsActive(@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)), body_id);
|
|
}
|
|
|
|
pub fn setLinearAndAngularVelocity(
|
|
body_iface: *BodyInterface,
|
|
body_id: BodyId,
|
|
linear_velocity: [3]f32,
|
|
angular_velocity: [3]f32,
|
|
) void {
|
|
return c.JPC_BodyInterface_SetLinearAndAngularVelocity(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&linear_velocity,
|
|
&angular_velocity,
|
|
);
|
|
}
|
|
pub fn getLinearAndAngularVelocity(
|
|
body_iface: *const BodyInterface,
|
|
body_id: BodyId,
|
|
) struct { linear: [3]f32, angular: [3]f32 } {
|
|
var linear: [3]f32 = undefined;
|
|
var angular: [3]f32 = undefined;
|
|
c.JPC_BodyInterface_GetLinearAndAngularVelocity(
|
|
@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&linear,
|
|
&angular,
|
|
);
|
|
return .{ .linear = linear, .angular = angular };
|
|
}
|
|
|
|
pub fn setLinearVelocity(body_iface: *BodyInterface, body_id: BodyId, velocity: [3]f32) void {
|
|
return c.JPC_BodyInterface_SetLinearVelocity(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&velocity,
|
|
);
|
|
}
|
|
pub fn getLinearVelocity(body_iface: *const BodyInterface, body_id: BodyId) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_BodyInterface_GetLinearVelocity(
|
|
@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&velocity,
|
|
);
|
|
return velocity;
|
|
}
|
|
|
|
pub fn addLinearVelocity(body_iface: *BodyInterface, body_id: BodyId, velocity: [3]f32) void {
|
|
return c.JPC_BodyInterface_AddLinearVelocity(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&velocity,
|
|
);
|
|
}
|
|
|
|
pub fn addLinearAndAngularVelocity(
|
|
body_iface: *BodyInterface,
|
|
body_id: BodyId,
|
|
linear_velocity: [3]f32,
|
|
angular_velocity: [3]f32,
|
|
) void {
|
|
return c.JPC_BodyInterface_AddLinearAndAngularVelocity(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&linear_velocity,
|
|
&angular_velocity,
|
|
);
|
|
}
|
|
|
|
pub fn setAngularVelocity(body_iface: *BodyInterface, body_id: BodyId, velocity: [3]f32) void {
|
|
return c.JPC_BodyInterface_SetAngularVelocity(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&velocity,
|
|
);
|
|
}
|
|
pub fn getAngularVelocity(body_iface: *const BodyInterface, body_id: BodyId) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_BodyInterface_GetAngularVelocity(
|
|
@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&velocity,
|
|
);
|
|
return velocity;
|
|
}
|
|
|
|
pub fn getPointVelocity(body_iface: *const BodyInterface, body_id: BodyId, point: [3]Real) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_BodyInterface_GetPointVelocity(
|
|
@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&point,
|
|
&velocity,
|
|
);
|
|
return velocity;
|
|
}
|
|
|
|
pub fn getPosition(body_iface: *const BodyInterface, body_id: BodyId) [3]Real {
|
|
var position: [3]Real = undefined;
|
|
c.JPC_BodyInterface_GetPosition(
|
|
@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&position,
|
|
);
|
|
return position;
|
|
}
|
|
|
|
pub fn setPosition(body_iface: *BodyInterface, body_id: BodyId, in_position: [3]Real, in_activation_type: Activation) void {
|
|
c.JPC_BodyInterface_SetPosition(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id, &in_position, @intFromEnum(in_activation_type));
|
|
}
|
|
|
|
pub fn getCenterOfMassPosition(body_iface: *const BodyInterface, body_id: BodyId) [3]Real {
|
|
var position: [3]Real = undefined;
|
|
c.JPC_BodyInterface_GetCenterOfMassPosition(
|
|
@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&position,
|
|
);
|
|
return position;
|
|
}
|
|
|
|
pub fn getRotation(body_iface: *const BodyInterface, body_id: BodyId) [4]f32 {
|
|
var rotation: [4]f32 = undefined;
|
|
c.JPC_BodyInterface_GetRotation(
|
|
@as(*const c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&rotation,
|
|
);
|
|
return rotation;
|
|
}
|
|
|
|
pub fn setRotation(body_iface: *BodyInterface, body_id: BodyId, in_rotation: [4]Real, in_activation_type: Activation) void {
|
|
c.JPC_BodyInterface_SetRotation(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id, &in_rotation, @intFromEnum(in_activation_type));
|
|
}
|
|
|
|
pub fn setPositionRotationAndVelocity(
|
|
body_iface: *BodyInterface,
|
|
body_id: BodyId,
|
|
position: [3]Real,
|
|
rotation: [4]f32,
|
|
linear_velocity: [3]f32,
|
|
angular_velocity: [3]f32,
|
|
) void {
|
|
return c.JPC_BodyInterface_SetPositionRotationAndVelocity(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&position,
|
|
&rotation,
|
|
&linear_velocity,
|
|
&angular_velocity,
|
|
);
|
|
}
|
|
|
|
pub fn addForce(body_iface: *BodyInterface, body_id: BodyId, force: [3]f32) void {
|
|
return c.JPC_BodyInterface_AddForce(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&force,
|
|
);
|
|
}
|
|
pub fn addForceAtPosition(body_iface: *BodyInterface, body_id: BodyId, force: [3]f32, position: [3]Real) void {
|
|
return c.JPC_BodyInterface_AddForceAtPosition(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&force,
|
|
&position,
|
|
);
|
|
}
|
|
|
|
pub fn addTorque(body_iface: *BodyInterface, body_id: BodyId, torque: [3]f32) void {
|
|
return c.JPC_BodyInterface_AddTorque(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&torque,
|
|
);
|
|
}
|
|
pub fn addForceAndTorque(body_iface: *BodyInterface, body_id: BodyId, force: [3]f32, torque: [3]f32) void {
|
|
return c.JPC_BodyInterface_AddForceAndTorque(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&force,
|
|
&torque,
|
|
);
|
|
}
|
|
|
|
pub fn addImpulse(body_iface: *BodyInterface, body_id: BodyId, impulse: [3]f32) void {
|
|
return c.JPC_BodyInterface_AddImpulse(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&impulse,
|
|
);
|
|
}
|
|
pub fn addImpulseAtPosition(
|
|
body_iface: *BodyInterface,
|
|
body_id: BodyId,
|
|
impulse: [3]f32,
|
|
position: [3]Real,
|
|
) void {
|
|
return c.JPC_BodyInterface_AddImpulseAtPosition(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&impulse,
|
|
&position,
|
|
);
|
|
}
|
|
|
|
pub fn addAngularImpulse(body_iface: *BodyInterface, body_id: BodyId, impulse: [3]f32) void {
|
|
return c.JPC_BodyInterface_AddAngularImpulse(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
&impulse,
|
|
);
|
|
}
|
|
|
|
pub fn getMotionType(body_iface: *const BodyInterface, body_id: BodyId) MotionType {
|
|
return @as(MotionType, @enumFromInt(
|
|
c.JPC_BodyInterface_GetMotionType(
|
|
@ptrCast(body_iface),
|
|
body_id,
|
|
),
|
|
));
|
|
}
|
|
|
|
pub fn setMotionType(body_iface: *BodyInterface, body_id: BodyId, in_motion_type: MotionType, in_activation_type: Activation) void {
|
|
return c.JPC_BodyInterface_SetMotionType(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
@intFromEnum(in_motion_type),
|
|
@intFromEnum(in_activation_type),
|
|
);
|
|
}
|
|
|
|
pub fn getObjectLayer(body_iface: *BodyInterface, body_id: BodyId) ObjectLayer {
|
|
return c.JPC_BodyInterface_GetObjectLayer(@as(*c.JPC_BodyInterface, @ptrCast(body_iface)), body_id);
|
|
}
|
|
|
|
pub fn setObjectLayer(body_iface: *BodyInterface, body_id: BodyId, in_layer: ObjectLayer) void {
|
|
c.JPC_BodyInterface_SetObjectLayer(
|
|
@as(*c.JPC_BodyInterface, @ptrCast(body_iface)),
|
|
body_id,
|
|
in_layer,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// NarrowPhaseQuery
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const NarrowPhaseQuery = opaque {
|
|
pub fn castRay(
|
|
query: *const NarrowPhaseQuery,
|
|
ray: RRayCast,
|
|
args: struct {
|
|
broad_phase_layer_filter: ?*const BroadPhaseLayerFilter = null,
|
|
object_layer_filter: ?*const ObjectLayerFilter = null,
|
|
body_filter: ?*const BodyFilter = null,
|
|
},
|
|
) struct { has_hit: bool, hit: RayCastResult } {
|
|
var hit: RayCastResult = .{};
|
|
const has_hit = c.JPC_NarrowPhaseQuery_CastRay(
|
|
@as(*const c.JPC_NarrowPhaseQuery, @ptrCast(query)),
|
|
@as(*const c.JPC_RRayCast, @ptrCast(&ray)),
|
|
@as(*c.JPC_RayCastResult, @ptrCast(&hit)),
|
|
args.broad_phase_layer_filter,
|
|
args.object_layer_filter,
|
|
args.body_filter,
|
|
);
|
|
return .{ .has_hit = has_hit, .hit = hit };
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// Body
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const Body = extern struct {
|
|
position: [4]Real align(rvec_align), // 4th element is ignored
|
|
rotation: [4]f32 align(16),
|
|
bounds_min: [4]f32 align(16), // 4th element is ignored
|
|
bounds_max: [4]f32 align(16), // 4th element is ignored
|
|
|
|
shape: *const Shape,
|
|
motion_properties: ?*MotionProperties, // Will be null for static objects
|
|
user_data: u64,
|
|
collision_group: CollisionGroup,
|
|
|
|
friction: f32,
|
|
restitution: f32,
|
|
id: BodyId,
|
|
|
|
object_layer: ObjectLayer,
|
|
|
|
broad_phase_layer: BroadPhaseLayer,
|
|
motion_type: MotionType,
|
|
flags: u8,
|
|
|
|
pub fn getId(body: *const Body) BodyId {
|
|
return c.JPC_Body_GetID(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
|
|
pub fn isActive(body: *const Body) bool {
|
|
return c.JPC_Body_IsActive(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn isStatic(body: *const Body) bool {
|
|
return c.JPC_Body_IsStatic(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn isKinematic(body: *const Body) bool {
|
|
return c.JPC_Body_IsKinematic(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn isDynamic(body: *const Body) bool {
|
|
return c.JPC_Body_IsDynamic(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn canBeKinematicOrDynamic(body: *const Body) bool {
|
|
return c.JPC_Body_CanBeKinematicOrDynamic(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
|
|
pub fn isSensor(body: *const Body) bool {
|
|
return c.JPC_Body_IsSensor(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn setIsSensor(body: *Body, is_sensor: bool) void {
|
|
c.JPC_Body_SetIsSensor(@as(*c.JPC_Body, @ptrCast(body)), is_sensor);
|
|
}
|
|
|
|
pub fn getMotionType(body: *const Body) MotionType {
|
|
return @as(MotionType, @enumFromInt(c.JPC_Body_GetMotionType(@as(*const c.JPC_Body, @ptrCast(body)))));
|
|
}
|
|
pub fn setMotionType(body: *Body, motion_type: MotionType) void {
|
|
return c.JPC_Body_SetMotionType(@as(*c.JPC_Body, @ptrCast(body)), @intFromEnum(motion_type));
|
|
}
|
|
|
|
pub fn getBroadPhaseLayer(body: *const Body) BroadPhaseLayer {
|
|
return c.JPC_Body_GetBroadPhaseLayer(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn getObjectLayer(body: *const Body) ObjectLayer {
|
|
return c.JPC_Body_GetObjectLayer(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
|
|
pub fn getCollisionGroup(body: *const Body) *const CollisionGroup {
|
|
return @as(
|
|
*const CollisionGroup,
|
|
@ptrCast(c.JPC_Body_GetCollisionGroup(@as(*c.JPC_Body, @ptrFromInt(@intFromPtr(body))))),
|
|
);
|
|
}
|
|
pub fn getCollisionGroupMut(body: *Body) *CollisionGroup {
|
|
return @as(
|
|
*CollisionGroup,
|
|
@ptrCast(c.JPC_Body_GetCollisionGroup(@as(*c.JPC_Body, @ptrCast(body)))),
|
|
);
|
|
}
|
|
pub fn setCollisionGroup(body: *Body, group: CollisionGroup) void {
|
|
c.JPC_Body_SetCollisionGroup(
|
|
@as(*c.JPC_Body, @ptrCast(body)),
|
|
@as(*const c.JPC_CollisionGroup, @ptrCast(&group)),
|
|
);
|
|
}
|
|
|
|
pub fn getAllowSleeping(body: *const Body) bool {
|
|
return c.JPC_Body_GetAllowSleeping(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn setAllowSleeping(body: *Body, allow: bool) void {
|
|
c.JPC_Body_SetAllowSleeping(@as(*c.JPC_Body, @ptrCast(body)), allow);
|
|
}
|
|
|
|
pub fn getFriction(body: *const Body) f32 {
|
|
return c.JPC_Body_GetFriction(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn setFriction(body: *Body, friction: f32) void {
|
|
c.JPC_Body_SetFriction(@as(*c.JPC_Body, @ptrCast(body)), friction);
|
|
}
|
|
|
|
pub fn getRestitution(body: *const Body) f32 {
|
|
return c.JPC_Body_GetRestitution(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn setRestitution(body: *Body, restitution: f32) void {
|
|
c.JPC_Body_SetRestitution(@as(*c.JPC_Body, @ptrCast(body)), restitution);
|
|
}
|
|
|
|
pub fn getLinearVelocity(body: *const Body) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_Body_GetLinearVelocity(@as(*const c.JPC_Body, @ptrCast(body)), &velocity);
|
|
return velocity;
|
|
}
|
|
pub fn setLinearVelocity(body: *Body, velocity: [3]f32) void {
|
|
c.JPC_Body_SetLinearVelocity(@as(*c.JPC_Body, @ptrCast(body)), &velocity);
|
|
}
|
|
pub fn setLinearVelocityClamped(body: *Body, velocity: [3]f32) void {
|
|
c.JPC_Body_SetLinearVelocityClamped(@as(*c.JPC_Body, @ptrCast(body)), &velocity);
|
|
}
|
|
|
|
pub fn getAngularVelocity(body: *const Body) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_Body_GetAngularVelocity(@as(*const c.JPC_Body, @ptrCast(body)), &velocity);
|
|
return velocity;
|
|
}
|
|
pub fn setAngularVelocity(body: *Body, velocity: [3]f32) void {
|
|
c.JPC_Body_SetAngularVelocity(@as(*c.JPC_Body, @ptrCast(body)), &velocity);
|
|
}
|
|
pub fn setAngularVelocityClamped(body: *Body, velocity: [3]f32) void {
|
|
c.JPC_Body_SetAngularVelocityClamped(@as(*c.JPC_Body, @ptrCast(body)), &velocity);
|
|
}
|
|
|
|
/// `point` is relative to the center of mass (com)
|
|
pub fn getPointVelocityCom(body: *const Body, point: [3]f32) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_Body_GetPointVelocityCOM(@as(*const c.JPC_Body, @ptrCast(body)), &point, &velocity);
|
|
return velocity;
|
|
}
|
|
/// `point` is in the world space
|
|
pub fn getPointVelocity(body: *const Body, point: [3]Real) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_Body_GetPointVelocity(@as(*const c.JPC_Body, @ptrCast(body)), &point, &velocity);
|
|
return velocity;
|
|
}
|
|
|
|
pub fn addForce(body: *Body, force: [3]f32) void {
|
|
c.JPC_Body_AddForce(@as(*c.JPC_Body, @ptrCast(body)), &force);
|
|
}
|
|
pub fn addForceAtPosition(body: *Body, force: [3]f32, position: [3]Real) void {
|
|
c.JPC_Body_AddForceAtPosition(@as(*c.JPC_Body, @ptrCast(body)), &force, &position);
|
|
}
|
|
|
|
pub fn addTorque(body: *Body, torque: [3]f32) void {
|
|
c.JPC_Body_AddTorque(@as(*c.JPC_Body, @ptrCast(body)), &torque);
|
|
}
|
|
|
|
pub fn getInverseInertia(body: *const Body) [16]f32 {
|
|
var inverse_inertia: [16]f32 = undefined;
|
|
c.JPC_Body_GetInverseInertia(@as(*const c.JPC_Body, @ptrCast(body)), &inverse_inertia);
|
|
return inverse_inertia;
|
|
}
|
|
|
|
pub fn addImpulse(body: *Body, impulse: [3]f32) void {
|
|
c.JPC_Body_AddImpulse(@as(*c.JPC_Body, @ptrCast(body)), &impulse);
|
|
}
|
|
pub fn addImpulseAtPosition(body: *Body, impulse: [3]f32, position: [3]Real) void {
|
|
c.JPC_Body_AddImpulseAtPosition(@as(*c.JPC_Body, @ptrCast(body)), &impulse, &position);
|
|
}
|
|
|
|
pub fn addAngularImpulse(body: *Body, impulse: [3]f32) void {
|
|
c.JPC_Body_AddAngularImpulse(@as(*c.JPC_Body, @ptrCast(body)), &impulse);
|
|
}
|
|
|
|
pub fn moveKinematic(
|
|
body: *Body,
|
|
target_position: [3]Real,
|
|
target_rotation: [4]f32,
|
|
delta_time: f32,
|
|
) void {
|
|
c.JPC_Body_MoveKinematic(
|
|
@as(*c.JPC_Body, @ptrCast(body)),
|
|
&target_position,
|
|
&target_rotation,
|
|
delta_time,
|
|
);
|
|
}
|
|
|
|
pub fn applyBuoyancyImpulse(
|
|
body: *Body,
|
|
surface_position: [3]Real,
|
|
surface_normal: [3]f32,
|
|
buoyancy: f32,
|
|
linear_drag: f32,
|
|
angular_drag: f32,
|
|
fluid_velocity: [3]f32,
|
|
gravity: [3]f32,
|
|
delta_time: f32,
|
|
) void {
|
|
c.JPC_Body_ApplyBuoyancyImpulse(
|
|
@as(*c.JPC_Body, @ptrCast(body)),
|
|
&surface_position,
|
|
&surface_normal,
|
|
buoyancy,
|
|
linear_drag,
|
|
angular_drag,
|
|
&fluid_velocity,
|
|
&gravity,
|
|
delta_time,
|
|
);
|
|
}
|
|
|
|
pub fn isInBroadPhase(body: *const Body) bool {
|
|
return c.JPC_Body_IsInBroadPhase(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
|
|
pub fn isCollisionCacheInvalid(body: *const Body) bool {
|
|
return c.JPC_Body_IsCollisionCacheInvalid(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
|
|
pub fn getShape(body: *const Body) *const Shape {
|
|
return @as(*const Shape, @ptrCast(c.JPC_Body_GetShape(@as(*const c.JPC_Body, @ptrCast(body)))));
|
|
}
|
|
|
|
pub fn getPosition(body: *const Body) [3]Real {
|
|
var position: [3]Real = undefined;
|
|
c.JPC_Body_GetPosition(@as(*const c.JPC_Body, @ptrCast(body)), &position);
|
|
return position;
|
|
}
|
|
|
|
pub fn getRotation(body: *const Body) [4]f32 {
|
|
var rotation: [4]f32 = undefined;
|
|
c.JPC_Body_GetRotation(@as(*const c.JPC_Body, @ptrCast(body)), &rotation);
|
|
return rotation;
|
|
}
|
|
|
|
pub fn getWorldTransform(body: *const Body) struct {
|
|
rotation: [9]f32,
|
|
position: [3]Real,
|
|
} {
|
|
var rotation: [9]f32 = undefined;
|
|
var position: [3]Real = undefined;
|
|
c.JPC_Body_GetWorldTransform(@as(*const c.JPC_Body, @ptrCast(body)), &rotation, &position);
|
|
return .{ .rotation = rotation, .position = position };
|
|
}
|
|
|
|
pub fn getCenterOfMassPosition(body: *const Body) [3]Real {
|
|
var position: [3]Real = undefined;
|
|
c.JPC_Body_GetCenterOfMassPosition(@as(*const c.JPC_Body, @ptrCast(body)), &position);
|
|
return position;
|
|
}
|
|
|
|
pub fn getCenterOfMassTransform(body: *const Body) struct {
|
|
rotation: [9]f32,
|
|
position: [3]Real,
|
|
} {
|
|
var rotation: [9]f32 = undefined;
|
|
var position: [3]Real = undefined;
|
|
c.JPC_Body_GetCenterOfMassTransform(@as(*const c.JPC_Body, @ptrCast(body)), &rotation, &position);
|
|
return .{ .rotation = rotation, .position = position };
|
|
}
|
|
|
|
pub fn getInverseCenterOfMassTransform(body: *const Body) struct {
|
|
rotation: [9]f32,
|
|
position: [3]Real,
|
|
} {
|
|
var rotation: [9]f32 = undefined;
|
|
var position: [3]Real = undefined;
|
|
c.JPC_Body_GetInverseCenterOfMassTransform(@as(*const c.JPC_Body, @ptrCast(body)), &rotation, &position);
|
|
return .{ .rotation = rotation, .position = position };
|
|
}
|
|
|
|
pub fn getWorldSpaceBounds(body: *const Body) struct {
|
|
min: [3]f32,
|
|
max: [3]f32,
|
|
} {
|
|
var min: [3]f32 = undefined;
|
|
var max: [3]f32 = undefined;
|
|
c.JPC_Body_GetWorldSpaceBounds(@as(*const c.JPC_Body, @ptrCast(body)), &min, &max);
|
|
return .{ .min = min, .max = max };
|
|
}
|
|
|
|
pub fn getMotionProperties(body: *const Body) *const MotionProperties {
|
|
return @as(
|
|
*const MotionProperties,
|
|
@ptrCast(c.JPC_Body_GetMotionProperties(@as(*c.JPC_Body, @ptrFromInt(@intFromPtr(body))))),
|
|
);
|
|
}
|
|
pub fn getMotionPropertiesMut(body: *Body) *MotionProperties {
|
|
return @as(
|
|
*MotionProperties,
|
|
@ptrCast(c.JPC_Body_GetMotionProperties(@as(*c.JPC_Body, @ptrCast(body)))),
|
|
);
|
|
}
|
|
|
|
pub fn getUserData(body: *const Body) u64 {
|
|
return c.JPC_Body_GetUserData(@as(*const c.JPC_Body, @ptrCast(body)));
|
|
}
|
|
pub fn setUserData(body: *Body, user_data: u64) void {
|
|
return c.JPC_Body_SetUserData(@as(*c.JPC_Body, @ptrCast(body)), user_data);
|
|
}
|
|
|
|
pub fn getWorldSpaceSurfaceNormal(
|
|
body: *const Body,
|
|
sub_shape_id: SubShapeId,
|
|
position: [3]Real, // world space
|
|
) [3]f32 {
|
|
var normal: [3]f32 = undefined;
|
|
c.JPC_Body_GetWorldSpaceSurfaceNormal(
|
|
@as(*const c.JPC_Body, @ptrCast(body)),
|
|
sub_shape_id,
|
|
&position,
|
|
&normal,
|
|
);
|
|
return normal;
|
|
}
|
|
|
|
comptime {
|
|
assert(@sizeOf(Body) == @sizeOf(c.JPC_Body));
|
|
assert(@offsetOf(Body, "flags") == @offsetOf(c.JPC_Body, "flags"));
|
|
assert(@offsetOf(Body, "motion_properties") == @offsetOf(c.JPC_Body, "motion_properties"));
|
|
assert(@offsetOf(Body, "object_layer") == @offsetOf(c.JPC_Body, "object_layer"));
|
|
assert(@offsetOf(Body, "rotation") == @offsetOf(c.JPC_Body, "rotation"));
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// Character
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const Character = opaque {
|
|
pub fn create(
|
|
in_settings: *const CharacterSettings,
|
|
in_position: [3]Real,
|
|
in_rotation: [4]f32,
|
|
in_user_data: u64,
|
|
in_physics_system: *PhysicsSystem,
|
|
) !*Character {
|
|
return @as(*Character, @ptrCast(c.JPC_Character_Create(
|
|
@as(*const c.JPC_CharacterSettings, @ptrCast(in_settings)),
|
|
&in_position,
|
|
&in_rotation,
|
|
in_user_data,
|
|
@as(*c.JPC_PhysicsSystem, @ptrCast(in_physics_system)),
|
|
)));
|
|
}
|
|
pub fn destroy(character: *Character) void {
|
|
c.JPC_Character_Destroy(@as(*c.JPC_Character, @ptrCast(character)));
|
|
}
|
|
|
|
pub fn addToPhysicsSystem(character: *Character, args: struct { activation: Activation = .activate, lock_bodies: bool = true }) void {
|
|
c.JPC_Character_AddToPhysicsSystem(
|
|
@as(*c.JPC_Character, @ptrCast(character)),
|
|
@intFromEnum(args.activation),
|
|
args.lock_bodies,
|
|
);
|
|
}
|
|
pub fn removeFromPhysicsSystem(character: *Character, args: struct { lock_bodies: bool = true }) void {
|
|
c.JPC_Character_RemoveFromPhysicsSystem(@as(*c.JPC_Character, @ptrCast(character)), args.lock_bodies);
|
|
}
|
|
|
|
pub fn getBodyId(character: *const Character) BodyId {
|
|
return @bitCast(c.JPC_Character_GetBodyId(@as(*const c.JPC_Character, @ptrCast(character))));
|
|
}
|
|
|
|
pub fn getPosition(character: *const Character) [3]Real {
|
|
var position: [3]Real = undefined;
|
|
c.JPC_Character_GetPosition(@as(*const c.JPC_Character, @ptrCast(character)), &position);
|
|
return position;
|
|
}
|
|
pub fn setPosition(character: *Character, position: [3]Real) void {
|
|
c.JPC_Character_SetPosition(@as(*c.JPC_Character, @ptrCast(character)), &position);
|
|
}
|
|
|
|
pub fn getLinearVelocity(character: *const Character) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_Character_GetLinearVelocity(@as(*const c.JPC_Character, @ptrCast(character)), &velocity);
|
|
return velocity;
|
|
}
|
|
pub fn setLinearVelocity(character: *Character, velocity: [3]f32) void {
|
|
c.JPC_Character_SetLinearVelocity(@as(*c.JPC_Character, @ptrCast(character)), &velocity);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// CharacterVirtual
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const CharacterVirtual = opaque {
|
|
pub fn create(
|
|
in_settings: *const CharacterVirtualSettings,
|
|
in_position: [3]Real,
|
|
in_rotation: [4]f32,
|
|
in_physics_system: *PhysicsSystem,
|
|
) !*CharacterVirtual {
|
|
return @as(*CharacterVirtual, @ptrCast(c.JPC_CharacterVirtual_Create(
|
|
@as(*const c.JPC_CharacterVirtualSettings, @ptrCast(in_settings)),
|
|
&in_position,
|
|
&in_rotation,
|
|
@as(*c.JPC_PhysicsSystem, @ptrCast(in_physics_system)),
|
|
)));
|
|
}
|
|
|
|
pub fn destroy(character: *CharacterVirtual) void {
|
|
c.JPC_CharacterVirtual_Destroy(@as(*c.JPC_CharacterVirtual, @ptrCast(character)));
|
|
}
|
|
|
|
pub fn update(
|
|
character: *CharacterVirtual,
|
|
delta_time: f32,
|
|
gravity: [3]f32,
|
|
args: struct {
|
|
broad_phase_layer_filter: ?*const BroadPhaseLayerFilter = null,
|
|
object_layer_filter: ?*const ObjectLayerFilter = null,
|
|
body_filter: ?*const BodyFilter = null,
|
|
shape_filter: ?*const ShapeFilter = null,
|
|
},
|
|
) void {
|
|
c.JPC_CharacterVirtual_Update(
|
|
@as(*c.JPC_CharacterVirtual, @ptrCast(character)),
|
|
delta_time,
|
|
&gravity,
|
|
args.broad_phase_layer_filter,
|
|
args.object_layer_filter,
|
|
args.body_filter,
|
|
args.shape_filter,
|
|
@as(*c.JPC_TempAllocator, @ptrCast(temp_allocator)),
|
|
);
|
|
}
|
|
|
|
pub fn setListener(character: *CharacterVirtual, listener: ?*anyopaque) void {
|
|
c.JPC_CharacterVirtual_SetListener(@as(*c.JPC_CharacterVirtual, @ptrCast(character)), listener);
|
|
}
|
|
pub fn updateGroundVelocity(character: *CharacterVirtual) void {
|
|
c.JPC_CharacterVirtual_UpdateGroundVelocity(@as(*c.JPC_CharacterVirtual, @ptrCast(character)));
|
|
}
|
|
pub fn getGroundVelocity(character: *const CharacterVirtual) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_CharacterVirtual_GetGroundVelocity(@as(*const c.JPC_CharacterVirtual, @ptrCast(character)), &velocity);
|
|
return velocity;
|
|
}
|
|
pub fn getGroundState(character: *CharacterVirtual) CharacterGroundState {
|
|
return @enumFromInt(c.JPC_CharacterVirtual_GetGroundState(@as(*c.JPC_CharacterVirtual, @ptrCast(character))));
|
|
}
|
|
|
|
pub fn getPosition(character: *const CharacterVirtual) [3]Real {
|
|
var position: [3]Real = undefined;
|
|
c.JPC_CharacterVirtual_GetPosition(@as(*const c.JPC_CharacterVirtual, @ptrCast(character)), &position);
|
|
return position;
|
|
}
|
|
|
|
pub fn setPosition(character: *CharacterVirtual, position: [3]Real) void {
|
|
c.JPC_CharacterVirtual_SetPosition(@as(*c.JPC_CharacterVirtual, @ptrCast(character)), &position);
|
|
}
|
|
|
|
pub fn getRotation(character: *const CharacterVirtual) [4]f32 {
|
|
var rotation: [4]f32 = undefined;
|
|
c.JPC_CharacterVirtual_GetRotation(@as(*const c.JPC_CharacterVirtual, @ptrCast(character)), &rotation);
|
|
return rotation;
|
|
}
|
|
pub fn setRotation(character: *CharacterVirtual, rotation: [4]f32) void {
|
|
c.JPC_CharacterVirtual_SetRotation(@as(*c.JPC_CharacterVirtual, @ptrCast(character)), &rotation);
|
|
}
|
|
|
|
pub fn getLinearVelocity(character: *const CharacterVirtual) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_CharacterVirtual_GetLinearVelocity(@as(*const c.JPC_CharacterVirtual, @ptrCast(character)), &velocity);
|
|
return velocity;
|
|
}
|
|
pub fn setLinearVelocity(character: *CharacterVirtual, velocity: [3]f32) void {
|
|
c.JPC_CharacterVirtual_SetLinearVelocity(@as(*c.JPC_CharacterVirtual, @ptrCast(character)), &velocity);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// MotionProperties
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const MotionProperties = extern struct {
|
|
linear_velocity: [4]f32 align(16), // 4th element is ignored
|
|
angular_velocity: [4]f32 align(16), // 4th element is ignored
|
|
inv_inertia_diagonal: [4]f32 align(16),
|
|
inertia_rotation: [4]f32 align(16),
|
|
|
|
force: [3]f32,
|
|
torque: [3]f32,
|
|
inv_mass: f32,
|
|
linear_damping: f32,
|
|
angular_damping: f32,
|
|
max_linear_velocity: f32,
|
|
max_angular_velocity: f32,
|
|
gravity_factor: f32,
|
|
index_in_active_bodies: u32,
|
|
island_index: u32,
|
|
|
|
motion_quality: MotionQuality,
|
|
allow_sleeping: bool,
|
|
|
|
reserved: [52 + c.JPC_ENABLE_ASSERTS * 3 + c.JPC_DOUBLE_PRECISION * 24]u8 align(4 + 4 * c.JPC_DOUBLE_PRECISION),
|
|
|
|
pub fn getMotionQuality(motion: *const MotionProperties) MotionQuality {
|
|
return @as(MotionQuality, @enumFromInt(c.JPC_MotionProperties_GetMotionQuality(
|
|
@as(*const c.JPC_MotionProperties, @ptrCast(motion)),
|
|
)));
|
|
}
|
|
|
|
pub fn getLinearVelocity(motion: *const MotionProperties) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_MotionProperties_GetLinearVelocity(@as(*const c.JPC_MotionProperties, @ptrCast(motion)), &velocity);
|
|
return velocity;
|
|
}
|
|
pub fn setLinearVelocity(motion: *MotionProperties, velocity: [3]f32) void {
|
|
c.JPC_MotionProperties_SetLinearVelocity(@as(*c.JPC_MotionProperties, @ptrCast(motion)), &velocity);
|
|
}
|
|
pub fn setLinearVelocityClamped(motion: *MotionProperties, velocity: [3]f32) void {
|
|
c.JPC_MotionProperties_SetLinearVelocityClamped(@as(*c.JPC_MotionProperties, @ptrCast(motion)), &velocity);
|
|
}
|
|
|
|
pub fn getAngularVelocity(motion: *const MotionProperties) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_MotionProperties_GetAngularVelocity(@as(*const c.JPC_MotionProperties, @ptrCast(motion)), &velocity);
|
|
return velocity;
|
|
}
|
|
pub fn setAngularVelocity(motion: *MotionProperties, velocity: [3]f32) void {
|
|
c.JPC_MotionProperties_SetAngularVelocity(@as(*c.JPC_MotionProperties, @ptrCast(motion)), &velocity);
|
|
}
|
|
pub fn setAngularVelocityClamped(motion: *MotionProperties, velocity: [3]f32) void {
|
|
c.JPC_MotionProperties_SetAngularVelocityClamped(@as(*c.JPC_MotionProperties, @ptrCast(motion)), &velocity);
|
|
}
|
|
|
|
/// `point` is relative to the center of mass (com)
|
|
pub fn getPointVelocityCom(motion: *const MotionProperties, point: [3]f32) [3]f32 {
|
|
var velocity: [3]f32 = undefined;
|
|
c.JPC_MotionProperties_GetPointVelocityCOM(
|
|
@as(*const c.JPC_MotionProperties, @ptrCast(motion)),
|
|
&point,
|
|
&velocity,
|
|
);
|
|
return velocity;
|
|
}
|
|
|
|
pub fn getMaxLinearVelocity(motion: *const MotionProperties) f32 {
|
|
return c.JPC_MotionProperties_GetMaxLinearVelocity(@as(*const c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
pub fn setMaxLinearVelocity(motion: *MotionProperties, velocity: f32) void {
|
|
c.JPC_MotionProperties_SetMaxLinearVelocity(@as(*c.JPC_MotionProperties, @ptrCast(motion)), velocity);
|
|
}
|
|
|
|
pub fn getMaxAngularVelocity(motion: *const MotionProperties) f32 {
|
|
return c.JPC_MotionProperties_GetMaxAngularVelocity(@as(*const c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
pub fn setMaxAngularVelocity(motion: *MotionProperties, velocity: f32) void {
|
|
c.JPC_MotionProperties_SetMaxAngularVelocity(@as(*c.JPC_MotionProperties, @ptrCast(motion)), velocity);
|
|
}
|
|
|
|
pub fn moveKinematic(
|
|
motion: *MotionProperties,
|
|
delta_position: [3]f32,
|
|
delta_rotation: [4]f32,
|
|
delta_time: f32,
|
|
) void {
|
|
c.JPC_MotionProperties_MoveKinematic(
|
|
@as(*c.JPC_MotionProperties, @ptrCast(motion)),
|
|
&delta_position,
|
|
&delta_rotation,
|
|
delta_time,
|
|
);
|
|
}
|
|
|
|
pub fn clampLinearVelocity(motion: *MotionProperties) void {
|
|
c.JPC_MotionProperties_ClampLinearVelocity(@as(*c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
pub fn clampAngularVelocity(motion: *MotionProperties) void {
|
|
c.JPC_MotionProperties_ClampAngularVelocity(@as(*c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
|
|
pub fn getLinearDamping(motion: *const MotionProperties) f32 {
|
|
return c.JPC_MotionProperties_GetLinearDamping(@as(*const c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
pub fn setLinearDamping(motion: *MotionProperties, damping: f32) void {
|
|
c.JPC_MotionProperties_SetLinearDamping(@as(*c.JPC_MotionProperties, @ptrCast(motion)), damping);
|
|
}
|
|
|
|
pub fn getAngularDamping(motion: *const MotionProperties) f32 {
|
|
return c.JPC_MotionProperties_GetAngularDamping(@as(*const c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
pub fn setAngularDamping(motion: *MotionProperties, damping: f32) void {
|
|
c.JPC_MotionProperties_SetAngularDamping(@as(*c.JPC_MotionProperties, @ptrCast(motion)), damping);
|
|
}
|
|
|
|
pub fn getGravityFactor(motion: *const MotionProperties) f32 {
|
|
return c.JPC_MotionProperties_GetGravityFactor(@as(*const c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
pub fn setGravityFactor(motion: *MotionProperties, factor: f32) void {
|
|
c.JPC_MotionProperties_SetGravityFactor(@as(*c.JPC_MotionProperties, @ptrCast(motion)), factor);
|
|
}
|
|
|
|
pub fn setMassProperties(motion: *MotionProperties, mass_properties: MassProperties) void {
|
|
c.JPC_MotionProperties_SetMassProperties(
|
|
@as(*c.JPC_MotionProperties, @ptrCast(motion)),
|
|
@as(*const c.JPC_MassProperties, @ptrCast(&mass_properties)),
|
|
);
|
|
}
|
|
|
|
pub fn getInverseMass(motion: *const MotionProperties) f32 {
|
|
return c.JPC_MotionProperties_GetInverseMass(@as(*const c.JPC_MotionProperties, @ptrCast(motion)));
|
|
}
|
|
pub fn setInverseMass(motion: *MotionProperties, inverse_mass: f32) void {
|
|
c.JPC_MotionProperties_SetInverseMass(@as(*c.JPC_MotionProperties, @ptrCast(motion)), inverse_mass);
|
|
}
|
|
|
|
pub fn getInverseInertiaDiagonal(motion: *const MotionProperties) [3]f32 {
|
|
var diagonal: [3]f32 = undefined;
|
|
c.JPC_MotionProperties_GetInverseInertiaDiagonal(
|
|
@as(*const c.JPC_MotionProperties, @ptrCast(motion)),
|
|
&diagonal,
|
|
);
|
|
return diagonal;
|
|
}
|
|
|
|
pub fn getInertiaRotation(motion: *const MotionProperties) [4]f32 {
|
|
var rotation: [4]f32 = undefined;
|
|
c.JPC_MotionProperties_GetInertiaRotation(@as(*const c.JPC_MotionProperties, @ptrCast(motion)), &rotation);
|
|
return rotation;
|
|
}
|
|
|
|
pub fn setInverseInertia(motion: *MotionProperties, diagonal: [3]f32, rotation: [4]f32) void {
|
|
c.JPC_MotionProperties_SetInverseInertia(@as(*c.JPC_MotionProperties, @ptrCast(motion)), &diagonal, &rotation);
|
|
}
|
|
|
|
pub fn getLocalSpaceInverseInertia(motion: *const MotionProperties) [16]f32 {
|
|
var inertia: [16]f32 = undefined;
|
|
c.JPC_MotionProperties_GetLocalSpaceInverseInertia(
|
|
@as(*const c.JPC_MotionProperties, @ptrCast(motion)),
|
|
&inertia,
|
|
);
|
|
return inertia;
|
|
}
|
|
|
|
pub fn getInverseInertiaForRotation(motion: *const MotionProperties, rotation_matrix: [16]f32) [16]f32 {
|
|
var inertia: [16]f32 = undefined;
|
|
c.JPC_MotionProperties_GetInverseInertiaForRotation(
|
|
@as(*const c.JPC_MotionProperties, @ptrCast(motion)),
|
|
&rotation_matrix,
|
|
&inertia,
|
|
);
|
|
return inertia;
|
|
}
|
|
|
|
pub fn multiplyWorldSpaceInverseInertiaByVector(
|
|
motion: *const MotionProperties,
|
|
rotation: [4]f32,
|
|
vector: [3]f32,
|
|
) [3]f32 {
|
|
var out: [3]f32 = undefined;
|
|
c.JPC_MotionProperties_MultiplyWorldSpaceInverseInertiaByVector(
|
|
@as(*const c.JPC_MotionProperties, @ptrCast(motion)),
|
|
&rotation,
|
|
&vector,
|
|
&out,
|
|
);
|
|
return out;
|
|
}
|
|
|
|
comptime {
|
|
assert(@sizeOf(MotionProperties) == @sizeOf(c.JPC_MotionProperties));
|
|
assert(@offsetOf(MotionProperties, "force") == @offsetOf(c.JPC_MotionProperties, "force"));
|
|
assert(@offsetOf(MotionProperties, "motion_quality") == @offsetOf(c.JPC_MotionProperties, "motion_quality"));
|
|
assert(@offsetOf(MotionProperties, "gravity_factor") == @offsetOf(c.JPC_MotionProperties, "gravity_factor"));
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// ShapeSettings
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const ShapeSettings = opaque {
|
|
pub usingnamespace Methods(@This());
|
|
|
|
fn Methods(comptime T: type) type {
|
|
return struct {
|
|
pub fn asShapeSettings(shape_settings: *const T) *const ShapeSettings {
|
|
return @as(*const ShapeSettings, @ptrCast(shape_settings));
|
|
}
|
|
pub fn asShapeSettingsMut(shape_settings: *T) *ShapeSettings {
|
|
return @as(*ShapeSettings, @ptrCast(shape_settings));
|
|
}
|
|
|
|
pub fn addRef(shape_settings: *T) void {
|
|
c.JPC_ShapeSettings_AddRef(@as(*c.JPC_ShapeSettings, @ptrCast(shape_settings)));
|
|
}
|
|
pub fn release(shape_settings: *T) void {
|
|
c.JPC_ShapeSettings_Release(@as(*c.JPC_ShapeSettings, @ptrCast(shape_settings)));
|
|
}
|
|
pub fn getRefCount(shape_settings: *const T) u32 {
|
|
return c.JPC_ShapeSettings_GetRefCount(@as(*const c.JPC_ShapeSettings, @ptrCast(shape_settings)));
|
|
}
|
|
|
|
pub fn createShape(shape_settings: *const T) !*Shape {
|
|
const shape = c.JPC_ShapeSettings_CreateShape(@as(*const c.JPC_ShapeSettings, @ptrCast(shape_settings)));
|
|
if (shape == null)
|
|
return error.FailedToCreateShape;
|
|
return @as(*Shape, @ptrCast(shape));
|
|
}
|
|
|
|
pub fn getUserData(shape_settings: *const T) u64 {
|
|
return c.JPC_ShapeSettings_GetUserData(@as(*const c.JPC_ShapeSettings, @ptrCast(shape_settings)));
|
|
}
|
|
pub fn setUserData(shape_settings: *T, user_data: u64) void {
|
|
return c.JPC_ShapeSettings_SetUserData(@as(*c.JPC_ShapeSettings, @ptrCast(shape_settings)), user_data);
|
|
}
|
|
};
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// ConvexShapeSettings (-> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const ConvexShapeSettings = opaque {
|
|
pub usingnamespace Methods(@This());
|
|
|
|
fn Methods(comptime T: type) type {
|
|
return struct {
|
|
pub usingnamespace ShapeSettings.Methods(T);
|
|
|
|
pub fn asConvexShapeSettings(convex_shape_settings: *T) *ConvexShapeSettings {
|
|
return @as(*ConvexShapeSettings, @ptrCast(convex_shape_settings));
|
|
}
|
|
|
|
pub fn getMaterial(convex_shape_settings: *const T) ?*const Material {
|
|
return @as(?*const Material, @ptrCast(c.JPC_ConvexShapeSettings_GetMaterial(
|
|
@as(*const c.JPC_ConvexShapeSettings, @ptrCast(convex_shape_settings)),
|
|
)));
|
|
}
|
|
pub fn setMaterial(convex_shape_settings: *T, material: ?*Material) void {
|
|
c.JPC_ConvexShapeSettings_SetMaterial(
|
|
@as(*c.JPC_ConvexShapeSettings, @ptrCast(convex_shape_settings)),
|
|
@as(?*c.JPC_PhysicsMaterial, @ptrCast(material)),
|
|
);
|
|
}
|
|
|
|
pub fn getDensity(convex_shape_settings: *const T) f32 {
|
|
return c.JPC_ConvexShapeSettings_GetDensity(
|
|
@as(*const c.JPC_ConvexShapeSettings, @ptrCast(convex_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setDensity(shape_settings: *T, density: f32) void {
|
|
c.JPC_ConvexShapeSettings_SetDensity(
|
|
@as(*c.JPC_ConvexShapeSettings, @ptrCast(shape_settings)),
|
|
density,
|
|
);
|
|
}
|
|
};
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// BoxShapeSettings (-> ConvexShapeSettings -> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const BoxShapeSettings = opaque {
|
|
pub usingnamespace ConvexShapeSettings.Methods(@This());
|
|
|
|
pub fn create(half_extent: [3]f32) !*BoxShapeSettings {
|
|
const box_shape_settings = c.JPC_BoxShapeSettings_Create(&half_extent);
|
|
if (box_shape_settings == null)
|
|
return error.FailedToCreateBoxShapeSettings;
|
|
return @as(*BoxShapeSettings, @ptrCast(box_shape_settings));
|
|
}
|
|
|
|
pub fn getHalfExtent(box_shape_settings: *const BoxShapeSettings) [3]f32 {
|
|
var half_extent: [3]f32 = undefined;
|
|
c.JPC_BoxShapeSettings_GetHalfExtent(
|
|
@as(*const c.JPC_BoxShapeSettings, @ptrCast(box_shape_settings)),
|
|
&half_extent,
|
|
);
|
|
return half_extent;
|
|
}
|
|
pub fn setHalfExtent(box_shape_settings: *BoxShapeSettings, half_extent: [3]f32) void {
|
|
c.JPC_BoxShapeSettings_SetHalfExtent(@as(*c.JPC_BoxShapeSettings, @ptrCast(box_shape_settings)), &half_extent);
|
|
}
|
|
|
|
pub fn getConvexRadius(box_shape_settings: *const BoxShapeSettings) f32 {
|
|
return c.JPC_BoxShapeSettings_GetConvexRadius(@as(*const c.JPC_BoxShapeSettings, @ptrCast(box_shape_settings)));
|
|
}
|
|
pub fn setConvexRadius(box_shape_settings: *BoxShapeSettings, convex_radius: f32) void {
|
|
c.JPC_BoxShapeSettings_SetConvexRadius(
|
|
@as(*c.JPC_BoxShapeSettings, @ptrCast(box_shape_settings)),
|
|
convex_radius,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// SphereShapeSettings (-> ConvexShapeSettings -> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const SphereShapeSettings = opaque {
|
|
pub usingnamespace ConvexShapeSettings.Methods(@This());
|
|
|
|
pub fn create(radius: f32) !*SphereShapeSettings {
|
|
const sphere_shape_settings = c.JPC_SphereShapeSettings_Create(radius);
|
|
if (sphere_shape_settings == null)
|
|
return error.FailedToCreateSphereShapeSettings;
|
|
return @as(*SphereShapeSettings, @ptrCast(sphere_shape_settings));
|
|
}
|
|
|
|
pub fn getRadius(sphere_shape_settings: *const SphereShapeSettings) f32 {
|
|
return c.JPC_SphereShapeSettings_GetRadius(
|
|
@as(*const c.JPC_SphereShapeSettings, @ptrCast(sphere_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setRadius(sphere_shape_settings: *SphereShapeSettings, radius: f32) void {
|
|
c.JPC_SphereShapeSettings_SetRadius(
|
|
@as(*c.JPC_SphereShapeSettings, @ptrCast(sphere_shape_settings)),
|
|
radius,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// TriangleShapeSettings (-> ConvexShapeSettings -> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const TriangleShapeSettings = opaque {
|
|
pub usingnamespace ConvexShapeSettings.Methods(@This());
|
|
|
|
pub fn create(v1: [3]f32, v2: [3]f32, v3: [3]f32) !*TriangleShapeSettings {
|
|
const triangle_shape_settings = c.JPC_TriangleShapeSettings_Create(&v1, &v2, &v3);
|
|
if (triangle_shape_settings == null)
|
|
return error.FailedToCreateTriangleShapeSettings;
|
|
return @as(*TriangleShapeSettings, @ptrCast(triangle_shape_settings));
|
|
}
|
|
|
|
pub fn getConvexRadius(triangle_shape_settings: *const TriangleShapeSettings) f32 {
|
|
return c.JPC_TriangleShapeSettings_GetConvexRadius(
|
|
@as(*const c.JPC_TriangleShapeSettings, @ptrCast(triangle_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setConvexRadius(triangle_shape_settings: *TriangleShapeSettings, convex_radius: f32) void {
|
|
c.JPC_TriangleShapeSettings_SetConvexRadius(
|
|
@as(*c.JPC_TriangleShapeSettings, @ptrCast(triangle_shape_settings)),
|
|
convex_radius,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// CapsuleShapeSettings (-> ConvexShapeSettings -> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const CapsuleShapeSettings = opaque {
|
|
pub usingnamespace ConvexShapeSettings.Methods(@This());
|
|
|
|
pub fn create(half_height: f32, radius: f32) !*CapsuleShapeSettings {
|
|
const capsule_shape_settings = c.JPC_CapsuleShapeSettings_Create(half_height, radius);
|
|
if (capsule_shape_settings == null)
|
|
return error.FailedToCreateCapsuleShapeSettings;
|
|
return @as(*CapsuleShapeSettings, @ptrCast(capsule_shape_settings));
|
|
}
|
|
|
|
pub fn getHalfHeight(capsule_shape_settings: *const CapsuleShapeSettings) f32 {
|
|
return c.JPC_CapsuleShapeSettings_GetHalfHeight(
|
|
@as(*const c.JPC_CapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setHalfHeight(capsule_shape_settings: *CapsuleShapeSettings, half_height: f32) void {
|
|
c.JPC_CapsuleShapeSettings_SetHalfHeight(
|
|
@as(*c.JPC_CapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
half_height,
|
|
);
|
|
}
|
|
|
|
pub fn getRadius(capsule_shape_settings: *const CapsuleShapeSettings) f32 {
|
|
return c.JPC_CapsuleShapeSettings_GetRadius(
|
|
@as(*const c.JPC_CapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setRadius(capsule_shape_settings: *CapsuleShapeSettings, radius: f32) void {
|
|
c.JPC_CapsuleShapeSettings_SetRadius(
|
|
@as(*c.JPC_CapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
radius,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// TaperedCapsuleShapeSettings (-> ConvexShapeSettings -> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const TaperedCapsuleShapeSettings = opaque {
|
|
pub usingnamespace ConvexShapeSettings.Methods(@This());
|
|
|
|
pub fn create(half_height: f32, top_radius: f32, bottom_radius: f32) !*TaperedCapsuleShapeSettings {
|
|
const capsule_shape_settings = c.JPC_TaperedCapsuleShapeSettings_Create(
|
|
half_height,
|
|
top_radius,
|
|
bottom_radius,
|
|
);
|
|
if (capsule_shape_settings == null)
|
|
return error.FailedToCreateTaperedCapsuleShapeSettings;
|
|
return @as(*TaperedCapsuleShapeSettings, @ptrCast(capsule_shape_settings));
|
|
}
|
|
|
|
pub fn getHalfHeight(capsule_shape_settings: *const TaperedCapsuleShapeSettings) f32 {
|
|
return c.JPC_TaperedCapsuleShapeSettings_GetHalfHeight(
|
|
@as(*const c.JPC_TaperedCapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setHalfHeight(capsule_shape_settings: *TaperedCapsuleShapeSettings, half_height: f32) void {
|
|
c.JPC_TaperedCapsuleShapeSettings_SetHalfHeight(
|
|
@as(*c.JPC_TaperedCapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
half_height,
|
|
);
|
|
}
|
|
|
|
pub fn getTopRadius(capsule_shape_settings: *const TaperedCapsuleShapeSettings) f32 {
|
|
return c.JPC_TaperedCapsuleShapeSettings_GetTopRadius(
|
|
@as(*const c.JPC_TaperedCapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setTopRadius(capsule_shape_settings: *TaperedCapsuleShapeSettings, radius: f32) void {
|
|
c.JPC_TaperedCapsuleShapeSettings_SetTopRadius(
|
|
@as(*c.JPC_TaperedCapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
radius,
|
|
);
|
|
}
|
|
|
|
pub fn getBottomRadius(capsule_shape_settings: *const TaperedCapsuleShapeSettings) f32 {
|
|
return c.JPC_TaperedCapsuleShapeSettings_GetBottomRadius(
|
|
@as(*const c.JPC_TaperedCapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setBottomRadius(capsule_shape_settings: *TaperedCapsuleShapeSettings, radius: f32) void {
|
|
c.JPC_TaperedCapsuleShapeSettings_SetBottomRadius(
|
|
@as(*c.JPC_TaperedCapsuleShapeSettings, @ptrCast(capsule_shape_settings)),
|
|
radius,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// CylinderShapeSettings (-> ConvexShapeSettings -> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const CylinderShapeSettings = opaque {
|
|
pub usingnamespace ConvexShapeSettings.Methods(@This());
|
|
|
|
pub fn create(half_height: f32, radius: f32) !*CylinderShapeSettings {
|
|
const cylinder_shape_settings = c.JPC_CylinderShapeSettings_Create(half_height, radius);
|
|
if (cylinder_shape_settings == null)
|
|
return error.FailedToCreateCylinderShapeSettings;
|
|
return @as(*CylinderShapeSettings, @ptrCast(cylinder_shape_settings));
|
|
}
|
|
|
|
pub fn getConvexRadius(cylinder_shape_settings: *const CylinderShapeSettings) f32 {
|
|
return c.JPC_CylinderShapeSettings_GetConvexRadius(
|
|
@as(*const c.JPC_CylinderShapeSettings, @ptrCast(cylinder_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setConvexRadius(cylinder_shape_settings: *CylinderShapeSettings, convex_radius: f32) void {
|
|
c.JPC_CylinderShapeSettings_SetConvexRadius(
|
|
@as(*c.JPC_CylinderShapeSettings, @ptrCast(cylinder_shape_settings)),
|
|
convex_radius,
|
|
);
|
|
}
|
|
|
|
pub fn getHalfHeight(cylinder_shape_settings: *const CylinderShapeSettings) f32 {
|
|
return c.JPC_CylinderShapeSettings_GetHalfHeight(
|
|
@as(*const c.JPC_CylinderShapeSettings, @ptrCast(cylinder_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setHalfHeight(cylinder_shape_settings: *CylinderShapeSettings, half_height: f32) void {
|
|
c.JPC_CylinderShapeSettings_SetHalfHeight(
|
|
@as(*c.JPC_CylinderShapeSettings, @ptrCast(cylinder_shape_settings)),
|
|
half_height,
|
|
);
|
|
}
|
|
|
|
pub fn getRadius(cylinder_shape_settings: *const CylinderShapeSettings) f32 {
|
|
return c.JPC_CylinderShapeSettings_GetRadius(
|
|
@as(*const c.JPC_CylinderShapeSettings, @ptrCast(cylinder_shape_settings)),
|
|
);
|
|
}
|
|
pub fn setRadius(cylinder_shape_settings: *CylinderShapeSettings, radius: f32) void {
|
|
c.JPC_CylinderShapeSettings_SetRadius(
|
|
@as(*c.JPC_CylinderShapeSettings, @ptrCast(cylinder_shape_settings)),
|
|
radius,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// ConvexHullShapeSettings (-> ConvexShapeSettings -> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const ConvexHullShapeSettings = opaque {
|
|
pub usingnamespace ConvexShapeSettings.Methods(@This());
|
|
|
|
pub fn create(vertices: *const anyopaque, num_vertices: u32, vertex_size: u32) !*ConvexHullShapeSettings {
|
|
const settings = c.JPC_ConvexHullShapeSettings_Create(vertices, num_vertices, vertex_size);
|
|
if (settings == null)
|
|
return error.FailedToCreateConvexHullShapeSettings;
|
|
return @as(*ConvexHullShapeSettings, @ptrCast(settings));
|
|
}
|
|
|
|
pub fn getMaxConvexRadius(settings: *const ConvexHullShapeSettings) f32 {
|
|
return c.JPC_ConvexHullShapeSettings_GetMaxConvexRadius(
|
|
@as(*const c.JPC_ConvexHullShapeSettings, @ptrCast(settings)),
|
|
);
|
|
}
|
|
pub fn setMaxConvexRadius(settings: *ConvexHullShapeSettings, radius: f32) void {
|
|
c.JPC_ConvexHullShapeSettings_SetMaxConvexRadius(
|
|
@as(*c.JPC_ConvexHullShapeSettings, @ptrCast(settings)),
|
|
radius,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// HeightFieldShapeSettings (-> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const HeightFieldShapeSettings = opaque {
|
|
pub usingnamespace ShapeSettings.Methods(@This());
|
|
|
|
pub fn create(
|
|
samples: [*]const f32, // height_field_size^2 samples
|
|
height_field_size: u32, // height_field_size / block_size must be a power of 2 and minimally 2
|
|
) !*HeightFieldShapeSettings {
|
|
const settings = c.JPC_HeightFieldShapeSettings_Create(samples, height_field_size);
|
|
if (settings == null)
|
|
return error.FailedToCreateHeightFieldShapeSettings;
|
|
return @as(*HeightFieldShapeSettings, @ptrCast(settings));
|
|
}
|
|
|
|
pub fn getBlockSize(settings: *const HeightFieldShapeSettings) u32 {
|
|
return c.JPC_HeightFieldShapeSettings_GetBlockSize(
|
|
@as(*const c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
);
|
|
}
|
|
pub fn setBlockSize(settings: *HeightFieldShapeSettings, block_size: u32) void {
|
|
c.JPC_HeightFieldShapeSettings_SetBlockSize(
|
|
@as(*c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
block_size,
|
|
);
|
|
}
|
|
|
|
pub fn getBitsPerSample(settings: *const HeightFieldShapeSettings) u32 {
|
|
return c.JPC_HeightFieldShapeSettings_GetBitsPerSample(
|
|
@as(*const c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
);
|
|
}
|
|
pub fn setBitsPerSample(settings: *HeightFieldShapeSettings, num_bits: u32) void {
|
|
c.JPC_HeightFieldShapeSettings_SetBitsPerSample(
|
|
@as(*c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
num_bits,
|
|
);
|
|
}
|
|
|
|
pub fn getOffset(settings: *const HeightFieldShapeSettings) [3]f32 {
|
|
var offset: [3]f32 = undefined;
|
|
c.JPC_HeightFieldShapeSettings_GetOffset(
|
|
@as(*const c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
&offset,
|
|
);
|
|
return offset;
|
|
}
|
|
pub fn setOffset(settings: *HeightFieldShapeSettings, offset: [3]f32) void {
|
|
c.JPC_HeightFieldShapeSettings_SetOffset(
|
|
@as(*c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
&offset,
|
|
);
|
|
}
|
|
|
|
pub fn getScale(settings: *const HeightFieldShapeSettings) [3]f32 {
|
|
var scale: [3]f32 = undefined;
|
|
c.JPC_HeightFieldShapeSettings_GetScale(
|
|
@as(*const c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
&scale,
|
|
);
|
|
return scale;
|
|
}
|
|
pub fn setScale(settings: *HeightFieldShapeSettings, scale: [3]f32) void {
|
|
c.JPC_HeightFieldShapeSettings_SetScale(
|
|
@as(*c.JPC_HeightFieldShapeSettings, @ptrCast(settings)),
|
|
&scale,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// MeshShapeSettings (-> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const MeshShapeSettings = opaque {
|
|
pub usingnamespace ShapeSettings.Methods(@This());
|
|
|
|
pub fn create(
|
|
vertices: *const anyopaque,
|
|
num_vertices: u32,
|
|
vertex_size: u32,
|
|
indices: []const u32,
|
|
) !*MeshShapeSettings {
|
|
const settings = c.JPC_MeshShapeSettings_Create(
|
|
vertices,
|
|
num_vertices,
|
|
vertex_size,
|
|
indices.ptr,
|
|
@as(u32, @intCast(indices.len)),
|
|
);
|
|
if (settings == null)
|
|
return error.FailedToCreateMeshShapeSettings;
|
|
return @as(*MeshShapeSettings, @ptrCast(settings));
|
|
}
|
|
|
|
pub fn getMaxTrianglesPerLeaf(settings: *const MeshShapeSettings) u32 {
|
|
return c.JPC_MeshShapeSettings_GetMaxTrianglesPerLeaf(
|
|
@as(*const c.JPC_MeshShapeSettings, @ptrCast(settings)),
|
|
);
|
|
}
|
|
pub fn setMaxTrianglesPerLeaf(settings: *MeshShapeSettings, max_triangles: u32) void {
|
|
c.JPC_MeshShapeSettings_SetMaxTrianglesPerLeaf(
|
|
@as(*c.JPC_MeshShapeSettings, @ptrCast(settings)),
|
|
max_triangles,
|
|
);
|
|
}
|
|
|
|
pub fn sanitize(settings: *MeshShapeSettings) void {
|
|
c.JPC_MeshShapeSettings_Sanitize(@as(*c.JPC_MeshShapeSettings, @ptrCast(settings)));
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// DecoratedShapeSettings (-> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const DecoratedShapeSettings = opaque {
|
|
pub usingnamespace ShapeSettings.Methods(@This());
|
|
|
|
pub fn createRotatedTranslated(
|
|
inner_shape: *const ShapeSettings,
|
|
rotation: [4]Real,
|
|
translation: [3]Real,
|
|
) !*DecoratedShapeSettings {
|
|
const settings = c.JPC_RotatedTranslatedShapeSettings_Create(
|
|
@as(*const c.JPC_ShapeSettings, @ptrCast(inner_shape)),
|
|
&rotation,
|
|
&translation,
|
|
);
|
|
if (settings == null) return error.FailedToCreateDecoratedShapeSettings;
|
|
return @as(*DecoratedShapeSettings, @ptrCast(settings));
|
|
}
|
|
|
|
pub fn createScaled(inner_shape: *const ShapeSettings, scale: [3]Real) !*DecoratedShapeSettings {
|
|
const settings = c.JPC_ScaledShapeSettings_Create(
|
|
@as(*const c.JPC_ShapeSettings, @ptrCast(inner_shape)),
|
|
&scale,
|
|
);
|
|
if (settings == null) return error.FailedToCreateDecoratedShapeSettings;
|
|
return @as(*DecoratedShapeSettings, @ptrCast(settings));
|
|
}
|
|
|
|
pub fn createOffsetCenterOfMass(inner_shape: *const ShapeSettings, offset: [3]Real) !*DecoratedShapeSettings {
|
|
const settings = c.JPC_OffsetCenterOfMassShapeSettings_Create(
|
|
@as(*const c.JPC_ShapeSettings, @ptrCast(inner_shape)),
|
|
&offset,
|
|
);
|
|
if (settings == null) return error.FailedToCreateDecoratedShapeSettings;
|
|
return @as(*DecoratedShapeSettings, @ptrCast(settings));
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// CompoundShapeSettings (-> ShapeSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const CompoundShapeSettings = opaque {
|
|
pub usingnamespace ShapeSettings.Methods(@This());
|
|
|
|
pub fn createStatic() !*CompoundShapeSettings {
|
|
const settings = c.JPC_StaticCompoundShapeSettings_Create();
|
|
if (settings == null) return error.FailedToCreateCompoundShapeSettings;
|
|
return @as(*CompoundShapeSettings, @ptrCast(settings));
|
|
}
|
|
|
|
pub fn createMutable() !*CompoundShapeSettings {
|
|
const settings = c.JPC_MutableCompoundShapeSettings_Create();
|
|
if (settings == null) return error.FailedToCreateCompoundShapeSettings;
|
|
return @as(*CompoundShapeSettings, @ptrCast(settings));
|
|
}
|
|
|
|
pub fn addShape(settings: *CompoundShapeSettings, position: [3]Real, rotation: [4]Real, shape: *const ShapeSettings, user_data: u32) void {
|
|
c.JPC_CompoundShapeSettings_AddShape(
|
|
@as(*c.JPC_CompoundShapeSettings, @ptrCast(settings)),
|
|
&position,
|
|
&rotation,
|
|
@as(*const c.JPC_ShapeSettings, @ptrCast(shape)),
|
|
user_data,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// Shape
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const Shape = opaque {
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub const Type = enum(c.JPC_ShapeType) {
|
|
convex = c.JPC_SHAPE_TYPE_CONVEX,
|
|
compound = c.JPC_SHAPE_TYPE_COMPOUND,
|
|
decorated = c.JPC_SHAPE_TYPE_DECORATED,
|
|
mesh = c.JPC_SHAPE_TYPE_MESH,
|
|
height_field = c.JPC_SHAPE_TYPE_HEIGHT_FIELD,
|
|
user1 = c.JPC_SHAPE_TYPE_USER1,
|
|
user2 = c.JPC_SHAPE_TYPE_USER2,
|
|
user3 = c.JPC_SHAPE_TYPE_USER3,
|
|
user4 = c.JPC_SHAPE_TYPE_USER4,
|
|
};
|
|
|
|
pub const SubType = enum(c.JPC_ShapeSubType) {
|
|
sphere = c.JPC_SHAPE_SUB_TYPE_SPHERE,
|
|
box = c.JPC_SHAPE_SUB_TYPE_BOX,
|
|
triangle = c.JPC_SHAPE_SUB_TYPE_TRIANGLE,
|
|
capsule = c.JPC_SHAPE_SUB_TYPE_CAPSULE,
|
|
tapered_capsule = c.JPC_SHAPE_SUB_TYPE_TAPERED_CAPSULE,
|
|
cylinder = c.JPC_SHAPE_SUB_TYPE_CYLINDER,
|
|
convex_hull = c.JPC_SHAPE_SUB_TYPE_CONVEX_HULL,
|
|
static_compound = c.JPC_SHAPE_SUB_TYPE_STATIC_COMPOUND,
|
|
mutable_compound = c.JPC_SHAPE_SUB_TYPE_MUTABLE_COMPOUND,
|
|
rotated_translated = c.JPC_SHAPE_SUB_TYPE_ROTATED_TRANSLATED,
|
|
scaled = c.JPC_SHAPE_SUB_TYPE_SCALED,
|
|
offset_center_of_mass = c.JPC_SHAPE_SUB_TYPE_OFFSET_CENTER_OF_MASS,
|
|
mesh = c.JPC_SHAPE_SUB_TYPE_MESH,
|
|
height_field = c.JPC_SHAPE_SUB_TYPE_HEIGHT_FIELD,
|
|
user1 = c.JPC_SHAPE_SUB_TYPE_USER1,
|
|
user2 = c.JPC_SHAPE_SUB_TYPE_USER2,
|
|
user3 = c.JPC_SHAPE_SUB_TYPE_USER3,
|
|
user4 = c.JPC_SHAPE_SUB_TYPE_USER4,
|
|
user5 = c.JPC_SHAPE_SUB_TYPE_USER5,
|
|
user6 = c.JPC_SHAPE_SUB_TYPE_USER6,
|
|
user7 = c.JPC_SHAPE_SUB_TYPE_USER7,
|
|
user8 = c.JPC_SHAPE_SUB_TYPE_USER8,
|
|
user_convex1 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX1,
|
|
user_convex2 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX2,
|
|
user_convex3 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX3,
|
|
user_convex4 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX4,
|
|
user_convex5 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX5,
|
|
user_convex6 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX6,
|
|
user_convex7 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX7,
|
|
user_convex8 = c.JPC_SHAPE_SUB_TYPE_USER_CONVEX8,
|
|
};
|
|
|
|
fn Methods(comptime T: type) type {
|
|
return struct {
|
|
pub fn asShape(shape: *const T) *const Shape {
|
|
return @as(*const Shape, @ptrCast(shape));
|
|
}
|
|
pub fn asShapeMut(shape: *T) *Shape {
|
|
return @as(*Shape, @ptrCast(shape));
|
|
}
|
|
|
|
pub fn addRef(shape: *T) void {
|
|
c.JPC_Shape_AddRef(@as(*c.JPC_Shape, @ptrCast(shape)));
|
|
}
|
|
pub fn release(shape: *T) void {
|
|
c.JPC_Shape_Release(@as(*c.JPC_Shape, @ptrCast(shape)));
|
|
}
|
|
pub fn getRefCount(shape: *const T) u32 {
|
|
return c.JPC_Shape_GetRefCount(@as(*const c.JPC_Shape, @ptrCast(shape)));
|
|
}
|
|
|
|
pub fn getType(shape: *const T) Type {
|
|
return @as(
|
|
Type,
|
|
@enumFromInt(c.JPC_Shape_GetType(@as(*const c.JPC_Shape, @ptrCast(shape)))),
|
|
);
|
|
}
|
|
pub fn getSubType(shape: *const T) SubType {
|
|
return @as(
|
|
SubType,
|
|
@enumFromInt(c.JPC_Shape_GetSubType(@as(*const c.JPC_Shape, @ptrCast(shape)))),
|
|
);
|
|
}
|
|
|
|
pub fn getUserData(shape: *const T) u64 {
|
|
return c.JPC_Shape_GetUserData(@as(*const c.JPC_Shape, @ptrCast(shape)));
|
|
}
|
|
pub fn setUserData(shape: *T, user_data: u64) void {
|
|
return c.JPC_Shape_SetUserData(@as(*c.JPC_Shape, @ptrCast(shape)), user_data);
|
|
}
|
|
|
|
pub fn getCenterOfMass(shape: *const T) [3]Real {
|
|
var center: [3]Real = undefined;
|
|
c.JPC_Shape_GetCenterOfMass(@as(*const c.JPC_Shape, @ptrCast(shape)), ¢er);
|
|
return center;
|
|
}
|
|
};
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// ConvexHullShape (-> Shape)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const ConvexHullShape = opaque {
|
|
pub usingnamespace Shape.Methods(@This());
|
|
|
|
pub fn asConvexHullShape(shape: *const Shape) *const ConvexHullShape {
|
|
assert(shape.getSubType() == .convex_hull);
|
|
return @as(*const ConvexHullShape, @ptrCast(shape));
|
|
}
|
|
pub fn asConvexHullShapeMut(shape: *Shape) *ConvexHullShape {
|
|
assert(shape.getSubType() == .convex_hull);
|
|
return @as(*ConvexHullShape, @ptrCast(shape));
|
|
}
|
|
|
|
pub fn getNumPoints(shape: *const ConvexHullShape) u32 {
|
|
return c.JPC_ConvexHullShape_GetNumPoints(@as(*const c.JPC_ConvexHullShape, @ptrCast(shape)));
|
|
}
|
|
pub fn getPoint(shape: *const ConvexHullShape, in_point_index: u32) [3]f32 {
|
|
var point: [3]f32 = undefined;
|
|
c.JPC_ConvexHullShape_GetPoint(@as(*const c.JPC_ConvexHullShape, @ptrCast(shape)), in_point_index, &point);
|
|
return point;
|
|
}
|
|
|
|
pub fn getNumFaces(shape: *const ConvexHullShape) u32 {
|
|
return c.JPC_ConvexHullShape_GetNumFaces(@as(*const c.JPC_ConvexHullShape, @ptrCast(shape)));
|
|
}
|
|
pub fn getNumVerticesInFace(shape: *const ConvexHullShape, in_face_index: u32) u32 {
|
|
return c.JPC_ConvexHullShape_GetNumVerticesInFace(
|
|
@as(*const c.JPC_ConvexHullShape, @ptrCast(shape)),
|
|
in_face_index,
|
|
);
|
|
}
|
|
|
|
/// out_vertex_buffer points to memory owned by the caller.
|
|
/// If out_vertex_buffer.len is less than getNumVerticesInFace(in_face_index), not all vertices are returned.
|
|
/// The return value gives the number of vertices in the face, identical to getNumVerticesInFace(in_face_index).
|
|
pub fn getFaceVertices(shape: *const ConvexHullShape, in_face_index: u32, out_vertex_buffer: []u32) u32 {
|
|
return c.JPC_ConvexHullShape_GetFaceVertices(
|
|
@as(*const c.JPC_ConvexHullShape, @ptrCast(shape)),
|
|
in_face_index,
|
|
@as(u32, @intCast(out_vertex_buffer.len)),
|
|
out_vertex_buffer.ptr,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// ConstraintSettings
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const ConstraintSettings = opaque {
|
|
pub usingnamespace Methods(@This());
|
|
|
|
fn Methods(comptime T: type) type {
|
|
return struct {
|
|
pub fn asConstraintSettings(constraint_settings: *const T) *const ConstraintSettings {
|
|
return @as(*const ConstraintSettings, @ptrCast(constraint_settings));
|
|
}
|
|
pub fn asConstraintSettingsMut(constraint_settings: *T) *ConstraintSettings {
|
|
return @as(*ConstraintSettings, @ptrCast(constraint_settings));
|
|
}
|
|
|
|
pub fn addRef(constraint_settings: *T) void {
|
|
c.JPC_ConstraintSettings_AddRef(@as(*c.JPC_ConstraintSettings, @ptrCast(constraint_settings)));
|
|
}
|
|
pub fn release(constraint_settings: *T) void {
|
|
c.JPC_ConstraintSettings_Release(@as(*c.JPC_ConstraintSettings, @ptrCast(constraint_settings)));
|
|
}
|
|
pub fn getRefCount(constraint_settings: *const T) u32 {
|
|
return c.JPC_ConstraintSettings_GetRefCount(@as(*const c.JPC_ConstraintSettings, @ptrCast(constraint_settings)));
|
|
}
|
|
|
|
pub fn getUserData(constraint_settings: *const T) u64 {
|
|
return c.JPC_ConstraintSettings_GetUserData(@as(*const c.JPC_ConstraintSettings, @ptrCast(constraint_settings)));
|
|
}
|
|
pub fn setUserData(constraint_settings: *T, user_data: u64) void {
|
|
return c.JPC_ConstraintSettings_SetUserData(
|
|
@as(*c.JPC_ConstraintSettings, @ptrCast(constraint_settings)),
|
|
user_data,
|
|
);
|
|
}
|
|
};
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// TwoBodyConstraintSettings (-> ConstraintSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const TwoBodyConstraintSettings = opaque {
|
|
pub usingnamespace Methods(@This());
|
|
|
|
fn Methods(comptime T: type) type {
|
|
return struct {
|
|
pub usingnamespace ConstraintSettings.Methods(T);
|
|
|
|
pub fn asTwoBodyConstraintSettings(two_body_constraint_settings: *T) *TwoBodyConstraintSettings {
|
|
return @as(*TwoBodyConstraintSettings, @ptrCast(two_body_constraint_settings));
|
|
}
|
|
|
|
pub fn createConstraint(two_body_constraint_settings: *const T, body1: *Body, body2: *Body) !*Constraint {
|
|
const constraint = c.JPC_TwoBodyConstraintSettings_CreateConstraint(
|
|
@as(*const c.JPC_TwoBodyConstraintSettings, @ptrCast(two_body_constraint_settings)),
|
|
@as(*c.JPC_Body, @ptrCast(body1)),
|
|
@as(*c.JPC_Body, @ptrCast(body2)),
|
|
);
|
|
if (constraint == null)
|
|
return error.FailedToCreateConstraint;
|
|
return @as(*Constraint, @ptrCast(constraint));
|
|
}
|
|
};
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// FixedConstraintSettings (-> TwoBodyConstraintSettings -> ConstraintSettings)
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const FixedConstraintSettings = opaque {
|
|
pub usingnamespace TwoBodyConstraintSettings.Methods(@This());
|
|
|
|
pub fn create() !*FixedConstraintSettings {
|
|
const fixed_constraint_settings = c.JPC_FixedConstraintSettings_Create();
|
|
if (fixed_constraint_settings == null) return error.FailedToCreateFixedConstraintSettings;
|
|
return @as(*FixedConstraintSettings, @ptrCast(fixed_constraint_settings));
|
|
}
|
|
|
|
pub fn setSpace(settings: *FixedConstraintSettings, space: Constraint.Space) void {
|
|
c.JPC_FixedConstraintSettings_SetSpace(
|
|
@as(*c.JPC_FixedConstraintSettings, @ptrCast(settings)),
|
|
@intFromEnum(space),
|
|
);
|
|
}
|
|
|
|
pub fn setAutoDetectPoint(settings: *FixedConstraintSettings, enabled: bool) void {
|
|
c.JPC_FixedConstraintSettings_SetAutoDetectPoint(
|
|
@as(*c.JPC_FixedConstraintSettings, @ptrCast(settings)),
|
|
enabled,
|
|
);
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// Constraint
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
pub const Constraint = opaque {
|
|
pub usingnamespace Methods(@This());
|
|
|
|
pub const Type = enum(c.JPC_ConstraintType) {
|
|
constraint = c.JPC_CONSTRAINT_TYPE_CONSTRAINT,
|
|
two_body_constraint = c.JPC_CONSTRAINT_TYPE_TWO_BODY_CONSTRAINT,
|
|
};
|
|
|
|
pub const SubType = enum(c.JPC_ConstraintSubType) {
|
|
fixed = c.JPC_CONSTRAINT_SUB_TYPE_FIXED,
|
|
point = c.JPC_CONSTRAINT_SUB_TYPE_POINT,
|
|
hinge = c.JPC_CONSTRAINT_SUB_TYPE_HINGE,
|
|
slider = c.JPC_CONSTRAINT_SUB_TYPE_SLIDER,
|
|
distance = c.JPC_CONSTRAINT_SUB_TYPE_DISTANCE,
|
|
cone = c.JPC_CONSTRAINT_SUB_TYPE_CONE,
|
|
swing_twist = c.JPC_CONSTRAINT_SUB_TYPE_SWING_TWIST,
|
|
six_dof = c.JPC_CONSTRAINT_SUB_TYPE_SIX_DOF,
|
|
path = c.JPC_CONSTRAINT_SUB_TYPE_PATH,
|
|
vehicle = c.JPC_CONSTRAINT_SUB_TYPE_VEHICLE,
|
|
rack_and_pinion = c.JPC_CONSTRAINT_SUB_TYPE_RACK_AND_PINION,
|
|
gear = c.JPC_CONSTRAINT_SUB_TYPE_GEAR,
|
|
pulley = c.JPC_CONSTRAINT_SUB_TYPE_PULLEY,
|
|
user1 = c.JPC_CONSTRAINT_SUB_TYPE_USER1,
|
|
user2 = c.JPC_CONSTRAINT_SUB_TYPE_USER2,
|
|
user3 = c.JPC_CONSTRAINT_SUB_TYPE_USER3,
|
|
user4 = c.JPC_CONSTRAINT_SUB_TYPE_USER4,
|
|
};
|
|
|
|
pub const Space = enum(c.JPC_ConstraintSpace) {
|
|
local_to_body_com = c.JPC_CONSTRAINT_SPACE_LOCAL_TO_BODY_COM,
|
|
world_space = c.JPC_CONSTRAINT_SPACE_WORLD_SPACE,
|
|
};
|
|
|
|
fn Methods(comptime T: type) type {
|
|
return struct {
|
|
pub fn asConstraint(constraint: *const T) *const Constraint {
|
|
return @as(*const Constraint, @ptrCast(constraint));
|
|
}
|
|
pub fn asConstraintMut(constraint: *T) *Constraint {
|
|
return @as(*Constraint, @ptrCast(constraint));
|
|
}
|
|
|
|
pub fn addRef(constraint: *T) void {
|
|
c.JPC_Constraint_AddRef(@as(*c.JPC_Constraint, @ptrCast(constraint)));
|
|
}
|
|
pub fn release(constraint: *T) void {
|
|
c.JPC_Constraint_Release(@as(*c.JPC_Constraint, @ptrCast(constraint)));
|
|
}
|
|
pub fn getRefCount(constraint: *const T) u32 {
|
|
return c.JPC_Constraint_GetRefCount(@as(*const c.JPC_Constraint, @ptrCast(constraint)));
|
|
}
|
|
|
|
pub fn getType(constraint: *const T) Type {
|
|
return @as(
|
|
Type,
|
|
@enumFromInt(c.JPC_Constraint_GetType(@as(*const c.JPC_Constraint, @ptrCast(constraint)))),
|
|
);
|
|
}
|
|
pub fn getSubType(constraint: *const T) SubType {
|
|
return @as(
|
|
SubType,
|
|
@enumFromInt(c.JPC_Constraint_GetSubType(@as(*const c.JPC_Constraint, @ptrCast(constraint)))),
|
|
);
|
|
}
|
|
|
|
pub fn getUserData(constraint: *const T) u64 {
|
|
return c.JPC_Constraint_GetUserData(@as(*const c.JPC_Constraint, @ptrCast(constraint)));
|
|
}
|
|
pub fn setUserData(constraint: *T, user_data: u64) void {
|
|
return c.JPC_Constraint_SetUserData(@as(*c.JPC_Constraint, @ptrCast(constraint)), user_data);
|
|
}
|
|
};
|
|
}
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// Memory allocation
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
fn zphysicsAlloc(size: usize) callconv(.C) ?*anyopaque {
|
|
mem_mutex.lock();
|
|
defer mem_mutex.unlock();
|
|
|
|
const ptr = mem_allocator.?.rawAlloc(
|
|
size,
|
|
std.mem.Alignment.@"16",
|
|
@returnAddress(),
|
|
);
|
|
if (ptr == null) @panic("zphysics: out of memory");
|
|
|
|
mem_allocations.?.put(
|
|
@intFromPtr(ptr),
|
|
.{ .size = @as(u48, @intCast(size)), .alignment = mem_alignment },
|
|
) catch @panic("zphysics: out of memory");
|
|
|
|
return ptr;
|
|
}
|
|
|
|
fn zphysicsAlignedAlloc(size: usize, alignment: usize) callconv(.C) ?*anyopaque {
|
|
mem_mutex.lock();
|
|
defer mem_mutex.unlock();
|
|
|
|
const ptr = mem_allocator.?.rawAlloc(
|
|
size,
|
|
@enumFromInt(std.math.log2_int(u29, @as(u29, @intCast(alignment)))),
|
|
@returnAddress(),
|
|
);
|
|
if (ptr == null) @panic("zphysics: out of memory");
|
|
|
|
mem_allocations.?.put(
|
|
@intFromPtr(ptr),
|
|
.{ .size = @as(u32, @intCast(size)), .alignment = @as(u16, @intCast(alignment)) },
|
|
) catch @panic("zphysics: out of memory");
|
|
|
|
return ptr;
|
|
}
|
|
|
|
fn zphysicsFree(maybe_ptr: ?*anyopaque) callconv(.C) void {
|
|
if (maybe_ptr) |ptr| {
|
|
mem_mutex.lock();
|
|
defer mem_mutex.unlock();
|
|
|
|
const info = mem_allocations.?.fetchRemove(@intFromPtr(ptr)).?.value;
|
|
|
|
const mem = @as([*]u8, @ptrCast(ptr))[0..info.size];
|
|
|
|
mem_allocator.?.rawFree(
|
|
mem,
|
|
@enumFromInt(std.math.log2_int(u29, @as(u29, @intCast(info.alignment)))),
|
|
@returnAddress(),
|
|
);
|
|
}
|
|
}
|
|
//--------------------------------------------------------------------------------------------------
|
|
//
|
|
// Tests
|
|
//
|
|
//--------------------------------------------------------------------------------------------------
|
|
const expect = std.testing.expect;
|
|
|
|
test {
|
|
std.testing.refAllDeclsRecursive(@This());
|
|
}
|
|
|
|
extern fn JoltCTest_Basic1() u32;
|
|
test "jolt_c.basic1" {
|
|
const ret = JoltCTest_Basic1();
|
|
try expect(ret != 0);
|
|
}
|
|
|
|
extern fn JoltCTest_Basic2() u32;
|
|
test "jolt_c.basic2" {
|
|
const ret = JoltCTest_Basic2();
|
|
try expect(ret != 0);
|
|
}
|
|
|
|
extern fn JoltCTest_HelloWorld() u32;
|
|
test "jolt_c.helloworld" {
|
|
const ret = JoltCTest_HelloWorld();
|
|
try expect(ret != 0);
|
|
}
|
|
|
|
test "zphysics.BodyCreationSettings" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const approxEql = std.math.approxEqAbs;
|
|
|
|
const bcs0 = BodyCreationSettings{};
|
|
const bcs1 = blk: {
|
|
var settings: c.JPC_BodyCreationSettings = undefined;
|
|
c.JPC_BodyCreationSettings_SetDefault(&settings);
|
|
break :blk @as(*const BodyCreationSettings, @ptrCast(&settings)).*;
|
|
};
|
|
|
|
try expect(approxEql(Real, bcs0.position[0], bcs1.position[0], 0.0001));
|
|
try expect(approxEql(Real, bcs0.position[1], bcs1.position[1], 0.0001));
|
|
try expect(approxEql(Real, bcs0.position[2], bcs1.position[2], 0.0001));
|
|
|
|
try expect(approxEql(f32, bcs0.rotation[0], bcs1.rotation[0], 0.0001));
|
|
try expect(approxEql(f32, bcs0.rotation[1], bcs1.rotation[1], 0.0001));
|
|
try expect(approxEql(f32, bcs0.rotation[2], bcs1.rotation[2], 0.0001));
|
|
try expect(approxEql(f32, bcs0.rotation[3], bcs1.rotation[3], 0.0001));
|
|
|
|
try expect(approxEql(f32, bcs0.linear_velocity[0], bcs1.linear_velocity[0], 0.0001));
|
|
try expect(approxEql(f32, bcs0.linear_velocity[1], bcs1.linear_velocity[1], 0.0001));
|
|
try expect(approxEql(f32, bcs0.linear_velocity[2], bcs1.linear_velocity[2], 0.0001));
|
|
|
|
try expect(approxEql(f32, bcs0.angular_velocity[0], bcs1.angular_velocity[0], 0.0001));
|
|
try expect(approxEql(f32, bcs0.angular_velocity[1], bcs1.angular_velocity[1], 0.0001));
|
|
try expect(approxEql(f32, bcs0.angular_velocity[2], bcs1.angular_velocity[2], 0.0001));
|
|
|
|
try expect(bcs0.user_data == bcs1.user_data);
|
|
try expect(bcs0.object_layer == bcs1.object_layer);
|
|
//try expect(eql(u8, asBytes(&bcs0.collision_group), asBytes(&bcs1.collision_group)));
|
|
try expect(bcs0.motion_type == bcs1.motion_type);
|
|
try expect(bcs0.allow_dynamic_or_kinematic == bcs1.allow_dynamic_or_kinematic);
|
|
try expect(bcs0.is_sensor == bcs1.is_sensor);
|
|
try expect(bcs0.use_manifold_reduction == bcs1.use_manifold_reduction);
|
|
try expect(bcs0.motion_quality == bcs1.motion_quality);
|
|
try expect(bcs0.allow_sleeping == bcs1.allow_sleeping);
|
|
try expect(approxEql(f32, bcs0.friction, bcs1.friction, 0.0001));
|
|
try expect(approxEql(f32, bcs0.restitution, bcs1.restitution, 0.0001));
|
|
try expect(approxEql(f32, bcs0.linear_damping, bcs1.linear_damping, 0.0001));
|
|
try expect(approxEql(f32, bcs0.angular_damping, bcs1.angular_damping, 0.0001));
|
|
try expect(approxEql(f32, bcs0.max_linear_velocity, bcs1.max_linear_velocity, 0.0001));
|
|
try expect(approxEql(f32, bcs0.max_angular_velocity, bcs1.max_angular_velocity, 0.0001));
|
|
try expect(approxEql(f32, bcs0.gravity_factor, bcs1.gravity_factor, 0.0001));
|
|
try expect(bcs0.override_mass_properties == bcs1.override_mass_properties);
|
|
try expect(approxEql(f32, bcs0.inertia_multiplier, bcs1.inertia_multiplier, 0.0001));
|
|
try expect(approxEql(f32, bcs0.mass_properties_override.mass, bcs1.mass_properties_override.mass, 0.0001));
|
|
//try expect(eql(
|
|
// u8,
|
|
// asBytes(&bcs0.mass_properties_override.inertia),
|
|
// asBytes(&bcs1.mass_properties_override.inertia),
|
|
//));
|
|
try expect(bcs0.reserved == bcs1.reserved);
|
|
try expect(bcs0.shape == bcs1.shape);
|
|
}
|
|
|
|
test "zphysics.basic" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{
|
|
.max_bodies = 1024,
|
|
.num_body_mutexes = 0,
|
|
.max_body_pairs = 1024,
|
|
.max_contact_constraints = 1024,
|
|
},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
try expect(physics_system.getNumBodies() == 0);
|
|
try expect(physics_system.getNumActiveBodies() == 0);
|
|
try expect(physics_system.getMaxBodies() == 1024);
|
|
|
|
{
|
|
physics_system.setGravity(.{ 0, -10.0, 0 });
|
|
const gravity = physics_system.getGravity();
|
|
try expect(gravity[0] == 0 and gravity[1] == -10.0 and gravity[2] == 0);
|
|
}
|
|
|
|
try expect(physics_system.getBodyActivationListener() == null);
|
|
physics_system.setBodyActivationListener(null);
|
|
try expect(physics_system.getBodyActivationListener() == null);
|
|
|
|
try expect(physics_system.getContactListener() == null);
|
|
physics_system.setContactListener(null);
|
|
try expect(physics_system.getContactListener() == null);
|
|
|
|
_ = physics_system.getBodyInterface();
|
|
_ = physics_system.getBodyInterfaceNoLock();
|
|
_ = physics_system.getBodyInterfaceMut();
|
|
_ = physics_system.getBodyInterfaceMutNoLock();
|
|
_ = physics_system.getBodyLockInterface();
|
|
_ = physics_system.getBodyLockInterfaceNoLock();
|
|
_ = physics_system.getNarrowPhaseQuery();
|
|
_ = physics_system.getNarrowPhaseQueryNoLock();
|
|
|
|
var my_step_listener = test_cb1.MyPhysicsStepListener{};
|
|
physics_system.addStepListener(@ptrCast(@alignCast(&my_step_listener)));
|
|
|
|
physics_system.optimizeBroadPhase();
|
|
try physics_system.update(1.0 / 60.0, .{ .collision_steps = 1, .integration_sub_steps = 1 });
|
|
try physics_system.update(1.0 / 60.0, .{});
|
|
|
|
physics_system.removeStepListener(@ptrCast(@alignCast(&my_step_listener)));
|
|
|
|
var box_shape_settings: ?*BoxShapeSettings = null;
|
|
box_shape_settings = try BoxShapeSettings.create(.{ 1.0, 2.0, 3.0 });
|
|
defer {
|
|
if (box_shape_settings) |bss| bss.release();
|
|
}
|
|
|
|
box_shape_settings.?.setDensity(2.0);
|
|
try expect(box_shape_settings.?.getDensity() == 2.0);
|
|
|
|
box_shape_settings.?.setUserData(123);
|
|
try expect(box_shape_settings.?.getUserData() == 123);
|
|
|
|
box_shape_settings.?.setConvexRadius(0.5);
|
|
try expect(box_shape_settings.?.getConvexRadius() == 0.5);
|
|
|
|
try expect(box_shape_settings.?.getRefCount() == 1);
|
|
box_shape_settings.?.addRef();
|
|
try expect(box_shape_settings.?.getRefCount() == 2);
|
|
box_shape_settings.?.release();
|
|
try expect(box_shape_settings.?.getRefCount() == 1);
|
|
|
|
{
|
|
var he = box_shape_settings.?.getHalfExtent();
|
|
try expect(he[0] == 1.0 and he[1] == 2.0 and he[2] == 3.0);
|
|
box_shape_settings.?.setHalfExtent(.{ 4.0, 5.0, 6.0 });
|
|
he = box_shape_settings.?.getHalfExtent();
|
|
try expect(he[0] == 4.0 and he[1] == 5.0 and he[2] == 6.0);
|
|
}
|
|
|
|
try expect(box_shape_settings.?.asConvexShapeSettings().getDensity() == 2.0);
|
|
try expect(box_shape_settings.?.asShapeSettings().getRefCount() == 1);
|
|
|
|
const box_shape = try box_shape_settings.?.createShape();
|
|
defer box_shape.release();
|
|
|
|
{
|
|
const bs = try box_shape_settings.?.createShape();
|
|
defer bs.release();
|
|
try expect(bs == box_shape);
|
|
try expect(bs.getRefCount() == 3);
|
|
}
|
|
|
|
try expect(box_shape.getRefCount() == 2);
|
|
box_shape_settings.?.release();
|
|
box_shape_settings = null;
|
|
try expect(box_shape.getRefCount() == 1);
|
|
|
|
try expect(box_shape.getType() == .convex);
|
|
try expect(box_shape.getSubType() == .box);
|
|
|
|
box_shape.setUserData(456);
|
|
try expect(box_shape.getUserData() == 456);
|
|
}
|
|
|
|
test "zphysics.shape.sphere" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const sphere_shape_settings = try SphereShapeSettings.create(10.0);
|
|
defer sphere_shape_settings.release();
|
|
|
|
try expect(sphere_shape_settings.getRadius() == 10.0);
|
|
|
|
sphere_shape_settings.setRadius(2.0);
|
|
try expect(sphere_shape_settings.getRadius() == 2.0);
|
|
|
|
sphere_shape_settings.setDensity(2.0);
|
|
try expect(sphere_shape_settings.getDensity() == 2.0);
|
|
|
|
sphere_shape_settings.setMaterial(null);
|
|
try expect(sphere_shape_settings.getMaterial() == null);
|
|
|
|
const sphere_shape = try sphere_shape_settings.createShape();
|
|
defer sphere_shape.release();
|
|
|
|
try expect(sphere_shape.getRefCount() == 2);
|
|
try expect(sphere_shape.getType() == .convex);
|
|
try expect(sphere_shape.getSubType() == .sphere);
|
|
|
|
sphere_shape.setUserData(1456);
|
|
try expect(sphere_shape.getUserData() == 1456);
|
|
}
|
|
|
|
test "zphysics.shape.capsule" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const capsule_shape_settings = try CapsuleShapeSettings.create(10.0, 2.0);
|
|
defer capsule_shape_settings.release();
|
|
|
|
try expect(capsule_shape_settings.getRadius() == 2.0);
|
|
try expect(capsule_shape_settings.getHalfHeight() == 10.0);
|
|
|
|
capsule_shape_settings.setRadius(4.0);
|
|
try expect(capsule_shape_settings.getRadius() == 4.0);
|
|
|
|
capsule_shape_settings.setHalfHeight(1.0);
|
|
try expect(capsule_shape_settings.getHalfHeight() == 1.0);
|
|
|
|
const capsule_shape = try capsule_shape_settings.createShape();
|
|
defer capsule_shape.release();
|
|
|
|
try expect(capsule_shape.getRefCount() == 2);
|
|
try expect(capsule_shape.getType() == .convex);
|
|
try expect(capsule_shape.getSubType() == .capsule);
|
|
|
|
capsule_shape.setUserData(146);
|
|
try expect(capsule_shape.getUserData() == 146);
|
|
}
|
|
|
|
test "zphysics.shape.taperedcapsule" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const capsule_shape_settings = try TaperedCapsuleShapeSettings.create(10.0, 2.0, 3.0);
|
|
defer capsule_shape_settings.release();
|
|
|
|
try expect(capsule_shape_settings.getTopRadius() == 2.0);
|
|
try expect(capsule_shape_settings.getBottomRadius() == 3.0);
|
|
try expect(capsule_shape_settings.getHalfHeight() == 10.0);
|
|
|
|
capsule_shape_settings.setTopRadius(4.0);
|
|
try expect(capsule_shape_settings.getTopRadius() == 4.0);
|
|
|
|
capsule_shape_settings.setBottomRadius(1.0);
|
|
try expect(capsule_shape_settings.getBottomRadius() == 1.0);
|
|
|
|
const capsule_shape = try capsule_shape_settings.createShape();
|
|
defer capsule_shape.release();
|
|
|
|
try expect(capsule_shape.getRefCount() == 2);
|
|
try expect(capsule_shape.getType() == .convex);
|
|
try expect(capsule_shape.getSubType() == .tapered_capsule);
|
|
|
|
capsule_shape.setUserData(1146);
|
|
try expect(capsule_shape.getUserData() == 1146);
|
|
}
|
|
|
|
test "zphysics.shape.cylinder" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const cylinder_shape_settings = try CylinderShapeSettings.create(10.0, 2.0);
|
|
defer cylinder_shape_settings.release();
|
|
|
|
try expect(cylinder_shape_settings.getRadius() == 2.0);
|
|
try expect(cylinder_shape_settings.getHalfHeight() == 10.0);
|
|
|
|
cylinder_shape_settings.setRadius(4.0);
|
|
try expect(cylinder_shape_settings.getRadius() == 4.0);
|
|
|
|
cylinder_shape_settings.setHalfHeight(1.0);
|
|
try expect(cylinder_shape_settings.getHalfHeight() == 1.0);
|
|
|
|
cylinder_shape_settings.setConvexRadius(0.5);
|
|
try expect(cylinder_shape_settings.getConvexRadius() == 0.5);
|
|
|
|
const cylinder_shape = try cylinder_shape_settings.createShape();
|
|
defer cylinder_shape.release();
|
|
|
|
try expect(cylinder_shape.getRefCount() == 2);
|
|
try expect(cylinder_shape.getType() == .convex);
|
|
try expect(cylinder_shape.getSubType() == .cylinder);
|
|
|
|
cylinder_shape.setUserData(146);
|
|
try expect(cylinder_shape.getUserData() == 146);
|
|
}
|
|
|
|
test "zphysics.shape.convexhull" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const points = [_]f32{ 0, 0, 0, 1, 1, 1, 1, 1, 0 };
|
|
|
|
const settings = try ConvexHullShapeSettings.create(&points, 3, 12);
|
|
defer settings.release();
|
|
|
|
settings.setMaxConvexRadius(0.1);
|
|
try expect(settings.getMaxConvexRadius() == 0.1);
|
|
|
|
const shape = try settings.createShape();
|
|
defer shape.release();
|
|
|
|
try expect(shape.getRefCount() == 2);
|
|
try expect(shape.getType() == .convex);
|
|
try expect(shape.getSubType() == .convex_hull);
|
|
|
|
shape.setUserData(111);
|
|
try expect(shape.getUserData() == 111);
|
|
}
|
|
|
|
test "zphysics.shape.heightfield" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const points = [16]f32{ 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 };
|
|
|
|
// Height field size is 4x4
|
|
const settings = try HeightFieldShapeSettings.create(&points, 4);
|
|
defer settings.release();
|
|
|
|
settings.setBlockSize(2);
|
|
settings.setBitsPerSample(6);
|
|
settings.setOffset(.{ 1, 2, 3 });
|
|
settings.setScale(.{ 4, 5, 6 });
|
|
|
|
try expect(settings.getBlockSize() == 2);
|
|
try expect(settings.getBitsPerSample() == 6);
|
|
try expect(settings.getOffset()[0] == 1);
|
|
try expect(settings.getOffset()[1] == 2);
|
|
try expect(settings.getOffset()[2] == 3);
|
|
try expect(settings.getScale()[0] == 4);
|
|
try expect(settings.getScale()[1] == 5);
|
|
try expect(settings.getScale()[2] == 6);
|
|
|
|
const shape = try settings.createShape();
|
|
defer shape.release();
|
|
|
|
try expect(shape.getRefCount() == 2);
|
|
try expect(shape.getType() == .height_field);
|
|
try expect(shape.getSubType() == .height_field);
|
|
|
|
shape.setUserData(1112);
|
|
try expect(shape.getUserData() == 1112);
|
|
}
|
|
|
|
test "zphysics.shape.meshshape" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const vertices = [9]f32{ 0, 0, 0, 1, 1, 1, 1, -1, 1 };
|
|
const indices = [3]u32{ 0, 1, 2 };
|
|
|
|
const settings = try MeshShapeSettings.create(&vertices, 3, @sizeOf([3]f32), &indices);
|
|
defer settings.release();
|
|
|
|
settings.setMaxTrianglesPerLeaf(4);
|
|
settings.sanitize();
|
|
|
|
try expect(settings.getMaxTrianglesPerLeaf() == 4);
|
|
|
|
const shape = try settings.createShape();
|
|
defer shape.release();
|
|
|
|
try expect(shape.getRefCount() == 2);
|
|
try expect(shape.getType() == .mesh);
|
|
try expect(shape.getSubType() == .mesh);
|
|
|
|
shape.setUserData(1112);
|
|
try expect(shape.getUserData() == 1112);
|
|
}
|
|
|
|
test "zphysics.body.basic" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{
|
|
.max_bodies = 1024,
|
|
.num_body_mutexes = 0,
|
|
.max_body_pairs = 1024,
|
|
.max_contact_constraints = 1024,
|
|
},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const body_interface_mut = physics_system.getBodyInterfaceMut();
|
|
const body_interface = physics_system.getBodyInterface();
|
|
|
|
const floor_shape_settings = try BoxShapeSettings.create(.{ 100.0, 1.0, 100.0 });
|
|
defer floor_shape_settings.release();
|
|
|
|
const floor_shape = try floor_shape_settings.createShape();
|
|
defer floor_shape.release();
|
|
|
|
const floor_settings = BodyCreationSettings{
|
|
.position = .{ 0.0, -1.0, 0.0, 1.0 },
|
|
.rotation = .{ 0.0, 0.0, 0.0, 1.0 },
|
|
.shape = floor_shape,
|
|
.motion_type = .static,
|
|
.object_layer = test_cb1.object_layers.non_moving,
|
|
};
|
|
const body_id = try body_interface_mut.createAndAddBody(floor_settings, .activate);
|
|
defer {
|
|
body_interface_mut.removeBody(body_id);
|
|
body_interface_mut.destroyBody(body_id);
|
|
}
|
|
|
|
physics_system.optimizeBroadPhase();
|
|
|
|
{
|
|
const query = physics_system.getNarrowPhaseQuery();
|
|
|
|
var result = query.castRay(.{ .origin = .{ 0, 10, 0, 1 }, .direction = .{ 0, -20, 0, 0 } }, .{});
|
|
try expect(result.has_hit == true);
|
|
try expect(result.hit.body_id == body_id);
|
|
try expect(result.hit.sub_shape_id == sub_shape_id_empty);
|
|
try expect(std.math.approxEqAbs(f32, result.hit.fraction, 0.5, 0.001) == true);
|
|
|
|
result = query.castRay(.{ .origin = .{ 0, 10, 0, 1 }, .direction = .{ 0, 20, 0, 0 } }, .{});
|
|
try expect(result.has_hit == false);
|
|
try expect(result.hit.body_id == body_id_invalid);
|
|
|
|
result = query.castRay(.{ .origin = .{ 0, 10, 0, 1 }, .direction = .{ 0, -5, 0, 0 } }, .{});
|
|
try expect(result.has_hit == false);
|
|
try expect(result.hit.body_id == body_id_invalid);
|
|
|
|
const ray = c.JPC_RRayCast{
|
|
.origin = .{ 0, 10, 0, 0 },
|
|
.direction = .{ 0, -20, 0, 0 },
|
|
};
|
|
var hit: c.JPC_RayCastResult = .{
|
|
.body_id = body_id_invalid,
|
|
.fraction = 1.0 + flt_epsilon,
|
|
.sub_shape_id = undefined,
|
|
};
|
|
const has_hit = c.JPC_NarrowPhaseQuery_CastRay(
|
|
@as(*const c.JPC_NarrowPhaseQuery, @ptrCast(query)),
|
|
&ray,
|
|
&hit,
|
|
null, // broad_phase_layer_filter
|
|
null, // object_layer_filter
|
|
null, // body_filter
|
|
);
|
|
try expect(has_hit == true);
|
|
try expect(std.math.approxEqAbs(f32, hit.fraction, 0.5, 0.001) == true);
|
|
}
|
|
|
|
{
|
|
var body_ids = std.ArrayList(BodyId).init(std.testing.allocator);
|
|
defer body_ids.deinit();
|
|
try physics_system.getBodyIds(&body_ids);
|
|
try expect(body_ids.items.len == 1);
|
|
try expect(body_ids.capacity >= physics_system.getMaxBodies());
|
|
try expect(body_ids.items[0] == body_id);
|
|
}
|
|
|
|
{
|
|
var body_ids = std.ArrayList(BodyId).init(std.testing.allocator);
|
|
defer body_ids.deinit();
|
|
try physics_system.getActiveBodyIds(&body_ids);
|
|
try expect(body_ids.items.len == 0);
|
|
try expect(body_ids.capacity >= physics_system.getMaxBodies());
|
|
}
|
|
|
|
{
|
|
const lock_interface = physics_system.getBodyLockInterfaceNoLock();
|
|
|
|
var read_lock: BodyLockRead = .{};
|
|
read_lock.lock(lock_interface, body_id);
|
|
defer read_lock.unlock();
|
|
|
|
if (read_lock.body) |locked_body| {
|
|
const all_bodies: []const *const Body = physics_system.getBodiesUnsafe();
|
|
|
|
try expect(isValidBodyPointer(all_bodies[body_id & body_id_index_bits]));
|
|
try expect(locked_body == all_bodies[body_id & body_id_index_bits]);
|
|
try expect(locked_body.id == body_id);
|
|
try expect(locked_body.id == all_bodies[body_id & body_id_index_bits].id);
|
|
}
|
|
}
|
|
{
|
|
const lock_interface = physics_system.getBodyLockInterface();
|
|
|
|
var write_lock: BodyLockWrite = .{};
|
|
write_lock.lock(lock_interface, body_id);
|
|
defer write_lock.unlock();
|
|
|
|
if (write_lock.body) |locked_body| {
|
|
const all_bodies_mut: []const *Body = physics_system.getBodiesMutUnsafe();
|
|
|
|
try expect(isValidBodyPointer(all_bodies_mut[body_id & body_id_index_bits]));
|
|
try expect(locked_body == all_bodies_mut[body_id & body_id_index_bits]);
|
|
try expect(locked_body.id == body_id);
|
|
try expect(locked_body.id == all_bodies_mut[body_id & body_id_index_bits].id);
|
|
|
|
all_bodies_mut[body_id & body_id_index_bits].user_data = 12345;
|
|
try expect(all_bodies_mut[body_id & body_id_index_bits].user_data == 12345);
|
|
}
|
|
}
|
|
|
|
try expect(physics_system.getNumBodies() == 1);
|
|
try expect(physics_system.getNumActiveBodies() == 0);
|
|
|
|
{
|
|
const body1 = try body_interface_mut.createBody(floor_settings);
|
|
defer body_interface_mut.destroyBody(body1.id);
|
|
try expect(body_interface.isAdded(body1.getId()) == false);
|
|
|
|
const xform = body1.getWorldTransform();
|
|
try expect(xform.rotation[0] == 1.0);
|
|
try expect(xform.position[1] == -1.0);
|
|
|
|
body1.setUserData(12345);
|
|
try expect(body1.getUserData() == 12345);
|
|
|
|
body1.setMotionType(.static);
|
|
try expect(body1.getMotionType() == .static);
|
|
|
|
body1.setCollisionGroup(.{ .group_id = 123 });
|
|
try expect(body1.getCollisionGroup().group_id == 123);
|
|
body1.getCollisionGroupMut().group_id += 1;
|
|
try expect(body1.getCollisionGroup().group_id == 124);
|
|
|
|
body_interface_mut.addBody(body1.getId(), .activate);
|
|
try expect(body_interface_mut.isAdded(body1.getId()) == true);
|
|
try expect(body_interface.isActive(body1.id) == false);
|
|
|
|
body_interface_mut.removeBody(body1.getId());
|
|
try expect(body_interface.isAdded(body1.id) == false);
|
|
|
|
try expect(physics_system.getNumBodies() == 2);
|
|
try expect(physics_system.getNumActiveBodies() == 0);
|
|
}
|
|
|
|
try expect(physics_system.getNumBodies() == 1);
|
|
try expect(physics_system.getNumActiveBodies() == 0);
|
|
}
|
|
|
|
test "zphysics.body.motion" {
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const body_interface = physics_system.getBodyInterfaceMut();
|
|
const lock_interface = physics_system.getBodyLockInterface();
|
|
|
|
const shape_settings = try BoxShapeSettings.create(.{ 1.0, 2.0, 3.0 });
|
|
defer shape_settings.release();
|
|
|
|
const shape = try shape_settings.createShape();
|
|
defer shape.release();
|
|
|
|
const body_settings = BodyCreationSettings{
|
|
.position = .{ 0.0, 10.0, 0.0, 1.0 },
|
|
.rotation = .{ 0.0, 0.0, 0.0, 1.0 },
|
|
.shape = shape,
|
|
.motion_type = .dynamic,
|
|
.object_layer = test_cb1.object_layers.moving,
|
|
};
|
|
const body_id = try body_interface.createAndAddBody(body_settings, .activate);
|
|
defer body_interface.removeAndDestroyBody(body_id);
|
|
|
|
physics_system.optimizeBroadPhase();
|
|
|
|
var write_lock: BodyLockWrite = .{};
|
|
write_lock.lock(lock_interface, body_id);
|
|
defer write_lock.unlock();
|
|
const body = write_lock.body.?;
|
|
|
|
body.setRestitution(0.5);
|
|
body.setFriction(0.25);
|
|
body.setUserData(0xC0DE_C0DE_C0DE_C0DE);
|
|
body.setAllowSleeping(false);
|
|
|
|
try expect(body.getFriction() == 0.25);
|
|
try expect(body.friction == 0.25);
|
|
try expect(body.getRestitution() == 0.5);
|
|
try expect(body.restitution == 0.5);
|
|
try expect(body.isInBroadPhase() == true);
|
|
try expect(body.isDynamic() == true);
|
|
try expect(body.isStatic() == false);
|
|
try expect(body.isSensor() == false);
|
|
try expect(body.getShape() == shape);
|
|
try expect(body.shape == shape);
|
|
try expect(body.getUserData() == 0xC0DE_C0DE_C0DE_C0DE);
|
|
try expect(body.user_data == 0xC0DE_C0DE_C0DE_C0DE);
|
|
try expect(body.getAllowSleeping() == false);
|
|
|
|
const normal0 = body.getWorldSpaceSurfaceNormal(sub_shape_id_empty, .{ 0, 12, 0 });
|
|
const normal1 = body.getWorldSpaceSurfaceNormal(sub_shape_id_empty, .{ -1, 10, 0 });
|
|
|
|
try expect(std.math.approxEqAbs(f32, normal0[0], 0.0, 0.001) == true);
|
|
try expect(std.math.approxEqAbs(f32, normal0[1], 1.0, 0.001) == true);
|
|
try expect(std.math.approxEqAbs(f32, normal0[2], 0.0, 0.001) == true);
|
|
try expect(std.math.approxEqAbs(f32, normal1[0], -1.0, 0.001) == true);
|
|
try expect(std.math.approxEqAbs(f32, normal1[1], 0.0, 0.001) == true);
|
|
try expect(std.math.approxEqAbs(f32, normal1[2], 0.0, 0.001) == true);
|
|
|
|
const motion = body.getMotionPropertiesMut();
|
|
|
|
try expect(body.motion_properties.? == motion);
|
|
|
|
motion.setLinearDamping(0.5);
|
|
motion.setAngularDamping(0.25);
|
|
motion.setGravityFactor(0.5);
|
|
|
|
try expect(motion.allow_sleeping == false);
|
|
try expect(motion.getLinearDamping() == 0.5);
|
|
try expect(motion.linear_damping == 0.5);
|
|
try expect(motion.getAngularDamping() == 0.25);
|
|
try expect(motion.angular_damping == 0.25);
|
|
try expect(motion.getGravityFactor() == 0.5);
|
|
try expect(motion.gravity_factor == 0.5);
|
|
}
|
|
|
|
test "zphysics.debugrenderer" {
|
|
if (!debug_renderer_enabled) return;
|
|
|
|
try init(std.testing.allocator, .{});
|
|
defer deinit();
|
|
|
|
var my_debug_renderer = test_cb1.MyDebugRenderer{};
|
|
try DebugRenderer.createSingleton(&my_debug_renderer);
|
|
defer DebugRenderer.destroySingleton();
|
|
|
|
const my_broad_phase_layer_interface = test_cb1.MyBroadphaseLayerInterface.init();
|
|
const my_broad_phase_should_collide = test_cb1.MyObjectVsBroadPhaseLayerFilter{};
|
|
const my_object_should_collide = test_cb1.MyObjectLayerPairFilter{};
|
|
|
|
const physics_system = try PhysicsSystem.create(
|
|
@as(*const BroadPhaseLayerInterface, @ptrCast(&my_broad_phase_layer_interface)),
|
|
@as(*const ObjectVsBroadPhaseLayerFilter, @ptrCast(&my_broad_phase_should_collide)),
|
|
@as(*const ObjectLayerPairFilter, @ptrCast(&my_object_should_collide)),
|
|
.{},
|
|
);
|
|
defer physics_system.destroy();
|
|
|
|
const shape_settings = try BoxShapeSettings.create(.{ 1.0, 2.0, 3.0 });
|
|
defer shape_settings.release();
|
|
|
|
const shape = try shape_settings.createShape();
|
|
defer shape.release();
|
|
|
|
const body_settings = BodyCreationSettings{
|
|
.position = .{ 0.0, 10.0, 0.0, 1.0 },
|
|
.rotation = .{ 0.0, 0.0, 0.0, 1.0 },
|
|
.shape = shape,
|
|
.motion_type = .dynamic,
|
|
.object_layer = test_cb1.object_layers.moving,
|
|
};
|
|
|
|
const body_interface = physics_system.getBodyInterfaceMut();
|
|
const body_id = try body_interface.createAndAddBody(body_settings, .activate);
|
|
defer body_interface.removeAndDestroyBody(body_id);
|
|
|
|
physics_system.optimizeBroadPhase();
|
|
|
|
try physics_system.update(0.1, .{});
|
|
|
|
const draw_settings: DebugRenderer.BodyDrawSettings = .{};
|
|
const draw_filter = DebugRenderer.createBodyDrawFilter(test_cb1.MyDebugRenderer.shouldBodyDraw);
|
|
defer DebugRenderer.destroyBodyDrawFilter(draw_filter);
|
|
|
|
physics_system.drawBodies(&draw_settings, draw_filter);
|
|
}
|
|
|
|
test {
|
|
std.testing.refAllDecls(@This());
|
|
}
|
|
|
|
const test_cb1 = struct {
|
|
const object_layers = struct {
|
|
const non_moving: ObjectLayer = 0;
|
|
const moving: ObjectLayer = 1;
|
|
const len: u32 = 2;
|
|
};
|
|
|
|
const broad_phase_layers = struct {
|
|
const non_moving: BroadPhaseLayer = 0;
|
|
const moving: BroadPhaseLayer = 1;
|
|
const len: u32 = 2;
|
|
};
|
|
|
|
const MyBroadphaseLayerInterface = extern struct {
|
|
usingnamespace BroadPhaseLayerInterface.Methods(@This());
|
|
__v: *const BroadPhaseLayerInterface.VTable = &vtable,
|
|
|
|
object_to_broad_phase: [object_layers.len]BroadPhaseLayer = undefined,
|
|
|
|
const vtable = BroadPhaseLayerInterface.VTable{
|
|
.getNumBroadPhaseLayers = _getNumBroadPhaseLayers,
|
|
.getBroadPhaseLayer = if (@import("builtin").abi == .msvc)
|
|
_getBroadPhaseLayerMsvc
|
|
else
|
|
_getBroadPhaseLayer,
|
|
};
|
|
|
|
fn init() MyBroadphaseLayerInterface {
|
|
var layer_interface: MyBroadphaseLayerInterface = .{};
|
|
layer_interface.object_to_broad_phase[object_layers.non_moving] = broad_phase_layers.non_moving;
|
|
layer_interface.object_to_broad_phase[object_layers.moving] = broad_phase_layers.moving;
|
|
return layer_interface;
|
|
}
|
|
|
|
fn _getNumBroadPhaseLayers(iself: *const BroadPhaseLayerInterface) callconv(.C) u32 {
|
|
const self = @as(*const MyBroadphaseLayerInterface, @ptrCast(iself));
|
|
return @as(u32, @intCast(self.object_to_broad_phase.len));
|
|
}
|
|
|
|
fn _getBroadPhaseLayer(
|
|
iself: *const BroadPhaseLayerInterface,
|
|
layer: ObjectLayer,
|
|
) callconv(.C) BroadPhaseLayer {
|
|
const self = @as(*const MyBroadphaseLayerInterface, @ptrCast(iself));
|
|
return self.object_to_broad_phase[@as(usize, @intCast(layer))];
|
|
}
|
|
|
|
fn _getBroadPhaseLayerMsvc(
|
|
iself: *const BroadPhaseLayerInterface,
|
|
out_layer: *BroadPhaseLayer,
|
|
layer: ObjectLayer,
|
|
) callconv(.C) *const BroadPhaseLayer {
|
|
const self = @as(*const MyBroadphaseLayerInterface, @ptrCast(iself));
|
|
out_layer.* = self.object_to_broad_phase[@as(usize, @intCast(layer))];
|
|
return out_layer;
|
|
}
|
|
};
|
|
|
|
const MyObjectVsBroadPhaseLayerFilter = extern struct {
|
|
usingnamespace ObjectVsBroadPhaseLayerFilter.Methods(@This());
|
|
__v: *const ObjectVsBroadPhaseLayerFilter.VTable = &vtable,
|
|
|
|
const vtable = ObjectVsBroadPhaseLayerFilter.VTable{ .shouldCollide = _shouldCollide };
|
|
|
|
fn _shouldCollide(
|
|
_: *const ObjectVsBroadPhaseLayerFilter,
|
|
layer1: ObjectLayer,
|
|
layer2: BroadPhaseLayer,
|
|
) callconv(.C) bool {
|
|
return switch (layer1) {
|
|
object_layers.non_moving => layer2 == broad_phase_layers.moving,
|
|
object_layers.moving => true,
|
|
else => unreachable,
|
|
};
|
|
}
|
|
};
|
|
|
|
const MyObjectLayerPairFilter = extern struct {
|
|
usingnamespace ObjectLayerPairFilter.Methods(@This());
|
|
__v: *const ObjectLayerPairFilter.VTable = &vtable,
|
|
|
|
const vtable = ObjectLayerPairFilter.VTable{ .shouldCollide = _shouldCollide };
|
|
|
|
fn _shouldCollide(
|
|
_: *const ObjectLayerPairFilter,
|
|
object1: ObjectLayer,
|
|
object2: ObjectLayer,
|
|
) callconv(.C) bool {
|
|
return switch (object1) {
|
|
object_layers.non_moving => object2 == object_layers.moving,
|
|
object_layers.moving => true,
|
|
else => unreachable,
|
|
};
|
|
}
|
|
};
|
|
|
|
const MyPhysicsStepListener = extern struct {
|
|
usingnamespace PhysicsStepListener.Methods(@This());
|
|
__v: *const PhysicsStepListener.VTable = &vtable,
|
|
steps_heard: u32 = 0,
|
|
|
|
const vtable = PhysicsStepListener.VTable{ .onStep = _onStep };
|
|
|
|
fn _onStep(psl: *PhysicsStepListener, delta_time: f32, physics_system: *PhysicsSystem) callconv(.C) void {
|
|
_ = delta_time;
|
|
_ = physics_system;
|
|
const self = @as(*MyPhysicsStepListener, @ptrCast(psl));
|
|
self.steps_heard += 1;
|
|
}
|
|
};
|
|
|
|
const MyDebugRenderer = if (!debug_renderer_enabled) void else extern struct {
|
|
const MyRenderPrimitive = extern struct {
|
|
// Actual render data goes here
|
|
foobar: i32 = 0,
|
|
};
|
|
|
|
usingnamespace DebugRenderer.Methods(@This());
|
|
__v: *const DebugRenderer.VTable(@This()) = &vtable,
|
|
|
|
primitives: [32]MyRenderPrimitive = [_]MyRenderPrimitive{.{}} ** 32,
|
|
prim_head: i32 = -1,
|
|
|
|
const vtable = DebugRenderer.VTable(@This()){
|
|
.drawLine = drawLine,
|
|
.drawTriangle = drawTriangle,
|
|
.createTriangleBatch = createTriangleBatch,
|
|
.createTriangleBatchIndexed = createTriangleBatchIndexed,
|
|
.drawGeometry = drawGeometry,
|
|
.drawText3D = drawText3D,
|
|
};
|
|
|
|
pub fn shouldBodyDraw(_: *const Body) align(DebugRenderer.BodyDrawFilterFuncAlignment) callconv(.C) bool {
|
|
return true;
|
|
}
|
|
|
|
fn drawLine(
|
|
self: *MyDebugRenderer,
|
|
from: *const [3]Real,
|
|
to: *const [3]Real,
|
|
color: *const DebugRenderer.Color,
|
|
) callconv(.C) void {
|
|
_ = self;
|
|
_ = from;
|
|
_ = to;
|
|
_ = color;
|
|
}
|
|
fn drawTriangle(
|
|
self: *MyDebugRenderer,
|
|
v1: *const [3]Real,
|
|
v2: *const [3]Real,
|
|
v3: *const [3]Real,
|
|
color: *const DebugRenderer.Color,
|
|
) callconv(.C) void {
|
|
_ = self;
|
|
_ = v1;
|
|
_ = v2;
|
|
_ = v3;
|
|
_ = color;
|
|
}
|
|
fn createTriangleBatch(
|
|
self: *MyDebugRenderer,
|
|
triangles: [*]DebugRenderer.Triangle,
|
|
triangle_count: u32,
|
|
) callconv(.C) *anyopaque {
|
|
_ = triangles;
|
|
_ = triangle_count;
|
|
self.prim_head += 1;
|
|
const prim = &self.primitives[@as(usize, @intCast(self.prim_head))];
|
|
return DebugRenderer.createTriangleBatch(prim);
|
|
}
|
|
fn createTriangleBatchIndexed(
|
|
self: *MyDebugRenderer,
|
|
vertices: [*]DebugRenderer.Vertex,
|
|
vertex_count: u32,
|
|
indices: [*]u32,
|
|
index_count: u32,
|
|
) callconv(.C) *anyopaque {
|
|
_ = vertices;
|
|
_ = vertex_count;
|
|
_ = indices;
|
|
_ = index_count;
|
|
self.prim_head += 1;
|
|
const prim = &self.primitives[@as(usize, @intCast(self.prim_head))];
|
|
return DebugRenderer.createTriangleBatch(prim);
|
|
}
|
|
fn drawGeometry(
|
|
self: *MyDebugRenderer,
|
|
model_matrix: *const [16]Real,
|
|
world_space_bound: *const DebugRenderer.AABox,
|
|
lod_scale_sq: f32,
|
|
color: DebugRenderer.Color,
|
|
geometry: *const DebugRenderer.Geometry,
|
|
cull_mode: DebugRenderer.CullMode,
|
|
cast_shadow: DebugRenderer.CastShadow,
|
|
draw_mode: DebugRenderer.DrawMode,
|
|
) callconv(.C) void {
|
|
_ = self;
|
|
_ = model_matrix;
|
|
_ = world_space_bound;
|
|
_ = lod_scale_sq;
|
|
_ = color;
|
|
_ = geometry;
|
|
_ = cull_mode;
|
|
_ = cast_shadow;
|
|
_ = draw_mode;
|
|
}
|
|
fn drawText3D(
|
|
self: *MyDebugRenderer,
|
|
positions: *const [3]Real,
|
|
string: [*:0]const u8,
|
|
color: DebugRenderer.Color,
|
|
height: f32,
|
|
) callconv(.C) void {
|
|
_ = self;
|
|
_ = positions;
|
|
_ = string;
|
|
_ = color;
|
|
_ = height;
|
|
}
|
|
};
|
|
};
|
|
//--------------------------------------------------------------------------------------------------
|