plasma_prp/animation/
controller.rs1use std::io::Read;
6
7use anyhow::{Result, bail};
8
9use crate::core::class_index::ClassIndex;
10use crate::resource::prp::PlasmaRead;
11
12use super::keys::{KeyFrame, KeyType, read_keys};
13
14#[derive(Debug, Clone)]
16pub enum Controller {
17 Leaf(LeafController),
19 Compound(CompoundController),
21 TM(TMController),
23}
24
25impl Controller {
26 pub fn read_creatable(reader: &mut impl Read) -> Result<Option<Self>> {
29 let class_idx = reader.read_u16()?;
30 if class_idx == 0x8000 {
31 return Ok(None); }
33
34 log::trace!("Controller: reading class 0x{:04X} ({})",
35 class_idx, crate::core::class_index::ClassIndex::class_name(class_idx));
36
37 match class_idx {
38 ClassIndex::PL_LEAF_CONTROLLER => {
39 Ok(Some(Controller::Leaf(LeafController::read(reader)?)))
40 }
41 ClassIndex::PL_COMPOUND_CONTROLLER => {
42 Ok(Some(Controller::Compound(CompoundController::read(reader)?)))
43 }
44 ClassIndex::PL_TMCONTROLLER => {
45 Ok(Some(Controller::TM(TMController::read(reader)?)))
46 }
47 ClassIndex::PL_COMPOUND_ROT_CONTROLLER | ClassIndex::PL_COMPOUND_POS_CONTROLLER => {
49 Ok(Some(Controller::Compound(CompoundController::read(reader)?)))
50 }
51 _ => {
52 bail!(
53 "Unknown controller class: 0x{:04X} ({})",
54 class_idx,
55 crate::core::class_index::ClassIndex::class_name(class_idx)
56 );
57 }
58 }
59 }
60}
61
62#[derive(Debug, Clone)]
64pub struct LeafController {
65 pub key_type: KeyType,
66 pub keys: Vec<KeyFrame>,
67}
68
69impl LeafController {
70 pub fn read(reader: &mut impl Read) -> Result<Self> {
71 let type_byte = reader.read_u8()?;
72 let key_type = KeyType::from_u8(type_byte)?;
73 let num_keys = reader.read_u32()?;
74 let keys = read_keys(reader, key_type, num_keys)?;
75
76 Ok(Self { key_type, keys })
77 }
78
79 pub fn num_keys(&self) -> usize {
80 self.keys.len()
81 }
82
83 pub fn is_empty(&self) -> bool {
84 self.keys.is_empty()
85 }
86}
87
88#[derive(Debug, Clone)]
90pub struct CompoundController {
91 pub x_controller: Option<Box<Controller>>,
92 pub y_controller: Option<Box<Controller>>,
93 pub z_controller: Option<Box<Controller>>,
94}
95
96impl CompoundController {
97 pub fn read(reader: &mut impl Read) -> Result<Self> {
98 let x = Controller::read_creatable(reader)?.map(Box::new);
99 let y = Controller::read_creatable(reader)?.map(Box::new);
100 let z = Controller::read_creatable(reader)?.map(Box::new);
101
102 Ok(Self {
103 x_controller: x,
104 y_controller: y,
105 z_controller: z,
106 })
107 }
108}
109
110#[derive(Debug, Clone)]
112pub struct TMController {
113 pub pos_controller: Option<Box<Controller>>,
114 pub rot_controller: Option<Box<Controller>>,
115 pub scale_controller: Option<Box<Controller>>,
116}
117
118impl TMController {
119 pub fn read(reader: &mut impl Read) -> Result<Self> {
120 let pos = Controller::read_creatable(reader)?.map(Box::new);
121 let rot = Controller::read_creatable(reader)?.map(Box::new);
122 let scale = Controller::read_creatable(reader)?.map(Box::new);
123
124 Ok(Self {
125 pos_controller: pos,
126 rot_controller: rot,
127 scale_controller: scale,
128 })
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135 use std::io::Cursor;
136
137 #[test]
138 fn test_read_null_creatable() {
139 let data = [0x00, 0x80]; let mut cursor = Cursor::new(&data);
141 let ctrl = Controller::read_creatable(&mut cursor).unwrap();
142 assert!(ctrl.is_none());
143 }
144
145 #[test]
146 fn test_read_leaf_scalar() {
147 let mut data = Vec::new();
148 data.extend_from_slice(&ClassIndex::PL_LEAF_CONTROLLER.to_le_bytes());
150 data.push(3);
152 data.extend_from_slice(&2u32.to_le_bytes());
154 data.extend_from_slice(&0u16.to_le_bytes());
156 data.extend_from_slice(&0.0f32.to_le_bytes());
157 data.extend_from_slice(&30u16.to_le_bytes());
159 data.extend_from_slice(&1.0f32.to_le_bytes());
160
161 let mut cursor = Cursor::new(&data);
162 let ctrl = Controller::read_creatable(&mut cursor).unwrap().unwrap();
163 match ctrl {
164 Controller::Leaf(leaf) => {
165 assert_eq!(leaf.num_keys(), 2);
166 assert_eq!(leaf.key_type, KeyType::Scalar);
167 }
168 _ => panic!("Expected leaf controller"),
169 }
170 }
171
172 #[test]
173 fn test_read_compound() {
174 let mut data = Vec::new();
175 data.extend_from_slice(&ClassIndex::PL_COMPOUND_CONTROLLER.to_le_bytes());
177 data.extend_from_slice(&0x8000u16.to_le_bytes());
179 data.extend_from_slice(&ClassIndex::PL_LEAF_CONTROLLER.to_le_bytes());
181 data.push(3); data.extend_from_slice(&1u32.to_le_bytes());
183 data.extend_from_slice(&0u16.to_le_bytes());
184 data.extend_from_slice(&0.5f32.to_le_bytes());
185 data.extend_from_slice(&0x8000u16.to_le_bytes());
187
188 let mut cursor = Cursor::new(&data);
189 let ctrl = Controller::read_creatable(&mut cursor).unwrap().unwrap();
190 match ctrl {
191 Controller::Compound(compound) => {
192 assert!(compound.x_controller.is_none());
193 assert!(compound.y_controller.is_some());
194 assert!(compound.z_controller.is_none());
195 }
196 _ => panic!("Expected compound controller"),
197 }
198 }
199}