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

    }

}

