Skip to documentation
SLOP

tiny.rig.JointClip

Reference tiny.rig JointClip

Defined in tiny.rig.

API (14)

Actions

Public operations.

Fields and members

Public fields and members.

No direct callersNo direct callstiny.rigJointClip
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: fun/rig/src/clip.zig:71

zig
pub const JointClip = struct {    /// Keys per second.    rate: f32,    /// Keys in every channel that is not constant.    frames: u32,    interpolation: Interpolation = .linear,    channels: []const Channel,    rotations: []const Quat = &.{},    translations: []const Vec3 = &.{},    part_channels: []const PartChannel = &.{},    choices: []const u8 = &.{},    /// Checks every channel against the key slices and the joint and slot    /// counts it will be sampled into. Sampling assumes a clip that passed.    pub fn check(clip: JointClip, joint_count: usize, slot_count: usize) Error!void {        if (!std.math.isFinite(clip.rate) or !(clip.rate > 0)) return error.InvalidRate;        if (clip.frames == 0) return error.InvalidFrames;        for (clip.channels) |channel| {            if (channel.joint >= joint_count) return error.InvalidTarget;            const keys = switch (channel.target) {                .rotation => clip.rotations.len,                .translation => clip.translations.len,            };            try checkKeys(clip.frames, channel.first, channel.count, keys);        }        for (clip.part_channels) |channel| {            if (channel.slot >= slot_count) return error.InvalidTarget;            try checkKeys(clip.frames, channel.first, channel.count, clip.choices.len);        }    }    /// Seconds from the first key to the first key again, for a loop.    pub fn period(clip: JointClip) f64 {        return @as(f64, @floatFromInt(clip.frames)) / clip.rate;    }    /// Seconds from the first key to the last.    pub fn span(clip: JointClip) f64 {        return @as(f64, @floatFromInt(clip.frames - 1)) / clip.rate;    }    /// The keys on either side of `time`. A time within    /// `time.boundary_tolerance` of a key counts as on it, so sampling at    /// `k / rate` returns key `k` exactly.    pub fn position(clip: JointClip, time: f64, loop: bool) Position {        assert(clip.frames > 0);        assert(std.math.isFinite(time));        const frames: f64 = @floatFromInt(clip.frames);        var key = time * clip.rate;        var base: f64 = undefined;        if (loop) {            key = @mod(key, frames);            base = time_position.floorSnapped(key);            if (base >= frames) {                base -= frames;                key -= frames;            }        } else {            key = std.math.clamp(key, 0, frames - 1);            base = time_position.floorSnapped(key);        }        const lower: u32 = @intFromFloat(base);        assert(lower < clip.frames);        const upper = if (lower + 1 < clip.frames) lower + 1 else if (loop) 0 else lower;        const fraction: f32 = switch (clip.interpolation) {            .step => 0,            .linear => @floatCast(std.math.clamp(key - base, 0, 1)),        };        return .{            .lower = lower,            .upper = upper,            .fraction = @min(fraction, 1 - std.math.floatEps(f32)),        };    }    /// The local transforms at `time`: `rest` where no channel applies.    pub fn sample(        clip: JointClip,        time: f64,        loop: bool,        rest: []const Transform,        local: []Transform,    ) void {        assert(local.len == rest.len);        @memcpy(local, rest);        const at = clip.position(time, loop);        for (clip.channels) |channel| {            assert(channel.joint < local.len);            const lower = channel.first + if (channel.count == 1) 0 else at.lower;            const upper = channel.first + if (channel.count == 1) 0 else at.upper;            const joint = &local[channel.joint];            switch (channel.target) {                .rotation => joint.rotation = rotationAt(                    clip.rotations[lower],                    clip.rotations[upper],                    at.fraction,                ),                .translation => joint.translation = translationAt(                    clip.translations[lower],                    clip.translations[upper],                    at.fraction,                ),            }        }    }    /// Each part channel's choice at `time`, written to its slot. Slots    /// without a channel keep what `choices` held.    pub fn selectParts(clip: JointClip, time: f64, loop: bool, choices: []u8) void {        const at = clip.position(time, loop);        for (clip.part_channels) |channel| {            assert(channel.slot < choices.len);            const key = channel.first + if (channel.count == 1) 0 else at.lower;            choices[channel.slot] = clip.choices[key];        }    }};

Source: fun/rig/src/root.zig:36

zig
pub const JointClip = clip.JointClip;
Called byCallsNo direct callersprivate; no linkfun.rig.src.clipcheckKeysJointClipcheck
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate; no linkfun.rig.src.cliprotationAtprivate; no linkfun.rig.src.cliptranslationAtJointClipsample
Static calls · unresolved targets: 0 · external targets: 1.

Audit

Definitions7
Public names7
Members8
Version26.7.0
Revisiondaab053ee433