import { Texture } from "../../../../../../three@0.154.0/node_modules/three/build/three.module.js";
import { clone } from "../../../../../../three@0.154.0/node_modules/three/examples/jsm/utils/SkeletonUtils.js";
/* @license
 * Copyright 2020 Google LLC. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
const $prepared = Symbol("prepared");
const $prepare = Symbol("prepare");
const $preparedGLTF = Symbol("preparedGLTF");
const $clone = Symbol("clone");
class GLTFInstance {
  constructor(preparedGLTF) {
    this[$preparedGLTF] = preparedGLTF;
  }
  /**
   * Prepares a given GLTF for presentation and future cloning. A GLTF that is
   * prepared can safely have this method invoked on it multiple times; it will
   * only be prepared once, including after being cloned.
   */
  static prepare(source) {
    if (source.scene == null) {
      throw new Error("Model does not have a scene");
    }
    if (source[$prepared]) {
      return source;
    }
    const prepared = this[$prepare](source);
    prepared[$prepared] = true;
    return prepared;
  }
  /**
   * Override in an inheriting class to apply specialty one-time preparations
   * for a given input GLTF.
   */
  static [$prepare](source) {
    const { scene } = source;
    const scenes = [scene];
    return Object.assign(Object.assign({}, source), { scene, scenes });
  }
  get parser() {
    return this[$preparedGLTF].parser;
  }
  get animations() {
    return this[$preparedGLTF].animations;
  }
  get scene() {
    return this[$preparedGLTF].scene;
  }
  get scenes() {
    return this[$preparedGLTF].scenes;
  }
  get cameras() {
    return this[$preparedGLTF].cameras;
  }
  get asset() {
    return this[$preparedGLTF].asset;
  }
  get userData() {
    return this[$preparedGLTF].userData;
  }
  /**
   * Creates and returns a copy of this instance.
   */
  clone() {
    const GLTFInstanceConstructor = this.constructor;
    const clonedGLTF = this[$clone]();
    return new GLTFInstanceConstructor(clonedGLTF);
  }
  /**
   * Cleans up any retained memory that might not otherwise be released when
   * this instance is done being used.
   */
  dispose() {
    this.scenes.forEach((scene) => {
      scene.traverse((object) => {
        const mesh = object;
        if (!mesh.material) {
          return;
        }
        const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
        materials.forEach((material) => {
          for (const propertyName in material) {
            const texture = material[propertyName];
            if (texture instanceof Texture) {
              const image = texture.source.data;
              if (image.close != null) {
                image.close();
              }
              texture.dispose();
            }
          }
          material.dispose();
        });
        mesh.geometry.dispose();
      });
    });
  }
  /**
   * Override in an inheriting class to implement specialized cloning strategies
   */
  [$clone]() {
    const source = this[$preparedGLTF];
    const scene = clone(this.scene);
    cloneVariantMaterials(scene, this.scene);
    const scenes = [scene];
    const userData = source.userData ? Object.assign({}, source.userData) : {};
    return Object.assign(Object.assign({}, source), { scene, scenes, userData });
  }
}
const cloneVariantMaterials = (dst, src) => {
  traversePair(dst, src, (dst2, src2) => {
    if (src2.userData.variantMaterials !== void 0) {
      dst2.userData.variantMaterials = new Map(src2.userData.variantMaterials);
    }
    if (src2.userData.variantData !== void 0) {
      dst2.userData.variantData = src2.userData.variantData;
    }
    if (src2.userData.originalMaterial !== void 0) {
      dst2.userData.originalMaterial = src2.userData.originalMaterial;
    }
  });
};
const traversePair = (obj1, obj2, callback) => {
  callback(obj1, obj2);
  for (let i = 0; i < obj1.children.length; i++) {
    traversePair(obj1.children[i], obj2.children[i], callback);
  }
};
export {
  $clone,
  $prepare,
  $prepared,
  $preparedGLTF,
  GLTFInstance
};
//# sourceMappingURL=GLTFInstance.js.map
