"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
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 THREE = _interopRequireWildcard(require("three"));
var _Capabilities = _interopRequireDefault(require("../Core/System/Capabilities"));
var _ShaderUtils = _interopRequireDefault(require("./Shader/ShaderUtils"));
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/ProjectiveTextureVS.glsl' */
var textureVS = "#include <itowns/WebGL2_pars_vertex>\n#include <itowns/precision_qualifier>\n#include <itowns/project_pars_vertex>\n#include <itowns/projective_texturing_pars_vertex>\n#include <common>\n#include <logdepthbuf_pars_vertex>\n\nvarying vec3 vNormal;\nattribute vec3 normal;\n\nvoid main() {\n    #include <begin_vertex>\n    #include <project_vertex>\n    vNormal = normal;\n    #include <itowns/projective_texturing_vertex>\n    #include <logdepthbuf_vertex>\n}\n";
/* babel-plugin-inline-import './Shader/ProjectiveTextureFS.glsl' */
var textureFS = "#include <itowns/WebGL2_pars_fragment>\n#include <itowns/precision_qualifier>\n#include <logdepthbuf_pars_fragment>\n#include <itowns/projective_texturing_pars_fragment>\nvarying vec3 vNormal;\n\n#ifdef USE_BASE_MATERIAL\nstruct noPT {\n    vec3 lightDirection;\n    vec3 ambient;\n    float opacity;\n};\n\nuniform noPT noProjectiveMaterial;\n#endif\n\nvoid main(void)\n{\n    #include <logdepthbuf_fragment>\n    #ifdef USE_BASE_MATERIAL\n    float nDotVP = (max(0.1, dot(vNormal, normalize(noProjectiveMaterial.lightDirection))));\n    vec4 color = vec4(noProjectiveMaterial.ambient + nDotVP, 0.0);\n    #else\n    vec4 color = vec4(0.0);\n    #endif\n\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\n    #ifdef USE_BASE_MATERIAL\n    color.a = color.a < 1.0 ? max(noProjectiveMaterial.opacity, color.a) : 1.0 ;\n    gl_FragColor = vec4(color.rgb, color.a * opacity);\n    #else\n    gl_FragColor = vec4(color.rgb / color.a, opacity);\n    #endif\n\n}\n";
var ndcToTextureMatrix = new THREE.Matrix4(1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 2, 0, 0, 0, 0, 2);
var noMask = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1, THREE.RGBAFormat, THREE.UnsignedByteType);
noMask.needsUpdate = true;
var noTexture = new THREE.Texture();
var rawShaderMaterial = new THREE.RawShaderMaterial();
/**
 * @classdesc OrientedImageMaterial is a custom shader material used to do projective texture mapping.<br/>
 *
 * This Material is designed to project many textures simultaneously.
 * Each projected texture setting is stored as an {@link OrientedImageCamera}.<br/>
 * <br/>
 * All cameras settings, like distorsion, can be specified in a configuration file.
 * See [CameraCalibrationParser]{@link module:CameraCalibrationParser.parse}
 * used to parse a configuration file and create an array of camera.<br/>
 * <br/>
 * The current implementation supports the following distortion models : <br/>
 *  - no distortion (polynom==vec3(0),l1l2==vec2(0))<br/>
 *  - radial distortion (polynom!=vec3(0),l1l2==vec2(0)) (see <b>15.2.2 Radial Model</b> in [MicMac doc]{@link https://github.com/micmacIGN/Documentation/blob/master/DocMicMac.pdf}) </br>
 *  - equilinear fish eye distortion (polynom!=vec3(0),l1l2 != vec2(0)) (see <b>15.3.4 Fish eye models</b> in [MicMac doc]{@link https://github.com/micmacIGN/Documentation/blob/master/DocMicMac.pdf}) </br>
 * (Note: radial decentric parameters P1 are P2 not supported and assumed to be 0).<br/>
 * <br/>
 * To get a more comprehensive support of camera Micmac models, you can consider using [three-photogrammetric-camera]{@link https://github.com/mbredif/three-photogrammetric-camera} instead.
 */
