[Bf-extensions-cvs] [c552e88] master: FBX: Fix template issue when several sub-types use the same 'super type' element.

Bastien Montagne noreply at git.blender.org
Tue Apr 1 21:50:44 CEST 2014


Commit: c552e88485c5824efb74d6070aa9ae3c096bf598
Author: Bastien Montagne
Date:   Tue Apr 1 21:43:03 2014 +0200
https://developer.blender.org/rBAc552e88485c5824efb74d6070aa9ae3c096bf598

FBX: Fix template issue when several sub-types use the same 'super type' element.

E.g. camera, lamp and empty (Null) data all use the same "NodeAttribute" element type,
while having different "sub-types" (FbxNull, FbxCamera, etc.) with different properties.

It would have been perfectly possible to have multiple property templates, but from
"reading" official FBX files, it’s obvious this is not supported, so in this case we
have to pick one to write a real template, and for the other subtypes, we have to
explicitely write the whole templates' content in each and every element...

At this point, you might wonder why introducing templates, if you have to handle
such hairy cases? Well, I’m wondering too...

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

M	io_scene_fbx/export_fbx_bin.py

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

diff --git a/io_scene_fbx/export_fbx_bin.py b/io_scene_fbx/export_fbx_bin.py
index be5776a..dad89f1 100644
--- a/io_scene_fbx/export_fbx_bin.py
+++ b/io_scene_fbx/export_fbx_bin.py
@@ -442,23 +442,57 @@ def elem_props_compound(elem, cmpd_name, custom=False):
     return _setter
 
 
+def elem_props_template_init(templates, template_type):
+    """
+    Init a writing template of given type, for *one* element's properties.
+    """
+    ret = None
+    if template_type in templates:
+        tmpl = templates[template_type]
+        written = tmpl.written[0]
+        print(template_type, written)
+        props = tmpl.properties
+        ret = OrderedDict((name, [val, ptype, anim, written]) for name, (val, ptype, anim) in props.items())
+    return ret or OrderedDict()
+
+
 def elem_props_template_set(template, elem, ptype_name, name, value, animatable=False):
     """
     Only add a prop if the same value is not already defined in given template.
     Note it is important to not give iterators as value, here!
     """
     ptype = FBX_PROPERTIES_DEFINITIONS[ptype_name]
-    tmpl_val, tmpl_ptype, tmpl_animatable = template.properties.get(name, (None, None, False))
+    if len(ptype) > 3:
+        value = tuple(value)
+    tmpl_val, tmpl_ptype, tmpl_animatable, tmpl_written = template.get(name, (None, None, False, False))
     # Note animatable flag from template takes precedence over given one, if applicable.
     if tmpl_ptype is not None:
-        if ((len(ptype) == 3 and (tmpl_val, tmpl_ptype) == (value, ptype_name)) or
-                (len(ptype) > 3 and (tuple(tmpl_val), tmpl_ptype) == (tuple(value), ptype_name))):
+        if (tmpl_written and
+            ((len(ptype) == 3 and (tmpl_val, tmpl_ptype) == (value, ptype_name)) or
+             (len(ptype) > 3 and (tuple(tmpl_val), tmpl_ptype) == (value, ptype_name)))):
             return  # Already in template and same value.
         _elem_props_set(elem, ptype, name, value, _elem_props_flags(tmpl_animatable, False))
+        template[name][3] = True
     else:
         _elem_props_set(elem, ptype, name, value, _elem_props_flags(animatable, False))
 
 
+def elem_props_template_finalize(template, elem):
+    """
+    Finalize one element's template/props.
+    Issue is, some templates might be "needed" by different types (e.g. NodeAttribute is for lights, cameras, etc.),
+    but values for only *one* subtype can be written as template. So we have to be sure we write those for ths other
+    subtypes in each and every elements, if they are not overriden by that element.
+    Yes, hairy, FBX that is to say. When they could easily support several subtypes per template... :(
+    """
+    for name, (value, ptype_name, animatable, written) in template.items():
+        if written:
+            continue
+        ptype = FBX_PROPERTIES_DEFINITIONS[ptype_name]
+        print(elem, ptype, name, value, _elem_props_flags(animatable, False))
+        _elem_props_set(elem, ptype, name, value, _elem_props_flags(animatable, False))
+
+
 ##### Generators for connection elements. #####
 
 def elem_connection(elem, c_type, uid_src, uid_dst, prop_dst=None):
@@ -472,37 +506,55 @@ def elem_connection(elem, c_type, uid_src, uid_dst, prop_dst=None):
 ##### Templates #####
 # TODO: check all those "default" values, they should match Blender's default as much as possible, I guess?
 
-FBXTemplate = namedtuple("FBXTemplate", ("type_name", "prop_type_name", "properties", "nbr_users"))
+FBXTemplate = namedtuple("FBXTemplate", ("type_name", "prop_type_name", "properties", "nbr_users", "written"))
 
 
 def fbx_templates_generate(root, fbx_templates):
     # We may have to gather different templates in the same node (e.g. NodeAttribute template gathers properties
     # for Lights, Cameras, LibNodes, etc.).
+    ref_templates = {(tmpl.type_name, tmpl.prop_type_name) : tmpl for tmpl in fbx_templates.values()}
+
     templates = OrderedDict()
-    for type_name, prop_type_name, properties, nbr_users in fbx_templates.values():
+    for type_name, prop_type_name, properties, nbr_users, _written in fbx_templates.values():
         if type_name not in templates:
