// Pixel shader input structure
struct PS_INPUT
{
    float4 Position   : VPOS;
    float2 Texture    : TEXCOORD0;
};

struct PS_OUTPUT
{
    float4 Color   : COLOR0;
    float Depth: DEPTH;
};


// Global variables

float time;

float4x4 matView;

float LFSine;
float HFSine;
float scene_select;

float2 resolution = {1,1};
// Rotation macro - see toolbox thread
#define R(p, a) p=cos(a)*p+sin(a)*float2(p.y,-p.x)

#include "part2.c"


#define pi 3.14159

float3 hsv(float h,float s,float v) {
	return lerp(float3(1,1,1),clamp((abs(frac(h+float3(3.,2.,1.)/3.)*6.-3.)-1.),0.,1.),s)*v;
}

float pn(float3 p) {
   float3 i = floor(p);
   float4 a = dot(i, float3(1., 57., 21.)) + float4(0., 57., 21., 78.);
   float3 f = cos((p-i)*pi)*(-.5) + .5;
   a = lerp(sin(cos(a)*a), sin(cos(1.+a)*(1.+a)), f.x);
   a.xy = lerp(a.xz, a.yw, f.y);
   return lerp(a.x, a.y, f.z);
}

float fpn(float3 p) {
   return pn(p*.06125)*.5 + pn(p*.125)*.25 + pn(p*.25)*.125;
}





float part1(float3 pos, float xo, float yo, float zo, float xs, float ys, float zs) {;
   pos.x += xo;
   pos.z += zo;
   pos.y += yo;
   /*float size = 1;
   xs *= size;
   ys *= size;
   zs *= size;*/
   float a = max(max(abs(pos.x)-xs,abs(pos.y)-ys),abs(pos.z)-zs);
   float b = max(max(abs(pos.x)-xs*0.9,abs(pos.y)-ys),abs(pos.z-0.1)-zs*0.9);
   float c = max(max(abs(pos.x-0.1)-xs*0.9,abs(pos.y)-ys),abs(pos.z)-zs*0.9);
   float d = max(max(abs(pos.x+0.1)-xs*0.9,abs(pos.y)-ys),abs(pos.z)-zs*0.9);
   return min(a,min(b,min(c,d)));
}

float part2(float3 pos, float xo, float yo, float zo, float xs, float ys, float zs) {;
   pos.x += xo;
   pos.z += zo;
   pos.y += yo;
   if(abs(pos.y) < 0.8*ys)
      { zs += sin(pos.x*30)*0.05; }
   /*float size = 1;
   xs *= size;
   ys *= size;
   zs *= size;*/
   return max(max(abs(pos.x)-xs,abs(pos.y)-ys),abs(pos.z)-zs);
}

static float materialId;

float tower(float3 p) {
   float a = 100000;

   p.z -= 96*ceil(p.z/96);
   
  // a = min(a,part2(p, 0, -10, 6, 1.1, 11, 1.2));
  // if(a > 1) return a;
  // else a = 100000;
   
   a = min(a,part1(p, 1, 0,48,   0.3, 6, 1));
   a = min(a,part1(p, -1,0,48,   0.3, 6, 1));
   a = min(a,part2(p, 0,-5,48,  1, 1, 0.25));
 
   a = min(a,part1(p, 1, -9,48,   0.27, 3, 0.8));
   a = min(a,part1(p, -1,-9,48,   0.27, 3, 0.8));
   a = min(a,part2(p, 0,-11,48,  1, 1, 0.25));   
   
   a = min(a,part1(p, 1, -14,48,   0.24, 2, 0.7));
   a = min(a,part1(p, -1,-14,48,   0.24, 2, 0.7));
   a = min(a,part2(p, 0,-15.5,48,  1, 0.5, 0.25));
   
   a = min(a,part1(p, 1, -18,48,   0.21, 2, 0.6));
   a = min(a,part1(p, -1,-18,48,   0.21, 2, 0.6));
   a = min(a,part2(p, 0,-19.0,48,  1, 0.4, 0.25));
   
   //if(a < 0.1) materialId = 1;
   
   return a;
}

float cables(float3 p) {
   float a = 100000;
   p.z -= 96*ceil(p.z/96); 
   
   float h= 19*pow( (abs(p.z+48) - 48)/48.,2) + 1;
   //a = min(a, -p.y - 19*pow( (-p.z - 48)/48.,2));

   
   
   if(p.x > 0) p.x *= -1;
   
   a = min(a, length(p.xy + float2(1, -h)) - 0.04);
   
   if(p.y > h) return a;

   p.z -= 2*ceil(p.z/2);
   
   
   
 //  a = min(a, length(p.xz + float2(-1, 1)) - 0.01);
 

//if(p.x > -0.1) return a;
//if(p.x < -1.1) return a;
   a = min(a, length(p.xz + float2(1, 1)) - 0.01);



   return a;
}

float road(float3 p) {
   float a = 100000;
   
   a = min(a,part1(p, 0, 0.5, 450, 1.1, 0.4, 900));
   
   a = min(a,part1(p, -1, 0.5, 450, 0.1, 0.5, 900));
   
   a = min(a,part1(p, 1, 0.5, 450, 0.1, 0.5, 900));


   return a;

}


