(function (global, factory) {
  if (typeof define === "function" && define.amd) {
    define(["exports", "three", "../geometries/LightningStrike.js"], factory);
  } else if (typeof exports !== "undefined") {
    factory(exports, require("three"), require("../geometries/LightningStrike.js"));
  } else {
    var mod = {
      exports: {}
    };
    factory(mod.exports, global.three, global.LightningStrike);
    global.LightningStorm = mod.exports;
  }
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three, _LightningStrike) {
  "use strict";

  Object.defineProperty(_exports, "__esModule", {
    value: true
  });
  _exports.LightningStorm = void 0;

  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }

  function _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); }

  function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }

  function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } Object.defineProperty(subClass, "prototype", { value: Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }), writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }

  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }

  function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }

  function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

  function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }

  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

  /**
   * @fileoverview Lightning strike object generator
   *
   *
   * Usage
   *
   * const myStorm = new LightningStorm( paramsObject );
   * myStorm.position.set( ... );
   * scene.add( myStorm );
   * ...
   * myStorm.update( currentTime );
   *
   * The "currentTime" can only go forwards or be stopped.
   *
   *
   * LightningStorm parameters:
   *
   * @param {double} size Size of the storm. If no 'onRayPosition' parameter is defined, it means the side of the rectangle the storm covers.
   *
   * @param {double} minHeight Minimum height a ray can start at. If no 'onRayPosition' parameter is defined, it means the height above plane y = 0.
   *
   * @param {double} maxHeight Maximum height a ray can start at. If no 'onRayPosition' parameter is defined, it means the height above plane y = 0.
   *
   * @param {double} maxSlope The maximum inclination slope of a ray. If no 'onRayPosition' parameter is defined, it means the slope relative to plane y = 0.
   *
   * @param {integer} maxLightnings Greater than 0. The maximum number of simultaneous rays.
   *
   * @param {double} lightningMinPeriod minimum time between two consecutive rays.
   *
   * @param {double} lightningMaxPeriod maximum time between two consecutive rays.
   *
   * @param {double} lightningMinDuration The minimum time a ray can last.
   *
   * @param {double} lightningMaxDuration The maximum time a ray can last.
   *
   * @param {Object} lightningParameters The parameters for created rays. See LightningStrike (geometry)
   *
   * @param {Material} lightningMaterial The THREE.Material used for the created rays.
   *
   * @param {function} onRayPosition Optional callback with two Vector3 parameters (source, dest). You can set here the start and end points for each created ray, using the standard size, minHeight, etc parameters and other values in your algorithm.
   *
   * @param {function} onLightningDown This optional callback is called with one parameter (lightningStrike) when a ray ends propagating, so it has hit the ground.
   *
   *
  */
  var LightningStorm = /*#__PURE__*/function (_Object3D) {
    _inherits(LightningStorm, _Object3D);

    var _super = _createSuper(LightningStorm);

    function LightningStorm() {
      var _this;

      var stormParams = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

      _classCallCheck(this, LightningStorm);

      _this = _super.call(this); // Parameters

      _this.stormParams = stormParams;
      stormParams.size = stormParams.size !== undefined ? stormParams.size : 1000.0;
      stormParams.minHeight = stormParams.minHeight !== undefined ? stormParams.minHeight : 80.0;
      stormParams.maxHeight = stormParams.maxHeight !== undefined ? stormParams.maxHeight : 100.0;
      stormParams.maxSlope = stormParams.maxSlope !== undefined ? stormParams.maxSlope : 1.1;
      stormParams.maxLightnings = stormParams.maxLightnings !== undefined ? stormParams.maxLightnings : 3;
      stormParams.lightningMinPeriod = stormParams.lightningMinPeriod !== undefined ? stormParams.lightningMinPeriod : 3.0;
      stormParams.lightningMaxPeriod = stormParams.lightningMaxPeriod !== undefined ? stormParams.lightningMaxPeriod : 7.0;
      stormParams.lightningMinDuration = stormParams.lightningMinDuration !== undefined ? stormParams.lightningMinDuration : 1.0;
      stormParams.lightningMaxDuration = stormParams.lightningMaxDuration !== undefined ? stormParams.lightningMaxDuration : 2.5;
      _this.lightningParameters = _LightningStrike.LightningStrike.copyParameters(stormParams.lightningParameters, stormParams.lightningParameters);
      _this.lightningParameters.isEternal = false;
      _this.lightningMaterial = stormParams.lightningMaterial !== undefined ? stormParams.lightningMaterial : new _three.MeshBasicMaterial({
        color: 0xB0FFFF
      });

      if (stormParams.onRayPosition !== undefined) {
        _this.onRayPosition = stormParams.onRayPosition;
      } else {
        _this.onRayPosition = function (source, dest) {
          dest.set((Math.random() - 0.5) * stormParams.size, 0, (Math.random() - 0.5) * stormParams.size);

          var height = _three.MathUtils.lerp(stormParams.minHeight, stormParams.maxHeight, Math.random());

          source.set(stormParams.maxSlope * (2 * Math.random() - 1), 1, stormParams.maxSlope * (2 * Math.random() - 1)).multiplyScalar(height).add(dest);
        };
      }

      _this.onLightningDown = stormParams.onLightningDown; // Internal state

      _this.inited = false;
      _this.nextLightningTime = 0;
      _this.lightningsMeshes = [];
      _this.deadLightningsMeshes = [];

      for (var i = 0; i < _this.stormParams.maxLightnings; i++) {
        var lightning = new _LightningStrike.LightningStrike(_LightningStrike.LightningStrike.copyParameters({}, _this.lightningParameters));
        var mesh = new _three.Mesh(lightning, _this.lightningMaterial);

        _this.deadLightningsMeshes.push(mesh);
      }

      return _this;
    }

    _createClass(LightningStorm, [{
      key: "update",
      value: function update(time) {
        if (!this.inited) {
          this.nextLightningTime = this.getNextLightningTime(time) * Math.random();
          this.inited = true;
        }

        if (time >= this.nextLightningTime) {
          // Lightning creation
          var lightningMesh = this.deadLightningsMeshes.pop();

          if (lightningMesh) {
            var lightningParams1 = _LightningStrike.LightningStrike.copyParameters(lightningMesh.geometry.rayParameters, this.lightningParameters);

            lightningParams1.birthTime = time;
            lightningParams1.deathTime = time + _three.MathUtils.lerp(this.stormParams.lightningMinDuration, this.stormParams.lightningMaxDuration, Math.random());
            this.onRayPosition(lightningParams1.sourceOffset, lightningParams1.destOffset);
            lightningParams1.noiseSeed = Math.random();
            this.add(lightningMesh);
            this.lightningsMeshes.push(lightningMesh);
          } // Schedule next lightning


          this.nextLightningTime = this.getNextLightningTime(time);
        }

        var i = 0,
            il = this.lightningsMeshes.length;

        while (i < il) {
          var mesh = this.lightningsMeshes[i];
          var lightning = mesh.geometry;
          var prevState = lightning.state;
          lightning.update(time);

          if (prevState === _LightningStrike.LightningStrike.RAY_PROPAGATING && lightning.state > prevState) {
            if (this.onLightningDown) {
              this.onLightningDown(lightning);
            }
          }

          if (lightning.state === _LightningStrike.LightningStrike.RAY_EXTINGUISHED) {
            // Lightning is to be destroyed
            this.lightningsMeshes.splice(this.lightningsMeshes.indexOf(mesh), 1);
            this.deadLightningsMeshes.push(mesh);
            this.remove(mesh);
            il--;
          } else {
            i++;
          }
        }
      }
    }, {
      key: "getNextLightningTime",
      value: function getNextLightningTime(currentTime) {
        return currentTime + _three.MathUtils.lerp(this.stormParams.lightningMinPeriod, this.stormParams.lightningMaxPeriod, Math.random()) / (this.stormParams.maxLightnings + 1);
      }
    }, {
      key: "copy",
      value: function copy(source) {
        _get(_getPrototypeOf(LightningStorm.prototype), "copy", this).call(this, source);

        this.stormParams.size = source.stormParams.size;
        this.stormParams.minHeight = source.stormParams.minHeight;
        this.stormParams.maxHeight = source.stormParams.maxHeight;
        this.stormParams.maxSlope = source.stormParams.maxSlope;
        this.stormParams.maxLightnings = source.stormParams.maxLightnings;
        this.stormParams.lightningMinPeriod = source.stormParams.lightningMinPeriod;
        this.stormParams.lightningMaxPeriod = source.stormParams.lightningMaxPeriod;
        this.stormParams.lightningMinDuration = source.stormParams.lightningMinDuration;
        this.stormParams.lightningMaxDuration = source.stormParams.lightningMaxDuration;
        this.lightningParameters = _LightningStrike.LightningStrike.copyParameters({}, source.lightningParameters);
        this.lightningMaterial = source.stormParams.lightningMaterial;
        this.onLightningDown = source.onLightningDown;
        return this;
      }
    }, {
      key: "clone",
      value: function clone() {
        return new this.constructor(this.stormParams).copy(this);
      }
    }]);

    return LightningStorm;
  }(_three.Object3D);

  _exports.LightningStorm = LightningStorm;
  LightningStorm.prototype.isLightningStorm = true;
});