1use geng::prelude::*;
2
3pub struct GifFrame {
5 pub texture: ugli::Texture,
6 pub duration: f32,
8}
9
10#[derive(Debug, Clone, Default)]
12pub struct GifOptions {
13 pub frame: geng::asset::TextureOptions,
14}
15
16pub async fn load_gif(
18 manager: &geng::asset::Manager,
19 path: impl AsRef<std::path::Path>,
20 options: GifOptions,
21) -> anyhow::Result<Vec<GifFrame>> {
22 use image::AnimationDecoder;
23
24 let path = path.as_ref();
25 log::debug!("Loading gif at {:?}", path);
26
27 let data = <Vec<u8> as geng::asset::Load>::load(manager, path, &())
28 .await
29 .context("when loading gif bytes")?;
30 let gif = image::codecs::gif::GifDecoder::new(data.as_slice()).context("when decoding gif")?;
31 let frames = gif
32 .into_frames()
33 .map(|frame| {
34 let frame = frame.unwrap();
35 let (n, d) = frame.delay().numer_denom_ms();
36 let duration = n as f32 / d as f32 / 1000.0;
37
38 let mut image = frame.into_buffer();
39 if options.frame.premultiply_alpha {
40 for pixel in image.pixels_mut() {
41 use image::Pixel;
42 *pixel = pixel.map_without_alpha(|x| {
43 (x as f32 * (pixel[3] as f32 / 0xff as f32)).round() as u8
44 });
45 }
46 }
47
48 let mut texture = ugli::Texture::from_image_image(manager.ugli(), image);
49 texture.set_filter(options.frame.filter);
50 texture.set_wrap_mode(options.frame.wrap_mode);
51
52 GifFrame { texture, duration }
53 })
54 .collect();
55
56 Ok(frames)
57}