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
2 changed files with 31 additions and 6 deletions

View File

@ -5,7 +5,7 @@
bl_info = {
"name": "FBX format",
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem",
"version": (5, 8, 2),
"version": (5, 8, 3),
"blender": (3, 6, 0),
"location": "File > Import-Export",
"description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions",

View File

@ -12,8 +12,10 @@ import array
import numpy as np
import zlib
_BLOCK_SENTINEL_LENGTH = 13
_BLOCK_SENTINEL_DATA = (b'\0' * _BLOCK_SENTINEL_LENGTH)
_BLOCK_SENTINEL_LENGTH = ...
_BLOCK_SENTINEL_DATA = ...
_ELEM_META_FORMAT = ...
_ELEM_META_SIZE = ...
_IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little')
_HEAD_MAGIC = b'Kaydara FBX Binary\x20\x20\x00\x1a\x00'
@ -227,7 +229,7 @@ class FBXElem:
assert(self._end_offset == -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
props_length = 0
@ -258,7 +260,7 @@ class FBXElem:
assert(self._end_offset != -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(self.id)
@ -271,7 +273,7 @@ class FBXElem:
if tell() != self._end_offset:
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):
if self.elems:
@ -316,6 +318,27 @@ def _write_timedate_hack(elem_root):
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):
assert(elem_root.id == b'')
@ -323,6 +346,8 @@ def write(fn, elem_root, version):
write = f.write
tell = f.tell
init_version(version)
write(_HEAD_MAGIC)
write(pack('<I', version))