Skip to content

Commit

Permalink
add minimalistic video example,
Browse files Browse the repository at this point in the history
fix error handling and docs
  • Loading branch information
boozook committed Sep 26, 2023
1 parent baf0a13 commit 716d966
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 9 deletions.
2 changes: 1 addition & 1 deletion api/gfx/src/bitmap/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl<Api: api::Api + Default, const FOD: bool> From<*mut LCDBitmap> for Bitmap<A

impl<Api: api::Api + Copy> Bitmap<Api, true> {
/// 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<Api, false> {
Expand Down
27 changes: 20 additions & 7 deletions api/gfx/src/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ impl<Api: api::Api, const FOD: bool> Drop for VideoPlayer<Api, FOD> {
}


impl<Api: api::Api + Copy> VideoPlayer<Api, true> {
/// 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<Api, false> {
let res = VideoPlayer(self.0, self.1);
self.0 = core::ptr::null_mut();
res
}
}


impl<Api: api::Api> VideoPlayer<Api, true> {
/// Opens the `pdv` file at path and returns a new video player object for rendering its frames.
///
Expand Down Expand Up @@ -123,7 +136,7 @@ impl<Api: api::Api, const FOD: bool> VideoPlayer<Api, FOD> {
#[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))
Expand Down Expand Up @@ -163,7 +176,7 @@ impl<Api: api::Api, const FOD: bool> VideoPlayer<Api, FOD> {
#[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))
Expand Down Expand Up @@ -255,11 +268,11 @@ impl<Api: api::Api, const FOD: bool> VideoPlayer<Api, FOD> {

#[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,
}


Expand Down
8 changes: 7 additions & 1 deletion api/playdate/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
76 changes: 76 additions & 0 deletions api/playdate/examples/video.rs
Original file line number Diff line number Diff line change
@@ -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<video::api::Cache, true>,

// Current frame
current: c_int,
// Number of frames
length: c_int,
}


/// Entry point
#[no_mangle]
fn event_handler(api: NonNull<PlaydateAPI>, 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!();
9 changes: 9 additions & 0 deletions api/playdate/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<system::api::Cache>;

// fn file() -> file::File;

/// Playdate Graphics API.
fn graphics(&self) -> graphics::Graphics<graphics::api::Cache>;

// fn sprite() -> sprite::Sprite;

/// Playdate Display API.
fn display(&self) -> display::Display<display::api::Cache>;

// fn sound() -> sound::Sound;
// fn lua() -> lua::Lua;
// fn json() -> json::Json;
Expand Down

0 comments on commit 716d966

Please sign in to comment.