mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-24 03:11:29 +11:00
Get all the code lined up
This commit is contained in:
parent
89b7cc0eaa
commit
3b688b907c
|
@ -1,61 +0,0 @@
|
||||||
#![no_std]
|
|
||||||
#![feature(start)]
|
|
||||||
#![forbid(unsafe_code)]
|
|
||||||
|
|
||||||
use gba::{
|
|
||||||
io::{
|
|
||||||
display::{spin_until_vblank, spin_until_vdraw, DisplayControlSetting, DisplayMode, DISPCNT},
|
|
||||||
keypad::read_key_input,
|
|
||||||
},
|
|
||||||
vram::bitmap::Mode3,
|
|
||||||
Color,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[panic_handler]
|
|
||||||
fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|
||||||
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 the input 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.column_direction() as usize);
|
|
||||||
py = py.wrapping_add(2 * this_frame_keys.row_direction() as usize);
|
|
||||||
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::clear_to(BLACK);
|
|
||||||
color = color.rotate_left(5);
|
|
||||||
px = Mode3::WIDTH / 2;
|
|
||||||
py = Mode3::HEIGHT / 2;
|
|
||||||
} else {
|
|
||||||
let color_here = Mode3::read(px, py);
|
|
||||||
if color_here != Some(BLACK) {
|
|
||||||
// crashed into our own line, reset the screen
|
|
||||||
Mode3::dma_clear_to(BLACK);
|
|
||||||
color = color.rotate_left(5);
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_until_vdraw();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,11 +4,13 @@
|
||||||
|
|
||||||
use gba::{
|
use gba::{
|
||||||
fatal,
|
fatal,
|
||||||
io::display::{DisplayControlSetting, DisplayMode, DISPCNT},
|
io::{
|
||||||
|
display::{DisplayControlSetting, DisplayMode, DISPCNT, VBLANK_SCANLINE, VCOUNT},
|
||||||
|
keypad::read_key_input,
|
||||||
|
},
|
||||||
vram::bitmap::Mode3,
|
vram::bitmap::Mode3,
|
||||||
Color,
|
Color,
|
||||||
};
|
};
|
||||||
use gba::io::keypad::read_key_input;
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &core::panic::PanicInfo) -> ! {
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
@ -33,9 +35,51 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||||
// read our keys for this frame
|
// read our keys for this frame
|
||||||
let this_frame_keys = read_key_input();
|
let this_frame_keys = read_key_input();
|
||||||
|
|
||||||
gba::io::display::spin_until_vblank();
|
// adjust game state and wait for vblank
|
||||||
Mode5::dma_clear_to(Page::Zero, Color(111));
|
px = px.wrapping_add(2 * this_frame_keys.x_tribool() as usize);
|
||||||
Mode5::draw_line(Page::Zero, 5, 5, 100, 100, Color(0b0_11111_11111_11111));
|
py = py.wrapping_add(2 * this_frame_keys.y_tribool() as usize);
|
||||||
gba::io::display::spin_until_vdraw();
|
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 {}
|
||||||
|
}
|
||||||
|
|
|
@ -26,7 +26,8 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
fn start_timers() {
|
fn start_timers() {
|
||||||
let init_val: u16 = u32::wrapping_sub(0x1_0000, 64) as u16;
|
let init_val: u16 = u32::wrapping_sub(0x1_0000, 64) as u16;
|
||||||
const TIMER_SETTINGS: TimerControlSetting = TimerControlSetting::new().with_overflow_irq(true).with_enabled(true);
|
const TIMER_SETTINGS: TimerControlSetting =
|
||||||
|
TimerControlSetting::new().with_overflow_irq(true).with_enabled(true);
|
||||||
|
|
||||||
TM0CNT_L.write(init_val);
|
TM0CNT_L.write(init_val);
|
||||||
TM0CNT_H.write(TIMER_SETTINGS.with_tick_rate(TimerTickRate::CPU1024));
|
TM0CNT_H.write(TIMER_SETTINGS.with_tick_rate(TimerTickRate::CPU1024));
|
||||||
|
@ -90,8 +91,8 @@ static mut PIXEL: usize = 0;
|
||||||
|
|
||||||
fn write_pixel(color: Color) {
|
fn write_pixel(color: Color) {
|
||||||
unsafe {
|
unsafe {
|
||||||
Mode3::write_pixel(PIXEL, 0, color);
|
Mode3::write(PIXEL, 0, color);
|
||||||
PIXEL = (PIXEL + 1) % Mode3::SCREEN_PIXEL_COUNT;
|
PIXEL = (PIXEL + 1) % (Mode3::WIDTH * Mode3::HEIGHT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,37 +127,6 @@ pub const VCOUNT: ROVolAddress<u16> = unsafe { ROVolAddress::new(0x400_0006) };
|
||||||
/// If the `VCOUNT` register reads equal to or above this then you're in vblank.
|
/// If the `VCOUNT` register reads equal to or above this then you're in vblank.
|
||||||
pub const VBLANK_SCANLINE: u16 = 160;
|
pub const VBLANK_SCANLINE: u16 = 160;
|
||||||
|
|
||||||
/// Obtains the current `VCOUNT` value.
|
|
||||||
pub fn vcount() -> u16 {
|
|
||||||
VCOUNT.read()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a busy loop until VBlank starts.
|
|
||||||
///
|
|
||||||
/// NOTE: This method isn't very power efficient, since it is equivalent to
|
|
||||||
/// calling "halt" repeatedly. The recommended way to wait for a VBlank or VDraw
|
|
||||||
/// is to set an IRQ handler with
|
|
||||||
/// [`io::irq::set_irq_handler`](`io::irq::set_irq_handler`) and using
|
|
||||||
/// [`bios::vblank_intr_wait`](bios::vblank_interrupt_wait) to sleep the CPU
|
|
||||||
/// until a VBlank IRQ is generated. See the [`io::irq`](io::irq) module for
|
|
||||||
/// more details.
|
|
||||||
pub fn spin_until_vblank() {
|
|
||||||
while vcount() < VBLANK_SCANLINE {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a busy loop until VDraw starts.
|
|
||||||
///
|
|
||||||
/// NOTE: This method isn't very power efficient, since it is equivalent to
|
|
||||||
/// calling "halt" repeatedly. The recommended way to wait for a VBlank or VDraw
|
|
||||||
/// is to set an IRQ handler with
|
|
||||||
/// [`io::irq::set_irq_handler`](`io::irq::set_irq_handler`) and using
|
|
||||||
/// [`bios::vblank_intr_wait`](bios::vblank_interrupt_wait) to sleep the CPU
|
|
||||||
/// until a VBlank IRQ is generated. See the [`io::irq`](io::irq) module for
|
|
||||||
/// more details.
|
|
||||||
pub fn spin_until_vdraw() {
|
|
||||||
while vcount() >= VBLANK_SCANLINE {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Global mosaic effect control. Write-only.
|
/// Global mosaic effect control. Write-only.
|
||||||
pub const MOSAIC: VolAddress<MosaicSetting> = unsafe { VolAddress::new(0x400_004C) };
|
pub const MOSAIC: VolAddress<MosaicSetting> = unsafe { VolAddress::new(0x400_004C) };
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,10 @@ impl KeyInput {
|
||||||
KeyInput(self.0 ^ other.0)
|
KeyInput(self.0 ^ other.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives the arrow pad value as a tribool, with Plus being increased column
|
/// Right/left tribool.
|
||||||
/// value (right).
|
///
|
||||||
pub fn column_direction(self) -> TriBool {
|
/// Right is Plus and Left is Minus
|
||||||
|
pub fn x_tribool(self) -> TriBool {
|
||||||
if self.right() {
|
if self.right() {
|
||||||
TriBool::Plus
|
TriBool::Plus
|
||||||
} else if self.left() {
|
} else if self.left() {
|
||||||
|
@ -62,9 +63,10 @@ impl KeyInput {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gives the arrow pad value as a tribool, with Plus being increased row
|
/// Up/down tribool.
|
||||||
/// value (down).
|
///
|
||||||
pub fn row_direction(self) -> TriBool {
|
/// Down is Plus and Up is Minus
|
||||||
|
pub fn y_tribool(self) -> TriBool {
|
||||||
if self.down() {
|
if self.down() {
|
||||||
TriBool::Plus
|
TriBool::Plus
|
||||||
} else if self.up() {
|
} else if self.up() {
|
||||||
|
|
|
@ -71,13 +71,6 @@ impl Color {
|
||||||
pub const fn from_rgb(r: u16, g: u16, b: u16) -> Color {
|
pub const fn from_rgb(r: u16, g: u16, b: u16) -> Color {
|
||||||
Color(b << 10 | g << 5 | r)
|
Color(b << 10 | g << 5 | r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does a left rotate of the bits.
|
|
||||||
///
|
|
||||||
/// This has no particular meaning but is a wild way to cycle colors.
|
|
||||||
pub const fn rotate_left(self, n: u32) -> Color {
|
|
||||||
Color(self.0.rotate_left(n))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue