Implement batch creation

This commit is contained in:
Patrick Walton 2017-01-10 13:37:01 -08:00
parent 941aaea676
commit d59bafced1
3 changed files with 122 additions and 34 deletions

View File

@ -8,6 +8,79 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use atlas::Atlas;
use compute_shader::buffer::{Buffer, BufferData, HostAllocatedData, Protection};
use compute_shader::device::Device;
use glyph_buffer::GlyphBufferBuilder;
use std::u16;
const POINTS_PER_SEGMENT: u32 = 32;
pub struct BatchBuilder {
pub atlas: Atlas,
pub indices: Vec<u16>,
pub images: Vec<ImageDescriptor>,
pub point_count: u32,
}
impl BatchBuilder {
/// FIXME(pcwalton): Including the shelf height here may be a bad API.
#[inline]
pub fn new(available_width: u32, shelf_height: u32) -> BatchBuilder {
BatchBuilder {
atlas: Atlas::new(available_width, shelf_height),
indices: vec![],
images: vec![],
point_count: 0,
}
}
pub fn add_glyph(&mut self,
glyph_buffer_builder: &GlyphBufferBuilder,
glyph_index: u32,
point_size: f32)
-> Result<(), ()> {
let descriptor = &glyph_buffer_builder.descriptors[glyph_index as usize];
// FIXME(pcwalton): I think this will check for negative values and panic, which is
// unnecessary.
let pixel_size = descriptor.pixel_rect(point_size).size.ceil().cast().unwrap();
let atlas_origin = try!(self.atlas.place(&pixel_size));
if self.point_count % POINTS_PER_SEGMENT == 0 {
self.indices.push(self.images.len() as u16)
}
self.images.push(ImageDescriptor {
atlas_x: atlas_origin.x,
atlas_y: atlas_origin.y,
point_size: point_size,
glyph_index: glyph_index,
start_point_in_glyph: descriptor.start_point,
start_point_in_batch: self.point_count,
point_count: descriptor.point_count as u32,
});
self.point_count += descriptor.point_count as u32;
Ok(())
}
pub fn finish(&mut self, device: &mut Device) -> Result<Batch, ()> {
let indices = BufferData::HostAllocated(HostAllocatedData::new(&self.indices));
let images = BufferData::HostAllocated(HostAllocatedData::new(&self.images));
Ok(Batch {
indices: try!(device.create_buffer(Protection::ReadOnly, indices).map_err(drop)),
images: try!(device.create_buffer(Protection::ReadOnly, images).map_err(drop)),
})
}
}
pub struct Batch {
pub indices: Buffer,
pub images: Buffer,
}
#[derive(Clone, Copy, Debug)]
pub struct GlyphRange {
pub start: u16,
@ -45,22 +118,15 @@ impl Iterator for GlyphRangeIter {
}
}
#[derive(Clone, Debug)]
pub struct FontGlyphRange {
pub font_id: u32,
pub ranges: Vec<GlyphRange>,
}
#[derive(Clone)]
pub struct FontGlyphRanges {
pub fonts: Vec<FontGlyphRange>,
}
impl FontGlyphRanges {
pub fn new() -> FontGlyphRanges {
FontGlyphRanges {
fonts: vec![],
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct ImageDescriptor {
atlas_x: u32,
atlas_y: u32,
point_size: f32,
glyph_index: u32,
start_point_in_glyph: u32,
start_point_in_batch: u32,
point_count: u32,
}

View File

@ -8,38 +8,30 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use compute_shader::buffer::Buffer;
use compute_shader::buffer::{Buffer, BufferData, HostAllocatedData, Protection};
use compute_shader::device::Device;
use euclid::{Point2D, Rect, Size2D};
use otf::glyf::GlyfTable;
use otf::loca::LocaTable;
pub struct GlyphBuffers {
pub struct GlyphBufferBuilder {
pub coordinates: Vec<(i16, i16)>,
pub operations: Vec<u8>,
pub descriptors: Vec<GlyphDescriptor>,
pub cached_coordinates_buffer: Option<Buffer>,
pub cached_operations_buffer: Option<Buffer>,
pub cached_descriptors_buffer: Option<Buffer>,
}
impl GlyphBuffers {
impl GlyphBufferBuilder {
#[inline]
pub fn new() -> GlyphBuffers {
GlyphBuffers {
pub fn new() -> GlyphBufferBuilder {
GlyphBufferBuilder {
coordinates: vec![],
operations: vec![],
descriptors: vec![],
cached_coordinates_buffer: None,
cached_operations_buffer: None,
cached_descriptors_buffer: None,
}
}
pub fn add_glyph(&mut self, glyph_id: u32, loca_table: &LocaTable, glyf_table: &GlyfTable)
-> Result<(), ()> {
self.cached_coordinates_buffer = None;
self.cached_operations_buffer = None;
self.cached_descriptors_buffer = None;
let mut point_index = self.coordinates.len() / 2;
let mut operations = if point_index % 4 == 0 {
0
@ -70,8 +62,29 @@ impl GlyphBuffers {
self.operations.push(operations)
}
// TODO(pcwalton): Add a glyph descriptor.
Ok(())
}
pub fn finish(&self, device: &mut Device) -> Result<GlyphBuffers, ()> {
let coordinates = BufferData::HostAllocated(HostAllocatedData::new(&self.coordinates));
let operations = BufferData::HostAllocated(HostAllocatedData::new(&self.operations));
let descriptors = BufferData::HostAllocated(HostAllocatedData::new(&self.descriptors));
Ok(GlyphBuffers {
coordinates: try!(device.create_buffer(Protection::ReadOnly, coordinates)
.map_err(drop)),
operations: try!(device.create_buffer(Protection::ReadOnly, operations).map_err(drop)),
descriptors: try!(device.create_buffer(Protection::ReadOnly, descriptors)
.map_err(drop)),
})
}
}
pub struct GlyphBuffers {
pub coordinates: Buffer,
pub operations: Buffer,
pub descriptors: Buffer,
}
#[repr(C)]
@ -82,6 +95,15 @@ pub struct GlyphDescriptor {
pub height: i16,
pub units_per_em: u16,
pub point_count: u16,
pub index_of_first_point: u32,
pub start_point: u32,
}
impl GlyphDescriptor {
#[inline]
pub fn pixel_rect(&self, point_size: f32) -> Rect<f32> {
let pixels_per_unit = point_size / self.units_per_em as f32;
Rect::new(Point2D::new(self.left as f32, self.bottom as f32),
Size2D::new(self.width as f32, self.height as f32)) * pixels_per_unit
}
}

View File

@ -25,8 +25,8 @@ extern crate test;
pub mod atlas;
pub mod batch;
pub mod buffers;
pub mod charmap;
pub mod glyph_buffer;
pub mod otf;
pub mod rasterizer;
mod util;