| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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 SoftLight |
| |
| < namespace : "Flame"; |
| |
| vendor : "Adobe"; |
| |
| version : 1; |
| |
| description : "SoftLight blend mode"; |
| |
| > |
| |
| { |
| |
| input image4 dst; |
| |
| input image4 src; |
| |
| output pixel4 result; |
| |
| |
| |
| void |
| |
| evaluatePixel() |
| |
| { |
| |
| pixel4 a = sampleNearest(dst,outCoord()); // cb |
| |
| pixel4 b = sampleNearest(src,outCoord()); // cs |
| |
| |
| |
| // remove premultiplied (srcCP/srcA, dstCP/dstA) |
| |
| pixel3 cb = a.rgb; |
| |
| pixel3 cs = b.rgb; |
| |
| 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; |
| |
| |
| |
| // B(cs,cb) = cb � (1 � 2*cs)*cb*(1-cb), if (cs <= 0.5) |
| |
| // = cb + (2*cs � 1)*(D(cb) � cb), otherwise |
| |
| |
| |
| float3 blendResult; |
| |
| |
| |
| // red |
| |
| if (cs.r <= 0.5) { |
| |
| blendResult.r = cb.r - (1.0 - clamp(2.0*cs.r,0.0,1.0))*cb.r*(1.0-cb.r); |
| |
| } else { |
| |
| // this could be a helper function, but bytecode doesn't support this |
| |
| // = ((16*x � 12)*x +4)*x, if x <= 0.25 |
| |
| // = x**0.5, otherwise |
| |
| float dcb; |
| |
| if (cb.r <= 0.25) { |
| |
| dcb = ((16.0*cb.r - 12.0) *4.0)*cb.r; |
| |
| } else { |
| |
| dcb = sqrt(cb.r); |
| |
| } |
| |
| |
| |
| blendResult.r = cb.r + (2.0*cs.r - 1.0)*(dcb - cb.r); |
| |
| } |
| |
| |
| |
| // green |
| |
| if (cs.g <= 0.5) { |
| |
| blendResult.g = cb.g - (1.0 - 2.0*cs.g)*cb.g*(1.0-cb.g); |
| |
| } else { |
| |
| // = ((16*x � 12)*x +4)*x, if x <= 0.25 |
| |
| // = x**0.5, otherwise |
| |
| float dcb; |
| |
| if (cb.g <= 0.25) { |
| |
| dcb = ((16.0*cb.g - 12.0) *4.0)*cb.g; |
| |
| } else { |
| |
| dcb = sqrt(cb.g); |
| |
| } |
| |
| |
| |
| blendResult.g = cb.g + (2.0*cs.g - 1.0)*(dcb - cb.g); |
| |
| } |
| |
| |
| |
| // blue |
| |
| if (cs.b <= 0.5) { |
| |
| blendResult.b = cb.b - (1.0 - 2.0*cs.b)*cb.b*(1.0-cb.b); |
| |
| } else { |
| |
| // = ((16*x � 12)*x +4)*x, if x <= 0.25 |
| |
| // = x**0.5, otherwise |
| |
| float dcb; |
| |
| if (cb.b <= 0.25) { |
| |
| dcb = ((16.0*cb.b - 12.0) *4.0)*cb.b; |
| |
| } else { |
| |
| dcb = sqrt(cb.b); |
| |
| } |
| |
| |
| |
| blendResult.b = cb.b + (2.0*cs.b - 1.0)*(dcb - cb.b); |
| |
| } |
| |
| |
| |
| |
| |
| // 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*blendResult.rgb; |
| |
| } |
| |
| } |
| |