

// Original   "Train Ride 2" by dr2 - 2018
// License: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License

#define TREES  1   // optional trees

float PrBoxDf (vec3 p, vec3 b);
float PrBox2Df (vec2 p, vec2 b);
float PrRoundBoxDf (vec3 p, vec3 b, float r);
float PrRoundBox2Df (vec2 p, vec2 b, float r);
float PrCapsDf (vec3 p, float r, float h);
float PrCylDf (vec3 p, float r, float h);
float PrFlatCyl2Df (vec2 p, float rhi, float rlo);
float PrFlatCylAnDf (vec3 p, float rhi, float rlo, float w, float h);
float Maxv3 (vec3 p);
vec2 Rot2D (vec2 q, float a);
float SmoothBump (float lo, float hi, float w, float x);
vec2 PixToHex (vec2 p);
vec2 HexToPix (vec2 h);
float HexEdgeDst (vec2 p);
float Hashfv2 (vec2 p);
vec2 Hashv2v2 (vec2 p);
float Noisefv2 (vec2 p);
float Fbm2 (vec2 p);
float Fbm3 (vec3 p);
vec3 VaryNf (vec3 p, vec3 n, float f);
vec4 Loadv4 (vec2 vId);


//--------------------------------------------- ad White Path Route
vec3 HsvToRgb (vec3 c)
{
  vec3 p;
  p = abs (fract (c.xxx + vec3 (1., 2./3., 1./3.)) * 6. - 3.);
  return c.z * mix (vec3 (1.), clamp (p - 1., 0., 1.), c.y);
}

const float cHashM = 43758.54;

float Hashff (float p)
{
  return fract (sin (p) * cHashM);
}
//---------------------------------------------- ad   End

#define N_CAR 8

mat3 carMat[N_CAR], trMat;
vec3 carPos[N_CAR], trPos, qHit, trkAx, trkFx, trkAy, trkFy, sunDir;
float dstFar, tCur, trMid, trLen, tunSep, tunLen, tunRad,  idCyc,tCyc,engFac;
#if TREES
vec2 gId, trOff;
float grHt, szFac, hgSize, trkWid;
#endif
int idObj;
const int idRail = 1, idRbase = 2, idSlp = 3, idVia = 4, idTun = 5, idGrnd = 6,
 /* idCar = 11,   idFCar = 12, idBCar = 13, idWhl = 14, idCon = 15, idBLamp = 16, idFLamp = 17, */
   idTrnk = 18, idLvs = 19,  // 21=>18, 22=>19 change
   //--------------------------------id ad
    idEng = 11, idAxle = 12, idCar = 13, idWheel = 14, idCrod = 15, idFun = 16, idCpl = 17, idLamp = 18,
   idBand =21,idBase=22, idRoof =23,idCabin=24, idCoal =25,idSpoke =26,
   idFunl=27,idFunt=28,   idStripe =29 ;
//---------------------------------------

const float pi = 3.14159, sqrt3 = 1.7320508;
//---------------------------------------------------- id end



vec3 TrackPath (float t)
{
  return vec3 (dot (trkAx, sin (trkFx * t)), 0.3 + dot (trkAy, sin (trkFy * t)), t);
}

vec3 TrackDir (float t)
{
  return vec3 (dot (trkFx * trkAx, cos (trkFx * t)), dot (trkFy * trkAy, cos (trkFy * t)), 1.);
}

float GrCentHt (vec2 p)
{
  return mix (- (3. + 0.2 * sin (0.1 * 2. * pi * p.y)) *
     SmoothBump (tunLen + 20., tunSep - tunLen - 20., 20., mod (p.y, tunSep)),
     0., smoothstep (6., 12., clamp (abs (p.x), 6., 12.)));
}

#define DMINQ(id) if (d < dMin) { dMin = d;  idObj = id;  qHit = q; }
#define DMIN(id) if (d < dMin) { dMin = d;  idObj = id; /* qHit = q; */} //ad


float GrCentDf (vec3 p, float dMin)
{
  vec3 q;
  float d;
  p.xy -= TrackPath (p.z).xy;
  q = p;
  q.z = mod (q.z + 0.5 * tunSep, tunSep) - 0.5 * tunSep;
  q.y -= -1. - 4. * smoothstep (20., 40., abs (q.x));
  d = PrFlatCyl2Df (q.zy, tunLen - 4. + 0.03 * q.x * q.x, 4. + 0.02 * cos (0.2 * 2. * pi * q.x));
  d = max (d, - PrFlatCyl2Df (p.yx, 0.7 * tunRad, tunRad));
  DMINQ (idGrnd);
  q = p;
  d = q.y - GrCentHt (q.xz);
  DMINQ (idGrnd);
  return dMin;
}

float GrndHt (vec2 p)
{
  mat2 qRot;
  vec2 q;
  float wAmp, h, w;
  w = smoothstep (2., 30., abs (p.x));
  h = 0.;
  if (w > 0.) {
    q = 0.07 * p;
    qRot = 2.2 * mat2 (0.8, -0.6, 0.6, 0.8);
    wAmp = 25.;
    for (int j = 0; j < 4; j ++) {
      h += wAmp * Noisefv2 (q);
      wAmp *= -0.35;
      q *= qRot;
    }
  }
  if (w < 1.) h = mix (GrCentHt (p), h, w);
  return h;
}

float GrndRay (vec3 ro, vec3 rd)
{
  vec3 p;
  float dHit, h, s, sLo, sHi;
  s = 0.;
  sLo = 0.;
  dHit = dstFar;
  for (int j = 0; j < 150; j ++) {
    p = ro + s * rd;
    p.x -= TrackPath (p.z).x;
    h = p.y - GrndHt (p.xz);
    if (h < 0. || s > dstFar) break;
    sLo = s;
    s += max (0.01 * s, 0.4 * h);
  }
  if (h < 0.) {
    sHi = s;
    for (int j = 0; j < 5; j ++) {
      s = 0.5 * (sLo + sHi);
      p = ro + s * rd;
      p.x -= TrackPath (p.z).x;
      if (p.y > GrndHt (p.xz)) sLo = s;
      else sHi = s;
    }
    dHit = 0.5 * (sLo + sHi);
  }
  return dHit;
}

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

//------------------------------------------------------- CarDf()  END

