1use std::path::PathBuf;
2use std::sync::{Arc, Mutex};
3
4use anyhow::*;
5use image::{load_from_memory, GenericImage, RgbaImage};
6
7#[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}