'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 _deck = require('deck.gl');

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

var _meshLayerVertex = require('./mesh-layer-vertex.glsl');

var _meshLayerVertex2 = _interopRequireDefault(_meshLayerVertex);

var _meshLayerVertex3 = require('./mesh-layer-vertex-64.glsl');

var _meshLayerVertex4 = _interopRequireDefault(_meshLayerVertex3);

var _meshLayerFragment = require('./mesh-layer-fragment.glsl');

var _meshLayerFragment2 = _interopRequireDefault(_meshLayerFragment);

var _project64utils = require('../shaderlib/project64utils/project64utils');

var _project64utils2 = _interopRequireDefault(_project64utils);

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; } // Note: This file will either be moved back to deck.gl or reformatted to web-monorepo standards
// Disabling lint temporarily to facilitate copying code in and out of this repo
/* eslint-disable */

// Copyright (c) 2015 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 = _deck.experimental.fp64LowPart,
    enable64bitSupport = _deck.experimental.enable64bitSupport;


function degreeToRadian(degree) {
  return degree * Math.PI / 180;
}

/*
 * Load image data into luma.gl Texture2D objects
 * @param {WebGLContext} gl
 * @param {String|Texture2D|HTMLImageElement|Uint8ClampedArray} src - source of image data
 *   can be url string, Texture2D object, HTMLImageElement or pixel array
 * @returns {Promise} resolves to an object with name -> texture mapping
 */
function getTexture(gl, src, opts) {
  if (typeof src === 'string') {
    // Url, load the image
    return (0, _luma.loadTextures)(gl, Object.assign({ urls: [src] }, opts)).then(function (textures) {
      return textures[0];
    }).catch(function (error) {
      throw new Error('Could not load texture from ' + src + ': ' + error);
    });
  }
  return new Promise(function (resolve) {
    return resolve(getTextureFromData(gl, src, opts));
  });
}

/*
 * Convert image data into texture
 * @returns {Texture2D} texture
 */
function getTextureFromData(gl, data, opts) {
  if (data instanceof _luma.Texture2D) {
    return data;
  }
  return new _luma.Texture2D(gl, Object.assign({ data: data }, opts));
}

