fennel_engine/resources/
loadable.rs

1use image::ImageReader;
2use sdl3::{
3    pixels::PixelFormat,
4    render::{Texture, TextureCreator},
5    video::WindowContext,
6};
7use std::{
8    cell::{Ref, RefCell},
9    path::PathBuf,
10    rc::Rc,
11    sync::Arc,
12};
13
14use crate::resources::LoadableResource;
15
16/// Simple image asset that stores its file location.
17pub struct Image {
18    /// Filesystem path to the image.
19    pub path: PathBuf,
20    pub buffer: Rc<RefCell<Vec<u8>>>,
21    pub texture: Rc<Texture<'static>>,
22    pub width: u32,
23    pub height: u32,
24}
25
26impl LoadableResource for Image {
27    /// Construct an `Image` from `path` and return it as a boxed trait object.
28    ///
29    /// # Errors
30    /// This implementation never fails, but the signature matches the trait.
31    fn load(
32        path: PathBuf,
33        texture_creator: &Arc<TextureCreator<WindowContext>>,
34    ) -> anyhow::Result<Box<dyn LoadableResource>> {
35        let img = ImageReader::open(&path)?.decode()?;
36        let mut buffer = img.to_rgba8().into_raw();
37        let surface = sdl3::surface::Surface::from_data(
38            &mut buffer,
39            img.width(),
40            img.height(),
41            img.width() * 4,
42            PixelFormat::RGBA32,
43        )?;
44
45        let texture = unsafe {
46            std::mem::transmute::<sdl3::render::Texture<'_>, sdl3::render::Texture<'static>>(
47                texture_creator.create_texture_from_surface(surface)?,
48            )
49        };
50
51        Ok(Box::new(Self {
52            path,
53            buffer: Rc::new(RefCell::new(buffer)),
54            texture: Rc::new(texture),
55            width: img.width(),
56            height: img.height(),
57        }))
58    }
59
60    /// Identifier for the asset is the the string representation of its path.
61    fn name(&self) -> String {
62        self.path.to_string_lossy().to_string()
63    }
64
65    fn as_mut_slice(&self) -> &mut [u8] {
66        let mut mut_ref = self.buffer.borrow_mut();
67        // even more evil shit that PROBABLY :) should be safe because as we know in normal conditions only
68        // one thread should access (graphics, audio, ..) its respecting resources
69        // otherwise have a SEGFAULT >:3
70        unsafe { &mut *(mut_ref.as_mut_slice() as *mut [u8]) }
71    }
72
73    fn as_slice(&self) -> Ref<'_, [u8]> {
74        Ref::map(self.buffer.borrow(), |v| v.as_slice())
75    }
76}