wip: dilation not working yet

This commit is contained in:
Patrick Walton 2019-02-05 20:10:20 -08:00
parent 45dec44a53
commit 8771dd6789
11 changed files with 184 additions and 46 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/demo3/shaders/defringe.fs.glsl // pathfinder/demo3/shaders/post.fs.glsl
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2019 The Pathfinder Project Developers.
// //
@ -16,13 +16,26 @@
precision highp float; precision highp float;
uniform sampler2D uSource; uniform sampler2D uSource;
uniform sampler2D uGammaLUT;
uniform vec2 uFramebufferSize; uniform vec2 uFramebufferSize;
uniform vec4 uKernel; uniform vec4 uKernel;
uniform vec4 uBGColor;
in vec2 vTexCoord; in vec2 vTexCoord;
out vec4 oFragColor; out vec4 oFragColor;
float gammaCorrectChannel(float fgColor) {
return texture(uGammaLUT, vec2(fgColor, 1.0 - uBGColor)).r;
}
// `fgColor` is in linear space.
vec3 gammaCorrect(vec3 fgColor) {
return vec3(gammaCorrectChannel(fgColor.r),
gammaCorrectChannel(fgColor.g),
gammaCorrectChannel(fgColor.b));
}
float sample1Tap(float offset) { float sample1Tap(float offset) {
return texture(uSource, vec2(vTexCoord.x + offset, vTexCoord.y)).r; return texture(uSource, vec2(vTexCoord.x + offset, vTexCoord.y)).r;
} }
@ -47,13 +60,25 @@ float convolve7Tap(vec4 alpha0, vec3 alpha1) {
} }
void main() { void main() {
vec4 alphaLeft, alphaRight; // Apply defringing if necessary.
float alphaCenter; vec3 fgColor;
sample9Tap(alphaLeft, alphaCenter, alphaRight, 1.0 / uFramebufferSize.x); if (uKernel.w == 0.0) {
fgColor = texture(uSource, vTexCoord).rgb;
} else {
vec4 alphaLeft, alphaRight;
float alphaCenter;
sample9Tap(alphaLeft, alphaCenter, alphaRight, 1.0 / uFramebufferSize.x);
vec3 alpha = vec3(convolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight.xy)), fgColor =
convolve7Tap(vec4(alphaLeft.yzw, alphaCenter), alphaRight.xyz), vec3(convolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight.xy)),
convolve7Tap(vec4(alphaLeft.zw, alphaCenter, alphaRight.x), alphaRight.yzw)); convolve7Tap(vec4(alphaLeft.yzw, alphaCenter), alphaRight.xyz),
convolve7Tap(vec4(alphaLeft.zw, alphaCenter, alphaRight.x), alphaRight.yzw));
}
oFragColor = vec4(alpha, 1.0); // Apply gamma correction if necessary.
if (uBGColor.a > 0.0)
fgColor = gammaCorrect(fgColor);
// Finish.
oFragColor = vec4(fgColor, 1.0);
} }

View File

@ -1,6 +1,6 @@
#version 330 #version 330
// pathfinder/demo3/shaders/defringe.vs.glsl // pathfinder/demo3/shaders/post.vs.glsl
// //
// Copyright © 2019 The Pathfinder Project Developers. // Copyright © 2019 The Pathfinder Project Developers.
// //

View File

