//#version 130
//#define texture2D texture

uniform float selectrender;
uniform int plasmafx;
vec3 plasmacol;

vec3 fadepos, fadecol;
float debug;
//float stime;
uniform float speed;

bool leftside=false;
float fishdx,fishdy;
bool renderingreflection=false;
vec2 skrul=vec2(0,0);
vec2 uv_;
vec2 uvice;

float h_; // for smooth union result
float h_ice,h_ice_g;
float material=0.0;

vec3 refro;
vec3 refrd;
vec3 refno;

mat3 ca;
const float depthmult=20.0;
const float depthmax=19.3872;
/*
float testvalue=1.0;
int flavor=1;
float roughsize=0.0080;
float pioffset=1.0;

vec3 rayorigin=vec3(0.0116,3.7571,17.31);
vec3 raydirection=vec3(-0.0635,-8.3669,2.3102);
vec3 upvector=vec3(0.0,1.0,0.0);

float fov=1.2;
*/
/*
mat4 mat4cam=mat4(
1.7840, -0.0100, -0.0039, -0.0039,
0.0000, 2.4666, -0.6289, -0.6286,
-0.0089, -1.9937, -0.7780, -0.7777,
0.1339, 25.2431, 15.6303, 15.8240
);
*/
/*
mat4 mat4cam=mat4(
vec4(1.7840,0.0,-0.0089,0.1339),
vec4(-0.01,2.4666,-1.9937,25.2431),
vec4(-0.0039,-0.6289,-0.7780,15.6303),
vec4(-0.0039,-0.6286,-0.7777,15.8240)
);
*/

uniform float testvalue;
uniform int flavor; //0 - standard  1 - snow
uniform float roughsize;
uniform float pioffset;

uniform vec3 rayorigin;
uniform vec3 raydirection;
uniform vec3 upvector;

uniform float fov;

uniform mat4 mat4cam;

#define noisetexturea noisetexture2
uniform sampler2D noisetexture2;
uniform sampler2D terraincolor;
uniform sampler2D waternormal;
uniform samplerCube env;
/*
#define noisetexture iChannel0
#define terraincolor iChannel1
#define waternormal iChannel2
#define noisetexture2 iChannel3
*/
///important

uniform float iTime;
uniform float scrollTime;
vec3 iResolution=vec3(1920.0,1080.0,1.0);
vec4 iMouse=vec4(1920.0/2.0,1080.0/2.0,1.0,1.0);
float iFrame=0.0;


float localTime = 0.0;
float marchCount;


vec2 hash2( vec2 p )
{
	// texture based white noise
	return textureLod( noisetexturea, (p+0.5)/256.0, 0.0 ).xy;
	
    // procedural white noise	
	//return fract(sin(vec2(dot(p,vec2(127.1,311.7)),dot(p,vec2(269.5,183.3))))*43758.5453);
}

#define ANIMATE
float iTime2=200123.456;
vec2 hash( vec2 p ) // replace this by something better
{
	p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
	return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

vec3 voronoi( in vec2 x )
{
    vec2 n = floor(x);
    vec2 f = fract(x);

    //----------------------------------
    // first pass: regular voronoi
    //----------------------------------
	vec2 mg, mr;

    float md = 8.0;
    for( int j=-1; j<=1; j++ )
    for( int i=-1; i<=1; i++ )
    {
        vec2 g = vec2(float(i),float(j));
		vec2 o = hash( n + g );
		#ifdef ANIMATE
        o = 0.5 + 0.5*sin( iTime2 + 6.2831*o );
        #endif	
        vec2 r = g + o - f;
        float d = dot(r,r);

        if( d<md )
        {
            md = d;
            mr = r;
            mg = g;
        }
    }

    //----------------------------------
    // second pass: distance to borders
    //----------------------------------
    md = 8.0;//8.0
    for( int j=-2; j<=2; j++ )
    for( int i=-2; i<=2; i++ )
    {
        vec2 g = mg + vec2(float(i),float(j));
		vec2 o = hash( n + g );
		#ifdef ANIMATE
        o = 0.5 + 0.5*sin( iTime2 + 6.2831*o );
        #endif	
        vec2 r = g + o - f;

        if( dot(mr-r,mr-r)>0.00001 )
        md = min( md, dot( 0.5*(mr+r), normalize(r-mr) ) );
    }

    return vec3( md, mr );
}

float PI=3.14159265;

vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }
vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }
float saturate(float a) { return clamp(a, 0.0, 1.0); }

vec3 RotateX(vec3 v, float rad)
{
  float cos = cos(rad);
  float sin = sin(rad);
  return vec3(v.x, cos * v.y + sin * v.z, -sin * v.y + cos * v.z);
}
vec3 RotateY(vec3 v, float rad)
{
  float cos = cos(rad);
  float sin = sin(rad);
  return vec3(cos * v.x - sin * v.z, v.y, sin * v.x + cos * v.z);
}
vec3 RotateZ(vec3 v, float rad)
{
  float cos = cos(rad);
  float sin = sin(rad);
  return vec3(cos * v.x + sin * v.y, -sin * v.x + cos * v.y, v.z);
}

vec3 rotateAxis(vec3 p, vec3 axis, float angle) {
return mix(dot(axis, p)*axis, p, cos(angle)) + cross(axis,p)*sin(angle);
}

mat4 rotationMatrix(vec3 axis, float angle)
{
    axis = normalize(axis);
    float s = sin(angle);
    float c = cos(angle);
    float oc = 1.0 - c;
    
    return mat4(oc * axis.x * axis.x + c,           oc * axis.x * axis.y - axis.z * s,  oc * axis.z * axis.x + axis.y * s,  0.0,
                oc * axis.x * axis.y + axis.z * s,  oc * axis.y * axis.y + c,           oc * axis.y * axis.z - axis.x * s,  0.0,
                oc * axis.z * axis.x - axis.y * s,  oc * axis.y * axis.z + axis.x * s,  oc * axis.z * axis.z + c,           0.0,
                0.0,                                0.0,                                0.0,                                1.0);
}

// noise functions
float Hash2d(vec2 uv)
{
    float f = uv.x + uv.y * 37.0;
    return fract(sin(f)*104003.9);
}
float Hash3d(vec3 uv)
{
    float f = uv.x + uv.y * 37.0 + uv.z * 521.0;
    return fract(sin(f)*110003.9);
}
float mixP(float f0, float f1, float a)
{
    return mix(f0, f1, a*a*(3.0-2.0*a));
}
const vec2 zeroOne = vec2(0.0, 1.0);
float noise2d(vec2 uv)
{
    vec2 fr = fract(uv.xy);
    vec2 fl = floor(uv.xy);
    float h00 = Hash2d(fl);
    float h10 = Hash2d(fl + zeroOne.yx);
    float h01 = Hash2d(fl + zeroOne);
    float h11 = Hash2d(fl + zeroOne.yy);
    return mixP(mixP(h00, h10, fr.x), mixP(h01, h11, fr.x), fr.y);
}
float noiseValue(vec3 uv)
{
    vec3 fr = fract(uv.xyz);
    vec3 fl = floor(uv.xyz);
    float h000 = Hash3d(fl);
    float h100 = Hash3d(fl + zeroOne.yxx);
    float h010 = Hash3d(fl + zeroOne.xyx);
    float h110 = Hash3d(fl + zeroOne.yyx);
    float h001 = Hash3d(fl + zeroOne.xxy);
    float h101 = Hash3d(fl + zeroOne.yxy);
    float h011 = Hash3d(fl + zeroOne.xyy);
    float h111 = Hash3d(fl + zeroOne.yyy);
    return mixP(
        mixP(mixP(h000, h100, fr.x),
             mixP(h010, h110, fr.x), fr.y),
        mixP(mixP(h001, h101, fr.x),
             mixP(h011, h111, fr.x), fr.y)
        , fr.z);
}

// IQ's style of super fast texture noise
float noiseTex(in vec3 x)
{
    vec3 fl = floor(x);
    vec3 fr = fract(x);
	fr = fr * fr * (3.0 - 2.0 * fr);
	vec2 uv = (fl.xy + vec2(37.0, 17.0) * fl.z) + fr.xy;
	vec2 rg = textureLod(noisetexturea, (uv + 0.5) * 0.00390625, 0.0 ).xy;
	return mix(rg.y, rg.x, fr.z);
}
float noiseTexdm(in vec3 x)
{
    vec3 fl = floor(x);
    vec3 fr = fract(x);
	fr = fr * fr * (3.0 - 2.0 * fr);
	vec2 uv = (fl.xy) + fr.xy;
	vec2 rg = textureLod(noisetexturea, (uv + 0.5) * 0.00390625, 0.0 ).xy;

    if (fl.z/2.0-floor(fl.z/2.0)==0.0)
	    return mix(rg.y, rg.x, fr.z);
    else
	    return mix(rg.x, rg.y, fr.z);
}
// 2 components returned
vec2 noiseTex2(in vec3 x)
{
    vec3 fl = floor(x);
    vec3 fr = fract(x);
	fr = fr * fr * (3.0 - 2.0 * fr);
	vec2 uv = (fl.xy + vec2(37.0, 17.0) * fl.z) + fr.xy;
	vec4 rgba = textureLod(noisetexturea, (uv + 0.5) * 0.00390625, 0.0 ).xyzw;
	return mix(rgba.yw, rgba.xz, fr.z);
}

float pnoise2 (in vec2 x){
return (texture2D(noisetexturea,x)).r;
}

vec3 camPos = vec3(0.0), camFacing;
vec3 camLookat=vec3(0,0.0,0);

// polynomial smooth min (k = 0.1);
float smin(float a, float b, float k)
{
    float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
    return mix( b, a, h ) - k*h*(1.0-h);
}
float smax(float a, float b, float k)
{
    float h = clamp( 0.5+0.5*((-b)+a)/k, 0.0, 1.0 );
    return -(mix( -b, -a, h ) - k*h*(1.0-h));
}

vec2 matMin(vec2 a, vec2 b)
{
	if (a.x < b.x) return a;
	else return b;
}

// Calculate the distance field that defines the object.
vec2 DistanceToObject(in vec3 p)
{
    // first distort the y with some noise so it doesn't look repetitive.
    //p.xyz = RotateY(p, length(p.xz) + iTime);
    //p.y += 0.1;
    //p.xyz = RotateZ(p, length(p.z) + iTime);
    p.y += noiseTex(p*0.5)*0.5;
    // multiple frequencies of noise, with time added for animation
    float n = noiseTex(p*2.0);
    n += noiseTex(p*4.0)*0.5;
    n += noiseTex(p*8.0)*0.25;
    n += noiseTex(p*16.0)*0.125;
    n += noiseTex(p*32.0)*0.0625;
    n += noiseTex(p*64.0)*0.0625*0.5;
    n += noiseTex(p*128.0)*0.0625*0.25;
    // subtract off distance for cloud thickness
    float dist = n*0.25 - (0.275);// - abs(p.y*0.02));
    //dist = smax(dist, -(length(p-camPos) - 0.3), 0.1);	// nice near fade
    // smooth blend subtract repeated layers
    dist = smax(dist, -(abs(fract(p.y*4.0)-0.5) - 0.15), 0.4);
    vec2 distMat = vec2(dist, 0.0);
    // sun in the distance
    distMat = matMin(distMat, vec2(length(p-camLookat - vec3(0.0, 0.5, -1.0)) - 0.6, 6.0));
    return distMat;
}

// discontinuous pseudorandom uniformly distributed in [-0.5, +0.5]^3 
vec3 random3(vec3 c) {
	float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));
	vec3 r;
	r.z = fract(512.0*j);
	j *= .125;
	r.x = fract(512.0*j);
	j *= .125;
	r.y = fract(512.0*j);
	return r-0.5;
}

// skew constants for 3d simplex functions 
const float F3 =  0.3333333;
const float G3 =  0.1666667;

