import {
  AnimationClip,
  Bone,
  FileLoader,
  Loader,
  Quaternion,
  QuaternionKeyframeTrack,
  Skeleton,
  Vector3,
  VectorKeyframeTrack
} from "./chunk-5JQWN2BK.js";
import "./chunk-CL4PTTKD.js";

// node_modules/three/examples/jsm/loaders/BVHLoader.js
var BVHLoader = class extends Loader {
  constructor(manager) {
    super(manager);
    this.animateBonePositions = true;
    this.animateBoneRotations = true;
  }
  load(url, onLoad, onProgress, onError) {
    const scope = this;
    const loader = new FileLoader(scope.manager);
    loader.setPath(scope.path);
    loader.setRequestHeader(scope.requestHeader);
    loader.setWithCredentials(scope.withCredentials);
    loader.load(url, function(text) {
      try {
        onLoad(scope.parse(text));
      } catch (e) {
        if (onError) {
          onError(e);
        } else {
          console.error(e);
        }
        scope.manager.itemError(url);
      }
    }, onProgress, onError);
  }
  parse(text) {
    function readBvh(lines2) {
      if (nextLine(lines2) !== "HIERARCHY") {
        console.error("THREE.BVHLoader: HIERARCHY expected.");
      }
      const list = [];
      const root = readNode(lines2, nextLine(lines2), list);
      if (nextLine(lines2) !== "MOTION") {
        console.error("THREE.BVHLoader: MOTION expected.");
      }
      let tokens = nextLine(lines2).split(/[\s]+/);
      const numFrames = parseInt(tokens[1]);
      if (isNaN(numFrames)) {
        console.error("THREE.BVHLoader: Failed to read number of frames.");
      }
      tokens = nextLine(lines2).split(/[\s]+/);
      const frameTime = parseFloat(tokens[2]);
      if (isNaN(frameTime)) {
        console.error("THREE.BVHLoader: Failed to read frame time.");
      }
      for (let i = 0; i < numFrames; i++) {
        tokens = nextLine(lines2).split(/[\s]+/);
        readFrameData(tokens, i * frameTime, root);
      }
      return list;
    }
    function readFrameData(data, frameTime, bone) {
      if (bone.type === "ENDSITE")
        return;
      const keyframe = {
        time: frameTime,
        position: new Vector3(),
        rotation: new Quaternion()
      };
      bone.frames.push(keyframe);
      const quat = new Quaternion();
      const vx = new Vector3(1, 0, 0);
      const vy = new Vector3(0, 1, 0);
      const vz = new Vector3(0, 0, 1);
      for (let i = 0; i < bone.channels.length; i++) {
        switch (bone.channels[i]) {
          case "Xposition":
            keyframe.position.x = parseFloat(data.shift().trim());
            break;
          case "Yposition":
            keyframe.position.y = parseFloat(data.shift().trim());
            break;
          case "Zposition":
            keyframe.position.z = parseFloat(data.shift().trim());
            break;
          case "Xrotation":
            quat.setFromAxisAngle(vx, parseFloat(data.shift().trim()) * Math.PI / 180);
            keyframe.rotation.multiply(quat);
            break;
          case "Yrotation":
            quat.setFromAxisAngle(vy, parseFloat(data.shift().trim()) * Math.PI / 180);
            keyframe.rotation.multiply(quat);
            break;
          case "Zrotation":
            quat.setFromAxisAngle(vz, parseFloat(data.shift().trim()) * Math.PI / 180);
            keyframe.rotation.multiply(quat);
            break;
          default:
            console.warn("THREE.BVHLoader: Invalid channel type.");
        }
      }
      for (let i = 0; i < bone.children.length; i++) {
        readFrameData(data, frameTime, bone.children[i]);
      }
    }
    function readNode(lines2, firstline, list) {
      const node = { name: "", type: "", frames: [] };
      list.push(node);
      let tokens = firstline.split(/[\s]+/);
      if (tokens[0].toUpperCase() === "END" && tokens[1].toUpperCase() === "SITE") {
        node.type = "ENDSITE";
        node.name = "ENDSITE";
      } else {
        node.name = tokens[1];
        node.type = tokens[0].toUpperCase();
      }
      if (nextLine(lines2) !== "{") {
        console.error("THREE.BVHLoader: Expected opening { after type & name");
      }
      tokens = nextLine(lines2).split(/[\s]+/);
      if (tokens[0] !== "OFFSET") {
        console.error("THREE.BVHLoader: Expected OFFSET but got: " + tokens[0]);
      }
      if (tokens.length !== 4) {
        console.error("THREE.BVHLoader: Invalid number of values for OFFSET.");
      }
      const offset = new Vector3(
        parseFloat(tokens[1]),
        parseFloat(tokens[2]),
        parseFloat(tokens[3])
      );
      if (isNaN(offset.x) || isNaN(offset.y) || isNaN(offset.z)) {
        console.error("THREE.BVHLoader: Invalid values of OFFSET.");
      }
      node.offset = offset;
      if (node.type !== "ENDSITE") {
        tokens = nextLine(lines2).split(/[\s]+/);
        if (tokens[0] !== "CHANNELS") {
          console.error("THREE.BVHLoader: Expected CHANNELS definition.");
        }
        const numChannels = parseInt(tokens[1]);
        node.channels = tokens.splice(2, numChannels);
        node.children = [];
      }
      while (true) {
        const line = nextLine(lines2);
        if (line === "}") {
          return node;
        } else {
          node.children.push(readNode(lines2, line, list));
        }
      }
    }
    function toTHREEBone(source, list) {
      const bone = new Bone();
      list.push(bone);
      bone.position.add(source.offset);
      bone.name = source.name;
      if (source.type !== "ENDSITE") {
        for (let i = 0; i < source.children.length; i++) {
          bone.add(toTHREEBone(source.children[i], list));
        }
      }
      return bone;
    }
    function toTHREEAnimation(bones2) {
      const tracks = [];
      for (let i = 0; i < bones2.length; i++) {
        const bone = bones2[i];
        if (bone.type === "ENDSITE")
          continue;
        const times = [];
        const positions = [];
        const rotations = [];
        for (let j = 0; j < bone.frames.length; j++) {
          const frame = bone.frames[j];
          times.push(frame.time);
          positions.push(frame.position.x + bone.offset.x);
          positions.push(frame.position.y + bone.offset.y);
          positions.push(frame.position.z + bone.offset.z);
          rotations.push(frame.rotation.x);
          rotations.push(frame.rotation.y);
          rotations.push(frame.rotation.z);
          rotations.push(frame.rotation.w);
        }
        if (scope.animateBonePositions) {
          tracks.push(new VectorKeyframeTrack(bone.name + ".position", times, positions));
        }
        if (scope.animateBoneRotations) {
          tracks.push(new QuaternionKeyframeTrack(bone.name + ".quaternion", times, rotations));
        }
      }
      return new AnimationClip("animation", -1, tracks);
    }
    function nextLine(lines2) {
      let line;
      while ((line = lines2.shift().trim()).length === 0) {
      }
      return line;
    }
    const scope = this;
    const lines = text.split(/[\r\n]+/g);
    const bones = readBvh(lines);
    const threeBones = [];
    toTHREEBone(bones[0], threeBones);
    const threeClip = toTHREEAnimation(bones);
    return {
      skeleton: new Skeleton(threeBones),
      clip: threeClip
    };
  }
};
export {
  BVHLoader
};
