
/////////////////////////////////////////////////////////////
//                                                         //
// Author:Yusef28                                          //
// Start Date: 28-07-2021                                  //
// Status: On Going                                        //
// Topic: Circle-Circle Intersection                       //
// Sources: https://www.analyzemath.com/CircleEq           //
//                      /circle_intersection.html          //
//                                                         //
// The original: https://www.shadertoy.com/view/lldcDf     //
//                                                         //
// Listening to: satellites - Familiar Shorelines [Album]  //
//                                                         // 
/////////////////////////////////////////////////////////////

//before I get into it, here is the main inspiration for this
//effect https://www.shadertoy.com/view/lldcDf
//some of the code has been "borrowed" like the add function 
//used to add objects to the distance field without returning 
//anything. It's pretty sleak.

//If you have every tryed getting into path tracing but
//didn't enjoy the learning curve, 2d pathtracing is a grate
//way to get something on the screen fast and gain some 
//understanding.
//
//
//I had a few false starts with the intersection code in this one. 
//Then I didn't want to upload too many at once so I spaced things
//out. In doing so I stumbled on a cooler idea and decided to 
//apply it to this shader before uploading it.

//So other than a basic circle x circle intersection I 
//am also path tracing everything in 2 dimentions to calculate
//global illumination. So what that means is for every pixel 
//I take samples out in many "random" direction.Where here
//it is actually just rays shot out offset by uniform angles + 
//the angle is offset by a random number. So from every pixel we
//ge tthe 360 degree view of where the other objects are.

//To do that we use raymarching of a 2d map. 

//Not sure how coherent I am right now since it's pretty late.
//

//somthing new to try
#define numSamples 68.

    
      ////////////////////////////////////////////
      //                                       //
////////      RayMarching Functions          //
      //                                   //
      /////////////////////////////////////
      
      
float rnd(vec2 uv){
    return fract(sin(dot(uv,
        vec2(12.9898,78.233)))*
        43758.5453123);
}


void add(float dist, vec3 color, inout float endDist, inout vec3 endColor){
    if(dist < endDist){
        endDist = dist;
        endColor = color;
    }
}

void map(vec2 uv, inout float d, inout vec3 color){

      ////////////////////////////////////////////
      //                                       //
////////     INTERSECTION CALCULATIONS       //
      //                                   //
      /////////////////////////////////////
    
    
    //centers for two circles
    vec2 center1 = vec2(-4.*cos(iTime*1.),-3.*sin(iTime*2.));
    vec2 center2 = vec2(.8*sin(iTime),.5*cos(iTime));
    
    //radius for 2 circles
    float c1 = 2.; //radius 1
    float c2 = 3.; //radius 2
    
    //x and y for each circle separate for algebra
    float h1 = center1.x;
    float k1 = center1.y;
    float h2 = center2.x;
    float k2 = center2.y;
    
    //and here we go...
    
    //So in order to solve for our firss term we need
    //to do a similar thing to what we do with line segments.
    //we set the standard form circle equations to equal
    //each other and then shift everything to one side leaving
    //0 on the other. Then we do the subtraction and notice
    //only the second order variable terms x^2 and y^2 will cancel
    //The result is a line equation (which maybe have some significance).
    
    //I go a step further by laying all the constant like-terms
    //from this step into variables since they are constants. 
    //That makes future steps way more manageble.
    
    //so after setting the equality, and subtracting, I will..
    //Well I set the x term but I can't show that step because
    //it still has the unknown of "y" so I'll just set up the constants
    //so after isolating x we have
    
    float k3 = k1 - k2;
    float h3 = h1 - h2;
    float c3 = k1*k1 - (k2*k2) + h1*h1 - (h2*h2) - (c1*c1) + (c2*c2);
    // x = y*w - u where....
    float w = -(k3/h3);
    float u = -c3/(2.*h3);
    
    //and I've already worked out a,b and c so I'll go ahead and...
    float a = w*w + 1.;
    float b = 2.*(w*h1 + w*u + k1);
    float c = (u*u) + 2.*u*h1 + k1*k1 - (c1*c1) + h1*h1;
    
    /*float w = (-2.*(k1-k2))/(2.*(h1-h2));
    float u = k1*k1 - (k2*k2) + h1*h1 - (h2*h2) - (c1*c1) + (c2*c2);
    
    //and I've already worked out a,b and c so I'll go ahead and...
    float a = w*w + 1.;
    float b = w*w*h1 - w*u - k1;
    float c = -(u*u) - 2.*u*h1 + k1*k1 - (c1*c1) + h1*h1;
    */
    
    //the discriminant
    float disc = b*b - 4.*a*c;
    
    //the two roots (or one or none de0pending)
    float y1 = (-b + sqrt(disc))/(2.*a); //<-- this right here!!!!
    float y2 = (-b - sqrt(disc))/(2.*a); //<-- If you forget bracket on (2.*a)...
                                         //you're gonna have a bad experience.
                                         
    
    //Note:
    //You can factor out the "2." from the "b" initialization
    //and then the "4." from the discriminant along with the "2."
    //from each of y1 and y2. Deleting all these is akin to
    //things canceling and you end up with the same result
    
    //so what we did was kind of snuck past getting x, 
    //we got out of that and went for y while only having x
    //in terms of y. Then we got out qaudtradic variables and solved the 
    //quadratic for 0-2 roots which will bw our y1 and y2
    //now we'll swing back around and get the x's using our x = yw - u
    //formula.
   
    float x1 = y1*w + u;
    float x2 = y2*w + u;
    //ja just like that and now...
    //calculate the intersection points
    
    //I had to calculate everything again and somehow still ended up
    //missing a sign somewhere because the points have the wrong sign.
    //so I flip the sign of the points and there it is.
    //I know what I did! I calculated everything with:
    // (x + h)^2 + (y + k)^2 = c^2
    // it should have been -h and -k
    // so flipping the sign of the coordinates at the end is the same
    // as flipping the signs of the centers
    vec2 intersectionPoint1 = -vec2(x1,y1);
    vec2 intersectionPoint2 = -vec2(x2,y2);
        
        
      ////////////////////////////////////////////
      //                                       //
////////        DRAWING EVERYTHING           //
      //                                   //
      /////////////////////////////////////
    
    
    //This time everything is happening in the distance
    //estimation map so I use all the algebra above
    //in the basic process of finding the closest object
    
    d = 1e9;
    color = vec3(0.0);
    float f;
    
    float radicalLine = -uv.x +(uv.y*w - u);//adjusted because of 
    //the sign error above
    
    
    
    //circle at center1
    
    f = abs(length(uv-center1)-c1);
    add(f,vec3(0.8,0.3,0.7)/4., d, color);
    
    //circle at center2
    //f = 1.-smoothstep(0.02,0.04,abs(length(uv-center2)-c2));
    
    if(length(uv-center1) > c1){
    f = abs(length(uv-center2)-c2);
    add(f,vec3(0.2,0.5,0.9)/3., d, color);
    }
    
    if(disc >= 0.){
    
    //intersection pointss
    f = abs(length(uv-intersectionPoint1)-0.12);
    add(f,vec3(0.6,0.7,1.)*2., d, color);
    f = abs(length(uv-intersectionPoint2)-0.12);
    add(f,vec3(0.6,0.7,1.)*2., d, color);

    
    }
    
    f = abs(length(uv-vec2(7.,4.*sin(iTime)))-0.5);
    add(f,vec3(1.,1.,0.7), d, color);
    f = abs(length(uv+vec2(7.,4.*cos(iTime)))-0.5);
    add(f,vec3(1.4,0.9,.5), d, color);

}

