Skip to content

Commit

Permalink
add text api, improve sprite api, add missed crates to cargo-playdate…
Browse files Browse the repository at this point in the history
… for `new/init` cmd.
  • Loading branch information
boozook committed Sep 20, 2023
1 parent 1f1bc30 commit c590a6b
Show file tree
Hide file tree
Showing 17 changed files with 718 additions and 106 deletions.
22 changes: 11 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion api/gfx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "playdate-graphics"
version = "0.1.4"
version = "0.2.0"
edition = "2021"

readme = "README.md"
Expand Down Expand Up @@ -61,6 +61,11 @@ name = "bitmap"
crate-type = ["dylib", "staticlib"]
path = "examples/bitmap.rs"

[[example]]
name = "font"
crate-type = ["dylib", "staticlib"]
path = "examples/font.rs"

[package.metadata.playdate]
bundle-id = "rs.playdate.menu"

Expand Down
4 changes: 2 additions & 2 deletions api/gfx/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

```bash
# Simulator:
cargo playdate run -p=playdate-graphics --example=bitmap --features=bindgen-runtime,bindings-derive-debug
cargo playdate run -p=playdate-graphics --example=bitmap --features=bindgen-runtime
# Device:
cargo playdate run -p=playdate-graphics --example=bitmap --features=bindgen-runtime,bindings-derive-debug --device
cargo playdate run -p=playdate-graphics --example=bitmap --features=bindgen-runtime --device
```

More information how to use [cargo-playdate][] in help: `cargo playdate --help`.
Expand Down
6 changes: 5 additions & 1 deletion api/gfx/examples/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use alloc::boxed::Box;
use sys::ffi::*;
use gfx::color::*;
use gfx::bitmap;
use gfx::text;
use gfx::text::StringEncodingExt;


const CENTER_X: u32 = LCD_COLUMNS / 2;
Expand All @@ -34,17 +36,19 @@ impl State {
/// Updates the state
fn update(&mut self) -> Option<()> {
const LABEL_DEF: &str = "Just rotating bitmap:\0";
const ENC: text::StringEncoding = text::StringEncoding::ASCII;

let cstr = CStr::from_bytes_with_nul(LABEL_DEF.as_bytes()).unwrap();

gfx::clear(Color::WHITE);

// get width (screen-size) of text
let text_width = gfx::text::get_text_width_cstr(cstr, None, 0);
let text_width = gfx::text::get_text_width_cstr(cstr, ENC, None, 0);

// render text
gfx::text::draw_text_cstr(
cstr,
ENC,
CENTER_X as c_int - text_width / 2,
TEXT_HEIGHT.try_into().unwrap(),
);
Expand Down
168 changes: 168 additions & 0 deletions api/gfx/examples/font.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#![no_std]
extern crate alloc;

#[macro_use]
extern crate sys;
extern crate playdate_graphics as gfx;

use core::ffi::*;
use alloc::boxed::Box;

use sys::ffi::*;
use gfx::color::*;

use gfx::bitmap;
use gfx::bitmap::{BitmapDrawMode, BitmapFlip, BitmapFlipExt};

use gfx::text;
use gfx::text::StringEncodingExt;


const CENTER_X: u32 = LCD_COLUMNS / 2;
const CENTER_Y: u32 = LCD_ROWS / 2;
const TEXT_HEIGHT: u32 = 16;
const FONT_PATH: &'static str = "/System/Fonts/Asheville-Sans-14-Bold.pft";


/// App state
struct State {
rotation: c_float,
image: Option<bitmap::Bitmap>,
font: Option<text::Font>,
}

impl State {
const fn new() -> Self {
Self { rotation: 0.,
image: None,
font: None }
}


/// Updates the state
fn update(&mut self) -> Option<()> {
const LABEL_DEF: &str = "Just rotating bitmap:\0";
const ENC: text::StringEncoding = text::StringEncoding::ASCII;

let cstr = CStr::from_bytes_with_nul(LABEL_DEF.as_bytes()).unwrap();

gfx::clear(Color::WHITE);

// get width (screen-size) of text
let text_width = gfx::text::get_text_width_cstr(cstr, ENC, self.font.as_ref(), 0);

// set font
gfx::text::set_font(self.font.as_ref().unwrap());

// render text
gfx::text::draw_text_cstr(
cstr,
ENC,
CENTER_X as c_int - text_width / 2,
TEXT_HEIGHT.try_into().unwrap(),
);

// draw bitmap
if let Some(image) = self.image.as_ref() {
image.draw_rotated(CENTER_X as _, CENTER_Y as _, self.rotation, 0.5, 0.5, 1.0, 1.0);
}

self.rotation += 1.0;
if self.rotation > 360.0 {
self.rotation = 0.0;
}

Some(())
}


/// Event handler
fn event(&'static mut self, event: PDSystemEvent) -> Option<()> {
match event {
// initial setup
PDSystemEvent::kEventInit => {
unsafe { (*(*sys::API).display).setRefreshRate?(60.0) };

let font = text::load_font(FONT_PATH).unwrap();
let bitmap = bitmap::Bitmap::new(100, 100, color::Color::BLACK).unwrap();

// Indexes of symbols in system representation:
// Note, UTF-codes is also should be acceptable.
const RUST: [u32; 4] = [82, 117, 115, 116];

let page = text::get_font_page(&font, RUST[0]).unwrap();

// draw some glyphs to bitmap:
const OFFSET: i32 = 16;
gfx::push_context(&bitmap);
for (i, code) in RUST.into_iter().enumerate() {
let mut advance = 0;
let (glyph, bitmap_ref) = text::get_page_glyph_with_bitmap(&page, code, &mut advance).unwrap();
let mut char = bitmap_ref.into_bitmap();

let kern = RUST.get(i + 1)
.map(|next| text::get_glyph_kerning(&glyph, code, *next))
.unwrap_or_default();

let w = char.bitmap_data().map(|bd| bd.width).unwrap();
let x = OFFSET + i as i32 * w;
let y = OFFSET + kern;

gfx::set_draw_mode(BitmapDrawMode::kDrawModeInverted);
char.draw(x as _, y as _, BitmapFlip::Unflipped);
}
gfx::pop_context();


self.font = font.into();
self.image = Some(bitmap);
},
_ => {},
}
Some(())
}
}


#[no_mangle]
/// Proxy event handler, calls `State::event`
pub extern "C" fn eventHandlerShim(api: *const PlaydateAPI, event: PDSystemEvent, _arg: u32) -> c_int {
static mut STATE: Option<Box<State>> = None;

match event {
PDSystemEvent::kEventInit => unsafe {
// register the API entry point
sys::API = api;

// create game state
if STATE.is_none() {
STATE = Some(Box::new(State::new()));
}
let state = STATE.as_mut().unwrap().as_mut() as *mut State;

// get `setUpdateCallback` fn
let f = (*(*api).system).setUpdateCallback.expect("setUpdateCallback");
// register update callback with user-data = our state
f(Some(on_update), state.cast());
},
_ => {},
}

if let Some(state) = unsafe { STATE.as_mut() } {
state.event(event).and(Some(0)).unwrap_or(1)
} else {
1
}
}


/// Proxy update callback, calls `State::update`
unsafe extern "C" fn on_update(state: *mut c_void) -> i32 {
let ptr: *mut State = state.cast();
let state = ptr.as_mut().expect("missed state");
state.update().and(Some(1)).unwrap_or_default()
}


// Needed for debug build
ll_symbols!();
Loading

0 comments on commit c590a6b

Please sign in to comment.