Implement the difference and exclusion blend modes

This commit is contained in:
Patrick Walton 2020-02-25 14:55:58 -08:00
parent a8e33d3d3d
commit 0a3f64eb44
10 changed files with 401 additions and 0 deletions

View File

@ -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,

View File

@ -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 |

View File

@ -88,6 +88,8 @@ where
alpha_tile_overlay_program: AlphaTileOverlayProgram<D>,
alpha_tile_dodgeburn_program: AlphaTileDodgeBurnProgram<D>,
alpha_tile_softlight_program: AlphaTileBlendModeProgram<D>,
alpha_tile_difference_program: AlphaTileBlendModeProgram<D>,
alpha_tile_exclusion_program: AlphaTileBlendModeProgram<D>,
alpha_tile_hsl_program: AlphaTileHSLProgram<D>,
mask_winding_tile_vertex_array: MaskTileVertexArray<D>,
mask_evenodd_tile_vertex_array: MaskTileVertexArray<D>,
@ -98,6 +100,8 @@ where
alpha_tile_overlay_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_dodgeburn_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_softlight_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_difference_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_exclusion_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_hsl_vertex_array: AlphaTileVertexArray<D>,
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,
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -0,0 +1,61 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -0,0 +1,63 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> 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<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> 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<float> 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;
}

View File

@ -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 \

View File

@ -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 <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.
// 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);
}

View File

@ -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 <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.
// 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);
}