diff --git a/agb-fixnum/src/lib.rs b/agb-fixnum/src/lib.rs index 99aa5d3a..cc5669a6 100644 --- a/agb-fixnum/src/lib.rs +++ b/agb-fixnum/src/lib.rs @@ -570,7 +570,7 @@ impl Debug for Num { } /// A vector of two points: (x, y) represened by integers or fixed point numbers -#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] #[repr(C)] pub struct Vector2D { /// The x coordinate @@ -1016,7 +1016,7 @@ impl Vector2D { } } -impl > Neg for Vector2D { +impl> Neg for Vector2D { type Output = Self; fn neg(self) -> Self::Output { diff --git a/agb/examples/affine_background.rs b/agb/examples/affine_background.rs index 2e336b13..9c337f8a 100644 --- a/agb/examples/affine_background.rs +++ b/agb/examples/affine_background.rs @@ -56,13 +56,9 @@ fn main(mut gba: agb::Gba) -> ! { _ => {} } - bg.set_scroll_pos((16 * 4, 16 * 4).into()); let scroll_pos = (scroll_x as i16, scroll_y as i16); - bg.set_transform( - scroll_pos, - (1, 1), - rotation, - ); + bg.set_scroll_pos(scroll_pos.into()); + bg.set_transform((0, 0), (1, 1), 0); rotation += rotation_increase; if rotation >= num!(255.) { diff --git a/agb/src/display/object.rs b/agb/src/display/object.rs index 4389a0fa..4d76b9a5 100644 --- a/agb/src/display/object.rs +++ b/agb/src/display/object.rs @@ -1197,7 +1197,7 @@ enum ColourMode { /// that can apply to objects and background layers in modes 1 and 2. /// This can be obtained from X/Y scale and rotation angle with /// [`agb::syscall::affine_matrix`]. -#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(C, packed)] pub struct AffineMatrixAttributes { /// Adjustment made to *X* coordinate when drawing *horizontal* lines. @@ -1218,6 +1218,17 @@ pub struct AffineMatrixAttributes { pub p_d: Num, } +impl Default for AffineMatrixAttributes { + fn default() -> Self { + Self { + p_a: 1.into(), + p_b: Default::default(), + p_c: Default::default(), + p_d: 1.into(), + } + } +} + // this mod is not public, so the internal parts don't need documenting. #[allow(dead_code)] mod attributes { diff --git a/agb/src/display/tiled/infinite_scrolled_map.rs b/agb/src/display/tiled/infinite_scrolled_map.rs index 8497802c..773ff782 100644 --- a/agb/src/display/tiled/infinite_scrolled_map.rs +++ b/agb/src/display/tiled/infinite_scrolled_map.rs @@ -257,13 +257,9 @@ impl<'a> InfiniteScrolledMap<'a> { let y_end = div_ceil(self.current_pos.y + display::HEIGHT, 8) + 1; let offset = self.current_pos - (x_start * 8, y_start * 8).into(); - let offset_scroll = ( - self.map.size().tile_pos_x(offset.x), - self.map.size().tile_pos_y(offset.y), - ) - .into(); - self.map.set_scroll_pos(offset_scroll); + self.map + .set_scroll_pos((offset.x as i16, offset.y as i16).into()); self.offset = (x_start, y_start).into(); let copy_from = self.copied_up_to; @@ -386,11 +382,7 @@ impl<'a> InfiniteScrolledMap<'a> { } let current_scroll = self.map.scroll_pos(); - let new_scroll = ( - size.px_offset_x(i32::from(current_scroll.x) + difference.x), - size.px_offset_y(i32::from(current_scroll.y) + difference.y), - ) - .into(); + let new_scroll = current_scroll + (difference.x as i16, difference.y as i16).into(); self.map.set_scroll_pos(new_scroll); diff --git a/agb/src/display/tiled/map.rs b/agb/src/display/tiled/map.rs index 45b09646..f5b60d89 100644 --- a/agb/src/display/tiled/map.rs +++ b/agb/src/display/tiled/map.rs @@ -4,7 +4,7 @@ use core::ops::{Deref, DerefMut}; use crate::bitarray::Bitarray; use crate::display::{object::AffineMatrixAttributes, Priority, DISPLAY_CONTROL}; use crate::dma::dma_copy16; -use crate::fixnum::{Num, Number, Vector2D}; +use crate::fixnum::{Num, Vector2D}; use crate::memory_mapped::MemoryMapped; use super::{ @@ -16,7 +16,6 @@ use crate::syscall::BgAffineSetData; use alloc::{vec, vec::Vec}; pub trait TiledMapTypes { - type Position: Number; type Size: BackgroundSize + Copy; } @@ -26,19 +25,17 @@ trait TiledMapPrivate: TiledMapTypes { fn tiles_mut(&mut self) -> &mut [Self::TileType]; fn tiles_dirty(&mut self) -> &mut bool; - fn x_scroll_mut(&mut self) -> &mut Self::Position; - fn y_scroll_mut(&mut self) -> &mut Self::Position; - fn x_scroll(&self) -> Self::Position; - fn y_scroll(&self) -> Self::Position; - fn affine_matrix(&self) -> Self::AffineMatrix; fn background_id(&self) -> usize; fn screenblock(&self) -> usize; fn priority(&self) -> Priority; fn map_size(&self) -> Self::Size; - fn bg_x(&self) -> MemoryMapped; - fn bg_y(&self) -> MemoryMapped; - fn bg_affine_matrix(&self) -> MemoryMapped; + + fn update_bg_registers(&self); + + fn scroll_pos(&self) -> Vector2D; + fn set_scroll_pos(&mut self, new_pos: Vector2D); + fn bg_control_register(&self) -> MemoryMapped { unsafe { MemoryMapped::new(0x0400_0008 + 2 * self.background_id()) } } @@ -55,8 +52,8 @@ pub trait TiledMap: TiledMapTypes { fn size(&self) -> Self::Size; #[must_use] - fn scroll_pos(&self) -> Vector2D; - fn set_scroll_pos(&mut self, pos: Vector2D); + fn scroll_pos(&self) -> Vector2D; + fn set_scroll_pos(&mut self, pos: Vector2D); } impl TiledMap for T @@ -92,9 +89,7 @@ where | (self.map_size().size_flag() << 14); self.bg_control_register().set(new_bg_control_value); - self.bg_x().set(self.x_scroll()); - self.bg_y().set(self.y_scroll()); - self.bg_affine_matrix().set(self.affine_matrix()); + self.update_bg_registers(); let screenblock_memory = self.screenblock_memory(); let x: TileIndex = unsafe { *self.tiles_mut().get_unchecked(0) }.into(); @@ -119,13 +114,12 @@ where } #[must_use] - fn scroll_pos(&self) -> Vector2D { - (self.x_scroll(), self.y_scroll()).into() + fn scroll_pos(&self) -> Vector2D { + TiledMapPrivate::scroll_pos(self) } - fn set_scroll_pos(&mut self, pos: Vector2D) { - *self.x_scroll_mut() = pos.x; - *self.y_scroll_mut() = pos.y; + fn set_scroll_pos(&mut self, pos: Vector2D) { + TiledMapPrivate::set_scroll_pos(self, pos); } } @@ -135,8 +129,7 @@ pub struct RegularMap { priority: Priority, size: RegularBackgroundSize, - x_scroll: u16, - y_scroll: u16, + scroll: Vector2D, tiles: Vec, tiles_dirty: bool, @@ -145,7 +138,6 @@ pub struct RegularMap { pub const TRANSPARENT_TILE_INDEX: u16 = (1 << 10) - 1; impl TiledMapTypes for RegularMap { - type Position = u16; type Size = RegularBackgroundSize; } @@ -159,19 +151,7 @@ impl TiledMapPrivate for RegularMap { fn tiles_dirty(&mut self) -> &mut bool { &mut self.tiles_dirty } - fn x_scroll_mut(&mut self) -> &mut Self::Position { - &mut self.x_scroll - } - fn y_scroll_mut(&mut self) -> &mut Self::Position { - &mut self.y_scroll - } - fn x_scroll(&self) -> Self::Position { - self.x_scroll - } - fn y_scroll(&self) -> Self::Position { - self.y_scroll - } - fn affine_matrix(&self) -> Self::AffineMatrix {} + fn background_id(&self) -> usize { self.background_id as usize } @@ -184,14 +164,15 @@ impl TiledMapPrivate for RegularMap { fn map_size(&self) -> Self::Size { self.size } - fn bg_x(&self) -> MemoryMapped { - unsafe { MemoryMapped::new(0x0400_0010 + 4 * self.background_id as usize) } + fn update_bg_registers(&self) { + self.x_register().set(self.scroll.x); + self.y_register().set(self.scroll.y); } - fn bg_y(&self) -> MemoryMapped { - unsafe { MemoryMapped::new(0x0400_0012 + 4 * self.background_id as usize) } + fn scroll_pos(&self) -> Vector2D { + self.scroll } - fn bg_affine_matrix(&self) -> MemoryMapped { - unsafe { MemoryMapped::new(0) } + fn set_scroll_pos(&mut self, new_pos: Vector2D) { + self.scroll = new_pos; } } @@ -208,8 +189,7 @@ impl RegularMap { priority, size, - x_scroll: 0, - y_scroll: 0, + scroll: Default::default(), tiles: vec![Default::default(); size.num_tiles()], tiles_dirty: true, @@ -247,6 +227,14 @@ impl RegularMap { self.tiles_mut()[pos] = new_tile; *self.tiles_dirty() = true; } + + fn x_register(&self) -> MemoryMapped { + unsafe { MemoryMapped::new(0x0400_0010 + 4 * self.background_id as usize) } + } + + fn y_register(&self) -> MemoryMapped { + unsafe { MemoryMapped::new(0x0400_0012 + 4 * self.background_id as usize) } + } } pub struct AffineMap { @@ -255,7 +243,9 @@ pub struct AffineMap { priority: Priority, size: AffineBackgroundSize, - bg_center: Vector2D>, + scroll: Vector2D, + + transform_origin: Vector2D>, transform: BgAffineSetData, tiles: Vec, @@ -263,7 +253,6 @@ pub struct AffineMap { } impl TiledMapTypes for AffineMap { - type Position = Num; type Size = AffineBackgroundSize; } @@ -277,21 +266,6 @@ impl TiledMapPrivate for AffineMap { fn tiles_dirty(&mut self) -> &mut bool { &mut self.tiles_dirty } - fn x_scroll_mut(&mut self) -> &mut Self::Position { - &mut self.bg_center.x - } - fn y_scroll_mut(&mut self) -> &mut Self::Position { - &mut self.bg_center.y - } - fn x_scroll(&self) -> Self::Position { - self.bg_center.x + self.transform.position.x - } - fn y_scroll(&self) -> Self::Position { - self.bg_center.y + self.transform.position.y - } - fn affine_matrix(&self) -> Self::AffineMatrix { - self.transform.matrix - } fn background_id(&self) -> usize { self.background_id as usize } @@ -304,14 +278,23 @@ impl TiledMapPrivate for AffineMap { fn map_size(&self) -> Self::Size { self.size } - fn bg_x(&self) -> MemoryMapped { - unsafe { MemoryMapped::new(0x0400_0008 + 0x10 * self.background_id()) } + fn update_bg_registers(&self) { + let register_pos = self.transform.position + self.transform_origin; + self.bg_x().set(register_pos.x); + self.bg_y().set(register_pos.y); + self.bg_affine_matrix().set(self.transform.matrix); + + crate::println!( + "update: {:?} {:?}", + self.transform.matrix, + self.bg_affine_matrix().get() + ); } - fn bg_y(&self) -> MemoryMapped { - unsafe { MemoryMapped::new(0x0400_000c + 0x10 * self.background_id()) } + fn scroll_pos(&self) -> Vector2D { + self.scroll } - fn bg_affine_matrix(&self) -> MemoryMapped { - unsafe { MemoryMapped::new(0x0400_0000 + 0x10 * self.background_id()) } + fn set_scroll_pos(&mut self, new_pos: Vector2D) { + self.scroll = new_pos; } } @@ -321,7 +304,6 @@ impl AffineMap { screenblock: u8, priority: Priority, size: AffineBackgroundSize, - bg_center: Vector2D>, ) -> Self { Self { background_id, @@ -329,7 +311,9 @@ impl AffineMap { priority, size, - bg_center, + scroll: Default::default(), + + transform_origin: Default::default(), transform: Default::default(), tiles: vec![Default::default(); size.num_tiles()], @@ -369,22 +353,36 @@ impl AffineMap { *self.tiles_dirty() = true; } - pub fn set_transform_raw(&mut self, transform: BgAffineSetData) { - self.transform = transform; - } - pub fn set_transform( &mut self, - display_center: impl Into>, + transform_origin: impl Into>>, scale: impl Into>>, rotation: impl Into>, ) { - self.set_transform_raw(crate::syscall::bg_affine_matrix( - self.bg_center, - display_center.into(), - scale.into(), - rotation.into(), - )); + self.transform_origin = transform_origin.into(); + let scale = scale.into(); + let rotation = rotation.into(); + self.transform = + crate::syscall::bg_affine_matrix(self.transform_origin, self.scroll, scale, rotation); + + crate::println!( + "{:?}, {:?}, {:?}, {:?}", + self.transform_origin, + self.scroll, + scale, + rotation + ); + crate::println!("{:?}", self.transform.matrix); + } + + fn bg_x(&self) -> MemoryMapped> { + unsafe { MemoryMapped::new(0x0400_0008 + 0x10 * self.background_id()) } + } + fn bg_y(&self) -> MemoryMapped> { + unsafe { MemoryMapped::new(0x0400_000c + 0x10 * self.background_id()) } + } + fn bg_affine_matrix(&self) -> MemoryMapped { + unsafe { MemoryMapped::new(0x0400_0000 + 0x10 * self.background_id()) } } } diff --git a/agb/src/display/tiled/mod.rs b/agb/src/display/tiled/mod.rs index 164ce3a6..ea23aa4a 100644 --- a/agb/src/display/tiled/mod.rs +++ b/agb/src/display/tiled/mod.rs @@ -7,7 +7,7 @@ mod vram_manager; use crate::bitarray::Bitarray; use crate::display::Priority; -use agb_fixnum::{Num, Vector2D}; +use agb_fixnum::Vector2D; use core::cell::RefCell; pub use infinite_scrolled_map::{InfiniteScrolledMap, PartialUpdateStatus}; pub use map::{AffineMap, MapLoan, RegularMap, TiledMap}; @@ -307,16 +307,7 @@ where screenblocks.set(id, true); } - let center_dim = Num::new(size.width() as i32 * 8 / 2); - let default_bg_center = (center_dim, center_dim).into(); - - let bg = AffineMap::new( - new_background as u8, - screenblock as u8 + 16, - priority, - size, - default_bg_center, - ); + let bg = AffineMap::new(new_background as u8, screenblock as u8 + 16, priority, size); affine.set(new_background, true); diff --git a/agb/src/syscall.rs b/agb/src/syscall.rs index e7d342bd..dd123ace 100644 --- a/agb/src/syscall.rs +++ b/agb/src/syscall.rs @@ -185,7 +185,8 @@ pub fn bg_affine_matrix( in("r0") &input as *const Input, in("r1") output.as_mut_ptr(), in("r2") 1, - lateout("r3") _, + + clobber_abi("C") ); } @@ -231,7 +232,7 @@ mod tests { use super::*; #[test_case] - fn affine(_gba: &mut crate::Gba) { + fn affine_obj(_gba: &mut crate::Gba) { // expect identity matrix let one: Num = 1.into(); @@ -241,4 +242,22 @@ mod tests { assert_eq!(p_a, one); assert_eq!(p_d, one); } + + #[test_case] + fn affine_bg(_gba: &mut crate::Gba) { + // expect the identity matrix + let aff = bg_affine_matrix( + (0, 0).into(), + (0i16, 0i16).into(), + (1i16, 1i16).into(), + 0.into(), + ); + + let matrix = aff.matrix; + let (p_a, p_b, p_c, p_d) = (matrix.p_a, matrix.p_b, matrix.p_c, matrix.p_d); + assert_eq!(p_a, 1.into()); + assert_eq!(p_b, 0.into()); + assert_eq!(p_c, 0.into()); + assert_eq!(p_d, 1.into()); + } } diff --git a/examples/hyperspace-roll/src/background.rs b/examples/hyperspace-roll/src/background.rs index 037fa20a..91d16c95 100644 --- a/examples/hyperspace-roll/src/background.rs +++ b/examples/hyperspace-roll/src/background.rs @@ -1,27 +1,21 @@ use agb::{ - display::tiled::{RegularMap, TileFormat, TileSet, TileSetting, TiledMap, VRamManager}, + display::tiled::{RegularMap, TileFormat, TileSet, TileSetting, VRamManager}, include_gfx, rng, }; use crate::sfx::Sfx; -include_gfx!("gfx/backgrounds.toml"); +include_gfx!("gfx/stars.toml"); + +include_gfx!("gfx/help.toml"); pub fn load_palettes(vram: &mut VRamManager) { - vram.set_background_palettes(backgrounds::stars.palettes); -} - -fn description_tileset() -> (TileSet<'static>, TileSet<'static>) { - let descriptions_1_tileset = TileSet::new( - backgrounds::descriptions1.tiles, - agb::display::tiled::TileFormat::FourBpp, - ); - let descriptions_2_tileset = TileSet::new( - backgrounds::descriptions2.tiles, - agb::display::tiled::TileFormat::FourBpp, - ); - - (descriptions_1_tileset, descriptions_2_tileset) + vram.set_background_palettes(&[ + stars::stars.palettes[0].clone(), + crate::customise::DESCRIPTIONS_1_PALETTE.clone(), + crate::customise::DESCRIPTIONS_2_PALETTE.clone(), + help::help.palettes[0].clone(), + ]); } pub(crate) fn load_help_text( @@ -30,69 +24,18 @@ pub(crate) fn load_help_text( help_text_line: u16, at_tile: (u16, u16), ) { - let help_tileset = TileSet::new( - backgrounds::help.tiles, - agb::display::tiled::TileFormat::FourBpp, - ); + let help_tileset = TileSet::new(help::help.tiles, agb::display::tiled::TileFormat::FourBpp); for x in 0..16 { - let tile_id = help_text_line * 16 + x; background.set_tile( vram, (x + at_tile.0, at_tile.1).into(), &help_tileset, - TileSetting::new( - tile_id, - false, - false, - backgrounds::help.palette_assignments[tile_id as usize], - ), + TileSetting::new(help_text_line * 16 + x, false, false, 3), ) } } -pub(crate) fn load_description( - upgrade: usize, - descriptions_map: &mut RegularMap, - vram: &mut VRamManager, -) { - let (descriptions_1_tileset, descriptions_2_tileset) = description_tileset(); - - for y in 0..11 { - for x in 0..8 { - if upgrade < 10 { - let tile_id = y * 8 + x + 8 * 11 * upgrade as u16; - - descriptions_map.set_tile( - vram, - (x, y).into(), - &descriptions_1_tileset, - TileSetting::new( - tile_id, - false, - false, - backgrounds::descriptions1.palette_assignments[tile_id as usize], - ), - ) - } else { - let tile_id = y * 8 + x + 8 * 11 * (upgrade as u16 - 10); - - descriptions_map.set_tile( - vram, - (x, y).into(), - &descriptions_2_tileset, - TileSetting::new( - tile_id, - false, - false, - backgrounds::descriptions2.palette_assignments[tile_id as usize], - ), - ) - } - } - } -} - // Expects a 64x32 map fn create_background_map(map: &mut RegularMap, vram: &mut VRamManager, stars_tileset: &TileSet) { for x in 0..64u16 { @@ -104,16 +47,7 @@ fn create_background_map(map: &mut RegularMap, vram: &mut VRamManager, stars_til } else { rng::gen().rem_euclid(64) as u16 }; - let tile_setting = TileSetting::new( - tile_id, - false, - false, - if blank { - 0 - } else { - backgrounds::stars.palette_assignments[tile_id as usize] - }, - ); + let tile_setting = TileSetting::new(tile_id, false, false, 0); map.set_tile(vram, (x, y).into(), stars_tileset, tile_setting); } @@ -124,11 +58,8 @@ fn create_background_map(map: &mut RegularMap, vram: &mut VRamManager, stars_til pub fn show_title_screen(background: &mut RegularMap, vram: &mut VRamManager, sfx: &mut Sfx) { background.set_scroll_pos((0_u16, 0_u16).into()); - vram.set_background_palettes(backgrounds::title.palettes); - let tile_set = TileSet::new( - backgrounds::title.tiles, - agb::display::tiled::TileFormat::FourBpp, - ); + vram.set_background_palettes(stars::title.palettes); + let tile_set = TileSet::new(stars::title.tiles, agb::display::tiled::TileFormat::FourBpp); background.hide(); for x in 0..30u16 { @@ -142,7 +73,7 @@ pub fn show_title_screen(background: &mut RegularMap, vram: &mut VRamManager, sf tile_id, false, false, - backgrounds::title.palette_assignments[tile_id as usize], + stars::title.palette_assignments[tile_id as usize], ), ); } @@ -169,7 +100,7 @@ impl<'a> StarBackground<'a> { background2: &'a mut RegularMap, vram: &'_ mut VRamManager, ) -> Self { - let stars_tileset = TileSet::new(backgrounds::stars.tiles, TileFormat::FourBpp); + let stars_tileset = TileSet::new(stars::stars.tiles, TileFormat::FourBpp); create_background_map(background1, vram, &stars_tileset); create_background_map(background2, vram, &stars_tileset);