1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use num_derive::{FromPrimitive, ToPrimitive};
use num_traits::FromPrimitive;

use crate::{
	conventions::{forward_vec, up_vec},
	newtypes::{Global, Local},
	UnitQuat,
};

#[allow(rustdoc::private_intra_doc_links)]
/// Describes the various types of bones in the skeleton.
///
/// All of this information is static rather than dynamic information. "Static" here
/// refers to information that does not change - this information is "hard coded".
/// This includes:
/// - The parent/child relationships between the various types of bones
/// - The pose of the bones when performing a calibration
/// - Names of the bones
/// - Etc
///
/// Where possible, this information is provided as [`const`] functions so that they
/// can be evaluated at compile-time.
///
/// There is also dynamic information associated with bones. "Dynamic" here refers to
/// the fact that some bone data cannot be known up front and changes as the skeletal
/// model receives inputs and produces outputs. This data is stored in the
/// [`Skeleton`](crate::Skeleton) as an [`Edge`](crate::skeleton::Edge).
///
/// `BoneKind` is also represented as a `u8`, so it can be used as an index for an
/// array. This is used for example in [`BoneMap`]. **Please note that we make no
/// stability guarantees for the particular value that any variant gets, only that
/// these values are contiguous and start at 0.** Use the variant directly or refer to
/// the various functions implemented on this type for stability.
///
/// [`const`]: https://doc.rust-lang.org/std/keyword.const.html
/// [`BoneMap`]: super::BoneMap
#[repr(u8)]
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, FromPrimitive, ToPrimitive)]
pub enum BoneKind {
	Neck = 0,
	Chest,
	Waist,
	Hip,
	ThighL,
	ThighR,
	AnkleL,
	AnkleR,
	FootL,
	FootR,

	UpperArmL,
	UpperArmR,
	ForearmL,
	ForearmR,
	WristL,
	WristR,
}
impl BoneKind {
	/// The bone with the largest integer value
	pub const fn max() -> BoneKind {
		BoneKind::WristR
	}
	pub const MAX: BoneKind = Self::max();

	/// The bone with the smallest integer value
	pub const fn min() -> BoneKind {
		BoneKind::root()
	}
	pub const MIN: BoneKind = Self::min();

	/// The root bone of the skeletal graph/tree.
	pub const fn root() -> Self {
		Self::Neck
	}
	pub const ROOT: BoneKind = Self::root();

	/// Returns the number of unique kinds of bones. This is equivalent to the number
	/// of variants in `BoneKind`
	pub const fn num_types() -> usize {
		BoneKind::max() as usize + 1
	}
	pub const NUM_TYPES: usize = Self::num_types();

	/// Returns the children of any particular bone.
	///
	/// The slice is `'static`, which means the lifetime of the returned slice lives
	/// for the entire duration of the program. This is because the parent/child
	/// relationship of bones is known at compile-time.
	pub const fn children(&self) -> &'static [Self] {
		use BoneKind::*;
		match self {
			Neck => &[Chest, UpperArmL, UpperArmR],
			Chest => &[Waist],
			Waist => &[Hip],
			Hip => &[ThighL, ThighR],
			ThighL => &[AnkleL],
			ThighR => &[AnkleR],
			AnkleL => &[FootL],
			AnkleR => &[FootR],
			FootL => &[],
			FootR => &[],

			UpperArmL => &[ForearmL],
			UpperArmR => &[ForearmR],
			ForearmL => &[WristL],
			ForearmR => &[WristR],
			WristR => &[],
			WristL => &[],
		}
	}

	/// The parent of a bone.
	pub const fn parent(&self) -> Option<BoneKind> {
		use BoneKind::*;
		Some(match self {
			Neck => return None,
			Chest => Neck,
			Waist => Chest,
			Hip => Waist,
			ThighL => Hip,
			ThighR => Hip,
			AnkleL => ThighL,
			AnkleR => ThighR,
			FootL => AnkleL,
			FootR => AnkleR,

			UpperArmL => Neck,
			UpperArmR => Neck,
			ForearmL => UpperArmL,
			ForearmR => UpperArmR,
			WristL => ForearmL,
			WristR => ForearmR,
		})
	}

	pub fn iter() -> std::iter::Map<std::ops::RangeInclusive<u8>, fn(u8) -> BoneKind> {
		(Self::MIN as u8..=Self::MAX as u8).map(|x| x.try_into().unwrap())
	}

	/// Returns the initial calibration pose of the bone. Rotating the up vector by
	/// this rotation would cause it to point in the same target direction as the bone.
	pub fn calibration_rotation(self) -> Global<UnitQuat> {
		use BoneKind::*;
		Global(match self {
			FootL | FootR => UnitQuat::look_at_rh(&-up_vec(), &forward_vec()),
			_ => UnitQuat::default(),
		})
	}

	/// Returns the initial calibration pose of the bone, as a rotation relative to the
	/// parent bone. See also: [`Self::calibration_rotation`]
	pub fn calibration_rotation_local(self) -> Local<UnitQuat> {
		let child_rot_g = self.calibration_rotation();
		let parent_rot_g = self.parent().unwrap_or(self).calibration_rotation();
		Local(parent_rot_g.0.rotation_to(&child_rot_g.0))
	}
}
impl TryFrom<u8> for BoneKind {
	type Error = ();

	fn try_from(value: u8) -> Result<Self, Self::Error> {
		FromPrimitive::from_u8(value).ok_or(())
	}
}
impl TryFrom<usize> for BoneKind {
	type Error = ();
	fn try_from(value: usize) -> Result<Self, Self::Error> {
		FromPrimitive::from_usize(value).ok_or(())
	}
}
impl From<BoneKind> for u8 {
	fn from(other: BoneKind) -> Self {
		other as _
	}
}
impl From<BoneKind> for usize {
	fn from(other: BoneKind) -> Self {
		other as _
	}
}