var OrientedImageMaterial = /*#__PURE__*/function (_THREE$RawShaderMater) {
  (0, _inherits2["default"])(OrientedImageMaterial, _THREE$RawShaderMater);
  var _super = _createSuper(OrientedImageMaterial);
  /**
   * @constructor
   * @param { OrientedImageCamera[]} cameras - Array of {@link OrientedImageCamera}. Each camera will project a texture.
   * [CameraCalibrationParser]{@link module:CameraCalibrationParser.parse} can used to create this array of camera from a configuration file.
   * @param {Object} [options={}] - Object with one or more properties defining the material's appearance.
   * Any property of the material (including any property inherited from
   * [THREE.Material]{@link https://threejs.org/docs/#api/en/materials/Material} and
   * [THREE.ShaderMaterial]{@link https://threejs.org/docs/#api/en/materials/ShaderMaterial}) can be passed in here.
   * @param {Number} [options.side=THREE.DoubleSide] - We override default
   * [THREE.Material.side]{@link https://threejs.org/docs/#api/en/materials/Material.side} from FrontSide to DoubleSide.
   * @param {Boolean} [options.transparent=true] - We override default
   * [THREE.Material.transparent]{@link https://threejs.org/docs/#api/en/materials/Material.transparent} from false to true.
   * @param {Number} [options.opacity=0.1] - We override default
   * [THREE.Material.opacity]{@link https://threejs.org/docs/#api/en/materials/Material.opacity} from 1 to 0.1.
   * @param {Number} [options.alphaBorder=20] - Part of the texture that is blended, when texture crosses each other.
   * For example, 10 means a border as large as 1 / 10 of the size of the texture is used to blend colors.
   * @param {Number} [options.debugAlphaBorder=0] - Set this option to 1 to see influence of alphaBorder option.
   */
  function OrientedImageMaterial(cameras) {
    var _options$side, _options$transparent, _options$opacity, _options$OrientedImag;
    var _this;
    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    (0, _classCallCheck2["default"])(this, OrientedImageMaterial);
    options.side = (_options$side = options.side) !== null && _options$side !== void 0 ? _options$side : THREE.DoubleSide;
    options.transparent = (_options$transparent = options.transparent) !== null && _options$transparent !== void 0 ? _options$transparent : true;
    options.opacity = (_options$opacity = options.opacity) !== null && _options$opacity !== void 0 ? _options$opacity : 1;

    // Filter the rawShaderMaterial options
    var rawShaderMaterialOptions = {};
    for (var key in options) {
      if (Object.prototype.hasOwnProperty.call(options, key)) {
        var currentValue = rawShaderMaterial[key];
        if (currentValue !== undefined) {
          rawShaderMaterialOptions[key] = options[key];
        }
      }
    }
    _this = _super.call(this, rawShaderMaterialOptions);
    _this.defines.ORIENTED_IMAGES_COUNT = (_options$OrientedImag = options.OrientedImagesCount) !== null && _options$OrientedImag !== void 0 ? _options$OrientedImag : cameras.length;

    // verify that number of textures doesn't exceed GPU capabilities
    var maxTexturesUnits = _Capabilities["default"].getMaxTextureUnitsCount();
    if (_this.defines.ORIENTED_IMAGES_COUNT > maxTexturesUnits) {
      console.warn("OrientedImageMaterial: Can't project ".concat(cameras.length, " textures, because it's more than GPU capabilities maximum texture units (").concat(maxTexturesUnits, ")"));

      // Clamp number of textures used
      _this.defines.ORIENTED_IMAGES_COUNT = maxTexturesUnits - 1;
      console.warn("OrientedImageMaterial: We'll use only the first ".concat(_this.defines.ORIENTED_IMAGES_COUNT, " cameras."));
    }
    if (options.useBaseMaterial) {
      _this.defines.USE_BASE_MATERIAL = true;
    }
    _this.defines.USE_DISTORTION = Number(cameras.some(function (camera) {
      return camera.distortion.pps !== null;
    }));
    _this.alphaBorder = options.alphaBorder | 20;
    _this.defines.DEBUG_ALPHA_BORDER = options.debugAlphaBorder | 0;
    _this.cameras = cameras;
    var textureMatrix = [];
    var texture = [];
    var mask = [];
    var distortion = [];
    _this.group = new THREE.Group();
    for (var i = 0; i < _this.defines.ORIENTED_IMAGES_COUNT; ++i) {
      texture[i] = noTexture;
      mask[i] = noMask;
      textureMatrix[i] = new THREE.Matrix4();
      cameras[i].needsUpdate = true;
      distortion[i] = cameras[i].distortion;
      _this.group.add(cameras[i]);
    }
    _this.uniforms.opacity = new THREE.Uniform(_this.opacity);
    _this.uniforms.projectiveTextureAlphaBorder = new THREE.Uniform(_this.alphaBorder);
    _this.uniforms.projectiveTextureDistortion = new THREE.Uniform(distortion);
    _this.uniforms.projectiveTextureMatrix = new THREE.Uniform(textureMatrix);
    _this.uniforms.projectiveTexture = new THREE.Uniform(texture);
    _this.uniforms.mask = new THREE.Uniform(mask);
    _this.uniforms.boostLight = new THREE.Uniform(false);
    _this.uniforms.noProjectiveMaterial = new THREE.Uniform({
      lightDirection: new THREE.Vector3(0.5, 0.5, -0.5),
      ambient: new THREE.Color(0.1, 0.1, 0.1),
      opacity: 0.75
    });
    if (_Capabilities["default"].isLogDepthBufferSupported()) {
      _this.defines.USE_LOGDEPTHBUF = 1;
      _this.defines.USE_LOGDEPTHBUF_EXT = 1;
    }
    _this.vertexShader = textureVS;
    _this.fragmentShader = _ShaderUtils["default"].unrollLoops(textureFS, _this.defines);
    return _this;
  }
  (0, _createClass2["default"])(OrientedImageMaterial, [{
    key: "onBeforeCompile",
    value: function onBeforeCompile(shader, renderer) {
      if (renderer.capabilities.isWebGL2) {
        this.defines.WEBGL2 = true;
        shader.glslVersion = '300 es';
      }
    }

    /**
     * Set new textures and new position/orientation of the camera set.
     * @param {THREE.Texture} textures - Array of [THREE.Texture]{@link https://threejs.org/docs/#api/en/textures/Texture}.
     * @param {Object} feature - New position / orientation of the set of cameras
     * @param {Array} camerasNames - camera names of panoramic feature
     * @param {THREE.Vector3} feature.position - New position.
     * @param {THREE.Quaternion} feature.quaternion - New orientation.
     */
  }, {
    key: "setTextures",
    value: function setTextures(textures, feature, camerasNames) {
      var _this2 = this;
      if (!textures) {
        return;
      }
      this.group.position.copy(feature.position);
      this.group.quaternion.copy(feature.quaternion);
      var _loop = function _loop(i) {
        _this2.uniforms.projectiveTexture.value[i].dispose();
        _this2.uniforms.projectiveTexture.value[i] = textures[i];

        // check camera changes
        if (camerasNames) {
          var currentCamera = _this2.group.children[i];
          if (camerasNames[i] != currentCamera.name) {
            var camera = _this2.cameras.find(function (cam) {
              return cam.name === camerasNames[i];
            });
            _this2.uniforms.mask.value[i] = camera.maskTexture || noMask;
            _this2.uniforms.mask.value[i].needsUpdate = true;
            _this2.uniforms.projectiveTextureDistortion.value[i] = camera.distortion;
            _this2.group.children[i] = camera;
            camera.parent = _this2.group;
          }
        }
        _this2.group.children[i].needsUpdate = true;
      };
      for (var i = 0; i < textures.length && i < this.defines.ORIENTED_IMAGES_COUNT; ++i) {
        _loop(i);
      }
      this.group.updateMatrixWorld(true); // update the matrixWorldInverse of the cameras
    }

    /**
     * Udate the uniforms using the current value of camera.matrixWorld.
     * Need to be called when the camera of the scene has changed.
     * @param {THREE.Camera} viewCamera - Camera of the scene.
     */
  }, {
    key: "updateUniforms",
    value: function updateUniforms(viewCamera) {
      for (var i = 0; i < this.group.children.length; ++i) {
        var camera = this.group.children[i];
        if (camera.needsUpdate) {
          camera.textureMatrixWorldInverse.multiplyMatrices(ndcToTextureMatrix, camera.projectionMatrix);
          camera.textureMatrixWorldInverse.multiply(camera.matrixWorldInverse);
          camera.needsUpdate = false;
        }
        this.uniforms.projectiveTextureMatrix.value[i].multiplyMatrices(camera.textureMatrixWorldInverse, viewCamera.matrixWorld);
      }
    }
  }]);
  return OrientedImageMaterial;
}(THREE.RawShaderMaterial);
var _default = OrientedImageMaterial;
exports["default"] = _default;