fennel_engine/resources/
loadable.rs1use anyhow::bail;
2use image::ImageReader;
3use sdl3::{
4 pixels::PixelFormat,
5 render::Texture, surface::Surface
6};
7use std::{
8 cell::{Ref, RefCell},
9 path::PathBuf,
10 rc::Rc,
11};
12
13use crate::{graphics::Graphics, resources::LoadableResource};
14
15pub struct Image {
17 pub name: String,
19 pub buffer: Rc<RefCell<Vec<u8>>>,
21 pub texture: Rc<Texture<'static>>,
23 pub width: u32,
25 pub height: u32,
27}
28
29pub struct Font {
31 pub path: PathBuf,
33 pub family_name: String,
35 pub size: f32,
37 pub buffer: Rc<sdl3::ttf::Font<'static>>,
39}
40
41impl Image {
42 pub fn load_from_surface(
43 name: String,
44 graphics: &mut Graphics,
45 surface: Surface
46 ) -> anyhow::Result<Box<dyn LoadableResource>> {
47 let texture = unsafe {
48 std::mem::transmute::<sdl3::render::Texture<'_>, sdl3::render::Texture<'static>>(
49 graphics.texture_creator.create_texture_from_surface(&surface)?,
50 )
51 };
52
53 Ok(Box::new(Self {
54 name,
55 buffer: Rc::new(RefCell::new(vec![])), texture: Rc::new(texture),
57 width: surface.width(),
58 height: surface.height()
59 }))
60 }
61}
62
63impl LoadableResource for Image {
64 fn load(
66 path: PathBuf,
67 graphics: &mut Graphics,
68 _size: Option<f32>
69 ) -> anyhow::Result<Box<dyn LoadableResource>> {
70 let img = ImageReader::open(&path)?.decode()?;
71 let mut buffer = img.to_rgba8().into_raw();
72 let surface = sdl3::surface::Surface::from_data(
73 &mut buffer,
74 img.width(),
75 img.height(),
76 img.width() * 4,
77 PixelFormat::RGBA32,
78 )?;
79
80 let texture = unsafe {
81 std::mem::transmute::<sdl3::render::Texture<'_>, sdl3::render::Texture<'static>>(
82 graphics.texture_creator.create_texture_from_surface(surface)?,
83 )
84 };
85
86 Ok(Box::new(Self {
87 name: path.to_string_lossy().to_string(),
88 buffer: Rc::new(RefCell::new(buffer)),
89 texture: Rc::new(texture),
90 width: img.width(),
91 height: img.height(),
92 }))
93 }
94
95 fn name(&self) -> String {
96 self.name.clone()
97 }
98
99 fn as_mut_slice(&self) -> Option<&mut [u8]> {
100 let mut mut_ref = self.buffer.borrow_mut();
101 unsafe { Some(&mut *(mut_ref.as_mut_slice() as *mut [u8])) }
105 }
106
107 fn as_slice(&self) -> Option<Ref<'_, [u8]>> {
108 Some(Ref::map(self.buffer.borrow(), |v| v.as_slice()))
109 }
110}
111
112impl LoadableResource for Font {
113 fn load(
114 path: PathBuf,
115 graphics: &mut Graphics,
116 size: Option<f32>
117 ) -> anyhow::Result<Box<dyn LoadableResource>>
118 where
119 Self: Sized {
120 if size.is_none() {
121 bail!("no font size was provided");
122 }
123
124 let font = graphics.ttf_context.load_font(&path, size.unwrap())?;
125 Ok(Box::new(Self {
126 path,
127 family_name: font.face_family_name().expect("failed to get font family name"),
128 size: size.unwrap(),
129 buffer: Rc::new(font)
130 }))
131 }
132
133 fn name(&self) -> String {
134 format!("{} {}", self.family_name, self.size)
135 }
136}