/* 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/. */

#define WR_FEATURE_TEXTURE_2D

#include shared,prim_shared

// interpolated UV coordinates to sample.
varying highp vec2 vUv;

// Flag to allow perspective interpolation of UV.
// Packed in to a vector to work around bug 1630356.
flat varying mediump vec2 vPerspective;

flat varying highp vec4 vUvSampleBounds;

#ifdef WR_VERTEX_SHADER
struct SplitGeometry {
    vec2 local[4];
};

SplitGeometry fetch_split_geometry(int address) {
    ivec2 uv = get_gpu_cache_uv(address);

    vec4 data0 = TEXEL_FETCH(sGpuCache, uv, 0, ivec2(0, 0));
    vec4 data1 = TEXEL_FETCH(sGpuCache, uv, 0, ivec2(1, 0));

    SplitGeometry geo;
    geo.local = vec2[4](
        data0.xy,
        data0.zw,
        data1.xy,
        data1.zw
    );

    return geo;
}

vec2 bilerp(vec2 a, vec2 b, vec2 c, vec2 d, float s, float t) {
    vec2 x = mix(a, b, t);
    vec2 y = mix(c, d, t);
    return mix(x, y, s);
}

struct SplitCompositeInstance {
    int prim_header_index;
    int polygons_address;
    float z;
    int render_task_index;
};

SplitCompositeInstance fetch_composite_instance() {
    SplitCompositeInstance ci;

    ci.prim_header_index = aData.x;
    ci.polygons_address = aData.y;
    ci.z = float(aData.z);
    ci.render_task_index = aData.w;

    return ci;
}

void main(void) {
    SplitCompositeInstance ci = fetch_composite_instance();
    SplitGeometry geometry = fetch_split_geometry(ci.polygons_address);
    PrimitiveHeader ph = fetch_prim_header(ci.prim_header_index);
    PictureTask dest_task = fetch_picture_task(ci.render_task_index);
    Transform transform = fetch_transform(ph.transform_id);
    ImageSource res = fetch_image_source(ph.user_data.x);
    ClipArea clip_area = fetch_clip_area(ph.user_data.w);

    vec2 dest_origin = dest_task.task_rect.p0 -
                       dest_task.content_origin;

    vec2 local_pos = bilerp(geometry.local[0], geometry.local[1],
                            geometry.local[3], geometry.local[2],
                            aPosition.y, aPosition.x);
    vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0);

    vec4 final_pos = vec4(
        dest_origin * world_pos.w + world_pos.xy * dest_task.device_pixel_scale,
        world_pos.w * ci.z,
        world_pos.w
    );

    write_clip(
        world_pos,
        clip_area,
        dest_task
    );

    gl_Position = uTransform * final_pos;

    vec2 texture_size = vec2(TEX_SIZE(sColor0));
    vec2 uv0 = res.uv_rect.p0;
    vec2 uv1 = res.uv_rect.p1;

    vec2 min_uv = min(uv0, uv1);
    vec2 max_uv = max(uv0, uv1);

    vUvSampleBounds = vec4(
        min_uv + vec2(0.5),
        max_uv - vec2(0.5)
    ) / texture_size.xyxy;

    vec2 f = (local_pos - ph.local_rect.p0) / rect_size(ph.local_rect);
    f = get_image_quad_uv(ph.user_data.x, f);
    vec2 uv = mix(uv0, uv1, f);
    float perspective_interpolate = float(ph.user_data.y);

    vUv = uv / texture_size * mix(gl_Position.w, 1.0, perspective_interpolate);
    vPerspective.x = perspective_interpolate;
}
#endif

#ifdef WR_FRAGMENT_SHADER
void main(void) {
    float alpha = do_clip();
    float perspective_divisor = mix(gl_FragCoord.w, 1.0, vPerspective.x);
    vec2 uv = clamp(vUv * perspective_divisor, vUvSampleBounds.xy, vUvSampleBounds.zw);
    write_output(alpha * texture(sColor0, uv));
}

#ifdef SWGL_DRAW_SPAN
void swgl_drawSpanRGBA8() {
    float perspective_divisor = mix(swgl_forceScalar(gl_FragCoord.w), 1.0, vPerspective.x);
    vec2 uv = vUv * perspective_divisor;

    swgl_commitTextureRGBA8(sColor0, uv, vUvSampleBounds);
}
#endif

#endif
