FbxBinaryParser.hx 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. package arm.format;
  2. import arm.format.FbxLibrary;
  3. class FbxBinaryParser {
  4. var pos: Int;
  5. var blob: kha.Blob;
  6. var version: Int;
  7. var is64: Bool;
  8. var root: FbxNode;
  9. function new(blob: kha.Blob) {
  10. this.blob = blob;
  11. pos = 0;
  12. var magic = "Kaydara FBX Binary\x20\x20\x00\x1a\x00";
  13. var valid = readChars(magic.length) == magic;
  14. if (!valid) return;
  15. var version = read32();
  16. is64 = version >= 7500;
  17. root = {
  18. name: "Root",
  19. props: [PInt(0), PString("Root"), PString("Root")],
  20. childs: parseNodes()
  21. };
  22. }
  23. public static function parse(blob: kha.Blob): FbxNode {
  24. return new FbxBinaryParser(blob).root;
  25. }
  26. function parseArray(readVal: Void->Dynamic, isFloat = false): FbxProp {
  27. var len = read32();
  28. var encoding = read32();
  29. var compressedLen = read32();
  30. var endPos = pos + compressedLen;
  31. var _blob = blob;
  32. if (encoding != 0) {
  33. pos += 2;
  34. var input = blob.sub(pos, compressedLen).toBytes().getData();
  35. blob = kha.Blob.fromBytes(haxe.io.Bytes.ofData(Krom.inflate(input, true)));
  36. pos = 0;
  37. }
  38. var res = isFloat ? parseArrayf(readVal, len) : parseArrayi(readVal, len);
  39. if (encoding != 0) {
  40. pos = endPos;
  41. blob = _blob;
  42. }
  43. return res;
  44. }
  45. function parseArrayf(readVal: Void->Dynamic, len: Int): FbxProp {
  46. var res: Array<Float> = [];
  47. for (i in 0...len) res.push(readVal());
  48. return PFloats(res);
  49. }
  50. function parseArrayi(readVal: Void->Dynamic, len: Int): FbxProp {
  51. var res: Array<Int> = [];
  52. for (i in 0...len) res.push(readVal());
  53. return PInts(res);
  54. }
  55. function parseProp(): FbxProp {
  56. switch (readChar()) {
  57. case "C":
  58. return PString(readChar());
  59. case "Y":
  60. return PInt(read16());
  61. case "I":
  62. return PInt(read32());
  63. case "L":
  64. return PInt(read64());
  65. case "F":
  66. return PFloat(readf32());
  67. case "D":
  68. return PFloat(readf64());
  69. case "f":
  70. return parseArray(readf32, true);
  71. case "d":
  72. return parseArray(readf64, true);
  73. case "l":
  74. return parseArray(read64);
  75. case "i":
  76. return parseArray(read32);
  77. case "b":
  78. return parseArray(readBool);
  79. case "S":
  80. var len = read32();
  81. return PString(readChars(len));
  82. case "R":
  83. var b = readBytes(read32());
  84. return null;
  85. default:
  86. return null;
  87. }
  88. }
  89. function parseNode(): FbxNode {
  90. var endPos = 0;
  91. var numProps = 0;
  92. var propListLen = 0;
  93. if (is64) {
  94. endPos = read64();
  95. numProps = read64();
  96. propListLen = read64();
  97. }
  98. else {
  99. endPos = read32();
  100. numProps = read32();
  101. propListLen = read32();
  102. }
  103. var nameLen = read8();
  104. var name = nameLen == 0 ? "" : readChars(nameLen);
  105. if (endPos == 0) return null; // Null node
  106. var props: Array<FbxProp> = null;
  107. if (numProps > 0) props = [];
  108. for (i in 0...numProps) props.push(parseProp());
  109. var childs: Array<FbxNode> = null;
  110. var listLen = endPos - pos;
  111. if (listLen > 0) {
  112. childs = [];
  113. while (true) {
  114. var nested = parseNode();
  115. nested == null ? break : childs.push(nested);
  116. }
  117. }
  118. return { name: name, props: props, childs: childs };
  119. }
  120. function parseNodes(): Array<FbxNode> {
  121. var nodes = [];
  122. while (true) {
  123. var n = parseNode();
  124. n == null ? break : nodes.push(n);
  125. }
  126. return nodes;
  127. }
  128. function read8(): Int {
  129. var i = blob.readU8(pos);
  130. pos += 1;
  131. return i;
  132. }
  133. function read16(): Int {
  134. var i = blob.readS16LE(pos);
  135. pos += 2;
  136. return i;
  137. }
  138. function read32(): Int {
  139. var i = blob.bytes.getInt32(pos);
  140. // var i = blob.readS32LE(pos); // Result sometimes off by 1?
  141. pos += 4;
  142. return i;
  143. }
  144. function read64(): Int {
  145. var i1 = read32();
  146. var i2 = read32();
  147. // return cast haxe.Int64.make(i1, i2);
  148. return i1;
  149. }
  150. function readf32(): Float {
  151. var f = blob.readF32LE(pos);
  152. pos += 4;
  153. return f;
  154. }
  155. function readf64(): Float {
  156. var i1 = read32();
  157. var i2 = read32();
  158. return haxe.io.FPHelper.i64ToDouble(i1, i2); // LE
  159. }
  160. function readString(): String {
  161. var s = "";
  162. while (true) {
  163. var ch = read8();
  164. if (ch == 0) break;
  165. s += String.fromCharCode(ch);
  166. }
  167. return s;
  168. }
  169. function readChars(len: Int): String {
  170. var s = "";
  171. for (i in 0...len) s += readChar();
  172. return s;
  173. }
  174. function readChar(): String {
  175. return String.fromCharCode(read8());
  176. }
  177. function readBool(): Int {
  178. return read8(); // return read8() == 1;
  179. }
  180. function readBytes(len: Int): kha.Blob {
  181. var b = blob.sub(pos, len);
  182. pos += len;
  183. return b;
  184. }
  185. }