"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

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

var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));

var _constants = require("../../lib/constants");

var _project = _interopRequireDefault(require("../project/project"));

var _core = require("@math.gl/core");

var _memoize = _interopRequireDefault(require("../../utils/memoize"));

var _webMercator = require("@math.gl/web-mercator");

function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

var vs = "\nconst int max_lights = 2;\nuniform mat4 shadow_uViewProjectionMatrices[max_lights];\nuniform vec4 shadow_uProjectCenters[max_lights];\nuniform bool shadow_uDrawShadowMap;\nuniform bool shadow_uUseShadowMap;\nuniform int shadow_uLightId;\nuniform float shadow_uLightCount;\n\nout vec3 shadow_vPosition[max_lights];\n\nvec4 shadow_setVertexPosition(vec4 position_commonspace) {\n  if (shadow_uDrawShadowMap) {\n    return project_common_position_to_clipspace(position_commonspace, shadow_uViewProjectionMatrices[shadow_uLightId], shadow_uProjectCenters[shadow_uLightId]);\n  }\n  if (shadow_uUseShadowMap) {\n    for (int i = 0; i < max_lights; i++) {\n      if(i < int(shadow_uLightCount)) {\n        vec4 shadowMap_position = project_common_position_to_clipspace(position_commonspace, shadow_uViewProjectionMatrices[i], shadow_uProjectCenters[i]);\n        shadow_vPosition[i] = (shadowMap_position.xyz / shadowMap_position.w + 1.0) / 2.0;\n      }\n    }\n  }\n  return gl_Position;\n}\n";
var fs = "\nconst int max_lights = 2;\nuniform bool shadow_uDrawShadowMap;\nuniform bool shadow_uUseShadowMap;\nuniform sampler2D shadow_uShadowMap0;\nuniform sampler2D shadow_uShadowMap1;\nuniform vec4 shadow_uColor;\nuniform float shadow_uLightCount;\n\nin vec3 shadow_vPosition[max_lights];\n\nconst vec4 bitPackShift = vec4(1.0, 255.0, 65025.0, 16581375.0);\nconst vec4 bitUnpackShift = 1.0 / bitPackShift;\nconst vec4 bitMask = vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0,  0.0);\n\nfloat shadow_getShadowWeight(vec3 position, sampler2D shadowMap) {\n  vec4 rgbaDepth = texture(shadowMap, position.xy);\n\n  float z = dot(rgbaDepth, bitUnpackShift);\n  return smoothstep(0.001, 0.01, position.z - z);\n}\n\nvec4 shadow_filterShadowColor(vec4 color) {\n  if (shadow_uDrawShadowMap) {\n    vec4 rgbaDepth = fract(gl_FragCoord.z * bitPackShift);\n    rgbaDepth -= rgbaDepth.gbaa * bitMask;\n    return rgbaDepth;\n  }\n  if (shadow_uUseShadowMap) {\n    float shadowAlpha = 0.0;\n    shadowAlpha += shadow_getShadowWeight(shadow_vPosition[0], shadow_uShadowMap0);\n    if(shadow_uLightCount > 1.0) {\n      shadowAlpha += shadow_getShadowWeight(shadow_vPosition[1], shadow_uShadowMap1);\n    }\n    shadowAlpha *= shadow_uColor.a / shadow_uLightCount;\n    float blendedAlpha = shadowAlpha + color.a * (1.0 - shadowAlpha);\n\n    return vec4(\n      mix(color.rgb, shadow_uColor.rgb, shadowAlpha / blendedAlpha),\n      blendedAlpha\n    );\n  }\n  return color;\n}\n";
var getMemoizedViewportCenterPosition = (0, _memoize.default)(getViewportCenterPosition);
var getMemoizedViewProjectionMatrices = (0, _memoize.default)(getViewProjectionMatrices);
var DEFAULT_SHADOW_COLOR = [0, 0, 0, 1.0];
var VECTOR_TO_POINT_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0];

function screenToCommonSpace(xyz, pixelUnprojectionMatrix) {
  var _xyz = (0, _slicedToArray2.default)(xyz, 3),
      x = _xyz[0],
      y = _xyz[1],
      z = _xyz[2];

  var coord = (0, _webMercator.pixelsToWorld)([x, y, z], pixelUnprojectionMatrix);

  if (Number.isFinite(z)) {
    return coord;
  }

  return [coord[0], coord[1], 0];
}

function getViewportCenterPosition(_ref) {
  var viewport = _ref.viewport,
      center = _ref.center;
  return new _core.Matrix4(viewport.viewProjectionMatrix).invert().transform(center);
}