//------------------------------------------------------ EngDf() CarDf() ad start
//------------------------------------------------          cf  Thoms 3X insert
float EngDf (vec3 p, float dMin)
{
  vec3 q;    p /=engFac ;  p *=1.2 ; // ad
  p *=vec3(1.,1.,-1.) ; //shrink by 3.
  float d, aw, a, sx, wRad, tw;       p.y +=0.10; //down
  wRad = 0.8;     float szFacX=0.07 ; float trkWidX= 0.07095; // ad
//xxx  tw = 214. * szFacX * trkWidX ;  // 0.22/0.07=WhitePath/Thomas 3X ratio
  tw = 1.30970423; // trkWid/engFac;     ///////////////////////////////////////////TRY Pending

  q = p;
  q -= vec3 (0., -0.2, 0.5);
  d = max (PrCapsDf (q, 1., 2.), - (q.z + 1.7));
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp +*/ idEng; }
  q = p;  q.z = abs (q.z - 0.85);  q -= vec3 (0., -0.2, 1.8);
  d = PrCylDf (q, 1.05, 0.05);
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp +*/ idBand; }
  q = p;  q -= vec3 (0., -1.3, -0.25);
  d = PrBoxDf (q, vec3 (1., 0.1, 3.2));
  q = p;  q -= vec3 (0., -1.4, 3.);
  d = min (d, PrBoxDf (q, vec3 (1.1, 0.2, 0.07)));
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp +*/ idBase; }
  q.x = abs (q.x);  q -= vec3 (0.6, 0., 0.1);
  d = PrCylDf (q, 0.2, 0.1);
  q = p;  q -= vec3 (0., -2.4, -1.75);
  d = min (d, max (PrCylDf (q, 4., 0.65), - (q.y - 3.75)));
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp + */idRoof; }
  q = p;  q -= vec3 (0., 0.01, -1.75);
  d = max (max (PrBoxDf (q, vec3 (1., 1.4, 0.6)),
     - PrBoxDf (q - vec3 (0., 0., -0.2), vec3 (0.95, 1.3, 0.65))),
     - PrBoxDf (q - vec3 (0., 0.7, 0.), vec3 (1.1, 0.4, 0.5)));
  q.x = abs (q.x);  q -= vec3 (0.4, 1., 0.4);
  d = max (d, - PrBoxDf (q, vec3 (0.35, 0.15, 0.3)));
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp +*/ idCabin;  qHit = q; }
  q = p;  q -= vec3 (0., -0.5, -3.15);
  d = PrBoxDf (q, vec3 (1., 0.7, 0.3));
  if (d < dMin) { dMin = d;  idObj =/* idObjGrp +*/ idCoal;  qHit = q; }
  q = p;  q -= vec3 (0., -1.4, -3.5);
  d = PrCylDf (q.xzy, 0.4, 0.03);
  if (d < dMin) { dMin = d;  idObj =/* idObjGrp +*/ idCpl; }

  //-----------------------------------------------------Delete idWheel => OK
  q = p;  q.xz = abs (q.xz);  //q -= vec3(1.30, -1.4, 1.1);　　　　//tw =1.42
  q -=vec3(1.3,-1.4,1.1);
  d = PrCylDf (q.zyx, wRad, 0.1);
  float trSpd =0.8 ;
 // aw = - trSpd * tCur / (szFac * wRad);   //Black Plane is cut by delete 215line?// aw eqution
  if (d < dMin) {
    d = min (max (min (d, PrCylDf (q.zyx - vec3 (0.,0., -0.07), wRad + 0.05, 0.03)),
       - PrCylDf (q.zyx, wRad - 0.1, 0.12)), PrCylDf (q.zyx, 0.15, 0.10));
    if (d < dMin) { dMin = d;  idObj = idWheel; }  }
  //--------------------------------------------------------------

    q = p;  q.x = abs (q.x);  q -= vec3 (tw - 0.17, -1.4, 1.1 * sign (q.z));
    q.yz = q.yz * cos (/*aw*/ tCur*5.) + q.zy * sin (/*aw*/tCur*5.) * vec2 (-1., 1.);                 //////aw
    a = floor ((atan (q.y, q.z) + pi) * 8. / (2. * pi) + 0.5) / 8.;
    q.yz = q.yz * cos (2. * pi * a) + q.zy * sin (2. * pi * a) * vec2 (-1., 1.);
    q.z += 0.5 * wRad;
    d = PrCylDf (q, 0.05, 0.5 * wRad);
    if (d < dMin) { dMin = d;  idObj =  idSpoke; }
 // }

  q = p;  sx = sign (q.x);  q.x = abs (q.x);
  q -= vec3 (/*tw*/1.42 + 0.08, -1.4, 0.);                                         // tw
  aw -= 0.5 * pi * sx;
  q.yz -= 0.3 * vec2 (cos (-aw*tCur*5.),  sin (-aw*tCur*5.));                                /// aw
  d = PrCylDf (q, 0.04, 1.2);
  q.z = abs (q.z);  q -= vec3 (-0.1, 0., 1.1);
  d = min (d, PrCylDf (q.zyx, 0.06, 0.15));
  if (d < dMin) { dMin = d;  idObj =/* idObjGrp + */idCrod; }

  q = p;  q.z = abs (q.z);  q -= vec3 (0., -1.4, 1.1);
  d = PrCylDf (q.zyx, 0.1, /*tw*/1.42 - 0.1);                                     //tw
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp +*/ idAxle; }
  q = p;  q -= vec3 (0., 1.1, 2.15);  d = PrCylDf (q.xzy, 0.3, 0.5);
  if (d < dMin) { dMin = d;  idObj =/* idObjGrp +*/ idFunl; }
  q = p;  q -= vec3 (0., 1.5, 2.15);
  d = max (PrCylDf (q.xzy, 0.4, 0.15), - PrCylDf (q.xzy, 0.3, 0.2));
  q = p;  q -= vec3 (0., 0.8, 0.55);
  d = min (d, PrCapsDf (q.xzy, 0.3, 0.2));
  if (d < dMin) { dMin = d;  idObj =/* idObjGrp +*/ idFunt; }
  q = p;  q.x = abs (q.x);  q -= vec3 (1., -0.2, 0.85);
  d = PrBoxDf (q, vec3 (0.05, 0.1, 1.8));
  q = p;  q.x = abs (q.x);  q -= vec3 (1., -0.2, -1.75);
  d = min (d, PrBoxDf (q, vec3 (0.05, 0.1, 0.6)));
  q = p;  q.x = abs (q.x);  q -= vec3 (1., -0.2, -3.15);
  d = min (d, PrBoxDf (q, vec3 (0.05, 0.1, 0.3)));
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp + */idStripe; }
  q = p;  q -= vec3 (0., -0.2, 3.5);
  d = PrCylDf (q, 0.2, 0.1);
  if (d < dMin) { dMin = d;  idObj = /*idObjGrp +*/ idLamp; }

     // dMin /=10.2 ;
  return dMin*engFac  /**0.22/0.07 */ ;
}

