Add the soft light blend mode

This commit is contained in:
Patrick Walton 2020-02-25 14:39:06 -08:00
parent 9b4217300f
commit a8e33d3d3d
8 changed files with 342 additions and 54 deletions

View File

@ -541,6 +541,7 @@ pub enum CompositeOperation {
ColorDodge,
ColorBurn,
HardLight,
SoftLight,
Hue,
Saturation,
Color,
@ -568,6 +569,7 @@ impl CompositeOperation {
CompositeOperation::ColorDodge => BlendMode::ColorDodge,
CompositeOperation::ColorBurn => BlendMode::ColorBurn,
CompositeOperation::HardLight => BlendMode::HardLight,
CompositeOperation::SoftLight => BlendMode::SoftLight,
CompositeOperation::Hue => BlendMode::Hue,
CompositeOperation::Saturation => BlendMode::Saturation,
CompositeOperation::Color => BlendMode::Color,

View File

@ -91,6 +91,9 @@ pub enum BlendMode {
ColorDodge,
ColorBurn,
// Soft light
SoftLight,
// HSL
Hue,
Saturation,
@ -139,6 +142,7 @@ impl BlendMode {
BlendMode::Overlay |
BlendMode::ColorDodge |
BlendMode::ColorBurn |
BlendMode::SoftLight |
BlendMode::Hue |
BlendMode::Saturation |
BlendMode::Color |

View File

@ -10,7 +10,8 @@
use crate::gpu::debug::DebugUIPresenter;
use crate::gpu::options::{DestFramebuffer, RendererOptions};
use crate::gpu::shaders::{AlphaTileDodgeBurnProgram, AlphaTileHSLProgram, AlphaTileOverlayProgram};
use crate::gpu::shaders::{AlphaTileBlendModeProgram, AlphaTileDodgeBurnProgram};
use crate::gpu::shaders::{AlphaTileHSLProgram, AlphaTileOverlayProgram};
use crate::gpu::shaders::{AlphaTilePorterDuffProgram, AlphaTileProgram, AlphaTileVertexArray};
use crate::gpu::shaders::{CopyTileProgram, CopyTileVertexArray, FillProgram, FillVertexArray};
use crate::gpu::shaders::{FilterBasicProgram, FilterBasicVertexArray, FilterTextProgram};
@ -86,6 +87,7 @@ where
alpha_tile_porterduff_program: AlphaTilePorterDuffProgram<D>,
alpha_tile_overlay_program: AlphaTileOverlayProgram<D>,
alpha_tile_dodgeburn_program: AlphaTileDodgeBurnProgram<D>,
alpha_tile_softlight_program: AlphaTileBlendModeProgram<D>,
alpha_tile_hsl_program: AlphaTileHSLProgram<D>,
mask_winding_tile_vertex_array: MaskTileVertexArray<D>,
mask_evenodd_tile_vertex_array: MaskTileVertexArray<D>,
@ -95,6 +97,7 @@ where
alpha_tile_porterduff_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_overlay_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_dodgeburn_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_softlight_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_hsl_vertex_array: AlphaTileVertexArray<D>,
area_lut_texture: D::Texture,
alpha_tile_vertex_buffer: D::Buffer,
@ -169,6 +172,9 @@ where
let alpha_tile_porterduff_program = AlphaTilePorterDuffProgram::new(&device, resources);
let alpha_tile_overlay_program = AlphaTileOverlayProgram::new(&device, resources);
let alpha_tile_dodgeburn_program = AlphaTileDodgeBurnProgram::new(&device, resources);
let alpha_tile_softlight_program = AlphaTileBlendModeProgram::new(&device,
resources,
"tile_alpha_softlight");
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);
@ -225,25 +231,31 @@ where
);
let alpha_tile_porterduff_vertex_array = AlphaTileVertexArray::new(
&device,
&alpha_tile_porterduff_program.alpha_tile_program,
&alpha_tile_porterduff_program.alpha_tile_blend_mode_program.alpha_tile_program,
&alpha_tile_vertex_buffer,
&quads_vertex_indices_buffer,
);
let alpha_tile_overlay_vertex_array = AlphaTileVertexArray::new(
&device,
&alpha_tile_overlay_program.alpha_tile_program,
&alpha_tile_overlay_program.alpha_tile_blend_mode_program.alpha_tile_program,
&alpha_tile_vertex_buffer,
&quads_vertex_indices_buffer,
);
let alpha_tile_dodgeburn_vertex_array = AlphaTileVertexArray::new(
&device,
&alpha_tile_dodgeburn_program.alpha_tile_program,
&alpha_tile_dodgeburn_program.alpha_tile_blend_mode_program.alpha_tile_program,
&alpha_tile_vertex_buffer,
&quads_vertex_indices_buffer,
);
let alpha_tile_softlight_vertex_array = AlphaTileVertexArray::new(
&device,
&alpha_tile_softlight_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_program,
&alpha_tile_hsl_program.alpha_tile_blend_mode_program.alpha_tile_program,
&alpha_tile_vertex_buffer,
&quads_vertex_indices_buffer,
);
@ -311,6 +323,7 @@ where
alpha_tile_porterduff_program,
alpha_tile_overlay_program,
alpha_tile_dodgeburn_program,
alpha_tile_softlight_program,
alpha_tile_hsl_program,
mask_winding_tile_vertex_array,
mask_evenodd_tile_vertex_array,
@ -320,6 +333,7 @@ where
alpha_tile_porterduff_vertex_array,
alpha_tile_overlay_vertex_array,
alpha_tile_dodgeburn_vertex_array,
alpha_tile_softlight_vertex_array,
alpha_tile_hsl_vertex_array,
area_lut_texture,
alpha_tile_vertex_buffer,
@ -753,19 +767,27 @@ where
let (alpha_tile_program, alpha_tile_vertex_array) = match blend_mode_program {
BlendModeProgram::Regular => (&self.alpha_tile_program, &self.alpha_tile_vertex_array),
BlendModeProgram::PorterDuff => {
(&self.alpha_tile_porterduff_program.alpha_tile_program,
(&self.alpha_tile_porterduff_program
.alpha_tile_blend_mode_program
.alpha_tile_program,
&self.alpha_tile_porterduff_vertex_array)
}
BlendModeProgram::Overlay => {
(&self.alpha_tile_overlay_program.alpha_tile_program,
(&self.alpha_tile_overlay_program.alpha_tile_blend_mode_program.alpha_tile_program,
&self.alpha_tile_overlay_vertex_array)
}
BlendModeProgram::DodgeBurn => {
(&self.alpha_tile_dodgeburn_program.alpha_tile_program,
(&self.alpha_tile_dodgeburn_program
.alpha_tile_blend_mode_program
.alpha_tile_program,
&self.alpha_tile_dodgeburn_vertex_array)
}
BlendModeProgram::SoftLight => {
(&self.alpha_tile_softlight_program.alpha_tile_program,
&self.alpha_tile_softlight_vertex_array)
}
BlendModeProgram::HSL => {
(&self.alpha_tile_hsl_program.alpha_tile_program,
(&self.alpha_tile_hsl_program.alpha_tile_blend_mode_program.alpha_tile_program,
&self.alpha_tile_hsl_vertex_array)
}
};
@ -811,6 +833,11 @@ where
&mut uniforms,
blend_mode);
}
BlendModeProgram::SoftLight => {
self.set_uniforms_for_blend_mode(&mut textures,
&mut uniforms,
&self.alpha_tile_softlight_program);
}
BlendModeProgram::HSL => {
self.set_uniforms_for_hsl_blend_mode(&mut textures, &mut uniforms, blend_mode);
}
@ -835,6 +862,16 @@ where
self.preserve_draw_framebuffer();
}
fn set_uniforms_for_blend_mode<'a>(
&'a self,
textures: &mut Vec<&'a D::Texture>,
uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
alpha_tile_blend_mode_program: &'a AlphaTileBlendModeProgram<D>) {
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
uniforms.push((&alpha_tile_blend_mode_program.dest_uniform,
UniformData::TextureUnit(textures.len() as u32 - 1)));
}
fn set_uniforms_for_porter_duff_blend_mode<'a>(
&'a self,
textures: &mut Vec<&'a D::Texture>,
@ -861,9 +898,10 @@ where
uniforms.push((&self.alpha_tile_porterduff_program.dest_factor_uniform,
UniformData::Int(dest_factor)));
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
uniforms.push((&self.alpha_tile_porterduff_program.dest_uniform,
UniformData::TextureUnit(textures.len() as u32 - 1)));
self.set_uniforms_for_blend_mode(textures,
uniforms,
&self.alpha_tile_porterduff_program
.alpha_tile_blend_mode_program);
}
fn set_uniforms_for_overlay_blend_mode<'a>(&'a self,
@ -881,9 +919,10 @@ where
uniforms.push((&self.alpha_tile_overlay_program.blend_mode_uniform,
UniformData::Int(overlay_blend_mode)));
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
uniforms.push((&self.alpha_tile_overlay_program.dest_uniform,
UniformData::TextureUnit(textures.len() as u32 - 1)));
self.set_uniforms_for_blend_mode(textures,
uniforms,
&self.alpha_tile_overlay_program
.alpha_tile_blend_mode_program);
}
fn set_uniforms_for_dodge_burn_blend_mode<'a>(
@ -894,9 +933,10 @@ where
uniforms.push((&self.alpha_tile_dodgeburn_program.burn_uniform,
UniformData::Int(if blend_mode == BlendMode::ColorBurn { 1 } else { 0 })));
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
uniforms.push((&self.alpha_tile_dodgeburn_program.dest_uniform,
UniformData::TextureUnit(textures.len() as u32 - 1)));
self.set_uniforms_for_blend_mode(textures,
uniforms,
&self.alpha_tile_dodgeburn_program
.alpha_tile_blend_mode_program);
}
fn set_uniforms_for_hsl_blend_mode<'a>(&'a self,
@ -914,9 +954,10 @@ where
uniforms.push((&self.alpha_tile_hsl_program.blend_hsl_uniform,
UniformData::IVec3(hsl_terms)));
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
uniforms.push((&self.alpha_tile_hsl_program.dest_uniform,
UniformData::TextureUnit(textures.len() as u32 - 1)));
self.set_uniforms_for_blend_mode(textures,
uniforms,
&self.alpha_tile_hsl_program
.alpha_tile_blend_mode_program);
}
fn copy_alpha_tiles_to_dest_blend_texture(&mut self, tile_count: u32) {
@ -1544,6 +1585,7 @@ impl BlendModeExt for BlendMode {
BlendMode::Overlay |
BlendMode::ColorDodge |
BlendMode::ColorBurn |
BlendMode::SoftLight |
BlendMode::Hue |
BlendMode::Saturation |
BlendMode::Color |
@ -1561,6 +1603,7 @@ pub(crate) enum BlendModeProgram {
PorterDuff,
Overlay,
DodgeBurn,
SoftLight,
HSL,
}
@ -1586,6 +1629,7 @@ impl BlendModeProgram {
BlendMode::Overlay => BlendModeProgram::Overlay,
BlendMode::ColorDodge |
BlendMode::ColorBurn => BlendModeProgram::DodgeBurn,
BlendMode::SoftLight => BlendModeProgram::SoftLight,
BlendMode::Hue |
BlendMode::Saturation |
BlendMode::Color |
@ -1599,6 +1643,7 @@ impl BlendModeProgram {
BlendModeProgram::PorterDuff |
BlendModeProgram::Overlay |
BlendModeProgram::DodgeBurn |
BlendModeProgram::SoftLight |
BlendModeProgram::HSL => true,
}
}

View File

@ -450,25 +450,39 @@ impl<D> CopyTileProgram<D> where D: Device {
}
}
pub struct AlphaTilePorterDuffProgram<D> where D: Device {
pub struct AlphaTileBlendModeProgram<D> where D: Device {
pub alpha_tile_program: AlphaTileProgram<D>,
pub dest_uniform: D::Uniform,
}
impl<D> AlphaTileBlendModeProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader, name: &str)
-> AlphaTileBlendModeProgram<D> {
let alpha_tile_program =
AlphaTileProgram::from_fragment_shader_name(device, resources, name);
let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest");
AlphaTileBlendModeProgram { alpha_tile_program, dest_uniform }
}
}
pub struct AlphaTilePorterDuffProgram<D> where D: Device {
pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram<D>,
pub dest_factor_uniform: D::Uniform,
pub src_factor_uniform: D::Uniform,
}
impl<D> AlphaTilePorterDuffProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTilePorterDuffProgram<D> {
let alpha_tile_program =
AlphaTileProgram::from_fragment_shader_name(device,
resources,
"tile_alpha_porterduff");
let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest");
let dest_factor_uniform = device.get_uniform(&alpha_tile_program.program, "DestFactor");
let src_factor_uniform = device.get_uniform(&alpha_tile_program.program, "SrcFactor");
let alpha_tile_blend_mode_program =
AlphaTileBlendModeProgram::new(device, resources, "tile_alpha_porterduff");
let dest_factor_uniform =
device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program,
"DestFactor");
let src_factor_uniform =
device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program,
"SrcFactor");
AlphaTilePorterDuffProgram {
alpha_tile_program,
dest_uniform,
alpha_tile_blend_mode_program,
dest_factor_uniform,
src_factor_uniform,
}
@ -476,52 +490,50 @@ impl<D> AlphaTilePorterDuffProgram<D> where D: Device {
}
pub struct AlphaTileHSLProgram<D> where D: Device {
pub alpha_tile_program: AlphaTileProgram<D>,
pub dest_uniform: D::Uniform,
pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram<D>,
pub blend_hsl_uniform: D::Uniform,
}
impl<D> AlphaTileHSLProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileHSLProgram<D> {
let alpha_tile_program = AlphaTileProgram::from_fragment_shader_name(device,
resources,
"tile_alpha_hsl");
let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest");
let blend_hsl_uniform = device.get_uniform(&alpha_tile_program.program, "BlendHSL");
AlphaTileHSLProgram { alpha_tile_program, dest_uniform, blend_hsl_uniform }
let alpha_tile_blend_mode_program =
AlphaTileBlendModeProgram::new(device, resources, "tile_alpha_hsl");
let blend_hsl_uniform =
device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program,
"BlendHSL");
AlphaTileHSLProgram { alpha_tile_blend_mode_program, blend_hsl_uniform }
}
}
pub struct AlphaTileOverlayProgram<D> where D: Device {
pub alpha_tile_program: AlphaTileProgram<D>,
pub dest_uniform: D::Uniform,
pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram<D>,
pub blend_mode_uniform: D::Uniform,
}
impl<D> AlphaTileOverlayProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileOverlayProgram<D> {
let alpha_tile_program = AlphaTileProgram::from_fragment_shader_name(device,
let alpha_tile_blend_mode_program = AlphaTileBlendModeProgram::new(device,
resources,
"tile_alpha_overlay");
let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest");
let blend_mode_uniform = device.get_uniform(&alpha_tile_program.program, "BlendMode");
AlphaTileOverlayProgram { alpha_tile_program, dest_uniform, blend_mode_uniform }
let blend_mode_uniform =
device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program,
"BlendMode");
AlphaTileOverlayProgram { alpha_tile_blend_mode_program, blend_mode_uniform }
}
}
pub struct AlphaTileDodgeBurnProgram<D> where D: Device {
pub alpha_tile_program: AlphaTileProgram<D>,
pub dest_uniform: D::Uniform,
pub alpha_tile_blend_mode_program: AlphaTileBlendModeProgram<D>,
pub burn_uniform: D::Uniform,
}
impl<D> AlphaTileDodgeBurnProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTileDodgeBurnProgram<D> {
let alpha_tile_program =
AlphaTileProgram::from_fragment_shader_name(device, resources, "tile_alpha_dodgeburn");
let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest");
let burn_uniform = device.get_uniform(&alpha_tile_program.program, "Burn");
AlphaTileDodgeBurnProgram { alpha_tile_program, dest_uniform, burn_uniform }
let alpha_tile_blend_mode_program =
AlphaTileBlendModeProgram::new(device, resources, "tile_alpha_dodgeburn");
let burn_uniform =
device.get_uniform(&alpha_tile_blend_mode_program.alpha_tile_program.program, "Burn");
AlphaTileDodgeBurnProgram { alpha_tile_blend_mode_program, burn_uniform }
}
}

