diff --git a/api/gfx/src/bitmap/bitmap.rs b/api/gfx/src/bitmap/bitmap.rs index 731be397..34ff148b 100644 --- a/api/gfx/src/bitmap/bitmap.rs +++ b/api/gfx/src/bitmap/bitmap.rs @@ -86,7 +86,7 @@ impl From<*mut LCDBitmap> for Bitmap Bitmap { /// Convert this bitmap into the same bitmap that will not be freed on drop. - /// That means that only C-part of the bitmap will be freed. + /// That means that only C-part of the bitmap will __not__ be freed. /// /// __Safety is guaranteed by the caller.__ pub fn into_shared(mut self) -> Bitmap { diff --git a/api/gfx/src/video.rs b/api/gfx/src/video.rs index 38196fd5..7eb34185 100644 --- a/api/gfx/src/video.rs +++ b/api/gfx/src/video.rs @@ -83,6 +83,19 @@ impl Drop for VideoPlayer { } +impl VideoPlayer { + /// Convert this video player into the same but that will not be freed on drop. + /// That means that only C-part of the player will __not__ be freed. + /// + /// __Safety is guaranteed by the caller.__ + pub fn into_shared(mut self) -> VideoPlayer { + let res = VideoPlayer(self.0, self.1); + self.0 = core::ptr::null_mut(); + res + } +} + + impl VideoPlayer { /// Opens the `pdv` file at path and returns a new video player object for rendering its frames. /// @@ -123,7 +136,7 @@ impl VideoPlayer { #[doc(alias = "sys::ffi::playdate_video::setContext")] pub fn set_context<'a, 'b: 'a>(&'a self, bitmap: &'b impl AnyBitmap) -> Result<(), Error> { let f = self.1.set_context(); - if unsafe { f(self.0, bitmap.as_raw()) } == 0 { + if unsafe { f(self.0, bitmap.as_raw()) } != 0 { Ok(()) } else { Err(self.get_error().unwrap_or(Error::Unknown)) @@ -163,7 +176,7 @@ impl VideoPlayer { #[doc(alias = "sys::ffi::playdate_video::renderFrame")] pub fn render_frame(&self, n: c_int) -> Result<(), Error> { let f = self.1.render_frame(); - if unsafe { f(self.0, n) } == 0 { + if unsafe { f(self.0, n) } != 0 { Ok(()) } else { Err(self.get_error().unwrap_or(Error::Unknown)) @@ -255,11 +268,11 @@ impl VideoPlayer { #[derive(Debug, Clone, Default)] pub struct VideoPlayerOutInfo { - width: c_int, - height: c_int, - frame_rate: c_float, - frame_count: c_int, - current_frame: c_int, + pub width: c_int, + pub height: c_int, + pub frame_rate: c_float, + pub frame_count: c_int, + pub current_frame: c_int, } diff --git a/api/playdate/Cargo.toml b/api/playdate/Cargo.toml index 539375a9..b6de4ee2 100644 --- a/api/playdate/Cargo.toml +++ b/api/playdate/Cargo.toml @@ -195,19 +195,25 @@ crate-type = ["dylib", "staticlib"] path = "examples/hello-world.rs" required-features = ["entry-point"] -# TODO: REMOVE ME! [[example]] name = "minimal" crate-type = ["dylib", "staticlib"] path = "examples/minimal.rs" required-features = ["entry-point"] +[[example]] +name = "video" +crate-type = ["dylib", "staticlib"] +path = "examples/video.rs" +required-features = ["entry-point"] + [package.metadata.playdate] bundle-id = "rs.playdate.core" [package.metadata.playdate.dev-assets] "examples/ferris.png" = true "examples/" = "${PLAYDATE_SDK_PATH}/Examples/Level 1-1/Source/sfx/main_theme.wav" +"examples/video.pdv" = "${PLAYDATE_SDK_PATH}/Disk/System/Setup.pdx/videos/outro.pdv" [package.metadata.docs.rs] diff --git a/api/playdate/examples/video.rs b/api/playdate/examples/video.rs new file mode 100644 index 00000000..a4a2c0fb --- /dev/null +++ b/api/playdate/examples/video.rs @@ -0,0 +1,76 @@ +#![no_std] +extern crate alloc; + +#[macro_use] +extern crate playdate as pd; + +use core::ffi::*; +use core::ptr::NonNull; +use pd::ext::PlaydateAPIExt; +use pd::sys::ffi::PlaydateAPI; +use pd::graphics::video::VideoPlayer; + +use fs::Path; +use pd::graphics::*; +use pd::system::prelude::*; + + +const VIDEO_PATH: &Path = "examples/video.pdv"; + + +/// Game state +struct State { + player: VideoPlayer, + + // Current frame + current: c_int, + // Number of frames + length: c_int, +} + + +/// Entry point +#[no_mangle] +fn event_handler(api: NonNull, event: SystemEvent, _sim_key_code: u32) -> bool { + // Ignore any other events, just for this minimalistic example + if !matches!(event, SystemEvent::Init) { + return true; + } + + // Set FPS + api.display().set_refresh_rate(20.0); + + // Create video player + let player = api.graphics().video().load(VIDEO_PATH).unwrap(); + // Set draw-target to the screen + player.use_screen_context(); + + // Register update handler + api.system().set_update_callback_boxed( + |state| { + // Draw current frame of the player + state.player.render_frame(state.current).unwrap(); + + // Advance to the next frame + state.current += 1; + if state.current >= state.length { + state.current = 0; + } + + // Draw FPS on-top of the player's render + System::Default().draw_fps(0, 0); + + // Continue + true + }, + State { length: player.info().frame_count, + current: 0, + player, }, + ); + + true +} + + +// Needed for debug build, absolutely optional +ll_symbols!(); diff --git a/api/playdate/src/lib.rs b/api/playdate/src/lib.rs index e4785d3f..7814fc7f 100644 --- a/api/playdate/src/lib.rs +++ b/api/playdate/src/lib.rs @@ -39,12 +39,21 @@ pub mod ext { use core::ptr::NonNull; + /// Main Playdate API entry point. pub trait PlaydateAPIExt { + /// Playdate System API. fn system(&self) -> system::System; + // fn file() -> file::File; + + /// Playdate Graphics API. fn graphics(&self) -> graphics::Graphics; + // fn sprite() -> sprite::Sprite; + + /// Playdate Display API. fn display(&self) -> display::Display; + // fn sound() -> sound::Sound; // fn lua() -> lua::Lua; // fn json() -> json::Json;