1#![cfg_attr(not(test), no_std)]
2
3extern crate sys;
4extern crate alloc;
5
6use core::ffi::c_int;
7use core::ffi::c_float;
8
9use sys::traits::AsRaw;
10use sys::ffi::SpriteQueryInfo;
11use sys::ffi::LCDRect;
12use sys::ffi::LCDSprite;
13
14pub mod ext;
15mod sprite;
16pub mod api;
17
18pub mod callback {
19 pub mod draw;
20 pub mod update;
21 pub mod collision;
22}
23
24pub mod prelude {
25 pub use super::sprite::*;
26 pub use super::api::Api as _;
27 pub use super::api::Default as DefaultSpriteApi;
28 pub use super::callback::draw::SpriteDraw;
29 pub use super::callback::update::SpriteUpdate;
30 pub use super::callback::collision::SpriteCollisionResponse;
31
32 pub use super::{TypedSprite, SpriteApi};
33}
34
35pub use sprite::*;
36use crate::api::Api;
37
38
39#[doc(alias = "sys::ffi::playdate_sprite::setAlwaysRedraw")]
45pub fn set_always_redraw(value: bool) {
46 let f = api::Api::set_always_redraw(&api::Default);
47 unsafe { f(value.into()) }
48}
49
50#[doc(alias = "sys::ffi::playdate_sprite::addDirtyRect")]
58pub fn add_dirty_rect(rect: LCDRect) {
59 let f = api::Api::add_dirty_rect(&api::Default);
60 unsafe { f(rect) }
61}
62
63#[doc(alias = "sys::ffi::playdate_sprite::drawSprites")]
67pub fn draw_sprites() {
68 let f = api::Api::draw_sprites(&api::Default);
69 unsafe { f() }
70}
71
72#[doc(alias = "sys::ffi::playdate_sprite::updateAndDrawSprites")]
76pub fn update_and_draw_sprites() {
77 let f = api::Api::update_and_draw_sprites(&api::Default);
78 unsafe { f() }
79}
80
81
82#[doc(alias = "sys::ffi::playdate_sprite::addSprite")]
89pub fn add_sprite(sprite: &impl AnySprite) {
90 let f = sprite.api_ref().add_sprite();
91 unsafe { f(sprite.as_raw()) }
92}
93
94#[doc(alias = "sys::ffi::playdate_sprite::removeSprite")]
100pub fn remove_sprite(sprite: &impl AnySprite) {
101 let f = sprite.api_ref().remove_sprite();
102 unsafe { f(sprite.as_raw()) }
103}
104
105#[doc(alias = "sys::ffi::playdate_sprite::removeSprites")]
109pub fn remove_sprites(sprites: &[impl AnySprite]) {
110 let mut ptrs = alloc::vec::Vec::with_capacity(sprites.len());
111 ptrs.extend(sprites.into_iter().map(|sp| unsafe { sp.as_raw() }));
112 let f = sprites.first()
113 .map(|sp| sp.api_ref().remove_sprites())
114 .unwrap_or(api::Default.remove_sprites());
115 unsafe { f(ptrs.as_mut_ptr(), sprites.len() as _) }
116 drop(ptrs);
117}
118
119
120#[doc(alias = "sys::ffi::playdate_sprite::removeAllSprites")]
124pub fn remove_all_sprites() {
125 let f = api::Api::remove_all_sprites(&api::Default);
126 unsafe { f() }
127}
128
129
130#[doc(alias = "sys::ffi::playdate_sprite::getSpriteCount")]
134pub fn sprite_count() -> c_int {
135 let f = api::Api::get_sprite_count(&api::Default);
136 unsafe { f() }
137}
138
139
140#[doc(alias = "sys::ffi::playdate_sprite::setClipRectsInRange")]
144pub fn set_clip_rects_in_range(clip: LCDRect, start_z: c_int, end_z: c_int) {
145 let f = api::Api::set_clip_rects_in_range(&api::Default);
146 unsafe { f(clip, start_z, end_z) }
147}
148
149#[doc(alias = "sys::ffi::playdate_sprite::clearClipRectsInRange")]
153pub fn clear_clip_rects_in_range(start_z: c_int, end_z: c_int) {
154 let f = api::Api::clear_clip_rects_in_range(&api::Default);
155 unsafe { f(start_z, end_z) }
156}
157
158
159#[doc(alias = "sys::ffi::playdate_sprite::resetCollisionWorld")]
163pub fn reset_collision_world() {
164 let f = api::Api::reset_collision_world(&api::Default);
165 unsafe { f() }
166}
167
168
169#[doc(alias = "sys::ffi::playdate_sprite::querySpritesAtPoint")]
173pub fn query_sprites_at_point(x: c_float, y: c_float) -> &'static [SpriteRef] {
174 let mut len: c_int = 0;
175 let api = api::Default;
176 let f = api.query_sprites_at_point();
177 let ptr = unsafe { f(x, y, &mut len) };
178 let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) };
179 unsafe { core::mem::transmute(slice) }
180}
181
182#[doc(alias = "sys::ffi::playdate_sprite::querySpritesInRect")]
187pub fn query_sprites_in_rect(x: c_float, y: c_float, width: c_float, height: c_float) -> &'static [SpriteRef] {
188 let mut len: c_int = 0;
189 let f = api::Api::query_sprites_in_rect(&api::Default);
190 let ptr = unsafe { f(x, y, width, height, &mut len) };
191 let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) };
192 unsafe { core::mem::transmute(slice) }
193}
194
195#[doc(alias = "sys::ffi::playdate_sprite::querySpritesAlongLine")]
200pub fn query_sprites_along_line(x1: c_float, y1: c_float, x2: c_float, y2: c_float) -> &'static [SpriteRef] {
201 let mut len: c_int = 0;
202 let f = api::Api::query_sprites_along_line(&api::Default);
203 let ptr = unsafe { f(x1, y1, x2, y2, &mut len) };
204 let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) };
205 unsafe { core::mem::transmute(slice) }
206}
207
208#[doc(alias = "sys::ffi::playdate_sprite::querySpriteInfoAlongLine")]
215pub fn query_sprite_info_along_line(x1: c_float,
216 y1: c_float,
217 x2: c_float,
218 y2: c_float)
219 -> &'static [SpriteQueryInfo] {
220 let mut len: c_int = 0;
221 let f = api::Api::query_sprite_info_along_line(&api::Default);
222 let ptr = unsafe { f(x1, y1, x2, y2, &mut len) };
223 unsafe { core::slice::from_raw_parts(ptr, len as _) }
224}
225
226
227#[doc(alias = "sys::ffi::playdate_sprite::allOverlappingSprites")]
233pub fn all_overlapping_sprites() -> &'static [SpriteRef] {
234 let f = api::Api::all_overlapping_sprites(&api::Default);
235 let mut len: c_int = 0;
236 let ptr = unsafe { f(&mut len) };
237 let slice = unsafe { core::slice::from_raw_parts(ptr, len as _) };
238 unsafe { core::mem::transmute(slice) }
239}
240
241
242pub trait AnySprite: AsRaw<Type = LCDSprite> + SpriteApi {}
243impl<T: AnySprite> AnySprite for &'_ T {}
244
245
246pub trait SpriteApi {
247 type Api: api::Api;
249
250 fn api(&self) -> Self::Api
252 where Self::Api: Copy;
253
254 fn api_ref(&self) -> &Self::Api;
256}
257
258impl<T: SpriteApi> SpriteApi for &'_ T {
259 type Api = T::Api;
260
261 fn api(&self) -> Self::Api
262 where Self::Api: Copy {
263 (*self).api()
264 }
265
266 fn api_ref(&self) -> &Self::Api { (*self).api_ref() }
267}
268
269
270pub trait TypedSprite: AsRaw<Type = LCDSprite> + SpriteApi {
272 type Userdata;
274 const FREE_ON_DROP: bool = true;
276}
277
278
279pub trait SpriteType {
281 type Api: api::Api;
283
284 type Userdata;
286
287 const FREE_ON_DROP: bool = false;
289}
290
291impl<T: TypedSprite> SpriteType for T {
292 type Api = <T as SpriteApi>::Api;
293 type Userdata = <T as TypedSprite>::Userdata;
294 const FREE_ON_DROP: bool = <T as TypedSprite>::FREE_ON_DROP;
295}
296
297
298pub mod utils {
299 use core::ops::Deref;
300
301 #[must_use]
303 #[repr(transparent)]
304 pub struct Arr<'t, T>(pub(super) &'t [T]);
305
306 impl<T> Drop for Arr<'_, T> {
307 fn drop(&mut self) {
308 let p = self.0.as_ptr() as _;
309
310 #[inline]
311 const fn inner<T>(len: usize) -> core::alloc::Layout {
312 if let Ok(l) = core::alloc::Layout::array::<T>(len) {
313 l
314 } else {
315 use core::mem::{size_of, align_of};
316 let (size, align) = (size_of::<T>(), align_of::<T>());
317 unsafe { core::alloc::Layout::from_size_align_unchecked(size.unchecked_mul(len), align) }
318 }
319 }
320
321 let l = inner::<T>(self.0.len());
322 unsafe {
323 alloc::alloc::dealloc(p, l);
326 };
327 }
328 }
329
330 impl<T> Deref for Arr<'_, T> {
331 type Target = [T];
332 fn deref(&self) -> &Self::Target { self.0 }
333 }
334 impl<T> AsRef<[T]> for Arr<'_, T> {
335 fn as_ref(&self) -> &[T] { self.0 }
336 }
337}