blob: 87fb50256eb9bb7d5515ac9d36b31f8332ba1089 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
<languageVersion : 1.0;>
kernel Hue
< namespace : "Flame";
vendor : "Adobe";
version : 1;
description : "Hue blend mode";
>
{
input image4 dst;
input image4 src;
output pixel4 result;
// PB bytecode can't do functions, use macros to define common functions
// gets the max number out of the three
#define max3( x, y, z ) ( max((x), max((y), (z))) )
// gets the min number out of the three
#define min3( x, y, z ) ( min((x), min((y), (z))) )
// gets the max number out of the three elements in a vector
#define max3v(C) ( max3((C.x), (C.y), (C.z)) )
// gets the min number out of the three elements in a vector
#define min3v(C) ( min3((C.x), (C.y), (C.z)) )
// Sat - returns float, takes in a pixel3, or pixel4
#define saturation(C) ( (max3((C.r), (C.g), (C.b)) - min3((C.r), (C.g), (C.b))) )
// Luminance - returns float, takes in a pixel3, or pixel4
#define luminance(C) ( (((C.r) * 0.3) + ((C.g) * 0.59) + ((C.b) * 0.11)) )
void
evaluatePixel()
{
pixel4 a = sampleNearest(dst,outCoord()); // cb
pixel4 b = sampleNearest(src,outCoord()); // cs
// remove premultiplied (srcCP/srcA, dstCP/dstA)
pixel3 cb, cs;
if (a.a > 0.0) {
cb.rgb = a.rgb / a.a;
}
if (b.a > 0.0) {
cs.rgb = b.rgb / b.a;
}
// dstA' = (1-srcA)*dstA + srcA
result.a = (1.0-b.a)*a.a + b.a;
// setSat(cs, Sat(cb))
// setSat (setSatColor, sat) -> setSatResult
/* --------------------------------------------------------
* void setsaturation(inout float3 color, in float satVal)
* makes color have the target saturation.
* input and output of float3 color
* input of the target saturation
*
* --------------------------------------------------------
void setsatcomponents(inout float minComp, inout float midComp, inout float maxComp, in float satVal)
{
midComp -= minComp;
maxComp -= minComp;
minComp = 0.0;
if (maxComp > 0.0) {
// max(..., 0.0000001) prevents divide by 0
midComp *= satVal/max(maxComp, 0.0000001);
maxComp = satVal;
}
}
*/
float3 color = cs.rgb;
float satVal = saturation(cb);
if (color.x <= color.y) {
if (color.y <= color.z) {
// x <= y <= z
// setsatcomponents(color.x, color.y, color.z, satVal);
// min, mid, max, val
color.y -= color.x;
color.z -= color.x;
color.x = 0.0;
if (color.z > 0.0) {
// max(..., 0.0000001) prevents divide by 0
color.y *= satVal/max(color.z, 0.0000001);
color.z = satVal;
}
} else {
if (color.x <= color.z) {
// x <= z <= y
// setsatcomponents(color.x, color.z, color.y, satVal);
// min, mid, max, value
color.z -= color.x;
color.y -= color.x;
color.x = 0.0;
if (color.y > 0.0) {
// max(..., 0.0000001) prevents divide by 0
color.z *= satVal/max(color.y, 0.0000001);
color.y = satVal;
}
} else {
// z <= x <= y
// setsatcomponents(color.z, color.x, color.y, satVal);
// min, mid, max, val
color.x -= color.z;
color.y -= color.z;
color.z = 0.0;
if (color.y > 0.0) {
// max(..., 0.0000001) prevents divide by 0
color.x *= satVal/max(color.y, 0.0000001);
color.y = satVal;
}
}
}
} else {
if (color.x <= color.z) {
// y <= x <= z
// setsatcomponents(color.y, color.x, color.z, satVal);
color.x -= color.y;
color.z -= color.y;
color.y = 0.0;
if (color.z > 0.0) {
// max(..., 0.0000001) prevents divide by 0
color.x *= satVal/max(color.z, 0.0000001);
color.z = satVal;
}
} else {
if (color.y <= color.z) {
// y <= z <= x
// setsatcomponents(color.y, color.z, color.x, satVal);
// min, mid, max, val
color.z -= color.y;
color.x -= color.y;
color.y = 0.0;
if (color.x > 0.0) {
// max(..., 0.0000001) prevents divide by 0
color.z *= satVal/max(color.x, 0.0000001);
color.x = satVal;
}
} else {
// z <= y <= x
// setsatcomponents(color.z, color.y, color.x, satVal);
// min, mid, max, val
color.y -= color.z;
color.x -= color.z;
color.z = 0.0;
if (color.x > 0.0) {
// max(..., 0.0000001) prevents divide by 0
color.y *= satVal/max(color.x, 0.0000001);
color.x = satVal;
}
}
}
}
// end setSaturation - result: color ---------------------- //
// intermediate adjustment (setSatResult) -> adjustedcs
float3 adjVec = (cb - color);
float adjustment = luminance(adjVec);
float3 adjustedcs = color + adjustment;
// ClipRGB(adjustedcs) -> blendResult
/* --------------------------------------------------------
* void clipcolor(inout float3 color)
* clips color.
* input and output float3 color_cl
*
* -------------------------------------------------------- */
float3 color_cl = adjustedcs;
float lum_cl = luminance(color_cl);
float3 lumVec = float3(lum_cl, lum_cl, lum_cl);
float mini = min3v(color_cl);
float maxi = max3v(color_cl);
if (mini < 0.0) {
mini = lum_cl - mini;
// max(..., 0.0000001) prevents divide by 0
color_cl = lumVec + (color_cl - lumVec)*lum_cl/max(mini, 0.0000001);
}
if (maxi > 1.0) {
maxi = maxi - lum_cl;
// max(..., 0.0000001) prevents divide by 0
color_cl = lumVec + (color_cl - lumVec)*(1.0 - lum_cl)/max(maxi, 0.0000001);
}
// end clipcolor - result: color_cl ---------------------- //
// dstCP' = (1-srcA)*dstCP + (1-dstA)*srcCP + srcA*dstA*Blend(srcCP/srcA, dstCP/dstA)
result.rgb = ((1.0-b.a)*a.rgb) + ((1.0-a.a)*b.rgb) + b.a*a.a*color_cl.rgb;
}
}