Skip to content
Snippets Groups Projects
Commit 22b54f61 authored by Bastien Montagne's avatar Bastien Montagne
Browse files

FBX: Fix fbx2json tool for 7500 FBX files (FBX2016).

Based on patch from T49822, thanks a bunch for investigation.

Change is actually pretty limited - 7500 now uses some uint64 instead of
uint32 integers as some root element info (like size etc.), and
accordingly raised the 'stop nested data' marker from 13 to 25 NULL
bytes.

Next step: check if we can make actual importer load FBX2016 files that
simply!
parent 9b58f808
No related branches found
No related tags found
No related merge requests found
...@@ -75,9 +75,9 @@ import zlib ...@@ -75,9 +75,9 @@ import zlib
# at the end of each nested block, there is a NUL record to indicate # at the end of each nested block, there is a NUL record to indicate
# that the sub-scope exists (i.e. to distinguish between P: and P : {}) # that the sub-scope exists (i.e. to distinguish between P: and P : {})
# this NUL record is 13 bytes long. _BLOCK_SENTINEL_LENGTH = ...
_BLOCK_SENTINEL_LENGTH = 13 _BLOCK_SENTINEL_DATA = ...
_BLOCK_SENTINEL_DATA = (b'\0' * _BLOCK_SENTINEL_LENGTH) read_fbx_elem_uint = ...
_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'
from collections import namedtuple from collections import namedtuple
...@@ -88,6 +88,8 @@ del namedtuple ...@@ -88,6 +88,8 @@ del namedtuple
def read_uint(read): def read_uint(read):
return unpack(b'<I', read(4))[0] return unpack(b'<I', read(4))[0]
def read_uint64(read):
return unpack(b'<Q', read(8))[0]
def read_ubyte(read): def read_ubyte(read):
return unpack(b'B', read(1))[0] return unpack(b'B', read(1))[0]
...@@ -137,16 +139,34 @@ read_data_dict = { ...@@ -137,16 +139,34 @@ read_data_dict = {
} }
# 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, read_fbx_elem_uint
assert(_BLOCK_SENTINEL_LENGTH == ...)
assert(_BLOCK_SENTINEL_DATA == ...)
if fbx_version < 7500:
_BLOCK_SENTINEL_LENGTH = 13
read_fbx_elem_uint = read_uint
else:
_BLOCK_SENTINEL_LENGTH = 25
read_fbx_elem_uint = read_uint64
_BLOCK_SENTINEL_DATA = (b'\0' * _BLOCK_SENTINEL_LENGTH)
def read_elem(read, tell, use_namedtuple): def read_elem(read, tell, use_namedtuple):
# [0] the offset at which this block ends # [0] the offset at which this block ends
# [1] the number of properties in the scope # [1] the number of properties in the scope
# [2] the length of the property list # [2] the length of the property list
end_offset = read_uint(read) end_offset = read_fbx_elem_uint(read)
if end_offset == 0: if end_offset == 0:
return None return None
prop_count = read_uint(read) prop_count = read_fbx_elem_uint(read)
prop_length = read_uint(read) prop_length = read_fbx_elem_uint(read)
elem_id = read_string_ubyte(read) # elem name of the scope/key elem_id = read_string_ubyte(read) # elem name of the scope/key
elem_props_type = bytearray(prop_count) # elem property types elem_props_type = bytearray(prop_count) # elem property types
...@@ -198,8 +218,7 @@ def parse(fn, use_namedtuple=True): ...@@ -198,8 +218,7 @@ def parse(fn, use_namedtuple=True):
raise IOError("Invalid header") raise IOError("Invalid header")
fbx_version = read_uint(read) fbx_version = read_uint(read)
if fbx_version >= 7500: init_version(fbx_version)
raise IOError("Unsupported FBX version (%d), binary format is incompatible!" % fbx_version)
while True: while True:
elem = read_elem(read, tell, use_namedtuple) elem = read_elem(read, tell, use_namedtuple)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment