From ebc4e15f3d9da4d944922eb6b67b6992f1930ca4 Mon Sep 17 00:00:00 2001
From: Corwin <corwin@kuiper.dev>
Date: Fri, 15 Jul 2022 21:59:36 +0100
Subject: [PATCH 1/9] constify sprite function

---
 agb/src/display/object.rs | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/agb/src/display/object.rs b/agb/src/display/object.rs
index 0b88c3e1..8f18f34b 100644
--- a/agb/src/display/object.rs
+++ b/agb/src/display/object.rs
@@ -249,8 +249,11 @@ impl Tag {
     }
 
     #[must_use]
-    pub fn sprite(&self, idx: usize) -> &'static Sprite {
-        &self.sprites()[idx]
+    pub const fn sprite(&self, idx: usize) -> &'static Sprite {
+        if idx >= self.len {
+            panic!("out of bounds access to sprite");
+        }
+        unsafe { &*self.sprites.add(idx) }
     }
 
     #[inline]

From 8a55fc7f0e7cca350fa2568b77d0ca95e92bf420 Mon Sep 17 00:00:00 2001
From: Corwin <corwin@kuiper.dev>
Date: Sat, 16 Jul 2022 09:08:35 +0100
Subject: [PATCH 2/9] support larger sprites

---
 agb-image-converter/src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs
