"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = exports.PNTS_SIZE_MODE = exports.PNTS_SHAPE = exports.PNTS_MODE = exports.ClassificationScheme = void 0;
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var THREE = _interopRequireWildcard(require("three"));
var _Capabilities = _interopRequireDefault(require("../Core/System/Capabilities"));
var _ShaderUtils = _interopRequireDefault(require("./Shader/ShaderUtils"));
var _CommonMaterial = _interopRequireDefault(require("./CommonMaterial"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
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; } }
/* babel-plugin-inline-import './Shader/PointsVS.glsl' */
var PointsVS = "#include <itowns/WebGL2_pars_vertex>\n#include <itowns/precision_qualifier>\n#include <itowns/project_pars_vertex>\n#if defined(USE_TEXTURES_PROJECTIVE)\n#include <itowns/projective_texturing_pars_vertex>\n#endif\n#include <common>\n#include <logdepthbuf_pars_vertex>\n\nuniform float size;\nuniform float preSSE;\n\nuniform bool picking;\nuniform int mode;\nuniform float opacity;\nuniform vec4 overlayColor;\nuniform vec2 intensityRange;\nuniform bool applyOpacityClassication;\nattribute vec3 color;\nattribute vec4 unique_id;\nattribute float intensity;\nattribute float classification;\nuniform sampler2D classificationLUT;\nuniform int sizeMode;\nuniform float minAttenuatedSize;\nuniform float maxAttenuatedSize;\n\n#if defined(NORMAL_OCT16)\nattribute vec2 oct16Normal;\n#elif defined(NORMAL_SPHEREMAPPED)\nattribute vec2 sphereMappedNormal;\n#else\nattribute vec3 normal;\n#endif\n\nvarying vec4 vColor;\n\n// see https://web.archive.org/web/20150303053317/http://lgdv.cs.fau.de/get/1602\n// and implementation in PotreeConverter (BINPointReader.cpp) and potree (BinaryDecoderWorker.js)\n#if defined(NORMAL_OCT16)\nvec3 decodeOct16Normal(vec2 encodedNormal) {\n    vec2 nNorm = 2. * (encodedNormal / 255.) - 1.;\n    vec3 n;\n    n.z = 1. - abs(nNorm.x) - abs(nNorm.y);\n    if (n.z >= 0.) {\n        n.x = nNorm.x;\n        n.y = nNorm.y;\n    } else {\n        n.x = sign(nNorm.x) - sign(nNorm.x) * sign(nNorm.y) * nNorm.y;\n        n.y = sign(nNorm.y) - sign(nNorm.y) * sign(nNorm.x) * nNorm.x;\n    }\n    return normalize(n);\n}\n#elif defined(NORMAL_SPHEREMAPPED)\n// see http://aras-p.info/texts/CompactNormalStorage.html method #4\n// or see potree's implementation in BINPointReader.cpp\nvec3 decodeSphereMappedNormal(vec2 encodedNormal) {\n    vec2 fenc = 2. * encodedNormal / 255. - 1.;\n    float f = dot(fenc,fenc);\n    float g = 2. * sqrt(1. - f);\n    vec3 n;\n    n.xy = fenc * g;\n    n.z = 1. - 2. * f;\n    return n;\n}\n#endif\n\nvoid main() {\n\n#if defined(NORMAL_OCT16)\n    vec3  normal = decodeOct16Normal(oct16Normal);\n#elif defined(NORMAL_SPHEREMAPPED)\n    vec3 normal = decodeSphereMappedNormal(sphereMappedNormal);\n#elif defined(NORMAL)\n    // nothing to do\n#else\n    // default to color\n    vec3 normal = color;\n#endif\n\n    if (picking) {\n        vColor = unique_id;\n    } else {\n        vColor.a = opacity;\n        if (applyOpacityClassication || mode == PNTS_MODE_CLASSIFICATION) {\n            vec2 uv = vec2(classification, 0.5);\n            vColor = texture2D(classificationLUT, uv);\n            vColor.a *= opacity;\n        }\n\n        if (mode == PNTS_MODE_INTENSITY) {\n            // adapt the grayscale knowing the range\n            float i = (intensity - intensityRange.x) / (intensityRange.y - intensityRange.x);\n            vColor.rgb = vec3(i, i, i);\n        } else if (mode == PNTS_MODE_NORMAL) {\n            vColor.rgb = abs(normal);\n        } else if (mode == PNTS_MODE_COLOR) {\n            // default to color mode\n            vColor.rgb = mix(color, overlayColor.rgb, overlayColor.a);\n        }\n    }\n\n    #include <begin_vertex>\n    #include <project_vertex>\n\n    if (sizeMode == PNTS_SIZE_MODE_VALUE) {\n        gl_PointSize = size;\n    } else if (sizeMode == PNTS_SIZE_MODE_ATTENUATED) {\n        gl_PointSize = size;\n        gl_PointSize *= (preSSE / -mvPosition.z);\n        gl_PointSize = clamp(gl_PointSize, minAttenuatedSize, maxAttenuatedSize);\n    }\n\n#if defined(USE_TEXTURES_PROJECTIVE)\n    #include <itowns/projective_texturing_vertex>\n#endif\n    #include <logdepthbuf_vertex>\n}\n";
/* babel-plugin-inline-import './Shader/PointsFS.glsl' */
var PointsFS = "#include <itowns/WebGL2_pars_fragment>\n#include <itowns/precision_qualifier>\n#include <logdepthbuf_pars_fragment>\n#if defined(USE_TEXTURES_PROJECTIVE)\n#include <itowns/projective_texturing_pars_fragment>\n#endif\n\nvarying vec4 vColor;\nuniform bool picking;\nuniform int shape;\n\nvoid main() {\n    #include <logdepthbuf_fragment>\n    //square shape does not require any change.\n    if (shape == PNTS_SHAPE_CIRCLE) {\n        //circular rendering in glsl\n        if ((length(gl_PointCoord - 0.5) > 0.5) || (vColor.a == 0.0)) {\n            discard;\n        }\n    }\n\n#if defined(USE_TEXTURES_PROJECTIVE)\n    vec4 color = vColor;\n    if (!picking) {\n        #pragma unroll_loop\n        for (int i = 0; i < ORIENTED_IMAGES_COUNT; i++) {\n            color = projectiveTextureColor(projectiveTextureCoords[ ORIENTED_IMAGES_COUNT - 1 - i ], projectiveTextureDistortion[ ORIENTED_IMAGES_COUNT - 1 - i ], projectiveTexture[ ORIENTED_IMAGES_COUNT - 1 - i ], mask[ORIENTED_IMAGES_COUNT - 1 - i], color);\n        }\n        gl_FragColor = vec4(color.rgb, color.a * opacity);\n    } else {\n        gl_FragColor = color;\n    }\n#else\n    gl_FragColor = vColor;\n#endif\n}\n";
var PNTS_MODE = {
  COLOR: 0,
  INTENSITY: 1,
  CLASSIFICATION: 2,
  NORMAL: 3
};
exports.PNTS_MODE = PNTS_MODE;
var PNTS_SHAPE = {
  CIRCLE: 0,
  SQUARE: 1
};
exports.PNTS_SHAPE = PNTS_SHAPE;
var PNTS_SIZE_MODE = {
  VALUE: 0,
  ATTENUATED: 1
};
exports.PNTS_SIZE_MODE = PNTS_SIZE_MODE;
var white = new THREE.Color(1.0, 1.0, 1.0);

