#![no_std] #![feature(start)] #![forbid(unsafe_code)] use gba::{ fatal, io::{ display::{DisplayControlSetting, DisplayMode, DISPCNT, VBLANK_SCANLINE, VCOUNT}, keypad::read_key_input, }, vram::bitmap::Mode3, Color, }; #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { // This kills the emulation with a message if we're running within mGBA. fatal!("{}", info); // If we're _not_ running within mGBA then we still need to not return, so // loop forever doing nothing. loop {} } #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { const SETTING: DisplayControlSetting = DisplayControlSetting::new().with_mode(DisplayMode::Mode3).with_bg2(true); DISPCNT.write(SETTING); let mut px = Mode3::WIDTH / 2; let mut py = Mode3::HEIGHT / 2; let mut color = Color::from_rgb(31, 0, 0); loop { // read our keys for this frame let this_frame_keys = read_key_input(); // adjust game state and wait for vblank px = px.wrapping_add(2 * this_frame_keys.x_tribool() as usize); py = py.wrapping_add(2 * this_frame_keys.y_tribool() as usize); if this_frame_keys.l() { color = Color(color.0.rotate_left(5)); } if this_frame_keys.r() { color = Color(color.0.rotate_right(5)); } // now we wait spin_until_vblank(); // draw the new game and wait until the next frame starts. const BLACK: Color = Color::from_rgb(0, 0, 0); if px >= Mode3::WIDTH || py >= Mode3::HEIGHT { // out of bounds, reset the screen and position. Mode3::dma_clear_to(BLACK); px = Mode3::WIDTH / 2; py = Mode3::HEIGHT / 2; } else { // draw the new part of the line Mode3::write(px, py, color); Mode3::write(px, py + 1, color); Mode3::write(px + 1, py, color); Mode3::write(px + 1, py + 1, color); } // now we wait again spin_until_vdraw(); } } /// Performs a busy loop until VBlank starts. /// /// This is very inefficient, and please keep following the lessons until we /// cover how interrupts work! pub fn spin_until_vblank() { while VCOUNT.read() < VBLANK_SCANLINE {} } /// Performs a busy loop until VDraw starts. /// /// This is very inefficient, and please keep following the lessons until we /// cover how interrupts work! pub fn spin_until_vdraw() { while VCOUNT.read() >= VBLANK_SCANLINE {} }