1use std::convert::TryFrom;
2use std::path::Path;
3use std::sync::atomic::{AtomicU64, Ordering};
4use std::sync::Arc;
5
6use image::{DynamicImage, RgbaImage};
7use lazy_static::lazy_static;
8use winit::window::Icon;
9
10use crate::math::Size;
11
12lazy_static! {
13 static ref GLOBAL_ID_CELL: AtomicU64 = AtomicU64::new(0);
14}
15
16#[macro_export]
18macro_rules! include_texture {
19 ($image_path:expr) => {{
20 let image_bytes = std::include_bytes!($image_path);
21 <$crate::texture::Texture as std::convert::TryFrom<&[u8]>>::try_from(image_bytes)
22 }};
23}
24
25#[derive(Debug, Clone)]
27pub struct Texture {
28 id: u64,
29 pub image: Arc<RgbaImage>,
31}
32
33impl Texture {
34 #[must_use]
37 pub const fn id(&self) -> u64 {
38 self.id
39 }
40
41 #[must_use]
43 pub fn new(image: Arc<RgbaImage>) -> Self {
44 let id = GLOBAL_ID_CELL.fetch_add(1, Ordering::SeqCst);
45 Self { id, image }
46 }
47
48 pub fn load<P: AsRef<Path>>(path: P) -> crate::Result<Self> {
50 let img = image::open(path)?;
51
52 Ok(Self::from(&img))
53 }
54
55 #[must_use]
57 pub fn size(&self) -> Size<u32> {
58 let (w, h) = self.image.dimensions();
59 Size::new(w, h)
60 }
61
62 #[must_use]
64 pub fn rgba_pixels(&self) -> Vec<u8> {
65 (*self.image).clone().into_vec()
66 }
67
68 pub fn window_icon(&self) -> Result<Icon, winit::window::BadIcon> {
71 Icon::from_rgba(self.rgba_pixels(), self.image.width(), self.image.height())
72 }
73}
74
75impl<'a> TryFrom<&'a [u8]> for Texture {
76 type Error = crate::Error;
77
78 fn try_from(bytes: &[u8]) -> crate::Result<Self> {
79 let img = image::load_from_memory(bytes)?;
80
81 Ok(Self::from(&img))
82 }
83}
84
85impl<'a> From<&'a DynamicImage> for Texture {
86 fn from(img: &'a DynamicImage) -> Self {
87 let img = img.to_rgba8();
88 Self::new(Arc::new(img))
89 }
90}