/**
 * Every lidar point can have a classification assigned to it that defines
 * the type of object that has reflected the laser pulse. Lidar points can be
 * classified into a number of categories including bare earth or ground,
 * top of canopy, and water. The different classes are defined using numeric
 * integer codes in the files.
 *
 * @property {object} category - category classification,
 * @property {boolean} category.visible - category visibility,
 * @property {string} category.name - category name,
 * @property {THREE.Color} category.color - category color,
 * @property {number} category.opacity - category opacity,
 */
// eslint-disable-next-line
var /* istanbul ignore next */Classification = /*#__PURE__*/(0, _createClass2["default"])(function Classification() {
  (0, _classCallCheck2["default"])(this, Classification);
});
var ClassificationScheme = {
  DEFAULT: {
    0: {
      visible: true,
      name: 'never classified',
      color: new THREE.Color(0.5, 0.5, 0.5),
      opacity: 1.0
    },
    1: {
      visible: true,
      name: 'unclassified',
      color: new THREE.Color(0.5, 0.5, 0.5),
      opacity: 1.0
    },
    2: {
      visible: true,
      name: 'ground',
      color: new THREE.Color(0.63, 0.32, 0.18),
      opacity: 1.0
    },
    3: {
      visible: true,
      name: 'low vegetation',
      color: new THREE.Color(0.0, 1.0, 0.0),
      opacity: 1.0
    },
    4: {
      visible: true,
      name: 'medium vegetation',
      color: new THREE.Color(0.0, 0.8, 0.0),
      opacity: 1.0
    },
    5: {
      visible: true,
      name: 'high vegetation',
      color: new THREE.Color(0.0, 0.6, 0.0),
      opacity: 1.0
    },
    6: {
      visible: true,
      name: 'building',
      color: new THREE.Color(1.0, 0.66, 0.0),
      opacity: 1.0
    },
    7: {
      visible: true,
      name: 'low point(noise)',
      color: new THREE.Color(1.0, 0.0, 1.0),
      opacity: 1.0
    },
    8: {
      visible: true,
      name: 'key-point',
      color: new THREE.Color(1.0, 0.0, 0.0),
      opacity: 1.0
    },
    9: {
      visible: true,
      name: 'water',
      color: new THREE.Color(0.0, 0.0, 1.0),
      opacity: 1.0
    },
    10: {
      visible: true,
      name: 'rail',
      color: new THREE.Color(0.8, 0.8, 1.0),
      opacity: 1.0
    },
    11: {
      visible: true,
      name: 'road Surface',
      color: new THREE.Color(0.4, 0.4, 0.7),
      opacity: 1.0
    },
    12: {
      visible: true,
      name: 'overlap',
      color: new THREE.Color(1.0, 1.0, 0.0),
      opacity: 1.0
    },
    DEFAULT: {
      visible: true,
      name: 'default',
      color: new THREE.Color(0.3, 0.6, 0.6),
      opacity: 0.5
    }
  }
};
exports.ClassificationScheme = ClassificationScheme;
var PointsMaterial = /*#__PURE__*/function (_THREE$RawShaderMater) {
  (0, _inherits2["default"])(PointsMaterial, _THREE$RawShaderMater);
  var _super = _createSuper(PointsMaterial);
  /**
   * @class      PointsMaterial
   * @param      {object}  [options={}]  The options
   * @param      {number}  [options.size=0]  size point
   * @param      {number}  [options.mode=PNTS_MODE.COLOR]  display mode.
   * @param      {number}  [options.mode=PNTS_SHAPE.CIRCLE]  rendered points shape.
   * @param      {THREE.Vector4}  [options.overlayColor=new THREE.Vector4(0, 0, 0, 0)]  overlay color.
   * @param      {THREE.Vector2}  [options.intensityRange=new THREE.Vector2(0, 1)]  intensity range.
   * @param      {boolean}  [options.applyOpacityClassication=false]  apply opacity classification on all display mode.
   * @param      {Classification}  [options.classification] -  define points classification.
   * @param      {number}  [options.sizeMode=PNTS_SIZE_MODE.VALUE]  point cloud size mode. Only 'VALUE' or 'ATTENUATED' are possible. VALUE use constant size, ATTENUATED compute size depending on distance from point to camera.
   * @param      {number}  [options.minAttenuatedSize=3]  minimum scale used by 'ATTENUATED' size mode
   * @param      {number}  [options.maxAttenuatedSize=10]  maximum scale used by 'ATTENUATED' size mode
   * @property {Classification}  classification - points classification.
   *
   * @example
   * // change color category classification
   * const pointMaterial = new PointsMaterial();
   * pointMaterial.classification[3].color.setStyle('red');
   * pointMaterial.recomputeClassification();
   */
  function PointsMaterial() {
    var _this;
    var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
    (0, _classCallCheck2["default"])(this, PointsMaterial);
    var intensityRange = options.intensityRange || new THREE.Vector2(0, 1);
    var oiMaterial = options.orientedImageMaterial;
    var classification = options.classification || ClassificationScheme.DEFAULT;
    var applyOpacityClassication = options.applyOpacityClassication == undefined ? false : options.applyOpacityClassication;
    var size = options.size || 0;
    var mode = options.mode || PNTS_MODE.COLOR;
    var shape = options.shape || PNTS_SHAPE.CIRCLE;
    var sizeMode = size === 0 ? PNTS_SIZE_MODE.ATTENUATED : options.sizeMode || PNTS_SIZE_MODE.VALUE;
    var minAttenuatedSize = options.minAttenuatedSize || 3;
    var maxAttenuatedSize = options.maxAttenuatedSize || 10;
    delete options.orientedImageMaterial;
    delete options.intensityRange;
    delete options.classification;
    delete options.applyOpacityClassication;
    delete options.size;
    delete options.mode;
    delete options.shape;
    delete options.sizeMode;
    delete options.minAttenuatedSize;
    delete options.maxAttenuatedSize;
    _this = _super.call(this, options);
    _this.vertexShader = PointsVS;
    _this.scale = options.scale || 0.05 * 0.5 / Math.tan(1.0 / 2.0); // autosizing scale

    _CommonMaterial["default"].setDefineMapping((0, _assertThisInitialized2["default"])(_this), 'PNTS_MODE', PNTS_MODE);
    _CommonMaterial["default"].setDefineMapping((0, _assertThisInitialized2["default"])(_this), 'PNTS_SHAPE', PNTS_SHAPE);
    _CommonMaterial["default"].setDefineMapping((0, _assertThisInitialized2["default"])(_this), 'PNTS_SIZE_MODE', PNTS_SIZE_MODE);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'size', size);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'mode', mode);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'shape', shape);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'picking', false);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'opacity', _this.opacity);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'overlayColor', options.overlayColor || new THREE.Vector4(0, 0, 0, 0));
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'intensityRange', intensityRange);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'applyOpacityClassication', applyOpacityClassication);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'sizeMode', sizeMode);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'preSSE', 1.0);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'minAttenuatedSize', minAttenuatedSize);
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'maxAttenuatedSize', maxAttenuatedSize);

    // add classification texture to apply classification lut.
    var data = new Uint8Array(256 * 4);
    var texture = new THREE.DataTexture(data, 256, 1, THREE.RGBAFormat);
    texture.needsUpdate = true;
    texture.magFilter = THREE.NearestFilter;
    _CommonMaterial["default"].setUniformProperty((0, _assertThisInitialized2["default"])(_this), 'classificationLUT', texture);

    // Classification scheme
    _this.classification = classification;

    // Update classification
    _this.recomputeClassification();
    if (oiMaterial) {
      _this.uniforms.projectiveTextureAlphaBorder = oiMaterial.uniforms.projectiveTextureAlphaBorder;
      _this.uniforms.projectiveTextureDistortion = oiMaterial.uniforms.projectiveTextureDistortion;
      _this.uniforms.projectiveTextureMatrix = oiMaterial.uniforms.projectiveTextureMatrix;
      _this.uniforms.projectiveTexture = oiMaterial.uniforms.projectiveTexture;
      _this.uniforms.mask = oiMaterial.uniforms.mask;
      _this.uniforms.boostLight = oiMaterial.uniforms.boostLight;
      _this.defines.ORIENTED_IMAGES_COUNT = oiMaterial.defines.ORIENTED_IMAGES_COUNT;
      _this.defines.USE_DISTORTION = oiMaterial.defines.USE_DISTORTION;
      _this.defines.DEBUG_ALPHA_BORDER = oiMaterial.defines.DEBUG_ALPHA_BORDER;
      _this.defines.USE_TEXTURES_PROJECTIVE = true;
      _this.defines.USE_BASE_MATERIAL = true;
      _this.fragmentShader = _ShaderUtils["default"].unrollLoops(PointsFS, _this.defines);
    } else {
      _this.fragmentShader = PointsFS;
    }
    if (_Capabilities["default"].isLogDepthBufferSupported()) {
      _this.defines.USE_LOGDEPTHBUF = 1;
      _this.defines.USE_LOGDEPTHBUF_EXT = 1;
    }
    return _this;
  }
  (0, _createClass2["default"])(PointsMaterial, [{
    key: "recomputeClassification",
    value: function recomputeClassification() {
      var classification = this.classification;
      var data = this.classificationLUT.image.data;
      var width = this.classificationLUT.image.width;
      for (var i = 0; i < width; i++) {
        var color = void 0;
        var opacity = void 0;
        var visible = true;
        if (classification[i]) {
          color = classification[i].color;
          visible = classification[i].visible;
          opacity = classification[i].opacity;
        } else if (classification[i % 32]) {
          color = classification[i % 32].color;
          visible = classification[i % 32].visible;
          opacity = classification[i % 32].opacity;
        } else if (classification.DEFAULT) {
          color = classification.DEFAULT.color;
          visible = classification.DEFAULT.visible;
          opacity = classification.DEFAULT.opacity;
        } else {
          color = white;
          opacity = 1.0;
        }
        var j = 4 * i;
        data[j + 0] = parseInt(255 * color.r, 10);
        data[j + 1] = parseInt(255 * color.g, 10);
        data[j + 2] = parseInt(255 * color.b, 10);
        data[j + 3] = visible ? parseInt(255 * opacity, 10) : 0;
      }
      this.classificationLUT.needsUpdate = true;
      this.dispatchEvent({
        type: 'material_property_changed',
        target: this
      });
    }
  }, {
    key: "onBeforeCompile",
    value: function onBeforeCompile(shader, renderer) {
      if (renderer.capabilities.isWebGL2) {
        this.defines.WEBGL2 = true;
        shader.glslVersion = '300 es';
      }
    }
  }, {
    key: "copy",
    value: function copy(source) {
      (0, _get2["default"])((0, _getPrototypeOf2["default"])(PointsMaterial.prototype), "copy", this).call(this, source);
      if (source.uniforms.projectiveTextureAlphaBorder) {
        // Don't copy oriented image because, it's a link to oriented image material.
        // It needs a reference to oriented image material.
        this.uniforms.projectiveTextureAlphaBorder = source.uniforms.projectiveTextureAlphaBorder;
        this.uniforms.projectiveTextureDistortion = source.uniforms.projectiveTextureDistortion;
        this.uniforms.projectiveTextureMatrix = source.uniforms.projectiveTextureMatrix;
        this.uniforms.projectiveTexture = source.uniforms.projectiveTexture;
        this.uniforms.mask = source.uniforms.mask;
        this.uniforms.boostLight = source.uniforms.boostLight;
      }
      return this;
    }
  }, {
    key: "enablePicking",
    value: function enablePicking(picking) {
      this.picking = picking;
      this.blending = picking ? THREE.NoBlending : THREE.NormalBlending;
    }
  }, {
    key: "update",
    value: function update(source) {
      this.visible = source.visible;
      this.opacity = source.opacity;
      this.transparent = source.transparent;
      this.size = source.size;
      this.mode = source.mode;
      this.shape = source.shape;
      this.sizeMode = source.sizeMode;
      this.minAttenuatedSize = source.minAttenuatedSize;
      this.maxAttenuatedSize = source.maxAttenuatedSize;
      this.picking = source.picking;
      this.scale = source.scale;
      this.overlayColor.copy(source.overlayColor);
      this.intensityRange.copy(source.intensityRange);
      Object.assign(this.defines, source.defines);
      return this;
    }
  }]);
  return PointsMaterial;
}(THREE.RawShaderMaterial);
var _default = PointsMaterial;
exports["default"] = _default;