content/hifi-content/dave/walk-tools/walkTools/libraries/murayama-bvh-parser-hifi-version.js
2022-02-13 22:49:05 +01:00

252 lines
6.8 KiB
JavaScript

// Ryo Murayama's bvh parser: https://github.com/hitsujiwool/bvh
// シンタックスハイライトが崩れるので修正
// Copyright (c) 2012 hitsujiwool
//
BVH = function (parser) {
function iter(node, res) {
if (res[node.id]) throw new Error('Error: Node ' + node.id + ' already exists');
res[node.id] = node;
for (var i = 0, len = node.children.length; i < len; i++) {
iter(node.children[i], res);
}
return res;
}
this.root = parser.currentNode;
this.numFrames = parser.numFrames;
this.frameTime = parser.frameTime;
this.nodeList = this.root.flatten();
this._nodeIndex = iter(this.root, {});
}
BVH.prototype.at = function(nthFrame) {
nthFrame = nthFrame | 0;
for (var prop in this._nodeIndex) {
this._nodeIndex[prop].at(nthFrame);
}
return this;
};
BVH.prototype.of = function(id) {
return this._nodeIndex[id];
};
Parser = function(lines) {
this._lines = lines;
this._lineNumber = -1;
this.currentNode = null;
this.next();
};
Parser.prototype.parse = function() {
this
.expect('HIERARCHY')
.root()
.motion();
if (this.get()) throw new Error('Parse error: Invalid token ' + this.get() + '.');
return this;
};
Parser.prototype.root = function() {
var that = this,
node;
this
.expect('ROOT', function(line) {
var nodeName = line.split(/\s+/)[1];
if (nodeName.contains('mixamorig_')) {
nodeName = nodeName.substring(10);
}
node = new BVHNode(nodeName);
that.currentNode = node;
})
.expect('{')
.offset()
.channels();
while (this.accept('JOINT')) {
this.joint();
this.currentNode = node;
}
if (this.accept('End')) this.end();
this.expect('}');
return this;
};
Parser.prototype.joint = function() {
var that = this,
node;
this
.expect('JOINT', function(line) {
var nodeName = line.split(/\s+/)[1];
if (nodeName.contains('mixamorig_')) {
nodeName = nodeName.substring(10);
}
node = new BVHNode(nodeName);
node.parent = that.currentNode;
that.currentNode.children.push(node);
that.currentNode = node;
})
.expect('{')
.offset()
.channels();
while (this.accept('JOINT')) {
this.joint();
this.currentNode = node;
}
if (this.accept('End')) this.end();
this.expect('}');
return this;
};
Parser.prototype.end = function() {
if (this.get(0) !== 'End Site') throw new Error('Parse error: End Site expected, but ' + this.get() + '.');
this
.next()
.expect('{')
.endOffset()
.expect('}');
return this;
};
Parser.prototype.offset = function() {
var offsets = this.get().split(/\s+/).slice(1);
if (offsets.length !== 3) throw new Error('Parse error: Invalid offset number.');
this.currentNode.offsetX = +offsets[0];
this.currentNode.offsetY = +offsets[1];
this.currentNode.offsetZ = +offsets[2];
return this.next();
};
Parser.prototype.endOffset = function() {
var offsets = this.get().split(/\s+/).slice(1);
if (offsets.length !== 3) throw new Error('Parse error: Invalid offset number.');
this.currentNode.hasEnd = true;
this.currentNode.endOffsetX = +offsets[0];
this.currentNode.endOffsetY = +offsets[1];
this.currentNode.endOffsetZ = +offsets[2];
return this.next();
};
Parser.prototype.channels = function() {
var pieces = this.get(0).split(/\s+/),
n = parseInt(pieces[1], 10),
channels = pieces.slice(2);
if (n !== channels.length) throw new Error('Parse error: ' + n + ' expected for number of channels, but ' + channels.length + '.');
this.currentNode.channels = channels;
return this.next();
};
Parser.prototype.motion = function() {
this._nodeList = this.currentNode.flatten();
this
.expect('MOTION')
.frames()
.frameTime();
for (var i = 0, len = this.numFrames; i < len; i++) {
this.frameValues();
}
return this;
};
Parser.prototype.frames = function() {
var match = /^Frames:\s+(\d+)\s*$/.exec(this.get());
if (match !== null) {
this.numFrames = +match[1];
} else {
throw new Error('Parse error: Cannot find valid number of frames');
}
return this.next();
};
Parser.prototype.frameTime = function() {
var match = /^Frame Time:\s+([0-9.]+)$/.exec(this.get());
if (match !== null) {
this.frameTime = +match[1];
} else {
throw new Error('Parse error: Cannot find valid frametime');
}
return this.next();
};
Parser.prototype.frameValues = function() {
var values = this.get().split(/\s+/),
that = this;
this._nodeList.forEach(function(node) {
if (values.length < node.channels.length) throw new Error('Parse error: Too short motion values per frame');
node.frames.push(values.splice(0, node.channels.length).map(function(str) { return +str; }));
});
if (values.length > 0) throw new Error('Parse error: Too much motion values per frame');
return this.next();
};
Parser.prototype.expect = function(state, callback) {
if (this.accept(state)) {
if (callback) callback(this.get());
return this.next();
} else {
throw new Error('Parse error: Unexpected token ' + this.get() + ' for ' + state);
}
};
Parser.prototype.accept = function(state) {
var line = this.get();
if (line === undefined) return false;
return line.split(/\s+/)[0] == state;
};
Parser.prototype.next = function() {
do {
this._lineNumber++;
} while (this.get() === '')
return this;
};
Parser.prototype.get = function() {
if (typeof this._lines[this._lineNumber] === 'undefined') {
return undefined;
} else {
return this._lines[this._lineNumber].replace(/(^\s+)|(\s+$)/g, "");
}
};
function BVHNode(nodeName) {
this.id = nodeName;
this.children = [];
this.parent = null;
this.frames = [];
this.channels = null;
this.hasEnd = false;
}
BVHNode.prototype.at = function(nthFrame) {
var that = this;
nthFrame = nthFrame | 0;
this.currentFrame = nthFrame;
var frame = this.frames[nthFrame - 1];
this.channels.forEach(function(channel, i) {
var prop = channel.slice(1) + channel.slice(0, 1).toUpperCase();
that[prop] = frame[i];
});
return this;
};
BVHNode.prototype.flatten = function() {
function iter(node) {
var tmp = [node];
for (var i = 0, len = node.children.length; i < len; i++) {
tmp = tmp.concat(iter(node.children[i]));
}
return tmp;
};
return iter(this);
};
BVHNode.prototype.toString = function() {
function iter(node, indent) {
var tmp = [indent + '- ' + node.id];
for (var i = 0, len = node.children.length; i < len; i++) {
tmp = tmp.concat(iter(node.children[i], indent + ' '));
}
return tmp;
};
return iter(this, '').join("\n");
};