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, } } }