Merge branch 'main' of https://github.com/rust-console/gba into main

This commit is contained in:
Lokathor 2023-01-01 22:54:35 -07:00
commit f200c84ff6
4 changed files with 165 additions and 142 deletions

View file

@ -5,8 +5,9 @@ use gba::prelude::*;
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
use core::fmt::Write;
#[cfg(debug_assertions)]
if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Fatal) {
use core::fmt::Write;
writeln!(logger, "{info}").ok();
}
loop {}
@ -25,7 +26,7 @@ struct Rect {
h: u16,
}
impl Rect {
pub fn intersect(self, other: Self) -> bool {
fn intersect(self, other: Self) -> bool {
self.x < other.x + other.w
&& self.x + self.w > other.x
&& self.y < other.y + other.h
@ -50,7 +51,7 @@ extern "C" fn main() -> ! {
creatures[0].x = 11;
creatures[0].y = 14;
//
creatures[1].x = 41;
creatures[1].x = 44;
creatures[1].y = 38;
creatures[2].x = 100;
creatures[2].y = 23;
@ -61,11 +62,16 @@ extern "C" fn main() -> ! {
let mut world = [[0_u8; 32]; 32];
for i in 0..32 {
world[0][i] = b'z';
world[31][i] = b'z';
world[i][0] = b'z';
world[i][31] = b'z';
world[0][i] = Cga8x8Thick::BOX_HORIZONTAL;
world[19][i] = Cga8x8Thick::BOX_HORIZONTAL;
world[i][0] = Cga8x8Thick::BOX_VERTICAL;
world[i][29] = Cga8x8Thick::BOX_VERTICAL;
}
world[0][0] = Cga8x8Thick::BOX_UPPER_LEFT;
world[0][29] = Cga8x8Thick::BOX_UPPER_RIGHT;
world[19][0] = Cga8x8Thick::BOX_LOWER_LEFT;
world[19][29] = Cga8x8Thick::BOX_LOWER_RIGHT;
//
world[1][3] = b'B';
world[2][3] = b'G';
world[3][3] = b'0';
@ -77,12 +83,14 @@ extern "C" fn main() -> ! {
TIMER0_CONTROL.write(TimerControl::new().with_enabled(true));
// bg
BG_PALETTE.index(1).write(Color::MAGENTA);
OBJ_PALETTE.index(1).write(Color::CYAN);
OBJ_PALETTE.index(16 * 1 + 1).write(Color::GREEN);
OBJ_PALETTE.index(16 * 2 + 1).write(Color::RED);
OBJ_PALETTE.index(16 * 3 + 1).write(Color::BLUE);
OBJ_PALETTE.index(16 * 4 + 1).write(Color::YELLOW);
// obj
let colors =
[Color::CYAN, Color::GREEN, Color::RED, Color::BLUE, Color::YELLOW];
for (pal, color) in colors.iter().enumerate() {
obj_palbank(pal).index(1).write(*color);
}
Cga8x8Thick.bitunpack_4bpp(CHARBLOCK0_4BPP.as_region(), 0);
Cga8x8Thick.bitunpack_4bpp(OBJ_TILES.as_region(), 0);
@ -141,56 +149,56 @@ extern "C" fn main() -> ! {
if keys.up() {
let new_p = Position { x: player.x, y: player.y - 1 };
let new_r = Rect { x: new_p.x, y: new_p.y, w: 8, h: 8 };
if new_r
let terrain_clear = new_r
.iter_tiles()
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]))
&& enemies.iter().all(|enemy| {
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]));
let enemy_clear = enemies.iter().all(|enemy| {
let enemy_r = Rect { x: enemy.x, y: enemy.y, w: 8, h: 8 };
!new_r.intersect(enemy_r)
})
{
});
if terrain_clear && enemy_clear {
*player = new_p;
}
}
if keys.down() {
let new_p = Position { x: player.x, y: player.y + 1 };
let new_r = Rect { x: new_p.x, y: new_p.y, w: 8, h: 8 };
if new_r
let terrain_clear = new_r
.iter_tiles()
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]))
&& enemies.iter().all(|enemy| {
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]));
let enemy_clear = enemies.iter().all(|enemy| {
let enemy_r = Rect { x: enemy.x, y: enemy.y, w: 8, h: 8 };
!new_r.intersect(enemy_r)
})
{
});
if terrain_clear && enemy_clear {
*player = new_p;
}
}
if keys.left() {
let new_p = Position { x: player.x - 1, y: player.y };
let new_r = Rect { x: new_p.x, y: new_p.y, w: 8, h: 8 };
if new_r
let terrain_clear = new_r
.iter_tiles()
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]))
&& enemies.iter().all(|enemy| {
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]));
let enemy_clear = enemies.iter().all(|enemy| {
let enemy_r = Rect { x: enemy.x, y: enemy.y, w: 8, h: 8 };
!new_r.intersect(enemy_r)
})
{
});
if terrain_clear && enemy_clear {
*player = new_p;
}
}
if keys.right() {
let new_p = Position { x: player.x + 1, y: player.y };
let new_r = Rect { x: new_p.x, y: new_p.y, w: 8, h: 8 };
if new_r
let terrain_clear = new_r
.iter_tiles()
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]))
&& enemies.iter().all(|enemy| {
.all(|(tx, ty)| allows_movement(world[ty as usize][tx as usize]));
let enemy_clear = enemies.iter().all(|enemy| {
let enemy_r = Rect { x: enemy.x, y: enemy.y, w: 8, h: 8 };
!new_r.intersect(enemy_r)
})
{
});
if terrain_clear && enemy_clear {
*player = new_p;
}
}

