// Compatibility #ifdefs needed for parameters
#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

// Parameter lines go here:
#pragma parameter RETRO_PIXEL_SIZE "Retro Pixel Size" 0.84 0.0 1.0 0.01
#ifdef PARAMETER_UNIFORM
// All parameter floats need to have COMPAT_PRECISION in front of them
uniform COMPAT_PRECISION float RETRO_PIXEL_SIZE;
#else
#define RETRO_PIXEL_SIZE 0.84
#endif

#if defined(VERTEX)

#if __VERSION__ >= 130
#define COMPAT_VARYING out
#define COMPAT_ATTRIBUTE in
#define COMPAT_TEXTURE texture
#else
#define COMPAT_VARYING varying 
#define COMPAT_ATTRIBUTE attribute 
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

COMPAT_ATTRIBUTE vec4 VertexCoord;
COMPAT_ATTRIBUTE vec4 COLOR;
COMPAT_ATTRIBUTE vec4 TexCoord;
COMPAT_VARYING vec4 COL0;
COMPAT_VARYING vec4 TEX0;
// out variables go here as COMPAT_VARYING whatever

vec4 _oPosition1; 
uniform mat4 MVPMatrix;
uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;

// compatibility #defines
#define vTexCoord TEX0.xy
#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

void main()
{
    gl_Position = MVPMatrix * VertexCoord;
    TEX0.xy = VertexCoord.xy;
// Paste vertex contents here:
}

#elif defined(FRAGMENT)

#if __VERSION__ >= 130
#define COMPAT_VARYING in
#define COMPAT_TEXTURE texture
out vec4 FragColor;
#else
#define COMPAT_VARYING varying
#define FragColor gl_FragColor
#define COMPAT_TEXTURE texture2D
#endif

#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#define COMPAT_PRECISION mediump
#else
#define COMPAT_PRECISION
#endif

uniform COMPAT_PRECISION int FrameDirection;
uniform COMPAT_PRECISION int FrameCount;
uniform COMPAT_PRECISION vec2 OutputSize;
uniform COMPAT_PRECISION vec2 TextureSize;
uniform COMPAT_PRECISION vec2 InputSize;
uniform sampler2D Texture;
COMPAT_VARYING vec4 TEX0;
// in variables go here as COMPAT_VARYING whatever

// compatibility #defines
#define Source Texture
#define vTexCoord TEX0.xy

#define SourceSize vec4(TextureSize, 1.0 / TextureSize) //either TextureSize or InputSize
#define OutSize vec4(OutputSize, 1.0 / OutputSize)

// delete all 'params.' or 'registers.' or whatever in the fragment
float iGlobalTime = float(FrameCount)*0.025;
vec2 iResolution = OutputSize.xy;

// River Flight -  dr2 - 2014-11-06
// https://www.shadertoy.com/view/4sSXDG

// Fasten your seatbelts for a wild ride.

// "River Flight" by dr2 - 2014
// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License

const vec4 cHashA4 = vec4 (0., 1., 57., 58.);
const vec3 cHashA3 = vec3 (1., 57., 113.);
const float cHashM = 43758.54;

vec4 Hashv4f (float p)
{
  return fract (sin (p + cHashA4) * cHashM);
}

float Noisefv2 (vec2 p)
{
  vec2 i = floor (p);
  vec2 f = fract (p);
  f = f * f * (3. - 2. * f);
  vec4 t = Hashv4f (dot (i, cHashA3.xy));
  return mix (mix (t.x, t.y, f.x), mix (t.z, t.w, f.x), f.y);
}

float Noisefv3 (vec3 p)
{
  vec3 i = floor (p);
  vec3 f = fract (p);
  f = f * f * (3. - 2. * f);
  float q = dot (i, cHashA3);
  vec4 t1 = Hashv4f (q);
  vec4 t2 = Hashv4f (q + cHashA3.z);
  return mix (mix (mix (t1.x, t1.y, f.x), mix (t1.z, t1.w, f.x), f.y),
     mix (mix (t2.x, t2.y, f.x), mix (t2.z, t2.w, f.x), f.y), f.z);
}

