Files
armorpaint/Sources/arm/format/FbxBinaryParser.hx
T

200 lines
4.1 KiB
Haxe
Raw Normal View History

2019-07-17 12:40:24 +02:00
package arm.format;
import arm.format.FbxLibrary;
class FbxBinaryParser {
2019-12-09 00:28:10 +01:00
var pos: Int;
var blob: kha.Blob;
2019-07-17 12:40:24 +02:00
2019-12-09 00:28:10 +01:00
var version: Int;
var root: FbxNode;
2019-07-17 12:40:24 +02:00
2019-12-09 00:28:10 +01:00
function new(blob: kha.Blob) {
2019-07-17 12:40:24 +02:00
this.blob = blob;
pos = 0;
var magic = "Kaydara FBX Binary\x20\x20\x00\x1a\x00";
var valid = readChars(magic.length) == magic;
if (!valid) return;
var version = read32();
2019-10-06 19:03:59 +02:00
root = {
2019-07-17 12:40:24 +02:00
name : "Root",
props : [PInt(0), PString("Root"), PString("Root")],
childs : parseNodes()
};
}
2019-12-09 00:28:10 +01:00
public static function parse(blob: kha.Blob): FbxNode {
2019-07-17 12:40:24 +02:00
return new FbxBinaryParser(blob).root;
}
2019-12-09 00:28:10 +01:00
function parseArray(readVal: Void->Dynamic, isFloat = false): FbxProp {
2019-07-17 12:40:24 +02:00
var len = read32();
var encoding = read32();
var compressedLen = read32();
var endPos = pos + compressedLen;
2019-12-09 00:28:10 +01:00
var _blob = blob;
2019-07-17 12:40:24 +02:00
if (encoding != 0) {
pos += 2;
var input = haxe.io.UInt8Array.fromBytes(blob.sub(pos, compressedLen).toBytes());
var output = arm.format.pako.Pako.inflate(input, { raw: true });
blob = kha.Blob.fromBytes(output.view.buffer);
pos = 0;
}
var res = isFloat ? parseArrayf(readVal, len) : parseArrayi(readVal, len);
if (encoding != 0) {
pos = endPos;
2019-12-09 00:28:10 +01:00
blob = _blob;
2019-07-17 12:40:24 +02:00
}
return res;
}
2019-12-09 00:28:10 +01:00
function parseArrayf(readVal: Void->Dynamic, len: Int): FbxProp {
var res: Array<Float> = [];
2019-07-17 12:40:24 +02:00
for (i in 0...len) res.push(readVal());
return PFloats(res);
}
2019-12-09 00:28:10 +01:00
function parseArrayi(readVal: Void->Dynamic, len: Int): FbxProp {
var res: Array<Int> = [];
2019-07-17 12:40:24 +02:00
for (i in 0...len) res.push(readVal());
return PInts(res);
}
2019-12-09 00:28:10 +01:00
function parseProp(): FbxProp {
2019-07-17 12:40:24 +02:00
switch (readChar()) {
2019-12-09 00:28:10 +01:00
case "C":
2019-07-17 12:40:24 +02:00
return PString(readChar());
2019-12-09 00:28:10 +01:00
case "Y":
2019-07-17 12:40:24 +02:00
return PInt(read16());
2019-12-09 00:28:10 +01:00
case "I":
2019-07-17 12:40:24 +02:00
return PInt(read32());
2019-12-09 00:28:10 +01:00
case "L":
2019-07-17 12:40:24 +02:00
return PInt(read64());
2019-12-09 00:28:10 +01:00
case "F":
2019-07-17 12:40:24 +02:00
return PFloat(readf32());
2019-12-09 00:28:10 +01:00
case "D":
2019-07-17 12:40:24 +02:00
return PFloat(readf64());
2019-12-09 00:28:10 +01:00
case "f":
2019-07-17 12:40:24 +02:00
return parseArray(readf32, true);
2019-12-09 00:28:10 +01:00
case "d":
2019-07-17 12:40:24 +02:00
return parseArray(readf64, true);
2019-12-09 00:28:10 +01:00
case "l":
2019-07-17 12:40:24 +02:00
return parseArray(read64);
2019-12-09 00:28:10 +01:00
case "i":
2019-07-17 12:40:24 +02:00
return parseArray(read32);
2019-12-09 00:28:10 +01:00
case "b":
2019-07-17 12:40:24 +02:00
return parseArray(readBool);
2019-12-09 00:28:10 +01:00
case "S":
2019-07-17 12:40:24 +02:00
var len = read32();
return PString(readChars(len));
2019-12-09 00:28:10 +01:00
case "R":
2019-07-17 12:40:24 +02:00
var b = readBytes(read32());
return null;
default:
return null;
}
}
2019-12-09 00:28:10 +01:00
function parseNode(): FbxNode {
2019-07-17 12:40:24 +02:00
var endPos = read32();
var numProps = read32();
var propListLen = read32();
var nameLen = read8();
var name = nameLen == 0 ? "" : readChars(nameLen);
if (endPos == 0) return null; // Null node
2019-12-09 00:28:10 +01:00
var props: Array<FbxProp> = null;
2019-07-17 12:40:24 +02:00
if (numProps > 0) props = [];
for (i in 0...numProps) props.push(parseProp());
2019-12-09 00:28:10 +01:00
var childs: Array<FbxNode> = null;
2019-07-17 12:40:24 +02:00
var listLen = endPos - pos;
if (listLen > 0) {
childs = [];
while (true) {
var nested = parseNode();
nested == null ? break : childs.push(nested);
}
}
return { name: name, props: props, childs: childs };
}
2019-12-09 00:28:10 +01:00
function parseNodes(): Array<FbxNode> {
2019-07-17 12:40:24 +02:00
var nodes = [];
while (true) {
var n = parseNode();
n == null ? break : nodes.push(n);
}
return nodes;
}
2019-12-09 00:28:10 +01:00
function read8(): Int {
2019-07-17 12:40:24 +02:00
var i = blob.readU8(pos);
pos += 1;
return i;
}
2019-12-09 00:28:10 +01:00
function read16(): Int {
2019-07-17 12:40:24 +02:00
var i = blob.readS16LE(pos);
pos += 2;
return i;
}
2019-12-09 00:28:10 +01:00
function read32(): Int {
2019-07-17 12:40:24 +02:00
var i = blob.bytes.getInt32(pos);
// var i = blob.readS32LE(pos); // Result sometimes off by 1?
pos += 4;
return i;
}
2019-12-09 00:28:10 +01:00
function read64(): Int {
2019-07-17 12:40:24 +02:00
var i1 = read32();
var i2 = read32();
// return cast haxe.Int64.make(i1, i2);
return i1;
}
2019-12-09 00:28:10 +01:00
function readf32(): Float {
2019-07-17 12:40:24 +02:00
var f = blob.readF32LE(pos);
pos += 4;
return f;
}
2019-12-09 00:28:10 +01:00
function readf64(): Float {
2019-07-17 12:40:24 +02:00
var i1 = read32();
var i2 = read32();
return haxe.io.FPHelper.i64ToDouble(i1, i2); // LE
}
2019-12-09 00:28:10 +01:00
function readString(): String {
var s = "";
2019-07-17 12:40:24 +02:00
while (true) {
var ch = read8();
if (ch == 0) break;
s += String.fromCharCode(ch);
}
return s;
}
2019-12-09 00:28:10 +01:00
function readChars(len: Int): String {
var s = "";
2019-07-17 12:40:24 +02:00
for (i in 0...len) s += readChar();
return s;
}
2019-12-09 00:28:10 +01:00
function readChar(): String {
2019-07-17 12:40:24 +02:00
return String.fromCharCode(read8());
}
2019-12-09 00:28:10 +01:00
function readBool(): Int {
2019-07-17 12:40:24 +02:00
return read8(); // return read8() == 1;
}
2019-12-09 00:28:10 +01:00
function readBytes(len: Int): kha.Blob {
2019-07-17 12:40:24 +02:00
var b = blob.sub(pos, len);
pos += len;
return b;
}
}