mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-25 09:11:34 +11:00
Merge pull request #233 from gwilymk/more-clippy-lints
More clippy lints
This commit is contained in:
commit
e051a17836
|
@ -10,8 +10,8 @@ fn main(_gba: agb::Gba) -> ! {
|
||||||
let count = Mutex::new(RefCell::new(0));
|
let count = Mutex::new(RefCell::new(0));
|
||||||
let _a = agb::interrupt::add_interrupt_handler(
|
let _a = agb::interrupt::add_interrupt_handler(
|
||||||
agb::interrupt::Interrupt::VBlank,
|
agb::interrupt::Interrupt::VBlank,
|
||||||
|key: &CriticalSection| {
|
|key: CriticalSection| {
|
||||||
let mut count = count.borrow(*key).borrow_mut();
|
let mut count = count.borrow(key).borrow_mut();
|
||||||
agb::println!("Hello, world, frame = {}", *count);
|
agb::println!("Hello, world, frame = {}", *count);
|
||||||
*count += 1;
|
*count += 1;
|
||||||
},
|
},
|
||||||
|
|
|
@ -31,8 +31,8 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
|
|
||||||
let back = Mutex::new(RefCell::new(BackCosines { cosines, row: 0 }));
|
let back = Mutex::new(RefCell::new(BackCosines { cosines, row: 0 }));
|
||||||
|
|
||||||
let _a = agb::interrupt::add_interrupt_handler(Interrupt::HBlank, |key: &CriticalSection| {
|
let _a = agb::interrupt::add_interrupt_handler(Interrupt::HBlank, |key: CriticalSection| {
|
||||||
let mut backc = back.borrow(*key).borrow_mut();
|
let mut backc = back.borrow(key).borrow_mut();
|
||||||
let deflection = backc.cosines[backc.row % 32];
|
let deflection = backc.cosines[backc.row % 32];
|
||||||
unsafe { ((0x0400_0010) as *mut u16).write_volatile(deflection) }
|
unsafe { ((0x0400_0010) as *mut u16).write_volatile(deflection) }
|
||||||
backc.row += 1;
|
backc.row += 1;
|
||||||
|
@ -43,7 +43,7 @@ fn main(mut gba: agb::Gba) -> ! {
|
||||||
loop {
|
loop {
|
||||||
vblank.wait_for_vblank();
|
vblank.wait_for_vblank();
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut backc = back.borrow(*key).borrow_mut();
|
let mut backc = back.borrow(key).borrow_mut();
|
||||||
backc.row = 0;
|
backc.row = 0;
|
||||||
time += 1;
|
time += 1;
|
||||||
for (r, a) in backc.cosines.iter_mut().enumerate() {
|
for (r, a) in backc.cosines.iter_mut().enumerate() {
|
||||||
|
|
|
@ -61,7 +61,7 @@ impl BlockAllocator {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub unsafe fn number_of_blocks(&self) -> u32 {
|
pub unsafe fn number_of_blocks(&self) -> u32 {
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut state = self.state.borrow(*key).borrow_mut();
|
let mut state = self.state.borrow(key).borrow_mut();
|
||||||
|
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ impl BlockAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requests a brand new block from the inner bump allocator
|
/// Requests a brand new block from the inner bump allocator
|
||||||
fn new_block(&self, layout: Layout, cs: &CriticalSection) -> Option<NonNull<u8>> {
|
fn new_block(&self, layout: Layout, cs: CriticalSection) -> Option<NonNull<u8>> {
|
||||||
let overall_layout = Block::either_layout(layout);
|
let overall_layout = Block::either_layout(layout);
|
||||||
self.inner_allocator.alloc_critical(overall_layout, cs)
|
self.inner_allocator.alloc_critical(overall_layout, cs)
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ impl BlockAllocator {
|
||||||
/// Merges blocks together to create a normalised list
|
/// Merges blocks together to create a normalised list
|
||||||
unsafe fn normalise(&self) {
|
unsafe fn normalise(&self) {
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut state = self.state.borrow(*key).borrow_mut();
|
let mut state = self.state.borrow(key).borrow_mut();
|
||||||
|
|
||||||
let mut list_ptr = &mut state.first_free_block;
|
let mut list_ptr = &mut state.first_free_block;
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ impl BlockAllocator {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut state = self.state.borrow(*key).borrow_mut();
|
let mut state = self.state.borrow(key).borrow_mut();
|
||||||
let mut current_block = state.first_free_block;
|
let mut current_block = state.first_free_block;
|
||||||
let mut list_ptr = &mut state.first_free_block;
|
let mut list_ptr = &mut state.first_free_block;
|
||||||
// This iterates the free list until it either finds a block that
|
// This iterates the free list until it either finds a block that
|
||||||
|
@ -164,7 +164,7 @@ impl BlockAllocator {
|
||||||
pub unsafe fn dealloc_no_normalise(&self, ptr: *mut u8, layout: Layout) {
|
pub unsafe fn dealloc_no_normalise(&self, ptr: *mut u8, layout: Layout) {
|
||||||
let new_layout = Block::either_layout(layout).pad_to_align();
|
let new_layout = Block::either_layout(layout).pad_to_align();
|
||||||
free(|key| {
|
free(|key| {
|
||||||
let mut state = self.state.borrow(*key).borrow_mut();
|
let mut state = self.state.borrow(key).borrow_mut();
|
||||||
|
|
||||||
// note that this is a reference to a pointer
|
// note that this is a reference to a pointer
|
||||||
let mut list_ptr = &mut state.first_free_block;
|
let mut list_ptr = &mut state.first_free_block;
|
||||||
|
|
|
@ -26,13 +26,13 @@ impl BumpAllocator {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BumpAllocator {
|
impl BumpAllocator {
|
||||||
pub fn alloc_critical(&self, layout: Layout, cs: &CriticalSection) -> Option<NonNull<u8>> {
|
pub fn alloc_critical(&self, layout: Layout, cs: CriticalSection) -> Option<NonNull<u8>> {
|
||||||
let mut current_ptr = self.current_ptr.borrow(*cs).borrow_mut();
|
let mut current_ptr = self.current_ptr.borrow(cs).borrow_mut();
|
||||||
|
|
||||||
let ptr = if let Some(c) = *current_ptr {
|
let ptr = if let Some(c) = *current_ptr {
|
||||||
c.as_ptr() as usize
|
c.as_ptr() as usize
|
||||||
} else {
|
} else {
|
||||||
(self.start_end.borrow(*cs).start)()
|
(self.start_end.borrow(cs).start)()
|
||||||
};
|
};
|
||||||
|
|
||||||
let alignment_bitmask = layout.align() - 1;
|
let alignment_bitmask = layout.align() - 1;
|
||||||
|
@ -43,7 +43,7 @@ impl BumpAllocator {
|
||||||
let resulting_ptr = ptr + amount_to_add;
|
let resulting_ptr = ptr + amount_to_add;
|
||||||
let new_current_ptr = resulting_ptr + layout.size();
|
let new_current_ptr = resulting_ptr + layout.size();
|
||||||
|
|
||||||
if new_current_ptr as usize >= (self.start_end.borrow(*cs).end)() {
|
if new_current_ptr as usize >= (self.start_end.borrow(cs).end)() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,10 @@ impl<const N: usize> Bitarray<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, index: usize, value: bool) {
|
pub fn set(&mut self, index: usize, value: bool) {
|
||||||
let value = value as u32;
|
let value = u32::from(value);
|
||||||
let mask = 1 << (index % 32);
|
let mask = 1 << (index % 32);
|
||||||
let value_mask = value << (index % 32);
|
let value_mask = value << (index % 32);
|
||||||
self.a[index / 32] = self.a[index / 32] & !mask | value_mask
|
self.a[index / 32] = self.a[index / 32] & !mask | value_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn first_zero(&self) -> Option<usize> {
|
pub fn first_zero(&self) -> Option<usize> {
|
||||||
|
|
|
@ -24,6 +24,6 @@ impl Bitmap3 {
|
||||||
pub fn draw_point(&mut self, x: i32, y: i32, colour: u16) {
|
pub fn draw_point(&mut self, x: i32, y: i32, colour: u16) {
|
||||||
let x = x.try_into().unwrap();
|
let x = x.try_into().unwrap();
|
||||||
let y = y.try_into().unwrap();
|
let y = y.try_into().unwrap();
|
||||||
BITMAP_MODE_3.set(x, y, colour)
|
BITMAP_MODE_3.set(x, y, colour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ const BITMAP_PAGE_BACK_MODE_4: MemoryMapped2DArray<
|
||||||
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
||||||
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
|
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
pub enum Page {
|
pub enum Page {
|
||||||
Front = 0,
|
Front = 0,
|
||||||
Back = 1,
|
Back = 1,
|
||||||
|
@ -47,9 +48,9 @@ impl Bitmap4 {
|
||||||
|
|
||||||
let c = addr.get(x_in_screen, y_in_screen);
|
let c = addr.get(x_in_screen, y_in_screen);
|
||||||
if x & 0b1 != 0 {
|
if x & 0b1 != 0 {
|
||||||
addr.set(x_in_screen, y_in_screen, c | (colour as u16) << 8);
|
addr.set(x_in_screen, y_in_screen, c | u16::from(colour) << 8);
|
||||||
} else {
|
} else {
|
||||||
addr.set(x_in_screen, y_in_screen, c | colour as u16);
|
addr.set(x_in_screen, y_in_screen, c | u16::from(colour));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +67,7 @@ impl Bitmap4 {
|
||||||
Page::Back
|
Page::Back
|
||||||
};
|
};
|
||||||
|
|
||||||
self.draw_point_page(x, y, colour, page)
|
self.draw_point_page(x, y, colour, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the colour of colour index in the background palette.
|
/// Sets the colour of colour index in the background palette.
|
||||||
|
|
|
@ -15,6 +15,7 @@ pub struct FontLetter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FontLetter {
|
impl FontLetter {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
width: u8,
|
width: u8,
|
||||||
height: u8,
|
height: u8,
|
||||||
|
@ -41,6 +42,7 @@ pub struct Font {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Font {
|
impl Font {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(letters: &'static [FontLetter], line_height: i32, ascent: i32) -> Self {
|
pub const fn new(letters: &'static [FontLetter], line_height: i32, ascent: i32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
letters,
|
letters,
|
||||||
|
@ -102,7 +104,7 @@ impl<'a> Write for TextRenderer<'a> {
|
||||||
|
|
||||||
self.render_letter(letter);
|
self.render_letter(letter);
|
||||||
|
|
||||||
self.current_x_pos += letter.advance_width as i32;
|
self.current_x_pos += i32::from(letter.advance_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -119,9 +121,10 @@ impl<'a> TextRenderer<'a> {
|
||||||
let foreground_colour = self.foreground_colour;
|
let foreground_colour = self.foreground_colour;
|
||||||
let background_colour = self.background_colour;
|
let background_colour = self.background_colour;
|
||||||
|
|
||||||
let x_start = (self.current_x_pos + letter.xmin as i32).max(0);
|
let x_start = (self.current_x_pos + i32::from(letter.xmin)).max(0);
|
||||||
let y_start =
|
let y_start = self.current_y_pos + self.font.ascent
|
||||||
self.current_y_pos + self.font.ascent - letter.height as i32 - letter.ymin as i32;
|
- i32::from(letter.height)
|
||||||
|
- i32::from(letter.ymin);
|
||||||
|
|
||||||
let x_tile_start = x_start / 8;
|
let x_tile_start = x_start / 8;
|
||||||
let y_tile_start = y_start / 8;
|
let y_tile_start = y_start / 8;
|
||||||
|
@ -129,20 +132,20 @@ impl<'a> TextRenderer<'a> {
|
||||||
let letter_offset_x = x_start.rem_euclid(8);
|
let letter_offset_x = x_start.rem_euclid(8);
|
||||||
let letter_offset_y = y_start.rem_euclid(8);
|
let letter_offset_y = y_start.rem_euclid(8);
|
||||||
|
|
||||||
let x_tiles = div_ceil(letter.width as i32 + letter_offset_x, 8);
|
let x_tiles = div_ceil(i32::from(letter.width) + letter_offset_x, 8);
|
||||||
let y_tiles = div_ceil(letter.height as i32 + letter_offset_y, 8);
|
let y_tiles = div_ceil(i32::from(letter.height) + letter_offset_y, 8);
|
||||||
|
|
||||||
for letter_y_tile in 0..(y_tiles + 1) {
|
for letter_y_tile in 0..(y_tiles + 1) {
|
||||||
let letter_y_start = 0.max(letter_offset_y - 8 * letter_y_tile) + 8 * letter_y_tile;
|
let letter_y_start = 0.max(letter_offset_y - 8 * letter_y_tile) + 8 * letter_y_tile;
|
||||||
let letter_y_end =
|
let letter_y_end =
|
||||||
(letter_offset_y + letter.height as i32).min((letter_y_tile + 1) * 8);
|
(letter_offset_y + i32::from(letter.height)).min((letter_y_tile + 1) * 8);
|
||||||
|
|
||||||
let tile_y = y_tile_start + letter_y_tile;
|
let tile_y = y_tile_start + letter_y_tile;
|
||||||
|
|
||||||
for letter_x_tile in 0..(x_tiles + 1) {
|
for letter_x_tile in 0..(x_tiles + 1) {
|
||||||
let letter_x_start = 0.max(letter_offset_x - 8 * letter_x_tile) + 8 * letter_x_tile;
|
let letter_x_start = 0.max(letter_offset_x - 8 * letter_x_tile) + 8 * letter_x_tile;
|
||||||
let letter_x_end =
|
let letter_x_end =
|
||||||
(letter_offset_x + letter.width as i32).min((letter_x_tile + 1) * 8);
|
(letter_offset_x + i32::from(letter.width)).min((letter_x_tile + 1) * 8);
|
||||||
|
|
||||||
let tile_x = x_tile_start + letter_x_tile;
|
let tile_x = x_tile_start + letter_x_tile;
|
||||||
|
|
||||||
|
@ -154,13 +157,13 @@ impl<'a> TextRenderer<'a> {
|
||||||
|
|
||||||
for letter_x in letter_x_start..letter_x_end {
|
for letter_x in letter_x_start..letter_x_end {
|
||||||
let x = letter_x - letter_offset_x;
|
let x = letter_x - letter_offset_x;
|
||||||
let pos = x + y * letter.width as i32;
|
let pos = x + y * i32::from(letter.width);
|
||||||
let px_line = letter.data[(pos / 8) as usize];
|
let px_line = letter.data[(pos / 8) as usize];
|
||||||
let px = (px_line >> (pos & 7)) & 1;
|
let px = (px_line >> (pos & 7)) & 1;
|
||||||
|
|
||||||
if px != 0 {
|
if px != 0 {
|
||||||
masks[(letter_y & 7) as usize] |=
|
masks[(letter_y & 7) as usize] |=
|
||||||
(foreground_colour as u32) << ((letter_x & 7) * 4);
|
u32::from(foreground_colour) << ((letter_x & 7) * 4);
|
||||||
zero = false;
|
zero = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ unsafe fn init_object_controller() {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn uninit_object_controller() {
|
unsafe fn uninit_object_controller() {
|
||||||
OBJECT_CONTROLLER.assume_init_drop()
|
OBJECT_CONTROLLER.assume_init_drop();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ObjectControllerRef {}
|
struct ObjectControllerRef {}
|
||||||
|
@ -56,7 +56,7 @@ impl ObjectControllerRef {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
let a = crate::interrupt::free(|c| {
|
let a = crate::interrupt::free(|c| {
|
||||||
let mut b = OBJECT_REFS_CURRENT.borrow(*c).borrow_mut();
|
let mut b = OBJECT_REFS_CURRENT.borrow(c).borrow_mut();
|
||||||
let a = *b;
|
let a = *b;
|
||||||
*b += 1;
|
*b += 1;
|
||||||
a
|
a
|
||||||
|
@ -76,13 +76,13 @@ impl ObjectControllerRef {
|
||||||
impl Drop for ObjectControllerRef {
|
impl Drop for ObjectControllerRef {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
crate::interrupt::free(|c| {
|
crate::interrupt::free(|c| {
|
||||||
let mut b = OBJECT_REFS_CURRENT.borrow(*c).borrow_mut();
|
let mut b = OBJECT_REFS_CURRENT.borrow(c).borrow_mut();
|
||||||
*b -= 1;
|
*b -= 1;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_object_controller(_r: &ObjectControllerReference) -> ObjectControllerRef {
|
unsafe fn get_object_controller(_r: ObjectControllerReference) -> ObjectControllerRef {
|
||||||
ObjectControllerRef::new()
|
ObjectControllerRef::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,12 +153,15 @@ pub struct Graphics {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Graphics {
|
impl Graphics {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(sprites: &'static [Sprite], tag_map: &'static TagMap) -> Self {
|
pub const fn new(sprites: &'static [Sprite], tag_map: &'static TagMap) -> Self {
|
||||||
Self { sprites, tag_map }
|
Self { sprites, tag_map }
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub const fn tags(&self) -> &TagMap {
|
pub const fn tags(&self) -> &TagMap {
|
||||||
self.tag_map
|
self.tag_map
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub const fn sprites(&self) -> &[Sprite] {
|
pub const fn sprites(&self) -> &[Sprite] {
|
||||||
self.sprites
|
self.sprites
|
||||||
}
|
}
|
||||||
|
@ -184,9 +187,11 @@ const fn const_byte_compare(a: &[u8], b: &[u8]) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TagMap {
|
impl TagMap {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(tags: &'static [(&'static str, Tag)]) -> TagMap {
|
pub const fn new(tags: &'static [(&'static str, Tag)]) -> TagMap {
|
||||||
Self { tags }
|
Self { tags }
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub const fn try_get(&'static self, tag: &str) -> Option<&'static Tag> {
|
pub const fn try_get(&'static self, tag: &str) -> Option<&'static Tag> {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < self.tags.len() {
|
while i < self.tags.len() {
|
||||||
|
@ -200,6 +205,7 @@ impl TagMap {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub const fn get(&'static self, tag: &str) -> &'static Tag {
|
pub const fn get(&'static self, tag: &str) -> &'static Tag {
|
||||||
let t = self.try_get(tag);
|
let t = self.try_get(tag);
|
||||||
match t {
|
match t {
|
||||||
|
@ -237,15 +243,18 @@ pub struct Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tag {
|
impl Tag {
|
||||||
|
#[must_use]
|
||||||
pub fn sprites(&self) -> &'static [Sprite] {
|
pub fn sprites(&self) -> &'static [Sprite] {
|
||||||
unsafe { slice::from_raw_parts(self.sprites, self.len) }
|
unsafe { slice::from_raw_parts(self.sprites, self.len) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn sprite(&self, idx: usize) -> &'static Sprite {
|
pub fn sprite(&self, idx: usize) -> &'static Sprite {
|
||||||
&self.sprites()[idx]
|
&self.sprites()[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
pub fn animation_sprite(&self, idx: usize) -> &'static Sprite {
|
pub fn animation_sprite(&self, idx: usize) -> &'static Sprite {
|
||||||
let len_sub_1 = self.len - 1;
|
let len_sub_1 = self.len - 1;
|
||||||
match self.direction {
|
match self.direction {
|
||||||
|
@ -259,6 +268,7 @@ impl Tag {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
#[must_use]
|
||||||
pub const fn new(sprites: &'static [Sprite], from: usize, to: usize, direction: usize) -> Self {
|
pub const fn new(sprites: &'static [Sprite], from: usize, to: usize, direction: usize) -> Self {
|
||||||
assert!(from <= to);
|
assert!(from <= to);
|
||||||
assert!(to < sprites.len());
|
assert!(to < sprites.len());
|
||||||
|
@ -291,6 +301,7 @@ impl Size {
|
||||||
(self as u8 >> 2, self as u8 & 0b11)
|
(self as u8 >> 2, self as u8 & 0b11)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn from_width_height(width: usize, height: usize) -> Self {
|
pub const fn from_width_height(width: usize, height: usize) -> Self {
|
||||||
match (width, height) {
|
match (width, height) {
|
||||||
(8, 8) => Size::S8x8,
|
(8, 8) => Size::S8x8,
|
||||||
|
@ -309,6 +320,7 @@ impl Size {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn to_width_height(self) -> (usize, usize) {
|
pub const fn to_width_height(self) -> (usize, usize) {
|
||||||
match self {
|
match self {
|
||||||
Size::S8x8 => (8, 8),
|
Size::S8x8 => (8, 8),
|
||||||
|
@ -353,10 +365,10 @@ impl Storage {
|
||||||
count: 1,
|
count: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn as_palette_ptr(&self) -> *mut u8 {
|
fn as_palette_ptr(self) -> *mut u8 {
|
||||||
(self.location as usize * Palette16::layout().size() + PALETTE_SPRITE) as *mut u8
|
(self.location as usize * Palette16::layout().size() + PALETTE_SPRITE) as *mut u8
|
||||||
}
|
}
|
||||||
fn as_sprite_ptr(&self) -> *mut u8 {
|
fn as_sprite_ptr(self) -> *mut u8 {
|
||||||
(self.location as usize * BYTES_PER_TILE_4BPP + TILE_SPRITE) as *mut u8
|
(self.location as usize * BYTES_PER_TILE_4BPP + TILE_SPRITE) as *mut u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,13 +433,13 @@ struct Loan<'a> {
|
||||||
|
|
||||||
impl Drop for Loan<'_> {
|
impl Drop for Loan<'_> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut s = unsafe { get_object_controller(&self.phantom) };
|
let mut s = unsafe { get_object_controller(self.phantom) };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
s.shadow_oam[self.index as usize]
|
s.shadow_oam[self.index as usize]
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap_unchecked()
|
.unwrap_unchecked()
|
||||||
.destroy = true
|
.destroy = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,12 +473,8 @@ impl ObjectControllerStatic {
|
||||||
|
|
||||||
fn update_z_ordering(&mut self) {
|
fn update_z_ordering(&mut self) {
|
||||||
let shadow_oam = &self.shadow_oam;
|
let shadow_oam = &self.shadow_oam;
|
||||||
self.z_order.sort_by_key(|&a| {
|
self.z_order
|
||||||
shadow_oam[a as usize]
|
.sort_by_key(|&a| shadow_oam[a as usize].as_ref().map_or(i32::MAX, |s| s.z));
|
||||||
.as_ref()
|
|
||||||
.map(|s| s.z)
|
|
||||||
.unwrap_or(i32::MAX)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +494,7 @@ const HIDDEN_VALUE: u16 = 0b10 << 8;
|
||||||
|
|
||||||
impl ObjectController {
|
impl ObjectController {
|
||||||
pub fn commit(&self) {
|
pub fn commit(&self) {
|
||||||
let mut s = unsafe { get_object_controller(&self.phantom) };
|
let mut s = unsafe { get_object_controller(self.phantom) };
|
||||||
|
|
||||||
let s = &mut *s;
|
let s = &mut *s;
|
||||||
|
|
||||||
|
@ -498,7 +506,7 @@ impl ObjectController {
|
||||||
unsafe {
|
unsafe {
|
||||||
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
||||||
.add((i as usize) * 4)
|
.add((i as usize) * 4)
|
||||||
.write_volatile(HIDDEN_VALUE)
|
.write_volatile(HIDDEN_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = unsafe { s.shadow_oam[z as usize].take().unwrap_unchecked() };
|
let a = unsafe { s.shadow_oam[z as usize].take().unwrap_unchecked() };
|
||||||
|
@ -515,7 +523,7 @@ impl ObjectController {
|
||||||
unsafe {
|
unsafe {
|
||||||
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
||||||
.add(i * 4)
|
.add(i * 4)
|
||||||
.write_volatile(HIDDEN_VALUE)
|
.write_volatile(HIDDEN_VALUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,7 +538,7 @@ impl ObjectController {
|
||||||
unsafe {
|
unsafe {
|
||||||
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
(OBJECT_ATTRIBUTE_MEMORY as *mut u16)
|
||||||
.add(i * 4)
|
.add(i * 4)
|
||||||
.write_volatile(HIDDEN_VALUE)
|
.write_volatile(HIDDEN_VALUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,12 +548,14 @@ impl ObjectController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn object<'a>(&'a self, sprite: SpriteBorrow<'a>) -> Object<'a> {
|
pub fn object<'a>(&'a self, sprite: SpriteBorrow<'a>) -> Object<'a> {
|
||||||
self.try_get_object(sprite).expect("No object available")
|
self.try_get_object(sprite).expect("No object available")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn try_get_object<'a>(&'a self, sprite: SpriteBorrow<'a>) -> Option<Object<'a>> {
|
pub fn try_get_object<'a>(&'a self, sprite: SpriteBorrow<'a>) -> Option<Object<'a>> {
|
||||||
let mut s = unsafe { get_object_controller(&self.phantom) };
|
let mut s = unsafe { get_object_controller(self.phantom) };
|
||||||
|
|
||||||
let mut attrs = Attributes::new();
|
let mut attrs = Attributes::new();
|
||||||
|
|
||||||
|
@ -578,13 +588,15 @@ impl ObjectController {
|
||||||
Some(Object { loan })
|
Some(Object { loan })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn sprite(&self, sprite: &'static Sprite) -> SpriteBorrow {
|
pub fn sprite(&self, sprite: &'static Sprite) -> SpriteBorrow {
|
||||||
self.try_get_sprite(sprite)
|
self.try_get_sprite(sprite)
|
||||||
.expect("No slot for sprite available")
|
.expect("No slot for sprite available")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn try_get_sprite(&self, sprite: &'static Sprite) -> Option<SpriteBorrow> {
|
pub fn try_get_sprite(&self, sprite: &'static Sprite) -> Option<SpriteBorrow> {
|
||||||
let s = unsafe { get_object_controller(&self.phantom) };
|
let s = unsafe { get_object_controller(self.phantom) };
|
||||||
unsafe {
|
unsafe {
|
||||||
s.very_unsafe_borrow()
|
s.very_unsafe_borrow()
|
||||||
.sprite_controller
|
.sprite_controller
|
||||||
|
@ -596,7 +608,7 @@ impl ObjectController {
|
||||||
impl<'a> Object<'a> {
|
impl<'a> Object<'a> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn object_inner(&mut self) -> &mut ObjectInner {
|
unsafe fn object_inner(&mut self) -> &mut ObjectInner {
|
||||||
let s = get_object_controller(&self.loan.phantom);
|
let s = get_object_controller(self.loan.phantom);
|
||||||
s.very_unsafe_borrow().shadow_oam[self.loan.index as usize]
|
s.very_unsafe_borrow().shadow_oam[self.loan.index as usize]
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap_unchecked()
|
.unwrap_unchecked()
|
||||||
|
@ -665,7 +677,7 @@ impl<'a> Object<'a> {
|
||||||
let object_inner = unsafe { self.object_inner() };
|
let object_inner = unsafe { self.object_inner() };
|
||||||
object_inner.z = z;
|
object_inner.z = z;
|
||||||
unsafe {
|
unsafe {
|
||||||
get_object_controller(&self.loan.phantom).update_z_ordering();
|
get_object_controller(self.loan.phantom).update_z_ordering();
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -721,6 +733,7 @@ impl Sprite {
|
||||||
fn layout(&self) -> Layout {
|
fn layout(&self) -> Layout {
|
||||||
Layout::from_size_align(self.size.number_of_tiles() * BYTES_PER_TILE_4BPP, 8).unwrap()
|
Layout::from_size_align(self.size.number_of_tiles() * BYTES_PER_TILE_4BPP, 8).unwrap()
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub const fn new(palette: &'static Palette16, data: &'static [u8], size: Size) -> Self {
|
pub const fn new(palette: &'static Palette16, data: &'static [u8], size: Size) -> Self {
|
||||||
Self {
|
Self {
|
||||||
palette,
|
palette,
|
||||||
|
@ -728,6 +741,7 @@ impl Sprite {
|
||||||
size,
|
size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub const fn size(&self) -> Size {
|
pub const fn size(&self) -> Size {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
@ -823,7 +837,7 @@ impl SpriteControllerInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.return_palette(sprite.palette)
|
self.return_palette(sprite.palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_palette(&mut self, palette: &'static Palette16) {
|
fn return_palette(&mut self, palette: &'static Palette16) {
|
||||||
|
@ -842,8 +856,8 @@ impl SpriteControllerInner {
|
||||||
|
|
||||||
impl<'a> Drop for SpriteBorrow<'a> {
|
impl<'a> Drop for SpriteBorrow<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut s = unsafe { get_object_controller(&self.phantom) };
|
let mut s = unsafe { get_object_controller(self.phantom) };
|
||||||
s.sprite_controller.return_sprite(self.id.sprite())
|
s.sprite_controller.return_sprite(self.id.sprite());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -867,7 +881,7 @@ impl<'a> SpriteBorrow<'a> {
|
||||||
|
|
||||||
impl<'a> Clone for SpriteBorrow<'a> {
|
impl<'a> Clone for SpriteBorrow<'a> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let mut s = unsafe { get_object_controller(&self.phantom) };
|
let mut s = unsafe { get_object_controller(self.phantom) };
|
||||||
self.clone(&mut s.sprite_controller)
|
self.clone(&mut s.sprite_controller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ pub struct Palette16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Palette16 {
|
impl Palette16 {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(colours: [u16; 16]) -> Self {
|
pub const fn new(colours: [u16; 16]) -> Self {
|
||||||
Palette16 { colours }
|
Palette16 { colours }
|
||||||
}
|
}
|
||||||
|
@ -16,6 +17,7 @@ impl Palette16 {
|
||||||
self.colours[index] = colour;
|
self.colours[index] = colour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn colour(&self, index: usize) -> u16 {
|
pub fn colour(&self, index: usize) -> u16 {
|
||||||
self.colours[index]
|
self.colours[index]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ pub struct TileData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileData {
|
impl TileData {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(
|
pub const fn new(
|
||||||
palettes: &'static [Palette16],
|
palettes: &'static [Palette16],
|
||||||
tiles: &'static [u8],
|
tiles: &'static [u8],
|
||||||
|
|
|
@ -24,6 +24,7 @@ pub enum PartialUpdateStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> InfiniteScrolledMap<'a> {
|
impl<'a> InfiniteScrolledMap<'a> {
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
map: MapLoan<'a, RegularMap>,
|
map: MapLoan<'a, RegularMap>,
|
||||||
tile: Box<dyn Fn(Vector2D<i32>) -> (&'a TileSet<'a>, TileSetting) + 'a>,
|
tile: Box<dyn Fn(Vector2D<i32>) -> (&'a TileSet<'a>, TileSetting) + 'a>,
|
||||||
|
@ -190,8 +191,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 = (
|
||||||
size.px_offset_x(current_scroll.x as i32 + difference.x),
|
size.px_offset_x(i32::from(current_scroll.x) + difference.x),
|
||||||
size.px_offset_y(current_scroll.y as i32 + difference.y),
|
size.px_offset_y(i32::from(current_scroll.y) + difference.y),
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ 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)
|
let new_bg_control_value = (self.priority as u16)
|
||||||
| ((self.screenblock as u16) << 8)
|
| (u16::from(self.screenblock) << 8)
|
||||||
| (self.size.size_flag() << 14);
|
| (self.size.size_flag() << 14);
|
||||||
|
|
||||||
self.bg_control_register().set(new_bg_control_value);
|
self.bg_control_register().set(new_bg_control_value);
|
||||||
|
@ -136,6 +136,7 @@ impl RegularMap {
|
||||||
self.y_scroll = pos.y;
|
self.y_scroll = pos.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn scroll_pos(&self) -> Vector2D<u16> {
|
pub fn scroll_pos(&self) -> Vector2D<u16> {
|
||||||
(self.x_scroll, self.y_scroll).into()
|
(self.x_scroll, self.y_scroll).into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,25 +18,23 @@ pub enum RegularBackgroundSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RegularBackgroundSize {
|
impl RegularBackgroundSize {
|
||||||
|
#[must_use]
|
||||||
pub fn width(&self) -> u32 {
|
pub fn width(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
RegularBackgroundSize::Background32x32 => 32,
|
RegularBackgroundSize::Background32x64 | RegularBackgroundSize::Background32x32 => 32,
|
||||||
RegularBackgroundSize::Background64x32 => 64,
|
RegularBackgroundSize::Background64x64 | RegularBackgroundSize::Background64x32 => 64,
|
||||||
RegularBackgroundSize::Background32x64 => 32,
|
|
||||||
RegularBackgroundSize::Background64x64 => 64,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn height(&self) -> u32 {
|
pub fn height(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
RegularBackgroundSize::Background32x32 => 32,
|
RegularBackgroundSize::Background32x32 | RegularBackgroundSize::Background64x32 => 32,
|
||||||
RegularBackgroundSize::Background64x32 => 32,
|
RegularBackgroundSize::Background32x64 | RegularBackgroundSize::Background64x64 => 64,
|
||||||
RegularBackgroundSize::Background32x64 => 64,
|
|
||||||
RegularBackgroundSize::Background64x64 => 64,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn size_flag(&self) -> u16 {
|
pub(crate) fn size_flag(self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
RegularBackgroundSize::Background32x32 => 0,
|
RegularBackgroundSize::Background32x32 => 0,
|
||||||
RegularBackgroundSize::Background64x32 => 1,
|
RegularBackgroundSize::Background64x32 => 1,
|
||||||
|
@ -45,17 +43,17 @@ impl RegularBackgroundSize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn num_tiles(&self) -> usize {
|
pub(crate) fn num_tiles(self) -> usize {
|
||||||
(self.width() * self.height()) as usize
|
(self.width() * self.height()) as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn num_screen_blocks(&self) -> usize {
|
pub(crate) fn num_screen_blocks(self) -> usize {
|
||||||
self.num_tiles() / (32 * 32)
|
self.num_tiles() / (32 * 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is hilariously complicated due to how the GBA stores the background screenblocks.
|
// 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
|
// See https://www.coranac.com/tonc/text/regbg.htm#sec-map for an explanation
|
||||||
pub(crate) fn gba_offset(&self, pos: Vector2D<u16>) -> usize {
|
pub(crate) fn gba_offset(self, pos: Vector2D<u16>) -> usize {
|
||||||
let x_mod = pos.x & (self.width() as u16 - 1);
|
let x_mod = pos.x & (self.width() as u16 - 1);
|
||||||
let y_mod = pos.y & (self.height() as u16 - 1);
|
let y_mod = pos.y & (self.height() as u16 - 1);
|
||||||
|
|
||||||
|
@ -66,19 +64,19 @@ impl RegularBackgroundSize {
|
||||||
pos as usize
|
pos as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tile_pos_x(&self, x: i32) -> u16 {
|
pub(crate) fn tile_pos_x(self, x: i32) -> u16 {
|
||||||
((x as u32) & (self.width() - 1)) as u16
|
((x as u32) & (self.width() - 1)) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn tile_pos_y(&self, y: i32) -> u16 {
|
pub(crate) fn tile_pos_y(self, y: i32) -> u16 {
|
||||||
((y as u32) & (self.height() - 1)) as u16
|
((y as u32) & (self.height() - 1)) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn px_offset_x(&self, x: i32) -> u16 {
|
pub(crate) fn px_offset_x(self, x: i32) -> u16 {
|
||||||
((x as u32) & (self.width() * 8 - 1)) as u16
|
((x as u32) & (self.width() * 8 - 1)) as u16
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn px_offset_y(&self, y: i32) -> u16 {
|
pub(crate) fn px_offset_y(self, y: i32) -> u16 {
|
||||||
((y as u32) & (self.height() * 8 - 1)) as u16
|
((y as u32) & (self.height() * 8 - 1)) as u16
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,6 +99,7 @@ impl Tile {
|
||||||
pub struct TileSetting(u16);
|
pub struct TileSetting(u16);
|
||||||
|
|
||||||
impl TileSetting {
|
impl TileSetting {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(tile_id: u16, hflip: bool, vflip: bool, palette_id: u8) -> Self {
|
pub const fn new(tile_id: u16, hflip: bool, vflip: bool, palette_id: u8) -> Self {
|
||||||
Self(
|
Self(
|
||||||
(tile_id & ((1 << 10) - 1))
|
(tile_id & ((1 << 10) - 1))
|
||||||
|
@ -110,6 +109,7 @@ impl TileSetting {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn from_raw(raw: u16) -> Self {
|
pub const fn from_raw(raw: u16) -> Self {
|
||||||
Self(raw)
|
Self(raw)
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ pub struct TileSet<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TileSet<'a> {
|
impl<'a> TileSet<'a> {
|
||||||
|
#[must_use]
|
||||||
pub fn new(tiles: &'a [u8], format: TileFormat) -> Self {
|
pub fn new(tiles: &'a [u8], format: TileFormat) -> Self {
|
||||||
Self { tiles, format }
|
Self { tiles, format }
|
||||||
}
|
}
|
||||||
|
@ -53,7 +54,7 @@ impl<'a> TileSet<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct TileIndex(u16);
|
pub struct TileIndex(u16);
|
||||||
|
|
||||||
impl TileIndex {
|
impl TileIndex {
|
||||||
|
@ -61,7 +62,7 @@ impl TileIndex {
|
||||||
Self(index as u16)
|
Self(index as u16)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const fn index(&self) -> u16 {
|
pub(crate) const fn index(self) -> u16 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,8 +129,9 @@ pub struct DynamicTile<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicTile<'_> {
|
impl DynamicTile<'_> {
|
||||||
|
#[must_use]
|
||||||
pub fn fill_with(self, colour_index: u8) -> Self {
|
pub fn fill_with(self, colour_index: u8) -> Self {
|
||||||
let colour_index = colour_index as u32;
|
let colour_index = u32::from(colour_index);
|
||||||
|
|
||||||
let mut value = 0;
|
let mut value = 0;
|
||||||
for i in 0..8 {
|
for i in 0..8 {
|
||||||
|
@ -142,6 +144,7 @@ impl DynamicTile<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicTile<'_> {
|
impl DynamicTile<'_> {
|
||||||
|
#[must_use]
|
||||||
pub fn tile_set(&self) -> TileSet<'_> {
|
pub fn tile_set(&self) -> TileSet<'_> {
|
||||||
let tiles = unsafe {
|
let tiles = unsafe {
|
||||||
slice::from_raw_parts_mut(
|
slice::from_raw_parts_mut(
|
||||||
|
@ -153,6 +156,7 @@ impl DynamicTile<'_> {
|
||||||
TileSet::new(tiles, TileFormat::FourBpp)
|
TileSet::new(tiles, TileFormat::FourBpp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn tile_index(&self) -> u16 {
|
pub fn tile_index(&self) -> u16 {
|
||||||
let difference = self.tile_data.as_ptr() as usize - TILE_RAM_START;
|
let difference = self.tile_data.as_ptr() as usize - TILE_RAM_START;
|
||||||
(difference / (8 * 8 / 2)) as u16
|
(difference / (8 * 8 / 2)) as u16
|
||||||
|
@ -188,6 +192,7 @@ impl VRamManager {
|
||||||
TileReference(NonNull::new(ptr as *mut _).unwrap())
|
TileReference(NonNull::new(ptr as *mut _).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn new_dynamic_tile<'a>(&mut self) -> DynamicTile<'a> {
|
pub fn new_dynamic_tile<'a>(&mut self) -> DynamicTile<'a> {
|
||||||
let tile_format = TileFormat::FourBpp;
|
let tile_format = TileFormat::FourBpp;
|
||||||
let new_reference: NonNull<u32> =
|
let new_reference: NonNull<u32> =
|
||||||
|
@ -227,6 +232,8 @@ impl VRamManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This needs to take ownership of the dynamic tile because it will no longer be valid after this call
|
||||||
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
pub fn remove_dynamic_tile(&mut self, dynamic_tile: DynamicTile<'_>) {
|
pub fn remove_dynamic_tile(&mut self, dynamic_tile: DynamicTile<'_>) {
|
||||||
let pointer = NonNull::new(dynamic_tile.tile_data.as_mut_ptr() as *mut _).unwrap();
|
let pointer = NonNull::new(dynamic_tile.tile_data.as_mut_ptr() as *mut _).unwrap();
|
||||||
let tile_reference = TileReference(pointer);
|
let tile_reference = TileReference(pointer);
|
||||||
|
@ -336,7 +343,7 @@ impl VRamManager {
|
||||||
tile_slice.as_ptr() as *const u16,
|
tile_slice.as_ptr() as *const u16,
|
||||||
target_location,
|
target_location,
|
||||||
tile_size_in_half_words,
|
tile_size_in_half_words,
|
||||||
)
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +363,7 @@ impl VRamManager {
|
||||||
/// Copies palettes to the background palettes without any checks.
|
/// Copies palettes to the background palettes without any checks.
|
||||||
pub fn set_background_palettes(&mut self, palettes: &[palette16::Palette16]) {
|
pub fn set_background_palettes(&mut self, palettes: &[palette16::Palette16]) {
|
||||||
for (palette_index, entry) in palettes.iter().enumerate() {
|
for (palette_index, entry) in palettes.iter().enumerate() {
|
||||||
self.set_background_palette(palette_index as u8, entry)
|
self.set_background_palette(palette_index as u8, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ type HashType = u32;
|
||||||
|
|
||||||
/// A hash map implemented very simply using robin hood hashing.
|
/// A hash map implemented very simply using robin hood hashing.
|
||||||
///
|
///
|
||||||
/// HashMap uses FxHasher internally, which is a very fast hashing algorithm used
|
/// `HashMap` uses `FxHasher` internally, which is a very fast hashing algorithm used
|
||||||
/// by rustc and firefox in non-adversarial places. It is incredibly fast, and good
|
/// by rustc and firefox in non-adversarial places. It is incredibly fast, and good
|
||||||
/// enough for most cases.
|
/// enough for most cases.
|
||||||
///
|
///
|
||||||
|
@ -76,7 +76,7 @@ type HashType = u32;
|
||||||
/// aborts, memory leaks and non-termination.
|
/// aborts, memory leaks and non-termination.
|
||||||
///
|
///
|
||||||
/// The API surface provided is incredibly similar to the
|
/// The API surface provided is incredibly similar to the
|
||||||
/// [std::collections::HashMap](https://doc.rust-lang.org/std/collections/struct.HashMap.html)
|
/// [`std::collections::HashMap`](https://doc.rust-lang.org/std/collections/struct.HashMap.html)
|
||||||
/// implementation with fewer guarantees, and better optimised for the GameBoy Advance.
|
/// implementation with fewer guarantees, and better optimised for the GameBoy Advance.
|
||||||
///
|
///
|
||||||
/// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html
|
/// [`Eq`]: https://doc.rust-lang.org/core/cmp/trait.Eq.html
|
||||||
|
@ -89,11 +89,13 @@ pub struct HashMap<K, V> {
|
||||||
|
|
||||||
impl<K, V> HashMap<K, V> {
|
impl<K, V> HashMap<K, V> {
|
||||||
/// Creates a `HashMap`
|
/// Creates a `HashMap`
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::with_size(16)
|
Self::with_size(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an empty `HashMap` with specified internal size. The size must be a power of 2
|
/// Creates an empty `HashMap` with specified internal size. The size must be a power of 2
|
||||||
|
#[must_use]
|
||||||
pub fn with_size(size: usize) -> Self {
|
pub fn with_size(size: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
nodes: NodeStorage::with_size(size),
|
nodes: NodeStorage::with_size(size),
|
||||||
|
@ -103,6 +105,7 @@ impl<K, V> HashMap<K, V> {
|
||||||
|
|
||||||
/// Creates an empty `HashMap` which can hold at least `capacity` elements before resizing. The actual
|
/// Creates an empty `HashMap` which can hold at least `capacity` elements before resizing. The actual
|
||||||
/// internal size may be larger as it must be a power of 2
|
/// internal size may be larger as it must be a power of 2
|
||||||
|
#[must_use]
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
let attempted_size = 1usize << i;
|
let attempted_size = 1usize << i;
|
||||||
|
@ -118,11 +121,13 @@ impl<K, V> HashMap<K, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of elements in the map
|
/// Returns the number of elements in the map
|
||||||
|
#[must_use]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.nodes.len()
|
self.nodes.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of elements the map can hold
|
/// Returns the number of elements the map can hold
|
||||||
|
#[must_use]
|
||||||
pub fn capacity(&self) -> usize {
|
pub fn capacity(&self) -> usize {
|
||||||
self.nodes.capacity()
|
self.nodes.capacity()
|
||||||
}
|
}
|
||||||
|
@ -149,21 +154,16 @@ impl<K, V> HashMap<K, V> {
|
||||||
|
|
||||||
/// An iterator visiting all key-value pairs in an arbitrary order
|
/// An iterator visiting all key-value pairs in an arbitrary order
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (&'_ K, &'_ V)> {
|
pub fn iter(&self) -> impl Iterator<Item = (&'_ K, &'_ V)> {
|
||||||
self.nodes
|
self.nodes.nodes.iter().filter_map(Node::key_value_ref)
|
||||||
.nodes
|
|
||||||
.iter()
|
|
||||||
.filter_map(|node| node.key_value_ref())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator visiting all key-value pairs in an arbitrary order, with mutable references to the values
|
/// An iterator visiting all key-value pairs in an arbitrary order, with mutable references to the values
|
||||||
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&'_ K, &'_ mut V)> {
|
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&'_ K, &'_ mut V)> {
|
||||||
self.nodes
|
self.nodes.nodes.iter_mut().filter_map(Node::key_value_mut)
|
||||||
.nodes
|
|
||||||
.iter_mut()
|
|
||||||
.filter_map(|node| node.key_value_mut())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the map contains no elements
|
/// Returns `true` if the map contains no elements
|
||||||
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len() == 0
|
self.len() == 0
|
||||||
}
|
}
|
||||||
|
@ -1179,7 +1179,7 @@ mod test {
|
||||||
fn test_entry(_gba: &mut Gba) {
|
fn test_entry(_gba: &mut Gba) {
|
||||||
let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
|
let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
|
||||||
|
|
||||||
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
|
let mut map: HashMap<_, _> = xs.iter().copied().collect();
|
||||||
|
|
||||||
// Existing key (insert)
|
// Existing key (insert)
|
||||||
match map.entry(1) {
|
match map.entry(1) {
|
||||||
|
|
|
@ -10,8 +10,8 @@ pub enum Tri {
|
||||||
|
|
||||||
impl From<(bool, bool)> for Tri {
|
impl From<(bool, bool)> for Tri {
|
||||||
fn from(a: (bool, bool)) -> Tri {
|
fn from(a: (bool, bool)) -> Tri {
|
||||||
let b1 = a.0 as i8;
|
let b1 = i8::from(a.0);
|
||||||
let b2 = a.1 as i8;
|
let b2 = i8::from(a.1);
|
||||||
unsafe { core::mem::transmute(b2 - b1) }
|
unsafe { core::mem::transmute(b2 - b1) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@ impl Default for ButtonController {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ButtonController {
|
impl ButtonController {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let pressed = !unsafe { BUTTON_INPUT.read_volatile() };
|
let pressed = !unsafe { BUTTON_INPUT.read_volatile() };
|
||||||
ButtonController {
|
ButtonController {
|
||||||
|
@ -60,6 +61,7 @@ impl ButtonController {
|
||||||
self.current = !unsafe { BUTTON_INPUT.read_volatile() };
|
self.current = !unsafe { BUTTON_INPUT.read_volatile() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn x_tri(&self) -> Tri {
|
pub fn x_tri(&self) -> Tri {
|
||||||
let left = self.is_pressed(Button::LEFT);
|
let left = self.is_pressed(Button::LEFT);
|
||||||
let right = self.is_pressed(Button::RIGHT);
|
let right = self.is_pressed(Button::RIGHT);
|
||||||
|
@ -67,6 +69,7 @@ impl ButtonController {
|
||||||
(left, right).into()
|
(left, right).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn y_tri(&self) -> Tri {
|
pub fn y_tri(&self) -> Tri {
|
||||||
let up = self.is_pressed(Button::UP);
|
let up = self.is_pressed(Button::UP);
|
||||||
let down = self.is_pressed(Button::DOWN);
|
let down = self.is_pressed(Button::DOWN);
|
||||||
|
@ -74,25 +77,30 @@ impl ButtonController {
|
||||||
(up, down).into()
|
(up, down).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_pressed(&self, keys: Button) -> bool {
|
pub fn is_pressed(&self, keys: Button) -> bool {
|
||||||
let currently_pressed = self.current as u32;
|
let currently_pressed = u32::from(self.current);
|
||||||
let keys = keys.bits();
|
let keys = keys.bits();
|
||||||
(currently_pressed & keys) != 0
|
(currently_pressed & keys) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_released(&self, keys: Button) -> bool {
|
pub fn is_released(&self, keys: Button) -> bool {
|
||||||
!self.is_pressed(keys)
|
!self.is_pressed(keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_just_pressed(&self, keys: Button) -> bool {
|
pub fn is_just_pressed(&self, keys: Button) -> bool {
|
||||||
let current = self.current as u32;
|
let current = u32::from(self.current);
|
||||||
let previous = self.previous as u32;
|
let previous = u32::from(self.previous);
|
||||||
let keys = keys.bits();
|
let keys = keys.bits();
|
||||||
((current & keys) != 0) && ((previous & keys) == 0)
|
((current & keys) != 0) && ((previous & keys) == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_just_released(&self, keys: Button) -> bool {
|
pub fn is_just_released(&self, keys: Button) -> bool {
|
||||||
let current = self.current as u32;
|
let current = u32::from(self.current);
|
||||||
let previous = self.previous as u32;
|
let previous = u32::from(self.previous);
|
||||||
let keys = keys.bits();
|
let keys = keys.bits();
|
||||||
((current & keys) == 0) && ((previous & keys) != 0)
|
((current & keys) == 0) && ((previous & keys) != 0)
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,17 +157,17 @@ extern "C" fn __RUST_INTERRUPT_HANDLER(interrupt: u16) -> u16 {
|
||||||
struct InterruptInner {
|
struct InterruptInner {
|
||||||
next: Cell<*const InterruptInner>,
|
next: Cell<*const InterruptInner>,
|
||||||
root: *const InterruptRoot,
|
root: *const InterruptRoot,
|
||||||
closure: *const dyn Fn(&CriticalSection),
|
closure: *const dyn Fn(CriticalSection),
|
||||||
_pin: PhantomPinned,
|
_pin: PhantomPinned,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn create_interrupt_inner(
|
unsafe fn create_interrupt_inner(
|
||||||
c: impl Fn(&CriticalSection),
|
c: impl Fn(CriticalSection),
|
||||||
root: *const InterruptRoot,
|
root: *const InterruptRoot,
|
||||||
) -> Pin<Box<InterruptInner>> {
|
) -> Pin<Box<InterruptInner>> {
|
||||||
let c = Box::new(c);
|
let c = Box::new(c);
|
||||||
let c: &dyn Fn(&CriticalSection) = Box::leak(c);
|
let c: &dyn Fn(CriticalSection) = Box::leak(c);
|
||||||
let c: &dyn Fn(&CriticalSection) = core::mem::transmute(c);
|
let c: &dyn Fn(CriticalSection) = core::mem::transmute(c);
|
||||||
Box::pin(InterruptInner {
|
Box::pin(InterruptInner {
|
||||||
next: Cell::new(core::ptr::null()),
|
next: Cell::new(core::ptr::null()),
|
||||||
root,
|
root,
|
||||||
|
@ -179,6 +179,7 @@ unsafe fn create_interrupt_inner(
|
||||||
impl Drop for InterruptInner {
|
impl Drop for InterruptInner {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
inner_drop(unsafe { Pin::new_unchecked(self) });
|
inner_drop(unsafe { Pin::new_unchecked(self) });
|
||||||
|
#[allow(clippy::needless_pass_by_value)] // needed for safety reasons
|
||||||
fn inner_drop(this: Pin<&mut InterruptInner>) {
|
fn inner_drop(this: Pin<&mut InterruptInner>) {
|
||||||
// drop the closure allocation safely
|
// drop the closure allocation safely
|
||||||
let _closure_box =
|
let _closure_box =
|
||||||
|
@ -216,7 +217,7 @@ impl InterruptRoot {
|
||||||
while !c.is_null() {
|
while !c.is_null() {
|
||||||
let closure_ptr = unsafe { &*c }.closure;
|
let closure_ptr = unsafe { &*c }.closure;
|
||||||
let closure_ref = unsafe { &*closure_ptr };
|
let closure_ref = unsafe { &*closure_ptr };
|
||||||
closure_ref(unsafe { &CriticalSection::new() });
|
closure_ref(unsafe { CriticalSection::new() });
|
||||||
c = unsafe { &*c }.next.get();
|
c = unsafe { &*c }.next.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +242,7 @@ fn interrupt_to_root(interrupt: Interrupt) -> &'static InterruptRoot {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_interrupt_handler<'a>(
|
pub fn add_interrupt_handler<'a>(
|
||||||
interrupt: Interrupt,
|
interrupt: Interrupt,
|
||||||
handler: impl Fn(&CriticalSection) + Send + Sync + 'a,
|
handler: impl Fn(CriticalSection) + Send + Sync + 'a,
|
||||||
) -> InterruptHandler<'a> {
|
) -> InterruptHandler<'a> {
|
||||||
fn do_with_inner<'a>(
|
fn do_with_inner<'a>(
|
||||||
interrupt: Interrupt,
|
interrupt: Interrupt,
|
||||||
|
@ -282,13 +283,13 @@ pub fn add_interrupt_handler<'a>(
|
||||||
/// [`CriticalSection`]: bare_metal::CriticalSection
|
/// [`CriticalSection`]: bare_metal::CriticalSection
|
||||||
pub fn free<F, R>(f: F) -> R
|
pub fn free<F, R>(f: F) -> R
|
||||||
where
|
where
|
||||||
F: FnOnce(&CriticalSection) -> R,
|
F: FnOnce(CriticalSection) -> R,
|
||||||
{
|
{
|
||||||
let enabled = INTERRUPTS_ENABLED.get();
|
let enabled = INTERRUPTS_ENABLED.get();
|
||||||
|
|
||||||
disable_interrupts();
|
disable_interrupts();
|
||||||
|
|
||||||
let r = f(unsafe { &CriticalSection::new() });
|
let r = f(unsafe { CriticalSection::new() });
|
||||||
|
|
||||||
INTERRUPTS_ENABLED.set(enabled);
|
INTERRUPTS_ENABLED.set(enabled);
|
||||||
r
|
r
|
||||||
|
@ -300,6 +301,7 @@ pub struct VBlank {}
|
||||||
impl VBlank {
|
impl VBlank {
|
||||||
/// Handles setting up everything reqired to be able to use the wait for
|
/// Handles setting up everything reqired to be able to use the wait for
|
||||||
/// interrupt syscall.
|
/// interrupt syscall.
|
||||||
|
#[must_use]
|
||||||
pub fn get() -> Self {
|
pub fn get() -> Self {
|
||||||
interrupt_to_root(Interrupt::VBlank).add();
|
interrupt_to_root(Interrupt::VBlank).add();
|
||||||
VBlank {}
|
VBlank {}
|
||||||
|
@ -328,17 +330,17 @@ mod tests {
|
||||||
{
|
{
|
||||||
let counter = Mutex::new(RefCell::new(0));
|
let counter = Mutex::new(RefCell::new(0));
|
||||||
let counter_2 = Mutex::new(RefCell::new(0));
|
let counter_2 = Mutex::new(RefCell::new(0));
|
||||||
let _a = add_interrupt_handler(Interrupt::VBlank, |key: &CriticalSection| {
|
let _a = add_interrupt_handler(Interrupt::VBlank, |key: CriticalSection| {
|
||||||
*counter.borrow(*key).borrow_mut() += 1
|
*counter.borrow(key).borrow_mut() += 1;
|
||||||
});
|
});
|
||||||
let _b = add_interrupt_handler(Interrupt::VBlank, |key: &CriticalSection| {
|
let _b = add_interrupt_handler(Interrupt::VBlank, |key: CriticalSection| {
|
||||||
*counter_2.borrow(*key).borrow_mut() += 1
|
*counter_2.borrow(key).borrow_mut() += 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
let vblank = VBlank::get();
|
let vblank = VBlank::get();
|
||||||
|
|
||||||
while free(|key| {
|
while free(|key| {
|
||||||
*counter.borrow(*key).borrow() < 100 || *counter_2.borrow(*key).borrow() < 100
|
*counter.borrow(key).borrow() < 100 || *counter_2.borrow(key).borrow() < 100
|
||||||
}) {
|
}) {
|
||||||
vblank.wait_for_vblank();
|
vblank.wait_for_vblank();
|
||||||
}
|
}
|
||||||
|
@ -375,7 +377,7 @@ pub fn profiler(timer: &mut crate::timer::Timer, period: u16) -> InterruptHandle
|
||||||
timer.set_overflow_amount(period);
|
timer.set_overflow_amount(period);
|
||||||
timer.set_enabled(true);
|
timer.set_enabled(true);
|
||||||
|
|
||||||
add_interrupt_handler(timer.interrupt(), |_key: &CriticalSection| {
|
add_interrupt_handler(timer.interrupt(), |_key: CriticalSection| {
|
||||||
crate::println!("{:#010x}", crate::program_counter_before_interrupt());
|
crate::println!("{:#010x}", crate::program_counter_before_interrupt());
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,14 @@
|
||||||
#![cfg_attr(test, test_runner(crate::test_runner::test_runner))]
|
#![cfg_attr(test, test_runner(crate::test_runner::test_runner))]
|
||||||
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
|
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
|
#![warn(clippy::all)]
|
||||||
|
#![deny(clippy::must_use_candidate)]
|
||||||
|
#![deny(clippy::trivially_copy_pass_by_ref)]
|
||||||
|
#![deny(clippy::semicolon_if_nothing_returned)]
|
||||||
|
#![deny(clippy::map_unwrap_or)]
|
||||||
|
#![deny(clippy::needless_pass_by_value)]
|
||||||
|
#![deny(clippy::redundant_closure_for_method_calls)]
|
||||||
|
#![deny(clippy::cloned_instead_of_copied)]
|
||||||
|
|
||||||
//! # agb
|
//! # agb
|
||||||
//! `agb` is a library for making games on the Game Boy Advance using the Rust
|
//! `agb` is a library for making games on the Game Boy Advance using the Rust
|
||||||
|
@ -225,6 +233,7 @@ pub struct Gba {
|
||||||
|
|
||||||
impl Gba {
|
impl Gba {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
#[must_use]
|
||||||
pub unsafe fn new_in_entry() -> Self {
|
pub unsafe fn new_in_entry() -> Self {
|
||||||
GBASINGLE.take()
|
GBASINGLE.take()
|
||||||
}
|
}
|
||||||
|
@ -356,7 +365,7 @@ mod test {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vblank.wait_for_vblank();
|
vblank.wait_for_vblank();
|
||||||
counter += 1
|
counter += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ fn is_running_in_mgba() -> bool {
|
||||||
const NUMBER_OF_CYCLES: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x04FF_F800) };
|
const NUMBER_OF_CYCLES: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x04FF_F800) };
|
||||||
|
|
||||||
pub fn number_of_cycles_tagged(tag: u16) {
|
pub fn number_of_cycles_tagged(tag: u16) {
|
||||||
NUMBER_OF_CYCLES.set(tag)
|
NUMBER_OF_CYCLES.set(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Mgba {
|
pub struct Mgba {
|
||||||
|
@ -37,6 +37,7 @@ pub struct Mgba {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mgba {
|
impl Mgba {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Option<Self> {
|
pub fn new() -> Option<Self> {
|
||||||
if is_running_in_mgba() {
|
if is_running_in_mgba() {
|
||||||
Some(Mgba { bytes_written: 0 })
|
Some(Mgba { bytes_written: 0 })
|
||||||
|
|
|
@ -15,12 +15,14 @@ impl RandomNumberGenerator {
|
||||||
/// Create a new random number generator with a fixed seed
|
/// Create a new random number generator with a fixed seed
|
||||||
///
|
///
|
||||||
/// Note that this seed is guaranteed to be the same between minor releases.
|
/// Note that this seed is guaranteed to be the same between minor releases.
|
||||||
|
#[must_use]
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self::new_with_seed([1014776995, 476057059, 3301633994, 706340607])
|
Self::new_with_seed([1014776995, 476057059, 3301633994, 706340607])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produces a random number generator with the given initial state / seed.
|
/// Produces a random number generator with the given initial state / seed.
|
||||||
/// None of the values can be 0.
|
/// None of the values can be 0.
|
||||||
|
#[must_use]
|
||||||
pub const fn new_with_seed(seed: [u32; 4]) -> Self {
|
pub const fn new_with_seed(seed: [u32; 4]) -> Self {
|
||||||
// this can't be in a loop because const
|
// this can't be in a loop because const
|
||||||
assert!(seed[0] != 0, "seed must not be 0");
|
assert!(seed[0] != 0, "seed must not be 0");
|
||||||
|
@ -54,8 +56,9 @@ static GLOBAL_RNG: Mutex<RefCell<RandomNumberGenerator>> =
|
||||||
Mutex::new(RefCell::new(RandomNumberGenerator::new()));
|
Mutex::new(RefCell::new(RandomNumberGenerator::new()));
|
||||||
|
|
||||||
/// Using a global random number generator, provides the next random number
|
/// Using a global random number generator, provides the next random number
|
||||||
|
#[must_use]
|
||||||
pub fn gen() -> i32 {
|
pub fn gen() -> i32 {
|
||||||
free(|cs| GLOBAL_RNG.borrow(*cs).borrow_mut().gen())
|
free(|cs| GLOBAL_RNG.borrow(cs).borrow_mut().gen())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -22,14 +22,17 @@ impl Sound {
|
||||||
Sound {}
|
Sound {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn channel1(&self) -> Channel1 {
|
pub fn channel1(&self) -> Channel1 {
|
||||||
Channel1 {}
|
Channel1 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn channel2(&self) -> Channel2 {
|
pub fn channel2(&self) -> Channel2 {
|
||||||
Channel2 {}
|
Channel2 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn noise(&self) -> Noise {
|
pub fn noise(&self) -> Noise {
|
||||||
Noise {}
|
Noise {}
|
||||||
}
|
}
|
||||||
|
@ -56,10 +59,10 @@ impl Channel1 {
|
||||||
duty_cycle: DutyCycle,
|
duty_cycle: DutyCycle,
|
||||||
) {
|
) {
|
||||||
CHANNEL_1_SWEEP.set(sweep_settings.as_bits());
|
CHANNEL_1_SWEEP.set(sweep_settings.as_bits());
|
||||||
let length_bits = length.unwrap_or(0) as u16;
|
let length_bits = u16::from(length.unwrap_or(0));
|
||||||
assert!(length_bits < 64, "Length must be less than 64");
|
assert!(length_bits < 64, "Length must be less than 64");
|
||||||
|
|
||||||
let length_flag: u16 = length.map(|_| 1 << 14).unwrap_or(0);
|
let length_flag: u16 = length.map_or(0, |_| 1 << 14);
|
||||||
let initial: u16 = 1 << 15;
|
let initial: u16 = 1 << 15;
|
||||||
|
|
||||||
assert!(frequency < 2048, "Frequency must be less than 2048");
|
assert!(frequency < 2048, "Frequency must be less than 2048");
|
||||||
|
@ -81,10 +84,10 @@ impl Channel2 {
|
||||||
envelope_settings: &EnvelopeSettings,
|
envelope_settings: &EnvelopeSettings,
|
||||||
duty_cycle: DutyCycle,
|
duty_cycle: DutyCycle,
|
||||||
) {
|
) {
|
||||||
let length_bits = length.unwrap_or(0) as u16;
|
let length_bits = u16::from(length.unwrap_or(0));
|
||||||
assert!(length_bits < 64, "Length must be less than 64");
|
assert!(length_bits < 64, "Length must be less than 64");
|
||||||
|
|
||||||
let length_flag: u16 = length.map(|_| 1 << 14).unwrap_or(0);
|
let length_flag: u16 = length.map_or(0, |_| 1 << 14);
|
||||||
let initial: u16 = 1 << 15;
|
let initial: u16 = 1 << 15;
|
||||||
|
|
||||||
assert!(frequency < 2048, "Frequency must be less than 2048");
|
assert!(frequency < 2048, "Frequency must be less than 2048");
|
||||||
|
@ -107,7 +110,7 @@ impl Noise {
|
||||||
counter_step_width_15: bool,
|
counter_step_width_15: bool,
|
||||||
shift_clock_frequency: u8,
|
shift_clock_frequency: u8,
|
||||||
) {
|
) {
|
||||||
let length_bits = length.unwrap_or(0) as u16;
|
let length_bits = u16::from(length.unwrap_or(0));
|
||||||
assert!(length_bits < 64, "length must be less than 16");
|
assert!(length_bits < 64, "length must be less than 16");
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -119,19 +122,19 @@ impl Noise {
|
||||||
"frequency clock divider must be less than 16"
|
"frequency clock divider must be less than 16"
|
||||||
);
|
);
|
||||||
|
|
||||||
let length_flag: u16 = length.map(|_| 1 << 14).unwrap_or(0);
|
let length_flag: u16 = length.map_or(0, |_| 1 << 14);
|
||||||
let initial: u16 = 1 << 15;
|
let initial: u16 = 1 << 15;
|
||||||
|
|
||||||
let counter_step_bit = if counter_step_width_15 { 0 } else { 1 << 3 };
|
let counter_step_bit = if counter_step_width_15 { 0 } else { 1 << 3 };
|
||||||
|
|
||||||
CHANNEL_4_LENGTH_ENVELOPE.set(length_bits | envelope_setting.as_bits());
|
CHANNEL_4_LENGTH_ENVELOPE.set(length_bits | envelope_setting.as_bits());
|
||||||
CHANNEL_4_FREQUENCY_CONTROL.set(
|
CHANNEL_4_FREQUENCY_CONTROL.set(
|
||||||
(frequency_divider as u16)
|
u16::from(frequency_divider)
|
||||||
| counter_step_bit
|
| counter_step_bit
|
||||||
| ((shift_clock_frequency as u16) << 4)
|
| (u16::from(shift_clock_frequency) << 4)
|
||||||
| length_flag
|
| length_flag
|
||||||
| initial,
|
| initial,
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,6 +159,7 @@ pub struct SweepSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SweepSettings {
|
impl SweepSettings {
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
number_of_sweep_shifts: u8,
|
number_of_sweep_shifts: u8,
|
||||||
sound_direction: SoundDirection,
|
sound_direction: SoundDirection,
|
||||||
|
@ -175,9 +179,9 @@ impl SweepSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_bits(&self) -> u16 {
|
fn as_bits(&self) -> u16 {
|
||||||
((self.number_of_sweep_shifts as u16) & 0b111)
|
(u16::from(self.number_of_sweep_shifts) & 0b111)
|
||||||
| ((1 - self.sound_direction.as_bits()) << 3) // sweep works backwards
|
| ((1 - self.sound_direction.as_bits()) << 3) // sweep works backwards
|
||||||
| ((self.sweep_time as u16) & 0b111) << 4
|
| (u16::from(self.sweep_time) & 0b111) << 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,6 +198,7 @@ pub struct EnvelopeSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvelopeSettings {
|
impl EnvelopeSettings {
|
||||||
|
#[must_use]
|
||||||
pub fn new(step_time: u8, direction: SoundDirection, initial_volume: u8) -> Self {
|
pub fn new(step_time: u8, direction: SoundDirection, initial_volume: u8) -> Self {
|
||||||
assert!(step_time < 8, "Step time must be less than 8");
|
assert!(step_time < 8, "Step time must be less than 8");
|
||||||
assert!(initial_volume < 16, "Initial volume must be less that 16");
|
assert!(initial_volume < 16, "Initial volume must be less that 16");
|
||||||
|
@ -205,9 +210,9 @@ impl EnvelopeSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_bits(&self) -> u16 {
|
fn as_bits(&self) -> u16 {
|
||||||
(self.step_time as u16) << 8
|
u16::from(self.step_time) << 8
|
||||||
| (self.direction.as_bits() << 11)
|
| (self.direction.as_bits() << 11)
|
||||||
| ((self.initial_volume as u16) << 12)
|
| (u16::from(self.initial_volume) << 12)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,6 +222,7 @@ impl Default for EnvelopeSettings {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub enum DutyCycle {
|
pub enum DutyCycle {
|
||||||
OneEighth,
|
OneEighth,
|
||||||
OneQuarter,
|
OneQuarter,
|
||||||
|
@ -225,10 +231,10 @@ pub enum DutyCycle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DutyCycle {
|
impl DutyCycle {
|
||||||
fn as_bits(&self) -> u16 {
|
fn as_bits(self) -> u16 {
|
||||||
use DutyCycle::*;
|
use DutyCycle::*;
|
||||||
|
|
||||||
match &self {
|
match self {
|
||||||
OneEighth => 0,
|
OneEighth => 0,
|
||||||
OneQuarter => 1,
|
OneQuarter => 1,
|
||||||
Half => 2,
|
Half => 2,
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub struct SoundChannel {
|
||||||
|
|
||||||
impl SoundChannel {
|
impl SoundChannel {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn new(data: &'static [u8]) -> Self {
|
pub fn new(data: &'static [u8]) -> Self {
|
||||||
SoundChannel {
|
SoundChannel {
|
||||||
data,
|
data,
|
||||||
|
@ -58,6 +59,7 @@ impl SoundChannel {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[must_use]
|
||||||
pub fn new_high_priority(data: &'static [u8]) -> Self {
|
pub fn new_high_priority(data: &'static [u8]) -> Self {
|
||||||
SoundChannel {
|
SoundChannel {
|
||||||
data,
|
data,
|
||||||
|
@ -110,6 +112,6 @@ impl SoundChannel {
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn stop(&mut self) {
|
pub fn stop(&mut self) {
|
||||||
self.is_done = true
|
self.is_done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -216,11 +216,11 @@ impl MixerBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_calculate(&self) -> bool {
|
fn should_calculate(&self) -> bool {
|
||||||
free(|cs| self.state.borrow(*cs).borrow().should_calculate())
|
free(|cs| self.state.borrow(cs).borrow().should_calculate())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn swap(&self, cs: &CriticalSection) {
|
fn swap(&self, cs: CriticalSection) {
|
||||||
let buffer = self.state.borrow(*cs).borrow_mut().playing_advanced();
|
let buffer = self.state.borrow(cs).borrow_mut().playing_advanced();
|
||||||
|
|
||||||
let (left_buffer, right_buffer) = self.buffers[buffer]
|
let (left_buffer, right_buffer) = self.buffers[buffer]
|
||||||
.0
|
.0
|
||||||
|
@ -282,7 +282,7 @@ impl MixerBuffer {
|
||||||
channel.pos += playback_speed * constants::SOUND_BUFFER_SIZE;
|
channel.pos += playback_speed * constants::SOUND_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
let write_buffer_index = free(|cs| self.state.borrow(*cs).borrow_mut().active_advanced());
|
let write_buffer_index = free(|cs| self.state.borrow(cs).borrow_mut().active_advanced());
|
||||||
|
|
||||||
let write_buffer = &mut self.buffers[write_buffer_index].0;
|
let write_buffer = &mut self.buffers[write_buffer_index].0;
|
||||||
cpu_fast_fill_i8(write_buffer, 0);
|
cpu_fast_fill_i8(write_buffer, 0);
|
||||||
|
|
|
@ -54,6 +54,7 @@ pub fn wait_for_vblank() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn div(numerator: i32, denominator: i32) -> (i32, i32, i32) {
|
pub fn div(numerator: i32, denominator: i32) -> (i32, i32, i32) {
|
||||||
let divide: i32;
|
let divide: i32;
|
||||||
let modulo: i32;
|
let modulo: i32;
|
||||||
|
@ -71,6 +72,7 @@ pub fn div(numerator: i32, denominator: i32) -> (i32, i32, i32) {
|
||||||
(divide, modulo, abs_divide)
|
(divide, modulo, abs_divide)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn sqrt(n: i32) -> i32 {
|
pub fn sqrt(n: i32) -> i32 {
|
||||||
let result: i32;
|
let result: i32;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -86,6 +88,7 @@ pub fn sqrt(n: i32) -> i32 {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn arc_tan(n: i16) -> i16 {
|
pub fn arc_tan(n: i16) -> i16 {
|
||||||
let result: i16;
|
let result: i16;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -101,6 +104,7 @@ pub fn arc_tan(n: i16) -> i16 {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn arc_tan2(x: i16, y: i32) -> i16 {
|
pub fn arc_tan2(x: i16, y: i32) -> i16 {
|
||||||
let result: i16;
|
let result: i16;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub enum Divider {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Divider {
|
impl Divider {
|
||||||
fn as_bits(&self) -> u16 {
|
fn as_bits(self) -> u16 {
|
||||||
use Divider::*;
|
use Divider::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
@ -68,6 +68,7 @@ impl Timer {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn value(&self) -> u16 {
|
pub fn value(&self) -> u16 {
|
||||||
self.data_register().get()
|
self.data_register().get()
|
||||||
}
|
}
|
||||||
|
@ -90,7 +91,7 @@ impl Timer {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_interrupt(&mut self, interrupt: bool) -> &mut Self {
|
pub fn set_interrupt(&mut self, interrupt: bool) -> &mut Self {
|
||||||
let bit = interrupt as u16;
|
let bit = u16::from(interrupt);
|
||||||
self.control_register().set_bits(bit, 1, 6);
|
self.control_register().set_bits(bit, 1, 6);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -107,6 +108,7 @@ impl Timer {
|
||||||
self.timer_number as usize
|
self.timer_number as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn interrupt(&self) -> crate::interrupt::Interrupt {
|
pub fn interrupt(&self) -> crate::interrupt::Interrupt {
|
||||||
use crate::interrupt::Interrupt;
|
use crate::interrupt::Interrupt;
|
||||||
match self.timer_number {
|
match self.timer_number {
|
||||||
|
|
|
@ -2291,7 +2291,7 @@ fn game_with_level(gba: &mut agb::Gba) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rng::gen(); // advance RNG to make it less predictable between runs
|
let _ = rng::gen(); // advance RNG to make it less predictable between runs
|
||||||
};
|
};
|
||||||
|
|
||||||
game.clear(&mut vram);
|
game.clear(&mut vram);
|
||||||
|
|
Loading…
Reference in a new issue