vec3 Noisev3v2 (vec2 p)
{
  vec2 i = floor (p);
  vec2 f = fract (p);
  vec2 ff = f * f;
  vec2 u = ff * (3. - 2. * f);
  vec2 uu = 30. * ff * (ff - 2. * f + 1.);
  vec4 h = Hashv4f (dot (i, cHashA3.xy));
  return vec3 (h.x + (h.y - h.x) * u.x + (h.z - h.x) * u.y +
     (h.x - h.y - h.z + h.w) * u.x * u.y, uu * (vec2 (h.y - h.x, h.z - h.x) +
     (h.x - h.y - h.z + h.w) * u.yx));
}

float SmoothMin (float a, float b, float r)
{
  float h = clamp (0.5 + 0.5 * (b - a) / r, 0., 1.);
  return mix (b, a, h) - r * h * (1. - h);
}

float SmoothBump (float lo, float hi, float w, float x)
{
  return (1. - smoothstep (hi - w, hi + w, x)) * smoothstep (lo - w, lo + w, x);
}

float PrCapsDf (vec3 p, vec2 b)
{
  return length (p - vec3 (0., 0., b.x * clamp (p.z / b.x, -1., 1.))) - b.y;
}

float PrCylDf (vec3 p, vec2 b)
{
  return max (length (p.xy) - b.x, abs (p.z) - b.y);
}

float PrConeDf (vec3 p, vec3 b)
{
  return max (dot (vec2 (length (p.xy), p.z), b.xy), abs (p.z) - b.z);
}

int idObj;
mat3 flyerMat;
vec3 flyerPos, engPos, qHit, qHitTransObj, sunDir, sunCol;
vec2 trkOffset;
float szFac, wSpan, tCur;
const float dstFar = 400.;
const float pi = 3.14159;

vec3 TrackPath (float t)
{
  return vec3 (24. * sin (0.035 * t) * sin (0.012 * t) * cos (0.01 * t) +
     19. * sin (0.0032 * t) + 100. * trkOffset.x, 0., t);
}

float GrndHt (vec2 p, int hiRes)
{
  const vec2 vRot = vec2 (1.4624, 1.6721);
  vec2 q = p * 0.06;
  float w = 0.75 * Noisefv2 (0.25 * q) + 0.15;
  w *= 36. * w;
  vec2 vyz = vec2 (0.);
  float ht = 0.;
  for (int j = 0; j < 10; j ++) {
    vec3 v = Noisev3v2 (q);
    vyz += v.yz;
    ht += w * v.x / (1. + dot (vyz, vyz));
    if (j == 4) {
      if (hiRes == 0) break;
    }
    w *= -0.37;      
    q *= mat2 (vRot.x, vRot.y, - vRot.y, vRot.x);
  }
  vec3 pt = TrackPath (p.y);
  pt.y -= 2.;
  float g = smoothstep (1.5, 4.5, sqrt (abs (p.x - pt.x)));
  return min (ht, pt.y * (1. - g) + ht * g);
}

vec3 GrndNf (vec3 p, float d)
{
  float ht = GrndHt (p.xz, 1);
  vec2 e = vec2 (max (0.01, 0.00001 * d * d), 0.);
  return normalize (vec3 (ht - GrndHt (p.xz + e.xy, 1), e.x,
     ht - GrndHt (p.xz + e.yx, 1)));
}

