mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-24 00:31:34 +11:00
Merge pull request #225 from gwilymk/allow-setting-size-of-backgrounds
Allow setting size of backgrounds
This commit is contained in:
commit
5c76961506
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -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];
|
||||||
(
|
(
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue