diff --git a/examples/lorem-ipsum.rs b/examples/lorem-ipsum.rs index 2b9461db..a803cf97 100644 --- a/examples/lorem-ipsum.rs +++ b/examples/lorem-ipsum.rs @@ -40,7 +40,6 @@ const ATLAS_SIZE: u32 = 2048; const WIDTH: u32 = 640; const HEIGHT: u32 = 480; const SCROLL_SPEED: f64 = 6.0; -const UNITS_PER_EM: u32 = 2048; const INITIAL_POINT_SIZE: f32 = 24.0; const MIN_POINT_SIZE: f32 = 6.0; @@ -102,12 +101,12 @@ fn main() { shaped_glyph_positions = shaper::shape_text(&font, &glyph_ranges, &text) } - let paragraph_width = (device_pixel_size.width as f32 * UNITS_PER_EM as f32 / + let paragraph_width = (device_pixel_size.width as f32 * font.units_per_em() as f32 / INITIAL_POINT_SIZE) as u32; // Do some basic line breaking. let mut glyph_positions = vec![]; - let line_spacing = UNITS_PER_EM; + let line_spacing = font.units_per_em() as u32; let (mut current_x, mut current_y) = (0, line_spacing); for glyph_position in &shaped_glyph_positions { current_x += glyph_position.advance as u32; @@ -136,11 +135,15 @@ fn main() { let outline_buffers = outline_builder.create_buffers().unwrap(); - let mut fps_atlas = renderer.create_fps_atlas(&outline_builder, &outline_buffers, glyph_count); + let mut fps_atlas = renderer.create_fps_atlas(&font, + &outline_builder, + &outline_buffers, + glyph_count); while !window.should_close() { if dirty { let events = renderer.redraw(point_size, + &font, &outline_builder, &outline_buffers, glyph_count, @@ -232,9 +235,8 @@ struct Renderer { composite_translation_uniform: GLint, composite_color_uniform: GLint, - composite_vertex_array: GLuint, - composite_vertex_buffer: GLuint, - composite_index_buffer: GLuint, + main_composite_vertex_array: CompositeVertexArray, + fps_composite_vertex_array: CompositeVertexArray, solid_color_program: GLuint, solid_color_color_uniform: GLint, @@ -245,7 +247,8 @@ struct Renderer { atlas_size: Size2D, - coverage_buffer: CoverageBuffer, + main_coverage_buffer: CoverageBuffer, + fps_coverage_buffer: CoverageBuffer, main_compute_image: Image, main_gl_texture: GLuint, fps_compute_image: Image, @@ -266,10 +269,10 @@ impl Renderer { let (composite_program, composite_position_attribute, composite_tex_coord_attribute); let (composite_atlas_uniform, composite_transform_uniform); let (composite_translation_uniform, composite_color_uniform); + let (main_composite_vertex_array, fps_composite_vertex_array); let (solid_color_program, solid_color_position_attribute, solid_color_color_uniform); - let (mut composite_vertex_array, mut solid_color_vertex_array) = (0, 0); - let (mut composite_vertex_buffer, mut composite_index_buffer) = (0, 0); let (mut solid_color_vertex_buffer, mut solid_color_index_buffer) = (0, 0); + let mut solid_color_vertex_array = 0; unsafe { composite_program = create_program(COMPOSITE_VERTEX_SHADER, COMPOSITE_FRAGMENT_SHADER); composite_position_attribute = @@ -297,29 +300,29 @@ impl Renderer { gl::UseProgram(composite_program); - gl::GenVertexArrays(1, &mut composite_vertex_array); - gl::BindVertexArray(composite_vertex_array); + main_composite_vertex_array = CompositeVertexArray::new(); + fps_composite_vertex_array = CompositeVertexArray::new(); + for vertex_array in &[&main_composite_vertex_array, &fps_composite_vertex_array] { + gl::BindVertexArray(vertex_array.vertex_array); - gl::GenBuffers(1, &mut composite_vertex_buffer); - gl::GenBuffers(1, &mut composite_index_buffer); + gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vertex_array.index_buffer); + gl::BindBuffer(gl::ARRAY_BUFFER, vertex_array.vertex_buffer); - gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, composite_index_buffer); - gl::BindBuffer(gl::ARRAY_BUFFER, composite_vertex_buffer); - - gl::VertexAttribPointer(composite_position_attribute as GLuint, - 2, - gl::INT, - gl::FALSE, - mem::size_of::() as GLsizei, - 0 as *const GLvoid); - gl::VertexAttribPointer(composite_tex_coord_attribute as GLuint, - 2, - gl::UNSIGNED_INT, - gl::FALSE, - mem::size_of::() as GLsizei, - (mem::size_of::() * 2) as *const GLvoid); - gl::EnableVertexAttribArray(composite_position_attribute as GLuint); - gl::EnableVertexAttribArray(composite_tex_coord_attribute as GLuint); + gl::VertexAttribPointer(composite_position_attribute as GLuint, + 2, + gl::INT, + gl::FALSE, + mem::size_of::() as GLsizei, + 0 as *const GLvoid); + gl::VertexAttribPointer(composite_tex_coord_attribute as GLuint, + 2, + gl::UNSIGNED_INT, + gl::FALSE, + mem::size_of::() as GLsizei, + (mem::size_of::() * 2) as *const GLvoid); + gl::EnableVertexAttribArray(composite_position_attribute as GLuint); + gl::EnableVertexAttribArray(composite_tex_coord_attribute as GLuint); + } gl::UseProgram(solid_color_program); @@ -349,7 +352,8 @@ impl Renderer { // FIXME(pcwalton) let atlas_size = Size2D::new(ATLAS_SIZE, ATLAS_SIZE); - let coverage_buffer = CoverageBuffer::new(&rasterizer.device, &atlas_size).unwrap(); + let main_coverage_buffer = CoverageBuffer::new(&rasterizer.device, &atlas_size).unwrap(); + let fps_coverage_buffer = CoverageBuffer::new(&rasterizer.device, &atlas_size).unwrap(); let (main_compute_image, main_gl_texture) = create_image(&rasterizer, &atlas_size); let (fps_compute_image, fps_gl_texture) = create_image(&rasterizer, &atlas_size); @@ -368,9 +372,8 @@ impl Renderer { composite_translation_uniform: composite_translation_uniform, composite_color_uniform: composite_color_uniform, - composite_vertex_array: composite_vertex_array, - composite_vertex_buffer: composite_vertex_buffer, - composite_index_buffer: composite_index_buffer, + main_composite_vertex_array: main_composite_vertex_array, + fps_composite_vertex_array: fps_composite_vertex_array, solid_color_program: solid_color_program, solid_color_color_uniform: solid_color_color_uniform, @@ -381,7 +384,8 @@ impl Renderer { atlas_size: atlas_size, - coverage_buffer: coverage_buffer, + main_coverage_buffer: main_coverage_buffer, + fps_coverage_buffer: fps_coverage_buffer, main_compute_image: main_compute_image, main_gl_texture: main_gl_texture, fps_compute_image: fps_compute_image, @@ -393,6 +397,7 @@ impl Renderer { fn redraw(&self, point_size: f32, + font: &Font, outline_builder: &OutlineBuilder, outline_buffers: &OutlineBuffers, glyph_count: usize, @@ -400,9 +405,7 @@ impl Renderer { device_pixel_size: &Size2D, translation: &Point2D) -> DrawAtlasProfilingEvents { - // FIXME(pcwalton) - let shelf_height = (point_size * 2.0).ceil() as u32; - + 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() @@ -416,7 +419,7 @@ impl Renderer { &rect, &atlas, outline_buffers, - &self.coverage_buffer).unwrap(); + &self.main_coverage_buffer).unwrap(); self.rasterizer.queue.flush().unwrap(); unsafe { @@ -428,8 +431,10 @@ impl Renderer { gl::Clear(gl::COLOR_BUFFER_BIT); } - self.draw_glyphs(&mut atlas_builder, + self.draw_glyphs(&font, + &mut atlas_builder, outline_builder, + &self.main_composite_vertex_array, glyph_positions, device_pixel_size, translation, @@ -449,8 +454,10 @@ impl Renderer { } fn draw_glyphs(&self, + font: &Font, atlas_builder: &mut AtlasBuilder, outline_builder: &OutlineBuilder, + vertex_array: &CompositeVertexArray, glyph_positions: &[GlyphPos], device_pixel_size: &Size2D, translation: &Point2D, @@ -459,11 +466,12 @@ impl Renderer { color: &[f32]) { unsafe { gl::UseProgram(self.composite_program); - gl::BindVertexArray(self.composite_vertex_array); - gl::BindBuffer(gl::ARRAY_BUFFER, self.composite_vertex_buffer); - gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.composite_index_buffer); + gl::BindVertexArray(vertex_array.vertex_array); + gl::BindBuffer(gl::ARRAY_BUFFER, vertex_array.vertex_buffer); + gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vertex_array.index_buffer); - let vertex_count = self.upload_quads_for_text(atlas_builder, + let vertex_count = self.upload_quads_for_text(font, + atlas_builder, outline_builder, glyph_positions, point_size); @@ -500,12 +508,13 @@ impl Renderer { } fn upload_quads_for_text(&self, + font: &Font, atlas_builder: &mut AtlasBuilder, outline_builder: &OutlineBuilder, glyph_positions: &[GlyphPos], point_size: f32) -> usize { - let pixels_per_unit = point_size as f32 / UNITS_PER_EM as f32; + let pixels_per_unit = point_size as f32 / font.units_per_em() as f32; let (mut vertices, mut indices) = (vec![], vec![]); for position in glyph_positions { @@ -548,13 +557,12 @@ impl Renderer { } fn create_fps_atlas(&self, + font: &Font, outline_builder: &OutlineBuilder, outline_buffers: &OutlineBuffers, glyph_count: usize) -> AtlasBuilder { - // FIXME(pcwalton) - let shelf_height = (FPS_DISPLAY_POINT_SIZE * 2.0).ceil() as u32; - + 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) @@ -569,7 +577,7 @@ impl Renderer { &rect, &atlas, outline_buffers, - &self.coverage_buffer).unwrap(); + &self.fps_coverage_buffer).unwrap(); atlas_builder } @@ -633,8 +641,10 @@ impl Renderer { }); } - self.draw_glyphs(atlas_builder, + self.draw_glyphs(font, + atlas_builder, outline_builder, + &self.fps_composite_vertex_array, &fps_glyphs, device_pixel_size, &Point2D::new(FPS_PADDING, device_pixel_size.height as i32 - FPS_PADDING), @@ -701,6 +711,31 @@ struct GlyphPos { glyph_id: u16, } +#[derive(Debug)] +struct CompositeVertexArray { + vertex_array: GLuint, + vertex_buffer: GLuint, + index_buffer: GLuint, +} + +impl CompositeVertexArray { + fn new() -> CompositeVertexArray { + let (mut vertex_array, mut vertex_buffer, mut index_buffer) = (0, 0, 0); + + unsafe { + gl::GenVertexArrays(1, &mut vertex_array); + gl::GenBuffers(1, &mut vertex_buffer); + gl::GenBuffers(1, &mut index_buffer); + } + + CompositeVertexArray { + vertex_array: vertex_array, + vertex_buffer: vertex_buffer, + index_buffer: index_buffer, + } + } +} + fn create_program(vertex_shader_source: &str, fragment_shader_source: &str) -> GLuint { unsafe { let vertex_shader = gl::CreateShader(gl::VERTEX_SHADER); diff --git a/src/otf/head.rs b/src/otf/head.rs index df172173..ca2ac3dc 100644 --- a/src/otf/head.rs +++ b/src/otf/head.rs @@ -10,6 +10,7 @@ use byteorder::{BigEndian, ReadBytesExt}; use otf::{Error, FontTable}; +use outline::GlyphBounds; use std::mem; use util::Jump; @@ -19,6 +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: GlyphBounds, } impl HeadTable { @@ -43,11 +45,21 @@ impl HeadTable { try!(reader.jump(mem::size_of::()).map_err(Error::eof)); let units_per_em = try!(reader.read_u16::().map_err(Error::eof)); + // Read the maximum bounds. + try!(reader.jump(mem::size_of::() * 2).map_err(Error::eof)); + let x_min = try!(reader.read_i16::().map_err(Error::eof)); + 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 = GlyphBounds { + left: x_min as i32, + bottom: y_min as i32, + right: x_max as i32, + top: y_max as i32, + }; + // Read the index-to-location format. - try!(reader.jump(mem::size_of::() * 2 + - mem::size_of::() * 4 + - mem::size_of::() * 2 + - mem::size_of::()).map_err(Error::eof)); + try!(reader.jump(mem::size_of::() * 2 + mem::size_of::()).map_err(Error::eof)); let index_to_loc_format = try!(reader.read_i16::().map_err(Error::eof)); // Check the glyph data format. @@ -59,6 +71,7 @@ impl HeadTable { Ok(HeadTable { units_per_em: units_per_em, index_to_loc_format: index_to_loc_format, + max_glyph_bounds: max_glyph_bounds, }) } } diff --git a/src/otf/mod.rs b/src/otf/mod.rs index 1949bc4c..e9e47e25 100644 --- a/src/otf/mod.rs +++ b/src/otf/mod.rs @@ -284,6 +284,12 @@ impl<'a> Font<'a> { } } + #[inline] + pub fn shelf_height(&self, point_size: f32) -> u32 { + let pixel_rect = self.head.max_glyph_bounds.pixel_rect(self.head.units_per_em, point_size); + pixel_rect.round_out().size.height as u32 + } + #[inline] pub fn units_per_em(&self) -> u16 { self.head.units_per_em diff --git a/src/outline.rs b/src/outline.rs index 061debf0..8d081044 100644 --- a/src/outline.rs +++ b/src/outline.rs @@ -162,10 +162,7 @@ pub struct GlyphDescriptor { impl GlyphDescriptor { #[inline] fn pixel_rect(&self, point_size: f32) -> Rect { - let pixels_per_unit = point_size / self.units_per_em as f32; - Rect::new(Point2D::new(self.bounds.left as f32, self.bounds.bottom as f32), - Size2D::new((self.bounds.right - self.bounds.left) as f32, - (self.bounds.top - self.bounds.bottom) as f32)) * pixels_per_unit + self.bounds.pixel_rect(self.units_per_em as u16, point_size) } } @@ -187,3 +184,13 @@ pub struct GlyphBounds { pub top: i32, } +impl GlyphBounds { + #[inline] + pub fn pixel_rect(&self, units_per_em: u16, point_size: f32) -> Rect { + let pixels_per_unit = point_size / units_per_em as f32; + Rect::new(Point2D::new(self.left as f32, self.bottom as f32), + Size2D::new((self.right - self.left) as f32, (self.top - self.bottom) as f32)) * + pixels_per_unit + } +} +