mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 10:51:30 +11:00
Merge branch 'main' of https://github.com/rust-console/gba into main
This commit is contained in:
commit
f200c84ff6
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) };
|
||||
}
|
||||
}
|
||||
|
|
15
src/mmio.rs
15
src/mmio.rs
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue