playdate_graphics/bitmap/
bitmap.rs

1//! Playdate bitmap API
2
3use core::ffi::c_char;
4use core::ffi::c_float;
5use core::ffi::c_int;
6use core::fmt::Write;
7use core::marker::PhantomData;
8use alloc::boxed::Box;
9
10use sys::error::NullPtrError;
11use sys::error::OkMutOrNullErr;
12use sys::error::OkOrNullFnErr;
13use sys::ffi::LCDPattern;
14use sys::ffi::LCDSolidColor;
15use sys::traits::AsRaw;
16use sys::ffi::CString;
17use sys::ffi::LCDColor;
18use sys::ffi::LCDRect;
19use sys::ffi::LCDBitmap;
20use fs::Path;
21
22use crate::Graphics;
23use crate::error::ApiError;
24use crate::error::Error;
25use super::api;
26
27pub use color::*;
28pub use sys::ffi::LCDBitmapFlip as BitmapFlip;
29pub use sys::ffi::LCDBitmapDrawMode as BitmapDrawMode;
30pub use crate::{BitmapFlipExt, BitmapDrawModeExt};
31
32
33pub trait AnyBitmap: AsRaw<Type = LCDBitmap> + BitmapApi {}
34impl<T: AnyBitmap> AnyBitmap for &'_ T {}
35impl AnyBitmap for BitmapRef<'_> {}
36impl<Api: api::Api, const FOD: bool> AnyBitmap for Bitmap<Api, FOD> {}
37
38
39pub trait BitmapApi {
40	type Api: api::Api;
41	fn api(&self) -> Self::Api
42		where Self::Api: Copy;
43	fn api_ref(&self) -> &Self::Api;
44}
45
46impl BitmapApi for BitmapRef<'_> {
47	type Api = api::Default;
48
49	fn api(&self) -> Self::Api
50		where Self::Api: Copy {
51		api::Default::default()
52	}
53
54	fn api_ref(&self) -> &Self::Api { &self.1 }
55}
56
57impl<Api: api::Api, const FOD: bool> BitmapApi for Bitmap<Api, FOD> {
58	type Api = Api;
59	fn api(&self) -> Api
60		where Self::Api: Copy {
61		self.1
62	}
63
64	fn api_ref(&self) -> &Self::Api { &self.1 }
65}
66
67impl<T: BitmapApi> BitmapApi for &'_ T {
68	type Api = T::Api;
69
70	fn api(&self) -> Self::Api
71		where Self::Api: Copy {
72		(*self).api()
73	}
74
75	fn api_ref(&self) -> &Self::Api { (*self).api_ref() }
76}
77
78
79#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
80pub struct Bitmap<Api: api::Api = api::Default, const FREE_ON_DROP: bool = true>(pub(crate) *mut LCDBitmap,
81                                                                                 pub(crate) Api);
82
83impl<Api: api::Api, const FOD: bool> AsRaw for Bitmap<Api, FOD> {
84	type Type = LCDBitmap;
85	unsafe fn as_raw(&self) -> *mut LCDBitmap { self.0 }
86}
87
88impl<Api: api::Api + Default, const FOD: bool> From<*mut LCDBitmap> for Bitmap<Api, FOD> {
89	fn from(ptr: *mut LCDBitmap) -> Self { Self(ptr, Api::default()) }
90}
91
92impl<Api: api::Api + Copy> Bitmap<Api, true> {
93	/// Convert this bitmap into the same bitmap that will not be freed on drop.
94	/// That means that only C-part of the bitmap will __not__ be freed.
95	///
96	/// __Safety is guaranteed by the caller.__
97	pub fn into_shared(mut self) -> Bitmap<Api, false> {
98		let res = Bitmap(self.0, self.1);
99		self.0 = core::ptr::null_mut();
100		res
101	}
102}
103
104
105#[repr(transparent)]
106pub struct BitmapRef<'owner>(*mut LCDBitmap, api::Default, PhantomData<&'owner ()>);
107
108impl AsRaw for BitmapRef<'_> {
109	type Type = LCDBitmap;
110	unsafe fn as_raw(&self) -> *mut LCDBitmap { self.0 }
111}
112
113impl From<*mut LCDBitmap> for BitmapRef<'_> {
114	fn from(ptr: *mut LCDBitmap) -> Self { Self(ptr, Default::default(), PhantomData) }
115}
116
117impl<'owner> BitmapRef<'owner> {
118	pub fn into_bitmap(self) -> Result<Bitmap<<Self as BitmapApi>::Api, false>, NullPtrError> {
119		let ptr = unsafe { self.as_raw() }.ok_or_null()?;
120		Ok(Bitmap(ptr, self.api()))
121	}
122
123	pub fn into_bitmap_with<Api: api::Api>(self, api: Api) -> Result<Bitmap<Api, false>, NullPtrError> {
124		let ptr = unsafe { self.as_raw() }.ok_or_null()?;
125		Ok(Bitmap(ptr, api))
126	}
127
128	pub fn null() -> Self { Self::from(core::ptr::null_mut()) }
129}
130
131
132impl<Api: api::Api> Bitmap<Api, true> {
133	/// Allocates and returns a new `width` by `height` Bitmap filled with `bg` color.
134	///
135	/// Calls [`sys::ffi::playdate_graphics::newBitmap`].
136	#[doc(alias = "sys::ffi::playdate_graphics::newBitmap")]
137	pub fn new(width: c_int, height: c_int, bg: Color) -> Result<Self, Error>
138		where Api: Default {
139		let api = Api::default();
140		Self::new_with(api, width, height, bg)
141	}
142
143	/// Allocates and returns a new `width` by `height` Bitmap filled with `bg` color,
144	/// using the given `api`.
145	///
146	/// Calls [`sys::ffi::playdate_graphics::newBitmap`].
147	#[doc(alias = "sys::ffi::playdate_graphics::newBitmap")]
148	pub fn new_with(api: Api, width: c_int, height: c_int, bg: Color) -> Result<Self, Error> {
149		let f = api.new_bitmap();
150		let ptr = unsafe { f(width, height, bg.into()) };
151		if ptr.is_null() {
152			Err(Error::Alloc)
153		} else {
154			Ok(Self(ptr, api))
155		}
156	}
157
158
159	/// Load a bitmap from a file.
160	///
161	/// Calls [`sys::ffi::playdate_graphics::loadBitmap`].
162	#[doc(alias = "sys::ffi::playdate_graphics::loadBitmap")]
163	pub fn load<P: AsRef<Path>>(path: P) -> Result<Self, ApiError>
164		where Api: Default {
165		let api = Api::default();
166		Self::load_with(api, path)
167	}
168
169	/// Load a bitmap from a file,
170	/// create new bitmap with given `api`.
171	///
172	/// Calls [`sys::ffi::playdate_graphics::loadBitmap`].
173	#[doc(alias = "sys::ffi::playdate_graphics::loadBitmap")]
174	pub fn load_with<P: AsRef<Path>>(api: Api, path: P) -> Result<Self, ApiError> {
175		let mut err = Box::new(core::ptr::null() as *const c_char);
176		let out_err = Box::into_raw(err);
177
178		let path = CString::new(path.as_ref())?;
179
180		let f = api.load_bitmap();
181		let ptr = unsafe { f(path.as_ptr() as *mut c_char, out_err as _) };
182		if ptr.is_null() {
183			err = unsafe { Box::from_raw(out_err) };
184			if let Some(err) = fs::error::Error::from_ptr(*err) {
185				Err(Error::Fs(err).into())
186			} else {
187				Err(Error::Alloc.into())
188			}
189		} else {
190			Ok(Self(ptr, api))
191		}
192	}
193}
194
195
196impl<Api: api::Api, const FOD: bool> Bitmap<Api, FOD> {
197	/// Load a bitmap from a file into `self`.
198	///
199	/// Calls [`sys::ffi::playdate_graphics::loadIntoBitmap`].
200	#[doc(alias = "sys::ffi::playdate_graphics::loadIntoBitmap")]
201	pub fn load_into<P: AsRef<Path>>(&mut self, path: P) -> Result<(), ApiError> {
202		let mut err = Box::new(core::ptr::null() as *const c_char);
203		let out_err = Box::into_raw(err);
204
205		let path = CString::new(path.as_ref())?;
206
207		let f = self.1.load_into_bitmap();
208		unsafe { f(path.as_ptr() as *mut c_char, self.0, out_err as _) };
209		err = unsafe { Box::from_raw(out_err) };
210		if let Some(err) = fs::error::Error::from_ptr(*err) {
211			Err(Error::Fs(err).into())
212		} else {
213			Ok(())
214		}
215	}
216}
217
218
219impl<Api: api::Api, const FOD: bool> Drop for Bitmap<Api, FOD> {
220	fn drop(&mut self) {
221		if FOD && !self.0.is_null() {
222			let f = self.1.free_bitmap();
223			unsafe { f(self.0) };
224			self.0 = core::ptr::null_mut();
225		}
226	}
227}
228
229impl<Api: api::Api + Clone> Clone for Bitmap<Api, true> {
230	/// Allocates and returns a new `Bitmap` that is an exact copy of `self`,
231	/// __not a reference__.
232	///
233	/// Equivalent to [`sys::ffi::playdate_graphics::copyBitmap`].
234	#[doc(alias = "sys::ffi::playdate_graphics::copyBitmap")]
235	fn clone(&self) -> Self {
236		let f = self.1.copy_bitmap();
237		let ptr = unsafe { f(self.0) };
238		if ptr.is_null() {
239			panic!("{}: bitmap clone", Error::Alloc)
240		} else {
241			Self(ptr, self.1.clone())
242		}
243	}
244}
245
246
247impl<Api: api::Api, const FOD: bool> Bitmap<Api, FOD> {
248	/// Clears bitmap, filling with the given `bg` color.
249	///
250	/// Equivalent to [`sys::ffi::playdate_graphics::clearBitmap`].
251	#[doc(alias = "sys::ffi::playdate_graphics::clearBitmap")]
252	pub fn clear(&self, bg: Color) {
253		let f = self.1.clear_bitmap();
254		unsafe { f(self.0, bg.into()) };
255	}
256
257
258	/// Returns `(width, height)` of the bitmap.
259	///
260	/// Can return error if there is no bitmap-data or any internal error occurred.
261	///
262	/// Calls [`sys::ffi::playdate_graphics::getBitmapData`].
263	#[doc(alias = "sys::ffi::playdate_graphics::getBitmapData")]
264	pub fn size(&self) -> (c_int, c_int) {
265		let mut width: c_int = 0;
266		let mut height: c_int = 0;
267		let mut row_bytes: c_int = 0;
268
269		let f = self.1.get_bitmap_data();
270		unsafe {
271			f(
272			  self.0,
273			  &mut width,
274			  &mut height,
275			  &mut row_bytes,
276			  core::ptr::null_mut(),
277			  core::ptr::null_mut(),
278			)
279		};
280
281		(width, height)
282	}
283
284	/// Returns mutable borrow of bitmap-data by this bitmap.
285	///
286	/// Calls [`sys::ffi::playdate_graphics::getBitmapData`].
287	#[doc(alias = "sys::ffi::playdate_graphics::getBitmapData")]
288	pub fn bitmap_data<'bitmap>(&'bitmap mut self) -> BitmapData<'bitmap> {
289		let mut width: c_int = 0;
290		let mut height: c_int = 0;
291		let mut row_bytes: c_int = 0;
292
293
294		let mut boxed_data = Box::new(core::ptr::null_mut());
295		let data = Box::into_raw(boxed_data);
296		let mut boxed_mask = Box::new(core::ptr::null_mut());
297		let mask = Box::into_raw(boxed_mask);
298
299		let f = self.1.get_bitmap_data();
300		unsafe { f(self.0, &mut width, &mut height, &mut row_bytes, mask, data) };
301
302		let len = row_bytes * height;
303
304		boxed_data = unsafe { Box::from_raw(data) };
305		boxed_mask = unsafe { Box::from_raw(mask) };
306
307		// get mask:
308		let mask = {
309			if !boxed_mask.is_null() && !(*boxed_mask).is_null() {
310				let mask = unsafe { core::slice::from_raw_parts_mut::<u8>(*boxed_mask, len as usize) };
311				Some(mask)
312			} else {
313				None
314			}
315		};
316
317		// get data:
318		let data = unsafe { core::slice::from_raw_parts_mut::<u8>(*boxed_data, len as usize) };
319
320		BitmapData { width,
321		             height,
322		             row_bytes,
323		             mask,
324		             data }
325	}
326
327
328	/// Sets a mask image for the bitmap.
329	/// The set mask must be the same size as the `self` bitmap.
330	///
331	/// Calls [`sys::ffi::playdate_graphics::setBitmapMask`].
332	#[doc(alias = "sys::ffi::playdate_graphics::setBitmapMask")]
333	pub fn set_mask<Api2: api::Api, const FREE: bool>(&self, mask: &mut Bitmap<Api2, FREE>) -> Result<(), Error> {
334		// TODO: investigate is it correct "res == 0 => Ok"
335		let f = self.1.set_bitmap_mask();
336		let res = unsafe { f(self.0, mask.0) };
337		if res == 0 { Ok(()) } else { Err(Error::InvalidMask) }
338	}
339
340	/// Gets a mask image for the given bitmap.
341	/// If the image doesn’t have a mask, returns None.
342	///
343	/// Clones inner api-access.
344	///
345	/// Calls [`sys::ffi::playdate_graphics::getBitmapMask`].
346	#[doc(alias = "sys::ffi::playdate_graphics::getBitmapMask")]
347	#[inline(always)]
348	pub fn mask(&self) -> Option<Bitmap<Api, false>>
349		where Api: Clone {
350		self.mask_with(self.1.clone())
351	}
352
353	/// Gets a mask image for the given bitmap.
354	/// If the image doesn’t have a mask, returns None.
355	///
356	/// Produced `Bitmap` uses passed `api` api-access.
357	///
358	/// Calls [`sys::ffi::playdate_graphics::getBitmapMask`].
359	#[doc(alias = "sys::ffi::playdate_graphics::getBitmapMask")]
360	// XXX: investigate is it should be free-on-drop?
361	pub fn mask_with<NewApi: api::Api>(&self, api: NewApi) -> Option<Bitmap<NewApi, false>> {
362		let f = self.1.get_bitmap_mask();
363		let ptr = unsafe { f(self.0) };
364		if !ptr.is_null() {
365			Some(Bitmap(ptr, api))
366		} else {
367			None
368		}
369	}
370
371	/// Returns a new, rotated and scaled Bitmap based on the bitmap.
372	///
373	/// Calls [`sys::ffi::playdate_graphics::rotatedBitmap`].
374	#[doc(alias = "sys::ffi::playdate_graphics::rotatedBitmap")]
375	#[inline(always)]
376	pub fn rotated_clone(&self,
377	                     rotation: c_float,
378	                     x_scale: c_float,
379	                     y_scale: c_float)
380	                     -> Result<Bitmap<Api, true>, Error>
381		where Api: Clone
382	{
383		self.rotated_clone_with(self.1.clone(), rotation, x_scale, y_scale)
384	}
385
386	/// Returns a new, rotated and scaled Bitmap based on the bitmap using given `api`.
387	///
388	/// Calls [`sys::ffi::playdate_graphics::rotatedBitmap`].
389	#[doc(alias = "sys::ffi::playdate_graphics::rotatedBitmap")]
390	pub fn rotated_clone_with<NewApi: api::Api>(&self,
391	                                            api: NewApi,
392	                                            rotation: c_float,
393	                                            x_scale: c_float,
394	                                            y_scale: c_float)
395	                                            -> Result<Bitmap<NewApi, true>, Error>
396		where Api: Clone
397	{
398		let mut alloced_size: c_int = 0;
399		let alloced_size_ref = &mut alloced_size;
400		let f = self.1.rotated_bitmap();
401		let ptr = unsafe { f(self.0, rotation, x_scale, y_scale, alloced_size_ref) };
402
403		if alloced_size == 0 || ptr.is_null() {
404			Err(Error::Alloc)
405		} else {
406			Ok(Bitmap(ptr, api))
407		}
408	}
409
410
411	/// Draws `self` with its upper-left corner at location `x`, `y`,
412	/// using the given `flip` orientation.
413	///
414	/// Equivalent to [`sys::ffi::playdate_graphics::drawBitmap`].
415	#[doc(alias = "sys::ffi::playdate_graphics::drawBitmap")]
416	#[inline(always)]
417	pub fn draw(&self, x: c_int, y: c_int, flip: BitmapFlip) {
418		let f = self.1.draw_bitmap();
419		unsafe { f(self.0, x, y, flip) }
420	}
421
422	/// Draws `self` with its upper-left corner at location `x`, `y`
423	/// __tiled inside a `width` by `height` rectangle__.
424	///
425	/// Equivalent to [`sys::ffi::playdate_graphics::tileBitmap`].
426	#[doc(alias = "sys::ffi::playdate_graphics::tileBitmap")]
427	#[inline(always)]
428	pub fn draw_tiled(&self, x: c_int, y: c_int, width: c_int, height: c_int, flip: BitmapFlip) {
429		let f = self.1.tile_bitmap();
430		unsafe { f(self.0, x, y, width, height, flip) }
431	}
432
433	/// Draws the *bitmap* scaled to `x_scale` and `y_scale`
434	/// then rotated by `degrees` with its center as given by proportions `center_x` and `center_y` at `x`, `y`;
435	///
436	/// that is:
437	/// * if `center_x` and `center_y` are both 0.5 the center of the image is at (`x`,`y`),
438	/// * if `center_x` and `center_y` are both 0 the top left corner of the image (before rotation) is at (`x`,`y`), etc.
439	///
440	/// Equivalent to [`sys::ffi::playdate_graphics::drawRotatedBitmap`].
441	#[doc(alias = "sys::ffi::playdate_graphics::drawRotatedBitmap")]
442	#[inline(always)]
443	pub fn draw_rotated(&self,
444	                    x: c_int,
445	                    y: c_int,
446	                    degrees: c_float,
447	                    center_x: c_float,
448	                    center_y: c_float,
449	                    x_scale: c_float,
450	                    y_scale: c_float) {
451		let f = self.1.draw_rotated_bitmap();
452		unsafe { f(self.0, x, y, degrees, center_x, center_y, x_scale, y_scale) }
453	}
454
455	/// Draws this bitmap scaled to `x_scale` and `y_scale` with its upper-left corner at location `x`, `y`.
456	///
457	/// Note that flip is not available when drawing scaled bitmaps but negative scale values will achieve the same effect.
458	///
459	/// Equivalent to [`sys::ffi::playdate_graphics::drawScaledBitmap`].
460	#[doc(alias = "sys::ffi::playdate_graphics::drawScaledBitmap")]
461	#[inline(always)]
462	pub fn draw_scaled(&self, x: c_int, y: c_int, x_scale: c_float, y_scale: c_float) {
463		let f = self.1.draw_scaled_bitmap();
464		unsafe { f(self.0, x, y, x_scale, y_scale) }
465	}
466
467
468	/// Returns `true` if any of the opaque pixels in this bitmap when positioned at `x, y` with `flip`
469	/// overlap any of the opaque pixels in `other` bitmap at `x_other`, `y_other` with `flip_other`
470	/// within the non-empty `rect`,
471	/// or `false` if no pixels overlap or if one or both fall completely outside of `rect`.
472	///
473	/// Equivalent to [`sys::ffi::playdate_graphics::checkMaskCollision`].
474	#[doc(alias = "sys::ffi::playdate_graphics::checkMaskCollision")]
475	#[inline(always)]
476	pub fn check_mask_collision<OApi: api::Api, const OFOD: bool>(&self,
477	                                                              x: c_int,
478	                                                              y: c_int,
479	                                                              flip: BitmapFlip,
480	                                                              other: Bitmap<OApi, OFOD>,
481	                                                              x_other: c_int,
482	                                                              y_other: c_int,
483	                                                              flip_other: BitmapFlip,
484	                                                              rect: LCDRect)
485	                                                              -> bool {
486		let f = self.1.check_mask_collision();
487		unsafe { f(self.0, x, y, flip, other.0, x_other, y_other, flip_other, rect) == 1 }
488	}
489
490
491	/// Returns pattern `8 x 8` from this bitmap.
492	///
493	/// `x, y` indicates the top left corner of the 8 x 8 pattern in bitmap's coordinates.
494	///
495	/// Returned pattern is owned by rust and can be dropped freely.
496	///
497	/// Uses [`sys::ffi::playdate_graphics::setColorToPattern`].
498	#[doc(alias = "sys::ffi::playdate_graphics::setColorToPattern")]
499	pub fn pattern_at(&self, x: c_int, y: c_int) -> LCDPattern {
500		let mut color = LCDColor::default();
501		let f = self.1.set_color_to_pattern();
502
503		unsafe {
504			f(core::ptr::addr_of_mut!(color), self.0, x, y);
505			*(color as *mut u8 as *mut LCDPattern)
506		}
507	}
508
509	/// Sets `color` to an `8 x 8` pattern using this bitmap.
510	///
511	/// `x, y` indicates the top left corner of the 8 x 8 pattern.
512	///
513	/// After this operation inner pointer is owned by the system.
514	/// To get owned pattern use [`Bitmap::pattern_at`].
515	///
516	/// Equivalent to [`sys::ffi::playdate_graphics::setColorToPattern`].
517	#[doc(alias = "sys::ffi::playdate_graphics::setColorToPattern")]
518	pub fn set_color_to_pattern(&self, color: &mut LCDColor, x: c_int, y: c_int) {
519		let f = self.1.set_color_to_pattern();
520		unsafe { f(color as _, self.0, x, y) }
521	}
522
523	/// Gets the color of the pixel at `(x,y)` in this bitmap.
524	/// If the coordinate is outside the bounds of the bitmap,
525	/// or if the bitmap has a mask and the pixel is marked transparent,
526	/// the function returns [`Clear`][LCDSolidColor::kColorClear];
527	/// otherwise the return value is [`White`][LCDSolidColor::kColorWhite] or [`Black`][LCDSolidColor::kColorBlack].
528	///
529	/// Calls [`sys::ffi::playdate_graphics::getBitmapPixel`].
530	#[doc(alias = "sys::ffi::playdate_graphics::getBitmapPixel")]
531	#[inline(always)]
532	pub fn pixel_at(&self, x: c_int, y: c_int) -> LCDSolidColor {
533		let f = self.1.get_pixel();
534		unsafe { f(self.0, x, y) }
535	}
536}
537
538
539/// The data is 1 bit per pixel packed format, in MSB order; in other words,
540/// the high bit of the first byte in data is the top left pixel of the image.
541///
542/// The `mask` data is in same format but means transparency.
543pub struct BitmapData<'bitmap> {
544	pub width: c_int,
545	pub height: c_int,
546	pub row_bytes: c_int,
547	mask: Option<&'bitmap mut [u8]>,
548	data: &'bitmap mut [u8],
549}
550
551impl<'bitmap> BitmapData<'bitmap> {
552	pub const fn width(&self) -> c_int { self.width }
553	pub const fn height(&self) -> c_int { self.height }
554	pub const fn row_bytes(&self) -> c_int { self.row_bytes }
555	pub fn mask(&self) -> Option<&[u8]> { self.mask.as_deref() }
556	pub fn mask_mut(&mut self) -> Option<&mut [u8]> { self.mask.as_deref_mut() }
557	pub const fn data(&self) -> &[u8] { self.data }
558	pub fn data_mut(&mut self) -> &mut [u8] { self.data }
559}
560
561impl core::fmt::Display for BitmapData<'_> {
562	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
563		write!(f, "BitmapData({}, {}", self.width(), self.height())?;
564		if self.mask.is_some() {
565			write!(f, ", masked)")
566		} else {
567			write!(f, ")")
568		}
569	}
570}
571
572impl core::fmt::Debug for BitmapData<'_> {
573	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
574		let alternate = f.alternate();
575		if alternate {
576			let fmt_bd = |f: &mut core::fmt::Formatter<'_>, data: &[u8], row_len: c_int| {
577				for (i, b) in data.iter().enumerate() {
578					if i % row_len as usize == 0 {
579						f.write_char('\n')?;
580						f.write_char('\t')?;
581					}
582					f.write_fmt(format_args!("{b:08b} "))?;
583				}
584				Ok(())
585			};
586
587			write!(f, "BitmapData({}, {}", self.width(), self.height())?;
588			if self.mask.is_some() {
589				write!(f, ", masked")?;
590			}
591			write!(f, ", data:")?;
592			fmt_bd(f, self.data, self.row_bytes)?;
593			write!(f, ")")
594		} else {
595			let mut res = f.debug_struct("BitmapData");
596			res.field("width", &self.width)
597			   .field("height", &self.height)
598			   .field("row_bytes", &self.row_bytes);
599			res.field("data", &self.data).field("mask", &self.mask).finish()
600		}
601	}
602}
603
604
605//
606// Global Bitmap-related methods
607//
608
609/// Only valid in the Simulator,
610/// returns the debug framebuffer as a bitmap.
611///
612/// Returns error on device.
613///
614/// This function is shorthand for [`Graphics::debug_bitmap`],
615/// using default ZST end-point.
616///
617/// Equivalent to [`sys::ffi::playdate_graphics::getDebugBitmap`].
618#[doc(alias = "sys::ffi::playdate_graphics::getDebugBitmap")]
619#[inline(always)]
620pub fn debug_bitmap() -> Result<Bitmap<api::Default, false>, ApiError> { Graphics::Default().debug_bitmap() }
621
622/// Returns a bitmap containing the contents of the display buffer.
623///
624/// __The system owns this bitmap—​do not free it.__
625///
626/// This function is shorthand for [`Graphics::display_buffer_bitmap`],
627/// using default ZST end-point.
628///
629/// Equivalent to [`sys::ffi::playdate_graphics::getDisplayBufferBitmap`].
630#[doc(alias = "sys::ffi::playdate_graphics::getDisplayBufferBitmap")]
631#[inline(always)]
632pub fn display_buffer_bitmap() -> Result<Bitmap<api::Default, false>, Error> {
633	Graphics::Default().display_buffer_bitmap()
634}
635
636/// Returns a copy the contents of the working frame buffer as a bitmap.
637///
638/// The caller is responsible for freeing the returned bitmap, it will automatically on drop.
639///
640/// This function is shorthand for [`Graphics::frame_buffer_bitmap`],
641/// using default ZST end-point.
642///
643/// Equivalent to [`sys::ffi::playdate_graphics::copyFrameBufferBitmap`].
644#[doc(alias = "sys::ffi::playdate_graphics::copyFrameBufferBitmap")]
645#[inline(always)]
646pub fn copy_frame_buffer_bitmap() -> Result<Bitmap<api::Default, true>, Error> {
647	Graphics::Default().frame_buffer_bitmap()
648}
649
650
651/// Sets the stencil used for drawing.
652///
653/// If the `tile` is `true` the stencil image will be tiled.
654///
655/// Tiled stencils must have width equal to a multiple of 32 pixels.
656///
657/// This function is shorthand for [`Graphics::set_stencil_tiled`],
658/// using default ZST end-point.
659///
660/// Equivalent to [`sys::ffi::playdate_graphics::setStencilImage`].
661#[doc(alias = "sys::ffi::playdate_graphics::setStencilImage")]
662#[inline(always)]
663pub fn set_stencil_tiled(image: &impl AnyBitmap, tile: bool) {
664	Graphics::Default().set_stencil_tiled(image, tile)
665}
666
667/// Sets the stencil used for drawing.
668/// For a tiled stencil, use [`set_stencil_tiled`] instead.
669///
670/// NOTE: Officially deprecated in favor of [`set_stencil_tiled`], which adds a `tile` flag
671///
672/// This function is shorthand for [`Graphics::set_stencil`],
673/// using default ZST end-point.
674///
675/// Equivalent to [`sys::ffi::playdate_graphics::setStencil`].
676#[doc(alias = "sys::ffi::playdate_graphics::setStencil")]
677#[inline(always)]
678pub fn set_stencil(image: &impl AnyBitmap) { Graphics::Default().set_stencil(image) }
679
680/// Sets the mode used for drawing bitmaps.
681///
682/// Note that text drawing uses bitmaps, so this affects how fonts are displayed as well.
683///
684/// This function is shorthand for [`Graphics::set_draw_mode`],
685/// using default ZST end-point.
686///
687/// Equivalent to [`sys::ffi::playdate_graphics::setDrawMode`].
688#[doc(alias = "sys::ffi::playdate_graphics::setDrawMode")]
689#[inline(always)]
690pub fn set_draw_mode(mode: BitmapDrawMode) -> BitmapDrawMode { Graphics::Default().set_draw_mode(mode) }
691
692/// Push a new drawing context for drawing into the given bitmap.
693///
694/// If `target` is [`BitmapRef::null()`], the drawing functions will use the display framebuffer.
695///
696/// To push framebuffer to context use [`push_framebuffer_to_context`].
697///
698/// This function is shorthand for [`Graphics::push_context`],
699/// using default ZST end-point.
700///
701/// Equivalent to [`sys::ffi::playdate_graphics::pushContext`].
702#[doc(alias = "sys::ffi::playdate_graphics::pushContext")]
703#[inline(always)]
704pub fn push_context(target: &impl AnyBitmap) { Graphics::Default().push_context(target) }
705
706/// Push a new drawing context for drawing into the display framebuffer.
707///
708/// This function is shorthand for [`Graphics::push_framebuffer_to_context`],
709/// using default ZST end-point.
710///
711/// Equivalent to [`sys::ffi::playdate_graphics::pushContext`].
712#[doc(alias = "sys::ffi::playdate_graphics::pushContext")]
713#[inline(always)]
714pub fn push_framebuffer_to_context() { Graphics::Default().push_framebuffer_to_context() }
715
716/// Pops a context off the stack (if any are left),
717/// restoring the drawing settings from before the context was pushed.
718///
719/// This function is shorthand for [`Graphics::pop_context`],
720/// using default ZST end-point.
721///
722/// Equivalent to [`sys::ffi::playdate_graphics::popContext`].
723#[doc(alias = "sys::ffi::playdate_graphics::popContext")]
724#[inline(always)]
725pub fn pop_context() { Graphics::Default().pop_context() }
726
727
728impl<Api: crate::api::Api> Graphics<Api> {
729	/// Only valid in the Simulator,
730	/// returns the debug framebuffer as a bitmap.
731	///
732	/// Returns error on device.
733	///
734	/// Equivalent to [`sys::ffi::playdate_graphics::getDebugBitmap`].
735	#[doc(alias = "sys::ffi::playdate_graphics::getDebugBitmap")]
736	pub fn debug_bitmap(&self) -> Result<Bitmap<api::Default, false>, ApiError> {
737		let f = self.0.get_debug_bitmap().ok_or_null()?;
738		let ptr = unsafe { f() };
739		if ptr.is_null() {
740			Err(Error::Alloc.into())
741		} else {
742			Ok(Bitmap(ptr, Default::default()))
743		}
744	}
745
746	/// Returns a bitmap containing the contents of the display buffer.
747	///
748	/// __The system owns this bitmap—​do not free it.__
749	///
750	/// Equivalent to [`sys::ffi::playdate_graphics::getDisplayBufferBitmap`].
751	#[doc(alias = "sys::ffi::playdate_graphics::getDisplayBufferBitmap")]
752	pub fn display_buffer_bitmap(&self) -> Result<Bitmap<api::Default, false>, Error> {
753		let f = self.0.get_display_buffer_bitmap();
754		let ptr = unsafe { f() };
755		if ptr.is_null() {
756			Err(Error::Alloc)
757		} else {
758			Ok(Bitmap(ptr, Default::default()))
759		}
760	}
761
762	/// Returns a __copy__ the contents of the working frame buffer as a bitmap.
763	///
764	/// The caller is responsible for freeing the returned bitmap, it will automatically on drop.
765	///
766	/// Equivalent to [`sys::ffi::playdate_graphics::copyFrameBufferBitmap`].
767	#[doc(alias = "sys::ffi::playdate_graphics::copyFrameBufferBitmap")]
768	pub fn frame_buffer_bitmap(&self) -> Result<Bitmap<api::Default, true>, Error> {
769		let f = self.0.copy_frame_buffer_bitmap();
770		let ptr = unsafe { f() };
771		if ptr.is_null() {
772			Err(Error::Alloc)
773		} else {
774			Ok(Bitmap(ptr, Default::default()))
775		}
776	}
777
778
779	/// Sets the stencil used for drawing.
780	///
781	/// If the `tile` is `true` the stencil image will be tiled.
782	///
783	/// Tiled stencils must have width equal to a multiple of 32 pixels.
784	///
785	/// Equivalent to [`sys::ffi::playdate_graphics::setStencilImage`].
786	#[doc(alias = "sys::ffi::playdate_graphics::setStencilImage")]
787	pub fn set_stencil_tiled(&self, image: &impl AnyBitmap, tile: bool) {
788		let f = self.0.set_stencil_image();
789		unsafe { f(image.as_raw(), tile as _) };
790	}
791
792	/// Sets the stencil used for drawing.
793	/// For a tiled stencil, use [`set_stencil_tiled`] instead.
794	///
795	/// NOTE: Officially deprecated in favor of [`set_stencil_tiled`], which adds a `tile` flag
796	///
797	/// Equivalent to [`sys::ffi::playdate_graphics::setStencil`].
798	#[doc(alias = "sys::ffi::playdate_graphics::setStencil")]
799	pub fn set_stencil(&self, image: &impl AnyBitmap) {
800		let f = self.0.set_stencil();
801		unsafe { f(image.as_raw()) };
802	}
803
804	/// Sets the mode used for drawing bitmaps.
805	///
806	/// Returns the previous draw mode.
807	///
808	/// Note that text drawing uses bitmaps, so this affects how fonts are displayed as well.
809	///
810	/// Equivalent to [`sys::ffi::playdate_graphics::setDrawMode`].
811	#[doc(alias = "sys::ffi::playdate_graphics::setDrawMode")]
812	pub fn set_draw_mode(&self, mode: BitmapDrawMode) -> BitmapDrawMode {
813		let f = self.0.set_draw_mode();
814		unsafe { f(mode) }
815	}
816
817	/// Push a new drawing context for drawing into the given bitmap.
818	///
819	/// If `target` is [`BitmapRef::null()`], the drawing functions will use the display framebuffer.
820	///
821	/// To push framebuffer to context use [`Graphics::push_framebuffer_to_context`].
822	///
823	/// Equivalent to [`sys::ffi::playdate_graphics::pushContext`].
824	#[doc(alias = "sys::ffi::playdate_graphics::pushContext")]
825	pub fn push_context(&self, target: &impl AnyBitmap) {
826		let f = self.0.push_context();
827		unsafe { f(target.as_raw()) };
828	}
829
830	/// Push a new drawing context for drawing into the display framebuffer.
831	///
832	/// Equivalent to [`sys::ffi::playdate_graphics::pushContext`].
833	#[doc(alias = "sys::ffi::playdate_graphics::pushContext")]
834	pub fn push_framebuffer_to_context(&self) {
835		let f = self.0.push_context();
836		unsafe { f(core::ptr::null_mut()) };
837	}
838
839	/// Pops a context off the stack (if any are left),
840	/// restoring the drawing settings from before the context was pushed.
841	///
842	/// Equivalent to [`sys::ffi::playdate_graphics::popContext`].
843	#[doc(alias = "sys::ffi::playdate_graphics::popContext")]
844	pub fn pop_context(&self) {
845		let f = self.0.pop_context();
846		unsafe { f() };
847	}
848}
849
850
851impl<Api: crate::api::Api> Graphics<Api> {
852	/// Draws `self` with its upper-left corner at location `x`, `y`,
853	/// using the given `flip` orientation.
854	///
855	/// Equivalent to [`sys::ffi::playdate_graphics::drawBitmap`].
856	#[doc(alias = "sys::ffi::playdate_graphics::drawBitmap")]
857	#[inline(always)]
858	pub fn draw(&self, bitmap: &impl AnyBitmap, x: c_int, y: c_int, flip: BitmapFlip) {
859		let f = self.0.draw_bitmap();
860		unsafe { f(bitmap.as_raw(), x, y, flip) }
861	}
862
863	/// Draws `self` with its upper-left corner at location `x`, `y`
864	/// __tiled inside a `width` by `height` rectangle__.
865	///
866	/// Equivalent to [`sys::ffi::playdate_graphics::tileBitmap`].
867	#[doc(alias = "sys::ffi::playdate_graphics::tileBitmap")]
868	#[inline(always)]
869	pub fn draw_tiled(&self,
870	                  bitmap: &impl AnyBitmap,
871	                  x: c_int,
872	                  y: c_int,
873	                  width: c_int,
874	                  height: c_int,
875	                  flip: BitmapFlip) {
876		let f = self.0.tile_bitmap();
877		unsafe { f(bitmap.as_raw(), x, y, width, height, flip) }
878	}
879
880	/// Draws the *bitmap* scaled to `x_scale` and `y_scale`
881	/// then rotated by `degrees` with its center as given by proportions `center_x` and `center_y` at `x`, `y`;
882	///
883	/// that is:
884	/// * if `center_x` and `center_y` are both 0.5 the center of the image is at (`x`,`y`),
885	/// * if `center_x` and `center_y` are both 0 the top left corner of the image (before rotation) is at (`x`,`y`), etc.
886	///
887	/// Equivalent to [`sys::ffi::playdate_graphics::drawRotatedBitmap`].
888	#[doc(alias = "sys::ffi::playdate_graphics::drawRotatedBitmap")]
889	#[inline(always)]
890	pub fn draw_rotated(&self,
891	                    bitmap: &impl AnyBitmap,
892	                    x: c_int,
893	                    y: c_int,
894	                    degrees: c_float,
895	                    center_x: c_float,
896	                    center_y: c_float,
897	                    x_scale: c_float,
898	                    y_scale: c_float) {
899		let f = self.0.draw_rotated_bitmap();
900		unsafe {
901			f(
902			  bitmap.as_raw(),
903			  x,
904			  y,
905			  degrees,
906			  center_x,
907			  center_y,
908			  x_scale,
909			  y_scale,
910			)
911		}
912	}
913
914	/// Draws this bitmap scaled to `x_scale` and `y_scale` with its upper-left corner at location `x`, `y`.
915	///
916	/// Note that flip is not available when drawing scaled bitmaps but negative scale values will achieve the same effect.
917	///
918	/// Equivalent to [`sys::ffi::playdate_graphics::drawScaledBitmap`].
919	#[doc(alias = "sys::ffi::playdate_graphics::drawScaledBitmap")]
920	#[inline(always)]
921	pub fn draw_scaled(&self, bitmap: &impl AnyBitmap, x: c_int, y: c_int, x_scale: c_float, y_scale: c_float) {
922		let f = self.0.draw_scaled_bitmap();
923		unsafe { f(bitmap.as_raw(), x, y, x_scale, y_scale) }
924	}
925}