use alloc::vec::Vec;
use crate::constraint::Constraint;
use crate::math::{Quat, Vec3};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct NodeId(pub u32);
impl NodeId {
#[inline(always)]
pub fn index(self) -> usize {
self.0 as usize
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct EffectorFlags(pub u8);
impl EffectorFlags {
pub const WEIGHT_NLERP: u8 = 0x01;
pub const INHERIT_ROTATION: u8 = 0x02;
pub const fn contains(self, bit: u8) -> bool {
self.0 & bit != 0
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Effector {
pub target_position: Vec3,
pub target_rotation: Quat,
pub weight: f32,
pub rotation_weight: f32,
pub chain_length: u16,
pub flags: EffectorFlags,
}
impl Default for Effector {
fn default() -> Self {
Effector {
target_position: Vec3::ZERO,
target_rotation: Quat::IDENTITY,
weight: 1.0,
rotation_weight: 1.0,
chain_length: 0,
flags: EffectorFlags(0),
}
}
}
impl Effector {
pub fn new(target_position: Vec3) -> Self {
Effector {
target_position,
..Default::default()
}
}
pub fn with_chain_length(mut self, n: u16) -> Self {
self.chain_length = n;
self
}
pub fn with_weight(mut self, w: f32) -> Self {
self.weight = w;
self
}
pub fn with_flags(mut self, bits: u8) -> Self {
self.flags = EffectorFlags(bits);
self
}
}
#[derive(Clone, Debug)]
pub struct Node {
parent: Option<NodeId>,
children: Vec<NodeId>,
pub position: Vec3,
pub rotation: Quat,
pub effector: Option<Effector>,
pub constraint: Constraint,
}
impl Node {
pub fn parent(&self) -> Option<NodeId> {
self.parent
}
pub fn children(&self) -> &[NodeId] {
&self.children
}
}
#[derive(Clone, Debug, Default)]
pub struct Skeleton {
nodes: Vec<Node>,
}
impl Skeleton {
pub fn new() -> Self {
Skeleton { nodes: Vec::new() }
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn add_root(&mut self, position: Vec3) -> NodeId {
assert!(self.nodes.is_empty(), "skeleton already has a root");
self.nodes.push(Node {
parent: None,
children: Vec::new(),
position,
rotation: Quat::IDENTITY,
effector: None,
constraint: Constraint::None,
});
NodeId(0)
}
pub fn add_child(&mut self, parent: NodeId, offset: Vec3) -> NodeId {
let id = NodeId(self.nodes.len() as u32);
assert!(parent.index() < self.nodes.len(), "unknown parent");
self.nodes.push(Node {
parent: Some(parent),
children: Vec::new(),
position: offset,
rotation: Quat::IDENTITY,
effector: None,
constraint: Constraint::None,
});
self.nodes[parent.index()].children.push(id);
id
}
pub fn node(&self, id: NodeId) -> &Node {
&self.nodes[id.index()]
}
pub fn node_mut(&mut self, id: NodeId) -> &mut Node {
&mut self.nodes[id.index()]
}
pub fn nodes(&self) -> &[Node] {
&self.nodes
}
pub fn set_effector(&mut self, id: NodeId, effector: Effector) {
self.nodes[id.index()].effector = Some(effector);
}
pub fn clear_effector(&mut self, id: NodeId) {
self.nodes[id.index()].effector = None;
}
pub fn set_constraint(&mut self, id: NodeId, c: Constraint) {
self.nodes[id.index()].constraint = c;
}
pub fn set_target(&mut self, id: NodeId, target: Vec3) {
self.nodes[id.index()]
.effector
.as_mut()
.expect("node has no effector")
.target_position = target;
}
pub fn global_transforms(&self, pos: &mut Vec<Vec3>, rot: &mut Vec<Quat>) {
pos.clear();
rot.clear();
pos.reserve(self.nodes.len());
rot.reserve(self.nodes.len());
for n in &self.nodes {
match n.parent {
None => {
pos.push(n.position);
rot.push(n.rotation);
}
Some(p) => {
let (pp, pr) = (pos[p.index()], rot[p.index()]);
pos.push(pp + pr.rotate(n.position));
rot.push(pr * n.rotation);
}
}
}
}
pub fn global_position(&self, id: NodeId) -> Vec3 {
let mut pos = Vec::new();
let mut rot = Vec::new();
self.global_transforms(&mut pos, &mut rot);
pos[id.index()]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn global_transforms_follow_parents() {
let mut s = Skeleton::new();
let root = s.add_root(Vec3::new(1.0, 0.0, 0.0));
let a = s.add_child(root, Vec3::new(0.0, 2.0, 0.0));
let b = s.add_child(a, Vec3::new(0.0, 3.0, 0.0));
s.node_mut(root).rotation = Quat::from_axis_angle(Vec3::Z, core::f32::consts::FRAC_PI_2);
let (mut p, mut r) = (Vec::new(), Vec::new());
s.global_transforms(&mut p, &mut r);
assert!((p[a.index()] - Vec3::new(-1.0, 0.0, 0.0)).length() < 1e-5);
assert!((p[b.index()] - Vec3::new(-4.0, 0.0, 0.0)).length() < 1e-5);
}
#[test]
fn children_order_is_insertion_order() {
let mut s = Skeleton::new();
let r = s.add_root(Vec3::ZERO);
let a = s.add_child(r, Vec3::X);
let b = s.add_child(r, Vec3::Y);
assert_eq!(s.node(r).children(), &[a, b]);
assert_eq!(s.node(a).parent(), Some(r));
}
}