part way implementation of background

This commit is contained in:
Corwin Kuiper 2021-08-01 00:18:09 +01:00
parent f9014a0bf9
commit e176e986ad
3 changed files with 82 additions and 15 deletions

View file

@ -4,6 +4,7 @@
extern crate agb;
use agb::display::example_logo;
use agb::display::tiled0::Map;
#[no_mangle]
pub fn main() -> ! {

View file

@ -2,6 +2,8 @@ use crate::display::tiled0::Tiled0;
crate::include_gfx!("gfx/agb_logo.toml");
use super::tiled0::Map;
pub fn display_logo(gfx: &mut Tiled0) {
gfx.set_background_palettes(agb_logo::test_logo.palettes);
gfx.set_background_tilemap(0, agb_logo::test_logo.tiles);
@ -14,7 +16,11 @@ pub fn display_logo(gfx: &mut Tiled0) {
entries[tile_id as usize] = tile_id | (palette_entry << 12);
}
back.draw_full_map(&entries, (30_u32, 20_u32).into(), 0);
back.set_map(Map {
store: &mut entries,
dimensions: (30_u32, 20_u32).into(),
default: 0,
});
back.show();
}

View file

@ -1,5 +1,3 @@
use core::{convert::TryInto, ops::Deref};
use crate::{
memory_mapped::{MemoryMapped, MemoryMapped1DArray},
number::{Rect, Vector2D},
@ -12,13 +10,9 @@ use super::{
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
const PALETTE_SPRITE: MemoryMapped1DArray<u16, 256> =
unsafe { MemoryMapped1DArray::new(0x0500_0200) };
const TILE_BACKGROUND: MemoryMapped1DArray<u32, { 2048 * 8 }> =
unsafe { MemoryMapped1DArray::new(0x06000000) };
const TILE_SPRITE: MemoryMapped1DArray<u32, { 512 * 8 }> =
unsafe { MemoryMapped1DArray::new(0x06010000) };
const MAP: *mut [[[u16; 32]; 32]; 32] = 0x0600_0000 as *mut _;
@ -37,17 +31,36 @@ pub enum BackgroundSize {
/// The map background is the method of drawing game maps to the screen. It
/// automatically handles copying the correct portion of a provided map to the
/// assigned block depending on given coordinates.
pub struct Background {
pub struct Background<'a> {
background: u8,
block: u8,
commited_position: Vector2D<i32>,
shadowed_position: Vector2D<i32>,
poisoned: bool,
shadowed_register: u16,
map: Option<Map<'a>>,
}
impl Background {
unsafe fn new(background: u8, block: u8) -> Background {
pub struct Map<'a> {
pub store: &'a mut [u16],
pub dimensions: Vector2D<u32>,
pub default: u16,
}
impl<'a> Map<'a> {
fn get_position(&self, x: i32, y: i32) -> u16 {
if x < 0 || x as u32 >= self.dimensions.x {
self.default
} else if y < 0 || y as u32 >= self.dimensions.y {
self.default
} else {
self.store[y as usize * self.dimensions.x as usize + x as usize]
}
}
}
impl<'a> Background<'a> {
unsafe fn new(background: u8, block: u8) -> Background<'a> {
let mut b = Background {
background,
block,
@ -55,6 +68,7 @@ impl Background {
shadowed_position: (0, 0).into(),
shadowed_register: 0,
poisoned: true,
map: None,
};
b.set_block(block);
b.set_colour_mode(ColourMode::FourBitPerPixel);
@ -62,6 +76,22 @@ impl Background {
b
}
/// Sets the background to be shown on screen. Requires the background to
/// have a map enabled otherwise a panic is caused.
pub fn show(&mut self) {
assert!(self.map.is_some());
let mode = DISPLAY_CONTROL.get();
let new_mode = mode | (1 << (self.background + 0x08));
DISPLAY_CONTROL.set(new_mode);
}
/// Hides the background, nothing from this background is rendered to screen.
pub fn hide(&mut self) {
let mode = DISPLAY_CONTROL.get();
let new_mode = mode & !(1 << (self.background + 0x08));
DISPLAY_CONTROL.set(new_mode);
}
unsafe fn set_shadowed_register_bits(&mut self, value: u16, length: u16, shift: u16) {
let mask = !(((1 << length) - 1) << shift);
let new = (self.shadowed_register & mask) | (value << shift);
@ -88,15 +118,27 @@ impl Background {
self.set_shadowed_register_bits(size as u16, 0x2, 0xE);
}
unsafe fn set_position_x_register(&self, x: u16) {
*((0x0400_0010 + 4 * self.background as usize) as *mut u16) = x
}
unsafe fn set_position_y_register(&self, y: u16) {
*((0x0400_0012 + 4 * self.background as usize) as *mut u16) = y
}
pub fn set_position(&mut self, position: Vector2D<i32>) {
self.shadowed_position = position;
}
pub fn map_has_changed(&mut self) {
pub fn get_map(&mut self) -> &mut Option<Map<'a>> {
self.poisoned = true;
&mut self.map
}
pub fn commit_area(&self, map: &[u16], map_dimensions: Vector2D<u32>, area: Rect<i32>) {
pub fn set_map(&mut self, map: Map<'a>) {
self.map = Some(map);
}
pub fn commit_area(&mut self, area: Rect<i32>) {
// commit shadowed register
unsafe { self.get_register().set(self.shadowed_register) };
@ -143,19 +185,37 @@ impl Background {
y_update.iter().chain(x_update.iter())
};
for (x, y) in positions_to_be_updated {}
if let Some(map) = &self.map {
for (x, y) in positions_to_be_updated {
let tile_space_position = self.shadowed_position / 8;
unsafe {
(&mut (*MAP)[self.block as usize][y.rem_euclid(32) as usize]
[x.rem_euclid(32) as usize] as *mut u16)
.write_volatile(
map.get_position(x + tile_space_position.x, y + tile_space_position.y),
);
}
}
}
// update commited position
self.commited_position = self.shadowed_position;
// update position in registers
unsafe {
self.set_position_x_register((self.commited_position.x % (32 * 8)) as u16);
self.set_position_y_register((self.commited_position.y % (32 * 8)) as u16);
}
}
pub fn commit(&self, map: &[u16], map_dimensions: Vector2D<u32>) {
pub fn commit(&mut self) {
let area: Rect<i32> = Rect {
position: Vector2D::new(-1, -1),
size: Vector2D::new(32, 22),
};
self.commit_area(map, map_dimensions, area)
self.commit_area(area)
}
}