vec4 GrndCol (vec3 p, vec3 n)
{
  const vec3 gCol1 = vec3 (0.6, 0.7, 0.7), gCol2 = vec3 (0.2, 0.1, 0.1),
     gCol3 = vec3 (0.4, 0.3, 0.3), gCol4 = vec3 (0.1, 0.2, 0.1),
     gCol5 = vec3 (0.7, 0.7, 0.8), gCol6 = vec3 (0.05, 0.3, 0.03),
     gCol7 = vec3 (0.1, 0.08, 0.);
  vec2 q = p.xz;
  float f, d;
  float cSpec = 0.;
  f = 0.5 * (clamp (Noisefv2 (0.1 * q), 0., 1.) +
      0.8 * Noisefv2 (0.2 * q + 2.1 * n.xy + 2.2 * n.yz));
  vec3 col = f * mix (f * gCol1 + gCol2, f * gCol3 + gCol4, 0.65 * f);
  if (n.y < 0.5) {
    f = 0.4 * (Noisefv2 (0.4 * q + vec2 (0., 0.57 * p.y)) +
       0.5 * Noisefv2 (6. * q));
    d = 4. * (0.5 - n.y);
    col = mix (col, vec3 (f), clamp (d * d, 0.1, 1.));
    cSpec += 0.1;
  }
  if (p.y > 22.) {
    if (n.y > 0.25) {
      f = clamp (0.07 * (p.y - 22. - Noisefv2 (0.2 * q) * 15.), 0., 1.);
      col = mix (col, gCol5, f);
      cSpec += f;
    }
  } else {
    if (n.y > 0.45) {
      vec3 c = (n.y - 0.3) * (gCol6 * vec3 (Noisefv2 (0.4 * q),
         Noisefv2 (0.34 * q), Noisefv2 (0.38 * q)) + vec3 (0.02, 0.1, 0.02));
      col = mix (col, c, smoothstep (0.45, 0.65, n.y) *
         (1. - smoothstep (15., 22., p.y - 1.5 + 1.5 * Noisefv2 (0.2 * q))));
    }
    if (p.y < 0.65 && n.y > 0.4) {
      d = n.y - 0.4;
      col = mix (col, d * d + gCol7, 2. * clamp ((0.65 - p.y -
         0.35 * (Noisefv2 (0.4 * q) + 0.5 * Noisefv2 (0.8 * q) +
         0.25 * Noisefv2 (1.6 * q))), 0., 0.3));
      cSpec += 0.1;
    }
  }
  return vec4 (col, cSpec);
}

float GrndRay (vec3 ro, vec3 rd)
{
  vec3 p;
  float h, s, sLo, sHi;
  s = 0.;
  sLo = 0.;
  float dHit = dstFar;
  for (int j = 0; j < 150; j ++) {
    p = ro + s * rd;
    h = p.y - GrndHt (p.xz, 0);
    if (h < 0.) break;
    sLo = s;
    s += max (0.15, 0.4 * h) + 0.008 * s;
    if (s > dstFar) break;
  }
  if (h < 0.) {
    sHi = s;
    for (int j = 0; j < 10; j ++) {
      s = 0.5 * (sLo + sHi);
      p = ro + s * rd;
      h = step (0., p.y - GrndHt (p.xz, 0));
      sLo += h * (s - sLo);
      sHi += (1. - h) * (s - sHi);
    }
    dHit = sHi;
  }
  return dHit;
}

float WaterHt (vec3 p)
{
  p *= 0.1;
  float ht = 0.;
  const float wb = 1.414;
  float w = 0.2 * wb;
  for (int j = 0; j < 7; j ++) {
    w *= 0.5;
    p = wb * vec3 (p.y + p.z, p.z - p.y, 2. * p.x);
    ht += w * abs (Noisefv3 (p) - 0.5);
  }
  return ht;
}

vec3 WaterNf (vec3 p, float d)
{
  float ht = WaterHt (p);
  vec2 e = vec2 (max (0.01, 0.001 * d * d), 0.);
  return normalize (vec3 (ht - WaterHt (p + e.xyy), e.x, ht - WaterHt (p + e.yyx)));
}

vec3 SkyBg (vec3 rd)
{
  const vec3 sbCol = vec3 (0.15, 0.2, 0.65);
  vec3 col;
  col = sbCol + 0.2 * sunCol * pow (1. - max (rd.y, 0.), 5.);
  return col;
}

