1#![deny(clippy::all, clippy::pedantic)]
2#![allow(dead_code, clippy::module_name_repetitions, clippy::must_use_candidate)]
3
4use atlas::AtlasPage;
5use std::ffi::CStr;
6use std::{os::raw::c_char, path::Path};
7use thiserror::Error;
8
9pub mod ffi;
10
11pub mod animation;
12pub mod atlas;
13pub mod enums;
14pub mod skeleton;
15
16mod spine_ptr;
17use spine_ptr::*;
18
19#[derive(Debug, Error)]
20pub enum SpineError {
21 #[error("LOL")]
22 FailLoadAtlas(String),
23 #[error("{}", 0)]
24 FailLoadSkeleton(String),
25}
26
27#[allow(clippy::mut_mut)]
28#[no_mangle]
29extern "C" fn _spAtlasPage_createTexture(
30 atlas_page_ptr: *mut ffi::spAtlasPage,
31 path: *const std::os::raw::c_char,
32) {
33 std::panic::catch_unwind(|| {
34 let path = unsafe { CStr::from_ptr(path).to_str().unwrap().to_owned() };
35
36 let mut atlas_page = AtlasPage {
37 inner: SpineMutPtr::new(atlas_page_ptr, None),
38 };
39
40 let atlas_object_ptr = unsafe { (*atlas_page.inner.as_mut().atlas).rendererObject };
41 if !atlas_object_ptr.is_null() {
44 let closure: &mut &mut dyn FnMut(&AtlasPage, &Path) -> u32 =
45 unsafe { &mut *(atlas_object_ptr as *mut _) };
46
47 atlas_page.set_texture_id(closure(&atlas_page, Path::new(&path)));
48 }
49 })
50 .unwrap_or_else(|e| println!("ERROR: {:?}", e));
51}
52
53#[no_mangle]
54extern "C" fn _spAtlasPage_disposeTexture(atlas: *mut ffi::spAtlasPage) {
55 std::panic::catch_unwind(|| {
56 let _atlas_page = AtlasPage {
57 inner: SpineMutPtr::new(atlas, None),
58 };
59
60 })
62 .unwrap_or_else(|e| println!("ERROR: {:?}", e));
63}
64
65#[no_mangle]
66unsafe extern "C" fn _spUtil_readFile(path: *const c_char, length: *mut i32) -> *mut c_char {
67 std::panic::catch_unwind(|| ffi::_spReadFile(path, length)).unwrap_or_else(|e| {
68 println!("ERROR: {:?}", e);
69 std::ptr::null_mut()
70 })
71}
72
73#[cfg(test)]
74pub(crate) mod tests {
75 use std::path::PathBuf;
76
77 pub struct TestCase {
78 name: &'static str,
79 atlas: &'static str,
80 binary: &'static str,
81 json: &'static str,
82 path: &'static str,
83 }
84 impl TestCase {
85 pub fn name(&self) -> &str {
86 self.name
87 }
88
89 pub fn atlas(&self) -> PathBuf {
90 PathBuf::from(self.path).join(self.atlas)
91 }
92
93 pub fn binary(&self) -> PathBuf {
94 PathBuf::from(self.path).join(self.binary)
95 }
96
97 pub fn json(&self) -> PathBuf {
98 PathBuf::from(self.path).join(self.json)
99 }
100 }
101
102 pub const TEST_CASES: &[TestCase] = &[TestCase {
103 name: "dragon",
104 atlas: "dragon.atlas",
105 binary: "dragon-ess.skel",
106 json: "dragon-ess.json",
107 path: "../spine-example/examples/dragon/export",
108 }];
109}