mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
Use deduplication in hyperspace roll
This commit is contained in:
parent
6d56e72d66
commit
b39f99990c
152
agb-image-converter/src/deduplicator.rs
Normal file
152
agb-image-converter/src/deduplicator.rs
Normal file
|
@ -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<Self> {
|
||||
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<DeduplicatedData>) {
|
||||
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::<Vec<_>>();
|
||||
(Image::from_colour_data(image_data), deduplication_data)
|
||||
}
|
|
@ -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],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue