Skip to content

Commit

Permalink
Skeleton T-pose + Angle vs Rotation + more
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Sep 2, 2024
1 parent 69c2a04 commit 8944800
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 179 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 23 additions & 20 deletions examples/skeleton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ use cushy::{
widgets::{slider::Slidable, Canvas},
Run,
};
use funnybones::{Angle, BoneId, BoneKind, Joint, JointId, Skeleton, Vector};
use funnybones::{Angle, BoneId, BoneKind, Joint, JointId, Rotation, Skeleton, Vector};

fn main() {
// begin rustme snippet: readme
let mut skeleton = Skeleton::default();
skeleton.set_rotation(Rotation::degrees(-90.));

// Create our root bone: the spine
let spine = skeleton.push_bone(BoneKind::Rigid { length: 3. }.with_label("spine"));
// Create the right-half of the hips.
let r_hip = skeleton.push_bone(BoneKind::Rigid { length: 0.5 }.with_label("r_hip"));
// Connect the right hip to the spine.
skeleton.push_joint(Joint::new(
Angle::degrees(-90.),
Rotation::degrees(90.),
spine.axis_a(),
r_hip.axis_a(),
));
Expand All @@ -46,15 +47,15 @@ fn main() {

// Connect the right leg to the right hip.
skeleton.push_joint(Joint::new(
Angle::degrees(0.),
Rotation::degrees(-90.),
r_hip.axis_b(),
r_leg.axis_a(),
));
// Create the right foot.
let r_foot = skeleton.push_bone(BoneKind::Rigid { length: 0.5 }.with_label("r_foot"));
// Connect the right foot to the right leg.
let r_ankle_id = skeleton.push_joint(Joint::new(
Angle::degrees(90.),
Rotation::degrees(0.),
r_leg.axis_b(),
r_foot.axis_a(),
));
Expand All @@ -63,7 +64,7 @@ fn main() {
// Create the left-half of our lower half.
let l_hip = skeleton.push_bone(BoneKind::Rigid { length: 0.5 }.with_label("l_hip"));
skeleton.push_joint(Joint::new(
Angle::degrees(90.),
Rotation::degrees(-90.),
spine.axis_a(),
l_hip.axis_a(),
));
Expand All @@ -76,21 +77,21 @@ fn main() {
.with_label("l_leg"),
);
skeleton.push_joint(Joint::new(
Angle::degrees(90.),
Rotation::degrees(90.),
l_hip.axis_b(),
l_leg.axis_a(),
));
let l_foot = skeleton.push_bone(BoneKind::Rigid { length: 0.5 }.with_label("l_foot"));
let l_ankle_id = skeleton.push_joint(Joint::new(
Angle::degrees(-90.),
Rotation::degrees(0.),
l_leg.axis_b(),
l_foot.axis_a(),
));

// Create our two arms in the same fashion as our leg structure.
let r_shoulder = skeleton.push_bone(BoneKind::Rigid { length: 0.5 }.with_label("r_shoulder"));
skeleton.push_joint(Joint::new(
Angle::degrees(-90.),
Rotation::degrees(-90.),
spine.axis_b(),
r_shoulder.axis_a(),
));
Expand All @@ -103,20 +104,20 @@ fn main() {
.with_label("r_arm"),
);
skeleton.push_joint(Joint::new(
Angle::degrees(-90.),
Rotation::degrees(0.),
r_shoulder.axis_b(),
r_arm.axis_a(),
));
let r_hand = skeleton.push_bone(BoneKind::Rigid { length: 0.3 }.with_label("r_hand"));
let r_wrist_id = skeleton.push_joint(Joint::new(
Angle::degrees(175.),
Rotation::degrees(0.),
r_arm.axis_b(),
r_hand.axis_a(),
));

let l_shoulder = skeleton.push_bone(BoneKind::Rigid { length: 0.5 }.with_label("l_shoulder"));
skeleton.push_joint(Joint::new(
Angle::degrees(90.),
Rotation::degrees(90.),
spine.axis_b(),
l_shoulder.axis_a(),
));
Expand All @@ -129,21 +130,21 @@ fn main() {
.with_label("l_arm"),
);
skeleton.push_joint(Joint::new(
Angle::degrees(90.),
Rotation::degrees(0.),
l_shoulder.axis_b(),
l_arm.axis_a(),
));
let l_hand = skeleton.push_bone(BoneKind::Rigid { length: 0.3 }.with_label("l_hand"));
let l_wrist_id = skeleton.push_joint(Joint::new(
Angle::degrees(-175.),
Rotation::degrees(0.),
l_arm.axis_b(),
l_hand.axis_a(),
));

// Finally, create a bone to represent our head.
let head = skeleton.push_bone(BoneKind::Rigid { length: 0.5 }.with_label("head"));
let neck = skeleton.push_joint(Joint::new(
Angle::degrees(180.),
Rotation::degrees(0.),
spine.axis_b(),
head.axis_a(),
));
Expand All @@ -155,7 +156,7 @@ fn main() {
.for_each_cloned({
let skeleton = skeleton.clone();
move |rotation| {
skeleton.lock().set_rotation(rotation);
skeleton.lock().set_rotation(rotation.into());
}
})
.persist();
Expand Down Expand Up @@ -237,14 +238,14 @@ fn main() {
.contain()
.and(bone_widget(
"Left Leg",
Angle::degrees(90.),
Angle::degrees(0.),
&skeleton,
l_leg,
))
.and(joint_widget("Left Ankle", &skeleton, l_ankle_id))
.and(bone_widget(
"Right Leg",
Angle::degrees(-90.),
Angle::degrees(0.),
&skeleton,
r_leg,
))
Expand Down Expand Up @@ -285,7 +286,7 @@ fn joint_widget(label: &str, skeleton: &Dynamic<Skeleton>, joint: JointId) -> im
}
})
.persist();
let angle_slider = angle.slider_between(Angle::degrees(0.), Angle::degrees(359.9));
let angle_slider = angle.slider_between(Rotation::degrees(0.), Rotation::degrees(359.9));

label.and(angle_slider).into_rows().contain()
}
Expand All @@ -307,8 +308,10 @@ fn bone_widget(
move |direction| {
let mut skeleton = skeleton.lock();
let current_end = skeleton[bone].desired_end().unwrap_or_default();
skeleton[bone]
.set_desired_end(Some(Vector::new(current_end.magnitude, *direction)));
skeleton[bone].set_desired_end(Some(Vector::new(
current_end.magnitude,
Rotation::from(*direction),
)));
}
})
.persist();
Expand Down
10 changes: 5 additions & 5 deletions src/animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::{

use easing_function::easings::StandardEasing;

use crate::{Angle, Bone, BoneId, Coordinate, Joint, JointId, Skeleton, Vector};
use crate::{Rotation, Bone, BoneId, Coordinate, Joint, JointId, Skeleton, Vector};

#[derive(Default, Debug, PartialEq, Clone)]
pub struct Animation(Arc<AnimationData>);
Expand Down Expand Up @@ -258,7 +258,7 @@ impl BoneProperty {
match self {
BoneProperty::Target => Value::Vector(
bone.desired_end()
.unwrap_or_else(|| Vector::new(bone.kind().full_length(), Angle::default())),
.unwrap_or_else(|| Vector::new(bone.kind().full_length(), Rotation::default())),
),
// BoneProperty::Scale => ,
BoneProperty::Inverse => Value::Bool(bone.kind().is_inverse()),
Expand Down Expand Up @@ -303,7 +303,7 @@ impl JointProperty {
let Value::Number(value) = value else {
return;
};
joint.set_angle(Angle::radians(value));
joint.set_angle(Rotation::radians(value));
}
}
}
Expand Down Expand Up @@ -566,7 +566,7 @@ impl Lerp for Coordinate {
}
}

