import { ShaderAssembler } from '@luma.gl/shadertools';
import { AmbientLight } from './ambient-light';
import { DirectionalLight } from './directional-light';
import { Matrix4, Vector3 } from '@math.gl/core';
import ShadowPass from '../../passes/shadow-pass';
import shadow from '../../shaderlib/shadow/shadow';
const DEFAULT_AMBIENT_LIGHT_PROPS = {
  color: [255, 255, 255],
  intensity: 1.0
};
const DEFAULT_DIRECTIONAL_LIGHT_PROPS = [{
  color: [255, 255, 255],
  intensity: 1.0,
  direction: [-1, 3, -1]
}, {
  color: [255, 255, 255],
  intensity: 0.9,
  direction: [1, -8, -2.5]
}];
const DEFAULT_SHADOW_COLOR = [0, 0, 0, 200 / 255];
export default class LightingEffect {
  constructor(props = {}) {
    this.id = 'lighting-effect';
    this.props = void 0;
    this.shadowColor = DEFAULT_SHADOW_COLOR;
    this.shadow = false;
    this.ambientLight = null;
    this.directionalLights = [];
    this.pointLights = [];
    this.shadowPasses = [];
    this.shadowMaps = [];
    this.dummyShadowMap = null;
    this.shaderAssembler = void 0;
    this.shadowMatrices = void 0;
    this.setProps(props);
  }

  setProps(props) {
    this.ambientLight = null;
    this.directionalLights = [];
    this.pointLights = [];

    for (const key in props) {
      const lightSource = props[key];

      switch (lightSource.type) {
        case 'ambient':
          this.ambientLight = lightSource;
          break;

        case 'directional':
          this.directionalLights.push(lightSource);
          break;

        case 'point':
          this.pointLights.push(lightSource);
          break;

        default:
      }
    }

    this._applyDefaultLights();

    this.shadow = this.directionalLights.some(light => light.shadow);
    this.props = props;
  }

  preRender(device, {
    layers,
    layerFilter,
    viewports,
    onViewportActive,
    views
  }) {
    if (!this.shadow) return;
    this.shadowMatrices = this._calculateMatrices();

    if (this.shadowPasses.length === 0) {
      this._createShadowPasses(device);
    }

    if (!this.shaderAssembler) {
      this.shaderAssembler = ShaderAssembler.getDefaultShaderAssembler();

      if (shadow) {
        this.shaderAssembler.addDefaultModule(shadow);
      }
    }

    if (!this.dummyShadowMap) {
      this.dummyShadowMap = device.createTexture({
        width: 1,
        height: 1
      });
    }

    for (let i = 0; i < this.shadowPasses.length; i++) {
      const shadowPass = this.shadowPasses[i];
      shadowPass.render({
        layers,
        layerFilter,
        viewports,
        onViewportActive,
        views,
        moduleParameters: {
          shadowLightId: i,
          dummyShadowMap: this.dummyShadowMap,
          shadowMatrices: this.shadowMatrices
        }
      });
    }
  }

  getModuleParameters(layer) {
    const parameters = this.shadow ? {
      shadowMaps: this.shadowMaps,
      dummyShadowMap: this.dummyShadowMap,
      shadowColor: this.shadowColor,
      shadowMatrices: this.shadowMatrices
    } : {};
    parameters.lightSources = {
      ambientLight: this.ambientLight,
      directionalLights: this.directionalLights.map(directionalLight => directionalLight.getProjectedLight({
        layer
      })),
      pointLights: this.pointLights.map(pointLight => pointLight.getProjectedLight({
        layer
      }))
    };
    return parameters;
  }

  cleanup() {
    for (const shadowPass of this.shadowPasses) {
      shadowPass.delete();
    }

    this.shadowPasses.length = 0;
    this.shadowMaps.length = 0;

    if (this.dummyShadowMap) {
      this.dummyShadowMap.destroy();
      this.dummyShadowMap = null;
    }

    if (this.shadow && this.shaderAssembler) {
      this.shaderAssembler.removeDefaultModule(shadow);
      this.shaderAssembler = null;
    }
  }

  _calculateMatrices() {
    const lightMatrices = [];

    for (const light of this.directionalLights) {
      const viewMatrix = new Matrix4().lookAt({
        eye: new Vector3(light.direction).negate()
      });
      lightMatrices.push(viewMatrix);
    }

    return lightMatrices;
  }

  _createShadowPasses(device) {
    for (let i = 0; i < this.directionalLights.length; i++) {
      const shadowPass = new ShadowPass(device);
      this.shadowPasses[i] = shadowPass;
      this.shadowMaps[i] = shadowPass.shadowMap;
    }
  }

  _applyDefaultLights() {
    const {
      ambientLight,
      pointLights,
      directionalLights
    } = this;

    if (!ambientLight && pointLights.length === 0 && directionalLights.length === 0) {
      this.ambientLight = new AmbientLight(DEFAULT_AMBIENT_LIGHT_PROPS);
      this.directionalLights.push(new DirectionalLight(DEFAULT_DIRECTIONAL_LIGHT_PROPS[0]), new DirectionalLight(DEFAULT_DIRECTIONAL_LIGHT_PROPS[1]));
    }
  }

}
//# sourceMappingURL=lighting-effect.js.map