View File

@ -0,0 +1,82 @@
#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;
bvec3 destDark = lessThanEqual(dest, vec3(0.25)), srcDark = lessThanEqual(src, vec3(0.5));
vec3 d = select3(destDark,(dest * 16.0 - 12.0)* dest + 4.0, inversesqrt(dest));
vec3 x = select3(srcDark, vec3(1.0)- dest, d - 1.0);
vec3 blended = dest *((src * 2.0 - 1.0)* x + 1.0);
oFragColor = blendColors(destRGBA, srcRGBA, blended);
}

View File

@ -0,0 +1,105 @@
// 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);
}
float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b)
{
float _118;
if (cond.x)
{
_118 = a.x;
}
else
{
_118 = b.x;
}
float _130;
if (cond.y)
{
_130 = a.y;
}
else
{
_130 = b.y;
}
float _142;
if (cond.z)
{
_142 = a.z;
}
else
{
_142 = b.z;
}
return float3(_118, _130, _142);
}
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;
bool3 destDark = dest <= float3(0.25);
bool3 srcDark = src <= float3(0.5);
bool3 param = destDark;
float3 param_1 = (((dest * 16.0) - float3(12.0)) * dest) + float3(4.0);
float3 param_2 = rsqrt(dest);
float3 d = select3(param, param_1, param_2);
bool3 param_3 = srcDark;
float3 param_4 = float3(1.0) - dest;
float3 param_5 = d - float3(1.0);
float3 x = select3(param_3, param_4, param_5);
float3 blended = dest * ((((src * 2.0) - float3(1.0)) * x) + float3(1.0));
float4 param_6 = destRGBA;
float4 param_7 = srcRGBA;
float3 param_8 = blended;
out.oFragColor = blendColors(param_6, param_7, param_8);
return out;
}

