diff --git a/CHANGELOG.md b/CHANGELOG.md index 224ebb0e..8931515e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,14 +12,18 @@ 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. +- Methods on tile_setting to toggle its hflip and vflip status. ### 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 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/deduplicator.rs b/agb-image-converter/src/deduplicator.rs new file mode 100644 index 00000000..92498b6d --- /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..4 { + 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..4 { + 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/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 6e227d1d..d5fa34e4 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; @@ -36,6 +37,7 @@ struct BackgroundGfxOption { module_name: String, file_name: String, colours: Colours, + deduplicate: bool, } impl config::Image for BackgroundGfxOption { @@ -46,6 +48,10 @@ impl config::Image for BackgroundGfxOption { fn colours(&self) -> Colours { self.colours } + + fn deduplicate(&self) -> bool { + self.deduplicate + } } impl Parse for BackgroundGfxOption { @@ -72,12 +78,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, }) } } @@ -406,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, @@ -414,6 +439,7 @@ fn convert_image( &image_filename.to_string_lossy(), crate_prefix.to_owned(), assignment_offset, + deduplicate, ) } @@ -468,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); @@ -491,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; @@ -501,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 9a7de049..bd6f243c 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}; @@ -5,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( @@ -40,36 +42,77 @@ 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 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) } 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 +134,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/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 351d80ab..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, TileSetting, TiledMap, VRamManager}; +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); @@ -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, } } } diff --git a/agb/src/display/tiled/map.rs b/agb/src/display/tiled/map.rs index ea1cdac4..367f111b 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(); @@ -82,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) @@ -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 7248e380..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) } } @@ -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/agb/src/display/tiled/vram_manager.rs b/agb/src/display/tiled/vram_manager.rs index c9220f73..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); @@ -302,7 +289,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); 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], /// ); /// } /// } 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 00000000..7f820ac4 Binary files /dev/null and b/examples/combo/gfx/dungeon_puzzler.png differ diff --git a/examples/combo/src/lib.rs b/examples/combo/src/lib.rs index 67dd4263..33a63a14 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}, @@ -21,6 +21,7 @@ pub enum Game { TheHatChoosesTheWizard, ThePurpleNight, HyperspaceRoll, + TheDungeonPuzzlersLament, Amplitude, } @@ -30,6 +31,7 @@ impl Game { Game::TheHatChoosesTheWizard => 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"), } } @@ -47,10 +50,11 @@ impl Game { include_background_gfx!( games, "121105", - hat => "gfx/hat.png", - purple => "gfx/purple.png", - hyperspace => "gfx/hyperspace.png", - amplitude => "gfx/amplitude.png" + hat => 256 deduplicate "gfx/hat.png", + purple => 256 deduplicate "gfx/purple.png", + hyperspace => 256 deduplicate "gfx/hyperspace.png", + dungeon_puzzler => 256 deduplicate "gfx/dungeon_puzzler.png", + amplitude => 256 deduplicate "gfx/amplitude.png", ); fn get_game(gba: &mut agb::Gba) -> Game { @@ -59,18 +63,20 @@ 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 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 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::dungeon_puzzler.tile_settings, + games::amplitude.tile_settings, ]; vram.set_background_palettes(games::PALETTES); @@ -79,7 +85,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); @@ -87,15 +93,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]) }), ); 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], ); } diff --git a/examples/the-dungeon-puzzlers-lament/build.rs b/examples/the-dungeon-puzzlers-lament/build.rs index 7e4a297a..ae98913d 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); } } } 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..006a8941 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,25 +14,21 @@ 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() { - map.set_tile( - vram, - (i as u16, 0).into(), - tileset, - TileSetting::from_raw(tile), - ); + 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()); 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], ) }), ); 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], ); } 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], ) }), );