1use std::collections::BTreeMap;
2
3use pfx_core::anim::{AnimError, Animator, Fired, Playback, SpritePlayer};
4use pfx_load::scene::{Camera, Matrix, Posed, Scene, billboard};
5
6use super::{ObjectId, World};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
9pub struct AnimationEvent {
10 pub object: ObjectId,
11 pub clip: String,
12 pub event: String,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq)]
16struct Defaults {
17 speed: f32,
18 playback: Playback,
19}
20
21impl Default for Defaults {
22 fn default() -> Self {
23 Self {
24 speed: 1.0,
25 playback: Playback::Loop,
26 }
27 }
28}
29
30#[derive(Clone, Debug, Default)]
31pub(crate) struct Animations {
32 animators: BTreeMap<usize, Animator>,
33 sprites: BTreeMap<usize, SpritePlayer>,
34 defaults: BTreeMap<usize, Defaults>,
35 events: Vec<AnimationEvent>,
36 errors: Vec<AnimError>,
37}
38
39fn object_error(name: &str, error: AnimError) -> String {
40 format!("object {name}: {error}")
41}
42
43impl Animations {
44 pub(crate) fn new(scene: &Scene, rate: u32) -> Result<Self, String> {
45 let mut out = Self::default();
46 for (index, object) in scene.objects.iter().enumerate() {
47 let data = scene.animations.get(&object.name);
48 let defaults = data.map_or_else(Defaults::default, |data| Defaults {
49 speed: data.speed,
50 playback: data.playback,
51 });
52 out.defaults.insert(index, defaults);
53 if let Some(sprite) = data.and_then(|data| data.sprite.as_ref()) {
54 let mut player = SpritePlayer::new(sprite.sheet.clone(), rate);
55 if let Some(data) = data
56 && let Some(clip) = &data.clip
57 {
58 player
59 .play_from(clip, data.start, 0)
60 .and_then(|()| player.set_speed(data.speed, 0))
61 .map_err(|error| object_error(&object.name, error))?;
62 }
63 out.sprites.insert(index, player);
64 continue;
65 }
66 let rig = data.and_then(|data| data.rig.clone()).or_else(|| {
67 scene
68 .meshes
69 .get(&object.mesh)
70 .and_then(|mesh| mesh.rig.clone())
71 });
72 let Some(rig) = rig else {
73 continue;
74 };
75 let mut animator = Animator::new(rig, rate);
76 if let Some(data) = data.filter(|data| data.plays()) {
77 let clips: Vec<(&str, f32)> = if data.blend.is_empty() {
78 data.clip.iter().map(|clip| (clip.as_str(), 1.0)).collect()
79 } else {
80 data.blend
81 .iter()
82 .map(|(clip, weight)| (clip.as_str(), *weight))
83 .collect()
84 };
85 animator
86 .play_blend(&clips, 0)
87 .map_err(|error| object_error(&object.name, error))?;
88 for (clip, _) in &clips {
89 animator
90 .set_playback(clip, data.playback)
91 .and_then(|()| animator.set_start(clip, data.start, 0))
92 .and_then(|()| animator.set_speed(clip, data.speed, 0))
93 .map_err(|error| object_error(&object.name, error))?;
94 }
95 }
96 out.animators.insert(index, animator);
97 }
98 Ok(out)
99 }
100}
101
102pub struct Animate<'a> {
103 world: &'a mut World,
104 id: ObjectId,
105 error: Option<AnimError>,
106}
107
108impl Animate<'_> {
109 fn each(mut self, change: impl FnOnce(&mut World, ObjectId) -> Result<(), AnimError>) -> Self {
110 if self.error.is_none()
111 && let Err(error) = change(self.world, self.id)
112 {
113 self.world.animations.errors.push(error.clone());
114 self.error = Some(error);
115 }
116 self
117 }
118
119 pub fn blend(self, clip: &str, weight: f32) -> Self {
120 self.each(|world, id| {
121 let tick = world.ticks;
122 let defaults = world.defaults(id);
123 match world.animations.animators.get_mut(&id.index()) {
124 Some(animator) => {
125 animator.blend(clip, weight, tick)?;
126 animator.set_playback(clip, defaults.playback)?;
127 animator.set_speed(clip, defaults.speed, tick)
128 }
129 None => Err(world.not_animated(id, "blends only skeletal clips")),
130 }
131 })
132 }
133
134 pub fn fade(self, seconds: f32) -> Self {
135 self.each(
136 |world, id| match world.animations.animators.get_mut(&id.index()) {
137 Some(animator) => animator.set_fade(seconds),
138 None => Err(world.not_animated(id, "crossfades only skeletal clips")),
139 },
140 )
141 }
142
143 pub fn speed(self, speed: f32) -> Self {
144 self.each(|world, id| {
145 let tick = world.ticks;
146 if let Some(player) = world.animations.sprites.get_mut(&id.index()) {
147 return player.set_speed(speed, tick);
148 }
149 let Some(animator) = world.animations.animators.get_mut(&id.index()) else {
150 return Err(world.not_animated(id, "has no animation"));
151 };
152 for clip in playing(animator) {
153 animator.set_speed(&clip, speed, tick)?;
154 }
155 Ok(())
156 })
157 }
158
159 pub fn start(self, seconds: f32) -> Self {
160 self.each(|world, id| {
161 let tick = world.ticks;
162 if let Some(player) = world.animations.sprites.get_mut(&id.index()) {
163 let Some(clip) = player.clip().map(|clip| clip.name().to_string()) else {
164 return Ok(());
165 };
166 return player.play_from(&clip, seconds, tick);
167 }
168 let Some(animator) = world.animations.animators.get_mut(&id.index()) else {
169 return Err(world.not_animated(id, "has no animation"));
170 };
171 for clip in playing(animator) {
172 animator.set_start(&clip, seconds, tick)?;
173 }
174 Ok(())
175 })
176 }
177
178 pub fn playback(self, playback: Playback) -> Self {
179 self.each(|world, id| {
180 let Some(animator) = world.animations.animators.get_mut(&id.index()) else {
181 return Err(world.not_animated(id, "sets a sprite clip's loop in the scene"));
182 };
183 for clip in playing(animator) {
184 animator.set_playback(&clip, playback)?;
185 }
186 Ok(())
187 })
188 }
189
190 pub fn once(self) -> Self {
191 self.playback(Playback::Once)
192 }
193
194 pub fn looped(self) -> Self {
195 self.playback(Playback::Loop)
196 }
197
198 pub fn ping_pong(self) -> Self {
199 self.playback(Playback::PingPong)
200 }
201
202 pub fn done(self) -> Result<(), AnimError> {
203 match self.error {
204 Some(error) => Err(error),
205 None => Ok(()),
206 }
207 }
208}
209
210impl World {
211 fn defaults(&self, id: ObjectId) -> Defaults {
212 self.animations
213 .defaults
214 .get(&id.index())
215 .copied()
216 .unwrap_or_default()
217 }
218
219 fn not_animated(&self, id: ObjectId, reason: &str) -> AnimError {
220 AnimError::NotAnimated(format!(
221 "object {} {reason}",
222 self.objects
223 .get(id.index())
224 .map_or("(gone)", |entry| entry.name.as_str())
225 ))
226 }
227
228 fn start_clip(&mut self, id: ObjectId, clip: &str) -> Result<(), AnimError> {
229 let tick = self.ticks;
230 let defaults = self.defaults(id);
231 if let Some(player) = self.animations.sprites.get_mut(&id.index()) {
232 return player.play(clip, tick);
233 }
234 let Some(animator) = self.animations.animators.get_mut(&id.index()) else {
235 return Err(self.not_animated(id, "has no animation"));
236 };
237 animator.play(clip, tick)?;
238 animator.set_playback(clip, defaults.playback)?;
239 animator.set_speed(clip, defaults.speed, tick)
240 }
241
242 pub fn play_clip(&mut self, id: ObjectId, clip: &str) -> Result<(), AnimError> {
243 let result = self.start_clip(id, clip);
244 if let Err(error) = &result {
245 self.animations.errors.push(error.clone());
246 }
247 result
248 }
249
250 pub fn animate(&mut self, id: ObjectId, clip: &str) -> Animate<'_> {
251 let error = self.play_clip(id, clip).err();
252 Animate {
253 world: self,
254 id,
255 error,
256 }
257 }
258
259 pub fn stop_animation(&mut self, id: ObjectId) -> bool {
260 if let Some(player) = self.animations.sprites.get_mut(&id.index()) {
261 player.stop();
262 return true;
263 }
264 match self.animations.animators.get_mut(&id.index()) {
265 Some(animator) => {
266 animator.stop();
267 true
268 }
269 None => false,
270 }
271 }
272
273 pub fn animator(&self, id: ObjectId) -> Option<&Animator> {
274 self.animations.animators.get(&id.index())
275 }
276
277 pub fn animator_mut(&mut self, id: ObjectId) -> Option<&mut Animator> {
278 self.animations.animators.get_mut(&id.index())
279 }
280
281 pub fn sprite(&self, id: ObjectId) -> Option<&SpritePlayer> {
282 self.animations.sprites.get(&id.index())
283 }
284
285 pub fn sprite_mut(&mut self, id: ObjectId) -> Option<&mut SpritePlayer> {
286 self.animations.sprites.get_mut(&id.index())
287 }
288
289 pub fn palette(&self, id: ObjectId) -> Option<Vec<Matrix>> {
290 self.animator(id)
291 .map(|animator| animator.palette(self.ticks))
292 }
293
294 pub fn sprite_frame(&self, id: ObjectId) -> Option<[f32; 4]> {
295 let player = self.sprite(id)?;
296 player
297 .uv(self.ticks)
298 .or_else(|| player.sheet().atlas().uv(0))
299 }
300
301 pub fn animation_events(&self) -> &[AnimationEvent] {
302 &self.animations.events
303 }
304
305 pub fn animation_errors(&self) -> &[AnimError] {
306 &self.animations.errors
307 }
308
309 pub(crate) fn palettes(&self) -> BTreeMap<usize, Vec<Matrix>> {
310 self.animations
311 .animators
312 .iter()
313 .map(|(&index, animator)| (index, animator.palette(self.ticks)))
314 .collect()
315 }
316
317 pub(crate) fn sprite_frames(&self) -> BTreeMap<usize, [f32; 4]> {
318 self.animations
319 .sprites
320 .keys()
321 .filter_map(|&index| Some((index, self.sprite_frame(ObjectId::from_index(index))?)))
322 .collect()
323 }
324
325 pub(crate) fn faced_models(&self, camera: &Camera) -> Vec<Matrix> {
326 let mut models = self.models();
327 for (model, object) in models.iter_mut().zip(&self.scene.objects) {
328 if object.face_camera {
329 *model = billboard(*model, camera);
330 }
331 }
332 models
333 }
334
335 pub fn posed(&self) -> Posed {
336 Posed {
337 time: self.time() as f32,
338 models: self.faced_models(&self.fx.camera(&self.camera)),
339 palettes: self.palettes(),
340 frames: self.sprite_frames(),
341 }
342 }
343
344 pub(crate) fn begin_animations(&mut self) {
345 self.animations.errors.clear();
346 self.animations.events.clear();
347 }
348
349 pub(crate) fn step_animations(&mut self) {
350 let tick = self.ticks;
351 let mut fired: Vec<(usize, Fired)> = Vec::new();
352 for (&index, animator) in &mut self.animations.animators {
353 fired.extend(animator.advance(tick).into_iter().map(|one| (index, one)));
354 }
355 for (&index, player) in &mut self.animations.sprites {
356 fired.extend(player.advance(tick).into_iter().map(|one| (index, one)));
357 }
358 fired.sort_by_key(|(index, _)| *index);
359 self.animations.events = fired
360 .into_iter()
361 .map(|(index, one)| AnimationEvent {
362 object: ObjectId::from_index(index),
363 clip: one.clip,
364 event: one.event,
365 })
366 .collect();
367 }
368
369 pub(crate) fn rate_of(clock: &pfx_core::clock::Clock) -> u32 {
370 clock.tick_rate().round().max(1.0) as u32
371 }
372}
373
374fn playing(animator: &Animator) -> Vec<String> {
375 animator
376 .playing()
377 .into_iter()
378 .map(|(clip, _)| clip.to_string())
379 .collect()
380}