Implement the atlas
This commit is contained in:
parent
34cd1ef9b0
commit
ce811c0e48
|
@ -9,3 +9,6 @@ byteorder = "1"
|
|||
euclid = "0.10"
|
||||
memmap = "0.5"
|
||||
|
||||
[dev-dependencies]
|
||||
quickcheck = "0.4"
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
extern crate memmap;
|
||||
extern crate pathfinder;
|
||||
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright 2017 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
|
||||
/// TODO(pcwalton): Track width of last shelf.
|
||||
pub struct Atlas {
|
||||
free_rects: Vec<Rect<u32>>,
|
||||
available_width: u32,
|
||||
shelf_height: u32,
|
||||
shelf_count: u32,
|
||||
}
|
||||
|
||||
impl Atlas {
|
||||
#[inline]
|
||||
pub fn new(available_width: u32, shelf_height: u32) -> Atlas {
|
||||
Atlas {
|
||||
free_rects: vec![],
|
||||
available_width: available_width,
|
||||
shelf_height: shelf_height,
|
||||
shelf_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn place(&mut self, size: &Size2D<u32>) -> Result<Point2D<u32>, ()> {
|
||||
let chosen_index_and_rect =
|
||||
self.free_rects
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|&(_, rect)| {
|
||||
size.width <= rect.size.width && size.height <= rect.size.height
|
||||
})
|
||||
.min_by(|&(_, a), &(_, b)| area(a).cmp(&area(b)))
|
||||
.map(|(index, rect)| (index, *rect));
|
||||
|
||||
let chosen_rect;
|
||||
match chosen_index_and_rect {
|
||||
None => {
|
||||
// Make a new shelf.
|
||||
chosen_rect = Rect::new(Point2D::new(0, self.shelf_height * self.shelf_count),
|
||||
Size2D::new(self.available_width, self.shelf_height));
|
||||
self.shelf_count += 1
|
||||
}
|
||||
Some((index, rect)) => {
|
||||
self.free_rects.swap_remove(index);
|
||||
chosen_rect = rect;
|
||||
}
|
||||
}
|
||||
|
||||
// Guillotine to bottom.
|
||||
let free_below =
|
||||
Rect::new(Point2D::new(chosen_rect.origin.x, chosen_rect.origin.y + size.height),
|
||||
Size2D::new(size.width, chosen_rect.size.height - size.height));
|
||||
if !free_below.is_empty() {
|
||||
self.free_rects.push(free_below);
|
||||
}
|
||||
|
||||
// Guillotine to right.
|
||||
let free_to_right =
|
||||
Rect::new(Point2D::new(chosen_rect.origin.x + size.width, chosen_rect.origin.y),
|
||||
Size2D::new(chosen_rect.size.width - size.width, chosen_rect.size.height));
|
||||
if !free_to_right.is_empty() {
|
||||
self.free_rects.push(free_to_right);
|
||||
}
|
||||
|
||||
Ok(chosen_rect.origin)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn available_width(&self) -> u32 {
|
||||
self.available_width
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn shelf_height(&self) -> u32 {
|
||||
self.shelf_height
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn area(rect: &Rect<u32>) -> u32 {
|
||||
rect.size.width * rect.size.height
|
||||
}
|
||||
|
|
@ -8,12 +8,21 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(iter_min_by)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate byteorder;
|
||||
extern crate euclid;
|
||||
#[cfg(test)]
|
||||
#[macro_use]
|
||||
extern crate quickcheck;
|
||||
|
||||
pub mod atlas;
|
||||
pub mod batch;
|
||||
pub mod otf;
|
||||
mod util;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
use atlas::Atlas;
|
||||
use euclid::{Rect, Size2D};
|
||||
use std::cmp;
|
||||
|
||||
fn place_objects(available_width: u32, objects: Vec<(u32, u32)>) -> (Atlas, Vec<Rect<u32>>) {
|
||||
let objects: Vec<_> = objects.iter()
|
||||
.map(|&(width, height)| Size2D::new(width, height))
|
||||
.collect();
|
||||
|
||||
let available_width = cmp::max(available_width,
|
||||
objects.iter().map(|object| object.width).max().unwrap_or(0));
|
||||
let shelf_height = objects.iter().map(|object| object.height).max().unwrap_or(0);
|
||||
|
||||
let mut atlas = Atlas::new(available_width, shelf_height);
|
||||
let rects = objects.iter()
|
||||
.map(|object| Rect::new(atlas.place(object).unwrap(), *object))
|
||||
.collect();
|
||||
(atlas, rects)
|
||||
}
|
||||
|
||||
quickcheck! {
|
||||
fn objects_dont_overlap(available_width: u32, objects: Vec<(u32, u32)>) -> bool {
|
||||
let (_, rects) = place_objects(available_width, objects);
|
||||
for (i, a) in rects.iter().enumerate() {
|
||||
for b in &rects[(i + 1)..] {
|
||||
assert!(!a.intersects(b))
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn objects_dont_exceed_available_width(available_width: u32, objects: Vec<(u32, u32)>) -> bool {
|
||||
let (atlas, rects) = place_objects(available_width, objects);
|
||||
rects.iter().all(|rect| rect.max_x() <= atlas.available_width())
|
||||
}
|
||||
|
||||
fn objects_dont_cross_shelves(available_width: u32, objects: Vec<(u32, u32)>) -> bool {
|
||||
let (atlas, rects) = place_objects(available_width, objects);
|
||||
rects.iter().all(|rect| {
|
||||
rect.is_empty() ||
|
||||
rect.origin.y / atlas.shelf_height() == (rect.max_y() - 1) / atlas.shelf_height()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright 2017 The Servo Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
mod atlas;
|
||||
|
Loading…
Reference in New Issue