//------------------------------------------------- Thomas 3X END


float CarDf (vec3 p, float dMin)       //---------- White Pass CarDf() ad
{
  vec3 q;
  float wRad, d, tw;
  wRad = 0.35;
    p /= engFac;  p *=1.2; // ad
 // p /= szFac;
  tw = trkWid / engFac;
  q = p;
  d = min (min (PrBoxDf (q, vec3 (1.3, 1.4, 2.8)),
     max (PrCylDf (q - vec3 (0., -2.35, 0.), 4., 2.8), - (q.y - 1.4))),
     PrBoxDf (q - vec3 (0., -1.6, 0.), vec3 (0.8, 0.3, 2.)));
  DMINQ (idCar);
  q = p;  q.z = abs (q.z);  q -= vec3 (0., -1.4, 2.9);
  d = PrCylDf (q.xzy, 0.4, 0.03);
  DMIN (idCpl);
                                      //tw =trkWid/szFac =0.31/0.22=1.41;
  q = p;  q.xz = abs (q.xz);  q -= vec3 (/*tw*/1.41 - 0.1, -1.85, 1.1);   //---- tw
  d = min (min (PrCylDf (q.zyx, wRad, 0.1),
     PrCylDf (q.zyx - vec3 (0.,0., -0.07), wRad + 0.05, 0.03)),
     PrCylDf (q.zyx, 0.15, 0.10));
  q.x -= 0.1;
  d = max (d, - PrCylDf (q.zyx, 0.2, 0.05));
  DMIN (idWheel);

  q = p;  q.z = abs (q.z);  q -= vec3 (0., -1.85, 1.1);
  d = PrCylDf (q.zyx, 0.1, /*tw*/1.41 - 0.15);                          //--- tw
  DMIN (idAxle);

   //dMin /=2.2;
  return dMin;
}

//------------------------------------------------------ EngDf(),CarDf()  END

float TrackDf (vec3 p, float dMin)
{
  vec3 q;
  vec2 b;
  float d;
  p.xy -= TrackPath (p.z).xy;
  q = p;
  q.z = mod (q.z + 0.5 * tunSep, tunSep) - 0.5 * tunSep;
  d = min (PrFlatCylAnDf (q.yxz, 0.7 * tunRad, tunRad, 0.05, tunLen),
     PrBoxDf (q, vec3 (tunRad, 0.15, tunLen)));
  DMINQ (idTun);
  q = p;
  q.y += 3.6;
  q.z = mod (q.z + 2., 4.) - 2.;
  b = abs (q.xz) - vec2 (0.35, 1.8);
  d = max (max (abs (q.x) - 0.7, q.y - 3.82),
     - max (length (q.yz + vec2 (clamp (q.y, -2., 2.), 0.)) - 5.5, min (b.x, b.y)));
  DMINQ (idVia);
  q = p;
  q.y -= 0.17;
  d = PrBox2Df (q.xy, vec2 (0.6, 0.05));
  DMINQ (idRbase);
  q = p;
  q.y -= 0.15;
  q.z = mod (q.z + 1., 2.) - 1.;
  d = PrBoxDf (q, vec3 (0.6, 0.1, 0.15));
  DMINQ (idSlp);
  q = p;
  q.x = abs (q.x) - 0.4;
  q.y -= 0.33;
  d = PrRoundBox2Df (q.xy, vec2 (0.012, 0.027), 0.02);
  DMINQ (idRail);
  return dMin;
}

float ObjDf (vec3 p)
{
  float dMin;  vec3 q ;   float d;
  dMin = dstFar;
  dMin = GrCentDf (p, dMin);
  dMin = TrackDf (p, dMin);

  /*
  for (int k = 0; k < N_CAR; k ++) {
    dMin = CarDf (carMat[k] * (p - carPos[k]),
       ((k == 0) ? -1. : ((k < N_CAR - 1) ? 0. : 1.)), dMin);
  }  */

  //----------------------------------------------  EngDf() CarDf() insert
 //  dMin /= engFac;                  //  ?????
  for (int k = 0; k < N_CAR; k ++) {
    // if (k == nCar) break;
    q = carMat[k]*(p - carPos[k].xyz );
    //d = PrCylDf (q.xzy, 3.4 * engFac*0.01, 2.2 * engFac*0.01);
      d = PrCylDf (q.xzy, 3.4 * engFac*0.726905, 2.2 * engFac*0.7269505);

    if (d <  0.20 ) {
    //  q.xz = Rot2D (q.xz, carStat[k].w);
    //           first 1   forth4   eigth 8 =>EngDf()
      dMin = (k== 0 || k ==3 ||k == 7) ? EngDf (q, dMin) : CarDf (q, dMin);
    } else dMin = min (dMin, d*0.99);   // ???????
  }
 // dMin *= engFac;                   // ??????

  //-----------------------------------------------
  return  dMin;              //  0.9*dMin  ???
}

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

vec3 ObjNf (vec3 p)
{
  vec4 v;
  vec2 e = vec2 (0.001, -0.001);
  v = vec4 (ObjDf (p + e.xxx), ObjDf (p + e.xyy), ObjDf (p + e.yxy), ObjDf (p + e.yyx));
  return normalize (vec3 (v.x - v.y - v.z - v.w) + 2. * v.yzw);
}

float ObjSShadow (vec3 ro, vec3 rd)
{
  float sh, d, h;
  sh = 1.;
  d = 0.05;
  for (int j = 0; j < 20; j ++) {
    h = ObjDf (ro + d * rd);
    sh = min (sh, smoothstep (0., 0.05 * d, h));
    d += clamp (3. * h, 0.05, 0.2);
    if (sh < 0.05) break;
  }
  return 0.6 + 0.4 * sh;
}

