// // Collects all images into a single texture, commonly known as a texture atlas. // // There are a number of rectangle packer crates with different feature sets and // with more or less complex APIs. For this example we picked rect_packer which // is very easy to use. // // The rect packer tells us where to place each image and then we must create // the final texture ourselves. // use asefile::AsepriteFile; use image::{ImageFormat, RgbaImage}; use rect_packer::{Config, Packer, Rect}; use std::path::Path; #[allow(unused)] #[derive(Debug, Clone)] pub struct SpriteInfo { name: String, source: Rect, } pub struct ImageInfo { location: Rect, image: RgbaImage, } fn main() { let config = Config { width: 64, height: 64, border_padding: 0, rectangle_padding: 1, }; let mut packer = Packer::new(config); let basedir = Path::new("examples").join("atlas"); let mut sprites: Vec = Vec::new(); let mut images: Vec = Vec::new(); // Place all the sprites for basename in &["big", "small"] { let file = format!("{}.aseprite", basename); let ase = AsepriteFile::read_file(&basedir.join(&file)).unwrap(); let (width, height) = ase.size(); for frame in 0..ase.num_frames() { if let Some(rect) = packer.pack(width as i32, height as i32, false) { let name = format!("{}_{}", basename, frame); sprites.push(SpriteInfo { name, source: rect }); images.push(ImageInfo { location: rect, image: ase.frame(frame).image(), }); } else { panic!("Could not place {} frame {}", file, frame); // You could keep a list of packers and try to insert into // another one instead. } } } // Compute output size let (out_width, out_height) = images.iter().fold((1, 1), |(w, h), img| { (w.max(img.location.right()), h.max(img.location.bottom())) }); // Build the final image let mut output = RgbaImage::new(out_width as u32, out_height as u32); for img in &images { image::imageops::replace( &mut output, &img.image, img.location.x.into(), img.location.y.into(), ); } let output_file = basedir.join("atlas.png"); output .save_with_format(&output_file, ImageFormat::Png) .unwrap(); // Write sprite info. In a real use case should be serialized as json or similar. println!("{:#?}", sprites); }