diff --git a/src/lib.rs b/src/lib.rs index a0d938c..d922038 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ pub mod export; pub mod pack; pub mod place; +pub mod rectpack; pub mod texture; diff --git a/src/pack.rs b/src/pack.rs index 72c1c4c..31c63f5 100644 --- a/src/pack.rs +++ b/src/pack.rs @@ -5,6 +5,7 @@ use rayon::prelude::*; use crate::export::AtlasExporter; use crate::place::{PlacedTextureInfo, TexturePlacer}; +use crate::rectpack::{Image, Node, Rectangle}; use crate::texture::{CroppedTexture, TextureCache}; pub type Atlas = Vec; @@ -15,22 +16,36 @@ pub struct TexturePacker { pub atlases: HashMap, placer: P, exporter: E, + root_node: Node, } impl TexturePacker { - pub fn new(placer: P, exporter: E) -> Self { + pub fn new(placer: P, exporter: E, width: u32, height: u32) -> Self { + let root_rect = Rectangle { + left: 0, + top: 0, + right: width, + bottom: height, + }; TexturePacker { textures: HashMap::new(), current_atlas: Vec::new(), atlases: HashMap::new(), placer, exporter, + root_node: Node::new(root_rect), } } pub fn add_texture(&mut self, id: String, texture: CroppedTexture) -> PlacedTextureInfo { let current_atlas_id = self.atlases.len(); + let img = Image { + id: id.clone(), + width: texture.width, + height: texture.height, + }; + if self.placer.can_place(&texture) { let texture_info = self.placer diff --git a/src/rectpack.rs b/src/rectpack.rs new file mode 100644 index 0000000..5b4a3ba --- /dev/null +++ b/src/rectpack.rs @@ -0,0 +1,109 @@ +#[derive(Clone, Copy)] +pub struct Rectangle { + pub left: u32, + pub top: u32, + pub right: u32, + pub bottom: u32, +} + +impl Rectangle { + pub fn width(&self) -> u32 { + self.right - self.left + } + + pub fn height(&self) -> u32 { + self.bottom - self.top + } + + pub fn fits(&self, img: &Image) -> bool { + self.width() >= img.width && self.height() >= img.height + } + + pub fn fits_perfectly(&self, img: &Image) -> bool { + self.width() == img.width && self.height() == img.height + } +} + +pub struct Image { + pub id: String, + pub width: u32, + pub height: u32, +} + +pub struct Node { + child: [Option>; 2], + rect: Rectangle, + image_id: Option, +} + +impl Node { + pub fn new(rect: Rectangle) -> Self { + Node { + child: [None, None], + rect, + image_id: None, + } + } + + pub fn insert(&mut self, img: &Image) -> Option<&mut Node> { + if let Some(ref mut child0) = self.child[0] { + if let Some(new_node) = child0.insert(img) { + return Some(new_node); + } + } else { + if self.image_id.is_some() { + return None; + } + + if !self.rect.fits(img) { + return None; + } + + if self.rect.fits_perfectly(img) { + // self.image_id = Some(img.id); + return Some(self); + } + + let child0_rect; + let child1_rect; + let dw = self.rect.width() - img.width; + let dh = self.rect.height() - img.height; + + if dw > dh { + child0_rect = Rectangle { + left: self.rect.left, + top: self.rect.top, + right: self.rect.left + img.width - 1, + bottom: self.rect.bottom, + }; + child1_rect = Rectangle { + left: self.rect.left + img.width, + top: self.rect.top, + right: self.rect.right, + bottom: self.rect.bottom, + }; + } else { + child0_rect = Rectangle { + left: self.rect.left, + top: self.rect.top, + right: self.rect.right, + bottom: self.rect.top + img.height - 1, + }; + child1_rect = Rectangle { + left: self.rect.left, + top: self.rect.top + img.height, + right: self.rect.right, + bottom: self.rect.bottom, + }; + } + + self.child[0] = Some(Box::new(Node::new(child0_rect))); + self.child[1] = Some(Box::new(Node::new(child1_rect))); + + if let Some(ref mut child0) = self.child[0] { + return child0.insert(img); + } + } + None + } +}