From 8771dd67894582522e923739b3eb6c948c9dc105 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 5 Feb 2019 20:10:20 -0800 Subject: [PATCH] wip: dilation not working yet --- demo3/resources/textures/gamma-lut.png | Bin 0 -> 388 bytes .../{defringe.fs.glsl => post.fs.glsl} | 41 +++++++-- .../{defringe.vs.glsl => post.vs.glsl} | 2 +- geometry/src/basic/point.rs | 12 +++ geometry/src/basic/rect.rs | 5 ++ geometry/src/dilation.rs | 83 ++++++++++++++++++ geometry/src/lib.rs | 2 + geometry/src/outline.rs | 16 +++- geometry/src/segment.rs | 11 --- gl/src/renderer.rs | 56 +++++++----- renderer/src/scene.rs | 2 +- 11 files changed, 184 insertions(+), 46 deletions(-) create mode 100644 demo3/resources/textures/gamma-lut.png rename demo3/shaders/{defringe.fs.glsl => post.fs.glsl} (57%) rename demo3/shaders/{defringe.vs.glsl => post.vs.glsl} (92%) create mode 100644 geometry/src/dilation.rs diff --git a/demo3/resources/textures/gamma-lut.png b/demo3/resources/textures/gamma-lut.png new file mode 100644 index 0000000000000000000000000000000000000000..8d2bdd5c78feb20cb9c6483aca966b1ef99742db GIT binary patch literal 388 zcmV-~0ek+5P)o{I9kOO_-VW1A=fDP=zQ5a^&48v=n z?3>=$6N{L)ES)yz`G>CS^W|deKo0nT4cNdEpa8`Nv$J)H$gHy5#E+EJ7Fa~s4_6eO z;P=4p0vG4Zhrv*CoEggVuN2c^)=fF40lhUdn^N z0n#6WNZNoR7%qXbQCYk6kwfDYODp9jei+PPu9!Ot!GnOufgTGy9k>lcaVLNQg&}*O z?7O(UD;6*1h>acd4h1OS7HgHItv;{g`?)S|g5Lus#1F?Yft 0.0) + fgColor = gammaCorrect(fgColor); + + // Finish. + oFragColor = vec4(fgColor, 1.0); } diff --git a/demo3/shaders/defringe.vs.glsl b/demo3/shaders/post.vs.glsl similarity index 92% rename from demo3/shaders/defringe.vs.glsl rename to demo3/shaders/post.vs.glsl index 608cb421..74172dd8 100644 --- a/demo3/shaders/defringe.vs.glsl +++ b/demo3/shaders/post.vs.glsl @@ -1,6 +1,6 @@ #version 330 -// pathfinder/demo3/shaders/defringe.vs.glsl +// pathfinder/demo3/shaders/post.vs.glsl // // Copyright © 2019 The Pathfinder Project Developers. // diff --git a/geometry/src/basic/point.rs b/geometry/src/basic/point.rs index e7a9985d..c69b060b 100644 --- a/geometry/src/basic/point.rs +++ b/geometry/src/basic/point.rs @@ -89,6 +89,11 @@ impl Point2DF32 { Point2DF32(self.0 * F32x4::splat(x)) } + #[inline] + pub fn scale_xy(&self, factors: Point2DF32) -> Point2DF32 { + Point2DF32(self.0 * factors.0) + } + #[inline] pub fn floor(&self) -> Point2DF32 { Point2DF32(self.0.floor()) @@ -98,6 +103,13 @@ impl Point2DF32 { pub fn ceil(&self) -> Point2DF32 { Point2DF32(self.0.ceil()) } + + /// Treats this point as a vector and calculates its length. + #[inline] + pub fn length(&self) -> f32 { + let squared = self.0 * self.0; + f32::sqrt(squared[0] + squared[1]) + } } impl PartialEq for Point2DF32 { diff --git a/geometry/src/basic/rect.rs b/geometry/src/basic/rect.rs index ecb6a646..413c2e23 100644 --- a/geometry/src/basic/rect.rs +++ b/geometry/src/basic/rect.rs @@ -126,6 +126,11 @@ impl RectF32 { RectF32::from_points(self.origin().floor(), self.lower_right().ceil()) } + #[inline] + pub fn dilate(self, amount: Point2DF32) -> RectF32 { + RectF32::from_points(self.origin() - amount, self.lower_right() + amount) + } + #[inline] pub fn to_i32(&self) -> RectI32 { RectI32(self.0.to_i32x4()) diff --git a/geometry/src/dilation.rs b/geometry/src/dilation.rs new file mode 100644 index 00000000..43662501 --- /dev/null +++ b/geometry/src/dilation.rs @@ -0,0 +1,83 @@ +// pathfinder/geometry/src/dilation.rs +// +// Copyright © 2019 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::basic::point::Point2DF32; +use crate::outline::Contour; + +pub struct ContourDilator<'a> { + contour: &'a mut Contour, + amount: Point2DF32, +} + +impl<'a> ContourDilator<'a> { + pub fn new(contour: &'a mut Contour, amount: Point2DF32) -> ContourDilator<'a> { + ContourDilator { contour, amount } + } + + pub fn dilate(&mut self) { + let mut position = self.contour.position_of(0); + let mut prev_point_index = 0; + let mut prev_position; + loop { + prev_point_index = self.contour.prev_point_index_of(prev_point_index); + prev_position = self.contour.position_of(prev_point_index); + if prev_point_index == 0 || prev_position != position { + break; + } + } + + let mut point_index = 0; + loop { + // Find the next non-degenerate position. + let mut next_point_index = point_index; + let mut next_position; + loop { + next_point_index = self.contour.next_point_index_of(next_point_index); + next_position = self.contour.position_of(next_point_index); + if next_point_index == point_index || next_position != position { + break; + } + } + + // Calculate new position by moving the point by the bisector. + let (prev_vector, next_vector) = (position - prev_position, next_position - position); + let bisector = prev_vector.scale(next_vector.length()) + + next_vector.scale(prev_vector.length()); + let bisector_length = bisector.length(); + let new_position = if bisector_length == 0.0 { + position + } else { + position - bisector.scale_xy(self.amount).scale(1.0 / bisector_length) + }; + + /*println!("dilate({:?}): {:?} -> {:?} (bisector {:?}, length {:?})", + self.amount, + position, + new_position, + bisector, + bisector_length);*/ + + // Update all points. + for point_index in point_index..next_point_index { + self.contour.points[point_index as usize] = new_position; + } + + // We're done if we start to loop around. + if next_point_index < point_index { + break; + } + + // Continue. + prev_position = position; + position = next_position; + point_index = next_point_index; + } + } +} diff --git a/geometry/src/lib.rs b/geometry/src/lib.rs index b70e135b..8c824da7 100644 --- a/geometry/src/lib.rs +++ b/geometry/src/lib.rs @@ -26,3 +26,5 @@ pub mod segment; pub mod segments; pub mod stroke; pub mod util; + +mod dilation; diff --git a/geometry/src/outline.rs b/geometry/src/outline.rs index 3b48a18b..926fdac4 100644 --- a/geometry/src/outline.rs +++ b/geometry/src/outline.rs @@ -16,7 +16,7 @@ use crate::basic::rect::RectF32; use crate::basic::transform2d::Transform2DF32; use crate::basic::transform3d::Perspective; use crate::clip::{ContourPolygonClipper, ContourRectClipper}; -use crate::monotonic::MonotonicConversionIter; +use crate::dilation::ContourDilator; use crate::segment::{Segment, SegmentFlags, SegmentKind}; use std::fmt::{self, Debug, Formatter}; use std::mem; @@ -126,10 +126,13 @@ impl Outline { self.bounds = new_bounds.unwrap_or_else(|| RectF32::default()); } + pub fn dilate(&mut self, amount: Point2DF32) { + self.contours.iter_mut().for_each(|contour| contour.dilate(amount)); + self.bounds = self.bounds.dilate(amount); + } + pub fn prepare_for_tiling(&mut self, view_box: RectF32) { - for contour in &mut self.contours { - contour.prepare_for_tiling(view_box); - } + self.contours.iter_mut().for_each(|contour| contour.prepare_for_tiling(view_box)); self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default()); } @@ -360,6 +363,11 @@ impl Contour { } } + pub fn dilate(&mut self, amount: Point2DF32) { + ContourDilator::new(self, amount).dilate(); + self.bounds = self.bounds.dilate(amount); + } + fn prepare_for_tiling(&mut self, view_box: RectF32) { // Snap points to the view box bounds. This mops up floating point error from the clipping // process. diff --git a/geometry/src/segment.rs b/geometry/src/segment.rs index b7805df7..d4a7c521 100644 --- a/geometry/src/segment.rs +++ b/geometry/src/segment.rs @@ -196,17 +196,6 @@ impl<'s> CubicSegment<'s> { uv[0] + uv[1] <= 16.0 * tolerance * tolerance } - /* - #[inline] - pub fn flatten_once(self, tolerance: f32) -> Option { - if self.is_flat(tolerance) { - None - } else { - Some(self.split_after(0.5)) - } - } - */ - #[inline] pub fn split(self, t: f32) -> (Segment, Segment) { let (baseline0, ctrl0, baseline1, ctrl1); diff --git a/gl/src/renderer.rs b/gl/src/renderer.rs index ef22ca75..debf2ec4 100644 --- a/gl/src/renderer.rs +++ b/gl/src/renderer.rs @@ -46,9 +46,10 @@ pub struct Renderer { mask_framebuffer: Framebuffer, fill_colors_texture: Texture, - // Postprocessing shaders - defringe_program: DefringeProgram, - defringe_vertex_array: DefringeVertexArray, + // Postprocessing shader + postprocess_program: PostprocessProgram, + postprocess_vertex_array: PostprocessVertexArray, + gamma_lut_texture: Texture, // Debug pending_timer_queries: VecDeque, @@ -65,9 +66,10 @@ impl Renderer { let solid_tile_program = SolidTileProgram::new(); let mask_tile_program = MaskTileProgram::new(); - let defringe_program = DefringeProgram::new(); + let postprocess_program = PostprocessProgram::new(); let area_lut_texture = Texture::from_png("area-lut"); + let gamma_lut_texture = Texture::from_png("gamma-lut"); let quad_vertex_positions_buffer = Buffer::new(); quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS, @@ -80,8 +82,8 @@ impl Renderer { let solid_tile_vertex_array = SolidTileVertexArray::new(&solid_tile_program, &quad_vertex_positions_buffer); - let defringe_vertex_array = DefringeVertexArray::new(&defringe_program, - &quad_vertex_positions_buffer); + let postprocess_vertex_array = PostprocessVertexArray::new(&postprocess_program, + &quad_vertex_positions_buffer); let mask_framebuffer = Framebuffer::new(&Size2D::new(MASK_FRAMEBUFFER_WIDTH, MASK_FRAMEBUFFER_HEIGHT)); @@ -103,8 +105,9 @@ impl Renderer { mask_framebuffer, fill_colors_texture, - defringe_program, - defringe_vertex_array, + postprocess_program, + postprocess_vertex_array, + gamma_lut_texture, pending_timer_queries: VecDeque::new(), free_timer_queries: vec![], @@ -467,46 +470,57 @@ impl MaskTileProgram { } } -struct DefringeProgram { +struct PostprocessProgram { program: Program, source_uniform: Uniform, framebuffer_size_uniform: Uniform, kernel_uniform: Uniform, + gamma_lut_uniform: Uniform, + bg_color_uniform: Uniform, } -impl DefringeProgram { - fn new() -> DefringeProgram { - let program = Program::new("defringe"); +impl PostprocessProgram { + fn new() -> PostprocessProgram { + let program = Program::new("post"); let source_uniform = Uniform::new(&program, "Source"); let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize"); let kernel_uniform = Uniform::new(&program, "Kernel"); - DefringeProgram { program, source_uniform, framebuffer_size_uniform, kernel_uniform } + let gamma_lut_uniform = Uniform::new(&program, "GammaLUT"); + let bg_color_uniform = Uniform::new(&program, "BGColor"); + PostprocessProgram { + program, + source_uniform, + framebuffer_size_uniform, + kernel_uniform, + gamma_lut_uniform, + bg_color_uniform, + } } } -struct DefringeVertexArray { +struct PostprocessVertexArray { gl_vertex_array: GLuint, } -impl DefringeVertexArray { - fn new(defringe_program: &DefringeProgram, quad_vertex_positions_buffer: &Buffer) - -> DefringeVertexArray { +impl PostprocessVertexArray { + fn new(postprocess_program: &PostprocessProgram, quad_vertex_positions_buffer: &Buffer) + -> PostprocessVertexArray { let mut gl_vertex_array = 0; unsafe { - let position_attr = VertexAttr::new(&defringe_program.program, "Position"); + let position_attr = VertexAttr::new(&postprocess_program.program, "Position"); gl::GenVertexArrays(1, &mut gl_vertex_array); gl::BindVertexArray(gl_vertex_array); - gl::UseProgram(defringe_program.program.gl_program); + gl::UseProgram(postprocess_program.program.gl_program); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer); position_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0); } - DefringeVertexArray { gl_vertex_array } + PostprocessVertexArray { gl_vertex_array } } } -impl Drop for DefringeVertexArray { +impl Drop for PostprocessVertexArray { #[inline] fn drop(&mut self) { unsafe { diff --git a/renderer/src/scene.rs b/renderer/src/scene.rs index ba1996df..7b76a5b1 100644 --- a/renderer/src/scene.rs +++ b/renderer/src/scene.rs @@ -116,7 +116,7 @@ impl Scene { PreparedBuildTransform::Perspective(ref perspective, ref quad) => { outline.clip_against_polygon(quad); outline.apply_perspective(perspective); - outline.prepare_for_tiling(self.view_box); + outline.dilate(Point2DF32::splat(4.0)); } PreparedBuildTransform::Transform2D(ref transform) => { outline.transform(transform);