Skip to main content

spine_sys/
atlas.rs

1use crate::{
2    enums::{AtlasFilter, AtlasFormat, AtlasWrap},
3    ffi,
4    spine_ptr::SpineMutPtr,
5    SpineError,
6};
7use std::{
8    ffi::{CStr, CString},
9    path::Path,
10};
11
12pub struct Atlas {
13    pub(crate) inner: SpineMutPtr<ffi::spAtlas>,
14}
15
16impl Atlas {
17    /// Loads a `Atlas` instance from the provided file path.
18    ///
19    /// # Errors
20    /// Returns a `SpineError::FailLoadAtlas` instance, with a text message detailing why loading failed.
21    #[allow(clippy::mut_mut)]
22    pub fn from_file<P, F>(path: P, mut create_texture: F) -> Result<Self, SpineError>
23    where
24        P: AsRef<Path>,
25        F: FnMut(&AtlasPage, &Path) -> u32,
26    {
27        let path_str_c = CString::new(path.as_ref().to_str().ok_or_else(|| {
28            SpineError::FailLoadAtlas("Failed to convert path to string".to_owned())
29        })?)
30        .map_err(|e| {
31            SpineError::FailLoadAtlas(format!("Failed to convert path to string: {:?}", e))
32        })?;
33
34        // TODO:
35        let mut closure_ref: &mut dyn FnMut(&AtlasPage, &Path) -> u32 = &mut create_texture;
36        let trait_obj_ref: &mut &mut dyn FnMut(&AtlasPage, &Path) -> u32 = &mut closure_ref;
37
38        let closure_pointer_pointer = trait_obj_ref as *mut _ as *mut std::os::raw::c_void;
39
40        let inner =
41            unsafe { ffi::spAtlas_createFromFile(path_str_c.as_ptr(), closure_pointer_pointer) };
42        if inner.is_null() {
43            Err(SpineError::FailLoadAtlas(
44                "spAtlas_createFromFile failed".to_owned(),
45            ))
46        } else {
47            Ok(Self {
48                inner: SpineMutPtr::new(inner, Some(ffi::spAtlas_dispose)),
49            })
50        }
51    }
52}
53
54pub struct AtlasPage {
55    pub(crate) inner: SpineMutPtr<ffi::spAtlasPage>,
56}
57impl AtlasPage {
58    pub fn name(&self) -> &str {
59        unsafe { CStr::from_ptr(self.inner.as_ref().name) }
60            .to_str()
61            .ok()
62            .unwrap()
63    }
64
65    pub fn set_texture_id(&mut self, id: u32) {
66        self.inner.as_mut().rendererObject = id as *mut std::os::raw::c_void;
67    }
68
69    pub fn texture_id(&self) -> u32 {
70        self.inner.as_ref().rendererObject as u32
71    }
72
73    pub fn format(&self) -> AtlasFormat {
74        self.inner.as_ref().format.into()
75    }
76
77    pub fn min_filter(&self) -> AtlasFilter {
78        self.inner.as_ref().minFilter.into()
79    }
80
81    pub fn mag_filter(&self) -> AtlasFilter {
82        self.inner.as_ref().magFilter.into()
83    }
84
85    // (U, V)
86    pub fn wrap(&self) -> (AtlasWrap, AtlasWrap) {
87        let r = self.inner.as_ref();
88        (r.uWrap.into(), r.vWrap.into())
89    }
90
91    pub fn dimensions(&self) -> (i32, i32) {
92        let r = self.inner.as_ref();
93        (r.width, r.height)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100    use crate::tests::*;
101
102    #[test]
103    fn load_atlas() {
104        let test_case = &TEST_CASES[0];
105
106        let mut load = 0;
107
108        let _ = Atlas::from_file(test_case.atlas(), |_, _| {
109            load += 1;
110            0
111        })
112        .unwrap();
113
114        assert_eq!(2, load);
115    }
116}