Move radial gradients from the CPU to the GPU
This commit is contained in:
parent
0c24619dd0
commit
55df287fec
|
@ -295,6 +295,7 @@ dependencies = [
|
|||
"pathfinder_gpu 0.1.0",
|
||||
"pathfinder_renderer 0.1.0",
|
||||
"pathfinder_resources 0.1.0",
|
||||
"pathfinder_simd 0.4.0",
|
||||
"sdl2 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2-sys 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
|
|
@ -98,7 +98,7 @@ impl Debug for ColorU {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
#[derive(Clone, Copy, PartialEq, Default)]
|
||||
pub struct ColorF(pub F32x4);
|
||||
|
||||
impl ColorF {
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
//! Special effects that can be applied to layers.
|
||||
|
||||
use pathfinder_color::ColorF;
|
||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||
use pathfinder_geometry::vector::Vector2F;
|
||||
use pathfinder_simd::default::F32x2;
|
||||
|
||||
/// This intentionally does not precisely match what Core Graphics does (a
|
||||
/// Lanczos function), because we don't want any ringing artefacts.
|
||||
|
@ -29,18 +32,28 @@ pub const MAX_STEM_DARKENING_AMOUNT: [f32; 2] = [0.3, 0.3];
|
|||
pub const MAX_STEM_DARKENING_PIXELS_PER_EM: f32 = 72.0;
|
||||
|
||||
/// Effects that can be applied to a layer.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||
pub struct Effects {
|
||||
/// The shader that should be used when compositing this layer onto its destination.
|
||||
pub filter: Filter,
|
||||
}
|
||||
|
||||
/// The shader that should be used when compositing this layer onto its destination.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum Filter {
|
||||
/// No special filter.
|
||||
None,
|
||||
|
||||
/// Converts a linear gradient to a radial one.
|
||||
RadialGradient {
|
||||
/// The line that the circles lie along.
|
||||
line: LineSegment2F,
|
||||
/// The radii of the circles at the two endpoints.
|
||||
radii: F32x2,
|
||||
/// The origin of the linearized gradient in the texture.
|
||||
uv_origin: Vector2F,
|
||||
},
|
||||
|
||||
/// Performs postprocessing operations useful for monochrome text.
|
||||
Text {
|
||||
/// The foreground color of the text.
|
||||
|
|
|
@ -13,6 +13,7 @@ use crate::util;
|
|||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||
use pathfinder_geometry::util as geometry_util;
|
||||
use pathfinder_simd::default::F32x2;
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
use std::convert;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
@ -20,20 +21,17 @@ use std::mem;
|
|||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
pub struct Gradient {
|
||||
pub geometry: GradientGeometry,
|
||||
/// The line this gradient runs along.
|
||||
///
|
||||
/// If this is a radial gradient, this is the line that connects the two circles. It may have
|
||||
/// zero-length in the case of simple radial gradients.
|
||||
pub line: LineSegment2F,
|
||||
/// For radial gradients, the radii of the start and endpoints respectively. If this is a
|
||||
/// linear gradient, this is `None`.
|
||||
pub radii: Option<F32x2>,
|
||||
stops: SortedVector<ColorStop>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||
pub enum GradientGeometry {
|
||||
Linear(LineSegment2F),
|
||||
Radial {
|
||||
line: LineSegment2F,
|
||||
start_radius: f32,
|
||||
end_radius: f32,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
|
||||
pub struct ColorStop {
|
||||
pub offset: f32,
|
||||
|
@ -44,19 +42,15 @@ impl Eq for Gradient {}
|
|||
|
||||
impl Hash for Gradient {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
match self.geometry {
|
||||
GradientGeometry::Linear(line) => {
|
||||
(0).hash(state);
|
||||
util::hash_line_segment(line, state);
|
||||
}
|
||||
GradientGeometry::Radial { line, start_radius, end_radius } => {
|
||||
util::hash_line_segment(self.line, state);
|
||||
match self.radii {
|
||||
None => (0).hash(state),
|
||||
Some(radii) => {
|
||||
(1).hash(state);
|
||||
util::hash_line_segment(line, state);
|
||||
util::hash_f32(start_radius, state);
|
||||
util::hash_f32(end_radius, state);
|
||||
util::hash_f32(radii.x(), state);
|
||||
util::hash_f32(radii.y(), state);
|
||||
}
|
||||
}
|
||||
|
||||
self.stops.hash(state);
|
||||
}
|
||||
}
|
||||
|
@ -74,19 +68,14 @@ impl Hash for ColorStop {
|
|||
}
|
||||
|
||||
impl Gradient {
|
||||
#[inline]
|
||||
pub fn new(geometry: GradientGeometry) -> Gradient {
|
||||
Gradient { geometry, stops: SortedVector::new() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn linear(line: LineSegment2F) -> Gradient {
|
||||
Gradient::new(GradientGeometry::Linear(line))
|
||||
Gradient { line, radii: None, stops: SortedVector::new() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn radial(line: LineSegment2F, start_radius: f32, end_radius: f32) -> Gradient {
|
||||
Gradient::new(GradientGeometry::Radial { line, start_radius, end_radius })
|
||||
pub fn radial(line: LineSegment2F, radii: F32x2) -> Gradient {
|
||||
Gradient { line, radii: Some(radii), stops: SortedVector::new() }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -95,13 +84,23 @@ impl Gradient {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn geometry(&self) -> &GradientGeometry {
|
||||
&self.geometry
|
||||
pub fn line(&self) -> LineSegment2F {
|
||||
self.line
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn geometry_mut(&mut self) -> &mut GradientGeometry {
|
||||
&mut self.geometry
|
||||
pub fn set_line(&mut self, line: LineSegment2F) {
|
||||
self.line = line
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn radii(&self) -> Option<F32x2> {
|
||||
self.radii
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_radii(&mut self, radii: Option<F32x2>) {
|
||||
self.radii = radii
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -34,3 +34,6 @@ path = "../../renderer"
|
|||
|
||||
[dependencies.pathfinder_resources]
|
||||
path = "../../resources"
|
||||
|
||||
[dependencies.pathfinder_simd]
|
||||
path = "../../simd"
|
||||
|
|
|
@ -29,6 +29,7 @@ use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
|
|||
use pathfinder_renderer::gpu::renderer::Renderer;
|
||||
use pathfinder_renderer::options::BuildOptions;
|
||||
use pathfinder_resources::fs::FilesystemResourceLoader;
|
||||
use pathfinder_simd::default::F32x2;
|
||||
use sdl2::event::Event;
|
||||
use sdl2::keyboard::Keycode;
|
||||
use sdl2::video::GLProfile;
|
||||
|
@ -134,9 +135,9 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D,
|
|||
canvas.fill_path(path, FillRule::Winding);
|
||||
|
||||
let gloss_position = eyes_left_position - eyes_radii.scale_xy(Vector2F::new(0.25, 0.5));
|
||||
let gloss_radii = F32x2::new(0.1, 0.75) * F32x2::splat(eyes_radii.x());
|
||||
let mut gloss = Gradient::radial(LineSegment2F::new(gloss_position, gloss_position),
|
||||
eyes_radii.x() * 0.1,
|
||||
eyes_radii.x() * 0.75);
|
||||
gloss_radii);
|
||||
gloss.add_color_stop(ColorStop::new(ColorU::new(255, 255, 255, 128), 0.0));
|
||||
gloss.add_color_stop(ColorStop::new(ColorU::new(255, 255, 255, 0), 1.0));
|
||||
canvas.set_fill_style(FillStyle::Gradient(gloss));
|
||||
|
@ -146,8 +147,7 @@ fn draw_eyes(canvas: &mut CanvasRenderingContext2D,
|
|||
|
||||
let gloss_position = eyes_right_position - eyes_radii.scale_xy(Vector2F::new(0.25, 0.5));
|
||||
let mut gloss = Gradient::radial(LineSegment2F::new(gloss_position, gloss_position),
|
||||
eyes_radii.x() * 0.1,
|
||||
eyes_radii.x() * 0.75);
|
||||
gloss_radii);
|
||||
gloss.add_color_stop(ColorStop::new(ColorU::new(255, 255, 255, 128), 0.0));
|
||||
gloss.add_color_stop(ColorStop::new(ColorU::new(255, 255, 255, 0), 1.0));
|
||||
canvas.set_fill_style(FillStyle::Gradient(gloss));
|
||||
|
@ -251,8 +251,7 @@ fn draw_graph(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f32) {
|
|||
for &sample_point in &sample_points {
|
||||
let gradient_center = sample_point + Vector2F::new(0.0, 2.0);
|
||||
let mut background = Gradient::radial(LineSegment2F::new(gradient_center, gradient_center),
|
||||
3.0,
|
||||
8.0);
|
||||
F32x2::new(3.0, 8.0));
|
||||
background.add_color_stop(ColorStop::new(ColorU::new(0, 0, 0, 32), 0.0));
|
||||
background.add_color_stop(ColorStop::new(ColorU::transparent_black(), 1.0));
|
||||
canvas.set_fill_style(FillStyle::Gradient(background));
|
||||
|
@ -372,8 +371,7 @@ fn draw_color_wheel(canvas: &mut CanvasRenderingContext2D, rect: RectF, time: f3
|
|||
// Fill the selection circle.
|
||||
let mut gradient = Gradient::radial(LineSegment2F::new(selection_circle_center,
|
||||
selection_circle_center),
|
||||
7.0,
|
||||
9.0);
|
||||
F32x2::new(7.0, 9.0));
|
||||
gradient.add_color_stop(ColorStop::new(ColorU::new(0, 0, 0, 64), 0.0));
|
||||
gradient.add_color_stop(ColorStop::new(ColorU::transparent_black(), 1.0));
|
||||
canvas.set_fill_style(FillStyle::Gradient(gradient));
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::tile_map::DenseTileMap;
|
|||
use crate::tiles::{self, DrawTilingPathInfo, PackedTile, TILE_HEIGHT, TILE_WIDTH};
|
||||
use crate::tiles::{Tiler, TilingPathInfo};
|
||||
use crate::z_buffer::{DepthMetadata, ZBuffer};
|
||||
use pathfinder_content::effects::{BlendMode, Effects, Filter};
|
||||
use pathfinder_content::effects::{BlendMode, Effects};
|
||||
use pathfinder_content::fill::FillRule;
|
||||
use pathfinder_content::render_target::RenderTargetId;
|
||||
use pathfinder_geometry::line_segment::{LineSegment2F, LineSegmentU4, LineSegmentU8};
|
||||
|
@ -55,6 +55,7 @@ pub(crate) struct ObjectBuilder {
|
|||
struct BuiltDrawPath {
|
||||
path: BuiltPath,
|
||||
blend_mode: BlendMode,
|
||||
effects: Effects,
|
||||
color_texture_page_0: TexturePageId,
|
||||
color_texture_page_1: TexturePageId,
|
||||
sampling_flags_0: TextureSamplingFlags,
|
||||
|
@ -191,8 +192,9 @@ impl<'a> SceneBuilder<'a> {
|
|||
|
||||
let paint_id = path_object.paint();
|
||||
let paint_metadata = &paint_metadata[paint_id.0 as usize];
|
||||
let built_clip_path =
|
||||
path_object.clip_path().map(|clip_path_id| &built_clip_paths[clip_path_id.0 as usize]);
|
||||
let built_clip_path = path_object.clip_path().map(|clip_path_id| {
|
||||
&built_clip_paths[clip_path_id.0 as usize]
|
||||
});
|
||||
|
||||
let mut tiler = Tiler::new(self,
|
||||
&outline,
|
||||
|
@ -213,6 +215,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
BuiltDrawPath {
|
||||
path: tiler.object_builder.built_path,
|
||||
blend_mode: path_object.blend_mode(),
|
||||
effects: paint_metadata.effects(),
|
||||
color_texture_page_0: paint_metadata.location.page,
|
||||
sampling_flags_0: paint_metadata.sampling_flags,
|
||||
color_texture_page_1: opacity_tile_page,
|
||||
|
@ -322,6 +325,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
None,
|
||||
None,
|
||||
built_draw_path.blend_mode,
|
||||
built_draw_path.effects,
|
||||
None,
|
||||
None);
|
||||
|
||||
|
@ -332,6 +336,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
color_texture_0,
|
||||
color_texture_1,
|
||||
built_draw_path.blend_mode,
|
||||
built_draw_path.effects,
|
||||
Some(built_draw_path.mask_0_fill_rule),
|
||||
None);
|
||||
|
||||
|
@ -343,6 +348,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
color_texture_0,
|
||||
color_texture_1,
|
||||
built_draw_path.blend_mode,
|
||||
built_draw_path.effects,
|
||||
Some(built_draw_path.mask_0_fill_rule),
|
||||
Some(mask_1_fill_rule));
|
||||
}
|
||||
|
@ -356,6 +362,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
color_texture_0,
|
||||
color_texture_1,
|
||||
built_draw_path.blend_mode,
|
||||
built_draw_path.effects,
|
||||
None,
|
||||
built_draw_path.mask_1_fill_rule);
|
||||
}
|
||||
|
@ -425,6 +432,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
color_texture_0: Option<TileBatchTexture>,
|
||||
color_texture_1: Option<TileBatchTexture>,
|
||||
blend_mode: BlendMode,
|
||||
effects: Effects,
|
||||
mask_0_fill_rule: Option<FillRule>,
|
||||
mask_1_fill_rule: Option<FillRule>) {
|
||||
if alpha_tiles.is_empty() {
|
||||
|
@ -443,12 +451,13 @@ impl<'a> SceneBuilder<'a> {
|
|||
color_texture_0: ref batch_color_texture_0,
|
||||
color_texture_1: ref batch_color_texture_1,
|
||||
blend_mode: batch_blend_mode,
|
||||
effects: Effects { filter: Filter::None },
|
||||
effects: batch_effects,
|
||||
mask_0_fill_rule: batch_mask_0_fill_rule,
|
||||
mask_1_fill_rule: batch_mask_1_fill_rule,
|
||||
})) if *batch_color_texture_0 == color_texture_0 &&
|
||||
*batch_color_texture_1 == color_texture_1 &&
|
||||
batch_blend_mode == blend_mode &&
|
||||
batch_effects == effects &&
|
||||
batch_mask_0_fill_rule == mask_0_fill_rule &&
|
||||
batch_mask_1_fill_rule == mask_1_fill_rule &&
|
||||
!batch_blend_mode.needs_readable_framebuffer() => {}
|
||||
|
@ -458,7 +467,7 @@ impl<'a> SceneBuilder<'a> {
|
|||
color_texture_0,
|
||||
color_texture_1,
|
||||
blend_mode,
|
||||
effects: Effects::default(),
|
||||
effects,
|
||||
mask_0_fill_rule,
|
||||
mask_1_fill_rule,
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@ use pathfinder_color::{self as color, ColorF, ColorU};
|
|||
use pathfinder_content::effects::{BlendMode, BlurDirection, DefringingKernel, Effects, Filter};
|
||||
use pathfinder_content::fill::FillRule;
|
||||
use pathfinder_content::render_target::RenderTargetId;
|
||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||
use pathfinder_geometry::rect::RectI;
|
||||
use pathfinder_geometry::transform3d::Transform4F;
|
||||
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F};
|
||||
|
@ -59,6 +60,7 @@ const COMBINER_CTRL_MASK_EVEN_ODD: i32 = 0x2;
|
|||
|
||||
const COMBINER_CTRL_COLOR_ENABLE_MASK: i32 = 0x1;
|
||||
|
||||
const COMBINER_CTRL_FILTER_RADIAL_GRADIENT: i32 = 0x1;
|
||||
const COMBINER_CTRL_FILTER_TEXT: i32 = 0x2;
|
||||
const COMBINER_CTRL_FILTER_BLUR: i32 = 0x3;
|
||||
|
||||
|
@ -611,13 +613,13 @@ where
|
|||
UniformData::Mat4(self.tile_transform().to_columns())),
|
||||
(&self.tile_program.tile_size_uniform,
|
||||
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
|
||||
(&self.tile_program.framebuffer_size_uniform,
|
||||
UniformData::Vec2(draw_viewport.size().to_f32().0)),
|
||||
];
|
||||
|
||||
if needs_readable_framebuffer {
|
||||
uniforms.push((&self.tile_program.dest_texture_uniform,
|
||||
UniformData::TextureUnit(textures.len() as u32)));
|
||||
uniforms.push((&self.tile_program.dest_texture_size_uniform,
|
||||
UniformData::Vec2(draw_viewport.size().to_f32().0)));
|
||||
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
|
||||
}
|
||||
|
||||
|
@ -659,6 +661,10 @@ where
|
|||
|
||||
match effects.filter {
|
||||
Filter::None => {}
|
||||
Filter::RadialGradient { line, radii, uv_origin } => {
|
||||
ctrl |= COMBINER_CTRL_FILTER_RADIAL_GRADIENT << COMBINER_CTRL_COLOR_0_FILTER_SHIFT;
|
||||
self.set_uniforms_for_radial_gradient_filter(&mut uniforms, line, radii, uv_origin)
|
||||
}
|
||||
Filter::Text { fg_color, bg_color, defringing_kernel, gamma_correction } => {
|
||||
ctrl |= COMBINER_CTRL_FILTER_TEXT << COMBINER_CTRL_COLOR_0_FILTER_SHIFT;
|
||||
self.set_uniforms_for_text_filter(&mut textures,
|
||||
|
@ -844,6 +850,20 @@ where
|
|||
self.render_target_stack.pop().expect("Render target stack underflow!");
|
||||
}
|
||||
|
||||
fn set_uniforms_for_radial_gradient_filter<'a>(
|
||||
&'a self,
|
||||
uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
|
||||
line: LineSegment2F,
|
||||
radii: F32x2,
|
||||
uv_origin: Vector2F) {
|
||||
uniforms.extend_from_slice(&[
|
||||
(&self.tile_program.filter_params_0_uniform,
|
||||
UniformData::Vec4(line.from().0.concat_xy_xy(line.vector().0))),
|
||||
(&self.tile_program.filter_params_1_uniform,
|
||||
UniformData::Vec4(radii.concat_xy_xy(uv_origin.0))),
|
||||
]);
|
||||
}
|
||||
|
||||
fn set_uniforms_for_text_filter<'a>(&'a self,
|
||||
textures: &mut Vec<&'a D::Texture>,
|
||||
uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
|
||||
|
|
|
@ -324,7 +324,7 @@ pub struct TileProgram<D> where D: Device {
|
|||
pub filter_params_0_uniform: D::Uniform,
|
||||
pub filter_params_1_uniform: D::Uniform,
|
||||
pub filter_params_2_uniform: D::Uniform,
|
||||
pub dest_texture_size_uniform: D::Uniform,
|
||||
pub framebuffer_size_uniform: D::Uniform,
|
||||
pub ctrl_uniform: D::Uniform,
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ impl<D> TileProgram<D> where D: Device {
|
|||
let filter_params_0_uniform = device.get_uniform(&program, "FilterParams0");
|
||||
let filter_params_1_uniform = device.get_uniform(&program, "FilterParams1");
|
||||
let filter_params_2_uniform = device.get_uniform(&program, "FilterParams2");
|
||||
let dest_texture_size_uniform = device.get_uniform(&program, "DestTextureSize");
|
||||
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
|
||||
let ctrl_uniform = device.get_uniform(&program, "Ctrl");
|
||||
TileProgram {
|
||||
program,
|
||||
|
@ -359,7 +359,7 @@ impl<D> TileProgram<D> where D: Device {
|
|||
filter_params_0_uniform,
|
||||
filter_params_1_uniform,
|
||||
filter_params_2_uniform,
|
||||
dest_texture_size_uniform,
|
||||
framebuffer_size_uniform,
|
||||
ctrl_uniform,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,9 +14,11 @@ use crate::scene::RenderTarget;
|
|||
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
|
||||
use hashbrown::HashMap;
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_content::gradient::{Gradient, GradientGeometry};
|
||||
use pathfinder_content::effects::{Effects, Filter};
|
||||
use pathfinder_content::gradient::Gradient;
|
||||
use pathfinder_content::pattern::{Image, Pattern, PatternFlags, PatternSource};
|
||||
use pathfinder_content::render_target::RenderTargetId;
|
||||
use pathfinder_geometry::line_segment::LineSegment2F;
|
||||
use pathfinder_geometry::rect::{RectF, RectI};
|
||||
use pathfinder_geometry::transform2d::{Matrix2x2F, Transform2F};
|
||||
use pathfinder_geometry::util;
|
||||
|
@ -123,26 +125,11 @@ impl Paint {
|
|||
match *self {
|
||||
Paint::Color(_) => {}
|
||||
Paint::Gradient(ref mut gradient) => {
|
||||
match *gradient.geometry_mut() {
|
||||
GradientGeometry::Linear(ref mut line) => {
|
||||
*line = *transform * *line;
|
||||
}
|
||||
GradientGeometry::Radial {
|
||||
ref mut line,
|
||||
ref mut start_radius,
|
||||
ref mut end_radius,
|
||||
} => {
|
||||
*line = *transform * *line;
|
||||
|
||||
// FIXME(pcwalton): This is wrong; I think the transform can make the
|
||||
// radial gradient into an ellipse.
|
||||
*start_radius *= util::lerp(transform.matrix.m11(),
|
||||
gradient.set_line(*transform * gradient.line());
|
||||
if let Some(radii) = gradient.radii() {
|
||||
gradient.set_radii(Some(radii * F32x2::splat(util::lerp(transform.matrix.m11(),
|
||||
transform.matrix.m22(),
|
||||
0.5);
|
||||
*end_radius *= util::lerp(transform.matrix.m11(),
|
||||
transform.matrix.m22(),
|
||||
0.5);
|
||||
}
|
||||
0.5))));
|
||||
}
|
||||
}
|
||||
Paint::Pattern(ref mut pattern) => pattern.transform = *transform * pattern.transform,
|
||||
|
@ -177,6 +164,16 @@ pub struct PaintMetadata {
|
|||
pub sampling_flags: TextureSamplingFlags,
|
||||
/// True if this paint is fully opaque.
|
||||
pub is_opaque: bool,
|
||||
/// The radial gradient for this paint, if applicable.
|
||||
pub radial_gradient: Option<RadialGradientMetadata>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct RadialGradientMetadata {
|
||||
/// The line segment that connects the two circles.
|
||||
pub line: LineSegment2F,
|
||||
/// The radii of the two circles.
|
||||
pub radii: F32x2,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -204,7 +201,7 @@ impl Palette {
|
|||
id
|
||||
}
|
||||
|
||||
pub fn build_paint_info(&self, view_box_size: Vector2I) -> PaintInfo {
|
||||
pub fn build_paint_info(&self) -> PaintInfo {
|
||||
let mut allocator = TextureAllocator::new();
|
||||
let (mut paint_metadata, mut render_target_metadata) = (vec![], vec![]);
|
||||
|
||||
|
@ -220,26 +217,20 @@ impl Palette {
|
|||
let mut solid_color_tile_builder = SolidColorTileBuilder::new();
|
||||
let mut gradient_tile_builder = GradientTileBuilder::new();
|
||||
for paint in &self.paints {
|
||||
let (texture_location, mut sampling_flags);
|
||||
let (texture_location, mut sampling_flags, radial_gradient);
|
||||
match paint {
|
||||
Paint::Color(_) => {
|
||||
texture_location = solid_color_tile_builder.allocate(&mut allocator);
|
||||
sampling_flags = TextureSamplingFlags::empty();
|
||||
radial_gradient = None;
|
||||
}
|
||||
Paint::Gradient(Gradient { geometry: GradientGeometry::Linear(_), .. }) => {
|
||||
Paint::Gradient(ref gradient) => {
|
||||
// FIXME(pcwalton): The gradient size might not be big enough. Detect this.
|
||||
texture_location = gradient_tile_builder.allocate(&mut allocator);
|
||||
sampling_flags = TextureSamplingFlags::empty();
|
||||
}
|
||||
Paint::Gradient(Gradient { geometry: GradientGeometry::Radial { .. }, .. }) => {
|
||||
// TODO(pcwalton): Optimize this:
|
||||
// 1. Use repeating/clamp on the sides.
|
||||
// 2. Choose an optimal size for the gradient that minimizes memory usage while
|
||||
// retaining quality.
|
||||
texture_location =
|
||||
allocator.allocate(Vector2I::splat(GRADIENT_TILE_LENGTH as i32),
|
||||
AllocationMode::Atlas);
|
||||
sampling_flags = TextureSamplingFlags::empty();
|
||||
radial_gradient = gradient.radii().map(|radii| {
|
||||
RadialGradientMetadata { line: gradient.line(), radii }
|
||||
});
|
||||
}
|
||||
Paint::Pattern(ref pattern) => {
|
||||
match pattern.source {
|
||||
|
@ -271,6 +262,8 @@ impl Palette {
|
|||
sampling_flags.insert(TextureSamplingFlags::NEAREST_MIN |
|
||||
TextureSamplingFlags::NEAREST_MAG);
|
||||
}
|
||||
|
||||
radial_gradient = None;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -279,6 +272,7 @@ impl Palette {
|
|||
texture_transform: Transform2F::default(),
|
||||
sampling_flags,
|
||||
is_opaque: paint.is_opaque(),
|
||||
radial_gradient,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -290,10 +284,7 @@ impl Palette {
|
|||
let vector = rect_to_inset_uv(metadata.location.rect, texture_scale).origin();
|
||||
Transform2F { matrix: Matrix2x2F(F32x4::default()), vector }
|
||||
}
|
||||
Paint::Gradient(Gradient {
|
||||
geometry: GradientGeometry::Linear(gradient_line),
|
||||
..
|
||||
}) => {
|
||||
Paint::Gradient(Gradient { line: gradient_line, radii: None, .. }) => {
|
||||
let v0 = metadata.location.rect.to_f32().center().y() * texture_scale.y();
|
||||
let length_inv = 1.0 / gradient_line.square_length();
|
||||
let (p0, d) = (gradient_line.from(), gradient_line.vector());
|
||||
|
@ -302,12 +293,15 @@ impl Palette {
|
|||
vector: Vector2F::new(-p0.dot(d) * length_inv, v0),
|
||||
}
|
||||
}
|
||||
Paint::Gradient(Gradient { geometry: GradientGeometry::Radial { .. }, .. }) => {
|
||||
Paint::Gradient(Gradient { radii: Some(_), .. }) => {
|
||||
let texture_origin_uv =
|
||||
rect_to_uv(metadata.location.rect, texture_scale).origin();
|
||||
let gradient_tile_scale = texture_scale.scale(GRADIENT_TILE_LENGTH as f32);
|
||||
Transform2F::from_translation(texture_origin_uv) *
|
||||
Transform2F::from_scale(gradient_tile_scale / view_box_size.to_f32())
|
||||
rect_to_inset_uv(metadata.location.rect, texture_scale).origin();
|
||||
let gradient_tile_scale =
|
||||
texture_scale.scale((GRADIENT_TILE_LENGTH - 1) as f32);
|
||||
Transform2F {
|
||||
matrix: Matrix2x2F::from_scale(gradient_tile_scale),
|
||||
vector: texture_origin_uv,
|
||||
}
|
||||
}
|
||||
Paint::Pattern(Pattern { source: PatternSource::Image(_), transform, .. }) => {
|
||||
let texture_origin_uv =
|
||||
|
@ -359,10 +353,7 @@ impl Palette {
|
|||
texels.put_texel(metadata.location.rect.origin(), *color);
|
||||
}
|
||||
Paint::Gradient(ref gradient) => {
|
||||
self.render_gradient(gradient,
|
||||
metadata.location.rect,
|
||||
&metadata.texture_transform,
|
||||
texels);
|
||||
self.render_gradient(gradient, metadata.location.rect, texels);
|
||||
}
|
||||
Paint::Pattern(ref pattern) => {
|
||||
match pattern.source {
|
||||
|
@ -408,13 +399,7 @@ impl Palette {
|
|||
}
|
||||
|
||||
// TODO(pcwalton): This is slow. Do on GPU instead.
|
||||
fn render_gradient(&self,
|
||||
gradient: &Gradient,
|
||||
tex_rect: RectI,
|
||||
tex_transform: &Transform2F,
|
||||
texels: &mut Texels) {
|
||||
match *gradient.geometry() {
|
||||
GradientGeometry::Linear(_) => {
|
||||
fn render_gradient(&self, gradient: &Gradient, tex_rect: RectI, texels: &mut Texels) {
|
||||
// FIXME(pcwalton): Paint transparent if gradient line has zero size, per spec.
|
||||
// TODO(pcwalton): Optimize this:
|
||||
// 1. Calculate ∇t up front and use differencing in the inner loop.
|
||||
|
@ -426,129 +411,6 @@ impl Palette {
|
|||
}
|
||||
}
|
||||
|
||||
GradientGeometry::Radial { line, start_radius: r0, end_radius: r1 } => {
|
||||
// FIXME(pcwalton): Paint transparent if line has zero size and radii are equal,
|
||||
// per spec.
|
||||
let line = *tex_transform * line;
|
||||
|
||||
// This is based on Pixman (MIT license). Copy and pasting the excellent comment
|
||||
// from there:
|
||||
|
||||
// Implementation of radial gradients following the PDF specification.
|
||||
// See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
|
||||
// Manual (PDF 32000-1:2008 at the time of this writing).
|
||||
//
|
||||
// In the radial gradient problem we are given two circles (c₁,r₁) and
|
||||
// (c₂,r₂) that define the gradient itself.
|
||||
//
|
||||
// Mathematically the gradient can be defined as the family of circles
|
||||
//
|
||||
// ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
|
||||
//
|
||||
// excluding those circles whose radius would be < 0. When a point
|
||||
// belongs to more than one circle, the one with a bigger t is the only
|
||||
// one that contributes to its color. When a point does not belong
|
||||
// to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
|
||||
// Further limitations on the range of values for t are imposed when
|
||||
// the gradient is not repeated, namely t must belong to [0,1].
|
||||
//
|
||||
// The graphical result is the same as drawing the valid (radius > 0)
|
||||
// circles with increasing t in [-inf, +inf] (or in [0,1] if the gradient
|
||||
// is not repeated) using SOURCE operator composition.
|
||||
//
|
||||
// It looks like a cone pointing towards the viewer if the ending circle
|
||||
// is smaller than the starting one, a cone pointing inside the page if
|
||||
// the starting circle is the smaller one and like a cylinder if they
|
||||
// have the same radius.
|
||||
//
|
||||
// What we actually do is, given the point whose color we are interested
|
||||
// in, compute the t values for that point, solving for t in:
|
||||
//
|
||||
// length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
|
||||
//
|
||||
// Let's rewrite it in a simpler way, by defining some auxiliary
|
||||
// variables:
|
||||
//
|
||||
// cd = c₂ - c₁
|
||||
// pd = p - c₁
|
||||
// dr = r₂ - r₁
|
||||
// length(t·cd - pd) = r₁ + t·dr
|
||||
//
|
||||
// which actually means
|
||||
//
|
||||
// hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
|
||||
//
|
||||
// or
|
||||
//
|
||||
// ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
|
||||
//
|
||||
// If we impose (as stated earlier) that r₁ + t·dr >= 0, it becomes:
|
||||
//
|
||||
// (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
|
||||
//
|
||||
// where we can actually expand the squares and solve for t:
|
||||
//
|
||||
// t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
|
||||
// = r₁² + 2·r₁·t·dr + t²·dr²
|
||||
//
|
||||
// (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
|
||||
// (pdx² + pdy² - r₁²) = 0
|
||||
//
|
||||
// A = cdx² + cdy² - dr²
|
||||
// B = pdx·cdx + pdy·cdy + r₁·dr
|
||||
// C = pdx² + pdy² - r₁²
|
||||
// At² - 2Bt + C = 0
|
||||
//
|
||||
// The solutions (unless the equation degenerates because of A = 0) are:
|
||||
//
|
||||
// t = (B ± ⎷(B² - A·C)) / A
|
||||
//
|
||||
// The solution we are going to prefer is the bigger one, unless the
|
||||
// radius associated to it is negative (or it falls outside the valid t
|
||||
// range).
|
||||
//
|
||||
// Additional observations (useful for optimizations):
|
||||
// A does not depend on p
|
||||
//
|
||||
// A < 0 <=> one of the two circles completely contains the other one
|
||||
// <=> for every p, the radiuses associated with the two t solutions
|
||||
// have opposite sign
|
||||
|
||||
let cd = line.vector();
|
||||
let dr = r1 - r0;
|
||||
let a = cd.square_length() - dr * dr;
|
||||
let a_inv = 1.0 / a;
|
||||
|
||||
for y in 0..(GRADIENT_TILE_LENGTH as i32) {
|
||||
for x in 0..(GRADIENT_TILE_LENGTH as i32) {
|
||||
let point = tex_rect.origin() + Vector2I::new(x, y);
|
||||
let point_f = point.to_f32();
|
||||
let pd = point_f - line.from();
|
||||
|
||||
let b = pd.dot(cd) + r0 * dr;
|
||||
let c = pd.square_length() - r0 * r0;
|
||||
let discrim = b * b - a * c;
|
||||
|
||||
let mut color = ColorU::transparent_black();
|
||||
if !util::approx_eq(discrim, 0.0) {
|
||||
let discrim_sqrt = f32::sqrt(discrim);
|
||||
let discrim_sqrts = F32x2::new(discrim_sqrt, -discrim_sqrt);
|
||||
let ts = (discrim_sqrts + F32x2::splat(b)) * F32x2::splat(a_inv);
|
||||
let t_min = f32::min(ts.x(), ts.y());
|
||||
let t_max = f32::max(ts.x(), ts.y());
|
||||
let t = if t_max <= 1.0 { t_max } else { t_min };
|
||||
if t >= 0.0 {
|
||||
color = gradient.sample(t);
|
||||
}
|
||||
};
|
||||
|
||||
texels.put_texel(point, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_image(&self, image: &Image, tex_rect: RectI, texels: &mut Texels) {
|
||||
let image_size = image.size();
|
||||
for y in 0..image_size.y() {
|
||||
|
@ -568,6 +430,21 @@ impl PaintMetadata {
|
|||
let tex_coords = self.texture_transform * position;
|
||||
tex_coords
|
||||
}
|
||||
|
||||
pub(crate) fn effects(&self) -> Effects {
|
||||
Effects {
|
||||
filter: match self.radial_gradient {
|
||||
None => Filter::None,
|
||||
Some(gradient) => {
|
||||
Filter::RadialGradient {
|
||||
line: gradient.line,
|
||||
radii: gradient.radii,
|
||||
uv_origin: self.texture_transform.vector,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Texels {
|
||||
|
|
|
@ -87,7 +87,7 @@ impl Scene {
|
|||
|
||||
#[inline]
|
||||
pub fn build_paint_info(&self) -> PaintInfo {
|
||||
self.palette.build_paint_info(self.view_box.size().to_i32())
|
||||
self.palette.build_paint_info()
|
||||
}
|
||||
|
||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
||||
|
|
|
@ -73,6 +73,8 @@ precision highp float;
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -85,7 +87,7 @@ uniform sampler2D uGammaLUT;
|
|||
uniform vec4 uFilterParams0;
|
||||
uniform vec4 uFilterParams1;
|
||||
uniform vec4 uFilterParams2;
|
||||
uniform vec2 uDestTextureSize;
|
||||
uniform vec2 uFramebufferSize;
|
||||
uniform vec2 uColorTexture0Size;
|
||||
uniform int uCtrl;
|
||||
|
||||
|
@ -202,6 +204,128 @@ vec4 filterText(vec2 colorTexCoord,
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
vec4 filterRadialGradient(vec2 colorTexCoord,
|
||||
sampler2D colorTexture,
|
||||
vec2 colorTextureSize,
|
||||
vec2 fragCoord,
|
||||
vec2 framebufferSize,
|
||||
vec4 filterParams0,
|
||||
vec4 filterParams1){
|
||||
vec2 lineFrom = filterParams0 . xy, lineVector = filterParams0 . zw;
|
||||
vec2 radii = filterParams1 . xy, uvOrigin = filterParams1 . zw;
|
||||
|
||||
|
||||
fragCoord . y = framebufferSize . y - fragCoord . y;
|
||||
|
||||
|
||||
vec2 dP = fragCoord - lineFrom, dC = lineVector;
|
||||
float dR = radii . y - radii . x;
|
||||
|
||||
float a = dot(dC, dC)- dR * dR;
|
||||
float b = dot(dP, dC)+ radii . x * dR;
|
||||
float c = dot(dP, dP)- radii . x * radii . x;
|
||||
float discrim = b * b - a * c;
|
||||
|
||||
vec4 color = vec4(0.0);
|
||||
if(abs(discrim)>= 0.00001){
|
||||
vec2 ts = vec2(sqrt(discrim)* vec2(1.0, - 1.0)+ vec2(b))/ vec2(a);
|
||||
float tMax = max(ts . x, ts . y);
|
||||
float t = tMax <= 1.0 ? tMax : min(ts . x, ts . y);
|
||||
if(t >= 0.0)
|
||||
color = texture(colorTexture, uvOrigin + vec2(t, 0.0));
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
vec4 filterBlur(vec2 colorTexCoord,
|
||||
sampler2D colorTexture,
|
||||
vec2 colorTextureSize,
|
||||
|
@ -250,11 +374,21 @@ vec4 filterColor(vec2 colorTexCoord,
|
|||
sampler2D colorTexture,
|
||||
sampler2D gammaLUT,
|
||||
vec2 colorTextureSize,
|
||||
vec2 fragCoord,
|
||||
vec2 framebufferSize,
|
||||
vec4 filterParams0,
|
||||
vec4 filterParams1,
|
||||
vec4 filterParams2,
|
||||
int colorFilter){
|
||||
switch(colorFilter){
|
||||
case 0x1 :
|
||||
return filterRadialGradient(colorTexCoord,
|
||||
colorTexture,
|
||||
colorTextureSize,
|
||||
fragCoord,
|
||||
framebufferSize,
|
||||
filterParams0,
|
||||
filterParams1);
|
||||
case 0x3 :
|
||||
return filterBlur(colorTexCoord,
|
||||
colorTexture,
|
||||
|
@ -433,6 +567,8 @@ void calculateColor(int ctrl){
|
|||
uColorTexture0,
|
||||
uGammaLUT,
|
||||
uColorTexture0Size,
|
||||
gl_FragCoord . xy,
|
||||
uFramebufferSize,
|
||||
uFilterParams0,
|
||||
uFilterParams1,
|
||||
uFilterParams2,
|
||||
|
@ -446,7 +582,7 @@ void calculateColor(int ctrl){
|
|||
|
||||
|
||||
int compositeOp =(ctrl >> 8)& 0xf;
|
||||
color = composite(color, uDestTexture, uDestTextureSize, gl_FragCoord . xy, compositeOp);
|
||||
color = composite(color, uDestTexture, uFramebufferSize, gl_FragCoord . xy, compositeOp);
|
||||
|
||||
|
||||
color . rgb *= color . a;
|
||||
|
|
|
@ -17,18 +17,18 @@ struct spvDescriptorSetBuffer0
|
|||
texture2d<float> uGammaLUT [[id(6)]];
|
||||
sampler uGammaLUTSmplr [[id(7)]];
|
||||
constant float2* uColorTexture0Size [[id(8)]];
|
||||
constant float4* uFilterParams0 [[id(9)]];
|
||||
constant float4* uFilterParams1 [[id(10)]];
|
||||
constant float4* uFilterParams2 [[id(11)]];
|
||||
texture2d<float> uColorTexture1 [[id(12)]];
|
||||
sampler uColorTexture1Smplr [[id(13)]];
|
||||
texture2d<float> uDestTexture [[id(14)]];
|
||||
sampler uDestTextureSmplr [[id(15)]];
|
||||
constant float2* uDestTextureSize [[id(16)]];
|
||||
constant float2* uFramebufferSize [[id(9)]];
|
||||
constant float4* uFilterParams0 [[id(10)]];
|
||||
constant float4* uFilterParams1 [[id(11)]];
|
||||
constant float4* uFilterParams2 [[id(12)]];
|
||||
texture2d<float> uColorTexture1 [[id(13)]];
|
||||
sampler uColorTexture1Smplr [[id(14)]];
|
||||
texture2d<float> uDestTexture [[id(15)]];
|
||||
sampler uDestTextureSmplr [[id(16)]];
|
||||
constant int* uCtrl [[id(17)]];
|
||||
};
|
||||
|
||||
constant float3 _862 = {};
|
||||
constant float3 _1003 = {};
|
||||
|
||||
struct main0_out
|
||||
{
|
||||
|
@ -68,6 +68,42 @@ float sampleMask(thread const float& maskAlpha, thread const texture2d<float> ma
|
|||
return fast::min(maskAlpha, coverage);
|
||||
}
|
||||
|
||||
float4 filterRadialGradient(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTextureSize, thread const float2& fragCoord, thread const float2& framebufferSize, thread const float4& filterParams0, thread const float4& filterParams1)
|
||||
{
|
||||
float2 lineFrom = filterParams0.xy;
|
||||
float2 lineVector = filterParams0.zw;
|
||||
float2 radii = filterParams1.xy;
|
||||
float2 uvOrigin = filterParams1.zw;
|
||||
float2 dP = fragCoord - lineFrom;
|
||||
float2 dC = lineVector;
|
||||
float dR = radii.y - radii.x;
|
||||
float a = dot(dC, dC) - (dR * dR);
|
||||
float b = dot(dP, dC) + (radii.x * dR);
|
||||
float c = dot(dP, dP) - (radii.x * radii.x);
|
||||
float discrim = (b * b) - (a * c);
|
||||
float4 color = float4(0.0);
|
||||
if (abs(discrim) >= 9.9999997473787516355514526367188e-06)
|
||||
{
|
||||
float2 ts = float2((float2(1.0, -1.0) * sqrt(discrim)) + float2(b)) / float2(a);
|
||||
float tMax = fast::max(ts.x, ts.y);
|
||||
float _511;
|
||||
if (tMax <= 1.0)
|
||||
{
|
||||
_511 = tMax;
|
||||
}
|
||||
else
|
||||
{
|
||||
_511 = fast::min(ts.x, ts.y);
|
||||
}
|
||||
float t = _511;
|
||||
if (t >= 0.0)
|
||||
{
|
||||
color = colorTexture.sample(colorTextureSmplr, (uvOrigin + float2(t, 0.0)));
|
||||
}
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
float4 filterBlur(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTextureSize, thread const float4& filterParams0, thread const float4& filterParams1)
|
||||
{
|
||||
float2 srcOffsetScale = filterParams0.xy / colorTextureSize;
|
||||
|
@ -75,19 +111,19 @@ float4 filterBlur(thread const float2& colorTexCoord, thread const texture2d<flo
|
|||
float3 gaussCoeff = filterParams1.xyz;
|
||||
float gaussSum = gaussCoeff.x;
|
||||
float4 color = colorTexture.sample(colorTextureSmplr, colorTexCoord) * gaussCoeff.x;
|
||||
float2 _435 = gaussCoeff.xy * gaussCoeff.yz;
|
||||
gaussCoeff = float3(_435.x, _435.y, gaussCoeff.z);
|
||||
float2 _561 = gaussCoeff.xy * gaussCoeff.yz;
|
||||
gaussCoeff = float3(_561.x, _561.y, gaussCoeff.z);
|
||||
for (int i = 1; i <= support; i += 2)
|
||||
{
|
||||
float gaussPartialSum = gaussCoeff.x;
|
||||
float2 _455 = gaussCoeff.xy * gaussCoeff.yz;
|
||||
gaussCoeff = float3(_455.x, _455.y, gaussCoeff.z);
|
||||
float2 _581 = gaussCoeff.xy * gaussCoeff.yz;
|
||||
gaussCoeff = float3(_581.x, _581.y, gaussCoeff.z);
|
||||
gaussPartialSum += gaussCoeff.x;
|
||||
float2 srcOffset = srcOffsetScale * (float(i) + (gaussCoeff.x / gaussPartialSum));
|
||||
color += ((colorTexture.sample(colorTextureSmplr, (colorTexCoord - srcOffset)) + colorTexture.sample(colorTextureSmplr, (colorTexCoord + srcOffset))) * gaussPartialSum);
|
||||
gaussSum += (2.0 * gaussPartialSum);
|
||||
float2 _495 = gaussCoeff.xy * gaussCoeff.yz;
|
||||
gaussCoeff = float3(_495.x, _495.y, gaussCoeff.z);
|
||||
float2 _621 = gaussCoeff.xy * gaussCoeff.yz;
|
||||
gaussCoeff = float3(_621.x, _621.y, gaussCoeff.z);
|
||||
}
|
||||
return color / float4(gaussSum);
|
||||
}
|
||||
|
@ -100,16 +136,16 @@ float filterTextSample1Tap(thread const float& offset, thread const texture2d<fl
|
|||
void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCenter, thread float4& outAlphaRight, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const float2& colorTexCoord, thread const float4& kernel0, thread const float& onePixel)
|
||||
{
|
||||
bool wide = kernel0.x > 0.0;
|
||||
float _183;
|
||||
float _195;
|
||||
if (wide)
|
||||
{
|
||||
float param = (-4.0) * onePixel;
|
||||
float2 param_1 = colorTexCoord;
|
||||
_183 = filterTextSample1Tap(param, colorTexture, colorTextureSmplr, param_1);
|
||||
_195 = filterTextSample1Tap(param, colorTexture, colorTextureSmplr, param_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
_183 = 0.0;
|
||||
_195 = 0.0;
|
||||
}
|
||||
float param_2 = (-3.0) * onePixel;
|
||||
float2 param_3 = colorTexCoord;
|
||||
|
@ -117,7 +153,7 @@ void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCen
|
|||
float2 param_5 = colorTexCoord;
|
||||
float param_6 = (-1.0) * onePixel;
|
||||
float2 param_7 = colorTexCoord;
|
||||
outAlphaLeft = float4(_183, filterTextSample1Tap(param_2, colorTexture, colorTextureSmplr, param_3), filterTextSample1Tap(param_4, colorTexture, colorTextureSmplr, param_5), filterTextSample1Tap(param_6, colorTexture, colorTextureSmplr, param_7));
|
||||
outAlphaLeft = float4(_195, filterTextSample1Tap(param_2, colorTexture, colorTextureSmplr, param_3), filterTextSample1Tap(param_4, colorTexture, colorTextureSmplr, param_5), filterTextSample1Tap(param_6, colorTexture, colorTextureSmplr, param_7));
|
||||
float param_8 = 0.0;
|
||||
float2 param_9 = colorTexCoord;
|
||||
outAlphaCenter = filterTextSample1Tap(param_8, colorTexture, colorTextureSmplr, param_9);
|
||||
|
@ -127,18 +163,18 @@ void filterTextSample9Tap(thread float4& outAlphaLeft, thread float& outAlphaCen
|
|||
float2 param_13 = colorTexCoord;
|
||||
float param_14 = 3.0 * onePixel;
|
||||
float2 param_15 = colorTexCoord;
|
||||
float _243;
|
||||
float _255;
|
||||
if (wide)
|
||||
{
|
||||
float param_16 = 4.0 * onePixel;
|
||||
float2 param_17 = colorTexCoord;
|
||||
_243 = filterTextSample1Tap(param_16, colorTexture, colorTextureSmplr, param_17);
|
||||
_255 = filterTextSample1Tap(param_16, colorTexture, colorTextureSmplr, param_17);
|
||||
}
|
||||
else
|
||||
{
|
||||
_243 = 0.0;
|
||||
_255 = 0.0;
|
||||
}
|
||||
outAlphaRight = float4(filterTextSample1Tap(param_10, colorTexture, colorTextureSmplr, param_11), filterTextSample1Tap(param_12, colorTexture, colorTextureSmplr, param_13), filterTextSample1Tap(param_14, colorTexture, colorTextureSmplr, param_15), _243);
|
||||
outAlphaRight = float4(filterTextSample1Tap(param_10, colorTexture, colorTextureSmplr, param_11), filterTextSample1Tap(param_12, colorTexture, colorTextureSmplr, param_13), filterTextSample1Tap(param_14, colorTexture, colorTextureSmplr, param_15), _255);
|
||||
}
|
||||
|
||||
float filterTextConvolve7Tap(thread const float4& alpha0, thread const float3& alpha1, thread const float4& kernel0)
|
||||
|
@ -219,30 +255,40 @@ float4 filterNone(thread const float2& colorTexCoord, thread const texture2d<flo
|
|||
return sampleColor(colorTexture, colorTextureSmplr, param);
|
||||
}
|
||||
|
||||
float4 filterColor(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2, thread const int& colorFilter)
|
||||
float4 filterColor(thread const float2& colorTexCoord, thread const texture2d<float> colorTexture, thread const sampler colorTextureSmplr, thread const texture2d<float> gammaLUT, thread const sampler gammaLUTSmplr, thread const float2& colorTextureSize, thread const float2& fragCoord, thread const float2& framebufferSize, thread const float4& filterParams0, thread const float4& filterParams1, thread const float4& filterParams2, thread const int& colorFilter)
|
||||
{
|
||||
switch (colorFilter)
|
||||
{
|
||||
case 3:
|
||||
case 1:
|
||||
{
|
||||
float2 param = colorTexCoord;
|
||||
float2 param_1 = colorTextureSize;
|
||||
float4 param_2 = filterParams0;
|
||||
float4 param_3 = filterParams1;
|
||||
return filterBlur(param, colorTexture, colorTextureSmplr, param_1, param_2, param_3);
|
||||
float2 param_2 = fragCoord;
|
||||
float2 param_3 = framebufferSize;
|
||||
float4 param_4 = filterParams0;
|
||||
float4 param_5 = filterParams1;
|
||||
return filterRadialGradient(param, colorTexture, colorTextureSmplr, param_1, param_2, param_3, param_4, param_5);
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
float2 param_6 = colorTexCoord;
|
||||
float2 param_7 = colorTextureSize;
|
||||
float4 param_8 = filterParams0;
|
||||
float4 param_9 = filterParams1;
|
||||
return filterBlur(param_6, colorTexture, colorTextureSmplr, param_7, param_8, param_9);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
float2 param_4 = colorTexCoord;
|
||||
float2 param_5 = colorTextureSize;
|
||||
float4 param_6 = filterParams0;
|
||||
float4 param_7 = filterParams1;
|
||||
float4 param_8 = filterParams2;
|
||||
return filterText(param_4, colorTexture, colorTextureSmplr, gammaLUT, gammaLUTSmplr, param_5, param_6, param_7, param_8);
|
||||
float2 param_10 = colorTexCoord;
|
||||
float2 param_11 = colorTextureSize;
|
||||
float4 param_12 = filterParams0;
|
||||
float4 param_13 = filterParams1;
|
||||
float4 param_14 = filterParams2;
|
||||
return filterText(param_10, colorTexture, colorTextureSmplr, gammaLUT, gammaLUTSmplr, param_11, param_12, param_13, param_14);
|
||||
}
|
||||
}
|
||||
float2 param_9 = colorTexCoord;
|
||||
return filterNone(param_9, colorTexture, colorTextureSmplr);
|
||||
float2 param_15 = colorTexCoord;
|
||||
return filterNone(param_15, colorTexture, colorTextureSmplr);
|
||||
}
|
||||
|
||||
float3 compositeScreen(thread const float3& destColor, thread const float3& srcColor)
|
||||
|
@ -252,34 +298,34 @@ float3 compositeScreen(thread const float3& destColor, thread const float3& srcC
|
|||
|
||||
float3 compositeSelect(thread const bool3& cond, thread const float3& ifTrue, thread const float3& ifFalse)
|
||||
{
|
||||
float _546;
|
||||
float _687;
|
||||
if (cond.x)
|
||||
{
|
||||
_546 = ifTrue.x;
|
||||
_687 = ifTrue.x;
|
||||
}
|
||||
else
|
||||
{
|
||||
_546 = ifFalse.x;
|
||||
_687 = ifFalse.x;
|
||||
}
|
||||
float _557;
|
||||
float _698;
|
||||
if (cond.y)
|
||||
{
|
||||
_557 = ifTrue.y;
|
||||
_698 = ifTrue.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
_557 = ifFalse.y;
|
||||
_698 = ifFalse.y;
|
||||
}
|
||||
float _568;
|
||||
float _709;
|
||||
if (cond.z)
|
||||
{
|
||||
_568 = ifTrue.z;
|
||||
_709 = ifTrue.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
_568 = ifFalse.z;
|
||||
_709 = ifFalse.z;
|
||||
}
|
||||
return float3(_546, _557, _568);
|
||||
return float3(_687, _698, _709);
|
||||
}
|
||||
|
||||
float3 compositeHardLight(thread const float3& destColor, thread const float3& srcColor)
|
||||
|
@ -320,16 +366,16 @@ float3 compositeSoftLight(thread const float3& destColor, thread const float3& s
|
|||
|
||||
float compositeDivide(thread const float& num, thread const float& denom)
|
||||
{
|
||||
float _582;
|
||||
float _723;
|
||||
if (denom != 0.0)
|
||||
{
|
||||
_582 = num / denom;
|
||||
_723 = num / denom;
|
||||
}
|
||||
else
|
||||
{
|
||||
_582 = 0.0;
|
||||
_723 = 0.0;
|
||||
}
|
||||
return _582;
|
||||
return _723;
|
||||
}
|
||||
|
||||
float3 compositeRGBToHSL(thread const float3& rgb)
|
||||
|
@ -338,25 +384,25 @@ float3 compositeRGBToHSL(thread const float3& rgb)
|
|||
float xMin = fast::min(fast::min(rgb.x, rgb.y), rgb.z);
|
||||
float c = v - xMin;
|
||||
float l = mix(xMin, v, 0.5);
|
||||
float3 _688;
|
||||
float3 _829;
|
||||
if (rgb.x == v)
|
||||
{
|
||||
_688 = float3(0.0, rgb.yz);
|
||||
_829 = float3(0.0, rgb.yz);
|
||||
}
|
||||
else
|
||||
{
|
||||
float3 _701;
|
||||
float3 _842;
|
||||
if (rgb.y == v)
|
||||
{
|
||||
_701 = float3(2.0, rgb.zx);
|
||||
_842 = float3(2.0, rgb.zx);
|
||||
}
|
||||
else
|
||||
{
|
||||
_701 = float3(4.0, rgb.xy);
|
||||
_842 = float3(4.0, rgb.xy);
|
||||
}
|
||||
_688 = _701;
|
||||
_829 = _842;
|
||||
}
|
||||
float3 terms = _688;
|
||||
float3 terms = _829;
|
||||
float param = ((terms.x * c) + terms.y) - terms.z;
|
||||
float param_1 = c;
|
||||
float h = 1.0471975803375244140625 * compositeDivide(param, param_1);
|
||||
|
@ -488,7 +534,7 @@ float4 composite(thread const float4& srcColor, thread const texture2d<float> de
|
|||
return float4(((srcColor.xyz * (srcColor.w * (1.0 - destColor.w))) + (blendedRGB * (srcColor.w * destColor.w))) + (destColor.xyz * (1.0 - srcColor.w)), 1.0);
|
||||
}
|
||||
|
||||
void calculateColor(thread const int& ctrl, thread texture2d<float> uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float3& vMaskTexCoord0, thread texture2d<float> uMaskTexture1, thread const sampler uMaskTexture1Smplr, thread float3& vMaskTexCoord1, thread float2& vColorTexCoord0, thread texture2d<float> uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d<float> uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTexture0Size, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread texture2d<float> uColorTexture1, thread const sampler uColorTexture1Smplr, thread float2& vColorTexCoord1, thread texture2d<float> uDestTexture, thread const sampler uDestTextureSmplr, thread float2 uDestTextureSize, thread float4& gl_FragCoord, thread float4& oFragColor)
|
||||
void calculateColor(thread const int& ctrl, thread texture2d<float> uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float3& vMaskTexCoord0, thread texture2d<float> uMaskTexture1, thread const sampler uMaskTexture1Smplr, thread float3& vMaskTexCoord1, thread float2& vColorTexCoord0, thread texture2d<float> uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d<float> uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTexture0Size, thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread texture2d<float> uColorTexture1, thread const sampler uColorTexture1Smplr, thread float2& vColorTexCoord1, thread texture2d<float> uDestTexture, thread const sampler uDestTextureSmplr, thread float4& oFragColor)
|
||||
{
|
||||
int maskCtrl0 = (ctrl >> 0) & 3;
|
||||
int maskCtrl1 = (ctrl >> 2) & 3;
|
||||
|
@ -507,26 +553,28 @@ void calculateColor(thread const int& ctrl, thread texture2d<float> uMaskTexture
|
|||
int color0Filter = (ctrl >> 4) & 3;
|
||||
float2 param_6 = vColorTexCoord0;
|
||||
float2 param_7 = uColorTexture0Size;
|
||||
float4 param_8 = uFilterParams0;
|
||||
float4 param_9 = uFilterParams1;
|
||||
float4 param_10 = uFilterParams2;
|
||||
int param_11 = color0Filter;
|
||||
color += filterColor(param_6, uColorTexture0, uColorTexture0Smplr, uGammaLUT, uGammaLUTSmplr, param_7, param_8, param_9, param_10, param_11);
|
||||
float2 param_8 = gl_FragCoord.xy;
|
||||
float2 param_9 = uFramebufferSize;
|
||||
float4 param_10 = uFilterParams0;
|
||||
float4 param_11 = uFilterParams1;
|
||||
float4 param_12 = uFilterParams2;
|
||||
int param_13 = color0Filter;
|
||||
color += filterColor(param_6, uColorTexture0, uColorTexture0Smplr, uGammaLUT, uGammaLUTSmplr, param_7, param_8, param_9, param_10, param_11, param_12, param_13);
|
||||
}
|
||||
if (((ctrl >> 7) & 1) != 0)
|
||||
{
|
||||
float2 param_12 = vColorTexCoord1;
|
||||
color *= sampleColor(uColorTexture1, uColorTexture1Smplr, param_12);
|
||||
float2 param_14 = vColorTexCoord1;
|
||||
color *= sampleColor(uColorTexture1, uColorTexture1Smplr, param_14);
|
||||
}
|
||||
color.w *= maskAlpha;
|
||||
int compositeOp = (ctrl >> 8) & 15;
|
||||
float4 param_13 = color;
|
||||
float2 param_14 = uDestTextureSize;
|
||||
float2 param_15 = gl_FragCoord.xy;
|
||||
int param_16 = compositeOp;
|
||||
color = composite(param_13, uDestTexture, uDestTextureSmplr, param_14, param_15, param_16);
|
||||
float3 _1159 = color.xyz * color.w;
|
||||
color = float4(_1159.x, _1159.y, _1159.z, color.w);
|
||||
float4 param_15 = color;
|
||||
float2 param_16 = uFramebufferSize;
|
||||
float2 param_17 = gl_FragCoord.xy;
|
||||
int param_18 = compositeOp;
|
||||
color = composite(param_15, uDestTexture, uDestTextureSmplr, param_16, param_17, param_18);
|
||||
float3 _1304 = color.xyz * color.w;
|
||||
color = float4(_1304.x, _1304.y, _1304.z, color.w);
|
||||
oFragColor = color;
|
||||
}
|
||||
|
||||
|
@ -534,7 +582,7 @@ fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuff
|
|||
{
|
||||
main0_out out = {};
|
||||
int param = (*spvDescriptorSet0.uCtrl);
|
||||
calculateColor(param, spvDescriptorSet0.uMaskTexture0, spvDescriptorSet0.uMaskTexture0Smplr, in.vMaskTexCoord0, spvDescriptorSet0.uMaskTexture1, spvDescriptorSet0.uMaskTexture1Smplr, in.vMaskTexCoord1, in.vColorTexCoord0, spvDescriptorSet0.uColorTexture0, spvDescriptorSet0.uColorTexture0Smplr, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr, (*spvDescriptorSet0.uColorTexture0Size), (*spvDescriptorSet0.uFilterParams0), (*spvDescriptorSet0.uFilterParams1), (*spvDescriptorSet0.uFilterParams2), spvDescriptorSet0.uColorTexture1, spvDescriptorSet0.uColorTexture1Smplr, in.vColorTexCoord1, spvDescriptorSet0.uDestTexture, spvDescriptorSet0.uDestTextureSmplr, (*spvDescriptorSet0.uDestTextureSize), gl_FragCoord, out.oFragColor);
|
||||
calculateColor(param, spvDescriptorSet0.uMaskTexture0, spvDescriptorSet0.uMaskTexture0Smplr, in.vMaskTexCoord0, spvDescriptorSet0.uMaskTexture1, spvDescriptorSet0.uMaskTexture1Smplr, in.vMaskTexCoord1, in.vColorTexCoord0, spvDescriptorSet0.uColorTexture0, spvDescriptorSet0.uColorTexture0Smplr, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr, (*spvDescriptorSet0.uColorTexture0Size), gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), (*spvDescriptorSet0.uFilterParams0), (*spvDescriptorSet0.uFilterParams1), (*spvDescriptorSet0.uFilterParams2), spvDescriptorSet0.uColorTexture1, spvDescriptorSet0.uColorTexture1Smplr, in.vColorTexCoord1, spvDescriptorSet0.uDestTexture, spvDescriptorSet0.uDestTextureSmplr, out.oFragColor);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
precision highp float;
|
||||
|
||||
#define EPSILON 0.00001
|
||||
|
||||
#define FRAC_6_PI 1.9098593171027443
|
||||
#define FRAC_PI_3 1.0471975511965976
|
||||
|
||||
|
@ -83,7 +85,7 @@ uniform sampler2D uGammaLUT;
|
|||
uniform vec4 uFilterParams0;
|
||||
uniform vec4 uFilterParams1;
|
||||
uniform vec4 uFilterParams2;
|
||||
uniform vec2 uDestTextureSize;
|
||||
uniform vec2 uFramebufferSize;
|
||||
uniform vec2 uColorTexture0Size;
|
||||
uniform int uCtrl;
|
||||
|
||||
|
@ -193,7 +195,129 @@ vec4 filterText(vec2 colorTexCoord,
|
|||
return vec4(mix(bgColor, fgColor, alpha), 1.0);
|
||||
}
|
||||
|
||||
// Filters
|
||||
// Other filters
|
||||
|
||||
// This is based on Pixman (MIT license). Copy and pasting the excellent comment
|
||||
// from there:
|
||||
|
||||
// Implementation of radial gradients following the PDF specification.
|
||||
// See section 8.7.4.5.4 Type 3 (Radial) Shadings of the PDF Reference
|
||||
// Manual (PDF 32000-1:2008 at the time of this writing).
|
||||
//
|
||||
// In the radial gradient problem we are given two circles (c₁,r₁) and
|
||||
// (c₂,r₂) that define the gradient itself.
|
||||
//
|
||||
// Mathematically the gradient can be defined as the family of circles
|
||||
//
|
||||
// ((1-t)·c₁ + t·(c₂), (1-t)·r₁ + t·r₂)
|
||||
//
|
||||
// excluding those circles whose radius would be < 0. When a point
|
||||
// belongs to more than one circle, the one with a bigger t is the only
|
||||
// one that contributes to its color. When a point does not belong
|
||||
// to any of the circles, it is transparent black, i.e. RGBA (0, 0, 0, 0).
|
||||
// Further limitations on the range of values for t are imposed when
|
||||
// the gradient is not repeated, namely t must belong to [0,1].
|
||||
//
|
||||
// The graphical result is the same as drawing the valid (radius > 0)
|
||||
// circles with increasing t in [-∞, +∞] (or in [0,1] if the gradient
|
||||
// is not repeated) using SOURCE operator composition.
|
||||
//
|
||||
// It looks like a cone pointing towards the viewer if the ending circle
|
||||
// is smaller than the starting one, a cone pointing inside the page if
|
||||
// the starting circle is the smaller one and like a cylinder if they
|
||||
// have the same radius.
|
||||
//
|
||||
// What we actually do is, given the point whose color we are interested
|
||||
// in, compute the t values for that point, solving for t in:
|
||||
//
|
||||
// length((1-t)·c₁ + t·(c₂) - p) = (1-t)·r₁ + t·r₂
|
||||
//
|
||||
// Let's rewrite it in a simpler way, by defining some auxiliary
|
||||
// variables:
|
||||
//
|
||||
// cd = c₂ - c₁
|
||||
// pd = p - c₁
|
||||
// dr = r₂ - r₁
|
||||
// length(t·cd - pd) = r₁ + t·dr
|
||||
//
|
||||
// which actually means
|
||||
//
|
||||
// hypot(t·cdx - pdx, t·cdy - pdy) = r₁ + t·dr
|
||||
//
|
||||
// or
|
||||
//
|
||||
// ⎷((t·cdx - pdx)² + (t·cdy - pdy)²) = r₁ + t·dr.
|
||||
//
|
||||
// If we impose (as stated earlier) that r₁ + t·dr ≥ 0, it becomes:
|
||||
//
|
||||
// (t·cdx - pdx)² + (t·cdy - pdy)² = (r₁ + t·dr)²
|
||||
//
|
||||
// where we can actually expand the squares and solve for t:
|
||||
//
|
||||
// t²cdx² - 2t·cdx·pdx + pdx² + t²cdy² - 2t·cdy·pdy + pdy² =
|
||||
// = r₁² + 2·r₁·t·dr + t²·dr²
|
||||
//
|
||||
// (cdx² + cdy² - dr²)t² - 2(cdx·pdx + cdy·pdy + r₁·dr)t +
|
||||
// (pdx² + pdy² - r₁²) = 0
|
||||
//
|
||||
// A = cdx² + cdy² - dr²
|
||||
// B = pdx·cdx + pdy·cdy + r₁·dr
|
||||
// C = pdx² + pdy² - r₁²
|
||||
// At² - 2Bt + C = 0
|
||||
//
|
||||
// The solutions (unless the equation degenerates because of A = 0) are:
|
||||
//
|
||||
// t = (B ± ⎷(B² - A·C)) / A
|
||||
//
|
||||
// The solution we are going to prefer is the bigger one, unless the
|
||||
// radius associated to it is negative (or it falls outside the valid t
|
||||
// range).
|
||||
//
|
||||
// Additional observations (useful for optimizations):
|
||||
// A does not depend on p
|
||||
//
|
||||
// A < 0 ⟺ one of the two circles completely contains the other one
|
||||
// ⟺ for every p, the radii associated with the two t solutions have
|
||||
// opposite sign
|
||||
//
|
||||
// | x y z w
|
||||
// --------------+-------------------------------------------
|
||||
// filterParams0 | lineFrom.x lineFrom.y lineVector.x lineVector.y
|
||||
// filterParams1 | radii.x radii.y uvOrigin.x uvOrigin.y
|
||||
// filterParams2 | - - - -
|
||||
vec4 filterRadialGradient(vec2 colorTexCoord,
|
||||
sampler2D colorTexture,
|
||||
vec2 colorTextureSize,
|
||||
vec2 fragCoord,
|
||||
vec2 framebufferSize,
|
||||
vec4 filterParams0,
|
||||
vec4 filterParams1) {
|
||||
vec2 lineFrom = filterParams0.xy, lineVector = filterParams0.zw;
|
||||
vec2 radii = filterParams1.xy, uvOrigin = filterParams1.zw;
|
||||
|
||||
#ifndef PF_ORIGIN_UPPER_LEFT
|
||||
fragCoord.y = framebufferSize.y - fragCoord.y;
|
||||
#endif
|
||||
|
||||
vec2 dP = fragCoord - lineFrom, dC = lineVector;
|
||||
float dR = radii.y - radii.x;
|
||||
|
||||
float a = dot(dC, dC) - dR * dR;
|
||||
float b = dot(dP, dC) + radii.x * dR;
|
||||
float c = dot(dP, dP) - radii.x * radii.x;
|
||||
float discrim = b * b - a * c;
|
||||
|
||||
vec4 color = vec4(0.0);
|
||||
if (abs(discrim) >= EPSILON) {
|
||||
vec2 ts = vec2(sqrt(discrim) * vec2(1.0, -1.0) + vec2(b)) / vec2(a);
|
||||
float tMax = max(ts.x, ts.y);
|
||||
float t = tMax <= 1.0 ? tMax : min(ts.x, ts.y);
|
||||
if (t >= 0.0)
|
||||
color = texture(colorTexture, uvOrigin + vec2(t, 0.0));
|
||||
}
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
// | x y z w
|
||||
// --------------+----------------------------------------------------
|
||||
|
@ -248,11 +372,21 @@ vec4 filterColor(vec2 colorTexCoord,
|
|||
sampler2D colorTexture,
|
||||
sampler2D gammaLUT,
|
||||
vec2 colorTextureSize,
|
||||
vec2 fragCoord,
|
||||
vec2 framebufferSize,
|
||||
vec4 filterParams0,
|
||||
vec4 filterParams1,
|
||||
vec4 filterParams2,
|
||||
int colorFilter) {
|
||||
switch (colorFilter) {
|
||||
case COMBINER_CTRL_FILTER_RADIAL_GRADIENT:
|
||||
return filterRadialGradient(colorTexCoord,
|
||||
colorTexture,
|
||||
colorTextureSize,
|
||||
fragCoord,
|
||||
framebufferSize,
|
||||
filterParams0,
|
||||
filterParams1);
|
||||
case COMBINER_CTRL_FILTER_BLUR:
|
||||
return filterBlur(colorTexCoord,
|
||||
colorTexture,
|
||||
|
@ -431,6 +565,8 @@ void calculateColor(int ctrl) {
|
|||
uColorTexture0,
|
||||
uGammaLUT,
|
||||
uColorTexture0Size,
|
||||
gl_FragCoord.xy,
|
||||
uFramebufferSize,
|
||||
uFilterParams0,
|
||||
uFilterParams1,
|
||||
uFilterParams2,
|
||||
|
@ -444,7 +580,7 @@ void calculateColor(int ctrl) {
|
|||
|
||||
// Apply composite.
|
||||
int compositeOp = (ctrl >> COMBINER_CTRL_COMPOSITE_SHIFT) & COMBINER_CTRL_COMPOSITE_MASK;
|
||||
color = composite(color, uDestTexture, uDestTextureSize, gl_FragCoord.xy, compositeOp);
|
||||
color = composite(color, uDestTexture, uFramebufferSize, gl_FragCoord.xy, compositeOp);
|
||||
|
||||
// Premultiply alpha.
|
||||
color.rgb *= color.a;
|
||||
|
|
Loading…
Reference in New Issue