float f(float3 p) {

   materialId = 0;
  


   float a = 4 + p.y + 0.09*fpn(p*13+float3(0,time,0)) ;
   
  if(scene_select == 3)
  	a += 0.5*(LFSine+HFSine)*fpn(p*13+float3(0,time,0));
   
      p.y += sin(p.z*0.5)*0.4*LFSine;
    
    p.y += sin(p.z*4)*0.6*HFSine;
 
  
   if(0*p.x > 6) {
     // a = min(a, p.x - 1.2);
   }
   else if(0*p.x < -6) {
    a = min(a, -p.x + 1.2);
   }
   else {
   
      a = min(a, cables(p));
      
      
      a = min(a, road(p));
      
      
      float twr = tower(p);
      if(a > twr) {
         a = twr;
         materialId = 1;
        }
      
   }

	if(LFSine==0&&HFSine==0) return a;   

   return a*0.8;
}


PS_OUTPUT ps_main(in PS_INPUT In){
	PS_OUTPUT Out; 
	if(scene_select == 1 || scene_select == 2)
	return PART2_ps_main(In);
	
   float2 v = In.Texture;// * 2 - 1;
    
   // p: Position / d: Direction
   float3 p = float3(0,0,0);
   
   
   float3 d = float3(v*float2(16.f/9,1), 1);
   
   p += matView[3].xyz;
   p += 0.005*float3(pn(time/14),pn(4-time/14),pn(2-time/14)) + fmod(v.y*v.y*v.x+time,0.001);
   d = mul(d, (float3x3)matView);
   
   
   // braf
   //R(v.xy, 1*length(v.xy)+sin(time));
   //d.x = (atan2(v.x,-v.y));
   //d.y = -length(v.yx);
   
   
   // For proper raymarching we need ||d|| = 1
   d = normalize(d);
   
   // Iteration counter
   float i;
   
   // What distance did we march on the ray?
   float t = 0;
      
   materialId = 0;



      
   // Loop using i, loops from i = 0 to i = 1
   for (i=0; i<1; i+=1/64.){
      //R(p.xy, 0.9*p.z);
      float l = f(p) /*+ 0.0005*t*/ ;//* pow(1.01,t);
      //float l = 0.3;
      //R(p.xy, 0.9*-p.z);
      // Advance along our ray into direction d or step back a little in
      // case f(p) is negative - this might actually happen.
      p += l * d;


      // In order to compute t we want to use the absolute value of f(p) -
      // we need the absolute value anyways to check against the threshold
      l = abs(l);
      t += l;
      
      
      // If |f(p)| is below a magic threshold we are close enough and can
      // stop here. Using t to determine the threshold might be a good
      // idea here - this implements some kind of cone tracing - for further
      // information you want to read the zeno paper from John C. Hart.
      if (abs(l) < .005*t) { break; }
      l = clamp(l, 0.001, 100000);
      if(t > 140) { t = 140; break; }
   }
   
   
   
   // In case this is true we didn't hit anything. This also means this ray
   // was very expensive - you should do something to avoid that - bounding
   // spheres are a good start.
   if (i >= 1.) {
      //t = 900;
   }

   // Compute normal using central differences - for other, faster and
   // possibly more imprecise methods you want to read the toolbox thread
   float2 epsilon = {.001,0};
   float OPTIMIZED = f(p);
   float3 normal = normalize(
      float3(
         f(p+epsilon.xyy) - OPTIMIZED,
         f(p+epsilon.yxy) - OPTIMIZED,
         f(p+epsilon.yyx) - OPTIMIZED
         )
      );

   // Now let's shade that thing
   
   float4 col = 0.4*smoothstep(0,1,0.9 + dot(normal,d));
   
   col.rgb += pow(dot(normal,-d), 16.0)*pow(dot(normal,float3(0,-1,0)), 16.0)*float3(0.7,0.8,0.9);
   
   col += i*0.5;
   //col.z += (1-i)*(1-i);
   //col.bg += 0.2*log(t*0.25);
   //col -= 0.015*p.z;
   col += smoothstep(0, 96, t)*0.2;
  col.a = 1;
  if(materialId == 1) { col.r *= 1.3; col.g *= 1.05; }
  
  if(scene_select == 3) {
  	col.rgb += hsv(0.5+0.5*sin(p.z+p.y*p.y), 0.5, 0.5);
  	if(materialId == 1) col.rgb = float3(1, 0.2, 0.1);
  	if(p.y < -3.5) col.rgb = float3(0, -v.y*0.2, -v.y);
	}
  
  //col = lerp(col, float4(0.5,0.9,1.0,1.0), clamp(-p.z/72, 0, 1));
    float fogAmount = pow(2.7, (-1.0/35)*(t) );
    float sunAmount = max( dot( d, float3(0.2,1,0.1) ), 0.0 );
    float3  fogColor  = lerp( float3(0.7,0.8,0.9), // bluish
                           float3(1.0,0.9,0.8), // yellowish
                           pow(sunAmount,1.0) );
                
				if(scene_select == 3) fogColor = 0;           
    
    //fogAmount = 0;
    for(i=0;i<1;i+=1./16.) {
       fogAmount += abs(pn(p-d*t*i))*0.02*smoothstep(-3, 10, -p.y);
      }
      
    col.rgb = lerp( col, fogColor, clamp(1 - fogAmount,0,1) );
    
   //col += pow(cos(2*atan2(v.y,v.x)), 80.0);

   //col.xyz = float3(v*float2(resolution.x/resolution.y,1), 0);
   Out.Color = col;
   //Out.Color.rgb = p.zzz;
   float3 viewpos = mul(p  - matView[3].xyz , transpose((float3x3)matView));
   Out.Depth = (1.0/viewpos.z*(-2*1*1000.0/999) + (1001.0/999) + 1.0)/2.0; // http://en.wikipedia.org/wiki/Z-buffering#Mathematics
   //Out.Color.rgb = viewpos.zzz;
   return Out;
}