#define repeat(v, r) (mod(v, r)-r/2.)

struct Shape{ // Basic constructor for shape
  float dist; // Distance from center
  vec4 color; // Color of shape
};



//=======================
// Utility Functions
//=======================
float random(vec3 v) { // Utility function that utilizes the fract() function to create recurring patterns.
  return fract(tan(dot(v*100.1, vec3(400.654, 160.546, 100.)))*46.2);
}

mat2 rot(float a){ // Rotates and gives the rotated matrix
  float r = cos(a);
  float f = sin(a);
  return mat2(-r, -f, f, -r);
}

float sphere(vec3 v, float r){ // Creates a sphere
  return length(v)-r;
}


float pole(vec2 v, float r){ // Creates a pole
  return length(v)-r;
}

float mixColors(float r, float v, float z){
  return clamp(0.5+0.5*(v-r)/z, 0., 1.);
}


float mixShapes(float v, float f, float r){ // Mixes both the color and the shape of objects.
  float z = mixColors(v, f, r);
  return mix(f,v,z)-r*z*(1.-z);
}

float pModPolar(inout vec2 v, float r){
  float f = 6.28318/r;
  float z = atan(v.y, v.x)+f*0.5;
  float m = floor(z/f);
  z = mod(z, f)-f*0.5;
  v = vec2(cos(z), sin(z))*length(v);
  return m;
}
//=======================

Shape vines(vec3 c){ // Creates a vine shape (kind of an extension of Shape
  Shape shape; // Creates basic Shape first
  float vine;
  shape.dist = 100.; // Draw Distance
  shape.color = vec4(3.); // Initial Color

  // Shape Attributes
  float twist = 5.; // Vine Repeat
  float vineOffset = 5.; // Leaf Offset


  // Stems
    random(c);// Passes vec3 c through the random function first
  	vec3 i = c;
    i.xz *= rot(c.y*0.2+iTime*0.2); // Rotates the vines about the xz system.
    float detail = pModPolar(i.xz, twist);
    float x = mix(5., 5.1, mod(detail, 1.)); // Small Ripples
    i.x -= vineOffset; // Offset Stems
  	float stemWidth = .15;
    //stemWidth/= 10000000.;
  	vine = pole(i.xz, stemWidth+0.02*sin(i.y*x));


  vec4 color = vec4(0.4, 1.0, 0.4, 10.); // Initialize vine color

  shape.dist = vine;
  shape.color = color;

  return shape;
}

Shape orb(vec3 c){
  Shape shape;
  float orb;
  shape.dist = 1000.; // Draw Distance
  shape.color = vec4(1.); // Initial Color

  // Stems
  vec3 i = c;
    //i.xz *= rot(iTime);
    i.y = repeat(i.y, 2.5); // Repeats the orbs in they y direction every 2.5 pixels.
    i.y = abs(i.y)-2.5;
    i.x = abs(i.x)-1.5;
    orb = sphere(i, cos(sin(iTime)*0.25)*2.25);


  vec4 color = vec4(0.8, 1., 0.8, 1.); // Initializes color

  shape.dist = orb;
  shape.color = color;

  return shape;
}


Shape map(vec3 c, vec3 c1){
  Shape vines = vines(c); // Create vines
  Shape orbs = orb(c); // Create orbs

  float df = mixShapes(vines.dist, orbs.dist, 1.); // Mix vines and orbs
  vines.dist = df;

  vines.color = mix(vines.color,
                    orbs.color*0.8,
                    mixColors(orbs.dist*=0.9, vines.dist, 0.0)); // Mixes the colors
	return vines; // Returns everything as one

}

void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
  vec2 v = (fragCoord.xy-0.5 * iResolution.xy) / iResolution.y; // Normalize


  vec3 cam = vec3(0., sin(iTime)-3.5, -10.); // Dictates where the camera is/will move.
  random(cam+0.5);
  vec3 f = normalize(vec3(v, .9));
  random(f);
  vec3 scene = cam;
  random(scene);
  vec3 scene1 = cam *= 5.;
  fragColor = vec4(0.2);

  // Ray Marcher
  for(float z = 0.001 ; z <= 10.; z += 0.1){
    Shape c = map(scene, scene1); // Calc SDF
    if(c.dist < 0.4){
      fragColor = c.color*(1.-z); // Hit  - invert pixels
      break;
    }
    scene += f * c.dist;


  }
}

