1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
#![deny(clippy::all, clippy::pedantic)]
#![allow(dead_code, clippy::module_name_repetitions, clippy::must_use_candidate)]

use atlas::AtlasPage;
use std::ffi::CStr;
use std::{os::raw::c_char, path::Path};
use thiserror::Error;

pub mod ffi;

pub mod animation;
pub mod atlas;
pub mod enums;
pub mod skeleton;

mod spine_ptr;
use spine_ptr::*;

#[derive(Debug, Error)]
pub enum SpineError {
    #[error("LOL")]
    FailLoadAtlas(String),
    #[error("{}", 0)]
    FailLoadSkeleton(String),
}

#[allow(clippy::mut_mut)]
#[no_mangle]
extern "C" fn _spAtlasPage_createTexture(
    atlas_page_ptr: *mut ffi::spAtlasPage,
    path: *const std::os::raw::c_char,
) {
    std::panic::catch_unwind(|| {
        let path = unsafe { CStr::from_ptr(path).to_str().unwrap().to_owned() };

        let mut atlas_page = AtlasPage {
            inner: SpineMutPtr::new(atlas_page_ptr, None),
        };

        let atlas_object_ptr = unsafe { (*atlas_page.inner.as_mut().atlas).rendererObject };
        //let atlas_page_object_ptr = atlas_page.inner.as_mut().rendererObject;

        if !atlas_object_ptr.is_null() {
            let closure: &mut &mut dyn FnMut(&AtlasPage, &Path) -> u32 =
                unsafe { &mut *(atlas_object_ptr as *mut _) };

            atlas_page.set_texture_id(closure(&atlas_page, Path::new(&path)));
        }
    })
    .unwrap_or_else(|e| println!("ERROR: {:?}", e));
}

#[no_mangle]
extern "C" fn _spAtlasPage_disposeTexture(atlas: *mut ffi::spAtlasPage) {
    std::panic::catch_unwind(|| {
        let _atlas_page = AtlasPage {
            inner: SpineMutPtr::new(atlas, None),
        };

        // TODO: no-op?
    })
    .unwrap_or_else(|e| println!("ERROR: {:?}", e));
}

#[no_mangle]
unsafe extern "C" fn _spUtil_readFile(path: *const c_char, length: *mut i32) -> *mut c_char {
    std::panic::catch_unwind(|| ffi::_spReadFile(path, length)).unwrap_or_else(|e| {
        println!("ERROR: {:?}", e);
        std::ptr::null_mut()
    })
}

#[cfg(test)]
pub(crate) mod tests {
    use std::path::PathBuf;

    pub struct TestCase {
        name: &'static str,
        atlas: &'static str,
        binary: &'static str,
        json: &'static str,
        path: &'static str,
    }
    impl TestCase {
        pub fn name(&self) -> &str {
            self.name
        }

        pub fn atlas(&self) -> PathBuf {
            PathBuf::from(self.path).join(self.atlas)
        }

        pub fn binary(&self) -> PathBuf {
            PathBuf::from(self.path).join(self.binary)
        }

        pub fn json(&self) -> PathBuf {
            PathBuf::from(self.path).join(self.json)
        }
    }

    pub const TEST_CASES: &[TestCase] = &[TestCase {
        name: "dragon",
        atlas: "dragon.atlas",
        binary: "dragon-ess.skel",
        json: "dragon-ess.json",
        path: "../spine-example/examples/dragon/export",
    }];
}