{"version":3,"file":"BVHLoader.cjs","sources":["../../src/loaders/BVHLoader.js"],"sourcesContent":["import {\n  AnimationClip,\n  Bone,\n  FileLoader,\n  Loader,\n  Quaternion,\n  QuaternionKeyframeTrack,\n  Skeleton,\n  Vector3,\n  VectorKeyframeTrack,\n} from 'three'\n\n/**\n * Description: reads BVH files and outputs a single Skeleton and an AnimationClip\n *\n * Currently only supports bvh files containing a single root.\n *\n */\n\nclass BVHLoader extends Loader {\n  constructor(manager) {\n    super(manager)\n\n    this.animateBonePositions = true\n    this.animateBoneRotations = true\n  }\n\n  load(url, onLoad, onProgress, onError) {\n    const scope = this\n\n    const loader = new FileLoader(scope.manager)\n    loader.setPath(scope.path)\n    loader.setRequestHeader(scope.requestHeader)\n    loader.setWithCredentials(scope.withCredentials)\n    loader.load(\n      url,\n      function (text) {\n        try {\n          onLoad(scope.parse(text))\n        } catch (e) {\n          if (onError) {\n            onError(e)\n          } else {\n            console.error(e)\n          }\n\n          scope.manager.itemError(url)\n        }\n      },\n      onProgress,\n      onError,\n    )\n  }\n\n  parse(text) {\n    /*\n\t\t\treads a string array (lines) from a BVH file\n\t\t\tand outputs a skeleton structure including motion data\n\n\t\t\treturns thee root node:\n\t\t\t{ name: '', channels: [], children: [] }\n\t\t*/\n    function readBvh(lines) {\n      // read model structure\n\n      if (nextLine(lines) !== 'HIERARCHY') {\n        console.error('THREE.BVHLoader: HIERARCHY expected.')\n      }\n\n      const list = [] // collects flat array of all bones\n      const root = readNode(lines, nextLine(lines), list)\n\n      // read motion data\n\n      if (nextLine(lines) !== 'MOTION') {\n        console.error('THREE.BVHLoader: MOTION expected.')\n      }\n\n      // number of frames\n\n      let tokens = nextLine(lines).split(/[\\s]+/)\n      const numFrames = parseInt(tokens[1])\n\n      if (isNaN(numFrames)) {\n        console.error('THREE.BVHLoader: Failed to read number of frames.')\n      }\n\n      // frame time\n\n      tokens = nextLine(lines).split(/[\\s]+/)\n      const frameTime = parseFloat(tokens[2])\n\n      if (isNaN(frameTime)) {\n        console.error('THREE.BVHLoader: Failed to read frame time.')\n      }\n\n      // read frame data line by line\n\n      for (let i = 0; i < numFrames; i++) {\n        tokens = nextLine(lines).split(/[\\s]+/)\n        readFrameData(tokens, i * frameTime, root)\n      }\n\n      return list\n    }\n\n    /*\n\t\t\tRecursively reads data from a single frame into the bone hierarchy.\n\t\t\tThe passed bone hierarchy has to be structured in the same order as the BVH file.\n\t\t\tkeyframe data is stored in bone.frames.\n\n\t\t\t- data: splitted string array (frame values), values are shift()ed so\n\t\t\tthis should be empty after parsing the whole hierarchy.\n\t\t\t- frameTime: playback time for this keyframe.\n\t\t\t- bone: the bone to read frame data from.\n\t\t*/\n    function readFrameData(data, frameTime, bone) {\n      // end sites have no motion data\n\n      if (bone.type === 'ENDSITE') return\n\n      // add keyframe\n\n      const keyframe = {\n        time: frameTime,\n        position: new Vector3(),\n        rotation: new Quaternion(),\n      }\n\n      bone.frames.push(keyframe)\n\n      const quat = new Quaternion()\n\n      const vx = new Vector3(1, 0, 0)\n      const vy = new Vector3(0, 1, 0)\n      const vz = new Vector3(0, 0, 1)\n\n      // parse values for each channel in node\n\n      for (let i = 0; i < bone.channels.length; i++) {\n        switch (bone.channels[i]) {\n          case 'Xposition':\n            keyframe.position.x = parseFloat(data.shift().trim())\n            break\n          case 'Yposition':\n            keyframe.position.y = parseFloat(data.shift().trim())\n            break\n          case 'Zposition':\n            keyframe.position.z = parseFloat(data.shift().trim())\n            break\n          case 'Xrotation':\n            quat.setFromAxisAngle(vx, (parseFloat(data.shift().trim()) * Math.PI) / 180)\n            keyframe.rotation.multiply(quat)\n            break\n          case 'Yrotation':\n            quat.setFromAxisAngle(vy, (parseFloat(data.shift().trim()) * Math.PI) / 180)\n            keyframe.rotation.multiply(quat)\n            break\n          case 'Zrotation':\n            quat.setFromAxisAngle(vz, (parseFloat(data.shift().trim()) * Math.PI) / 180)\n            keyframe.rotation.multiply(quat)\n            break\n          default:\n            console.warn('THREE.BVHLoader: Invalid channel type.')\n        }\n      }\n\n      // parse child nodes\n\n      for (let i = 0; i < bone.children.length; i++) {\n        readFrameData(data, frameTime, bone.children[i])\n      }\n    }\n\n    /*\n\t\t Recursively parses the HIERACHY section of the BVH file\n\n\t\t - lines: all lines of the file. lines are consumed as we go along.\n\t\t - firstline: line containing the node type and name e.g. 'JOINT hip'\n\t\t - list: collects a flat list of nodes\n\n\t\t returns: a BVH node including children\n\t\t*/\n    function readNode(lines, firstline, list) {\n      const node = { name: '', type: '', frames: [] }\n      list.push(node)\n\n      // parse node type and name\n\n      let tokens = firstline.split(/[\\s]+/)\n\n      if (tokens[0].toUpperCase() === 'END' && tokens[1].toUpperCase() === 'SITE') {\n        node.type = 'ENDSITE'\n        node.name = 'ENDSITE' // bvh end sites have no name\n      } else {\n        node.name = tokens[1]\n        node.type = tokens[0].toUpperCase()\n      }\n\n      if (nextLine(lines) !== '{') {\n        console.error('THREE.BVHLoader: Expected opening { after type & name')\n      }\n\n      // parse OFFSET\n\n      tokens = nextLine(lines).split(/[\\s]+/)\n\n      if (tokens[0] !== 'OFFSET') {\n        console.error('THREE.BVHLoader: Expected OFFSET but got: ' + tokens[0])\n      }\n\n      if (tokens.length !== 4) {\n        console.error('THREE.BVHLoader: Invalid number of values for OFFSET.')\n      }\n\n      const offset = new Vector3(parseFloat(tokens[1]), parseFloat(tokens[2]), parseFloat(tokens[3]))\n\n      if (isNaN(offset.x) || isNaN(offset.y) || isNaN(offset.z)) {\n        console.error('THREE.BVHLoader: Invalid values of OFFSET.')\n      }\n\n      node.offset = offset\n\n      // parse CHANNELS definitions\n\n      if (node.type !== 'ENDSITE') {\n        tokens = nextLine(lines).split(/[\\s]+/)\n\n        if (tokens[0] !== 'CHANNELS') {\n          console.error('THREE.BVHLoader: Expected CHANNELS definition.')\n        }\n\n        const numChannels = parseInt(tokens[1])\n        node.channels = tokens.splice(2, numChannels)\n        node.children = []\n      }\n\n      // read children\n\n      while (true) {\n        const line = nextLine(lines)\n\n        if (line === '}') {\n          return node\n        } else {\n          node.children.push(readNode(lines, line, list))\n        }\n      }\n    }\n\n    /*\n\t\t\trecursively converts the internal bvh node structure to a Bone hierarchy\n\n\t\t\tsource: the bvh root node\n\t\t\tlist: pass an empty array, collects a flat list of all converted THREE.Bones\n\n\t\t\treturns the root Bone\n\t\t*/\n    function toTHREEBone(source, list) {\n      const bone = new Bone()\n      list.push(bone)\n\n      bone.position.add(source.offset)\n      bone.name = source.name\n\n      if (source.type !== 'ENDSITE') {\n        for (let i = 0; i < source.children.length; i++) {\n          bone.add(toTHREEBone(source.children[i], list))\n        }\n      }\n\n      return bone\n    }\n\n    /*\n\t\t\tbuilds a AnimationClip from the keyframe data saved in each bone.\n\n\t\t\tbone: bvh root node\n\n\t\t\treturns: a AnimationClip containing position and quaternion tracks\n\t\t*/\n    function toTHREEAnimation(bones) {\n      const tracks = []\n\n      // create a position and quaternion animation track for each node\n\n      for (let i = 0; i < bones.length; i++) {\n        const bone = bones[i]\n\n        if (bone.type === 'ENDSITE') continue\n\n        // track data\n\n        const times = []\n        const positions = []\n        const rotations = []\n\n        for (let j = 0; j < bone.frames.length; j++) {\n          const frame = bone.frames[j]\n\n          times.push(frame.time)\n\n          // the animation system animates the position property,\n          // so we have to add the joint offset to all values\n\n          positions.push(frame.position.x + bone.offset.x)\n          positions.push(frame.position.y + bone.offset.y)\n          positions.push(frame.position.z + bone.offset.z)\n\n          rotations.push(frame.rotation.x)\n          rotations.push(frame.rotation.y)\n          rotations.push(frame.rotation.z)\n          rotations.push(frame.rotation.w)\n        }\n\n        if (scope.animateBonePositions) {\n          tracks.push(new VectorKeyframeTrack('.bones[' + bone.name + '].position', times, positions))\n        }\n\n        if (scope.animateBoneRotations) {\n          tracks.push(new QuaternionKeyframeTrack('.bones[' + bone.name + '].quaternion', times, rotations))\n        }\n      }\n\n      return new AnimationClip('animation', -1, tracks)\n    }\n\n    /*\n\t\t\treturns the next non-empty line in lines\n\t\t*/\n    function nextLine(lines) {\n      let line\n      // skip empty lines\n      while ((line = lines.shift().trim()).length === 0) {}\n\n      return line\n    }\n\n    const scope = this\n\n    const lines = text.split(/[\\r\\n]+/g)\n\n    const bones = readBvh(lines)\n\n    const threeBones = []\n    toTHREEBone(bones[0], threeBones)\n\n    const threeClip = toTHREEAnimation(bones)\n\n    return {\n      skeleton: new Skeleton(threeBones),\n      clip: threeClip,\n    }\n  }\n}\n\nexport { BVHLoader }\n"],"names":["Loader","FileLoader","lines","Vector3","Quaternion","Bone","bones","VectorKeyframeTrack","QuaternionKeyframeTrack","AnimationClip","Skeleton"],"mappings":";;;AAmBA,MAAM,kBAAkBA,MAAAA,OAAO;AAAA,EAC7B,YAAY,SAAS;AACnB,UAAM,OAAO;AAEb,SAAK,uBAAuB;AAC5B,SAAK,uBAAuB;AAAA,EAC7B;AAAA,EAED,KAAK,KAAK,QAAQ,YAAY,SAAS;AACrC,UAAM,QAAQ;AAEd,UAAM,SAAS,IAAIC,iBAAW,MAAM,OAAO;AAC3C,WAAO,QAAQ,MAAM,IAAI;AACzB,WAAO,iBAAiB,MAAM,aAAa;AAC3C,WAAO,mBAAmB,MAAM,eAAe;AAC/C,WAAO;AAAA,MACL;AAAA,MACA,SAAU,MAAM;AACd,YAAI;AACF,iBAAO,MAAM,MAAM,IAAI,CAAC;AAAA,QACzB,SAAQ,GAAP;AACA,cAAI,SAAS;AACX,oBAAQ,CAAC;AAAA,UACrB,OAAiB;AACL,oBAAQ,MAAM,CAAC;AAAA,UAChB;AAED,gBAAM,QAAQ,UAAU,GAAG;AAAA,QAC5B;AAAA,MACF;AAAA,MACD;AAAA,MACA;AAAA,IACD;AAAA,EACF;AAAA,EAED,MAAM,MAAM;AAQV,aAAS,QAAQC,QAAO;AAGtB,UAAI,SAASA,MAAK,MAAM,aAAa;AACnC,gBAAQ,MAAM,sCAAsC;AAAA,MACrD;AAED,YAAM,OAAO,CAAE;AACf,YAAM,OAAO,SAASA,QAAO,SAASA,MAAK,GAAG,IAAI;AAIlD,UAAI,SAASA,MAAK,MAAM,UAAU;AAChC,gBAAQ,MAAM,mCAAmC;AAAA,MAClD;AAID,UAAI,SAAS,SAASA,MAAK,EAAE,MAAM,OAAO;AAC1C,YAAM,YAAY,SAAS,OAAO,CAAC,CAAC;AAEpC,UAAI,MAAM,SAAS,GAAG;AACpB,gBAAQ,MAAM,mDAAmD;AAAA,MAClE;AAID,eAAS,SAASA,MAAK,EAAE,MAAM,OAAO;AACtC,YAAM,YAAY,WAAW,OAAO,CAAC,CAAC;AAEtC,UAAI,MAAM,SAAS,GAAG;AACpB,gBAAQ,MAAM,6CAA6C;AAAA,MAC5D;AAID,eAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,iBAAS,SAASA,MAAK,EAAE,MAAM,OAAO;AACtC,sBAAc,QAAQ,IAAI,WAAW,IAAI;AAAA,MAC1C;AAED,aAAO;AAAA,IACR;AAYD,aAAS,cAAc,MAAM,WAAW,MAAM;AAG5C,UAAI,KAAK,SAAS;AAAW;AAI7B,YAAM,WAAW;AAAA,QACf,MAAM;AAAA,QACN,UAAU,IAAIC,MAAAA,QAAS;AAAA,QACvB,UAAU,IAAIC,MAAAA,WAAY;AAAA,MAC3B;AAED,WAAK,OAAO,KAAK,QAAQ;AAEzB,YAAM,OAAO,IAAIA,iBAAY;AAE7B,YAAM,KAAK,IAAID,MAAAA,QAAQ,GAAG,GAAG,CAAC;AAC9B,YAAM,KAAK,IAAIA,MAAAA,QAAQ,GAAG,GAAG,CAAC;AAC9B,YAAM,KAAK,IAAIA,MAAAA,QAAQ,GAAG,GAAG,CAAC;AAI9B,eAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KAAK;AAC7C,gBAAQ,KAAK,SAAS,CAAC,GAAC;AAAA,UACtB,KAAK;AACH,qBAAS,SAAS,IAAI,WAAW,KAAK,MAAK,EAAG,MAAM;AACpD;AAAA,UACF,KAAK;AACH,qBAAS,SAAS,IAAI,WAAW,KAAK,MAAK,EAAG,MAAM;AACpD;AAAA,UACF,KAAK;AACH,qBAAS,SAAS,IAAI,WAAW,KAAK,MAAK,EAAG,MAAM;AACpD;AAAA,UACF,KAAK;AACH,iBAAK,iBAAiB,IAAK,WAAW,KAAK,MAAO,EAAC,KAAI,CAAE,IAAI,KAAK,KAAM,GAAG;AAC3E,qBAAS,SAAS,SAAS,IAAI;AAC/B;AAAA,UACF,KAAK;AACH,iBAAK,iBAAiB,IAAK,WAAW,KAAK,MAAO,EAAC,KAAI,CAAE,IAAI,KAAK,KAAM,GAAG;AAC3E,qBAAS,SAAS,SAAS,IAAI;AAC/B;AAAA,UACF,KAAK;AACH,iBAAK,iBAAiB,IAAK,WAAW,KAAK,MAAO,EAAC,KAAI,CAAE,IAAI,KAAK,KAAM,GAAG;AAC3E,qBAAS,SAAS,SAAS,IAAI;AAC/B;AAAA,UACF;AACE,oBAAQ,KAAK,wCAAwC;AAAA,QACxD;AAAA,MACF;AAID,eAAS,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KAAK;AAC7C,sBAAc,MAAM,WAAW,KAAK,SAAS,CAAC,CAAC;AAAA,MAChD;AAAA,IACF;AAWD,aAAS,SAASD,QAAO,WAAW,MAAM;AACxC,YAAM,OAAO,EAAE,MAAM,IAAI,MAAM,IAAI,QAAQ,GAAI;AAC/C,WAAK,KAAK,IAAI;AAId,UAAI,SAAS,UAAU,MAAM,OAAO;AAEpC,UAAI,OAAO,CAAC,EAAE,kBAAkB,SAAS,OAAO,CAAC,EAAE,YAAa,MAAK,QAAQ;AAC3E,aAAK,OAAO;AACZ,aAAK,OAAO;AAAA,MACpB,OAAa;AACL,aAAK,OAAO,OAAO,CAAC;AACpB,aAAK,OAAO,OAAO,CAAC,EAAE,YAAa;AAAA,MACpC;AAED,UAAI,SAASA,MAAK,MAAM,KAAK;AAC3B,gBAAQ,MAAM,uDAAuD;AAAA,MACtE;AAID,eAAS,SAASA,MAAK,EAAE,MAAM,OAAO;AAEtC,UAAI,OAAO,CAAC,MAAM,UAAU;AAC1B,gBAAQ,MAAM,+CAA+C,OAAO,CAAC,CAAC;AAAA,MACvE;AAED,UAAI,OAAO,WAAW,GAAG;AACvB,gBAAQ,MAAM,uDAAuD;AAAA,MACtE;AAED,YAAM,SAAS,IAAIC,MAAO,QAAC,WAAW,OAAO,CAAC,CAAC,GAAG,WAAW,OAAO,CAAC,CAAC,GAAG,WAAW,OAAO,CAAC,CAAC,CAAC;AAE9F,UAAI,MAAM,OAAO,CAAC,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,OAAO,CAAC,GAAG;AACzD,gBAAQ,MAAM,4CAA4C;AAAA,MAC3D;AAED,WAAK,SAAS;AAId,UAAI,KAAK,SAAS,WAAW;AAC3B,iBAAS,SAASD,MAAK,EAAE,MAAM,OAAO;AAEtC,YAAI,OAAO,CAAC,MAAM,YAAY;AAC5B,kBAAQ,MAAM,gDAAgD;AAAA,QAC/D;AAED,cAAM,cAAc,SAAS,OAAO,CAAC,CAAC;AACtC,aAAK,WAAW,OAAO,OAAO,GAAG,WAAW;AAC5C,aAAK,WAAW,CAAE;AAAA,MACnB;AAID,aAAO,MAAM;AACX,cAAM,OAAO,SAASA,MAAK;AAE3B,YAAI,SAAS,KAAK;AAChB,iBAAO;AAAA,QACjB,OAAe;AACL,eAAK,SAAS,KAAK,SAASA,QAAO,MAAM,IAAI,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AAUD,aAAS,YAAY,QAAQ,MAAM;AACjC,YAAM,OAAO,IAAIG,WAAM;AACvB,WAAK,KAAK,IAAI;AAEd,WAAK,SAAS,IAAI,OAAO,MAAM;AAC/B,WAAK,OAAO,OAAO;AAEnB,UAAI,OAAO,SAAS,WAAW;AAC7B,iBAAS,IAAI,GAAG,IAAI,OAAO,SAAS,QAAQ,KAAK;AAC/C,eAAK,IAAI,YAAY,OAAO,SAAS,CAAC,GAAG,IAAI,CAAC;AAAA,QAC/C;AAAA,MACF;AAED,aAAO;AAAA,IACR;AASD,aAAS,iBAAiBC,QAAO;AAC/B,YAAM,SAAS,CAAE;AAIjB,eAAS,IAAI,GAAG,IAAIA,OAAM,QAAQ,KAAK;AACrC,cAAM,OAAOA,OAAM,CAAC;AAEpB,YAAI,KAAK,SAAS;AAAW;AAI7B,cAAM,QAAQ,CAAE;AAChB,cAAM,YAAY,CAAE;AACpB,cAAM,YAAY,CAAE;AAEpB,iBAAS,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ,KAAK;AAC3C,gBAAM,QAAQ,KAAK,OAAO,CAAC;AAE3B,gBAAM,KAAK,MAAM,IAAI;AAKrB,oBAAU,KAAK,MAAM,SAAS,IAAI,KAAK,OAAO,CAAC;AAC/C,oBAAU,KAAK,MAAM,SAAS,IAAI,KAAK,OAAO,CAAC;AAC/C,oBAAU,KAAK,MAAM,SAAS,IAAI,KAAK,OAAO,CAAC;AAE/C,oBAAU,KAAK,MAAM,SAAS,CAAC;AAC/B,oBAAU,KAAK,MAAM,SAAS,CAAC;AAC/B,oBAAU,KAAK,MAAM,SAAS,CAAC;AAC/B,oBAAU,KAAK,MAAM,SAAS,CAAC;AAAA,QAChC;AAED,YAAI,MAAM,sBAAsB;AAC9B,iBAAO,KAAK,IAAIC,MAAAA,oBAAoB,YAAY,KAAK,OAAO,cAAc,OAAO,SAAS,CAAC;AAAA,QAC5F;AAED,YAAI,MAAM,sBAAsB;AAC9B,iBAAO,KAAK,IAAIC,MAAAA,wBAAwB,YAAY,KAAK,OAAO,gBAAgB,OAAO,SAAS,CAAC;AAAA,QAClG;AAAA,MACF;AAED,aAAO,IAAIC,MAAAA,cAAc,aAAa,IAAI,MAAM;AAAA,IACjD;AAKD,aAAS,SAASP,QAAO;AACvB,UAAI;AAEJ,cAAQ,OAAOA,OAAM,MAAK,EAAG,QAAQ,WAAW,GAAG;AAAA,MAAE;AAErD,aAAO;AAAA,IACR;AAED,UAAM,QAAQ;AAEd,UAAM,QAAQ,KAAK,MAAM,UAAU;AAEnC,UAAM,QAAQ,QAAQ,KAAK;AAE3B,UAAM,aAAa,CAAE;AACrB,gBAAY,MAAM,CAAC,GAAG,UAAU;AAEhC,UAAM,YAAY,iBAAiB,KAAK;AAExC,WAAO;AAAA,MACL,UAAU,IAAIQ,MAAQ,SAAC,UAAU;AAAA,MACjC,MAAM;AAAA,IACP;AAAA,EACF;AACH;;"}