function getViewProjectionMatrices(_ref2) {
  var viewport = _ref2.viewport,
      shadowMatrices = _ref2.shadowMatrices;
  var projectionMatrices = [];
  var pixelUnprojectionMatrix = viewport.pixelUnprojectionMatrix;
  var farZ = viewport.isGeospatial ? undefined : 1;
  var corners = [[0, 0, farZ], [viewport.width, 0, farZ], [0, viewport.height, farZ], [viewport.width, viewport.height, farZ], [0, 0, -1], [viewport.width, 0, -1], [0, viewport.height, -1], [viewport.width, viewport.height, -1]].map(function (pixel) {
    return screenToCommonSpace(pixel, pixelUnprojectionMatrix);
  });

  var _iterator = _createForOfIteratorHelper(shadowMatrices),
      _step;

  try {
    var _loop = function _loop() {
      var shadowMatrix = _step.value;
      var viewMatrix = shadowMatrix.clone().translate(new _core.Vector3(viewport.center).negate());
      var positions = corners.map(function (corner) {
        return viewMatrix.transform(corner);
      });
      var projectionMatrix = new _core.Matrix4().ortho({
        left: Math.min.apply(Math, (0, _toConsumableArray2.default)(positions.map(function (position) {
          return position[0];
        }))),
        right: Math.max.apply(Math, (0, _toConsumableArray2.default)(positions.map(function (position) {
          return position[0];
        }))),
        bottom: Math.min.apply(Math, (0, _toConsumableArray2.default)(positions.map(function (position) {
          return position[1];
        }))),
        top: Math.max.apply(Math, (0, _toConsumableArray2.default)(positions.map(function (position) {
          return position[1];
        }))),
        near: Math.min.apply(Math, (0, _toConsumableArray2.default)(positions.map(function (position) {
          return -position[2];
        }))),
        far: Math.max.apply(Math, (0, _toConsumableArray2.default)(positions.map(function (position) {
          return -position[2];
        })))
      });
      projectionMatrices.push(projectionMatrix.multiplyRight(shadowMatrix));
    };

    for (_iterator.s(); !(_step = _iterator.n()).done;) {
      _loop();
    }
  } catch (err) {
    _iterator.e(err);
  } finally {
    _iterator.f();
  }

  return projectionMatrices;
}

function createShadowUniforms(opts, context) {
  var _opts$shadowEnabled = opts.shadowEnabled,
      shadowEnabled = _opts$shadowEnabled === void 0 ? true : _opts$shadowEnabled;

  if (!shadowEnabled || !opts.shadowMatrices || !opts.shadowMatrices.length) {
    return {
      shadow_uDrawShadowMap: false,
      shadow_uUseShadowMap: false
    };
  }

  var uniforms = {
    shadow_uDrawShadowMap: Boolean(opts.drawToShadowMap),
    shadow_uUseShadowMap: opts.shadowMaps ? opts.shadowMaps.length > 0 : false,
    shadow_uColor: opts.shadowColor || DEFAULT_SHADOW_COLOR,
    shadow_uLightId: opts.shadowLightId || 0,
    shadow_uLightCount: opts.shadowMatrices.length
  };
  var center = getMemoizedViewportCenterPosition({
    viewport: opts.viewport,
    center: context.project_uCenter
  });
  var projectCenters = [];
  var viewProjectionMatrices = getMemoizedViewProjectionMatrices({
    shadowMatrices: opts.shadowMatrices,
    viewport: opts.viewport
  }).slice();

  for (var i = 0; i < opts.shadowMatrices.length; i++) {
    var viewProjectionMatrix = viewProjectionMatrices[i];
    var viewProjectionMatrixCentered = viewProjectionMatrix.clone().translate(new _core.Vector3(opts.viewport.center).negate());

    if (context.project_uCoordinateSystem === _constants.COORDINATE_SYSTEM.LNGLAT && context.project_uProjectionMode === _constants.PROJECTION_MODE.WEB_MERCATOR) {
      viewProjectionMatrices[i] = viewProjectionMatrixCentered;
      projectCenters[i] = center;
    } else {
      viewProjectionMatrices[i] = viewProjectionMatrix.clone().multiplyRight(VECTOR_TO_POINT_MATRIX);
      projectCenters[i] = viewProjectionMatrixCentered.transform(center);
    }
  }

  for (var _i = 0; _i < viewProjectionMatrices.length; _i++) {
    uniforms["shadow_uViewProjectionMatrices[".concat(_i, "]")] = viewProjectionMatrices[_i];
    uniforms["shadow_uProjectCenters[".concat(_i, "]")] = projectCenters[_i];
  }

  for (var _i2 = 0; _i2 < 2; _i2++) {
    uniforms["shadow_uShadowMap".concat(_i2)] = opts.shadowMaps && opts.shadowMaps[_i2] || opts.dummyShadowMap;
  }

  return uniforms;
}

var _default = {
  name: 'shadow',
  dependencies: [_project.default],
  vs: vs,
  fs: fs,
  inject: {
    'vs:DECKGL_FILTER_GL_POSITION': "\n    position = shadow_setVertexPosition(geometry.position);\n    ",
    'fs:DECKGL_FILTER_COLOR': "\n    color = shadow_filterShadowColor(color);\n    "
  },
  getUniforms: function getUniforms() {
    var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

    if ('viewport' in opts && (opts.drawToShadowMap || opts.shadowMaps && opts.shadowMaps.length > 0)) {
      return createShadowUniforms(opts, context);
    }

    return {};
  }
};
exports.default = _default;
//# sourceMappingURL=shadow.js.map