diff options
Diffstat (limited to 'packer')
| -rw-r--r-- | packer/Cargo.toml | 13 | ||||
| -rw-r--r-- | packer/packed.png | bin | 1268654 -> 0 bytes | |||
| -rw-r--r-- | packer/src/bin/benchmark.rs | 28 | ||||
| -rw-r--r-- | packer/src/bin/res/bunny.ff | bin | 8208 -> 0 bytes | |||
| -rw-r--r-- | packer/src/bin/res/bunny.png | bin | 438 -> 0 bytes | |||
| -rw-r--r-- | packer/src/bin/res/gator.bmp | bin | 750054 -> 0 bytes | |||
| -rw-r--r-- | packer/src/bin/res/gator.ff | bin | 2000016 -> 0 bytes | |||
| -rw-r--r-- | packer/src/bin/res/ghost.ico | bin | 67646 -> 0 bytes | |||
| -rw-r--r-- | packer/src/lib.rs | 175 |
9 files changed, 0 insertions, 216 deletions
diff --git a/packer/Cargo.toml b/packer/Cargo.toml deleted file mode 100644 index 0b1beb8..0000000 --- a/packer/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "packer" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -image = "0.24" -exun = "0.2" - -[[bin]] -name = "benchmark" diff --git a/packer/packed.png b/packer/packed.png Binary files differdeleted file mode 100644 index 9602cdb..0000000 --- a/packer/packed.png +++ /dev/null diff --git a/packer/src/bin/benchmark.rs b/packer/src/bin/benchmark.rs deleted file mode 100644 index 4d898d5..0000000 --- a/packer/src/bin/benchmark.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::{fs::File, sync::Arc, time::Instant}; - -use image::{io::Reader as ImageReader, ImageOutputFormat}; -use packer::RectanglePacker; - -fn main() -> Result<(), exun::RawUnexpected> { - let img1 = ImageReader::open("src/bin/res/gator.bmp")?.decode()?; - let img2 = ImageReader::open("src/bin/res/bunny.ff")?.decode()?; - let img3 = ImageReader::open("src/bin/res/ghost.ico")?.decode()?; - - let start = Instant::now(); - let mut packer = RectanglePacker::new(); - packer.add_texture("gator".into(), Arc::new(img1.to_rgba8())); - packer.add_texture("bunny".into(), Arc::new(img2.to_rgba8())); - packer.add_texture("ghost".into(), Arc::new(img3.to_rgba8())); - println!("{} milliseconds", start.elapsed().as_secs_f32() * 1000.0); - - let start = Instant::now(); - let packed = packer.output(1, 1); - println!("{} milliseconds", start.elapsed().as_secs_f32() * 1000.0); - - let mut file = File::create("packed.png")?; - packed? - .get_full_atlas() - .write_to(&mut file, ImageOutputFormat::Bmp)?; - - Ok(()) -} diff --git a/packer/src/bin/res/bunny.ff b/packer/src/bin/res/bunny.ff Binary files differdeleted file mode 100644 index 64c5a69..0000000 --- a/packer/src/bin/res/bunny.ff +++ /dev/null diff --git a/packer/src/bin/res/bunny.png b/packer/src/bin/res/bunny.png Binary files differdeleted file mode 100644 index 87ba72d..0000000 --- a/packer/src/bin/res/bunny.png +++ /dev/null diff --git a/packer/src/bin/res/gator.bmp b/packer/src/bin/res/gator.bmp Binary files differdeleted file mode 100644 index e752b56..0000000 --- a/packer/src/bin/res/gator.bmp +++ /dev/null diff --git a/packer/src/bin/res/gator.ff b/packer/src/bin/res/gator.ff Binary files differdeleted file mode 100644 index aac1bcb..0000000 --- a/packer/src/bin/res/gator.ff +++ /dev/null diff --git a/packer/src/bin/res/ghost.ico b/packer/src/bin/res/ghost.ico Binary files differdeleted file mode 100644 index 102de00..0000000 --- a/packer/src/bin/res/ghost.ico +++ /dev/null diff --git a/packer/src/lib.rs b/packer/src/lib.rs deleted file mode 100644 index 6715a9e..0000000 --- a/packer/src/lib.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::collections::HashMap; -use std::ops::Deref; -use std::sync::Arc; - -use exun::RawUnexpected; -use image::{GenericImage, RgbaImage}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Rectangle { - pub x: u32, - pub y: u32, - pub width: u32, - pub height: u32, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct Texture { - id: Arc<str>, - x: u32, - y: u32, - texture: Arc<RgbaImage>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -struct ImageRect(Arc<RgbaImage>, Arc<str>); - -#[derive(Debug, Default, Clone)] -pub struct RectanglePacker { - min_width: u32, - textures: Vec<ImageRect>, -} - -#[derive(Debug, Clone)] -pub struct TextureAtlas { - atlas: RgbaImage, - ids: HashMap<Arc<str>, Rectangle>, -} - -impl PartialOrd for ImageRect { - fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for ImageRect { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.height().cmp(&other.0.height()) - } -} - -impl RectanglePacker { - pub fn new() -> Self { - Self { - min_width: 1, - textures: Vec::new(), - } - } - - pub fn with_capacity(capacity: usize) -> Self { - Self { - min_width: 1, - textures: Vec::with_capacity(capacity), - } - } - - pub fn capacity(&self) -> usize { - self.textures.capacity() - } - - pub fn len(&self) -> usize { - self.textures.len() - } - - pub fn is_empty(&self) -> bool { - self.textures.is_empty() - } - - pub fn reserve(&mut self, additional: usize) { - self.textures.reserve(additional) - } - - pub fn shrink_to_fit(&mut self) { - self.textures.shrink_to_fit() - } - - pub fn add_texture(&mut self, name: Arc<str>, texture: Arc<RgbaImage>) { - if texture.width() > self.min_width { - self.min_width = texture.width() + 1; - } - self.textures.push(ImageRect(texture, name)); - } - - fn pack(&mut self, min_width: u32) -> (Vec<Texture>, u32, u32) { - let image_width = self.min_width.max(min_width); - - // to make sure padding is rounded up and not down, 64 is added - // to make sure some padding is always present, minimum is 1 pixel - let horizontal_padding = ((image_width + 64) / 128).max(1); - - let mut x_position = 0; - let mut y_position = 0; - let mut largest_row_height = 0; - let mut rectangles = Vec::with_capacity(self.textures.len()); - - self.textures.sort(); - self.textures.reverse(); - for texture in &self.textures { - // loop to the next row if we've gone off the edge - if (x_position + texture.0.width()) > image_width { - let vertical_padding = ((largest_row_height + 64) / 128).max(1); - - y_position += largest_row_height + vertical_padding; - x_position = 0; - largest_row_height = 0; - } - - // set the rectangle position - let x = x_position; - let y = y_position; - - x_position += texture.0.width() + horizontal_padding; - - if texture.0.height() > largest_row_height { - largest_row_height = texture.0.height(); - } - - rectangles.push(Texture { - id: texture.1.clone(), - x, - y, - texture: texture.0.clone(), - }); - } - - let vertical_padding = ((largest_row_height + 64) / 128).max(1); - let total_height = y_position + largest_row_height + vertical_padding; - - (rectangles, image_width, total_height) - } - - pub fn output( - &mut self, - min_width: u32, - min_height: u32, - ) -> Result<TextureAtlas, RawUnexpected> { - let (rectangles, image_width, image_height) = self.pack(min_width); - let image_height = image_height.max(min_height); - let mut atlas = RgbaImage::new(image_width, image_height); - let mut ids = HashMap::with_capacity(rectangles.len()); - for rectangle in rectangles { - atlas.copy_from(rectangle.texture.deref(), rectangle.x, rectangle.y)?; - ids.insert( - rectangle.id, - Rectangle { - x: rectangle.x, - y: rectangle.y, - width: rectangle.texture.width(), - height: rectangle.texture.height(), - }, - ); - } - - Ok(TextureAtlas { atlas, ids }) - } -} - -impl TextureAtlas { - pub fn get_full_atlas(&self) -> &RgbaImage { - &self.atlas - } - - pub fn get_texture_rect(&self, id: &str) -> Option<Rectangle> { - self.ids.get(id).cloned() - } -} |
