From 8158bc1ff3572a6df682e76ff9894a5b231edee9 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 13:16:57 +0100 Subject: [PATCH 01/20] Allow deduplicating background tiles --- agb-image-converter/src/lib.rs | 19 +++++++++++++++++++ examples/combo/src/lib.rs | 8 ++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs index 6e227d1d..af3ab982 100644 --- a/agb-image-converter/src/lib.rs +++ b/agb-image-converter/src/lib.rs @@ -36,6 +36,7 @@ struct BackgroundGfxOption { module_name: String, file_name: String, colours: Colours, + deduplicate: bool, } impl config::Image for BackgroundGfxOption { @@ -72,12 +73,30 @@ impl Parse for BackgroundGfxOption { Colours::Colours16 }; + let lookahead = input.lookahead1(); + + let deduplicate = if lookahead.peek(syn::Ident) { + let deduplicate: syn::Ident = input.parse()?; + + if deduplicate == "deduplicate" { + true + } else { + return Err(syn::Error::new_spanned( + deduplicate, + "Must either be the literal deduplicate or missing", + )); + } + } else { + false + }; + let file_name: syn::LitStr = input.parse()?; Ok(Self { module_name: module_name.to_string(), file_name: file_name.value(), colours, + deduplicate, }) } } diff --git a/examples/combo/src/lib.rs b/examples/combo/src/lib.rs index 67dd4263..69f495ae 100644 --- a/examples/combo/src/lib.rs +++ b/examples/combo/src/lib.rs @@ -47,10 +47,10 @@ impl Game { include_background_gfx!( games, "121105", - hat => "gfx/hat.png", - purple => "gfx/purple.png", - hyperspace => "gfx/hyperspace.png", - amplitude => "gfx/amplitude.png" + hat => deduplicate "gfx/hat.png", + purple => deduplicate "gfx/purple.png", + hyperspace => deduplicate "gfx/hyperspace.png", + amplitude => deduplicate "gfx/amplitude.png" ); fn get_game(gba: &mut agb::Gba) -> Game { From f097e152cc13bbb3724c05b02c601862cbd32e7c Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 13:18:14 +0100 Subject: [PATCH 02/20] Pass deduplicate one step further --- agb-image-converter/src/config.rs | 1 + agb-image-converter/src/lib.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/agb-image-converter/src/config.rs b/agb-image-converter/src/config.rs index 814fced2..39d8936c 100644 --- a/agb-image-converter/src/config.rs +++ b/agb-image-converter/src/config.rs @@ -11,4 +11,5 @@ pub(crate) trait Config { pub(crate) trait Image { fn filename(&self) -> String; fn colours(&self) -> Colours; + fn deduplicate(&self) -> bool; } diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs index af3ab982..a247e04a 100644 --- a/agb-image-converter/src/lib.rs +++ b/agb-image-converter/src/lib.rs @@ -47,6 +47,10 @@ impl config::Image for BackgroundGfxOption { fn colours(&self) -> Colours { self.colours } + + fn deduplicate(&self) -> bool { + self.deduplicate + } } impl Parse for BackgroundGfxOption { From b5af3a3aff4d76d9af6b66f655a625d6edb5da53 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 14:07:19 +0100 Subject: [PATCH 03/20] Generate tile settings instead of palette assignments --- agb-image-converter/src/image_loader.rs | 9 +++++ agb-image-converter/src/lib.rs | 3 ++ agb-image-converter/src/rust_generator.rs | 40 ++++++++++++++++++++--- agb/src/display/example_logo.rs | 12 ++++--- agb/src/display/tile_data.rs | 8 +++-- 5 files changed, 59 insertions(+), 13 deletions(-) diff --git a/agb-image-converter/src/image_loader.rs b/agb-image-converter/src/image_loader.rs index a7909ce0..5c95ad67 100644 --- a/agb-image-converter/src/image_loader.rs +++ b/agb-image-converter/src/image_loader.rs @@ -4,6 +4,7 @@ use image::{DynamicImage, GenericImageView}; use crate::colour::Colour; +#[derive(Clone)] pub(crate) struct Image { pub width: usize, pub height: usize, @@ -42,6 +43,14 @@ impl Image { } } + pub fn from_colour_data(colour_data: Vec) -> Self { + Self { + height: colour_data.len() / 8, + colour_data, + width: 8, + } + } + pub fn colour(&self, x: usize, y: usize) -> Colour { self.colour_data[x + y * self.width] } diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs index a247e04a..16f19adb 100644 --- a/agb-image-converter/src/lib.rs +++ b/agb-image-converter/src/lib.rs @@ -15,6 +15,7 @@ use quote::{format_ident, quote, ToTokens}; mod aseprite; mod colour; mod config; +mod deduplicator; mod font_loader; mod image_loader; mod palette16; @@ -429,6 +430,7 @@ fn convert_image( ) -> proc_macro2::TokenStream { let image_filename = &parent.join(settings.filename()); let image = Image::load_from_file(image_filename); + let deduplicate = settings.deduplicate(); rust_generator::generate_code( variable_name, @@ -437,6 +439,7 @@ fn convert_image( &image_filename.to_string_lossy(), crate_prefix.to_owned(), assignment_offset, + deduplicate, ) } diff --git a/agb-image-converter/src/rust_generator.rs b/agb-image-converter/src/rust_generator.rs index 9a7de049..3ea5da90 100644 --- a/agb-image-converter/src/rust_generator.rs +++ b/agb-image-converter/src/rust_generator.rs @@ -1,3 +1,4 @@ +use crate::deduplicator::{DeduplicatedData, Transformation}; use crate::palette16::Palette16OptimisationResults; use crate::{add_image_256_to_tile_data, add_image_to_tile_data, collapse_to_4bpp}; use crate::{image_loader::Image, ByteString}; @@ -40,14 +41,32 @@ pub(crate) fn generate_code( image_filename: &str, crate_prefix: String, assignment_offset: Option, + deduplicate: bool, ) -> TokenStream { let crate_prefix = format_ident!("{}", crate_prefix); let output_variable_name = format_ident!("{}", output_variable_name); + let (image, dedup_data) = if deduplicate { + let (new_image, dedup_data) = + crate::deduplicator::deduplicate_image(image, assignment_offset.is_some()); + + (new_image, dedup_data) + } else { + ( + image.clone(), + (0..(image.width * image.height / 8 / 8)) + .map(|i| DeduplicatedData { + new_index: i, + transformation: Transformation::none(), + }) + .collect(), + ) + }; + let (tile_data, assignments) = if let Some(assignment_offset) = assignment_offset { let mut tile_data = Vec::new(); - add_image_to_tile_data(&mut tile_data, image, results, assignment_offset, false); + add_image_to_tile_data(&mut tile_data, &image, results, assignment_offset, false); let tile_data = collapse_to_4bpp(&tile_data); @@ -65,11 +84,22 @@ pub(crate) fn generate_code( } else { let mut tile_data = Vec::new(); - add_image_256_to_tile_data(&mut tile_data, image, results); + add_image_256_to_tile_data(&mut tile_data, &image, results); (tile_data, vec![]) }; + let tile_settings = dedup_data.iter().map(|data| { + let palette_assignment = assignments.get(data.new_index).unwrap_or(&0); + let vflipped = data.transformation.vflip; + let hflipped = data.transformation.hflip; + let index= data.new_index as u16; + + quote! { + #crate_prefix::display::tiled::TileSetting::new(#index, #hflipped, #vflipped, #palette_assignment) + } + }); + let data = ByteString(&tile_data); quote! { @@ -91,11 +121,11 @@ pub(crate) fn generate_code( &ALIGNED.bytes }; - const PALETTE_ASSIGNMENT: &[u8] = &[ - #(#assignments),* + const TILE_SETTINGS: &[#crate_prefix::display::tiled::TileSetting] = &[ + #(#tile_settings),* ]; - #crate_prefix::display::tile_data::TileData::new(TILE_DATA, PALETTE_ASSIGNMENT) + #crate_prefix::display::tile_data::TileData::new(TILE_DATA, TILE_SETTINGS) }; } } diff --git a/agb/src/display/example_logo.rs b/agb/src/display/example_logo.rs index 351d80ab..240f6638 100644 --- a/agb/src/display/example_logo.rs +++ b/agb/src/display/example_logo.rs @@ -1,4 +1,4 @@ -use super::tiled::{RegularMap, TileFormat, TileSet, TileSetting, TiledMap, VRamManager}; +use super::tiled::{RegularMap, TileFormat, TileSet, TiledMap, VRamManager}; crate::include_background_gfx!(crate, agb_logo, test_logo => "gfx/test_logo.png"); @@ -11,10 +11,12 @@ pub fn display_logo(map: &mut RegularMap, vram: &mut VRamManager) { for x in 0..30 { let tile_id = y * 30 + x; - let palette_entry = agb_logo::test_logo.palette_assignments[tile_id as usize]; - let tile_setting = TileSetting::new(tile_id, false, false, palette_entry); - - map.set_tile(vram, (x, y).into(), &background_tilemap, tile_setting); + map.set_tile( + vram, + (x as u16, y as u16).into(), + &background_tilemap, + agb_logo::test_logo.tile_settings[tile_id], + ); } } diff --git a/agb/src/display/tile_data.rs b/agb/src/display/tile_data.rs index cc51ef9b..c1193417 100644 --- a/agb/src/display/tile_data.rs +++ b/agb/src/display/tile_data.rs @@ -1,15 +1,17 @@ +use super::tiled::TileSetting; + #[non_exhaustive] pub struct TileData { pub tiles: &'static [u8], - pub palette_assignments: &'static [u8], + pub tile_settings: &'static [TileSetting], } impl TileData { #[must_use] - pub const fn new(tiles: &'static [u8], palette_assignments: &'static [u8]) -> Self { + pub const fn new(tiles: &'static [u8], tile_settings: &'static [TileSetting]) -> Self { TileData { tiles, - palette_assignments, + tile_settings, } } } From 3d7d3f25a2f7f500f0774a1bcc18b3d137854196 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 14:13:40 +0100 Subject: [PATCH 04/20] Update agb repo --- agb-image-converter/src/rust_generator.rs | 2 +- agb/examples/animated_background.rs | 4 ++-- agb/src/display/example_logo.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/agb-image-converter/src/rust_generator.rs b/agb-image-converter/src/rust_generator.rs index 3ea5da90..aad0b001 100644 --- a/agb-image-converter/src/rust_generator.rs +++ b/agb-image-converter/src/rust_generator.rs @@ -93,7 +93,7 @@ pub(crate) fn generate_code( let palette_assignment = assignments.get(data.new_index).unwrap_or(&0); let vflipped = data.transformation.vflip; let hflipped = data.transformation.hflip; - let index= data.new_index as u16; + let index = data.new_index as u16; quote! { #crate_prefix::display::tiled::TileSetting::new(#index, #hflipped, #vflipped, #palette_assignment) diff --git a/agb/examples/animated_background.rs b/agb/examples/animated_background.rs index 31ef37b1..398932b7 100644 --- a/agb/examples/animated_background.rs +++ b/agb/examples/animated_background.rs @@ -3,7 +3,7 @@ use agb::{ display::{ - tiled::{RegularBackgroundSize, TileFormat, TileSet, TileSetting, TiledMap}, + tiled::{RegularBackgroundSize, TileFormat, TileSet, TiledMap}, Priority, }, include_background_gfx, @@ -32,7 +32,7 @@ fn main(mut gba: agb::Gba) -> ! { &mut vram, (x, y).into(), &tileset, - TileSetting::new(0, false, false, 0), + water_tiles::water_tiles.tile_settings[0], ); } } diff --git a/agb/src/display/example_logo.rs b/agb/src/display/example_logo.rs index 240f6638..5c008a29 100644 --- a/agb/src/display/example_logo.rs +++ b/agb/src/display/example_logo.rs @@ -1,6 +1,6 @@ use super::tiled::{RegularMap, TileFormat, TileSet, TiledMap, VRamManager}; -crate::include_background_gfx!(crate, agb_logo, test_logo => "gfx/test_logo.png"); +crate::include_background_gfx!(crate, agb_logo, test_logo => deduplicate "gfx/test_logo.png"); pub fn display_logo(map: &mut RegularMap, vram: &mut VRamManager) { vram.set_background_palettes(agb_logo::PALETTES); From 6d56e72d662a97334ed4573fab736755d4715ad4 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 14:39:41 +0100 Subject: [PATCH 05/20] Fix palette assignment --- agb-image-converter/src/lib.rs | 12 ++++++++-- agb-image-converter/src/rust_generator.rs | 27 +++++++++++++++++------ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/agb-image-converter/src/lib.rs b/agb-image-converter/src/lib.rs index 16f19adb..d5fa34e4 100644 --- a/agb-image-converter/src/lib.rs +++ b/agb-image-converter/src/lib.rs @@ -494,7 +494,14 @@ fn palette_tile_data( let mut tile_data = Vec::new(); for (image_idx, image) in images.iter().enumerate() { - add_image_to_tile_data(&mut tile_data, image, optimiser, image_idx, true) + add_image_to_tile_data( + &mut tile_data, + image, + optimiser, + image_idx, + true, + &(0..images.len()).collect::>(), + ); } let tile_data = collapse_to_4bpp(&tile_data); @@ -517,6 +524,7 @@ fn add_image_to_tile_data( optimiser: &Palette16OptimisationResults, assignment_offset: usize, is_sprite: bool, + remap_index: &[usize], ) { let tile_size = 8; let tiles_x = image.width / tile_size; @@ -527,7 +535,7 @@ fn add_image_to_tile_data( let assignment = if is_sprite { assignment_offset } else { - y * tiles_x + x + assignment_offset + remap_index[y * tiles_x + x] + assignment_offset }; let palette_index = optimiser.assignments[assignment]; diff --git a/agb-image-converter/src/rust_generator.rs b/agb-image-converter/src/rust_generator.rs index aad0b001..bd6f243c 100644 --- a/agb-image-converter/src/rust_generator.rs +++ b/agb-image-converter/src/rust_generator.rs @@ -6,6 +6,7 @@ use crate::{image_loader::Image, ByteString}; use proc_macro2::TokenStream; use quote::{format_ident, quote}; +use std::collections::BTreeMap; use std::iter; pub(crate) fn generate_palette_code( @@ -63,21 +64,33 @@ pub(crate) fn generate_code( ) }; + let remap_index = dedup_data + .iter() + .enumerate() + .map(|(i, data)| (data.new_index, i)) + .collect::>(); // BTreeMap so that values below is in order + + let remap_index = remap_index.values().cloned().collect::>(); + let (tile_data, assignments) = if let Some(assignment_offset) = assignment_offset { let mut tile_data = Vec::new(); - add_image_to_tile_data(&mut tile_data, &image, results, assignment_offset, false); + add_image_to_tile_data( + &mut tile_data, + &image, + results, + assignment_offset, + false, + &remap_index, + ); let tile_data = collapse_to_4bpp(&tile_data); let num_tiles = image.width * image.height / 8usize.pow(2); - let assignments = results - .assignments - .iter() - .skip(assignment_offset) - .take(num_tiles) - .map(|&x| x as u8) + let all_assignments = &results.assignments[assignment_offset..]; + let assignments = (0..num_tiles) + .map(|tile_id| all_assignments[remap_index[tile_id]] as u8) .collect(); (tile_data, assignments) From b39f99990c9318f757f62aa1929bc41a47d8e271 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 14:52:20 +0100 Subject: [PATCH 06/20] Use deduplication in hyperspace roll --- agb-image-converter/src/deduplicator.rs | 152 +++++++++++++++++++++ examples/hyperspace-roll/src/background.rs | 42 ++---- 2 files changed, 166 insertions(+), 28 deletions(-) create mode 100644 agb-image-converter/src/deduplicator.rs diff --git a/agb-image-converter/src/deduplicator.rs b/agb-image-converter/src/deduplicator.rs new file mode 100644 index 00000000..cb20608b --- /dev/null +++ b/agb-image-converter/src/deduplicator.rs @@ -0,0 +1,152 @@ +use std::{collections::HashMap, hash::BuildHasher}; + +use crate::{colour::Colour, image_loader::Image}; + +pub struct Transformation { + pub vflip: bool, + pub hflip: bool, +} + +impl Transformation { + pub fn none() -> Self { + Self { + vflip: false, + hflip: false, + } + } + + pub fn vflipped() -> Self { + Self { + vflip: true, + hflip: false, + } + } + + pub fn hflipped() -> Self { + Self { + vflip: false, + hflip: true, + } + } + + pub fn vhflipped() -> Self { + Self { + vflip: true, + hflip: true, + } + } +} + +pub struct DeduplicatedData { + pub new_index: usize, + pub transformation: Transformation, +} + +#[derive(Clone, PartialEq, Eq, Hash)] +struct Tile { + data: [Colour; 64], +} + +impl Tile { + fn split_image(input: &Image) -> Vec { + let mut ret = vec![]; + + for y in 0..(input.height / 8) { + for x in 0..(input.width / 8) { + let mut tile_data = Vec::with_capacity(64); + + for j in 0..8 { + for i in 0..8 { + tile_data.push(input.colour(x * 8 + i, y * 8 + j)); + } + } + + ret.push(Tile { + data: tile_data.try_into().unwrap(), + }); + } + } + + ret + } + + fn vflipped(&self) -> Self { + let mut new_data = self.data; + for y in 0..8 { + for x in 0..8 { + new_data.swap(y * 8 + x, (7 - y) * 8 + x); + } + } + + Self { data: new_data } + } + + fn hflipped(&self) -> Self { + let mut new_data = self.data; + + for y in 0..8 { + for x in 0..8 { + new_data.swap(y * 8 + x, y * 8 + (7 - x)); + } + } + + Self { data: new_data } + } +} + +pub(crate) fn deduplicate_image(input: &Image, can_flip: bool) -> (Image, Vec) { + let mut resulting_tiles = vec![]; + let mut deduplication_data = vec![]; + + let all_tiles = Tile::split_image(input); + let mut existing_tiles = HashMap::new(); + + let hasher = std::collections::hash_map::RandomState::new(); + + for tile in all_tiles { + let (tile, transformation) = if can_flip { + let vflipped = tile.vflipped(); + let hflipped = tile.hflipped(); + let vhflipped = vflipped.hflipped(); + + // find the one with the smallest hash + let tile_hash = hasher.hash_one(&tile); + let vflipped_hash = hasher.hash_one(&vflipped); + let hflipped_hash = hasher.hash_one(&hflipped); + let vhflipped_hash = hasher.hash_one(&vhflipped); + + let minimum = tile_hash + .min(vflipped_hash) + .min(hflipped_hash) + .min(vhflipped_hash); + + if minimum == tile_hash { + (tile, Transformation::none()) + } else if minimum == vflipped_hash { + (vflipped, Transformation::vflipped()) + } else if minimum == hflipped_hash { + (hflipped, Transformation::hflipped()) + } else { + (vhflipped, Transformation::vhflipped()) + } + } else { + (tile, Transformation::none()) + }; + + let index = *existing_tiles.entry(tile.clone()).or_insert_with(|| { + resulting_tiles.push(tile); + resulting_tiles.len() - 1 + }); + + deduplication_data.push(DeduplicatedData { + new_index: index, + transformation, + }); + } + + let image_data = resulting_tiles + .iter() + .flat_map(|tile| tile.data) + .collect::>(); + (Image::from_colour_data(image_data), deduplication_data) +} diff --git a/examples/hyperspace-roll/src/background.rs b/examples/hyperspace-roll/src/background.rs index 61035ce1..fa0ea199 100644 --- a/examples/hyperspace-roll/src/background.rs +++ b/examples/hyperspace-roll/src/background.rs @@ -6,11 +6,11 @@ use agb::{ use crate::sfx::Sfx; include_background_gfx!(backgrounds, "121105", - stars => "gfx/stars.aseprite", - title => "gfx/title-screen.aseprite", - help => "gfx/help-text.aseprite", - descriptions1 => "gfx/descriptions1.png", - descriptions2 => "gfx/descriptions2.png", + stars => deduplicate "gfx/stars.aseprite", + title => deduplicate "gfx/title-screen.aseprite", + help => deduplicate "gfx/help-text.aseprite", + descriptions1 => deduplicate "gfx/descriptions1.png", + descriptions2 => deduplicate "gfx/descriptions2.png", ); pub fn load_palettes(vram: &mut VRamManager) { @@ -35,12 +35,7 @@ pub(crate) fn load_help_text( 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], - ), + backgrounds::help.tile_settings[tile_id as usize], ) } } @@ -50,13 +45,13 @@ pub(crate) fn load_description( descriptions_map: &mut RegularMap, vram: &mut VRamManager, ) { - let (tileset, palette_assignments) = if face_id < 10 { + let (tileset, tile_settings) = if face_id < 10 { ( TileSet::new( backgrounds::descriptions1.tiles, agb::display::tiled::TileFormat::FourBpp, ), - backgrounds::descriptions1.palette_assignments, + backgrounds::descriptions1.tile_settings, ) } else { ( @@ -64,7 +59,7 @@ pub(crate) fn load_description( backgrounds::descriptions2.tiles, agb::display::tiled::TileFormat::FourBpp, ), - backgrounds::descriptions2.palette_assignments, + backgrounds::descriptions2.tile_settings, ) }; @@ -75,7 +70,7 @@ pub(crate) fn load_description( vram, (x, y).into(), &tileset, - TileSetting::new(tile_id, false, false, palette_assignments[tile_id as usize]), + tile_settings[tile_id as usize], ) } } @@ -87,16 +82,12 @@ fn create_background_map(map: &mut RegularMap, vram: &mut VRamManager, stars_til for y in 0..32u16 { let blank = rng::gen().rem_euclid(32) < 30; - let (tile_id, palette_id) = if blank { - ((1 << 10) - 1, 0) + let tile_setting = if blank { + TileSetting::new((1 << 10) - 1, false, false, 0) } else { let tile_id = rng::gen().rem_euclid(64) as u16; - ( - tile_id, - backgrounds::stars.palette_assignments[tile_id as usize], - ) + backgrounds::stars.tile_settings[tile_id as usize] }; - let tile_setting = TileSetting::new(tile_id, false, false, palette_id); map.set_tile(vram, (x, y).into(), stars_tileset, tile_setting); } @@ -121,12 +112,7 @@ pub fn show_title_screen(background: &mut RegularMap, vram: &mut VRamManager, sf vram, (x, y).into(), &tile_set, - TileSetting::new( - tile_id, - false, - false, - backgrounds::title.palette_assignments[tile_id as usize], - ), + backgrounds::title.tile_settings[tile_id as usize], ); } From 201a1276732f4e87e61ad1a53fd2d5aa6350a06f Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 14:55:23 +0100 Subject: [PATCH 07/20] Use deduplicated tiles for hatwiz splash screens --- .../src/splash_screen.rs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/examples/the-hat-chooses-the-wizard/src/splash_screen.rs b/examples/the-hat-chooses-the-wizard/src/splash_screen.rs index fb90190f..2c13a1ac 100644 --- a/examples/the-hat-chooses-the-wizard/src/splash_screen.rs +++ b/examples/the-hat-chooses-the-wizard/src/splash_screen.rs @@ -1,9 +1,9 @@ use super::sfx::SfxPlayer; -use agb::display::tiled::{RegularMap, TileFormat, TileSet, TileSetting, TiledMap, VRamManager}; +use agb::display::tiled::{RegularMap, TileFormat, TileSet, TiledMap, VRamManager}; agb::include_background_gfx!(splash_screens, - splash => "gfx/splash.png", - thanks_for_playing => "gfx/thanks_for_playing.png", + splash => deduplicate "gfx/splash.png", + thanks_for_playing => deduplicate "gfx/thanks_for_playing.png", ); pub enum SplashScreen { @@ -18,12 +18,18 @@ pub fn show_splash_screen( vram: &mut VRamManager, ) { map.set_scroll_pos((0i16, 0i16).into()); - let tileset = match which { - SplashScreen::Start => TileSet::new(splash_screens::splash.tiles, TileFormat::FourBpp), + let (tileset, settings) = match which { + SplashScreen::Start => ( + TileSet::new(splash_screens::splash.tiles, TileFormat::FourBpp), + splash_screens::splash.tile_settings, + ), - SplashScreen::End => TileSet::new( - splash_screens::thanks_for_playing.tiles, - TileFormat::FourBpp, + SplashScreen::End => ( + TileSet::new( + splash_screens::thanks_for_playing.tiles, + TileFormat::FourBpp, + ), + splash_screens::thanks_for_playing.tile_settings, ), }; @@ -40,7 +46,7 @@ pub fn show_splash_screen( vram, (x, y).into(), &tileset, - TileSetting::from_raw(y * 30 + x), + settings[(y * 30 + x) as usize], ); } From a73e817f0215c5b6db0717269862fc85ceb82888 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 15:05:57 +0100 Subject: [PATCH 08/20] Deduplicate everything in hatwiz --- agb-image-converter/src/deduplicator.rs | 4 +-- .../src/level_display.rs | 15 +++++----- .../the-hat-chooses-the-wizard/src/lib.rs | 29 +++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/agb-image-converter/src/deduplicator.rs b/agb-image-converter/src/deduplicator.rs index cb20608b..92498b6d 100644 --- a/agb-image-converter/src/deduplicator.rs +++ b/agb-image-converter/src/deduplicator.rs @@ -72,7 +72,7 @@ impl Tile { fn vflipped(&self) -> Self { let mut new_data = self.data; - for y in 0..8 { + for y in 0..4 { for x in 0..8 { new_data.swap(y * 8 + x, (7 - y) * 8 + x); } @@ -85,7 +85,7 @@ impl Tile { let mut new_data = self.data; for y in 0..8 { - for x in 0..8 { + for x in 0..4 { new_data.swap(y * 8 + x, y * 8 + (7 - x)); } } diff --git a/examples/the-hat-chooses-the-wizard/src/level_display.rs b/examples/the-hat-chooses-the-wizard/src/level_display.rs index 3e87f58b..268d31af 100644 --- a/examples/the-hat-chooses-the-wizard/src/level_display.rs +++ b/examples/the-hat-chooses-the-wizard/src/level_display.rs @@ -3,10 +3,10 @@ use agb::display::{ HEIGHT, WIDTH, }; -const LEVEL_START: u16 = 12 * 28; -const NUMBERS_START: u16 = 12 * 28 + 3; -const HYPHEN: u16 = 12 * 28 + 11; -pub const BLANK: u16 = 11 * 28; +const LEVEL_START: usize = 12 * 28; +const NUMBERS_START: usize = 12 * 28 + 3; +const HYPHEN: usize = 12 * 28 + 11; +pub const BLANK: usize = 11 * 28; pub fn write_level( map: &mut RegularMap, @@ -14,15 +14,16 @@ pub fn write_level( level: u32, tileset: &'_ TileSet<'_>, vram: &mut VRamManager, + tile_settings: &[TileSetting], ) { for (i, &tile) in [ LEVEL_START, LEVEL_START + 1, LEVEL_START + 2, BLANK, - world as u16 + NUMBERS_START - 1, + world as usize + NUMBERS_START - 1, HYPHEN, - level as u16 + NUMBERS_START - 1, + level as usize + NUMBERS_START - 1, ] .iter() .enumerate() @@ -31,7 +32,7 @@ pub fn write_level( vram, (i as u16, 0).into(), tileset, - TileSetting::from_raw(tile), + tile_settings[tile as usize], ); } diff --git a/examples/the-hat-chooses-the-wizard/src/lib.rs b/examples/the-hat-chooses-the-wizard/src/lib.rs index 5a03e89c..7dd67e99 100644 --- a/examples/the-hat-chooses-the-wizard/src/lib.rs +++ b/examples/the-hat-chooses-the-wizard/src/lib.rs @@ -11,7 +11,7 @@ use agb::{ object::{Graphics, OamManaged, Object, Tag, TagMap}, tiled::{ InfiniteScrolledMap, PartialUpdateStatus, RegularBackgroundSize, TileFormat, TileSet, - TileSetting, TiledMap, VRamManager, + TiledMap, VRamManager, }, Priority, HEIGHT, WIDTH, }, @@ -101,7 +101,7 @@ mod map_tiles { } } -agb::include_background_gfx!(tile_sheet, "2ce8f4", background => "gfx/tile_sheet.png"); +agb::include_background_gfx!(tile_sheet, "2ce8f4", background => deduplicate "gfx/tile_sheet.png"); const GRAPHICS: &Graphics = agb::include_aseprite!("gfx/sprites.aseprite"); const TAG_MAP: &TagMap = GRAPHICS.tags(); @@ -801,7 +801,7 @@ pub fn main(mut agb: agb::Gba) -> ! { &mut vram, (x, y).into(), &tileset, - TileSetting::from_raw(level_display::BLANK), + tile_sheet::background.tile_settings[level_display::BLANK], ); } } @@ -846,6 +846,7 @@ pub fn main(mut agb: agb::Gba) -> ! { current_level % 8 + 1, &tileset, &mut vram, + tile_sheet::background.tile_settings, ); world_display.commit(&mut vram); @@ -865,12 +866,11 @@ pub fn main(mut agb: agb::Gba) -> ! { let level = &map_tiles::LEVELS[map_current_level as usize]; ( &tileset, - TileSetting::from_raw( - *level - .background - .get((pos.y * level.dimensions.x as i32 + pos.x) as usize) - .unwrap_or(&0), - ), + tile_sheet::background.tile_settings[*level + .background + .get((pos.y * level.dimensions.x as i32 + pos.x) as usize) + .unwrap_or(&0) + as usize], ) }), ); @@ -884,12 +884,11 @@ pub fn main(mut agb: agb::Gba) -> ! { let level = &map_tiles::LEVELS[map_current_level as usize]; ( &tileset, - TileSetting::from_raw( - *level - .foreground - .get((pos.y * level.dimensions.x as i32 + pos.x) as usize) - .unwrap_or(&0), - ), + tile_sheet::background.tile_settings[*level + .foreground + .get((pos.y * level.dimensions.x as i32 + pos.x) as usize) + .unwrap_or(&0) + as usize], ) }), ); From c9bf56755ac35494c6d2279e4b6b7ddd4bb40025 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 15:17:50 +0100 Subject: [PATCH 09/20] Also deduplicate for the dungeon puzzler --- agb/src/display/tiled/mod.rs | 12 +++++++++++ examples/the-dungeon-puzzlers-lament/build.rs | 13 +++++------- .../src/backgrounds.rs | 20 +++++++++---------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/agb/src/display/tiled/mod.rs b/agb/src/display/tiled/mod.rs index 7248e380..8120c763 100644 --- a/agb/src/display/tiled/mod.rs +++ b/agb/src/display/tiled/mod.rs @@ -165,6 +165,8 @@ impl Tile { pub struct TileSetting(u16); impl TileSetting { + pub const BLANK: Self = TileSetting::new(1023, false, false, 0); + #[must_use] pub const fn new(tile_id: u16, hflip: bool, vflip: bool, palette_id: u8) -> Self { Self( @@ -180,6 +182,16 @@ impl TileSetting { Self(raw) } + #[must_use] + pub const fn hflip(self, should_flip: bool) -> Self { + Self(self.0 ^ ((should_flip as u16) << 10)) + } + + #[must_use] + pub const fn vflip(self, should_flip: bool) -> Self { + Self(self.0 ^ ((should_flip as u16) << 11)) + } + fn index(self) -> u16 { self.0 & ((1 << 10) - 1) } diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 7e4a297a..62b68f75 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -331,12 +331,10 @@ fn export_tiles(map: &tiled::Map, background: TokenStream) -> TokenStream { tile_tileset_x * 2 + x_offset + tile_tileset_y * 9 * 4 + y_offset * 9 * 2; let gba_tile_id = gba_tile_id as u16; - let palette_id = - quote! { backgrounds::#background.palette_assignments[#gba_tile_id as usize] }; - quote! { TileSetting::new(#gba_tile_id, #hflip, #vflip, #palette_id) } + quote! { backgrounds::#background.tile_settings[#gba_tile_id as usize].hflip(#hflip).vflip(#vflip) } } None => { - quote! { TileSetting::new(1023, false, false, 0) } + quote! { TileSetting::BLANK } } } }); @@ -361,12 +359,11 @@ fn export_ui_tiles(map: &tiled::Map, background: TokenStream) -> TokenStream { let tile_id = tile.id() as u16; let vflip = tile.flip_v; let hflip = tile.flip_h; - let palette_id = - quote! { backgrounds::#background.palette_assignments[#tile_id as usize] }; - quote! { TileSetting::new(#tile_id, #hflip, #vflip, #palette_id) } + + quote! { backgrounds::#background.tile_settings[#tile_id as usize].hflip(#hflip).vflip(#vflip) } } None => { - quote! { TileSetting::new(1023, false, false, 0) } + quote! { TileSetting::BLANK } } } }); diff --git a/examples/the-dungeon-puzzlers-lament/src/backgrounds.rs b/examples/the-dungeon-puzzlers-lament/src/backgrounds.rs index d2ac283c..9d31a94e 100644 --- a/examples/the-dungeon-puzzlers-lament/src/backgrounds.rs +++ b/examples/the-dungeon-puzzlers-lament/src/backgrounds.rs @@ -1,12 +1,12 @@ use agb::{ - display::tiled::{RegularMap, TileFormat, TileSet, TileSetting, VRamManager}, + display::tiled::{RegularMap, TileFormat, TileSet, VRamManager}, include_background_gfx, }; include_background_gfx!(backgrounds, "1e151b", - ui => "maps/ui_tiles.png", - level => "maps/level.png", - ending => "gfx/ending_page.aseprite", + ui => deduplicate "maps/ui_tiles.png", + level => deduplicate "maps/level.png", + ending => deduplicate "gfx/ending_page.aseprite", ); mod tilemaps { @@ -56,13 +56,13 @@ pub fn load_ending_page(map: &mut RegularMap, vram_manager: &mut VRamManager) { for y in 0..20u16 { for x in 0..30u16 { let tile_pos = y * 30 + x; - let tile_setting = TileSetting::new( - tile_pos, - false, - false, - backgrounds::ending.palette_assignments[tile_pos as usize], + + map.set_tile( + vram_manager, + (x, y).into(), + &ending_tileset, + backgrounds::ending.tile_settings[tile_pos as usize], ); - map.set_tile(vram_manager, (x, y).into(), &ending_tileset, tile_setting); } } } From c25cd74f4305379289fed65f65a2c6a18192aba7 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 15:20:41 +0100 Subject: [PATCH 10/20] Correctly use deduplication for combo rom --- examples/combo/src/lib.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/examples/combo/src/lib.rs b/examples/combo/src/lib.rs index 69f495ae..faaaa6f2 100644 --- a/examples/combo/src/lib.rs +++ b/examples/combo/src/lib.rs @@ -8,7 +8,7 @@ use alloc::boxed::Box; use agb::{ display::{ - tiled::{InfiniteScrolledMap, RegularBackgroundSize, TileFormat, TileSet, TileSetting}, + tiled::{InfiniteScrolledMap, RegularBackgroundSize, TileFormat, TileSet}, Priority, }, fixnum::{Num, Vector2D}, @@ -66,11 +66,11 @@ fn get_game(gba: &mut agb::Gba) -> Game { let tiles = [hat, purple, hyperspace, amplitude]; - let palette_assignments = &[ - games::hat.palette_assignments, - games::purple.palette_assignments, - games::hyperspace.palette_assignments, - games::amplitude.palette_assignments, + let tile_settings = &[ + games::hat.tile_settings, + games::purple.tile_settings, + games::hyperspace.tile_settings, + games::amplitude.tile_settings, ]; vram.set_background_palettes(games::PALETTES); @@ -87,15 +87,7 @@ fn get_game(gba: &mut agb::Gba) -> Game { let game = (pos.x).rem_euclid(tiles.len() as i32 * 30) as usize / 30; let tile_id = (y * 30 + x) as usize; - ( - &tiles[game], - TileSetting::new( - tile_id as u16, - false, - false, - palette_assignments[game][tile_id], - ), - ) + (&tiles[game], tile_settings[game][tile_id]) }), ); From 9db4230aeedfbeec1aaf1827ab6becb79d1db886 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 15:34:07 +0100 Subject: [PATCH 11/20] Better error if we run out of VRam --- 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 c9220f73..bb5bb200 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -302,7 +302,7 @@ impl VRamManager { let new_reference: NonNull = unsafe { TILE_ALLOCATOR.alloc(layout_of(tile_set.format)) } - .unwrap() + .expect("Ran out of video RAM for tiles") .cast(); let tile_reference = TileReference(new_reference); reference.or_insert(tile_reference); From a865240308ba8a6886fc40487746f3fa82d9e983 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:07:50 +0100 Subject: [PATCH 12/20] Start fixing 256 colours --- agb/src/display/tiled/map.rs | 33 ++++++++++++++------------- agb/src/display/tiled/mod.rs | 4 ++-- agb/src/display/tiled/vram_manager.rs | 19 +++------------ examples/combo/src/lib.rs | 18 +++++++-------- 4 files changed, 31 insertions(+), 43 deletions(-) diff --git a/agb/src/display/tiled/map.rs b/agb/src/display/tiled/map.rs index ea1cdac4..5023a3e9 100644 --- a/agb/src/display/tiled/map.rs +++ b/agb/src/display/tiled/map.rs @@ -10,7 +10,7 @@ use crate::memory_mapped::MemoryMapped; use super::{ AffineBackgroundSize, BackgroundID, BackgroundSize, BackgroundSizePrivate, - RegularBackgroundSize, Tile, TileFormat, TileIndex, TileSet, TileSetting, VRamManager, + RegularBackgroundSize, Tile, TileFormat, TileSet, TileSetting, VRamManager, }; use alloc::{vec, vec::Vec}; @@ -20,10 +20,9 @@ pub trait TiledMapTypes: private::Sealed { } trait TiledMapPrivate: TiledMapTypes { - type TileType: Into + Copy + Default + Eq + PartialEq; type AffineMatrix; - fn tiles_mut(&mut self) -> &mut [Self::TileType]; + fn tiles_mut(&mut self) -> &mut [Tile]; fn tiles_dirty(&mut self) -> &mut bool; fn colours(&self) -> TileFormat; @@ -59,9 +58,11 @@ where T::Size: BackgroundSizePrivate, { fn clear(&mut self, vram: &mut VRamManager) { + let colours = self.colours(); + for tile in self.tiles_mut() { if *tile != Default::default() { - vram.remove_tile((*tile).into()); + vram.remove_tile(tile.tile_index(colours)); } *tile = Default::default(); @@ -134,10 +135,9 @@ impl TiledMapTypes for RegularMap { } impl TiledMapPrivate for RegularMap { - type TileType = Tile; type AffineMatrix = (); - fn tiles_mut(&mut self) -> &mut [Self::TileType] { + fn tiles_mut(&mut self) -> &mut [Tile] { &mut self.tiles } fn tiles_dirty(&mut self) -> &mut bool { @@ -195,11 +195,12 @@ impl RegularMap { tileset: &TileSet<'_>, tile_setting: TileSetting, ) { - if tileset.format() != self.colours() { + let colours = self.colours(); + if tileset.format() != colours { panic!( "Cannot set a {:?} colour tile on a {:?} colour background", tileset.format(), - self.colours() + colours ); } @@ -207,7 +208,7 @@ impl RegularMap { let old_tile = self.tiles_mut()[pos]; if old_tile != Tile::default() { - vram.remove_tile(old_tile.into()); + vram.remove_tile(old_tile.tile_index(colours)); } let tile_index = tile_setting.index(); @@ -254,7 +255,7 @@ pub struct AffineMap { transform: AffineMatrixBackground, - tiles: Vec, + tiles: Vec, tiles_dirty: bool, } @@ -263,10 +264,9 @@ impl TiledMapTypes for AffineMap { } impl TiledMapPrivate for AffineMap { - type TileType = u8; type AffineMatrix = AffineMatrixBackground; - fn tiles_mut(&mut self) -> &mut [Self::TileType] { + fn tiles_mut(&mut self) -> &mut [Tile] { &mut self.tiles } fn tiles_dirty(&mut self) -> &mut bool { @@ -320,19 +320,20 @@ impl AffineMap { tile_id: u8, ) { let pos = self.map_size().gba_offset(pos); + let colours = self.colours(); let old_tile = self.tiles_mut()[pos]; - if old_tile != 0 { - vram.remove_tile(old_tile.into()); + if old_tile != Tile::default() { + vram.remove_tile(old_tile.tile_index(colours)); } let tile_index = tile_id as u16; let new_tile = if tile_index != TRANSPARENT_TILE_INDEX { let new_tile_idx = vram.add_tile(tileset, tile_index); - new_tile_idx.raw_index() as u8 + Tile::new(new_tile_idx, TileSetting(0)) } else { - 0 + Tile::default() }; if old_tile == new_tile { diff --git a/agb/src/display/tiled/mod.rs b/agb/src/display/tiled/mod.rs index 8120c763..7c289a3f 100644 --- a/agb/src/display/tiled/mod.rs +++ b/agb/src/display/tiled/mod.rs @@ -156,8 +156,8 @@ impl Tile { Self(idx.raw_index() | setting.setting()) } - fn tile_index(self) -> TileIndex { - TileIndex::new(self.0 as usize & ((1 << 10) - 1), TileFormat::FourBpp) + fn tile_index(self, format: TileFormat) -> TileIndex { + TileIndex::new(self.0 as usize & ((1 << 10) - 1), format) } } diff --git a/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index bb5bb200..d98c968d 100644 --- a/agb/src/display/tiled/vram_manager.rs +++ b/agb/src/display/tiled/vram_manager.rs @@ -2,7 +2,6 @@ use core::{alloc::Layout, ptr::NonNull}; use alloc::{slice, vec::Vec}; -use crate::display::tiled::Tile; use crate::{ agb_alloc::{block_allocator::BlockAllocator, bump_allocator::StartEnd}, display::palette16, @@ -66,21 +65,21 @@ impl<'a> TileSet<'a> { #[derive(Debug, Clone, Copy)] pub enum TileIndex { FourBpp(u16), - EightBpp(u8), + EightBpp(u16), } impl TileIndex { pub(crate) const fn new(index: usize, format: TileFormat) -> Self { match format { TileFormat::FourBpp => Self::FourBpp(index as u16), - TileFormat::EightBpp => Self::EightBpp(index as u8), + TileFormat::EightBpp => Self::EightBpp(index as u16), } } pub(crate) const fn raw_index(self) -> u16 { match self { TileIndex::FourBpp(x) => x, - TileIndex::EightBpp(x) => x as u16, + TileIndex::EightBpp(x) => x, } } @@ -99,18 +98,6 @@ impl TileIndex { } } -impl From for TileIndex { - fn from(tile: Tile) -> Self { - tile.tile_index() - } -} - -impl From for TileIndex { - fn from(index: u8) -> TileIndex { - TileIndex::new(usize::from(index), TileFormat::EightBpp) - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct TileReference(NonNull); diff --git a/examples/combo/src/lib.rs b/examples/combo/src/lib.rs index faaaa6f2..213f9301 100644 --- a/examples/combo/src/lib.rs +++ b/examples/combo/src/lib.rs @@ -47,10 +47,10 @@ impl Game { include_background_gfx!( games, "121105", - hat => deduplicate "gfx/hat.png", - purple => deduplicate "gfx/purple.png", - hyperspace => deduplicate "gfx/hyperspace.png", - amplitude => deduplicate "gfx/amplitude.png" + hat => 256 deduplicate "gfx/hat.png", + purple => 256 deduplicate "gfx/purple.png", + hyperspace => 256 deduplicate "gfx/hyperspace.png", + amplitude => 256 deduplicate "gfx/amplitude.png" ); fn get_game(gba: &mut agb::Gba) -> Game { @@ -59,10 +59,10 @@ fn get_game(gba: &mut agb::Gba) -> Game { let (tile, mut vram) = gba.display.video.tiled0(); - let hat = TileSet::new(games::hat.tiles, TileFormat::FourBpp); - let purple = TileSet::new(games::purple.tiles, TileFormat::FourBpp); - let hyperspace = TileSet::new(games::hyperspace.tiles, TileFormat::FourBpp); - let amplitude = TileSet::new(games::amplitude.tiles, TileFormat::FourBpp); + let hat = TileSet::new(games::hat.tiles, TileFormat::EightBpp); + let purple = TileSet::new(games::purple.tiles, TileFormat::EightBpp); + let hyperspace = TileSet::new(games::hyperspace.tiles, TileFormat::EightBpp); + let amplitude = TileSet::new(games::amplitude.tiles, TileFormat::EightBpp); let tiles = [hat, purple, hyperspace, amplitude]; @@ -79,7 +79,7 @@ fn get_game(gba: &mut agb::Gba) -> Game { tile.background( Priority::P0, RegularBackgroundSize::Background32x32, - TileFormat::FourBpp, + TileFormat::EightBpp, ), Box::new(|pos| { let y = pos.y.rem_euclid(20); From b5991d3ccc7a48ed19c9b828916dc85cdba258ec Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:14:05 +0100 Subject: [PATCH 13/20] Copy all the tiles for a 256 colour map --- agb/src/display/tiled/map.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/agb/src/display/tiled/map.rs b/agb/src/display/tiled/map.rs index 5023a3e9..367f111b 100644 --- a/agb/src/display/tiled/map.rs +++ b/agb/src/display/tiled/map.rs @@ -83,18 +83,18 @@ where fn commit(&mut self, vram: &mut VRamManager) { let screenblock_memory = self.screenblock_memory(); - let tile_count_divisor = self.colours().tile_size() / TileFormat::FourBpp.tile_size(); + if *self.tiles_dirty() { unsafe { dma_copy16( self.tiles_mut().as_ptr() as *const u16, screenblock_memory, - self.map_size().num_tiles() / tile_count_divisor, + self.map_size().num_tiles(), ); } } - let tile_colour_flag: u16 = (tile_count_divisor == 2).into(); + let tile_colour_flag: u16 = (self.colours() == TileFormat::EightBpp).into(); let new_bg_control_value = (self.priority() as u16) | ((self.screenblock() as u16) << 8) From 3eb7aabe374a91eb4e2c1c659185b49d41cc9e04 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:17:14 +0100 Subject: [PATCH 14/20] Add dungeon puzzler to combo --- examples/combo/Cargo.lock | 304 ++++++++++++++++++++++++- examples/combo/Cargo.toml | 1 + examples/combo/gfx/dungeon_puzzler.png | Bin 0 -> 8022 bytes examples/combo/src/lib.rs | 12 +- 4 files changed, 305 insertions(+), 12 deletions(-) create mode 100644 examples/combo/gfx/dungeon_puzzler.png diff --git a/examples/combo/Cargo.lock b/examples/combo/Cargo.lock index b1a7c38f..3898d9ee 100644 --- a/examples/combo/Cargo.lock +++ b/examples/combo/Cargo.lock @@ -52,7 +52,7 @@ dependencies = [ "image", "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -61,7 +61,7 @@ version = "0.16.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -71,7 +71,47 @@ dependencies = [ "hound", "proc-macro2", "quote", - "syn", + "syn 2.0.28", +] + +[[package]] +name = "agb_tracker" +version = "0.16.0" +dependencies = [ + "agb", + "agb_tracker_interop", + "agb_xm", +] + +[[package]] +name = "agb_tracker_interop" +version = "0.16.0" +dependencies = [ + "agb_fixnum", + "proc-macro2", + "quote", +] + +[[package]] +name = "agb_xm" +version = "0.16.0" +dependencies = [ + "agb_xm_core", + "proc-macro-error", + "proc-macro2", +] + +[[package]] +name = "agb_xm_core" +version = "0.16.0" +dependencies = [ + "agb_fixnum", + "agb_tracker_interop", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.28", + "xmrs", ] [[package]] @@ -133,6 +173,12 @@ dependencies = [ "byteorder", ] +[[package]] +name = "base64" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" + [[package]] name = "bilge" version = "0.2.0" @@ -153,7 +199,16 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.28", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", ] [[package]] @@ -199,6 +254,7 @@ dependencies = [ "agb", "amplitude", "hyperspace-roll", + "the-dungeon-puzzlers-lament", "the-hat-chooses-the-wizard", "the-purple-night", ] @@ -228,6 +284,12 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "flate2" version = "1.0.26" @@ -244,7 +306,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0793f5137567643cf65ea42043a538804ff0fbf288649e2141442b602d81f9bc" dependencies = [ - "hashbrown", + "hashbrown 0.13.2", "ttf-parser", ] @@ -257,6 +319,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -266,6 +339,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "hound" version = "3.5.0" @@ -294,6 +373,16 @@ dependencies = [ "png", ] +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", +] + [[package]] name = "itertools" version = "0.11.0" @@ -309,6 +398,12 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + [[package]] name = "libflate" version = "0.1.27" @@ -321,12 +416,38 @@ dependencies = [ "take_mut", ] +[[package]] +name = "libflate" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ff4ae71b685bbad2f2f391fe74f6b7659a34871c08b210fdc039e43bee07d18" +dependencies = [ + "adler32", + "crc32fast", + "libflate_lz77", +] + +[[package]] +name = "libflate_lz77" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a52d3a8bfc85f250440e4424db7d857e241a3aebbbe301f3eb606ab15c39acbf" +dependencies = [ + "rle-decode-fast", +] + [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "memchr" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f478948fd84d9f8e86967bf432640e46adfb5a4bd4f14ef7e864ab38220534ae" + [[package]] name = "miniz_oxide" version = "0.3.7" @@ -392,6 +513,27 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.28", +] + [[package]] name = "once_cell" version = "1.18.0" @@ -410,6 +552,22 @@ dependencies = [ "miniz_oxide 0.3.7", ] +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -419,6 +577,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", + "syn 1.0.109", "version_check", ] @@ -451,6 +610,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -478,6 +667,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.183" @@ -486,7 +684,7 @@ checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.28", ] [[package]] @@ -500,6 +698,25 @@ dependencies = [ "serde", ] +[[package]] +name = "slotmap" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342" +dependencies = [ + "version_check", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.28" @@ -517,6 +734,18 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" +[[package]] +name = "the-dungeon-puzzlers-lament" +version = "0.1.0" +dependencies = [ + "agb", + "agb_tracker", + "proc-macro2", + "quote", + "slotmap", + "tiled 0.11.1", +] + [[package]] name = "the-hat-chooses-the-wizard" version = "0.1.0" @@ -533,7 +762,7 @@ dependencies = [ "agb", "generational-arena", "quote", - "tiled", + "tiled 0.9.4", ] [[package]] @@ -542,11 +771,39 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d2c30aeea9d8159cb461a17dba23ad28980a2a9c217a6784a14e931e4979d6f" dependencies = [ - "base64", - "libflate", + "base64 0.10.1", + "libflate 0.1.27", "xml-rs", ] +[[package]] +name = "tiled" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "181e2402be287d74e951a8e81c8798d0737cc94b1a089237bb3b838be76c6b5b" +dependencies = [ + "base64 0.21.3", + "libflate 1.4.0", + "xml-rs", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + [[package]] name = "ttf-parser" version = "0.15.2" @@ -565,8 +822,37 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winnow" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +dependencies = [ + "memchr", +] + [[package]] name = "xml-rs" version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47430998a7b5d499ccee752b41567bc3afc57e1327dc855b1a2aa44ce29b5fa1" + +[[package]] +name = "xmrs" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fa1ec7c01e6bb4c716f84a418f4ced5f4a735b2ae6364f4bb5850da61321d16" +dependencies = [ + "bincode", + "libflate 1.4.0", + "num_enum", + "rand", + "serde", + "serde-big-array", +] diff --git a/examples/combo/Cargo.toml b/examples/combo/Cargo.toml index d21d703b..4027ef61 100644 --- a/examples/combo/Cargo.toml +++ b/examples/combo/Cargo.toml @@ -11,6 +11,7 @@ the-purple-night = { path = "../the-purple-night" } the-hat-chooses-the-wizard = { path = "../the-hat-chooses-the-wizard" } hyperspace-roll = { path = "../hyperspace-roll" } amplitude = { path = "../amplitude" } +the-dungeon-puzzlers-lament = { path = "../the-dungeon-puzzlers-lament" } [profile.dev] opt-level = 3 diff --git a/examples/combo/gfx/dungeon_puzzler.png b/examples/combo/gfx/dungeon_puzzler.png new file mode 100644 index 0000000000000000000000000000000000000000..7f820ac4e1bc4c0e890337727c804c241d7868a8 GIT binary patch literal 8022 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 YKmYKbp=f the_hat_chooses_the_wizard::main(gba), Game::ThePurpleNight => the_purple_night::main(gba), Game::HyperspaceRoll => hyperspace_roll::main(gba), + Game::TheDungeonPuzzlersLament => the_dungeon_puzzlers_lament::entry(gba), Game::Amplitude => amplitude::main(gba), } } @@ -39,7 +41,8 @@ impl Game { 0 => Game::TheHatChoosesTheWizard, 1 => Game::ThePurpleNight, 2 => Game::HyperspaceRoll, - 3 => Game::Amplitude, + 3 => Game::TheDungeonPuzzlersLament, + 4 => Game::Amplitude, _ => unreachable!("game out of index in an unreachable manner"), } } @@ -50,7 +53,8 @@ include_background_gfx!( hat => 256 deduplicate "gfx/hat.png", purple => 256 deduplicate "gfx/purple.png", hyperspace => 256 deduplicate "gfx/hyperspace.png", - amplitude => 256 deduplicate "gfx/amplitude.png" + dungeon_puzzler => 256 deduplicate "gfx/dungeon_puzzler.png", + amplitude => 256 deduplicate "gfx/amplitude.png", ); fn get_game(gba: &mut agb::Gba) -> Game { @@ -62,14 +66,16 @@ fn get_game(gba: &mut agb::Gba) -> Game { let hat = TileSet::new(games::hat.tiles, TileFormat::EightBpp); let purple = TileSet::new(games::purple.tiles, TileFormat::EightBpp); let hyperspace = TileSet::new(games::hyperspace.tiles, TileFormat::EightBpp); + let dungeon_puzzler = TileSet::new(games::dungeon_puzzler.tiles, TileFormat::EightBpp); let amplitude = TileSet::new(games::amplitude.tiles, TileFormat::EightBpp); - let tiles = [hat, purple, hyperspace, amplitude]; + let tiles = [hat, purple, hyperspace, dungeon_puzzler, amplitude]; let tile_settings = &[ games::hat.tile_settings, games::purple.tile_settings, games::hyperspace.tile_settings, + games::dungeon_puzzler.tile_settings, games::amplitude.tile_settings, ]; From eede8c371942aa44b96137ad4af28a9b33ac9fcd Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:19:15 +0100 Subject: [PATCH 15/20] Add changelog entries --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 224ebb0e..44821e13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,14 +12,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New tracker for playing XM files (see the `agb-tracker` crate). - You can now declare where looping sound channels should restart. - Fixnums now have constructors from_f32 and from_f64. This is mainly useful if using agb-fixnum outside of the Game Boy Advance e.g. in build scripts or macros. +- New option when loading a background to automatically deduplicate tiles. ### Changed - Sound channel panning and volume options are now `Num` rather than `Num` for improved precision and sound quality. - Due to dependency changes, agb-gbafix is now released under MPL rather than GPL. +- `include_background_gfx!` now produces tile settings directly rather than palette assigments. ### Fixed +- 256-colour backgrounds are better supported. - Mono looping samples will now correctly play to the end if it doesn't perfectly align with a buffer boundry and short samples now also loop correctly. ## [0.16.0] - 2023/07/18 From 9abfa7f8e1ca42066bb31bc93c65c459395fe926 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:20:54 +0100 Subject: [PATCH 16/20] Update documentation --- agb/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/agb/src/lib.rs b/agb/src/lib.rs index c4e57618..cd4762f6 100644 --- a/agb/src/lib.rs +++ b/agb/src/lib.rs @@ -33,7 +33,7 @@ //! //! To get started with agb, you should clone the [template repo](https://github.com/agbrs/template) and work from there. -/// This macro is used to convert a png or bmp into a format usable by the Game Boy Advance. +/// This macro is used to convert a png, bmp or aseprite file into a format usable by the Game Boy Advance. /// /// Suppose you have a file in `examples/water_tiles.png` which contains some tiles you'd like to use. /// @@ -89,7 +89,7 @@ /// &mut vram, /// (x, y).into(), /// &tileset, -/// TileSetting::new(0, false, false, 0), +/// water_tiles::tiles.tile_settings[0], /// ); /// } /// } From b25ebf4a948c01aca56d3777ae513316fe591ff4 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:21:28 +0100 Subject: [PATCH 17/20] Add a changelog entry about the new flip methods --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44821e13..8931515e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - You can now declare where looping sound channels should restart. - Fixnums now have constructors from_f32 and from_f64. This is mainly useful if using agb-fixnum outside of the Game Boy Advance e.g. in build scripts or macros. - New option when loading a background to automatically deduplicate tiles. +- Methods on tile_setting to toggle its hflip and vflip status. ### Changed From 345a27a7d946e0ac863ea4b15528cf8db2328c42 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:25:16 +0100 Subject: [PATCH 18/20] Remove useless cast --- examples/the-hat-chooses-the-wizard/src/level_display.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/the-hat-chooses-the-wizard/src/level_display.rs b/examples/the-hat-chooses-the-wizard/src/level_display.rs index 268d31af..006a8941 100644 --- a/examples/the-hat-chooses-the-wizard/src/level_display.rs +++ b/examples/the-hat-chooses-the-wizard/src/level_display.rs @@ -28,12 +28,7 @@ pub fn write_level( .iter() .enumerate() { - map.set_tile( - vram, - (i as u16, 0).into(), - tileset, - tile_settings[tile as usize], - ); + map.set_tile(vram, (i as u16, 0).into(), tileset, tile_settings[tile]); } map.set_scroll_pos((-(WIDTH / 2 - 7 * 8 / 2) as i16, -(HEIGHT / 2 - 4) as i16).into()); From 54237c0fcec1401884994dcec83b71d2f339f4f3 Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:28:57 +0100 Subject: [PATCH 19/20] Remove trailing whitespace --- examples/the-dungeon-puzzlers-lament/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 62b68f75..ae98913d 100644 --- a/examples/the-dungeon-puzzlers-lament/build.rs +++ b/examples/the-dungeon-puzzlers-lament/build.rs @@ -359,7 +359,7 @@ fn export_ui_tiles(map: &tiled::Map, background: TokenStream) -> TokenStream { let tile_id = tile.id() as u16; let vflip = tile.flip_v; let hflip = tile.flip_h; - + quote! { backgrounds::#background.tile_settings[#tile_id as usize].hflip(#hflip).vflip(#vflip) } } None => { From 6422ed63f1f0a916539300f176a5f55ab8f0cadf Mon Sep 17 00:00:00 2001 From: Gwilym Inzani Date: Tue, 29 Aug 2023 16:33:11 +0100 Subject: [PATCH 20/20] Give purple night the deduplication treatment --- examples/the-purple-night/src/lib.rs | 34 ++++++++++++---------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/examples/the-purple-night/src/lib.rs b/examples/the-purple-night/src/lib.rs index 754216df..65b75f45 100644 --- a/examples/the-purple-night/src/lib.rs +++ b/examples/the-purple-night/src/lib.rs @@ -15,10 +15,7 @@ use alloc::{boxed::Box, vec::Vec}; use agb::{ display::{ object::{Graphics, OamManaged, Object, Sprite, Tag, TagMap}, - tiled::{ - InfiniteScrolledMap, RegularBackgroundSize, TileFormat, TileSet, TileSetting, - VRamManager, - }, + tiled::{InfiniteScrolledMap, RegularBackgroundSize, TileFormat, TileSet, VRamManager}, Priority, HEIGHT, WIDTH, }, fixnum::{num, FixedNum, Rect, Vector2D}, @@ -57,7 +54,7 @@ const SWORDLESS_JUMP: &Tag = TAG_MAP.get("jump swordless"); const SWORDLESS_ATTACK: &Tag = KNIFE_ATTACK; const SWORDLESS_JUMP_ATTACK: &Tag = KNIFE_JUMP_ATTACK; -agb::include_background_gfx!(background, "53269a", background => "gfx/background.aseprite"); +agb::include_background_gfx!(background, "53269a", background => deduplicate "gfx/background.aseprite"); type Number = FixedNum<8>; @@ -2207,11 +2204,10 @@ fn game_with_level(gba: &mut agb::Gba) { Box::new(|pos| { ( &tileset, - TileSetting::from_raw( - *tilemap::BACKGROUND_MAP - .get((pos.x + tilemap::WIDTH * pos.y) as usize) - .unwrap_or(&0), - ), + background::background.tile_settings[*tilemap::BACKGROUND_MAP + .get((pos.x + tilemap::WIDTH * pos.y) as usize) + .unwrap_or(&0) + as usize], ) }), ); @@ -2225,11 +2221,10 @@ fn game_with_level(gba: &mut agb::Gba) { Box::new(|pos| { ( &tileset, - TileSetting::from_raw( - *tilemap::FOREGROUND_MAP - .get((pos.x + tilemap::WIDTH * pos.y) as usize) - .unwrap_or(&0), - ), + background::background.tile_settings[*tilemap::FOREGROUND_MAP + .get((pos.x + tilemap::WIDTH * pos.y) as usize) + .unwrap_or(&0) + as usize], ) }), ); @@ -2243,11 +2238,10 @@ fn game_with_level(gba: &mut agb::Gba) { Box::new(|pos| { ( &tileset, - TileSetting::from_raw( - *tilemap::CLOUD_MAP - .get((pos.x + tilemap::WIDTH * pos.y) as usize) - .unwrap_or(&0), - ), + background::background.tile_settings[*tilemap::CLOUD_MAP + .get((pos.x + tilemap::WIDTH * pos.y) as usize) + .unwrap_or(&0) + as usize], ) }), );