index 6077dc1c..baa3a92c 100644
--- a/agb-image-converter/src/lib.rs
+++ b/agb-image-converter/src/lib.rs
@@ -115,7 +115,7 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream {
 
         for frame in frames {
             let width = frame.width();
-            assert!(width == frame.height() && width.is_power_of_two() && width <= 32);
+            assert!(width == frame.height() && width.is_power_of_two() && width <= 64);
 
             let image = Image::load_from_dyn_image(frame);
             add_to_optimiser(

From 2026e49569627e889dbd0d606e09abc1c9a6d242 Mon Sep 17 00:00:00 2001
From: Gwilym Kuiper <gw@ilym.me>
Date: Fri, 15 Jul 2022 23:55:19 +0100
Subject: [PATCH 3/9] Start the tile ram one tile in to prevent overwriting the
 transparent tile

---
 agb/src/display/tiled/vram_manager.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs
index a2a2ce15..6caa8956 100644
--- a/agb/src/display/tiled/vram_manager.rs
+++ b/agb/src/display/tiled/vram_manager.rs
@@ -17,7 +17,7 @@ const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
 
 static TILE_ALLOCATOR: BlockAllocator = unsafe {
     BlockAllocator::new(StartEnd {
-        start: || TILE_RAM_START,
+        start: || TILE_RAM_START + 8 * 8,
         end: || TILE_RAM_START + 0x8000,
     })
 };

From 1be10ba45031b921322bb7a0e76f754bd18d2c83 Mon Sep 17 00:00:00 2001
From: Corwin <corwin@kuiper.dev>
Date: Sat, 16 Jul 2022 13:36:33 +0100
Subject: [PATCH 4/9] align sprite data to 2 byte boundaries

---
 agb-image-converter/src/lib.rs |  2 +-
 agb/src/display/object.rs      | 33 ++++++++++++++++++++++++++++-----
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs
index baa3a92c..c9c58898 100644
--- a/agb-image-converter/src/lib.rs
+++ b/agb-image-converter/src/lib.rs
@@ -154,7 +154,7 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream {
             quote! {
                 Sprite::new(
                     &PALETTES[#assignment],
-                    #data,
+                    align_bytes!(u16, #data),
                     Size::from_width_height(#width, #height)
                 )
             }
diff --git a/agb/src/display/object.rs b/agb/src/display/object.rs
index 8f18f34b..b5a3287b 100644
--- a/agb/src/display/object.rs
+++ b/agb/src/display/object.rs
@@ -135,11 +135,32 @@ pub enum Size {
     S32x64 = 0b10_11,
 }
 
+#[repr(C)] // guarantee 'bytes' comes after '_align'
+pub struct AlignedAs<Align, Bytes: ?Sized> {
+    pub _align: [Align; 0],
+    pub bytes: Bytes,
+}
+
+#[macro_export]
+macro_rules! align_bytes {
+    ($align_ty:ty, $data:literal) => {{
+        use $crate::display::object::AlignedAs;
+
+        const ALIGNED: &AlignedAs<$align_ty, [u8]> = &AlignedAs {
+            _align: [],
+            bytes: *$data,
+        };
+
+        &ALIGNED.bytes
+    }};
+}
+
 #[macro_export]
 macro_rules! include_aseprite {
     ($($aseprite_path: expr),*) => {{
         use $crate::display::object::{Size, Sprite, Tag, TagMap, Graphics};
         use $crate::display::palette16::Palette16;
+        use $crate::align_bytes;
 
         $crate::include_aseprite_inner!($($aseprite_path),*);
 
@@ -778,11 +799,13 @@ impl SpriteControllerInner {
             };
 
             unsafe {
-                dma::dma_copy16(
-                    sprite.data.as_ptr().cast(),
-                    dest.as_ptr().cast(),
-                    sprite.data.len() / 2,
-                );
+                dest.as_ptr()
+                    .copy_from_nonoverlapping(sprite.data.as_ptr(), sprite.data.len());
+                // dma::dma_copy16(
+                //     sprite.data.as_ptr().cast(),
+                //     dest.as_ptr().cast(),
+                //     sprite.data.len() / 2,
+                // );
             }
 
             let storage = Storage::from_sprite_ptr(dest);

From 3d579390c8b652f1175cf14b553dac09c11064c4 Mon Sep 17 00:00:00 2001
From: Gwilym Kuiper <gw@ilym.me>
Date: Sat, 16 Jul 2022 18:02:55 +0100
Subject: [PATCH 5/9] Make the num macro work if you don't depend on agb_macros
 yourself

---
 agb-fixnum/src/lib.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/agb-fixnum/src/lib.rs b/agb-fixnum/src/lib.rs
index efa6586e..ebbe2179 100644
--- a/agb-fixnum/src/lib.rs
+++ b/agb-fixnum/src/lib.rs
@@ -9,10 +9,13 @@ use core::{
     },
 };
 
+#[doc(hidden)]
+pub use agb_macros::num as num_inner;
+
 #[macro_export]
 macro_rules! num {
     ($value:literal) => {{
-        $crate::Num::new_from_parts(agb_macros::num!($value))
+        $crate::Num::new_from_parts($crate::num_inner!($value))
     }};
 }
 

From a5e0e145d2a41d8cdca9a26f56250631adecc590 Mon Sep 17 00:00:00 2001
From: Gwilym Kuiper <gw@ilym.me>
Date: Sat, 16 Jul 2022 18:47:39 +0100
Subject: [PATCH 6/9] Attempt to support changing the volume of stereo sound

---
 agb/src/sound/mixer/mixer.s     | 8 +++++---
 agb/src/sound/mixer/sw_mixer.rs | 7 ++++++-
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/agb/src/sound/mixer/mixer.s b/agb/src/sound/mixer/mixer.s
index 33f59172..4af591e1 100644
--- a/agb/src/sound/mixer/mixer.s
+++ b/agb/src/sound/mixer/mixer.s
@@ -95,10 +95,12 @@ agb_arm_func agb_rs__mixer_add_stereo
     @ Arguments
     @ r0 - pointer to the data to be copied (u8 array)
     @ r1 - pointer to the sound buffer (i16 array which will alternate left and right channels, 32-bit aligned)
+    @ r2 - volume to play the sound at
     @
     @ The sound buffer must be SOUND_BUFFER_SIZE * 2 in size = 176 * 2
-    push {r4-r8}
+    push {r4-r9}
 
+    mov r9, r2
     ldr r5, =0x00000FFF
 
     ldr r8, =agb_rs__buffer_size
@@ -128,7 +130,7 @@ agb_arm_func agb_rs__mixer_add_stereo
     lsl r6, r6, #24        @ r6 = | R | 0 | 0 | 0 | drop everything except the right sample
     orr r6, r7, r6, asr #8 @ r6 = | 1 | R | 1 | L | now we have it perfectly set up
 
-    add r4, r4, r6, lsl #4  @ r4 += r6 << 4 (calculating both the left and right samples together)
+    mla r4, r6, r9, r4     @ r4 += r6 * r9 (calculating both the left and right samples together)
 
     str r4, [r1], #4         @ store the new value, and increment the pointer
 .endr
@@ -136,7 +138,7 @@ agb_arm_func agb_rs__mixer_add_stereo
     subs r8, r8, #4          @ loop counter
     bne 1b                   @ jump back if we're done with the loop
 
-    pop {r4-r8}
+    pop {r4-r9}
     bx lr
 
 agb_arm_end agb_rs__mixer_add_stereo
diff --git a/agb/src/sound/mixer/sw_mixer.rs b/agb/src/sound/mixer/sw_mixer.rs
index 676c0ed8..80b5b139 100644
--- a/agb/src/sound/mixer/sw_mixer.rs
+++ b/agb/src/sound/mixer/sw_mixer.rs
@@ -25,7 +25,11 @@ extern "C" {
         right_amount: Num<i16, 4>,
     );
 
-    fn agb_rs__mixer_add_stereo(sound_data: *const u8, sound_buffer: *mut Num<i16, 4>);
+    fn agb_rs__mixer_add_stereo(
+        sound_data: *const u8,
+        sound_buffer: *mut Num<i16, 4>,
+        volume: Num<i16, 4>,
+    );
 
     fn agb_rs__mixer_collapse(sound_buffer: *mut i8, input_buffer: *const Num<i16, 4>);
 }
@@ -447,6 +451,7 @@ impl MixerBuffer {
                     agb_rs__mixer_add_stereo(
                         channel.data.as_ptr().add(channel.pos.floor()),
                         buffer.as_mut_ptr(),
+                        channel.volume,
                     );
                 }
             } else {

From 3de22df7a2591141434e9e3d1173b3e3e5544e0b Mon Sep 17 00:00:00 2001
From: Gwilym Kuiper <gw@ilym.me>
Date: Sun, 17 Jul 2022 10:32:01 +0100
Subject: [PATCH 7/9] Add get and set position on sound channels

---
 agb/src/sound/mixer/mod.rs | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs
index 9b72e599..dda398e1 100644
--- a/agb/src/sound/mixer/mod.rs
+++ b/agb/src/sound/mixer/mod.rs
@@ -375,4 +375,17 @@ impl SoundChannel {
     pub fn stop(&mut self) {
         self.is_done = true;
     }
+
+    /// Gets how far along the sound has played.
+    #[inline]
+    pub fn pos(&self) -> Num<usize, 8> {
+        self.pos
+    }
+
+    /// Sets the playback position
+    #[inline]
+    pub fn set_pos(&mut self, pos: impl Into<Num<usize, 8>>) -> &mut Self {
+        self.pos = pos.into();
+        self
+    }
 }

From c2a4845a2e6ad87ad8961ec489c7b5762ea66c73 Mon Sep 17 00:00:00 2001
From: Gwilym Kuiper <gw@ilym.me>
Date: Thu, 21 Jul 2022 20:34:26 +0100
Subject: [PATCH 8/9] Add a must_use to pos

---
 agb/src/sound/mixer/mod.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/agb/src/sound/mixer/mod.rs b/agb/src/sound/mixer/mod.rs
index dda398e1..ac01dba7 100644
--- a/agb/src/sound/mixer/mod.rs
+++ b/agb/src/sound/mixer/mod.rs
@@ -378,6 +378,7 @@ impl SoundChannel {
 
     /// Gets how far along the sound has played.
     #[inline]
+    #[must_use]
     pub fn pos(&self) -> Num<usize, 8> {
         self.pos
     }

From 8df9f4b5c461d25ba2e899b1eabf953d45a6a391 Mon Sep 17 00:00:00 2001
From: Gwilym Kuiper <gw@ilym.me>
Date: Thu, 21 Jul 2022 20:52:07 +0100
Subject: [PATCH 9/9] Go back to using DMA for sprites

---
 agb/src/display/object.rs | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/agb/src/display/object.rs b/agb/src/display/object.rs
index b5a3287b..04a33587 100644
--- a/agb/src/display/object.rs
+++ b/agb/src/display/object.rs
@@ -799,13 +799,11 @@ impl SpriteControllerInner {
             };
 
             unsafe {
-                dest.as_ptr()
-                    .copy_from_nonoverlapping(sprite.data.as_ptr(), sprite.data.len());
-                // dma::dma_copy16(
-                //     sprite.data.as_ptr().cast(),
-                //     dest.as_ptr().cast(),
-                //     sprite.data.len() / 2,
-                // );
+                dma::dma_copy16(
+                    sprite.data.as_ptr().cast(),
+                    dest.as_ptr().cast(),
+                    sprite.data.len() / 2,
+                );
             }
 
             let storage = Storage::from_sprite_ptr(dest);