feat: mwee

This commit is contained in:
Kat Inskip 2025-08-09 21:41:21 -07:00
parent cd75ebcf4f
commit ff59f63baf
Signed by: kat
GPG key ID: 465E64DECEA8CF0F
3 changed files with 113 additions and 82 deletions

View file

@ -30,10 +30,15 @@
in flake-utils.lib.eachDefaultSystem (system: let in flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs { pkgs = import nixpkgs {
inherit system; inherit system;
overlays = [ (import rust-overlay) ]; overlays = [
(import rust-overlay)
];
}; };
pkgsCross = import nixpkgs { pkgsCross = import nixpkgs {
inherit system; inherit system;
overlays = [
(import rust-overlay)
];
config = { config = {
allowUnsupportedSystem = true; allowUnsupportedSystem = true;
#replaceStdenv = ({ pkgs }: pkgs.clangStdenvNoLibs ); #replaceStdenv = ({ pkgs }: pkgs.clangStdenvNoLibs );
@ -47,24 +52,25 @@
}; };
}; };
}; };
rustToolchainFor = rustToolchainFor =
p: p:
p.rust-bin.selectLatestNightlyWith ( p.rust-bin.selectLatestNightlyWith (
toolchain: toolchain:
toolchain.minimal.override { toolchain.minimal.override {
extensions = [ "rust-src" ]; extensions = [ "rust-analyzer" "rust-src" "clippy" "rustfmt" ];
targets = [ ]; targets = [ ];
} }
); );
rustToolchain = rustToolchainFor pkgs; rustToolchain = rustToolchainFor pkgs;
rustToolchainConfig = builtins.fromTOML (builtins.readFile ./rust-toolchain.toml );
craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchainFor; craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchainFor;
katgba-emu = pkgs.callPackage ./katgba-emu.nix { inherit katgba; }; katgba-emu = pkgs.callPackage ./katgba-emu.nix { inherit katgba; };
katgba = pkgs.callPackage ./package.nix { inherit craneLib rustToolchain rustTriple; }; katgba = pkgs.callPackage ./package.nix { inherit craneLib rustToolchain rustTriple; };
in { in {
devShells = let devShells = let
katgba-emu = import ./shell.nix { inherit self pkgs; }; katgba-emu = import ./shell.nix { inherit self pkgs rustToolchain; };
in { in {
default = katgba-emu; default = katgba-emu;
inherit katgba-emu; inherit katgba-emu;

View file

@ -1,4 +1,4 @@
{pkgs, self}: let {pkgs, self, rustToolchain}: let
inherit (pkgs) lib mkShell toilet; inherit (pkgs) lib mkShell toilet;
inherit (lib.meta) getExe; inherit (lib.meta) getExe;
in mkShell { in mkShell {
@ -7,5 +7,6 @@ in mkShell {
''; '';
nativeBuildInputs = [ nativeBuildInputs = [
self.packages.${pkgs.system}.katgba-emu self.packages.${pkgs.system}.katgba-emu
rustToolchain
]; ];
} }

View file

@ -1,101 +1,125 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use core::fmt::Write; use core::{error::Error, num::{NonZero, NonZeroI32}, ptr};
use gba::prelude::*; use gba::prelude::*;
const SCREEN_WIDTH: u16 = 240;
const SCREEN_HEIGHT: u16 = 160;
#[panic_handler] #[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! { fn panic_handler(_: &core::panic::PanicInfo) -> ! {
#[cfg(debug_assertions)]
if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Fatal) {
writeln!(logger, "{info}").ok();
}
loop {} loop {}
} }
#[allow(dead_code)] #[derive(Copy,Clone,PartialEq, Eq)]
const FOO: Align4<[u8; 14]> = include_aligned_bytes!("foo.txt"); struct Position(u16, u16);
#[unsafe(link_section = ".ewram")] #[derive(Copy,Clone,PartialEq, Eq)]
static FRAME_KEYS: GbaCell<KeyInput> = GbaCell::new(KeyInput::new()); struct Dimensions(u16, u16);
#[unsafe(link_section = ".iwram")] #[derive(Copy,Clone,PartialEq,Eq)]
extern "C" fn irq_handler(_: IrqBits) { struct Render {
// We'll read the keys during vblank and store it for later. position: Position,
FRAME_KEYS.write(KEYINPUT.read()); dimensions: Dimensions,
color: Color,
} }
impl Render {
fn draw(&self) {
draw_rect(self.position.0, self.position.1, self.dimensions.0, self.dimensions.1, self.color);
}
}
#[derive(Copy,Clone,PartialEq,Eq)]
struct Player(Render);
impl Player {
fn spawn() -> Player {
Self(Render {
position: Position(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2),
dimensions: Dimensions(24, 24),
color: Color::WHITE,
})
}
fn update(&mut self) {
}
fn draw(&self) {
self.0.draw();
}
}
#[derive(Copy,Clone,PartialEq,Eq)]
enum Entity {
Player(Player),
}
#[derive(Copy,Clone)]
struct Engine {
player: Option<Player>,
}
static mut ENGINE: Engine = Engine {
player: None,
};
impl Engine {
fn start(mut self) {
self.player = Some(Player::spawn());
}
fn update(mut self) {
if let Some(player) = &mut self.player {
player.update();
}
}
fn draw(self) {
if let Some(player) = self.player {
player.draw();
video3_clear_to(Color::WHITE);
}
}
}
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
extern "C" fn main() -> ! { fn main() -> ! {
RUST_IRQ_HANDLER.write(Some(irq_handler)); DISPCNT.write(
DisplayControl::new().with_video_mode(VideoMode::_3).with_show_bg2(true),
);
RUST_IRQ_HANDLER.write(Some(draw_sprites));
DISPSTAT.write(DisplayStatus::new().with_irq_vblank(true)); DISPSTAT.write(DisplayStatus::new().with_irq_vblank(true));
IE.write(IrqBits::VBLANK); IE.write(IrqBits::VBLANK);
IME.write(true); IME.write(true);
if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Debug) { unsafe { ENGINE.start(); };
writeln!(logger, "hello!").ok();
let fx_u: Fixed<u32, 8> =
Fixed::<u32, 8>::wrapping_from(7) + Fixed::<u32, 8>::from_bits(12);
writeln!(logger, "fixed unsigned: {fx_u:?}").ok();
let fx_i1: Fixed<i32, 8> =
Fixed::<i32, 8>::wrapping_from(8) + Fixed::<i32, 8>::from_bits(15);
writeln!(logger, "fixed signed positive: {fx_i1:?}").ok();
let fx_i2: Fixed<i32, 8> = Fixed::<i32, 8>::wrapping_from(0)
- Fixed::<i32, 8>::wrapping_from(3)
- Fixed::<i32, 8>::from_bits(17);
writeln!(logger, "fixed signed negative: {fx_i2:?}").ok();
}
{
// get our tile data into memory.
Cga8x8Thick.bitunpack_4bpp(CHARBLOCK0_4BPP.as_region(), 0);
}
{
// set up the tilemap
let tsb = TEXT_SCREENBLOCKS.get_frame(31).unwrap();
for y in 0..16 {
let row = tsb.get_row(y).unwrap();
for (x, addr) in row.iter().enumerate().take(16) {
let te = TextEntry::new().with_tile((y * 16 + x) as u16);
addr.write(te);
}
}
}
{
// Set BG0 to use the tilemap we just made, and set it to be shown.
BG0CNT.write(BackgroundControl::new().with_screenblock(31));
DISPCNT.write(DisplayControl::new().with_show_bg0(true));
}
let mut x_off = 0_u32;
let mut y_off = 0_u32;
let mut backdrop_color = Color(0);
loop { loop {
unsafe { ENGINE.update(); };
VBlankIntrWait(); VBlankIntrWait();
// show current frame }
BACKDROP_COLOR.write(backdrop_color); }
BG0HOFS.write(x_off as u16);
BG0VOFS.write(y_off as u16);
// prep next frame #[unsafe(link_section = ".iwram.draw_sprites")]
let k = FRAME_KEYS.read(); extern "C" fn draw_sprites(_bits: IrqBits) {
backdrop_color = Color(k.to_u16()); video3_clear_to(Color::BLACK);
if k.up() {
y_off = y_off.wrapping_add(1); unsafe { ENGINE.draw(); };
} }
if k.down() {
y_off = y_off.wrapping_sub(1);
} #[unsafe(link_section = ".iwram.draw_rect")]
if k.left() { fn draw_rect(x: u16, y: u16, width: u16, height: u16, color: Color) {
x_off = x_off.wrapping_add(1); for i in 0..width {
} for j in 0..height {
if k.right() { VIDEO3_VRAM.index((x + i) as usize, (y + j) as usize).write(color);
x_off = x_off.wrapping_sub(1);
} }
} }
} }