float simplex3d(vec3 p) {

	 // calculate s and x 
	 vec3 s = floor(p + dot(p, vec3(F3)));
	 vec3 x = p - s + dot(s, vec3(G3));

	  //calculate i1 and i2 
	 vec3 e = step(vec3(0.0), x - x.yzx);
	 vec3 i1 = e*(1.0 - e.zxy);
	 vec3 i2 = 1.0 - e.zxy*(1.0 - e);

	 // x1, x2, x3 
	 vec3 x1 = x - i1 + G3;
	 vec3 x2 = x - i2 + 2.0*G3;
	 vec3 x3 = x - 1.0 + 3.0*G3;

     //const float scale=0.65; // the lower the bigger
     //x*=scale; x1*=scale; x2*=scale; x3*=scale; // added by dm

	 // 2. find four surflets and store them in d 
	 vec4 w, d;

	 // calculate surflet weights 
	 w.x = dot(x, x);
	 w.y = dot(x1, x1);
	 w.z = dot(x2, x2);
	 w.w = dot(x3, x3);

	 // w fades from 0.6 at the center of the surflet to 0.0 at the margin 
	 w = max(0.6 - w, 0.0);

	 // calculate surflet components 
	 d.x = dot(random3(s), x);
	 d.y = dot(random3(s + i1), x1);
	 d.z = dot(random3(s + i2), x2);
	 d.w = dot(random3(s + 1.0), x3);

	 // multiply d by w^4 
	 w *= w;
	 w *= w;
	 d *= w;

	 // 3. return the sum of the four surflets 
	 return dot(d, vec4(52.0));
}

vec2 opI( vec2 d1, vec2 d2 ) //{ return max(d1,d2); }
///-
{return (d1.x>d2.x) ? (d1) : (d2);}

vec2 map2( in vec3 pos ) /// intro sphere
{
    vec2 res=vec2(15.0, -100.0);

    pos=vec3(0,0,0.0);

    vec2 resnoise=vec2(simplex3d(pos+iTime/10.0),1.0);
    float noisefade=0.5;
    float a=resnoise.x; a=a+noisefade; a=clamp(a,-1.0,1.0); resnoise.x=a; ///noisefade -1.0,1.0
    res=opI(resnoise,res);
    res.y=1.0;
    return res;
}

void mainImage_( out vec4 fragColor, in vec2 fragCoord )
{
    localTime = iTime - 0.0;
	// ---------------- First, set up the camera rays for ray marching ----------------
	vec2 uv = fragCoord.xy/iResolution.xy * 2.0 - 1.0;
    float zoom = 1.7;
    uv /= zoom;

	// Camera up vector.
	vec3 camUp=vec3(0,1,0);

	// Camera lookat.
	camLookat=vec3(0,0.0,0);

    // debugging camera
    float mx=(iMouse.x/iResolution.x+0.375)*PI*2.0-0.7 + localTime*3.1415 * 0.0625*0.666*0.0;
	float my=-iMouse.y*0.0/iResolution.y*10.0 - sin(localTime * 0.31)*0.5*0.0;// *PI/2.01;
	camPos += vec3(cos(my)*cos(mx),sin(my),cos(my)*sin(mx))*(3.2);
    camPos.z -= iTime * 0.5;
    camLookat.z -= iTime * 0.5;

    camPos.y=60.0;
    camLookat.y = camPos.y;

    // add randomness to camera for depth-of-field look close up.
    // Reduces the banding the the marchcount glow causes
    camPos += vec3(Hash2d(uv)*0.91, Hash2d(uv+37.0), Hash2d(uv+47.0))*0.01;

	// Camera setup.
	vec3 camVec=normalize(camLookat - camPos);
	vec3 sideNorm=normalize(cross(camUp, camVec));
	vec3 upNorm=cross(camVec, sideNorm);
	vec3 worldFacing=(camPos + camVec);
	vec3 worldPix = worldFacing + uv.x * sideNorm * (iResolution.x/iResolution.y) + uv.y * upNorm;
	vec3 rayVec = normalize(worldPix - camPos);

	// ----------------------------------- Animate ------------------------------------
	// --------------------------------------------------------------------------------
	vec2 distAndMat = vec2(0.5, 0.0);
    const float nearClip = 0.02;
	float t = nearClip;
	//float maxDepth = 10.0;
    float maxDepth = 10.0;
	vec3 pos = vec3(0,0,0);
    marchCount = 0.0;
    if (false)
    {
        // ray marching time
        for (int i = int(max(0,-iFrame)); i < 150; i++)	// This is the count of the max times the ray actually marches.
        {
            pos = camPos + rayVec * t;
            // *******************************************************
            // This is _the_ function that defines the "distance field".
            // It's really what makes the scene geometry.
            // *******************************************************
            distAndMat = DistanceToObject(pos);
            if ((t > maxDepth) || (abs(distAndMat.x) < 0.0025)) break;
            // move along the ray
            t += distAndMat.x * 0.7;
            //marchCount+= (10.0-distAndMat.x)*(10.0-distAndMat.x)*1.2;//distance(lastPos, pos);
            marchCount+= 1.0/distAndMat.x;
        }
    }
    // dm standard rm:
    {
        ///tmin = max(tb.x,tmin);
        ///tmax = min(tb.y,tmax);

        const float tmin = 0.0000001;
        float t = tmin;
        const int steps_=60;
        const float precision_=0.001;

        for(int i=0; i<steps_; i++)
        {
            ///vec2 h = map2( ro+rd*t );
            vec2 h = map2(pos);
            if( abs(h.x)<(precision_*t) )
            {
                 ///res = vec2(t,h.y);
                 distAndMat = vec2(t,h.y);
                 break;
            }
            t += h.x*0.85;
        }
    }



    // --------------------------------------------------------------------------------
	// Now that we have done our ray marching, let's put some color on this geometry.

	vec3 finalColor = vec3(0.0);

	// If a ray actually hit the object, let's light it.
	if (abs(distAndMat.x) < 0.0025)
   // if (t <= maxDepth)
	{
        // ------ Calculate texture color ------
        ///vec3 texColor = vec3(0.2, 0.26, 0.21)*0.75;
        vec3 texColor;
        if (flavor==0)
            texColor = texture2D(terraincolor, pos.xz).xyz; //rock
        if (flavor==1)
            texColor = texture2D(terraincolor, pos.xz*2.0).xyz; //snow
        if (flavor==2)
            texColor = texture2D(terraincolor, pos.xz*15.0).xyz; //grass
        // sun material
        if (distAndMat.y == 6.0) texColor = vec3(0.51, 0.21, 0.1)*10.5;
        finalColor = texColor;

        // visualize length of gradient of distance field to check distance field correctness
        //finalColor = vec3(0.5) * (length(normalU) / smallVec.x);
        //finalColor = normal * 0.5 + 0.5;
	}
    else
    {
    }
    // This is the glow
    finalColor += marchCount * vec3(4.2, 1.0, 0.41) * 0.0001;
    // fog
	finalColor = mix(vec3(0.91, 0.81, 0.99)*1.75, finalColor, exp(-t*0.15));

    if (t <= nearClip) finalColor = vec3(1.9, 1.1, 0.9)*0.25 * noiseTex(vec3(iTime*8.0));

    // vignette?
    finalColor *= vec3(1.0) * pow(saturate(1.0 - length(uv/2.5)), 2.0);
    finalColor *= 1.2;
    finalColor *= 0.85;

	// output the final color with sqrt for "gamma correction"
	fragColor = vec4(sqrt(clamp(finalColor, 0.0, 1.0)),1.0);
fragColor = vec4(finalColor,1.0);
}







vec3 applyFog( vec3 rgb, float distance, vec3 rayDir, vec3  sunDir )  
{
    //float b = 23.6;
    float b = 2.36;
    float fogAmount = 1.0 - exp( -distance*b );
    float sunAmount = max( dot( rayDir, sunDir ), 0.0 );
    vec3  fogColor  =  vec3(1.0,0.9,0.7);
    return mix( rgb, fogColor, fogAmount );
}

float fn( float x, float y ){
	///return sin(x * 0.5) + sin(y * sin(-iTime*0.1) * 0.5)+ 1.5+0.5 *sin(x*0.01)*6.0;
    return sin(x * 0.5) + sin(y * 0.5)+ 1.5+0.5 *sin(x*0.01)*6.0;
}



vec3 castRay_( const vec2 uv, const vec3 ro, const vec3 rd )
{	

    const float delt = 0.01;
    const float mint = 0.001;
    const float maxt = 20.0;
    for( float t = mint; t < maxt; t += delt )
    {
        vec3 p = ro + rd*t;
        //float a=fn( p.x, p.z );
        float a = noiseValue(p.xyz);

        if( p.y < a)
        {
            //vec3 rgb = texture2D(terraincolor, p.xz * 0.5 + vec2(sin(p.x*14.0), cos(p.x * 14.435)+ iTime*1.0)).xyz * (0.4+ p.y * 0.5) ;
            vec3 rgb = texture2D(terraincolor, p.xz).xyz;
			///rgb = applyFog( rgb, delt, rd, vec3(0,0,-1.0));
			return rgb;
        }
    }
    return vec3(0.3 + uv.x * 0.5, 0.6, 0.9) ;
}

float sdBox( vec3 p, vec3 b )
{
    vec3 d = abs(p) - b;
    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}


float sdCylinder( vec3 p, vec2 h )
{
    vec2 d = abs(vec2(length(p.xz),p.y)) - h;
    return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}

//------------------------------------------------------------------

vec2 opUnion( vec2 d1, vec2 d2 ) { 
if (d1.x<d2.x) return d1; else return d2;
//return min(d1,d2); 
}

vec2 opSubtraction( vec2 d1, vec2 d2 ) {
if (-d1.x>d2.x) return -d1; else return d2;
//return max(-d1,d2); 
}

vec2 opIntersection( vec2 d1, vec2 d2 ) { 
if (d1.x>d2.x) return d1; else return d2;
//return max(d1,d2); 
}

//------------------------------------------------------------------

vec2 opSmoothIntersection( vec2 d1, vec2 d2, float k ) {
    float h = clamp( 0.5 - 0.5*(d2.x-d1.x)/k, 0.0, 1.0 );
    return vec2(mix( d2.x, d1.x, h ) + k*h*(1.0-h),17.0); }

vec2 opUs( vec2 d1, vec2 d2, float k ) {
    float h = clamp( 0.5 + 0.5*(d2.x-d1.x)/k, 0.0, 1.0 );
    h_=clamp((d2.x-d1.x)/k, -1.0, 1.0 );
    return vec2(mix( d2.x, d1.x, h ) - k*h*(1.0-h), d1.y); }

vec2 opUsIce( vec2 d1, vec2 d2, float k ) {
    float h = clamp( 0.5 + 0.5*(d2.x-d1.x)/k, 0.0, 1.0 );
    h_ice=clamp((d2.x-d1.x)/k, -1.0, 1.0 );
    return vec2(mix( d2.x, d1.x, h ) - k*h*(1.0-h), d1.y); }

float h_d;
vec2 opSs( vec2 d1, vec2 d2, float k ) {
    float h = clamp( 0.5 + 0.5*(-d2.x-d1.x)/k, 0.0, 1.0 );
    h_d=h;
    h_ice=clamp((-d2.x-d1.x)/k, -1.0, 1.0 );
    return vec2(mix( d1.x, -d2.x,  h ) + k*h*(1.0-h), d1.y); }

vec2 opSs_( vec2 d1, vec2 d2, float k ) {
    float h = clamp( 0.5 - 0.5*(d2.x+d1.x)/k, 0.0, 1.0 );
    return vec2(mix( d2.x, -d1.x, h ) + k*h*(1.0-h),d1.y); }

vec2 opS_( vec2 d1, vec2 d2 ){
    return (d1.x>-d2.x) ? d1 : -d2; }

vec2 blob2s( vec2 d1, vec2 d2, float k) {
    //const float k=4.5;
    float h = clamp( 0.5 + 0.5*(d2.x-d1.x)/k, 0.0, 1.0 );
    float color=(0.5-abs(0.5-h))*2.0;
    return vec2(mix( d2.x, d1.x, h ) - k*h*(1.0-h), color); }

float blob2(float d1, float d2)
{
    float k = 4.5;
    return -log(exp(-k*d1)+exp(-k*d2))/k;
}
float blob3(float d1, float d2,float d3)
{
    float k = 4.5;
    return -log(exp(-k*d1)+exp(-k*d2)+exp(-k*d3))/k;
}



