wip: dilation not working yet
This commit is contained in:
parent
45dec44a53
commit
8771dd6789
Binary file not shown.
After Width: | Height: | Size: 388 B |
|
@ -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);
|
||||||
}
|
}
|
|
@ -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.
|
||||||
//
|
//
|
|
@ -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 {
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue