diff --git a/examples/benchmark.rs b/examples/benchmark.rs index 3ef0765d..5e9d107c 100644 --- a/examples/benchmark.rs +++ b/examples/benchmark.rs @@ -63,12 +63,9 @@ fn main() { let mut results = vec![]; let start = time::precise_time_ns(); let mut last_time = start; - let (mut outline_builder, mut outline_buffers, mut glyph_count); - let (mut atlas_builder, mut atlas); + let (mut outlines, mut glyph_count, mut atlas); loop { - outline_builder = OutlineBuilder::new(); - atlas_builder = AtlasBuilder::new(device_pixel_width as GLuint, shelf_height); glyph_count = 0; unsafe { let font = Font::new(file.as_slice()).unwrap(); @@ -76,19 +73,21 @@ fn main() { let glyph_ranges = font.glyph_ranges_for_codepoint_ranges(&codepoint_ranges) .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(); - atlas_builder.pack_glyph(&outline_builder, - glyph_index as u32, - point_size as f32).unwrap(); 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(); results.push((end - last_time) as f64); if end - start > MAX_TIME_PER_SIZE { @@ -113,9 +112,8 @@ fn main() { let mut results = vec![]; let start_time = time::precise_time_ns(); loop { - let events = - rasterizer.draw_atlas(&image, &rect, &atlas, &outline_buffers, &coverage_buffer) - .unwrap(); + let events = rasterizer.draw_atlas(&image, &rect, &atlas, &outlines, &coverage_buffer) + .unwrap(); let mut draw_time = 0u64; unsafe { diff --git a/examples/generate-atlas.rs b/examples/generate-atlas.rs index 7777e678..17a1af03 100644 --- a/examples/generate-atlas.rs +++ b/examples/generate-atlas.rs @@ -58,22 +58,25 @@ fn main() { // FIXME(pcwalton) 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 { let font = Font::new(file.as_slice()).unwrap(); let codepoint_ranges = [CodepointRange::new(' ' as u32, '~' as u32)]; - 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() { 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 atlas = atlas_builder.create_atlas(&outline_builder).unwrap(); + let mut atlas_builder = AtlasBuilder::new(device_pixel_width as GLuint, shelf_height); + 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 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); - 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(); let draw_context = lord_drawquaad::Context::new(); diff --git a/examples/lorem-ipsum.rs b/examples/lorem-ipsum.rs index 16f7af18..890345dd 100644 --- a/examples/lorem-ipsum.rs +++ b/examples/lorem-ipsum.rs @@ -19,12 +19,12 @@ use euclid::{Point2D, Rect, Size2D}; use gl::types::{GLchar, GLint, GLsizei, GLsizeiptr, GLuint, GLvoid}; use glfw::{Action, Context, Key, OpenGlProfileHint, WindowEvent, WindowHint, WindowMode}; use memmap::{Mmap, Protection}; -use pathfinder::atlas::AtlasBuilder; +use pathfinder::atlas::{Atlas, AtlasBuilder}; use pathfinder::charmap::CodepointRanges; use pathfinder::coverage::CoverageBuffer; use pathfinder::glyph_range::GlyphRanges; use pathfinder::otf::Font; -use pathfinder::outline::{OutlineBuffers, OutlineBuilder}; +use pathfinder::outline::{OutlineBuilder, Outlines}; use pathfinder::rasterizer::{DrawAtlasProfilingEvents, Rasterizer, RasterizerOptions}; use pathfinder::shaper; use std::char; @@ -136,25 +136,28 @@ fn main() { let mut dirty = true; let mut outline_builder = OutlineBuilder::new(); + let mut glyph_indices = vec![]; let mut glyph_count = 0; 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 } - let outline_buffers = outline_builder.create_buffers().unwrap(); - - let mut fps_atlas = renderer.create_fps_atlas(&font, - &outline_builder, - &outline_buffers, - glyph_count); + let outlines = outline_builder.create_buffers().unwrap(); + let fps_atlas = renderer.create_fps_atlas(&font, &outlines, glyph_count); while !window.should_close() { if dirty { let events = renderer.redraw(point_size, &font, - &outline_builder, - &outline_buffers, + &outlines, + &glyph_indices, glyph_count, &glyph_positions, &device_pixel_size, @@ -170,9 +173,10 @@ fn main() { let timing = renderer.get_timing_in_ms(); renderer.draw_fps(&font, - &mut fps_atlas, - &outline_builder, + &fps_atlas, + &outlines, &device_pixel_size, + &glyph_indices, &glyph_ranges, draw_time, accum_time, @@ -407,8 +411,8 @@ impl Renderer { fn redraw(&self, point_size: f32, font: &Font, - outline_builder: &OutlineBuilder, - outline_buffers: &OutlineBuffers, + outlines: &Outlines, + glyph_indices: &[u16], glyph_count: usize, glyph_positions: &[GlyphPos], device_pixel_size: &Size2D, @@ -416,18 +420,18 @@ impl Renderer { -> DrawAtlasProfilingEvents { let shelf_height = font.shelf_height(point_size); let mut atlas_builder = AtlasBuilder::new(ATLAS_SIZE, shelf_height); - for glyph_index in 0..(glyph_count as u32) { - atlas_builder.pack_glyph(&outline_builder, glyph_index, point_size).unwrap() + for glyph_index in 0..(glyph_count as u16) { + 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 events = self.rasterizer.draw_atlas(&self.main_compute_image, &rect, &atlas, - outline_buffers, + outlines, &self.main_coverage_buffer).unwrap(); self.rasterizer.queue.flush().unwrap(); @@ -441,9 +445,10 @@ impl Renderer { } self.draw_glyphs(&font, - &mut atlas_builder, - outline_builder, + &atlas, + outlines, &self.main_composite_vertex_array, + glyph_indices, glyph_positions, device_pixel_size, translation, @@ -464,9 +469,10 @@ impl Renderer { fn draw_glyphs(&self, font: &Font, - atlas_builder: &mut AtlasBuilder, - outline_builder: &OutlineBuilder, + atlas: &Atlas, + outlines: &Outlines, vertex_array: &CompositeVertexArray, + glyph_indices: &[u16], glyph_positions: &[GlyphPos], device_pixel_size: &Size2D, translation: &Point2D, @@ -480,8 +486,9 @@ impl Renderer { gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vertex_array.index_buffer); let vertex_count = self.upload_quads_for_text(font, - atlas_builder, - outline_builder, + atlas, + outlines, + glyph_indices, glyph_positions, point_size); @@ -518,8 +525,9 @@ impl Renderer { fn upload_quads_for_text(&self, font: &Font, - atlas_builder: &mut AtlasBuilder, - outline_builder: &OutlineBuilder, + atlas: &Atlas, + outlines: &Outlines, + glyph_indices: &[u16], glyph_positions: &[GlyphPos], point_size: f32) -> usize { @@ -527,17 +535,10 @@ impl Renderer { let (mut vertices, mut indices) = (vec![], vec![]); for position in glyph_positions { - let glyph_index = match atlas_builder.glyph_index_for(position.glyph_id) { - None => continue, - Some(glyph_index) => glyph_index, - }; + let glyph_index = glyph_indices[position.glyph_id as usize]; + let glyph_rect_i = outlines.glyph_pixel_bounds(glyph_index, point_size); - let glyph_rect_i = outline_builder.glyph_pixel_bounds_i(glyph_index, point_size); - - let uv_tl: Point2D = atlas_builder.atlas_origin(glyph_index) - .floor() - .cast() - .unwrap(); + let uv_tl: Point2D = atlas.atlas_origin(glyph_index).floor().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; @@ -572,37 +573,30 @@ impl Renderer { indices.len() } - fn create_fps_atlas(&self, - font: &Font, - outline_builder: &OutlineBuilder, - outline_buffers: &OutlineBuffers, - glyph_count: usize) - -> AtlasBuilder { + fn create_fps_atlas(&self, font: &Font, outlines: &Outlines, glyph_count: usize) -> Atlas { let shelf_height = font.shelf_height(FPS_DISPLAY_POINT_SIZE); let mut atlas_builder = AtlasBuilder::new(ATLAS_SIZE, shelf_height); - for glyph_index in 0..(glyph_count as u32) { - atlas_builder.pack_glyph(&outline_builder, glyph_index, FPS_DISPLAY_POINT_SIZE) - .unwrap() + for glyph_index in 0..(glyph_count as u16) { + atlas_builder.pack_glyph(&outlines, glyph_index, FPS_DISPLAY_POINT_SIZE).unwrap() } - let atlas = atlas_builder.create_atlas(&outline_builder).unwrap(); - - let rect = Rect::new(Point2D::new(0, 0), self.atlas_size); + let atlas = atlas_builder.create_atlas().unwrap(); self.rasterizer.draw_atlas(&self.fps_compute_image, - &rect, + &Rect::new(Point2D::new(0, 0), self.atlas_size), &atlas, - outline_buffers, + outlines, &self.fps_coverage_buffer).unwrap(); - atlas_builder + atlas } fn draw_fps(&self, font: &Font, - atlas_builder: &mut AtlasBuilder, - outline_builder: &OutlineBuilder, + atlas: &Atlas, + outlines: &Outlines, device_pixel_size: &Size2D, + glyph_indices: &[u16], glyph_ranges: &GlyphRanges, draw_time: f64, accum_time: f64, @@ -658,9 +652,10 @@ impl Renderer { } self.draw_glyphs(font, - atlas_builder, - outline_builder, + atlas, + outlines, &self.fps_composite_vertex_array, + glyph_indices, &fps_glyphs, device_pixel_size, &Point2D::new(FPS_PADDING, device_pixel_size.height as i32 - FPS_PADDING), diff --git a/src/atlas.rs b/src/atlas.rs index a4c16be8..bad0e414 100644 --- a/src/atlas.rs +++ b/src/atlas.rs @@ -9,14 +9,12 @@ // except according to those terms. //! Atlases, which hold rendered glyphs on the GPU. -//! -//! TODO(pcwalton): Make the atlas own the outline builder. use error::GlError; use euclid::{Point2D, Rect, Size2D}; use gl::types::{GLenum, GLsizei, GLsizeiptr, GLuint, GLvoid}; use gl; -use outline::OutlineBuilder; +use outline::Outlines; use rect_packer::RectPacker; use std::mem; 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 - /// this is a glyph *index* in the outline builder, not a glyph *ID*. Glyph indices are - /// assigned sequentially starting from 0 each time you call `OutlineBuilder::add_glyph()`. - /// - /// You may not use multiple outline builders in the same + /// The glyph is supplied as an *index* into the supplied outline buffer. Note that indices are + /// separate from IDs; the indices are returned from each call to + /// `OutlineBuilder::add_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. - pub fn pack_glyph(&mut self, - outline_builder: &OutlineBuilder, - glyph_index: u32, - point_size: f32) + pub fn pack_glyph(&mut self, outlines: &Outlines, glyph_index: u16, point_size: f32) -> Result<(), ()> { - let pixel_bounds_f = outline_builder.glyph_pixel_bounds_f(glyph_index, point_size); - let pixel_bounds_i = outline_builder.glyph_pixel_bounds_i(glyph_index, point_size); + let subpixel_bounds = outlines.glyph_subpixel_bounds(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; while self.image_descriptors.len() < glyph_index as usize + 1 { @@ -86,8 +81,8 @@ impl AtlasBuilder { } self.image_descriptors[glyph_index as usize] = ImageDescriptor { - atlas_x: atlas_origin.x as f32 + pixel_bounds_f.left.fract(), - atlas_y: atlas_origin.y as f32 + (1.0 - pixel_bounds_f.top.fract()), + atlas_x: atlas_origin.x as f32 + subpixel_bounds.left.fract(), + atlas_y: atlas_origin.y as f32 + (1.0 - subpixel_bounds.top.fract()), point_size: point_size, glyph_index: glyph_index as f32, }; @@ -99,44 +94,41 @@ impl AtlasBuilder { self.image_metadata[glyph_index as usize] = ImageMetadata { glyph_index: glyph_index, 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(()) } /// Creates an atlas by uploading the atlas info to the GPU. - /// - /// 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 { + pub fn create_atlas(mut self) -> Result { 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![]); for image_metadata in &self.image_metadata { let glyph_index = image_metadata.glyph_index; - - let first_index = outline_builder.descriptors[glyph_index as usize] - .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(), - }; + let start_index = image_metadata.start_index; + let end_index = image_metadata.end_index; match current_range { - Some((current_first, current_last)) if first_index == current_last => { - current_range = Some((current_first, last_index)) + Some((current_first, current_last)) if start_index == current_last => { + current_range = Some((current_first, end_index)) } Some((current_first, current_last)) => { counts.push((current_last - current_first) as GLsizei); - start_indices.push(current_first); - current_range = Some((first_index, last_index)) + start_indices.push(current_first as usize); + 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 { 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. @@ -150,49 +142,41 @@ impl AtlasBuilder { gl::BufferData(gl::UNIFORM_BUFFER, length as GLsizeiptr, ptr, gl::DYNAMIC_DRAW); Ok(Atlas { + images_buffer: images, + images: self.image_descriptors, + start_indices: start_indices, counts: counts, - images: images, shelf_height: self.rect_packer.shelf_height(), shelf_columns: self.rect_packer.shelf_columns(), }) } } - - #[inline] - pub fn glyph_index_for(&self, glyph_id: u16) -> Option { - 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 { - 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 { + images_buffer: GLuint, + images: Vec, + start_indices: Vec, counts: Vec, - images: GLuint, - pub shelf_height: u32, - pub shelf_columns: u32, + shelf_height: u32, + shelf_columns: u32, } impl Drop for Atlas { fn drop(&mut self) { unsafe { - gl::DeleteBuffers(1, &mut self.images); + gl::DeleteBuffers(1, &mut self.images_buffer); } } } impl Atlas { + #[doc(hidden)] pub unsafe fn draw(&self, primitive: GLenum) { debug_assert!(self.counts.len() == self.start_indices.len()); gl::MultiDrawElements(primitive, @@ -202,9 +186,31 @@ impl Atlas { self.counts.len() as GLsizei); } + /// Returns the height of each shelf. #[inline] - pub fn images(&self) -> GLuint { - self.images + pub fn shelf_height(&self) -> u32 { + 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 { + 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 { glyph_index: u32, glyph_id: u16, + start_index: u32, + end_index: u32, } diff --git a/src/otf/glyf.rs b/src/otf/glyf.rs index 4366e50d..2fb4a756 100644 --- a/src/otf/glyf.rs +++ b/src/otf/glyf.rs @@ -13,7 +13,7 @@ use euclid::Point2D; use otf::head::HeadTable; use otf::loca::LocaTable; use otf::{Error, FontTable}; -use outline::GlyphBoundsI; +use outline::GlyphBounds; use std::mem; use std::ops::Mul; 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) - -> Result { + -> Result { let mut reader = self.table.bytes; match try!(loca_table.location_of(head_table, glyph_id)) { None => { // No outlines. - return Ok(GlyphBoundsI { + return Ok(GlyphBounds { left: 0, bottom: 0, right: 0, @@ -302,7 +302,7 @@ impl<'a> GlyfTable<'a> { let y_min = try!(reader.read_i16::().map_err(Error::eof)); let x_max = try!(reader.read_i16::().map_err(Error::eof)); let y_max = try!(reader.read_i16::().map_err(Error::eof)); - Ok(GlyphBoundsI { + Ok(GlyphBounds { left: x_min as i32, bottom: y_min as i32, right: x_max as i32, diff --git a/src/otf/head.rs b/src/otf/head.rs index 5400f593..ca2ac3dc 100644 --- a/src/otf/head.rs +++ b/src/otf/head.rs @@ -10,7 +10,7 @@ use byteorder::{BigEndian, ReadBytesExt}; use otf::{Error, FontTable}; -use outline::GlyphBoundsI; +use outline::GlyphBounds; use std::mem; use util::Jump; @@ -20,7 +20,7 @@ const MAGIC_NUMBER: u32 = 0x5f0f3cf5; pub struct HeadTable { pub units_per_em: u16, pub index_to_loc_format: i16, - pub max_glyph_bounds: GlyphBoundsI, + pub max_glyph_bounds: GlyphBounds, } impl HeadTable { @@ -51,7 +51,7 @@ impl HeadTable { let y_min = try!(reader.read_i16::().map_err(Error::eof)); let x_max = try!(reader.read_i16::().map_err(Error::eof)); let y_max = try!(reader.read_i16::().map_err(Error::eof)); - let max_glyph_bounds = GlyphBoundsI { + let max_glyph_bounds = GlyphBounds { left: x_min as i32, bottom: y_min as i32, right: x_max as i32, diff --git a/src/otf/mod.rs b/src/otf/mod.rs index 053ce5b8..87796193 100644 --- a/src/otf/mod.rs +++ b/src/otf/mod.rs @@ -19,7 +19,7 @@ use otf::head::HeadTable; use otf::hhea::HheaTable; use otf::hmtx::{HmtxTable, HorizontalMetrics}; use otf::loca::LocaTable; -use outline::GlyphBoundsI; +use outline::GlyphBounds; use std::mem; use std::u16; use util::Jump; @@ -299,7 +299,7 @@ impl<'a> Font<'a> { /// Returns the boundaries of the given glyph in font units. #[inline] - pub fn glyph_bounds(&self, glyph_id: u16) -> Result { + pub fn glyph_bounds(&self, glyph_id: u16) -> Result { match self.glyf { Some(glyf) => { let loca = match self.loca { @@ -319,8 +319,8 @@ impl<'a> Font<'a> { // Add 2 to account for the border. self.head .max_glyph_bounds - .pixel_rect_f(self.head.units_per_em, point_size) - .to_i() + .subpixel_bounds(self.head.units_per_em, point_size) + .round_out() .size() .height as u32 + 2 } diff --git a/src/outline.rs b/src/outline.rs index 37eb4dea..ea40e39a 100644 --- a/src/outline.rs +++ b/src/outline.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Glyph vectors, uploaded in a resolution-independent manner to the GPU. + use error::GlError; use euclid::{Point2D, Rect, Size2D}; use gl::types::{GLsizeiptr, GLuint}; @@ -80,31 +82,7 @@ impl OutlineBuilder { Ok(glyph_index) } - /// Returns the glyph rectangle in units. - #[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 { + pub fn create_buffers(self) -> Result { // TODO(pcwalton): Try using `glMapBuffer` here. Requires precomputing contour types and // counts. unsafe { @@ -132,50 +110,83 @@ impl OutlineBuilder { self.descriptors.as_ptr() as *const GlyphDescriptor as *const c_void, gl::STATIC_DRAW); - Ok(OutlineBuffers { - vertices: vertices, - indices: indices, - descriptors: descriptors, + Ok(Outlines { + vertices_buffer: vertices, + indices_buffer: indices, + descriptors_buffer: descriptors, + descriptors: self.descriptors, + indices_count: self.indices.len(), }) } } } -pub struct OutlineBuffers { - pub vertices: GLuint, - pub indices: GLuint, - pub descriptors: GLuint, +pub struct Outlines { + pub vertices_buffer: GLuint, + pub indices_buffer: GLuint, + pub descriptors_buffer: GLuint, + pub descriptors: Vec, + pub indices_count: usize, } -impl Drop for OutlineBuffers { +impl Drop for Outlines { fn drop(&mut self) { unsafe { - gl::DeleteBuffers(1, &mut self.descriptors); - gl::DeleteBuffers(1, &mut self.indices); - gl::DeleteBuffers(1, &mut self.vertices); + gl::DeleteBuffers(1, &mut self.descriptors_buffer); + gl::DeleteBuffers(1, &mut self.indices_buffer); + 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)] #[derive(Clone, Copy, Debug)] pub struct GlyphDescriptor { - pub bounds: GlyphBoundsI, - pub units_per_em: u32, - pub start_point: u32, - pub start_index: u32, - pub glyph_id: u16, + bounds: GlyphBounds, + units_per_em: u32, + start_point: u32, + start_index: u32, + glyph_id: u16, } impl GlyphDescriptor { + #[doc(hidden)] #[inline] - fn pixel_rect_f(&self, point_size: f32) -> GlyphBoundsF { - self.bounds.pixel_rect_f(self.units_per_em as u16, point_size) + pub fn start_index(&self) -> u32 { + self.start_index } + #[doc(hidden)] #[inline] - fn pixel_rect_i(&self, point_size: f32) -> GlyphBoundsI { - self.bounds.pixel_rect_f(self.units_per_em as u16, point_size).to_i() + fn subpixel_bounds(&self, point_size: f32) -> GlyphSubpixelBounds { + self.bounds.subpixel_bounds(self.units_per_em as u16, point_size) } } @@ -189,18 +200,20 @@ pub struct Vertex { pub glyph_index: u16, } +/// The boundaries of the glyph in fractional pixels. #[derive(Copy, Clone, Debug)] -pub struct GlyphBoundsF { +pub struct GlyphSubpixelBounds { pub left: f32, pub bottom: f32, pub right: f32, pub top: f32, } -impl GlyphBoundsF { +impl GlyphSubpixelBounds { + /// Rounds these bounds out to the nearest pixel. #[inline] - pub fn to_i(&self) -> GlyphBoundsI { - GlyphBoundsI { + pub fn round_out(&self) -> GlyphPixelBounds { + GlyphPixelBounds { left: self.left.floor() as i32, bottom: self.bottom.floor() 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] pub fn size(&self) -> Size2D { 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)] -pub struct GlyphBoundsI { +pub struct GlyphPixelBounds { pub left: i32, pub bottom: i32, pub right: i32, pub top: i32, } -impl GlyphBoundsI { +impl GlyphPixelBounds { + /// Returns the total size of the glyph in whole pixels. #[inline] - pub fn pixel_rect_f(&self, units_per_em: u16, point_size: f32) -> GlyphBoundsF { + pub fn size(&self) -> Size2D { + 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; - GlyphBoundsF { + GlyphSubpixelBounds { left: self.left as f32 * pixels_per_unit, bottom: self.bottom 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] pub fn size(&self) -> Size2D { Size2D::new(self.right - self.left, self.top - self.bottom) diff --git a/src/rasterizer.rs b/src/rasterizer.rs index 84810ec8..ebd96d1d 100644 --- a/src/rasterizer.rs +++ b/src/rasterizer.rs @@ -20,7 +20,7 @@ use error::{InitError, RasterError}; use euclid::rect::Rect; use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint, GLvoid}; use gl; -use outline::{OutlineBuffers, Vertex}; +use outline::{Outlines, Vertex}; use std::ascii::AsciiExt; use std::env; use std::mem; @@ -148,7 +148,7 @@ impl Rasterizer { image: &Image, rect: &Rect, atlas: &Atlas, - outline_buffers: &OutlineBuffers, + outlines: &Outlines, coverage_buffer: &CoverageBuffer) -> Result { unsafe { @@ -163,7 +163,7 @@ impl Rasterizer { gl::UseProgram(self.draw_program); // 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, 2, gl::SHORT, @@ -177,10 +177,10 @@ impl Rasterizer { gl::EnableVertexAttribArray(self.draw_position_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, 2, atlas.images()); + gl::BindBufferBase(gl::UNIFORM_BUFFER, 1, outlines.descriptors_buffer); + 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_image_descriptors_uniform, 2); @@ -226,11 +226,11 @@ impl Rasterizer { (0, Uniform::Image(image)), (1, Uniform::Image(coverage_buffer.image())), (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, - &[atlas.shelf_columns], + &[atlas.shelf_columns()], &accum_uniforms, &[]).map_err(RasterError::ComputeError));