View file

@ -6,6 +6,7 @@ use gba::prelude::*;
#[panic_handler]
fn panic_handler(info: &core::panic::PanicInfo) -> ! {
#[cfg(debug_assertions)]
if let Ok(mut logger) = MgbaBufferedLogger::try_new(MgbaMessageLevel::Fatal) {
writeln!(logger, "{info}").ok();
}

View file

@ -7,6 +7,107 @@ use crate::{
video::{Tile4, Tile8},
};
macro_rules! glyph {
($name:ident = $id:expr) => {
pub const $name: u8 = $id;
};
}
#[derive(Debug, Clone, Copy)]
pub struct Cga8x8Thick;
impl Cga8x8Thick {
// 0x0?
glyph!(NULL = 0x00);
glyph!(FACE = 0x01);
glyph!(FACE_INVERSE = 0x02);
glyph!(HEART = 0x03);
glyph!(DIAMOND = 0x04);
glyph!(CLUB = 0x05);
glyph!(SPADE = 0x06);
glyph!(BULLET = 0x07);
glyph!(BULLET_INVERSE = 0x08);
glyph!(CIRCLE = 0x09);
glyph!(CIRCLE_INVERSE = 0x0A);
glyph!(MALE = 0x0B);
glyph!(FEMALE = 0x0C);
glyph!(NOTE = 0x0D);
glyph!(NOTE_DOUBLE = 0x0E);
glyph!(SOLAR = 0x0F);
// 0x1?
glyph!(POINTER_RIGHT = 0x10);
glyph!(POINTER_LEFT = 0x11);
glyph!(ARROW_UP_DOWN = 0x12);
glyph!(BANG_DOUBLE = 0x13);
glyph!(PARAGRAPH = 0x14);
glyph!(SECTION = 0x15);
glyph!(UNDERLINE_THICK = 0x16);
glyph!(ARROW_UP_DOWN_UNDERLINED = 0x17);
glyph!(ARROW_UP = 0x18);
glyph!(ARROW_DOWN = 0x19);
glyph!(ARROW_RIGHT = 0x1A);
glyph!(ARROW_LEFT = 0x1B);
glyph!(RIGHT_ANGLE = 0x1C);
glyph!(ARROW_LEFT_RIGHT = 0x1D);
glyph!(POINTER_UP = 0x1E);
glyph!(POINTER_DOWN = 0x1F);
// Box drawing
glyph!(BOX_VERTICAL = 0xB3);
glyph!(BOX_HORIZONTAL = 0xC4);
glyph!(BOX_UPPER_RIGHT = 0xBF);
glyph!(BOX_UPPER_LEFT = 0xDA);
glyph!(BOX_LOWER_RIGHT = 0xD9);
glyph!(BOX_LOWER_LEFT = 0xC0);
/// Bit unpacks the data (4bpp depth) to the location given.
///
/// * `offset_and_touch_zero`: Works like the [`BitUnpackInfo`] field. By
/// default you should usually pass 0 here.
///
/// ## Panics
/// * Requires at least 256 elements of space within the region.
#[inline]
pub fn bitunpack_4bpp(
self, b: VolRegion<Tile4, Safe, Safe>, offset_and_touch_zero: u32,
) {
assert!(b.len() >= 256);
let src = CGA_8X8_THICK.as_ptr();
let dest = b.index(0).as_usize() as *mut u32;
let info = BitUnpackInfo {
src_byte_len: size_of_val(&CGA_8X8_THICK) as u16,
src_elem_width: 1,
dest_elem_width: 4,
offset_and_touch_zero,
};
unsafe { BitUnPack(src.cast(), dest, &info) };
}
/// Bit unpacks the data (8bpp depth) to the location given.
///
/// * `offset_and_touch_zero`: Works like the [`BitUnpackInfo`] field. By
/// default you should usually pass 0 here.
///
/// ## Panics
/// * Requires at least 256 elements of space within the region.
#[inline]
pub fn bitunpack_8bpp(
self, b: VolRegion<Tile8, Safe, Safe>, offset_and_touch_zero: u32,
) {
assert!(b.len() >= 256);
let src = CGA_8X8_THICK.as_ptr();
let dest = b.index(0).as_usize() as *mut u32;
let info = BitUnpackInfo {
src_byte_len: size_of_val(&CGA_8X8_THICK) as u16,
src_elem_width: 1,
dest_elem_width: 8,
offset_and_touch_zero,
};
unsafe { BitUnPack(src.cast(), dest, &info) };
}
}
/// The CGA [Code Page 437][cp437] type face, with thick lines.
///
/// There's 256 tiles, packed down to 1bpp.
@ -126,105 +227,3 @@ pub static CGA_8X8_THICK: [u32; 512] = [
0x3636361E, 0x00000036, 0x060C180E, 0x0000001E, 0x3C3C0000, 0x00003C3C,
0x00000000, 0x00000000,
];
macro_rules! glyph_name {
($name:ident = $x:expr) => {
pub const $name: u8 = $x;
};
}
#[derive(Debug, Clone, Copy)]
pub struct Cga8x8Thick;
impl Cga8x8Thick {
// 0x0? series
glyph_name!(NULL = 0x00);
glyph_name!(SMILEY = 0x01);
glyph_name!(SMILEY_INVERSE = 0x02);
glyph_name!(HEART = 0x03);
glyph_name!(DIAMOND = 0x04);
glyph_name!(CLUB = 0x05);
glyph_name!(SPADE = 0x06);
glyph_name!(BULLET = 0x07);
glyph_name!(BULLET_INVERSE = 0x08);
glyph_name!(BULLET_BIG = 0x09);
glyph_name!(BULLET_INVERSE_BIG = 0x0A);
glyph_name!(MALE = 0x0B);
glyph_name!(FEMALE = 0x0C);
glyph_name!(NOTE = 0x0D);
glyph_name!(DOUBLE_NOTE = 0x0E);
glyph_name!(SOLAR = 0x0F);
// 0x1? series
glyph_name!(POINTER_RIGHT = 0x10);
glyph_name!(POINTER_LEFT = 0x11);
glyph_name!(ARROW_UP_DOWN = 0x12);
glyph_name!(DOUBLE_BANG = 0x13);
glyph_name!(PARAGRAPH = 0x14);
glyph_name!(SECTION = 0x15);
glyph_name!(UNDERLINE_THICK = 0x16);
glyph_name!(ARROW_UP_DOWN_UNDERLINED = 0x17);
glyph_name!(ARROW_UP = 0x18);
glyph_name!(ARROW_DOWN = 0x19);
glyph_name!(ARROW_RIGHT = 0x1A);
glyph_name!(ARROW_LEFT = 0x1B);
glyph_name!(RIGHT_ANGLE = 0x1C);
glyph_name!(ARROW_LEFT_RIGHT = 0x1D);
glyph_name!(POINTER_UP = 0x1E);
glyph_name!(POINTER_DOWN = 0x1F);
// 0x7? series
glyph_name!(HOUSE = 0x7F);
//
glyph_name!(BOX_LIGHT_HORIZONTAL = 0xC4);
glyph_name!(BOX_LIGHT_VERTICAL = 0xB3);
glyph_name!(BOX_LIGHT_UPPER_LEFT = 0xDA);
glyph_name!(BOX_LIGHT_UPPER_RIGHT = 0xBF);
glyph_name!(BOX_LIGHT_LOWER_LEFT = 0xC0);
glyph_name!(BOX_LIGHT_LOWER_RIGHT = 0xD9);
}
impl Cga8x8Thick {
/// Bit unpacks the data (4bpp depth) to the location given.
///
/// * `offset_and_touch_zero`: Works like the [`BitUnpackInfo`] field. By
/// default you should usually pass 0 here.
///
/// ## Panics
/// * Requires at least 256 elements of space within the region.
#[inline]
pub fn bitunpack_4bpp(
self, b: VolRegion<Tile4, Safe, Safe>, offset_and_touch_zero: u32,
) {
assert!(b.len() >= 256);
let src = CGA_8X8_THICK.as_ptr();
let dest = b.index(0).as_usize() as *mut u32;
let info = BitUnpackInfo {
src_byte_len: size_of_val(&CGA_8X8_THICK) as u16,
src_elem_width: 1,
dest_elem_width: 4,
offset_and_touch_zero,
};
unsafe { BitUnPack(src.cast(), dest, &info) };
}
/// Bit unpacks the data (8bpp depth) to the location given.
///
/// * `offset_and_touch_zero`: Works like the [`BitUnpackInfo`] field. By
/// default you should usually pass 0 here.
///
/// ## Panics
/// * Requires at least 256 elements of space within the region.
#[inline]
pub fn bitunpack_8bpp(
self, b: VolRegion<Tile8, Safe, Safe>, offset_and_touch_zero: u32,
) {
assert!(b.len() >= 256);
let src = CGA_8X8_THICK.as_ptr();
let dest = b.index(0).as_usize() as *mut u32;
let info = BitUnpackInfo {
src_byte_len: size_of_val(&CGA_8X8_THICK) as u16,
src_elem_width: 1,
dest_elem_width: 8,
offset_and_touch_zero,
};
unsafe { BitUnPack(src.cast(), dest, &info) };
}
}

View file

@ -201,6 +201,21 @@ def_mmio!(0x0500_0000 = BACKDROP_COLOR: VolAddress<Color, Safe, Safe>; "Color th
def_mmio!(0x0500_0000 = BG_PALETTE: VolBlock<Color, Safe, Safe, 256>; "Background tile palette entries.");
def_mmio!(0x0500_0200 = OBJ_PALETTE: VolBlock<Color, Safe, Safe, 256>; "Object tile palette entries.");
#[inline]
#[must_use]
#[cfg_attr(feature="track_caller", track_caller)]
pub const fn bg_palbank(bank: usize) -> VolBlock<Color, Safe, Safe, 16> {
let u = BG_PALETTE.index(bank * 16).as_usize();
unsafe { VolBlock::new(u) }
}
#[inline]
#[must_use]
#[cfg_attr(feature="track_caller", track_caller)]
pub const fn obj_palbank(bank: usize) -> VolBlock<Color, Safe, Safe, 16> {
let u = OBJ_PALETTE.index(bank * 16).as_usize();
unsafe { VolBlock::new(u) }
}
// Video RAM (VRAM)
/// The VRAM byte offset per screenblock index.