(function (global, factory) {
  if (typeof define === "function" && define.amd) {
    define(["exports", "three", "../shaders/MMDToonShader.js", "../loaders/TGALoader.js", "../libs/mmdparser.module.js"], factory);
  } else if (typeof exports !== "undefined") {
    factory(exports, require("three"), require("../shaders/MMDToonShader.js"), require("../loaders/TGALoader.js"), require("../libs/mmdparser.module.js"));
  } else {
    var mod = {
      exports: {}
    };
    factory(mod.exports, global.three, global.MMDToonShader, global.TGALoader, global.mmdparserModule);
    global.MMDLoader = mod.exports;
  }
})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three, _MMDToonShader, _TGALoader, _mmdparserModule) {
  "use strict";

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

  function _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); }

  function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }

  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; }

  function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } Object.defineProperty(subClass, "prototype", { value: Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }), writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); }

  function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

  function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }

  function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }

  function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

  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; } }

  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }

  /**
   * Dependencies
   *  - mmd-parser https://github.com/takahirox/mmd-parser
   *  - TGALoader
   *  - OutlineEffect
   *
   * MMDLoader creates Three.js Objects from MMD resources as
   * PMD, PMX, VMD, and VPD files.
   *
   * PMD/PMX is a model data format, VMD is a motion data format
   * VPD is a posing data format used in MMD(Miku Miku Dance).
   *
   * MMD official site
   *  - https://sites.google.com/view/evpvp/
   *
   * PMD, VMD format (in Japanese)
   *  - http://blog.goo.ne.jp/torisu_tetosuki/e/209ad341d3ece2b1b4df24abf619d6e4
   *
   * PMX format
   *  - https://gist.github.com/felixjones/f8a06bd48f9da9a4539f
   *
   * TODO
   *  - light motion in vmd support.
   *  - SDEF support.
   *  - uv/material/bone morphing support.
   *  - more precise grant skinning support.
   *  - shadow support.
   */

  /**
   * @param {THREE.LoadingManager} manager
   */
  var MMDLoader = /*#__PURE__*/function (_Loader) {
    _inherits(MMDLoader, _Loader);

    var _super = _createSuper(MMDLoader);

    function MMDLoader(manager) {
      var _this;

      _classCallCheck(this, MMDLoader);

      _this = _super.call(this, manager);
      _this.loader = new _three.FileLoader(_this.manager);
      _this.parser = null; // lazy generation

      _this.meshBuilder = new MeshBuilder(_this.manager);
      _this.animationBuilder = new AnimationBuilder();
      return _this;
    }
    /**
     * @param {string} animationPath
     * @return {MMDLoader}
     */


    _createClass(MMDLoader, [{
      key: "setAnimationPath",
      value: function setAnimationPath(animationPath) {
        this.animationPath = animationPath;
        return this;
      } // Load MMD assets as Three.js Object

      /**
       * Loads Model file (.pmd or .pmx) as a SkinnedMesh.
       *
       * @param {string} url - url to Model(.pmd or .pmx) file
       * @param {function} onLoad
       * @param {function} onProgress
       * @param {function} onError
       */

    }, {
      key: "load",
      value: function load(url, onLoad, onProgress, onError) {
        var builder = this.meshBuilder.setCrossOrigin(this.crossOrigin); // resource path

        var resourcePath;

        if (this.resourcePath !== '') {
          resourcePath = this.resourcePath;
        } else if (this.path !== '') {
          resourcePath = this.path;
        } else {
          resourcePath = _three.LoaderUtils.extractUrlBase(url);
        }

        var modelExtension = this._extractExtension(url).toLowerCase(); // Should I detect by seeing header?


        if (modelExtension !== 'pmd' && modelExtension !== 'pmx') {
          if (onError) onError(new Error('THREE.MMDLoader: Unknown model file extension .' + modelExtension + '.'));
          return;
        }

        this[modelExtension === 'pmd' ? 'loadPMD' : 'loadPMX'](url, function (data) {
          onLoad(builder.build(data, resourcePath, onProgress, onError));
        }, onProgress, onError);
      }
      /**
       * Loads Motion file(s) (.vmd) as a AnimationClip.
       * If two or more files are specified, they'll be merged.
       *
       * @param {string|Array<string>} url - url(s) to animation(.vmd) file(s)
       * @param {SkinnedMesh|THREE.Camera} object - tracks will be fitting to this object
       * @param {function} onLoad
       * @param {function} onProgress
       * @param {function} onError
       */

    }, {
      key: "loadAnimation",
      value: function loadAnimation(url, object, onLoad, onProgress, onError) {
        var builder = this.animationBuilder;
        this.loadVMD(url, function (vmd) {
          onLoad(object.isCamera ? builder.buildCameraAnimation(vmd) : builder.build(vmd, object));
        }, onProgress, onError);
      }
      /**
       * Loads mode file and motion file(s) as an object containing
       * a SkinnedMesh and a AnimationClip.
       * Tracks of AnimationClip are fitting to the model.
       *
       * @param {string} modelUrl - url to Model(.pmd or .pmx) file
       * @param {string|Array{string}} vmdUrl - url(s) to animation(.vmd) file
       * @param {function} onLoad
       * @param {function} onProgress
       * @param {function} onError
       */

    }, {
      key: "loadWithAnimation",
      value: function loadWithAnimation(modelUrl, vmdUrl, onLoad, onProgress, onError) {
        var scope = this;
        this.load(modelUrl, function (mesh) {
          scope.loadAnimation(vmdUrl, mesh, function (animation) {
            onLoad({
              mesh: mesh,
              animation: animation
            });
          }, onProgress, onError);
        }, onProgress, onError);
      } // Load MMD assets as Object data parsed by MMDParser

      /**
       * Loads .pmd file as an Object.
       *
       * @param {string} url - url to .pmd file
       * @param {function} onLoad
       * @param {function} onProgress
       * @param {function} onError
       */

    }, {
      key: "loadPMD",
      value: function loadPMD(url, onLoad, onProgress, onError) {
        var parser = this._getParser();

        this.loader.setMimeType(undefined).setPath(this.path).setResponseType('arraybuffer').setRequestHeader(this.requestHeader).setWithCredentials(this.withCredentials).load(url, function (buffer) {
          onLoad(parser.parsePmd(buffer, true));
        }, onProgress, onError);
      }
      /**
       * Loads .pmx file as an Object.
       *
       * @param {string} url - url to .pmx file
       * @param {function} onLoad
       * @param {function} onProgress
       * @param {function} onError
       */

    }, {
      key: "loadPMX",
      value: function loadPMX(url, onLoad, onProgress, onError) {
        var parser = this._getParser();

        this.loader.setMimeType(undefined).setPath(this.path).setResponseType('arraybuffer').setRequestHeader(this.requestHeader).setWithCredentials(this.withCredentials).load(url, function (buffer) {
          onLoad(parser.parsePmx(buffer, true));
        }, onProgress, onError);
      }
      /**
       * Loads .vmd file as an Object. If two or more files are specified
       * they'll be merged.
       *
       * @param {string|Array<string>} url - url(s) to .vmd file(s)
       * @param {function} onLoad
       * @param {function} onProgress
       * @param {function} onError
       */

    }, {
      key: "loadVMD",
      value: function loadVMD(url, onLoad, onProgress, onError) {
        var urls = Array.isArray(url) ? url : [url];
        var vmds = [];
        var vmdNum = urls.length;

        var parser = this._getParser();

        this.loader.setMimeType(undefined).setPath(this.animationPath).setResponseType('arraybuffer').setRequestHeader(this.requestHeader).setWithCredentials(this.withCredentials);

        for (var i = 0, il = urls.length; i < il; i++) {
          this.loader.load(urls[i], function (buffer) {
            vmds.push(parser.parseVmd(buffer, true));
            if (vmds.length === vmdNum) onLoad(parser.mergeVmds(vmds));
          }, onProgress, onError);
        }
      }
      /**
       * Loads .vpd file as an Object.
       *
       * @param {string} url - url to .vpd file
       * @param {boolean} isUnicode
       * @param {function} onLoad
       * @param {function} onProgress
       * @param {function} onError
       */

    }, {
      key: "loadVPD",
      value: function loadVPD(url, isUnicode, onLoad, onProgress, onError) {
        var parser = this._getParser();

        this.loader.setMimeType(isUnicode ? undefined : 'text/plain; charset=shift_jis').setPath(this.animationPath).setResponseType('text').setRequestHeader(this.requestHeader).setWithCredentials(this.withCredentials).load(url, function (text) {
          onLoad(parser.parseVpd(text, true));
        }, onProgress, onError);
      } // private methods

    }, {
      key: "_extractExtension",
      value: function _extractExtension(url) {
        var index = url.lastIndexOf('.');
        return index < 0 ? '' : url.slice(index + 1);
      }
    }, {
      key: "_getParser",
      value: function _getParser() {
        if (this.parser === null) {
          if (typeof _mmdparserModule.MMDParser === 'undefined') {
            throw new Error('THREE.MMDLoader: Import MMDParser https://github.com/takahirox/mmd-parser');
          }

          this.parser = new _mmdparserModule.MMDParser.Parser(); // eslint-disable-line no-undef
        }

        return this.parser;
      }
    }]);

    return MMDLoader;
  }(_three.Loader); // Utilities

  /*
  	 * base64 encoded defalut toon textures toon00.bmp - toon10.bmp.
  	 * We don't need to request external toon image files.
  	 * This idea is from http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js
  	 */


  _exports.MMDLoader = MMDLoader;
  var DEFAULT_TOON_TEXTURES = ['data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAN0lEQVRYR+3WQREAMBACsZ5/bWiiMvgEBTt5cW37hjsBBAgQIECAwFwgyfYPCCBAgAABAgTWAh8aBHZBl14e8wAAAABJRU5ErkJggg==', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAOUlEQVRYR+3WMREAMAwDsYY/yoDI7MLwIiP40+RJklfcCCBAgAABAgTqArfb/QMCCBAgQIAAgbbAB3z/e0F3js2cAAAAAElFTkSuQmCC', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAN0lEQVRYR+3WQREAMBACsZ5/B5ilMvgEBTt5cW37hjsBBAgQIECAwFwgyfYPCCBAgAABAgTWAh81dWyx0gFwKAAAAABJRU5ErkJggg==', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAOklEQVRYR+3WoREAMAwDsWb/UQtCy9wxTOQJ/oQ8SXKKGwEECBAgQIBAXeDt7f4BAQQIECBAgEBb4AOz8Hzx7WLY4wAAAABJRU5ErkJggg==', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABPUlEQVRYR+1XwW7CMAy1+f9fZOMysSEOEweEOPRNdm3HbdOyIhAcklPrOs/PLy9RygBALxzcCDQFmgJNgaZAU6Ap0BR4PwX8gsRMVLssMRH5HcpzJEaWL7EVg9F1IHRlyqQohgVr4FGUlUcMJSjcUlDw0zvjeun70cLWmneoyf7NgBTQSniBTQQSuJAZsOnnaczjIMb5hCiuHKxokCrJfVnrctyZL0PkJAJe1HMil4nxeyi3Ypfn1kX51jpPvo/JeCNC4PhVdHdJw2XjBR8brF8PEIhNVn12AgP7uHsTBguBn53MUZCqv7Lp07Pn5k1Ro+uWmUNn7D+M57rtk7aG0Vo73xyF/fbFf0bPJjDXngnGocDTdFhygZjwUQrMNrDcmZlQT50VJ/g/UwNyHpu778+yW+/ksOz/BFo54P4AsUXMfRq7XWsAAAAASUVORK5CYII=', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACMElEQVRYR+2Xv4pTQRTGf2dubhLdICiii2KnYKHVolhauKWPoGAnNr6BD6CvIVaihYuI2i1ia0BY0MZGRHQXjZj/mSPnnskfNWiWZUlzJ5k7M2cm833nO5Mziej2DWWJRUoCpQKlAntSQCqgw39/iUWAGmh37jrRnVsKlgpiqmkoGVABA7E57fvY+pJDdgKqF6HzFCSADkDq+F6AHABtQ+UMVE5D7zXod7fFNhTEckTbj5XQgHzNN+5tQvc5NG7C6BNkp6D3EmpXHDR+dQAjFLchW3VS9rlw3JBh+B7ys5Cf9z0GW1C/7P32AyBAOAz1q4jGliIH3YPuBnSfQX4OGreTIgEYQb/pBDtPnEQ4CivXYPAWBk13oHrB54yA9QuSn2H4AcKRpEILDt0BUzj+RLR1V5EqjD66NPRBVpLcQwjHoHYJOhsQv6U4mnzmrIXJCFr4LDwm/xBUoboG9XX4cc9VKdYoSA2yk5NQLJaKDUjTBoveG3Z2TElTxwjNK4M3LEZgUdDdruvcXzKBpStgp2NPiWi3ks9ZXxIoFVi+AvHLdc9TqtjL3/aYjpPlrzOcEnK62Szhimdd7xX232zFDTgtxezOu3WNMRLjiKgjtOhHVMd1loynVHvOgjuIIJMaELEqhJAV/RCSLbWTcfPFakFgFlALTRRvx+ok6Hlp/Q+v3fmx90bMyUzaEAhmM3KvHlXTL5DxnbGf/1M8RNNACLL5MNtPxP/mypJAqcDSFfgFhpYqWUzhTEAAAAAASUVORK5CYII=', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII=', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAL0lEQVRYR+3QQREAAAzCsOFfNJPBJ1XQS9r2hsUAAQIECBAgQIAAAQIECBAgsBZ4MUx/ofm2I/kAAAAASUVORK5CYII='];
  var NON_ALPHA_CHANNEL_FORMATS = [_three.RGB_S3TC_DXT1_Format, _three.RGB_PVRTC_4BPPV1_Format, _three.RGB_PVRTC_2BPPV1_Format, _three.RGB_ETC1_Format, _three.RGB_ETC2_Format]; // Builders. They build Three.js object from Object data parsed by MMDParser.

  /**
   * @param {THREE.LoadingManager} manager
   */

  var MeshBuilder = /*#__PURE__*/function () {
    function MeshBuilder(manager) {
      _classCallCheck(this, MeshBuilder);

      this.crossOrigin = 'anonymous';
      this.geometryBuilder = new GeometryBuilder();
      this.materialBuilder = new MaterialBuilder(manager);
    }
    /**
     * @param {string} crossOrigin
     * @return {MeshBuilder}
     */


    _createClass(MeshBuilder, [{
      key: "setCrossOrigin",
      value: function setCrossOrigin(crossOrigin) {
        this.crossOrigin = crossOrigin;
        return this;
      }
      /**
       * @param {Object} data - parsed PMD/PMX data
       * @param {string} resourcePath
       * @param {function} onProgress
       * @param {function} onError
       * @return {SkinnedMesh}
       */

    }, {
      key: "build",
      value: function build(data, resourcePath, onProgress, onError) {
        var geometry = this.geometryBuilder.build(data);
        var material = this.materialBuilder.setCrossOrigin(this.crossOrigin).setResourcePath(resourcePath).build(data, geometry, onProgress, onError);
        var mesh = new _three.SkinnedMesh(geometry, material);
        var skeleton = new _three.Skeleton(initBones(mesh));
        mesh.bind(skeleton); // console.log( mesh ); // for console debug

        return mesh;
      }
    }]);

    return MeshBuilder;
  }(); // TODO: Try to remove this function


  function initBones(mesh) {
    var geometry = mesh.geometry;
    var bones = [];

    if (geometry && geometry.bones !== undefined) {
      // first, create array of 'Bone' objects from geometry data
      for (var i = 0, il = geometry.bones.length; i < il; i++) {
        var gbone = geometry.bones[i]; // create new 'Bone' object

        var bone = new _three.Bone();
        bones.push(bone); // apply values

        bone.name = gbone.name;
        bone.position.fromArray(gbone.pos);
        bone.quaternion.fromArray(gbone.rotq);
        if (gbone.scl !== undefined) bone.scale.fromArray(gbone.scl);
      } // second, create bone hierarchy


      for (var _i = 0, _il = geometry.bones.length; _i < _il; _i++) {
        var _gbone = geometry.bones[_i];

        if (_gbone.parent !== -1 && _gbone.parent !== null && bones[_gbone.parent] !== undefined) {
          // subsequent bones in the hierarchy
          bones[_gbone.parent].add(bones[_i]);
        } else {
          // topmost bone, immediate child of the skinned mesh
          mesh.add(bones[_i]);
        }
      }
    } // now the bones are part of the scene graph and children of the skinned mesh.
    // let's update the corresponding matrices


    mesh.updateMatrixWorld(true);
    return bones;
  } //


  var GeometryBuilder = /*#__PURE__*/function () {
    function GeometryBuilder() {
      _classCallCheck(this, GeometryBuilder);
    }

    _createClass(GeometryBuilder, [{
      key: "build",
      value:
      /**
       * @param {Object} data - parsed PMD/PMX data
       * @return {BufferGeometry}
       */
      function build(data) {
        // for geometry
        var positions = [];
        var uvs = [];
        var normals = [];
        var indices = [];
        var groups = [];
        var bones = [];
        var skinIndices = [];
        var skinWeights = [];
        var morphTargets = [];
        var morphPositions = [];
        var iks = [];
        var grants = [];
        var rigidBodies = [];
        var constraints = []; // for work

        var offset = 0;
        var boneTypeTable = {}; // positions, normals, uvs, skinIndices, skinWeights

        for (var i = 0; i < data.metadata.vertexCount; i++) {
          var v = data.vertices[i];

          for (var j = 0, jl = v.position.length; j < jl; j++) {
            positions.push(v.position[j]);
          }

          for (var _j = 0, _jl = v.normal.length; _j < _jl; _j++) {
            normals.push(v.normal[_j]);
          }

          for (var _j2 = 0, _jl2 = v.uv.length; _j2 < _jl2; _j2++) {
            uvs.push(v.uv[_j2]);
          }

          for (var _j3 = 0; _j3 < 4; _j3++) {
            skinIndices.push(v.skinIndices.length - 1 >= _j3 ? v.skinIndices[_j3] : 0.0);
          }

          for (var _j4 = 0; _j4 < 4; _j4++) {
            skinWeights.push(v.skinWeights.length - 1 >= _j4 ? v.skinWeights[_j4] : 0.0);
          }
        } // indices


        for (var _i2 = 0; _i2 < data.metadata.faceCount; _i2++) {
          var face = data.faces[_i2];

          for (var _j5 = 0, _jl3 = face.indices.length; _j5 < _jl3; _j5++) {
            indices.push(face.indices[_j5]);
          }
        } // groups


        for (var _i3 = 0; _i3 < data.metadata.materialCount; _i3++) {
          var material = data.materials[_i3];
          groups.push({
            offset: offset * 3,
            count: material.faceCount * 3
          });
          offset += material.faceCount;
        } // bones


        for (var _i4 = 0; _i4 < data.metadata.rigidBodyCount; _i4++) {
          var body = data.rigidBodies[_i4];
          var value = boneTypeTable[body.boneIndex]; // keeps greater number if already value is set without any special reasons

          value = value === undefined ? body.type : Math.max(body.type, value);
          boneTypeTable[body.boneIndex] = value;
        }

        for (var _i5 = 0; _i5 < data.metadata.boneCount; _i5++) {
          var boneData = data.bones[_i5];
          var bone = {
            index: _i5,
            transformationClass: boneData.transformationClass,
            parent: boneData.parentIndex,
            name: boneData.name,
            pos: boneData.position.slice(0, 3),
            rotq: [0, 0, 0, 1],
            scl: [1, 1, 1],
            rigidBodyType: boneTypeTable[_i5] !== undefined ? boneTypeTable[_i5] : -1
          };

          if (bone.parent !== -1) {
            bone.pos[0] -= data.bones[bone.parent].position[0];
            bone.pos[1] -= data.bones[bone.parent].position[1];
            bone.pos[2] -= data.bones[bone.parent].position[2];
          }

          bones.push(bone);
        } // iks
        // TODO: remove duplicated codes between PMD and PMX


        if (data.metadata.format === 'pmd') {
          for (var _i6 = 0; _i6 < data.metadata.ikCount; _i6++) {
            var ik = data.iks[_i6];
            var param = {
              target: ik.target,
              effector: ik.effector,
              iteration: ik.iteration,
              maxAngle: ik.maxAngle * 4,
              links: []
            };

            for (var _j6 = 0, _jl4 = ik.links.length; _j6 < _jl4; _j6++) {
              var link = {};
              link.index = ik.links[_j6].index;
              link.enabled = true;

              if (data.bones[link.index].name.indexOf('ひざ') >= 0) {
                link.limitation = new _three.Vector3(1.0, 0.0, 0.0);
              }

              param.links.push(link);
            }

            iks.push(param);
          }
        } else {
          for (var _i7 = 0; _i7 < data.metadata.boneCount; _i7++) {
            var _ik = data.bones[_i7].ik;
            if (_ik === undefined) continue;
            var _param = {
              target: _i7,
              effector: _ik.effector,
              iteration: _ik.iteration,
              maxAngle: _ik.maxAngle,
              links: []
            };

            for (var _j7 = 0, _jl5 = _ik.links.length; _j7 < _jl5; _j7++) {
              var _link = {};
              _link.index = _ik.links[_j7].index;
              _link.enabled = true;

              if (_ik.links[_j7].angleLimitation === 1) {
                // Revert if rotationMin/Max doesn't work well
                // link.limitation = new Vector3( 1.0, 0.0, 0.0 );
                var rotationMin = _ik.links[_j7].lowerLimitationAngle;
                var rotationMax = _ik.links[_j7].upperLimitationAngle; // Convert Left to Right coordinate by myself because
                // MMDParser doesn't convert. It's a MMDParser's bug

                var tmp1 = -rotationMax[0];
                var tmp2 = -rotationMax[1];
                rotationMax[0] = -rotationMin[0];
                rotationMax[1] = -rotationMin[1];
                rotationMin[0] = tmp1;
                rotationMin[1] = tmp2;
                _link.rotationMin = new _three.Vector3().fromArray(rotationMin);
                _link.rotationMax = new _three.Vector3().fromArray(rotationMax);
              }

              _param.links.push(_link);
            }

            iks.push(_param); // Save the reference even from bone data for efficiently
            // simulating PMX animation system

            bones[_i7].ik = _param;
          }
        } // grants


        if (data.metadata.format === 'pmx') {
          // Sort grant parameters from parents to children because
          // grant uses parent's transform that parent's grant is already applied
          // so grant should be applied in order from parents to children
          var traverse = function traverse(entry) {
            if (entry.param) {
              grants.push(entry.param); // Save the reference even from bone data for efficiently
              // simulating PMX animation system

              bones[entry.param.index].grant = entry.param;
            }

            entry.visited = true;

            for (var _i9 = 0, il = entry.children.length; _i9 < il; _i9++) {
              var child = entry.children[_i9]; // Cut off a loop if exists. (Is a grant loop invalid?)

              if (!child.visited) traverse(child);
            }
          };

          // bone index -> grant entry map
          var grantEntryMap = {};

          for (var _i8 = 0; _i8 < data.metadata.boneCount; _i8++) {
            var _boneData = data.bones[_i8];
            var grant = _boneData.grant;
            if (grant === undefined) continue;
            var _param2 = {
              index: _i8,
              parentIndex: grant.parentIndex,
              ratio: grant.ratio,
              isLocal: grant.isLocal,
              affectRotation: grant.affectRotation,
              affectPosition: grant.affectPosition,
              transformationClass: _boneData.transformationClass
            };
            grantEntryMap[_i8] = {
              parent: null,
              children: [],
              param: _param2,
              visited: false
            };
          }

          var rootEntry = {
            parent: null,
            children: [],
            param: null,
            visited: false
          }; // Build a tree representing grant hierarchy

          for (var boneIndex in grantEntryMap) {
            var grantEntry = grantEntryMap[boneIndex];
            var parentGrantEntry = grantEntryMap[grantEntry.parentIndex] || rootEntry;
            grantEntry.parent = parentGrantEntry;
            parentGrantEntry.children.push(grantEntry);
          }

          traverse(rootEntry);
        } // morph


        function updateAttributes(attribute, morph, ratio) {
          for (var _i10 = 0; _i10 < morph.elementCount; _i10++) {
            var element = morph.elements[_i10];
            var index = void 0;

            if (data.metadata.format === 'pmd') {
              index = data.morphs[0].elements[element.index].index;
            } else {
              index = element.index;
            }

            attribute.array[index * 3 + 0] += element.position[0] * ratio;
            attribute.array[index * 3 + 1] += element.position[1] * ratio;
            attribute.array[index * 3 + 2] += element.position[2] * ratio;
          }
        }

        for (var _i11 = 0; _i11 < data.metadata.morphCount; _i11++) {
          var morph = data.morphs[_i11];
          var params = {
            name: morph.name
          };
          var attribute = new _three.Float32BufferAttribute(data.metadata.vertexCount * 3, 3);
          attribute.name = morph.name;

          for (var _j8 = 0; _j8 < data.metadata.vertexCount * 3; _j8++) {
            attribute.array[_j8] = positions[_j8];
          }

          if (data.metadata.format === 'pmd') {
            if (_i11 !== 0) {
              updateAttributes(attribute, morph, 1.0);
            }
          } else {
            if (morph.type === 0) {
              // group
              for (var _j9 = 0; _j9 < morph.elementCount; _j9++) {
                var morph2 = data.morphs[morph.elements[_j9].index];
                var ratio = morph.elements[_j9].ratio;

                if (morph2.type === 1) {
                  updateAttributes(attribute, morph2, ratio);
                } else {// TODO: implement
                }
              }
            } else if (morph.type === 1) {
              // vertex
              updateAttributes(attribute, morph, 1.0);
            } else if (morph.type === 2) {// bone
              // TODO: implement
            } else if (morph.type === 3) {// uv
              // TODO: implement
            } else if (morph.type === 4) {// additional uv1
              // TODO: implement
            } else if (morph.type === 5) {// additional uv2
              // TODO: implement
            } else if (morph.type === 6) {// additional uv3
              // TODO: implement
            } else if (morph.type === 7) {// additional uv4
              // TODO: implement
            } else if (morph.type === 8) {// material
              // TODO: implement
            }
          }

          morphTargets.push(params);
          morphPositions.push(attribute);
        } // rigid bodies from rigidBodies field.


        for (var _i12 = 0; _i12 < data.metadata.rigidBodyCount; _i12++) {
          var rigidBody = data.rigidBodies[_i12];
          var _params = {};

          for (var key in rigidBody) {
            _params[key] = rigidBody[key];
          }
          /*
          	 * RigidBody position parameter in PMX seems global position
          	 * while the one in PMD seems offset from corresponding bone.
          	 * So unify being offset.
          	 */


          if (data.metadata.format === 'pmx') {
            if (_params.boneIndex !== -1) {
              var _bone = data.bones[_params.boneIndex];
              _params.position[0] -= _bone.position[0];
              _params.position[1] -= _bone.position[1];
              _params.position[2] -= _bone.position[2];
            }
          }

          rigidBodies.push(_params);
        } // constraints from constraints field.


        for (var _i13 = 0; _i13 < data.metadata.constraintCount; _i13++) {
          var constraint = data.constraints[_i13];
          var _params2 = {};

          for (var _key in constraint) {
            _params2[_key] = constraint[_key];
          }

          var bodyA = rigidBodies[_params2.rigidBodyIndex1];
          var bodyB = rigidBodies[_params2.rigidBodyIndex2]; // Refer to http://www20.atpages.jp/katwat/wp/?p=4135

          if (bodyA.type !== 0 && bodyB.type === 2) {
            if (bodyA.boneIndex !== -1 && bodyB.boneIndex !== -1 && data.bones[bodyB.boneIndex].parentIndex === bodyA.boneIndex) {
              bodyB.type = 1;
            }
          }

          constraints.push(_params2);
        } // build BufferGeometry.


        var geometry = new _three.BufferGeometry();
        geometry.setAttribute('position', new _three.Float32BufferAttribute(positions, 3));
        geometry.setAttribute('normal', new _three.Float32BufferAttribute(normals, 3));
        geometry.setAttribute('uv', new _three.Float32BufferAttribute(uvs, 2));
        geometry.setAttribute('skinIndex', new _three.Uint16BufferAttribute(skinIndices, 4));
        geometry.setAttribute('skinWeight', new _three.Float32BufferAttribute(skinWeights, 4));
        geometry.setIndex(indices);

        for (var _i14 = 0, il = groups.length; _i14 < il; _i14++) {
          geometry.addGroup(groups[_i14].offset, groups[_i14].count, _i14);
        }

        geometry.bones = bones;
        geometry.morphTargets = morphTargets;
        geometry.morphAttributes.position = morphPositions;
        geometry.morphTargetsRelative = false;
        geometry.userData.MMD = {
          bones: bones,
          iks: iks,
          grants: grants,
          rigidBodies: rigidBodies,
          constraints: constraints,
          format: data.metadata.format
        };
        geometry.computeBoundingSphere();
        return geometry;
      }
    }]);

    return GeometryBuilder;
  }(); //

  /**
   * @param {THREE.LoadingManager} manager
   */


  var MaterialBuilder = /*#__PURE__*/function () {
    function MaterialBuilder(manager) {
      _classCallCheck(this, MaterialBuilder);

      this.manager = manager;
      this.textureLoader = new _three.TextureLoader(this.manager);
      this.tgaLoader = null; // lazy generation

      this.crossOrigin = 'anonymous';
      this.resourcePath = undefined;
    }
    /**
     * @param {string} crossOrigin
     * @return {MaterialBuilder}
     */


    _createClass(MaterialBuilder, [{
      key: "setCrossOrigin",
      value: function setCrossOrigin(crossOrigin) {
        this.crossOrigin = crossOrigin;
        return this;
      }
      /**
       * @param {string} resourcePath
       * @return {MaterialBuilder}
       */

    }, {
      key: "setResourcePath",
      value: function setResourcePath(resourcePath) {
        this.resourcePath = resourcePath;
        return this;
      }
      /**
       * @param {Object} data - parsed PMD/PMX data
       * @param {BufferGeometry} geometry - some properties are dependend on geometry
       * @param {function} onProgress
       * @param {function} onError
       * @return {Array<MMDToonMaterial>}
       */

    }, {
      key: "build",
      value: function build(data, geometry
      /*, onProgress, onError */
      ) {
        var materials = [];
        var textures = {};
        this.textureLoader.setCrossOrigin(this.crossOrigin); // materials

        for (var i = 0; i < data.metadata.materialCount; i++) {
          var material = data.materials[i];
          var params = {
            userData: {
              MMD: {}
            }
          };
          if (material.name !== undefined) params.name = material.name;
          /*
          	 * Color
          	 *
          	 * MMD         MMDToonMaterial
          	 * ambient  -  emissive * a
          	 *               (a = 1.0 without map texture or 0.2 with map texture)
          	 *
          	 * MMDToonMaterial doesn't have ambient. Set it to emissive instead.
          	 * It'll be too bright if material has map texture so using coef 0.2.
          	 */

          params.diffuse = new _three.Color().fromArray(material.diffuse);
          params.opacity = material.diffuse[3];
          params.specular = new _three.Color().fromArray(material.specular);
          params.shininess = material.shininess;
          params.emissive = new _three.Color().fromArray(material.ambient);
          params.transparent = params.opacity !== 1.0; //

          params.fog = true; // blend

          params.blending = _three.CustomBlending;
          params.blendSrc = _three.SrcAlphaFactor;
          params.blendDst = _three.OneMinusSrcAlphaFactor;
          params.blendSrcAlpha = _three.SrcAlphaFactor;
          params.blendDstAlpha = _three.DstAlphaFactor; // side

          if (data.metadata.format === 'pmx' && (material.flag & 0x1) === 1) {
            params.side = _three.DoubleSide;
          } else {
            params.side = params.opacity === 1.0 ? _three.FrontSide : _three.DoubleSide;
          }

          if (data.metadata.format === 'pmd') {
            // map, envMap
            if (material.fileName) {
              var fileName = material.fileName;
              var fileNames = fileName.split('*'); // fileNames[ 0 ]: mapFileName
              // fileNames[ 1 ]: envMapFileName( optional )

              params.map = this._loadTexture(fileNames[0], textures);

              if (fileNames.length > 1) {
                var extension = fileNames[1].slice(-4).toLowerCase();
                params.envMap = this._loadTexture(fileNames[1], textures);
                params.combine = extension === '.sph' ? _three.MultiplyOperation : _three.AddOperation;
              }
            } // gradientMap


            var toonFileName = material.toonIndex === -1 ? 'toon00.bmp' : data.toonTextures[material.toonIndex].fileName;
            params.gradientMap = this._loadTexture(toonFileName, textures, {
              isToonTexture: true,
              isDefaultToonTexture: this._isDefaultToonTexture(toonFileName)
            }); // parameters for OutlineEffect

            params.userData.outlineParameters = {
              thickness: material.edgeFlag === 1 ? 0.003 : 0.0,
              color: [0, 0, 0],
              alpha: 1.0,
              visible: material.edgeFlag === 1
            };
          } else {
            // map
            if (material.textureIndex !== -1) {
              params.map = this._loadTexture(data.textures[material.textureIndex], textures); // Since PMX spec don't have standard to list map files except color map and env map,
              // we need to save file name for further mapping, like matching normal map file names after model loaded.
              // ref: https://gist.github.com/felixjones/f8a06bd48f9da9a4539f#texture

              params.userData.MMD.mapFileName = data.textures[material.textureIndex];
            } // envMap TODO: support m.envFlag === 3


            if (material.envTextureIndex !== -1 && (material.envFlag === 1 || material.envFlag == 2)) {
              params.matcap = this._loadTexture(data.textures[material.envTextureIndex], textures); // Same as color map above, keep file name in userData for further usage.

              params.userData.MMD.matcapFileName = data.textures[material.envTextureIndex];
              params.matcapCombine = material.envFlag === 1 ? _three.MultiplyOperation : _three.AddOperation;
            } // gradientMap


            var _toonFileName = void 0,
                isDefaultToon = void 0;

            if (material.toonIndex === -1 || material.toonFlag !== 0) {
              _toonFileName = 'toon' + ('0' + (material.toonIndex + 1)).slice(-2) + '.bmp';
              isDefaultToon = true;
            } else {
              _toonFileName = data.textures[material.toonIndex];
              isDefaultToon = false;
            }

            params.gradientMap = this._loadTexture(_toonFileName, textures, {
              isToonTexture: true,
              isDefaultToonTexture: isDefaultToon
            }); // parameters for OutlineEffect

            params.userData.outlineParameters = {
              thickness: material.edgeSize / 300,
              // TODO: better calculation?
              color: material.edgeColor.slice(0, 3),
              alpha: material.edgeColor[3],
              visible: (material.flag & 0x10) !== 0 && material.edgeSize > 0.0
            };
          }

          if (params.map !== undefined) {
            if (!params.transparent) {
              this._checkImageTransparency(params.map, geometry, i);
            }

            params.emissive.multiplyScalar(0.2);
          }

          materials.push(new MMDToonMaterial(params));
        }

        if (data.metadata.format === 'pmx') {
          // set transparent true if alpha morph is defined.
          var checkAlphaMorph = function checkAlphaMorph(elements, materials) {
            for (var _i15 = 0, il = elements.length; _i15 < il; _i15++) {
              var element = elements[_i15];
              if (element.index === -1) continue;
              var _material = materials[element.index];

              if (_material.opacity !== element.diffuse[3]) {
                _material.transparent = true;
              }
            }
          };

          for (var _i16 = 0, il = data.morphs.length; _i16 < il; _i16++) {
            var morph = data.morphs[_i16];
            var elements = morph.elements;

            if (morph.type === 0) {
              for (var j = 0, jl = elements.length; j < jl; j++) {
                var morph2 = data.morphs[elements[j].index];
                if (morph2.type !== 8) continue;
                checkAlphaMorph(morph2.elements, materials);
              }
            } else if (morph.type === 8) {
              checkAlphaMorph(elements, materials);
            }
          }
        }

        return materials;
      } // private methods

    }, {
      key: "_getTGALoader",
      value: function _getTGALoader() {
        if (this.tgaLoader === null) {
          if (_TGALoader.TGALoader === undefined) {
            throw new Error('THREE.MMDLoader: Import TGALoader');
          }

          this.tgaLoader = new _TGALoader.TGALoader(this.manager);
        }

        return this.tgaLoader;
      }
    }, {
      key: "_isDefaultToonTexture",
      value: function _isDefaultToonTexture(name) {
        if (name.length !== 10) return false;
        return /toon(10|0[0-9])\.bmp/.test(name);
      }
    }, {
      key: "_loadTexture",
      value: function _loadTexture(filePath, textures, params, onProgress, onError) {
        params = params || {};
        var scope = this;
        var fullPath;

        if (params.isDefaultToonTexture === true) {
          var index;

          try {
            index = parseInt(filePath.match(/toon([0-9]{2})\.bmp$/)[1]);
          } catch (e) {
            console.warn('THREE.MMDLoader: ' + filePath + ' seems like a ' + 'not right default texture path. Using toon00.bmp instead.');
            index = 0;
          }

          fullPath = DEFAULT_TOON_TEXTURES[index];
        } else {
          fullPath = this.resourcePath + filePath;
        }

        if (textures[fullPath] !== undefined) return textures[fullPath];
        var loader = this.manager.getHandler(fullPath);

        if (loader === null) {
          loader = filePath.slice(-4).toLowerCase() === '.tga' ? this._getTGALoader() : this.textureLoader;
        }

        var texture = loader.load(fullPath, function (t) {
          // MMD toon texture is Axis-Y oriented
          // but Three.js gradient map is Axis-X oriented.
          // So here replaces the toon texture image with the rotated one.
          if (params.isToonTexture === true) {
            t.image = scope._getRotatedImage(t.image);
            t.magFilter = _three.NearestFilter;
            t.minFilter = _three.NearestFilter;
          }

          t.flipY = false;
          t.wrapS = _three.RepeatWrapping;
          t.wrapT = _three.RepeatWrapping;

          for (var i = 0; i < texture.readyCallbacks.length; i++) {
            texture.readyCallbacks[i](texture);
          }

          delete texture.readyCallbacks;
        }, onProgress, onError);
        texture.readyCallbacks = [];
        textures[fullPath] = texture;
        return texture;
      }
    }, {
      key: "_getRotatedImage",
      value: function _getRotatedImage(image) {
        var canvas = document.createElement('canvas');
        var context = canvas.getContext('2d');
        var width = image.width;
        var height = image.height;
        canvas.width = width;
        canvas.height = height;
        context.clearRect(0, 0, width, height);
        context.translate(width / 2.0, height / 2.0);
        context.rotate(0.5 * Math.PI); // 90.0 * Math.PI / 180.0

        context.translate(-width / 2.0, -height / 2.0);
        context.drawImage(image, 0, 0);
        return context.getImageData(0, 0, width, height);
      } // Check if the partial image area used by the texture is transparent.

    }, {
      key: "_checkImageTransparency",
      value: function _checkImageTransparency(map, geometry, groupIndex) {
        map.readyCallbacks.push(function (texture) {
          // Is there any efficient ways?
          function createImageData(image) {
            var canvas = document.createElement('canvas');
            canvas.width = image.width;
            canvas.height = image.height;
            var context = canvas.getContext('2d');
            context.drawImage(image, 0, 0);
            return context.getImageData(0, 0, canvas.width, canvas.height);
          }

          function detectImageTransparency(image, uvs, indices) {
            var width = image.width;
            var height = image.height;
            var data = image.data;
            var threshold = 253;
            if (data.length / (width * height) !== 4) return false;

            for (var i = 0; i < indices.length; i += 3) {
              var centerUV = {
                x: 0.0,
                y: 0.0
              };

              for (var j = 0; j < 3; j++) {
                var index = indices[i * 3 + j];
                var uv = {
                  x: uvs[index * 2 + 0],
                  y: uvs[index * 2 + 1]
                };
                if (getAlphaByUv(image, uv) < threshold) return true;
                centerUV.x += uv.x;
                centerUV.y += uv.y;
              }

              centerUV.x /= 3;
              centerUV.y /= 3;
              if (getAlphaByUv(image, centerUV) < threshold) return true;
            }

            return false;
          }
          /*
          	 * This method expects
          	 *   texture.flipY = false
          	 *   texture.wrapS = RepeatWrapping
          	 *   texture.wrapT = RepeatWrapping
          	 * TODO: more precise
          	 */


          function getAlphaByUv(image, uv) {
            var width = image.width;
            var height = image.height;
            var x = Math.round(uv.x * width) % width;
            var y = Math.round(uv.y * height) % height;
            if (x < 0) x += width;
            if (y < 0) y += height;
            var index = y * width + x;
            return image.data[index * 4 + 3];
          }

          if (texture.isCompressedTexture === true) {
            if (NON_ALPHA_CHANNEL_FORMATS.includes(texture.format)) {
              map.transparent = false;
            } else {
              // any other way to check transparency of CompressedTexture?
              map.transparent = true;
            }

            return;
          }

          var imageData = texture.image.data !== undefined ? texture.image : createImageData(texture.image);
          var group = geometry.groups[groupIndex];

          if (detectImageTransparency(imageData, geometry.attributes.uv.array, geometry.index.array.slice(group.start, group.start + group.count))) {
            map.transparent = true;
          }
        });
      }
    }]);

    return MaterialBuilder;
  }(); //


  var AnimationBuilder = /*#__PURE__*/function () {
    function AnimationBuilder() {
      _classCallCheck(this, AnimationBuilder);
    }

    _createClass(AnimationBuilder, [{
      key: "build",
      value:
      /**
       * @param {Object} vmd - parsed VMD data
       * @param {SkinnedMesh} mesh - tracks will be fitting to mesh
       * @return {AnimationClip}
       */
      function build(vmd, mesh) {
        // combine skeletal and morph animations
        var tracks = this.buildSkeletalAnimation(vmd, mesh).tracks;
        var tracks2 = this.buildMorphAnimation(vmd, mesh).tracks;

        for (var i = 0, il = tracks2.length; i < il; i++) {
          tracks.push(tracks2[i]);
        }

        return new _three.AnimationClip('', -1, tracks);
      }
      /**
       * @param {Object} vmd - parsed VMD data
       * @param {SkinnedMesh} mesh - tracks will be fitting to mesh
       * @return {AnimationClip}
       */

    }, {
      key: "buildSkeletalAnimation",
      value: function buildSkeletalAnimation(vmd, mesh) {
        function pushInterpolation(array, interpolation, index) {
          array.push(interpolation[index + 0] / 127); // x1

          array.push(interpolation[index + 8] / 127); // x2

          array.push(interpolation[index + 4] / 127); // y1

          array.push(interpolation[index + 12] / 127); // y2
        }

        var tracks = [];
        var motions = {};
        var bones = mesh.skeleton.bones;
        var boneNameDictionary = {};

        for (var i = 0, il = bones.length; i < il; i++) {
          boneNameDictionary[bones[i].name] = true;
        }

        for (var _i17 = 0; _i17 < vmd.metadata.motionCount; _i17++) {
          var motion = vmd.motions[_i17];
          var boneName = motion.boneName;
          if (boneNameDictionary[boneName] === undefined) continue;
          motions[boneName] = motions[boneName] || [];
          motions[boneName].push(motion);
        }

        for (var key in motions) {
          var array = motions[key];
          array.sort(function (a, b) {
            return a.frameNum - b.frameNum;
          });
          var times = [];
          var positions = [];
          var rotations = [];
          var pInterpolations = [];
          var rInterpolations = [];
          var basePosition = mesh.skeleton.getBoneByName(key).position.toArray();

          for (var _i18 = 0, _il2 = array.length; _i18 < _il2; _i18++) {
            var time = array[_i18].frameNum / 30;
            var position = array[_i18].position;
            var rotation = array[_i18].rotation;
            var interpolation = array[_i18].interpolation;
            times.push(time);

            for (var j = 0; j < 3; j++) {
              positions.push(basePosition[j] + position[j]);
            }

            for (var _j10 = 0; _j10 < 4; _j10++) {
              rotations.push(rotation[_j10]);
            }

            for (var _j11 = 0; _j11 < 3; _j11++) {
              pushInterpolation(pInterpolations, interpolation, _j11);
            }

            pushInterpolation(rInterpolations, interpolation, 3);
          }

          var targetName = '.bones[' + key + ']';
          tracks.push(this._createTrack(targetName + '.position', _three.VectorKeyframeTrack, times, positions, pInterpolations));
          tracks.push(this._createTrack(targetName + '.quaternion', _three.QuaternionKeyframeTrack, times, rotations, rInterpolations));
        }

        return new _three.AnimationClip('', -1, tracks);
      }
      /**
       * @param {Object} vmd - parsed VMD data
       * @param {SkinnedMesh} mesh - tracks will be fitting to mesh
       * @return {AnimationClip}
       */

    }, {
      key: "buildMorphAnimation",
      value: function buildMorphAnimation(vmd, mesh) {
        var tracks = [];
        var morphs = {};
        var morphTargetDictionary = mesh.morphTargetDictionary;

        for (var i = 0; i < vmd.metadata.morphCount; i++) {
          var morph = vmd.morphs[i];
          var morphName = morph.morphName;
          if (morphTargetDictionary[morphName] === undefined) continue;
          morphs[morphName] = morphs[morphName] || [];
          morphs[morphName].push(morph);
        }

        for (var key in morphs) {
          var array = morphs[key];
          array.sort(function (a, b) {
            return a.frameNum - b.frameNum;
          });
          var times = [];
          var values = [];

          for (var _i19 = 0, il = array.length; _i19 < il; _i19++) {
            times.push(array[_i19].frameNum / 30);
            values.push(array[_i19].weight);
          }

          tracks.push(new _three.NumberKeyframeTrack('.morphTargetInfluences[' + morphTargetDictionary[key] + ']', times, values));
        }

        return new _three.AnimationClip('', -1, tracks);
      }
      /**
       * @param {Object} vmd - parsed VMD data
       * @return {AnimationClip}
       */

    }, {
      key: "buildCameraAnimation",
      value: function buildCameraAnimation(vmd) {
        function pushVector3(array, vec) {
          array.push(vec.x);
          array.push(vec.y);
          array.push(vec.z);
        }

        function pushQuaternion(array, q) {
          array.push(q.x);
          array.push(q.y);
          array.push(q.z);
          array.push(q.w);
        }

        function pushInterpolation(array, interpolation, index) {
          array.push(interpolation[index * 4 + 0] / 127); // x1

          array.push(interpolation[index * 4 + 1] / 127); // x2

          array.push(interpolation[index * 4 + 2] / 127); // y1

          array.push(interpolation[index * 4 + 3] / 127); // y2
        }

        var cameras = vmd.cameras === undefined ? [] : vmd.cameras.slice();
        cameras.sort(function (a, b) {
          return a.frameNum - b.frameNum;
        });
        var times = [];
        var centers = [];
        var quaternions = [];
        var positions = [];
        var fovs = [];
        var cInterpolations = [];
        var qInterpolations = [];
        var pInterpolations = [];
        var fInterpolations = [];
        var quaternion = new _three.Quaternion();
        var euler = new _three.Euler();
        var position = new _three.Vector3();
        var center = new _three.Vector3();

        for (var i = 0, il = cameras.length; i < il; i++) {
          var motion = cameras[i];
          var time = motion.frameNum / 30;
          var pos = motion.position;
          var rot = motion.rotation;
          var distance = motion.distance;
          var fov = motion.fov;
          var interpolation = motion.interpolation;
          times.push(time);
          position.set(0, 0, -distance);
          center.set(pos[0], pos[1], pos[2]);
          euler.set(-rot[0], -rot[1], -rot[2]);
          quaternion.setFromEuler(euler);
          position.add(center);
          position.applyQuaternion(quaternion);
          pushVector3(centers, center);
          pushQuaternion(quaternions, quaternion);
          pushVector3(positions, position);
          fovs.push(fov);

          for (var j = 0; j < 3; j++) {
            pushInterpolation(cInterpolations, interpolation, j);
          }

          pushInterpolation(qInterpolations, interpolation, 3); // use the same parameter for x, y, z axis.

          for (var _j12 = 0; _j12 < 3; _j12++) {
            pushInterpolation(pInterpolations, interpolation, 4);
          }

          pushInterpolation(fInterpolations, interpolation, 5);
        }

        var tracks = []; // I expect an object whose name 'target' exists under THREE.Camera

        tracks.push(this._createTrack('target.position', _three.VectorKeyframeTrack, times, centers, cInterpolations));
        tracks.push(this._createTrack('.quaternion', _three.QuaternionKeyframeTrack, times, quaternions, qInterpolations));
        tracks.push(this._createTrack('.position', _three.VectorKeyframeTrack, times, positions, pInterpolations));
        tracks.push(this._createTrack('.fov', _three.NumberKeyframeTrack, times, fovs, fInterpolations));
        return new _three.AnimationClip('', -1, tracks);
      } // private method

    }, {
      key: "_createTrack",
      value: function _createTrack(node, typedKeyframeTrack, times, values, interpolations) {
        /*
        	 * optimizes here not to let KeyframeTrackPrototype optimize
        	 * because KeyframeTrackPrototype optimizes times and values but
        	 * doesn't optimize interpolations.
        	 */
        if (times.length > 2) {
          times = times.slice();
          values = values.slice();
          interpolations = interpolations.slice();
          var stride = values.length / times.length;
          var interpolateStride = interpolations.length / times.length;
          var index = 1;

          for (var aheadIndex = 2, endIndex = times.length; aheadIndex < endIndex; aheadIndex++) {
            for (var i = 0; i < stride; i++) {
              if (values[index * stride + i] !== values[(index - 1) * stride + i] || values[index * stride + i] !== values[aheadIndex * stride + i]) {
                index++;
                break;
              }
            }

            if (aheadIndex > index) {
              times[index] = times[aheadIndex];

              for (var _i20 = 0; _i20 < stride; _i20++) {
                values[index * stride + _i20] = values[aheadIndex * stride + _i20];
              }

              for (var _i21 = 0; _i21 < interpolateStride; _i21++) {
                interpolations[index * interpolateStride + _i21] = interpolations[aheadIndex * interpolateStride + _i21];
              }
            }
          }

          times.length = index + 1;
          values.length = (index + 1) * stride;
          interpolations.length = (index + 1) * interpolateStride;
        }

        var track = new typedKeyframeTrack(node, times, values);

        track.createInterpolant = function InterpolantFactoryMethodCubicBezier(result) {
          return new CubicBezierInterpolation(this.times, this.values, this.getValueSize(), result, new Float32Array(interpolations));
        };

        return track;
      }
    }]);

    return AnimationBuilder;
  }(); // interpolation


  var CubicBezierInterpolation = /*#__PURE__*/function (_Interpolant) {
    _inherits(CubicBezierInterpolation, _Interpolant);

    var _super2 = _createSuper(CubicBezierInterpolation);

    function CubicBezierInterpolation(parameterPositions, sampleValues, sampleSize, resultBuffer, params) {
      var _this2;

      _classCallCheck(this, CubicBezierInterpolation);

      _this2 = _super2.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer);
      _this2.interpolationParams = params;
      return _this2;
    }

    _createClass(CubicBezierInterpolation, [{
      key: "interpolate_",
      value: function interpolate_(i1, t0, t, t1) {
        var result = this.resultBuffer;
        var values = this.sampleValues;
        var stride = this.valueSize;
        var params = this.interpolationParams;
        var offset1 = i1 * stride;
        var offset0 = offset1 - stride; // No interpolation if next key frame is in one frame in 30fps.
        // This is from MMD animation spec.
        // '1.5' is for precision loss. times are Float32 in Three.js Animation system.

        var weight1 = t1 - t0 < 1 / 30 * 1.5 ? 0.0 : (t - t0) / (t1 - t0);

        if (stride === 4) {
          // Quaternion
          var x1 = params[i1 * 4 + 0];
          var x2 = params[i1 * 4 + 1];
          var y1 = params[i1 * 4 + 2];
          var y2 = params[i1 * 4 + 3];

          var ratio = this._calculate(x1, x2, y1, y2, weight1);

          _three.Quaternion.slerpFlat(result, 0, values, offset0, values, offset1, ratio);
        } else if (stride === 3) {
          // Vector3
          for (var i = 0; i !== stride; ++i) {
            var _x = params[i1 * 12 + i * 4 + 0];
            var _x2 = params[i1 * 12 + i * 4 + 1];
            var _y = params[i1 * 12 + i * 4 + 2];
            var _y2 = params[i1 * 12 + i * 4 + 3];

            var _ratio = this._calculate(_x, _x2, _y, _y2, weight1);

            result[i] = values[offset0 + i] * (1 - _ratio) + values[offset1 + i] * _ratio;
          }
        } else {
          // Number
          var _x3 = params[i1 * 4 + 0];
          var _x4 = params[i1 * 4 + 1];
          var _y3 = params[i1 * 4 + 2];
          var _y4 = params[i1 * 4 + 3];

          var _ratio2 = this._calculate(_x3, _x4, _y3, _y4, weight1);

          result[0] = values[offset0] * (1 - _ratio2) + values[offset1] * _ratio2;
        }

        return result;
      }
    }, {
      key: "_calculate",
      value: function _calculate(x1, x2, y1, y2, x) {
        /*
        	 * Cubic Bezier curves
        	 *   https://en.wikipedia.org/wiki/B%C3%A9zier_curve#Cubic_B.C3.A9zier_curves
        	 *
        	 * B(t) = ( 1 - t ) ^ 3 * P0
        	 *      + 3 * ( 1 - t ) ^ 2 * t * P1
        	 *      + 3 * ( 1 - t ) * t^2 * P2
        	 *      + t ^ 3 * P3
        	 *      ( 0 <= t <= 1 )
        	 *
        	 * MMD uses Cubic Bezier curves for bone and camera animation interpolation.
        	 *   http://d.hatena.ne.jp/edvakf/20111016/1318716097
        	 *
        	 *    x = ( 1 - t ) ^ 3 * x0
        	 *      + 3 * ( 1 - t ) ^ 2 * t * x1
        	 *      + 3 * ( 1 - t ) * t^2 * x2
        	 *      + t ^ 3 * x3
        	 *    y = ( 1 - t ) ^ 3 * y0
        	 *      + 3 * ( 1 - t ) ^ 2 * t * y1
        	 *      + 3 * ( 1 - t ) * t^2 * y2
        	 *      + t ^ 3 * y3
        	 *      ( x0 = 0, y0 = 0 )
        	 *      ( x3 = 1, y3 = 1 )
        	 *      ( 0 <= t, x1, x2, y1, y2 <= 1 )
        	 *
        	 * Here solves this equation with Bisection method,
        	 *   https://en.wikipedia.org/wiki/Bisection_method
        	 * gets t, and then calculate y.
        	 *
        	 * f(t) = 3 * ( 1 - t ) ^ 2 * t * x1
        	 *      + 3 * ( 1 - t ) * t^2 * x2
        	 *      + t ^ 3 - x = 0
        	 *
        	 * (Another option: Newton's method
        	 *    https://en.wikipedia.org/wiki/Newton%27s_method)
        	 */
        var c = 0.5;
        var t = c;
        var s = 1.0 - t;
        var loop = 15;
        var eps = 1e-5;
        var math = Math;
        var sst3, stt3, ttt;

        for (var i = 0; i < loop; i++) {
          sst3 = 3.0 * s * s * t;
          stt3 = 3.0 * s * t * t;
          ttt = t * t * t;
          var ft = sst3 * x1 + stt3 * x2 + ttt - x;
          if (math.abs(ft) < eps) break;
          c /= 2.0;
          t += ft < 0 ? c : -c;
          s = 1.0 - t;
        }

        return sst3 * y1 + stt3 * y2 + ttt;
      }
    }]);

    return CubicBezierInterpolation;
  }(_three.Interpolant);

  var MMDToonMaterial = /*#__PURE__*/function (_ShaderMaterial) {
    _inherits(MMDToonMaterial, _ShaderMaterial);

    var _super3 = _createSuper(MMDToonMaterial);

    function MMDToonMaterial(parameters) {
      var _this3;

      _classCallCheck(this, MMDToonMaterial);

      _this3 = _super3.call(this);
      _this3._matcapCombine = _three.AddOperation;
      _this3.emissiveIntensity = 1.0;
      _this3.normalMapType = _three.TangentSpaceNormalMap;
      _this3.combine = _three.MultiplyOperation;
      _this3.wireframeLinecap = 'round';
      _this3.wireframeLinejoin = 'round';
      _this3.flatShading = false;
      _this3.lights = true;
      _this3.vertexShader = _MMDToonShader.MMDToonShader.vertexShader;
      _this3.fragmentShader = _MMDToonShader.MMDToonShader.fragmentShader;
      _this3.defines = Object.assign({}, _MMDToonShader.MMDToonShader.defines);
      Object.defineProperty(_assertThisInitialized(_this3), 'matcapCombine', {
        get: function get() {
          return this._matcapCombine;
        },
        set: function set(value) {
          this._matcapCombine = value;

          switch (value) {
            case _three.MultiplyOperation:
              this.defines.MATCAP_BLENDING_MULTIPLY = true;
              delete this.defines.MATCAP_BLENDING_ADD;
              break;

            default:
            case _three.AddOperation:
              this.defines.MATCAP_BLENDING_ADD = true;
              delete this.defines.MATCAP_BLENDING_MULTIPLY;
              break;
          }
        }
      });
      _this3.uniforms = _three.UniformsUtils.clone(_MMDToonShader.MMDToonShader.uniforms); // merged from MeshToon/Phong/MatcapMaterial

      var exposePropertyNames = ['specular', 'shininess', 'opacity', 'diffuse', 'map', 'matcap', 'gradientMap', 'lightMap', 'lightMapIntensity', 'aoMap', 'aoMapIntensity', 'emissive', 'emissiveMap', 'bumpMap', 'bumpScale', 'normalMap', 'normalScale', 'displacemantBias', 'displacemantMap', 'displacemantScale', 'specularMap', 'alphaMap', 'envMap', 'reflectivity', 'refractionRatio'];

      var _loop = function _loop() {
        var propertyName = _exposePropertyNames[_i22];
        Object.defineProperty(_assertThisInitialized(_this3), propertyName, {
          get: function get() {
            return this.uniforms[propertyName].value;
          },
          set: function set(value) {
            this.uniforms[propertyName].value = value;
          }
        });
      };

      for (var _i22 = 0, _exposePropertyNames = exposePropertyNames; _i22 < _exposePropertyNames.length; _i22++) {
        _loop();
      }

      Object.defineProperty(_assertThisInitialized(_this3), 'color', Object.getOwnPropertyDescriptor(_assertThisInitialized(_this3), 'diffuse'));

      _this3.setValues(parameters);

      return _this3;
    }

    _createClass(MMDToonMaterial, [{
      key: "copy",
      value: function copy(source) {
        _get(_getPrototypeOf(MMDToonMaterial.prototype), "copy", this).call(this, source);

        this.matcapCombine = source.matcapCombine;
        this.emissiveIntensity = source.emissiveIntensity;
        this.normalMapType = source.normalMapType;
        this.combine = source.combine;
        this.wireframeLinecap = source.wireframeLinecap;
        this.wireframeLinejoin = source.wireframeLinejoin;
        this.flatShading = source.flatShading;
        return this;
      }
    }]);

    return MMDToonMaterial;
  }(_three.ShaderMaterial);

  MMDToonMaterial.prototype.isMMDToonMaterial = true;
});