pronto_graphics/
texture.rs

1use sfml::graphics::Texture as SfmlTexture;
2use sfml::SfBox;
3
4/// A global static array containing all textures that have been loaded during the runtime of the program.
5/// Should not be accesses directly outside this module.
6/// # Excuses
7/// So, this isn't a pretty look, I know.
8/// The problem is, as far as I can tell, there is no way to tell Rust's lifetime rules that I just want to give
9/// an existing [`RectangleShape`] a reference to a texture for just the scope of one [`Window::texture`] call.
10/// Neither can I create a bundle of the Shape and it's Texture in one object to align their lifetimes.
11/// Therefore, to ensure than all Textures always outlive the Shape that potentially is referencing them,
12/// I have to make the textures `static`. Hence, this ungodly bunch of code.
13/// If there is a prettier solution that I have overlooked, this should be changed.
14static mut TEXTURE_STORE: Option<Vec<SfBox<SfmlTexture>>> = None;
15pub fn init_texture_store() {
16    unsafe {
17        if let None = TEXTURE_STORE {
18            TEXTURE_STORE = Some(Vec::new());
19        }
20    }
21}
22
23pub fn texture_store(texture: Texture) -> Option<&'static SfBox<SfmlTexture>> {
24    unsafe {
25        if let Some(textures) = &TEXTURE_STORE {
26            Some(&textures[texture.index])
27        } else {
28            None
29        }
30    }
31}
32
33pub fn texture_store_add(texture: SfBox<SfmlTexture>) -> Option<Texture> {
34    unsafe {
35        if let Some(textures) = &mut TEXTURE_STORE {
36            textures.push(texture);
37            Some(Texture {
38                index: textures.len() - 1,
39            })
40        } else {
41            None
42        }
43    }
44}
45
46/// A texture object returned by [`Window::load_texture`], that can be passed to [`Window::texture`] to draw the texture to the screen.
47/// # Examples
48/// ```
49/// let mut pg = Window::new_fullscreen();
50/// let my_texture = pg.load_texture("my_texture.png").unwrap();
51/// loop {
52///     pg.texture_((100., 250.), my_texture, 100.);
53///
54///     pg.update();
55/// }
56/// ```
57///
58/// [`Window::texture`]: crate::window::Window::texture
59/// [`Window::load_texture`]: crate::window::Window::load_texture
60#[derive(Clone, Copy)]
61pub struct Texture {
62    pub index: usize,
63}
64
65impl Texture {
66    /// The width of the texture in pixels.
67    pub fn width(&self) -> u32 {
68        texture_store(*self)
69            .and_then(|t| Some(t.size().x))
70            .unwrap_or(0)
71    }
72
73    /// The height of the texture in pixels.
74    pub fn height(&self) -> u32 {
75        texture_store(*self)
76            .and_then(|t| Some(t.size().y))
77            .unwrap_or(0)
78    }
79
80    /// The aspect ratio of the texture.
81    /// (`.width()/.height()`)
82    pub fn aspect(&self) -> f32 {
83        let h = self.height();
84        if h > 0 {
85            (self.width() as f32) / (h as f32)
86        } else {
87            0.
88        }
89    }
90}