var defaultProps = {
  mesh: null,
  texture: null,
  sizeScale: 1,

  // TODO - parameters should be merged, not completely overridden
  parameters: {
    depthTest: true,
    depthFunc: _luma.GL.LEQUAL
  },
  fp64: false,
  // Optional settings for 'lighting' shader module
  lightSettings: {},

  getPosition: function getPosition(x) {
    return x.position;
  },
  getAngleDegreesCW: function getAngleDegreesCW(x) {
    return x.angle || 0;
  },
  getColor: function getColor(x) {
    return x.color || [0, 0, 0, 255];
  }
};

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

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

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

  _createClass(MeshLayer, [{
    key: 'getShaders',
    value: function getShaders(id) {
      var shaderCache = this.context.shaderCache;

      return enable64bitSupport(this.props) ? { vs: _meshLayerVertex4.default, fs: _meshLayerFragment2.default, modules: [_project64utils2.default, 'picking', 'lighting'], shaderCache: shaderCache } : { vs: _meshLayerVertex2.default, fs: _meshLayerFragment2.default, modules: ['picking', 'lighting'], shaderCache: shaderCache }; // 'project' module added by default.
    }
  }, {
    key: 'initializeState',
    value: function initializeState() {
      var attributeManager = this.getAttributeManager();
      attributeManager.addInstanced({
        instancePositions: {
          size: 3,
          accessor: 'getPosition',
          update: this.calculateInstancePositions
        },
        instanceAngles: {
          size: 1,
          accessor: 'getAngleDegreesCW',
          update: this.calculateInstanceAngles
        },
        instanceColors: { size: 4, accessor: 'getColor', update: this.calculateInstanceColors }
      });
    }
  }, {
    key: 'updateState',
    value: function updateState(_ref) {
      var props = _ref.props,
          oldProps = _ref.oldProps,
          changeFlags = _ref.changeFlags;

      var attributeManager = this.getAttributeManager();

      // super.updateState({props, oldProps, changeFlags});
      if (changeFlags.dataChanged) {
        attributeManager.invalidateAll();
      }

      if (changeFlags.propsChanged) {
        this._updateFP64(props, oldProps);

        if (props.sizeScale !== oldProps.sizeScale) {
          var sizeScale = props.sizeScale;

          this.state.model.setUniforms({ sizeScale: sizeScale });
        }

        if (props.texture !== oldProps.texture) {
          if (props.texture) {
            this.loadTexture(props.texture);
          } else {
            // TODO - reset
          }
        }
      }
    }
  }, {
    key: '_updateFP64',
    value: function _updateFP64(props, oldProps) {
      if (props.fp64 !== oldProps.fp64) {
        this.setState({ model: this.getModel(this.context.gl) });

        this.state.model.setUniforms({
          sizeScale: props.sizeScale
        });

        var attributeManager = this.getAttributeManager();
        attributeManager.invalidateAll();

        if (enable64bitSupport(this.props)) {
          attributeManager.addInstanced({
            instancePositions64xy: {
              size: 2,
              accessor: 'getPosition',
              update: this.calculateInstancePositions64xyLow
            }
          });
        } else {
          attributeManager.remove(['instancePositions64xy']);
        }
      }
    }
  }, {
    key: 'draw',
    value: function draw(_ref2) {
      var uniforms = _ref2.uniforms;

      this.state.model.render(uniforms);
    }
  }, {
    key: 'getModel',
    value: function getModel(gl) {
      // const isValidMesh = this.props.mesh instanceof Geometry && this.props.mesh.attributes.positions;
      // assert(isValidMesh);

      return new _luma.Model(gl, Object.assign({}, this.getShaders(), {
        id: this.props.id,
        geometry: this.props.mesh,
        isInstanced: true
      }));
    }
  }, {
    key: 'loadTexture',
    value: function loadTexture(src) {
      var _this2 = this;

      var gl = this.context.gl;
      var model = this.state.model;

      getTexture(gl, src).then(function (texture) {
        model.setUniforms({ sampler1: texture });
        _this2.setNeedsRedraw();
      });
    }
  }, {
    key: 'calculateInstancePositions',
    value: function calculateInstancePositions(attribute) {
      var _props = this.props,
          data = _props.data,
          getPosition = _props.getPosition;
      var value = attribute.value,
          size = attribute.size;

      var i = 0;
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = data[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var point = _step.value;

          var position = getPosition(point);
          value[i] = position[0];
          value[i + 1] = position[1];
          value[i + 2] = position[2] || 0;
          i += size;
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    }
  }, {
    key: 'calculateInstancePositions64xyLow',
    value: function calculateInstancePositions64xyLow(attribute) {
      var _props2 = this.props,
          data = _props2.data,
          getPosition = _props2.getPosition;
      var value = attribute.value;

      var i = 0;
      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = data[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var point = _step2.value;

          var position = getPosition(point);
          value[i++] = fp64LowPart(position[0]);
          value[i++] = fp64LowPart(position[1]);
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2.return) {
            _iterator2.return();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    }
  }, {
    key: 'calculateInstanceAngles',
    value: function calculateInstanceAngles(attribute) {
      var _props3 = this.props,
          data = _props3.data,
          getAngleDegreesCW = _props3.getAngleDegreesCW;
      var value = attribute.value,
          size = attribute.size;

      var i = 0;
      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = data[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var point = _step3.value;

          var angle = getAngleDegreesCW(point);
          value[i] = -degreeToRadian(angle);
          i += size;
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3.return) {
            _iterator3.return();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }
    }
  }, {
    key: 'calculateInstanceColors',
    value: function calculateInstanceColors(attribute) {
      var _props4 = this.props,
          data = _props4.data,
          getColor = _props4.getColor;
      var value = attribute.value;

      var i = 0;
      var _iteratorNormalCompletion4 = true;
      var _didIteratorError4 = false;
      var _iteratorError4 = undefined;

      try {
        for (var _iterator4 = data[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
          var point = _step4.value;

          var color = getColor(point) || DEFAULT_COLOR;
          value[i++] = color[0];
          value[i++] = color[1];
          value[i++] = color[2];
          value[i++] = isNaN(color[3]) ? 255 : color[3];
        }
      } catch (err) {
        _didIteratorError4 = true;
        _iteratorError4 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion4 && _iterator4.return) {
            _iterator4.return();
          }
        } finally {
          if (_didIteratorError4) {
            throw _iteratorError4;
          }
        }
      }
    }
  }]);

  return MeshLayer;
}(_deck.Layer);

exports.default = MeshLayer;


MeshLayer.layerName = 'MeshLayer';
MeshLayer.defaultProps = defaultProps;
//# sourceMappingURL=mesh-layer.js.map