///|
pub enum AtlasStrategy {
Rows
CompactRows
PowerOfTwo
} derive(Debug, Eq, ToJson, FromJson)
///|
fn next_power_of_two(value : Int) -> Int {
let mut result = 1
let target = if value < 1 { 1 } else { value }
while result < target {
result *= 2
}
result
}
///|
fn compact_frames(sheet : SpriteSheet) -> SpriteSheet {
let frames = sheet.frames.copy()
frames.sort_by(fn(left, right) {
let area_order = right.source_size.area().compare(left.source_size.area())
if area_order == 0 {
left.filename.compare(right.filename)
} else {
area_order
}
})
{ ..sheet, frames, }
}
///|
pub fn pack_strategy(
sheet : SpriteSheet,
strategy~ : AtlasStrategy,
options? : AtlasOptions = AtlasOptions::default(),
) -> AtlasPlan {
let input = match strategy {
CompactRows => compact_frames(sheet)
_ => sheet
}
let base = pack_rows(input, options~)
match strategy {
PowerOfTwo => {
let width = next_power_of_two(base.size.w)
let height = next_power_of_two(base.size.h)
{
..base,
size: { w: width, h: height },
occupancy: if width * height == 0 {
0.0
} else {
base.packed_area().to_double() / (width * height).to_double()
},
}
}
_ => base
}
}
///|
pub fn pack_strategy_checked(
sheet : SpriteSheet,
strategy~ : AtlasStrategy,
options? : AtlasOptions = AtlasOptions::default(),
) -> AtlasPlan raise {
let plan = pack_rows_checked(sheet, options~)
match strategy {
Rows => plan
CompactRows => pack_strategy(sheet, strategy=CompactRows, options~)
PowerOfTwo => pack_strategy(sheet, strategy=PowerOfTwo, options~)
}
}
///|
pub fn AtlasPlan::fits(self : AtlasPlan, bounds : Size) -> Bool {
self.size.w <= bounds.w && self.size.h <= bounds.h
}
///|
pub fn AtlasPlan::max_frame_width(self : AtlasPlan) -> Int {
self.frames.fold(init=0, (current, frame) => {
if frame.packed.w > current {
frame.packed.w
} else {
current
}
})
}
///|
pub fn AtlasPlan::max_frame_height(self : AtlasPlan) -> Int {
self.frames.fold(init=0, (current, frame) => {
if frame.packed.h > current {
frame.packed.h
} else {
current
}
})
}
///|
pub fn AtlasPlan::frame_named(self : AtlasPlan, name : String) -> PackedFrame? {
match self.frames.search_by(fn(frame) { frame.filename == name }) {
Some(index) => Some(self.frames[index])
None => None
}
}
///|
pub fn AtlasPlan::contains_all_frames(
self : AtlasPlan,
sheet : SpriteSheet,
) -> Bool {
if self.frames.length() != sheet.frames.length() {
return false
}
for frame in self.frames {
if frame.packed.x < 0 ||
frame.packed.y < 0 ||
!self.size_rect().contains_rect(frame.packed) {
return false
}
}
true
}
///|
fn AtlasPlan::size_rect(self : AtlasPlan) -> Rect {
{ x: 0, y: 0, w: self.size.w, h: self.size.h }
}
///|
pub fn AtlasPlan::padding_gaps(self : AtlasPlan) -> Int {
if self.frames.length() < 2 {
return 0
}
let mut gaps = 0
for i in 1.. previous.right() {
gaps += current.x - previous.right()
}
}
gaps
}