vec3 SkyCol (vec3 ro, vec3 rd)
{
  const float skyHt = 200.;
  vec3 col;
  float cloudFac;
  if (rd.y > 0.) {
    ro.x += 0.5 * tCur;
    vec2 p = 0.01 * (rd.xz * (skyHt - ro.y) / rd.y + ro.xz);
    float w = 0.65;
    float f = 0.;
    for (int j = 0; j < 4; j ++) {
      f += w * Noisefv2 (p);
      w *= 0.5;
      p *= 2.3;
    }
    cloudFac = clamp (5. * (f - 0.5) * rd.y - 0.1, 0., 1.);
  } else cloudFac = 0.;
  float s = max (dot (rd, sunDir), 0.);
  col = SkyBg (rd) + sunCol * (0.35 * pow (s, 6.) +
     0.65 * min (pow (s, 256.), 0.3));
  col = mix (col, vec3 (0.85), cloudFac);
  return col;
}

float GrndSShadow (vec3 ro, vec3 rd)
{
  float sh = 1.;
  float d = 0.01;
  for (int i = 0; i < 80; i++) {
    vec3 p = ro + rd * d;
    float h = p.y - GrndHt (p.xz, 0);
    sh = min (sh, 20. * h / d);
    d += 0.5;
    if (h < 0.001) break;
  }
  return clamp (sh, 0., 1.);
}

struct WingParm
{
  float span, sRad, trans, thck, leCut, leRad;
};

float WingDf (vec3 p, WingParm wg)
{
  vec2 q = p.yz;
  float w = max (length (q - vec2 (wg.sRad, 0.)),
     length (q + vec2 (wg.sRad, 0.)));
  w = max (max (w - wg.thck, abs (p.x - wg.trans) - wg.span),
     p.z - wg.leCut);
  return min (w, max (length (q - vec2 (0., wg.leCut)) - wg.leRad,
     abs (p.x - wg.trans) - wg.span));
}

float PropelDf (vec3 p, float dHit)
{
  vec3 q;
  float d;
  dHit /= szFac;
  p /= szFac;
  q = p;
  q.x = abs (q.x);
  q -= engPos;
  d = PrCylDf (q - vec3 (0., 0., 3.65), vec2 (1.9, 0.05));
  if (d < dHit) {
    dHit = d;
    qHitTransObj = q;
  }
  return dHit * szFac;
}

float TransObjDf (vec3 p)
{
  float dHit = dstFar;
  dHit = PropelDf (flyerMat * (p - flyerPos), dHit);
  return dHit;
}

float TransObjRay (vec3 ro, vec3 rd)
{
  const float dTol = 0.001;
  float d;
  float dHit = 0.;
  for (int j = 0; j < 150; j ++) {
    d = TransObjDf (ro + dHit * rd);
    dHit += d;
    if (d < dTol || dHit > dstFar) break;
  }
  return dHit;
}

