(function (global, factory) {
  if (typeof define === "function" && define.amd) {
    define(["exports", "three"], factory);
  } else if (typeof exports !== "undefined") {
    factory(exports, require("three"));
  } else {
    var mod = {
      exports: {}
    };
    factory(mod.exports, global.three);
    global.RoughnessMipmapper = mod.exports;
  }
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three) {
  "use strict";

  Object.defineProperty(_exports, "__esModule", {
    value: true
  });
  _exports.RoughnessMipmapper = void 0;

  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } }

  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }

  var _mipmapMaterial = _getMipmapMaterial();

  var _mesh = new _three.Mesh(new _three.PlaneGeometry(2, 2), _mipmapMaterial);

  var _flatCamera = new _three.OrthographicCamera(0, 1, 0, 1, 0, 1);

  var _tempTarget = null;
  var _renderer = null;

  var RoughnessMipmapper = /*#__PURE__*/function () {
    function RoughnessMipmapper(renderer) {
      _classCallCheck(this, RoughnessMipmapper);

      _renderer = renderer;

      _renderer.compile(_mesh, _flatCamera);
    }

    _createClass(RoughnessMipmapper, [{
      key: "generateMipmaps",
      value: function generateMipmaps(material) {
        if ('roughnessMap' in material === false) return;
        var roughnessMap = material.roughnessMap,
            normalMap = material.normalMap;
        if (roughnessMap === null || normalMap === null || !roughnessMap.generateMipmaps || material.userData.roughnessUpdated) return;
        material.userData.roughnessUpdated = true;
        var width = Math.max(roughnessMap.image.width, normalMap.image.width);
        var height = Math.max(roughnessMap.image.height, normalMap.image.height);
        if (!_three.MathUtils.isPowerOfTwo(width) || !_three.MathUtils.isPowerOfTwo(height)) return;

        var oldTarget = _renderer.getRenderTarget();

        var autoClear = _renderer.autoClear;
        _renderer.autoClear = false;

        if (_tempTarget === null || _tempTarget.width !== width || _tempTarget.height !== height) {
          if (_tempTarget !== null) _tempTarget.dispose();
          _tempTarget = new _three.WebGLRenderTarget(width, height, {
            depthBuffer: false
          });
          _tempTarget.scissorTest = true;
        }

        if (width !== roughnessMap.image.width || height !== roughnessMap.image.height) {
          var params = {
            wrapS: roughnessMap.wrapS,
            wrapT: roughnessMap.wrapT,
            magFilter: roughnessMap.magFilter,
            minFilter: roughnessMap.minFilter,
            depthBuffer: false
          };
          var newRoughnessTarget = new _three.WebGLRenderTarget(width, height, params);
          newRoughnessTarget.texture.generateMipmaps = true; // Setting the render target causes the memory to be allocated.

          _renderer.setRenderTarget(newRoughnessTarget);

          material.roughnessMap = newRoughnessTarget.texture;
          if (material.metalnessMap == roughnessMap) material.metalnessMap = material.roughnessMap;
          if (material.aoMap == roughnessMap) material.aoMap = material.roughnessMap; // Copy UV transform parameters

          material.roughnessMap.offset.copy(roughnessMap.offset);
          material.roughnessMap.repeat.copy(roughnessMap.repeat);
          material.roughnessMap.center.copy(roughnessMap.center);
          material.roughnessMap.rotation = roughnessMap.rotation;
          material.roughnessMap.image = roughnessMap.image;
          material.roughnessMap.matrixAutoUpdate = roughnessMap.matrixAutoUpdate;
          material.roughnessMap.matrix.copy(roughnessMap.matrix);
        }

        _mipmapMaterial.uniforms.roughnessMap.value = roughnessMap;
        _mipmapMaterial.uniforms.normalMap.value = normalMap;
        var position = new _three.Vector2(0, 0);
        var texelSize = _mipmapMaterial.uniforms.texelSize.value;

        for (var mip = 0; width >= 1 && height >= 1; ++mip, width /= 2, height /= 2) {
          // Rendering to a mip level is not allowed in webGL1. Instead we must set
          // up a secondary texture to write the result to, then copy it back to the
          // proper mipmap level.
          texelSize.set(1.0 / width, 1.0 / height);
          if (mip == 0) texelSize.set(0.0, 0.0);

          _tempTarget.viewport.set(position.x, position.y, width, height);

          _tempTarget.scissor.set(position.x, position.y, width, height);

          _renderer.setRenderTarget(_tempTarget);

          _renderer.render(_mesh, _flatCamera);

          _renderer.copyFramebufferToTexture(position, material.roughnessMap, mip);

          _mipmapMaterial.uniforms.roughnessMap.value = material.roughnessMap;
        }

        if (roughnessMap !== material.roughnessMap) roughnessMap.dispose();

        _renderer.setRenderTarget(oldTarget);

        _renderer.autoClear = autoClear;
      }
    }, {
      key: "dispose",
      value: function dispose() {
        _mipmapMaterial.dispose();

        _mesh.geometry.dispose();

        if (_tempTarget != null) _tempTarget.dispose();
      }
    }]);

    return RoughnessMipmapper;
  }();

  _exports.RoughnessMipmapper = RoughnessMipmapper;

  function _getMipmapMaterial() {
    var shaderMaterial = new _three.RawShaderMaterial({
      uniforms: {
        roughnessMap: {
          value: null
        },
        normalMap: {
          value: null
        },
        texelSize: {
          value: new _three.Vector2(1, 1)
        }
      },
      vertexShader:
      /* glsl */
      "\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tattribute vec3 position;\n\t\t\tattribute vec2 uv;\n\n\t\t\tvarying vec2 vUv;\n\n\t\t\tvoid main() {\n\n\t\t\t\tvUv = uv;\n\n\t\t\t\tgl_Position = vec4( position, 1.0 );\n\n\t\t\t}\n\t\t",
      fragmentShader:
      /* glsl */
      "\n\t\t\tprecision mediump float;\n\t\t\tprecision mediump int;\n\n\t\t\tvarying vec2 vUv;\n\n\t\t\tuniform sampler2D roughnessMap;\n\t\t\tuniform sampler2D normalMap;\n\t\t\tuniform vec2 texelSize;\n\n\t\t\t#define ENVMAP_TYPE_CUBE_UV\n\n\t\t\tvec4 envMapTexelToLinear( vec4 a ) { return a; }\n\n\t\t\t#include <cube_uv_reflection_fragment>\n\n\t\t\tfloat roughnessToVariance( float roughness ) {\n\n\t\t\t\tfloat variance = 0.0;\n\n\t\t\t\tif ( roughness >= r1 ) {\n\n\t\t\t\t\tvariance = ( r0 - roughness ) * ( v1 - v0 ) / ( r0 - r1 ) + v0;\n\n\t\t\t\t} else if ( roughness >= r4 ) {\n\n\t\t\t\t\tvariance = ( r1 - roughness ) * ( v4 - v1 ) / ( r1 - r4 ) + v1;\n\n\t\t\t\t} else if ( roughness >= r5 ) {\n\n\t\t\t\t\tvariance = ( r4 - roughness ) * ( v5 - v4 ) / ( r4 - r5 ) + v4;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tfloat roughness2 = roughness * roughness;\n\n\t\t\t\t\tvariance = 1.79 * roughness2 * roughness2;\n\n\t\t\t\t}\n\n\t\t\t\treturn variance;\n\n\t\t\t}\n\n\t\t\tfloat varianceToRoughness( float variance ) {\n\n\t\t\t\tfloat roughness = 0.0;\n\n\t\t\t\tif ( variance >= v1 ) {\n\n\t\t\t\t\troughness = ( v0 - variance ) * ( r1 - r0 ) / ( v0 - v1 ) + r0;\n\n\t\t\t\t} else if ( variance >= v4 ) {\n\n\t\t\t\t\troughness = ( v1 - variance ) * ( r4 - r1 ) / ( v1 - v4 ) + r1;\n\n\t\t\t\t} else if ( variance >= v5 ) {\n\n\t\t\t\t\troughness = ( v4 - variance ) * ( r5 - r4 ) / ( v4 - v5 ) + r4;\n\n\t\t\t\t} else {\n\n\t\t\t\t\troughness = pow( 0.559 * variance, 0.25 ); // 0.559 = 1.0 / 1.79\n\n\t\t\t\t}\n\n\t\t\t\treturn roughness;\n\n\t\t\t}\n\n\t\t\tvoid main() {\n\n\t\t\t\tgl_FragColor = texture2D( roughnessMap, vUv, - 1.0 );\n\n\t\t\t\tif ( texelSize.x == 0.0 ) return;\n\n\t\t\t\tfloat roughness = gl_FragColor.g;\n\n\t\t\t\tfloat variance = roughnessToVariance( roughness );\n\n\t\t\t\tvec3 avgNormal;\n\n\t\t\t\tfor ( float x = - 1.0; x < 2.0; x += 2.0 ) {\n\n\t\t\t\t\tfor ( float y = - 1.0; y < 2.0; y += 2.0 ) {\n\n\t\t\t\t\t\tvec2 uv = vUv + vec2( x, y ) * 0.25 * texelSize;\n\n\t\t\t\t\t\tavgNormal += normalize( texture2D( normalMap, uv, - 1.0 ).xyz - 0.5 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tvariance += 1.0 - 0.25 * length( avgNormal );\n\n\t\t\t\tgl_FragColor.g = varianceToRoughness( variance );\n\n\t\t\t}\n\t\t",
      blending: _three.NoBlending,
      depthTest: false,
      depthWrite: false
    });
    shaderMaterial.type = 'RoughnessMipmapper';
    return shaderMaterial;
  }
});