diff --git a/agb/examples/dma_effect.rs b/agb/examples/dma_effect.rs index e76545d2..5d08c693 100644 --- a/agb/examples/dma_effect.rs +++ b/agb/examples/dma_effect.rs @@ -8,7 +8,7 @@ use alloc::boxed::Box; use agb::{ display::{ example_logo, - tiled::{RegularBackgroundSize, TileFormat}, + tiled::{RegularBackgroundSize, TileFormat, TiledMap}, }, interrupt::VBlank, }; @@ -17,6 +17,8 @@ use agb::{ fn main(mut gba: agb::Gba) -> ! { let (gfx, mut vram) = gba.display.video.tiled0(); + let mut input = agb::input::ButtonController::new(); + let mut map = gfx.background( agb::display::Priority::P0, RegularBackgroundSize::Background32x32, @@ -30,12 +32,36 @@ fn main(mut gba: agb::Gba) -> ! { let vblank = VBlank::get(); let offsets: Box<[_]> = (0..160 * 2).collect(); + let colours: Box<[_]> = (0..160).map(|i| ((i * 0xffff) / 160) as u16).collect(); let mut frame = 0; - loop { - let _transfer = unsafe { dma.hblank_transfer(&map.x_scroll_dma(), &offsets[frame..]) }; + let mut effect = false; + loop { + input.update(); + + if input.is_just_pressed(agb::input::Button::A) { + effect = !effect; + } + + let _x_scroll_transfer = if effect { + Some(unsafe { dma.hblank_transfer(&map.x_scroll_dma(), &offsets[frame..]) }) + } else { + map.set_scroll_pos((0i16, 0i16)); + None + }; + + let _background_color_transfer = if !effect { + Some(unsafe { + dma.hblank_transfer(&vram.background_palette_colour_dma(0, 2), &colours) + }) + } else { + vram.set_background_palette_colour(0, 0, 0xffff); + None + }; + + map.commit(&mut vram); vblank.wait_for_vblank(); frame += 1; if frame > 160 { diff --git a/agb/src/display/tiled/infinite_scrolled_map.rs b/agb/src/display/tiled/infinite_scrolled_map.rs index 7d6e66fb..cd510810 100644 --- a/agb/src/display/tiled/infinite_scrolled_map.rs +++ b/agb/src/display/tiled/infinite_scrolled_map.rs @@ -258,8 +258,7 @@ impl<'a> InfiniteScrolledMap<'a> { let offset = self.current_pos - (x_start * 8, y_start * 8).into(); - self.map - .set_scroll_pos((offset.x as i16, offset.y as i16).into()); + self.map.set_scroll_pos((offset.x as i16, offset.y as i16)); self.offset = (x_start, y_start).into(); let copy_from = self.copied_up_to; diff --git a/agb/src/display/tiled/map.rs b/agb/src/display/tiled/map.rs index ec379d0c..c7185c3c 100644 --- a/agb/src/display/tiled/map.rs +++ b/agb/src/display/tiled/map.rs @@ -291,8 +291,8 @@ impl RegularMap { self.scroll } - pub fn set_scroll_pos(&mut self, pos: Vector2D) { - self.scroll = pos; + pub fn set_scroll_pos(&mut self, pos: impl Into>) { + self.scroll = pos.into(); } #[must_use] diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index fcbfe69f..55503332 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -5,6 +5,7 @@ use alloc::{slice, vec::Vec}; use crate::{ agb_alloc::{block_allocator::BlockAllocator, bump_allocator::StartEnd}, display::palette16, + dma, hash_map::{Entry, HashMap}, memory_mapped::MemoryMapped1DArray, }; @@ -424,6 +425,36 @@ impl VRamManager { } } + /// The DMA register for controlling a single colour in a single background. Good for drawing gradients + #[must_use] + pub fn background_palette_colour_dma( + &self, + pal_index: usize, + colour_index: usize, + ) -> dma::DmaControllable { + assert!(pal_index < 16); + assert!(colour_index < 16); + + dma::DmaControllable::new(unsafe { + PALETTE_BACKGROUND + .as_ptr() + .add(16 * pal_index + colour_index) + }) + } + + /// Sets a single colour for a given background palette. Takes effect immediately + pub fn set_background_palette_colour( + &mut self, + pal_index: usize, + colour_index: usize, + colour: u16, + ) { + assert!(pal_index < 16); + assert!(colour_index < 16); + + PALETTE_BACKGROUND.set(colour_index + 16 * pal_index, colour); + } + /// Copies palettes to the background palettes without any checks. pub fn set_background_palettes(&mut self, palettes: &[palette16::Palette16]) { for (palette_index, entry) in palettes.iter().enumerate() {