Skip to main content

grafix_toolbox/kit/opengl/utility/image/
animation.rs

1use 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}