#if TREES

float TreesDf (vec3 p)
{
  vec3 q, qq;
  float dMin, d, ht;
  dMin = dstFar;
  if (szFac > 0.) {
    p.xz -= HexToPix (gId * hgSize) + trOff;
    p.y -= grHt;
    dMin /= szFac;
    p /= szFac;
    ht = 2.;
    q = p;
    q.y -= ht - 0.1;
    d = PrCylDf (q.xzy, 0.15 - 0.03 * q.y / ht, ht);
    DMINQ (idTrnk);
    q = p;
    q.y -= ht + 2.5;
    d = PrCapsDf (q.xzy, 1. - 0.2 * q.y, 1.5);
    DMINQ (idLvs);
    dMin *= szFac;
  }
  return dMin;
}

void SetTrParms ()
{
  vec2 g, w;
  float t;
  szFac = 0.2 + 0.3 * Hashfv2 (17. * gId + 99.);
  w = Hashv2v2 (33. * gId);
  g = HexToPix (gId * hgSize);
  g.x -= TrackPath (g.y).x;
  trOff = hgSize * max (0., 0.5 * sqrt3 - szFac) * w.x * sin (2. * pi * w.y + vec2 (0.5 * pi, 0.));
  t = abs (mod (g.y + 0.5 * tunSep, tunSep) - 0.5 * tunSep);
  grHt = (t > tunLen) ? GrndHt (g + trOff) : 3.2;
  if (! (grHt < -0.5 && abs (g.x) >  2. * tunRad || t < 0.5 * tunLen && abs (g.x) < 10.)) szFac = 0.;
}

float TreesRay (vec3 ro, vec3 rd, float dstLim)
{
  vec3 vri, vf, hv, p;
  vec2 edN[3], pM, gIdP;
  float dHit, d, s;
  edN[0] = vec2 (1., 0.);
  edN[1] = 0.5 * vec2 (1., sqrt3);
  edN[2] = 0.5 * vec2 (1., - sqrt3);
  for (int k = 0; k < 3; k ++) edN[k] *= sign (dot (edN[k], rd.xz));
  vri = hgSize / vec3 (dot (rd.xz, edN[0]), dot (rd.xz, edN[1]), dot (rd.xz, edN[2]));
  vf = 0.5 * sqrt3 - vec3 (dot (ro.xz, edN[0]), dot (ro.xz, edN[1]),
     dot (ro.xz, edN[2])) / hgSize;
  pM = HexToPix (PixToHex (ro.xz / hgSize));
  gIdP = vec2 (-99.);
  dHit = 0.;
  for (int j = 0; j < 80; j ++) {
    hv = (vf + vec3 (dot (pM, edN[0]), dot (pM, edN[1]), dot (pM, edN[2]))) * vri;
    s = min (hv.x, min (hv.y, hv.z));
    p = ro + dHit * rd;
    gId = PixToHex (p.xz / hgSize);
    if (gId.x != gIdP.x || gId.y != gIdP.y) {
      gIdP = gId;
      SetTrParms ();
    }
    d = TreesDf (p);
    if (dHit + d < s) {
      dHit += d;
    } else {
      dHit = s + 0.002;
      pM += sqrt3 * ((s == hv.x) ? edN[0] : ((s == hv.y) ? edN[1] : edN[2]));
    }
    if (d < 0.0005 || dHit > dstLim || p.y < -5. || rd.y > 0. && p.y > 25.) break;
  }
  if (d >= 0.0005) dHit = dstFar;
  return dHit;
}

vec3 TreesNf (vec3 p)
{
  vec4 v;
  vec2 e = vec2 (0.0005, -0.0005);
  v = vec4 (TreesDf (p + e.xxx), TreesDf (p + e.xyy), TreesDf (p + e.yxy), TreesDf (p + e.yyx));
  return normalize (vec3 (v.x - v.y - v.z - v.w) + 2. * v.yzw);
}

float TreesSShadow (vec3 ro, vec3 rd)
{
  vec3 p;
  vec2 gIdP;
  float sh, d, h;
  sh = 1.;
  gIdP = vec2 (-99.);
  d = 0.01;
  for (int j = 0; j < 20; j ++) {
    p = ro + d * rd;
    gId = PixToHex (p.xz / hgSize);
    if (gId.x != gIdP.x || gId.y != gIdP.y) {
      gIdP = gId;
      SetTrParms ();
    }
    h = TreesDf (p);
    sh = min (sh, smoothstep (0., 0.05 * d, h));
    d += clamp (3. * h, 0.1, 0.2);
    if (sh < 0.05) break;
  }
  return 0.6 + 0.4 * sh;
}

#endif

vec3 SkyBg (vec3 rd)
{
  return mix (vec3 (0.3, 0.3, 0.9), vec3 (0.45, 0.45, 0.6), 1. - max (rd.y, 0.));
}

vec3 SkyCol (vec3 ro, vec3 rd)
{
  vec3 col;
  rd.y = abs (rd.y);
  ro.xz += 2. * tCur;
  col = SkyBg (rd) + 0.1 * vec3 (1., 1., 0.9) * pow (max (dot (rd, sunDir), 0.), 64.);
  col = mix (col, vec3 (0.8), clamp (0.2 + Fbm2 (0.05 *
     (ro.xz + rd.xz * (100. - ro.y) / max (rd.y, 0.001))) * rd.y, 0., 1.));
  return col;
}

