import * as o from "three";
import * as l from "@mkkellogg/gaussian-splats-3d";
var a = /* @__PURE__ */ ((n) => (n.LoadStart = "gaussian-load-start", n.LoadProgress = "gaussian-load-progress", n.Loaded = "gaussian-loaded", n.LoadError = "gaussian-load-error", n.SceneRemoved = "gaussian-scene-removed", n.FpsUpdated = "gaussian-fps-updated", n.ViewChanged = "gaussian-view-changed", n))(a || {});
class c {
  listeners = /* @__PURE__ */ new Map();
  on(e, t) {
    const i = String(e);
    this.listeners.has(i) || this.listeners.set(i, []), this.listeners.get(i).push(t);
  }
  off(e, t) {
    const i = String(e), r = this.listeners.get(i);
    if (!r)
      return;
    const s = r.indexOf(t);
    s !== -1 && r.splice(s, 1), r.length === 0 && this.listeners.delete(i);
  }
  trigger(e, t) {
    const i = this.listeners.get(String(e));
    !i || i.length === 0 || [...i].forEach((r) => {
      try {
        r(t);
      } catch (s) {
        console.error(`[EventModuleGaussian] event handler failed: ${e}`, s);
      }
    });
  }
  clear() {
    this.listeners.clear();
  }
  dispose() {
    this.clear();
  }
}
class h {
  scene;
  constructor(e) {
    this.scene = new o.Scene(), e && (this.scene.background = new o.Color(e));
  }
  getScene() {
    return this.scene;
  }
  setBackgroundColor(e) {
    this.scene.background = e == null ? null : new o.Color(e);
  }
  dispose() {
    this.scene.clear(), this.scene.background = null, this.scene.environment = null;
  }
}
class u {
  camera;
  container;
  cameraUp;
  initialLookAt;
  constructor(e, t, i, r) {
    this.container = e, this.cameraUp = t, this.initialLookAt = r, this.camera = this.createCamera(i);
  }
  createCamera(e) {
    const t = Math.max(this.container.clientWidth, 1), i = Math.max(this.container.clientHeight, 1), r = new o.PerspectiveCamera(65, t / i, 0.1, 5e3);
    return r.position.fromArray(e), r.up.fromArray(this.cameraUp).normalize(), r.lookAt(new o.Vector3().fromArray(this.initialLookAt)), r.updateProjectionMatrix(), r;
  }
  getCamera() {
    return this.camera;
  }
  updateAspectRatio(e, t) {
    this.camera.aspect = Math.max(e, 1) / Math.max(t, 1), this.camera.updateProjectionMatrix();
  }
  reset(e, t) {
    e && this.camera.position.fromArray(e), this.camera.lookAt(new o.Vector3().fromArray(t ?? this.initialLookAt)), this.camera.updateMatrixWorld(!0);
  }
  dispose() {
    this.camera = null;
  }
}
class m {
  renderer;
  viewer;
  container;
  animationId = null;
  isRenderingPaused = !0;
  fpsFrameCount = 0;
  fpsLastTime = performance.now();
  fpsInfo = { fps: 0, frameTimeMs: 0, minFps: 0 };
  onBeforeRenderCallback;
  onAfterRenderCallback;
  onFpsUpdatedCallback;
  constructor(e, t, i, r) {
    this.container = e, this.renderer = this.createRenderer(r.antialias), this.viewer = new l.Viewer({
      selfDrivenMode: !1,
      renderer: this.renderer,
      camera: i,
      threeScene: t,
      rootElement: e,
      useBuiltInControls: !0,
      cameraUp: r.cameraUp,
      initialCameraPosition: r.initialCameraPosition,
      initialCameraLookAt: r.initialCameraLookAt,
      sharedMemoryForWorkers: r.sharedMemoryForWorkers,
      gpuAcceleratedSort: r.gpuAcceleratedSort,
      sphericalHarmonicsDegree: r.sphericalHarmonicsDegree,
      ...r.viewerOptions ?? {}
    });
  }
  createRenderer(e) {
    const t = new o.WebGLRenderer({
      antialias: e,
      alpha: !0,
      preserveDrawingBuffer: !1
    });
    return t.setSize(Math.max(this.container.clientWidth, 1), Math.max(this.container.clientHeight, 1)), t.setPixelRatio(Math.min(window.devicePixelRatio, 2)), this.container.appendChild(t.domElement), t;
  }
  setOnBeforeRender(e) {
    this.onBeforeRenderCallback = e;
  }
  setOnAfterRender(e) {
    this.onAfterRenderCallback = e;
  }
  setOnFpsUpdated(e) {
    this.onFpsUpdatedCallback = e;
  }
  startRenderLoop() {
    this.animationId === null && (this.isRenderingPaused = !1, this.animate());
  }
  animate() {
    if (this.isRenderingPaused) {
      this.animationId = null;
      return;
    }
    this.animationId = requestAnimationFrame(() => this.animate()), this.render();
  }
  render() {
    this.onBeforeRenderCallback?.(), this.viewer.update(this.renderer), this.viewer.render(), this.onAfterRenderCallback?.(), this.updateFps();
  }
  updateFps() {
    this.fpsFrameCount++;
    const e = performance.now(), t = e - this.fpsLastTime;
    if (t < 1e3)
      return;
    const i = Math.round(this.fpsFrameCount * 1e3 / t);
    this.fpsInfo = {
      fps: i,
      frameTimeMs: i > 0 ? 1e3 / i : 0,
      minFps: this.fpsInfo.minFps === 0 ? i : Math.min(this.fpsInfo.minFps, i)
    }, this.fpsFrameCount = 0, this.fpsLastTime = e, this.onFpsUpdatedCallback?.({ ...this.fpsInfo });
  }
  resetFpsStats() {
    this.fpsInfo = { fps: 0, frameTimeMs: 0, minFps: 0 }, this.fpsFrameCount = 0, this.fpsLastTime = performance.now();
  }
  pauseRendering() {
    this.isRenderingPaused = !0, this.animationId !== null && (cancelAnimationFrame(this.animationId), this.animationId = null);
  }
  resumeRendering() {
    this.isRenderingPaused && this.startRenderLoop();
  }
  isRenderingPausedState() {
    return this.isRenderingPaused;
  }
  resize(e, t) {
    this.renderer.setSize(Math.max(e, 1), Math.max(t, 1)), this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  }
  getViewer() {
    return this.viewer;
  }
  getRenderer() {
    return this.renderer;
  }
  getDomElement() {
    return this.renderer.domElement;
  }
  getFpsInfo() {
    return { ...this.fpsInfo };
  }
  async dispose() {
    this.pauseRendering(), await this.viewer.dispose(), this.container.contains(this.renderer.domElement) && this.container.removeChild(this.renderer.domElement), this.renderer.dispose(), this.renderer.forceContextLoss();
  }
}
const g = {
  identity: [0, 0, 0, 1],
  "x-90": [-0.7071068, 0, 0, 0.7071068],
  x90: [0.7071068, 0, 0, 0.7071068],
  x180: [1, 0, 0, 0],
  "y-90": [0, -0.7071068, 0, 0.7071068],
  y90: [0, 0.7071068, 0, 0.7071068],
  "z-90": [0, 0, -0.7071068, 0.7071068],
  z90: [0, 0, 0.7071068, 0.7071068],
  z180: [0, 0, 1, 0]
};
class p {
  orientationPreset;
  constructor(e = "x180") {
    this.orientationPreset = e;
  }
  setOrientationPreset(e) {
    this.orientationPreset = e;
  }
  getOrientationPreset() {
    return this.orientationPreset;
  }
  getOrientationRotation() {
    return [...g[this.orientationPreset]];
  }
  active() {
  }
  disActive() {
  }
  update() {
  }
  dispose() {
  }
}
function f(n, e) {
  return `${n}#${e}`;
}
class M {
  viewer;
  getDefaultRotation;
  scenes = /* @__PURE__ */ new Map();
  constructor(e, t) {
    this.viewer = e, this.getDefaultRotation = t;
  }
  async loadModel(e, t = {}) {
    const i = this.viewer.getSceneCount(), r = {
      showLoadingUI: !0,
      progressiveLoad: !1,
      position: [0, 0, 0],
      rotation: this.getDefaultRotation(),
      scale: [1, 1, 1],
      ...t
    };
    await this.viewer.addSplatScene(e, r);
    const s = {
      id: r.id ?? f(e, i),
      name: r.name ?? e.split(/[\\/]/).pop() ?? e,
      url: e,
      index: i,
      options: r
    };
    return this.scenes.set(s.id, s), s;
  }
  async loadModels(e) {
    const t = [];
    for (const i of e)
      t.push(await this.loadModel(i.url, i.options));
    return t;
  }
  async unloadModel(e, t = !0) {
    const i = this.scenes.get(e);
    i && (await this.viewer.removeSplatScene(i.index, t), this.scenes.delete(e), this.reindexScenesAfterRemove(i.index));
  }
  getModel(e) {
    return this.scenes.get(e);
  }
  getAllModels() {
    return Array.from(this.scenes.values());
  }
  getRawSplatScene(e) {
    const t = typeof e == "number" ? e : this.scenes.get(e)?.index;
    return t == null ? void 0 : this.viewer.getSplatScene(t);
  }
  async clear(e = !1) {
    const t = this.getAllModels().map((i) => i.index);
    t.length > 0 && await this.viewer.removeSplatScenes(t, e), this.scenes.clear();
  }
  reindexScenesAfterRemove(e) {
    this.scenes.forEach((t) => {
      t.index > e && (t.index -= 1);
    });
  }
}
const w = "3.9.12", v = {
  version: w
}, R = v.version;
class I {
  eventModule;
  sceneModule;
  cameraModule;
  renderModule;
  controlModule;
  loaderModule;
  isInitialized = !1;
  version = R;
  constructor(e) {
    this.initialize(e);
  }
  initialize(e) {
    const t = {
      containerId: e.containerId,
      cameraUp: e.cameraUp ?? [0, 1, 0],
      initialCameraPosition: e.initialCameraPosition ?? [0, 0, 6],
      initialCameraLookAt: e.initialCameraLookAt ?? [0, 0, 0],
      backgroundColor: e.backgroundColor,
      antialias: e.antialias ?? !1,
      showLoadingUI: e.showLoadingUI ?? !0,
      sharedMemoryForWorkers: e.sharedMemoryForWorkers ?? !1,
      gpuAcceleratedSort: e.gpuAcceleratedSort ?? !1,
      sphericalHarmonicsDegree: e.sphericalHarmonicsDegree ?? 0,
      orientationPreset: e.orientationPreset ?? "x180",
      viewerOptions: e.viewerOptions
    }, i = document.getElementById(t.containerId);
    if (!i)
      throw new Error(`Container with id "${t.containerId}" not found`);
    this.eventModule = new c(), this.sceneModule = new h(t.backgroundColor), this.cameraModule = new u(
      i,
      t.cameraUp,
      t.initialCameraPosition,
      t.initialCameraLookAt
    ), this.controlModule = new p(t.orientationPreset), this.renderModule = new m(
      i,
      this.sceneModule.getScene(),
      this.cameraModule.getCamera(),
      t
    ), this.loaderModule = new M(
      this.renderModule.getViewer(),
      () => this.controlModule.getOrientationRotation()
    ), this.renderModule.setOnBeforeRender(() => {
      this.controlModule.update();
    }), this.renderModule.setOnFpsUpdated((r) => {
      this.eventModule.trigger(a.FpsUpdated, r);
    }), this.renderModule.startRenderLoop(), this.isInitialized = !0;
  }
  async loadModel(e, t = {}) {
    this.checkInitialized(), this.eventModule.trigger(a.LoadStart, { url: e, name: t.name });
    try {
      const i = await this.loaderModule.loadModel(e, {
        showLoadingUI: !0,
        ...t,
        onProgress: (r, s, d) => {
          this.eventModule.trigger(a.LoadProgress, { url: e, name: t.name, progress: r }), t.onProgress?.(r, s, d);
        }
      });
      return this.eventModule.trigger(a.Loaded, { url: e, name: i.name, progress: 100 }), i;
    } catch (i) {
      throw this.eventModule.trigger(a.LoadError, {
        url: e,
        name: t.name,
        error: i instanceof Error ? i : new Error(String(i))
      }), i;
    }
  }
  async unloadModel(e) {
    this.checkInitialized(), await this.loaderModule.unloadModel(e, !1), this.eventModule.trigger(a.SceneRemoved, { id: e });
  }
  setOrientationPreset(e) {
    this.checkInitialized(), this.controlModule.setOrientationPreset(e);
  }
  getOrientationPreset() {
    return this.checkInitialized(), this.controlModule.getOrientationPreset();
  }
  resize(e, t) {
    this.checkInitialized();
    const i = this.renderModule.getDomElement(), r = e ?? i.parentElement?.clientWidth ?? i.clientWidth, s = t ?? i.parentElement?.clientHeight ?? i.clientHeight;
    this.renderModule.resize(r, s), this.cameraModule.updateAspectRatio(r, s);
  }
  pauseRendering() {
    this.checkInitialized(), this.renderModule.pauseRendering();
  }
  resumeRendering() {
    this.checkInitialized(), this.renderModule.resumeRendering();
  }
  resetFpsStats() {
    this.checkInitialized(), this.renderModule.resetFpsStats();
  }
  getFpsInfo() {
    return this.checkInitialized(), this.renderModule.getFpsInfo();
  }
  on(e, t) {
    this.checkInitialized(), this.eventModule.on(e, t);
  }
  off(e, t) {
    this.checkInitialized(), this.eventModule.off(e, t);
  }
  getVersion() {
    return this.version;
  }
  async dispose() {
    this.isInitialized && (await this.loaderModule.clear(!1), await this.renderModule.dispose(), this.controlModule.dispose(), this.cameraModule.dispose(), this.sceneModule.dispose(), this.eventModule.dispose(), this.isInitialized = !1);
  }
  checkInitialized() {
    if (!this.isInitialized)
      throw new Error("EngineKernelGaussian: Not initialized");
  }
}
function k(n) {
  return new I(n);
}
export {
  I as EngineKernelGaussian,
  a as EventTypeGaussian,
  l as GaussianSplats3D,
  k as createEngineGaussian
};
//# sourceMappingURL=gaussian.es.js.map
