'use strict';

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

var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

var _core = require('../../core');

var _luma = require('luma.gl');

var _pathLayerVertex = require('./path-layer-vertex.glsl');

var _pathLayerVertex2 = _interopRequireDefault(_pathLayerVertex);

var _pathLayerVertex3 = require('./path-layer-vertex-64.glsl');

var _pathLayerVertex4 = _interopRequireDefault(_pathLayerVertex3);

var _pathLayerFragment = require('./path-layer-fragment.glsl');

var _pathLayerFragment2 = _interopRequireDefault(_pathLayerFragment);

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

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

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // 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 fp64LowPart = _core.experimental.fp64LowPart,
    enable64bitSupport = _core.experimental.enable64bitSupport;


var DEFAULT_COLOR = [0, 0, 0, 255];

var defaultProps = {
  widthScale: 1, // stroke width in meters
  widthMinPixels: 0, //  min stroke width in pixels
  widthMaxPixels: Number.MAX_SAFE_INTEGER, // max stroke width in pixels
  rounded: false,
  miterLimit: 4,
  fp64: false,
  dashJustified: false,

  getPath: function getPath(object) {
    return object.path;
  },
  getColor: function getColor(object) {
    return object.color || DEFAULT_COLOR;
  },
  getWidth: function getWidth(object) {
    return object.width || 1;
  },
  getDashArray: null
};

var isClosed = function isClosed(path) {
  var firstPoint = path[0];
  var lastPoint = path[path.length - 1];
  return firstPoint[0] === lastPoint[0] && firstPoint[1] === lastPoint[1] && firstPoint[2] === lastPoint[2];
};

var PathLayer = function (_Layer) {
  _inherits(PathLayer, _Layer);

  function PathLayer() {
    _classCallCheck(this, PathLayer);

    return _possibleConstructorReturn(this, (PathLayer.__proto__ || Object.getPrototypeOf(PathLayer)).apply(this, arguments));
  }

  _createClass(PathLayer, [{
    key: 'getShaders',
    value: function getShaders() {
      return enable64bitSupport(this.props) ? { vs: _pathLayerVertex4.default, fs: _pathLayerFragment2.default, modules: ['project64', 'picking'] } : { vs: _pathLayerVertex2.default, fs: _pathLayerFragment2.default, modules: ['picking'] }; // 'project' module added by default.
    }
  }, {
    key: 'initializeState',
    value: function initializeState() {
      var attributeManager = this.getAttributeManager();
      /* eslint-disable max-len */
      attributeManager.addInstanced({
        instanceStartPositions: { size: 3, update: this.calculateStartPositions },
        instanceEndPositions: { size: 3, update: this.calculateEndPositions },
        instanceLeftDeltas: { size: 3, update: this.calculateLeftDeltas },
        instanceRightDeltas: { size: 3, update: this.calculateRightDeltas },
        instanceStrokeWidths: { size: 1, accessor: 'getWidth', update: this.calculateStrokeWidths },
        instanceDashArrays: { size: 2, accessor: 'getDashArray', update: this.calculateDashArrays },
        instanceColors: {
          size: 4,
          type: _luma.GL.UNSIGNED_BYTE,
          accessor: 'getColor',
          update: this.calculateColors
        },
        instancePickingColors: { size: 3, type: _luma.GL.UNSIGNED_BYTE, update: this.calculatePickingColors }
      });
      /* eslint-enable max-len */
    }
  }, {
    key: 'updateAttribute',
    value: function updateAttribute(_ref) {
      var props = _ref.props,
          oldProps = _ref.oldProps,
          changeFlags = _ref.changeFlags;

      if (props.fp64 !== oldProps.fp64) {
        var attributeManager = this.getAttributeManager();
        attributeManager.invalidateAll();

        if (props.fp64 && props.coordinateSystem === _core.COORDINATE_SYSTEM.LNGLAT) {
          attributeManager.addInstanced({
            instanceStartEndPositions64xyLow: {
              size: 4,
              update: this.calculateInstanceStartEndPositions64xyLow
            }
          });
        } else {
          attributeManager.remove(['instanceStartEndPositions64xyLow']);
        }
      }
    }
  }, {
    key: 'updateState',
    value: function updateState(_ref2) {
      var oldProps = _ref2.oldProps,
          props = _ref2.props,
          changeFlags = _ref2.changeFlags;

      _get(PathLayer.prototype.__proto__ || Object.getPrototypeOf(PathLayer.prototype), 'updateState', this).call(this, { props: props, oldProps: oldProps, changeFlags: changeFlags });

      var getPath = this.props.getPath;

      var attributeManager = this.getAttributeManager();
      if (props.fp64 !== oldProps.fp64) {
        var gl = this.context.gl;

        if (this.state.model) {
          this.state.model.delete();
        }
        this.setState({ model: this._getModel(gl) });
      }
      this.updateAttribute({ props: props, oldProps: oldProps, changeFlags: changeFlags });

      var geometryChanged = changeFlags.dataChanged || changeFlags.updateTriggersChanged && (changeFlags.updateTriggersChanged.all || changeFlags.updateTriggersChanged.getPath);

      if (geometryChanged) {
        // this.state.paths only stores point positions in each path
        var paths = props.data.map(getPath);
        var numInstances = paths.reduce(function (count, path) {
          return count + path.length - 1;
        }, 0);

        this.setState({ paths: paths, numInstances: numInstances });
        attributeManager.invalidateAll();
      }
    }
  }, {
    key: 'draw',
    value: function draw(_ref3) {
      var uniforms = _ref3.uniforms;
      var _props = this.props,
          rounded = _props.rounded,
          miterLimit = _props.miterLimit,
          widthScale = _props.widthScale,
          widthMinPixels = _props.widthMinPixels,
          widthMaxPixels = _props.widthMaxPixels,
          dashJustified = _props.dashJustified;


      this.state.model.render(Object.assign({}, uniforms, {
        jointType: Number(rounded),
        alignMode: Number(dashJustified),
        widthScale: widthScale,
        miterLimit: miterLimit,
        widthMinPixels: widthMinPixels,
        widthMaxPixels: widthMaxPixels
      }));
    }
  }, {
    key: '_getModel',
    value: function _getModel(gl) {
      /*
       *       _
       *        "-_ 1                   3                       5
       *     _     "o---------------------o-------------------_-o
       *       -   / ""--..__              '.             _.-' /
       *   _     "@- - - - - ""--..__- - - - x - - - -_.@'    /
       *    "-_  /                   ""--..__ '.  _,-` :     /
       *       "o----------------------------""-o'    :     /
       *      0,2                            4 / '.  :     /
       *                                      /   '.:     /
       *                                     /     :'.   /
       *                                    /     :  ', /
       *                                   /     :     o
       */

      var SEGMENT_INDICES = [
      // start corner
      0, 2, 1,
      // body
      1, 2, 4, 1, 4, 3,
      // end corner
      3, 4, 5];

      // [0] position on segment - 0: start, 1: end
      // [1] side of path - -1: left, 0: center, 1: right
      // [2] role - 0: offset point 1: joint point
      var SEGMENT_POSITIONS = [
      // bevel start corner
      0, 0, 1,
      // start inner corner
      0, -1, 0,
      // start outer corner
      0, 1, 0,
      // end inner corner
      1, -1, 0,
      // end outer corner
      1, 1, 0,
      // bevel end corner
      1, 0, 1];

      return new _luma.Model(gl, Object.assign({}, this.getShaders(), {
        id: this.props.id,
        geometry: new _luma.Geometry({
          drawMode: _luma.GL.TRIANGLES,
          attributes: {
            indices: new Uint16Array(SEGMENT_INDICES),
            positions: new Float32Array(SEGMENT_POSITIONS)
          }
        }),
        isInstanced: true,
        shaderCache: this.context.shaderCache
      }));
    }
  }, {
    key: 'calculateStartPositions',
    value: function calculateStartPositions(attribute) {
      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path) {
        var numSegments = path.length - 1;
        for (var ptIndex = 0; ptIndex < numSegments; ptIndex++) {
          var point = path[ptIndex];
          value[i++] = point[0];
          value[i++] = point[1];
          value[i++] = point[2] || 0;
        }
      });
    }
  }, {
    key: 'calculateEndPositions',
    value: function calculateEndPositions(attribute) {
      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path) {
        for (var ptIndex = 1; ptIndex < path.length; ptIndex++) {
          var point = path[ptIndex];
          value[i++] = point[0];
          value[i++] = point[1];
          value[i++] = point[2] || 0;
        }
      });
    }
  }, {
    key: 'calculateInstanceStartEndPositions64xyLow',
    value: function calculateInstanceStartEndPositions64xyLow(attribute) {
      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path) {
        var numSegments = path.length - 1;
        for (var ptIndex = 0; ptIndex < numSegments; ptIndex++) {
          var startPoint = path[ptIndex];
          var endPoint = path[ptIndex + 1];
          value[i++] = fp64LowPart(startPoint[0]);
          value[i++] = fp64LowPart(startPoint[1]);
          value[i++] = fp64LowPart(endPoint[0]);
          value[i++] = fp64LowPart(endPoint[1]);
        }
      });
    }
  }, {
    key: 'calculateLeftDeltas',
    value: function calculateLeftDeltas(attribute) {
      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path) {
        var numSegments = path.length - 1;
        var prevPoint = isClosed(path) ? path[path.length - 2] : path[0];

        for (var ptIndex = 0; ptIndex < numSegments; ptIndex++) {
          var point = path[ptIndex];
          value[i++] = point[0] - prevPoint[0];
          value[i++] = point[1] - prevPoint[1];
          value[i++] = point[2] - prevPoint[2] || 0;
          prevPoint = point;
        }
      });
    }
  }, {
    key: 'calculateRightDeltas',
    value: function calculateRightDeltas(attribute) {
      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path) {
        for (var ptIndex = 1; ptIndex < path.length; ptIndex++) {
          var point = path[ptIndex];
          var nextPoint = path[ptIndex + 1];
          if (!nextPoint) {
            nextPoint = isClosed(path) ? path[1] : point;
          }

          value[i++] = nextPoint[0] - point[0];
          value[i++] = nextPoint[1] - point[1];
          value[i++] = nextPoint[2] - point[2] || 0;
        }
      });
    }
  }, {
    key: 'calculateStrokeWidths',
    value: function calculateStrokeWidths(attribute) {
      var _props2 = this.props,
          data = _props2.data,
          getWidth = _props2.getWidth;
      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path, index) {
        var width = getWidth(data[index], index);
        for (var ptIndex = 1; ptIndex < path.length; ptIndex++) {
          value[i++] = width;
        }
      });
    }
  }, {
    key: 'calculateDashArrays',
    value: function calculateDashArrays(attribute) {
      var _props3 = this.props,
          data = _props3.data,
          getDashArray = _props3.getDashArray;

      if (!getDashArray) {
        return;
      }

      var paths = this.state.paths;
      var value = attribute.value;

      var i = 0;
      paths.forEach(function (path, index) {
        var dashArray = getDashArray(data[index], index);
        for (var ptIndex = 1; ptIndex < path.length; ptIndex++) {
          value[i++] = dashArray[0];
          value[i++] = dashArray[1];
        }
      });
    }
  }, {
    key: 'calculateColors',
    value: function calculateColors(attribute) {
      var _props4 = this.props,
          data = _props4.data,
          getColor = _props4.getColor;
      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path, index) {
        var pointColor = getColor(data[index], index);
        if (isNaN(pointColor[3])) {
          pointColor[3] = 255;
        }
        for (var ptIndex = 1; ptIndex < path.length; ptIndex++) {
          value[i++] = pointColor[0];
          value[i++] = pointColor[1];
          value[i++] = pointColor[2];
          value[i++] = pointColor[3];
        }
      });
    }

    // Override the default picking colors calculation

  }, {
    key: 'calculatePickingColors',
    value: function calculatePickingColors(attribute) {
      var _this2 = this;

      var paths = this.state.paths;
      var value = attribute.value;


      var i = 0;
      paths.forEach(function (path, index) {
        var pickingColor = _this2.encodePickingColor(index);
        for (var ptIndex = 1; ptIndex < path.length; ptIndex++) {
          value[i++] = pickingColor[0];
          value[i++] = pickingColor[1];
          value[i++] = pickingColor[2];
        }
      });
    }
  }]);

  return PathLayer;
}(_core.Layer);

exports.default = PathLayer;


PathLayer.layerName = 'PathLayer';
PathLayer.defaultProps = defaultProps;
//# sourceMappingURL=path-layer.js.map