tmx/
texture.rs

1use std::path::PathBuf;
2use std::sync::{Arc, Mutex};
3
4use anyhow::*;
5use image::{load_from_memory, GenericImage, RgbaImage};
6
7/// A shared image
8#[derive(Clone)]
9pub struct Texture {
10    data: Arc<Mutex<Inner>>,
11    label: Arc<str>,
12    width: u32,
13    height: u32,
14}
15
16enum Inner {
17    Defined { path: PathBuf },
18    Decoded { buffer: RgbaImage },
19}
20
21impl Texture {
22    pub(crate) fn from_bytes(data: &[u8], label: impl Into<Arc<str>>) -> Result<Self> {
23        let buffer = load_from_memory(data)?.to_rgba8();
24        let width = buffer.width();
25        let height = buffer.height();
26        Ok(Texture {
27            data: Arc::new(Mutex::new(Inner::Decoded { buffer })),
28            label: label.into(),
29            width,
30            height,
31        })
32    }
33
34    pub(crate) fn from_path(path: PathBuf) -> Self {
35        let label = format!("{}", path.display()).into();
36        Texture {
37            data: Arc::new(Mutex::new(Inner::Defined { path })),
38            label,
39            width: 0,
40            height: 0,
41        }
42    }
43
44    pub(crate) fn resize(&self, width: u32, height: u32) -> Result<Self> {
45        if width != self.width && height != self.height {
46            let data = self.data.lock().unwrap();
47            match &*data {
48                Inner::Defined { path } => Ok(Texture {
49                    data: Arc::new(Mutex::new(Inner::Defined { path: path.clone() })),
50                    label: format!("{}#{}x{}", self.label, width, height).into(),
51                    width,
52                    height,
53                }),
54                Inner::Decoded { buffer } => {
55                    let mut new_image: RgbaImage = RgbaImage::new(width, height);
56                    new_image.copy_from(buffer, 0, 0)?;
57                    Ok(Texture {
58                        data: Arc::new(Mutex::new(Inner::Decoded { buffer: new_image })),
59                        label: format!("{}#{}x{}", self.label, width, height).into(),
60                        width,
61                        height,
62                    })
63                }
64            }
65        } else {
66            Ok(self.clone())
67        }
68    }
69
70    pub(crate) fn width(&self) -> u32 {
71        self.width
72    }
73
74    pub(crate) fn height(&self) -> u32 {
75        self.height
76    }
77}