-            templates[type_name] = [OrderedDict(((prop_type_name, properties),)), nbr_users]
+            templates[type_name] = [OrderedDict(((prop_type_name, (properties, nbr_users)),)), nbr_users]
         else:
-            templates[type_name][0][prop_type_name] = properties
+            templates[type_name][0][prop_type_name] = (properties, nbr_users)
             templates[type_name][1] += nbr_users
 
     for type_name, (subprops, nbr_users) in templates.items():
         template = elem_data_single_string(root, b"ObjectType", type_name)
         elem_data_single_int32(template, b"Count", nbr_users)
 
-        for prop_type_name, properties in subprops.items():
-            if prop_type_name and properties:
-                elem = elem_data_single_string(template, b"PropertyTemplate", prop_type_name)
-                props = elem_properties(elem)
-                for name, (value, ptype, animatable) in properties.items():
-                    elem_props_set(props, ptype, name, value, animatable=animatable)
+        if len(subprops) == 1:
+            prop_type_name, (properties, _nbr_sub_type_users) = next(iter(subprops.items()))
+            subprops = (prop_type_name, properties)
+            ref_templates[(type_name, prop_type_name)].written[0] = True
+        else:
+            # Ack! Even though this could/should work, looks like it is not supported. So we have to chose one. :|
+            max_users = max_props = -1
+            written_prop_type_name = None
+            for prop_type_name, (properties, nbr_sub_type_users) in subprops.items():
+                if nbr_sub_type_users > max_users or (nbr_sub_type_users == max_users and len(properties) > max_props):
+                    max_users = nbr_sub_type_users
+                    max_props = len(properties)
+                    written_prop_type_name = prop_type_name
+            subprops = (written_prop_type_name, properties)
+            ref_templates[(type_name, written_prop_type_name)].written[0] = True
+
+        prop_type_name, properties = subprops
+        if prop_type_name and properties:
+            elem = elem_data_single_string(template, b"PropertyTemplate", prop_type_name)
+            props = elem_properties(elem)
+            for name, (value, ptype, animatable) in properties.items():
+                elem_props_set(props, ptype, name, value, animatable=animatable)
 
 
 def fbx_template_def_globalsettings(scene, settings, override_defaults=None, nbr_users=0):
     props = OrderedDict()
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"GlobalSettings", b"", props, nbr_users)
+    return FBXTemplate(b"GlobalSettings", b"", props, nbr_users, [False])
 
 
 def fbx_template_def_model(scene, settings, override_defaults=None, nbr_users=0):
@@ -583,7 +635,7 @@ def fbx_template_def_model(scene, settings, override_defaults=None, nbr_users=0)
     ))
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"Model", b"FbxNode", props, nbr_users)
+    return FBXTemplate(b"Model", b"FbxNode", props, nbr_users, [False])
 
 
 def fbx_template_def_null(scene, settings, override_defaults=None, nbr_users=0):
@@ -594,7 +646,7 @@ def fbx_template_def_null(scene, settings, override_defaults=None, nbr_users=0):
     ))
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"NodeAttribute", b"FbxNull", props, nbr_users)
+    return FBXTemplate(b"NodeAttribute", b"FbxNull", props, nbr_users, [False])
 
 
 def fbx_template_def_light(scene, settings, override_defaults=None, nbr_users=0):
@@ -612,7 +664,7 @@ def fbx_template_def_light(scene, settings, override_defaults=None, nbr_users=0)
     ))
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"NodeAttribute", b"FbxLight", props, nbr_users)
+    return FBXTemplate(b"NodeAttribute", b"FbxLight", props, nbr_users, [False])
 
 
 def fbx_template_def_camera(scene, settings, override_defaults=None, nbr_users=0):
@@ -727,14 +779,14 @@ def fbx_template_def_camera(scene, settings, override_defaults=None, nbr_users=0
     ))
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"NodeAttribute", b"FbxCamera", props, nbr_users)
+    return FBXTemplate(b"NodeAttribute", b"FbxCamera", props, nbr_users, [False])
 
 
 def fbx_template_def_bone(scene, settings, override_defaults=None, nbr_users=0):
     props = OrderedDict()
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"NodeAttribute", b"LimbNode", props, nbr_users)
+    return FBXTemplate(b"NodeAttribute", b"LimbNode", props, nbr_users, [False])
 
 
 def fbx_template_def_geometry(scene, settings, override_defaults=None, nbr_users=0):
@@ -748,7 +800,7 @@ def fbx_template_def_geometry(scene, settings, override_defaults=None, nbr_users
     ))
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"Geometry", b"FbxMesh", props, nbr_users)
+    return FBXTemplate(b"Geometry", b"FbxMesh", props, nbr_users, [False])
 
 
 def fbx_template_def_material(scene, settings, override_defaults=None, nbr_users=0):
@@ -786,7 +838,7 @@ def fbx_template_def_material(scene, settings, override_defaults=None, nbr_users
     ))
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"Material", b"FbxSurfacePhong", props, nbr_users)
+    return FBXTemplate(b"Material", b"FbxSurfacePhong", props, nbr_users, [False])
 
 
 def fbx_template_def_texture_file(scene, settings, override_defaults=None, nbr_users=0):
@@ -813,7 +865,7 @@ def fbx_template_def_texture_file(scene, settings, override_defaults=None, nbr_u
     ))
     if override_defaults is not None:
         props.update(override_defaults)
-    return FBXTemplate(b"Texture", b"FbxFileTexture", props, nbr_users)
+    return FBXTemplate(b"Texture", b"FbxFileTexture", props, nbr_users, [Fa

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-extensions-cvs mailing list