grafix_toolbox/kit/opengl/utility/image/
animation.rs1use super::*;
2
3pub struct Animation<'r, S: TexSize> {
4 frames: Box<[(Vec2, VTex2dEntry<'r, S>)]>,
5 c: Cell<usize>,
6}
7impl<'a, S: TexSize> Animation<'a, S> {
8 pub fn from_file(name: &str, atlas: &'a TexAtlas<S>) -> Res<Self> {
9 let anim_desc = format!("res/{name}/desc");
10 let data = FS::Load::Text(&anim_desc)?;
11
12 let mut time = 0.;
13 let (starts, frames): (Vec<_>, Vec<_>) = data
14 .lines()
15 .filter_map(|l| {
16 if "d " == l.slice(..2) {
17 time += l.slice(2..).parse::<f32>().explain_err(|| format!("Malformed animation file {anim_desc:?}")).warn();
18 None?
19 }
20 let t = atlas.load(&format!("{name}/{l}"));
21 let f = (time, t);
22 time += 1.;
23 Some(f)
24 })
25 .collect();
26
27 let frames = frames
28 .into_iter()
29 .zip(starts.iter().zip(starts.iter().chain(&[time]).skip(1)))
30 .map(|(f, (&s, &e))| ((s, e).div(time), f))
31 .collect_box();
32
33 if frames.is_empty() {
34 format!("Empty animation file {anim_desc}").pipe(Err)?
35 }
36 Self { frames, c: Def() }.pipe(Ok)
37 }
38 pub fn frame(&self, t: f32) -> &VTex2d<S, u8> {
39 let Self { frames, c } = self;
40 ASSERT!(t <= 1., "Animation assumes time in (0..1), given {t}");
41
42 let n = c.get();
43 for (n, ((b, e), guess)) in frames.iter().skip(n).chain(frames.iter().take(n)).enumerate() {
44 if t >= *b && t <= *e {
45 c.set(n);
46 return guess.get();
47 }
48 }
49 frames.last().map(|(_, tex)| tex).valid().get()
50 }
51}