stevenarella/src/render/atlas.rs

98 lines
3.0 KiB
Rust
Raw Normal View History

2015-09-17 11:21:56 -04:00
// Copyright 2015 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2015-09-17 11:04:25 -04:00
pub struct Atlas {
2015-10-07 14:36:59 -04:00
free_space: Vec<Rect>,
2015-09-17 11:04:25 -04:00
}
#[derive(Debug, Clone, Copy)]
pub struct Rect {
2015-10-07 14:36:59 -04:00
pub x: usize,
pub y: usize,
pub width: usize,
pub height: usize,
2015-09-17 11:04:25 -04:00
}
impl Atlas {
2015-10-07 14:36:59 -04:00
pub fn new(width: usize, height: usize) -> Atlas {
let mut a = Atlas { free_space: Vec::new() };
a.free_space.push(Rect {
x: 0,
y: 0,
width: width,
height: height,
});
a
}
2015-09-17 11:04:25 -04:00
2015-10-07 14:36:59 -04:00
pub fn add(&mut self, width: usize, height: usize) -> Option<Rect> {
let mut priority = usize::max_value();
let mut target: Option<Rect> = None;
let mut target_index = 0;
2015-09-17 11:04:25 -04:00
// Search through and find the best fit for this texture
2015-10-07 14:36:59 -04:00
for (index, free) in self.free_space.iter().enumerate() {
if free.width >= width && free.height >= height {
let current_priority = (free.width - width) * (free.height - height);
if target.is_none() || current_priority < priority {
target = Some(*free);
priority = current_priority;
target_index = index;
}
2015-09-17 11:04:25 -04:00
// Perfect match, we can break early
2015-10-07 14:36:59 -04:00
if priority == 0 {
break;
}
}
}
if target.is_none() {
return None;
}
let mut t = target.unwrap();
let ret = Rect {
x: t.x,
y: t.y,
width: width,
height: height,
};
2015-09-17 11:04:25 -04:00
2015-10-07 14:36:59 -04:00
if width == t.width {
t.y += height;
t.height -= height;
if t.height == 0 {
2015-09-17 11:04:25 -04:00
// Remove empty sections
2015-10-07 14:36:59 -04:00
self.free_space.remove(target_index);
} else {
self.free_space[target_index] = t;
}
} else {
if t.height > height {
2015-09-17 11:04:25 -04:00
// Split by height
2015-10-07 14:36:59 -04:00
self.free_space.insert(0,
Rect {
x: t.x,
y: t.y + height,
width: width,
height: t.height - height,
});
target_index += 1;
}
t.x += width;
t.width -= width;
self.free_space[target_index] = t;
}
2015-09-17 11:04:25 -04:00
2015-10-07 14:36:59 -04:00
Some(ret)
}
}