/* COPYRIGHT Esri - https://js.arcgis.com/5.1.2/LICENSE.txt */
import has from"../core/has.js";import{lerp as t}from"../core/mathUtils.js";import{create as e}from"../core/libs/gl-matrix-2/factories/mat3f64.js";import{set as a}from"../core/libs/gl-matrix-2/math/vec2.js";import{create as o}from"../core/libs/gl-matrix-2/factories/vec2f64.js";import{ScreenSpacePass as i}from"../views/3d/webgl-engine/core/shaderLibrary/ScreenSpacePass.glsl.js";import{BooleanPassUniform as s}from"../views/3d/webgl-engine/core/shaderModules/BooleanPassUniform.js";import{Float2PassUniform as r}from"../views/3d/webgl-engine/core/shaderModules/Float2PassUniform.js";import{FloatPassUniform as l}from"../views/3d/webgl-engine/core/shaderModules/FloatPassUniform.js";import{glsl as n}from"../views/3d/webgl-engine/core/shaderModules/glsl.js";import{Matrix3PassUniform as c}from"../views/3d/webgl-engine/core/shaderModules/Matrix3PassUniform.js";import{Texture2DPassUniform as d}from"../views/3d/webgl-engine/core/shaderModules/Texture2DPassUniform.js";import{atlasSize as u,tileRows as f,tileSize as m,textureScale as h,weatherMapScale as p}from"../views/3d/webgl-engine/effects/clouds/NoiseTextureAtlasDimensions.js";import{SphereIntersect as g}from"../views/3d/webgl-engine/shaders/SphereIntersect.glsl.js";import{NoParameters as y}from"../views/webgl/NoParameters.js";import{ShaderBuilder as v}from"../views/webgl/ShaderBuilder.js";class w extends y{constructor(){super(...arguments),this.cloudRadius=0,this.cloudSize=0,this.detailSize=0,this.absorption=0,this.density=0,this.smoothness=0,this.cloudHeight=0,this.coverage=0,this.lastSlice=!1,this.viewMatrix=e()}}const S=has("esri-mobile")?1024:2048;function x(e){const o=new v;o.include(i,!1);const y=o.fragment;return y.include(g),y.uniforms.add(new l("cloudRadius",t=>t.cloudRadius),new l("power",e=>t(35,120,e.absorption)),new l("sigmaE",t=>1+t.absorption),new l("density",e=>t(0,.3,e.density)),new l("cloudSize",e=>t(0,.02,Math.max(.01,1-e.cloudSize))),new l("detailSize",e=>t(0,.2,Math.max(.01,1-e.detailSize))),new l("smoothness",e=>t(0,.5,1-e.smoothness)),new l("cloudHeight",e=>t(0,1500,e.cloudHeight)),new l("coverage",t=>t.coverage),new c("view",t=>t.viewMatrix),new d("cloudShapeTexture",t=>t.noiseTexture?.textureAtlas),new r("cloudVariables",t=>a(D,t.coverage,t.absorption)),new s("lastSlice",t=>t.lastSlice)),y.constants.add("halfCubeMapSize","float",.5*S),y.code.add(n`
    const int STEPS = ${0===e.steps?n`16`:1===e.steps?n`100`:n`200`};
    const int STEPS_LIGHT = 6;
    const float stepL = 300.0 / float(STEPS_LIGHT);
    const float cloudStart = 1500.0;

    vec3 rayDirection(vec2 fragCoord) {
      vec2 xy = fragCoord;
      xy.x -= halfCubeMapSize;
      xy.y = lastSlice ? fragCoord.y - halfCubeMapSize : fragCoord.y;

      return normalize(vec3(-xy, -halfCubeMapSize));
    }

    float remap(float x, float low1, float high1, float low2, float high2) {
      return low2 + (x - low1) * (high2 - low2) / (high1 - low1);
    }

    float saturate(float x) {
      return clamp(x, 0.0, 1.0);
    }`),y.code.add(n`
    float getCloudShape(vec3 pos, float pOffset) {
      const float textureWidth = ${n.float(u)};
      const float dataWidth = ${n.float(u)};
      const float tileRows = ${n.float(f)};
      const vec3 atlasDimensions = vec3(${n.float(m)}, ${n.float(m)}, tileRows * tileRows);

      //Change from Y being height to Z being height
      vec3 p = float(${n.float(h)}) * pos.xzy;

      //Pixel coordinates of point in the 3D data
      vec3 coord = vec3(mod(p - pOffset * atlasDimensions, atlasDimensions));
      float f = fract(coord.z);
      float level = floor(coord.z);
      float tileY = floor(level / tileRows);
      float tileX = level - tileY * tileRows;

      //The data coordinates are offset by the x and y tile, the two boundary cells between each tile pair and the initial boundary cell on the first row/column
      vec2 offset = atlasDimensions.x * vec2(tileX, tileY) + 2.0 * vec2(tileX, tileY) + 1.0;
      vec2 pixel = coord.xy + offset;
      vec2 data = texture(cloudShapeTexture, mod(pixel, dataWidth) / textureWidth).xy;

      return 1.0 - mix(data.x, data.y, f);
    }

    float getCloudMap(vec2 p){
      // Shift the texture center to origin to avoid seam artifacts
      vec2 uv = (${n.float(p)} * p) / ${n.float(u)} + 0.5;

      return texture(cloudShapeTexture, uv).a;
    }
    `),y.code.add(n`float clouds(vec3 p) {
float cloud = saturate(0.5 * mix(0.0, 1.0, min(2.0 * coverage, 1.0)));
if (cloud <= 0.0) {
return 0.0;
}
float cloudMap = getCloudMap(cloudSize * p.xy);
cloud = mix(cloud, min(2.0 * (coverage), 1.0) * cloudMap, min(2.0 * (1.0 - coverage), 1.0));
if (cloud <= 0.0) {
return 0.0;
}
float shape = getCloudShape(8.0 * cloudSize * p, 0.0);
cloud = saturate(remap(cloud, smoothness * shape, 1.0, 0.0, 1.0));
if (cloud <= 0.0) {
return 0.0;
}
float heightFraction = saturate((length(p) - cloudRadius - cloudStart) / cloudHeight);
cloud *= saturate(remap(heightFraction, 0.0, 0.25, 0.0, 1.0)) * smoothstep(1.0, 0.25, heightFraction);
if (cloud <= 0.0) {
return 0.0;
}
return density * saturate(remap(cloud, 0.35 * smoothness * getCloudShape(detailSize * p, 0.0), 1.0, 0.0, 1.0));
}`),y.code.add(n`float HenyeyGreenstein(float g, float costh) {
return (1.0 / (4.0 * 3.1415))  * ((1.0 - g * g) / pow(1.0 + g * g - 2.0 * g * costh, 1.5));
}
float multipleOctaves(float extinction, float mu, float stepL) {
float attenuation = 1.0;
float contribution = 1.0;
float phaseAttenuation = 1.0;
float luminance = 0.0;
for (int i = 0; i < 4; i++) {
float phase = mix(HenyeyGreenstein(0.0, mu), HenyeyGreenstein(0.3 * phaseAttenuation, mu), 0.7);
luminance += contribution * phase * exp(-stepL * extinction * sigmaE * attenuation);
attenuation *= 0.2;
contribution *= 0.6;
phaseAttenuation *= 0.5;
}
return luminance;
}`),y.code.add(n`float lightRay(vec3 org, vec3 p, float phaseFunction, float mu, vec3 sunDirection) {
float lightRayDensity = clouds(p);
lightRayDensity += clouds(p + sunDirection * 1.0 * stepL);
lightRayDensity += clouds(p + sunDirection * 2.0 * stepL);
lightRayDensity += clouds(p + sunDirection * 3.0 * stepL);
lightRayDensity += clouds(p + sunDirection * 4.0 * stepL);
lightRayDensity += clouds(p + sunDirection * 5.0 * stepL);
float beersLaw = multipleOctaves(lightRayDensity, mu, stepL);
return mix(beersLaw * 2.0 * (1.0 - (exp(-stepL * lightRayDensity * 2.0 * sigmaE ))), beersLaw, 0.5 + 0.5 * mu);
}`),y.code.add(n`float mainRay(vec3 org, vec3 dir, vec3 sunDirection, float distToStart, float totalDistance, out float totalTransmittance) {
if (dir.z < 0.0) {
return 0.0;
}
totalTransmittance = 1.0;
float stepS = totalDistance / float(STEPS);
float cameraHeight = length(org);
float mu = 0.5 + 0.5 * dot(sunDirection, dir);
float phaseFunction = mix(HenyeyGreenstein(-0.3, mu), HenyeyGreenstein(0.3, mu), 0.7);
vec3 p = org + distToStart  * dir;
float dist = distToStart;
float shading = 0.0;
for (int i = 0; i < STEPS; i++) {
float sampleDensity = clouds(p);
float sampleSigmaE = sampleDensity * sigmaE;
if (sampleDensity > 0.0 ) {
float ambient = mix((1.2), (1.6), saturate((length(p) - cloudRadius - cloudStart) / cloudHeight));
float luminance = sampleDensity * (ambient + power * phaseFunction * lightRay(org, p, phaseFunction, mu, sunDirection));
float transmittance = exp(-sampleSigmaE * stepS);
shading += totalTransmittance * (luminance - luminance * transmittance) / sampleSigmaE;
totalTransmittance *= transmittance;
if (totalTransmittance <= 0.001) {
totalTransmittance = 0.0;
break;
}
}
dist += stepS;
p = org + dir * dist;
}
return shading;
}`),y.main.add(n`if (coverage ==  0.0) {
fragColor = vec4(0.0, 1.0, 0.0, 1.0);
return;
}
vec3 rayDir = rayDirection(gl_FragCoord.xy);
rayDir = normalize(view * rayDir);
vec3 viewPos = vec3(0, 0, cloudRadius + 1.0);
float hazeFactor = smoothstep(-0.01, mix(0.0, 0.075, cloudVariables.x), abs(dot(rayDir, vec3(0, 0, 1))));
float totalTransmittance = 1.0;
float shading = 0.0;
float cloudDistance = cloudRadius + cloudStart;
float rayStartDistance = dot(viewPos, viewPos) - (cloudDistance * cloudDistance);
vec2 rayStartIntersect = sphereIntersect(viewPos, rayDir, rayStartDistance);
float rayEndDistance = dot(viewPos, viewPos) - ((cloudDistance + cloudHeight) * (cloudDistance + cloudHeight));
vec2 rayEndIntersect = sphereIntersect(viewPos, rayDir, rayEndDistance);
float distToStart = rayStartIntersect.y;
float totalDistance = rayEndIntersect.y - distToStart;
vec3 sunDirection = normalize(vec3(0, 0, 1));
shading = 0.5 * mainRay(viewPos, rayDir, sunDirection, distToStart, totalDistance, totalTransmittance);
shading = mix(clamp(1.0 - cloudVariables.y, 0.6, 1.0), shading, hazeFactor);
totalTransmittance = mix(0.0, totalTransmittance, hazeFactor);
fragColor = vec4(shading, totalTransmittance, shading, totalTransmittance);`),o}const D=o(),b=Object.freeze(Object.defineProperty({__proto__:null,CloudsPassParameters:w,build:x,cubeMapSize:S},Symbol.toStringTag,{value:"Module"}));export{w as C,b as a,x as b,S as c};
