/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include shared

#ifdef WR_VERTEX_SHADER

in vec2 aFromPosition;
in vec2 aCtrlPosition;
in vec2 aToPosition;
in vec2 aFromNormal;
in vec2 aCtrlNormal;
in vec2 aToNormal;
in int aPathID;
in int aPad;

out vec2 vFrom;
out vec2 vCtrl;
out vec2 vTo;

void main(void) {
    // Unpack.
    int pathID = int(aPathID);

    ivec2 pathAddress = ivec2(0.0, aPathID);
    mat2 transformLinear = mat2(TEXEL_FETCH(sColor1, pathAddress, 0, ivec2(0, 0)));
    vec2 transformTranslation = TEXEL_FETCH(sColor1, pathAddress, 0, ivec2(1, 0)).xy;

    vec4 miscInfo = TEXEL_FETCH(sColor1, pathAddress, 0, ivec2(2, 0));
    float rectHeight = miscInfo.y;
    vec2 emboldenAmount = miscInfo.zw * 0.5;

    // TODO(pcwalton): Hint positions.
    vec2 from = aFromPosition;
    vec2 ctrl = aCtrlPosition;
    vec2 to = aToPosition;

    // Embolden as necessary.
    from -= aFromNormal * emboldenAmount;
    ctrl -= aCtrlNormal * emboldenAmount;
    to -= aToNormal * emboldenAmount;

    // Perform the transform.
    from = transformLinear * from + transformTranslation;
    ctrl = transformLinear * ctrl + transformTranslation;
    to = transformLinear * to + transformTranslation;

    // Choose correct quadrant for rotation.
    vec2 corner = vec2(0.0, rectHeight) + transformTranslation;

    // Compute edge vectors. De Casteljau subdivide if necessary.
    // TODO(pcwalton): Actually do the two-pass rendering.

    // Compute position and dilate. If too thin, discard to avoid artefacts.
    vec2 position;
    if (abs(from.x - to.x) < 0.0001)
        position.x = 0.0;
    else if (aPosition.x < 0.5)
        position.x = floor(min(min(from.x, to.x), ctrl.x));
    else
        position.x = ceil(max(max(from.x, to.x), ctrl.x));
    if (aPosition.y < 0.5)
        position.y = floor(min(min(from.y, to.y), ctrl.y));
    else
        position.y = corner.y;

    // Compute final position and depth.
    vec4 clipPosition = uTransform * vec4(position, aPosition.z, 1.0);

    // Finish up.
    gl_Position = clipPosition;
    vFrom = from - position;
    vCtrl = ctrl - position;
    vTo = to - position;
}

#endif

#ifdef WR_FRAGMENT_SHADER

uniform sampler2D uAreaLUT;

in vec2 vFrom;
in vec2 vCtrl;
in vec2 vTo;

void main(void) {
    // Unpack.
    vec2 from = vFrom, ctrl = vCtrl, to = vTo;

    // Determine winding, and sort into a consistent order so we only need to find one root below.
    bool winding = from.x < to.x;
    vec2 left = winding ? from : to, right = winding ? to : from;
    vec2 v0 = ctrl - left, v1 = right - ctrl;

    // Shoot a vertical ray toward the curve.
    vec2 window = clamp(vec2(from.x, to.x), -0.5, 0.5);
    float offset = mix(window.x, window.y, 0.5) - left.x;
    float t = offset / (v0.x + sqrt(v1.x * offset - v0.x * (offset - v0.x)));

    // Compute position and derivative to form a line approximation.
    float y = mix(mix(left.y, ctrl.y, t), mix(ctrl.y, right.y, t), t);
    float d = mix(v0.y, v1.y, t) / mix(v0.x, v1.x, t);

    // Look up area under that line, and scale horizontally to the window size.
    float dX = window.x - window.y;
    oFragColor = vec4(texture(sColor0, vec2(y + 8.0, abs(d * dX)) / 16.0).r * dX);
}

#endif
