"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const three_module = require("../../../../../../three@0.154.0/node_modules/three/build/three.module.js");
const HorizontalBlurShader = require("../../../../../../three@0.154.0/node_modules/three/examples/jsm/shaders/HorizontalBlurShader.js");
const VerticalBlurShader = require("../../../../../../three@0.154.0/node_modules/three/examples/jsm/shaders/VerticalBlurShader.js");
const MathUtils = require("../../../../../../three@0.154.0/node_modules/three/src/math/MathUtils.js");
/* @license
 * Copyright 2022 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
const LOG_MAX_RESOLUTION = 9;
const LOG_MIN_RESOLUTION = 6;
const ANIMATION_SCALING = 2;
const DEFAULT_HARD_INTENSITY = 0.3;
class Shadow extends three_module.Object3D {
  constructor(scene, softness, side) {
    super();
    this.camera = new three_module.OrthographicCamera();
    this.renderTarget = null;
    this.renderTargetBlur = null;
    this.depthMaterial = new three_module.MeshDepthMaterial();
    this.horizontalBlurMaterial = new three_module.ShaderMaterial(HorizontalBlurShader.HorizontalBlurShader);
    this.verticalBlurMaterial = new three_module.ShaderMaterial(VerticalBlurShader.VerticalBlurShader);
    this.intensity = 0;
    this.softness = 1;
    this.boundingBox = new three_module.Box3();
    this.size = new three_module.Vector3();
    this.maxDimension = 0;
    this.isAnimated = false;
    this.needsUpdate = false;
    const { camera } = this;
    camera.rotation.x = Math.PI / 2;
    camera.left = -0.5;
    camera.right = 0.5;
    camera.bottom = -0.5;
    camera.top = 0.5;
    this.add(camera);
    const plane = new three_module.PlaneGeometry();
    const shadowMaterial = new three_module.MeshBasicMaterial({
      // color: new Color(1, 0, 0),
      opacity: 1,
      transparent: true,
      side: three_module.BackSide
    });
    this.floor = new three_module.Mesh(plane, shadowMaterial);
    this.floor.userData.shadow = true;
    camera.add(this.floor);
    this.blurPlane = new three_module.Mesh(plane);
    this.blurPlane.visible = false;
    camera.add(this.blurPlane);
    scene.target.add(this);
    this.depthMaterial.onBeforeCompile = function(shader) {
      shader.fragmentShader = shader.fragmentShader.replace("gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );", "gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * opacity );");
    };
    this.horizontalBlurMaterial.depthTest = false;
    this.verticalBlurMaterial.depthTest = false;
    this.setScene(scene, softness, side);
  }
  /**
   * Update the shadow's size and position for a new scene. Softness is also
   * needed, as this controls the shadow's resolution.
   */
  setScene(scene, softness, side) {
    const { boundingBox, size, rotation, position } = this;
    this.isAnimated = scene.animationNames.length > 0;
    this.boundingBox.copy(scene.boundingBox);
    this.size.copy(scene.size);
    this.maxDimension = Math.max(size.x, size.y, size.z) * (this.isAnimated ? ANIMATION_SCALING : 1);
    this.boundingBox.getCenter(position);
    if (side === "back") {
      const { min, max } = boundingBox;
      [min.y, min.z] = [min.z, min.y];
      [max.y, max.z] = [max.z, max.y];
      [size.y, size.z] = [size.z, size.y];
      rotation.x = Math.PI / 2;
      rotation.y = Math.PI;
    } else {
      rotation.x = 0;
      rotation.y = 0;
    }
    if (this.isAnimated) {
      const minY = boundingBox.min.y;
      const maxY = boundingBox.max.y;
      size.y = this.maxDimension;
      boundingBox.expandByVector(size.subScalar(this.maxDimension).multiplyScalar(-0.5));
      boundingBox.min.y = minY;
      boundingBox.max.y = maxY;
      size.set(this.maxDimension, maxY - minY, this.maxDimension);
    }
    if (side === "bottom") {
      position.y = boundingBox.min.y;
    } else {
      position.z = boundingBox.min.y;
    }
    this.setSoftness(softness);
  }
  /**
   * Update the shadow's resolution based on softness (between 0 and 1). Should
   * not be called frequently, as this results in reallocation.
   */
  setSoftness(softness) {
    this.softness = softness;
    const { size, camera } = this;
    const scaleY = this.isAnimated ? ANIMATION_SCALING : 1;
    const resolution = scaleY * Math.pow(2, LOG_MAX_RESOLUTION - softness * (LOG_MAX_RESOLUTION - LOG_MIN_RESOLUTION));
    this.setMapSize(resolution);
    const softFar = size.y / 2;
    const hardFar = size.y * scaleY;
    camera.near = 0;
    camera.far = MathUtils.lerp(hardFar, softFar, softness);
    this.depthMaterial.opacity = 1 / softness;
    camera.updateProjectionMatrix();
    this.setIntensity(this.intensity);
    this.setOffset(0);
  }
  /**
   * Lower-level version of the above function.
   */
  setMapSize(maxMapSize) {
    const { size } = this;
    if (this.isAnimated) {
      maxMapSize *= ANIMATION_SCALING;
    }
    const baseWidth = Math.floor(size.x > size.z ? maxMapSize : maxMapSize * size.x / size.z);
    const baseHeight = Math.floor(size.x > size.z ? maxMapSize * size.z / size.x : maxMapSize);
    const TAP_WIDTH = 10;
    const width = TAP_WIDTH + baseWidth;
    const height = TAP_WIDTH + baseHeight;
    if (this.renderTarget != null && (this.renderTarget.width !== width || this.renderTarget.height !== height)) {
      this.renderTarget.dispose();
      this.renderTarget = null;
      this.renderTargetBlur.dispose();
      this.renderTargetBlur = null;
    }
    if (this.renderTarget == null) {
      const params = { format: three_module.RGBAFormat };
      this.renderTarget = new three_module.WebGLRenderTarget(width, height, params);
      this.renderTargetBlur = new three_module.WebGLRenderTarget(width, height, params);
      this.floor.material.map = this.renderTarget.texture;
    }
    this.camera.scale.set(size.x * (1 + TAP_WIDTH / baseWidth), size.z * (1 + TAP_WIDTH / baseHeight), 1);
    this.needsUpdate = true;
  }
  /**
   * Set the shadow's intensity (0 to 1), which is just its opacity. Turns off
   * shadow rendering if zero.
   */
  setIntensity(intensity) {
    this.intensity = intensity;
    if (intensity > 0) {
      this.visible = true;
      this.floor.visible = true;
      this.floor.material.opacity = intensity * MathUtils.lerp(DEFAULT_HARD_INTENSITY, 1, this.softness * this.softness);
    } else {
      this.visible = false;
      this.floor.visible = false;
    }
  }
  getIntensity() {
    return this.intensity;
  }
  /**
   * An offset can be specified to move the
   * shadow vertically relative to the bottom of the scene. Positive is up, so
   * values are generally negative. A small offset keeps our shadow from
   * z-fighting with any baked-in shadow plane.
   */
  setOffset(offset) {
    this.floor.position.z = -offset + 1e-3 * this.maxDimension;
  }
  render(renderer, scene) {
    scene.overrideMaterial = this.depthMaterial;
    const initialClearAlpha = renderer.getClearAlpha();
    renderer.setClearAlpha(0);
    this.floor.visible = false;
    const xrEnabled = renderer.xr.enabled;
    renderer.xr.enabled = false;
    const oldRenderTarget = renderer.getRenderTarget();
    renderer.setRenderTarget(this.renderTarget);
    renderer.render(scene, this.camera);
    scene.overrideMaterial = null;
    this.floor.visible = true;
    this.blurShadow(renderer);
    renderer.xr.enabled = xrEnabled;
    renderer.setRenderTarget(oldRenderTarget);
    renderer.setClearAlpha(initialClearAlpha);
  }
  blurShadow(renderer) {
    const { camera, horizontalBlurMaterial, verticalBlurMaterial, renderTarget, renderTargetBlur, blurPlane } = this;
    blurPlane.visible = true;
    blurPlane.material = horizontalBlurMaterial;
    horizontalBlurMaterial.uniforms.h.value = 1 / this.renderTarget.width;
    horizontalBlurMaterial.uniforms.tDiffuse.value = this.renderTarget.texture;
    renderer.setRenderTarget(renderTargetBlur);
    renderer.render(blurPlane, camera);
    blurPlane.material = verticalBlurMaterial;
    verticalBlurMaterial.uniforms.v.value = 1 / this.renderTarget.height;
    verticalBlurMaterial.uniforms.tDiffuse.value = this.renderTargetBlur.texture;
    renderer.setRenderTarget(renderTarget);
    renderer.render(blurPlane, camera);
    blurPlane.visible = false;
  }
  dispose() {
    if (this.renderTarget != null) {
      this.renderTarget.dispose();
    }
    if (this.renderTargetBlur != null) {
      this.renderTargetBlur.dispose();
    }
    this.depthMaterial.dispose();
    this.horizontalBlurMaterial.dispose();
    this.verticalBlurMaterial.dispose();
    this.floor.material.dispose();
    this.floor.geometry.dispose();
    this.blurPlane.geometry.dispose();
    this.removeFromParent();
  }
}
exports.Shadow = Shadow;
//# sourceMappingURL=Shadow.js.map
