1
0
Fork 0
mirror of https://github.com/italicsjenga/agb.git synced 2025-01-11 09:31:34 +11:00

Optimise all palettes together

This commit is contained in:
Gwilym Kuiper 2022-08-11 22:22:44 +01:00
parent c87a9ff077
commit e97061a5af
8 changed files with 177 additions and 119 deletions

View file

@ -1,10 +1,11 @@
use palette16::Palette16OptimisationResults;
use palette16::{Palette16OptimisationResults, Palette16Optimiser};
use proc_macro::TokenStream;
use proc_macro2::Literal;
use syn::parse::Parser;
use syn::{parse_macro_input, punctuated::Punctuated, LitStr};
use syn::{Expr, ExprLit, Lit};
use std::collections::HashMap;
use std::path::PathBuf;
use std::{iter, path::Path, str};
@ -68,9 +69,46 @@ pub fn include_gfx(input: TokenStream) -> TokenStream {
let include_path = path.to_string_lossy();
let images = config.images();
let image_code = images.iter().map(|(image_name, &image)| {
convert_image(image, parent, image_name, &config.crate_prefix())
});
let mut optimiser = Palette16Optimiser::new(None);
let mut assignment_offsets = HashMap::new();
let mut assignment_offset = 0;
for (name, settings) in images.iter() {
let image_filename = &parent.join(&settings.filename());
let image = Image::load_from_file(image_filename);
let tile_size = settings.tilesize().to_size();
if image.width % tile_size != 0 || image.height % tile_size != 0 {
panic!("Image size not a multiple of tile size");
}
add_to_optimiser(
&mut optimiser,
&image,
tile_size,
settings.transparent_colour(),
);
let num_tiles = image.width * image.height / settings.tilesize().to_size().pow(2);
assignment_offsets.insert(name, assignment_offset);
assignment_offset += num_tiles;
}
let optimisation_results = optimiser.optimise_palettes();
let mut image_code = vec![];
for (image_name, &image) in images.iter() {
image_code.push(convert_image(
image,
parent,
image_name,
&config.crate_prefix(),
&optimisation_results,
assignment_offsets[image_name],
));
}
let module = quote! {
mod #module_name {
@ -217,38 +255,23 @@ fn convert_image(
parent: &Path,
variable_name: &str,
crate_prefix: &str,
optimisation_results: &Palette16OptimisationResults,
assignment_offset: usize,
) -> proc_macro2::TokenStream {
let image_filename = &parent.join(&settings.filename());
let image = Image::load_from_file(image_filename);
let tile_size = settings.tilesize().to_size();
if image.width % tile_size != 0 || image.height % tile_size != 0 {
panic!("Image size not a multiple of tile size");
}
let optimiser = optimiser_for_image(&image, tile_size, settings.transparent_colour());
let optimisation_results = optimiser.optimise_palettes();
rust_generator::generate_code(
variable_name,
&optimisation_results,
optimisation_results,
&image,
&image_filename.to_string_lossy(),
settings.tilesize(),
crate_prefix.to_owned(),
assignment_offset,
)
}
fn optimiser_for_image(
image: &Image,
tile_size: usize,
transparent_colour: Option<Colour>,
) -> palette16::Palette16Optimiser {
let mut palette_optimiser = palette16::Palette16Optimiser::new(transparent_colour);
add_to_optimiser(&mut palette_optimiser, image, tile_size, transparent_colour);
palette_optimiser
}
fn add_to_optimiser(
palette_optimiser: &mut palette16::Palette16Optimiser,
image: &Image,
@ -301,7 +324,7 @@ fn palette_tile_data(
let tile_size = TileSize::Tile8;
for image in images {
add_image_to_tile_data(&mut tile_data, image, tile_size, &optimiser)
add_image_to_tile_data(&mut tile_data, image, tile_size, &optimiser, 0)
}
let tile_data = collapse_to_4bpp(&tile_data);
@ -322,7 +345,8 @@ fn add_image_to_tile_data(
tile_data: &mut Vec<u8>,
image: &Image,
tile_size: TileSize,
optimiser: &&Palette16OptimisationResults,
optimiser: &Palette16OptimisationResults,
assignment_offset: usize,
) {
let tile_size = tile_size.to_size();
let tiles_x = image.width / tile_size;
@ -330,7 +354,7 @@ fn add_image_to_tile_data(
for y in 0..tiles_y {
for x in 0..tiles_x {
let palette_index = optimiser.assignments[y * tiles_x + x];
let palette_index = optimiser.assignments[y * tiles_x + x + assignment_offset];
let palette = &optimiser.optimised_palettes[palette_index];
for inner_y in 0..tile_size / 8 {

View file

@ -14,6 +14,7 @@ pub(crate) fn generate_code(
image_filename: &str,
tile_size: TileSize,
crate_prefix: String,
assignment_offset: usize,
) -> TokenStream {
let crate_prefix = format_ident!("{}", crate_prefix);
let output_variable_name = format_ident!("{}", output_variable_name);
@ -36,13 +37,20 @@ pub(crate) fn generate_code(
let mut tile_data = Vec::new();
add_image_to_tile_data(&mut tile_data, image, tile_size, &results);
add_image_to_tile_data(&mut tile_data, image, tile_size, results, assignment_offset);
let tile_data = collapse_to_4bpp(&tile_data);
let data = ByteString(&tile_data);
let assignments = results.assignments.iter().map(|&x| x as u8);
let num_tiles = image.width * image.height / tile_size.to_size().pow(2);
let assignments = results
.assignments
.iter()
.skip(assignment_offset)
.take(num_tiles)
.map(|&x| x as u8);
quote! {
#[allow(non_upper_case_globals)]

View file

@ -0,0 +1,25 @@
version = "1.0"
[image.stars]
filename = "stars.png"
tile_size = "8x8"
transparent_colour = "121105"
[image.title]
filename = "title-screen.png"
tile_size = "8x8"
[image.help]
filename = "help-text.png"
tile_size = "8x8"
transparent_colour = "121105"
[image.descriptions1]
filename = "descriptions1.png"
tile_size = "8x8"
transparent_colour = "121105"
[image.descriptions2]
filename = "descriptions2.png"
tile_size = "8x8"
transparent_colour = "121105"

View file

@ -1,11 +0,0 @@
version = "1.0"
[image.descriptions1]
filename = "descriptions1.png"
tile_size = "8x8"
transparent_colour = "121105"
[image.descriptions2]
filename = "descriptions2.png"
tile_size = "8x8"
transparent_colour = "121105"

View file

@ -1,6 +0,0 @@
version = "1.0"
[image.help]
filename = "help-text.png"
tile_size = "8x8"
transparent_colour = "121105"

View file

@ -1,10 +0,0 @@
version = "1.0"
[image.stars]
filename = "stars.png"
tile_size = "8x8"
transparent_colour = "121105"
[image.title]
filename = "title-screen.png"
tile_size = "8x8"

View file

@ -5,17 +5,23 @@ use agb::{
use crate::sfx::Sfx;
include_gfx!("gfx/stars.toml");
include_gfx!("gfx/help.toml");
include_gfx!("gfx/backgrounds.toml");
pub fn load_palettes(vram: &mut VRamManager) {
vram.set_background_palettes(&[
stars::stars.palettes[0].clone(),
crate::customise::DESCRIPTIONS_1_PALETTE.clone(),
crate::customise::DESCRIPTIONS_2_PALETTE.clone(),
help::help.palettes[0].clone(),
]);
vram.set_background_palettes(backgrounds::stars.palettes);
}
fn description_tileset() -> (TileSet<'static>, TileSet<'static>) {
let descriptions_1_tileset = TileSet::new(
backgrounds::descriptions1.tiles,
agb::display::tiled::TileFormat::FourBpp,
);
let descriptions_2_tileset = TileSet::new(
backgrounds::descriptions2.tiles,
agb::display::tiled::TileFormat::FourBpp,
);
(descriptions_1_tileset, descriptions_2_tileset)
}
pub(crate) fn load_help_text(
@ -24,18 +30,69 @@ pub(crate) fn load_help_text(
help_text_line: u16,
at_tile: (u16, u16),
) {
let help_tileset = TileSet::new(help::help.tiles, agb::display::tiled::TileFormat::FourBpp);
let help_tileset = TileSet::new(
backgrounds::help.tiles,
agb::display::tiled::TileFormat::FourBpp,
);
for x in 0..16 {
let tile_id = help_text_line * 16 + x;
background.set_tile(
vram,
(x + at_tile.0, at_tile.1).into(),
&help_tileset,
TileSetting::new(help_text_line * 16 + x, false, false, 3),
TileSetting::new(
tile_id,
false,
false,
backgrounds::help.palette_assignments[tile_id as usize],
),
)
}
}
pub(crate) fn load_description(
upgrade: usize,
descriptions_map: &mut RegularMap,
vram: &mut VRamManager,
) {
let (descriptions_1_tileset, descriptions_2_tileset) = description_tileset();
for y in 0..11 {
for x in 0..8 {
if upgrade < 10 {
let tile_id = y * 8 + x + 8 * 11 * upgrade as u16;
descriptions_map.set_tile(
vram,
(x, y).into(),
&descriptions_1_tileset,
TileSetting::new(
tile_id,
false,
false,
backgrounds::descriptions1.palette_assignments[tile_id as usize],
),
)
} else {
let tile_id = y * 8 + x + 8 * 11 * (upgrade as u16 - 10);
descriptions_map.set_tile(
vram,
(x, y).into(),
&descriptions_2_tileset,
TileSetting::new(
tile_id,
false,
false,
backgrounds::descriptions2.palette_assignments[tile_id as usize],
),
)
}
}
}
}
// Expects a 64x32 map
fn create_background_map(map: &mut RegularMap, vram: &mut VRamManager, stars_tileset: &TileSet) {
for x in 0..64u16 {
@ -47,7 +104,16 @@ fn create_background_map(map: &mut RegularMap, vram: &mut VRamManager, stars_til
} else {
rng::gen().rem_euclid(64) as u16
};
let tile_setting = TileSetting::new(tile_id, false, false, 0);
let tile_setting = TileSetting::new(
tile_id,
false,
false,
if blank {
0
} else {
backgrounds::stars.palette_assignments[tile_id as usize]
},
);
map.set_tile(vram, (x, y).into(), stars_tileset, tile_setting);
}
@ -58,8 +124,11 @@ fn create_background_map(map: &mut RegularMap, vram: &mut VRamManager, stars_til
pub fn show_title_screen(background: &mut RegularMap, vram: &mut VRamManager, sfx: &mut Sfx) {
background.set_scroll_pos((0_u16, 0_u16).into());
vram.set_background_palettes(stars::title.palettes);
let tile_set = TileSet::new(stars::title.tiles, agb::display::tiled::TileFormat::FourBpp);
vram.set_background_palettes(backgrounds::title.palettes);
let tile_set = TileSet::new(
backgrounds::title.tiles,
agb::display::tiled::TileFormat::FourBpp,
);
background.hide();
for x in 0..30u16 {
@ -73,7 +142,7 @@ pub fn show_title_screen(background: &mut RegularMap, vram: &mut VRamManager, sf
tile_id,
false,
false,
stars::title.palette_assignments[tile_id as usize],
backgrounds::title.palette_assignments[tile_id as usize],
),
);
}
@ -100,7 +169,7 @@ impl<'a> StarBackground<'a> {
background2: &'a mut RegularMap,
vram: &'_ mut VRamManager,
) -> Self {
let stars_tileset = TileSet::new(stars::stars.tiles, TileFormat::FourBpp);
let stars_tileset = TileSet::new(backgrounds::stars.tiles, TileFormat::FourBpp);
create_background_map(background1, vram, &stars_tileset);
create_background_map(background2, vram, &stars_tileset);

View file

@ -1,26 +1,20 @@
use agb::{
display::{
object::{Object, ObjectController},
palette16::Palette16,
tiled::{RegularMap, TileSet, TileSetting, TiledMap},
tiled::{RegularMap, TiledMap},
HEIGHT, WIDTH,
},
include_gfx,
input::{Button, Tri},
};
use alloc::vec::Vec;
use crate::{
background::load_description,
graphics::{FACE_SPRITES, MODIFIED_BOX, SELECTED_BOX, SELECT_BOX},
Agb, Die, Face, PlayerDice,
};
include_gfx!("gfx/descriptions.toml");
pub const DESCRIPTIONS_1_PALETTE: &Palette16 = &descriptions::descriptions1.palettes[0];
pub const DESCRIPTIONS_2_PALETTE: &Palette16 = &descriptions::descriptions2.palettes[0];
enum CustomiseState {
Dice,
Face,
@ -174,15 +168,6 @@ pub(crate) fn customise_screen(
help_background.set_scroll_pos((u16::MAX - 148, u16::MAX - 34).into());
crate::background::load_help_text(&mut agb.vram, help_background, 0, (0, 0));
let descriptions_1_tileset = TileSet::new(
descriptions::descriptions1.tiles,
agb::display::tiled::TileFormat::FourBpp,
);
let descriptions_2_tileset = TileSet::new(
descriptions::descriptions2.tiles,
agb::display::tiled::TileFormat::FourBpp,
);
// create the dice
let mut _net = create_net(&agb.obj, &player_dice.dice[0], &[]);
@ -301,37 +286,11 @@ pub(crate) fn customise_screen(
if (upgrades[cursor.upgrade] as u32) < 17 {
if cursor.upgrade != old_updade {
for y in 0..11 {
for x in 0..8 {
if (upgrades[cursor.upgrade] as usize) < 10 {
descriptions_map.set_tile(
&mut agb.vram,
(x, y).into(),
&descriptions_1_tileset,
TileSetting::new(
y * 8 + x + 8 * 11 * upgrades[cursor.upgrade] as u16,
false,
false,
1,
),
)
} else {
descriptions_map.set_tile(
&mut agb.vram,
(x, y).into(),
&descriptions_2_tileset,
TileSetting::new(
y * 8
+ x
+ 8 * 11 * (upgrades[cursor.upgrade] as u16 - 10),
false,
false,
2,
),
)
}
}
}
load_description(
upgrades[cursor.upgrade] as usize,
descriptions_map,
&mut agb.vram,
);
}
descriptions_map.show();
} else {