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 #[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 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 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}