float FlyerDf (vec3 p, float dHit)
{
  vec3 q;
  WingParm wg;
  float d, wr, ws, cLen;
  const float wSweep = 0.2;
  const float fusLen = 11.;
  const float taPos = 12.5;
  dHit /= szFac;
  p /= szFac;
  q = p;
  wr = q.z / fusLen;
  d = PrCapsDf (q - fusLen * vec3 (0., 0.045 + 0.08 * wr, 0.),
     fusLen * vec2 (0.46, 0.11));
  if (d < dHit) {
    dHit = d;  idObj = 1;  qHit = q;
  }
  d = PrCapsDf (q - fusLen * vec3 (0., 0., -0.32),
     fusLen * vec2 (1., 0.15 - 0.051 * wr * wr));
  if (d < dHit + 0.1) {
    dHit = SmoothMin (dHit, d, 0.1);  idObj = 2;  qHit = q;
  }
  ws = wSweep * abs (p.x) / wSpan;
  q = p + vec3 (0., 0.054 * fusLen - 6. * ws, 12. * ws);
  wg = WingParm (wSpan, 13.7, 0., 14., 1.72, 0.195);
  d = WingDf (q, wg);
  if (d < dHit + 0.2) {
    dHit = SmoothMin (dHit, d, 0.2);  idObj = 3;  qHit = q;
   }
  q = p + vec3 (0., -0.1 - 6. * ws, taPos + 12. * ws);
  wg = WingParm (0.4 * wSpan, 6.8, 0., 7., 1.2, 0.095);
  d = WingDf (q, wg);
  if (d < dHit + 0.1) {
    dHit = SmoothMin (dHit, d, 0.1);  idObj = 4;  qHit = q;
  }
  ws = wSweep * abs (p.y) / wSpan;
  q = p.yxz + vec3 (-0.2, 0., taPos + 12. * ws);
  wg = WingParm (0.15 * wSpan, 6.8, 2.2, 7., 1.2, 0.095);
  d = WingDf (q, wg);
  if (d < dHit + 0.1) {
    dHit = SmoothMin (dHit, d, 0.1);  idObj = 5;  qHit = q;
  }
  q = p;
  q.x = abs (q.x);
  cLen = 3.5;
  wr = q.z / cLen;
  d = PrCylDf (q - engPos, cLen * vec2 (0.2  - 0.07 * wr * wr, 1.));
  float d2 = PrCylDf (q - engPos, cLen * vec2 (0.04, 1.02));
  d = max (d, - d2);
  if (d < dHit) {
    dHit = d;  idObj = 6;  qHit = q;
  }
  q = p;
  q.x = abs (q.x);
  d = PrConeDf (q - engPos - vec3 (0., 0., 4.2), vec3 (0.8, 0.6, 0.7));
  if (d < dHit) {
    dHit = d;  idObj = 7;  qHit = q;
  }
  q = p;
  cLen = 2.8;
  q.z += wSweep * wSpan - 0.025 * cLen;
  q.x = abs (q.x);
  wr = q.z / cLen;
  d = PrCapsDf (q - vec3 (wSpan + 0.1, 0.5 * wSweep * wSpan - 0.6, -0.5),
     cLen * vec2 (1., 0.15 - 0.055 * wr * wr));
  if (d < dHit) {
    dHit = d;  idObj = 8;  qHit = q;
  }
  return 0.8 * dHit * szFac;
}

float ObjDf (vec3 p)
{
  float dHit = dstFar;
  dHit = FlyerDf (flyerMat * (p - flyerPos), dHit);
  return dHit;
}

float ObjRay (vec3 ro, vec3 rd)
{
  const float dTol = 0.001;
  float d;
  float dHit = 0.;
  for (int j = 0; j < 150; j ++) {
    d = ObjDf (ro + dHit * rd);
    dHit += d;
    if (d < dTol || dHit > dstFar) break;
  }
  return dHit;
}

vec3 ObjNf (vec3 p)
{
  const vec3 e = vec3 (0.001, -0.001, 0.);
  float v0 = ObjDf (p + e.xxx);
  float v1 = ObjDf (p + e.xyy);
  float v2 = ObjDf (p + e.yxy);
  float v3 = ObjDf (p + e.yyx);
  return normalize (vec3 (v0 - v1 - v2 - v3) + 2. * vec3 (v1, v2, v3));
}

float ObjSShadow (vec3 ro, vec3 rd)
{
  float sh = 1.;
  float d = 0.07 * szFac;
  for (int i = 0; i < 50; i++) {
    float h = ObjDf (ro + rd * d);
    sh = min (sh, 20. * h / d);
    d += 0.07 * szFac;
    if (h < 0.001) break;
  }
  return clamp (sh, 0., 1.);
}

