Merge pull request #225 from gwilymk/allow-setting-size-of-backgrounds

Allow setting size of backgrounds
This commit is contained in:
Gwilym Kuiper 2022-05-04 21:00:07 +01:00 committed by GitHub
commit 5c76961506
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 244 additions and 39 deletions

View file

@ -3,7 +3,7 @@
use agb::{ use agb::{
display::{ display::{
tiled::{TileFormat, TileSet, TileSetting}, tiled::{RegularBackgroundSize, TileFormat, TileSet, TileSetting},
Priority, Priority,
}, },
include_gfx, include_gfx,
@ -20,7 +20,7 @@ fn main(mut gba: agb::Gba) -> ! {
vram.set_background_palettes(water_tiles::water_tiles.palettes); vram.set_background_palettes(water_tiles::water_tiles.palettes);
let mut bg = gfx.background(Priority::P0); let mut bg = gfx.background(Priority::P0, RegularBackgroundSize::Background32x32);
for y in 0..20u16 { for y in 0..20u16 {
for x in 0..30u16 { for x in 0..30u16 {

View file

@ -6,6 +6,7 @@ use agb::{
display::{ display::{
object::{Object, ObjectController, Size, Sprite}, object::{Object, ObjectController, Size, Sprite},
palette16::Palette16, palette16::Palette16,
tiled::RegularBackgroundSize,
HEIGHT, WIDTH, HEIGHT, WIDTH,
}, },
input::Button, input::Button,
@ -54,7 +55,10 @@ fn main(mut gba: agb::Gba) -> ! {
vram.set_background_palette_raw(&MAP_PALETTE); vram.set_background_palette_raw(&MAP_PALETTE);
let tileset = TileSet::new(&MAP_TILES, TileFormat::FourBpp); let tileset = TileSet::new(&MAP_TILES, TileFormat::FourBpp);
let mut background = gfx.background(agb::display::Priority::P0); let mut background = gfx.background(
agb::display::Priority::P0,
RegularBackgroundSize::Background32x32,
);
for (i, &tile) in MAP_MAP.iter().enumerate() { for (i, &tile) in MAP_MAP.iter().enumerate() {
let i = i as u16; let i = i as u16;

View file

@ -1,7 +1,11 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use agb::display::{palette16::Palette16, tiled::TileSetting, Priority}; use agb::display::{
palette16::Palette16,
tiled::{RegularBackgroundSize, TileSetting},
Priority,
};
#[agb::entry] #[agb::entry]
fn main(mut gba: agb::Gba) -> ! { fn main(mut gba: agb::Gba) -> ! {
@ -13,7 +17,7 @@ fn main(mut gba: agb::Gba) -> ! {
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
])]); ])]);
let mut bg = gfx.background(Priority::P0); let mut bg = gfx.background(Priority::P0, RegularBackgroundSize::Background32x32);
for y in 0..20u32 { for y in 0..20u32 {
for x in 0..30u32 { for x in 0..30u32 {

View file

@ -1,13 +1,16 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use agb::display::example_logo; use agb::display::{example_logo, tiled::RegularBackgroundSize};
#[agb::entry] #[agb::entry]
fn main(mut gba: agb::Gba) -> ! { fn main(mut gba: agb::Gba) -> ! {
let (gfx, mut vram) = gba.display.video.tiled0(); let (gfx, mut vram) = gba.display.video.tiled0();
let mut map = gfx.background(agb::display::Priority::P0); let mut map = gfx.background(
agb::display::Priority::P0,
RegularBackgroundSize::Background32x32,
);
example_logo::display_logo(&mut map, &mut vram); example_logo::display_logo(&mut map, &mut vram);

View file

@ -2,7 +2,10 @@
#![no_main] #![no_main]
use agb::{ use agb::{
display::{tiled::TileSetting, Font, Priority}, display::{
tiled::{RegularBackgroundSize, TileSetting},
Font, Priority,
},
include_font, include_font,
}; };
@ -22,7 +25,7 @@ fn main(mut gba: agb::Gba) -> ! {
let background_tile = vram.new_dynamic_tile().fill_with(0); let background_tile = vram.new_dynamic_tile().fill_with(0);
let mut bg = gfx.background(Priority::P0); let mut bg = gfx.background(Priority::P0, RegularBackgroundSize::Background32x32);
for y in 0..20u16 { for y in 0..20u16 {
for x in 0..30u16 { for x in 0..30u16 {

View file

@ -4,7 +4,7 @@
use core::cell::RefCell; use core::cell::RefCell;
use agb::{ use agb::{
display::example_logo, display::{example_logo, tiled::RegularBackgroundSize},
fixnum::FixedNum, fixnum::FixedNum,
interrupt::{free, Interrupt}, interrupt::{free, Interrupt},
}; };
@ -19,7 +19,10 @@ struct BackCosines {
fn main(mut gba: agb::Gba) -> ! { fn main(mut gba: agb::Gba) -> ! {
let (gfx, mut vram) = gba.display.video.tiled0(); let (gfx, mut vram) = gba.display.video.tiled0();
let mut background = gfx.background(agb::display::Priority::P0); let mut background = gfx.background(
agb::display::Priority::P0,
RegularBackgroundSize::Background32x32,
);
example_logo::display_logo(&mut background, &mut vram); example_logo::display_logo(&mut background, &mut vram);

View file

@ -23,13 +23,15 @@ pub fn display_logo(map: &mut RegularMap, vram: &mut VRamManager) {
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::display::{tiled::RegularBackgroundSize, Priority};
use super::*; use super::*;
#[test_case] #[test_case]
fn logo_display(gba: &mut crate::Gba) { fn logo_display(gba: &mut crate::Gba) {
let (gfx, mut vram) = gba.display.video.tiled0(); let (gfx, mut vram) = gba.display.video.tiled0();
let mut map = gfx.background(crate::display::Priority::P0); let mut map = gfx.background(Priority::P0, RegularBackgroundSize::Background32x32);
display_logo(&mut map, &mut vram); display_logo(&mut map, &mut vram);

View file

@ -213,7 +213,10 @@ mod tests {
fn font_display(gba: &mut crate::Gba) { fn font_display(gba: &mut crate::Gba) {
let (gfx, mut vram) = gba.display.video.tiled0(); let (gfx, mut vram) = gba.display.video.tiled0();
let mut bg = gfx.background(crate::display::Priority::P0); let mut bg = gfx.background(
crate::display::Priority::P0,
crate::display::tiled::RegularBackgroundSize::Background32x32,
);
vram.set_background_palette_raw(&[ vram.set_background_palette_raw(&[
0x0000, 0x0ff0, 0x00ff, 0xf00f, 0xf0f0, 0x0f0f, 0xaaaa, 0x5555, 0x0000, 0x0000, 0x0000, 0x0000, 0x0ff0, 0x00ff, 0xf00f, 0xf0f0, 0x0f0f, 0xaaaa, 0x5555, 0x0000, 0x0000, 0x0000,

View file

@ -63,8 +63,8 @@ impl<'a> InfiniteScrolledMap<'a> {
let offset = self.current_pos - (x_start * 8, y_start * 8).into(); let offset = self.current_pos - (x_start * 8, y_start * 8).into();
let offset_scroll = ( let offset_scroll = (
offset.x.rem_euclid(32 * 8) as u16, self.map.size().tile_pos_x(offset.x),
offset.y.rem_euclid(32 * 8) as u16, self.map.size().tile_pos_y(offset.y),
) )
.into(); .into();
@ -120,6 +120,8 @@ impl<'a> InfiniteScrolledMap<'a> {
let difference_tile_x = div_ceil(difference.x, 8); let difference_tile_x = div_ceil(difference.x, 8);
let difference_tile_y = div_ceil(difference.y, 8); let difference_tile_y = div_ceil(difference.y, 8);
let size = self.map.size();
let vertical_rect_to_update: Rect<i32> = if div_floor(old_pos.x, 8) != new_tile_x { let vertical_rect_to_update: Rect<i32> = if div_floor(old_pos.x, 8) != new_tile_x {
// need to update the x line // need to update the x line
// calculate which direction we need to update // calculate which direction we need to update
@ -177,8 +179,8 @@ impl<'a> InfiniteScrolledMap<'a> {
self.map.set_tile( self.map.set_tile(
vram, vram,
( (
(tile_x - self.offset.x).rem_euclid(32) as u16, size.tile_pos_x(tile_x - self.offset.x),
(tile_y - self.offset.y).rem_euclid(32) as u16, size.tile_pos_y(tile_y - self.offset.y),
) )
.into(), .into(),
tileset, tileset,
@ -188,8 +190,8 @@ impl<'a> InfiniteScrolledMap<'a> {
let current_scroll = self.map.scroll_pos(); let current_scroll = self.map.scroll_pos();
let new_scroll = ( let new_scroll = (
(current_scroll.x as i32 + difference.x).rem_euclid(32 * 8) as u16, size.px_offset_x(current_scroll.x as i32 + difference.x),
(current_scroll.y as i32 + difference.y).rem_euclid(32 * 8) as u16, size.px_offset_y(current_scroll.y as i32 + difference.y),
) )
.into(); .into();

View file

@ -7,7 +7,9 @@ use crate::dma::dma_copy16;
use crate::fixnum::Vector2D; use crate::fixnum::Vector2D;
use crate::memory_mapped::MemoryMapped; use crate::memory_mapped::MemoryMapped;
use super::{Tile, TileSet, TileSetting, VRamManager}; use super::{RegularBackgroundSize, Tile, TileSet, TileSetting, VRamManager};
use alloc::{vec, vec::Vec};
pub struct RegularMap { pub struct RegularMap {
background_id: u8, background_id: u8,
@ -17,14 +19,21 @@ pub struct RegularMap {
y_scroll: u16, y_scroll: u16,
priority: Priority, priority: Priority,
tiles: [Tile; 32 * 32], tiles: Vec<Tile>,
tiles_dirty: bool, tiles_dirty: bool,
size: RegularBackgroundSize,
} }
pub const TRANSPARENT_TILE_INDEX: u16 = (1 << 10) - 1; pub const TRANSPARENT_TILE_INDEX: u16 = (1 << 10) - 1;
impl RegularMap { impl RegularMap {
pub(crate) fn new(background_id: u8, screenblock: u8, priority: Priority) -> Self { pub(crate) fn new(
background_id: u8,
screenblock: u8,
priority: Priority,
size: RegularBackgroundSize,
) -> Self {
Self { Self {
background_id, background_id,
@ -33,8 +42,10 @@ impl RegularMap {
y_scroll: 0, y_scroll: 0,
priority, priority,
tiles: [Tile::default(); 32 * 32], tiles: vec![Default::default(); size.num_tiles()],
tiles_dirty: true, tiles_dirty: true,
size,
} }
} }
@ -45,7 +56,7 @@ impl RegularMap {
tileset: &TileSet<'_>, tileset: &TileSet<'_>,
tile_setting: TileSetting, tile_setting: TileSetting,
) { ) {
let pos = (pos.x + pos.y * 32) as usize; let pos = self.size.gba_offset(pos);
let old_tile = self.tiles[pos]; let old_tile = self.tiles[pos];
if old_tile != Tile::default() { if old_tile != Tile::default() {
@ -93,7 +104,9 @@ impl RegularMap {
} }
pub fn commit(&mut self, vram: &mut VRamManager) { pub fn commit(&mut self, vram: &mut VRamManager) {
let new_bg_control_value = (self.priority as u16) | ((self.screenblock as u16) << 8); let new_bg_control_value = (self.priority as u16)
| ((self.screenblock as u16) << 8)
| (self.size.size_flag() << 14);
self.bg_control_register().set(new_bg_control_value); self.bg_control_register().set(new_bg_control_value);
self.bg_h_offset().set(self.x_scroll); self.bg_h_offset().set(self.x_scroll);
@ -111,7 +124,7 @@ impl RegularMap {
dma_copy16( dma_copy16(
self.tiles.as_ptr() as *const u16, self.tiles.as_ptr() as *const u16,
screenblock_memory, screenblock_memory,
32 * 32, self.size.num_tiles(),
); );
} }
@ -127,6 +140,10 @@ impl RegularMap {
(self.x_scroll, self.y_scroll).into() (self.x_scroll, self.y_scroll).into()
} }
pub(crate) fn size(&self) -> RegularBackgroundSize {
self.size
}
const fn bg_control_register(&self) -> MemoryMapped<u16> { const fn bg_control_register(&self) -> MemoryMapped<u16> {
unsafe { MemoryMapped::new(0x0400_0008 + 2 * self.background_id as usize) } unsafe { MemoryMapped::new(0x0400_0008 + 2 * self.background_id as usize) }
} }
@ -147,7 +164,10 @@ impl RegularMap {
pub struct MapLoan<'a, T> { pub struct MapLoan<'a, T> {
map: T, map: T,
background_id: u8, background_id: u8,
screenblock_id: u8,
screenblock_length: u8,
regular_map_list: &'a RefCell<Bitarray<1>>, regular_map_list: &'a RefCell<Bitarray<1>>,
screenblock_list: &'a RefCell<Bitarray<1>>,
} }
impl<'a, T> Deref for MapLoan<'a, T> { impl<'a, T> Deref for MapLoan<'a, T> {
@ -168,12 +188,18 @@ impl<'a, T> MapLoan<'a, T> {
pub(crate) fn new( pub(crate) fn new(
map: T, map: T,
background_id: u8, background_id: u8,
screenblock_id: u8,
screenblock_length: u8,
regular_map_list: &'a RefCell<Bitarray<1>>, regular_map_list: &'a RefCell<Bitarray<1>>,
screenblock_list: &'a RefCell<Bitarray<1>>,
) -> Self { ) -> Self {
MapLoan { MapLoan {
map, map,
background_id, background_id,
screenblock_id,
screenblock_length,
regular_map_list, regular_map_list,
screenblock_list,
} }
} }
} }
@ -183,5 +209,11 @@ impl<'a, T> Drop for MapLoan<'a, T> {
self.regular_map_list self.regular_map_list
.borrow_mut() .borrow_mut()
.set(self.background_id as usize, false); .set(self.background_id as usize, false);
let mut screenblock_list = self.screenblock_list.borrow_mut();
for i in self.screenblock_id..self.screenblock_id + self.screenblock_length {
screenblock_list.set(i as usize, false);
}
} }
} }

View file

@ -3,11 +3,86 @@ mod map;
mod tiled0; mod tiled0;
mod vram_manager; mod vram_manager;
use agb_fixnum::Vector2D;
pub use infinite_scrolled_map::{InfiniteScrolledMap, PartialUpdateStatus}; pub use infinite_scrolled_map::{InfiniteScrolledMap, PartialUpdateStatus};
pub use map::{MapLoan, RegularMap}; pub use map::{MapLoan, RegularMap};
pub use tiled0::Tiled0; pub use tiled0::Tiled0;
pub use vram_manager::{DynamicTile, TileFormat, TileIndex, TileSet, VRamManager}; pub use vram_manager::{DynamicTile, TileFormat, TileIndex, TileSet, VRamManager};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RegularBackgroundSize {
Background32x32,
Background64x32,
Background32x64,
Background64x64,
}
impl RegularBackgroundSize {
pub fn width(&self) -> u32 {
match self {
RegularBackgroundSize::Background32x32 => 32,
RegularBackgroundSize::Background64x32 => 64,
RegularBackgroundSize::Background32x64 => 32,
RegularBackgroundSize::Background64x64 => 64,
}
}
pub fn height(&self) -> u32 {
match self {
RegularBackgroundSize::Background32x32 => 32,
RegularBackgroundSize::Background64x32 => 32,
RegularBackgroundSize::Background32x64 => 64,
RegularBackgroundSize::Background64x64 => 64,
}
}
pub(crate) fn size_flag(&self) -> u16 {
match self {
RegularBackgroundSize::Background32x32 => 0,
RegularBackgroundSize::Background64x32 => 1,
RegularBackgroundSize::Background32x64 => 2,
RegularBackgroundSize::Background64x64 => 3,
}
}
pub(crate) fn num_tiles(&self) -> usize {
(self.width() * self.height()) as usize
}
pub(crate) fn num_screen_blocks(&self) -> usize {
self.num_tiles() / (32 * 32)
}
// This is hilariously complicated due to how the GBA stores the background screenblocks.
// See https://www.coranac.com/tonc/text/regbg.htm#sec-map for an explanation
pub(crate) fn gba_offset(&self, pos: Vector2D<u16>) -> usize {
let x_mod = pos.x & (self.width() as u16 - 1);
let y_mod = pos.y & (self.height() as u16 - 1);
let screenblock = (x_mod / 32) + (y_mod / 32) * (self.width() as u16 / 32);
let pos = screenblock * 32 * 32 + (x_mod % 32 + 32 * (y_mod % 32));
pos as usize
}
pub(crate) fn tile_pos_x(&self, x: i32) -> u16 {
((x as u32) & (self.width() - 1)) as u16
}
pub(crate) fn tile_pos_y(&self, y: i32) -> u16 {
((y as u32) & (self.height() - 1)) as u16
}
pub(crate) fn px_offset_x(&self, x: i32) -> u16 {
((x as u32) & (self.width() * 8 - 1)) as u16
}
pub(crate) fn px_offset_y(&self, y: i32) -> u16 {
((y as u32) & (self.height() * 8 - 1)) as u16
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[repr(transparent)] #[repr(transparent)]
struct Tile(u16); struct Tile(u16);
@ -47,3 +122,31 @@ impl TileSetting {
self.0 & !((1 << 10) - 1) self.0 & !((1 << 10) - 1)
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test_case]
fn rem_euclid_width_works(_gba: &mut crate::Gba) {
use RegularBackgroundSize::*;
let sizes = [
Background32x32,
Background32x64,
Background64x32,
Background64x64,
];
for size in sizes.iter() {
let width = size.width() as i32;
assert_eq!(size.tile_pos_x(8), 8);
assert_eq!(size.tile_pos_x(3 + width), 3);
assert_eq!(size.tile_pos_x(7 + width * 9), 7);
assert_eq!(size.tile_pos_x(-8), (size.width() - 8) as u16);
assert_eq!(size.tile_pos_x(-17 - width * 8), (size.width() - 17) as u16);
}
}
}

View file

@ -5,10 +5,11 @@ use crate::{
display::{set_graphics_mode, DisplayMode, Priority}, display::{set_graphics_mode, DisplayMode, Priority},
}; };
use super::{MapLoan, RegularMap}; use super::{MapLoan, RegularBackgroundSize, RegularMap};
pub struct Tiled0 { pub struct Tiled0 {
regular: RefCell<Bitarray<1>>, regular: RefCell<Bitarray<1>>,
screenblocks: RefCell<Bitarray<1>>,
} }
impl Tiled0 { impl Tiled0 {
@ -17,20 +18,61 @@ impl Tiled0 {
Self { Self {
regular: Default::default(), regular: Default::default(),
screenblocks: Default::default(),
} }
} }
pub fn background(&self, priority: Priority) -> MapLoan<'_, RegularMap> { pub fn background(
&self,
priority: Priority,
size: RegularBackgroundSize,
) -> MapLoan<'_, RegularMap> {
let mut regular = self.regular.borrow_mut(); let mut regular = self.regular.borrow_mut();
let new_background = regular.first_zero().unwrap(); let new_background = regular.first_zero().unwrap();
if new_background >= 4 { if new_background >= 4 {
panic!("can only have 4 active backgrounds"); panic!("can only have 4 active backgrounds");
} }
let bg = RegularMap::new(new_background as u8, (new_background + 16) as u8, priority); let num_screenblocks = size.num_screen_blocks();
let mut screenblocks = self.screenblocks.borrow_mut();
let screenblock = find_screenblock_gap(&screenblocks, num_screenblocks);
for id in screenblock..(screenblock + num_screenblocks) {
screenblocks.set(id, true);
}
let bg = RegularMap::new(new_background as u8, screenblock as u8 + 16, priority, size);
regular.set(new_background, true); regular.set(new_background, true);
MapLoan::new(bg, new_background as u8, &self.regular) MapLoan::new(
bg,
new_background as u8,
screenblock as u8,
num_screenblocks as u8,
&self.regular,
&self.screenblocks,
)
} }
} }
fn find_screenblock_gap(screenblocks: &Bitarray<1>, gap: usize) -> usize {
let mut candidate = 0;
'outer: while candidate < 16 - gap {
let starting_point = candidate;
for attempt in starting_point..(starting_point + gap) {
if screenblocks.get(attempt) == Some(true) {
candidate = attempt + 1;
continue 'outer;
}
}
return candidate;
}
panic!(
"Failed to find screenblock gap of at least {} elements",
gap
);
}

View file

@ -7,7 +7,8 @@ use agb::{
display::{ display::{
object::{Graphics, Object, ObjectController, Tag, TagMap}, object::{Graphics, Object, ObjectController, Tag, TagMap},
tiled::{ tiled::{
InfiniteScrolledMap, PartialUpdateStatus, TileFormat, TileSet, TileSetting, VRamManager, InfiniteScrolledMap, PartialUpdateStatus, RegularBackgroundSize, TileFormat, TileSet,
TileSetting, VRamManager,
}, },
Priority, HEIGHT, WIDTH, Priority, HEIGHT, WIDTH,
}, },
@ -777,8 +778,8 @@ impl<'a, 'b, 'c> PlayingLevel<'a, 'b> {
fn main(mut agb: agb::Gba) -> ! { fn main(mut agb: agb::Gba) -> ! {
let (tiled, mut vram) = agb.display.video.tiled0(); let (tiled, mut vram) = agb.display.video.tiled0();
vram.set_background_palettes(tile_sheet::background.palettes); vram.set_background_palettes(tile_sheet::background.palettes);
let mut splash_screen = tiled.background(Priority::P0); let mut splash_screen = tiled.background(Priority::P0, RegularBackgroundSize::Background32x32);
let mut world_display = tiled.background(Priority::P0); let mut world_display = tiled.background(Priority::P0, RegularBackgroundSize::Background32x32);
let tileset = TileSet::new(tile_sheet::background.tiles, TileFormat::FourBpp); let tileset = TileSet::new(tile_sheet::background.tiles, TileFormat::FourBpp);
@ -845,7 +846,7 @@ fn main(mut agb: agb::Gba) -> ! {
let map_current_level = current_level; let map_current_level = current_level;
let mut background = InfiniteScrolledMap::new( let mut background = InfiniteScrolledMap::new(
tiled.background(Priority::P2), tiled.background(Priority::P2, RegularBackgroundSize::Background32x64),
Box::new(|pos: Vector2D<i32>| { Box::new(|pos: Vector2D<i32>| {
let level = &map_tiles::LEVELS[map_current_level as usize]; let level = &map_tiles::LEVELS[map_current_level as usize];
( (
@ -860,7 +861,7 @@ fn main(mut agb: agb::Gba) -> ! {
}), }),
); );
let mut foreground = InfiniteScrolledMap::new( let mut foreground = InfiniteScrolledMap::new(
tiled.background(Priority::P0), tiled.background(Priority::P0, RegularBackgroundSize::Background64x32),
Box::new(|pos: Vector2D<i32>| { Box::new(|pos: Vector2D<i32>| {
let level = &map_tiles::LEVELS[map_current_level as usize]; let level = &map_tiles::LEVELS[map_current_level as usize];
( (

View file

@ -12,7 +12,10 @@ use alloc::{boxed::Box, vec::Vec};
use agb::{ use agb::{
display::{ display::{
object::{Graphics, Object, ObjectController, Sprite, Tag, TagMap}, object::{Graphics, Object, ObjectController, Sprite, Tag, TagMap},
tiled::{InfiniteScrolledMap, TileFormat, TileSet, TileSetting, VRamManager}, tiled::{
InfiniteScrolledMap, RegularBackgroundSize, TileFormat, TileSet, TileSetting,
VRamManager,
},
Priority, HEIGHT, WIDTH, Priority, HEIGHT, WIDTH,
}, },
fixnum::{FixedNum, Rect, Vector2D}, fixnum::{FixedNum, Rect, Vector2D},
@ -2221,7 +2224,7 @@ fn game_with_level(gba: &mut agb::Gba) {
let object = gba.display.object.get(); let object = gba.display.object.get();
let backdrop = InfiniteScrolledMap::new( let backdrop = InfiniteScrolledMap::new(
background.background(Priority::P2), background.background(Priority::P2, RegularBackgroundSize::Background32x32),
Box::new(|pos| { Box::new(|pos| {
( (
&tileset, &tileset,
@ -2235,7 +2238,7 @@ fn game_with_level(gba: &mut agb::Gba) {
); );
let foreground = InfiniteScrolledMap::new( let foreground = InfiniteScrolledMap::new(
background.background(Priority::P0), background.background(Priority::P0, RegularBackgroundSize::Background32x32),
Box::new(|pos| { Box::new(|pos| {
( (
&tileset, &tileset,
@ -2249,7 +2252,7 @@ fn game_with_level(gba: &mut agb::Gba) {
); );
let clouds = InfiniteScrolledMap::new( let clouds = InfiniteScrolledMap::new(
background.background(Priority::P3), background.background(Priority::P3, RegularBackgroundSize::Background32x32),
Box::new(|pos| { Box::new(|pos| {
( (
&tileset, &tileset,