View File

@ -27,6 +27,7 @@ SHADERS=\
tile_alpha_hsl.fs.glsl \
tile_alpha_overlay.fs.glsl \
tile_alpha_porterduff.fs.glsl \
tile_alpha_softlight.fs.glsl \
tile_copy.fs.glsl \
tile_copy.vs.glsl \
tile_solid.fs.glsl \

View File

@ -0,0 +1,37 @@
#version 330
// pathfinder/shaders/tile_alpha_softlight.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 soft light 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();
// B(Cb, Cs) = Cb*(1 + (2*Cs - 1)*X)
// where X = if Cs <= 0.5 then 1 - Cb else D - 1
// and D = if Cb <= 0.25 then (16*Cb - 12)*Cb + 4 else 1/sqrt(Cb)
vec3 dest = destRGBA.rgb, src = srcRGBA.rgb;
bvec3 destDark = lessThanEqual(dest, vec3(0.25)), srcDark = lessThanEqual(src, vec3(0.5));
vec3 d = select3(destDark, (dest * 16.0 - 12.0) * dest + 4.0, inversesqrt(dest));
vec3 x = select3(srcDark, vec3(1.0) - dest, d - 1.0);
vec3 blended = dest * ((src * 2.0 - 1.0) * x + 1.0);
oFragColor = blendColors(destRGBA, srcRGBA, blended);
}