#version 450 core

const float PI = 3.14159;

// inputs 
in vec2 texCoord;

// outputs
out vec4 fragColor;

uniform samplerCube t_cubetest;

// uniforms
uniform float       g_time;
uniform ivec2       g_resolution;
uniform float       g_stripes_strength;
uniform float       g_tanfov;           // tan(fov / 2)
uniform vec3        g_origin;
uniform mat4        m_proj;
uniform mat4        m_viewInv;

float t = g_time;
float it = (int((t + .4*sin(t*0.3) + .2*sin(t*0.9)) * 2.)) * .9;

float rand(vec3 co){
    return 2*fract(sin(dot(co, vec3(12.9898, 78.233, 16.4495))) * 43758.5453)-.5;
}

vec3 triplanar(vec3 n, vec3 ray) {
	vec3 res = vec3(
		rand(vec3(ray.xy, it))+t*.07,
		rand(vec3(ray.yz, it))+t*.03,
		rand(vec3(ray.xz, it))+t*.03
	);
	vec3 blend = pow(abs(n), vec3(0.03));
	blend /= (blend.x + blend.y + blend.z);
	return vec3(mod(dot(res, blend), .05));
}

vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ) { return a + b*cos( 6.28318*(c*t+d) ); }

#define AA

// xyz - hit coords, w - t
vec4 traceSphere(vec3 origin, vec3 ray, float r, out bool hit) {
    const float sphereRadius = 60.0;

    vec3 eq = vec3(
        dot(ray, ray),                  // a
        2.*dot(origin, ray),            // b
        dot(origin, origin) - r*r  		// c
    );
    float delta = sqrt(eq.y*eq.y - 4 * eq.x * eq.z);            // b^2 - 4ac
    vec2  roots = vec2(-eq.y + delta, -eq.y - delta) * (0.5 / eq.x);  // (-b +- delta) / 2a

    hit = ((roots.x >= 0) || (roots.x >= 0));
    float t = (roots.x > 0 ? roots.x : roots.y);
    vec3  p = origin + t*ray;
    return vec4(p, t);
}

vec4 bgglow(vec3 p, vec3 ray) {
	float samples = 1;
	vec3 rtn = vec3(0.0); float depth = 1e8; vec4 r = vec4(0.);
	for (int i = 0; i < 6; i++) {
		// sphere mapping
		float radius = 5.*i+15; bool sphereHit = false;
		r = traceSphere(g_origin, ray.xyz, radius, sphereHit);

        if (sphereHit) {
            vec2 uv = vec2((atan(r.x, r.z)/(2*PI)), 2*(acos(r.y/radius)/(PI)));
            
            ivec2 iuvpre = ivec2(mod(uv, vec2(1)) * vec2(10, radius));
            ivec2 iuv = ivec2(mod((uv+vec2(iuvpre.y%4*t*0.1,0)), vec2(1.0,1.0)) * vec2(20+3*(iuvpre.y%4), 4*radius));
            
            float g = 0.5*rand(vec3(iuv, i))+0.5;

            vec3 c = 0.2*(1. / (i + 1))*step(2*g_stripes_strength,g)*palette(
                g, vec3(0.4, 0.54, 0.7), vec3(0.55, 0.52, 0.51), vec3(1.2, 0.6, 1.8), vec3(0.30, 0.20, 0.40)
            );
            if (any(greaterThan(c, vec3(0.01)))) {
                depth = min(depth, length(r.xyz - g_origin)); rtn += c;
            }
        }
	}
	
	return vec4(rtn / samples, depth);
}


void main(void) {
    vec2 uv = (.5/g_tanfov) * (2.*texCoord - 1.) * vec2(float(g_resolution.x) / g_resolution.y, 1.); // uniform rendertarget coords
    vec4 ray = vec4(vec3(uv, -1), 1.0);
    //ray *= m_projInv; ray.xyz /= ray.w;
    ray.xyz = normalize(ray.xyz);
    ray    *= mat4(m_viewInv);

    bool sphereHit = false;
    float depth    = 1e8;
    vec4 p = traceSphere(g_origin, ray.xyz, 20., sphereHit);
    vec3 color = vec3(0.); float a = 0.;
    if (sphereHit) {
        depth = min(depth, length(p.xyz - g_origin));
        vec3 np = normalize(p.xyz);

        ivec3 iray = ivec3(np*vec3(70., 60., 20.));
        a = smoothstep(.0, .03, triplanar(np, vec3(iray)).x);

	    vec3 light = normalize(vec3(0.8, 0.5, 0.6));
	    color = 0.3*vec3(0.4, 0.5, 0.7) * pow(clamp(dot(np, light), 0., 1.), 8.) +
	             1.5*(0.5+0.3*np)*pow(vec3(0.208, 0.112, 0.045), vec3(2.2));
    }

    // capture glow
    vec4 glow = bgglow(p.rgb, ray.xyz);

    // write to depth buffer
    depth = min(depth, glow.w);
    float d = (m_proj[2][2]*depth - m_proj[3][2])/(-depth);
    gl_FragDepth = d;

    fragColor = vec4(max(color - vec3(0.02*a) + glow.rgb, 0), 1.0);

    //fragColor = vec4(texture(t_cubetest, ray.xyz).rgb, 1.0);

    //fragColor = vec4(d, depth, 0, 1);
}




