initial commit

Signed-off-by: Jessie Williams <quorawings@gmail.com>
This commit is contained in:
Jessie Williams 2022-03-05 16:44:55 -05:00
commit 884f0125bc
12 changed files with 745 additions and 0 deletions

15
.cargo/config.toml Normal file
View File

@ -0,0 +1,15 @@
[build]
target = "wasm32-unknown-unknown"
[target.wasm32-unknown-unknown]
rustflags = [
# Import memory from WASM-4
"-C", "link-arg=--import-memory",
"-C", "link-arg=--initial-memory=65536",
"-C", "link-arg=--max-memory=65536",
# Temporary workaround for #255 issue.
# Reserve 8192 bytes of Rust stack space, offset from 6560.
# Bump this value, 16-byte aligned, if the framebuffer gets corrupted.
"-C", "link-arg=-zstack-size=14752",
]

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
target
dist
.DS_Store

48
Cargo.lock generated Normal file
View File

@ -0,0 +1,48 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "buddy-alloc"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ff9f338986406db85e2b5deb40a9255b796ca03a194c7457403d215173f3fd5"
[[package]]
name = "cart"
version = "0.1.0"
dependencies = [
"buddy-alloc",
"fastrand",
"lazy_static",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "fastrand"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [
"instant",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"

21
Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
name = "cart"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
crate-type = ["cdylib"]
[dependencies]
buddy-alloc = { version = "0.4.1", optional = true }
fastrand = "1.6.0"
lazy_static = "1.4.0"
[profile.release]
opt-level = "z"
lto = true
[features]
# use `--no-default-features` or comment out next line to disable allocator
default = ["buddy-alloc"]

26
README.md Normal file
View File

@ -0,0 +1,26 @@
# akesi
A game written in Rust for the [WASM-4](https://wasm4.org) fantasy console.
## Building
Build the cart by running:
```shell
cargo build --release
```
Then run it with:
```shell
w4 run target/wasm32-unknown-unknown/release/cart.wasm
```
For more info about setting up WASM-4, see the [quickstart guide](https://wasm4.org/docs/getting-started/setup?code-lang=rust#quickstart).
## Links
- [Documentation](https://wasm4.org/docs): Learn more about WASM-4.
- [Snake Tutorial](https://wasm4.org/docs/tutorials/snake/goal): Learn how to build a complete game
with a step-by-step tutorial.
- [GitHub](https://github.com/aduros/wasm4): Submit an issue or PR. Contributions are welcome!

BIN
sprites/akesi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

16
src/alloc.rs Normal file
View File

@ -0,0 +1,16 @@
use buddy_alloc::{BuddyAllocParam, FastAllocParam, NonThreadsafeAlloc};
// These values can be tuned
const FAST_HEAP_SIZE: usize = 4 * 1024; // 4 KB
const HEAP_SIZE: usize = 16 * 1024; // 16 KB
const LEAF_SIZE: usize = 16;
static mut FAST_HEAP: [u8; FAST_HEAP_SIZE] = [0u8; FAST_HEAP_SIZE];
static mut HEAP: [u8; HEAP_SIZE] = [0u8; HEAP_SIZE];
#[global_allocator]
static ALLOC: NonThreadsafeAlloc = unsafe {
let fast_param = FastAllocParam::new(FAST_HEAP.as_ptr(), FAST_HEAP_SIZE);
let buddy_param = BuddyAllocParam::new(HEAP.as_ptr(), HEAP_SIZE, LEAF_SIZE);
NonThreadsafeAlloc::new(fast_param, buddy_param)
};

217
src/lib.rs Normal file
View File

@ -0,0 +1,217 @@
#[cfg(feature = "buddy-alloc")]
mod alloc;
mod palette;
mod snake;
mod sprites;
mod wasm4;
use crate::snake::{Point, Snake};
use fastrand::Rng;
use lazy_static::lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref SNAKE_GAME: Mutex<Game> = Mutex::new(Game::new());
}
enum State {
Title,
Playing,
Dead,
}
pub struct Game {
state: State,
rng: Rng,
snake: Snake,
frame_count: u32,
prev_gamepad: u8,
fruit: Point,
}
impl Game {
pub fn new() -> Self {
let rng = Rng::with_seed(235);
Self {
state: State::Title,
snake: Snake::new(),
frame_count: 0,
prev_gamepad: 0,
fruit: Point {
x: rng.i32(0..20),
y: rng.i32(0..20),
},
rng,
}
}
pub fn reset(&mut self) {
self.snake = Snake::new();
self.state = State::Playing;
}
pub fn game_input(&mut self) {
let gamepad = unsafe { *wasm4::GAMEPAD1 };
let just_pressed = gamepad & (gamepad ^ self.prev_gamepad);
if just_pressed & wasm4::BUTTON_UP != 0 {
self.snake.up();
}
if just_pressed & wasm4::BUTTON_DOWN != 0 {
self.snake.down();
}
if just_pressed & wasm4::BUTTON_LEFT != 0 {
self.snake.left();
}
if just_pressed & wasm4::BUTTON_RIGHT != 0 {
self.snake.right();
}
self.prev_gamepad = gamepad;
}
pub fn update(&mut self) {
self.frame_count += 1;
match self.state {
State::Title => self.show_title(),
State::Playing => self.step_game(),
State::Dead => self.show_score(),
}
}
pub fn show_title(&mut self) {
wasm4::text("akesi", 48, 8);
wasm4::text("Press x", 48, 128);
wasm4::text("From Within", 32, 144);
palette::set_draw_color(0x30);
wasm4::blit(
&sprites::AKESI,
48,
24,
sprites::AKESI_WIDTH,
sprites::AKESI_HEIGHT,
wasm4::BLIT_1BPP,
);
let gamepad = unsafe { *wasm4::GAMEPAD1 };
let just_pressed = gamepad & (gamepad ^ self.prev_gamepad);
if just_pressed & wasm4::BUTTON_1 != 0 {
wasm4::tone(0 | (1000 << 16), 4 | (20 << 8), 80, wasm4::TONE_TRIANGLE);
self.reset();
}
if just_pressed & wasm4::BUTTON_UP != 0 {
palette::en4();
}
if just_pressed & wasm4::BUTTON_DOWN != 0 {
palette::moonlight();
}
if just_pressed & wasm4::BUTTON_LEFT != 0 {
palette::cafe_nouveau();
}
if just_pressed & wasm4::BUTTON_RIGHT != 0 {
palette::amanita();
}
self.prev_gamepad = gamepad;
}
pub fn show_score(&mut self) {
wasm4::text("Score", 48, 48);
wasm4::text("Press x to\nplay again", 36, 128);
let mut x = 16;
let mut y = 64;
for _ in 0..self.snake.body.len() - 3 {
palette::set_draw_color(0x4320);
wasm4::blit(&sprites::FRUIT, x, y, 8, 8, wasm4::BLIT_2BPP);
x += 8;
if x > 140 {
x = 16;
y += 8;
}
}
let gamepad = unsafe { *wasm4::GAMEPAD1 };
let just_pressed = gamepad & (gamepad ^ self.prev_gamepad);
if just_pressed & wasm4::BUTTON_1 != 0 {
wasm4::tone(0 | (1000 << 16), 4 | (20 << 8), 80, wasm4::TONE_TRIANGLE);
self.reset();
}
self.prev_gamepad = gamepad;
}
pub fn step_game(&mut self) {
self.game_input();
if self.snake.is_dead() {
wasm4::tone(
460 | (140 << 16),
94 | (48 << 8) | (62 << 16),
80,
wasm4::TONE_TRIANGLE,
);
self.state = State::Dead;
}
let speed = match self.snake.body.len() {
3..=8 => 18,
9..=15 => 14,
16..=24 => 12,
25..=32 => 10,
_ => 5,
};
if self.frame_count % speed == 0 {
let dropped_pos = self.snake.update();
if self.snake.body[0] == self.fruit {
if let Some(last_pos) = dropped_pos {
self.snake.body.push(last_pos);
}
self.fruit.x = self.rng.i32(0..20);
self.fruit.y = self.rng.i32(0..20);
while self.snake.inside(&self.fruit) {
self.fruit.x = self.rng.i32(0..20);
self.fruit.y = self.rng.i32(0..20);
}
wasm4::tone(140 | (250 << 16), 12 | (6 << 8), 80, wasm4::TONE_TRIANGLE);
}
}
self.snake.draw();
palette::set_draw_color(0x4320);
wasm4::blit(
&sprites::FRUIT,
self.fruit.x * 8,
self.fruit.y * 8,
8,
8,
wasm4::BLIT_2BPP,
);
}
}
#[no_mangle]
fn start() {
palette::moonlight();
}
#[no_mangle]
fn update() {
palette::set_draw_color(0x2);
SNAKE_GAME.lock().expect("game_state").update();
}

31
src/palette.rs Normal file
View File

@ -0,0 +1,31 @@
use crate::wasm4;
pub fn set_draw_color(idx: u16) {
unsafe { *wasm4::DRAW_COLORS = idx.into() }
}
pub fn set_palette(palette: [u32; 4]) {
unsafe {
*wasm4::PALETTE = palette;
}
}
pub fn moonlight() {
set_palette([0xf3eaab, 0x86a0b7, 0x3d476a, 0x19152a]);
}
pub fn en4() {
set_palette([0xfbf7f3, 0xe5b083, 0x426e5d, 0x20283d]);
}
pub fn amanita() {
set_palette([0xf1eee3, 0xccc2b8, 0xb34750, 0x4d0f40]);
}
pub fn cafe_nouveau() {
set_palette([0xf8e6d0, 0xc08e70, 0x683a34, 0x200816]);
}
/*pub fn coldfire() {
set_palette([0x46425e, 0x5b768d, 0xd17c7c, 0xf6c6a8]);
}*/

89
src/snake.rs Normal file
View File

@ -0,0 +1,89 @@
use crate::{palette::set_draw_color, wasm4};
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Point {
pub x: i32,
pub y: i32,
}
pub struct Snake {
pub body: Vec<Point>,
pub direction: Point,
}
impl Snake {
pub fn new() -> Self {
Self {
body: vec![
Point { x: 2, y: 0 },
Point { x: 1, y: 0 },
Point { x: 0, y: 0 },
],
direction: Point { x: 1, y: 0 },
}
}
pub fn is_dead(&self) -> bool {
self.inside(&self.body[0])
}
pub fn inside(&self, pt: &Point) -> bool {
self.body
.iter()
.skip(1)
.any(|body_section| body_section == pt)
}
pub fn down(&mut self) {
if self.direction.y == 0 {
self.direction = Point { x: 0, y: 1 };
}
}
pub fn up(&mut self) {
if self.direction.y == 0 {
self.direction = Point { x: 0, y: -1 };
}
}
pub fn left(&mut self) {
if self.direction.x == 0 {
self.direction = Point { x: -1, y: 0 };
}
}
pub fn right(&mut self) {
if self.direction.x == 0 {
self.direction = Point { x: 1, y: 0 };
}
}
pub fn update(&mut self) -> Option<Point> {
self.body.insert(
0,
Point {
x: (self.body[0].x + self.direction.x) % 20,
y: (self.body[0].y + self.direction.y) % 20,
},
);
if self.body[0].x < 0 {
self.body[0].x = 19;
}
if self.body[0].y < 0 {
self.body[0].y = 19;
}
self.body.pop()
}
pub fn draw(&self) {
set_draw_color(0x43);
for &Point { x, y } in self.body.iter() {
wasm4::rect(x * 8, y * 8, 8, 8);
}
set_draw_color(0x4);
wasm4::rect(self.body[0].x * 8, self.body[0].y * 8, 8, 8);
}
}

57
src/sprites.rs Normal file
View File

@ -0,0 +1,57 @@
pub const FRUIT: [u8; 16] = [
0x00, 0xa0, 0x02, 0x00, 0x0e, 0xf0, 0x36, 0x5c, 0xd6, 0x57, 0xd5, 0x57, 0x35, 0x5c, 0x0f, 0xf0,
];
// akesi
pub const AKESI_WIDTH: u32 = 64;
pub const AKESI_HEIGHT: u32 = 96;
pub const AKESI: [u8; 768] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x07, 0x80, 0x00,
0x00, 0x1f, 0xe0, 0x00, 0x00, 0x0f, 0xc0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x1f, 0xe0, 0x00,
0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00,
0x00, 0x3f, 0xf0, 0x00, 0x00, 0x3f, 0xf0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x3f, 0xf0, 0x00,
0x00, 0x0f, 0xc0, 0x00, 0x00, 0x1f, 0xe0, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x0f, 0xc0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfe, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xe3, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc1, 0xff, 0xf8, 0x00, 0x00,
0x00, 0x00, 0xff, 0xc0, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x80, 0x1f, 0xfc, 0x1f, 0x80,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00,
0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00, 0x00,
0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00, 0x00,
0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x01, 0xfe, 0x00, 0x00,
0x00, 0x07, 0xf8, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x03, 0xfe, 0x00, 0x00,
0x00, 0x07, 0xf8, 0x00, 0x03, 0xfe, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x03, 0xfc, 0x00, 0x00,
0x00, 0x07, 0xf8, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x03, 0xfc, 0x00, 0x00,
0x00, 0x07, 0xf8, 0x00, 0x07, 0xfc, 0x03, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0x01, 0xff, 0xe0, 0x00, 0x00,
0x00, 0x01, 0xff, 0x87, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0xff, 0x8f, 0xff, 0x80, 0x00, 0x00,
0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];

222
src/wasm4.rs Normal file
View File

@ -0,0 +1,222 @@
//
// WASM-4: https://wasm4.org/docs
#![allow(unused)]
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Platform Constants │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
pub const SCREEN_SIZE: u32 = 160;
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Memory Addresses │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
pub const PALETTE: *mut [u32; 4] = 0x04 as *mut [u32; 4];
pub const DRAW_COLORS: *mut u16 = 0x14 as *mut u16;
pub const GAMEPAD1: *const u8 = 0x16 as *const u8;
pub const GAMEPAD2: *const u8 = 0x17 as *const u8;
pub const GAMEPAD3: *const u8 = 0x18 as *const u8;
pub const GAMEPAD4: *const u8 = 0x19 as *const u8;
pub const MOUSE_X: *const i16 = 0x1a as *const i16;
pub const MOUSE_Y: *const i16 = 0x1c as *const i16;
pub const MOUSE_BUTTONS: *const u8 = 0x1e as *const u8;
pub const SYSTEM_FLAGS: *mut u8 = 0x1f as *mut u8;
pub const FRAMEBUFFER: *mut [u8; 6400] = 0xa0 as *mut [u8; 6400];
pub const BUTTON_1: u8 = 1;
pub const BUTTON_2: u8 = 2;
pub const BUTTON_LEFT: u8 = 16;
pub const BUTTON_RIGHT: u8 = 32;
pub const BUTTON_UP: u8 = 64;
pub const BUTTON_DOWN: u8 = 128;
pub const MOUSE_LEFT: u8 = 1;
pub const MOUSE_RIGHT: u8 = 2;
pub const MOUSE_MIDDLE: u8 = 4;
pub const SYSTEM_PRESERVE_FRAMEBUFFER: u8 = 1;
pub const SYSTEM_HIDE_GAMEPAD_OVERLAY: u8 = 2;
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Drawing Functions │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
/// Copies pixels to the framebuffer.
pub fn blit(sprite: &[u8], x: i32, y: i32, width: u32, height: u32, flags: u32) {
unsafe { extern_blit(sprite.as_ptr(), x, y, width, height, flags) }
}
extern "C" {
#[link_name = "blit"]
fn extern_blit(sprite: *const u8, x: i32, y: i32, width: u32, height: u32, flags: u32);
}
/// Copies a subregion within a larger sprite atlas to the framebuffer.
#[allow(clippy::too_many_arguments)]
pub fn blit_sub(
sprite: &[u8],
x: i32,
y: i32,
width: u32,
height: u32,
src_x: u32,
src_y: u32,
stride: u32,
flags: u32,
) {
unsafe {
extern_blit_sub(
sprite.as_ptr(),
x,
y,
width,
height,
src_x,
src_y,
stride,
flags,
)
}
}
extern "C" {
#[link_name = "blitSub"]
fn extern_blit_sub(
sprite: *const u8,
x: i32,
y: i32,
width: u32,
height: u32,
src_x: u32,
src_y: u32,
stride: u32,
flags: u32,
);
}
pub const BLIT_2BPP: u32 = 1;
pub const BLIT_1BPP: u32 = 0;
pub const BLIT_FLIP_X: u32 = 2;
pub const BLIT_FLIP_Y: u32 = 4;
pub const BLIT_ROTATE: u32 = 8;
/// Draws a line between two points.
pub fn line(x1: i32, y1: i32, x2: i32, y2: i32) {
unsafe { extern_line(x1, y1, x2, y2) }
}
extern "C" {
#[link_name = "line"]
fn extern_line(x1: i32, y1: i32, x2: i32, y2: i32);
}
/// Draws an oval (or circle).
pub fn oval(x: i32, y: i32, width: u32, height: u32) {
unsafe { extern_oval(x, y, width, height) }
}
extern "C" {
#[link_name = "oval"]
fn extern_oval(x: i32, y: i32, width: u32, height: u32);
}
/// Draws a rectangle.
pub fn rect(x: i32, y: i32, width: u32, height: u32) {
unsafe { extern_rect(x, y, width, height) }
}
extern "C" {
#[link_name = "rect"]
fn extern_rect(x: i32, y: i32, width: u32, height: u32);
}
/// Draws text using the built-in system font.
pub fn text<T: AsRef<str>>(text: T, x: i32, y: i32) {
let text_ref = text.as_ref();
unsafe { extern_text(text_ref.as_ptr(), text_ref.len(), x, y) }
}
extern "C" {
#[link_name = "textUtf8"]
fn extern_text(text: *const u8, length: usize, x: i32, y: i32);
}
/// Draws a vertical line
pub fn vline(x: i32, y: i32, len: u32) {
unsafe {
extern_vline(x, y, len);
}
}
extern "C" {
#[link_name = "vline"]
fn extern_vline(x: i32, y: i32, len: u32);
}
/// Draws a horizontal line
pub fn hline(x: i32, y: i32, len: u32) {
unsafe {
extern_hline(x, y, len);
}
}
extern "C" {
#[link_name = "hline"]
fn extern_hline(x: i32, y: i32, len: u32);
}
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Sound Functions │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
/// Plays a sound tone.
pub fn tone(frequency: u32, duration: u32, volume: u32, flags: u32) {
unsafe { extern_tone(frequency, duration, volume, flags) }
}
extern "C" {
#[link_name = "tone"]
fn extern_tone(frequency: u32, duration: u32, volume: u32, flags: u32);
}
pub const TONE_PULSE1: u32 = 0;
pub const TONE_PULSE2: u32 = 1;
pub const TONE_TRIANGLE: u32 = 2;
pub const TONE_NOISE: u32 = 3;
pub const TONE_MODE1: u32 = 0;
pub const TONE_MODE2: u32 = 4;
pub const TONE_MODE3: u32 = 8;
pub const TONE_MODE4: u32 = 12;
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Storage Functions │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
extern "C" {
/// Reads up to `size` bytes from persistent storage into the pointer `dest`.
pub fn diskr(dest: *mut u8, size: u32) -> u32;
/// Writes up to `size` bytes from the pointer `src` into persistent storage.
pub fn diskw(src: *const u8, size: u32) -> u32;
}
// ┌───────────────────────────────────────────────────────────────────────────┐
// │ │
// │ Other Functions │
// │ │
// └───────────────────────────────────────────────────────────────────────────┘
/// Prints a message to the debug console.
pub fn trace<T: AsRef<str>>(text: T) {
let text_ref = text.as_ref();
unsafe { extern_trace(text_ref.as_ptr(), text_ref.len()) }
}
extern "C" {
#[link_name = "traceUtf8"]
fn extern_trace(trace: *const u8, length: usize);
}