float trace(vec2 ro, vec2 rd, inout vec3 color, vec3 grid){
    float t = 0.;
    
    for(float i = 0.;i<30.;i++){
        
        float d;
        map(ro + rd*t, d, color);
        //if(d<0.0001)return;
        
        //if(d>10.)break;
        if(d <0.0001 || t > 10.) break;
        
            t += d;
    }
    
    if(t > 10.)color = grid;//if no hit at this point, draw background grid
    return t;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from -0.5,0.5)
    vec2 uv = (fragCoord-iResolution.xy*0.5)/iResolution.y;
    
    
      ////////////////////////////////////////////
      //                                       //
////////      BACKGROUND GRID DESIGN         //
      //                                   //
      /////////////////////////////////////
      
      
    vec2 st = uv;//save the unscaled uv
    //I'm only making an 8(*aspect)x8 grid, higher variables
    //may end up with graphs completely outside it
    uv*=8.;
    //graph background
    vec3 col = vec3(0.);
    //center highlights
    col = mix(col,vec3(0.16),1.0-length(uv/8.));
    //dust 
    float specks = fract(sin(dot(uv,vec2(123.,16.)))*43343.);
    //nice soft texture 
    float tex = texture(iChannel0,st).x;
    col = mix(col,vec3(0.25),pow(tex,2.));
    //small grid lines
    vec2 lines = fract(uv*5.);
    lines = smoothstep(0.45,0.52,abs(lines-0.5));
    col = mix(col,vec3(0.3),lines.x);
    col = mix(col,vec3(0.3),lines.y);
    //larger grid lines
    lines = fract(uv);
    lines = smoothstep(0.47,0.52,abs(lines-0.5));
    col = mix(col,vec3(0.5),lines.x);
    col = mix(col,vec3(0.5),lines.y);
    //axis lines
    lines = smoothstep(0.0,0.02,abs(uv));
    col = mix(col,vec3(0.6),1.0-lines.x);
    col = mix(col,vec3(0.6),1.-lines.y);
    //col = mix(col,vec3(0.1),step(0.1,specks)*0.2);
    
    vec3 grid = col/2.;
      //marching
      
    uv = (fragCoord-iResolution.xy*0.5)/iResolution.y*10.;
    vec2 ro = uv;
    vec2 rd;
    vec3 tmpColor;
    float t;
    vec3 marchColor = vec3(0.);
    
    // Time varying pixel color
    for(float i = 0.; i < numSamples; i++){
        float angle = ( i + rnd( uv + float(i)) ) / numSamples*3.1415*2. ;
        
        rd = vec2(cos(angle),sin(angle));
        //I give the grid design to the trace function
        t = trace(ro, rd, tmpColor,grid);
        marchColor += tmpColor;
    }
    

    
    
    marchColor/=(numSamples);
    col = marchColor*2.;//mix(col,marchColor,mask);
    // Output to screen
    //fragColor = vec4(col,1.0);
    
    
      ////////////////////////////////////////////
      //                                       //
////////          POST PROCESSING            //
      //                                   //
      /////////////////////////////////////
        
    col = pow(col,vec3(0.75));
    
    //vignette
    uv = fragCoord/iResolution.xy;
    uv *=  1.0 - uv.yx;
    float vig = uv.x*uv.y * 15.0; // multiply with sth for intensity
    vig = pow(vig, 0.15); // change pow for modifying the extend of the  vignette

    // Output to screen
    fragColor = vec4(col*vig,1.0);
}