vec2 opS( vec2 d1, vec2 d2 )
{
    return (d1.x>-d2.x) ? d1 : -d2;
}

vec2 opU( vec2 d1, vec2 d2 )
{
    return (d1.x<d2.x) ? d1 : d2;
}

vec3 opRep( vec3 p, vec3 c )
{
    return mod(p,c)-0.5*c;
}



float pnoise( in vec2 p )
{
    return (-1.0+2.0*texture2D(noisetexturea,p/100.0).r);

    const float K1 = 0.366025404; // (sqrt(3)-1)/2;
    const float K2 = 0.211324865; // (3-sqrt(3))/6;

	vec2  i = floor( p + (p.x+p.y)*K1 );
    vec2  a = p - i + (i.x+i.y)*K2;
    float m = step(a.y,a.x); 
    vec2  o = vec2(m,1.0-m);
    vec2  b = a - o + K2;
	vec2  c = a - 1.0 + 2.0*K2;
    vec3  h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
	vec3  n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
    return dot( n, vec3(70.0) );
}

//const float d=320.0;//40.0 dimension for the field 360.0
const float d=500.0;//40.0 dimension for the field 360.0
float screenwidth=1.0;
const float swbase=70.0;

vec2 mapsnowandice(vec3 pos){
    float background=sdBox(pos+vec3(0.0,0.0,0.0),vec3(d,d,d));
    vec2 background1=vec2(background,5.0); //background material = 5.0
    /*
    float a=simplex3d(pos);
    vec2 a1=vec2(a,1.0);
    float b=sdBox(pos+vec3(0.0,2.0,0.0),vec3(2.0,2.0,2.0));
    vec2 b1=vec2(b,1.0);
    float d=sdBox(pos+vec3(-6.5,1.5,-1.5),vec3(2.0,2.0,2.0));
    vec2 d1=vec2(d,1.0);

    vec2 c1=opI(a1,b1);
    */
    ///float n=pnoise(pos);
    float f,f_;
    const float stretch=12.0;
	//vec2 uv = vec2(pos.x/stretch,pos.z/stretch)+skrul;
    vec2 uv = vec2((pos.x+d/2.0)/stretch,(pos.z+d/2.0)/stretch)+skrul;
    uv_=uv;
    
        ///mat2 m = mat2( 1.6,  1.2, -1.2,  1.6 );
        mat2 m = mat2( 1.7,  1.3, -1.3,  1.7 );
		f  = 0.7000*pnoise( uv ); uv = m*uv;
		f_ = 0.250*pnoise( uv ); //uv = m*uv;
        //if (f<0.005) {f=-10.0;f_=0.0;} else 
        {f=(pow(f+0.8,1.5)-1.05)*2.0-0.05;}//f_/=2.5;}
        f+=f_;
        f*=2.0;

        float f2=0.0;
        uv = vec2((pos.x+d/2.0)/stretch/3.0,(pos.z+d/2.0)/stretch/3.0)+skrul/3.0;
		f2 = 0.3+0.2*pnoise( uv ); 
        if (!renderingreflection){
        uv = m*uv*10.0;
		f2 += 0.2*pnoise( uv ); //roughness
            uv = uv*(m*4.0)/3.0;
		    f2 += 0.1*pnoise( uv );//fine roughness
        }
    //f=0.5+f/2.0;
    const float size=1.5;//1.5
    vec2 n1=vec2(sdBox(pos+vec3(0,size,0),vec3(screenwidth,f*size,d)),2.0);
    vec2 nbig=n1;
    vec2 n2=vec2(sdBox(pos+vec3(0,size+0.7-1.3+0.11,0),vec3(d,f2*size,d)),2.0);
    vec2 n3=vec2(sdBox(pos+vec3(0,size+0.7-1.3+5.0-14.45,0),vec3(d,10.0,d)),2.0);
    n1 = opSs(n1, n2, 0.025); /// soft substraction
	n1 = opSs(n1, n3, 0.025); /// soft substraction

    nbig=n1=vec2(sdBox(pos+vec3(0,size,0),vec3(0.1,0.1,0.1)),2.0);

    vec2 water=vec2(sdBox(pos+vec3(0,size+0.1,0),vec3(d,0.1,d)),3.0);
    vec2 e1=opU(water,n1);

    vec2 temp=opUs(n1, water, 1.0);
    //if (h_<0.0&&h_>-0.3) {//-0.25
    if (h_<0.5&&h_>-0.8&&e1.y==3.0) {//-0.25
        e1.y=4.0; //water foam
        h_=(-h_+0.5)/1.3;
    }

    uv = vec2((pos.x+d/2.0)/stretch,(pos.z+1000.0+d/2.0)/stretch)+skrul;
	f  = 0.7000*pnoise( uv/2.5 );
    vec2 f1=vec2(0.0);
    if (!renderingreflection)
    if(f>0.035&&(e1.y==3.0||e1.y==4.0)) { //only on water and foam
    //if(f>0.035&&(e1.y==3.0)) { //only on water and foam
        float htemp=h_;
        
        vec2 ice=vec2(sdBox(pos+vec3(0,size+0.001,0),vec3(d,f*size,d)),2.0);
        
        temp=opSs(ice,water,1.1);
        float temph=h_ice;
        
        vec2 water2=opUs(water,nbig,1.0);
        temp=opSs(ice,water2,1.1);
        float h2=1.0-h_ice;
        
        
        //h_ice=min(h2,temph);
        h_ice=temph;
        
        

        
        
        float h_ice2=h_ice;
        //temp=opSs(temp,n1,1.1);
        //h_ice=max(h_,h_ice2);
        if (e1.y==3.0) //water
            h_ice=(1.0-clamp((h_)*1.0,0.0,1.0))*h_ice2;
        else //foam
            h_ice=(1.0-clamp((1.0-h_)*1.0,0.0,1.0))*h_ice2;
   h_ice=(1.0-clamp((1.0-h_)*1.0,0.0,1.0))*h_ice2;
        h_ice=-h_ice/0.5;
        h_ice_g=1.0-h_ice*2.0;

//if (e1.y==4.0) h_ice_g=1.0; //foam
   
//if (h_ice_g>0.99) h_ice_g=1.0;
debug=h_ice_g;
        
        if (h_ice_g<0.99) 
            e1.y=6.0; //ice

            //float a=clamp((-h_ice/1.0-0.2),0.0,1.0);
            //a=pow(a,1.25);
            //float a=1.0-clamp((h_ice_g/1.0),0.0,1.0);
            //a=pow(a,1.25);
            float a=1.0-clamp((h_ice_g/1.0),0.0,1.0);
            a=a/3.25;
            a=pow(a,1.25)/1.5;

float f11;//=-a;

        //f=0.25; f += 0.2500*pnoise( uv ); uv = m*uv;
        //f2=0.4*a;//1.2*a;
        //f2=0.2*a*1.1;
        //f11=f*(1.0-a);//decrease 0.04 to drop it lower//(a*2.0);//(1.0-a);
        f11=f*(2.0-(1.0+a))-0.035;//decrease 0.04 to drop it lower//(a*2.0);//(1.0-a);
        vec2 icebump=vec2(sdBox(pos+vec3(0,size,0),vec3(d,f11*size,d)),6.0);
        //vec2 icebump=vec2(sdBox(pos+vec3(0,f2*size/2.0,0),vec3(d,f2*size,d)),6.0);

        //vec2 icebump=vec2(sdBox(pos+vec3(0,size+0.001,0),vec3(d,f2*size,d)),6.0);
        //e1=opU(water,icebump);
        e1=icebump;
        //e1=water;
        e1.y=6.0;
        
        
        //h_=htemp;
        //h_=h_ice2=h_ice=h_ice_g;
    }
    //vec2 g1=opU(n1,c1);

    //vec2 e1=opU(g1,d1);
 
    ///vec2 f1=opI(e1,background1);
    f1=e1;//opI(e1,background1);
    return f1;
}


float sinusmaker(float x, float pos){
pos=pos/10.0;
float r;
float xoff[5], rsize[5], rd[5];
xoff[0]=100.0;
xoff[1]=1000.0;
/*
xoff[2]=20000.0;
xoff[3]=30000.0;
xoff[4]=4000.0;
*/

rsize[0]=0.3;
rsize[1]=0.4;
/*
rsize[2]=0.6;
rsize[3]=0.4;
rsize[4]=0.3;
*/

rd[0]=1.9;
rd[1]=2.2;
/*
rd[2]=1.3;
rd[3]=0.6;
rd[4]=0.4;
*/
    //r=sin(x/10.0);
    r=0.0;
    for (int i=0;i<2;i++){
        r=r+sin(x+pos*rd[i]+xoff[i])*2.0+rsize[i];
    }
    return clamp(r/2.4,-1.0,1.0);
}

vec2 mapice(vec3 pos){
float fade=1.0;
    if (pos.x<0){
        if (-pos.x<screenwidth) {fade=-pos.x/screenwidth; if (fade>0.8) {fade=1.0-fade;fade*=5.0;}else fade=1.0;}
    } else {
        if (pos.x<screenwidth) {fade=pos.x/screenwidth; if (fade>0.8) {fade=1.0-fade;fade*=5.0;}else fade=1.0;}
    }

    //float background=sdBox(pos+vec3(0.0,0.0,0.0),vec3(d,d,d));
    //vec2 background1=vec2(background,5.0); //background material = 5.0
    float f,f_;
    const float stretch=20.0;//12.0;
    vec2 uv = vec2((pos.x+d/2.0)/stretch,(pos.z+d/2.0)/stretch)+skrul;
    uv_=uv;
    
    const float heightboost=0.3;

        mat2 m = mat2( 1.7,  1.3, -1.3,  1.7 );
		f  = 0.7000*(pnoise( uv )+heightboost); uv = m*uv;
		f_ = 0.250*pnoise( uv ); //uv = m*uv;
        {f=(pow(f+0.8,1.5)-1.05)*2.0-0.05;}//f_/=2.5;}
        f+=f_;
        f+=0.3;
        f*=2.0;
        f*=fade;

        float f2=0.0;
        uv = vec2((pos.x+d/2.0)/stretch/3.0,(pos.z+d/2.0)/stretch/3.0)+skrul/3.0;
		f2 = 0.3+0.2*pnoise( uv ); 
        if (!renderingreflection){
        uv = m*uv*10.0;
		f2 += 0.2*pnoise( uv ); //roughness
            uv = uv*(m*4.0)/3.0;
		    f2 += 0.1*pnoise( uv );//fine roughness
        }
        f2*=fade;

    const float size=1.5;//1.5
    vec2 n1=vec2(sdBox(pos+vec3(0,size,0),vec3(screenwidth,f*size,d)),2.0);
    vec2 nbig=n1;
    if (!renderingreflection){
        vec2 n2=vec2(sdBox(pos+vec3(0,size+0.7-1.3+0.11,0),vec3(d,f2*size,d)),2.0);
        vec2 n3=vec2(sdBox(pos+vec3(0,size+0.7-1.3+5.0-14.45,0),vec3(d,10.0,d)),2.0);
        n1 = opSs(n1, n2, 0.025); /// soft substraction
	    n1 = opSs(n1, n3, 0.025); /// soft substraction
    }

    //nbig=n1=vec2(sdBox(pos+vec3(0,size,0),vec3(0.1,0.1,0.1)),2.0);

    vec2 water=vec2(sdBox(pos+vec3(0,size+0.1,0),vec3(d,0.1,d)),3.0);
    vec2 e1=opU(water,n1);

    vec2 temp=opUs(n1, water, 1.0);
    if (h_<0.5&&h_>-0.8&&e1.y==3.0&&fade>0.8) {//-0.25
        e1.y=4.0; //water foam
        h_=(-h_+0.5)/1.3;
    }
/*
    uv = vec2((pos.x+d/2.0)/stretch,(pos.z+1000.0+d/2.0)/stretch)+skrul;
	f  = 0.7000*pnoise( uv/2.5 );
    vec2 f1=vec2(0.0);
    if (!renderingreflection)
    if(f>0.035&&(e1.y==3.0||e1.y==4.0)) { //only on water and foam
        float htemp=h_;
        
        vec2 ice=vec2(sdBox(pos+vec3(0,size+0.001,0),vec3(d,f*size,d)),2.0);
        
        temp=opSs(ice,water,1.1);
        float temph=h_ice;
        
        vec2 water2=opUs(water,nbig,1.0);
        temp=opSs(ice,water2,1.1);
        float h2=1.0-h_ice;
        
        h_ice=temph;
        
        float h_ice2=h_ice;
        if (e1.y==3.0) //water
            h_ice=(1.0-clamp((h_)*1.0,0.0,1.0))*h_ice2;
        else //foam
            h_ice=(1.0-clamp((1.0-h_)*1.0,0.0,1.0))*h_ice2;
   h_ice=(1.0-clamp((1.0-h_)*1.0,0.0,1.0))*h_ice2;
        h_ice=-h_ice/0.5;
        h_ice_g=1.0-h_ice*2.0;

debug=h_ice_g;
        
        if (h_ice_g<0.99) 
            e1.y=6.0; //ice

            float a=1.0-clamp((h_ice_g/1.0),0.0,1.0);
            a=a/3.25;
            a=pow(a,1.25)/1.5;

float f11;//=-a;
        f11=f*(2.0-(1.0+a))-0.035;//decrease 0.04 to drop it lower//(a*2.0);//(1.0-a);
        vec2 icebump=vec2(sdBox(pos+vec3(0,size,0),vec3(d,f11*size,d)),6.0);
        e1=icebump;
        e1.y=6.0;
    }
    */
 
    vec2 cyl=vec2(sdCylinder(pos+vec3(0.0,0.0,0.0),vec2(d-10.0,d)),3.0);
    float mat=e1.y;
    vec2 f1=vec2(opIntersection(e1,cyl).x,mat);//opI(e1,background1);

    //vec2 f1=e1;//opI(e1,background1);
    return f1;
}

vec2 mapsnow(vec3 pos){
float fade=1.0;
    if (pos.x<0){
        if (-pos.x<screenwidth) {fade=-pos.x/screenwidth; if (fade>0.8) {fade=1.0-fade;fade*=5.0;}else fade=1.0;}
    } else {
        if (pos.x<screenwidth) {fade=pos.x/screenwidth; if (fade>0.8) {fade=1.0-fade;fade*=5.0;}else fade=1.0;}
    }

    //float background=sdBox(pos+vec3(0.0,0.0,0.0),vec3(d,d,d));
    //vec2 background1=vec2(background,5.0); //background material = 5.0
    /*
    float a=simplex3d(pos);
    vec2 a1=vec2(a,1.0);
    float b=sdBox(pos+vec3(0.0,2.0,0.0),vec3(2.0,2.0,2.0));
    vec2 b1=vec2(b,1.0);
    float d=sdBox(pos+vec3(-6.5,1.5,-1.5),vec3(2.0,2.0,2.0));
    vec2 d1=vec2(d,1.0);

    vec2 c1=opI(a1,b1);
    */
    ///float n=pnoise(pos);
    float f,f_;
    const float stretch=20.0;//12.0;
	//vec2 uv = vec2(pos.x/stretch,pos.z/stretch)+skrul;
    vec2 uv = vec2((pos.x+d/2.0)/stretch,(pos.z+d/2.0)/stretch)+skrul;
    uv_=uv;
/*    
        ///mat2 m = mat2( 1.6,  1.2, -1.2,  1.6 );
        mat2 m = mat2( 1.7,  1.3, -1.3,  1.7 );
		f  = 0.7000*pnoise( uv ); uv = m*uv;
		f_ = 0.250*pnoise( uv ); //uv = m*uv;
        //if (f<0.005) {f=-10.0;f_=0.0;} else 
        {f=(pow(f+0.8,1.5)-1.05)*2.0-0.05;}//f_/=2.5;}
        f+=f_;
        f*=2.0;

        float f2=0.0;
        uv = vec2((pos.x+d/2.0)/stretch/3.0,(pos.z+d/2.0)/stretch/3.0)+skrul/3.0;
		f2 = 0.3+0.2*pnoise( uv ); 
        if (!renderingreflection){
        uv = m*uv*10.0;
		f2 += 0.2*pnoise( uv ); //roughness
            uv = uv*(m*4.0)/3.0;
		    f2 += 0.1*pnoise( uv );//fine roughness
        }
    //f=0.5+f/2.0;
    const float size=1.5;//1.5
    vec2 n1=vec2(sdBox(pos+vec3(0,size,0),vec3(screenwidth,f*size,d)),2.0);
    vec2 nbig=n1;
    vec2 n2=vec2(sdBox(pos+vec3(0,size+0.7-1.3+0.11,0),vec3(d,f2*size,d)),2.0);
    vec2 n3=vec2(sdBox(pos+vec3(0,size+0.7-1.3+5.0-14.45,0),vec3(d,10.0,d)),2.0);
    n1 = opSs(n1, n2, 0.025); /// soft substraction
	n1 = opSs(n1, n3, 0.025); /// soft substraction
*/
    const float size=1.5;//1.5
    vec2 nbig,n1;
    nbig=n1=vec2(sdBox(pos+vec3(0,d,0),vec3(0.1,0.1,0.1)),2.0);

    vec2 water=vec2(sdBox(pos+vec3(0,size+0.1,0),vec3(d,0.1,d)),3.0);
    vec2 e1=opU(water,n1);

    vec2 temp=opUs(n1, water, 1.0);
    //if (h_<0.0&&h_>-0.3) {//-0.25
    if (h_<0.5&&h_>-0.8&&e1.y==3.0) {//-0.25
        e1.y=4.0; //water foam
        h_=(-h_+0.5)/1.3;
    }

    uv = vec2((pos.x+d/2.0)/stretch,(pos.z+1000.0+d/2.0)/stretch)+skrul;
	f  = 0.7000*pnoise( uv/2.5 );
	f  += 0.2+0.7*pnoise( uv/0.3+vec2(0.4123) );
    if (pos.x<-screenwidth||pos.x>screenwidth) f=0.0;
    vec2 f1=vec2(0.0);
    if (!renderingreflection)
    if(f>0.035&&(e1.y==3.0||e1.y==4.0)) { //only on water and foam
    //if(f>0.035&&(e1.y==3.0)) { //only on water and foam
        float htemp=h_;
        
        vec2 ice=vec2(sdBox(pos+vec3(0,size+0.001,0),vec3(d,f*size,d)),2.0);
        
        temp=opSs(ice,water,1.1);
        float temph=h_ice;
        
        vec2 water2=opUs(water,nbig,1.0);
        temp=opSs(ice,water2,1.1);
        float h2=1.0-h_ice;
        
        
        //h_ice=min(h2,temph);
        h_ice=temph;
        
        

        
        
        float h_ice2=h_ice;
        //temp=opSs(temp,n1,1.1);
        //h_ice=max(h_,h_ice2);
        if (e1.y==3.0) //water
            h_ice=(1.0-clamp((h_)*1.0,0.0,1.0))*h_ice2;
        else //foam
            h_ice=(1.0-clamp((1.0-h_)*1.0,0.0,1.0))*h_ice2;
   h_ice=(1.0-clamp((1.0-h_)*1.0,0.0,1.0))*h_ice2;
        h_ice=-h_ice/0.5;
        h_ice_g=1.0-h_ice*2.0;

//if (e1.y==4.0) h_ice_g=1.0; //foam
   
//if (h_ice_g>0.99) h_ice_g=1.0;
debug=h_ice_g;
        
        if (h_ice_g<0.99) 
            e1.y=6.0; //ice

            //float a=clamp((-h_ice/1.0-0.2),0.0,1.0);
            //a=pow(a,1.25);
            //float a=1.0-clamp((h_ice_g/1.0),0.0,1.0);
            //a=pow(a,1.25);
            float a=1.0-clamp((h_ice_g/1.0),0.0,1.0);
            a=a/3.25;
            a=pow(a,1.25)/1.5;

float f11;//=-a;

        //f=0.25; f += 0.2500*pnoise( uv ); uv = m*uv;
        //f2=0.4*a;//1.2*a;
        //f2=0.2*a*1.1;
        //f11=f*(1.0-a);//decrease 0.04 to drop it lower//(a*2.0);//(1.0-a);
        f11=f*(2.0-(1.0+a))-0.035;//decrease 0.04 to drop it lower//(a*2.0);//(1.0-a);
        f11 *=fade;
        vec2 icebump=vec2(sdBox(pos+vec3(0,size,0),vec3(d,f11*size,d)),6.0);
        //vec2 icebump=vec2(sdBox(pos+vec3(0,f2*size/2.0,0),vec3(d,f2*size,d)),6.0);

        //vec2 icebump=vec2(sdBox(pos+vec3(0,size+0.001,0),vec3(d,f2*size,d)),6.0);
        //e1=opU(water,icebump);
        e1=icebump;
        //e1=water;
        e1.y=6.0;
        
        
        //h_=htemp;
        //h_=h_ice2=h_ice=h_ice_g;
    }
    //vec2 g1=opU(n1,c1);

    //vec2 e1=opU(g1,d1);
 
    vec2 cyl=vec2(sdCylinder(pos+vec3(0.0,0.0,0.0),vec2(d-10.0,d)),3.0);
    float mat=e1.y;
    f1=vec2(opIntersection(e1,cyl).x,mat);//opI(e1,background1);

    ///vec2 f1=opI(e1,background1);
    //f1=e1;//opI(e1,background1);
    return f1;
}

vec2 mapgrass(vec3 pos){
    //float background=sdBox(pos+vec3(0.0,0.0,0.0),vec3(d,d,d));
    //vec2 background1=vec2(background,5.0); //background material = 5.0
    float f;
    const float stretch=30.0;
    vec2 uv = vec2((pos.x+d/2.0)/stretch,(pos.z+d/2.0)/stretch)+skrul;
    uv_=uv;
        mat2 m = mat2( 1.7,  1.3, -1.3,  1.7 );
        f=0.25;
		f += 0.2500*pnoise( uv ); uv = m*uv;
		f += 0.2500*pnoise( uv ); //uv = m*uv;
        /*
        if (!renderingreflection){
		    f += 0.1250*pnoise( uv ); uv = m*uv;
		    f += 0.0625*pnoise( uv ); 
        
            uv = m*uv*2.0;
		    f += roughsize*pnoise( uv ); //roughness
        
            uv = uv*(m*4.0)/3.0;
		    f += roughsize/2.0*pnoise( uv );//fine roughness
        }
        */
    //f=0.5+f/2.0;
    //f*=testvalue;
    f*=5.0;//8.3
    const float size=1.5;//1.5
    vec2 n1=vec2(sdBox(pos+vec3(0,size,0),vec3(d,f*size,d)),2.0);
	///vec2 n1 = vec2(dot(vec4(0,f,0,1), vec4(52.0)),2.0);
    
    vec2 water=vec2(sdBox(pos+vec3(0,size+0.1,0),vec3(d,0.1,d)),3.0);
    vec2 e1=opU(water,n1);
    
    vec2 temp=opUs(n1, water, 1.0);
    if (h_<0.0&&h_>-0.3) {//-0.25
        e1.y=4.0; //water foam
        h_=-h_/0.3;
    }

    vec2 cyl=vec2(sdCylinder(pos+vec3(0.0,0.0,0.0),vec2(d-10.0,d)),3.0);
    float mat=e1.y;
    vec2 f1=vec2(opIntersection(e1,cyl).x,mat);//opI(e1,background1);
    
    //vec2 f1=e1;//opI(e1,background1);
    return f1;
    
    //return n1;
}

float noisemaker(vec2 p){
    return -1.0+2.0*pnoise(p);
}

vec2 map(vec3 pos){
float sin1,sin2;

const float stretch1=1.0/3.0;
//vec2 uv1 = vec2((pos.x+d/2.0)/stretch1/3.0,(pos.z+d/2.0)/stretch1/3.0)+skrul/3.0;
vec2 uv1;

if (flavor==0) uv1=vec2(0.0,(pos.z+d/2.0)/stretch1/3.0*0.35)+skrul*4.1*1.7;
else           uv1=vec2(0.0,(pos.z+d/2.0)/stretch1/3.0*0.35)+skrul*4.1*1.7;

    //sin1=0.15+sinusmaker(stime,12345.0+pos.z/20.0*70.0/10.0)*0.25;
    //sin2=0.85+sinusmaker(stime,1234321.0+pos.z/20.0*70.0/10.0)*0.25;
    
    sin1=sin2=0.0;
    for (float i=-2.0;i<3.0;i++){
        if (flavor==0) uv1=vec2(0.0,(pos.z+0.1*i+d/2.0)/stretch1/3.0*0.35)+skrul*4.1*1.7;
        else           uv1=vec2(0.0,(pos.z+0.1*i+d/2.0)/stretch1/3.0*0.35)+skrul*4.1*1.7;
        //sin1+=0.25+noisemaker(uv1);
        //sin2+=0.75+noisemaker(uv1);
        sin1+=0.25+sinusmaker(0.0,12345.0+uv1.y)*0.25;
        sin2+=0.75+sinusmaker(0.0,1234321.0+uv1.y)*0.25;
    }
    sin1/=5.0;
    sin2/=5.0;
    //sin2=sin1;

        
    //if (uv.x>sin1&&uv.x<sin2) col=vec3(1.0,1.0,1.0);
    if (pos.x<0.0){
        //debug=vec3(sin1,0,0);
        screenwidth=1.0-sin1;
        }
    else{
        //debug=vec3(0,sin2,0);
        screenwidth=sin2;
        }
    //screenwidth*=10.0;
    screenwidth*=swbase;


    //==0 rocks
    if (flavor==1) return mapsnow(pos);
    if (flavor==2) return mapgrass(pos);
    if (flavor==3) return mapice(pos);

float fade=1.0;
    if (pos.x<0){
        if (-pos.x<screenwidth) {fade=-pos.x/screenwidth; if (fade>0.8) {fade=1.0-fade;fade*=5.0;} else fade=1.0;}
    } else {
        if (pos.x<screenwidth) {fade=pos.x/screenwidth; if (fade>0.8) {fade=1.0-fade;fade*=5.0;} else fade=1.0;}
    }

    //float background=sdBox(pos+vec3(0.0,0.0,0.0),vec3(d,d,d));
    //vec2 background1=vec2(background,5.0); //background material = 5.0
    /*
    float a=simplex3d(pos);
    vec2 a1=vec2(a,1.0);
    float b=sdBox(pos+vec3(0.0,2.0,0.0),vec3(2.0,2.0,2.0));
    vec2 b1=vec2(b,1.0);
    float d=sdBox(pos+vec3(-6.5,1.5,-1.5),vec3(2.0,2.0,2.0));
    vec2 d1=vec2(d,1.0);

    vec2 c1=opI(a1,b1);
    */
    ///float n=pnoise(pos);
    const float zoomin=2.0;
    float f=0.0;
    const float stretch=10.0*zoomin;
	//vec2 uv = vec2(pos.x/stretch,pos.z/stretch)+skrul;
    //vec2 uv = vec2((pos.x+10.0)/stretch,(pos.z+10.0)/stretch)+skrul;
    vec2 uv = vec2((pos.x+d/2.0)/stretch,(pos.z+d/2.0)/stretch)+skrul;
    uv_=uv;
        ///mat2 m = mat2( 1.6,  1.2, -1.2,  1.6 );
        if (fade>0.0){
        mat2 m = mat2( 1.7,  1.3, -1.3,  1.7 );
		f  = 0.5000*pnoise( uv ); uv = m*uv;
		f += 0.2500*pnoise( uv ); uv = m*uv;
        uv=uv_;
        float fplus;
		fplus = 0.5000*pnoise( uv +vec2(0.3123)); uv = m*uv;
		fplus += 0.2500*pnoise( uv +vec2(0.2123)); uv = m*uv;
        ///f=clamp(f,0.0,0.85);
        if (fplus>f) f=fplus;

        if (!renderingreflection){
		    f += 0.1250*pnoise( uv ); uv = m*uv;
		    f += 0.0625*pnoise( uv ); 

            f *= zoomin*1.5;
        
            uv = m*uv*2.0;
		    f += roughsize*pnoise( uv ); //roughness
        
            //uv = uv*(m*4.0)/3.0;
		    //f += roughsize/2.0*pnoise( uv );//fine roughness
        } else f=0.0;
        fade=clamp(fade*4.0,0.0,1.0);
        f *= fade;
    }
    const float size=1.5;//1.5
    if (pos.x<-screenwidth||pos.x>screenwidth) f=0.0;

    //vec2 n1=vec2(sdBox(pos+vec3(0,size,0),vec3(0.1,f*size,0.1)),2.0);
    
    //vec2 n1=pos.y-(terrain(pos.zx*0.07))*2.7-1.;
    /*
    vec2 n1;
    if (f==0.0)
        n1 = vec2(pos.y+0,2.0);
    else
        n1 = vec2(pos.y+f*size+1.8+testvalue,2.0);
    */
    vec2 n1=vec2(sdBox(pos+vec3(0,size,0),vec3(d,f*size+1.8-2.3,d)),2.0);

    /*
    //vec2 na=vec2(sdBox(pos+vec3(pos.x,size,pos.z),vec3(0.1,f*size,d)),2.0);
    //vec2 nb=vec2(sdBox(pos+vec3(pos.x,size,pos.z),vec3(d,f*size,0.1)),2.0);
    vec2 na=vec2(sdBox(pos+vec3(0,size,0),vec3(d,f*size,d)),2.0);
    vec2 nb=vec2(sdBox(pos+vec3(0,size,0),vec3(d,(f-0.15)*size,d)),2.0);
    vec2 n1=opU(na,nb);
    */

    vec2 water=vec2(sdBox(pos+vec3(0,size+0.1,0),vec3(d,0.1,d)),3.0);
    
    vec2 e1;
    if (fade<=0.0||f==0.0) {e1=water;} else 
    {
        e1=opU(water,n1);
    }

    vec2 temp=opUs(n1, water, 1.5);
    if (h_<0.0&&h_>-0.3&&fade>0.8&&e1.y==3.0) {//-0.25    -0.3
        e1.y=4.0; //water foam
        h_=-h_/0.3;
    }
    //vec2 g1=opU(n1,c1);

    //vec2 e1=opU(g1,d1);
 
    ///vec2 f1=opI(e1,background1);
    vec2 cyl=vec2(sdCylinder(pos+vec3(0.0,0.0,0.0),vec2(d-10.0,d/20.0)),3.0);
    float mat=e1.y;
    vec2 f1=vec2(opIntersection(e1,cyl).x,mat);//opI(e1,background1);

    //vec2 f1=e1;//opI(e1,background1);
    return f1;
}

const float normaleps=0.005;
vec3 calcNormal( in vec3 pos )
{
    vec3 eps = vec3( normaleps, 0.0, 0.0 );

    vec3 nor = vec3(
        map(pos+eps.xyy).x - map(pos-eps.xyy).x,
        map(pos+eps.yxy).x - map(pos-eps.yxy).x,
        map(pos+eps.yyx).x - map(pos-eps.yyx).x );
    return normalize(nor);

}

vec2 castRay_latest( const vec3 ro, vec3 rd )
 {
    vec2 res=vec2(-1,-1);
    const float tmin = 0.0000001;
    float t = tmin;
    int steps_=int(60.0*1.75);
    ///const float precision_=0.001;
    float precision_=0.001/64.0; //consider reverting to above for performance gain
    float stepper=0.85;

    if (flavor==0||flavor==1||flavor==3) { //rocks or snow or ice
        steps_=150;
        precision_=0.0001;
        stepper=0.72;
    }

    if (flavor==2) {
        steps_=150;//grass hills need fine resolution at edges
        precision_=0.0001;
        stepper=0.72;//1.2
    }
    if (renderingreflection) steps_=40;
    {
        ///tmin = max(tb.x,tmin);
        ///tmax = min(tb.y,tmax);

        float t = tmin;
        for( int i=0; i<steps_; i++ )
        {
            ///float a = noiseValue(ro+rd*t);
            vec2 a = map(ro+rd*t);

            vec2 h = a;
            ///vec2 h = vec2(noiseValue(p.xyz),1.0);
            if( abs(h.x)<(precision_*t) )
            {
                res = vec2(t,h.y);
                break;
            }
            t += h.x*stepper;
        }
    }

    ///t = res.x;
    float m = res.y;
    material=m;
    return res;

    //vec3 pos = ro + t*rd;
    //vec3 nor = calcNormal( pos );

    //vec3 col;
    //col = texture2D(terraincolor, pos.xz).xyz;
    //return col;
}

vec2 castRay( const vec3 ro, vec3 rd )
 {
    vec2 res=vec2(-1,-1);
    const float tmin = 0.0000001;
    float t = tmin;
    //int steps_=int(60.0*1.75);
    //float precision_=0.001/64.0; //consider reverting to above for performance gain
    int steps_=150*3;
    float precision_=0.001/64.0*200.0/2.0/100.0;
    float stepper=0.85; //0.85

    if (flavor==2) {
        steps_=150;//grass hills need fine resolution at edges
        precision_=0.0001;
        stepper=1.2;
    }
    if (renderingreflection) { //speedup for the empty sky area
        steps_=40;
        precision_=0.001/64.0;
    }
 
    if (rd.y>0.05) return vec2(0.0,0.0);


    {
        ///tmin = max(tb.x,tmin);
        ///tmax = min(tb.y,tmax);

        float t = tmin;
        for( int i=0; i<steps_; i++ )
        {
            ///float a = noiseValue(ro+rd*t);
            vec2 a = map(ro+rd*t);

            vec2 h = a;
            ///vec2 h = vec2(noiseValue(p.xyz),1.0);
            if( abs(h.x)<(precision_*t) )
            {
                res = vec2(t,h.y);
                break;
            }
            t += h.x*stepper;
        }
    }

    ///t = res.x;
    float m = res.y;
    material=m;
    return res;

    //vec3 pos = ro + t*rd;
    //vec3 nor = calcNormal( pos );

    //vec3 col;
    //col = texture2D(terraincolor, pos.xz).xyz;
    //return col;
}

mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
{
//return mat3cam;
    vec3 cw = normalize(ta-ro);

    //vec3 cp = vec3(sin(cr), cos(cr),0.0);
    vec3 cp = upvector;
    ///vec3 cp = vec3(0,1,0);

    vec3 cu = normalize( cross(cw,cp) );
    vec3 cv = normalize( cross(cu,cw) );
    return mat3( cu, cv, cw );
}

float softShadow(vec3 ro, vec3 lp, float k){

    // More would be nicer. More is always nicer, but not really affordable... Not on my slow test machine, anyway.
    int maxIterationsShad = 24;//24; 
    //if (flavor==2) maxIterationsShad = 48;//24; 
    
    vec3 rd = lp - ro; // Unnormalized direction ray.

    float shade = 1.;
    float dist = .002;    
    float end = max(length(rd), .001);
    /*
    if (flavor==2){
        dist = .000002;    
        end = max(length(rd), .000001);
    }
    */
    float stepDist = end/float(maxIterationsShad);
    
    rd /= end;

    // Max shadow iterations - More iterations make nicer shadows, but slow things down. Obviously, the lowest 
    // number to give a decent shadow is the best one to choose. 
    for (int i = 0; i<maxIterationsShad; i++){

        float h = map(ro + rd*dist).x;
        //shade = min(shade, k*h/dist);
        shade = min(shade, smoothstep(0., 1., k*h/dist)); // Subtle difference. Thanks to IQ for this tidbit.
        // So many options here, and none are perfect: dist += min(h, .2), dist += clamp(h, .01, .2), 
        // clamp(h, .02, stepDist*2.), etc.
        dist += clamp(h, .02, .25);
        //dist += clamp(h, .02, stepDist*2.);
        
        // Early exits from accumulative distance function calls tend to be a good thing.
        if (h<0. || dist>end) break; 
        //if (h<.001 || dist > end) break; // If you're prepared to put up with more artifacts.
    }

    // I've added 0.5 to the final shade value, which lightens the shadow a bit. It's a preference thing. 
    // Really dark shadows look too brutal to me.
    //return min(max(shade, 0.) + .25, 1.); 
    shade=1.0-(clamp((1.0-shade)*50.0,0.,1.));
    return clamp(shade, 0.05, 1.0); 
}

float pnoisex( in vec2 p )
{
    const float K1 = 0.366025404; // (sqrt(3)-1)/2;
    const float K2 = 0.211324865; // (3-sqrt(3))/6;

	vec2  i = floor( p + (p.x+p.y)*K1 );
    vec2  a = p - i + (i.x+i.y)*K2;
    float m = step(a.y,a.x); 
    vec2  o = vec2(m,1.0-m);
    vec2  b = a - o + K2;
	vec2  c = a - 1.0 + 2.0*K2;
    vec3  h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
	vec3  n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));
    return dot( n, vec3(70.0) );
}

/*
materials:
2 - terrain
3 - water
4 - foam
5 - background
6 - ice cracks
*/
vec3 render( in vec3 ro, in vec3 rd )
{
vec3 pos;
bool notbackground=false;
const float bkboost=0.7;

    //vec3 col = vec3(0.7, 0.7, 1.0) +rd.y*0.8;

    vec3 bkcolor1=vec3(0.3, 0.3, 0.5);// + vec3(1.0, 0.8, 0.9);
    vec3 bkcolor=vec3(23.0/256.0, 48.0/256.0, 92.0/256.0);// + vec3(1.0, 0.8, 0.9);
    bkcolor=mix(bkcolor1,bkcolor,0.3);
    //bkcolor=vec3(1,0,0);

    //vec3 bkcolor=vec3(0.7, 0.7, 1.0);// + vec3(1.0, 0.8, 0.9);
    //vec3 bkcolor=vec3(25.0/255.0, 26.0/255.0, 53.0/255.0);// + vec3(1.0, 0.8, 0.9);
    vec3 col = bkcolor;// + vec3(1.0, 0.8, 0.9);
    vec2 res = castRay(ro,rd);
    float t = res.x;
    float m = res.y;

        if (renderingreflection && selectrender>0.0) col=bkcolor; else
        {
            col=textureCube(env,rd+vec3(0.0,+0.125,0.0)).xyz; ///background
            //col=textureCube(env,rd).xyz; ///background
            if (!renderingreflection) {
                fadecol=col;
                if (rd.y<-0.07) if (flavor==0) col=vec3(33.0/255.0,29.0/255.0,28.0/255.0)*1.5; //else col=texture2D(terraincolor,vec2(0.2,0.2)); // 'hole' filling color for the terrain
            }
        }
        ///fadecol=vec3(1.0,0.0,0.0);

        notbackground=false;
        //return col;

        pos = ro + t*rd;
        //.if (!renderingreflection)
            fadepos=pos;
        vec4 poz=vec4(pos.xyz,1.0);// /10.0f
        poz=mat4cam*poz;
        float zp2 = poz.z;
        float wp2 = poz.w;
        float x22 = zp2/wp2;
        x22=zp2/wp2*depthmult-depthmax;

        ///pos = ro + t*rd;

        vec3 nor;
        if (material==3.0||material==4.0||material==6.0) //water or water foam //or snow
            nor = vec3(0,1,0);
        else
            nor = calcNormal( pos );


        //if(false)
        if (material==3.0||material==4.0||material==6.0){
            
            plasmacol=vec3(1.0,1.0,1.0); if (plasmafx>0) {
                //const float nzoom=0.45;
                //plasmacol*=(pow((simplex3d(vec3(uv_.x*nzoom/1.2,uv_.y*nzoom,iTime/3.0)))+1.2,1.4)/1.33);
                const float nzoom=3.45*3.0;
                //plasmacol*=(pow((noiseTexdm(vec3(uv_.x*nzoom/1.2,uv_.y*nzoom,iTime/2.5)))+1.1,1.4)/1.2);
                plasmacol*=(pow((noiseTexdm(vec3(uv_.x*nzoom/1.2,uv_.y*nzoom,iTime/2.5+uv_.y/10.0)))+1.1,1.4)/1.2);
            }
            vec2 uv2_;
            float uvscale=3.5*0.7;//testvalue; //1.2
            uv2_.x=uv_.x*-uvscale+1.0*iTime/40.0;
            uv2_.y=uv_.y*-uvscale+1.0*iTime/47.0;
            vec2 uvw1=uv_*uvscale+vec2(1.0)*iTime/44.0;
            vec2 uvw2=uv2_;
            /*
            const float spd=2.0;
            const float sinscl=5.0;
            float v11 = uv_.y+0.1*sin(uv_.x*3.1*0.2+ iTime/1.0*spd)*0.2*sinscl;
            float v12 = uv_.x+0.1*cos(uv_.y*3.1*0.2+ iTime/1.0*spd)*0.2*sinscl;
            float v21 = uv_.y+0.1*sin(uv_.x*4.2*0.2+ iTime/1.7*spd)*0.2*sinscl;
            float v22 = uv_.x+0.1*cos(uv_.y*4.2*0.2+ iTime/1.7*spd)*0.2*sinscl;
            uvw1+=vec2(v11,v12); uvw2+=vec2(v21,v22);
            */
            ///uvw1*=testvalue; uvw2*=testvalue;
            uvw1*=0.85; uvw2*=0.85;
            if (true)//if (selectrender>0.0)
            {
               const float spd=2.0;
               float res=2048.0*3.0;//testvalue;
               vec2 mov1=vec2(-10.0,-0.05)*iTime*spd/res;
               vec2 mov2=vec2(-10.0,0.05)*iTime*spd/res;
               const float scl=0.01*2.5;
               vec3 nor_=texture2D(waternormal, uvw1*scl+mov1).xyz/2.75+texture2D(waternormal, uvw2*scl+mov2).xyz/2.75;
               nor_+=texture2D(noisetexturea, uv_*scl).xyz/5.5;
               /*
               vec3 nor_=
               texture2D(waternormal, vec2(noise2d(uvw1),noise2d(uvw2))*testvalue).xyz/2.75+
               texture2D(waternormal, vec2(noise2d(uvw1+vec2(0.5,0.5)),noise2d(uvw2)+vec2(0.3,0.7))*testvalue).xyz/2.75;
               */
               //nor_*=testvalue;

               if (selectrender>0.0){
                    if (material==6.0){
                        float a=1.0-clamp((h_ice_g/1.0-.33),0.0,1.0);
                        a=pow(a,1.25);
                        nor_=mix(nor_,vec3(0.0,1.0,0.0),a);
                    }
                   nor_.z=-nor_.z;
                   nor_+=vec3(0.5,0.5,0.5);
                   nor+=nor_/vec3(5.15);
               } else {
                    nor_-=vec3(0.5,0.5,0.5);
                    if (material==6.0) {
                        float a=1.0-clamp((h_ice_g/1.0-.33),0.0,1.0);
                        a=pow(a,1.25);
                        nor_=mix(nor_,vec3(0.0,1.0,0.0),a);
                    }
                    nor+=nor_/vec3(5.15);
                    nor.y*=0.2*1.25;
                    ///if (plasmafx>0) nor.z*=-plasmacol.x;
                   //nor_.z=-nor_.z;
                   //nor_+=vec3(0.5,0.5,0.5);
                   //nor=nor_;// /vec3(5.15);
               }
            } 
            /*
            else {
               vec3 nor_=texture2D(waternormal, uvw1).xyz/3.0+texture2D(waternormal, uvw2).xyz/3.0;
               //const float nzoom=60.0;
               //nor_.z=nor_.z *(pnoise(vec2(uv_.x*nzoom,uv_.y*nzoom))+1.0)*3.0;
               if (material==6.0) {
                   float a=1.0-clamp((h_ice_g/1.0-.33),0.0,1.0);
                   a=pow(a,1.25);
                   nor_=mix(nor_,vec3(0.0,1.0,0.0),a);
                   //nor+=nor_/5.0;
                   nor_.z=-nor_.z;
                   nor_+=vec3(0.5,0.5,0.5);
                   nor+=nor_/vec3(5.15);
               }
               else{
                   //nor_.z=-nor_.z;
                   //nor_+=vec3(0.5,0.5,0.5);
                   nor=nor_/5.0;
               }
            }
            */
            ///if (testvalue<0) nor=vec3(0,1,0);
        }

        nor=normalize(nor);

        //refrd = reflect(rd, nor);
        refrd = reflect(rd, nor);
        ///refro=pos+nor*0.003;
        refro=pos+nor*-0.01;
        ///if (plasmafx>0) refro=pos+nor*0.03;

            //col=vec4(1.2,0.19,0.25,1.0).xyz;
            //col=textureCube(env,normalize(ro+rd)).xyz; ///background
            //col=textureCube(env,RotateY(rd,3.14)).xyz; ///background

        //vec3 ref;
        //ref = reflect( rd, nor );

        if (m>0.0){
        // lighting
        ///-float occ = calcAO( pos, nor );
        //vec3  lig = normalize( vec3(-4.4, 0.7, 0.0) )*100.0;
        vec3 lig;
        if (flavor==2)
            lig = normalize( vec3(-4.4, 0.7, -0.5) )*4.5; //grass
        else
            lig = normalize( vec3(-4.4, 0.7, -0.5) )*d*1.1;
/*
        float amb = clamp( 0.5+0.5*nor.y, 0.0, 1.0 );
        float dif = clamp( (1.0+dot( nor, lig ))/2.0, 0.0, 1.0 );
        float spe = pow(clamp((1.0+dot(rd-ro,ref))/2.0,0.0,1.0),1.2);
        */

        // sun
        float amb = 0.2;
        
            ///vec3  lig = normalize( vec3(-0.5, 0.4, -0.6) );
            vec3  hal = normalize( lig-rd );
            float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
          //if( dif>0.0001 )
        	      ///dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
			float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
                  spe *= dif;
                  spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
            //lin += col*2.20*dif*vec3(1.30,1.00,0.70);
            //lin +=     5.00*spe*vec3(1.30,1.00,0.70)*ks;

        vec3 lin = vec3(0.0);

        if (material==2.0){ //terrain
        /*
            float f1,f2;
            const float stretch=10.0;
	        vec2 uv = uv_*6.0;//vec2(pos.x/stretch,pos.z/stretch)+skrul;
		    f2 = (1.0+1.000*pnoise( uv ))/2.0;
            uv.x=uv.x+2000.0;
		    f1 = (1.0+1.000*pnoise( uv ))/2.0; 
            vec2 terruv=vec2(f1,f2);
            //vec2 terruv=vec2(skrul.x,f2);
            col=texture2D(terraincolor, terruv);
            ///col=vec4(0.5,0.5,0.5,1.0);
            */
            if (flavor==2)
                col=texture2D(terraincolor, uv_*3.0).xyz;//grass
            else if (flavor==3) {uvice=RotateZ(vec3 (uv_.x,uv_.y,0.0), 3.14/2.5).xy/1.5;col=texture2D(terraincolor, uvice).xyz;}
                 else
                    col=texture2D(terraincolor, uv_).xyz;
            notbackground=true;
        }
const float boost=1.2;//1.65


        ///lin += 2.00*spe*vec3(1.00,0.90,0.70)*dif*boost;
        if (material==3.0||material==4.0||material==6.0){ //water or water foam or ice
            //col=vec4(0.2,0.19,0.21,1.0);
            col=vec4(0.2,0.19,0.25,1.0).xyz;
            notbackground=true;
            lin += (1.33*spe*vec3(0.9,0.9,0.9)*(dif/4.0)*boost)/6.5;
            lin += (1.30*dif*vec3(0.9,0.9,0.9)*boost)/3.0;
        } else if (material==5.0){ //background
            //col=vec4(1.2,0.19,0.25,1.0).xyz;
            //col=textureCube(env,normalize(ro+rd)).xyz*vec3(10.0,1.0,1.0); ///background
            ///lin = vec3(1,1,1);
        } else {
            lin += 1.30*dif*vec3(1.00,1.00,1.00)*boost;
        }

        amb=1.0;
        lin += 0.75*amb*vec3(0.70,0.70,0.70)*boost;
        ///if (material==3.0||material==4.0||material==6.0) lin*=testvalue;
        ///-lin += 0.50*dom*vec3(0.70,0.70,0.70)*occ;
        ///-lin += 0.50*bac*vec3(0.25,0.25,0.25)*occ;
        ///-lin += 0.25*fre*vec3(1.00,1.00,1.00)*occ;
        lin=clamp(lin,0.1,1.0);

        if (material==4.0){ //water foam
            float a=clamp((1.1-h_)/3.0,0.0,1.0);
            vec2 uvf = uv_*1.5; uvf.x+=iTime/34.0;
            vec2 uvf2 = -uv_*1.2; uvf2.x+=iTime/44.0;
            uvf*=0.01*10.5; uvf2*=0.01*10.5; //0.01*2.5
            col+=(vec4(a*1.5,a*1.5,a*1.75,1)*(texture2D(waternormal, uvf).x+texture2D(waternormal, uvf2).x)/1.5).xyz;
        }
        if (material==6.0){ //snow
            const float crackzoom=24.0*1.66*1.33*2.0;
            float a=1.0-clamp((h_ice_g/1.0),0.0,1.0);
            a=pow(a,1.25);
            vec4 n=texture2D(noisetexture2,uv_/crackzoom)+
            texture2D(noisetexture2,(uv_/crackzoom*7.0+vec2(0.3,0.3))) /vec4(10.0)+
            texture2D(noisetexturea,(uv_/crackzoom*5.5+vec2(0.7,0.4))) /vec4(4.0*1.5)+
            texture2D(noisetexturea,(uv_/crackzoom*20.0+vec2(0.3,0.3))) /vec4(3.5*1.33);
            
            vec2 uv_2=RotateZ(vec3 (uv_.x,uv_.y,0.0), 3.14/2.5).xy;

            vec3 c = voronoi((uv_2*5.4/2.0+vec2(n.x,n.y)/1.1/2.0+vec2(5000,6543))*2.5);
            // isolines
            vec3 colv=vec3(1.0);//c.x*(0.5+0.5*sin(64.0*c.x))*vec3(1.0);
            // borders
            colv=mix(vec3(0.05,0.05,0.05), colv,smoothstep(0.03,0.03,c.x))*8.0;colv=clamp(colv,0.0,1.0);
            colv=(texture2D(terraincolor, uv_)*vec4(2.0)).xyz*colv;
            //col=mix(col*colv,col,a);

            col=mix(col,colv,a);
            //col=colv;
            //col=vec3(1,0,0);
        }

        if (notbackground)
            col=col*lin;

        float sh;
        //if (flavor==2)//grass
            //sh = softShadow(pos, lig, 32.0); //16.0
        //else
        if (flavor==0.0) //3.0 skipped for performance reasons
            sh = softShadow(pos, lig, 16.0); //16.0
        else //only water receives shadow
            sh=1.0;

        if (material==3.0||material==4.0) //water & foam
            sh=clamp(sh,0.1,1.0); //water gets darker shadows
        else
            sh=clamp(sh,0.65,1.0); //however we don't want rocks to get completely black
        if (flavor!=2&&notbackground)
            col = col * sh; //grass ain't using no shadows ;)
        }

        if (plasmafx>0&&(material==3.0||material==4.0||material==6.0)) col=mix(col,col*plasmacol,col.b);

        return vec3(clamp(col,0.0,1.0));
}
/*
vec3 render2( in vec3 ro, in vec3 rd )
{
vec3 pos;
bool notbackground=false;
const float bkboost=0.7;

    //vec3 col = vec3(0.7, 0.7, 1.0) +rd.y*0.8;

    vec3 bkcolor1=vec3(0.3, 0.3, 0.5);// + vec3(1.0, 0.8, 0.9);
    vec3 bkcolor=vec3(23.0/256.0, 48.0/256.0, 92.0/256.0);// + vec3(1.0, 0.8, 0.9);
    bkcolor=mix(bkcolor1,bkcolor,0.3);
    //bkcolor=vec3(1,0,0);

    //vec3 bkcolor=vec3(0.7, 0.7, 1.0);// + vec3(1.0, 0.8, 0.9);
    //vec3 bkcolor=vec3(25.0/255.0, 26.0/255.0, 53.0/255.0);// + vec3(1.0, 0.8, 0.9);
    vec3 col = bkcolor;// + vec3(1.0, 0.8, 0.9);
    vec2 res = castRay(ro,rd);
    float t = res.x;
    float m = res.y;

        //vec3 fadecol;    
        if (renderingreflection) col=bkcolor; else
        {
        fadecol=col=textureCube(env,rd+vec3(0.0,+0.125,0.0)).xyz; ///background
        if (rd.y<-0.095) if (flavor==0) col=vec3(33.0/255.0,29.0/255.0,28.0/255.0)*1.5; else col=texture2D(terraincolor,vec2(0.2,0.2)).rgb; // 'hole' filling color for the terrain
        //vec3 rd_=normalize(rd+vec3(0.0,+0.125,0.0));
        }

        notbackground=false;
        //return col;

        pos = ro + t*rd;
        if (!renderingreflection)
            fadepos=pos;
        vec4 poz=vec4(pos.xyz,1.0);// /10.0f
        poz=mat4cam*poz;
        float zp2 = poz.z;
        float wp2 = poz.w;
        float x22 = zp2/wp2;
        x22=zp2/wp2*depthmult-depthmax;

        ///pos = ro + t*rd;
        vec3 nor = calcNormal( pos );
        //if(false)
        if (material==3.0||material==4.0||material==6.0){ //water or water foam //or snow
           vec2 uv2_;
           float uvscale=3.5*0.7;//testvalue; //1.2
           //if (flavor==0) uvscale=3.5*1.0; //rocks 1.2
           //if (flavor==1) uvscale=3.5*0.8; //ice 0.65
           uv2_.x=uv_.x*-uvscale+1.0*iTime/40.0;
           uv2_.y=uv_.y*-uvscale+1.0*iTime/47.0;
           vec2 uvw1=uv_*uvscale+vec2(1.0)*iTime/44.0;
           vec2 uvw2=uv2_;
           float v11 = uv_.y+0.1*sin(uv_.x*3.1 + iTime/1.0);
           float v12 = uv_.x+0.1*cos(uv_.y*3.1 + iTime/1.0);
           float v21 = uv_.y+0.1*sin(uv_.x*4.2 + iTime/1.7);
           float v22 = uv_.x+0.1*cos(uv_.y*4.2 + iTime/1.7);
           uvw1+=vec2(v11,v12); uvw2+=vec2(v21,v22);
           vec3 nor_=texture2D(waternormal, uvw1).xyz/3.0+texture2D(waternormal, uvw2).xyz/3.0;
           //nor_/=2.0*1.0/2.0;
           const float nzoom=60.0;
           nor_.z=-nor_.z;// *(pnoise(vec2(uv_.x*nzoom,uv_.y*nzoom))+1.0)*3.0;
           if (material==6.0) {
            float a=1.0-clamp((h_ice_g/1.0-.33),0.0,1.0);
            a=pow(a,1.25);

               //float a=clamp((-h_ice_g/2.0-0.2),0.0,1.0);
               //a*=2.0; a=clamp(a,0.0,1.0);
               nor_=mix(nor_,vec3(0.0,1.0,0.0),a);
               //nor_=vec3(0.0,1.0,0.0);
           nor+=nor_/5.0;
           }
           else
           nor=nor_/5.0;
           //nor+=nor_;
        }
        nor=normalize(nor);

        refrd = reflect(rd, nor);
        //refno=nor;
        refro=pos+nor*0.003;

            //col=vec4(1.2,0.19,0.25,1.0).xyz;
            //col=textureCube(env,normalize(ro+rd)).xyz; ///background
            //col=textureCube(env,RotateY(rd,3.14)).xyz; ///background

        //vec3 ref;
        //ref = reflect( rd, nor );

        if (m>0.0){
        // lighting
        ///-float occ = calcAO( pos, nor );
        //vec3  lig = normalize( vec3(-4.4, 0.7, 0.0) )*100.0;
        vec3 lig;
        if (flavor==2)
            lig = normalize( vec3(-4.4, 0.7, -0.5) )*4.5; //grass
        else
            lig = normalize( vec3(-4.4, 0.7, -0.5) )*100.0;
        // sun
        float amb = 0.2;
        
            ///vec3  lig = normalize( vec3(-0.5, 0.4, -0.6) );
            vec3  hal = normalize( lig-rd );
            float dif = clamp( dot( nor, lig ), 0.0, 1.0 );
          //if( dif>0.0001 )
        	      ///dif *= calcSoftshadow( pos, lig, 0.02, 2.5 );
			float spe = pow( clamp( dot( nor, hal ), 0.0, 1.0 ),16.0);
                  spe *= dif;
                  spe *= 0.04+0.96*pow(clamp(1.0-dot(hal,lig),0.0,1.0),5.0);
            //lin += col*2.20*dif*vec3(1.30,1.00,0.70);
            //lin +=     5.00*spe*vec3(1.30,1.00,0.70)*ks;
        

        vec3 lin = vec3(0.0);

        if (material==2.0){ //terrain
            if (flavor==2)
                col=texture2D(terraincolor, uv_*3.0).xyz;//grass
            else
                col=texture2D(terraincolor, uv_).xyz;
            notbackground=true;
        }
const float boost=1.2;//1.65


        ///lin += 2.00*spe*vec3(1.00,0.90,0.70)*dif*boost;
        if (material==3.0||material==4.0||material==6.0){ //water or water foam or ice
            //col=vec4(0.2,0.19,0.21,1.0);
            col=vec4(0.2,0.19,0.25,1.0).xyz;
            notbackground=true;
            lin += (1.33*spe*vec3(0.9,0.9,0.9)*(dif/4.0)*boost)/6.5;
            lin += (1.30*dif*vec3(0.9,0.9,0.9)*boost)/3.0;
        } else if (material==5.0){ //background
            //col=vec4(1.2,0.19,0.25,1.0).xyz;
            //col=textureCube(env,normalize(ro+rd)).xyz*vec3(10.0,1.0,1.0); ///background
            ///lin = vec3(1,1,1);
        } else {
            lin += 1.30*dif*vec3(1.00,1.00,1.00)*boost;
        }

        amb=1.0;
        lin += 0.75*amb*vec3(0.70,0.70,0.70)*boost;
        ///-lin += 0.50*dom*vec3(0.70,0.70,0.70)*occ;
        ///-lin += 0.50*bac*vec3(0.25,0.25,0.25)*occ;
        ///-lin += 0.25*fre*vec3(1.00,1.00,1.00)*occ;
        lin=clamp(lin,0.1,1.0);

        if (material==4.0){ //water foam
            float a=clamp((1.1-h_)/3.0,0.0,1.0);
            vec2 uvf = uv_*1.5; uvf.x+=iTime/20.0;
            vec2 uvf2 = -uv_*1.4; uvf2.x+=iTime/24.0;
            col+=(vec4(a*1.5,a*1.5,a*1.75,1)*(texture2D(waternormal, uvf).x+texture2D(waternormal, uvf2).x)/1.5).xyz;
        }
        
        if (material==6.0){ //snow
            const float crackzoom=24.0*1.66*1.33*2.0;
            float a=1.0-clamp((h_ice_g/1.0),0.0,1.0);
            a=pow(a,1.25);
            vec2 uvsimplex_=vec2(pnoisex(uv_/crackzoom),pnoisex(uv_/crackzoom+vec2(0.12,0.61)))*3.1;
            vec4 n=texture2D(noisetexture2,uvsimplex_)+vec4(0.7,1.75,0.24,0.2)+
            texture2D(noisetexture2,(uv_/crackzoom*7.0+vec2(0.3,0.3))) /vec4(10.0)+
            texture2D(noisetexturea,(uv_/crackzoom*5.5+vec2(0.7,0.4))) /vec4(4.0*2.0)+
            texture2D(noisetexturea,(uv_/crackzoom*20.0+vec2(0.3,0.3))) /vec4(7.5*2.0);
            
            vec2 uv_2=RotateZ(vec3 (uv_.x,uv_.y,0.0), 3.14/2.5).xy;

            vec3 c = voronoi(uv_2*5.4+vec2(n.x,n.y)/1.1+vec2(.123456,.75123));
            // isolines
            vec3 colv=vec3(1.0);//c.x*(0.5+0.5*sin(64.0*c.x))*vec3(1.0);
            // borders
            colv=mix(vec3(0.05,0.05,0.05), colv,smoothstep(0.03,0.03,c.x))*8.0;colv=clamp(colv,0.0,1.0);
            colv=(texture2D(terraincolor, uv_)*vec4(2.0)).xyz*colv;
            //col=mix(col*colv,col,a);

            col=mix(col,colv,a);
            //col=colv;
            //col=vec3(1,0,0);
        }
        
  
        if (notbackground)
            col=col*lin;

        float sh;
        //if (flavor==2)//grass
            //sh = softShadow(pos, lig, 32.0); //16.0
        //else
        if (flavor==0)
            sh = softShadow(pos, lig, 16.0); //16.0
        else //only water receives shadow
            sh=1.0;

        if (material==3.0||material==4.0) //water foam
            sh=clamp(sh,0.1,1.0); //water gets darker shadows
        else
            sh=clamp(sh,0.4,1.0); //however we don't want rocks to get completely black
        if (flavor!=2&&notbackground)
            col = col * sh; //grass ain't using no shadows ;)
        }

        return vec3(clamp(col,0.0,1.0));
}
*/
vec3 render_( in vec3 ro, in vec3 rd )
{
    return render(ro,rd); 
    //if (selectrender<=0.0) return render(ro,rd); else return render2(ro,rd);
}


#define AA 1

void mainImage2( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 mo = iMouse.xy/iResolution.xy;
    float time = 15.0 + iTime;


    vec3 tot = vec3(0.0);
#if AA>1
    for( int m=0; m<AA; m++ )
        for( int n=0; n<AA; n++ )
        {
            // pixel coordinates
            vec2 o = vec2(float(m),float(n)) / float(AA) - 0.5;
            vec2 p = (-iResolution.xy + 2.0*(fragCoord+o))/iResolution.y;
#else
    vec2 p = (-iResolution.xy + 2.0*fragCoord)/iResolution.y;
#endif

            // camera
            vec3 ro = vec3( -0.5+3.5*cos(0.1*time + 6.0*mo.x), 3.0 + 2.0*mo.y, 0.5 + 4.0*sin(0.1*time + 6.0*mo.x) );
            vec3 ta = vec3( -0.5, -0.4, 0.5 );

//dm installed camera control:
            ro=rayorigin;// /vec3(20.0);
            ta=raydirection;// /vec3(20.0);
            
            //fully working camera based fish eye distortion effect
            //vec3 cameran=normalize(rotateAxis(normalize(ta-ro), normalize(upvector), PI/2.0));
            //ta+=cameran.xyz*fishdx*10.0;
            const float st=10.0; //strength
            if (leftside){
                vec3 cameran=normalize(rotateAxis(normalize(ta-ro), normalize(upvector), PI/2.0));
                //vec3 cameran=normalize(rotateAxis(normalize(ta-ro), vec3(0,1,0), PI/2.0));
                ta+=cameran.xyz*fishdx*st;
                ro+=cameran.xyz*fishdx*st;
            } else {
                vec3 cameran=normalize(rotateAxis(normalize(ta-ro), normalize(upvector), -PI/2.0));
                //vec3 cameran=normalize(rotateAxis(normalize(ta-ro), vec3(0,1,0), -PI/2.0));
                ta+=cameran.xyz*fishdx*st;
                ro+=cameran.xyz*fishdx*st;
            }


            //something semi-working
            /*
            vec3 cameran=normalize(rotateAxis(normalize(ta-ro), normalize(upvector), PI/2.0));
            ta+=cameran.xyz*fishdx*10.0;
            */

            //something semi-working
            /*
            vec3 cameran=normalize(rotateAxis(ta, upvector, PI));
            ta+=cameran.xyz*fishdx*10.0;
            */

            ///naive approach that works for default cam position:
            //ta.x+=fishdx*5.0*3.0;

            // camera-to-world transformation
            ca = setCamera( ro, ta, 0.0 );
            //mat3 ca = mat3cam;


            // ray direction
            //vec3 rd = ca * normalize( vec3(p.x,p.y+1.0,2.0) );
    //vec3 rd = ca * normalize( vec3(p.x,p.y,2.0) );
      vec3 rd = ca * normalize( vec3(p.x,p.y,fov ) );


            //vec4 rd1= ca * vec4(normalize( vec3(p.xy,2.0) ),1.0);
            //vec3 rd = vec3(rd1.xyz);

            // render
            vec3 col = render_( ro, rd );

            //render reflection:
            vec3 colref;
            if ((material==1.0||material==3.0||material==4.0||material==6.0)) //default material only, add as needed        water and foam added
            {
                renderingreflection=true;
                colref = render_(refro, refrd);
                renderingreflection=false;
                tot += col*.5+colref*.6;
            }
            else
            {
                tot += col;
            }

        if (true){
           //float dist=pow(clamp(1.0-length(pos)/length(vec3(d,0,0))*2.0,0.0,1.0)*10.0,1.0/1.15); //10.0 is the stretch factor (the smaller the more fade)
           //float dist=clamp((1.0-length(fadepos)/length(vec3(d,0,0))*1.2),0.0,1.0);
           float dist=clamp(((1.0-length(fadepos)/length(vec3(d,0,0)))*1.7),0.0,1.0);
           tot=mix(tot,fadecol,clamp(1.0-dist,0.0,1.0));//fade (alpha fog)
        }

            // gamma
            //col = pow( col, vec3(0.4545) );

#if AA>1
        }
    tot /= float(AA*AA);
#endif

    fragColor = vec4( tot, 1.0 );
}

//////////////////////////////////////////classic barrel distort
//http://github.prideout.net/barrel-distortion/

vec2 Distort(vec2 p)
{
vec2 p2;

    p.x=p.x-0.5;
    p.y=p.y-0.5;
    p=-p;
    float theta  = atan(p.y, p.x);
    float radius = length(p)*2.0;
    ///radius = pow(radius, 1.5);
    radius = pow(radius, 0.5);
    p2.x = -radius * cos(theta);
    p2.y = -radius * sin(theta);
    //return 0.5 * (p + 1.0);
    //p2.x=p2.x-0.5;
    //p2.y=p2.y-0.5;
    p2= 0.5 * (p2 + 1.0);
    //if (p2.x<0) p2.x=0; if (p2.x>1.0) p2.x=1.0;
    //if (p2.y<0) p2.y=0; if (p2.y>1.0) p2.y=1.0;
    return p2;
}

//void main()
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    ///skrul=vec2(0,-iTime/1.05)*speed;

    ///totalcolor=vec3(0,0,0);
    ///totalindex=0.0;

    ///if (rendertoshadowmap==1) iResolution=vec3(1024,1024,0);

    vec4 color=vec4(0.0, 0.0, 0.0, 1.0);
    vec2 coos=gl_FragCoord.xy;
    /*
    coos.x/=iResolution.x;
    coos.y/=iResolution.y;
    coos=Distort(coos);
    coos.x*=iResolution.x;
    coos.y*=iResolution.y;
    */
    //coos.x=(coos.x-400*(sin(coos.x/iResolution.x*PI+PI/2.0)+1.0));
    //coos.y=(coos.y-200*(sin(coos.y/iResolution.x*PI+PI/2.0)+1.0));
    //coos.x/=iResolution.x;
    float xc=coos.x/iResolution.x;
    //coos.x+=sin(((coos.x-0.5)*2.0)*PI/2)*0.26;
    //fishdx=sin(((coos.x-0.5)*2.0)*PI/2)*0.5;
    //fishdx=(1.0-pow((xc-0.5+pioffset),2.0))*10.0;
    const float dim=3.0;
    if (xc<0.40) { //0,0.5
        fishdx=sin(xc*PI*pioffset+PI/2.0); //1,0
        fishdx=mix(fishdx/dim,0.0,xc*(1.0/0.40));
        leftside=true;
    } else if (xc>0.60){
        xc-=0.5;
        xc=0.5-xc; //0.5,0
        //fishdx=sin(xc*PI+PI/2+pioffset); //0,1
        fishdx=sin(xc*PI*pioffset+PI/2.0); //1,0
        fishdx=mix(fishdx/dim,0.0,xc*(1.0/0.40));
        leftside=false;
    } else { 
        fishdx=0.0;
    }
    float yc=coos.y/iResolution.y;
    if (yc>0.5) {
        yc=1.0-yc;
        yc=0.5-yc; 
        yc=yc*2.0; yc*=-1.0;
    } else {
        yc=0.5-yc; 
        yc=yc*2.0;
    }
    // 0 -- 0.5 -- 0
    // 1 -- 0 -- -1
    fishdx*=yc;
    
    fishdx=0.0;

    //coos.x*=iResolution.x;
    /*
    coos.y/=iResolution.y;
    //coos.y-=(1.0-abs(cos(((xc-0.5)*2.0)*PI/2)))*0.25;
    coos.y*=iResolution.y;
    fishdy=(1.0-abs(cos(((xc-0.5)*2.0)*PI/2)))*0.25;
    */
    mainImage2(color,coos);

    //gl_FragColor = color;
    fragColor = color;
//    fragColor = vec4(debug,debug,debug,1);
}

void main()
{
    skrul=vec2(0,-scrollTime/1.05)*speed;// *testvalue;

    //stime=skrul.y/3.0;
    ///totalcolor=vec3(0,0,0);
    ///totalindex=0.0;

    ///if (rendertoshadowmap==1) iResolution=vec3(1024,1024,0);

    vec4 color=vec4(0.0, 0.0, 0.0, 1.0);
    vec2 coos=gl_FragCoord.xy;
    /*
    coos.x/=iResolution.x;
    coos.y/=iResolution.y;
    coos=Distort(coos);
    coos.x*=iResolution.x;
    coos.y*=iResolution.y;
    */
    //coos.x=(coos.x-400*(sin(coos.x/iResolution.x*PI+PI/2.0)+1.0));
    //coos.y=(coos.y-200*(sin(coos.y/iResolution.x*PI+PI/2.0)+1.0));
    //coos.x/=iResolution.x;
    float xc=coos.x/iResolution.x;
    float yc=coos.y/iResolution.y;
    //coos.x+=sin(((coos.x-0.5)*2.0)*PI/2)*0.26;
    //fishdx=sin(((coos.x-0.5)*2.0)*PI/2)*0.5;
    //fishdx=(1.0-pow((xc-0.5+pioffset),2.0))*10.0;
    float dim=0.9*2.0;
    //dim=testvalue;
    if (xc<0.40) { //0,0.5
        fishdx=sin(xc*PI*pioffset+PI/2); //1,0
        fishdx=mix(fishdx/dim,0,xc*(1.0/0.40));
        leftside=true;
    } else if (xc>0.60){
        xc-=0.5;
        xc=0.5-xc; //0.5,0
        //fishdx=sin(xc*PI+PI/2+pioffset); //0,1
        fishdx=sin(xc*PI*pioffset+PI/2); //1,0
        fishdx=mix(fishdx/dim,0,xc*(1.0/0.40));
        leftside=false;
    } else { 
        fishdx=0;
    }
    if (yc>0.5) {
        yc=1.0-yc;
        yc=0.5-yc; 
        yc=yc*2.0; yc*=-1;
    } else {
        yc=0.5-yc; 
        yc=yc*2.0;
    }
    // 0 -- 0.5 -- 0
    // 1 -- 0 -- -1
    fishdx*=yc;

    mainImage2(color,coos);

    //color=vec4(debug,0,0,1);

    gl_FragColor = color;
    //gl_FragColor =vec4(debug,1.0);
}
