pub fn hello() void { std.debug.print("whatsup\n", .{}); } pub const Skeleton = opaque { pub fn create() *@This() { return @ptrCast(CreateSkeleton_c()); } // todo add error messages pub fn loadFromFile(self: *@This(), path: [*c]const u8) void { LoadSkeletonFromFile_c(self, path); } pub fn loadFromBytes(self: *@This(), bytes: []const u8) void { LoadSkeletonFromBytes_c(self, @constCast(@ptrCast(bytes.ptr)), bytes.len); } pub fn getJointsList(self: *@This()) []const [*c]const u8 { const span: Span([*c]const u8) = @bitCast(SkeletonGetJointsList_c(@ptrCast(self))); // std.debug.print("{d} \n", .{@intFromPtr(span.end)}); return span.toSlice(); } pub fn getRestPoseModel(self: *@This()) Span(SoaTransform) { return @bitCast(SkeletonJointRestPoses_c(@ptrCast(self))); } pub fn numSoaJoints(self: *@This()) usize { return @intCast(SkeletonNumSoaJoints_c(@ptrCast(self))); } pub fn numJoints(self: *@This()) usize { return @intCast(SkeletonNumJoints_c(@ptrCast(self))); } pub fn destroy(self: *@This()) void { DestroySkeleton_c(@ptrCast(self)); } pub extern fn SkeletonJointRestPoses_c(s: ?*anyopaque) callconv(.C) OpaqueSpan; pub extern fn SkeletonNumJoints_c(s: ?*anyopaque) callconv(.C) c_int; pub extern fn SkeletonNumSoaJoints_c(s: ?*anyopaque) callconv(.C) c_int; pub extern fn SkeletonGetJointsList_c(s: ?*anyopaque) callconv(.C) OpaqueSpan; pub extern fn CreateSkeleton_c() callconv(.C) ?*anyopaque; pub extern fn DestroySkeleton_c(target: ?*anyopaque) callconv(.C) void; pub extern fn LoadSkeletonFromFile_c(s: ?*anyopaque, path: [*c]const u8) callconv(.C) void; pub extern fn LoadSkeletonFromBytes_c(s: ?*anyopaque, size: ?*anyopaque, size: usize) void; }; pub const Animation = opaque { pub fn create() *@This() { return @ptrCast(CreateAnimation_c()); } // todo add error messages pub fn loadFromFile(self: *@This(), path: [*c]const u8) void { LoadAnimationFromFile_c(self, path); } pub fn loadFromBytes(self: *@This(), bytes: []const u8) void { LoadAnimationFromBytes_c(self, @constCast(@ptrCast(bytes.ptr)), bytes.len); } pub fn destroy(self: *@This()) void { DestroyAnimation_c(@ptrCast(self)); } pub fn getDuration(self: *@This()) f32 { return AnimationGetDuration_c(@ptrCast(self)); } pub extern fn AnimationGetDuration_c(s: ?*anyopaque) callconv(.C) f32; pub extern fn CreateAnimation_c() callconv(.C) ?*anyopaque; pub extern fn LoadAnimationFromFile_c(s: ?*anyopaque, path: [*c]const u8) void; pub extern fn LoadAnimationFromBytes_c(s: ?*anyopaque, size: ?*anyopaque, size: usize) void; pub extern fn DestroyAnimation_c(target: ?*anyopaque) callconv(.C) void; }; pub const SamplingJob = extern struct { ratio: f32 = 0.0, // float ratio; animation: ?*Animation = undefined, // const Animation* animation; context: ?*SamplingJobContext = undefined, // output: Span(SoaTransform) = .{}, // ozz::span pub fn run(self: *@This()) bool { return SamplingJob_Run_c(@ptrCast(self)); } pub fn validate(self: *@This()) bool { return SamplingJob_Validate_c(@ptrCast(self)); } pub extern fn SamplingJob_Validate_c(*anyopaque) bool; pub extern fn SamplingJob_Run_c(*anyopaque) bool; }; pub fn spanFromArrayList(list: anytype) Span(@TypeOf(list.items[0])) { return makeSpan(list.items); } pub fn makeSpan(slice: anytype) Span(@TypeOf(slice[0])) { //return .{ .start = slice.ptr, .end = slice.ptr + slice.len }; return .{ .start = slice.ptr, .end = slice.len }; } pub fn Span(comptime T: type) type { return extern struct { start: [*c]T = null, end: [*c]T = null, pub fn fromArray(arr: []T) @This() { //return .{ .start = arr.ptr, .end = arr.ptr + arr.len }; return .{ .start = arr.ptr, .end = arr.len }; } pub fn toSlice(self: @This()) []T { return self.start[0..(@intFromPtr(self.end))]; } }; } pub const SamplingJobContext = opaque { pub fn create() *@This() { return @ptrCast(CreateSamplingJobContext_c()); } pub fn createMaxTracks(tracksCount: c_int) *@This() { return @ptrCast(CreateSamplingJobContextCount_c(tracksCount)); } pub fn resize(self: *@This(), tracksCount: usize) void { SamplingJobContext_Resize_c(@ptrCast(self), @intCast(tracksCount)); } pub fn invalidate(self: *@This()) void { SamplingJobContext_Invalidate_c(self); } pub fn maxTracks(self: *@This()) c_int { return SamplingJobContext_MaxTracks_c(@ptrCast(self)); } pub fn maxSoaTracks(self: *@This()) c_int { return SamplingJobContext_MaxSoaTracks_c(@ptrCast(self)); } pub fn destroy(self: *@This()) void { DestroySamplingJobContext_c(self); } pub extern fn CreateSamplingJobContextCount_c(c_int) callconv(.C) ?*anyopaque; pub extern fn CreateSamplingJobContext_c() callconv(.C) ?*anyopaque; pub extern fn DestroySamplingJobContext_c(?*anyopaque) callconv(.C) void; pub extern fn SamplingJobContext_Resize_c(?*anyopaque, c_int) callconv(.C) void; pub extern fn SamplingJobContext_Invalidate_c(?*anyopaque) callconv(.C) void; pub extern fn SamplingJobContext_MaxTracks_c(?*anyopaque) callconv(.C) c_int; pub extern fn SamplingJobContext_MaxSoaTracks_c(?*anyopaque) callconv(.C) c_int; }; pub extern fn testFunc() callconv(.C) void; pub extern fn startupOzz() callconv(.C) void; pub extern fn shutdownOzz() callconv(.C) void; pub const SimdFloat4 = @Vector(4, f32); pub const Float4x4 = extern struct { cols: [4]SimdFloat4, }; pub const SimdFloat4_one = .{ 1, 1, 1, 1 }; pub const SimdFloat4_zero = .{ 0, 0, 0, 0 }; pub const SoaFloat2 = extern struct { x: SimdFloat4 = undefined, y: SimdFloat4 = undefined, }; pub const SoaFloat3 = extern struct { x: SimdFloat4 = undefined, y: SimdFloat4 = undefined, z: SimdFloat4 = undefined, pub fn zero() @This() { return .{ .x = SimdFloat4_zero, .y = SimdFloat4_zero, .z = SimdFloat4_zero, }; } pub fn one() @This() { return .{ .x = SimdFloat4_one, .y = SimdFloat4_one, .z = SimdFloat4_one, }; } }; pub const SoaQuaternion = extern struct { x: SimdFloat4 = undefined, y: SimdFloat4 = undefined, z: SimdFloat4 = undefined, w: SimdFloat4 = undefined, pub fn identity() @This() { return .{ .x = SimdFloat4_zero, .y = SimdFloat4_zero, .z = SimdFloat4_zero, .w = SimdFloat4_one, }; } }; pub const OpaqueSpan = extern struct { start: ?*anyopaque, end: ?*anyopaque, }; pub const SoaTransform = extern struct { translation: SoaFloat3 = SoaFloat3.zero(), rotation: SoaQuaternion = SoaQuaternion.identity(), scale: SoaFloat3 = SoaFloat3.one(), }; pub const kNoParent = -1; pub const kMaxJoints = 1024; pub const kMaxSoAJoints = (kMaxJoints + 3) / 4; pub const LocalToModelJob = extern struct { // The Skeleton object describing the joint hierarchy used for local to // model space conversion. skeleton: ?*Skeleton, // The root matrix will multiply to every model space matrices, default nullptr // means an identity matrix. This can be used to directly compute world-space // transforms for example. root: ?*Float4x4 = null, // Defines "from" which joint the local-to-model conversion should start. // Default value is ozz::Skeleton::kNoParent, meaning the whole hierarchy is // updated. This parameter can be used to optimize update by limiting // conversion to part of the joint hierarchy. Note that "from" parent should // be a valid matrix, as it is going to be used as part of "from" joint // hierarchy update. from: c_int = kNoParent, // Defines "to" which joint the local-to-model conversion should go, "to" // included. Update will end before "to" joint is reached if "to" is not part // of the hierarchy starting from "from". Default value is // ozz::animation::Skeleton::kMaxJoints, meaning the hierarchy (starting from // "from") is updated to the last joint. to: c_int = kMaxJoints, // If true, "from" joint is not updated during job execution. Update starts // with all children of "from". This can be used to update a model-space // transform independently from the local-space one. To do so: set "from" // joint model-space transform matrix, and run this Job with "from_excluded" // to update all "from" children. // Default value is false. from_excluded: bool = false, // The input range that store local transforms. input: Span(SoaTransform), // Job output. // The output range to be filled with model-space matrices. output: Span(Float4x4), pub fn run(self: *@This()) bool { return LocalToModelJob_Run_c(@ptrCast(self)); } pub extern fn LocalToModelJob_Run_c(?*anyopaque) callconv(.C) bool; }; pub const Layer = extern struct { // Blending weight of this layer. Negative values are considered as 0. // Normalization is performed during the blending stage so weight can be in // any range, even though range [0:1] is optimal. weight: f32 = 0.0, // The range [begin,end[ of input layer posture. This buffer expect to store // local space transforms, that are usually outputted from a sampling job. // This range must be at least as big as the rest pose buffer, even though // only the number of transforms defined by the rest pose buffer will be // processed. transform: Span(SoaTransform) = .{}, // Optional range [begin,end[ of blending weight for each joint in this // layer. // If both pointers are nullptr (default case) then per joint weight // blending is disabled. A valid range is defined as being at least as big // as the rest pose buffer, even though only the number of transforms // defined by the rest pose buffer will be processed. When a layer doesn't // specifies per joint weights, then it is implicitly considered as // being 1.f. This default value is a reference value for the normalization // process, which implies that the range of values for joint weights should // be [0,1]. Negative weight values are considered as 0, but positive ones // aren't clamped because they could exceed 1.f if all layers contains valid // joint weights. jointWeights: Span(SoaTransform) = .{}, }; pub const BlendingJob = extern struct { // The job blends the rest pose to the output when the accumulated weight of // all layers is less than this threshold value. // Must be greater than 0.f. threshold: f32 = 0.01, // Job input layers, can be empty or nullptr. // The range of layers that must be blended. layers: Span(Layer) = .{}, // Job input additive layers, can be empty or nullptr. // The range of layers that must be added to the output. additive_layers: Span(Layer) = .{}, // The skeleton rest pose. The size of this buffer defines the number of // transforms to blend. This is the reference because this buffer is defined // by the skeleton that all the animations belongs to. // It is used when the accumulated weight for a bone on all layers is // less than the threshold value, in order to fall back on valid transforms. rest_pose: Span(SoaTransform) = .{}, // Job output. // The range of output transforms to be filled with blended layer // transforms during job execution. // Must be at least as big as the rest pose buffer, but only the number of // transforms defined by the rest pose buffer size will be processed. output: Span(SoaTransform) = .{}, // Validates job parameters. // Returns true for a valid job, false otherwise: // -if layer range is not valid (can be empty though). // -if additive layer range is not valid (can be empty though). // -if any layer is not valid. // -if output range is not valid. // -if any buffer (including layers' content : transform, joint weights...) is // smaller than the rest pose buffer. // -if the threshold value is less than or equal to 0.f. pub fn validate(self: *const @This()) bool { return self.BlendingJob_Validate_c(@ptrCast(self)); } // Runs job's blending task. // The job is validated before any operation is performed, see Validate() for // more details. // Returns false if *this job is not valid. pub fn run(self: *@This()) bool { return BlendingJob_Run_c(@ptrCast(self)); } pub extern fn BlendingJob_Validate_c(?*anyopaque) callconv(.C) bool; pub extern fn BlendingJob_Run_c(?*anyopaque) callconv(.C) bool; }; pub const std = @import("std");