vec3 ObjCol (vec3 p, vec3 n)
{
  vec3 bCol = vec3 (0.8, 0.8, 0.85), wCol = vec3 (0.3, 0.3, 0.7),
     tCol = vec3 (0.9, 0.7, 0.), uCol = vec3 (0.9, 0.1, 0.);
  float cFac = 1.;
  if (idObj >= 3 && idObj <= 5) {
    float s1, s2;
    if (idObj == 3) {
      s1 = 2.2;  s2 = 6.;
    } else if (idObj == 4) {
      s1 = 1.2;  s2 = 1.7;
    } else if (idObj == 5) {
      s1 = 1.;  s2 = 1.;
    }
    if (abs (qHit.x) > s2 - 0.03)
       cFac = 1. - 0.9 * SmoothBump (- 0.08, 0.08, 0.02, qHit.z + s1);
    if (qHit.z < - s1)
       cFac = 1. - 0.9 * SmoothBump (- 0.05, 0.05, 0.02, abs (qHit.x) - s2);
  }
  vec3 col;
  vec3 nn;
  if (idObj >= 1 && idObj <= 5) nn = flyerMat * n;
  if (idObj == 1 || idObj == 2) {
    col = mix (uCol, bCol, 1. - smoothstep (-0.6, 0., nn.y));
    if (idObj == 2 && nn.y < 0.)
       col = mix (bCol, wCol, SmoothBump (-0.8, 0.8, 0.3, qHit.z + 0.28));         
  } else if (idObj == 3 || idObj == 4) {
    col = mix (bCol, wCol, SmoothBump (-0.8, 0.8, 0.3, qHit.z));
  } else if (idObj == 5) {
    col = mix (bCol, tCol, SmoothBump (-0.6, 0.8, 0.3, qHit.z));
  } else if (idObj == 6) {
    col = bCol;
  } else if (idObj == 7 || idObj == 8) {
    col = tCol;
  }
  if (idObj == 1) {
    if (qHit.z > 4.5 && abs (qHit.x) > 0.07) idObj = 10;
  } else if (idObj == 2) {
    float s = - qHit.z;
    if (s > 0. && s < 9.) {
      vec2 ws = vec2 (qHit.y - 0.5, mod (s + 1.5, 1.5) - 0.75);
      ws *= ws;
      if (dot (ws, ws) < 0.02) idObj = 10;
    }
  }
  return col * cFac;
}

