Skip to content
Snippets Groups Projects
Verified Commit 02fb9b48 authored by Louis's avatar Louis :fire:
Browse files

Shift extrude impl to library types

parent ce7fb9b6
No related tags found
No related merge requests found
Pipeline #730 waiting for manual action with stages
in 1 minute and 7 seconds
mod colours;
mod sheets;
pub use colours::apply_colour_map;
pub use sheets::ExtrudeOptions;
use crate::utils::{RgbaOutputFormat, SpriteData};
use image::math::Rect;
use image::{DynamicImage, GenericImage, GenericImageView, Rgba, RgbaImage};
use std::ops::Deref;
#[derive(Default, Copy, Clone, Debug)]
pub struct ExtrudeOptions {
/// The amount of horizontal space to add between each sprite in the image
pub space_x: u32,
/// The amount of vertical space to add between each sprite in the image
pub space_y: u32,
/// The amount of padding to add around the edge of the spritesheet
pub padding: u32,
/// The size of each tile in the spritesheet. Assumed to be square tiles
pub tile_size: u32,
/// Use nearby pixels for spacing
pub extrude: bool,
}
impl ExtrudeOptions {
pub fn extrude(&self, image: &DynamicImage) -> anyhow::Result<RgbaOutputFormat> {
log::info!(
"Image loaded with size {} x {}",
image.width(),
image.height()
);
let columns = image.width() / self.tile_size;
let rows = image.height() / self.tile_size;
log::info!("Inferred sheet contains {} columns", columns);
log::info!("Inferred sheet contains {} rows", rows);
let mut views = Vec::with_capacity((columns * rows) as usize);
for x in 0..columns {
for y in 0..rows {
let img_x = x * self.tile_size;
let img_y = y * self.tile_size;
let payload = SpriteData {
data: image.view(img_x, img_y, self.tile_size, self.tile_size),
x: img_x,
y: img_y,
tx: x,
ty: y,
width: self.tile_size,
height: self.tile_size,
};
views.push(payload);
}
}
let new_width = (self.padding * 2 + self.space_x * columns) + image.width();
let new_height = (self.padding * 2 + self.space_y * rows) + image.height();
log::info!(
"Using new image width {} / height {}",
new_width,
new_height
);
let mut new_image = RgbaImage::from_pixel(new_width, new_height, Rgba::from([0, 0, 0, 0]));
for sprite in views.iter() {
let (width, height) = sprite.data.dimensions();
let (img_x, img_y) = sprite.data.offsets();
let target_x = self.padding + img_x + (sprite.tx * self.space_x);
let target_y = self.padding + img_y + (sprite.ty * self.space_y);
new_image.copy_from(sprite.data.deref(), target_x, target_y)?;
if self.extrude {
// Left Side
new_image.copy_within(
Rect {
x: target_x,
y: target_y,
width: 1,
height,
},
target_x.saturating_sub(1),
target_y,
);
// Right Side
new_image.copy_within(
Rect {
x: target_x + width - 1,
y: target_y,
width: 1,
height,
},
target_x + width,
target_y,
);
// Top Side
new_image.copy_within(
Rect {
x: target_x,
y: target_y,
width,
height: 1,
},
target_x,
target_y.saturating_sub(1),
);
// Bottom Side
new_image.copy_within(
Rect {
x: target_x,
y: target_y + height - 1,
width,
height: 1,
},
target_x,
target_y + height,
);
}
}
Ok(new_image)
}
}
use clap::Parser;
use image::math::Rect;
use image::{GenericImage, GenericImageView, Rgba, RgbaImage};
use image::{ColorType, DynamicImage, GenericImage, Rgba};
use crunch_cli::utils::{RgbaOutputFormat, SpriteData};
use crunch_cli::actions::ExtrudeOptions;
use crunch_cli::utils::RgbaOutputFormat;
use serde::{Deserialize, Serialize};
use std::ops::Deref;
#[inline(always)]
fn tile_size() -> u32 {
......@@ -51,102 +50,16 @@ impl Extrude {
&self,
image: &impl GenericImage<Pixel = Rgba<u8>>,
) -> anyhow::Result<RgbaOutputFormat> {
log::info!(
"Image loaded with size {} x {}",
image.width(),
image.height()
);
let opts = ExtrudeOptions {
extrude: self.extrude,
space_x: self.space_x,
space_y: self.space_y,
padding: self.padding,
tile_size: self.tile_size,
};
let columns = image.width() / self.tile_size;
let rows = image.height() / self.tile_size;
log::info!("Inferred sheet contains {} columns", columns);
log::info!("Inferred sheet contains {} rows", rows);
let mut views = Vec::with_capacity((columns * rows) as usize);
for x in 0..columns {
for y in 0..rows {
let img_x = x * self.tile_size;
let img_y = y * self.tile_size;
let payload = SpriteData {
data: image.view(img_x, img_y, self.tile_size, self.tile_size),
x: img_x,
y: img_y,
tx: x,
ty: y,
width: self.tile_size,
height: self.tile_size,
};
views.push(payload);
}
}
let new_width = (self.padding * 2 + self.space_x * columns) + image.width();
let new_height = (self.padding * 2 + self.space_y * rows) + image.height();
log::info!(
"Using new image width {} / height {}",
new_width,
new_height
);
let mut new_image = RgbaImage::from_pixel(new_width, new_height, Rgba::from([0, 0, 0, 0]));
for sprite in views.iter() {
let (width, height) = sprite.data.dimensions();
let (img_x, img_y) = sprite.data.offsets();
let target_x = self.padding + img_x + (sprite.tx * self.space_x);
let target_y = self.padding + img_y + (sprite.ty * self.space_y);
new_image.copy_from(sprite.data.deref(), target_x, target_y)?;
if self.extrude {
// Left Side
new_image.copy_within(
Rect {
x: target_x,
y: target_y,
width: 1,
height,
},
target_x.saturating_sub(1),
target_y,
);
// Right Side
new_image.copy_within(
Rect {
x: target_x + width - 1,
y: target_y,
width: 1,
height,
},
target_x + width,
target_y,
);
// Top Side
new_image.copy_within(
Rect {
x: target_x,
y: target_y,
width,
height: 1,
},
target_x,
target_y.saturating_sub(1),
);
// Bottom Side
new_image.copy_within(
Rect {
x: target_x,
y: target_y + height - 1,
width,
height: 1,
},
target_x,
target_y + height,
);
}
}
Ok(new_image)
let mut inner_image = DynamicImage::new(image.width(), image.height(), ColorType::Rgba8);
inner_image.copy_from(image, 0, 0)?;
opts.extrude(&inner_image)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment