1#![cfg_attr(all(target_arch = "arm", target_os = "none"), no_std)]
2
3extern crate alloc;
4pub extern crate num_traits;
5#[doc(hidden)]
6pub extern crate playdate_rs_sys as sys;
7pub extern crate rand;
8
9#[macro_use]
10#[doc(hidden)]
11pub mod print;
12
13#[macro_use]
14pub mod math;
15
16pub mod display;
17pub mod error;
18pub mod fs;
19pub mod graphics;
20pub mod lua;
21mod memory;
22pub mod scoreboards;
23pub mod sound;
24pub mod sprite;
25pub mod system;
26pub mod util;
27pub mod video;
28
29use core::{cell::UnsafeCell, ops::Deref};
30
31use alloc::{boxed::Box, format};
32pub use no_std_io::io;
33pub use playdate_rs_macros::app;
34
35pub struct PlaydateAPI {
36 raw_api: *mut sys::PlaydateAPI,
37 pub system: system::PlaydateSystem,
39 pub file: fs::PlaydateFileSystem,
41 pub graphics: graphics::PlaydateGraphics,
43 pub sprite: sprite::PlaydateSprite,
45 pub display: display::PlaydateDisplay,
47 pub sound: sound::PlaydateSound,
49 pub scoreboards: scoreboards::PlaydateScoreboards,
51 pub lua: lua::Lua,
53 }
56
57unsafe impl Sync for PlaydateAPI {}
58unsafe impl Send for PlaydateAPI {}
59
60impl PlaydateAPI {
61 fn new(playdate: *mut sys::PlaydateAPI) -> Self {
62 let playdate_ref = unsafe { &*playdate };
63 Self {
64 raw_api: playdate,
65 system: system::PlaydateSystem::new(playdate_ref.system),
66 file: fs::PlaydateFileSystem::new(playdate_ref.file),
67 graphics: graphics::PlaydateGraphics::new(playdate_ref.graphics),
68 sprite: sprite::PlaydateSprite::new(playdate_ref.sprite),
69 display: display::PlaydateDisplay::new(playdate_ref.display),
70 sound: sound::PlaydateSound::new(playdate_ref.sound),
71 scoreboards: scoreboards::PlaydateScoreboards::new(playdate_ref.scoreboards),
72 lua: lua::Lua::new(playdate_ref.lua),
73 }
74 }
75
76 pub fn get_raw_api(&self) -> *mut sys::PlaydateAPI {
78 self.raw_api
79 }
80}
81
82pub static PLAYDATE: Playdate = Playdate {
83 _p: UnsafeCell::new(None),
84};
85
86pub struct Playdate {
87 _p: UnsafeCell<Option<PlaydateAPI>>,
88}
89
90unsafe impl Sync for Playdate {}
91unsafe impl Send for Playdate {}
92
93impl Deref for Playdate {
94 type Target = PlaydateAPI;
95
96 fn deref(&self) -> &Self::Target {
97 unsafe { (*self._p.get()).as_ref().unwrap() }
98 }
99}
100
101pub trait App: Sized + 'static {
102 fn new() -> Self;
104
105 fn get() -> &'static Self {
107 unsafe { &*(APP.unwrap() as *const Self) }
108 }
109
110 unsafe fn get_mut() -> &'static mut Self {
114 unsafe { &mut *(APP.unwrap() as *mut Self) }
115 }
116
117 fn init(&mut self) {}
119
120 fn update(&mut self, _delta: f32) {}
124
125 fn handle_event(&mut self, _event: system::SystemEvent, _arg: u32) {}
127}
128
129static mut APP: Option<*mut ()> = None;
130
131unsafe extern "C" fn update<T: App>(_: *mut core::ffi::c_void) -> i32 {
132 let app = T::get_mut();
133 let delta_time = {
135 static mut LAST_FRAME_TIME: Option<usize> = None;
136 let current_time = PLAYDATE.system.get_current_time_milliseconds();
137 let delta = if let Some(last_frame_time) = LAST_FRAME_TIME {
138 (current_time - last_frame_time) as f32 / 1000.0
139 } else {
140 0.0
141 };
142 LAST_FRAME_TIME = Some(current_time);
143 delta
144 };
145 app.update(delta_time);
147 1
148}
149
150fn start_playdate_app<T: App>(pd: *mut sys::PlaydateAPI) {
151 unsafe {
153 *PLAYDATE._p.get() = Some(PlaydateAPI::new(pd));
154 }
155 let app = Box::leak(Box::new(T::new()));
157 unsafe {
158 APP = Some(app as *mut T as *mut ());
159 }
160 app.init();
162 PLAYDATE.system.set_update_callback(Some(update::<T>));
163}
164
165#[doc(hidden)]
166pub fn __playdate_handle_event<T: App>(
167 pd: *mut ::core::ffi::c_void,
168 event: system::SystemEvent,
169 arg: u32,
170) {
171 let pd = pd as *mut sys::PlaydateAPI;
172 if event == system::SystemEvent::Init {
173 start_playdate_app::<T>(pd);
174 }
175 unsafe { T::get_mut().handle_event(event, arg) };
176}
177
178#[doc(hidden)]
179pub fn __playdate_handle_panic(info: &core::panic::PanicInfo) -> ! {
180 PLAYDATE.system.error(format!("{}", info));
181 unreachable!()
182}
183
184#[macro_export]
185macro_rules! register_playdate_app {
186 ($app: ident) => {
187 mod __playdate_api {
188 #[no_mangle]
189 unsafe extern "C" fn eventHandler(
190 pd: *mut ::core::ffi::c_void,
191 event: $crate::system::SystemEvent,
192 arg: u32,
193 ) {
194 $crate::__playdate_handle_event::<super::$app>(pd, event, arg);
195 }
196 }
197
198 #[cfg(all(target_arch = "arm", target_os = "none"))]
199 #[panic_handler]
200 #[doc(hidden)]
201 fn __panic_handler(info: &core::panic::PanicInfo) -> ! {
202 $crate::__playdate_handle_panic(info);
203 }
204
205 #[cfg(all(target_arch = "arm", target_os = "none"))]
206 #[no_mangle]
207 pub extern "C" fn _sbrk() {}
208
209 #[cfg(all(target_arch = "arm", target_os = "none"))]
210 #[no_mangle]
211 extern "C" fn _exit() {}
212
213 #[cfg(all(target_arch = "arm", target_os = "none"))]
214 #[no_mangle]
215 extern "C" fn _kill() {}
216
217 #[cfg(all(target_arch = "arm", target_os = "none"))]
218 #[no_mangle]
219 extern "C" fn _getpid() {}
220
221 #[cfg(all(target_arch = "arm", target_os = "none"))]
222 #[no_mangle]
223 extern "C" fn __exidx_start() {
224 unimplemented!();
225 }
226
227 #[cfg(all(target_arch = "arm", target_os = "none"))]
228 #[no_mangle]
229 extern "C" fn __exidx_end() {
230 unimplemented!();
231 }
232 };
233}