vec3 ShowScene (vec3 ro, vec3 rd)
{
  const float eps = 0.01;
  vec4 col4;
  vec3 objCol, col, vn;
  float dstHit, dstGrnd, dstObj, dstPropel, f;
  int idObjT;
  vec3 roo = ro;
  dstHit = dstFar;
  dstGrnd = GrndRay (ro, rd);
  wSpan = 12.;
  engPos = vec3 (0.35 * wSpan, -0.2, -1.5);
  idObj = 0;
  dstObj = ObjRay (ro, rd);
  idObjT = idObj;
  dstPropel = TransObjRay (ro, rd);
  if (dstObj < dstPropel) dstPropel = dstFar;
  float refFac = 1.;
  if (dstGrnd < dstObj && ro.y + dstGrnd * rd.y < 0.) {
    float dw = - ro.y / rd.y;
    ro += dw * rd;
    rd = reflect (rd, WaterNf (ro, dw));
    ro += eps * rd;
    dstGrnd = GrndRay (ro, rd);
    idObj = 0;
    dstObj = ObjRay (ro, rd);
    idObjT = idObj;
    refFac *= 0.6;
  }
  bool isGrnd = false;
  if (dstObj < dstGrnd) {
    ro += dstObj * rd;
    vn = ObjNf (ro);
    idObj = idObjT;
    objCol = ObjCol (ro, vn);
    if (idObj == 10) objCol = vec3 (0.2) + 0.5 * SkyCol (ro, reflect (rd, vn));
    float dif = max (dot (vn, sunDir), 0.);
    col = sunCol * objCol * (0.2 * (1. +
       max (dot (vn, - normalize (vec3 (sunDir.x, 0., sunDir.z))), 0.)) +
       max (0., dif) * ObjSShadow (ro, sunDir) *
       (dif + 0.5 * pow (max (0., dot (sunDir, reflect (rd, vn))), 100.)));
    dstHit = dstObj;
  } else {
    vec3 rp = ro + dstGrnd * rd;
    if (refFac < 1.) dstHit = length (rp - roo);
    else dstHit = dstGrnd;
    if (dstHit < dstFar) {
      ro = rp;
      isGrnd = true;
    } else {
      col = refFac * SkyCol (ro, rd);
    }
  }
  if (isGrnd) {
    vn = GrndNf (ro, dstHit);
    col4 = GrndCol (ro, vn);
    col = col4.xyz * refFac;
    float dif = max (dot (vn, sunDir), 0.);
    col *= sunCol * (0.2 * (1. +
       max (dot (vn, - normalize (vec3 (sunDir.x, 0., sunDir.z))), 0.)) +
       max (0., dif) * GrndSShadow (ro, sunDir) *
       (dif + col4.w * pow (max (0., dot (sunDir, reflect (rd, vn))), 100.)));
  }
  if (dstPropel < dstFar) col = 0.7 * col + 0.1 -
     0.04 * SmoothBump (1.5, 1.7, 0.02, length (qHitTransObj.xy));
  if (dstHit < dstFar) {
    f = dstHit / dstFar;
    col = mix (col, refFac * SkyBg (rd), clamp (1.03 * f * f, 0., 1.));
  }
  col = sqrt (clamp (col, 0., 1.));
  return clamp (col, 0., 1.);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
  vec2 uv = 2. * fragCoord.xy / iResolution.xy - 1.;
  vec2 uvs = uv;
  uv.x *= iResolution.x / iResolution.y;
  trkOffset = vec2 (0.);
  float zmFac = 2.7;
  tCur = 15. * iGlobalTime + 100. * trkOffset.y;
  sunDir = normalize (vec3 (0.9, 1., 0.4));
  sunCol = vec3 (1., 0.9, 0.8);
  vec3 ro, rd, vd, fpF, fpB, vDir;
  szFac = 0.25;
  float dt = 1.;
  fpF = TrackPath (tCur + dt);
  flyerPos = TrackPath (tCur);
  fpB = TrackPath (tCur - dt);
  vec3 vel = (fpF - fpB) / (2. * dt);
  vel.y = 0.;
  vec3 acc = (fpF - 2. * flyerPos + fpB) / (dt * dt);
  acc.y = 0.;
  vec3 va = cross (acc, vel) / length (vel);
  float roll = 12. * length (va);
  if (va.y < 0.) roll *= -1.;
  vDir = normalize (vel);
  float cRl = cos (roll);
  float sRl = sin (roll);
  flyerMat = mat3 (cRl, - sRl, 0., sRl, cRl, 0., 0., 0., 1.) *
     mat3 (vDir.z, 0., vDir.x, 0., 1., 0., - vDir.x, 0., vDir.z);
  float vuPeriod = 500.;
  flyerPos.y = 3. + 1.5 * sin (2.5 * tCur / vuPeriod);
  float lookDir = 2. * mod (floor (tCur / vuPeriod), 2.) - 1.;
  ro = TrackPath (tCur - 40. * lookDir * (1. -
     0.8 * abs (sin (pi * mod (tCur, vuPeriod) / vuPeriod))));
  ro.y = 3. + 0.6 * sin (0.16 * tCur / vuPeriod);
  vd = flyerPos - ro;
  vd.y = 0.;
  vd = normalize (lookDir * vDir + 0.3 * normalize (vd));
  mat3 scMat = mat3 (vd.z, 0., - vd.x, 0., 1., 0., vd);
  rd = scMat * normalize (vec3 (uv, zmFac));
  vec3 col = ShowScene (ro, rd);
  uvs *= uvs * uvs;
  col = mix (vec3 (0.7), col, pow (max (0., 0.95 - length (uvs * uvs * uvs)), 0.3));
  fragColor = vec4 (col, 1.);
}

 void main(void)
{
  //just some shit to wrap shadertoy's stuff
  vec2 FragCoord = vTexCoord.xy*OutputSize.xy;
  mainImage(FragColor,FragCoord);
}
#endif
