Fix #104684: json2fbx.py script creates invalid FBX v7500+ files #104913

Merged
Thomas Barlow merged 3 commits from Mysteryem/blender-addons:fbx_fix_v7500_json2fbx into main 2023-09-26 03:57:19 +02:00
Showing only changes of commit 10028be6ce - Show all commits

View File

@ -12,8 +12,10 @@ import array
import numpy as np import numpy as np
import zlib import zlib
_BLOCK_SENTINEL_LENGTH = 13 _BLOCK_SENTINEL_LENGTH = ...
_BLOCK_SENTINEL_DATA = (b'\0' * _BLOCK_SENTINEL_LENGTH) _BLOCK_SENTINEL_DATA = ...
_ELEM_META_FORMAT = ...
_ELEM_META_SIZE = ...
_IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little') _IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little')
_HEAD_MAGIC = b'Kaydara FBX Binary\x20\x20\x00\x1a\x00' _HEAD_MAGIC = b'Kaydara FBX Binary\x20\x20\x00\x1a\x00'
@ -219,7 +221,7 @@ class FBXElem:
assert(self._end_offset == -1) assert(self._end_offset == -1)
assert(self._props_length == -1) assert(self._props_length == -1)
offset += 12 # 3 uints offset += _ELEM_META_SIZE # 3 uints (or 3 ulonglongs for FBX 7500 and later)
offset += 1 + len(self.id) # len + idname offset += 1 + len(self.id) # len + idname
props_length = 0 props_length = 0
@ -250,7 +252,7 @@ class FBXElem:
assert(self._end_offset != -1) assert(self._end_offset != -1)
assert(self._props_length != -1) assert(self._props_length != -1)
write(pack('<3I', self._end_offset, len(self.props), self._props_length)) write(pack(_ELEM_META_FORMAT, self._end_offset, len(self.props), self._props_length))
write(bytes((len(self.id),))) write(bytes((len(self.id),)))
write(self.id) write(self.id)
@ -263,7 +265,7 @@ class FBXElem:
if tell() != self._end_offset: if tell() != self._end_offset:
raise IOError("scope length not reached, " raise IOError("scope length not reached, "
"something is wrong (%d)" % (end_offset - tell())) "something is wrong (%d)" % (self._end_offset - tell()))
def _write_children(self, write, tell, is_last): def _write_children(self, write, tell, is_last):
if self.elems: if self.elems:
@ -308,6 +310,27 @@ def _write_timedate_hack(elem_root):
print("Missing fields!") print("Missing fields!")
# FBX 7500 (aka FBX2016) introduces incompatible changes at binary level:
# * The NULL block marking end of nested stuff switches from 13 bytes long to 25 bytes long.
# * The FBX element metadata (end_offset, prop_count and prop_length) switch from uint32 to uint64.
def init_version(fbx_version):
global _BLOCK_SENTINEL_LENGTH, _BLOCK_SENTINEL_DATA, _ELEM_META_FORMAT, _ELEM_META_SIZE
_BLOCK_SENTINEL_LENGTH = ...
_BLOCK_SENTINEL_DATA = ...
_ELEM_META_FORMAT = ...
_ELEM_META_SIZE = ...
if fbx_version < 7500:
_ELEM_META_FORMAT = '<3I'
_ELEM_META_SIZE = 12
else:
_ELEM_META_FORMAT = '<3Q'
_ELEM_META_SIZE = 24
_BLOCK_SENTINEL_LENGTH = _ELEM_META_SIZE + 1
_BLOCK_SENTINEL_DATA = (b'\0' * _BLOCK_SENTINEL_LENGTH)
def write(fn, elem_root, version): def write(fn, elem_root, version):
assert(elem_root.id == b'') assert(elem_root.id == b'')
@ -315,6 +338,8 @@ def write(fn, elem_root, version):
write = f.write write = f.write
tell = f.tell tell = f.tell
init_version(version)
write(_HEAD_MAGIC) write(_HEAD_MAGIC)
write(pack('<I', version)) write(pack('<I', version))