[Bf-extensions-cvs] [3879603] master: Initial commit of new FBX 7.4 binary exporter

Bastien Montagne noreply at git.blender.org
Wed Mar 12 21:05:15 CET 2014


Commit: 3879603620c4241bec612665dd97ab4b598559c6
Author: Bastien Montagne
Date:   Wed Mar 12 20:22:51 2014 +0100
https://developer.blender.org/rBA3879603620c4241bec612665dd97ab4b598559c6

Initial commit of new FBX 7.4 binary exporter

What to expect:
* Static export of empties, meshes, cameras and lamps, as well as materials and (image!) textures should work OK.
  There are a few advanced topics still TODO regarding meshes and mat/tex, though.
* Custom properties from objects/meshes/lamps/cameras/armatures/bones/materials/textures are exported too (only simple ones, ints/floats/strings).
* Armature export: this needs testing by people having *native* FBX aplications, linking between bones and meshes seems to work, but I have doubts about bones orientations.
* Animation: still a complete TODO.

Note that old FBX ASCII 6.1 exporter is still available (top dropdown in exporter's UI).

Many thanks to Campbell, which did the ground work of decyphering FBX binary format and wrote basic code to read/write it.

===================================================================

M	io_scene_fbx/__init__.py
A	io_scene_fbx/data_types.py
A	io_scene_fbx/encode_bin.py
M	io_scene_fbx/export_fbx.py
A	io_scene_fbx/export_fbx_bin.py
M	io_scene_fbx/import_fbx.py
A	io_scene_fbx/json2fbx.py
M	io_scene_fbx/parse_fbx.py

===================================================================

diff --git a/io_scene_fbx/__init__.py b/io_scene_fbx/__init__.py
index 1d7ba1c..8adb5eb 100644
--- a/io_scene_fbx/__init__.py
+++ b/io_scene_fbx/__init__.py
@@ -16,12 +16,12 @@
 #
 # ##### END GPL LICENSE BLOCK #####
 
-# <pep8-80 compliant>
+# <pep8 compliant>
 
 bl_info = {
     "name": "Autodesk FBX format",
-    "author": "Campbell Barton",
-    "blender": (2, 59, 0),
+    "author": "Campbell Barton, Bastien Montagne",
+    "blender": (2, 70, 0),
     "location": "File > Import-Export",
     "description": "Export FBX meshes, UV's, vertex colors, materials, "
                    "textures, cameras, lamps and actions",
@@ -37,6 +37,8 @@ if "bpy" in locals():
     import imp
     if "import_fbx" in locals():
         imp.reload(import_fbx)
+    if "export_fbx_bin" in locals():
+        imp.reload(export_fbx_bin)
     if "export_fbx" in locals():
         imp.reload(export_fbx)
 
@@ -148,6 +150,15 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
     # List of operator properties, the attributes will be assigned
     # to the class instance from the operator settings before calling.
 
+    version = EnumProperty(
+            items=(('BIN7400', "FBX 7.4 binary", "Newer 7.4 binary version, still in development (no animation yet)"),
+                   ('ASCII6100', "FBX 6.1 ASCII", "Legacy 6.1 ascii version"),
+                  ),
+            name="Exporter Version",
+            description="Choose which version of the exporter to use",
+            default='BIN7400',
+            )
+
     use_selection = BoolProperty(
             name="Selected Objects",
             description="Export selected objects on visible layers",
@@ -211,7 +222,18 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
             )
 
     use_mesh_edges = BoolProperty(
-            name="Include Edges",
+            name="Include Loose Edges",
+            default=False,
+            )
+    use_tspace = BoolProperty(
+            name="Include Tangent Space",
+            description=("Add binormal and tangent vectors, together with normal they form the tangent space "
+                         "(will only work correctly with tris/quads only meshes!)"),
+            default=False,
+            )
+    use_custom_properties = BoolProperty(
+            name="Custom Properties",
+            description="Export custom properties",
             default=False,
             )
     use_armature_deform_only = BoolProperty(
@@ -251,6 +273,11 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
             default=6.0,  # default: 10^-4 frames.
             )
     path_mode = path_reference_mode
+    embed_textures = BoolProperty(
+            name="Embed Textures",
+            description="Embed textures in FBX binary file (only for \"Copy\" path mode!)",
+            default=False,
+            )
     batch_mode = EnumProperty(
             name="Batch Mode",
             items=(('OFF', "Off", "Active scene to file"),
@@ -284,17 +311,19 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
                                          to_up=self.axis_up,
                                          ).to_4x4())
 
-        keywords = self.as_keywords(ignore=("axis_forward",
-                                            "axis_up",
-                                            "global_scale",
+        keywords = self.as_keywords(ignore=("global_scale",
                                             "check_existing",
                                             "filter_glob",
                                             ))
 
         keywords["global_matrix"] = global_matrix
 
-        from . import export_fbx
-        return export_fbx.save(self, context, **keywords)
+        if self.version == 'BIN7400':
+            from . import export_fbx_bin
+            return export_fbx_bin.save(self, context, **keywords)
+        else:
+            from . import export_fbx
+            return export_fbx.save(self, context, **keywords)
 
 
 def menu_func_import(self, context):
diff --git a/io_scene_fbx/data_types.py b/io_scene_fbx/data_types.py
new file mode 100644
index 0000000..3a505be
--- /dev/null
+++ b/io_scene_fbx/data_types.py
@@ -0,0 +1,74 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# Script copyright (C) 2006-2012, assimp team
+# Script copyright (C) 2013 Blender Foundation
+
+BOOL = b'C'[0]
+INT16 = b'Y'[0]
+INT32 = b'I'[0]
+INT64 = b'L'[0]
+FLOAT32 = b'F'[0]
+FLOAT64 = b'D'[0]
+BYTES = b'R'[0]
+STRING = b'S'[0]
+INT32_ARRAY = b'i'[0]
+INT64_ARRAY = b'l'[0]
+FLOAT32_ARRAY = b'f'[0]
+FLOAT64_ARRAY = b'd'[0]
+BOOL_ARRAY = b'b'[0]
+BYTE_ARRAY = b'c'[0]
+
+# array types - actual length may vary (depending on underlying C implementation)!
+import array
+
+# For now, bytes and bool are assumed always 1byte.
+ARRAY_BOOL = 'b'
+ARRAY_BYTE = 'B'
+
+ARRAY_INT32 = None
+ARRAY_INT64 = None
+for _t in 'ilq':
+    size = array.array(_t).itemsize
+    if size == 4:
+        ARRAY_INT32 = _t
+    elif size == 8:
+        ARRAY_INT64 = _t
+    if ARRAY_INT32 and ARRAY_INT64:
+        break
+if not ARRAY_INT32:
+    raise Exception("Impossible to get a 4-bytes integer type for array!")
+if not ARRAY_INT64:
+    raise Exception("Impossible to get an 8-bytes integer type for array!")
+
+ARRAY_FLOAT32 = None
+ARRAY_FLOAT64 = None
+for _t in 'fd':
+    size = array.array(_t).itemsize
+    if size == 4:
+        ARRAY_FLOAT32 = _t
+    elif size == 8:
+        ARRAY_FLOAT64 = _t
+    if ARRAY_FLOAT32 and ARRAY_FLOAT64:
+        break
+if not ARRAY_FLOAT32:
+    raise Exception("Impossible to get a 4-bytes float type for array!")
+if not ARRAY_FLOAT64:
+    raise Exception("Impossible to get an 8-bytes float type for array!")
diff --git a/io_scene_fbx/encode_bin.py b/io_scene_fbx/encode_bin.py
new file mode 100644
index 0000000..5cd3b74
--- /dev/null
+++ b/io_scene_fbx/encode_bin.py
@@ -0,0 +1,320 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# Script copyright (C) 2013 Campbell Barton
+
+try:
+    from . import data_types
+except:
+    import data_types
+
+from struct import pack
+import array
+import zlib
+
+_BLOCK_SENTINEL_LENGTH = 13
+_BLOCK_SENTINEL_DATA = (b'\0' * _BLOCK_SENTINEL_LENGTH)
+_IS_BIG_ENDIAN = (__import__("sys").byteorder != 'little')
+_HEAD_MAGIC = b'Kaydara FBX Binary\x20\x20\x00\x1a\x00'
+
+# fbx has very strict CRC rules, all based on file timestamp
+# until we figure these out, write files at a fixed time. (workaround!)
+
+# Assumes: CreationTime
+_TIME_ID = b'1970-01-01 10:00:00:000'
+_FILE_ID = b'\x28\xb3\x2a\xeb\xb6\x24\xcc\xc2\xbf\xc8\xb0\x2a\xa9\x2b\xfc\xf1'
+_FOOT_ID = b'\xfa\xbc\xab\x09\xd0\xc8\xd4\x66\xb1\x76\xfb\x83\x1c\xf7\x26\x7e'
+
+
+class FBXElem:
+    __slots__ = (
+        "id",
+        "props",
+        "props_type",
+        "elems",
+
+        "_props_length",  # combine length of props
+        "_end_offset",  # byte offset from the start of the file.
+        )
+
+    def __init__(self, id):
+        assert(len(id) < 256)  # length must fit in a uint8
+        self.id = id
+        self.props = []
+        self.props_type = bytearray()
+        self.elems = []
+        self._end_offset = -1
+        self._props_length = -1
+
+    def add_bool(self, data):
+        assert(isinstance(data, bool))
+        data = pack('?', data)
+
+        self.props_type.append(data_types.BOOL)
+        self.props.append(data)
+
+    def add_int16(self, data):
+        assert(isinstance(data, int))
+        data = pack('<h', data)
+
+        self.props_type.append(data_types.INT16)
+        self.props.append(data)
+
+    def add_int32(self, data):
+        assert(isinstance(data, int))
+        data = pack('<i', data)
+
+        self.props_type.append(data_types.INT32)
+        self.props.append(data)
+
+    def add_int64(self, data):
+        assert(isinstance(data, int))
+        data = pack('<q', data)
+
+        self.props_type.append(data_types.INT64)
+        self.props.append(data)
+
+    def add_float32(self, data):
+        assert(isinstance(data, float))
+        data = pack('<f', data)
+
+        self.props_type.append(data_types.FLOAT32)
+        self.props.append(data)
+
+    def add_float64(self, data):
+        assert(isinstance(data, float))
+        data = pack('<d', data)
+
+        self.props_type.append(data_types.FLOAT64)
+        self.props.append(data)
+
+    def add_bytes(self, data):
+        assert(isinstance(data, bytes))
+        data = pack('<I', len(data)) + data
+
+        self.props_type.append(data_types.BYTES)
+        self.props.append(data)
+
+    def add_string(self, data):
+        assert(isinstance(data, bytes))
+        data = pack('<I', len(data)) + data
+
+        self.props_ty

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list