1use core::ffi::c_int;
14use core::ffi::c_void;
15use core::ffi::c_float;
16use core::marker::PhantomData;
17use alloc::boxed::Box;
18
19use sys::traits::AsRaw;
20
21use sys::ffi::SpriteCollisionInfo;
22use sys::ffi::LCDRect;
23use sys::ffi::LCDSprite;
24use sys::ffi::PDRect;
25
26use gfx::bitmap::AnyBitmap;
27use gfx::bitmap::BitmapRef;
28use gfx::bitmap::BitmapDrawMode;
29use gfx::bitmap::BitmapFlip;
30
31use crate::utils;
32use crate::AnySprite;
33use crate::SpriteApi;
34use crate::TypedSprite;
35use crate::api;
36
37pub use crate::ext::*;
38
39
40pub type OwnedSprite<Userdata, Api> = Sprite<Userdata, Api, true>;
41pub type SharedSprite<Userdata, Api> = Sprite<Userdata, Api, false>;
42
43
44impl<UD, Api: api::Api, const FOD: bool> TypedSprite for Sprite<UD, Api, FOD> {
45 type Userdata = UD;
46 const FREE_ON_DROP: bool = FOD;
47}
48
49
50impl AnySprite for SpriteRef {}
51impl<UD, Api: api::Api, const FOD: bool> AnySprite for Sprite<UD, Api, FOD> {}
52
53
54impl SpriteApi for SpriteRef {
55 type Api = api::Default;
56
57 fn api(&self) -> Self::Api
58 where Self::Api: Copy {
59 api::Default::default()
60 }
61
62 fn api_ref(&self) -> &Self::Api {
63 static API: api::Default = api::Default;
64 &API
65 }
66}
67
68impl<UD, Api: api::Api, const FOD: bool> SpriteApi for Sprite<UD, Api, FOD> {
69 type Api = Api;
70 fn api(&self) -> Api
71 where Self::Api: Copy {
72 self.1
73 }
74
75 fn api_ref(&self) -> &Self::Api { &self.1 }
76}
77
78
79#[repr(transparent)]
80#[derive(Copy, Clone, Debug)]
81pub struct SpriteRef(*mut LCDSprite);
82
83impl From<*mut LCDSprite> for SpriteRef {
84 fn from(ptr: *mut LCDSprite) -> Self { Self(ptr) }
85}
86
87impl AsRaw for SpriteRef {
88 type Type = LCDSprite;
89 unsafe fn as_raw(&self) -> *mut LCDSprite { self.0 }
90}
91
92impl SpriteRef {
93 pub fn into_sprite<UD>(self) -> Sprite<UD, <Self as SpriteApi>::Api, false> {
94 Sprite(unsafe { self.as_raw() }, self.api(), PhantomData)
95 }
96
97 pub fn into_sprite_with<UD, Api: api::Api>(self, api: Api) -> Sprite<UD, Api, false> {
98 Sprite(unsafe { self.as_raw() }, api, PhantomData)
99 }
100}
101
102
103#[derive(Debug)]
104pub struct Sprite<Userdata = (), Api: api::Api = api::Default, const FREE_ON_DROP: bool = true>(*mut LCDSprite, Api, PhantomData<Userdata>);
105
106impl<UD, Api: api::Api, const FOD: bool> AsRaw for Sprite<UD, Api, FOD> {
107 type Type = LCDSprite;
108 unsafe fn as_raw(&self) -> *mut LCDSprite { self.0 }
109}
110
111impl<UD, Api: api::Api, const FOD: bool> AsRef<Self> for Sprite<UD, Api, FOD> {
112 fn as_ref(&self) -> &Self { self }
113}
114impl<UD, Api: api::Api, const FOD: bool> AsMut<Self> for Sprite<UD, Api, FOD> {
115 fn as_mut(&mut self) -> &mut Self { self }
116}
117
118impl<UD, Api, const FOD: bool> From<SpriteRef> for Sprite<UD, Api, FOD> where Api: api::Api + Default {
119 fn from(sprite: SpriteRef) -> Self { Self(unsafe { sprite.as_raw() }, Api::default(), PhantomData) }
120}
121
122impl<UD, Api: api::Api + Clone, const FOD: bool> Clone for Sprite<UD, Api, FOD> {
123 fn clone(&self) -> Self {
124 let f = self.1.copy();
125 let ptr = unsafe { f(self.0) };
126 Self(ptr, self.1.clone(), PhantomData)
127 }
128}
129
130impl<UD, Api: api::Api, const FOD: bool> Drop for Sprite<UD, Api, FOD> {
131 fn drop(&mut self) {
132 if FOD && !self.0.is_null() {
133 if let Some(ud) = self.take_userdata() {
134 drop(ud);
135 let f = self.1.set_userdata();
136 unsafe { f(self.0, core::ptr::null_mut()) }
137 }
138
139 let f = self.1.free_sprite();
140 unsafe { f(self.0) }
141 self.0 = core::ptr::null_mut();
142 }
143 }
144}
145
146impl<UD, Api: api::Api + Copy> Sprite<UD, Api, true> {
147 pub fn into_shared(mut self) -> Sprite<UD, Api, false> {
152 let res = Sprite(self.0, self.1, self.2);
153 self.0 = core::ptr::null_mut();
154 res
155 }
156}
157
158
159impl<UD, Api: Default + api::Api, const FOD: bool> Sprite<UD, Api, FOD> {
160 #[doc(alias = "sys::ffi::playdate_sprite::newSprite")]
166 pub fn new() -> Self {
167 let api = Default::default();
168 Self::new_with(api)
169 }
170}
171
172impl<UD, Api: api::Api, const FOD: bool> Sprite<UD, Api, FOD> {
173 #[doc(alias = "sys::ffi::playdate_sprite::newSprite")]
177 pub fn new_with(api: Api) -> Self {
178 let f = api.new_sprite();
179 let ptr = unsafe { f() };
180 Self(ptr, api, PhantomData)
181 }
182}
183
184
185impl<Userdata, Api: api::Api, const FOD: bool> Sprite<Userdata, Api, FOD> {
186 #[doc(alias = "sys::ffi::playdate_sprite::addSprite")]
190 pub fn add(&self) {
191 let f = self.1.add_sprite();
192 unsafe { f(self.0) }
193 }
194
195 #[doc(alias = "sys::ffi::playdate_sprite::removeSprite")]
199 pub fn remove(&self) {
200 let f = self.1.remove_sprite();
201 unsafe { f(self.0) }
202 }
203
204
205 #[doc(alias = "sys::ffi::playdate_sprite::setBounds")]
209 pub fn set_bounds(&self, bounds: PDRect) {
210 let f = self.1.set_bounds();
211 unsafe { f(self.0, bounds) }
212 }
213
214 #[doc(alias = "sys::ffi::playdate_sprite::getBounds")]
218 pub fn bounds(&self) -> PDRect {
219 let f = self.1.get_bounds();
220 unsafe { f(self.0) }
221 }
222
223
224 #[doc(alias = "sys::ffi::playdate_sprite::moveTo")]
228 pub fn move_to(&self, x: c_float, y: c_float) {
229 let f = self.1.move_to();
230 unsafe { f(self.0, x, y) }
231 }
232
233 #[doc(alias = "sys::ffi::playdate_sprite::moveBy")]
237 pub fn move_by(&self, dx: c_float, dy: c_float) {
238 let f = self.1.move_by();
239 unsafe { f(self.0, dx, dy) }
240 }
241
242
243 #[doc(alias = "sys::ffi::playdate_sprite::setImage")]
252 pub fn set_image(&self, image: impl AnyBitmap, flip: BitmapFlip) {
253 let f = self.1.set_image();
254 unsafe { f(self.0, image.as_raw(), flip) }
255 }
256
257 #[doc(alias = "sys::ffi::playdate_sprite::getImage")]
261 pub fn image<'t>(&'t self) -> Option<BitmapRef<'t>> {
262 let f = self.1.get_image();
263 let ptr = unsafe { f(self.0) };
264 if ptr.is_null() {
265 None
266 } else {
267 Some(BitmapRef::from(ptr))
268 }
269 }
270
271
272 #[doc(alias = "sys::ffi::playdate_sprite::setSize")]
277 pub fn set_size(&self, width: c_float, height: c_float) {
278 let f = self.1.set_size();
279 unsafe { f(self.0, width, height) }
280 }
281
282
283 #[doc(alias = "sys::ffi::playdate_sprite::setZIndex")]
288 pub fn set_z_index(&self, z_index: i16) {
289 let f = self.1.set_z_index();
290 unsafe { f(self.0, z_index) }
291 }
292
293 #[doc(alias = "sys::ffi::playdate_sprite::getZIndex")]
297 pub fn z_index(&self) -> i16 {
298 let f = self.1.get_z_index();
299 unsafe { f(self.0) }
300 }
301
302
303 #[doc(alias = "sys::ffi::playdate_sprite::setDrawMode")]
307 pub fn set_draw_mode(&self, mode: BitmapDrawMode) {
308 let f = self.1.set_draw_mode();
309 unsafe { f(self.0, mode) }
310 }
311
312
313 #[doc(alias = "sys::ffi::playdate_sprite::setImageFlip")]
317 pub fn set_image_flip(&self, flip: BitmapFlip) {
318 let f = self.1.set_image_flip();
319 unsafe { f(self.0, flip) }
320 }
321
322 #[doc(alias = "sys::ffi::playdate_sprite::getImageFlip")]
326 pub fn image_flip(&self) -> BitmapFlip {
327 let f = self.1.get_image_flip();
328 unsafe { f(self.0) }
329 }
330
331
332 #[doc(alias = "sys::ffi::playdate_sprite::setStencil")]
336 pub fn set_stencil(&self, stencil: impl AnyBitmap) {
337 let f = self.1.set_stencil();
338 unsafe { f(self.0, stencil.as_raw()) }
339 }
340
341
342 #[doc(alias = "sys::ffi::playdate_sprite::setClipRect")]
346 pub fn set_clip_rect(&self, clip: LCDRect) {
347 let f = self.1.set_clip_rect();
348 unsafe { f(self.0, clip) }
349 }
350
351 #[doc(alias = "sys::ffi::playdate_sprite::clearClipRect")]
355 pub fn clear_clip_rect(&self) {
356 let f = self.1.clear_clip_rect();
357 unsafe { f(self.0) }
358 }
359
360
361 #[doc(alias = "sys::ffi::playdate_sprite::setUpdatesEnabled")]
366 pub fn set_updates_enabled(&self, value: bool) {
367 let f = self.1.set_updates_enabled();
368 unsafe { f(self.0, value.into()) }
369 }
370
371 #[doc(alias = "sys::ffi::playdate_sprite::updatesEnabled")]
375 pub fn updates_enabled(&self) -> bool {
376 let f = self.1.updates_enabled();
377 unsafe { f(self.0) == 1 }
378 }
379
380 #[doc(alias = "sys::ffi::playdate_sprite::setCollisionsEnabled")]
391 pub fn set_collisions_enabled(&self, value: bool) {
392 let f = self.1.set_collisions_enabled();
393 unsafe { f(self.0, value.into()) }
394 }
395
396 #[doc(alias = "sys::ffi::playdate_sprite::collisionsEnabled")]
400 pub fn collisions_enabled(&self) -> bool {
401 let f = self.1.collisions_enabled();
402 unsafe { f(self.0) == 1 }
403 }
404
405 #[doc(alias = "sys::ffi::playdate_sprite::setVisible")]
410 pub fn set_visible(&self, value: bool) {
411 let f = self.1.set_visible();
412 unsafe { f(self.0, value.into()) }
413 }
414
415 #[doc(alias = "sys::ffi::playdate_sprite::isVisible")]
419 pub fn is_visible(&self) -> bool {
420 let f = self.1.is_visible();
421 unsafe { f(self.0) == 1 }
422 }
423
424 #[doc(alias = "sys::ffi::playdate_sprite::setOpaque")]
431 pub fn set_opaque(&self, value: bool) {
432 let f = self.1.set_opaque();
433 unsafe { f(self.0, value.into()) }
434 }
435
436 #[doc(alias = "sys::ffi::playdate_sprite::markDirty")]
440 pub fn mark_dirty(&self) {
441 let f = self.1.mark_dirty();
442 unsafe { f(self.0) }
443 }
444
445 #[doc(alias = "sys::ffi::playdate_sprite::setTag")]
453 pub fn set_tag(&self, tag: u8) {
454 let f = self.1.set_tag();
455 unsafe { f(self.0, tag) }
456 }
457
458 #[doc(alias = "sys::ffi::playdate_sprite::getTag")]
462 pub fn tag(&self) -> u8 {
463 let f = self.1.get_tag();
464 unsafe { f(self.0) }
465 }
466
467 #[doc(alias = "sys::ffi::playdate_sprite::setIgnoresDrawOffset")]
479 pub fn set_ignores_draw_offset(&self, value: bool) {
480 let f = self.1.set_ignores_draw_offset();
481 unsafe { f(self.0, value.into()) }
482 }
483
484
485 #[doc(alias = "sys::ffi::playdate_sprite::getPosition")]
490 pub fn position(&self) -> (c_float, c_float) {
491 let (mut x, mut y) = Default::default();
492 self.position_to(&mut x, &mut y);
493 (x, y)
494 }
495
496 #[doc(alias = "sys::ffi::playdate_sprite::getPosition")]
500 pub fn position_to(&self, x: &mut c_float, y: &mut c_float) {
501 let f = self.1.get_position();
502 unsafe { f(self.0, x, y) }
503 }
504
505
506 #[doc(alias = "sys::ffi::playdate_sprite::setCollideRect")]
511 pub fn set_collide_rect(&self, collide: PDRect) {
512 let f = self.1.set_collide_rect();
513 unsafe { f(self.0, collide) }
514 }
515
516 #[doc(alias = "sys::ffi::playdate_sprite::getCollideRect")]
520 pub fn collide_rect(&self) -> PDRect {
521 let f = self.1.get_collide_rect();
522 unsafe { f(self.0) }
523 }
524
525 #[doc(alias = "sys::ffi::playdate_sprite::clearCollideRect")]
529 pub fn clear_collide_rect(&self) {
530 let f = self.1.clear_collide_rect();
531 unsafe { f(self.0) }
532 }
533
534 #[doc(alias = "sys::ffi::playdate_sprite::check_collisions")]
538 #[must_use = "Expensive op, allocated array by C-API"]
539 pub fn check_collisions(&self,
540 goal_x: c_float,
541 goal_y: c_float,
542 actual_x: &mut c_float,
543 actual_y: &mut c_float)
544 -> Option<utils::Arr<SpriteCollisionInfo>> {
545 let f = self.1.check_collisions();
546 let mut len: c_int = 0;
547 let ptr = unsafe { f(self.0, goal_x, goal_y, actual_x, actual_y, &mut len) };
548
549 if ptr.is_null() || len == 0 {
550 None
551 } else {
552 let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) };
553 Some(utils::Arr(slice))
554 }
555 }
556
557 #[doc(alias = "sys::ffi::playdate_sprite::moveWithCollisions")]
567 #[must_use = "Expensive op, allocated array by C-API"]
568 pub fn move_with_collisions<'t>(&'t self,
569 goal_x: c_float,
570 goal_y: c_float,
571 actual_x: &mut c_float,
572 actual_y: &mut c_float)
573 -> Option<utils::Arr<'t, SpriteCollisionInfo>> {
574 let f = self.1.move_with_collisions();
575 let mut len: c_int = 0;
576 let ptr = unsafe { f(self.0, goal_x, goal_y, actual_x, actual_y, &mut len) };
577
578 if ptr.is_null() || len == 0 {
579 None
580 } else {
581 let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) };
582 Some(utils::Arr(slice))
583 }
584 }
585
586
587 #[doc(alias = "sys::ffi::playdate_sprite::overlapping_sprites")]
592 #[must_use = "Expensive op, allocated array by C-API"]
593 pub fn overlapping_sprites(&self) -> Option<utils::Arr<SpriteRef>> {
594 let f = self.1.overlapping_sprites();
595 let mut len: c_int = 0;
596 let ptr = unsafe { f(self.0, &mut len) };
597 if ptr.is_null() || len == 0 {
598 None
599 } else {
600 let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) };
601 let res = unsafe { core::mem::transmute(slice) };
602 Some(utils::Arr(res))
603 }
604 }
605
606
607 #[doc(alias = "sys::ffi::playdate_sprite::setStencilPattern")]
611 pub fn set_stencil_pattern(&self, pattern: &mut [u8; 8]) {
612 let f = self.1.set_stencil_pattern();
613 unsafe { f(self.0, pattern) }
614 }
615
616 #[doc(alias = "sys::ffi::playdate_sprite::setStencilImage")]
624 pub fn set_stencil_image(&self, stencil: impl AnyBitmap, tile: bool) {
625 let f = self.1.set_stencil_image();
626 unsafe { f(self.0, stencil.as_raw(), tile.into()) }
627 }
628
629 #[doc(alias = "sys::ffi::playdate_sprite::clearStencil")]
633 pub fn clear_stencil(&self) {
634 let f = self.1.clear_stencil();
635 unsafe { f(self.0) }
636 }
637
638 #[doc(alias = "sys::ffi::playdate_sprite::setCenter")]
649 #[inline(always)]
650 pub fn set_center(&self, x: c_float, y: c_float) {
651 let f = self.1.set_center();
652 unsafe { f(self.0, x, y) }
653 }
654
655 #[doc(alias = "sys::ffi::playdate_sprite::getCenter")]
659 #[inline(always)]
660 pub fn center(&self) -> (c_float, c_float) {
661 let (mut x, mut y) = (0.0, 0.0);
662 let f = self.1.get_center();
663 unsafe { f(self.0, &mut x, &mut y) };
664 (x, y)
665 }
666
667
668 #[doc(alias = "sys::ffi::playdate_sprite::setUserdata")]
674 pub fn set_userdata(&self, data: Userdata) {
675 let f = self.1.set_userdata();
676 let userdata = Box::into_raw(Box::new(data));
677 let ptr = userdata as *mut c_void;
678 unsafe { f(self.0, ptr) }
679 }
680
681 #[doc(alias = "sys::ffi::playdate_sprite::get_userdata")]
687 pub fn userdata(&self) -> Option<&mut Userdata> {
688 let f = self.1.get_userdata();
689 let ptr = unsafe { f(self.0) };
690 if ptr.is_null() {
691 None
692 } else {
693 let ptr = ptr as *mut Userdata;
694 unsafe { ptr.as_mut() }
696 }
697 }
698
699 #[doc(alias = "sys::ffi::playdate_sprite::get_userdata")]
703 pub(crate) fn take_userdata(&self) -> Option<Box<Userdata>> {
704 let f = self.1.get_userdata();
705 let ptr = unsafe { f(self.0) };
706 if ptr.is_null() {
707 None
708 } else {
709 let ud = unsafe { Box::from_raw(ptr as *mut Userdata) };
711 Some(ud)
712 }
713 }
714}
715
716
717#[cfg(test)]
718mod tests {
719 use super::*;
720
721 #[test]
722 fn sprite_ref_layout() {
724 assert_eq!(
725 core::mem::size_of::<SpriteRef>(),
726 core::mem::size_of::<*mut LCDSprite>()
727 );
728 assert_eq!(
729 core::mem::size_of::<&[SpriteRef]>(),
730 core::mem::size_of::<&[*mut LCDSprite]>()
731 );
732 }
733}