'use strict';

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

var _multiply = require('gl-mat4/multiply');

var _multiply2 = _interopRequireDefault(_multiply);

var _transformMat = require('gl-vec4/transformMat4');

var _transformMat2 = _interopRequireDefault(_transformMat);

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

var _memoize = require('../../utils/memoize');

var _memoize2 = _interopRequireDefault(_memoize);

var _log = require('../../utils/log');

var _log2 = _interopRequireDefault(_log);

var _assert = require('../../utils/assert');

var _assert2 = _interopRequireDefault(_assert);

var _viewportMercatorProject = require('viewport-mercator-project');

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

// To quickly set a vector to zero
var ZERO_VECTOR = [0, 0, 0, 0];
// 4x4 matrix that drops 4th component of vector
// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

var VECTOR_TO_POINT_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0];
var IDENTITY_MATRIX = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
var DEFAULT_PIXELS_PER_UNIT2 = [0, 0, 0];
var DEFAULT_COORDINATE_ORIGIN = [0, 0, 0];

var getMemoizedViewportUniforms = (0, _memoize2.default)(calculateViewportUniforms);

// The code that utilizes Matrix4 does the same calculation as their mat4 counterparts,
// has lower performance but provides error checking.
// Uncomment when debugging
function calculateMatrixAndOffset(_ref) {
  var viewport = _ref.viewport,
      coordinateSystem = _ref.coordinateSystem,
      coordinateOrigin = _ref.coordinateOrigin,
      coordinateZoom = _ref.coordinateZoom;
  var viewMatrixUncentered = viewport.viewMatrixUncentered;
  var viewMatrix = viewport.viewMatrix;
  var projectionMatrix = viewport.projectionMatrix;
  var viewProjectionMatrix = viewport.viewProjectionMatrix;


  var projectionCenter = void 0;

  switch (coordinateSystem) {
    case _constants.COORDINATE_SYSTEM.IDENTITY:
    case _constants.COORDINATE_SYSTEM.LNGLAT:
      projectionCenter = ZERO_VECTOR;
      break;

    // TODO: make lighting work for meter offset mode
    case _constants.COORDINATE_SYSTEM.LNGLAT_OFFSETS:
    case _constants.COORDINATE_SYSTEM.METER_OFFSETS:
      // Calculate transformed projectionCenter (using 64 bit precision JS)
      // This is the key to offset mode precision
      // (avoids doing this addition in 32 bit precision in GLSL)
      var positionPixels = (0, _viewportMercatorProject.lngLatToWorld)(coordinateOrigin, Math.pow(2, coordinateZoom));
      // projectionCenter = new Matrix4(viewProjectionMatrix)
      //   .transformVector([positionPixels[0], positionPixels[1], 0.0, 1.0]);
      projectionCenter = (0, _transformMat2.default)([], [positionPixels[0], positionPixels[1], 0.0, 1.0], viewProjectionMatrix);

      // Always apply uncentered projection matrix if available (shader adds center)
      viewMatrix = viewMatrixUncentered || viewMatrix;

      // Zero out 4th coordinate ("after" model matrix) - avoids further translations
      // viewMatrix = new Matrix4(viewMatrixUncentered || viewMatrix)
      //   .multiplyRight(VECTOR_TO_POINT_MATRIX);
      viewProjectionMatrix = (0, _multiply2.default)([], projectionMatrix, viewMatrix);
      viewProjectionMatrix = (0, _multiply2.default)([], viewProjectionMatrix, VECTOR_TO_POINT_MATRIX);
      break;

    default:
      throw new Error('Unknown projection mode');
  }

  return {
    viewMatrix: viewMatrix,
    viewProjectionMatrix: viewProjectionMatrix,
    projectionCenter: projectionCenter,
    cameraPos: viewport.cameraPosition
  };
}

/**
 * Returns uniforms for shaders based on current projection
 * includes: projection matrix suitable for shaders
 *
 * TODO - Ensure this works with any viewport, not just WebMercatorViewports
 *
 * @param {WebMercatorViewport} viewport -
 * @return {Float32Array} - 4x4 projection matrix that can be used in shaders
 */
