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