Add borders between glyphs in the atlas; allow the atlas to be dumped in the demo

This commit is contained in:
Patrick Walton 2017-01-30 20:04:39 -08:00
parent 5bccf88445
commit 6ae7601283
3 changed files with 51 additions and 6 deletions

View File

@ -15,6 +15,7 @@ memmap = "0.5"
path = "/Users/pcwalton/Source/rust-packages/compute-shader"
[dev-dependencies]
image = "0.12"
quickcheck = "0.4"
[dev-dependencies.glfw]

View File

@ -8,6 +8,7 @@ extern crate compute_shader;
extern crate euclid;
extern crate gl;
extern crate glfw;
extern crate image;
extern crate memmap;
extern crate pathfinder;
@ -29,6 +30,7 @@ use pathfinder::shaper;
use std::env;
use std::mem;
use std::os::raw::c_void;
use std::path::Path;
const ATLAS_SIZE: u32 = 2048;
const WIDTH: u32 = 640;
@ -47,6 +49,8 @@ static FPS_BACKGROUND_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 0.7];
static FPS_FOREGROUND_COLOR: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
static TEXT_COLOR: [f32; 4] = [0.0, 0.0, 0.0, 1.0];
static ATLAS_DUMP_FILENAME: &'static str = "lorem-ipsum-atlas.png";
fn main() {
let mut glfw = glfw::init(glfw::LOG_ERRORS).unwrap();
glfw.window_hint(WindowHint::ContextVersion(3, 3));
@ -56,6 +60,7 @@ fn main() {
let (mut window, events) = context.expect("Couldn't create a window!");
window.make_current();
window.set_key_polling(true);
window.set_scroll_polling(true);
window.set_size_polling(true);
window.set_framebuffer_size_polling(true);
@ -155,6 +160,10 @@ fn main() {
WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
window.set_should_close(true)
}
WindowEvent::Key(Key::S, _, Action::Press, _) => {
renderer.take_screenshot();
println!("wrote screenshot to: {}", ATLAS_DUMP_FILENAME);
}
WindowEvent::Scroll(x, y) => {
if window.get_key(Key::LeftAlt) == Action::Press ||
window.get_key(Key::RightAlt) == Action::Press {
@ -611,6 +620,36 @@ impl Renderer {
FPS_DISPLAY_POINT_SIZE,
&FPS_FOREGROUND_COLOR);
}
fn take_screenshot(&self) {
unsafe {
let mut fbo = 0;
gl::GenFramebuffers(1, &mut fbo);
gl::BindFramebuffer(gl::FRAMEBUFFER, fbo);
gl::FramebufferTexture2D(gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_RECTANGLE,
self.main_gl_texture,
0);
let length = 4 * self.atlas_size.width as usize * self.atlas_size.height as usize;
let mut pixels: Vec<u8> = vec![0; length];
gl::ReadPixels(0, 0,
self.atlas_size.width as GLint, self.atlas_size.height as GLint,
gl::RGBA,
gl::UNSIGNED_BYTE,
pixels.as_mut_ptr() as *mut c_void);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::DeleteFramebuffers(1, &mut fbo);
image::save_buffer(&Path::new(ATLAS_DUMP_FILENAME),
&pixels,
self.atlas_size.width,
self.atlas_size.height,
image::RGBA(8)).unwrap();
}
}
}
#[derive(Clone, Copy, Debug)]

View File

@ -32,12 +32,15 @@ impl Atlas {
}
pub fn place(&mut self, size: &Size2D<u32>) -> Result<Point2D<u32>, ()> {
// Add a one-pixel border to prevent bleed.
let alloc_size = *size + Size2D::new(2, 2);
let chosen_index_and_rect =
self.free_rects
.iter()
.enumerate()
.filter(|&(_, rect)| {
size.width <= rect.size.width && size.height <= rect.size.height
alloc_size.width <= rect.size.width && alloc_size.height <= rect.size.height
})
.min_by(|&(_, a), &(_, b)| area(a).cmp(&area(b)))
.map(|(index, rect)| (index, *rect));
@ -59,16 +62,17 @@ impl Atlas {
// 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));
Rect::new(Point2D::new(chosen_rect.origin.x, chosen_rect.origin.y + alloc_size.height),
Size2D::new(alloc_size.width, chosen_rect.size.height - alloc_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));
Rect::new(Point2D::new(chosen_rect.origin.x + alloc_size.width, chosen_rect.origin.y),
Size2D::new(chosen_rect.size.width - alloc_size.width,
chosen_rect.size.height));
if !free_to_right.is_empty() {
self.free_rects.push(free_to_right);
}
@ -79,7 +83,8 @@ impl Atlas {
self.width_of_last_shelf = chosen_rect.max_x()
}
Ok(chosen_rect.origin)
let object_origin = chosen_rect.origin + Point2D::new(1, 1);
Ok(object_origin)
}
#[inline]