Refactor the API to consume builders
This commit is contained in:
parent
9b6e8d1f41
commit
dcd3eefa33
|
@ -63,12 +63,9 @@ fn main() {
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
let start = time::precise_time_ns();
|
let start = time::precise_time_ns();
|
||||||
let mut last_time = start;
|
let mut last_time = start;
|
||||||
let (mut outline_builder, mut outline_buffers, mut glyph_count);
|
let (mut outlines, mut glyph_count, mut atlas);
|
||||||
let (mut atlas_builder, mut atlas);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
outline_builder = OutlineBuilder::new();
|
|
||||||
atlas_builder = AtlasBuilder::new(device_pixel_width as GLuint, shelf_height);
|
|
||||||
glyph_count = 0;
|
glyph_count = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
let font = Font::new(file.as_slice()).unwrap();
|
let font = Font::new(file.as_slice()).unwrap();
|
||||||
|
@ -76,18 +73,20 @@ fn main() {
|
||||||
|
|
||||||
let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges)
|
let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
for (glyph_index, glyph_id) in glyph_ranges.iter().enumerate() {
|
let mut outline_builder = OutlineBuilder::new();
|
||||||
|
for (_, glyph_id) in glyph_ranges.iter().enumerate() {
|
||||||
outline_builder.add_glyph(&font, glyph_id).unwrap();
|
outline_builder.add_glyph(&font, glyph_id).unwrap();
|
||||||
atlas_builder.pack_glyph(&outline_builder,
|
|
||||||
glyph_index as u32,
|
|
||||||
point_size as f32).unwrap();
|
|
||||||
glyph_count += 1
|
glyph_count += 1
|
||||||
}
|
}
|
||||||
|
outlines = outline_builder.create_buffers().unwrap();
|
||||||
|
|
||||||
|
let mut atlas_builder = AtlasBuilder::new(device_pixel_width as GLuint,
|
||||||
|
shelf_height);
|
||||||
|
for glyph_index in 0..(glyph_count as u16) {
|
||||||
|
atlas_builder.pack_glyph(&outlines, glyph_index, point_size as f32).unwrap()
|
||||||
|
}
|
||||||
|
atlas = atlas_builder.create_atlas().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
outline_buffers = outline_builder.create_buffers().unwrap();
|
|
||||||
atlas = atlas_builder.create_atlas(&outline_builder).unwrap();
|
|
||||||
|
|
||||||
let end = time::precise_time_ns();
|
let end = time::precise_time_ns();
|
||||||
results.push((end - last_time) as f64);
|
results.push((end - last_time) as f64);
|
||||||
|
@ -113,8 +112,7 @@ fn main() {
|
||||||
let mut results = vec![];
|
let mut results = vec![];
|
||||||
let start_time = time::precise_time_ns();
|
let start_time = time::precise_time_ns();
|
||||||
loop {
|
loop {
|
||||||
let events =
|
let events = rasterizer.draw_atlas(&image, &rect, &atlas, &outlines, &coverage_buffer)
|
||||||
rasterizer.draw_atlas(&image, &rect, &atlas, &outline_buffers, &coverage_buffer)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut draw_time = 0u64;
|
let mut draw_time = 0u64;
|
||||||
|
|
|
@ -58,22 +58,25 @@ fn main() {
|
||||||
// FIXME(pcwalton)
|
// FIXME(pcwalton)
|
||||||
let shelf_height = (point_size * 2.0).ceil() as u32;
|
let shelf_height = (point_size * 2.0).ceil() as u32;
|
||||||
|
|
||||||
let mut outline_builder = OutlineBuilder::new();
|
|
||||||
let mut atlas_builder = AtlasBuilder::new(device_pixel_width as GLuint, shelf_height);
|
|
||||||
|
|
||||||
|
let (outlines, atlas);
|
||||||
unsafe {
|
unsafe {
|
||||||
let font = Font::new(file.as_slice()).unwrap();
|
let font = Font::new(file.as_slice()).unwrap();
|
||||||
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
|
let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)];
|
||||||
|
|
||||||
let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
|
let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges).unwrap();
|
||||||
|
|
||||||
|
let mut outline_builder = OutlineBuilder::new();
|
||||||
for (glyph_index, glyph_id) in glyph_ranges.iter().enumerate() {
|
for (glyph_index, glyph_id) in glyph_ranges.iter().enumerate() {
|
||||||
outline_builder.add_glyph(&font, glyph_id).unwrap();
|
outline_builder.add_glyph(&font, glyph_id).unwrap();
|
||||||
atlas_builder.pack_glyph(&outline_builder, glyph_index as u32, point_size).unwrap()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
outlines = outline_builder.create_buffers().unwrap();
|
||||||
|
|
||||||
let outline_buffers = outline_builder.create_buffers().unwrap();
|
let mut atlas_builder = AtlasBuilder::new(device_pixel_width as GLuint, shelf_height);
|
||||||
let atlas = atlas_builder.create_atlas(&outline_builder).unwrap();
|
for (glyph_index, glyph_id) in glyph_ranges.iter().enumerate() {
|
||||||
|
atlas_builder.pack_glyph(&outlines, glyph_index as u16, point_size).unwrap();
|
||||||
|
}
|
||||||
|
atlas = atlas_builder.create_atlas().unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
let atlas_size = Size2D::new(device_pixel_width as GLuint, device_pixel_height as GLuint);
|
let atlas_size = Size2D::new(device_pixel_width as GLuint, device_pixel_height as GLuint);
|
||||||
let coverage_buffer = CoverageBuffer::new(&rasterizer.device, &atlas_size).unwrap();
|
let coverage_buffer = CoverageBuffer::new(&rasterizer.device, &atlas_size).unwrap();
|
||||||
|
@ -84,7 +87,7 @@ fn main() {
|
||||||
|
|
||||||
let rect = Rect::new(Point2D::new(0, 0), atlas_size);
|
let rect = Rect::new(Point2D::new(0, 0), atlas_size);
|
||||||
|
|
||||||
rasterizer.draw_atlas(&image, &rect, &atlas, &outline_buffers, &coverage_buffer).unwrap();
|
rasterizer.draw_atlas(&image, &rect, &atlas, &outlines, &coverage_buffer).unwrap();
|
||||||
rasterizer.queue.flush().unwrap();
|
rasterizer.queue.flush().unwrap();
|
||||||
|
|
||||||
let draw_context = lord_drawquaad::Context::new();
|
let draw_context = lord_drawquaad::Context::new();
|
||||||
|
|
|
@ -19,12 +19,12 @@ use euclid::{Point2D, Rect, Size2D};
|
||||||
use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
||||||
use glfw::{Action, Context, Key, OpenGlProfileHint, WindowEvent, WindowHint, WindowMode};
|
use glfw::{Action, Context, Key, OpenGlProfileHint, WindowEvent, WindowHint, WindowMode};
|
||||||
use memmap::{Mmap, Protection};
|
use memmap::{Mmap, Protection};
|
||||||
use pathfinder::atlas::AtlasBuilder;
|
use pathfinder::atlas::{Atlas, AtlasBuilder};
|
||||||
use pathfinder::charmap::CodepointRanges;
|
use pathfinder::charmap::CodepointRanges;
|
||||||
use pathfinder::coverage::CoverageBuffer;
|
use pathfinder::coverage::CoverageBuffer;
|
||||||
use pathfinder::glyph_range::GlyphRanges;
|
use pathfinder::glyph_range::GlyphRanges;
|
||||||
use pathfinder::otf::Font;
|
use pathfinder::otf::Font;
|
||||||
use pathfinder::outline::{OutlineBuffers, OutlineBuilder};
|
use pathfinder::outline::{OutlineBuilder, Outlines};
|
||||||
use pathfinder::rasterizer::{DrawAtlasProfilingEvents, Rasterizer, RasterizerOptions};
|
use pathfinder::rasterizer::{DrawAtlasProfilingEvents, Rasterizer, RasterizerOptions};
|
||||||
use pathfinder::shaper;
|
use pathfinder::shaper;
|
||||||
use std::char;
|
use std::char;
|
||||||
|
@ -136,25 +136,28 @@ fn main() {
|
||||||
let mut dirty = true;
|
let mut dirty = true;
|
||||||
|
|
||||||
let mut outline_builder = OutlineBuilder::new();
|
let mut outline_builder = OutlineBuilder::new();
|
||||||
|
let mut glyph_indices = vec![];
|
||||||
let mut glyph_count = 0;
|
let mut glyph_count = 0;
|
||||||
for glyph_id in glyph_ranges.iter() {
|
for glyph_id in glyph_ranges.iter() {
|
||||||
outline_builder.add_glyph(&font, glyph_id).unwrap();
|
let glyph_index = outline_builder.add_glyph(&font, glyph_id).unwrap();
|
||||||
|
|
||||||
|
while glyph_id as usize >= glyph_indices.len() {
|
||||||
|
glyph_indices.push(0)
|
||||||
|
}
|
||||||
|
glyph_indices[glyph_id as usize] = glyph_index;
|
||||||
|
|
||||||
glyph_count += 1
|
glyph_count += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
let outline_buffers = outline_builder.create_buffers().unwrap();
|
let outlines = outline_builder.create_buffers().unwrap();
|
||||||
|
let fps_atlas = renderer.create_fps_atlas(&font, &outlines, glyph_count);
|
||||||
let mut fps_atlas = renderer.create_fps_atlas(&font,
|
|
||||||
&outline_builder,
|
|
||||||
&outline_buffers,
|
|
||||||
glyph_count);
|
|
||||||
|
|
||||||
while !window.should_close() {
|
while !window.should_close() {
|
||||||
if dirty {
|
if dirty {
|
||||||
let events = renderer.redraw(point_size,
|
let events = renderer.redraw(point_size,
|
||||||
&font,
|
&font,
|
||||||
&outline_builder,
|
&outlines,
|
||||||
&outline_buffers,
|
&glyph_indices,
|
||||||
glyph_count,
|
glyph_count,
|
||||||
&glyph_positions,
|
&glyph_positions,
|
||||||
&device_pixel_size,
|
&device_pixel_size,
|
||||||
|
@ -170,9 +173,10 @@ fn main() {
|
||||||
let timing = renderer.get_timing_in_ms();
|
let timing = renderer.get_timing_in_ms();
|
||||||
|
|
||||||
renderer.draw_fps(&font,
|
renderer.draw_fps(&font,
|
||||||
&mut fps_atlas,
|
&fps_atlas,
|
||||||
&outline_builder,
|
&outlines,
|
||||||
&device_pixel_size,
|
&device_pixel_size,
|
||||||
|
&glyph_indices,
|
||||||
&glyph_ranges,
|
&glyph_ranges,
|
||||||
draw_time,
|
draw_time,
|
||||||
accum_time,
|
accum_time,
|
||||||
|
@ -407,8 +411,8 @@ impl Renderer {
|
||||||
fn redraw(&self,
|
fn redraw(&self,
|
||||||
point_size: f32,
|
point_size: f32,
|
||||||
font: &Font,
|
font: &Font,
|
||||||
outline_builder: &OutlineBuilder,
|
outlines: &Outlines,
|
||||||
outline_buffers: &OutlineBuffers,
|
glyph_indices: &[u16],
|
||||||
glyph_count: usize,
|
glyph_count: usize,
|
||||||
glyph_positions: &[GlyphPos],
|
glyph_positions: &[GlyphPos],
|
||||||
device_pixel_size: &Size2D<u32>,
|
device_pixel_size: &Size2D<u32>,
|
||||||
|
@ -416,18 +420,18 @@ impl Renderer {
|
||||||
-> DrawAtlasProfilingEvents {
|
-> DrawAtlasProfilingEvents {
|
||||||
let shelf_height = font.shelf_height(point_size);
|
let shelf_height = font.shelf_height(point_size);
|
||||||
let mut atlas_builder = AtlasBuilder::new(ATLAS_SIZE, shelf_height);
|
let mut atlas_builder = AtlasBuilder::new(ATLAS_SIZE, shelf_height);
|
||||||
for glyph_index in 0..(glyph_count as u32) {
|
for glyph_index in 0..(glyph_count as u16) {
|
||||||
atlas_builder.pack_glyph(&outline_builder, glyph_index, point_size).unwrap()
|
atlas_builder.pack_glyph(&outlines, glyph_index, point_size).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
let atlas = atlas_builder.create_atlas(&outline_builder).unwrap();
|
let atlas = atlas_builder.create_atlas().unwrap();
|
||||||
|
|
||||||
let rect = Rect::new(Point2D::new(0, 0), self.atlas_size);
|
let rect = Rect::new(Point2D::new(0, 0), self.atlas_size);
|
||||||
|
|
||||||
let events = self.rasterizer.draw_atlas(&self.main_compute_image,
|
let events = self.rasterizer.draw_atlas(&self.main_compute_image,
|
||||||
&rect,
|
&rect,
|
||||||
&atlas,
|
&atlas,
|
||||||
outline_buffers,
|
outlines,
|
||||||
&self.main_coverage_buffer).unwrap();
|
&self.main_coverage_buffer).unwrap();
|
||||||
self.rasterizer.queue.flush().unwrap();
|
self.rasterizer.queue.flush().unwrap();
|
||||||
|
|
||||||
|
@ -441,9 +445,10 @@ impl Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw_glyphs(&font,
|
self.draw_glyphs(&font,
|
||||||
&mut atlas_builder,
|
&atlas,
|
||||||
outline_builder,
|
outlines,
|
||||||
&self.main_composite_vertex_array,
|
&self.main_composite_vertex_array,
|
||||||
|
glyph_indices,
|
||||||
glyph_positions,
|
glyph_positions,
|
||||||
device_pixel_size,
|
device_pixel_size,
|
||||||
translation,
|
translation,
|
||||||
|
@ -464,9 +469,10 @@ impl Renderer {
|
||||||
|
|
||||||
fn draw_glyphs(&self,
|
fn draw_glyphs(&self,
|
||||||
font: &Font,
|
font: &Font,
|
||||||
atlas_builder: &mut AtlasBuilder,
|
atlas: &Atlas,
|
||||||
outline_builder: &OutlineBuilder,
|
outlines: &Outlines,
|
||||||
vertex_array: &CompositeVertexArray,
|
vertex_array: &CompositeVertexArray,
|
||||||
|
glyph_indices: &[u16],
|
||||||
glyph_positions: &[GlyphPos],
|
glyph_positions: &[GlyphPos],
|
||||||
device_pixel_size: &Size2D<u32>,
|
device_pixel_size: &Size2D<u32>,
|
||||||
translation: &Point2D<i32>,
|
translation: &Point2D<i32>,
|
||||||
|
@ -480,8 +486,9 @@ impl Renderer {
|
||||||
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vertex_array.index_buffer);
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vertex_array.index_buffer);
|
||||||
|
|
||||||
let vertex_count = self.upload_quads_for_text(font,
|
let vertex_count = self.upload_quads_for_text(font,
|
||||||
atlas_builder,
|
atlas,
|
||||||
outline_builder,
|
outlines,
|
||||||
|
glyph_indices,
|
||||||
glyph_positions,
|
glyph_positions,
|
||||||
point_size);
|
point_size);
|
||||||
|
|
||||||
|
@ -518,8 +525,9 @@ impl Renderer {
|
||||||
|
|
||||||
fn upload_quads_for_text(&self,
|
fn upload_quads_for_text(&self,
|
||||||
font: &Font,
|
font: &Font,
|
||||||
atlas_builder: &mut AtlasBuilder,
|
atlas: &Atlas,
|
||||||
outline_builder: &OutlineBuilder,
|
outlines: &Outlines,
|
||||||
|
glyph_indices: &[u16],
|
||||||
glyph_positions: &[GlyphPos],
|
glyph_positions: &[GlyphPos],
|
||||||
point_size: f32)
|
point_size: f32)
|
||||||
-> usize {
|
-> usize {
|
||||||
|
@ -527,17 +535,10 @@ impl Renderer {
|
||||||
|
|
||||||
let (mut vertices, mut indices) = (vec![], vec![]);
|
let (mut vertices, mut indices) = (vec![], vec![]);
|
||||||
for position in glyph_positions {
|
for position in glyph_positions {
|
||||||
let glyph_index = match atlas_builder.glyph_index_for(position.glyph_id) {
|
let glyph_index = glyph_indices[position.glyph_id as usize];
|
||||||
None => continue,
|
let glyph_rect_i = outlines.glyph_pixel_bounds(glyph_index, point_size);
|
||||||
Some(glyph_index) => glyph_index,
|
|
||||||
};
|
|
||||||
|
|
||||||
let glyph_rect_i = outline_builder.glyph_pixel_bounds_i(glyph_index, point_size);
|
let uv_tl: Point2D<u32> = atlas.atlas_origin(glyph_index).floor().cast().unwrap();
|
||||||
|
|
||||||
let uv_tl: Point2D<u32> = atlas_builder.atlas_origin(glyph_index)
|
|
||||||
.floor()
|
|
||||||
.cast()
|
|
||||||
.unwrap();
|
|
||||||
let uv_br = uv_tl + glyph_rect_i.size().cast().unwrap();
|
let uv_br = uv_tl + glyph_rect_i.size().cast().unwrap();
|
||||||
|
|
||||||
let bearing_pos = (position.x as f32 * pixels_per_unit).round() as i32;
|
let bearing_pos = (position.x as f32 * pixels_per_unit).round() as i32;
|
||||||
|
@ -572,37 +573,30 @@ impl Renderer {
|
||||||
indices.len()
|
indices.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_fps_atlas(&self,
|
fn create_fps_atlas(&self, font: &Font, outlines: &Outlines, glyph_count: usize) -> Atlas {
|
||||||
font: &Font,
|
|
||||||
outline_builder: &OutlineBuilder,
|
|
||||||
outline_buffers: &OutlineBuffers,
|
|
||||||
glyph_count: usize)
|
|
||||||
-> AtlasBuilder {
|
|
||||||
let shelf_height = font.shelf_height(FPS_DISPLAY_POINT_SIZE);
|
let shelf_height = font.shelf_height(FPS_DISPLAY_POINT_SIZE);
|
||||||
let mut atlas_builder = AtlasBuilder::new(ATLAS_SIZE, shelf_height);
|
let mut atlas_builder = AtlasBuilder::new(ATLAS_SIZE, shelf_height);
|
||||||
for glyph_index in 0..(glyph_count as u32) {
|
for glyph_index in 0..(glyph_count as u16) {
|
||||||
atlas_builder.pack_glyph(&outline_builder, glyph_index, FPS_DISPLAY_POINT_SIZE)
|
atlas_builder.pack_glyph(&outlines, glyph_index, FPS_DISPLAY_POINT_SIZE).unwrap()
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let atlas = atlas_builder.create_atlas(&outline_builder).unwrap();
|
let atlas = atlas_builder.create_atlas().unwrap();
|
||||||
|
|
||||||
let rect = Rect::new(Point2D::new(0, 0), self.atlas_size);
|
|
||||||
|
|
||||||
self.rasterizer.draw_atlas(&self.fps_compute_image,
|
self.rasterizer.draw_atlas(&self.fps_compute_image,
|
||||||
&rect,
|
&Rect::new(Point2D::new(0, 0), self.atlas_size),
|
||||||
&atlas,
|
&atlas,
|
||||||
outline_buffers,
|
outlines,
|
||||||
&self.fps_coverage_buffer).unwrap();
|
&self.fps_coverage_buffer).unwrap();
|
||||||
|
|
||||||
atlas_builder
|
atlas
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_fps(&self,
|
fn draw_fps(&self,
|
||||||
font: &Font,
|
font: &Font,
|
||||||
atlas_builder: &mut AtlasBuilder,
|
atlas: &Atlas,
|
||||||
outline_builder: &OutlineBuilder,
|
outlines: &Outlines,
|
||||||
device_pixel_size: &Size2D<u32>,
|
device_pixel_size: &Size2D<u32>,
|
||||||
|
glyph_indices: &[u16],
|
||||||
glyph_ranges: &GlyphRanges,
|
glyph_ranges: &GlyphRanges,
|
||||||
draw_time: f64,
|
draw_time: f64,
|
||||||
accum_time: f64,
|
accum_time: f64,
|
||||||
|
@ -658,9 +652,10 @@ impl Renderer {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.draw_glyphs(font,
|
self.draw_glyphs(font,
|
||||||
atlas_builder,
|
atlas,
|
||||||
outline_builder,
|
outlines,
|
||||||
&self.fps_composite_vertex_array,
|
&self.fps_composite_vertex_array,
|
||||||
|
glyph_indices,
|
||||||
&fps_glyphs,
|
&fps_glyphs,
|
||||||
device_pixel_size,
|
device_pixel_size,
|
||||||
&Point2D::new(FPS_PADDING, device_pixel_size.height as i32 - FPS_PADDING),
|
&Point2D::new(FPS_PADDING, device_pixel_size.height as i32 - FPS_PADDING),
|
||||||
|
|
122
src/atlas.rs
122
src/atlas.rs
|
@ -9,14 +9,12 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
//! Atlases, which hold rendered glyphs on the GPU.
|
//! Atlases, which hold rendered glyphs on the GPU.
|
||||||
//!
|
|
||||||
//! TODO(pcwalton): Make the atlas own the outline builder.
|
|
||||||
|
|
||||||
use error::GlError;
|
use error::GlError;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid};
|
||||||
use gl;
|
use gl;
|
||||||
use outline::OutlineBuilder;
|
use outline::Outlines;
|
||||||
use rect_packer::RectPacker;
|
use rect_packer::RectPacker;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::os::raw::c_void;
|
use std::os::raw::c_void;
|
||||||
|
@ -57,28 +55,25 @@ impl AtlasBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Places a glyph rendered in the outline builder into the atlas.
|
/// Places a glyph into the atlas.
|
||||||
///
|
///
|
||||||
/// The outline builder must contain the outlines for the glyph at the given index. Note that
|
/// The glyph is supplied as an *index* into the supplied outline buffer. Note that indices are
|
||||||
/// this is a glyph *index* in the outline builder, not a glyph *ID*. Glyph indices are
|
/// separate from IDs; the indices are returned from each call to
|
||||||
/// assigned sequentially starting from 0 each time you call `OutlineBuilder::add_glyph()`.
|
/// `OutlineBuilder::add_glyph()`.
|
||||||
///
|
|
||||||
/// You may not use multiple outline builders in the same
|
|
||||||
///
|
///
|
||||||
/// Returns an error if there is no space left for the glyph.
|
/// Returns an error if there is no space left for the glyph.
|
||||||
///
|
///
|
||||||
|
/// TODO(pcwalton): Support multiple outline buffers in the same atlas.
|
||||||
|
///
|
||||||
/// TODO(pcwalton): Support the same glyph drawn at multiple point sizes.
|
/// TODO(pcwalton): Support the same glyph drawn at multiple point sizes.
|
||||||
pub fn pack_glyph(&mut self,
|
pub fn pack_glyph(&mut self, outlines: &Outlines, glyph_index: u16, point_size: f32)
|
||||||
outline_builder: &OutlineBuilder,
|
|
||||||
glyph_index: u32,
|
|
||||||
point_size: f32)
|
|
||||||
-> Result<(), ()> {
|
-> Result<(), ()> {
|
||||||
let pixel_bounds_f = outline_builder.glyph_pixel_bounds_f(glyph_index, point_size);
|
let subpixel_bounds = outlines.glyph_subpixel_bounds(glyph_index, point_size);
|
||||||
let pixel_bounds_i = outline_builder.glyph_pixel_bounds_i(glyph_index, point_size);
|
let pixel_bounds = outlines.glyph_pixel_bounds(glyph_index, point_size);
|
||||||
|
|
||||||
let atlas_origin = try!(self.rect_packer.pack(&pixel_bounds_i.size().cast().unwrap()));
|
let atlas_origin = try!(self.rect_packer.pack(&pixel_bounds.size().cast().unwrap()));
|
||||||
|
|
||||||
let glyph_id = outline_builder.glyph_id(glyph_index);
|
let glyph_id = outlines.glyph_id(glyph_index);
|
||||||
let glyph_index = self.image_descriptors.len() as u32;
|
let glyph_index = self.image_descriptors.len() as u32;
|
||||||
|
|
||||||
while self.image_descriptors.len() < glyph_index as usize + 1 {
|
while self.image_descriptors.len() < glyph_index as usize + 1 {
|
||||||
|
@ -86,8 +81,8 @@ impl AtlasBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.image_descriptors[glyph_index as usize] = ImageDescriptor {
|
self.image_descriptors[glyph_index as usize] = ImageDescriptor {
|
||||||
atlas_x: atlas_origin.x as f32 + pixel_bounds_f.left.fract(),
|
atlas_x: atlas_origin.x as f32 + subpixel_bounds.left.fract(),
|
||||||
atlas_y: atlas_origin.y as f32 + (1.0 - pixel_bounds_f.top.fract()),
|
atlas_y: atlas_origin.y as f32 + (1.0 - subpixel_bounds.top.fract()),
|
||||||
point_size: point_size,
|
point_size: point_size,
|
||||||
glyph_index: glyph_index as f32,
|
glyph_index: glyph_index as f32,
|
||||||
};
|
};
|
||||||
|
@ -99,44 +94,41 @@ impl AtlasBuilder {
|
||||||
self.image_metadata[glyph_index as usize] = ImageMetadata {
|
self.image_metadata[glyph_index as usize] = ImageMetadata {
|
||||||
glyph_index: glyph_index,
|
glyph_index: glyph_index,
|
||||||
glyph_id: glyph_id,
|
glyph_id: glyph_id,
|
||||||
|
start_index: outlines.descriptors[glyph_index as usize].start_index(),
|
||||||
|
end_index: match outlines.descriptors.get(glyph_index as usize + 1) {
|
||||||
|
Some(ref descriptor) => descriptor.start_index() as u32,
|
||||||
|
None => outlines.indices_count as u32,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an atlas by uploading the atlas info to the GPU.
|
/// Creates an atlas by uploading the atlas info to the GPU.
|
||||||
///
|
pub fn create_atlas(mut self) -> Result<Atlas, GlError> {
|
||||||
/// The supplied outline builder must be the same as the outline builder passed to
|
|
||||||
/// `Atlas::pack_glyph()`.
|
|
||||||
pub fn create_atlas(&mut self, outline_builder: &OutlineBuilder) -> Result<Atlas, GlError> {
|
|
||||||
self.image_metadata.sort_by(|a, b| a.glyph_index.cmp(&b.glyph_index));
|
self.image_metadata.sort_by(|a, b| a.glyph_index.cmp(&b.glyph_index));
|
||||||
|
|
||||||
let (mut current_range, mut counts, mut start_indices) = (None, vec![], vec![]);
|
let (mut current_range, mut counts, mut start_indices) = (None, vec![], vec![]);
|
||||||
for image_metadata in &self.image_metadata {
|
for image_metadata in &self.image_metadata {
|
||||||
let glyph_index = image_metadata.glyph_index;
|
let glyph_index = image_metadata.glyph_index;
|
||||||
|
let start_index = image_metadata.start_index;
|
||||||
let first_index = outline_builder.descriptors[glyph_index as usize]
|
let end_index = image_metadata.end_index;
|
||||||
.start_index as usize;
|
|
||||||
let last_index = match outline_builder.descriptors.get(glyph_index as usize + 1) {
|
|
||||||
Some(ref descriptor) => descriptor.start_index as usize,
|
|
||||||
None => outline_builder.indices.len(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match current_range {
|
match current_range {
|
||||||
Some((current_first, current_last)) if first_index == current_last => {
|
Some((current_first, current_last)) if start_index == current_last => {
|
||||||
current_range = Some((current_first, last_index))
|
current_range = Some((current_first, end_index))
|
||||||
}
|
}
|
||||||
Some((current_first, current_last)) => {
|
Some((current_first, current_last)) => {
|
||||||
counts.push((current_last - current_first) as GLsizei);
|
counts.push((current_last - current_first) as GLsizei);
|
||||||
start_indices.push(current_first);
|
start_indices.push(current_first as usize);
|
||||||
current_range = Some((first_index, last_index))
|
current_range = Some((start_index, end_index))
|
||||||
}
|
}
|
||||||
None => current_range = Some((first_index, last_index)),
|
None => current_range = Some((start_index, end_index)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some((current_first, current_last)) = current_range {
|
if let Some((current_first, current_last)) = current_range {
|
||||||
counts.push((current_last - current_first) as GLsizei);
|
counts.push((current_last - current_first) as GLsizei);
|
||||||
start_indices.push(current_first);
|
start_indices.push(current_first as usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(pcwalton): Try using `glMapBuffer` here.
|
// TODO(pcwalton): Try using `glMapBuffer` here.
|
||||||
|
@ -150,49 +142,41 @@ impl AtlasBuilder {
|
||||||
gl::BufferData(gl::UNIFORM_BUFFER, length as GLsizeiptr, ptr, gl::DYNAMIC_DRAW);
|
gl::BufferData(gl::UNIFORM_BUFFER, length as GLsizeiptr, ptr, gl::DYNAMIC_DRAW);
|
||||||
|
|
||||||
Ok(Atlas {
|
Ok(Atlas {
|
||||||
|
images_buffer: images,
|
||||||
|
images: self.image_descriptors,
|
||||||
|
|
||||||
start_indices: start_indices,
|
start_indices: start_indices,
|
||||||
counts: counts,
|
counts: counts,
|
||||||
images: images,
|
|
||||||
|
|
||||||
shelf_height: self.rect_packer.shelf_height(),
|
shelf_height: self.rect_packer.shelf_height(),
|
||||||
shelf_columns: self.rect_packer.shelf_columns(),
|
shelf_columns: self.rect_packer.shelf_columns(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn glyph_index_for(&self, glyph_id: u16) -> Option<u32> {
|
|
||||||
match self.image_metadata.binary_search_by(|metadata| metadata.glyph_id.cmp(&glyph_id)) {
|
|
||||||
Ok(glyph_index) => Some(self.image_metadata[glyph_index].glyph_index),
|
|
||||||
Err(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn atlas_origin(&self, glyph_index: u32) -> Point2D<f32> {
|
|
||||||
let descriptor = &self.image_descriptors[glyph_index as usize];
|
|
||||||
Point2D::new(descriptor.atlas_x, descriptor.atlas_y)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An atlas holding rendered glyphs on the GPU.
|
||||||
pub struct Atlas {
|
pub struct Atlas {
|
||||||
|
images_buffer: GLuint,
|
||||||
|
images: Vec<ImageDescriptor>,
|
||||||
|
|
||||||
start_indices: Vec<usize>,
|
start_indices: Vec<usize>,
|
||||||
counts: Vec<GLsizei>,
|
counts: Vec<GLsizei>,
|
||||||
images: GLuint,
|
|
||||||
|
|
||||||
pub shelf_height: u32,
|
shelf_height: u32,
|
||||||
pub shelf_columns: u32,
|
shelf_columns: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Atlas {
|
impl Drop for Atlas {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::DeleteBuffers(1, &mut self.images);
|
gl::DeleteBuffers(1, &mut self.images_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Atlas {
|
impl Atlas {
|
||||||
|
#[doc(hidden)]
|
||||||
pub unsafe fn draw(&self, primitive: GLenum) {
|
pub unsafe fn draw(&self, primitive: GLenum) {
|
||||||
debug_assert!(self.counts.len() == self.start_indices.len());
|
debug_assert!(self.counts.len() == self.start_indices.len());
|
||||||
gl::MultiDrawElements(primitive,
|
gl::MultiDrawElements(primitive,
|
||||||
|
@ -202,9 +186,31 @@ impl Atlas {
|
||||||
self.counts.len() as GLsizei);
|
self.counts.len() as GLsizei);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the height of each shelf.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn images(&self) -> GLuint {
|
pub fn shelf_height(&self) -> u32 {
|
||||||
self.images
|
self.shelf_height
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
pub fn shelf_columns(&self) -> u32 {
|
||||||
|
self.shelf_columns
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[inline]
|
||||||
|
pub fn images_buffer(&self) -> GLuint {
|
||||||
|
self.images_buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the origin of the glyph with the given index in the atlas.
|
||||||
|
///
|
||||||
|
/// This is the subpixel origin.
|
||||||
|
#[inline]
|
||||||
|
pub fn atlas_origin(&self, glyph_index: u16) -> Point2D<f32> {
|
||||||
|
let image = &self.images[glyph_index as usize];
|
||||||
|
Point2D::new(image.atlas_x, image.atlas_y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,5 +229,7 @@ pub struct ImageDescriptor {
|
||||||
pub struct ImageMetadata {
|
pub struct ImageMetadata {
|
||||||
glyph_index: u32,
|
glyph_index: u32,
|
||||||
glyph_id: u16,
|
glyph_id: u16,
|
||||||
|
start_index: u32,
|
||||||
|
end_index: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use euclid::Point2D;
|
||||||
use otf::head::HeadTable;
|
use otf::head::HeadTable;
|
||||||
use otf::loca::LocaTable;
|
use otf::loca::LocaTable;
|
||||||
use otf::{Error, FontTable};
|
use otf::{Error, FontTable};
|
||||||
use outline::GlyphBoundsI;
|
use outline::GlyphBounds;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
@ -279,13 +279,13 @@ impl<'a> GlyfTable<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn glyph_bounds(&self, head_table: &HeadTable, loca_table: &LocaTable, glyph_id: u16)
|
pub fn glyph_bounds(&self, head_table: &HeadTable, loca_table: &LocaTable, glyph_id: u16)
|
||||||
-> Result<GlyphBoundsI, Error> {
|
-> Result<GlyphBounds, Error> {
|
||||||
let mut reader = self.table.bytes;
|
let mut reader = self.table.bytes;
|
||||||
|
|
||||||
match try!(loca_table.location_of(head_table, glyph_id)) {
|
match try!(loca_table.location_of(head_table, glyph_id)) {
|
||||||
None => {
|
None => {
|
||||||
// No outlines.
|
// No outlines.
|
||||||
return Ok(GlyphBoundsI {
|
return Ok(GlyphBounds {
|
||||||
left: 0,
|
left: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
|
@ -302,7 +302,7 @@ impl<'a> GlyfTable<'a> {
|
||||||
let y_min = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
let y_min = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let x_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
let x_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let y_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
let y_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
Ok(GlyphBoundsI {
|
Ok(GlyphBounds {
|
||||||
left: x_min as i32,
|
left: x_min as i32,
|
||||||
bottom: y_min as i32,
|
bottom: y_min as i32,
|
||||||
right: x_max as i32,
|
right: x_max as i32,
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
use otf::{Error, FontTable};
|
use otf::{Error, FontTable};
|
||||||
use outline::GlyphBoundsI;
|
use outline::GlyphBounds;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ const MAGIC_NUMBER: u32 = 0x5f0f3cf5;
|
||||||
pub struct HeadTable {
|
pub struct HeadTable {
|
||||||
pub units_per_em: u16,
|
pub units_per_em: u16,
|
||||||
pub index_to_loc_format: i16,
|
pub index_to_loc_format: i16,
|
||||||
pub max_glyph_bounds: GlyphBoundsI,
|
pub max_glyph_bounds: GlyphBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeadTable {
|
impl HeadTable {
|
||||||
|
@ -51,7 +51,7 @@ impl HeadTable {
|
||||||
let y_min = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
let y_min = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let x_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
let x_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let y_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
let y_max = try!(reader.read_i16::<BigEndian>().map_err(Error::eof));
|
||||||
let max_glyph_bounds = GlyphBoundsI {
|
let max_glyph_bounds = GlyphBounds {
|
||||||
left: x_min as i32,
|
left: x_min as i32,
|
||||||
bottom: y_min as i32,
|
bottom: y_min as i32,
|
||||||
right: x_max as i32,
|
right: x_max as i32,
|
||||||
|
|
|
@ -19,7 +19,7 @@ use otf::head::HeadTable;
|
||||||
use otf::hhea::HheaTable;
|
use otf::hhea::HheaTable;
|
||||||
use otf::hmtx::{HmtxTable, HorizontalMetrics};
|
use otf::hmtx::{HmtxTable, HorizontalMetrics};
|
||||||
use otf::loca::LocaTable;
|
use otf::loca::LocaTable;
|
||||||
use outline::GlyphBoundsI;
|
use outline::GlyphBounds;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::u16;
|
use std::u16;
|
||||||
use util::Jump;
|
use util::Jump;
|
||||||
|
@ -299,7 +299,7 @@ impl<'a> Font<'a> {
|
||||||
|
|
||||||
/// Returns the boundaries of the given glyph in font units.
|
/// Returns the boundaries of the given glyph in font units.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn glyph_bounds(&self, glyph_id: u16) -> Result<GlyphBoundsI, Error> {
|
pub fn glyph_bounds(&self, glyph_id: u16) -> Result<GlyphBounds, Error> {
|
||||||
match self.glyf {
|
match self.glyf {
|
||||||
Some(glyf) => {
|
Some(glyf) => {
|
||||||
let loca = match self.loca {
|
let loca = match self.loca {
|
||||||
|
@ -319,8 +319,8 @@ impl<'a> Font<'a> {
|
||||||
// Add 2 to account for the border.
|
// Add 2 to account for the border.
|
||||||
self.head
|
self.head
|
||||||
.max_glyph_bounds
|
.max_glyph_bounds
|
||||||
.pixel_rect_f(self.head.units_per_em, point_size)
|
.subpixel_bounds(self.head.units_per_em, point_size)
|
||||||
.to_i()
|
.round_out()
|
||||||
.size()
|
.size()
|
||||||
.height as u32 + 2
|
.height as u32 + 2
|
||||||
}
|
}
|
||||||
|
|
140
src/outline.rs
140
src/outline.rs
|
@ -8,6 +8,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Glyph vectors, uploaded in a resolution-independent manner to the GPU.
|
||||||
|
|
||||||
use error::GlError;
|
use error::GlError;
|
||||||
use euclid::{Point2D, Rect, Size2D};
|
use euclid::{Point2D, Rect, Size2D};
|
||||||
use gl::types::{GLsizeiptr, GLuint};
|
use gl::types::{GLsizeiptr, GLuint};
|
||||||
|
@ -80,31 +82,7 @@ impl OutlineBuilder {
|
||||||
Ok(glyph_index)
|
Ok(glyph_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the glyph rectangle in units.
|
pub fn create_buffers(self) -> Result<Outlines, GlError> {
|
||||||
#[inline]
|
|
||||||
pub fn glyph_bounds(&self, glyph_index: u32) -> GlyphBoundsI {
|
|
||||||
self.descriptors[glyph_index as usize].bounds
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the glyph rectangle in fractional pixels.
|
|
||||||
#[inline]
|
|
||||||
pub fn glyph_pixel_bounds_f(&self, glyph_index: u32, point_size: f32) -> GlyphBoundsF {
|
|
||||||
self.descriptors[glyph_index as usize].pixel_rect_f(point_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the glyph rectangle, rounded out to the nearest pixel.
|
|
||||||
#[inline]
|
|
||||||
pub fn glyph_pixel_bounds_i(&self, glyph_index: u32, point_size: f32) -> GlyphBoundsI {
|
|
||||||
self.descriptors[glyph_index as usize].pixel_rect_i(point_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the ID of the glyph with the given index.
|
|
||||||
#[inline]
|
|
||||||
pub fn glyph_id(&self, glyph_index: u32) -> u16 {
|
|
||||||
self.descriptors[glyph_index as usize].glyph_id
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_buffers(&self) -> Result<OutlineBuffers, GlError> {
|
|
||||||
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and
|
// TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and
|
||||||
// counts.
|
// counts.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -132,50 +110,83 @@ impl OutlineBuilder {
|
||||||
self.descriptors.as_ptr() as *const GlyphDescriptor as *const c_void,
|
self.descriptors.as_ptr() as *const GlyphDescriptor as *const c_void,
|
||||||
gl::STATIC_DRAW);
|
gl::STATIC_DRAW);
|
||||||
|
|
||||||
Ok(OutlineBuffers {
|
Ok(Outlines {
|
||||||
vertices: vertices,
|
vertices_buffer: vertices,
|
||||||
indices: indices,
|
indices_buffer: indices,
|
||||||
descriptors: descriptors,
|
descriptors_buffer: descriptors,
|
||||||
|
descriptors: self.descriptors,
|
||||||
|
indices_count: self.indices.len(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OutlineBuffers {
|
pub struct Outlines {
|
||||||
pub vertices: GLuint,
|
pub vertices_buffer: GLuint,
|
||||||
pub indices: GLuint,
|
pub indices_buffer: GLuint,
|
||||||
pub descriptors: GLuint,
|
pub descriptors_buffer: GLuint,
|
||||||
|
pub descriptors: Vec<GlyphDescriptor>,
|
||||||
|
pub indices_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for OutlineBuffers {
|
impl Drop for Outlines {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
gl::DeleteBuffers(1, &mut self.descriptors);
|
gl::DeleteBuffers(1, &mut self.descriptors_buffer);
|
||||||
gl::DeleteBuffers(1, &mut self.indices);
|
gl::DeleteBuffers(1, &mut self.indices_buffer);
|
||||||
gl::DeleteBuffers(1, &mut self.vertices);
|
gl::DeleteBuffers(1, &mut self.vertices_buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Outlines {
|
||||||
|
/// Returns the glyph rectangle in font units.
|
||||||
|
#[inline]
|
||||||
|
pub fn glyph_bounds(&self, glyph_index: u32) -> GlyphBounds {
|
||||||
|
self.descriptors[glyph_index as usize].bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the glyph rectangle in fractional pixels.
|
||||||
|
#[inline]
|
||||||
|
pub fn glyph_subpixel_bounds(&self, glyph_index: u16, point_size: f32) -> GlyphSubpixelBounds {
|
||||||
|
self.descriptors[glyph_index as usize].subpixel_bounds(point_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the boundaries of the glyph, rounded out to the nearest pixel.
|
||||||
|
#[inline]
|
||||||
|
pub fn glyph_pixel_bounds(&self, glyph_index: u16, point_size: f32) -> GlyphPixelBounds {
|
||||||
|
self.descriptors[glyph_index as usize].subpixel_bounds(point_size).round_out()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the ID of the glyph with the given index.
|
||||||
|
#[inline]
|
||||||
|
pub fn glyph_id(&self, glyph_index: u16) -> u16 {
|
||||||
|
self.descriptors[glyph_index as usize].glyph_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct GlyphDescriptor {
|
pub struct GlyphDescriptor {
|
||||||
pub bounds: GlyphBoundsI,
|
bounds: GlyphBounds,
|
||||||
pub units_per_em: u32,
|
units_per_em: u32,
|
||||||
pub start_point: u32,
|
start_point: u32,
|
||||||
pub start_index: u32,
|
start_index: u32,
|
||||||
pub glyph_id: u16,
|
glyph_id: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlyphDescriptor {
|
impl GlyphDescriptor {
|
||||||
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pixel_rect_f(&self, point_size: f32) -> GlyphBoundsF {
|
pub fn start_index(&self) -> u32 {
|
||||||
self.bounds.pixel_rect_f(self.units_per_em as u16, point_size)
|
self.start_index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn pixel_rect_i(&self, point_size: f32) -> GlyphBoundsI {
|
fn subpixel_bounds(&self, point_size: f32) -> GlyphSubpixelBounds {
|
||||||
self.bounds.pixel_rect_f(self.units_per_em as u16, point_size).to_i()
|
self.bounds.subpixel_bounds(self.units_per_em as u16, point_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,18 +200,20 @@ pub struct Vertex {
|
||||||
pub glyph_index: u16,
|
pub glyph_index: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The boundaries of the glyph in fractional pixels.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct GlyphBoundsF {
|
pub struct GlyphSubpixelBounds {
|
||||||
pub left: f32,
|
pub left: f32,
|
||||||
pub bottom: f32,
|
pub bottom: f32,
|
||||||
pub right: f32,
|
pub right: f32,
|
||||||
pub top: f32,
|
pub top: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlyphBoundsF {
|
impl GlyphSubpixelBounds {
|
||||||
|
/// Rounds these bounds out to the nearest pixel.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_i(&self) -> GlyphBoundsI {
|
pub fn round_out(&self) -> GlyphPixelBounds {
|
||||||
GlyphBoundsI {
|
GlyphPixelBounds {
|
||||||
left: self.left.floor() as i32,
|
left: self.left.floor() as i32,
|
||||||
bottom: self.bottom.floor() as i32,
|
bottom: self.bottom.floor() as i32,
|
||||||
right: self.right.ceil() as i32,
|
right: self.right.ceil() as i32,
|
||||||
|
@ -208,25 +221,43 @@ impl GlyphBoundsF {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the total size of the glyph in fractional pixels.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> Size2D<f32> {
|
pub fn size(&self) -> Size2D<f32> {
|
||||||
Size2D::new(self.right - self.left, self.top - self.bottom)
|
Size2D::new(self.right - self.left, self.top - self.bottom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The boundaries of the glyph, rounded out to the nearest pixel.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct GlyphBoundsI {
|
pub struct GlyphPixelBounds {
|
||||||
pub left: i32,
|
pub left: i32,
|
||||||
pub bottom: i32,
|
pub bottom: i32,
|
||||||
pub right: i32,
|
pub right: i32,
|
||||||
pub top: i32,
|
pub top: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlyphBoundsI {
|
impl GlyphPixelBounds {
|
||||||
|
/// Returns the total size of the glyph in whole pixels.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pixel_rect_f(&self, units_per_em: u16, point_size: f32) -> GlyphBoundsF {
|
pub fn size(&self) -> Size2D<i32> {
|
||||||
|
Size2D::new(self.right - self.left, self.top - self.bottom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct GlyphBounds {
|
||||||
|
pub left: i32,
|
||||||
|
pub bottom: i32,
|
||||||
|
pub right: i32,
|
||||||
|
pub top: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GlyphBounds {
|
||||||
|
#[inline]
|
||||||
|
pub fn subpixel_bounds(&self, units_per_em: u16, point_size: f32) -> GlyphSubpixelBounds {
|
||||||
let pixels_per_unit = point_size / units_per_em as f32;
|
let pixels_per_unit = point_size / units_per_em as f32;
|
||||||
GlyphBoundsF {
|
GlyphSubpixelBounds {
|
||||||
left: self.left as f32 * pixels_per_unit,
|
left: self.left as f32 * pixels_per_unit,
|
||||||
bottom: self.bottom as f32 * pixels_per_unit,
|
bottom: self.bottom as f32 * pixels_per_unit,
|
||||||
right: self.right as f32 * pixels_per_unit,
|
right: self.right as f32 * pixels_per_unit,
|
||||||
|
@ -234,6 +265,7 @@ impl GlyphBoundsI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the total size of the glyph in font units.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn size(&self) -> Size2D<i32> {
|
pub fn size(&self) -> Size2D<i32> {
|
||||||
Size2D::new(self.right - self.left, self.top - self.bottom)
|
Size2D::new(self.right - self.left, self.top - self.bottom)
|
||||||
|
|
|
@ -20,7 +20,7 @@ use error::{InitError, RasterError};
|
||||||
use euclid::rect::Rect;
|
use euclid::rect::Rect;
|
||||||
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint, GLvoid};
|
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint, GLvoid};
|
||||||
use gl;
|
use gl;
|
||||||
use outline::{OutlineBuffers, Vertex};
|
use outline::{Outlines, Vertex};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -148,7 +148,7 @@ impl Rasterizer {
|
||||||
image: &Image,
|
image: &Image,
|
||||||
rect: &Rect<u32>,
|
rect: &Rect<u32>,
|
||||||
atlas: &Atlas,
|
atlas: &Atlas,
|
||||||
outline_buffers: &OutlineBuffers,
|
outlines: &Outlines,
|
||||||
coverage_buffer: &CoverageBuffer)
|
coverage_buffer: &CoverageBuffer)
|
||||||
-> Result<DrawAtlasProfilingEvents, RasterError> {
|
-> Result<DrawAtlasProfilingEvents, RasterError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -163,7 +163,7 @@ impl Rasterizer {
|
||||||
gl::UseProgram(self.draw_program);
|
gl::UseProgram(self.draw_program);
|
||||||
|
|
||||||
// Set up the buffer layout.
|
// Set up the buffer layout.
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, outline_buffers.vertices);
|
gl::BindBuffer(gl::ARRAY_BUFFER, outlines.vertices_buffer);
|
||||||
gl::VertexAttribIPointer(self.draw_position_attribute as GLuint,
|
gl::VertexAttribIPointer(self.draw_position_attribute as GLuint,
|
||||||
2,
|
2,
|
||||||
gl::SHORT,
|
gl::SHORT,
|
||||||
|
@ -177,10 +177,10 @@ impl Rasterizer {
|
||||||
gl::EnableVertexAttribArray(self.draw_position_attribute as GLuint);
|
gl::EnableVertexAttribArray(self.draw_position_attribute as GLuint);
|
||||||
gl::EnableVertexAttribArray(self.draw_glyph_index_attribute as GLuint);
|
gl::EnableVertexAttribArray(self.draw_glyph_index_attribute as GLuint);
|
||||||
|
|
||||||
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, outline_buffers.indices);
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, outlines.indices_buffer);
|
||||||
|
|
||||||
gl::BindBufferBase(gl::UNIFORM_BUFFER, 1, outline_buffers.descriptors);
|
gl::BindBufferBase(gl::UNIFORM_BUFFER, 1, outlines.descriptors_buffer);
|
||||||
gl::BindBufferBase(gl::UNIFORM_BUFFER, 2, atlas.images());
|
gl::BindBufferBase(gl::UNIFORM_BUFFER, 2, atlas.images_buffer());
|
||||||
gl::UniformBlockBinding(self.draw_program, self.draw_glyph_descriptors_uniform, 1);
|
gl::UniformBlockBinding(self.draw_program, self.draw_glyph_descriptors_uniform, 1);
|
||||||
gl::UniformBlockBinding(self.draw_program, self.draw_image_descriptors_uniform, 2);
|
gl::UniformBlockBinding(self.draw_program, self.draw_image_descriptors_uniform, 2);
|
||||||
|
|
||||||
|
@ -226,11 +226,11 @@ impl Rasterizer {
|
||||||
(0, Uniform::Image(image)),
|
(0, Uniform::Image(image)),
|
||||||
(1, Uniform::Image(coverage_buffer.image())),
|
(1, Uniform::Image(coverage_buffer.image())),
|
||||||
(2, Uniform::UVec4([rect.origin.x, rect.origin.y, rect.max_x(), rect.max_y()])),
|
(2, Uniform::UVec4([rect.origin.x, rect.origin.y, rect.max_x(), rect.max_y()])),
|
||||||
(3, Uniform::U32(atlas.shelf_height)),
|
(3, Uniform::U32(atlas.shelf_height())),
|
||||||
];
|
];
|
||||||
|
|
||||||
let accum_event = try!(self.queue.submit_compute(&self.accum_program,
|
let accum_event = try!(self.queue.submit_compute(&self.accum_program,
|
||||||
&[atlas.shelf_columns],
|
&[atlas.shelf_columns()],
|
||||||
&accum_uniforms,
|
&accum_uniforms,
|
||||||
&[]).map_err(RasterError::ComputeError));
|
&[]).map_err(RasterError::ComputeError));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue