mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
Add support for transparent sprites
This commit is contained in:
parent
ece73dd975
commit
8b063f8440
|
@ -3,15 +3,20 @@ pub struct Colour {
|
|||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
pub a: u8,
|
||||
}
|
||||
|
||||
impl Colour {
|
||||
pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
|
||||
Colour { r, g, b }
|
||||
pub fn from_rgb(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Colour { r, g, b, a }
|
||||
}
|
||||
|
||||
pub fn to_rgb15(self) -> u16 {
|
||||
let (r, g, b) = (self.r as u16, self.g as u16, self.b as u16);
|
||||
((r >> 3) & 31) | (((g >> 3) & 31) << 5) | (((b >> 3) & 31) << 10)
|
||||
}
|
||||
|
||||
pub fn is_transparent(self) -> bool {
|
||||
self.a != 255
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ impl Image for ImageV1 {
|
|||
let g = u8::from_str_radix(&colour[2..4], 16).unwrap();
|
||||
let b = u8::from_str_radix(&colour[4..6], 16).unwrap();
|
||||
|
||||
return Some(Colour::from_rgb(r, g, b));
|
||||
return Some(Colour::from_rgb(r, g, b, 255));
|
||||
}
|
||||
|
||||
None
|
||||
|
|
|
@ -25,7 +25,7 @@ impl Image {
|
|||
let mut colour_data = Vec::with_capacity(width * height);
|
||||
|
||||
for (_, _, pixel) in img.pixels() {
|
||||
colour_data.push(Colour::from_rgb(pixel[0], pixel[1], pixel[2]));
|
||||
colour_data.push(Colour::from_rgb(pixel[0], pixel[1], pixel[2], pixel[3]));
|
||||
}
|
||||
|
||||
Image {
|
||||
|
|
|
@ -94,7 +94,9 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream {
|
|||
Err(e) => return e.to_compile_error().into(),
|
||||
};
|
||||
|
||||
let mut optimiser = palette16::Palette16Optimiser::new();
|
||||
let transparent_colour = Colour::from_rgb(255, 0, 255, 0);
|
||||
|
||||
let mut optimiser = palette16::Palette16Optimiser::new(Some(transparent_colour));
|
||||
let mut images = Vec::new();
|
||||
let mut tags = Vec::new();
|
||||
|
||||
|
@ -116,12 +118,17 @@ pub fn include_aseprite_inner(input: TokenStream) -> TokenStream {
|
|||
assert!(width == frame.height() && width.is_power_of_two() && width <= 32);
|
||||
|
||||
let image = Image::load_from_dyn_image(frame);
|
||||
add_to_optimiser(&mut optimiser, &image, width as usize);
|
||||
add_to_optimiser(
|
||||
&mut optimiser,
|
||||
&image,
|
||||
width as usize,
|
||||
Some(transparent_colour),
|
||||
);
|
||||
images.push(image);
|
||||
}
|
||||
}
|
||||
|
||||
let optimised_results = optimiser.optimise_palettes(None);
|
||||
let optimised_results = optimiser.optimise_palettes();
|
||||
|
||||
let (palette_data, tile_data, assignments) = palete_tile_data(&optimised_results, &images);
|
||||
|
||||
|
@ -212,8 +219,8 @@ fn convert_image(
|
|||
panic!("Image size not a multiple of tile size");
|
||||
}
|
||||
|
||||
let optimiser = optimiser_for_image(&image, tile_size);
|
||||
let optimisation_results = optimiser.optimise_palettes(settings.transparent_colour());
|
||||
let optimiser = optimiser_for_image(&image, tile_size, settings.transparent_colour());
|
||||
let optimisation_results = optimiser.optimise_palettes();
|
||||
|
||||
rust_generator::generate_code(
|
||||
variable_name,
|
||||
|
@ -225,9 +232,13 @@ fn convert_image(
|
|||
)
|
||||
}
|
||||
|
||||
fn optimiser_for_image(image: &Image, tile_size: usize) -> palette16::Palette16Optimiser {
|
||||
let mut palette_optimiser = palette16::Palette16Optimiser::new();
|
||||
add_to_optimiser(&mut palette_optimiser, image, tile_size);
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -235,6 +246,7 @@ fn add_to_optimiser(
|
|||
palette_optimiser: &mut palette16::Palette16Optimiser,
|
||||
image: &Image,
|
||||
tile_size: usize,
|
||||
transparent_colour: Option<Colour>,
|
||||
) {
|
||||
let tiles_x = image.width / tile_size;
|
||||
let tiles_y = image.height / tile_size;
|
||||
|
@ -247,7 +259,10 @@ fn add_to_optimiser(
|
|||
for i in 0..tile_size {
|
||||
let colour = image.colour(x * tile_size + i, y * tile_size + j);
|
||||
|
||||
palette.add_colour(colour);
|
||||
palette.add_colour(match (colour.is_transparent(), transparent_colour) {
|
||||
(true, Some(transparent_colour)) => transparent_colour,
|
||||
_ => colour,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,7 +307,9 @@ fn palete_tile_data(
|
|||
for j in inner_y * 8..inner_y * 8 + 8 {
|
||||
for i in inner_x * 8..inner_x * 8 + 8 {
|
||||
let colour = image.colour(x * tile_size + i, y * tile_size + j);
|
||||
tile_data.push(palette.colour_index(colour));
|
||||
tile_data.push(
|
||||
palette.colour_index(colour, optimiser.transparent_colour),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,11 +27,22 @@ impl Palette16 {
|
|||
self.colours.push(colour);
|
||||
true
|
||||
}
|
||||
pub fn colour_index(&self, colour: Colour) -> u8 {
|
||||
|
||||
pub fn colour_index(&self, colour: Colour, transparent_colour: Option<Colour>) -> u8 {
|
||||
let colour_to_search = match (transparent_colour, colour.is_transparent()) {
|
||||
(Some(transparent_colour), true) => transparent_colour,
|
||||
_ => colour,
|
||||
};
|
||||
|
||||
self.colours
|
||||
.iter()
|
||||
.position(|c| *c == colour)
|
||||
.expect("Can't get a colour index without it existing") as u8
|
||||
.position(|c| *c == colour_to_search)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Can't get a colour index without it existing, looking for {:?}, got {:?}",
|
||||
colour, self.colours
|
||||
)
|
||||
}) as u8
|
||||
}
|
||||
|
||||
fn union_length(&self, other: &Palette16) -> usize {
|
||||
|
@ -62,19 +73,22 @@ impl IntoIterator for Palette16 {
|
|||
pub(crate) struct Palette16Optimiser {
|
||||
palettes: Vec<Palette16>,
|
||||
colours: Vec<Colour>,
|
||||
transparent_colour: Option<Colour>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Palette16OptimisationResults {
|
||||
pub optimised_palettes: Vec<Palette16>,
|
||||
pub assignments: Vec<usize>,
|
||||
pub transparent_colour: Option<Colour>,
|
||||
}
|
||||
|
||||
impl Palette16Optimiser {
|
||||
pub fn new() -> Self {
|
||||
pub fn new(transparent_colour: Option<Colour>) -> Self {
|
||||
Palette16Optimiser {
|
||||
palettes: vec![],
|
||||
colours: Vec::new(),
|
||||
transparent_colour,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,10 +108,7 @@ impl Palette16Optimiser {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn optimise_palettes(
|
||||
&self,
|
||||
transparent_colour: Option<Colour>,
|
||||
) -> Palette16OptimisationResults {
|
||||
pub fn optimise_palettes(&self) -> Palette16OptimisationResults {
|
||||
let mut assignments = vec![0; self.palettes.len()];
|
||||
let mut optimised_palettes = vec![];
|
||||
|
||||
|
@ -108,7 +119,7 @@ impl Palette16Optimiser {
|
|||
.collect::<HashSet<Palette16>>();
|
||||
|
||||
while !unsatisfied_palettes.is_empty() {
|
||||
let palette = self.find_maximal_palette_for(&unsatisfied_palettes, transparent_colour);
|
||||
let palette = self.find_maximal_palette_for(&unsatisfied_palettes);
|
||||
|
||||
for test_palette in unsatisfied_palettes.clone() {
|
||||
if test_palette.is_satisfied_by(&palette) {
|
||||
|
@ -132,17 +143,14 @@ impl Palette16Optimiser {
|
|||
Palette16OptimisationResults {
|
||||
optimised_palettes,
|
||||
assignments,
|
||||
transparent_colour: self.transparent_colour,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_maximal_palette_for(
|
||||
&self,
|
||||
unsatisfied_palettes: &HashSet<Palette16>,
|
||||
transparent_colour: Option<Colour>,
|
||||
) -> Palette16 {
|
||||
fn find_maximal_palette_for(&self, unsatisfied_palettes: &HashSet<Palette16>) -> Palette16 {
|
||||
let mut palette = Palette16::new();
|
||||
|
||||
if let Some(transparent_colour) = transparent_colour {
|
||||
if let Some(transparent_colour) = self.transparent_colour {
|
||||
palette.add_colour(transparent_colour);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,8 @@ pub(crate) fn generate_code(
|
|||
for j in inner_y * 8..inner_y * 8 + 8 {
|
||||
for i in inner_x * 8..inner_x * 8 + 8 {
|
||||
let colour = image.colour(x * tile_size + i, y * tile_size + j);
|
||||
tile_data.push(palette.colour_index(colour));
|
||||
tile_data
|
||||
.push(palette.colour_index(colour, results.transparent_colour));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Loading…
Reference in a new issue