vec4 ObjCol ()
{
  vec4 col4, carCol, carCol2, objCol;  // ad
  col4 = vec4 (0.);
  carCol = vec4 (0.1, 0.3, 1., 0.3);

    //--------------------------------------------- thomas X3  Eng color
  const vec4 cR = vec4 (1., 0., 0., 1.), cY = vec4 (1., 1., 0., 1.),
     cG = vec4 (0., 1., 0., 1.), cB = vec4 (0., 0., 1., 1.),
     cBlk = vec4 (0.03, 0.03, 0.03, 0.1), cLB = vec4 (0.4, 0.4, 1., 1.);
  //col4 = vec4 (0.);
  //--------------------------------------------- white Path Route Car color
   float idCyc = floor(tCur/ (3.0*pi)) ;      //  de  /( 8./pi)pending  toriaezu??
  float h = Hashff (5. * idCyc + 17.1);
    carCol = vec4 (HsvToRgb (vec3 (mod (h, 3.), 0.8, 0.9)), 0.2); // de mod(h,1.)
    carCol2 = vec4 (HsvToRgb (vec3 (mod (h + 0.5, 3.), 0.8, 0.9)), 0.3);
  //--------------------------------------------------------

  if (idObj == idTun) {
    if (abs (qHit.x) < tunRad && (qHit.y < 0.7 * tunRad ||
       length (vec2 (qHit.x, qHit.y - 0.7 * tunRad)) < tunRad))
       col4 = (abs (qHit.x) < 0.03 && abs (mod (4. * qHit.z / tunLen + 0.5, 1.) - 0.5) < 0.1) ?
       vec4 (0.8, 0.8, 0.4, -1.) : 0.2 * vec4 (0.5, 0.3, 0.1, 0.);
    else col4 = vec4 (0.5, 0.3, 0.1, 0.);
  } else if (idObj == idVia) {
    col4 = vec4 (0.6, 0.4, 0.2, 0.05) * (0.6 + 0.4 * SmoothBump (0.05, 0.95, 0.02,
       mod (4. * qHit.y, 1.)));
  } else if (idObj == idRbase) {
    col4 = vec4 (0.5, 0.3, 0.2, 0.05) * (1. - 0.5 * Noisefv2 (128. * qHit.xz));
  } else if (idObj == idSlp) {
    col4 = vec4 (0.65, 0.6, 0.6, 0.1);
  } else if (idObj == idRail) {
    col4 = vec4 (0.3, 0.3, 0.4, 0.4);
  }


  //------------------------------------------------  EngDf()  CarDf() color insert
  //------------------------------------------------------------------ Thomas X3 Eng
    else if (idObj == idEng ) col4 = cG;

      else if (idObj == idCabin) col4 = (qHit.y > -1.3) ? cLB : cB;
    else if (idObj == idCoal)
       col4 = (qHit.y > 0.3) ?  cBlk  : cB;
    else if (idObj == idBase || idObj == idBand || idObj == idAxle)
       col4 = vec4 (0.3, 0.2, 0.2, 0.3);
    else if (idObj == idRoof || idObj == idCpl || idObj == idFunl )
       col4 =  cG ;
    else if (idObj == idFunl ) col4 = cBlk;
    else if (idObj == idWheel || idObj == idSpoke) {col4 = vec4 (0.6, 0.7, 0.7, 0.5);}
    else if (idObj == idCrod) col4 = cY;
    else if (idObj == idStripe || idObj == idFunt) col4 =  cG ;
    else if (idObj == idLamp ) {col4 =(mod(tCur+0.667*float(1),2.)<1.)?vec4(1.,1.,1.,-1.):vec4(0.6,0.6,0.6,-1.);}
 //------------------------------------------------------------------ Thomas X3
 //------------------------------------------------------------White Path Route Car
    else if (idObj == idCar)
      col4 = (abs (qHit.y + 0.2) < 0.05 || qHit.y > 1.4) ? carCol2 : carCol;
      if (qHit.y < -1.15) col4 *= 0.5;
      if (abs (qHit.y - 0.6) < 0.6 && (abs (qHit.x) < 0.5 || abs (abs (qHit.z) - 1.2) < 1.1))
         col4 *= 0.7;
    else if (idObj == idFun)
      col4 = (qHit.y > 1.35) ? carCol : carCol2;



  //-----------------------------------------------------EngDf() CarDf() color end

  return col4;
}

//---------------------------------------------------- continue 09 23 19:00 End
//------------------------------------------------------- start from here
vec3 ShowScene (vec3 ro, vec3 rd)
{
  vec4 col4;
  vec3 col, colS, vn, vnn;
  float dstHit, dstObj, dstTrees, dstGrnd, dstMin, f, dFac, dkTun, sh,h ;
  int idObjS;
#if TREES
  vec2 vf;
  int idObjT;
#endif
  bool isWind, isGrnd, isCar;
  dstGrnd = GrndRay (ro, rd);
  dstObj = ObjRay (ro, rd);
  dstMin = min (min (dstGrnd, dstObj), dstFar);
#if TREES
  idObjT = idObj;
  dstTrees = TreesRay (ro, rd, dstMin);
  if (dstTrees > dstObj) idObj = idObjT;
  dstMin = min (dstMin, dstTrees);
#else
  dstTrees = dstFar;
#endif //------------------------------------

  isWind = false;
  isGrnd = false;
  if (dstMin < dstFar) {
    col4 = vec4 (0.);
    if (dstTrees < min (dstGrnd, dstObj)) {
#if TREES
      ro += dstTrees * rd;
      gId = PixToHex (ro.xz / hgSize);
      vn = TreesNf (ro);
      if (idObj == idTrnk) {
        col4 = vec4 (0.4, 0.2, 0.1, 0.);
        vf = vec2 (32., 2.);
      } else if (idObj == idLvs) {
        col4.rgb = mix (vec3 (0.2, 0.4, 0.2), vec3 (0.9, 0.9, 0.95), 0.2 +
           0.8 * smoothstep (-0.6, -0.4, vn.y));
        col4.a = 0.2;
        vf = vec2 (16., 2.);
      }
      if (vf.x > 0.) vn = VaryNf (vf.x * ro, vn, vf.y);
      col = col4.rgb * (0.3 + 0.7 * max (0., dot (sunDir, vn))) +
         col4.a * pow (max (dot (rd, reflect (sunDir, vn)), 0.), 16.);
#endif
    }

    else {
      dkTun = 1.;
      if (dstObj < dstGrnd) {  //////////////////////////////////658
        ro += dstObj * rd;
        vn = ObjNf (ro);
        vnn = vn;
        dkTun = max (SmoothBump (tunLen, tunSep - tunLen, 3., mod (ro.z, tunSep)),
           step (1.7 * tunRad + 0.5, ro.y));
        if (idObj == idGrnd) isGrnd = true;
        else {
          col4 = ObjCol ();
          col = col4.rgb;
          if (idObj == idTun || idObj == idVia) vn = VaryNf (8. * ro, vn, 1.);
          isCar = (idObj == idCar || idObj == idEng/* idFcar*/ || idObj == idFun/* idBcar*/);  //repair

          if (dkTun == 0.) {
            col += vec3 (1., 1., 0.8) * (0.1 + 0.4 * max (dot (normalize (vn.xy),
               normalize (vec2 (0., 1.7 * tunRad) - (ro.xy - TrackPath (ro.z).xy))), 0.)) *
               (1. - smoothstep (0.1, 0.3, abs (mod (4. * ro.z / tunLen + 0.5, 1.) - 0.5)));
            if (! isCar) col *= 0.3 + 0.7 * smoothstep (-1., 0., abs (ro.z - trMid) - 0.5 * trLen);
          }

          if (col4.a >= 0.) {
            col = col * mix (0.3, 0.1 + 0.1 * max (vn.y, 0.) + 0.8 * max (0., dot (sunDir, vn)), dkTun) +
               col4.a * dkTun * pow (max (dot (rd, reflect (sunDir, vn)), 0.), 32.);
        //    if (dkTun == 1. && isCar) {

              //--------------------------------     EngDf() carDf() color ad

        if (idObj == idEng || idObj == idCar || idObj == idFun) {
    h = Hashff (5. * idCyc + 17.1);
    vec4 carCol = vec4 (HsvToRgb (vec3 (mod (h, 1.), 0.8, 0.9)), 0.2);
    vec4 carCol2 = vec4 (HsvToRgb (vec3 (mod (h + 0.5, 1.), 0.8, 0.9)), 0.3);

    if (idObj == idEng) {
      col = (abs (qHit.y + 0.2) < 0.05 || qHit.y > 1.35) ? carCol2.rgb : carCol.rgb;
     // col =objCol.rgb ;
      if (qHit.y < -1.15) col *= 0.5;
      if (abs (abs (qHit.x) - 0.5) < 0.4 && abs (qHit.y - 1.1) < 0.2) col *= 0.7;
      else if (abs (abs (qHit.z - 1.) - 1.5) < 0.1 && qHit.y > -1.1) col *= 0.7;
      if (qHit.z > 3.1 && qHit.y < -1.) col = carCol.rgb;
      if (qHit.z < - 2.8 && qHit.y > 0.1) col =  vec3 (0.01) ;
    } else if (idObj == idCar) {
      col = (abs (qHit.y + 0.2) < 0.05 || qHit.y > 1.4) ? carCol2.rgb : carCol.rgb;
      if (qHit.y < -1.15) col *= 0.5;
      if (abs (qHit.y - 0.6) < 0.6 && (abs (qHit.x) < 0.5 || abs (abs (qHit.z) - 1.2) < 1.1))
         col *= 0.7;
    } else if (idObj == idFun) {
      col = (qHit.y > 1.35) ? carCol.rgb : carCol2.rgb;
    }
  }

              //---------------------------------------
              col = mix (col, SkyCol (ro, reflect (rd, vn)), /*(isWind ? 0.7 : */
                 0.2 * smoothstep (0.1, 0.3, vn.y))   ;
            }


  //-------------------------------------------------------------
       else if (idObj == idAxle) col = vec3 (0.4, 0.4, 0.5);
  else if (idObj == idWheel) col = vec3 (0.5, 0.5, 0.6);
  else if (idObj == idCrod) col = vec3 (0.7, 0.7, 0.1);
  else if (idObj == idLamp) col = (mod (tCur, 2.) < 1.) ? vec3 (1., 1., 0.7) :
     vec3 (0.8, 0.8, 0.4);

      //-----------------------------------------      EngDf() CarDf() color ad End


          }
        }
    //  }         // Train Ride 2  Delete    //////////////////////////////690



    else {
        ro += dstGrnd * rd;
        vn = GrndNf (ro, dstGrnd);
        isGrnd = true;
      }
     }
    //--------------------------------------------------- under ok
    dFac = (1. - smoothstep (0.3, 0.4, min (dstObj, dstGrnd) / dstFar)) *
       (1. - smoothstep (-0.2, -0.1, dot (rd, vn)));
    if (isGrnd) {
      vnn = vn;
      col = vec3 (0.);
      colS = vec3 (0.);
      if (vnn.y < 0.8) {
        f = length (ro.xz);
        col = mix (vec3 (0.37, 0.35, 0.25), vec3 (0.27, 0.25, 0.3),
           mix (0.5, smoothstep (0.2, 0.8, Fbm2 (4. * vec2 (8. * f, ro.y))), dFac));
        col *= mix (1., 0.8 + 0.2 * Noisefv2 (64. * vec2 (f, ro.y)), dFac);
        vn = VaryNf (vec3 (1., 0.05, 1.) * ro, vnn,
           6. * (1. - smoothstep (0.4, 0.85, vnn.y)) * dFac);
        vn = VaryNf (32. * ro, vn, 0.5 * (1. - smoothstep (0.8, 1., dstGrnd / 25.)));
      } else {
        vn = VaryNf (8. * ro, vnn, 2. * smoothstep (0.75, 0.85, vnn.y) * dFac);
      }
    }
    if (dstObj < dstGrnd && idObj == idTun && vnn.y > 0.65 && qHit.y > 1.) isGrnd = true;
    if (isGrnd) {
      if (vnn.y > 0.65) colS = mix (vec3 (0.8, 0.8, 0.85), vec3 (0.9, 0.9, 0.95),
           mix (0.5, smoothstep (0.2, 0.8, Fbm3 (8. * ro)), dFac));
      col = mix (col, colS, smoothstep (0.75, 0.8, vnn.y + 0.1 * Fbm2 (32. * ro.xz)));
      col *= 0.1 + 0.1 * max (vn.y, 0.) + 0.8 * max (dot (sunDir, vn), 0.);
    }
    if (dkTun > 0. && col4.a >= 0.) {
      idObjS = idObj;
      sh = ObjSShadow (ro, sunDir);
      if ((idObjS == idRbase || idObjS == idSlp || idObjS == idRail) && sh < 1.) sh *= 0.5;
#if TREES
      sh = min (sh, TreesSShadow (ro, sunDir));
#endif
      col *= min (sh, 1. - 0.5 * max (1.2 * Fbm2 (0.1 * ro.xz - tCur * vec2 (0.15, 0.)) - 0.2, 0.));
    }
    col = mix (SkyBg (rd), col, exp (32. * min (0., 0.7 - dstMin / dstFar)));
   }
  else {
    col = SkyCol (ro, rd);
  }
  return clamp (mix (col, vec3 (col.b), 0.2) * mix (1., smoothstep (0., 1., Maxv3 (col)), 0.2), 0., 1.);
}

