Skip to main content

pfx_play/world/
anim.rs

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}