fennel_core/resources/
image.rs

1use std::{path::PathBuf, rc::Rc};
2
3use image::ImageReader;
4use sdl3::{render::Texture, pixels::PixelFormat, surface::Surface};
5
6use crate::{graphics::Graphics, resources::LoadableResource};
7
8
9unsafe impl Send for Image {}
10unsafe impl Sync for Image {}
11
12/// Image asset that can be created either from sdl3's `Surface` for rendering fonts, or from a
13/// file for rendering pictures
14#[derive(Clone)]
15pub struct Image {
16    /// Resource name
17    pub name: String,
18    /// SDL3 texture for caching
19    pub texture: Rc<Texture<'static>>,
20    /// Image width
21    pub width: u32,
22    /// Image heiht
23    pub height: u32,
24}
25
26impl Image {
27    pub fn load_from_surface(
28        name: String,
29        graphics: &mut Graphics,
30        surface: Surface,
31    ) -> anyhow::Result<Box<dyn LoadableResource>> {
32        let texture = unsafe {
33            std::mem::transmute::<sdl3::render::Texture<'_>, sdl3::render::Texture<'static>>(
34                graphics
35                    .texture_creator
36                    .create_texture_from_surface(&surface)?,
37            )
38        };
39
40        Ok(Box::new(Self {
41            name,
42            texture: Rc::new(texture),
43            width: surface.width(),
44            height: surface.height(),
45        }))
46    }
47}
48
49impl LoadableResource for Image {
50    /// Construct an `Image` from `path` and return it as a boxed trait object.
51    fn load(
52        path: PathBuf,
53        name: String,
54        graphics: &mut Graphics,
55        _size: Option<f32>,
56    ) -> anyhow::Result<Box<dyn LoadableResource>> {
57        let img = ImageReader::open(&path)?.decode()?;
58        let mut buffer = img.to_rgba8().into_raw();
59        let surface = sdl3::surface::Surface::from_data(
60            &mut buffer,
61            img.width(),
62            img.height(),
63            img.width() * 4,
64            PixelFormat::RGBA32,
65        )?;
66
67        let texture = unsafe {
68            std::mem::transmute::<sdl3::render::Texture<'_>, sdl3::render::Texture<'static>>(
69                graphics
70                    .texture_creator
71                    .create_texture_from_surface(surface)?,
72            )
73        };
74
75        Ok(Box::new(Self {
76            name,
77            texture: Rc::new(texture),
78            width: img.width(),
79            height: img.height(),
80        }))
81    }
82
83    fn name(&self) -> String {
84        self.name.clone()
85    }
86}