void TrainCarPM (float t)
{
  vec3 vp, vd, ve, vf;
  trPos = TrackPath (t);
  vp = TrackDir (t);
  vd = - normalize (vec3 (vp.x, 0., vp.z));
  ve = normalize (vec3 (0., vp.yz));
  trPos.y += 1.3;
  trMat = mat3 (vec3 (1., 0., 0.), vec3 (0., ve.z, - ve.y), ve) *
      mat3 (vec3 (- vd.z, 0., vd.x), vec3 (0., 1., 0.), vd);
}

#define N_VU 5

void mainImage (out vec4 fragColor, in vec2 fragCoord)
{
  mat3 vuMat;
  vec4 mPtr, dateCur, stDat;
  vec3 ro, rd, vd, vDir, col;
  vec2 canvas, uv, ori, ca, sa, mSize, mMid[N_VU], ut[N_VU];
  float nVu, el, az, zmFac, vuMode, centMode, asp, smMode, cGap, tz, trVel, dx, gh;
  canvas = iResolution.xy;
  uv = 2. * fragCoord.xy / canvas - 1.;
  uv.x *= canvas.x / canvas.y;
  tCur = iTime*0.7;
  //------------------------------------ White Path Route ad
  tCyc =2.*pi/8.0 ;  /* trVel=8.0  */
  idCyc =floor(tCur/(tCyc*10.)) ;
  //------------------------------------

  dateCur = iDate;
  stDat = Loadv4 (vec2 (0., 0.));
  mPtr.xyz = stDat.xyz;
//  vuMode = 0.; // vu = stDat.w;   // vuMode = 0. ; vuMode =1.0 ~4. ;
  vuMode =mod( floor(tCur/20.),5.);

  tCur = mod (tCur, 2400.) + 30. * floor (dateCur.w / 7200.);
  nVu = float (N_VU);
  centMode = (vuMode >= 0.) ? vuMode : mod (floor (tCur / 30.), nVu);
  asp = canvas.x / canvas.y;
  mSize = vec2 (asp / nVu, 1. / (nVu + 1.));
  for (int k = 0; k < N_VU; k ++) {
    mMid[k] = - vec2 (mSize.x / mSize.y, 1.) + vec2 (2 * (k + 1), 1) * mSize;
    ut[k] = abs (uv - mMid[k]) - mSize;
  }
  smMode = -1.;
  for (int k = 0; k < N_VU; k ++) {
    if (max (ut[k].x, ut[k].y) < 0.) {
      uv = (uv - mMid[k]) / mSize.y;
      smMode = float (k);
      break;
    }
  }
  if (smMode >= 0.) {
    vuMode = smMode;
  } else {
    vuMode = centMode;
    uv.y -= mSize.y;
    uv /= 1. - mSize.y;
  }
  trkAx = vec3 (1.9, 2.9, 4.3);
  trkFx = 0.15 * vec3 (0.23, 0.17, 0.13);
  trkAy = 0.03 * vec3 (1.9, 2.9, 4.3);
  trkFy = 0.5 * vec3 (0.23, 0.17, 0.13);
  tunSep = 150.;
  tunLen = 15.;
  tunRad = 1.4;
#if TREES
  hgSize = 1.5;
#endif

  trVel = 8.;
  trMid = trVel * tCur;
  vDir = TrackDir (trMid);
  cGap = 1.9 * 2.2 * sqrt (1. - vDir.x * vDir.x)*0.5 ;   // de ( )*1.
  trLen = float (N_CAR) * cGap;
  for (int n = 0; n < N_CAR; n ++) {
    TrainCarPM (trMid - 0.5 * float (2 * n - N_CAR + 1) * cGap);
    carPos[n] = trPos - vec3 (0., 0.15, 0.);
    carMat[n] = trMat;
  }
  az = 0.;
  el = -0.01;
  if (smMode == -1. && mPtr.z > 0. && mPtr.y > -0.5 + (1. / (nVu + 1.))) {
    az += 2. * pi * mPtr.x;
    el += 0.25 * pi * mPtr.y;
  }
  zmFac = 3.0;                     // de 3.
  if (vuMode == 0.) {
    tz = floor (trMid / tunSep) * tunSep;
    ro = TrackPath (tz + 0.5 * tunSep);
    dx = 2. * step (2.5, mod (tz / tunSep, 6.)) - 1.;
    ro.x += 13. * dx;
    gh = GrndHt (ro.xz);
    ro.xy += vec2 (-3. * dx, min (5. + 0.2 * gh * gh, 20.));
    vd = TrackPath (trMid) - ro;
  } else if (vuMode == 1.) {
    tz = trMid - 0.5 * trLen - 8.;
    ro = TrackPath (tz);
    ro.y += 2.;
    vd = TrackDir (tz);
    vd.y = 0.;
  } else if (vuMode == 2.) {
    tz = trMid + 0.5 * trLen + 8.;
    ro = TrackPath (tz);
    ro.y += 2.;
    vd.xz = Rot2D (TrackDir (tz).xz, pi);
    vd.y = 0.;
  } else if (vuMode == 3.) {
    tz = trMid + 0.5 * trLen + 6.;
    ro = TrackPath (tz);
    ro.y += 1.5;
    vd.xz = TrackDir (tz).xz;
    vd.y = 0.;
  } else if (vuMode == 4.) {
    tz = trMid - 25.;
    ro = TrackPath (tz);
    ro.y += 7.;
    vd = TrackPath (trMid + 0.6 * trLen) - ro;
  }
  vd = normalize (vd);
  ori = vec2 (el + asin (vd.y), az + 0.5 * pi - atan (vd.z, vd.x));
  ca = cos (ori);
  sa = sin (ori);
  vuMat = mat3 (ca.y, 0., - sa.y, 0., 1., 0., sa.y, 0., ca.y) *
          mat3 (1., 0., 0., 0., ca.x, - sa.x, 0., sa.x, ca.x);
  rd = vuMat * normalize (vec3 (uv, zmFac));
  sunDir = normalize (vec3 (0., 3., 1.));
  sunDir.xz = Rot2D (sunDir.xz, 0.01 * 2. * pi * tCur);
  dstFar = 250.;                           engFac =0.3840;  // de 10.
  col = pow (ShowScene (ro, rd), vec3 (0.8));
  for (int k = 0; k < N_VU; k ++) {
    if (max (ut[k].x, ut[k].y) < 0. && min (abs (ut[k].x), abs (ut[k].y)) * canvas.y < 2.)
       col = (float (k) == centMode) ? vec3 (0.8, 0.3, 0.3) : vec3 (0.5, 0.8, 0.5);
  }
  fragColor = vec4 (col, 1.);
}

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

