mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 10:51:30 +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::{
|
||||
fatal,
|
||||
io::display::{DisplayControlSetting, DisplayMode, DISPCNT},
|
||||
io::{
|
||||
display::{DisplayControlSetting, DisplayMode, DISPCNT, VBLANK_SCANLINE, VCOUNT},
|
||||
keypad::read_key_input,
|
||||
},
|
||||
vram::bitmap::Mode3,
|
||||
Color,
|
||||
};
|
||||
use gba::io::keypad::read_key_input;
|
||||
|
||||
#[panic_handler]
|
||||
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
|
||||
let this_frame_keys = read_key_input();
|
||||
|
||||
gba::io::display::spin_until_vblank();
|
||||
Mode5::dma_clear_to(Page::Zero, Color(111));
|
||||
Mode5::draw_line(Page::Zero, 5, 5, 100, 100, Color(0b0_11111_11111_11111));
|
||||
gba::io::display::spin_until_vdraw();
|
||||
// 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 {}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ fn panic(_info: &core::panic::PanicInfo) -> ! {
|
|||
|
||||
fn start_timers() {
|
||||
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_H.write(TIMER_SETTINGS.with_tick_rate(TimerTickRate::CPU1024));
|
||||
|
@ -90,8 +91,8 @@ static mut PIXEL: usize = 0;
|
|||
|
||||
fn write_pixel(color: Color) {
|
||||
unsafe {
|
||||
Mode3::write_pixel(PIXEL, 0, color);
|
||||
PIXEL = (PIXEL + 1) % Mode3::SCREEN_PIXEL_COUNT;
|
||||
Mode3::write(PIXEL, 0, color);
|
||||
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.
|
||||
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.
|
||||
pub const MOSAIC: VolAddress<MosaicSetting> = unsafe { VolAddress::new(0x400_004C) };
|
||||
|
||||
|
|
|
@ -50,9 +50,10 @@ impl KeyInput {
|
|||
KeyInput(self.0 ^ other.0)
|
||||
}
|
||||
|
||||
/// Gives the arrow pad value as a tribool, with Plus being increased column
|
||||
/// value (right).
|
||||
pub fn column_direction(self) -> TriBool {
|
||||
/// Right/left tribool.
|
||||
///
|
||||
/// Right is Plus and Left is Minus
|
||||
pub fn x_tribool(self) -> TriBool {
|
||||
if self.right() {
|
||||
TriBool::Plus
|
||||
} else if self.left() {
|
||||
|
@ -62,9 +63,10 @@ impl KeyInput {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gives the arrow pad value as a tribool, with Plus being increased row
|
||||
/// value (down).
|
||||
pub fn row_direction(self) -> TriBool {
|
||||
/// Up/down tribool.
|
||||
///
|
||||
/// Down is Plus and Up is Minus
|
||||
pub fn y_tribool(self) -> TriBool {
|
||||
if self.down() {
|
||||
TriBool::Plus
|
||||
} else if self.up() {
|
||||
|
|
|
@ -71,13 +71,6 @@ impl Color {
|
|||
pub const fn from_rgb(r: u16, g: u16, b: u16) -> Color {
|
||||
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