| //////////////////////////////////////////////////////////////////////////////// | |
| // | |
| // 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; | |
| } | |
| } |