diff --git a/canvas/src/lib.rs b/canvas/src/lib.rs index bee13e10..161b12e2 100644 --- a/canvas/src/lib.rs +++ b/canvas/src/lib.rs @@ -542,6 +542,8 @@ pub enum CompositeOperation { ColorBurn, HardLight, SoftLight, + Difference, + Exclusion, Hue, Saturation, Color, @@ -570,6 +572,8 @@ impl CompositeOperation { CompositeOperation::ColorBurn => BlendMode::ColorBurn, CompositeOperation::HardLight => BlendMode::HardLight, CompositeOperation::SoftLight => BlendMode::SoftLight, + CompositeOperation::Difference => BlendMode::Difference, + CompositeOperation::Exclusion => BlendMode::Exclusion, CompositeOperation::Hue => BlendMode::Hue, CompositeOperation::Saturation => BlendMode::Saturation, CompositeOperation::Color => BlendMode::Color, diff --git a/content/src/effects.rs b/content/src/effects.rs index 84da569d..b7d00845 100644 --- a/content/src/effects.rs +++ b/content/src/effects.rs @@ -94,6 +94,12 @@ pub enum BlendMode { // Soft light SoftLight, + // Difference + Difference, + + // Exclusion + Exclusion, + // HSL Hue, Saturation, @@ -143,6 +149,8 @@ impl BlendMode { BlendMode::ColorDodge | BlendMode::ColorBurn | BlendMode::SoftLight | + BlendMode::Difference | + BlendMode::Exclusion | BlendMode::Hue | BlendMode::Saturation | BlendMode::Color | diff --git a/renderer/src/gpu/renderer.rs b/renderer/src/gpu/renderer.rs index 0d851cd1..dd3374b6 100644 --- a/renderer/src/gpu/renderer.rs +++ b/renderer/src/gpu/renderer.rs @@ -88,6 +88,8 @@ where alpha_tile_overlay_program: AlphaTileOverlayProgram, alpha_tile_dodgeburn_program: AlphaTileDodgeBurnProgram, alpha_tile_softlight_program: AlphaTileBlendModeProgram, + alpha_tile_difference_program: AlphaTileBlendModeProgram, + alpha_tile_exclusion_program: AlphaTileBlendModeProgram, alpha_tile_hsl_program: AlphaTileHSLProgram, mask_winding_tile_vertex_array: MaskTileVertexArray, mask_evenodd_tile_vertex_array: MaskTileVertexArray, @@ -98,6 +100,8 @@ where alpha_tile_overlay_vertex_array: AlphaTileVertexArray, alpha_tile_dodgeburn_vertex_array: AlphaTileVertexArray, alpha_tile_softlight_vertex_array: AlphaTileVertexArray, + alpha_tile_difference_vertex_array: AlphaTileVertexArray, + alpha_tile_exclusion_vertex_array: AlphaTileVertexArray, alpha_tile_hsl_vertex_array: AlphaTileVertexArray, area_lut_texture: D::Texture, alpha_tile_vertex_buffer: D::Buffer, @@ -175,6 +179,11 @@ where let alpha_tile_softlight_program = AlphaTileBlendModeProgram::new(&device, resources, "tile_alpha_softlight"); + let alpha_tile_difference_program = + AlphaTileBlendModeProgram::new(&device, resources, "tile_alpha_difference"); + let alpha_tile_exclusion_program = AlphaTileBlendModeProgram::new(&device, + resources, + "tile_alpha_exclusion"); let alpha_tile_hsl_program = AlphaTileHSLProgram::new(&device, resources); let filter_basic_program = FilterBasicProgram::new(&device, resources); let filter_text_program = FilterTextProgram::new(&device, resources); @@ -253,6 +262,18 @@ where &alpha_tile_vertex_buffer, &quads_vertex_indices_buffer, ); + let alpha_tile_difference_vertex_array = AlphaTileVertexArray::new( + &device, + &alpha_tile_difference_program.alpha_tile_program, + &alpha_tile_vertex_buffer, + &quads_vertex_indices_buffer, + ); + let alpha_tile_exclusion_vertex_array = AlphaTileVertexArray::new( + &device, + &alpha_tile_exclusion_program.alpha_tile_program, + &alpha_tile_vertex_buffer, + &quads_vertex_indices_buffer, + ); let alpha_tile_hsl_vertex_array = AlphaTileVertexArray::new( &device, &alpha_tile_hsl_program.alpha_tile_blend_mode_program.alpha_tile_program, @@ -324,6 +345,8 @@ where alpha_tile_overlay_program, alpha_tile_dodgeburn_program, alpha_tile_softlight_program, + alpha_tile_difference_program, + alpha_tile_exclusion_program, alpha_tile_hsl_program, mask_winding_tile_vertex_array, mask_evenodd_tile_vertex_array, @@ -334,6 +357,8 @@ where alpha_tile_overlay_vertex_array, alpha_tile_dodgeburn_vertex_array, alpha_tile_softlight_vertex_array, + alpha_tile_difference_vertex_array, + alpha_tile_exclusion_vertex_array, alpha_tile_hsl_vertex_array, area_lut_texture, alpha_tile_vertex_buffer, @@ -786,6 +811,14 @@ where (&self.alpha_tile_softlight_program.alpha_tile_program, &self.alpha_tile_softlight_vertex_array) } + BlendModeProgram::Difference => { + (&self.alpha_tile_difference_program.alpha_tile_program, + &self.alpha_tile_difference_vertex_array) + } + BlendModeProgram::Exclusion => { + (&self.alpha_tile_exclusion_program.alpha_tile_program, + &self.alpha_tile_exclusion_vertex_array) + } BlendModeProgram::HSL => { (&self.alpha_tile_hsl_program.alpha_tile_blend_mode_program.alpha_tile_program, &self.alpha_tile_hsl_vertex_array) @@ -838,6 +871,16 @@ where &mut uniforms, &self.alpha_tile_softlight_program); } + BlendModeProgram::Difference => { + self.set_uniforms_for_blend_mode(&mut textures, + &mut uniforms, + &self.alpha_tile_difference_program); + } + BlendModeProgram::Exclusion => { + self.set_uniforms_for_blend_mode(&mut textures, + &mut uniforms, + &self.alpha_tile_exclusion_program); + } BlendModeProgram::HSL => { self.set_uniforms_for_hsl_blend_mode(&mut textures, &mut uniforms, blend_mode); } @@ -1586,6 +1629,8 @@ impl BlendModeExt for BlendMode { BlendMode::ColorDodge | BlendMode::ColorBurn | BlendMode::SoftLight | + BlendMode::Difference | + BlendMode::Exclusion | BlendMode::Hue | BlendMode::Saturation | BlendMode::Color | @@ -1604,6 +1649,8 @@ pub(crate) enum BlendModeProgram { Overlay, DodgeBurn, SoftLight, + Difference, + Exclusion, HSL, } @@ -1630,6 +1677,8 @@ impl BlendModeProgram { BlendMode::ColorDodge | BlendMode::ColorBurn => BlendModeProgram::DodgeBurn, BlendMode::SoftLight => BlendModeProgram::SoftLight, + BlendMode::Difference => BlendModeProgram::Difference, + BlendMode::Exclusion => BlendModeProgram::Exclusion, BlendMode::Hue | BlendMode::Saturation | BlendMode::Color | @@ -1644,6 +1693,8 @@ impl BlendModeProgram { BlendModeProgram::Overlay | BlendModeProgram::DodgeBurn | BlendModeProgram::SoftLight | + BlendModeProgram::Difference | + BlendModeProgram::Exclusion | BlendModeProgram::HSL => true, } } diff --git a/resources/shaders/gl3/tile_alpha_difference.fs.glsl b/resources/shaders/gl3/tile_alpha_difference.fs.glsl new file mode 100644 index 00000000..686c90e9 --- /dev/null +++ b/resources/shaders/gl3/tile_alpha_difference.fs.glsl @@ -0,0 +1,75 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + + + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; + +out vec4 oFragColor; + + + + + + + + + + + + +uniform sampler2D uStencilTexture; +uniform sampler2D uPaintTexture; +uniform sampler2D uDest; +uniform vec2 uFramebufferSize; + +in vec2 vColorTexCoord; +in vec2 vMaskTexCoord; + + +vec4 sampleSrcColor(){ + float coverage = texture(uStencilTexture, vMaskTexCoord). r; + vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); + return vec4(srcRGBA . rgb, srcRGBA . a * coverage); +} + +vec4 sampleDestColor(){ + vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; + return texture(uDest, destTexCoord); +} + + +vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ + return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + + srcRGBA . a * destRGBA . a * blendedRGB + + (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, + 1.0); +} + +vec3 select3(bvec3 cond, vec3 a, vec3 b){ + return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); +} + + +void main(){ + vec4 srcRGBA = sampleSrcColor(); + vec4 destRGBA = sampleDestColor(); + + vec3 blended = abs(destRGBA . rgb - srcRGBA . rgb); + + oFragColor = blendColors(destRGBA, srcRGBA, blended); +} + diff --git a/resources/shaders/gl3/tile_alpha_exclusion.fs.glsl b/resources/shaders/gl3/tile_alpha_exclusion.fs.glsl new file mode 100644 index 00000000..c830f88e --- /dev/null +++ b/resources/shaders/gl3/tile_alpha_exclusion.fs.glsl @@ -0,0 +1,76 @@ +#version {{version}} +// Automatically generated from files in pathfinder/shaders/. Do not edit! + + + + + + + + + + + + + + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; + +out vec4 oFragColor; + + + + + + + + + + + + +uniform sampler2D uStencilTexture; +uniform sampler2D uPaintTexture; +uniform sampler2D uDest; +uniform vec2 uFramebufferSize; + +in vec2 vColorTexCoord; +in vec2 vMaskTexCoord; + + +vec4 sampleSrcColor(){ + float coverage = texture(uStencilTexture, vMaskTexCoord). r; + vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord); + return vec4(srcRGBA . rgb, srcRGBA . a * coverage); +} + +vec4 sampleDestColor(){ + vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize; + return texture(uDest, destTexCoord); +} + + +vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){ + return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb + + srcRGBA . a * destRGBA . a * blendedRGB + + (1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb, + 1.0); +} + +vec3 select3(bvec3 cond, vec3 a, vec3 b){ + return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z); +} + + +void main(){ + vec4 srcRGBA = sampleSrcColor(); + vec4 destRGBA = sampleDestColor(); + + vec3 dest = destRGBA . rgb, src = srcRGBA . rgb; + vec3 blended = dest + src - dest * src * 2.0; + + oFragColor = blendColors(destRGBA, srcRGBA, blended); +} + diff --git a/resources/shaders/metal/tile_alpha_difference.fs.metal b/resources/shaders/metal/tile_alpha_difference.fs.metal new file mode 100644 index 00000000..a16905fb --- /dev/null +++ b/resources/shaders/metal/tile_alpha_difference.fs.metal @@ -0,0 +1,61 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct spvDescriptorSetBuffer0 +{ + texture2d uStencilTexture [[id(0)]]; + sampler uStencilTextureSmplr [[id(1)]]; + texture2d uPaintTexture [[id(2)]]; + sampler uPaintTextureSmplr [[id(3)]]; + constant float2* uFramebufferSize [[id(4)]]; + texture2d uDest [[id(5)]]; + sampler uDestSmplr [[id(6)]]; +}; + +struct main0_out +{ + float4 oFragColor [[color(0)]]; +}; + +struct main0_in +{ + float2 vColorTexCoord [[user(locn0)]]; + float2 vMaskTexCoord [[user(locn1)]]; +}; + +float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) +{ + float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; + float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); + return float4(srcRGBA.xyz, srcRGBA.w * coverage); +} + +float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) +{ + float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; + return uDest.sample(uDestSmplr, destTexCoord); +} + +float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) +{ + return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); +} + +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); + float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); + float3 blended = abs(destRGBA.xyz - srcRGBA.xyz); + float4 param = destRGBA; + float4 param_1 = srcRGBA; + float3 param_2 = blended; + out.oFragColor = blendColors(param, param_1, param_2); + return out; +} + diff --git a/resources/shaders/metal/tile_alpha_exclusion.fs.metal b/resources/shaders/metal/tile_alpha_exclusion.fs.metal new file mode 100644 index 00000000..63514ee9 --- /dev/null +++ b/resources/shaders/metal/tile_alpha_exclusion.fs.metal @@ -0,0 +1,63 @@ +// Automatically generated from files in pathfinder/shaders/. Do not edit! +#pragma clang diagnostic ignored "-Wmissing-prototypes" + +#include +#include + +using namespace metal; + +struct spvDescriptorSetBuffer0 +{ + texture2d uStencilTexture [[id(0)]]; + sampler uStencilTextureSmplr [[id(1)]]; + texture2d uPaintTexture [[id(2)]]; + sampler uPaintTextureSmplr [[id(3)]]; + constant float2* uFramebufferSize [[id(4)]]; + texture2d uDest [[id(5)]]; + sampler uDestSmplr [[id(6)]]; +}; + +struct main0_out +{ + float4 oFragColor [[color(0)]]; +}; + +struct main0_in +{ + float2 vColorTexCoord [[user(locn0)]]; + float2 vMaskTexCoord [[user(locn1)]]; +}; + +float4 sampleSrcColor(thread texture2d uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord) +{ + float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x; + float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord); + return float4(srcRGBA.xyz, srcRGBA.w * coverage); +} + +float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d uDest, thread const sampler uDestSmplr) +{ + float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize; + return uDest.sample(uDestSmplr, destTexCoord); +} + +float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB) +{ + return float4(((srcRGBA.xyz * (srcRGBA.w * (1.0 - destRGBA.w))) + (blendedRGB * (srcRGBA.w * destRGBA.w))) + (destRGBA.xyz * ((1.0 - srcRGBA.w) * destRGBA.w)), 1.0); +} + +fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]]) +{ + main0_out out = {}; + float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord); + float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr); + float3 dest = destRGBA.xyz; + float3 src = srcRGBA.xyz; + float3 blended = (dest + src) - ((dest * src) * 2.0); + float4 param = destRGBA; + float4 param_1 = srcRGBA; + float3 param_2 = blended; + out.oFragColor = blendColors(param, param_1, param_2); + return out; +} + diff --git a/shaders/Makefile b/shaders/Makefile index 5e1e2ec9..ceb6b138 100644 --- a/shaders/Makefile +++ b/shaders/Makefile @@ -23,7 +23,9 @@ SHADERS=\ stencil.vs.glsl \ tile_alpha.fs.glsl \ tile_alpha.vs.glsl \ + tile_alpha_difference.fs.glsl \ tile_alpha_dodgeburn.fs.glsl \ + tile_alpha_exclusion.fs.glsl \ tile_alpha_hsl.fs.glsl \ tile_alpha_overlay.fs.glsl \ tile_alpha_porterduff.fs.glsl \ diff --git a/shaders/tile_alpha_difference.fs.glsl b/shaders/tile_alpha_difference.fs.glsl new file mode 100644 index 00000000..54d3996d --- /dev/null +++ b/shaders/tile_alpha_difference.fs.glsl @@ -0,0 +1,30 @@ +#version 330 + +// pathfinder/shaders/tile_alpha_difference.fs.glsl +// +// Copyright © 2020 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The difference blend mode. + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; + +out vec4 oFragColor; + +#include "tile_alpha_sample.inc.glsl" + +void main() { + vec4 srcRGBA = sampleSrcColor(); + vec4 destRGBA = sampleDestColor(); + + vec3 blended = abs(destRGBA.rgb - srcRGBA.rgb); + + oFragColor = blendColors(destRGBA, srcRGBA, blended); +} diff --git a/shaders/tile_alpha_exclusion.fs.glsl b/shaders/tile_alpha_exclusion.fs.glsl new file mode 100644 index 00000000..ebf20f27 --- /dev/null +++ b/shaders/tile_alpha_exclusion.fs.glsl @@ -0,0 +1,31 @@ +#version 330 + +// pathfinder/shaders/tile_alpha_exclusion.fs.glsl +// +// Copyright © 2020 The Pathfinder Project Developers. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The exclusion blend mode. + +#extension GL_GOOGLE_include_directive : enable + +precision highp float; + +out vec4 oFragColor; + +#include "tile_alpha_sample.inc.glsl" + +void main() { + vec4 srcRGBA = sampleSrcColor(); + vec4 destRGBA = sampleDestColor(); + + vec3 dest = destRGBA.rgb, src = srcRGBA.rgb; + vec3 blended = dest + src - dest * src * 2.0; + + oFragColor = blendColors(destRGBA, srcRGBA, blended); +}