#version 330

#define PI 3.1415926535897932384626433832795

// Input vertex attributes (from vertex shader)
in vec2 fragTexCoord;
in vec4 fragColor;

// Output fragment color
out vec4 finalColor;

uniform vec2 offset;            // Offset of the scale
uniform float zoom;             // Zoom of the scale
uniform int maxIterations;      // Max iterations per pixel

const float max = 4.0;          // We consider infinite as 4.0: if a point reaches a distance of 4.0 it will escape to infinity
const float max2 = max*max;     // Square of max to avoid computing square root

void main()
{
    // The pixel coordinates are scaled so they are on the mandelbrot scale
    // NOTE: fragTexCoord already comes as normalized screen coordinates but offset must be normalized before scaling and zoom
    vec2 c = vec2((fragTexCoord.x - 0.5)*2.5, (fragTexCoord.y - 0.5)*1.5)/zoom;
    c.x += offset.x;
    c.y += offset.y;
    float a = 0.0;
    float b = 0.0;

    // The Mandelbrot set is a two-dimensional set defined in the complex plane on which the iteration of the function
    // Fc(z) = z^2 + c on the complex numbers c from the plane does not diverge to infinity starting at z = 0
    // Here: z = a + bi. Iterations: z -> z^2 + c = (a + bi)^2 + (c.x + c.yi) = (a^2 - b^2 + c.x) + (2ab + c.y)i

    int iter = 0;
    for (iter = 0; iter < maxIterations; iter++)
    {
        float aa = a*a;
        float bb = b*b;
        if (aa + bb > max2)
            break;

        float twoab = 2.0*a*b;
        a = aa - bb + c.x;
        b = twoab + c.y;
    }

    if (iter >= maxIterations)
    {
        finalColor = vec4(0.0, 0.0, 0.0, 1.0);
    }
    else
    {
        float normR = float(iter%55)/55.0;
        float normG = float(iter%69)/69.0;
        float normB = float(iter%40)/40.0;

        finalColor = vec4(sin(normR*PI), sin(normG*PI), sin(normB*PI), 1.0);
    }
}
