#version 460 core
#include <flutter/runtime_effect.glsl>

uniform vec2 uSize;
uniform float iTime;
vec2 iResolution;
out vec4 fragColor;

const float PI = 3.141592653589793;
const float TWO_PI = 6.283185307179586;
const float INV_PI = 0.318309886183791;

#define SCALE_FACTOR 8
#define TIME_SCALE 0.005

vec3 triangleIntersect(vec3 ro, vec3 rd, vec3 v0, vec3 v1, vec3 v2) {
    vec3 v1v0 = v1 - v0; // ~3 FLOP (3x SUB)
    vec3 v2v0 = v2 - v0; // ~3 FLOP (3x SUB)
    vec3 rov0 = ro - v0; // ~3 FLOP (3x SUB)

    vec3 n = cross(v1v0, v2v0); // ~9 FLOP (6x MUL, 3x SUB)
    vec3 q = cross(rov0, rd  ); // ~9 FLOP (6x MUL, 3x SUB)

    float d = 1.0 / dot(rd, n); // ~6 FLOP (3x MUL, 2x ADD, 1x DIV)

    float u = d * dot(-q, v2v0); // ~7 FLOP (1x NEG, 3x MUL, 2x ADD, 1x MUL)
    float v = d * dot( q, v1v0); // ~6 FLOP (3x MUL, 2x ADD, 1x MUL)
    float t = d * dot(-n, rov0); // ~7 FLOP (1x NEG, 3x MUL, 2x ADD, 1x MUL)

    t = (u < 0.0 || v < 0.0 || (u + v) > 1.0) ? -1.0 : t; // no intersection, ~9 FLOP (2x LESS, 1x ADD, 1x GREAT, 2x MAX, 1x SUB, 2x MUL)

    return vec3(t, u, v); // Total: ~62? FLOP (16x SUB, 29x MUL, 1x DIV, 7x ADD, 2x NEG, 2x LESS, 1x GREAT, 2x MAX)
}

void main(void) {

    iResolution = uSize;
    vec2 fragCoord = gl_FragCoord.xy; // Get the fragment coordinates
    vec2 center = 2.0 * vec2(fragCoord.xy - 0.5 * iResolution.xy) / iResolution.y;
    
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;
    
    const vec2 s0 = vec2(-0.375, -0.125);
    const vec2 s1 = vec2( 0.125, -0.375);
    const vec2 s2 = vec2(-0.125,  0.375);
    const vec2 s3 = vec2( 0.375,  0.125);

    // Triangle Vertex Positions
    const vec3 v0 = vec3( 1.000, -1.000, -1.000);
    const vec3 v1 = vec3(-1.000,  1.000, -1.000);
    const vec3 v2 = vec3(-1.000, -1.000,  1.000);

    vec2 hres = 0.5 * iResolution.xy; // ~2 FLOP (2x ADD)

    float ires = 1.0 / max(hres.x, hres.y); // ~2 FLOP (1x MAX, 1x DIV)

    vec2 uv0 = fragCoord.xy + s0; // ~2 FLOP (2x ADD)
    vec2 uv1 = fragCoord.xy + s1; // ~2 FLOP (2x ADD)
    vec2 uv2 = fragCoord.xy + s2; // ~2 FLOP (2x ADD)
    vec2 uv3 = fragCoord.xy + s3; // ~2 FLOP (2x ADD)

    uv0 = ires * (uv0 - hres); // ~4 FLOP (2x SUB, 2x MUL)
    uv1 = ires * (uv1 - hres); // ~4 FLOP (2x SUB, 2x MUL)
    uv2 = ires * (uv2 - hres); // ~4 FLOP (2x SUB, 2x MUL)
    uv3 = ires * (uv3 - hres); // ~4 FLOP (2x SUB, 2x MUL)

    float theta = TWO_PI * fract(0.5 * iTime);

    float cos_theta = cos(theta), sin_theta = sin(theta); // ~2 FLOP (1x COS, 1x SIN)

    vec3 ro = vec3(sin_theta, cos_theta, 5.0);

    vec3 rd0 = normalize(vec3(uv0, -1.0)); // ~8 FLOP (3x MUL, 2x ADD, 3x DIV)
    vec3 rd1 = normalize(vec3(uv1, -1.0)); // ~8 FLOP (3x MUL, 2x ADD, 3x DIV)
    vec3 rd2 = normalize(vec3(uv2, -1.0)); // ~8 FLOP (3x MUL, 2x ADD, 3x DIV)
    vec3 rd3 = normalize(vec3(uv3, -1.0)); // ~8 FLOP (3x MUL, 2x ADD, 3x DIV)

    vec3 t0 = triangleIntersect(ro, rd0, v0, v1, v2); // ~62 FLOP
    vec3 t1 = triangleIntersect(ro, rd1, v0, v1, v2); // ~62 FLOP
    vec3 t2 = triangleIntersect(ro, rd2, v0, v1, v2); // ~62 FLOP
    vec3 t3 = triangleIntersect(ro, rd3, v0, v1, v2); // ~62 FLOP

    fragColor.xy = vec2(0);

    fragColor.xy += t0.x >= 0.0 ? t0.yz : vec2(0); // ~8 FLOP (1x GREATEQUAL, 1x SUB, 4x MUL, 2x ADD)
    fragColor.xy += t1.x >= 0.0 ? t1.yz : vec2(0); // ~8 FLOP (1x GREATEQUAL, 1x SUB, 4x MUL, 2x ADD)
    fragColor.xy += t2.x >= 0.0 ? t2.yz : vec2(0); // ~8 FLOP (1x GREATEQUAL, 1x SUB, 4x MUL, 2x ADD)
    fragColor.xy += t3.x >= 0.0 ? t3.yz : vec2(0); // ~8 FLOP (1x GREATEQUAL, 1x SUB, 4x MUL, 2x ADD)

    fragColor.xy *= 0.25; // ~2 FLOP (2x MUL)

    fragColor = vec4(fragColor.xy, 0.0, 1.0); // Total: 347 FLOP per pixel
}