@ -89,6 +89,11 @@ impl Point2DF32 {
Point2DF32(self.0 * F32x4::splat(x)) Point2DF32(self.0 * F32x4::splat(x))
} }
#[inline]
pub fn scale_xy(&self, factors: Point2DF32) -> Point2DF32 {
Point2DF32(self.0 * factors.0)
}
#[inline] #[inline]
pub fn floor(&self) -> Point2DF32 { pub fn floor(&self) -> Point2DF32 {
Point2DF32(self.0.floor()) Point2DF32(self.0.floor())
@ -98,6 +103,13 @@ impl Point2DF32 {
pub fn ceil(&self) -> Point2DF32 { pub fn ceil(&self) -> Point2DF32 {
Point2DF32(self.0.ceil()) 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 { impl PartialEq for Point2DF32 {

View File

@ -126,6 +126,11 @@ impl RectF32 {
RectF32::from_points(self.origin().floor(), self.lower_right().ceil()) 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] #[inline]
pub fn to_i32(&self) -> RectI32 { pub fn to_i32(&self) -> RectI32 {
RectI32(self.0.to_i32x4()) RectI32(self.0.to_i32x4())

83
geometry/src/dilation.rs Normal file
View File

@ -0,0 +1,83 @@
// pathfinder/geometry/src/dilation.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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;
}
}
}

View File

@ -26,3 +26,5 @@ pub mod segment;
pub mod segments; pub mod segments;
pub mod stroke; pub mod stroke;
pub mod util; pub mod util;
mod dilation;

View File

@ -16,7 +16,7 @@ use crate::basic::rect::RectF32;
use crate::basic::transform2d::Transform2DF32; use crate::basic::transform2d::Transform2DF32;
use crate::basic::transform3d::Perspective; use crate::basic::transform3d::Perspective;
use crate::clip::{ContourPolygonClipper, ContourRectClipper}; use crate::clip::{ContourPolygonClipper, ContourRectClipper};
use crate::monotonic::MonotonicConversionIter; use crate::dilation::ContourDilator;
use crate::segment::{Segment, SegmentFlags, SegmentKind}; use crate::segment::{Segment, SegmentFlags, SegmentKind};
use std::fmt::{self, Debug, Formatter}; use std::fmt::{self, Debug, Formatter};
use std::mem; use std::mem;
@ -126,10 +126,13 @@ impl Outline {
self.bounds = new_bounds.unwrap_or_else(|| RectF32::default()); 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) { pub fn prepare_for_tiling(&mut self, view_box: RectF32) {
for contour in &mut self.contours { self.contours.iter_mut().for_each(|contour| contour.prepare_for_tiling(view_box));
contour.prepare_for_tiling(view_box);
}
self.bounds = self.bounds.intersection(view_box).unwrap_or_else(|| RectF32::default()); 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) { 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 // Snap points to the view box bounds. This mops up floating point error from the clipping
// process. // process.

View File

@ -196,17 +196,6 @@ impl<'s> CubicSegment<'s> {
uv[0] + uv[1] <= 16.0 * tolerance * tolerance uv[0] + uv[1] <= 16.0 * tolerance * tolerance
} }
/*
#[inline]
pub fn flatten_once(self, tolerance: f32) -> Option<Segment> {
if self.is_flat(tolerance) {
None
} else {
Some(self.split_after(0.5))
}
}
*/
#[inline] #[inline]
pub fn split(self, t: f32) -> (Segment, Segment) { pub fn split(self, t: f32) -> (Segment, Segment) {
let (baseline0, ctrl0, baseline1, ctrl1); let (baseline0, ctrl0, baseline1, ctrl1);

View File

@ -46,9 +46,10 @@ pub struct Renderer {
mask_framebuffer: Framebuffer, mask_framebuffer: Framebuffer,
fill_colors_texture: Texture, fill_colors_texture: Texture,
// Postprocessing shaders // Postprocessing shader
defringe_program: DefringeProgram, postprocess_program: PostprocessProgram,
defringe_vertex_array: DefringeVertexArray, postprocess_vertex_array: PostprocessVertexArray,
gamma_lut_texture: Texture,
// Debug // Debug
pending_timer_queries: VecDeque<TimerQuery>, pending_timer_queries: VecDeque<TimerQuery>,
@ -65,9 +66,10 @@ impl Renderer {
let solid_tile_program = SolidTileProgram::new(); let solid_tile_program = SolidTileProgram::new();
let mask_tile_program = MaskTileProgram::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 area_lut_texture = Texture::from_png("area-lut");
let gamma_lut_texture = Texture::from_png("gamma-lut");
let quad_vertex_positions_buffer = Buffer::new(); let quad_vertex_positions_buffer = Buffer::new();
quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS, quad_vertex_positions_buffer.upload(&QUAD_VERTEX_POSITIONS,
@ -80,8 +82,8 @@ impl Renderer {
let solid_tile_vertex_array = SolidTileVertexArray::new(&solid_tile_program, let solid_tile_vertex_array = SolidTileVertexArray::new(&solid_tile_program,
&quad_vertex_positions_buffer); &quad_vertex_positions_buffer);
let defringe_vertex_array = DefringeVertexArray::new(&defringe_program, let postprocess_vertex_array = PostprocessVertexArray::new(&postprocess_program,
&quad_vertex_positions_buffer); &quad_vertex_positions_buffer);
let mask_framebuffer = Framebuffer::new(&Size2D::new(MASK_FRAMEBUFFER_WIDTH, let mask_framebuffer = Framebuffer::new(&Size2D::new(MASK_FRAMEBUFFER_WIDTH,
MASK_FRAMEBUFFER_HEIGHT)); MASK_FRAMEBUFFER_HEIGHT));
@ -103,8 +105,9 @@ impl Renderer {
mask_framebuffer, mask_framebuffer,
fill_colors_texture, fill_colors_texture,
defringe_program, postprocess_program,
defringe_vertex_array, postprocess_vertex_array,
gamma_lut_texture,
pending_timer_queries: VecDeque::new(), pending_timer_queries: VecDeque::new(),
free_timer_queries: vec![], free_timer_queries: vec![],
@ -467,46 +470,57 @@ impl MaskTileProgram {
} }
} }
struct DefringeProgram { struct PostprocessProgram {
program: Program, program: Program,
source_uniform: Uniform, source_uniform: Uniform,
framebuffer_size_uniform: Uniform, framebuffer_size_uniform: Uniform,
kernel_uniform: Uniform, kernel_uniform: Uniform,
gamma_lut_uniform: Uniform,
bg_color_uniform: Uniform,
} }
impl DefringeProgram { impl PostprocessProgram {
fn new() -> DefringeProgram { fn new() -> PostprocessProgram {
let program = Program::new("defringe"); let program = Program::new("post");
let source_uniform = Uniform::new(&program, "Source"); let source_uniform = Uniform::new(&program, "Source");
let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize"); let framebuffer_size_uniform = Uniform::new(&program, "FramebufferSize");
let kernel_uniform = Uniform::new(&program, "Kernel"); 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, gl_vertex_array: GLuint,
} }
impl DefringeVertexArray { impl PostprocessVertexArray {
fn new(defringe_program: &DefringeProgram, quad_vertex_positions_buffer: &Buffer) fn new(postprocess_program: &PostprocessProgram, quad_vertex_positions_buffer: &Buffer)
-> DefringeVertexArray { -> PostprocessVertexArray {
let mut gl_vertex_array = 0; let mut gl_vertex_array = 0;
unsafe { 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::GenVertexArrays(1, &mut gl_vertex_array);
gl::BindVertexArray(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); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vertex_positions_buffer.gl_buffer);
position_attr.configure_float(2, gl::UNSIGNED_BYTE, false, 0, 0, 0); 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] #[inline]
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {

View File

@ -116,7 +116,7 @@ impl Scene {
PreparedBuildTransform::Perspective(ref perspective, ref quad) => { PreparedBuildTransform::Perspective(ref perspective, ref quad) => {
outline.clip_against_polygon(quad); outline.clip_against_polygon(quad);
outline.apply_perspective(perspective); outline.apply_perspective(perspective);
outline.prepare_for_tiling(self.view_box); outline.dilate(Point2DF32::splat(4.0));
} }
PreparedBuildTransform::Transform2D(ref transform) => { PreparedBuildTransform::Transform2D(ref transform) => {
outline.transform(transform); outline.transform(transform);