function getUniformsFromViewport() {
  var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
      viewport = _ref2.viewport,
      _ref2$devicePixelRati = _ref2.devicePixelRatio,
      devicePixelRatio = _ref2$devicePixelRati === undefined ? 1 : _ref2$devicePixelRati,
      _ref2$modelMatrix = _ref2.modelMatrix,
      modelMatrix = _ref2$modelMatrix === undefined ? null : _ref2$modelMatrix,
      _ref2$coordinateSyste = _ref2.coordinateSystem,
      coordinateSystem = _ref2$coordinateSyste === undefined ? _constants.COORDINATE_SYSTEM.LNGLAT : _ref2$coordinateSyste,
      _ref2$coordinateOrigi = _ref2.coordinateOrigin,
      coordinateOrigin = _ref2$coordinateOrigi === undefined ? DEFAULT_COORDINATE_ORIGIN : _ref2$coordinateOrigi,
      projectionMode = _ref2.projectionMode,
      positionOrigin = _ref2.positionOrigin;

  (0, _assert2.default)(viewport);

  if (projectionMode !== undefined) {
    _log2.default.removed('projectionMode', 'coordinateSystem');
  }
  if (positionOrigin !== undefined) {
    _log2.default.removed('positionOrigin', 'coordinateOrigin');
  }

  return Object.assign({
    project_uModelMatrix: modelMatrix || IDENTITY_MATRIX
  }, getMemoizedViewportUniforms({ viewport: viewport, devicePixelRatio: devicePixelRatio, coordinateSystem: coordinateSystem, coordinateOrigin: coordinateOrigin }));
}

function calculateViewportUniforms(_ref3) {
  var viewport = _ref3.viewport,
      devicePixelRatio = _ref3.devicePixelRatio,
      coordinateSystem = _ref3.coordinateSystem,
      coordinateOrigin = _ref3.coordinateOrigin;

  var coordinateZoom = viewport.zoom;
  (0, _assert2.default)(coordinateZoom >= 0);

  var _calculateMatrixAndOf = calculateMatrixAndOffset({
    coordinateSystem: coordinateSystem,
    coordinateOrigin: coordinateOrigin,
    coordinateZoom: coordinateZoom,
    viewport: viewport
  }),
      projectionCenter = _calculateMatrixAndOf.projectionCenter,
      viewProjectionMatrix = _calculateMatrixAndOf.viewProjectionMatrix,
      cameraPos = _calculateMatrixAndOf.cameraPos;

  (0, _assert2.default)(viewProjectionMatrix, 'Viewport missing modelViewProjectionMatrix');

  // Calculate projection pixels per unit
  var distanceScales = viewport.getDistanceScales();

  var viewportSize = [viewport.width * devicePixelRatio, viewport.height * devicePixelRatio];

  var uniforms = {
    // Projection mode values
    project_uCoordinateSystem: coordinateSystem,
    project_uCenter: projectionCenter,

    // Screen size
    project_uViewportSize: viewportSize,
    project_uDevicePixelRatio: devicePixelRatio,

    // Distance at which screen pixels are projected
    project_uFocalDistance: viewport.focalDistance || 1,
    project_uPixelsPerMeter: distanceScales.pixelsPerMeter,
    project_uPixelsPerDegree: distanceScales.pixelsPerDegree,
    project_uPixelsPerUnit: distanceScales.pixelsPerMeter,
    project_uPixelsPerUnit2: DEFAULT_PIXELS_PER_UNIT2,
    project_uScale: viewport.scale, // This is the mercator scale (2 ** zoom)

    project_uViewProjectionMatrix: viewProjectionMatrix,

    // This is for lighting calculations
    project_uCameraPosition: cameraPos
  };

  if (coordinateSystem === _constants.COORDINATE_SYSTEM.METER_OFFSETS) {
    var distanceScalesAtOrigin = viewport.getDistanceScales(coordinateOrigin);
    uniforms.project_uPixelsPerUnit = distanceScalesAtOrigin.pixelsPerMeter;
    uniforms.project_uPixelsPerUnit2 = distanceScalesAtOrigin.pixelsPerMeter2;
  }
  if (coordinateSystem === _constants.COORDINATE_SYSTEM.LNGLAT_OFFSETS) {
    var _distanceScalesAtOrigin = viewport.getDistanceScales(coordinateOrigin);
    uniforms.project_uPixelsPerUnit = _distanceScalesAtOrigin.pixelsPerDegree;
    uniforms.project_uPixelsPerUnit2 = _distanceScalesAtOrigin.pixelsPerDegree2;
  }

  return uniforms;
}
//# sourceMappingURL=viewport-uniforms.js.map