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 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
use crate::{
c::{
spSkeletonData, spSkin, spSkin_addSkin, spSkin_copySkin, spSkin_create, spSkin_dispose,
spSkin_getAttachments,
},
c_interface::{to_c_str, CTmpMut, CTmpRef, NewFromPtr, SyncPtr},
Attachment, Skeleton, SkeletonData,
};
/// A container for attachments which can be applied to a skeleton.
///
/// [Spine API Reference](http://esotericsoftware.com/spine-api-reference#Skin)
#[derive(Debug)]
pub struct Skin {
c_skin: SyncPtr<spSkin>,
pub(crate) owns_memory: bool,
}
impl NewFromPtr<spSkin> for Skin {
unsafe fn new_from_ptr(c_skin: *mut spSkin) -> Self {
Self {
c_skin: SyncPtr(c_skin),
owns_memory: false,
}
}
}
impl Skin {
#[must_use]
pub fn new(name: &str) -> Skin {
let c_name = to_c_str(name);
Self {
c_skin: SyncPtr(unsafe { spSkin_create(c_name.as_ptr()) }),
owns_memory: true,
}
}
/// Add a skin to this skin.
///
/// Typically used on a newly created skin (via [`Skin::new`]) to create conglomerate skins. A
/// safer way to create conglomerate skins is to use [`Skeleton::set_skins_by_name`].
///
/// # Safety
///
/// Skins must all originate from the same [`SkeletonData`].
pub unsafe fn add_skin(&mut self, other: &Skin) {
unsafe {
spSkin_addSkin(self.c_ptr_mut(), other.c_ptr());
}
}
pub fn copy_skin(&mut self, other: &Skin) {
unsafe {
spSkin_copySkin(self.c_ptr_mut(), other.c_ptr());
}
}
#[must_use]
pub fn attachments(&self) -> Vec<AttachmentEntry> {
let mut attachments = vec![];
unsafe {
let mut entry = spSkin_getAttachments(self.c_ptr());
while !entry.is_null() {
attachments.push(AttachmentEntry {
slot_index: (*entry).slotIndex,
attachment: Attachment::new_from_ptr((*entry).attachment),
});
entry = (*entry).next;
}
}
attachments
}
c_accessor_string!(name, name);
c_ptr!(c_skin, spSkin);
// TODO: accessors
}
impl Clone for Skin {
fn clone(&self) -> Self {
let mut clone = Skin::new(self.name());
clone.copy_skin(self);
clone
}
}
impl Drop for Skin {
fn drop(&mut self) {
if self.owns_memory {
unsafe {
spSkin_dispose(self.c_skin.0);
}
}
}
}
c_handle_decl!(
/// A storeable reference to a [`Skin`].
///
/// Can be acquired from a
/// [`CTmpRef<SkeletonData, Skin>`], [`CTmpMut<SkeletonData, Skin>`],
/// [`CTmpRef<Skeleton, Skin>`], or [`CTmpMut<Skeleton, Skin>`].
///
/// ```
/// # #[path="./test.rs"]
/// # mod test;
/// # use rusty_spine::{AnimationState, EventType, SkinHandle};
/// # let (skeleton, _) = test::TestAsset::spineboy().instance(true);
/// let skeleton_data = skeleton.data();
/// let skin_handles: Vec<SkinHandle> = skeleton_data.skins().map(|skin| skin.handle()).collect();
/// for skin_handle in skin_handles.iter() {
/// let skin = skin_handle.get(skeleton_data.as_ref()).unwrap();
/// println!("{}", skin.name());
/// }
/// ```
SkinHandle,
Skin,
SkeletonData,
spSkin,
spSkeletonData
);
impl<'a> CTmpRef<'a, SkeletonData, Skin> {
#[must_use]
pub fn handle(&self) -> SkinHandle {
SkinHandle::new(self.c_ptr(), self.parent.c_ptr())
}
}
impl<'a> CTmpMut<'a, SkeletonData, Skin> {
#[must_use]
pub fn handle(&self) -> SkinHandle {
SkinHandle::new(self.c_ptr(), self.parent.c_ptr())
}
}
impl<'a> CTmpRef<'a, Skeleton, Skin> {
#[must_use]
pub fn handle(&self) -> SkinHandle {
SkinHandle::new(self.c_ptr(), unsafe { self.parent.c_ptr_mut().data })
}
}
impl<'a> CTmpMut<'a, Skeleton, Skin> {
#[must_use]
pub fn handle(&self) -> SkinHandle {
SkinHandle::new(self.c_ptr(), unsafe { self.parent.c_ptr_mut().data })
}
}
/// An [`Skin`]'s [`Attachment`] and slot index.
pub struct AttachmentEntry {
pub slot_index: i32,
pub attachment: Attachment,
}
#[cfg(test)]
mod test {
use crate::test::TestAsset;
use super::*;
/// Check that dropped skins don't segfault.
#[test]
fn skin_drop() {
let (skeleton, _) = TestAsset::spineboy().instance(true);
drop(skeleton.data().default_skin());
drop(Skin::new("test"));
}
}