"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const THREE = require("three");
function _interopNamespaceDefault(e) {
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
  if (e) {
    for (const k in e) {
      if (k !== "default") {
        const d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: () => e[k]
        });
      }
    }
  }
  n.default = e;
  return Object.freeze(n);
}
const THREE__namespace = /* @__PURE__ */ _interopNamespaceDefault(THREE);
const PINCH_MAX = 0.05;
const PINCH_THRESHOLD = 0.02;
const PINCH_MIN = 0.01;
const POINTER_ADVANCE_MAX = 0.02;
const POINTER_OPACITY_MAX = 1;
const POINTER_OPACITY_MIN = 0.4;
const POINTER_FRONT_RADIUS = 2e-3;
const POINTER_REAR_RADIUS = 0.01;
const POINTER_REAR_RADIUS_MIN = 3e-3;
const POINTER_LENGTH = 0.035;
const POINTER_SEGMENTS = 16;
const POINTER_RINGS = 12;
const POINTER_HEMISPHERE_ANGLE = 110;
const YAXIS = /* @__PURE__ */ new THREE__namespace.Vector3(0, 1, 0);
const ZAXIS = /* @__PURE__ */ new THREE__namespace.Vector3(0, 0, 1);
const CURSOR_RADIUS = 0.02;
const CURSOR_MAX_DISTANCE = 1.5;
class OculusHandPointerModel extends THREE__namespace.Object3D {
  constructor(hand, controller) {
    super();
    this.hand = hand;
    this.controller = controller;
    this.motionController = null;
    this.envMap = null;
    this.mesh = null;
    this.pointerGeometry = null;
    this.pointerMesh = null;
    this.pointerObject = null;
    this.pinched = false;
    this.attached = false;
    this.cursorObject = null;
    this.raycaster = null;
    this._onConnected = this._onConnected.bind(this);
    this._onDisconnected = this._onDisconnected.bind(this);
    this.hand.addEventListener("connected", this._onConnected);
    this.hand.addEventListener("disconnected", this._onDisconnected);
  }
  _onConnected(event) {
    const xrInputSource = event.data;
    if (xrInputSource.hand) {
      this.visible = true;
      this.xrInputSource = xrInputSource;
      this.createPointer();
    }
  }
  _onDisconnected() {
    var _a, _b;
    this.visible = false;
    this.xrInputSource = null;
    (_a = this.pointerGeometry) == null ? void 0 : _a.dispose();
    (_b = this.pointerMesh) == null ? void 0 : _b.material.dispose();
    this.clear();
  }
  _drawVerticesRing(vertices, baseVector, ringIndex) {
    const segmentVector = baseVector.clone();
    for (var i = 0; i < POINTER_SEGMENTS; i++) {
      segmentVector.applyAxisAngle(ZAXIS, Math.PI * 2 / POINTER_SEGMENTS);
      const vid = ringIndex * POINTER_SEGMENTS + i;
      vertices[3 * vid] = segmentVector.x;
      vertices[3 * vid + 1] = segmentVector.y;
      vertices[3 * vid + 2] = segmentVector.z;
    }
  }
  _updatePointerVertices(rearRadius) {
    const vertices = this.pointerGeometry.attributes.position.array;
    const frontFaceBase = new THREE__namespace.Vector3(POINTER_FRONT_RADIUS, 0, -1 * (POINTER_LENGTH - rearRadius));
    this._drawVerticesRing(vertices, frontFaceBase, 0);
    const rearBase = new THREE__namespace.Vector3(
      Math.sin(Math.PI * POINTER_HEMISPHERE_ANGLE / 180) * rearRadius,
      Math.cos(Math.PI * POINTER_HEMISPHERE_ANGLE / 180) * rearRadius,
      0
    );
    for (var i = 0; i < POINTER_RINGS; i++) {
      this._drawVerticesRing(vertices, rearBase, i + 1);
      rearBase.applyAxisAngle(YAXIS, Math.PI * POINTER_HEMISPHERE_ANGLE / 180 / (POINTER_RINGS * -2));
    }
    const frontCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS);
    const rearCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS) + 1;
    const frontCenter = new THREE__namespace.Vector3(0, 0, -1 * (POINTER_LENGTH - rearRadius));
    vertices[frontCenterIndex * 3] = frontCenter.x;
    vertices[frontCenterIndex * 3 + 1] = frontCenter.y;
    vertices[frontCenterIndex * 3 + 2] = frontCenter.z;
    const rearCenter = new THREE__namespace.Vector3(0, 0, rearRadius);
    vertices[rearCenterIndex * 3] = rearCenter.x;
    vertices[rearCenterIndex * 3 + 1] = rearCenter.y;
    vertices[rearCenterIndex * 3 + 2] = rearCenter.z;
    this.pointerGeometry.setAttribute("position", new THREE__namespace.Float32BufferAttribute(vertices, 3));
  }
  createPointer() {
    var i, j;
    const vertices = new Array(((POINTER_RINGS + 1) * POINTER_SEGMENTS + 2) * 3).fill(0);
    const indices = [];
    this.pointerGeometry = new THREE__namespace.BufferGeometry();
    this.pointerGeometry.setAttribute("position", new THREE__namespace.Float32BufferAttribute(vertices, 3));
    this._updatePointerVertices(POINTER_REAR_RADIUS);
    for (i = 0; i < POINTER_RINGS; i++) {
      for (j = 0; j < POINTER_SEGMENTS - 1; j++) {
        indices.push(i * POINTER_SEGMENTS + j, i * POINTER_SEGMENTS + j + 1, (i + 1) * POINTER_SEGMENTS + j);
        indices.push(i * POINTER_SEGMENTS + j + 1, (i + 1) * POINTER_SEGMENTS + j + 1, (i + 1) * POINTER_SEGMENTS + j);
      }
      indices.push((i + 1) * POINTER_SEGMENTS - 1, i * POINTER_SEGMENTS, (i + 2) * POINTER_SEGMENTS - 1);
      indices.push(i * POINTER_SEGMENTS, (i + 1) * POINTER_SEGMENTS, (i + 2) * POINTER_SEGMENTS - 1);
    }
    const frontCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS);
    const rearCenterIndex = POINTER_SEGMENTS * (1 + POINTER_RINGS) + 1;
    for (i = 0; i < POINTER_SEGMENTS - 1; i++) {
      indices.push(frontCenterIndex, i + 1, i);
      indices.push(rearCenterIndex, i + POINTER_SEGMENTS * POINTER_RINGS, i + POINTER_SEGMENTS * POINTER_RINGS + 1);
    }
    indices.push(frontCenterIndex, 0, POINTER_SEGMENTS - 1);
    indices.push(rearCenterIndex, POINTER_SEGMENTS * (POINTER_RINGS + 1) - 1, POINTER_SEGMENTS * POINTER_RINGS);
    const material = new THREE__namespace.MeshBasicMaterial();
    material.transparent = true;
    material.opacity = POINTER_OPACITY_MIN;
    this.pointerGeometry.setIndex(indices);
    this.pointerMesh = new THREE__namespace.Mesh(this.pointerGeometry, material);
    this.pointerMesh.position.set(0, 0, -1 * POINTER_REAR_RADIUS);
    this.pointerObject = new THREE__namespace.Object3D();
    this.pointerObject.add(this.pointerMesh);
    this.raycaster = new THREE__namespace.Raycaster();
    const cursorGeometry = new THREE__namespace.SphereGeometry(CURSOR_RADIUS, 10, 10);
    const cursorMaterial = new THREE__namespace.MeshBasicMaterial();
    cursorMaterial.transparent = true;
    cursorMaterial.opacity = POINTER_OPACITY_MIN;
    this.cursorObject = new THREE__namespace.Mesh(cursorGeometry, cursorMaterial);
    this.pointerObject.add(this.cursorObject);
    this.add(this.pointerObject);
  }
  _updateRaycaster() {
    if (this.raycaster) {
      const pointerMatrix = this.pointerObject.matrixWorld;
      const tempMatrix = new THREE__namespace.Matrix4();
      tempMatrix.identity().extractRotation(pointerMatrix);
      this.raycaster.ray.origin.setFromMatrixPosition(pointerMatrix);
      this.raycaster.ray.direction.set(0, 0, -1).applyMatrix4(tempMatrix);
    }
  }
  _updatePointer() {
    this.pointerObject.visible = this.controller.visible;
    const indexTip = this.hand.joints["index-finger-tip"];
    const thumbTip = this.hand.joints["thumb-tip"];
    const distance = indexTip.position.distanceTo(thumbTip.position);
    const position = indexTip.position.clone().add(thumbTip.position).multiplyScalar(0.5);
    this.pointerObject.position.copy(position);
    this.pointerObject.quaternion.copy(this.controller.quaternion);
    this.pinched = distance <= PINCH_THRESHOLD;
    const pinchScale = (distance - PINCH_MIN) / (PINCH_MAX - PINCH_MIN);
    const focusScale = (distance - PINCH_MIN) / (PINCH_THRESHOLD - PINCH_MIN);
    if (pinchScale > 1) {
      this._updatePointerVertices(POINTER_REAR_RADIUS);
      this.pointerMesh.position.set(0, 0, -1 * POINTER_REAR_RADIUS);
      this.pointerMesh.material.opacity = POINTER_OPACITY_MIN;
    } else if (pinchScale > 0) {
      const rearRadius = (POINTER_REAR_RADIUS - POINTER_REAR_RADIUS_MIN) * pinchScale + POINTER_REAR_RADIUS_MIN;
      this._updatePointerVertices(rearRadius);
      if (focusScale < 1) {
        this.pointerMesh.position.set(0, 0, -1 * rearRadius - (1 - focusScale) * POINTER_ADVANCE_MAX);
        this.pointerMesh.material.opacity = POINTER_OPACITY_MIN + (1 - focusScale) * (POINTER_OPACITY_MAX - POINTER_OPACITY_MIN);
      } else {
        this.pointerMesh.position.set(0, 0, -1 * rearRadius);
        this.pointerMesh.material.opacity = POINTER_OPACITY_MIN;
      }
    } else {
      this._updatePointerVertices(POINTER_REAR_RADIUS_MIN);
      this.pointerMesh.position.set(0, 0, -1 * POINTER_REAR_RADIUS_MIN - POINTER_ADVANCE_MAX);
      this.pointerMesh.material.opacity = POINTER_OPACITY_MAX;
    }
    this.cursorObject.material.opacity = this.pointerMesh.material.opacity;
  }
  updateMatrixWorld(force) {
    super.updateMatrixWorld(force);
    if (this.pointerGeometry) {
      this._updatePointer();
      this._updateRaycaster();
    }
  }
  isPinched() {
    return this.pinched;
  }
  setAttached(attached) {
    this.attached = attached;
  }
  isAttached() {
    return this.attached;
  }
  intersectObject(object, recursive = true) {
    if (this.raycaster) {
      return this.raycaster.intersectObject(object, recursive);
    }
  }
  intersectObjects(objects, recursive = true) {
    if (this.raycaster) {
      return this.raycaster.intersectObjects(objects, recursive);
    }
  }
  checkIntersections(objects, recursive = false) {
    if (this.raycaster && !this.attached) {
      const intersections = this.raycaster.intersectObjects(objects, recursive);
      const direction = new THREE__namespace.Vector3(0, 0, -1);
      if (intersections.length > 0) {
        const intersection = intersections[0];
        const distance = intersection.distance;
        this.cursorObject.position.copy(direction.multiplyScalar(distance));
      } else {
        this.cursorObject.position.copy(direction.multiplyScalar(CURSOR_MAX_DISTANCE));
      }
    }
  }
  setCursor(distance) {
    const direction = new THREE__namespace.Vector3(0, 0, -1);
    if (this.raycaster && !this.attached) {
      this.cursorObject.position.copy(direction.multiplyScalar(distance));
    }
  }
  dispose() {
    this._onDisconnected();
    this.hand.removeEventListener("connected", this._onConnected);
    this.hand.removeEventListener("disconnected", this._onDisconnected);
  }
}
exports.OculusHandPointerModel = OculusHandPointerModel;
//# sourceMappingURL=OculusHandPointerModel.cjs.map