float PrBox2Df (vec2 p, vec2 b)
{
  vec2 d;
  d = abs (p) - b;
  return min (max (d.x, d.y), 0.) + length (max (d, 0.));
}

float PrRoundBoxDf (vec3 p, vec3 b, float r)
{
  return length (max (abs (p) - b, 0.)) - r;
}

float PrRoundBox2Df (vec2 p, vec2 b, float r)
{
  return length (max (abs (p) - b, 0.)) - r;
}

float PrCylDf (vec3 p, float r, float h)
{
  return max (length (p.xy) - r, abs (p.z) - h);
}

float PrFlatCyl2Df (vec2 p, float rhi, float rlo)
{
  return length (p - vec2 (rhi * clamp (p.x / rhi, -1., 1.), 0.)) - rlo;
}

float PrFlatCylAnDf (vec3 p, float rhi, float rlo, float w, float h)
{
  return max (abs (length (p.xy - vec2 (rhi * clamp (p.x / rhi, -1., 1.), 0.)) - rlo) - w, abs (p.z) - h);
}

float PrCapsDf (vec3 p, float r, float h)
{
  return length (p - vec3 (0., 0., clamp (p.z, - h, h))) - r;
}

float Maxv3 (vec3 p)
{
  return max (p.x, max (p.y, p.z));
}

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

vec2 Rot2D (vec2 q, float a)
{
  vec2 cs;
  cs = sin (a + vec2 (0.5 * pi, 0.));
  return vec2 (dot (q, vec2 (cs.x, - cs.y)), dot (q.yx, cs));
}

#if TREES

vec2 PixToHex (vec2 p)
{
  vec3 c, r, dr;
  c.xz = vec2 ((1./sqrt3) * p.x - (1./3.) * p.y, (2./3.) * p.y);
  c.y = - c.x - c.z;
  r = floor (c + 0.5);
  dr = abs (r - c);
  r -= step (dr.yzx, dr) * step (dr.zxy, dr) * dot (r, vec3 (1.));
  return r.xz;
}

vec2 HexToPix (vec2 h)
{
  return vec2 (sqrt3 * (h.x + 0.5 * h.y), (3./2.) * h.y);
}

float HexEdgeDst (vec2 p)
{
  p = abs (p);
  return 0.5 * sqrt3 - p.x + 0.5 * min (p.x - sqrt3 * p.y, 0.);
}

#endif

// const float cHashM = 43758.54;

float Hashfv2 (vec2 p)
{
  return fract (sin (dot (p, vec2 (37., 39.))) * cHashM);
}

vec2 Hashv2v2 (vec2 p)
{
  vec2 cHashVA2 = vec2 (37., 39.);
  return fract (sin (vec2 (dot (p, cHashVA2), dot (p + vec2 (1., 0.), cHashVA2))) * cHashM);
}

vec4 Hashv4v3 (vec3 p)
{
  vec3 cHashVA3 = vec3 (37., 39., 41.);
  vec2 e = vec2 (1., 0.);
  return fract (sin (vec4 (dot (p + e.yyy, cHashVA3), dot (p + e.xyy, cHashVA3),
     dot (p + e.yxy, cHashVA3), dot (p + e.xxy, cHashVA3))) * cHashM);
}

float Noisefv2 (vec2 p)
{
  vec2 t, ip, fp;
  ip = floor (p);
  fp = fract (p);
  fp = fp * fp * (3. - 2. * fp);
  t = mix (Hashv2v2 (ip), Hashv2v2 (ip + vec2 (0., 1.)), fp.y);
  return mix (t.x, t.y, fp.x);
}

float Fbm2 (vec2 p)
{
  float f, a;
  f = 0.;
  a = 1.;
  for (int j = 0; j < 5; j ++) {
    f += a * Noisefv2 (p);
    a *= 0.5;
    p *= 2.;
  }
  return f * (1. / 1.9375);
}

float Noisefv3 (vec3 p)
{
  vec4 t;
  vec3 ip, fp;
  ip = floor (p);
  fp = fract (p);
  fp *= fp * (3. - 2. * fp);
  t = mix (Hashv4v3 (ip), Hashv4v3 (ip + vec3 (0., 0., 1.)), fp.z);
  return mix (mix (t.x, t.y, fp.x), mix (t.z, t.w, fp.x), fp.y);
}

float Fbm3 (vec3 p)
{
  float f, a;
  f = 0.;
  a = 1.;
  for (int i = 0; i < 5; i ++) {
    f += a * Noisefv3 (p);
    a *= 0.5;
    p *= 2.;
  }
  return f * (1. / 1.9375);
}

float Fbmn (vec3 p, vec3 n)
{
  vec3 s;
  float a;
  s = vec3 (0.);
  a = 1.;
  for (int j = 0; j < 5; j ++) {
    s += a * vec3 (Noisefv2 (p.yz), Noisefv2 (p.zx), Noisefv2 (p.xy));
    a *= 0.5;
    p *= 2.;
  }
  return dot (s, abs (n));
}

vec3 VaryNf (vec3 p, vec3 n, float f)
{
  vec3 g;
  vec2 e = vec2 (0.1, 0.);
  if (f > 0.001) {
    g = vec3 (Fbmn (p + e.xyy, n), Fbmn (p + e.yxy, n), Fbmn (p + e.yyx, n)) - Fbmn (p, n);
    n += f * (g - n * dot (n, g));
    n = normalize (n);
  }
  return n;
}

#define txBuf iChannel0
#define txSize iChannelResolution[0].xy

vec4 Loadv4 (vec2 vId)
{
  return texture (txBuf, (vId + 0.5) / txSize);
}
