use super::{atlas_pack::*, *}; use std::hash; pub fn pack_into_atlas, S: TexSize, F: TexFmt>(mut tiles: Vec<(K, T)>, max_w: i32, max_h: i32) -> (Atlas, Vec<(K, T)>) where K: fmt::Debug + Clone + Eq + hash::Hash, { if tiles.is_empty() { FAIL!("Empty vector supplied to atlas"); return Def(); } tiles.sort_unstable_by(|(_, l), (_, r)| if l.h() != r.h() { r.h().cmp(&l.h()) } else { r.w().cmp(&l.w()) }); ASSERT!( tiles.iter().map(|(l, _)| l).collect::>().len() == tiles.len(), "Vector supplied to atlas needs unique keys" ); let max_w = { let area = tiles.iter().fold(0, |v, (_, t)| v + usize(t.w()) * usize(t.h())); max_w.min(i32(2_u32.pow(u32(f64(area).sqrt().log2().ceil())))) }; let (min_w, min_h) = (tiles.iter().map(|(_, e)| e.w()).min().valid(), tiles.last().valid().1.h()); let (c, empty, filled) = (S::SIZE, &mut vec![Rect { x: 0, y: 0, w: max_w, h: max_h }], &mut vec![]); let (mut tail, mut atlas, mut packed) = (vec![], vec![], HashMap::new()); let mut tiles = tiles.into_iter().map(Some).collect_vec(); for i in 0..tiles.len() { let (id, img) = tiles[i].as_ref().valid(); let duplicate = tiles[..i].iter().rev().flatten().take_while(|(_, e)| e.h() == img.h()).find(|(_, e)| *img == *e); if let Some((id_d, _)) = duplicate { packed.insert(id.clone(), *packed.get(id_d).valid()); DEBUG!("Deduped {id_d:?}, {id:?} in atlas"); continue; } let Ok(b) = pack(img.w(), img.h(), empty, filled, (min_w, min_h)) else { tail.push(tiles[i].take().valid()); continue; }; let (x, y, w, h) = (b.x, b.y, b.w, b.h); packed.insert(id.clone(), (x, y + h, x + w, y)); atlas.resize(atlas.len().max(usize(b.y2() * max_w * c)), Def()); for i in 0..h { let d = img.data(); let b = usize(((y + i) * max_w + x) * c); let w = usize(w * c); let x = usize(i) * w; atlas[b..b + w].copy_from_slice(&d[x..x + w]) } } let max_h = atlas.len() / usize(max_w * c); let tex = Rc::new(Tex2d::::new((max_w, max_h), &atlas[..])); let packed = packed .into_iter() .map(|(id, reg)| { let region = (0.5, -0.5, 0.5, -0.5).sum(reg).div((max_w, max_h, max_w, max_h)); (id, VTex2d { region, atlas: tex.clone() }) }) .collect(); (packed, tail) } type Atlas = HashMap>; pub trait Tile: Eq { fn w(&self) -> i32; fn h(&self) -> i32; fn data(&self) -> &[T]; }