// This file has been automatically generated from resource file src/Shaders/SkydomBackground.fs

static const char Shaders_SkydomBackground_fs[] =
  "// Constants\n"
  "const float M_PI = 3.1415926535;\n"
  "const float THE_EARTH_RADIUS = 6360e3;\n"
  "const vec3  THE_EARTH_CENTER = vec3 (0.0, -THE_EARTH_RADIUS, 0.0);\n"
  "const float THE_ATMO_RADIUS  = 6380e3;  // atmosphere radius (6420e3?)\n"
  "const float THE_G            = 0.76;    // anisotropy of the medium (papers use 0.76)\n"
  "const float THE_G2           = THE_G * THE_G;\n"
  "const float THE_HR           = 8000.0;  // Thickness of the atmosphere\n"
  "const float THE_HM           = 1000.0;  // Same as above but for Mie\n"
  "const vec3  THE_BETA_R       = vec3 (5.8e-6, 13.5e-6, 33.1e-6); // Reyleigh scattering normal earth\n"
  "const vec3  THE_BETA_M       = vec3 (21e-6); // Normal Mie scattering\n"
  "\n"
  "// Parameters\n"
  "const float THE_SunAttenuation = 1.0;   // sun intensity\n"
  "const float THE_EyeHeight      = 100.0; // viewer height\n"
  "const float THE_HorizonWidth   = 0.002;\n"
  "const int   THE_NbSamples      = 8;\n"
  "const int   THE_NbSamplesLight = 8;     // integral sampling rate (might highly hit performance)\n"
  "const float THE_SunPower       = 5.0;\n"
  "const float THE_StarTreshold   = 0.98;\n"
  "\n"
  "// Uniforms\n"
  "uniform vec3  uSunDir;\n"
  "uniform float uTime;\n"
  "uniform float uCloudy;\n"
  "uniform float uFog;\n"
  "\n"
  "float hash13 (in vec3 p3)\n"
  "{\n"
  "  p3  = fract (p3 * 0.1031);\n"
  "  p3 += dot (p3, p3.zyx + 31.32);\n"
  "  return fract ((p3.x + p3.y) * p3.z);\n"
  "}\n"
  "\n"
  "float hash12 (in vec2 p)\n"
  "{\n"
  "  vec3 p3  = fract (vec3(p.xyx) * .1031);\n"
  "  p3 += dot (p3, p3.yzx + 33.33);\n"
  "  return fract ((p3.x + p3.y) * p3.z);\n"
  "}\n"
  "\n"
  "float smoothStarField (in vec2 theSamplePos)\n"
  "{\n"
  "  vec2 aFract = fract (theSamplePos);\n"
  "  vec2 aFloorSample = floor (theSamplePos);\n"
  "  float v1 = hash12 (aFloorSample);\n"
  "  float v2 = hash12 (aFloorSample + vec2( 0.0, 1.0 ));\n"
  "  float v3 = hash12 (aFloorSample + vec2( 1.0, 0.0 ));\n"
  "  float v4 = hash12 (aFloorSample + vec2( 1.0, 1.0 ));\n"
  "\n"
  "  vec2 u = aFract * aFract * (3.0 - 2.0 * aFract);\n"
  "\n"
  "  return mix(v1, v2, u.x) +\n"
  "            (v3 - v1) * u.y * (1.0 - u.x) +\n"
  "            (v4 - v2) * u.x * u.y;\n"
  "}\n"
  "\n"
  "float noisyStarField (in vec2 theSamplePos)\n"
  "{\n"
  "  float aStarVal = smoothStarField (theSamplePos);\n"
  "  if (aStarVal >= THE_StarTreshold)\n"
  "  {\n"
  "    aStarVal = pow ((aStarVal - THE_StarTreshold) / (1.0 - THE_StarTreshold), 6.0);\n"
  "  }\n"
  "  else\n"
  "  {\n"
  "    aStarVal = 0.0;\n"
  "  }\n"
  "  return aStarVal;\n"
  "}\n"
  "\n"
  "float smoothNoise (in vec3 theCoord)\n"
  "{\n"
  "  vec3 anInt   = floor (theCoord);\n"
  "  vec3 anFract = fract (theCoord);\n"
  "  anFract = anFract * anFract * (3.0 - (2.0 * anFract));\n"
  "  return mix(mix(mix(hash13(anInt                      ),\n"
  "                     hash13(anInt + vec3(1.0, 0.0, 0.0)), anFract.x),\n"
  "                 mix(hash13(anInt + vec3(0.0, 1.0, 0.0)),\n"
  "                     hash13(anInt + vec3(1.0, 1.0, 0.0)), anFract.x), anFract.y),\n"
  "             mix(mix(hash13(anInt + vec3(0.0, 0.0, 1.0)),\n"
  "                     hash13(anInt + vec3(1.0, 0.0, 1.0)), anFract.x),\n"
  "                 mix(hash13(anInt + vec3(0.0, 1.0, 1.0)),\n"
  "                     hash13(anInt + vec3(1.0, 1.0, 1.0)), anFract.x), anFract.y), anFract.z);\n"
  "}\n"
  "\n"
  "float fnoise (in vec3 theCoord, in float theTime)\n"
  "{\n"
  "  theCoord *= .25;\n"
  "  float aNoise;\n"
  "\n"
  "  aNoise =  0.5000 * smoothNoise (theCoord);\n"
  "  theCoord = theCoord * 3.02; theCoord.y -= theTime * 0.2;\n"
  "  aNoise += 0.2500 * smoothNoise (theCoord);\n"
  "  theCoord = theCoord * 3.03; theCoord.y += theTime * 0.06;\n"
  "  aNoise += 0.1250 * smoothNoise (theCoord);\n"
  "  theCoord = theCoord * 3.01;\n"
  "  aNoise += 0.0625 * smoothNoise (theCoord);\n"
  "  theCoord = theCoord * 3.03;\n"
  "  aNoise += 0.03125 * smoothNoise (theCoord);\n"
  "  theCoord = theCoord * 3.02;\n"
  "  aNoise += 0.015625 * smoothNoise (theCoord);\n"
  "  return aNoise;\n"
  "}\n"
  "\n"
  "float clouds (in vec3 theTs, in float theTime)\n"
  "{\n"
  "  float aCloud = fnoise (theTs * 2e-4, theTime) + uCloudy * 0.1;\n"
  "  aCloud = smoothstep (0.44, 0.64, aCloud);\n"
  "  aCloud *= 70.0;\n"
  "  return aCloud + uFog;\n"
  "}\n"
  "\n"
  "void densities (in vec3 thePos, out float theRayleigh, out float theMie, in float theTime)\n"
  "{\n"
  "  float aHeight = length (thePos - THE_EARTH_CENTER) - THE_EARTH_RADIUS;\n"
  "  theRayleigh = exp (-aHeight / THE_HR);\n"
  "\n"
  "  float aCloud = 0.0;\n"
  "  if (aHeight > 5000.0 && aHeight < 8000.0)\n"
  "  {\n"
  "    aCloud  = clouds (thePos + vec3 (0.0, 0.,-theTime*3e3), theTime);\n"
  "    aCloud *= sin (M_PI*(aHeight - 5e3) / 5e3) * uCloudy;\n"
  "  }\n"
  "\n"
  "  float aCloud2 = 0.0;\n"
  "  if (aHeight > 12e3 && aHeight < 15.5e3)\n"
  "  {\n"
  "    aCloud2 = fnoise (thePos * 3e-4, theTime) * clouds (thePos * 32.0, theTime);\n"
  "    aCloud2 *= sin (M_PI * (aHeight - 12e3) / 12e3) * 0.05;\n"
  "    aCloud2 = clamp (aCloud2, 0.0, 1.0);\n"
  "  }\n"
  "\n"
  "  theMie = exp (-aHeight / THE_HM) + aCloud + uFog;\n"
  "  theMie += aCloud2;\n"
  "}\n"
  "\n"
  "// ray with sphere intersection problem is reduced to solving the equation\n"
  "// (P - C)^2 = r^2             <--- sphere equation\n"
  "// where P is P(t) = A + t*B   <--- point on ray\n"
  "// t^2*dot(B, B) + t*2*dot(B, A-C) + dot(A-C, A-C) - r^2 = 0\n"
  "//     [   A   ]     [     B     ]   [        C        ]\n"
  "// We just need to solve the above quadratic equation\n"
  "float raySphereIntersect (in vec3 theOrig, in vec3 theDir, in float theRadius)\n"
  "{\n"
  "  theOrig = theOrig - THE_EARTH_CENTER;\n"
  "  // A coefficient will be always 1 (theDir is normalized)\n"
  "  float B = dot (theOrig, theDir);\n"
  "  float C = dot (theOrig, theOrig) - theRadius * theRadius;\n"
  "  // optimized version of classic (-b +- sqrt(b^2 - 4ac)) / 2a\n"
  "  float aDet2 = B * B - C;\n"
  "  if (aDet2 < 0.0) { return -1.0; }\n"
  "  float aDet = sqrt (aDet2);\n"
  "  float aT1 = -B - aDet;\n"
  "  float aT2 = -B + aDet;\n"
  "  return aT1 >= 0.0 ? aT1 : aT2;\n"
  "}\n"
  "\n"
  "void scatter (in vec3 theEye, in vec3 theRay, in vec3 theSun,\n"
  "              out vec3 theCol, out float theScat, in float theTime)\n"
  "{\n"
  "  float aRayLen = raySphereIntersect (theEye, theRay, THE_ATMO_RADIUS);\n"
  "  float aMu     = dot (theRay, theSun);\n"
  "  float aMu2    = 1.0 + aMu*aMu;\n"
  "  // The Raleigh phase function looks like this:\n"
  "  float aPhaseR = 3.0/(16.0 * M_PI) * aMu2;\n"
  "  // And the Mie phase function equation is:\n"
  "  float aPhaseM = (3.0 / (8.0 * M_PI) * (1.0 - THE_G2) * aMu2)\n"
  "                / ((2.0 + THE_G2) * pow (1.0 + THE_G2 - 2.0 * THE_G * aMu, 1.5));\n"
  "\n"
  "  float anOpticalDepthR = 0.0;\n"
  "  float anOpticalDepthM = 0.0;\n"
  "  vec3 aSumR = vec3 (0.0);\n"
  "  vec3 aSumM = vec3 (0.0); // Mie and Rayleigh contribution\n"
  "\n"
  "  float dl = aRayLen / float (THE_NbSamples);\n"
  "  for (int i = 0; i < THE_NbSamples; ++i)\n"
  "  {\n"
  "    float l = float(i) * dl;\n"
  "    vec3 aSamplePos = theEye + theRay * l;\n"
  "\n"
  "    float dR, dM;\n"
  "    densities (aSamplePos, dR, dM, theTime);\n"
  "    dR *= dl;\n"
  "    dM *= dl;\n"
  "    anOpticalDepthR += dR;\n"
  "    anOpticalDepthM += dM;\n"
  "\n"
  "    float aSegmentLengthLight = raySphereIntersect (aSamplePos, theSun, THE_ATMO_RADIUS);\n"
  "    if (aSegmentLengthLight > 0.0)\n"
  "    {\n"
  "      float dls = aSegmentLengthLight / float (THE_NbSamplesLight);\n"
  "      float anOpticalDepthRs = 0.0;\n"
  "      float anOpticalDepthMs = 0.0;\n"
  "      for (int j = 0; j < THE_NbSamplesLight; ++j)\n"
  "      {\n"
  "        float ls = float (j) * dls;\n"
  "        vec3 aSamplePosS = aSamplePos + theSun * ls;\n"
  "        float dRs, dMs;\n"
  "        densities (aSamplePosS, dRs, dMs, theTime);\n"
  "        anOpticalDepthRs += dRs * dls;\n"
  "        anOpticalDepthMs += dMs * dls;\n"
  "      }\n"
  "\n"
  "      vec3 anAttenuation = exp (-(THE_BETA_R * (anOpticalDepthR + anOpticalDepthRs)\n"
  "                                + THE_BETA_M * (anOpticalDepthM + anOpticalDepthMs)));\n"
  "      aSumR += anAttenuation * dR;\n"
  "      aSumM += anAttenuation * dM;\n"
  "    }\n"
  "  }\n"
  "\n"
  "  theCol = THE_SunPower * (aSumR * THE_BETA_R * aPhaseR + aSumM * THE_BETA_M * aPhaseM);\n"
  "  theScat = 1.0 - clamp (anOpticalDepthM*1e-5, 0.0, 1.0);\n"
  "}\n"
  "\n"
  "// This is where all the magic happens. We first raymarch along the primary ray\n"
  "// (from the camera origin to the point where the ray exits the atmosphere).\n"
  "// For each sample along the primary ray,\n"
  "// we then \"cast\" a light ray and raymarch along that ray as well.\n"
  "// We basically shoot a ray in the direction of the sun.\n"
  "vec4 computeIncidentLight (in vec3 theRayDirection, in vec2 theUv, in float theTime)\n"
  "{\n"
  "  float aSunAttenuation = THE_SunAttenuation;\n"
  "  vec3 aSunDir = uSunDir;\n"
  "  // conversion to moon\n"
  "  float aStarAttenuation = 0.0;\n"
  "  if (aSunDir.y < 0.0)\n"
  "  {\n"
  "    aSunDir *= -1.0;\n"
  "    aSunAttenuation = aSunAttenuation * 0.1;\n"
  "    aStarAttenuation = sqrt (aSunDir.y);\n"
  "  }\n"
  "\n"
  "  vec3 anEyePosition = vec3(0.0, THE_EyeHeight, 0.0);\n"
  "\n"
  "  // draw a water surface horizontally symmetrically to the sky\n"
  "  if (theRayDirection.y <= -THE_HorizonWidth / 2.0)\n"
  "  {\n"
  "    theRayDirection.y = -THE_HorizonWidth - theRayDirection.y;\n"
  "  }\n"
  "\n"
  "  float aScattering = 0.0;\n"
  "  vec3  aColor = vec3 (0.0);\n"
  "\n"
  "  scatter (anEyePosition, theRayDirection, aSunDir, aColor, aScattering, theTime);\n"
  "  aColor *= aSunAttenuation;\n"
  "  float aStarIntensity = noisyStarField (theUv * 2048.0);\n"
  "  vec3 aStarColor = vec3 (aScattering * aStarIntensity * aStarAttenuation);\n"
  "  aColor += aStarColor;\n"
  "\n"
  "  return vec4 (1.18 * pow (aColor, vec3(0.7)), 1.0);\n"
  "}\n"
  "\n"
  "uniform int uSide;\n"
  "\n"
  "void main()\n"
  "{\n"
  "  vec2 anUv = vec2 (2.0 * TexCoord.x - 1.0,\n"
  "                    2.0 * TexCoord.y - 1.0);\n"
  "  vec3 aPlanes[6];\n"
  "  aPlanes[0] = vec3 (+1.0, 0.0, 0.0);\n"
  "  aPlanes[1] = vec3 (-1.0, 0.0, 0.0);\n"
  "  aPlanes[2] = vec3 ( 0.0,+1.0, 0.0);\n"
  "  aPlanes[3] = vec3 ( 0.0,-1.0, 0.0);\n"
  "  aPlanes[4] = vec3 ( 0.0, 0.0,+1.0);\n"
  "  aPlanes[5] = vec3 ( 0.0, 0.0,-1.0);\n"
  "  vec3 aRayDirection;\n"
  "  if (uSide == 0)\n"
  "  {\n"
  "    // Positive X side\n"
  "    aRayDirection = aPlanes[0] + vec3 (0.0, +anUv.y, -anUv.x);\n"
  "  }\n"
  "  else if (uSide == 1)\n"
  "  {\n"
  "    // Negative X side\n"
  "    aRayDirection = aPlanes[1] + vec3 (0.0, +anUv.y, +anUv.x);\n"
  "  }\n"
  "  else if (uSide == 2)\n"
  "  {\n"
  "    // Positive Y side\n"
  "    aRayDirection = aPlanes[2] + vec3 (+anUv.x, 0.0, +anUv.y);\n"
  "  }\n"
  "  else if (uSide == 3)\n"
  "  {\n"
  "    // Negative Y side\n"
  "    aRayDirection = aPlanes[3] + vec3 (+anUv.x, 0.0, -anUv.y);\n"
  "  }\n"
  "  else if (uSide == 4)\n"
  "  {\n"
  "    // Positive Z side\n"
  "    aRayDirection = aPlanes[4] + vec3 (+anUv.x, +anUv.y, 0.0);\n"
  "  }\n"
  "  else if (uSide == 5)\n"
  "  {\n"
  "    // Negative Z side\n"
  "    aRayDirection = aPlanes[5] + vec3 (-anUv.x, +anUv.y, 0.0);\n"
  "  }\n"
  "\n"
  "  occFragColor = computeIncidentLight (normalize (aRayDirection), anUv, uTime);\n"
  "}\n";
