blob: f92e6bc4ab9a08ed4182a1dfac1645ae3dcb98a2 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BLENDING_GLSL_
#define BLENDING_GLSL_
#include <impeller/branching.glsl>
#include <impeller/constants.glsl>
//------------------------------------------------------------------------------
/// HSV utilities.
///
float IPLuminosity(vec3 color) {
return color.r * 0.3 + color.g * 0.59 + color.b * 0.11;
}
/// Scales the color's luma by the amount necessary to place the color
/// components in a 1-0 range.
vec3 IPClipColor(vec3 color) {
float lum = IPLuminosity(color);
float mn = min(min(color.r, color.g), color.b);
float mx = max(max(color.r, color.g), color.b);
// `lum - mn` and `mx - lum` will always be >= 0 in the following conditions,
// so adding a tiny value is enough to make these divisions safe.
if (mn < 0) {
color = lum + (((color - lum) * lum) / (lum - mn + kEhCloseEnough));
}
if (mx > 1) {
color = lum + (((color - lum) * (1 - lum)) / (mx - lum + kEhCloseEnough));
}
return color;
}
vec3 IPSetLuminosity(vec3 color, float luminosity) {
float relative_lum = luminosity - IPLuminosity(color);
return IPClipColor(color + relative_lum);
}
float IPSaturation(vec3 color) {
return max(max(color.r, color.g), color.b) -
min(min(color.r, color.g), color.b);
}
vec3 IPSetSaturation(vec3 color, float saturation) {
float mn = min(min(color.r, color.g), color.b);
float mx = max(max(color.r, color.g), color.b);
return (mn < mx) ? ((color - mn) * saturation) / (mx - mn) : vec3(0);
}
//------------------------------------------------------------------------------
/// Color blend functions.
///
/// These routines take two unpremultiplied RGB colors and output a third color.
/// They can be combined with any alpha compositing operation. When these blend
/// functions are used for drawing Entities in Impeller, the output is always
/// applied to the destination using `SourceOver` alpha compositing.
///
vec3 IPBlendScreen(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingscreen
return dst + src - (dst * src);
}
vec3 IPBlendHardLight(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendinghardlight
return IPVec3Choose(dst * (2 * src), IPBlendScreen(dst, 2 * src - 1), src);
}
vec3 IPBlendOverlay(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingoverlay
// HardLight, but with reversed parameters.
return IPBlendHardLight(src, dst);
}
vec3 IPBlendDarken(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingdarken
return min(dst, src);
}
vec3 IPBlendLighten(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendinglighten
return max(dst, src);
}
vec3 IPBlendColorDodge(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingcolordodge
vec3 color = min(vec3(1), dst / (1 - src));
if (dst.r < kEhCloseEnough) {
color.r = 0;
}
if (dst.g < kEhCloseEnough) {
color.g = 0;
}
if (dst.b < kEhCloseEnough) {
color.b = 0;
}
if (1 - src.r < kEhCloseEnough) {
color.r = 1;
}
if (1 - src.g < kEhCloseEnough) {
color.g = 1;
}
if (1 - src.b < kEhCloseEnough) {
color.b = 1;
}
return color;
}
vec3 IPBlendColorBurn(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingcolorburn
vec3 color = 1 - min(vec3(1), (1 - dst) / src);
if (1 - dst.r < kEhCloseEnough) {
color.r = 1;
}
if (1 - dst.g < kEhCloseEnough) {
color.g = 1;
}
if (1 - dst.b < kEhCloseEnough) {
color.b = 1;
}
if (src.r < kEhCloseEnough) {
color.r = 0;
}
if (src.g < kEhCloseEnough) {
color.g = 0;
}
if (src.b < kEhCloseEnough) {
color.b = 0;
}
return color;
}
vec3 IPBlendSoftLight(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingsoftlight
vec3 D = IPVec3ChooseCutoff(((16 * dst - 12) * dst + 4) * dst, //
sqrt(dst), //
dst, //
0.25);
return IPVec3Choose(dst - (1 - 2 * src) * dst * (1 - dst), //
dst + (2 * src - 1) * (D - dst), //
src);
}
vec3 IPBlendDifference(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingdifference
return abs(dst - src);
}
vec3 IPBlendExclusion(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingexclusion
return dst + src - 2 * dst * src;
}
vec3 IPBlendMultiply(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingmultiply
return dst * src;
}
vec3 IPBlendHue(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendinghue
return IPSetLuminosity(IPSetSaturation(src, IPSaturation(dst)),
IPLuminosity(dst));
}
vec3 IPBlendSaturation(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingsaturation
return IPSetLuminosity(IPSetSaturation(dst, IPSaturation(src)),
IPLuminosity(dst));
}
vec3 IPBlendColor(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingcolor
return IPSetLuminosity(src, IPLuminosity(dst));
}
vec3 IPBlendLuminosity(vec3 dst, vec3 src) {
// https://www.w3.org/TR/compositing-1/#blendingluminosity
return IPSetLuminosity(dst, IPLuminosity(src));
}
#endif