/*
 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

param sampler dstColor;
param sampler glyphColor;

param float3 gamma; // gamma.x := gamma and gamma.y := 1/gamma
// gamma.z := unitXCoord

//This is the beef of the LCD Algorithm
//must inverse gamma each
float4 paint(float2 texCoord, float2 texCoord2, float4 jslVertexColor)
{
    // Sub-pixel positioning
    float unitXCoord = gamma.z;
    float2 dTexCoord = texCoord;

    float4 glyphClr;
    // Negative unitXCoord can be used for BGR sub pixel structure
    dTexCoord.x = texCoord.x - unitXCoord; // Left sub-pixel of center
    glyphClr.r = sample(glyphColor, dTexCoord).a;
    glyphClr.g = sample(glyphColor, texCoord).a;
    dTexCoord.x = texCoord.x + unitXCoord; // Right sub-pixel of center
    glyphClr.b = sample(glyphColor, dTexCoord).a;

    // glyphClr.a defined as average texel coverage of glyph
    const float third = 1.0/3.0;
    glyphClr.a = dot(glyphClr.rgb, float3(third, third, third));
    if (glyphClr.a == 0.0) {
        discard;
    }

    float4 dstClr = sample(dstColor, texCoord2);

    /*
    * Sub-pixel blending with non-opaque destination
    *
    * Sub-pixel/LCD blending can only occur over opaque colors in the
    * destination.
    *
    * Grayscale texel can be defined as an average texel coverage of glyph.
    * avg(g.rgb) := (g.r + g.g + r.b)/3.0
    * Grayscale SRC_OVER blend equation is given by:
    * (1) grayScaleResult = d * (1.0 - s.a * avg(g.rgb)) + s * avg(g.rgb);
    * where we define variables:
    * - g := glyph color
    * - s := source color
    * - d := destination color
    *
    * The SRC_OVER result of LCD blending to opaque destination can be obtained
    * via equation:
    * (2) LCDResult = d*(1 - g*s.a) + g*s
    * provided d.a == 1
    * If we ignore transparent part of destination equation (2) becomes:
    * (3) LCDOpaqueDstResult = (d/d.a) * (1 - g*s.a) + g*s
    *
    * Now we can derive an equation, which can handle non-opaque destination.
    * Let f(d.a) be a function, which depends on destination alpha (d.a) and
    * satisfies the conditions:
    * 1. For opaque destination we want LCD result by using blend equation (3)
    * 2. For fully transparent destination we should get grayscale results via
    * blend equation (1)
    * 3. Must satisfy pre-multiplication condition.
    * Mathematically these conditions can be expressed:
    * 1. f(1) = LCDOpaqueDstResult = (d/d.a)*(1 - g*s.a) + g*s
    *
    * 2. f(0) = d * (1 - avg(g) * s.a) + avg(g) * s
    *         = avg(g) * s
    * Since d == <0,0,0,0>
    * 3. It can be shown that (f(0).rgb <= f(0).a) && (f(1).rgb <= f(1)) is true
    *
    * Finally we can derive f(d.a), as a linear distribution from f(0) to f(1),
    * and which satisfies the above conditions:
    * f(d.a) = f(0) * (1 - d.a) + f(1) * d.a
    *        = avg(g) * s * (1-d.a) + ((d/d.a)*(1 - g*s) + g*s) * d.a
    *        = d*(1-g*s) + s *(avg(g) * (1-d.a) + g * d.a)
    * which simplifies to:
    * f(d.a) = d*(1-g*s) + s * mix(avg(g), g, d.a)
    */

    dstClr = pow(dstClr, float4(gamma.y, gamma.y, gamma.y, gamma.y));

    float4 c = jslVertexColor;
    // Source over LCD blend equation, which handles transparency.
    // REMIND this does not work with default alpha blending:
    // D3DRS_SRCBLEND, D3DBLEND_ONE  no change to source color
    // D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA  or (1 - src.a)
    // Requires that alpha channel composite is turned off (SRC composite mode).
    float4 glyphMix;
    glyphMix.a = glyphClr.a;
    glyphMix.rgb = mix(float3(glyphClr.a, glyphClr.a, glyphClr.a), glyphClr.rgb, dstClr.a);
    c = dstClr * (1.0 - glyphClr * c.a) + c * glyphMix;

    c = pow(c, float4(gamma.x, gamma.x, gamma.x, gamma.x));

    return c;
}
