diff --git a/agb/src/display/tiled0.rs b/agb/src/display/tiled0.rs index 42235bde..239af40a 100644 --- a/agb/src/display/tiled0.rs +++ b/agb/src/display/tiled0.rs @@ -42,29 +42,18 @@ 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<'a> { +pub struct Background { background: u8, block: u8, - map: Option>, - map_dim_x: u32, - map_dim_y: u32, pos_x: i32, pos_y: i32, } -enum MapStorage<'a> { - R(&'a RefCell<[u16]>), - S(&'a [u16]), -} - -impl<'a> Background<'a> { - unsafe fn new(layer: u8, block: u8) -> Background<'a> { +impl Background { + unsafe fn new(layer: u8, block: u8) -> Background { let mut background = Background { background: layer, block, - map: None, - map_dim_x: 0, - map_dim_y: 0, pos_x: 0, pos_y: 0, }; @@ -73,34 +62,12 @@ impl<'a> Background<'a> { background.set_block(block); background } - - /// Sets the internal map to the provided map. Dimensions should be the - /// dimensions of the map. The mapping between coordinate and index is given - /// by `y * dim_x + x`. The length of the map slice should be `dim_x * - /// dim_y`, or panics may occur. - /// - /// The portion of this map that is in view is copied to the map block - /// assigned to this background. - pub fn set_map(&mut self, map: &'a [u16], dim_x: u32, dim_y: u32) { - self.map = Some(MapStorage::S(map)); - self.map_dim_x = dim_x; - self.map_dim_y = dim_y; - self.draw_full_map(); - } - - pub fn set_map_refcell(&mut self, map: &'a RefCell<[u16]>, dim_x: u32, dim_y: u32) { - self.map = Some(MapStorage::R(map)); - self.map_dim_x = dim_x; - self.map_dim_y = dim_y; - self.draw_full_map(); - } } -impl Background<'_> { +impl Background { /// 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(), "map should be set before showing"); let mode = DISPLAY_CONTROL.get(); let new_mode = mode | (1 << (self.background + 0x08)); DISPLAY_CONTROL.set(new_mode); @@ -143,14 +110,14 @@ impl Background<'_> { unsafe { self.set_bits(0x0E, 2, size as u16) } } - fn map_get(&self, map: &T, x: i32, y: i32, default: u16) -> u16 + fn map_get(&self, map: &T, dim_x: u32, dim_y: u32, x: i32, y: i32, default: u16) -> u16 where T: Deref, { - if x >= self.map_dim_x as i32 || x < 0 || y >= self.map_dim_y as i32 || y < 0 { + if x >= dim_x as i32 || x < 0 || y >= dim_y as i32 || y < 0 { default } else { - map[(self.map_dim_x as i32 * y + x) as usize] + map[(dim_x as i32 * y + x) as usize] } } @@ -165,33 +132,34 @@ impl Background<'_> { /// block assigned to this background. This is currently unnecesary to call. /// Setting position already updates the drawn map, and changing map forces /// an update. - pub fn draw_full_map(&mut self) { - match self.map.as_ref().unwrap() { - MapStorage::R(m) => { - let map = (*m).borrow(); - self.draw_area_mapped(&map, -1, 32, -1, 22); - } - MapStorage::S(map) => { - self.draw_area_mapped(map, -1, 32, -1, 22); - } - } + pub fn draw_full_map(&mut self, map: &[u16], dim_x: u32, dim_y: u32) { + self.draw_area(map, dim_x, dim_y, -1, -1, 32, 22); } /// Forces a specific area of the screen to be drawn, taking into account any positonal offsets. - pub fn draw_area(&mut self, left: i32, top: i32, width: i32, height: i32) { - match self.map.as_ref().unwrap() { - MapStorage::R(m) => { - let map = (*m).borrow(); - self.draw_area_mapped(&map, left, top, width, height); - } - MapStorage::S(map) => { - self.draw_area_mapped(map, left, top, width, height); - } - } + pub fn draw_area( + &self, + map: &[u16], + dim_x: u32, + dim_y: u32, + left: i32, + top: i32, + width: i32, + height: i32, + ) { + self.draw_area_mapped(&map, dim_x, dim_y, left, top, width, height); } - fn draw_area_mapped(&self, map: &T, left: i32, top: i32, width: i32, height: i32) - where + fn draw_area_mapped( + &self, + map: &T, + dim_x: u32, + dim_y: u32, + left: i32, + top: i32, + width: i32, + height: i32, + ) where T: Deref, { let x_map_space = self.pos_x / 8; @@ -206,7 +174,14 @@ impl Background<'_> { (&mut (*MAP)[self.block as usize][(y_block_space + y).rem_euclid(32) as usize] [(x_block_space + x).rem_euclid(32) as usize] as *mut u16) - .write_volatile(self.map_get(map, x_map_space + x, y_map_space + y, 0)) + .write_volatile(self.map_get( + map, + dim_x, + dim_y, + x_map_space + x, + y_map_space + y, + 0, + )) }; } } @@ -215,21 +190,13 @@ impl Background<'_> { /// Sets the position of the map to be shown on screen. This automatically /// manages copying the correct portion to the map block and moving the map /// registers. - pub fn set_position(&mut self, x: i32, y: i32) { - match self.map.as_ref().unwrap() { - MapStorage::R(m) => { - let map = (*m).borrow(); - self.set_position_mapped(&map, x, y); - } - MapStorage::S(map) => { - self.set_position_mapped(map, x, y); - } - } + pub fn set_position(&mut self, map: &[u16], dim_x: u32, dim_y: u32, x: i32, y: i32) { + self.set_position_mapped(&map, dim_x, dim_y, x, y); self.pos_x = x; self.pos_y = y; } - pub fn set_position_mapped(&self, map: &T, x: i32, y: i32) + pub fn set_position_mapped(&self, map: &T, dim_x: u32, dim_y: u32, x: i32, y: i32) where T: Deref, { @@ -247,7 +214,7 @@ impl Background<'_> { // don't fancily handle if we've moved more than one tile, just copy the whole new map if x_difference.abs() > 1 || y_difference.abs() > 1 { - self.draw_area_mapped(map, -1, 32, -1, 22); + self.draw_area_mapped(map, dim_x, dim_y, -1, 32, -1, 22); } else { if x_difference != 0 { let x_offset = match x_difference { @@ -263,6 +230,8 @@ impl Background<'_> { as *mut u16) .write_volatile(self.map_get( map, + dim_x, + dim_y, x_map_space + x_offset, y_map_space + y, 0, @@ -284,6 +253,8 @@ impl Background<'_> { as *mut u16) .write_volatile(self.map_get( map, + dim_x, + dim_y, x_map_space + x, y_map_space + y_offset, 0,