/*

Optolith Background
-------------------
This shader renders the background from the character creator program
for The Black Eye 5 "Optolith". 

The default values are to make the shader as close to the original as 
possible. Thus I recommend using the fullscreen mode to view it, to
reduce flickering.

This is primarily designed to be used as ghostty shader, which
requires the use of the iChannel0 channel. But feel free to use it 
everywhere you like.

If you have any idea of improving it, feel free to let me know or even
create a fork. :)

I tried to make it as simple as possible and to document everything.
So even if you have no clue, whats going on, I hope my explainations 
are good enough, so you know what you can change and how.

License: (as always WTFPL)
           DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
                   Version 2, December 2004
 
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>

Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
 
           DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

 0. You just DO WHAT THE FUCK YOU WANT TO.

*/

/* --- USER PARAMETERS --- */
// These parameters you can change how ever you like.

// BACKGROUND and FOREGROUND define the colors.
#define BACKGROUND vec3(0.0666,0.0666,0.0666) // #111111
// If you prefer the light mode:
//#define BACKGROUND vec3(0.9411, 0.9411, 0.9411) // #F0F0F0
#define FOREGROUND vec3(0.5137,0.4196,0.2431) // #836B3E
// This value defines how visible the effect is.
// This default is different to the original.
// ORIGINAL VALUE: .15
#define FOREGROUND_OPACITY .25



// This defines how fast the animation is playing.
// To decrease the speed, increase the divider. (and vice versa)
// To stop the animation, just replace everything with 0 or 
// any number in case you want a specific point in time. 
// ORIGINAL VALUE: iTime/50.
#define TIME iTime / 50.

// MASK_DISTANCE define how far away from the center the line starts
// (should be between 0 and 1)
// ORIGINAL VALUE: 0.8
#define MASK_DISTANCE 0.8
// MASK_WIDTH defines how long the lines should be.
// ORIGINAL VALUE: 0.05
#define MASK_WIDTH 0.05

// LINE_DISTANCE defines how many degrees should be between two lines.
// For the best result, the number should be able to divide cleanly 
// with 360.
// ORIGINAL VALUE: 0.5
#define LINE_DISTANCE 0.5
// LINE_WIDTH defines how thick the line is. This is expressed in degrees.
// This should not be higher than LINE_DISTANCE and should be sufficiantly 
// large, otherwise the image begins to flicker. (as shown in the default)
// But I mean... I can't stop you either way.
// ORIGINAL VALUE: 0.05
#define LINE_WIDTH 0.05

/* --- SYSTEM PARAMETERS --- */
// Changing these parameters may break something... So just don't

// This is a constant to convert radians to degrees
#define RAD2DEG 57.295779513

/* --- CODE --- */

vec2 rotateUV(vec2 uv) {
    float sinUV = sin(TIME);
    float cosUV = cos(TIME);
    
    mat2 rotationMatrix = mat2(cosUV, -sinUV, sinUV, cosUV);
    return uv * rotationMatrix;
}

vec2 createEffectCoordnates(vec2 uv) {
    float aspectRatio = iResolution.y / iResolution.x;
    
    // Move (0,0) to the center
    uv -= 0.5;
    // Scale it back up, so we work with a range of 0..1
    // Also here we ensure, that the effect does not strech in an unwanted way
    // This also results in the effect being larger than the screen, but thats
    // intended.
    uv *= vec2(2., aspectRatio * 2.);
    // Finally, we rotate the UV so we get a nice rotation animation going.
    return rotateUV(uv);
}

float getMask(vec2 coordnates) {
    // This function returns a mask, that defines where the lines show up.
    // This can be modified to have more unique masks, but that is left as a 
    // exercise to the reader.

    // Calculate the distance to the center
    float uvLength = length(coordnates);
    // The first step ensures that everything up to MASK_DISTANCE is (0) and 
    // everything past it is (1)
    // The other step does the exact oppisite, but with MASK_DISTANCE + MASK_WIDTH.
    // When we multiply those, we get a mask, that only contains the overlapping masks. 
    return step(uvLength * -1., -MASK_DISTANCE) * step(uvLength, MASK_DISTANCE + MASK_WIDTH);
}

float getLines(vec2 coordnates) {
    // This returns a mask, that shows the lines on the effect.
    
    // This "atan" gives us a nice radial texture.
    // More specifically we get a value in radians.
    float lines = atan(coordnates.x, coordnates.y);
    // Since radians are kinda hard to work with as parameters, I convert it to degrees.
    float linesDegrees = lines * RAD2DEG;
    // This gives us the repeating pattern.
    float result = mod(linesDegrees, LINE_DISTANCE);
    // Finally a step instruction, gives us the mask in the specific width we want. 
    return step(result, LINE_WIDTH);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;
    
    vec2 effectCoords = createEffectCoordnates(uv);
    
    float mask = getMask(effectCoords);
    float lines = getLines(effectCoords);
    
    float result = lines * mask;
    
    vec3 col = mix(BACKGROUND, FOREGROUND, result * FOREGROUND_OPACITY);
    
    // Mixing iChannel0 into the mix. 
    // If you wish to use the alpha channel, just replace the 1 with 
    // "channel.a".
    vec4 channel = texture(iChannel0, uv);
    fragColor = vec4(mix(col, channel.rgb, length(channel.rgb)), 1);
    
}