impl Lerp for Angle {
impl Lerp for Rotation {
fn lerp(self, target: Self, percent: f32) -> Self {
let delta_neg = self.radians - target.radians;
let delta_pos = target.radians - self.radians;
Expand Down Expand Up @@ -613,7 +613,7 @@ fn basic() {
let mut skeleton = Skeleton::default();
let root = skeleton.push_bone(BoneKind::Rigid { length: 1. });
let arm = skeleton.push_bone(BoneKind::Rigid { length: 1. });
let joint = skeleton.push_joint(Joint::new(Angle::default(), root.axis_b(), arm.axis_a()));
let joint = skeleton.push_joint(Joint::new(Rotation::default(), root.axis_b(), arm.axis_a()));

let animation = Animation::default().with(
Timeline::new(Target::Joint {
Expand Down
22 changes: 17 additions & 5 deletions src/cushy.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
//! Widgets for editing and rendering skeletons.

use cushy::{
animation::{LinearInterpolate, PercentBetween},
animation::{LinearInterpolate, PercentBetween, ZeroToOne},
figures::{IntoComponents, Ranged},
};

use crate::{Angle, Coordinate, Vector};
use crate::{Angle, Coordinate, Rotation, Vector};

pub mod skeleton_canvas;

impl PercentBetween for Angle {
fn percent_between(&self, min: &Self, max: &Self) -> cushy::animation::ZeroToOne {
impl PercentBetween for Rotation {
fn percent_between(&self, min: &Self, max: &Self) -> ZeroToOne {
self.radians.percent_between(&min.radians, &max.radians)
}
}

impl LinearInterpolate for Angle {
impl LinearInterpolate for Rotation {
fn lerp(&self, target: &Self, percent: f32) -> Self {
Self {
radians: self.radians.lerp(&target.radians, percent),
Expand Down Expand Up @@ -48,3 +48,15 @@ impl Ranged for Angle {
const MIN: Self = Self::MIN;
const MAX: Self = Self::MAX;
}

impl PercentBetween for Angle {
fn percent_between(&self, min: &Self, max: &Self) -> ZeroToOne {
self.0.percent_between(&min.0, &max.0)
}
}

impl LinearInterpolate for Angle {
fn lerp(&self, target: &Self, percent: f32) -> Self {
Self(self.0.lerp(&target.0, percent).clamped())
}
}
4 changes: 2 additions & 2 deletions src/cushy/skeleton_canvas.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(missing_docs)]
use core::f32;

use crate::{Angle, BoneEnd, BoneId, Coordinate, JointId, Skeleton, Vector};
use crate::{Rotation, BoneEnd, BoneId, Coordinate, JointId, Skeleton, Vector};
use cushy::{
context::{EventContext, GraphicsContext, LayoutContext, Trackable},
figures::{
Expand Down Expand Up @@ -430,5 +430,5 @@ struct DragInfo {
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum SkeletonMutation {
SetDesiredEnd { bone: BoneId, end: Vector },
SetJointRotation { joint: JointId, rotation: Angle },
SetJointRotation { joint: JointId, rotation: Rotation },
}
Loading

0 comments on commit 8944800

Please sign in to comment.