addons contrib: bulk remove unmaintained i/o part 1
authormeta-androcto <meta.androcto1@gmail.com>
Sat, 14 Sep 2019 02:27:47 +0000 (12:27 +1000)
committermeta-androcto <meta.androcto1@gmail.com>
Sat, 14 Sep 2019 02:27:47 +0000 (12:27 +1000)
55 files changed:
cacharanth/__init__.py [deleted file]
cacharanth/meshcache.py [deleted file]
cacharanth/ui.py [deleted file]
io_anim_acclaim/__init__.py [deleted file]
io_anim_c3d/__init__.py [deleted file]
io_anim_c3d/import_c3d.py [deleted file]
io_convert_image_to_mesh_img/__init__.py [deleted file]
io_convert_image_to_mesh_img/mesh/__init__.py [deleted file]
io_convert_image_to_mesh_img/mesh/dtm.py [deleted file]
io_convert_image_to_mesh_img/mesh/terrain.py [deleted file]
io_convert_image_to_mesh_img/mesh/triangulate.py [deleted file]
io_convert_image_to_mesh_img/pvl/__init__.py [deleted file]
io_convert_image_to_mesh_img/pvl/label.py [deleted file]
io_convert_image_to_mesh_img/pvl/parse.py [deleted file]
io_convert_image_to_mesh_img/pvl/patterns.py [deleted file]
io_convert_image_to_mesh_img/ui/__init__.py [deleted file]
io_convert_image_to_mesh_img/ui/importer.py [deleted file]
io_convert_image_to_mesh_img/ui/terrainpanel.py [deleted file]
io_directx_bel/README [deleted file]
io_directx_bel/__init__.py [deleted file]
io_directx_bel/bel/__init__.py [deleted file]
io_directx_bel/bel/fs.py [deleted file]
io_directx_bel/bel/group.py [deleted file]
io_directx_bel/bel/image.py [deleted file]
io_directx_bel/bel/material.py [deleted file]
io_directx_bel/bel/mesh.py [deleted file]
io_directx_bel/bel/ob.py [deleted file]
io_directx_bel/bel/uv.py [deleted file]
io_directx_bel/import_x.py [deleted file]
io_directx_bel/templates_x.py [deleted file]
io_export_unreal_psk_psa.py [deleted file]
io_import_LRO_Lola_MGS_Mola_img.py [deleted file]
io_import_gimp_image_to_scene.py [deleted file]
io_import_scene_lwo.py [deleted file]
io_import_scene_unreal_psa_psk.py [deleted file]
io_import_voodoo_camera.py [deleted file]
io_scene_cod/__init__.py [deleted file]
io_scene_cod/export_xanim.py [deleted file]
io_scene_cod/export_xmodel.py [deleted file]
io_scene_cod/import_xanim.py [deleted file]
io_scene_cod/import_xmodel.py [deleted file]
io_scene_fpx/__init__.py [deleted file]
io_scene_fpx/cfb_spec.py [deleted file]
io_scene_fpx/fpx_import.py [deleted file]
io_scene_fpx/fpx_resource.blend [deleted file]
io_scene_fpx/fpx_spec.py [deleted file]
io_scene_fpx/fpx_strings.py [deleted file]
io_scene_fpx/fpx_ui.py [deleted file]
io_scene_fpx/fpx_utils.py [deleted file]
io_scene_fpx/lzo_spec.py [deleted file]
io_scene_x/__init__.py [deleted file]
io_scene_x/export_x.py [deleted file]
io_sequencer_edl/__init__.py [deleted file]
io_sequencer_edl/import_edl.py [deleted file]
io_sequencer_edl/parse_edl.py [deleted file]

diff --git a/cacharanth/__init__.py b/cacharanth/__init__.py
deleted file mode 100644 (file)
index e92c205..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-### 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>
-
-bl_info = {
-    "name": "Cacharanth",
-    "author": "Pablo Vazquez, Lukas Toenne",
-    "version": (0, 2),
-    "blender": (2, 73, 0),
-    "location": "View3D > Cacharanth (Tab)",
-    "description": "Import and Export Caches",
-    "warning": "",
-    "wiki_url": "",
-    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
-    "category": "Import-Export",
-    }
-
-import bpy
-from cacharanth import ui, meshcache
-
-def register():
-    ui.register()
-    meshcache.register()
-
-def unregister():
-    ui.unregister()
-    meshcache.unregister()
-
-if __name__ == "__main__":
-    register()
diff --git a/cacharanth/meshcache.py b/cacharanth/meshcache.py
deleted file mode 100644 (file)
index b259da4..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-### 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>
-
-import bpy
-from bpy.types import Operator
-from bpy.props import *
-
-
-def meshcache_export(context, objects):
-    scene = context.scene
-
-    for ob in objects:
-        filename = scene.meshcache_folder + "/" + scene.meshcache_group + "_" + ob.name + ".cache.mdd"
-
-        if ob.modifiers:
-            for mo in ob.modifiers:
-                if mo.type == 'SUBSURF':
-                    mo.show_viewport = False
-
-        override = {
-            'blend_data' : context.blend_data,
-            'window' : context.window,
-            'screen' : context.screen,
-            'area' : context.area,
-            'region' : context.region,
-            'scene' : scene,
-            'active_object' : ob,
-            'object' : ob,
-            }
-        bpy.ops.export_shape.mdd(override,
-                                 filepath=filename,
-                                 frame_start=scene.meshcache_frame_start,
-                                 frame_end=scene.meshcache_frame_end,
-                                 fps=scene.meshcache_frame_rate)
-
-
-def meshcache_import(context, objects):
-    scene = context.scene
-    mc_mod_name = "MeshCacheAM"
-
-    import os.path
-
-    for ob in objects:
-        filename = scene.meshcache_folder + "/" + scene.meshcache_group + "_" + ob.name + ".cache.mdd"
-
-        if os.path.isfile(filename):
-            has_meshcache = False
-
-            if ob.modifiers:
-                for mo in ob.modifiers:
-                    if mo.type == 'MESH_CACHE':
-                        has_meshcache = True
-                        mo.name = mc_mod_name
-
-            if not has_meshcache:
-                ob.modifiers.new(mc_mod_name, "MESH_CACHE")
-
-            ob.modifiers[mc_mod_name].filepath = filename
-            ob.modifiers[mc_mod_name].frame_start = scene.meshcache_frame_start
-        else:
-            print("! No Meshcache found for {0}".format(ob.name))
-
-
-class MeshcacheOperator():
-    @classmethod
-    def poll(cls, context):
-        if context.scene.meshcache_apply_to == 'GROUP':
-            # XXX doesn't seem correct
-            return bpy.data.collections
-        else:
-            return context.active_object is not None
-
-    def meshcache_objects(self, context):
-        """Filtered list of Blender Objects used by the cache export/import"""
-        scene = context.scene
-
-        if scene.meshcache_apply_to == 'GROUP':
-            objects = bpy.data.collections[scene.meshcache_group].objects
-        else:
-            objects = context.selected_objects
-
-        if scene.use_meshcache_exclude_names:
-            excluded = { ex.name for ex in scene.meshcache_exclude_names if ex.name }
-        else:
-            excluded = []
-
-        for ob in objects:
-            if ob.type == 'MESH':
-                if ob.name not in excluded:
-                    yield ob
-                    self.report_used(ob)
-                else:
-                    self.report_excluded(ob)
-
-
-class MESH_OP_MeshcacheExport(MeshcacheOperator, Operator):
-    """Export Meshcache"""
-    bl_idname = "object.meshcache_export"
-    bl_label = "Export Mesh Cache"
-    howmany_exported = 0
-    howmany_excluded = 0
-
-    def report_used(self, ob):
-        MESH_OP_MeshcacheExport.howmany_exported += 1
-        print("{0} - Exported".format(ob.name))
-
-    def report_excluded(self, ob):
-        MESH_OP_MeshcacheExport.howmany_excluded += 1
-        print("** {0} - Excluded".format(ob.name))
-
-    def execute(self, context):
-        print("\n== Meshcache Export Start ==")
-        MESH_OP_MeshcacheExport.howmany_exported = 0
-        MESH_OP_MeshcacheExport.howmany_excluded = 0
-        meshcache_export(context, self.meshcache_objects(context))
-        print("\n== Meshcache Export Finished ==")
-        print("== {0} Exported, {1} Excluded ==".format(
-              MESH_OP_MeshcacheExport.howmany_exported,
-              MESH_OP_MeshcacheExport.howmany_excluded))
-
-        self.report({'INFO'}, "Meshcache Exported")
-        return {'FINISHED'}
-
-
-class MESH_OP_MeshcacheImport(MeshcacheOperator, Operator):
-    """Import Meshcache (creates Meshcache modifiers when necessary)"""
-    bl_idname = "object.meshcache_import"
-    bl_label = "Import Mesh Cache"
-    howmany_imported = 0
-    howmany_excluded = 0
-
-    def report_used(self, ob):
-        MESH_OP_MeshcacheImport.howmany_imported += 1
-        print("{0} - Imported".format(ob.name))
-
-    def report_excluded(self, ob):
-        MESH_OP_MeshcacheImport.howmany_excluded += 1
-        print("** {0} - Excluded".format(ob.name))
-
-    def execute(self, context):
-        print("\n== Meshcache Import Start ==")
-        MESH_OP_MeshcacheImport.howmany_imported = 0
-        MESH_OP_MeshcacheImport.howmany_excluded = 0
-        meshcache_import(context, self.meshcache_objects(context))
-        print("\n== Meshcache Import Finished ==")
-        print("== {0} Imported, {1} Excluded ==".format(
-              MESH_OP_MeshcacheImport.howmany_imported,
-              MESH_OP_MeshcacheImport.howmany_excluded))
-
-        self.report({'INFO'}, "Meshcache Imported")
-        return {'FINISHED'}
-
-
-def register():
-    bpy.utils.register_class(MESH_OP_MeshcacheExport)
-    bpy.utils.register_class(MESH_OP_MeshcacheImport)
-
-def unregister():
-    bpy.utils.unregister_class(MESH_OP_MeshcacheExport)
-    bpy.utils.unregister_class(MESH_OP_MeshcacheImport)
diff --git a/cacharanth/ui.py b/cacharanth/ui.py
deleted file mode 100644 (file)
index 6b9480c..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-### 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>
-
-import bpy, os
-from bpy.types import Operator, Panel, UIList
-from bpy.props import *
-from bpy_extras.io_utils import ImportHelper
-
-from cacharanth import meshcache
-from cacharanth.meshcache import MESH_OP_MeshcacheExport, MESH_OP_MeshcacheImport
-
-
-class MESH_OP_MeshcacheRefresh(Operator):
-    """Refresh"""
-    bl_idname = "scene.meshcache_refresh"
-    bl_label = "Refresh"
-
-    def execute(self, context):
-        context.scene.frame_current = context.scene.frame_current
-        return {'FINISHED'}
-
-
-class CACHARANTH_GroupSelect(Operator):
-    bl_idname = "cacharanth.group_select"
-    bl_label = "Select Group"
-    bl_description = "Switch to another material in this mesh"
-
-    def avail_groups(self,context):
-        items = [(str(i),x.name,x.name, "GROUP", i) for i,x in enumerate(bpy.data.collections)]
-        return items
-
-    group_select: bpy.props.EnumProperty(items = avail_groups, name = "Available Groups")
-
-    @classmethod
-    def poll(cls, context):
-        return bpy.data.collections
-
-    def execute(self,context):
-        bpy.context.scene.meshcache_group = bpy.data.collections[int(self.group_select)].name
-        return {'FINISHED'}
-
-
-def MeshcacheFolderSet(context, filepath):
-    import os
-
-    fp =  filepath if os.path.isdir(filepath) else  os.path.dirname(filepath)
-    for sc in bpy.data.scenes:
-        sc.meshcache_folder = fp
-    return {'FINISHED'}
-
-
-class MeshcacheFolderSetButton(Operator, ImportHelper):
-    bl_idname = "buttons.meshcache_folder_set"
-    bl_label = "Set Mesh Cache Folder"
-    filename_ext = ".mdd"
-
-    def execute(self, context):
-        return MeshcacheFolderSet(context, self.filepath)
-
-
-class MESH_UL_MeshcacheExcludeName(bpy.types.UIList):
-    def draw_item(self, context, layout, data, rule, icon, active_data, active_propname, index):
-        split = layout.split(0.5)
-        row = split.split(align=False)
-        row.label(text="%s" % (rule.name))
-
-
-class MESH_OT_MeshcacheExcludeNameAdd(Operator):
-    bl_idname = "buttons.meshcache_exclude_add"
-    bl_label = "Add Exclude Rule"
-    bl_options = {'UNDO'}
-
-    def execute(self, context):
-        scene = context.scene
-        rules = scene.meshcache_exclude_names
-        rule = rules.add()
-        rule.name = "Rule.%.3d" % len(rules)
-        scene.meshcache_exclude_names_active_index = len(rules) - 1
-        return {'FINISHED'}
-
-
-class MESH_OT_MeshcacheExcludeNameRemove(Operator):
-    bl_idname = "buttons.meshcache_exclude_remove"
-    bl_label = "Remove Exclude Rule"
-    bl_options = {'UNDO'}
-
-    def execute(self, context):
-        scene = context.scene
-        rules = scene.meshcache_exclude_names
-        rules.remove(scene.meshcache_exclude_names_active_index)
-        if scene.meshcache_exclude_names_active_index > len(rules) - 1:
-            scene.meshcache_exclude_names_active_index = len(rules) - 1
-        return {'FINISHED'}
-
-class MeshcacheExcludeNames(bpy.types.PropertyGroup):
-    name: StringProperty(
-            name="Rule Name",
-            )
-
-class VIEW3D_PT_MeshcacheToolsPanel(Panel):
-    """Cacharanth Panel"""
-    bl_label = "Cacharanth Tools"
-    bl_idname = "VIEW3D_PT_MeshcacheToolsPanel"
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'TOOLS'
-    bl_category = "Cacharanth"
-
-    def draw(self, context):
-        layout = self.layout
-
-        scene = bpy.context.scene
-        howmany_exported = MESH_OP_MeshcacheExport.howmany_exported
-        howmany_exported_excluded = MESH_OP_MeshcacheExport.howmany_excluded
-        howmany_imported = MESH_OP_MeshcacheImport.howmany_imported
-        howmany_imported_excluded = MESH_OP_MeshcacheImport.howmany_excluded
-
-        row = layout.row(align=True)
-        row.prop(scene, "meshcache_apply_to", expand=True)
-
-        if scene.meshcache_apply_to == 'GROUP':
-            if bpy.data.collections:
-                row = layout.row(align=True)
-                row.enabled = len(bpy.data.collections) != 0
-                row.label(text="Select Group:")
-                row.operator_menu_enum("cacharanth.group_select",
-                                               "group_select",
-                                               text=scene.meshcache_group,
-                                               icon="GROUP")
-            else:
-                row = layout.row(align=True)
-                row.label(text="There are no groups", icon="ERROR")
-        else:
-            row = layout.row(align=True)
-            row.label(text="{0} Selected Objects".format(
-                      len(context.selected_objects)))
-
-        row = layout.row(align=True)
-        row.prop(scene, "meshcache_folder", text="Export Path")
-        row.operator("buttons.meshcache_folder_set", icon='FILEBROWSER', text="")
-
-
-        row = layout.row(align=True)
-        row.label(text="Export Settings:")
-        row.prop(scene, "meshcache_frame_start", text="Frame Start")
-        row.prop(scene, "meshcache_frame_end", text="Frame End")
-        row.prop(scene, "meshcache_frame_rate", text="FPS")
-
-        row = layout.row(align=True)
-        row.prop(scene, "use_meshcache_exclude_names",
-                 text="Exclude Objects by Name")
-
-        if scene.use_meshcache_exclude_names:
-            row = layout.row()
-            row.template_list(
-                    "MESH_UL_MeshcacheExcludeName", "meshcache_exclude_names",
-                    scene, "meshcache_exclude_names",
-                    scene, "meshcache_exclude_names_active_index")
-
-            col = row.column()
-            colsub = col.column(align=True)
-            colsub.operator("buttons.meshcache_exclude_add", icon='ZOOMIN', text="")
-            colsub.operator("buttons.meshcache_exclude_remove", icon='ZOOMOUT', text="")
-
-            if scene.meshcache_exclude_names:
-                index = scene.meshcache_exclude_names_active_index
-                rule = scene.meshcache_exclude_names[index]
-
-                row = layout.row(align=True)
-                row.prop(rule, "name", text="Exclude Text")
-
-        layout.separator()
-
-        row = layout.row(align=True)
-        row.operator("object.meshcache_import", icon="IMPORT")
-        row.operator("object.meshcache_export", icon="EXPORT")
-        row.operator("scene.meshcache_refresh", icon="FILE_REFRESH", text="")
-
-        row = layout.row(align=True)
-        row.label(text="Export:")
-        row.label(text="{0} Exported".format(str(howmany_exported)))
-        row.label(text="{0} Excluded".format(str(howmany_exported_excluded)))
-
-        row = layout.row(align=True)
-        row.label(text="Import:")
-        row.label(text="{0} Imported".format(str(howmany_imported)))
-        row.label(text="{0} Excluded".format(str(howmany_imported_excluded)))
-
-classes = (
-    VIEW3D_PT_MeshcacheToolsPanel,
-    MESH_OP_MeshcacheRefresh,
-    MESH_UL_MeshcacheExcludeName,
-    MESH_OT_MeshcacheExcludeNameAdd,
-    MESH_OT_MeshcacheExcludeNameRemove,
-    MeshcacheExcludeNames,
-    MeshcacheFolderSetButton,
-    CACHARANTH_GroupSelect
-    )
-
-def register():
-    for cls in classes:
-        bpy.utils.register_class(cls)
-
-    from bpy.types import Scene
-
-    Scene.meshcache_apply_to = EnumProperty(
-            name="Apply To",
-            items=(('GROUP', "Group", "Objects in a group"),
-                   ('OBJECT', "Selected Objects", "Selected objects only"),
-                   ),
-            default='OBJECT',
-            )
-
-    Scene.meshcache_folder = StringProperty(default="Choose a Path...")
-    Scene.meshcache_group = StringProperty(default="Select Group")
-    Scene.meshcache_frame_start = IntProperty(default=1,
-                                              soft_min=0)
-    Scene.meshcache_frame_end = IntProperty(default=1,
-                                            soft_min=1)
-    Scene.meshcache_frame_rate = IntProperty(default=24,
-                                             soft_min=1)
-
-    Scene.use_meshcache_exclude_names = BoolProperty(
-                                            default=False,
-                                            name="Exclude by Name",
-                                            description="Exclude objects with a name including text")
-    Scene.meshcache_exclude_names = CollectionProperty(type=MeshcacheExcludeNames)
-    Scene.meshcache_exclude_names_active_index = IntProperty()
-
-def unregister():
-    for cls in classes:
-        bpy.utils.unregister_class(cls)
diff --git a/io_anim_acclaim/__init__.py b/io_anim_acclaim/__init__.py
deleted file mode 100644 (file)
index 5aaaa5a..0000000
+++ /dev/null
@@ -1,546 +0,0 @@
-# ##### 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 3
-#  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-80 compliant>
-
-# This script was developed with financial support from the Foundation for
-# Science and Technology of Portugal, under the grant SFRH/BD/66452/2009.
-
-
-bl_info = {
-    "name": "Acclaim Motion Capture Files (.asf, .amc)",
-    "author": "Daniel Monteiro Basso <daniel@basso.inf.br>",
-    "version": (2013, 1, 26, 1),
-    "blender": (2, 65, 9),
-    "location": "File > Import-Export",
-    "description": "Imports Acclaim Skeleton and Motion Capture Files",
-    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/Acclaim_Importer",
-    "category": "Import-Export",
-}
-
-
-import re
-import bpy
-from mathutils import Vector, Matrix
-from math import radians, degrees
-from bpy.props import (
-        StringProperty,
-        BoolProperty,
-        FloatProperty,
-        IntProperty,
-        )
-
-
-class DataStructure:
-    """
-        Parse the Skeleton and Motion Files to an internal data structure.
-    """
-    doc = re.compile(r"(?ms):(\w+)\s+([^:]+)")
-    block = re.compile(r"(?ms)begin\s+(.*?)\s+end")
-    bonedata = re.compile(r"(?ms)(name|direction|length|axis|dof)\s+(.*?)\s*$"
-                          "|limits(\s.*)")
-
-    def __init__(self, file_path, scale=1.):
-        self.scale = scale
-        source = open(file_path, encoding="utf-8", errors="replace").read()
-        sections = dict(DataStructure.doc.findall(source))
-        if not sections:
-            raise ValueError("Wrong file structure.")
-
-        if 'units' in sections:
-            units = dict(u.strip().split()
-                for u in sections['units'].splitlines()
-                if u.strip())
-            if 'length' in units:
-                self.scale /= float(units['length'])
-
-        if 'bonedata' not in sections:
-            raise ValueError("Bone data section not found.")
-        bm = DataStructure.block.findall(sections['bonedata'])
-        if not bm:
-            raise ValueError("Bone data section malformed.")
-        self.bones = {'root': {
-            'dof': ['X', 'Y', 'Z'],
-            'direction': Vector(),  # should be orientation of root sector
-            'length': 1,
-            'axis': Matrix(),
-            'axis_inv': Matrix(),
-            }}
-        for b in bm:
-            bd = dict((i[0] or 'limits', i[0] and i[1] or i[2])
-                        for i in DataStructure.bonedata.findall(b))
-            for k in bd:
-                s = [t for t in re.split(r"[^a-zA-Z0-9-+.]", bd[k]) if t]
-                if k == 'axis':
-                    rot = Matrix()
-                    for ang, basis in zip(s[:3], s[3].upper()):
-                        rot = Matrix.Rotation(radians(float(ang)),
-                                              4, basis) * rot
-                    bd['axis'] = rot
-                elif k == 'direction':
-                    bd[k] = Vector([float(n) for n in s])
-                elif k == 'length':
-                    bd[k] = float(s[0]) * self.scale
-                elif k == 'dof':
-                    bd[k] = [a[1].upper() for a in s]  # only rotations
-                elif k == 'limits':
-                    bd[k] = s
-            if 'axis' in bd:
-                bd['axis_inv'] = bd['axis'].inverted()
-            self.bones[bd['name']] = bd
-
-        if 'hierarchy' not in sections:
-            raise ValueError("Hierarchy section not found.")
-        hm = DataStructure.block.search(sections['hierarchy'])
-        if not hm:
-            raise ValueError("Hierarchy section malformed.")
-        self.hierarchy = {}
-        for l in hm.group(1).splitlines():
-            t = l.strip().split()
-            self.hierarchy[t[0]] = t[1:]
-
-    def scan_motion_capture(self, filename, skip=5):
-        """
-            Parse an Acclaim Motion Capture file and iterates over the data
-        """
-        amc = open(filename, encoding="utf-8", errors="replace")
-        l = ' '
-        while l and not l[0].isdigit():
-            l = amc.readline().strip()
-        while l:
-            frame = int(l)
-            bdefs = []
-            while True:
-                l = amc.readline().strip()
-                if not l or l[0].isdigit():
-                    break
-                bdefs.append(l.split())
-            if (frame - 1) % skip != 0:
-                continue
-            self.pose_def = {}
-            for b in bdefs:
-                vs = [float(v) for v in b[1:]]
-                if b[0] == 'root':
-                    loc = Vector(vs[:3]) * self.scale
-                    vs = vs[3:]
-                rot = Matrix()
-                if 'dof' not in self.bones[b[0]]:
-                    # If 'dof' isn't defined it probably means the AMC comes
-                    # from a different origin than the ASF, such as the
-                    # AMC exporter in this package. Assume XYZ order.
-                    self.bones[b[0]]['dof'] = ['X', 'Y', 'Z']
-                for dof, ang in zip(self.bones[b[0]]['dof'], vs):
-                    rot = Matrix.Rotation(radians(ang), 4, dof) * rot
-                self.pose_def[b[0]] = rot
-            pose = self.calculate_pose(Matrix.Translation(loc))
-            yield(frame / skip + 1, pose)
-        amc.close()
-
-    def calculate_pose(self, parent, bone='root'):
-        """
-            Calculate each bone transform iteratively
-        """
-        bd = self.bones[bone]
-        tail = Matrix.Translation(bd['direction'] * bd['length'])
-        if bone in self.pose_def:
-            tail = bd['axis'] * self.pose_def[bone] * bd['axis_inv'] * tail
-        world = parent * tail
-        local = tail
-        yield(bone, world, local)
-        if bone in self.hierarchy:
-            for child in self.hierarchy[bone]:
-                for b, w, l in self.calculate_pose(world, child):
-                    yield(b, w, l)
-
-
-class StructureBuilder(DataStructure):
-    def __init__(self, file_path, name="Skel", scale=1.):
-        """
-            Setup instance data and load the skeleton
-        """
-        self.file_path = file_path
-        self.name = name
-        self.user_def_scale = scale
-        DataStructure.__init__(self, file_path, scale)
-
-    def create_armature(self):
-        """
-            Create the armature and leave it in edit mode
-        """
-        bpy.context.view_layer.objects.active = None
-        bpy.ops.object.add(type='ARMATURE', enter_editmode=True)
-        self.object = bpy.context.view_layer.objects.active
-        self.armature = self.object.data
-        self.object.name = self.name
-        self.armature.name = self.name
-        self.armature.display_type = 'STICK'
-        self.object['source_file_path'] = self.file_path
-        self.object['source_scale'] = self.user_def_scale
-        self.object['MhxArmature'] = 'Daz'
-
-    def load_armature(self, obj):
-        """
-            Assign the armature object to be used for loading motion
-        """
-        self.object = obj
-
-    def build_structure(self, use_limits=False):
-        """
-            Create the root bone and start the recursion, exit edit mode
-        """
-        self.use_limits = use_limits
-        bpy.ops.armature.bone_primitive_add(name='root')
-        root_dir = Vector((0, 0.1 * self.scale, 0))
-        bpy.ops.transform.translate(value=root_dir + Vector((.0, .0, -1.0)))
-        self.recursive_add_bones()
-        bpy.ops.armature.select_all(action='DESELECT')
-        bpy.ops.object.mode_set(mode='OBJECT')
-
-    def recursive_add_bones(self, parent_name='root'):
-        """
-            Traverse the hierarchy creating bones and constraints
-        """
-        if  parent_name not in self.hierarchy:
-            return
-        for name in self.hierarchy[parent_name]:
-            self.add_bone(name, parent_name)
-            if self.use_limits:
-                self.add_limit_constraint(name)
-            self.recursive_add_bones(name)
-
-    def add_bone(self, name, parent_name):
-        """
-            Extrude a bone from the specified parent, and configure it
-        """
-        bone_def = self.bones[name]
-        bpy.ops.armature.select_all(action='DESELECT')
-        # select tail of parent bone
-        self.armature.edit_bones[parent_name].select_tail = True
-        # extrude and name the new bone
-        bpy.ops.armature.extrude()
-        self.armature.edit_bones[-1].name = name
-        # translate the tail of the new bone
-        tail = bone_def['direction'] * bone_def['length']
-        bpy.ops.transform.translate(value=tail)
-        # align the bone to the rotation axis
-        axis = bone_def['axis'].to_3x3()
-        vec = axis * Vector((.0, .0, -1.0))
-        self.armature.edit_bones[-1].align_roll(vector=vec)
-
-    def add_limit_constraint(self, name):
-        """
-            Create the limit rotation constraint of the specified bone
-        """
-        bpy.ops.object.mode_set(mode='POSE')
-        bone_def = self.bones[name]
-        dof = bone_def['dof'] if 'dof' in bone_def else ''
-        pb = self.object.pose.bones[name]
-        self.armature.bones.active = self.armature.bones[name]
-        bpy.ops.pose.constraint_add(type='LIMIT_ROTATION')
-        constr = pb.constraints[-1]
-        constr.owner_space = 'LOCAL'
-        constr.use_limit_x = True
-        constr.use_limit_y = True
-        constr.use_limit_z = True
-        if dof:
-            limits = (radians(float(v)) for v in bone_def['limits'])
-            if 'X' in dof:
-                constr.min_x = next(limits)
-                constr.max_x = next(limits)
-            if 'Y' in dof:
-                constr.max_z = -next(limits)
-                constr.min_z = -next(limits)
-            if 'Z' in dof:
-                constr.min_y = next(limits)
-                constr.max_y = next(limits)
-        bpy.ops.object.mode_set(mode='EDIT')
-
-    def load_motion_capture(self, filename, frame_skip=5, use_frame_no=False):
-        """
-            Create the keyframes for a motion capture file
-        """
-        bpy.context.active_object.animation_data_clear()
-        bpy.ops.object.mode_set(mode='POSE')
-        bpy.ops.pose.select_all(action='SELECT')
-        bpy.ops.pose.rot_clear()
-        bpy.ops.pose.loc_clear()
-        self.rest = {}
-        for b in self.object.pose.bones:
-            self.rest[b.name] = (b,
-                                 b.matrix.to_3x3(),
-                                 b.matrix.to_3x3().inverted(),
-                                 )
-        self.fno = 1  # default Blender scene start frame
-        self.use_frame_no = use_frame_no
-        self.motion = iter(self.scan_motion_capture(filename, frame_skip))
-
-    def apply_next_frame(self):
-        try:
-            frame, bones = next(self.motion)
-        except StopIteration:
-            return False
-        regframe = frame if self.use_frame_no else self.fno
-        self.fno += 1
-        for name, w, l in bones:
-            b, P, Pi = self.rest[name]
-            if name == 'root':
-                b.location = w.to_translation()
-                b.keyframe_insert('location', -1, regframe, name)
-            T = Pi * l.to_3x3() * P
-            b.rotation_quaternion = T.to_quaternion()
-            b.keyframe_insert('rotation_quaternion', -1, regframe, name)
-        return True
-
-
-class AsfImporter(bpy.types.Operator):
-    #
-    "Load an Acclaim Skeleton File"
-    #
-    bl_idname = "import_anim.asf"
-    bl_label = "Import ASF"
-
-    filepath: StringProperty(
-            subtype='FILE_PATH',
-            )
-    armature_name: StringProperty(
-            name="Armature Name", maxlen=63,
-            default="Skeleton",
-            description="Name of the new object",
-            )
-    use_limits: BoolProperty(
-            name="Use Limits", default=False,
-            description="Create bone constraints for limits",
-            )
-    scale: FloatProperty(
-            name="Scale",
-            default=1.0,
-            description="Scale the armature by this value",
-            min=0.0001, max=1000000.0,
-            soft_min=0.001, soft_max=100.0,
-            )
-    from_inches: BoolProperty(
-            name="Convert from inches to metric",
-            default=False, description="Scale by 2.54/100",
-            )
-    use_rot_x: BoolProperty(
-            name="Rotate X 90 degrees",
-            default=False,
-            description="Correct orientation",
-            )
-    use_rot_z: BoolProperty(
-            name="Rotate Z 90 degrees",
-            default=False,
-            description="Correct orientation",
-            )
-
-    filter_glob: StringProperty(default="*.asf", options={'HIDDEN'})
-
-    def execute(self, context):
-        uscale = (0.0254 if self.from_inches else 1.0)
-        sb = StructureBuilder(self.filepath,
-                              self.armature_name,
-                              self.scale * uscale,
-                              )
-        sb.create_armature()
-        sb.build_structure(self.use_limits)
-        if self.use_rot_x:
-            bpy.ops.transform.rotate(value=radians(90.0), axis=(1, 0, 0))
-        if self.use_rot_z:
-            bpy.ops.transform.rotate(value=radians(90.0), axis=(0, 0, 1))
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        wm.fileselect_add(self)
-        return {'RUNNING_MODAL'}
-
-
-class AmcAnimator(bpy.types.Operator):
-    """
-        Load an Acclaim Motion Capture
-    """
-    bl_idname = "import_anim.amc_animate"
-    bl_label = "Animate AMC"
-
-    sb = None
-    timer = None
-
-    def modal(self, context, event):
-        if event.type == 'ESC':
-            self.cancel(context)
-            return {'CANCELLED'}
-        if event.type == 'TIMER':
-            if not self.sb.apply_next_frame():
-                self.cancel(context)
-                return {'FINISHED'}
-        return {'PASS_THROUGH'}
-
-    def execute(self, context):
-        self.timer = context.window_manager.\
-            event_timer_add(0.001, context.window)
-        context.window_manager.modal_handler_add(self)
-        return {'RUNNING_MODAL'}
-
-    def cancel(self, context):
-        bpy.context.scene.frame_set(bpy.context.scene.frame_current)
-        context.window_manager.event_timer_remove(self.timer)
-        bpy.ops.object.mode_set(mode='OBJECT')
-
-
-class AmcImporter(bpy.types.Operator):
-    #
-    "Load an Acclaim Motion Capture"
-    #
-    bl_idname = "import_anim.amc"
-    bl_label = "Import AMC"
-
-    filepath: StringProperty(
-            subtype='FILE_PATH',
-            )
-    frame_skip: IntProperty(
-            name="Fps divisor",
-            default=4,
-            # usually the sample rate is 120, so the default 4 gives you 30fps
-            description="Frame supersampling factor",
-            min=1,
-            )
-    use_frame_no: BoolProperty(
-            name="Use frame numbers",
-            default=False,
-            description="Offset start of animation according to the source",
-            )
-
-    filter_glob: StringProperty(default="*.amc", options={'HIDDEN'})
-
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return (ob and ob.type == 'ARMATURE' and 'source_file_path' in ob)
-
-    def execute(self, context):
-        ob = context.active_object
-        sb = StructureBuilder(
-            ob['source_file_path'],
-            ob.name,
-            ob['source_scale'])
-        sb.load_armature(ob)
-        sb.load_motion_capture(self.filepath,
-                               self.frame_skip,
-                               self.use_frame_no)
-        AmcAnimator.sb = sb
-        bpy.ops.import_anim.amc_animate()
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        ob = context.active_object
-        import os
-        if not os.path.exists(ob['source_file_path']):
-            self.report({'ERROR'},
-                "Original Armature source file not found... was it moved?")
-            return {'CANCELLED'}
-        wm = context.window_manager
-        wm.fileselect_add(self)
-        return {'RUNNING_MODAL'}
-
-
-class AmcExporter(bpy.types.Operator):
-    #
-    "Save an animation in Acclaim format"
-    #
-    bl_idname = "export_anim.amc"
-    bl_label = "Export AMC"
-
-    filepath: StringProperty(
-            subtype='FILE_PATH'
-            )
-    use_scale: BoolProperty(
-            name="Use original armature scale",
-            default=True,
-            description="Scale movement to original scale if available",
-            )
-
-    filter_glob: StringProperty(default="*.amc", options={'HIDDEN'})
-
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return (ob and ob.type == 'ARMATURE' and 'source_file_path' in ob)
-
-    def execute(self, context):
-        ob = context.active_object
-        scn = context.scene
-        out = open(self.filepath, "w")
-        out.write(":FULLY-SPECIFIED\n:DEGREES\n")
-        ds = DataStructure(ob['source_file_path'], ob['source_scale'])
-        scale = ds.scale if self.use_scale else 1
-        for frame in range(scn.frame_start, scn.frame_end + 1):
-            out.write("{}\n".format(frame))
-            scn.frame_set(frame)
-            for bone in ob.pose.bones:
-                out.write("{} ".format(bone.name))
-                if bone.name == "root":
-                    loc = bone.location / scale
-                    out.write(" ".join(str(v) for v in loc) + " ")
-                    rot = bone.matrix.to_euler()
-                else:
-                    A = ds.bones[bone.name]['axis'].to_3x3()
-                    R = ob.data.bones[bone.name].matrix_local.to_3x3()
-                    AiR = A.transposed() * R
-                    AiR_i = AiR.inverted()
-                    rot = (AiR * bone.matrix_basis.to_3x3() * AiR_i).to_euler()
-                out.write(" ".join(str(degrees(v)) for v in rot) + "\n")
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        wm.fileselect_add(self)
-        return {'RUNNING_MODAL'}
-
-
-def menu_func_s(self, context):
-    self.layout.operator(AsfImporter.bl_idname,
-                         text="Acclaim Skeleton File (.asf)")
-
-
-def menu_func_mi(self, context):
-    self.layout.operator(AmcImporter.bl_idname,
-                         text="Acclaim Motion Capture (.amc)")
-
-
-def menu_func_me(self, context):
-    self.layout.operator(AmcExporter.bl_idname,
-                         text="Acclaim Motion Capture (.amc)")
-
-
-def register():
-    bpy.utils.register_module(__name__)
-    bpy.types.TOPBAR_MT_file_import.append(menu_func_s)
-    bpy.types.TOPBAR_MT_file_import.append(menu_func_mi)
-    bpy.types.TOPBAR_MT_file_export.append(menu_func_me)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-    bpy.types.TOPBAR_MT_file_import.remove(menu_func_s)
-    bpy.types.TOPBAR_MT_file_import.remove(menu_func_mi)
-    bpy.types.TOPBAR_MT_file_export.remove(menu_func_me)
-
-
-if __name__ == "__main__":
-    register()
diff --git a/io_anim_c3d/__init__.py b/io_anim_c3d/__init__.py
deleted file mode 100644 (file)
index 88ff974..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-# ##### 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 3
-#  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-80 compliant>
-
-# This script was developed with financial support from the Foundation for
-# Science and Technology of Portugal, under the grant SFRH/BD/66452/2009.
-
-
-bl_info = {
-    "name": "C3D Graphics Lab Motion Capture file (.c3d)",
-    "author": "Daniel Monteiro Basso <daniel@basso.inf.br>",
-    "version": (2015, 5, 5, 1),
-    "blender": (2, 74, 1),
-    "location": "File > Import",
-    "description": "Imports C3D Graphics Lab Motion Capture files",
-    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/C3D_Importer",
-    "category": 'Import-Export',
-}
-
-
-import bpy
-from bpy.props import (
-    StringProperty,
-    BoolProperty,
-    FloatProperty,
-    IntProperty,
-)
-
-import os
-import math
-from mathutils import Vector
-from . import import_c3d
-
-
-class C3DAnimateCloud(bpy.types.Operator):
-    """
-        Animate the Marker Cloud
-    """
-    bl_idname = "import_anim.c3danim"
-    bl_label = "Animate C3D"
-
-    is_armature = False
-    markerset = None
-    uname = None
-    curframe = 0
-    fskip = 0
-    scale = 0
-    timer = None
-    Y_up = False
-
-    def update_empty(self, fno, ml, m):
-        name = self.unames[self.prefix + ml]
-        o = bpy.context.scene.objects[name]
-        p = Vector(m.position) * self.scale
-        o.location = Vector((p[0], -p[2], p[1])) if self.Y_up else p
-        o.keyframe_insert('location', frame=fno)
-
-    def update_bone(self, fno, ml, m, bones):
-        name = self.prefix + ml
-        if name not in bones:
-            return
-        b = bones[name]
-        p = Vector(m.position) * self.scale
-        b.matrix.translation = Vector((p[0], -p[2], p[1])) if self.Y_up else p
-        b.keyframe_insert('location', -1, fno, name)
-
-    def update_frame(self):
-        fno = self.curframe
-        if not self.use_frame_no:
-            fno = (self.curframe - self.markerset.startFrame) / self.fskip
-        for i in range(self.fskip):
-            self.markerset.readNextFrameData()
-        if self.is_armature:
-            bones = bpy.context.active_object.pose.bones
-        for ml in self.markerset.markerLabels:
-            m = self.markerset.getMarker(ml, self.curframe)
-            if m.confidence < self.confidence:
-                continue
-            if self.is_armature:
-                self.update_bone(fno, ml, m, bones)
-            else:
-                self.update_empty(fno, ml, m)
-
-    def modal(self, context, event):
-        if event.type == 'ESC':
-            return self.cancel(context)
-        if event.type == 'TIMER':
-            if self.curframe > self.markerset.endFrame:
-                return self.cancel(context)
-            self.update_frame()
-            self.curframe += self.fskip
-        return {'PASS_THROUGH'}
-
-    def execute(self, context):
-        self.timer = context.window_manager.\
-            event_timer_add(0.001, context.window)
-        context.window_manager.modal_handler_add(self)
-        return {'RUNNING_MODAL'}
-
-    def cancel(self, context):
-        bpy.context.scene.frame_set(bpy.context.scene.frame_current)
-        context.window_manager.event_timer_remove(self.timer)
-        return {'FINISHED'}
-
-
-class C3DImporter(bpy.types.Operator):
-    """
-        Load a C3D Marker Cloud
-    """
-    bl_idname = "import_anim.c3d"
-    bl_label = "Import C3D"
-
-    filepath: StringProperty(
-        subtype='FILE_PATH',
-    )
-    Y_up: BoolProperty(
-        name="Up vector is Y axis",
-        default=False,
-        description="Check when the data uses Y-up, uncheck when it uses Z-up",
-    )
-    from_inches: BoolProperty(
-        name="Convert from inches to meters",
-        default=False,
-        description="Scale by 2.54/100",
-    )
-    scale: FloatProperty(
-        name="Scale",
-        default=1.0,
-        description="Scale the positions by this value",
-        min=0.0000001, max=1000000.0,
-        soft_min=0.001, soft_max=100.0,
-    )
-    auto_scale: BoolProperty(
-        name="Adjust scale automatically",
-        default=False,
-        description="Guess correct scale factor",
-    )
-    auto_magnitude: BoolProperty(
-        name="Adjust scale magnitude",
-        default=True,
-        description="Automatically adjust scale magnitude",
-    )
-    create_armature: BoolProperty(
-        name="Create an armature",
-        default=True,
-        description="Import the markers as bones instead of empties",
-    )
-    size: FloatProperty(
-        name="Empty or bone size",
-        default=.03,
-        description="The size of each empty or bone",
-        min=0.0001, max=1000000.0,
-        soft_min=0.001, soft_max=100.0,
-    )
-    x_ray: BoolProperty(
-        name="Use X-Ray",
-        default=True,
-        description="Show the empties or armature over other objects",
-    )
-    frame_skip: IntProperty(
-        name="Fps divisor",
-        default=1,
-        description="Frame supersampling factor",
-        min=1,
-    )
-    use_frame_no: BoolProperty(
-        name="Use frame numbers",
-        default=False,
-        description="Offset start of animation according to the source",
-    )
-    show_names: BoolProperty(
-        name="Show Names", default=False,
-        description="Show the markers' name",
-    )
-    prefix: StringProperty(
-        name="Name Prefix", maxlen=32,
-        description="Prefix object names with this",
-    )
-    use_existing: BoolProperty(
-        name="Use existing empties or armature",
-        default=False,
-        description="Use previously created homonymous empties or bones",
-    )
-    confidence: FloatProperty(
-        name="Minimum Confidence Level", default=0,
-        description="Only consider markers with at least "
-                    "this confidence level",
-        min=-1., max=1000000.0,
-        soft_min=-1., soft_max=100.0,
-    )
-
-    filter_glob: StringProperty(default="*.c3d;*.csv", options={'HIDDEN'})
-
-    def find_height(self, ms):
-        """
-            Heuristic to find the height of the subject in the markerset
-            (only works for standing poses and you must have correct data
-            on the first frame)
-        """
-        zmin, zmax = None, None
-        hidx = 1 if self.properties.Y_up else 2
-        for ml in ms.markerLabels:
-            # check if LTOE is a substring of this marker label
-            if 'LTOE' in ml:
-                # substitute the substring to get the head marker
-                hd = ml.replace('LTOE', 'LFHD')
-                if hd not in ms.markerLabels:
-                    break
-                pmin_idx = ms.markerLabels.index(ml)
-                pmax_idx = ms.markerLabels.index(hd)
-                zmin = ms.frames[0][pmin_idx].position[hidx]
-                zmax = ms.frames[0][pmax_idx].position[hidx]
-                break
-        if zmin is None:  # could not find named markers, get extremes
-            allz = [m.position[hidx] for m in ms.frames[0]]
-            zmin, zmax = min(allz), max(allz)
-        return abs(zmax - zmin) or 1
-
-    def adjust_scale_magnitude(self, height, scale):
-        mag = math.log10(height * scale)
-        return scale * math.pow(10, -int(mag))
-
-    def adjust_scale(self, height, scale):
-        """
-            Try to find the correct scale for some common configurations
-            found in CMU's c3d files.
-        """
-        factor = height * scale / 1.75  # normalize
-        if factor < 0.5:
-            scale /= 10.0
-            factor *= 10.0
-        cmu_factors = [(1.0, 1.0), (1.1, 1.45), (1.6, 1.6), (2.54, 2.54)]
-        sqerr, fix = min(
-            ((cf[0] - factor) ** 2.0, 1.0 / cf[1])
-            for cf in cmu_factors
-        )
-        return scale * fix
-
-    def create_empties(self, ms):
-        """
-            Create the empties and get their collision-free names
-        """
-        unames = {}
-        use_existing = self.properties.use_existing
-        s = self.properties.size
-        empty_size = (s, s, s)
-        for ml in ms.markerLabels:
-            name = self.properties.prefix + ml
-            if use_existing and name in bpy.context.scene.objects:
-                o = bpy.context.scene.objects[name]
-            else:
-                bpy.ops.object.add()
-                o = bpy.context.active_object
-                o.name = name
-            unames[name] = o.name
-            bpy.ops.transform.resize(value=empty_size)
-            o.show_name = self.properties.show_names
-            o.show_in_front = self.properties.x_ray
-        for name in unames.values():
-            bpy.context.scene.objects[name].select_set(True)
-        return unames
-
-    def create_armature_obj(self, ms, scale):
-        """
-            Create or use existing armature, return a bone dict,
-            leave the armature in POSE mode
-        """
-        head_dir = Vector((0, 0, self.properties.size))
-        ao = bpy.context.active_object
-        # when using an existing armature we restrict importing
-        # the markers only for existing bones
-        if not self.properties.use_existing or not ao or ao.type != 'ARMATURE':
-            bpy.ops.object.add(type='ARMATURE', enter_editmode=True)
-            arm = bpy.context.active_object
-            arm.name = os.path.basename(self.properties.filepath)
-            arm.data.show_names = self.properties.show_names
-            arm.show_in_front = self.properties.x_ray
-            for idx, ml in enumerate(ms.markerLabels):
-                name = self.properties.prefix + ml
-                bpy.ops.armature.select_all(action='DESELECT')
-                bpy.ops.armature.bone_primitive_add(name=name)
-                pos = Vector(ms.frames[0][idx].position) * scale
-                if self.properties.Y_up:
-                    pos = Vector((pos[0], -pos[2], pos[1]))
-                b = arm.data.edit_bones[name]
-                b.head = pos + head_dir
-                b.tail = pos
-        bpy.ops.object.mode_set(mode='POSE')
-        bpy.ops.pose.select_all(action='SELECT')
-
-    def execute(self, context):
-        ms = import_c3d.read(self.properties.filepath, onlyHeader=True)
-        ms.readNextFrameData()
-
-        # determine the final scale
-        height = self.find_height(ms)
-        scale = 1.0 if not self.properties.from_inches else 0.0254
-        scale *= ms.scale
-        if self.properties.auto_magnitude:
-            scale = self.adjust_scale_magnitude(height, scale)
-        if self.properties.auto_scale:
-            scale = self.adjust_scale(height, scale)
-        scale *= self.properties.scale
-
-        if bpy.context.mode != 'OBJECT':
-            bpy.ops.object.mode_set(mode='OBJECT')
-        if self.properties.create_armature:
-            self.create_armature_obj(ms, scale)
-        else:
-            unames = self.create_empties(ms)
-
-        # start animating the empties
-        C3DAnimateCloud.markerset = ms
-        C3DAnimateCloud.is_armature = self.properties.create_armature
-        if not C3DAnimateCloud.is_armature:
-            C3DAnimateCloud.unames = unames
-        C3DAnimateCloud.scale = scale
-        C3DAnimateCloud.Y_up = self.properties.Y_up
-        C3DAnimateCloud.fskip = self.properties.frame_skip
-        C3DAnimateCloud.prefix = self.properties.prefix
-        C3DAnimateCloud.use_frame_no = self.properties.use_frame_no
-        C3DAnimateCloud.confidence = self.properties.confidence
-        C3DAnimateCloud.curframe = ms.startFrame
-        bpy.ops.import_anim.c3danim()
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        wm.fileselect_add(self)
-        return {'RUNNING_MODAL'}
-
-
-def menu_func(self, context):
-    self.layout.operator(C3DImporter.bl_idname,
-                         text="Graphics Lab Motion Capture (.c3d)")
-
-
-def register():
-    bpy.utils.register_module(__name__)
-    bpy.types.TOPBAR_MT_file_import.append(menu_func)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-    bpy.types.TOPBAR_MT_file_import.remove(menu_func)
-
-
-if __name__ == "__main__":
-    register()
diff --git a/io_anim_c3d/import_c3d.py b/io_anim_c3d/import_c3d.py
deleted file mode 100644 (file)
index 6694474..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-# ##### 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 3
-#  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-80 compliant>
-
-# By Daniel Monteiro Basso, April-November 2011.
-
-# This script was developed with financial support from the Foundation for
-# Science and Technology of Portugal, under the grant SFRH/BD/66452/2009.
-
-# Complete rewrite, but based on the original importer for Blender
-# 2.39, developed by Jean-Baptiste PERIN (jb_perin(at)yahoo.fr), which was
-# based on the MATLAB C3D loader from Alan Morris, Toronto, October 1998
-# and Jaap Harlaar, Amsterdam, april 2002
-
-
-import struct
-try:
-    from numpy import array as vec  # would be nice to have NumPy in Blender
-except:
-    from mathutils import Vector as vec
-
-
-class Marker:
-    position = (0., 0., 0.)
-    confidence = -1.
-
-
-class Parameter:
-    def __init__(self, infile):
-        (nameLength, self.paramIdx) = struct.unpack('bb', infile.read(2))
-        if not nameLength:
-            self.name = ''
-            return
-        nameLength = abs(nameLength)  # negative flags something
-        if nameLength > 64:
-            raise ValueError
-        self.name = infile.read(nameLength).decode('ascii')
-        (offset, b) = struct.unpack('hb', infile.read(3))
-        if self.paramIdx > 0:
-            self.isGroup = False
-            self.data = infile.read(offset - 3)
-        else:
-            self.isGroup = True
-            self.paramIdx *= -1
-            self.description = infile.read(b)
-            self.params = {}
-
-    def collect(self, infile):
-        while True:
-            p = Parameter(infile)
-            if not p.name or p.isGroup:
-                return p
-            self.params[p.name] = p
-
-    def decode(self):
-        # for now only decode labels
-        l, c = struct.unpack('BB', self.data[1:3])
-        return [self.data[3 + i:3 + i + l].strip().decode('ascii')
-                for i in range(0, l * c, l)]
-
-
-class MarkerSet:
-    def __init__(self, fileName, scale=1., stripPrefix=True, onlyHeader=False):
-        self.fileName = fileName
-        if fileName.endswith('.csv'):
-            with open(fileName, 'rt') as infile:
-                self.readCSV(infile)
-            return
-        if onlyHeader:
-            self.infile = open(fileName, 'rb')
-            self.readHeader(self.infile, scale)
-            self.identifyMarkerPrefix(stripPrefix)
-            self.infile.seek(512 * (self.dataBlock - 1))
-            self.frames = []
-            return
-        with open(fileName, 'rb') as infile:
-            self.readHeader(infile, scale)
-            self.identifyMarkerPrefix(stripPrefix)
-            self.readFrameData(infile)
-
-    def readCSV(self, infile):
-        import csv
-        csvr = csv.reader(infile)
-        header = next(csvr)
-        if 0 != len(header) % 3:
-            raise Exception('Incorrect data format in CSV file')
-        self.markerLabels = [label[:-2] for label in header[::3]]
-        self.frames = []
-        for framerow in csvr:
-            newFrame = []
-            for c in range(0, len(framerow), 3):
-                m = Marker()
-                try:
-                    m.position = vec([float(v) for v in framerow[c:c + 3]])
-                    m.confidence = 1.
-                except:
-                    pass
-                newFrame.append(m)
-            self.frames.append(newFrame)
-        self.startFrame = 0
-        self.endFrame = len(self.frames) - 1
-        self.scale = 1.
-
-    def writeCSV(self, fileName, applyScale=True, mfilter=[]):
-        import csv
-        with open(fileName, 'w') as fo:
-            o = csv.writer(fo)
-            appxyz = lambda m: [m + a for a in ('_X', '_Y', '_Z')]
-            explabels = (appxyz(m) for m in self.markerLabels
-                         if not mfilter or m in mfilter)
-            o.writerow(sum(explabels, []))
-            fmt = lambda m: tuple('{0:.4f}'.format(
-                a * (self.scale if applyScale else 1.))
-                for a in m.position)
-            nan = ('NaN', 'NaN', 'NaN')
-            if mfilter:
-                mfilter = [self.markerLabels.index(m)
-                            for m in self.markerLabels if m in mfilter]
-            for f in self.frames:
-                F = f
-                if mfilter:
-                    F = [m for i, m in enumerate(f) if i in mfilter]
-                expmarkers = (m.confidence < 0 and nan or fmt(m) for m in F)
-                o.writerow(sum(expmarkers, ()))
-
-    def identifyMarkerPrefix(self, stripPrefix):
-        prefix = self.markerLabels[0]
-        for ml in self.markerLabels[1:]:
-            if len(ml) < len(prefix):
-                prefix = prefix[:len(ml)]
-            if not prefix:
-                break
-            for i in range(len(prefix)):
-                if prefix[i] != ml[i]:
-                    prefix = prefix[:i]
-                    break
-        self.prefix = prefix
-        if stripPrefix:
-            p = len(self.prefix)
-            self.markerLabels = [ml[p:] for ml in self.markerLabels]
-
-    def readHeader(self, infile, scale):
-        (self.firstParameterBlock, key, self.markerCount, bogus,
-         self.startFrame, self.endFrame,
-         bogus) = struct.unpack('BBhhhhh', infile.read(12))
-        if key != 80:
-            raise Exception('Not a C3D file.')
-        self.readParameters(infile)
-        infile.seek(12)
-        td = infile.read(12)
-        if self.procType == 2:
-            td = td[2:4] + td[:2] + td[4:8] + td[10:] + td[8:10]
-        (self.scale, self.dataBlock, bogus,
-         self.frameRate) = struct.unpack('fhhf', td)
-        self.scale *= scale
-        if self.scale < 0:
-            if self.procType == 2:
-                self.readMarker = self.readFloatMarkerInvOrd
-            else:
-                self.readMarker = self.readFloatMarker
-            self.scale *= -1
-        else:
-            self.readMarker = self.readShortMarker
-
-    def readParameters(self, infile):
-        infile.seek(512 * (self.firstParameterBlock - 1))
-        (ig, ig, pointIdx,
-         self.procType) = struct.unpack('BBBB', infile.read(4))
-        self.procType -= 83
-        if self.procType not in {1, 2}:
-            # 1(INTEL-PC); 2(DEC-VAX); 3(MIPS-SUN/SGI)
-            print('Warning: importer was not tested for files from '
-                  'architectures other than Intel-PC and DEC-VAX')
-            print('Type: {0}'.format(self.procType))
-        self.paramGroups = {}
-        g = Parameter(infile)
-        self.paramGroups[g.name] = g
-        while(True):
-            g = g.collect(infile)
-            if not g.name:
-                break
-            self.paramGroups[g.name] = g
-        cand_mlabel = None
-        for pg in self.paramGroups:
-            #print("group: " + pg)
-            #for p in self.paramGroups[pg].params:
-            #    print("   * " + p)
-            if 'LABELS' in self.paramGroups[pg].params:
-                cand_mlabel = self.paramGroups[pg].params['LABELS'].decode()
-                if len(cand_mlabel) == self.markerCount:
-                    break
-                cand_mlabel = None
-        # pg should be 'POINT', but let's be liberal and accept any group
-        # as long as the LABELS parameter has the same number of markers
-        if cand_mlabel is None:
-            self.markerLabels = ["m{}".format(idx)
-                                 for idx in range(self.markerCount)]
-        else:
-            self.markerLabels = cand_mlabel
-        repeats = {}
-        for i, m in enumerate(self.markerLabels):
-            if m in repeats:
-                self.markerLabels[i] = '{}.{}'.format(m, repeats[m])
-                repeats[m] += 1
-            else:
-                repeats[m] = 1
-
-    def readMarker(self, infile):
-        pass  # ...
-
-    def readFloatMarker(self, infile):
-        m = Marker()
-        x, y, z, m.confidence = struct.unpack('ffff', infile.read(16))
-        m.position = (x * self.scale, y * self.scale, z * self.scale)
-        return m
-
-    def readFloatMarkerInvOrd(self, infile):
-        m = Marker()
-        inv = lambda f: f[2:] + f[:2]
-        i = lambda: inv(infile.read(4))
-        x, y, z, m.confidence = struct.unpack('ffff', i() + i() + i() + i())
-        m.position = (x * self.scale, y * self.scale, z * self.scale)
-        return m
-
-    def readShortMarker(self, infile):
-        m = Marker()
-        x, y, z, m.confidence = struct.unpack('hhhh', infile.read(8))
-        m.position = (x * self.scale, y * self.scale, z * self.scale)
-        return m
-
-    def readFrameData(self, infile):
-        infile.seek(512 * (self.dataBlock - 1))
-        self.frames = []
-        for f in range(self.startFrame, self.endFrame + 1):
-            frame = [self.readMarker(infile) for m in range(self.markerCount)]
-            self.frames.append(frame)
-
-    def readNextFrameData(self):
-        if len(self.frames) < (self.endFrame - self.startFrame + 1):
-            frame = [self.readMarker(self.infile)
-                for m in range(self.markerCount)]
-            self.frames.append(frame)
-        return self.frames[-1]
-
-    def getFramesByMarker(self, marker):
-        if type(marker) == int:
-            idx = marker
-        else:
-            idx = self.markerLabels.index(marker)
-        fcnt = self.endFrame - self.startFrame + 1
-        return [self.frames[f][idx] for f in range(fcnt)]
-
-    def getMarker(self, marker, frame):
-        idx = self.markerLabels.index(marker)
-        return self.frames[frame - self.startFrame][idx]
-
-
-def read(filename, *a, **kw):
-    return MarkerSet(filename, *a, **kw)
-
-# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-
-
-if __name__ == '__main__':
-    import os
-    import sys
-
-    sys.argv.pop(0)
-    if not sys.argv:
-        print("Convert C3D to CSV.\n"
-              "Please specify at least one C3D input file.")
-        raise SystemExit
-    while sys.argv:
-        fname = sys.argv.pop(0)
-        markerset = read(fname)
-        print("frameRate={0.frameRate}\t"
-              "scale={0.scale:.2f}\t"
-              "markers={0.markerCount}\t"
-              "startFrame={0.startFrame}\t"
-              "endFrame={0.endFrame}".format(markerset))
-        markerset.writeCSV(fname.lower().replace(".c3d", ".csv"))
diff --git a/io_convert_image_to_mesh_img/__init__.py b/io_convert_image_to_mesh_img/__init__.py
deleted file mode 100644 (file)
index a884fb9..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""A HiRISE DTM Importer for Blender"""
-
-bl_info = {
-    "name": "HiRISE DTM Importer",
-    "author": "Nicholas Wolf (nicwolf@pirl.lpl.arizona.edu)",
-    "version": (0, 2, 2),
-    "blender": (2, 78, 0),
-    "location": "File > Import > HiRISE DTM (.img)",
-    "description": "Import a HiRISE DTM as a mesh",
-    "warning": "May consume a lot of memory",
-    "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/HiRISE_DTM_from_PDS_IMG",
-    "category": "Import-Export",
-}
-
-if "bpy" in locals():
-    import importlib
-    importlib.reload(importer)
-    importlib.reload(terrainpanel)
-
-else:
-    from .ui import importer
-    from .ui import terrainpanel
-
-import bpy
-
-
-def menu_import(self, context):
-    i = importer.ImportHiRISETerrain
-    self.layout.operator(i.bl_idname, text=i.bl_label)
-
-
-def register():
-    bpy.utils.register_module(__name__)
-    bpy.types.TOPBAR_MT_file_import.append(menu_import)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-    bpy.types.TOPBAR_MT_file_import.remove(menu_import)
-
-
-if __name__ == '__main__':
-    register()
diff --git a/io_convert_image_to_mesh_img/mesh/__init__.py b/io_convert_image_to_mesh_img/mesh/__init__.py
deleted file mode 100644 (file)
index edbc8c8..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""A sub-package for loading DTMs as 3D models"""
-
-from . import dtm
-from . import terrain
-
-__all__ = ['dtm', 'terrain', ]
diff --git a/io_convert_image_to_mesh_img/mesh/dtm.py b/io_convert_image_to_mesh_img/mesh/dtm.py
deleted file mode 100644 (file)
index a6ab6e3..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""Objects for importing HiRISE DTMs."""
-
-import numpy as np
-
-from .. import pvl
-
-
-class DTM:
-    """
-    HiRISE Digital Terrain Model
-
-    This class imports a HiRISE DTM from a Planetary Data Systems (PDS)
-    compliant .IMG file.
-
-    Parameters
-    ----------
-    path : str
-    terrain_resolution : float, optional
-        Controls the resolution the DTM is read at. This should be a float
-        in the range [0.01, 1.0] (and will be constrained to this range). A
-        value of 1.0 will result in the DTM being read at full resolution. A
-        value of 0.01 will result in the DTM being read at 1/100th resolution.
-        Default is 1.0 (no downsampling).
-
-    Todo
-    ----
-    * Use GDAL for importing the DTM if it is installed for this Python
-      environment. If/when I have the time to do this, it probably
-      warrants breaking out separate importer classes. The benefits of
-      doing this are pretty substantial, though:
-
-        + More reliable (doesn't rely on my PVL parser for finding the
-          valid values in the DTM, for locating the starting position of
-          the elevation data in the .IMG file)
-
-        + Other, better, downsampling algorithms are already built in.
-
-        + Would make this much better at general PDS DTM importing,
-          currently some of the import code is specific to HiRISE DTMs.
-
-    """
-
-    # Special constants in our data:
-    #     NULL : No data at this point.
-    #     LRS  : Low Representation Saturation
-    #     LIS  : Low Instrument Saturation
-    #     HRS  : High Representation Saturation
-    #     HIS  : High Insturment Saturation
-    SPECIAL_VALUES = {
-        "NULL": np.fromstring(b'\xFF\x7F\xFF\xFB', dtype='>f4')[0],
-        "LRS": np.fromstring(b'\xFF\x7F\xFF\xFC', dtype='>f4')[0],
-        "LIS": np.fromstring(b'\xFF\x7F\xFF\xFD', dtype='>f4')[0],
-        "HRS": np.fromstring(b'\xFF\x7F\xFF\xFE', dtype='>f4')[0],
-        "HIS": np.fromstring(b'\xFF\x7F\xFF\xFF', dtype='>f4')[0]
-    }
-
-    def __init__(self, path, terrain_resolution=1.0):
-        self.path = path
-        self.terrain_resolution = terrain_resolution
-        self.label = self._read_label()
-        self.data = self._read_data()
-
-    def _read_label(self):
-        """Returns a dict-like representation of a PVL label"""
-        return pvl.load(self.path)
-
-    def _read_data(self):
-        """
-        Reads elevation data from a PDS .IMG file.
-
-        Notes
-        -----
-        * Uses nearest-neighbor to downsample data.
-
-        Todo
-        ----
-        * Add other downsampling algorithms.
-
-        """
-        h, w = self.image_resolution
-        max_samples = int(w - w % self.bin_size)
-
-        data = np.zeros(self.shape)
-        with open(self.path, 'rb') as f:
-            # Seek to the first byte of data
-            start_byte = self._get_data_start()
-            f.seek(start_byte)
-            # Iterate over each row of the data
-            for r in range(data.shape[0]):
-                # Each iteration, seek to the right location before
-                # reading a row. We determine this location as the
-                # first byte of data PLUS a offset which we calculate as the
-                # product of:
-                #
-                #     4, the number of bytes in a single record
-                #     r, the current row index
-                #     w, the number of records in a row of the DTM
-                #     bin_size, the number of records in a bin
-                #
-                # This is where we account for skipping over rows.
-                offset = int(4 * r * w * self.bin_size)
-                f.seek(start_byte + offset)
-                # Read a row
-                row = np.fromfile(f, dtype=np.float32, count=max_samples)
-                # This is where we account for skipping over columns.
-                data[r] = row[::self.bin_size]
-
-        data = self._process_invalid_data(data)
-        return data
-
-    def _get_data_start(self):
-        """Gets the start position of the DTM data block"""
-        label_length = self.label['RECORD_BYTES']
-        num_labels = self.label.get('LABEL_RECORDS', 1)
-        return int(label_length * num_labels)
-
-    def _process_invalid_data(self, data):
-        """Sets any 'NULL' elevation values to np.NaN"""
-        invalid_data_mask = (data <= self.SPECIAL_VALUES['NULL'])
-        data[invalid_data_mask] = np.NaN
-        return data
-
-    @property
-    def map_size(self):
-        """Geographic size of the bounding box around the DTM"""
-        scale = self.map_scale * self.unit_scale
-        w = self.image_resolution[0] * scale
-        h = self.image_resolution[1] * scale
-        return (w, h)
-
-    @property
-    def mesh_scale(self):
-        """Geographic spacing between mesh vertices"""
-        return self.bin_size * self.map_scale * self.unit_scale
-
-    @property
-    def map_info(self):
-        """Map Projection metadata"""
-        return self.label['IMAGE_MAP_PROJECTION']
-
-    @property
-    def map_scale(self):
-        """Geographic spacing between DTM posts"""
-        map_scale = self.map_info.get('MAP_SCALE', None)
-        return getattr(map_scale, 'value', 1.0)
-
-    @property
-    def map_units(self):
-        """Geographic unit for spacing between DTM posts"""
-        map_scale = self.map_info.get('MAP_SCALE', None)
-        return getattr(map_scale, 'units', None)
-
-    @property
-    def unit_scale(self):
-        """
-        The function that creates a Blender mesh from this object will assume
-        that the height values passed into it are in meters --- this
-        property is a multiplier to convert DTM-units to meters.
-        """
-        scaling_factors = {
-            'KM/PIXEL': 1000,
-            'METERS/PIXEL': 1
-        }
-        return scaling_factors.get(self.map_units, 1.0)
-
-    @property
-    def terrain_resolution(self):
-        """Vertex spacing, meters"""
-        return self._terrain_resolution
-
-    @terrain_resolution.setter
-    def terrain_resolution(self, t):
-        self._terrain_resolution = np.clip(t, 0.01, 1.0)
-
-    @property
-    def bin_size(self):
-        """The width of the (square) downsampling bin"""
-        return int(np.ceil(1 / self.terrain_resolution))
-
-    @property
-    def image_stats(self):
-        """Image statistics from the original DTM label"""
-        return self.label['IMAGE']
-
-    @property
-    def image_resolution(self):
-        """(Line, Sample) resolution of the original DTM"""
-        return (self.image_stats['LINES'], self.image_stats['LINE_SAMPLES'])
-
-    @property
-    def size(self):
-        """Number of posts in our reduced DTM"""
-        return self.shape[0] * self.shape[1]
-
-    @property
-    def shape(self):
-        """Shape of our reduced DTM"""
-        num_rows = self.image_resolution[0] // self.bin_size
-        num_cols = self.image_resolution[1] // self.bin_size
-        return (num_rows, num_cols)
diff --git a/io_convert_image_to_mesh_img/mesh/terrain.py b/io_convert_image_to_mesh_img/mesh/terrain.py
deleted file mode 100644 (file)
index 3949d69..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""Objects for creating 3D models in Blender"""
-
-import bpy
-import bmesh
-
-import numpy as np
-
-from .triangulate import Triangulate
-
-
-class BTerrain:
-    """
-    Functions for creating Blender meshes from DTM objects
-
-    This class contains functions that convert DTM objects to Blender meshes.
-    Its main responsibility is to triangulate a mesh from the elevation data in
-    the DTM. Additionally, it attaches some metadata to the object and creates
-    a UV map for it so that companion ortho-images drape properly.
-
-    This class provides two public methods: `new()` and `reload()`.
-
-    `new()` creates a new object[1] and attaches a new mesh to it.
-
-    `reload()` replaces the mesh that is attached to an already existing
-    object. This allows us to retain the location and orientation of the parent
-    object's coordinate system but to reload the terrain at a different
-    resolution.
-
-    Notes
-    ----------
-    [1] If you're unfamiliar with Blender, one thing that will help you in
-        reading this code is knowing the difference between 'meshes' and
-        'objects'. A mesh is just a collection of vertices, edges and
-        faces. An object may have a mesh as a child data object and
-        contains additional information, e.g. the location and orientation
-        of the coordinate system its child-meshes are reckoned in terms of.
-
-    """
-
-    @staticmethod
-    def new(dtm, name='Terrain'):
-        """
-        Loads a new terrain
-
-        Parameters
-        ----------
-        dtm : DTM
-        name : str, optional
-            The name that will be assigned to the new object, defaults
-            to 'Terrain' (and, if an object named 'Terrain' already
-            exists, Blender will automatically extend the name of the
-            new object to something like 'Terrain.001')
-
-        Returns
-        ----------
-        obj : bpy_types.Object
-
-        """
-        bpy.ops.object.add(type="MESH")
-        obj = bpy.context.object
-        obj.name = name
-
-        # Fill the object data with a Terrain mesh
-        obj.data = BTerrain._mesh_from_dtm(dtm)
-
-        # Add some meta-information to the object
-        metadata = BTerrain._create_metadata(dtm)
-        BTerrain._setobjattrs(obj, **metadata)
-
-        # Center the mesh to its origin and create a UV map for draping
-        # ortho images.
-        BTerrain._center(obj)
-
-        return obj
-
-    @staticmethod
-    def reload(obj, dtm):
-        """
-        Replaces an existing object's terrain mesh
-
-        This replaces an object's mesh with a new mesh, transferring old
-        materials over to the new mesh. This is useful for reloading DTMs
-        at different resolutions but maintaining textures/location/rotation.
-
-        Parameters
-        -----------
-        obj : bpy_types.Object
-            An already existing Blender object
-        dtm : DTM
-
-        Returns
-        ----------
-        obj : bpy_types.Object
-
-        """
-        old_mesh = obj.data
-        new_mesh = BTerrain._mesh_from_dtm(dtm)
-
-        # Copy any old materials to the new mesh
-        for mat in old_mesh.materials:
-            new_mesh.materials.append(mat.copy())
-
-        # Swap out the old mesh for the new one
-        obj.data = new_mesh
-
-        # Update out-dated meta-information
-        metadata = BTerrain._create_metadata(dtm)
-        BTerrain._setobjattrs(obj, **metadata)
-
-        # Center the mesh to its origin and create a UV map for draping
-        # ortho images.
-        BTerrain._center(obj)
-
-        return obj
-
-    @staticmethod
-    def _mesh_from_dtm(dtm, name='Terrain'):
-        """
-        Creates a Blender *mesh* from a DTM
-
-        Parameters
-        ----------
-        dtm : DTM
-        name : str, optional
-            The name that will be assigned to the new mesh, defaults
-            to 'Terrain' (and, if an object named 'Terrain' already
-            exists, Blender will automatically extend the name of the
-            new object to something like 'Terrain.001')
-
-        Returns
-        ----------
-        mesh : bpy_types.Mesh
-
-        Notes
-        ----------
-        * We are switching coordinate systems from the NumPy to Blender.
-
-              Numpy:            Blender:
-               + ----> (0, j)    ^ (0, y)
-               |                 |
-               |                 |
-               v (i, 0)          + ----> (x, 0)
-
-        """
-        # Create an empty mesh
-        mesh = bpy.data.meshes.new(name)
-
-        # Get the xy-coordinates from the DTM, see docstring notes
-        y, x = np.indices(dtm.data.shape).astype('float64')
-        x *= dtm.mesh_scale
-        y *= -1 * dtm.mesh_scale
-
-        # Create an array of 3D vertices
-        vertices = np.dstack([x, y, dtm.data]).reshape((-1, 3))
-
-        # Drop vertices with NaN values (used in the DTM to represent
-        # areas with no data)
-        vertices = vertices[~np.isnan(vertices).any(axis=1)]
-
-        # Calculate the faces of the mesh
-        triangulation = Triangulate(dtm.data)
-        faces = triangulation.face_list()
-
-        # Fill the mesh
-        mesh.from_pydata(vertices, [], faces)
-        mesh.update()
-
-        # Create a new UV layer
-        mesh.uv_textures.new("HiRISE Generated UV Map")
-        # We'll use a bmesh to populate the UV map with values
-        bm = bmesh.new()
-        bm.from_mesh(mesh)
-        bm.faces.ensure_lookup_table()
-        uv_layer = bm.loops.layers.uv[0]
-
-        # Iterate over each face in the bmesh
-        num_faces = len(bm.faces)
-        w = dtm.data.shape[1]
-        h = dtm.data.shape[0]
-        for face_index in range(num_faces):
-            # Iterate over each loop in the face
-            for loop in bm.faces[face_index].loops:
-                # Get this loop's vertex coordinates
-                vert_coords = loop.vert.co.xy
-                # And calculate it's uv coordinate. We do this by dividing the
-                # vertice's x and y coordinates by:
-                #
-                #     d + 1, dimensions of DTM (in "posts")
-                #     mesh_scale, meters/DTM "post"
-                #
-                # This has the effect of mapping the vertex to its
-                # corresponding "post" index in the DTM, and then mapping
-                # that value to the range [0, 1).
-                u = vert_coords.x / ((w + 1) * dtm.mesh_scale)
-                v = 1 + vert_coords.y / ((h + 1) * dtm.mesh_scale)
-                loop[uv_layer].uv = (u, v)
-
-        bm.to_mesh(mesh)
-
-        return mesh
-
-    @staticmethod
-    def _center(obj):
-        """Move object geometry to object origin"""
-        bpy.context.view_layer.objects.active = obj
-        bpy.ops.object.origin_set(center='BOUNDS')
-
-    @staticmethod
-    def _setobjattrs(obj, **attrs):
-        for key, value in attrs.items():
-            obj[key] = value
-
-    @staticmethod
-    def _create_metadata(dtm):
-        """Returns a dict containing meta-information about a DTM"""
-        return {
-            'PATH': dtm.path,
-            'MESH_SCALE': dtm.mesh_scale,
-            'DTM_RESOLUTION': dtm.terrain_resolution,
-            'BIN_SIZE': dtm.bin_size,
-            'MAP_SIZE': dtm.map_size,
-            'MAP_SCALE': dtm.map_scale * dtm.unit_scale,
-            'UNIT_SCALE': dtm.unit_scale,
-            'IS_TERRAIN': True,
-            'HAS_UV_MAP': True
-        }
diff --git a/io_convert_image_to_mesh_img/mesh/triangulate.py b/io_convert_image_to_mesh_img/mesh/triangulate.py
deleted file mode 100644 (file)
index bb0a50a..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""Triangulation algorithms"""
-
-import numpy as np
-
-
-class Triangulate:
-    """
-    A triangulation algorithm for creating a mesh from a DTM raster.
-
-    I have been re-writing parts of the Blender HiRISE DTM importer in an
-    effort to cull its dependencies on external packages. Originally, the
-    add-on relied on SciPy's Delaunay triangulation (really a wrapper for
-    Qhull's Delaunay triangulation) to triangulate a mesh from a HiRISE DTM.
-
-    This re-write is much better suited to the problem domain. The SciPy
-    Delaunay triangulation creates a mesh from any arbitrary point cloud and,
-    while robust, doesn't care about the fact that our HiRISE DTMs are
-    regularly gridded rasters. This triangulation algorithm is less robust
-    but much faster. Credit is due to Tim Spriggs for his work on the previous
-    Blender HiRISE DTM importer --- this triangulation algorithm largely
-    models the one in his add-on with a few changes (namely interfacing
-    with NumPy's API).
-
-    Overview
-    ----------
-    Suppose we have a DTM:
-
-    .. code::
-
-                -  -  -  -  -  -  -  -  X  X  -  -  -  -  -
-                -  -  -  -  -  -  X  X  X  X  X  -  -  -  -
-                -  -  -  -  X  X  X  X  X  X  X  X  -  -  -
-                -  -  X  X  X  X  X  X  X  X  X  X  X  -  -
-                X  X  X  X  X  X  X  X  X  X  X  X  X  X  -
-                -  X  X  X  X  X  X  X  X  X  X  X  X  X  X
-                -  -  X  X  X  X  X  X  X  X  X  X  X  -  -
-                -  -  -  X  X  X  X  X  X  X  X  -  -  -  -
-                -  -  -  -  X  X  X  X  X  -  -  -  -  -  -
-                -  -  -  -  -  X  X  -  -  -  -  -  -  -  -
-
-    where 'X' represents valid values and '-' represents invalid values.
-    Valid values should become vertices in the resulting mesh, invalid
-    values should be ignored.
-
-    Our end goal is to supply Blender with:
-
-        1. an (n x 3) list of vertices
-
-        2. an (m x 3) list of faces.
-
-    A vertex is a 3-tuple that we get from the DTM raster array. The
-    z-coordinate is whatever elevation value is in the DTM and the xy-
-    coordinates are the image indices multiplied by the resolution of the
-    DTM (e.g. if the DTM is at 5m/px, the first vertex is at (0m, 0m,
-    z_00) and the vertex to the right of it is at (5m, 0m, z_01)).
-
-    A face is a 3-tuple (because we're using triangles) where each element
-    is an index of a vertex in the vertices list. Computing the faces is
-    tricky because we want to leverage the orthogonal structure of the DTM
-    raster for computational efficiency but we also need to reference
-    vertex indices in our faces, which don't observe any regular
-    structure.
-
-    We take two rows at a time from the DTM raster and track the *raster
-    row* indices as well as well as the *vertex* indices. Raster row
-    indices are the distance of a pixel in the raster from the left-most
-    (valid *or* invalid) pixel of the row. The first vertex is index 0 and
-    corresponds to the upperleft-most valid pixel in the DTM raster.
-    Vertex indices increase to the right and then down.
-
-    For example, the first two rows:
-
-    .. code::
-
-                -  -  -  -  -  -  -  -  X  X  -  -  -  -  -
-                -  -  -  -  -  -  X  X  X  X  X  -  -  -  -
-
-    in vertex indices:
-
-    .. code::
-
-                -  -  -  -  -  -  -  -  0  1  -  -  -  -  -
-                -  -  -  -  -  -  2  3  4  5  6  -  -  -  -
-
-    and in raster row indices:
-
-    .. code::
-
-                -  -  -  -  -  -  -  -  9 10  -  -  -  -  -
-                -  -  -  -  -  -  7  8  9 10 11  -  -  -  -
-
-    To simplify, we will only add valid square regions to our mesh. So,
-    for these first two rows the only region that will be added to our
-    mesh is the quadrilateral formed by vertices 0, 1, 4 and 5. We
-    further divide this area into 2 triangles and add the vertices to the
-    face list in CCW order (i.e. t1: (4, 1, 0), t2: (4, 5, 1)).
-
-    After the triangulation between two rows is completed, the bottom
-    row is cached as the top row and the next row in the DTM raster is
-    read as the new bottom row. This process continues until the entire
-    raster has been triangulated.
-
-    Todo
-    ---------
-    * It should be pretty trivial to add support for triangular
-      regions (i.e. in the example above, also adding the triangles
-      formed by (3, 4, 0) and (5, 6, 1)).
-
-    """
-    def __init__(self, array):
-        self.array = array
-        self.faces = self._triangulate()
-
-    def _triangulate(self):
-        """Triangulate a mesh from a topography array."""
-        # Allocate memory for the triangles array
-        max_tris = (self.array.shape[0] - 1) * (self.array.shape[1] - 1) * 2
-        tris = np.zeros((max_tris, 3), dtype=int)
-        ntri = 0
-
-        # We initialize a vertex counter at 0
-        prev_vtx_start = 0
-        # We don't care about the values in the array, just whether or not
-        # they are valid.
-        prev = ~np.isnan(self.array[0])
-        # We can sum this boolean array to count the number of valid entries
-        prev_num_valid = prev.sum()
-        # TODO: Probably a more clear (and faster) function than argmax for
-        # getting the first Truth-y value in a 1d array.
-        prev_img_start = np.argmax(prev)
-
-        # Start quadrangulation
-        for i in range(1, self.array.shape[0]):
-            # Fetch this row, get our bearings in image *and* vertex space
-            curr = ~np.isnan(self.array[i])
-            curr_vtx_start = prev_vtx_start + prev_num_valid
-            curr_img_start = np.argmax(curr)
-            curr_num_valid = curr.sum()
-            # Find the overlap between this row and the previous one
-            overlap = np.logical_and(prev, curr)
-            num_tris = overlap.sum() - 1
-            overlap_start = np.argmax(overlap)
-            # Store triangles
-            for j in range(num_tris):
-                curr_pad = overlap_start - curr_img_start + j
-                prev_pad = overlap_start - prev_img_start + j
-                tris[ntri + 0] = [
-                    curr_vtx_start + curr_pad,
-                    prev_vtx_start + prev_pad + 1,
-                    prev_vtx_start + prev_pad
-                ]
-                tris[ntri + 1] = [
-                    curr_vtx_start + curr_pad,
-                    curr_vtx_start + curr_pad + 1,
-                    prev_vtx_start + prev_pad + 1
-                ]
-                ntri += 2
-            # Cache current row as previous row
-            prev = curr
-            prev_vtx_start = curr_vtx_start
-            prev_img_start = curr_img_start
-            prev_num_valid = curr_num_valid
-
-        return tris[:ntri]
-
-    def face_list(self):
-        return list(self.faces)
diff --git a/io_convert_image_to_mesh_img/pvl/__init__.py b/io_convert_image_to_mesh_img/pvl/__init__.py
deleted file mode 100644 (file)
index 4fcf394..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""A sub-package for parsing PVL labels"""
-
-from .parse import LabelParser
-
-
-def load(path):
-    """Returns a dict-like representation of a PVL label"""
-    return LabelParser.load(path)
diff --git a/io_convert_image_to_mesh_img/pvl/label.py b/io_convert_image_to_mesh_img/pvl/label.py
deleted file mode 100644 (file)
index 68d4f91..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-
-class Label(dict):
-    """A dict-like representation of a PVL label"""
-    def __init__(self, *args, **kwargs):
-        super(Label, self).__init__(*args, **kwargs)
diff --git a/io_convert_image_to_mesh_img/pvl/parse.py b/io_convert_image_to_mesh_img/pvl/parse.py
deleted file mode 100644 (file)
index 3a87d2f..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""PVL Label Parsing"""
-
-import collections
-import re
-
-from . import patterns
-from .label import Label
-
-Quantity = collections.namedtuple('Quantity', ['value', 'units'])
-
-
-class PVLParseError(Exception):
-    """Error parsing PVL file"""
-    def __init__(self, message):
-        super(PVLParseError, self).__init__(message)
-
-
-class LabelParser:
-    """A PVL Parser"""
-    @staticmethod
-    def load(path):
-        """
-        Load a dict-like representation of a PVL label header
-
-        Parameters
-        ----------
-        path : str
-            Path to a file containing a PVL header
-
-        Returns
-        ----------
-        label : pvl.Label
-
-        """
-        raw = LabelParser._read(path)
-        return Label(**LabelParser._parse(raw))
-
-    @staticmethod
-    def _read(path):
-        """
-        Get the PVL header from a file as a string
-
-        Parameters
-        ----------
-        path : str
-            Path to a file containing a PVL header
-
-        Returns
-        ----------
-        raw : str
-
-        Notes
-        ---------
-        * This function assumes that the file begins with a PVL header
-          and it will read lines from the file until it encounters
-          a PVL end statement.
-
-        To-Do
-        ---------
-        * This could be more robust. What happens if there is no label
-          in the file?
-
-        """
-        with open(path, 'rb') as f:
-            raw = ''
-            while True:
-                try:
-                    line = f.readline().decode()
-                    raw += line
-                    if re.match(patterns.END, line):
-                        break
-                except UnicodeDecodeError:
-                    raise PVLParseError("Error parsing PVL label from "
-                                        "file: {}".format(path))
-        return raw
-
-    @staticmethod
-    def _remove_comments(raw):
-        return re.sub(patterns.COMMENT, '', raw)
-
-    @staticmethod
-    def _parse(raw):
-        raw = LabelParser._remove_comments(raw)
-        label_iter = re.finditer(patterns.STATEMENT, raw)
-        return LabelParser._parse_iter(label_iter)
-
-    @staticmethod
-    def _parse_iter(label_iter):
-        """Recursively parse a PVL label iterator"""
-        obj = {}
-        while True:
-            try:
-                # Try to fetch the next match from the iter
-                match = next(label_iter)
-                val = match.group('val')
-                key = match.group('key')
-                # Handle nested object groups
-                if key == 'OBJECT':
-                    obj.update({
-                        val: LabelParser._parse_iter(label_iter)
-                    })
-                elif key == 'END_OBJECT':
-                    return obj
-                # Add key/value pair to dict
-                else:
-                    # Should this value be a numeric type?
-                    try:
-                        val = LabelParser._convert_to_numeric(val)
-                    except ValueError:
-                        pass
-                    # Should this value have units?
-                    if match.group('units'):
-                        val = Quantity(val, match.group('units'))
-                    # Add it to the dict
-                    obj.update({key: val})
-            except StopIteration:
-                break
-        return obj
-
-    @staticmethod
-    def _convert_to_numeric(s):
-        """Convert a string to its appropriate numeric type"""
-        if re.match(patterns.INTEGER, s):
-            return int(s)
-        elif re.match(patterns.FLOATING, s):
-            return float(s)
-        else:
-            raise ValueError
diff --git a/io_convert_image_to_mesh_img/pvl/patterns.py b/io_convert_image_to_mesh_img/pvl/patterns.py
deleted file mode 100644 (file)
index af92180..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""PVL Regular Expression Patterns"""
-
-import re
-
-# End of PVL File
-END = re.compile(
-    r'\s* \bEND\b \s*', (re.VERBOSE + re.IGNORECASE)
-)
-
-# PVL Comment
-COMMENT = re.compile(
-    r'/\* .*? \*/', (re.DOTALL + re.VERBOSE)
-)
-
-# PVL Statement
-STATEMENT = re.compile(
-    r"""
-    \s* (?P<key>\w+) # Match a PVL key
-    \s* = \s* # Who knows how many spaces we encounter
-    (?P<val> # Match a PVL value
-        ([+-]?\d+\.?\d*) # We could match a number
-        | (['"]?((\w+ \s*?)+)['"]?) # Or a string
-    )
-    (\s* <(?P<units>.*?) >)? # The value may have an associated unit
-    """, re.VERBOSE
-)
-
-# Integer Number
-INTEGER = re.compile(
-    r"""
-    [+-]?(?<!\.)\b[0-9]+\b(?!\.[0-9])
-    """, re.VERBOSE
-)
-
-# Floating Point Number
-FLOATING = re.compile(
-    r"""
-    [+-]?\b[0-9]*\.?[0-9]+
-    """, re.VERBOSE
-)
diff --git a/io_convert_image_to_mesh_img/ui/__init__.py b/io_convert_image_to_mesh_img/ui/__init__.py
deleted file mode 100644 (file)
index 57bd9fd..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""A sub-package for Blender UI elements"""
-
-from . import importer
-from . import terrainpanel
-
-__all__ = ['importer', 'terrainpanel', ]
diff --git a/io_convert_image_to_mesh_img/ui/importer.py b/io_convert_image_to_mesh_img/ui/importer.py
deleted file mode 100644 (file)
index 45ff3ff..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""Blender menu importer for loading a DTM"""
-
-import bpy
-from bpy.props import (
-        BoolProperty,
-        FloatProperty,
-        StringProperty,
-        )
-from bpy_extras.io_utils import ImportHelper
-
-from ..mesh.terrain import BTerrain
-from ..mesh.dtm import DTM
-
-
-class ImportHiRISETerrain(bpy.types.Operator, ImportHelper):
-    """DTM Import Helper"""
-    bl_idname = "import_mesh.pds_dtm"
-    bl_label = "Import HiRISE Terrain Model"
-    bl_options = {'UNDO'}
-
-    filename_ext = ".img"
-    filter_glob: StringProperty(
-        options={'HIDDEN'},
-        default="*.img"
-    )
-
-    # Allow the user to specify a resolution factor for loading the
-    # terrain data at. This is useful because it allows the user to stage
-    # a scene with a low resolution terrain map, apply textures, modifiers,
-    # etc. and then increase the resolution to prepare for final rendering.
-    #
-    # Displaying this value as a percentage (0, 100] is an intuitive way
-    # for users to grasp what this value does. The DTM importer, however,
-    # wants to receive a value between (0, 1]. This is obviously a
-    # straightforward conversion:
-    #
-    #     f(x) = x / 100
-    #
-    # But this conversion should happen here, in the terrain panel, rather
-    # than in the DTM importing utility itself. We can't pass get/set
-    # functions to the property itself because they result in a recursion
-    # error. Instead, we use another, hidden, property to store the scaled
-    # resolution.
-    dtm_resolution: FloatProperty(
-        subtype="PERCENTAGE",
-        description=(
-            "Percentage scale for terrain model resolution. 100\% loads the "
-            "model at full resolution (i.e. one vertex for each post in the "
-            "original terrain model) and is *MEMORY INTENSIVE*. Downsampling "
-            "uses Nearest Neighbors. You will be able to increase the "
-            "resolution of your mesh later, and still maintain all textures, "
-            "transformations, modifiers, etc., so best practice is to start "
-            "small. The downsampling algorithm may need to alter the "
-            "resolution you specify here to ensure it results in a whole "
-            "number of vertices. If it needs to alter the value you specify, "
-            "you are guaranteed that it will shrink it (i.e. decrease the "
-            "DTM resolution"
-        ),
-        name="Terrain Model Resolution",
-        min=1.0, max=100.0, default=10.0
-    )
-    scaled_dtm_resolution: FloatProperty(
-        options={'HIDDEN'},
-        name="Scaled Terrain Model Resolution",
-        get=(lambda self: self.dtm_resolution / 100)
-    )
-
-    # HiRISE DTMs are huge, but it can be nice to load them in at scale. Here,
-    # we present the user with the option of setting up the Blender viewport
-    # to avoid a couple of common pitfalls encountered when working with such
-    # a large mesh.
-    #
-    # 1. The Blender viewport has a default clipping distance of 1km. HiRISE
-    #    DTMs are often many kilometers in each direction. If this setting is
-    #    not changed, an unsuspecting user may only see part (or even nothing
-    #    at all) of the terrain. This option (true, by default) instructs
-    #    Blender to change the clipping distance to something appropriate for
-    #    the DTM, and scales the grid floor to have gridlines 1km apart,
-    #    instead of 1m apart.
-    should_setup_viewport: BoolProperty(
-        description=(
-            "Set up the Blender screen to try and avoid clipping the DTM "
-            "and to make the grid floor larger. *WARNING* This will change "
-            "clipping distances and the Blender grid floor, and will fit the "
-            "DTM in the viewport"
-        ),
-        name="Setup Blender Scene", default=True
-    )
-    # 2. Blender's default units are dimensionless. This option instructs
-    #    Blender to change its unit's dimension to meters.
-    should_setup_units: BoolProperty(
-        description=(
-            "Set the Blender scene to use meters as its unit"
-        ),
-        name="Set Blender Units to Meters", default=True
-    )
-
-    def execute(self, context):
-        """Runs when the "Import HiRISE Terrain Model" button is pressed"""
-        filepath = bpy.path.ensure_ext(self.filepath, self.filename_ext)
-        # Create a BTerrain from the DTM
-        dtm = DTM(filepath, self.scaled_dtm_resolution)
-        BTerrain.new(dtm)
-
-        # Set up the Blender UI
-        if self.should_setup_units:
-            self._setup_units(context)
-        if self.should_setup_viewport:
-            self._setup_viewport(context)
-
-        return {"FINISHED"}
-
-    def _setup_units(self, context):
-        """Sets up the Blender scene for viewing the DTM"""
-        scene = bpy.context.scene
-
-        # Set correct units
-        scene.unit_settings.system = 'METRIC'
-        scene.unit_settings.scale_length = 1.0
-
-        return {'FINISHED'}
-
-    def _setup_viewport(self, context):
-        """Sets up the Blender screen to make viewing the DTM easier"""
-        screen = bpy.context.screen
-
-        # Fetch the 3D_VIEW Area
-        for area in screen.areas:
-            if area.type == 'VIEW_3D':
-                space = area.spaces[0]
-                # Adjust 3D View Properties
-                # TODO: Can these be populated more intelligently?
-                space.clip_end = 100000
-                space.grid_scale = 1000
-                space.grid_lines = 50
-
-        # Fly to a nice view of the DTM
-        self._view_dtm(context)
-
-        return {'FINISHED'}
-
-    def _view_dtm(self, context):
-        """Sets up the Blender screen to make viewing the DTM easier"""
-        screen = bpy.context.screen
-
-        # Fetch the 3D_VIEW Area
-        for area in screen.areas:
-            if area.type == 'VIEW_3D':
-                # Move the camera around in the viewport. This requires
-                # a context override.
-                for region in area.regions:
-                    if region.type == 'WINDOW':
-                        override = {
-                            'area': area,
-                            'region': region,
-                            'edit_object': bpy.context.edit_object
-                        }
-                        # Center View on DTM (SHORTCUT: '.')
-                        bpy.ops.view3d.view_selected(override)
-                        # Move to 'TOP' viewport (SHORTCUT: NUMPAD7)
-                        bpy.ops.view3d.viewnumpad(override, type='TOP')
-
-        return {'FINISHED'}
diff --git a/io_convert_image_to_mesh_img/ui/terrainpanel.py b/io_convert_image_to_mesh_img/ui/terrainpanel.py
deleted file mode 100644 (file)
index 284b860..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-# This file is a part of the HiRISE DTM Importer for Blender
-#
-# Copyright (C) 2017 Arizona Board of Regents on behalf of the Planetary Image
-# Research Laboratory, Lunar and Planetary Laboratory at the University of
-# Arizona.
-#
-# 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 3 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, see <http://www.gnu.org/licenses/>.
-
-"""Blender panel for managing a DTM *after* it's been imported"""
-
-import bpy
-from bpy.types import (
-        Operator,
-        Panel,
-        )
-from bpy.props import FloatProperty
-
-from ..mesh.terrain import BTerrain
-from ..mesh.dtm import DTM
-
-
-class TerrainPanel(Panel):
-    """Creates a Panel in the Object properties window for terrain objects"""
-    bl_label = "Terrain Model"
-    bl_idname = "OBJECT_PT_terrain"
-    bl_space_type = "PROPERTIES"
-    bl_region_type = "WINDOW"
-    bl_context = "object"
-
-    # Allow the user to specify a new resolution factor for reloading the
-    # terrain data at. This is useful because it allows the user to stage
-    # a scene with a low resolution terrain map, apply textures, modifiers,
-    # etc. and then increase the resolution to prepare for final rendering.
-    #
-    # Displaying this value as a percentage (0, 100] is an intuitive way
-    # for users to grasp what this value does. The DTM importer, however,
-    # wants to receive a value between (0, 1]. This is obviously a
-    # straightforward conversion:
-    #
-    #     f(x) = x / 100
-    #
-    # But this conversion should happen here, in the terrain panel, rather
-    # than in the DTM importing utility itself. We can't pass get/set
-    # functions to the property itself because they result in a recursion
-    # error. Instead, we use another, hidden, property to store the scaled
-    # resolution.
-    bpy.types.Object.dtm_resolution: FloatProperty(
-        subtype="PERCENTAGE",
-        name="New Resolution",
-        description=(
-            "Percentage scale for terrain model resolution. 100\% loads the "
-            "model at full resolution (i.e. one vertex for each post in the "
-            "original terrain model) and is *MEMORY INTENSIVE*. Downsampling "
-            "uses Nearest Neighbors. The downsampling algorithm may need to "
-            "alter the resolution you specify here to ensure it results in a "
-            "whole number of vertices. If it needs to alter the value you "
-            "specify, you are guaranteed that it will shrink it (i.e. "
-            "decrease the DTM resolution"
-        ),
-        min=1.0, max=100.0, default=10.0
-    )
-    bpy.types.Object.scaled_dtm_resolution: FloatProperty(
-        options={'HIDDEN'},
-        name="Scaled Terrain Model Resolution",
-        get=(lambda self: self.dtm_resolution / 100.0)
-    )
-
-    @classmethod
-    def poll(cls, context):
-        obj = context.active_object
-        return obj and obj.get("IS_TERRAIN", False)
-
-    def draw(self, context):
-        obj = context.active_object
-        layout = self.layout
-
-        # User Controls
-        layout.prop(obj, 'dtm_resolution')
-        layout.operator("terrain.reload")
-
-        # Metadata
-        self.draw_metadata_panel(context)
-
-    def draw_metadata_panel(self, context):
-        """Display some metadata about the DTM"""
-        obj = context.active_object
-        layout = self.layout
-
-        metadata_panel = layout.box()
-
-        dtm_resolution = metadata_panel.row()
-        dtm_resolution.label(text='Current Resolution: ')
-        dtm_resolution.label(text='{:9,.2%}'.format(
-            obj['DTM_RESOLUTION']
-        ))
-
-        mesh_scale = metadata_panel.row()
-        mesh_scale.label(text='Current Scale: ')
-        mesh_scale.label(text='{:9,.2f} m/post'.format(
-            obj['MESH_SCALE']
-        ))
-
-        dtm_scale = metadata_panel.row()
-        dtm_scale.label(text='Original Scale: ')
-        dtm_scale.label(text='{:9,.2f} m/post'.format(
-            obj['MAP_SCALE']
-        ))
-
-        return {'FINISHED'}
-
-
-class ReloadTerrain(Operator):
-    """Button for reloading the terrain mesh at a new resolution"""
-    bl_idname = "terrain.reload"
-    bl_label = "Reload Terrain"
-
-    @classmethod
-    def poll(cls, context):
-        obj = context.active_object
-        return obj and obj.get("IS_TERRAIN", False)
-
-    def execute(self, context):
-        # Reload the terrain
-        obj = context.active_object
-        path = obj['PATH']
-
-        scaled_dtm_resolution = obj.scaled_dtm_resolution
-
-        # Reload BTerrain with new DTM
-        dtm = DTM(path, scaled_dtm_resolution)
-        BTerrain.reload(obj, dtm)
-
-        return {"FINISHED"}
diff --git a/io_directx_bel/README b/io_directx_bel/README
deleted file mode 100644 (file)
index 2867827..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-a DirectX importer addon for Blender 2.6\r
-\r
-first goals :\r
-\r
-. to import anything from an .x file.\r
-  obviously verts, faces but uv, armatures, weights, normals...\r
-. import .x in binary format too\r
-\r
-horizon :\r
-. export to .x or mod/co-maintain the existing x exporter.\r
-. this project is also a prototype for a 'Blender Exchange Layer' project.\r
-  BEL would be a common layer logically located between an importer/exporter\r
-  addon and the blender data format, that would allow :\r
-    . to provide a common set of methods to retrieve/inject objects in Blender\r
-    . to provide a common set of transformation and selection tools between an\r
-      import/export script and Blender datas (rotate, rescale, filters...)\r
-    . to provide a common set of parsing helpers for new io addons\r
-\r
-PLY won't be used unfortunately (it's way too slow as far as I tested)\r
-\r
-\r
-TO TEST THE SCRIPT :\r
-  . copy the 'io_directx_bel' in /scripts/addons or addons_contrib\r
-  . start blender\r
-  . enable then addon in  user prefs > addons\r
-  . run the script with file > import > directX\r
\r
-25/01/12 0.18\r
-  . code rewrite according to api bmesh changes (me.polygon and uv layers essentially)\r
-  . implemented foreachset() call for uv import (faster)\r
-  \r
-25/01/12 0.17\r
-  . faster, 60% faster in some case : various loops improvements, infile templates parsing disabled by default\r
-    saw another bottleneck about data chunks as string but will wait for binary support for better point of view.\r
-  . interface cosmetics\r
-    \r
-23/01/12 rc 0.16\r
-. committed to svn (and littleneo git as usual)\r
-. corrected a bug about referenced token parenting\r
-. corrected a bug about non parented meshes\r
-. armatures/empties importation enabled by default\r
-. last run importer options are saved in a 'last_run' preset,\r
-  so it can be replayed or saved under another name once a\r
-  particular .x profile has been defined\r
-. tagged script for 2.6.1\r
-\r
-12/01/12 rc 0.15 :)\r
-. name conversion changed from 5 to 4 digits\r
-. matname, imagename and texturename fixes :\r
-. a path test is made at image import time with any existing data images, \r
-  so a same file cant be loaded twice wathever the naming method, / or \, rel or abs etc \r
-  (bel.material.new() and after line 835)\r
-. image and texture names should be ok now (tested with : incrediblylongname.x)\r
-. materials are replaced accordingly in existing objs when using the 'replace' naming method\r
-. fyi, the Dx exporter has the following inconveniences :\r
-    . split linked faces into individual faces\r
-    . inversed uvmapping (y axis) ?\r
-    -> see testfiles/blender_x_export/incrediblylongname.x\r
-   \r
-29 and 31/12/11\r
-. Cosmetics, code cleaning and optimizations\r
-. bpy.ops.object.select_name methods replaced with\r
-    ob.select = True\r
-    bpy.context.scene.objects.active = ob\r
-. corrected a big bug about tokens info appending in dXtree()\r
-. new bpyname() method in bel module. removed bel.common\r
-\r
-26/12/11\r
-. armature import and bone max. length option\r
-\r
-23/11/11\r
-. contrib candidate :)\r
-. solved some naming cases, added bel methods.\r
-. added experimental option about parenting (no armature yet just empties, when needed)\r
-. a bit faster\r
-. added some test files (empty parenting, armature etc)\r
-\r
-22/11/11\r
-campbell feedback (cont):\r
-. added naming methods as options (default is blender name inc. if name exists)\r
-  me and ob remove() should be ok with special cases (empties, mesh with multi-users)\r
-. improved ui\r
-\r
-\r
-21/11/11\r
-campbell feedback :\r
-. converted immutables to tuples : templates_x.py and some other vars.\r
-  http://stackoverflow.com/questions/3340539/why-tuple-is-faster-than-list\r
-. dprint() (console debug) removed, replaced by a inloop tests (a bit faster)\r
-  I'd like to keep it for now for easier debug (eg user feedbacks with 'processing' option)\r
-  \r
-19/11/11\r
-. object parenting support. parsing the x tree from roots using import_dxtree()\r
-  actually faster than before\r
-  \r
-16/11/11\r
-. weight group import\r
-. improved ui a bit and console logs\r
-. x matrices to blender ones conversion\r
-\r
-14/11/11\r
-. global matrix options\r
-. added messy code about binary (not working)\r
-\r
-11/11/11\r
-. import materials and textures (basics) : uv and image mapped (multitex mode)\r
-  and material created with tex slot if any. alpha should be ok.. ?\r
-. added a smooth options\r
-. better tolerance with faulty .x (upper/lower case of template names)\r
-. token names length from x to blender conversion should be ok also (long name cases)\r
-. corrected a parser pointer error after one array parsing case.\r
-. added more templates (for mat and tex support)\r
-. removed texture files from repo in testfile (tex does not match meshes )\r
-  added some other x files for further tests in binary and compressed format\r
-  ( http://assimp.svn.sourceforge.net/viewvc/assimp/trunk/test/models/X/ )\r
-  \r
-08/11/11\r
-. turned into an addon (fork from obj import so unused functions atm)\r
-  enable it in addon, then file > import > directx\r
-. splitted directx parser (io_directx_bel folder) and bel draft \r
-  the bel folder is intended to be located in /scripts/modules (shared components)\r
-  but it's ok in scripts/addons too (tbd)\r
-  bel folder (will) includes anything related to blender data helper (read/write)\r
-. corrected duplicated quotes for x string type\r
-\r
-07/11/11\r
-. uv import\r
-. generic directx token parser. templates items are used to read datas of any token type\r
-  a bit slower but cool since it should support non strict standard directx files\r
-  virtually it can retrieve everything from now supposing the template is know\r
-  by default or given in the file. calls are now like :\r
-               nbslots, mats = readToken('MeshMaterialList001') or\r
-               uv = readToken('uv001') or\r
-               nVerts, verts, nFaces, faces = readToken('Hydralisk_backbone1') etc\r
-. removed the specific mesh parser the 'rigid' file is the last before mutation to\r
-  generic parser. a bit faster but harder to make evolve or adapt. keep it as a faster\r
-  strict 'branch'\r
-. added some default templates\r
-  goals / wip :\r
-  . to compare template declaration in file and default one.\r
-    so either use the default one (strict) or the .x one (could differ)\r
-  . use by the generic data parser to avoid a parser for each kind of token\r
-. cleaner code (grouping methods, function names, docs etc) \r
-  functions separated from calls\r
-  renamed token dict as tokens etc\r
-. added tweaks at the beginning of the file :\r
-       chunksize = 1024     # size of file streams red in a row\r
-       quickmode = False    # this to only find meshes (no parenting, no other tokens than Mesh ones)\r
-       showtree = False     # display the entire token tree in the console\r
-       showtemplate = True  # display template datas found in file\r
-. added a patch for malformed datas of vertices (meshFaces) :\r
-       # patch for malformed datas not completely clear yet ( I guess\r
-       # there's bunch of us when looking at meshface syntax in .x files) :\r
-       # when array members are like 3;v0,v1,v2;,\r
-       # and not like 3;v0;v1;v2;, depending on template declarations.\r
-       # http://paulbourke.net/dataformats/directx/#xfilefrm_Use_of_commas\r
-. the script now generates linked faces (was not my fault !)\r
-  > it seems Dx always separate each face :\r
-  so it defines (vert * linked faces) verts for one needed vert\r
-  the readvertices loop now remove duplicates at source\r
-  it uses a verts lookup list to redirect vert id defined in faces\r
-\r
-06/11/11\r
-. vertices and faces imported from each test files\r
-. added some info to test yourself in README \r
-. switched to binary for .x as text to retrieve eol (pointer bugs). should be ok whatever it's win, mac or unix text format,\r
-  also works with mixed eol.\r
-  it seems python 3.1 can't return a 'line' when data.realine() when read mode is 'rb' (U default and universal ? really ? ;) ) \r
-  when file has mac eol (\r)\r
-  -> read(1024) in binary, decode, and replace any \r with \n. yes, it doubles lines for windows and lines value is wrong for now\r
-  -> but the used pointer value is always ok now whatever the file format and still way faster than a data.tell()\r
-  see CRCF folder to compare output wispwind.x by format.\r
-. files are still splitted into chunks (1024 B) and readable as lines\r
-. references : added 'user' fields when token is used. users store a reference with their childs but with a '*' tag at chr0.\r
-  the tree reflects the changes\r
-. now read anything and add it to the 'tree'. this includes unknow tokens.\r
-. references are recognized. by reference I mean fields like { cube0 } rather than an inline frame cube0 {\r
-  declaration.\r
-  I don't know if one item can be referenced several time or referenced before declaration\r
-  should be.. waiting for a case. for now only one 'parent' token, messages will show up\r
-  multi references to one token if cases arise. \r
-. more permissive syntax : 'frame spam{', 'frame     spam   egg{', 'frame spam egg  {'..\r
-. comments are recognized (inlines ones not done yet, since still no useful data red :) )\r
-. header is red\r
-. found other .x test files here :\r
-  http://www.xbdev.net/3dformats/x/xfileformat.php\r
-  created from 3ds max\r
-. added .x files in repo. line 70 and following to switch.\r
-. some token comes with no names, add a noname<00000> to them\r
-. console gives line number (more useful than char position I guess)\r
-\r
-\r
-05/11/11       day 0 :\r
-\r
-. made some disapointing test with ply (from a speed point of view, else it looks really cool)\r
-. made my own parser\r
-. nothing imported for now, it's more about self-eduction to .x and concept\r
-. but it reads the .x structure and can gather some info\r
-\r
-resource gathered :\r
-\r
-http://paulbourke.net/dataformats/directx/\r
-http://www.informikon.com/various/the-simplest-skeletal-animation-possible.html\r
-http://msdn.microsoft.com/en-us/library/windows/desktop/bb173011%28v=VS.85%29.aspx\r
-http://www.toymaker.info/Games/index.html\r
-\r
-\r
-\r
-step 1 : read main structure :\r
-\r
-    read main token names (any 'template', any 'frame', any 'mesh')\r
-    stores names in a token directory :\r
-        token['template'] for templates :\r
-            token['template'][templatename]\r
-            token['template'][templatename]['pointer']          (int) chr position in .x file (tell() like*)\r
-            token['template'][templatename]['line']             (int) line number in .x file\r
-        token['frame'] for frame and mesh type :\r
-            token['template'][frame or mesh name]\r
-            token['template'][frame or mesh name]['pointer']    (int) chr position in .x file (tell() like*)\r
-            token['template'][frame or mesh name]['line']       (int) line number in .x file\r
-            token['template'][frame or mesh name]['type']       (str) 'ob/bone' or 'mesh'\r
-            token['template'][frame or mesh name]['parent']     (str) frame parent of current item\r
-            token['template'][frame or mesh name]['childs']     (str list) list of child frame or mesh names\r
-            token['template'][frame or mesh name]['matrix']     (int) for now chr position of FrameTransformMatrix\r
-\r
-at the end of step 1 the script prints a tree of these datas\r
-\r
-step 2 : read template definitions :\r
-\r
-    for each template in dict, populate definitions in it.\r
-    it creates new fields in each token['template'][templatename]\r
-    according to values found in .x :\r
-        token['template'][templatename]['uuid']                 (str) <universally unique identifier>\r
-        token['template'][templatename]['members']['name']      (str) member name\r
-        token['template'][templatename]['members']['type']      (str) DWORD,FLOAT etc keywords or template name\r
-        token['template'][templatename]['restriction']          (str) 'open' , 'closed' , or the specidied (restricted) value\r
-\r
-that's all for now.\r
-\r
-idea would be to allow 2 steps importation and random access to file :\r
-\r
-    . first the file is quickly parsed. we only retrieve main info, nothing about verts, faces etc\r
-    info like number of mats, textures, objects/mesh/bone trees\r
-    for now : 150000 lines in 5 secs for step 1\r
-    . then user select what to import\r
-    . then the script retrieve selected datas according to selection, using the 'pointer' value\r
-      to seek() to the needed data, then grab/parse/translate in something usable.\r
-    . template are used at this point to know how to parse a specific part (adaptive parser)\r
-         \r
-    so far this looks fast.\r
-       \r
-tested on windows. can be important because of eol and the code I wrote to compute pointer value.\r
-(data.tell() is slow)\r
-only one .x file tested, header is : xof 0303txt 0032 (windows \r\n eol)\r
-\r
-don't know a lot about .x format :\r
-\r
-uuid : \r
-  are the member/restriction always the same for a same uuid/template ?\r
-  template name can vary for a same uuid ?\r
-syntax :\r
-  blank lines IN a stream of a {} section, after ; ?\r
-  comments // and # IN a stream of data ?\r
-  '{' and '<something>' and '}' on the same line or '{' '}' are always unique ?\r
-  \r
\ No newline at end of file
diff --git a/io_directx_bel/__init__.py b/io_directx_bel/__init__.py
deleted file mode 100644 (file)
index b0a9895..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-# Blender directX importer
-bl_info = {
-    "name": "DirectX Importer",
-    "description": "Import directX Model Format (.x)",
-    "author": "Littleneo (Jerome Mahieux)",
-    "version": (0, 18),
-    "blender": (2, 63, 0),
-    "location": "File > Import > DirectX (.x)",
-    "warning": "",
-    "wiki_url": "https://github.com/littleneo/directX_blender/wiki",
-    "tracker_url": "https://github.com/littleneo/directX_blender/issues",
-    "category": "Import-Export",
-    "dependencies": ""
-}
-
-if "bpy" in locals():
-    import imp
-    if "import_x" in locals():
-        imp.reload(import_x)
-    #if "export_x" in locals():
-    #    imp.reload(export_x)
-
-
-import bpy
-from bpy.props import (BoolProperty,
-                       FloatProperty,
-                       StringProperty,
-                       EnumProperty,
-                       )
-from bpy_extras.io_utils import (ExportHelper,
-                                 ImportHelper,
-                                 path_reference_mode,
-                                 axis_conversion,
-                                 )
-try : import bel
-except : import io_directx_bel.bel
-
-class ImportX(bpy.types.Operator, ImportHelper):
-    '''Load a Direct x File'''
-    bl_idname = "import_scene.x"
-    bl_label = "Import X"
-    bl_options = {'PRESET', 'UNDO'}
-
-    filename_ext = ".x"
-    filter_glob = StringProperty(
-            default="*.x",
-            options={'HIDDEN'},
-            )
-    show_tree = BoolProperty(
-            name="Show x tokens tree",
-            description="display relationships between x items in the console",
-            default=False,
-            )
-    show_templates = BoolProperty(
-            name="Show x templates",
-            description="display templates defined in the .x file",
-            default=False,
-            )
-    show_geninfo = BoolProperty(
-            name="Show processing",
-            description="display details for each imported thing",
-            default=False,
-            )
-
-    quickmode = BoolProperty(
-            name="Quick mode",
-            description="only retrieve mesh basics",
-            default=False,
-            )
-
-    parented = BoolProperty(
-            name="Object Relationships",
-            description="import armatures, empties, rebuild parent-childs relations",
-            default=True,
-            )
-
-    bone_maxlength = FloatProperty(
-            name="Bone length",
-            description="Bones max length",
-            min=0.1, max=10.0,
-            soft_min=0.1, soft_max=10.0,
-            default=1.0,
-            )
-
-    chunksize = EnumProperty(
-            name="Chunksize",
-            items=(('0', "all", ""),
-                   ('4096', "4KB", ""),
-                   ('2048', "2KB", ""),
-                   ('1024', "1KB", ""),
-                   ),
-            default='2048',
-            description="number of bytes red in a row",
-            )
-    naming_method = EnumProperty(
-            name="Naming method",
-            items=(('0', "increment name if exists", "blender default"),
-                   ('1', "use existing", "this only append new elements"),
-                   ('2', "rename existing", "names are forced"),
-                   ('3', "replace existing", ""),
-                   ),
-            default='0',
-            description="behaviour when a name already exists in Blender Data",
-            )
-    use_ngons = BoolProperty(
-            name="NGons",
-            description="Import faces with more than 4 verts as fgons",
-            default=True,
-            )
-    use_edges = BoolProperty(
-            name="Lines",
-            description="Import lines and faces with 2 verts as edge",
-            default=True,
-            )
-    use_smooth_groups = BoolProperty(
-            name="Smooth Groups",
-            description="Surround smooth groups by sharp edges",
-            default=True,
-            )
-
-    use_split_objects = BoolProperty(
-            name="Object",
-            description="Import OBJ Objects into Blender Objects",
-            default=True,
-            )
-    use_split_groups = BoolProperty(
-            name="Group",
-            description="Import OBJ Groups into Blender Objects",
-            default=True,
-            )
-
-    use_groups_as_vgroups = BoolProperty(
-            name="Poly Groups",
-            description="Import OBJ groups as vertex groups",
-            default=False,
-            )
-
-    use_image_search = BoolProperty(
-            name="Image Search",
-            description="Search subdirs for any assosiated images " \
-                        "(Warning, may be slow)",
-            default=True,
-            )
-
-    split_mode = EnumProperty(
-            name="Split",
-            items=(('ON', "Split", "Split geometry, omits unused verts"),
-                   ('OFF', "Keep Vert Order", "Keep vertex order from file"),
-                   ),
-            )
-
-    global_clamp_size = FloatProperty(
-            name="Clamp Scale",
-            description="Clamp the size to this maximum (Zero to Disable)",
-            min=0.0, max=1000.0,
-            soft_min=0.0, soft_max=1000.0,
-            default=0.0,
-            )
-
-    axis_forward = EnumProperty(
-            name="Forward",
-            items=(('X', "Left (x)", ""),
-                   ('Y', "Same (y)", ""),
-                   ('Z', "Bottom (z)", ""),
-                   ('-X', "Right (-x)", ""),
-                   ('-Y', "Back (-y)", ""),
-                   ('-Z', "Up (-z)", ""),
-                   ),
-            default='-Z',
-            )
-
-    axis_up = EnumProperty(
-            name="Up",
-            items=(('X', "Right (x)", ""),
-                   ('Y', "Back (y)", ""),
-                   ('Z', "Same (z)", ""),
-                   ('-X', "Left (-x)", ""),
-                   ('-Y', "Front (-y)", ""),
-                   ('-Z', "Bottom (-z)", ""),
-                   ),
-            default='Y',
-            )
-
-    def execute(self, context):
-        from . import import_x
-        if self.split_mode == 'OFF':
-            self.use_split_objects = False
-            self.use_split_groups = False
-        else:
-            self.use_groups_as_vgroups = False
-
-        keywords = self.as_keywords(ignore=("axis_forward",
-                                            "axis_up",
-                                            "filter_glob",
-                                            "split_mode",
-                                            ))
-
-        keywords["naming_method"] = int(self.naming_method)
-
-        global_matrix = axis_conversion(from_forward=self.axis_forward,
-                                        from_up=self.axis_up,
-                                        ).to_4x4()
-        keywords["global_matrix"] = global_matrix
-
-
-        bel.fs.saveOptions(self,'import_scene.x', self.as_keywords(ignore=(
-                                            "filter_glob",
-                                            "filepath",
-                                            )))
-        return import_x.load(self, context, **keywords)
-
-    def draw(self, context):
-        layout = self.layout
-
-        # import box
-        box = layout.box()
-        col = box.column(align=True)
-        col.label('Import Options :')
-        col.prop(self, "chunksize")
-        col.prop(self, "use_smooth_groups")
-        actif = not(self.quickmode)
-        row = col.row()
-        row.enabled = actif
-        row.prop(self, "parented")
-        if self.parented :
-            row = col.row()
-            row.enabled = actif
-            row.prop(self, "bone_maxlength")
-        col.prop(self, "quickmode")
-
-        # source orientation box
-        box = layout.box()
-        col = box.column(align=True)
-        col.label('Source Orientation :')
-        col.prop(self, "axis_forward")
-        col.prop(self, "axis_up")
-
-        # naming methods box
-        box = layout.box()
-        col = box.column(align=True)
-        col.label('Naming Method :')
-        col.props_enum(self,"naming_method")
-
-        # info/debug box
-        box = layout.box()
-        col = box.column(align=True)
-        col.label('Info / Debug :')
-        col.prop(self, "show_tree")
-        col.prop(self, "show_templates")
-        col.prop(self, "show_geninfo")
-
-        #row = layout.row(align=True)
-        #row.prop(self, "use_ngons")
-        #row.prop(self, "use_edges")
-
-        '''
-        box = layout.box()
-        row = box.row()
-        row.prop(self, "split_mode", expand=True)
-
-        row = box.row()
-        if self.split_mode == 'ON':
-            row.label(text="Split by:")
-            row.prop(self, "use_split_objects")
-            row.prop(self, "use_split_groups")
-        else:
-            row.prop(self, "use_groups_as_vgroups")
-
-        row = layout.split(factor=0.67)
-        row.prop(self, "global_clamp_size")
-
-        layout.prop(self, "use_image_search")
-        '''
-
-def menu_func_import(self, context):
-    self.layout.operator(ImportX.bl_idname, text="DirectX (.x)")
-
-#def menu_func_export(self, context):
-#    self.layout.operator(ExportX.bl_idname, text="DirectX (.x)")
-
-def register():
-    bpy.utils.register_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
-    #bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
-    #bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
-
-if __name__ == "__main__":
-    register()
diff --git a/io_directx_bel/bel/__init__.py b/io_directx_bel/bel/__init__.py
deleted file mode 100644 (file)
index f8ce1d1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-
-# set a given name to a unique
-# blender data name in its collection
-def bpyname(name,collection,limit=63,suffix=4) :
-    name = name[:limit-suffix]
-    tpl = '%s.%.'+str(suffix)+'d'
-    bname = name
-    id = 0
-    while bname in collection :
-        id += 1
-        bname = tpl%(name,id)
-    return bname
-
-## check if there's nested lists in a list. used by functions that need
-# list(s) of vertices/faces/edges etc as input
-# @param lst a list of vector or a list of list of vectors
-# @returns always nested list(s)
-# a boolean True if was nested, False if was not
-def nested(lst) :
-    try :
-        t = lst[0][0][0]
-        return lst, True
-    except :
-        return [lst], False
diff --git a/io_directx_bel/bel/fs.py b/io_directx_bel/bel/fs.py
deleted file mode 100644 (file)
index 07239a6..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# v0.1
-import bpy
-from os import path as os_path, listdir as os_listdir
-from bpy import path as bpy_path
-
-# cross platform paths (since ms conform to / path ;) )
-# maybe add utf8 replace to old ascii blender builtin
-# // can be omitted for relative
-def clean(path) :
-    path = path.strip().replace('\\','/')
-    if ('/') not in path : path = '//'+path
-    return path
-
-## test for existence of a file or a dir
-def exist(path) :
-    if isfile(path) or isdir(path) : return True
-    return False
-
-## test for existence of a file
-def isfile(path) :
-    if os_path.isfile(path) : return True
-    # could be blender relative
-    path = bpy_path.abspath(path)
-    if os_path.isfile(path) : return True
-    return False
-
-## test for existence of a dir
-def isdir(path) :
-    if os_path.isdir(path) : return True
-    # could be blender relative
-    path = bpy_path.abspath(path)
-    if os_path.isdir(path) : return True
-    return False
-
-## returns a list of every absolute filepath
-# to each file within the 'ext' extensions
-# from a folder and its subfolders
-# warning, in windows filename are returned in lowercase.
-def scanDir(path,ext='all') :
-    files = []
-    fields = os_listdir(path)
-    if ext != 'all' and type(ext) != list : ext = [ext]
-    for item in fields :
-        if os_path.isfile(path + '/' + item) and (ext == 'all' or item.split('.')[-1] in ext) :
-            #print('  file %s'%item)
-            files.append(path + '/' + item)
-        elif os_path.isdir(path + '/' + item) :
-            #print('folder %s/%s :'%(path,item))
-            files.extend(scanDir(path + '/' + item,ext))
-    return files
-
-def saveOptions(op,operator_name, tokens, filename='last_run'):
-    #print(op.as_keywords())
-    #print(dir(op))
-    target_path = os_path.join("operator", operator_name)
-    target_path = os_path.join("presets", target_path)
-    target_path = bpy.utils.user_resource('SCRIPTS',target_path,create=True)
-    if target_path:
-        filepath = os_path.join(target_path, filename) + ".py"
-        file_preset = open(filepath, 'w')
-        file_preset.write("import bpy\nop = bpy.context.active_operator\n\n")
-        properties_blacklist = bpy.types.Operator.bl_rna.properties.keys()
-        for key, value in tokens.items() :
-            if key not in properties_blacklist :
-                # convert thin wrapped sequences to simple lists to repr()
-                try:
-                    value = value[:]
-                except:
-                    pass
-
-                file_preset.write("op.%s = %r\n" % (key, value))
-
-        file_preset.close()
diff --git a/io_directx_bel/bel/group.py b/io_directx_bel/bel/group.py
deleted file mode 100644 (file)
index 2e39b84..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-import bpy
-'''
-given name < 21
-if material name exists :
-naming_method = 0   blender default (increment name)
-naming_method = 1   do nothing, abort creation and use existing
-naming_method = 2   create new, rename existing,
-naming_method = 3   create new, replace existing
-'''
-
-def new(name,naming_method):
-    if name in bpy.data.collections and naming_method :
-        grp = bpy.data.collections[name]
-        # if naming_method == 1 return existing
-        if naming_method == 2 :
-            grp = bpy.data.collections.new(name)
-            grp.name = name
-        elif naming_method == 3 :
-            bpy.data.collections.remove(grp)
-            grp = bpy.data.collections.new(name)
-    else :
-        grp = bpy.data.collections.new(name)
-    return grp
-
-##  TODO
-# @param ob 'all', 'active', 'selected', <object>, 'objectname'
-# @return a list of objects or an empty list
-def get(grp) :
-    if type(ob) == str :
-        if ob == 'all' : return bpy.context.scene.objects
-        elif ob == 'active' : return [bpy.context.active_object] if bpy.context.active_object != None else []
-        elif ob == 'selected' : return bpy.context.selected_objects
-        else :
-            try : return [bpy.data.objects[ob]]
-            except : return []
-    return [ob]
-
-
-## TODO remove an object from blender internal
-def remove(ob,with_data=True) :
-    objs = get(ob)
-    #if objs :
-    #    if type(objs) == bpy.types.Object : objs = [objs]
-    for ob in objs :
-            data = ob.data
-            #and_data=False
-            # never wipe data before unlink the ex-user object of the scene else crash (2.58 3 770 2)
-            # if there's more than one user for this data, never wipeOutData. will be done with the last user
-            # if in the list
-            and_data = with_data
-            try :
-                if data.users > 1 :
-                    and_data=False
-            except :
-                and_data=False # empties
-
-            # odd (pre 2.60) :
-            # ob=bpy.data.objects[ob.name]
-            # if the ob (board) argument comes from bpy.data.collections['aGroup'].objects,
-            #  bpy.data.collections['board'].objects['board'].users_scene
-            ob.name = '_dead'
-            for sc in ob.users_scene :
-                sc.objects.unlink(ob)
-
-            #try :
-                #print('  removing object %s...'%(ob.name)),
-            bpy.data.objects.remove(ob)
-                #print('  done.')
-            #except :
-            #    print('removing failed, but renamed %s and unlinked'%ob.name)
-
-            # never wipe data before unlink the ex-user object of the scene else crash (2.58 3 770 2)
-            if and_data :
-                wipeOutData(data)
diff --git a/io_directx_bel/bel/image.py b/io_directx_bel/bel/image.py
deleted file mode 100644 (file)
index 9db42d9..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-import bpy
-import bpy.path
-
-from . import __init__ as bel
-from . import fs
-
-debuglevel = 0
-
-def dprint(str,l=2) :
-    if l <= debuglevel :
-        print(str)
-
-# create or retrieve a bdata image
-# given its path
-def new(path, name=False, relative = True) :
-    path = fs.clean(path)
-    # check file
-    if fs.isfile(path) == False :
-        dprint('Texture image not found')
-        return False
-
-    if relative :
-        try :
-            path = bpy.path.relpath(path)
-            path = fs.clean(path)
-        except :
-            print('cant turn path into relative one (.blend and img path drive letters ?) ')
-
-    # retrieve paths to image file from existing image slot
-    # returns img if paths match
-    for img in bpy.data.images :
-        if img.filepath != '' :
-            if bpy.path.abspath(path) == bpy.path.abspath(fs.clean(img.filepath)) :
-                return img
-
-    # create a unique name in image slot
-    if name == False :
-        name = bpy.path.basename(path)
-    name = bel.bpyname(name,bpy.data.images.keys())
-
-    # finally :
-    img = bpy.data.images.load(filepath=path)
-    img.name = name
-    return img
-
-
-def applyShader(mat,config) :
-
-    # matslot.link = 'DATA'
-    #mat = bpy.data.materials['Female_Body']
-
-    texslot = mat.texture_slots[0]
-    tex = texslot.texture
-    img = tex.image
-
-    #config = shaders[shadername]
-    alpha = True if 'alpha' in config else False
-
-    ## MAT
-
-    mat.type = 'SURFACE'
-    # diffuse
-    mat.diffuse_color = Color((0.6, 0.6, 0.6))
-    mat.diffuse_intensity = 0.8
-    mat.diffuse_shader = 'LAMBERT'
-    mat.use_diffuse_ramp = False
-
-    # specular
-    mat.specular_color = Color((1.0, 1.0, 1.0))
-    mat.specular_intensity = 0.25
-    mat.specular_shader = 'COOKTORR'
-    mat.use_specular_ramp = False
-    mat.specular_hardness = 1.0
-
-    # shading
-    mat.emit = 0.0
-    mat.ambient = 0.5
-    mat.translucency = 0.0
-    mat.use_shadeless = False
-    mat.use_tangent_shading = False
-    mat.use_cubic = False
-
-    # transparency
-    mat.use_transparency = alpha
-    mat.transparency_method = 'Z_TRANSPARENCY'
-    mat.alpha = not(alpha)
-    mat.specular_alpha = not(alpha)
-    mat.raytrace_transparency.fresnel = 0.0
-    mat.raytrace_transparency.fresnel_factor = 1.25
-
-    # mirror
-    mat.raytrace_mirror.use = False
-
-    # subsurface_scattering
-    mat.subsurface_scattering.use
-
-    # strand
-    # options
-    # shadow
-    mat.use_shadows = True
-    mat.use_transparent_shadows = True
-    mat.use_cast_shadows_only = False
-    mat.shadow_cast_alpha = 1.0
-    mat.use_only_shadow = False
-    mat.shadow_only_type = 'SHADOW_ONLY_OLD'
-    mat.use_cast_buffer_shadows = True
-    mat.shadow_buffer_bias = 0.0
-    mat.use_ray_shadow_bias = True
-    mat.shadow_ray_bias = 0.0
-    mat.use_cast_approximate = True
-
-    # TEXTURE SLOT 0
-
-    # diffuse
-    texslot.diffuse_factor = 1.0
-    texslot.use_map_diffuse = True
-    texslot.diffuse_color_factor = 1.0
-    texslot.use_map_color_diffuse = True
-    texslot.alpha_factor = 1.0
-    texslot.use_map_alpha = alpha
-    texslot.translucency_factor = 0.0
-    texslot.use_map_translucency = False
-
-    # specular
-    texslot.specular_factor = 0.3
-    texslot.use_map_specular = True
-    texslot.specular_color_factor = 1.0
-    texslot.use_map_color_spec = True
-    texslot.hardness_factor = 0.1
-    texslot.use_map_hardness = True
-
-    # shading
-    texslot.ambient_factor = 0.0
-    texslot.use_map_ambient = False
-    texslot.emit_factor = 0.1
-    texslot.use_map_emit = True
-    texslot.mirror_factor = 0.0
-    texslot.use_map_mirror = False
-    texslot.raymir_factor = 0.0
-    texslot.use_map_raymir = False
-
-    # geometry
-    texslot.normal_factor = 0.0
-    texslot.use_map_normal = False
-    texslot.warp_factor = 0.1
-    texslot.use_map_warp = False
-    texslot.displacement_factor = 0.0
-    texslot.use_map_displacement = False
-
-    texslot.blend_type = 'MIX'
-    texslot.invert = False
-    texslot.use_rgb_to_intensity = False
-    texslot.color = Color((1.0, 0.0, 1.0)) # default
-    texslot.use_stencil = False
-    texslot.default_value = 1.0
-
-    # TEXTURE
-    tex.use_alpha = alpha
-    tex.use_preview_alpha = alpha
-
-def BSshader(nodes,pointer) :
-    tkm = bpy.context.scene.tkm
-    typ, nodename = pointer.split(' ')
-    RenderShader = nodes[typ][nodename]
-    name = BSname(nodename,RenderShader['Object.Name'])
-    if name in bpy.data.materials :
-        mat = bpy.data.materials[name]
-    else :
-        mat = bpy.data.materials.new(name=name)
-        # Unused
-        DepthWriteEnable = RenderShader['DepthWriteEnable'] if 'DepthWriteEnable' in RenderShader else False # an integer
-        ShaderTransparency = RenderShader['MultiDrawLayer'] if 'MultiDrawLayer' in RenderShader else False # an integer
-        LightEnable = RenderShader['LightEnable'] if 'LightEnable' in RenderShader else False # an integer
-
-        ShaderPhong = BSnode(nodes,RenderShader['Surface'])
-        #print('mat : %s'%ShaderPhong['Material'])
-        RenderMaterial = BSnode(nodes,ShaderPhong['Material'])
-        DiffuseColor = RenderMaterial['DiffuseColor'] if 'DiffuseColor' in RenderMaterial else False
-        SpecularColor = RenderMaterial['SpecularColor'] if 'SpecularColor' in RenderMaterial else False
-        AmbientColor = RenderMaterial['AmbientColor'] if 'AmbientColor' in RenderMaterial else False
-        EmissionColor = RenderMaterial['Shininess'] if 'EmissionColor' in RenderMaterial else False
-        Shininess = RenderMaterial['Shininess'] if 'Shininess' in RenderMaterial else False
-        Transparency = RenderMaterial['Transparency'] if 'Transparency' in RenderMaterial else False
-        for key in RenderMaterial.keys() :
-            if key not in ['DiffuseColor','SpecularColor','AmbientColor','EmissionColor','Shininess','Transparency'] :
-                print('NEW RENDERMATERIAL PROP ! : %s'%key)
-
-        #print(AmbientColor)
-        if DiffuseColor : mat.diffuse_color = Color(DiffuseColor) #[0][0],DiffuseColor[0][1],DiffuseColor[0][2])
-        if SpecularColor : mat.specular_color = Color(SpecularColor)#[0][0],SpecularColor[0][1],SpecularColor[0][2])
-        if AmbientColor : mat.ambient = AmbientColor[0] # source value is a vector3f with x=y=z
-        if EmissionColor : mat.emit = EmissionColor[0] # source value is a vector3f with x=y=z
-        #if Shininess : mat.
-        #alpha is a boolean, whereas Transparency is a float or False
-        if Transparency :
-            mat.use_transparency = True
-            mat.transparency_method = 'Z_TRANSPARENCY'
-            mat.alpha = Transparency
-            mat.specular_alpha = 0
-            alpha = True
-        else : alpha = False
-        texinfluence = False
-        if 'Color' in ShaderPhong :
-            ShaderTexture = BSnode(nodes,ShaderPhong['Color'])
-            texinfluence = 'Color'
-        if 'Reflection' in ShaderPhong :
-            ShaderTexture = BSnode(nodes,ShaderPhong['Reflection'])
-            texinfluence = 'Reflection'
-        if texinfluence == False :
-            print('neither color nor refl. in ShaderPhong %s'%RenderShader['Surface'])
-            print('other props are : %s'%ShaderPhong.keys())
-            return mat
-
-        ShaderTextureName = ShaderTexture['Object.Name']
-
-        Texture2D = BSnode(nodes,ShaderTexture['Texture'])
-        Texture2DName = Texture2D['Object.Name']
-
-        FileObject = BSnode(nodes,Texture2D['Texture.FileObject'])
-        imgpath = FileObject['FileName']
-        imgname = imgpath.split('/')[-1]
-        imgpath = tkm.path_archives+'/Images/Q=Tex032M/'+imgpath
-
-        if imgname not in bpy.data.images :
-            if os.path.isfile(imgpath+'.png') : ext = '.png'
-            elif os.path.isfile(imgpath+'.jp2') : ext = '.jp2'
-            else :
-                print('Texture image not found ! %s'%Texture2D['Texture.FileObject'])
-                print('path : %s.png or .jp2 '%imgpath)
-                return mat
-            img = bpy.data.images.load(filepath=imgpath+ext)
-            img.name = imgname
-        else : img = bpy.data.images[imgname]
-
-        '''
-        texslot = mat.texture_slots[0]
-        mat.texture_slots[0]
-        tex = texslot.texture
-        tex.type = 'IMAGE'
-        img = tex.image
-        img.name
-        '''
-        #img = bpy.data.images.new(name='imgname',width=640, height=512)
-
-        if ShaderTextureName not in bpy.data.textures :
-            tex = bpy.data.textures.new(name=ShaderTextureName,type='IMAGE')
-            tex.image = img
-            tex.use_alpha = alpha
-            tex.use_preview_alpha = alpha
-        else : tex = bpy.data.textures[ShaderTextureName]
-
-        texslot = mat.texture_slots.create(index=0)
-        texslot.texture = tex
-        texslot.texture_coords = 'UV'
-        texslot.uv_layer = 'UV0'
-        texslot.use_map_alpha = alpha
-        texslot.alpha_factor = 1.0
-
-    return mat
diff --git a/io_directx_bel/bel/material.py b/io_directx_bel/bel/material.py
deleted file mode 100644 (file)
index 0f6d823..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-import bpy
-
-'''
-given name < 21
-if material name exists :
-naming_method = 0   blender default (increment name)
-naming_method = 1   do nothing, abort creation and use existing
-naming_method = 2   create new, rename existing,
-naming_method = 3   create new, replace existing
-'''
-
-def new(name, naming_method=0) :
-    if name not in bpy.data.materials or naming_method == 0:
-        return bpy.data.materials.new(name=name)
-
-    elif naming_method == 1 :
-        return bpy.data.materials[name]
-
-    mat = bpy.data.materials.new(name=name)
-
-    if naming_method == 2 :
-        mat.name = name
-        return mat
-
-    # naming_method = 3 : replace
-    prevmat = bpy.data.materials[name]
-    for ob in bpy.data.objects :
-        for matslot in ob.material_slots :
-            if matslot.material == prevmat :
-                matslot.material = mat
-    bpy.data.materials.remove(prevmat)
-    return mat
diff --git a/io_directx_bel/bel/mesh.py b/io_directx_bel/bel/mesh.py
deleted file mode 100644 (file)
index 1363f04..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-##\file
-# raw extract quick cleaning from blended cities2.6 project. thanks to myself for cooperation, but what a messy code we have here.
-import bpy
-import mathutils
-from mathutils import *
-import bmesh
-
-from . import uv as buv
-from . import ob as bob
-
-debuglevel = 0
-'''
-wip.. naming behaviour previous to any data
-name exist ?
-no : create
-yes :
-    naming_method = 0   blender default (increment name)
-    naming_method = 1   do nothing, abort creation and use existing
-    naming_method = 2   create new, rename existing,
-    naming_method = 3   create new, remove existing
-
-for now, and mesh data, 0 2 or 3
-'''
-
-'''
-given name < 21
-if material name exists :
-naming_method = 0   blender default (increment name)
-naming_method = 1   do nothing, abort creation and use existing
-naming_method = 2   create new, rename existing,
-naming_method = 3   create new, replace existing
-'''
-
-def new(name, naming_method=0) :
-    if name not in bpy.data.meshes or naming_method == 0:
-        return bpy.data.meshes.new(name=name)
-
-    if naming_method == 1 :
-        return bpy.data.meshes[name]
-
-    if naming_method == 2 :
-        me = bpy.data.meshes.new(name=name)
-        me.name = name
-        return me
-
-    # naming_method = 3 : replace, keep users
-    me = bpy.data.meshes[name]
-    bm = bmesh.new()
-    bm.to_mesh(me)
-    return me
-
-## material listed in matslots must exist before creation of material slots
-
-def write(obname,name,
-          verts=[], edges=[], faces=[],
-          matslots=[], mats=[], uvs=[],
-          groupnames=[], vindices=[], vweights=[],
-          smooth=False,
-          naming_method = 0,
-          ) :
-
-
-    obj = bpy.data.objects[obname] if obname in bpy.data.objects else False
-    me = bpy.data.meshes[name] if name in bpy.data.meshes else False
-
-    #print(naming_method,type(obj),type(me))
-    #print(obj,me)
-    #print()
-    if naming_method == 1 and me and obj and obj.data == me :
-        #print('%s and %s exist, reuse'%(obj.name,me.name))
-        return obj
-
-    if naming_method == 3 :
-        if obj :
-            #print('remove ob %s'%obj.name)
-            bob.remove(obj,False)
-        if me :
-            #print('remove me %s'%me.name)
-            bob.removeData(me)
-
-
-    me = bpy.data.meshes.new(name)
-    if naming_method == 2 : me.name = name
-
-    me.from_pydata(verts, edges, faces)
-    me.update()
-
-    if smooth : shadesmooth(me)
-
-    # material slots
-    matimage=[]
-    if len(matslots) > 0 :
-        for matname in matslots :
-            '''
-            if matname not in bpy.data.materials :
-                mat = bpy.data.materials.new(name=matname)
-                mat.diffuse_color=( random.uniform(0.0,1.0),random.uniform(0.0,1.0),random.uniform(0.0,1.0))
-                mat.use_fake_user = True
-                warn.append('Created missing material : %s'%matname)
-            else :
-            '''
-            mat = bpy.data.materials[matname]
-            me.materials.append(mat)
-            texslot_nb = len(mat.texture_slots)
-            if texslot_nb :
-                texslot = mat.texture_slots[0]
-                if type(texslot) != type(None) :
-                    tex = texslot.texture
-                    if tex.type == 'IMAGE' :
-                        img = tex.image
-                        if type(img) != type(None) :
-                            matimage.append(img)
-                            continue
-            matimage.append(False)
-
-    # uvs
-    if len(uvs) > 0 :
-        #buv.write(me, uvs, matimage)
-        buv.flatwrite(me, uvs)
-
-    # map a material to each face
-    if len(mats) > 0 :
-        for fi,f in enumerate(me.polygons) :
-            f.material_index = mats[fi]
-
-    obj = bpy.data.objects.new(name=obname, object_data=me)
-    if naming_method != 0 :
-        obj.name = obname
-
-    '''
-    else :
-        ob = bpy.data.objects[name]
-        ob.data = me
-        if naming_method == 2 : ob.name =
-        ob.parent = None
-        ob.matrix_local = Matrix()
-        print('  reuse object %s'%ob.name)
-    '''
-
-    # vertexgroups
-    if len(groupnames) > 0 :
-        for gpi, groupname in enumerate(groupnames) :
-            weightsadd(obj, groupname, vindices[gpi], vweights[gpi])
-
-    # scene link check
-    if obj.name not in bpy.context.scene.objects.keys() :
-        bpy.context.collection.objects.link(obj)
-
-    return obj
-
-def shadesmooth(me,lst=True) :
-    if type(lst) == list :
-        for fi in lst :
-            me.polygons[fi].use_smooth = True
-    else :
-        for fi,face in enumerate(me.polygons) :
-            face.use_smooth = True
-
-def shadeflat(me,lst=True) :
-    if type(lst) == list :
-        for fi in lst :
-            me.polygons[fi].use_smooth = False
-    else :
-        for fi,face in enumerate(me.polygons) :
-            face.use_smooth = False
-
-def weightsadd(ob, groupname, vindices, vweights=False) :
-    if vweights == False : vweights = [1.0 for i in range(len(vindices))]
-    elif type(vweights) == float : vweights = [vweights for i in range(len(vindices))]
-    group = ob.vertex_groups.new(groupname)
-    for vi,v in enumerate(vindices) :
-        group.add([v], vweights[vi], 'REPLACE')
-
-def matToString(mat) :
-    #print('*** %s %s'%(mat,type(mat)))
-    return str(mat).replace('\n       ','')[6:]
-
-def stringToMat(string) :
-    return Matrix(eval(string))
-
-
-def objectBuild(elm, verts, edges=[], faces=[], matslots=[], mats=[], uvs=[] ) :
-    #print('build element %s (%s)'%(elm,elm.className()))
-    dprint('object build',2)
-    city = bpy.context.scene.city
-    # apply current scale
-    verts = metersToBu(verts)
-
-    if type(elm) != str :
-        obname = elm.objectName()
-        if obname == 'not built' :
-            obname = elm.name
-    else : obname= elm
-
-    obnew = createMeshObject(obname, True, verts, edges, faces, matslots, mats, uvs)
-    #elm.asElement().pointer = str(ob.as_pointer())
-    if type(elm) != str :
-        if elm.className() == 'outlines' :
-            obnew.lock_scale[2] = True
-            if elm.parent :
-                obnew.parent = elm.Parent().object()
-        else :
-            #otl = elm.asOutline()
-            #ob.parent = otl.object()
-            objectLock(obnew,True)
-        #ob.matrix_local = Matrix() # not used
-        #ob.matrix_world = Matrix() # world
-    return obnew
-
-def dprint(str,l=2) :
-    if l <= debuglevel :
-        print(str)
-
-
-def materialsCheck(bld) :
-    if hasattr(bld,'materialslots') == False :
-        #print(bld.__class__.__name__)
-        builderclass = eval('bpy.types.%s'%(bld.__class__.__name__))
-        builderclass.materialslots=[bld.className()]
-
-    matslots = bld.materialslots
-    if len(matslots) > 0 :
-        for matname in matslots :
-            if matname not in bpy.data.materials :
-                mat = bpy.data.materials.new(name=matname)
-                mat.use_fake_user = True
-                if hasattr(bld,'mat_%s'%(matname)) :
-                    method = 'defined by builder'
-                    matdef = eval('bld.mat_%s'%(matname))
-                    mat.diffuse_color = matdef['diffuse_color']
-                else :
-                    method = 'random'
-                    mat.diffuse_color=( random.uniform(0.0,1.0),random.uniform(0.0,1.0),random.uniform(0.0,1.0))
-                dprint('Created missing material %s (%s)'%(matname,method),2)
diff --git a/io_directx_bel/bel/ob.py b/io_directx_bel/bel/ob.py
deleted file mode 100644 (file)
index 2ac50b5..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-import bpy
-from bpy.types import Mesh, PointLamp, SpotLamp, HemiLamp, AreaLamp, SunLamp, Camera, TextCurve, MetaBall, Lattice, Armature
-
-
-def new(name,datatype,naming_method):
-    if name in bpy.data.objects and naming_method :
-        ob = bpy.data.objects[name]
-        if naming_method == 1 :
-            ob.parent = None
-            ob.user_clear()
-        elif naming_method == 2 :
-            ob = bpy.data.objects.new(name,datatype)
-            ob.name = name
-        elif naming_method == 3 :
-            bpy.context.collection.objects.unlink(ob)
-            ob.user_clear()
-            bpy.data.objects.remove(ob)
-            ob = bpy.data.objects.new(name,datatype)
-    else :
-        ob = bpy.data.objects.new(name,datatype)
-    if ob.name not in bpy.context.scene.objects.keys() :
-        bpy.context.collection.objects.link(ob)
-    return ob
-
-## returns an object or a list of objects
-# @param ob 'all', 'active', 'selected', <object>, 'objectname'
-# @return a list of objects or an empty list
-def get(ob) :
-    if type(ob) == str :
-        if ob == 'all' : return bpy.context.scene.objects
-        elif ob == 'active' : return [bpy.context.active_object] if bpy.context.active_object != None else []
-        elif ob == 'selected' : return bpy.context.selected_objects
-        else :
-            try : return [bpy.data.objects[ob]]
-            except : return []
-    return [ob]
-
-
-## remove an object from blender internal
-def remove(ob,with_data=True) :
-    objs = get(ob)
-    #if objs :
-    #    if type(objs) == bpy.types.Object : objs = [objs]
-    for ob in objs :
-            data = ob.data
-            #and_data=False
-            # never wipe data before unlink the ex-user object of the scene else crash (2.58 3 770 2)
-            # if there's more than one user for this data, never wipeOutData. will be done with the last user
-            # if in the list
-            and_data = with_data
-            try :
-                if data.users > 1 :
-                    and_data=False
-            except :
-                and_data=False # empties
-
-            # odd (pre 2.60) :
-            # ob=bpy.data.objects[ob.name]
-            # if the ob (board) argument comes from bpy.data.collections['aGroup'].objects,
-            #  bpy.data.collections['board'].objects['board'].users_scene
-            ob.name = '_dead'
-            for sc in ob.users_scene :
-                sc.objects.unlink(ob)
-
-            #try :
-                #print('  removing object %s...'%(ob.name)),
-            bpy.data.objects.remove(ob)
-                #print('  done.')
-            #except :
-            #    print('removing failed, but renamed %s and unlinked'%ob.name)
-
-            # never wipe data before unlink the ex-user object of the scene else crash (2.58 3 770 2)
-            if and_data :
-                wipeOutData(data)
-
-
-## remove an object data from blender internal
-## or rename it _dead if there's still users
-def removeData(data) :
-    #print('%s has %s user(s) !'%(data.name,data.users))
-
-    if data.users <= 0 :
-
-            #data.user_clear()
-            data_type = type(data)
-
-            # mesh
-            if data_type == Mesh :
-                bpy.data.meshes.remove(data)
-            # lamp
-            elif data_type in [ PointLamp, SpotLamp, HemiLamp, AreaLamp, SunLamp ] :
-                bpy.data.lamps.remove(data)
-            # camera
-            elif data_type == Camera :
-                bpy.data.cameras.remove(data)
-            # Text, Curve
-            elif data_type in [ Curve, TextCurve ] :
-                bpy.data.curves.remove(data)
-            # metaball
-            elif data_type == MetaBall :
-                bpy.data.metaballs.remove(data)
-            # lattice
-            elif data_type == Lattice :
-                bpy.data.lattices.remove(data)
-            # armature
-            elif data_type == Armature :
-                bpy.data.armatures.remove(data)
-            else :
-                print('  data still here : forgot %s type'%type(data))
-        #except :
-            # empty, field
-        #    print('%s has no user_clear attribute ? (%s).'%(data.name,type(data)))
-    else :
-        #print('  not done, %s has %s user'%(data.name,data.users))
-        data.name = '_dead'
diff --git a/io_directx_bel/bel/uv.py b/io_directx_bel/bel/uv.py
deleted file mode 100644 (file)
index 9b21bb9..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-from mathutils import Vector
-from .__init__ import *
-from time import clock
-
-# uvs :
-#
-def write(me, uvs, matimage = False) :
-    t = clock()
-    uvs, nest = nested(uvs)
-    newuvs = []
-    # uvi : uvlayer id  uvlist : uv coordinates list
-    for uvi, uvlist in enumerate(uvs) :
-
-        uv = me.uv_textures.new()
-        uv.name = 'UV%s'%uvi
-
-        uvlayer = me.uv_layers[-1].data
-
-        for uvfi, uvface in enumerate(uvlist) :
-            #uv.data[uvfi].use_twoside = True # 2.60 changes mat ways
-            mslotid = me.polygons[uvfi].material_index
-            #mat = mesh.materials[mslotid]
-            if matimage :
-                if matimage[mslotid] :
-                    img = matimage[mslotid]
-                    uv.data[uvfi].image=img
-
-            vi = 0
-            for fi in me.polygons[uvfi].loop_indices :
-                uvlayer[fi].uv = Vector((uvface[vi],uvface[vi+1]))
-                vi += 2
-
-        newuvs.append(uv)
-    print('uvs in ',clock() - t)
-    if nest : return newuvs
-    return newuvs[0]
-
-## WAY faster
-def flatwrite(me, uvs, matimage = False) :
-    #t = clock()
-    newuvs = []
-    #print('uv funcinput : %s'%(len(uvs)))
-    # uvi : uvlayer id  uvlist : uv coordinates list
-    for uvi, uvlist in enumerate(uvs) :
-        #print('uvlist input : %s'%(len(uvlist)))
-        #print(uvlist[0:5])
-        uv = me.uv_textures.new()
-        uv.name = 'UV%s'%uvi
-        uvlayer = me.uv_layers[-1].data
-        # flatuv = awaited uvlist length
-        #flatuv = list( range(len(uvlayer) * 2) )
-        #print('uvlist need : %s'%(len(flatuv)))
-        uvlayer.foreach_set('uv',uvlist)
-
-        newuvs.append(uv)
-    #print('uvs in ',clock() - t)
-    return newuvs
-
-# face are squared or rectangular,
-# any orientation
-# vert order width then height 01 and 23 = x 12 and 03 = y
-# normal default when face has been built
-def row(vertices,faces,normals=True) :
-    uvs = []
-    for face in faces :
-        v0 = vertices[face[0]]
-        v1 = vertices[face[1]]
-        v2 = vertices[face[-1]]
-        print(v0,v1)
-        lx = (v1 - v0).length
-        ly = (v2 - v0).length
-        # init uv
-        if len(uvs) == 0 :
-            x = 0
-            y = 0
-        elif normals :
-            x = uvs[-1][2]
-            y = uvs[-1][3]
-        else :
-            x = uvs[-1][0]
-            y = uvs[-1][1]
-        if normals : uvs.append([x,y,x+lx,y,x+lx,y+ly,x,y+ly])
-        else : uvs.append([x+lx,y,x,y,x,y+ly,x+lx,y+ly])
-    return uvs
-
-## convert UV given as verts location to blender format
-# eg : [ [v0x,v0y] , [vnx , vny] ... ] -> [ [ v1x,v1y,v0x,v0y,v4x,v4y] ... ]
-# found in directx
-def asVertsLocation(verts2d, faces) :
-    t = clock()
-    uv = []
-    for f in faces :
-        uvface = []
-        for vi in f :
-            uvface.extend(verts2d[vi])
-        uv.append(uvface)
-    print('uvs convert in ',clock() - t)
-    return uv
-
-## Dx to flat
-#eg : [ [v0x,v0y] ,[v1x,v1y] , [vnx , vny] ] -> [ v0x,v0y,v1x,v1y,vnx,vny ]
-def asFlatList(uvlist,faces) :
-    #t = clock()
-    uv = []
-    for f in faces :
-        for vi in f :
-            uv.extend(uvlist[vi])
-    #print('uvs convert in %s len : %s'%(str(clock() - t),len(uv)))
-    return uv
diff --git a/io_directx_bel/import_x.py b/io_directx_bel/import_x.py
deleted file mode 100644 (file)
index 250e36e..0000000
+++ /dev/null
@@ -1,970 +0,0 @@
-# Blender directX importer
-# version baby
-
-# litterature explaining the parser directions :
-
-# I don't want to load the whole file as it can be huge : go chunks
-# also I want random access to 3d datas to import pieces, not always everything
-# so step1 is a whole file fast parsing, retrieving tokens name and building en empty internal dict
-# with only pointers and no 3d datas.
-# step 2 is to call any token by their names and retrieve the 3d datas thanks to pointers stored in dicts
-# between step 1 and step 2 a script ui should be provided to select, transform etc before import.
-# > I need to know the pointer position of tokens but data.tell() is slow
-# a += pointer computed from line length is way faster. so I need eol -> rb mode
-# and readline() is ok in binary mode 'rb' with \r\n (win) \n (unix) but not \r mac..
-# 2chrs for windows, 1 for mac and lunix > win eol \r\n becomes \n\n (add a line)
-# mac eol \r becomes \n so win lines info are wrong
-# this also allows support for wrong files format (mixed \r and \r\n)
-# for now it only works for text format, but the used methods will be independant of the container type.
-
-# TEST FILES
-# http://assimp.svn.sourceforge.net/viewvc/assimp/trunk/test/models/X/
-
-
-import os
-import re
-import struct, binascii
-import time
-
-import bpy
-import mathutils as bmat
-from mathutils import Vector, Matrix
-
-try :
-       import bel
-       import bel.mesh
-       import bel.image
-       import bel.uv
-       import bel.material
-       import bel.ob
-       import bel.fs
-except :
-       import io_directx_bel.bel as bel
-       from .bel import mesh,image,uv,material,ob,fs
-
-from .templates_x import *
-
-'''
-# just a temp hack to reload bel everytime
-import imp
-imp.reload(bel)
-imp.reload(bel.fs)
-imp.reload(bel.image)
-imp.reload(bel.material)
-imp.reload(bel.mesh)
-imp.reload(bel.ob)
-imp.reload(bel.uv)
-'''
-
-###################################################
-
-def load(operator, context, filepath,
-         global_clamp_size=0.0,
-         show_tree=False,
-         show_templates=False,
-         show_geninfo=False,
-         quickmode=False,
-         parented=False,
-         bone_maxlength=1.0,
-         chunksize=False,
-         naming_method=0,
-         use_ngons=True,
-         use_edges=True,
-         use_smooth_groups=True,
-         use_split_objects=True,
-         use_split_groups=True,
-         use_groups_as_vgroups=False,
-         use_image_search=True,
-         global_matrix=None,
-         ):
-
-
-    if quickmode :
-        parented = False
-
-    bone_minlength = bone_maxlength / 100.0
-
-    #global templates, tokens
-    rootTokens = []
-    namelookup = {}
-    imgnamelookup = {}
-    chunksize = int(chunksize)
-    reserved_type = (
-        'dword',
-        'float',
-        'string'
-    )
-
-    '''
-        'array',
-        'Matrix4x4',
-        'Vector',
-    '''
-    '''
-    with * : defined in dXdata
-
-    WORD     16 bits
-    * DWORD     32 bits
-    * FLOAT     IEEE float
-    DOUBLE     64 bits
-    CHAR     8 bits
-    UCHAR     8 bits
-    BYTE     8 bits
-    * STRING     NULL-terminated string
-    CSTRING     Formatted C-string (currently unsupported)
-    UNICODE     UNICODE string (currently unsupported)
-
-BINARY FORMAT
-# TOKENS in little-endian WORDs
-#define TOKEN_NAME         1
-#define TOKEN_STRING       2
-#define TOKEN_INTEGER      3
-#define TOKEN_GUID         5
-#define TOKEN_INTEGER_LIST 6
-#define TOKEN_FLOAT_LIST   7
-#define TOKEN_OBRACE      10
-#define TOKEN_CBRACE      11
-#define TOKEN_OPAREN      12
-#define TOKEN_CPAREN      13
-#define TOKEN_OBRACKET    14
-#define TOKEN_CBRACKET    15
-#define TOKEN_OANGLE      16
-#define TOKEN_CANGLE      17
-#define TOKEN_DOT         18
-#define TOKEN_COMMA       19
-#define TOKEN_SEMICOLON   20
-#define TOKEN_TEMPLATE    31
-#define TOKEN_WORD        40
-#define TOKEN_DWORD       41
-#define TOKEN_FLOAT       42
-#define TOKEN_DOUBLE      43
-#define TOKEN_CHAR        44
-#define TOKEN_UCHAR       45
-#define TOKEN_SWORD       46
-#define TOKEN_SDWORD      47
-#define TOKEN_VOID        48
-#define TOKEN_LPSTR       49
-#define TOKEN_UNICODE     50
-#define TOKEN_CSTRING     51
-#define TOKEN_ARRAY       52
-
-    '''
-
-    # COMMON REGEX
-    space = '[\ \t]{1,}' # at least one space / tab
-    space0 = '[\ \t]{0,}' # zero or more space / tab
-
-    # DIRECTX REGEX TOKENS
-    r_template = r'template' + space + '[\w]*' + space0 + '\{'
-    if quickmode :
-        r_sectionname = r'Mesh' + space + '[\W-]*'
-    else :
-        r_sectionname = r'[\w]*' + space + '[\w-]*' + space0 + '\{'
-    r_refsectionname = r'\{' + space0 + '[\w-]*' + space0 + '\}'
-    r_endsection = r'\{|\}'
-
-    # dX comments
-    r_ignore = r'#|//'
-
-    #r_frame = r'Frame' + space + '[\w]*'
-    #r_matrix = r'FrameTransformMatrix' + space + '\{[\s\d.,-]*'
-    #r_mesh = r'Mesh' + space + '[\W]*'
-
-    ###################
-    ## STEP 1 FUNCTIONS
-    ###################
-
-    ## HEADER
-    # returns header values or False if directx reco tag is missing
-    # assuming there's never comment header and that xof if the 1st
-    # string of the file
-    '''
-     they look like xof 0303txt 0032
-     4       Magic Number (required) "xof "
-     2       Minor Version 03
-     2       Major Version 02
-     4       Format Type (required)
-        "txt " Text File
-        "bin " Binary File
-        "tzip" MSZip Compressed Text File
-        "bzip" MSZip Compressed Binary File
-     4       Float Accuracy "0032" 32 bit or "0064" 64 bit
-    '''
-    def dXheader(data) :
-        l = data.read(4)
-        if l != b'xof ' :
-            print ('no header found !')
-            data.seek(0)
-            return False
-        minor = data.read(2).decode()
-        major = data.read(2).decode()
-        format = data.read(4).decode().strip()
-        accuracy = int(data.read(4).decode())
-        data.seek(0)
-        return ( minor, major, format, accuracy )
-
-
-    ##
-    def dXtree(data,quickmode = False) :
-        tokens = {}
-        templates = {}
-        tokentypes = {}
-        c = 0
-        lvl = 0
-        tree = ['']
-        ptr = 0
-        eol = 0
-        trunkated = False
-        previouslvl = False
-        while True :
-        #for l in data.readlines() :
-            lines, trunkated = nextFileChunk(data,trunkated)
-            if lines == None : break
-            for l in lines :
-
-                # compute pointer position
-                ptr += eol
-                c += 1
-                eol = len(l) + 1
-                #print(c,data.tell(),ptr+eol)
-                #if l != '' : print('***',l)
-                #if l == ''  : break
-                l = l.strip()
-
-                # remove blank and comment lines
-                if l == '' or re.match(r_ignore,l) :
-                    continue
-
-                # one line token cases level switch
-                if previouslvl :
-                    lvl -= 1
-                    previouslvl = False
-
-                #print('%s lines in %.2f\''%(c,time.clock()-t),end='\r')
-                #print(c,len(l)+1,ptr,data.tell())
-                if '{' in l :
-                    lvl += 1
-                    if '}' in l : previouslvl = True #; print('got one line token : \n%s'%l)
-                elif '}' in l :
-                    lvl -= 1
-                #print(c,lvl,tree)
-
-                if quickmode == False :
-                    ## look for templates
-                    if re.match(r_template,l) :
-                        tname = l.split(' ')[1]
-                        templates[tname] = {'pointer' : ptr, 'line' : c}
-                        continue
-
-                    ## look for {references}
-                    if re.match(r_refsectionname,l) :
-                        refname = namelookup[ l[1:-1].strip() ]
-                        #print('FOUND reference to %s in %s at line %s (level %s)'%(refname,tree[lvl-1],c,lvl))
-                        #tree = tree[0:lvl]
-                        parent = tree[lvl-1]
-                        # tag it as a reference, since it's not exactly a child.
-                        # put it in childs since order can matter in sub tokens declaration
-                        tokens[parent]['childs'].append('*'+refname)
-                        if refname not in tokens :
-                            print('reference to %s done before its declaration (line %s)\ncreated dummy'%(refname,c))
-                            tokens[refname] = {}
-                        if 'user' not in tokens[refname] : tokens[refname]['users'] = [parent]
-                        else : tokens[refname]['users'].append(parent)
-                        continue
-
-                ## look for any token or only Mesh token in quickmode
-                if re.match(r_sectionname,l) :
-                    tokenname = getName(l,tokens)
-                    #print('FOUND %s %s %s %s'%(tokenname,c,lvl,tree))
-                    #print('pointer %s %s'%(data.tell(),ptr))
-                    if lvl == 1 : rootTokens.append(tokenname)
-                    typ = l.split(' ')[0].strip().lower()
-                    tree = tree[0:lvl]
-                    if typ not in tokentypes : tokentypes[typ] = [tokenname]
-                    else : tokentypes[typ].append(tokenname)
-                    parent = tree[-1]
-                    if tokenname in tokens :
-                        tokens[tokenname]['pointer'] = ptr
-                        tokens[tokenname]['line'] = c
-                        tokens[tokenname]['parent'] = parent
-                        tokens[tokenname]['childs'] = []
-                        tokens[tokenname]['type'] = typ
-
-                    else : tokens[tokenname] = {'pointer': ptr,
-                                                'line'   : c,
-                                                'parent' : parent,
-                                                'childs' : [],
-                                                'users'  : [],
-                                                'type'   : typ
-                                                }
-                    tree.append(tokenname)
-                    if lvl > 1 and quickmode == False :
-                        tokens[parent]['childs'].append(tokenname)
-
-        return tokens, templates, tokentypes
-
-    ## returns file binary chunks
-    def nextFileChunk(data,trunkated=False,chunksize=1024) :
-        if chunksize == 0 : chunk = data.read()
-        else : chunk = data.read(chunksize)
-        if format == 'txt' :
-            lines = chunk.decode('utf-8', errors='ignore')
-            #if stream : return lines.replace('\r','').replace('\n','')
-            lines = lines.replace('\r','\n').split('\n')
-            if trunkated : lines[0] = trunkated + lines[0]
-            if len(lines) == 1 :
-                if lines[0] == '' : return None, None
-                return lines, False
-            return lines, lines.pop()
-        # wip, todo for binaries
-        else :
-            print(chunk)
-            for word in range(0,len(chunk)) :
-                w = chunk[word:word+4]
-                print(word,w,struct.unpack("<l", w),binascii.unhexlify(w))
-
-
-    # name unnamed tokens, watchout for x duplicate
-    # for blender, referenced token in x should be named and unique..
-    def getName(l,tokens) :
-        xnam = l.split(' ')[1].strip()
-
-        #if xnam[0] == '{' : xnam = ''
-        if xnam and xnam[-1] == '{' : xnam = xnam[:-1]
-
-        name = xnam
-        if len(name) == 0 : name = l.split(' ')[0].strip()
-
-        namelookup[xnam] = bel.bpyname(name,tokens,4)
-
-        return namelookup[xnam]
-
-
-    ###################
-    ## STEP 2 FUNCTIONS
-    ###################
-    # once the internal dict is populated the functions below can be used
-
-    ## from a list of tokens, displays every child, users and references
-    '''
-      walk_dxtree( [ 'Mesh01', 'Mesh02' ] ) # for particular pieces
-      walk_dxtree(tokens.keys()) for the whole tree
-    '''
-    def walk_dXtree(field,lvl=0,tab='') :
-        for fi, tokenname in enumerate(field) :
-            if lvl > 0 or tokens[tokenname]['parent'] == '' :
-                if tokenname not in tokens :
-                    tokenname = tokenname[1:]
-                    ref = 'ref: '
-                else : ref = False
-
-                frame_type = tokens[tokenname]['type']
-                line = ('{:7}'.format(tokens[tokenname]['line']))
-                log = ' %s%s (%s)'%( ref if ref else '', tokenname, frame_type )
-                print('%s.%s%s'%(line, tab, log))
-                if fi == len(field) - 1 : tab = tab[:-3] + '   '
-
-                if ref == False :
-                    for user in tokens[tokenname]['users'] :
-                         print('%s.%s |__ user: %s'%(line, tab.replace('_',' '), user))
-                    walk_dXtree(tokens[tokenname]['childs'],lvl+1,tab.replace('_',' ')+' |__')
-
-                if fi == len(field) - 1 and len(tokens[tokenname]['childs']) == 0 :
-                    print('%s.%s'%(line,tab))
-
-    ## remove eol, comments, spaces from a raw block of datas
-    def cleanBlock(block) :
-        while '//' in block :
-            s = block.index('//')
-            e = block.index('\n',s+1)
-            block = block[0:s] + block[e:]
-        while '#' in block :
-            s = block.index('#')
-            e = block.index('\n',s+1)
-            block = block[0:s] + block[e:]
-        block = block.replace('\n','').replace(' ','').replace('\t ','')
-        return block
-
-    def readToken(tokenname) :
-        token = tokens[tokenname]
-        datatype = token['type'].lower()
-        if datatype in templates : tpl = templates[datatype]
-        elif datatype in defaultTemplates : tpl = defaultTemplates[datatype]
-        else :
-            print("can't find any template to read %s (type : %s)"%(tokenname,datatype))
-            return False
-        #print('> use template %s'%datatype)
-        block = readBlock(data,token)
-        ptr = 0
-        #return dXtemplateData(tpl,block)
-        fields, ptr = dXtemplateData(tpl,block)
-        if datatype in templatesConvert :
-            fields = eval( templatesConvert[datatype] )
-        return fields
-
-    def dXtemplateData(tpl,block,ptr=0) :
-        #print('dxTPL',block[ptr])
-        pack = []
-        for member in tpl['members'] :
-            #print(member)
-            dataname = member[-1]
-            datatype = member[0].lower()
-            if datatype ==  'array' :
-                datatype = member[1].lower()
-                s = dataname.index('[') + 1
-                e = dataname.index(']')
-                #print(dataname[s:e])
-                length = eval(dataname[s:e])
-                #print("array %s type %s length defined by '%s' : %s"%(dataname[:s-1],datatype,dataname[s:e],length))
-                dataname = dataname[:s-1]
-                datavalue, ptr = dXarray(block, datatype, length, ptr)
-                #print('back to %s'%(dataname))
-            else :
-                length = 1
-                datavalue, ptr = dXdata(block, datatype, length, ptr)
-
-            #if len(str(datavalue)) > 50 : dispvalue = str(datavalue[0:25]) + ' [...] ' + str(datavalue[-25:])
-            #else : dispvalue = str(datavalue)
-            #print('%s :  %s %s'%(dataname,dispvalue,type(datavalue)))
-            exec('%s = datavalue'%(dataname))
-            pack.append( datavalue )
-        return pack, ptr + 1
-
-    def dXdata(block,datatype,length,s=0,eof=';') :
-        #print('dxDTA',block[s])
-        # at last, the data we need
-        # should be a ';' but one meet ',' often, like in meshface
-        if datatype == 'dword' :
-            e = block.index(';',s+1)
-            try : field = int(block[s:e])
-            except :
-                e = block.index(',',s+1)
-                field = int(block[s:e])
-            return field, e+1
-        elif datatype == 'float' :
-            e = block.index(eof,s+1)
-            return float(block[s:e]), e+1
-        elif datatype == 'string' :
-            e = block.index(eof,s+1)
-            return str(block[s+1:e-1]) , e+1
-        else :
-            if datatype in templates : tpl = templates[datatype]
-            elif datatype in defaultTemplates : tpl = defaultTemplates[datatype]
-            else :
-                print("can't find any template for type : %s"%(datatype))
-                return False
-            #print('> use template %s'%datatype)
-            fields, ptr = dXtemplateData(tpl,block,s)
-            if datatype in templatesConvert :
-                fields = eval( templatesConvert[datatype] )
-            return fields, ptr
-
-    def dXarray(block, datatype, length, s=0) :
-        #print('dxARR',block[s])
-        lst = []
-        if datatype in reserved_type :
-            eoi=','
-            for i in range(length) :
-                if i+1 == length : eoi = ';'
-                datavalue, s = dXdata(block,datatype,1,s,eoi)
-                lst.append( datavalue )
-
-        else :
-            eoi = ';,'
-            for i in range(length) :
-                if i+1 == length : eoi = ';;'
-                #print(eoi)
-                e = block.index(eoi,s)
-                #except : print(block,s) ; popo()
-                datavalue, na = dXdata(block[s:e+1],datatype,1)
-                lst.append( datavalue )
-                s = e + 2
-        return lst, s
-
-    ###################################################
-
-    ## populate a template with its datas
-    # this make them available in the internal dict. should be used in step 2 for unknown data type at least
-    def readTemplate(data,tpl_name,display=False) :
-        ptr = templates[tpl_name]['pointer']
-        line = templates[tpl_name]['line']
-        #print('> %s at line %s (chr %s)'%(tpl_name,line,ptr))
-        data.seek(ptr)
-        block = ''
-        trunkated = False
-        go = True
-        while go :
-            lines, trunkated = nextFileChunk(data,trunkated,chunksize) # stream ?
-            if lines == None :
-                break
-            for l in lines :
-                #l = data.readline().decode().strip()
-                block += l.strip()
-                if '}' in l :
-                    go = False
-                    break
-
-        uuid = re.search(r'<.+>',block).group()
-        templates[tpl_name]['uuid'] = uuid.lower()
-        templates[tpl_name]['members'] = []
-        templates[tpl_name]['restriction'] = 'closed'
-
-        members = re.search(r'>.+',block).group()[1:-1].split(';')
-        for member in members :
-            if member == '' : continue
-            if member[0] == '[' :
-                templates[tpl_name]['restriction'] = member
-                continue
-            templates[tpl_name]['members'].append( member.split(' ') )
-
-        if display :
-            print('\ntemplate %s :'%tpl_name)
-            for k,v in templates[tpl_name].items() :
-                if k != 'members' :
-                    print('  %s : %s'%(k,v))
-                else :
-                    for member in v :
-                        print('  %s'%str(member)[1:-1].replace(',',' ').replace("'",''))
-
-            if tpl_name in defaultTemplates :
-                defaultTemplates[tpl_name]['line'] = templates[tpl_name]['line']
-                defaultTemplates[tpl_name]['pointer'] = templates[tpl_name]['pointer']
-                if defaultTemplates[tpl_name] != templates[tpl_name] :
-                    print('! DIFFERS FROM BUILTIN TEMPLATE :')
-                    print('raw template %s :'%tpl_name)
-                    print(templates[tpl_name])
-                    print('raw default template %s :'%tpl_name)
-                    print(defaultTemplates[tpl_name])
-                    #for k,v in defaultTemplates[tpl_name].items() :
-                    #    if k != 'members' :
-                    #        print('  %s : %s'%(k,v))
-                    #    else :
-                    #        for member in v :
-                    #            print('  %s'%str(member)[1:-1].replace(',',' ').replace("'",''))
-                else :
-                    print('MATCHES BUILTIN TEMPLATE')
-
-
-    ##  read any kind of token data block
-    # by default the block is cleaned from inline comment space etc to allow data parsing
-    # useclean = False (retrieve all bytes) if you need to compute a file byte pointer
-    # to mimic the file.tell() function and use it with file.seek()
-    def readBlock(data,token, clean=True) :
-        ptr = token['pointer']
-        data.seek(ptr)
-        block = ''
-        #lvl = 0
-        trunkated = False
-        go = True
-        while go :
-            lines, trunkated = nextFileChunk(data,trunkated,chunksize)
-            if lines == None : break
-            for l in lines :
-                #eol = len(l) + 1
-                l = l.strip()
-                #c += 1
-                block += l+'\n'
-                if re.match(r_endsection,l) :
-                    go = False
-                    break
-        s = block.index('{') + 1
-        e = block.index('}')
-        block = block[s:e]
-        if clean : block = cleanBlock(block)
-        return block
-
-    def getChilds(tokenname) :
-        childs = []
-        # '*' in childname means it's a reference. always perform this test
-        # when using the childs field
-        for childname in tokens[tokenname]['childs'] :
-            if childname[0] == '*' : childname = childname[1:]
-            childs.append( childname )
-        return childs
-
-    # the input nested list of [bonename, matrix, [child0,child1..]] is given by import_dXtree()
-    def buildArm(armdata, child,lvl=0,parent_matrix=False) :
-
-        bonename, bonemat, bonechilds = child
-
-        if lvl == 0 :
-            armname = armdata
-            armdata = bpy.data.armatures.new(name=armname)
-            arm = bpy.data.objects.new(armname,armdata)
-            bpy.context.collection.objects.link(arm)
-            arm.select_set(True)
-            bpy.context.view_layer.objects.active = arm
-            bpy.ops.object.mode_set(mode='EDIT')
-            parent_matrix = Matrix()
-
-        bone = armdata.edit_bones.new(name=bonename)
-        bonematW = parent_matrix * bonemat
-        bone.head = bonematW.to_translation()
-        #bone.roll.. ?
-        bone_length = bone_maxlength
-        for bonechild in bonechilds :
-            bonechild = buildArm(armdata,bonechild,lvl+1,bonematW)
-            bonechild.parent = bone
-            bone_length = min((bonechild.head - bone.head).length, bone_length)
-        bone.tail = bonematW * Vector((0,bone_length,0))
-        if lvl == 0 :
-            bpy.ops.object.mode_set(mode='OBJECT')
-            return arm
-        return bone
-
-    def import_dXtree(field,lvl=0) :
-        tab = ' '*lvl*2
-        if field == [] :
-            if show_geninfo : print('%s>> no childs, return False'%(tab))
-            return False
-        ob = False
-        mat = False
-        is_root = False
-        frames = []
-        obs = []
-
-        parentname = tokens[field[0]]['parent']
-        if show_geninfo : print('%s>>childs in frame %s :'%(tab,parentname))
-
-        for tokenname in field :
-
-            tokentype = tokens[tokenname]['type']
-
-            # frames can contain more than one mesh
-            if tokentype  == 'mesh' :
-                # object and mesh naming :
-                # if parent frame has several meshes : obname = meshname = mesh token name,
-                # if parent frame has only one mesh  : obname = parent frame name, meshname =  mesh token name.
-                if parentname :
-                    meshcount = 0
-                    for child in getChilds(parentname) :
-                        if tokens[child]['type'] == 'mesh' :
-                            meshcount += 1
-                            if meshcount == 2 :
-                                parentname = tokenname
-                                break
-                else : parentname = tokenname
-
-                ob = getMesh(parentname,tokenname)
-                obs.append(ob)
-
-                if show_geninfo : print('%smesh : %s'%(tab,tokenname))
-
-            # frames contain one matrix (empty or bone)
-            elif tokentype  == 'frametransformmatrix' :
-                [mat] = readToken(tokenname)
-                if show_geninfo : print('%smatrix : %s'%(tab,tokenname))
-
-            # frames can contain 0 or more frames
-            elif tokentype  == 'frame' :
-                frames.append(tokenname)
-                if show_geninfo : print('%sframe : %s'%(tab,tokenname))
-
-        # matrix is used for mesh transform if some mesh(es) exist(s)
-        if ob :
-            is_root = True
-            if mat == False :
-                mat = Matrix()
-                if show_geninfo : print('%smesh token without matrix, set it to default\n%splease report in bug tracker if you read this !'%(tab,tab))
-            if parentname == '' :
-                mat = mat * global_matrix
-            if len(obs) == 1 :
-                ob.matrix_world = mat
-            else :
-                ob = bel.ob.new(parentname, None, naming_method)
-                ob.matrix_world = mat
-                for child in obs :
-                    child.parent = ob
-
-        # matrix only, store it as a list as we don't know if
-        # it's a bone or an empty yet
-        elif mat :
-            ob = [parentname, mat,[]]
-
-        # nothing case ?
-        else :
-            ob = [parentname, Matrix() * global_matrix,[]]
-            if show_geninfo : print('%snothing here'%(tab))
-
-        childs = []
-
-        for tokenname in frames :
-            if show_geninfo : print('%s<Begin %s :'%(tab,tokenname))
-
-            # child is either False, empty, object, or a list or undefined name matrices hierarchy
-            child = import_dXtree(getChilds(tokenname),lvl+1)
-            if child and type(child) != list :
-                is_root = True
-            childs.append( [tokenname, child] )
-            if show_geninfo : print('%sEnd %s>'%(tab,tokenname))
-
-        if is_root and parentname != '' :
-
-            if show_geninfo : print('%send of tree a this point'%(tab))
-            if type(ob) == list :
-                mat = ob[1]
-                ob = bel.ob.new(parentname, None, naming_method)
-            ob.matrix_world = mat
-
-        for tokenname, child in childs :
-            if show_geninfo : print('%sbegin2 %s>'%(tab,tokenname))
-            # returned a list of object(s) or matrice(s)
-            if child :
-
-                # current frame is an object or an empty, we parent this frame to it
-                #if eot or (ob and ( type(ob.data) == type(None) or type(ob.data) == bpy.types.Mesh ) ) :
-                if is_root :
-                    # this branch is an armature, convert it
-                    if type(child) == list :
-                        if show_geninfo : print('%sconvert to armature %s'%(tab,tokenname))
-                        child = buildArm(tokenname, child)
-
-                    # parent the obj/empty/arm to current
-                    # or apply the global user defined matrix to the object root
-                    if parentname != '' :
-                        child.parent = ob
-                    else :
-                        child.matrix_world = global_matrix
-
-                # returned a list of parented matrices. append it in childs list
-                elif type(child[0]) == str :
-                    ob[2].append(child)
-
-                # child is an empty or a mesh, so current frame is an empty, not an armature
-                elif ob and ( type(child.data) == type(None) or type(child.data) == bpy.types.Mesh ) :
-                    #print('  child data type: %s'%type(child.data))
-                    child.parent = ob
-                    #print('%s parented to %s'%(child.name,ob.name))
-
-            # returned False
-            else :
-                 if show_geninfo : print('%sreturned %s, nothing'%(tab,child))
-
-        #print('>> %s return %s'%(field,ob))
-        return ob# if ob else False
-
-    # build from mesh token type
-    def getMesh(obname,tokenname,debug = False):
-
-        if debug : print('\nmesh name : %s'%tokenname)
-
-        verts = []
-        edges = []
-        faces = []
-        matslots = []
-        facemats = []
-        uvs = []
-        groupnames = []
-        groupindices = []
-        groupweights = []
-
-        nVerts, verts, nFaces, faces = readToken(tokenname)
-
-        if debug :
-            print('verts    : %s %s\nfaces    : %s %s'%(nVerts, len(verts),nFaces, len(faces)))
-
-        #for childname in token['childs'] :
-        for childname in getChilds(tokenname) :
-
-            tokentype = tokens[childname]['type']
-
-            # UV
-            if tokentype == 'meshtexturecoords' :
-                uv = readToken(childname)
-                #uv = bel.uv.asVertsLocation(uv, faces)
-                uv = bel.uv.asFlatList(uv, faces)
-                uvs.append(uv)
-
-                if debug : print('uv       : %s'%(len(uv)))
-
-            # MATERIALS
-            elif tokentype == 'meshmateriallist' :
-                nbslots, facemats = readToken(childname)
-
-                if debug : print('facemats : %s'%(len(facemats)))
-
-                # mat can exist but with no datas so we prepare the mat slot
-                # with dummy ones
-                for slot in range(nbslots) :
-                    matslots.append('dXnoname%s'%slot )
-
-                # length does not match (could be tuned more, need more cases)
-                if len(facemats) != len(faces) :
-                    facemats = [ facemats[0] for i in faces ]
-
-                # seek for materials then textures if any mapped in this mesh.
-                # no type test, only one option type in token meshmateriallist : 'Material'
-                for slotid, matname in enumerate(getChilds(childname)) :
-
-                    # rename dummy mats with the right name
-                    matslots[slotid] = matname
-
-                    # blender material creation (need tuning)
-                    mat = bel.material.new(matname,naming_method)
-                    matslots[slotid] = mat.name
-
-                    if naming_method != 1 :
-                        #print('matname : %s'%matname)
-                        (diffuse_color,alpha), power, specCol, emitCol = readToken(matname)
-                        #if debug : print(diffuse_color,alpha, power, specCol, emitCol)
-                        mat.diffuse_color = diffuse_color
-                        mat.diffuse_intensity = power
-                        mat.specular_color = specCol
-                        # dX emit don't use diffuse color but is a color itself
-                        # convert it to a kind of intensity
-                        mat.emit = (emitCol[0] + emitCol[1] + emitCol[2] ) / 3
-
-                        if alpha != 1.0 :
-                            mat.use_transparency = True
-                            mat.transparency_method = 'Z_TRANSPARENCY'
-                            mat.alpha = alpha
-                            mat.specular_alpha = 0
-                            transp = True
-                        else : transp = False
-
-                        # texture
-                        # only 'TextureFilename' can be here, no type test
-                        # textures have no name in .x so we build
-                        # image and texture names from the image file name
-                        # bdata texture slot name = bdata image name
-                        btexnames = []
-                        for texname in getChilds(matname) :
-
-                            # create/rename/reuse etc corresponding data image
-                            # (returns False if not found)
-                            [filename] = readToken(texname)
-                            img = bel.image.new(path+'/'+filename)
-
-                            if img == False :
-                                imgname = 'not_found'
-                            else :
-                                imgname = img.name
-
-                            #print('texname : %s'%texname)
-                            #print('filename : %s'%filename)
-                            #print('btex/img name : %s'%imgname)
-
-                            # associated texture (no naming check.. maybe tune more)
-                            # tex and texslot are created even if img not found
-                            if imgname in bpy.data.textures and ( img == False or bpy.data.textures[imgname].image == img ) :
-                                tex = bpy.data.textures[imgname]
-                            else :
-                                tex = bpy.data.textures.new(name=imgname,type='IMAGE')
-                                if img : tex.image = img
-
-                            tex.use_alpha = transp
-                            tex.use_preview_alpha = transp
-
-                            # then create texture slot
-                            texslot = mat.texture_slots.create(index=0)
-                            texslot.texture = tex
-                            texslot.texture_coords = 'UV'
-                            texslot.uv_layer = 'UV0'
-                            texslot.use_map_alpha = transp
-                            texslot.alpha_factor = alpha
-
-                # create remaining dummy mat
-                for slotid, matname in enumerate(matslots) :
-                    if matname not in bpy.data.materials :
-                        mat = bel.material.new(matname,naming_method)
-                        matslots[slotid] = mat.name
-
-                if debug : print('matslots : %s'%matslots)
-
-            # VERTICES GROUPS/WEIGHTS
-            elif tokentype == 'skinweights' :
-                groupname, nverts, vindices, vweights, mat = readToken(childname)
-                groupname = namelookup[groupname]
-                if debug :
-                    print('vgroup    : %s (%s/%s verts) %s'%(groupname,len(vindices),len(vweights),'bone' if groupname in tokens else ''))
-
-                #if debug : print('matrix : %s\n%s'%(type(mat),mat))
-
-                groupnames.append(groupname)
-                groupindices.append(vindices)
-                groupweights.append(vweights)
-
-        ob = bel.mesh.write(obname,tokenname,
-                            verts, edges, faces,
-                            matslots, facemats, uvs,
-                            groupnames, groupindices, groupweights,
-                            use_smooth_groups,
-                            naming_method)
-
-        return ob
-
-    ## here we go
-
-    file = os.path.basename(filepath)
-
-    print('\nimporting %s...'%file)
-    start = time.clock()
-    path = os.path.dirname(filepath)
-    filepath = os.fsencode(filepath)
-    data = open(filepath,'rb')
-    header = dXheader(data)
-
-    if global_matrix is None:
-        global_matrix = mathutils.Matrix()
-
-    if header :
-        minor, major, format, accuracy = header
-
-        if show_geninfo :
-            print('\n%s directX header'%file)
-            print('  minor  : %s'%(minor))
-            print('  major  : %s'%(major))
-            print('  format : %s'%(format))
-            print('  floats are %s bits'%(accuracy))
-
-        if format in [ 'txt' ] : #, 'bin' ] :
-
-            ## FILE READ : STEP 1 : STRUCTURE
-            if show_geninfo : print('\nBuilding internal .x tree')
-            t = time.clock()
-            tokens, templates, tokentypes = dXtree(data,quickmode)
-            readstruct_time = time.clock()-t
-            if show_geninfo : print('builded tree in %.2f\''%(readstruct_time)) # ,end='\r')
-
-            ## populate templates with datas
-            for tplname in templates :
-                readTemplate(data,tplname,show_templates)
-
-            ## DATA TREE CHECK
-            if show_tree :
-                print('\nDirectX Data Tree :\n')
-                walk_dXtree(tokens.keys())
-
-            ## DATA IMPORTATION
-            if show_geninfo :
-                #print(tokens)
-                print('Root frames :\n %s'%rootTokens)
-            if parented :
-                import_dXtree(rootTokens)
-            else :
-                for tokenname in tokentypes['mesh'] :
-                    obname = tokens[tokenname]['parent']
-                    # object and mesh naming :
-                    # if parent frame has several meshes : obname = meshname = mesh token name,
-                    # if parent frame has only one mesh  : obname = parent frame name, meshname =  mesh token name.
-                    if obname :
-                        meshcount = 0
-                        for child in getChilds(obname) :
-                            if tokens[child]['type'] == 'mesh' :
-                                meshcount += 1
-                                if meshcount == 2 :
-                                    obname = tokenname
-                                    break
-                    else : obname = tokenname
-
-                    ob = getMesh(obname,tokenname,show_geninfo)
-                    ob.matrix_world = global_matrix
-
-            print('done in %.2f\''%(time.clock()-start)) # ,end='\r')
-
-        else :
-            print('only .x files in text format are currently supported')
-            print('please share your file to make the importer evolve')
-
-
-        return {'FINISHED'}
diff --git a/io_directx_bel/templates_x.py b/io_directx_bel/templates_x.py
deleted file mode 100644 (file)
index 7b51e0c..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-# dx 'strict' templates
-# lower() since some apps does not respect it,
-# and to keep the 'as it should be' syntax
-
-defaultTemplates={}
-templatesConvert={}
-
-# mesh template
-defaultTemplates['Mesh'.lower()] = {
-    'uuid' : '<3d82ab44-62da-11cf-ab39-0020af71e433>',
-    'restriction' : '[...]',
-    'members' : (
-        ('dword', 'nVertices'),
-        ('array', 'vector', 'vertices[nVertices]'),
-        ('dword', 'nFaces'),
-        ('array', 'MeshFace', 'faces[nFaces]'),
-    )
-}
-
-defaultTemplates['FrameTransformMatrix'.lower()] = {
-    'uuid' : '<f6f23f41-7686-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('matrix4x4', 'frameMatrix'),
-    )
-}
-
-templatesConvert['matrix4x4'] = 'Matrix( [fields[0][0:4], fields[0][4:8] , fields[0][8:12] , fields[0][12:16]] )'
-defaultTemplates['matrix4x4'.lower()] = {
-    'uuid' : '<f6f23f45-7686-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('array', 'float', 'matrix[16]'),
-    )
-}
-
-#returns [ [vid0,vid1,vid2], [vid1,vid2,vid3,vid4] .. ]
-templatesConvert['meshface'] = 'fields[1]'
-defaultTemplates['MeshFace'.lower()] = {
-    'uuid' : '<3d82ab5f-62da-11cf-ab39-0020af71e433>',
-    'restriction' : 'closed',
-    'members' : (
-        ('dword', 'nFaceVertexIndices'),
-        ('array', 'dword', 'faceVertexIndices[nFaceVertexIndices]')
-    )
-}
-
-defaultTemplates['vector'.lower()] = {
-    'uuid' : '<3d82ab5e-62da-11cf-ab39-0020af71e433>',
-    'restriction' : 'closed',
-    'members' : (
-        ('float', 'x'),
-        ('float', 'y'),
-        ('float', 'z')
-    )
-}
-
-defaultTemplates['Coords2d'.lower()] = {
-    'uuid' : '<f6f23f44-7686-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('float', 'u'),
-        ('float', 'v')
-    )
-}
-
-# returns [ uvAsVertsLocation ]
-templatesConvert['meshtexturecoords'] = 'fields[1]'
-defaultTemplates['MeshTextureCoords'.lower()] = {
-    'uuid' : '<f6f23f40-7686-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('dword', 'nTextureCoords'),
-        ('array', 'Coords2d', 'textureCoords[nTextureCoords]')
-    )
-}
-
-defaultTemplates['meshnormals'.lower()] = {
-    'uuid' : '<f6f23f43-7686-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('dword', 'nNormals'),
-        ('array', 'vector', 'normals[nNormals]'),
-        ('dword', 'nFaceNormals'),
-        ('array', 'MeshFace', 'faceNormals[nFaceNormals]')
-    )
-}
-
-# returns [ nMaterials, [ materialindex of each face ] ]
-templatesConvert['meshmateriallist'] = '[fields[0],fields[2]]'
-defaultTemplates['MeshMaterialList'.lower()] = {
-    'uuid' : '<f6f23f42-7686-11cf-8f52-0040333594a3>',
-    'restriction' : '[Material]',
-    'members' : (
-        ('dword', 'nMaterials'),
-        ('dword', 'nFaceIndexes'),
-        ('array', 'dword', 'faceIndexes[nFaceIndexes]')
-    )
-}
-
-defaultTemplates['Material'.lower()] = {
-    'uuid' : '<3d82ab4d-62da-11cf-ab39-0020af71e433>',
-    'restriction' : '[...]',
-    'members' : (
-        ('colorrgba', 'faceColor'),
-        ('float', 'power'),
-        ('colorrgb', 'specularColor'),
-        ('colorrgb', 'emissiveColor')
-    )
-}
-
-templatesConvert['colorrgba'] = 'fields[:3],fields[3]'
-defaultTemplates['colorrgba'.lower()] = {
-    'uuid' : '<35ff44e0-6c7c-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('float', 'red'),
-        ('float', 'green'),
-        ('float', 'blue'),
-        ('float', 'alpha')
-    )
-}
-
-defaultTemplates['colorrgb'.lower()] = {
-    'uuid' : '<d3e16e81-7835-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('float', 'red'),
-        ('float', 'green'),
-        ('float', 'blue')
-    )
-}
-
-defaultTemplates['TextureFilename'.lower()] = {
-    'uuid' : '<a42790e1-7810-11cf-8f52-0040333594a3>',
-    'restriction' : 'closed',
-    'members' : (
-        ('string', 'filename'),
-    )
-}
-
-defaultTemplates['SkinWeights'.lower()] = {
-    'uuid' : '<6f0d123b-bad2-4167-a0d0-80224f25fabb>',
-    'restriction' : 'closed',
-    'members' : (
-        ('string', 'transformNodeName'),
-        ('dword', 'nWeights'),
-        ('array', 'dword', 'vertexIndices[nWeights]'),
-        ('array', 'float', 'weights[nWeights]'),
-        ('matrix4x4', 'matrixOffset')
-    )
-}
-
-defaultTemplates['XSkinMeshHeader'.lower()] = {
-    'uuid' : '3cf169ce-ff7c-44ab-93c0-f78f62d172e2',
-    'restriction' : 'closed',
-    'members' : (
-        ('word', 'nMaxSkinWeightsPerVertex'),
-        ('word', 'nMaxSkinWeightsPerFace'),
-        ('word', 'nBones')
-    )
-}
diff --git a/io_export_unreal_psk_psa.py b/io_export_unreal_psk_psa.py
deleted file mode 100644 (file)
index 3008d6c..0000000
+++ /dev/null
@@ -1,3010 +0,0 @@
-# ##### 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 3 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, see <http://www.gnu.org/licenses/>.
-#  All rights reserved.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-bl_info = {
-    "name": "Export Unreal Engine Format(.psk/.psa)",
-    "author": "Darknet/Optimus_P-Fat/Active_Trash/Sinsoft/VendorX/Spoof",
-    "version": (2, 7, 1),
-    "blender": (2, 65, 4),
-    "location": "File > Export > Skeletal Mesh/Animation Data (.psk/.psa)",
-    "description": "Export Skeleletal Mesh/Animation Data",
-    "warning": "",
-    "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/Unreal_psk_psa",
-    "category": "Import-Export",
-}
-
-"""
--- Unreal Skeletal Mesh and Animation Export (.psk  and .psa) export script v0.0.1 --<br>
-
-- NOTES:
-- This script Exports To Unreal's PSK and PSA file formats for Skeletal Meshes and Animations. <br>
-- This script DOES NOT support vertex animation! These require completely different file formats. <br>
-
-- v0.0.1
-- Initial version
-
-- v0.0.2
-- This version adds support for more than one material index!
-
-[ - Edit by: Darknet
-- v0.0.3 - v0.0.12
-- This will work on UT3 and it is a stable version that work with vehicle for testing.
-- Main Bone fix no dummy needed to be there.
-- Just bone issues position, rotation, and offset for psk.
-- The armature bone position, rotation, and the offset of the bone is fix.
-  It was to deal with skeleton mesh export for psk.
-- Animation is fix for position, offset, rotation bone support one rotation direction when armature build.
-- It will convert your mesh into triangular when exporting to psk file.
-- Did not work with psa export yet.
-
-- v0.0.13
-- The animatoin will support different bone rotations when export the animation.
-
-- v0.0.14
-- Fixed Action set keys frames when there is no pose keys and it will ignore it.
-
-- v0.0.15
-- Fixed multiple objects when exporting to psk. Select one mesh to export to psk.
-- ]
-
-- v0.1.1
-- Blender 2.50 svn (Support)
-
-Credit to:
-- export_cal3d.py (Position of the Bones Format)
-- blender2md5.py (Animation Translation Format)
-- export_obj.py (Blender 2.5/Pyhton 3.x Format)
-
-- freenode #blendercoder -> user -> ideasman42
-
-- Give Credit to those who work on this script.
-
-- http://sinsoft.com
-"""
-
-
-# ===========================================================================
-"""
-NOTES for Jan 2012 refactor (Spoof)
-
-    * THIS IS A WORK IN PROGRESS. These modifications were originally
-    intended for internal use and are incomplete. Use at your own risk! *
-
-TODO
-
-- (Blender 2.62) changes to Matrix math
-- (Blender 2.62) check for long names
-- option to manually set the root bone for export
-
-CHANGES
-
-- new bone parsing to allow advanced rigging
-- identification of armature and mesh
-- removed the need to apply an action to the armature
-- fixed anim rate to work correctly in UDK (no more FPS fudging)
-- progress reporting while processing smooth groups
-- more informative logging
-- code refactor for clarity and modularity
-    - naming conventions unified to use lowercase_with_underscore
-    - C++ datatypes and PSK/PSA classes remain CamelCaseStyle for clarity
-    - names such as 'ut' and 'unreal' unified to 'udk'
-    - simplification of code structure
-    - removed legacy code paths
-
-USAGE
-
-This version of the exporter is more selective over which bones are considered
-part of the UDK skeletal mesh, and allows greater flexibility for adding
-control bones to aid in animation.
-
-Taking advantage of this script requires the following methodology:
-
-    * Place all exportable bones into a bone hierarchy extending from a single
-    root. This root bone must have use_deform enabled. All other root bones
-    in the armature must disable use_deform. *
-
-The script searches for a root bone with use_deform set true and considers all
-bones parented to it as part of the UDK skeletal mesh. Thus only these bones
-are exported and all other bones are ignored.
-
-This removes many restrictions on the rigger/animator, who can add control
-bone hierarchies to the rig, and keyframe any element into actions. With this
-approach you can build complex animation rigs in a similar vein to the Rigify
-add-on, by Nathan Vegdahl. However...
-
-    * Rigify is incompatible with this script *
-
-Rigify interlaces deformer bones within a single hierarchy making it difficult
-to deconstruct for export. It also splits some meta-rig bones into multiple
-deformer bones (bad for optimising a game character). I had partial success
-writing a parser for the structure, but it was taking too much time and,
-considering the other issues with Rigify, it was abandoned.
-"""
-# ===========================================================================
-
-import bmesh
-import os
-import time
-import bpy
-import mathutils
-import math
-import operator
-import sys
-from bpy.props import (
-        BoolProperty,
-        CollectionProperty,
-        EnumProperty,
-        FloatProperty,
-        IntProperty,
-        StringProperty,
-        )
-from bpy.types import (
-        Operator,
-        Panel,
-        UIList,
-        PropertyGroup,
-        AddonPreferences,
-        )
-from struct import pack
-
-
-# REFERENCE MATERIAL JUST IN CASE:
-#
-# U = x / sqrt(x^2 + y^2 + z^2)
-# V = y / sqrt(x^2 + y^2 + z^2)
-#
-# Triangles specified counter clockwise for front face
-#
-# defines for sizeofs
-SIZE_FQUAT = 16
-SIZE_FVECTOR = 12
-SIZE_VJOINTPOS = 44
-SIZE_ANIMINFOBINARY = 168
-SIZE_VCHUNKHEADER = 32
-SIZE_VMATERIAL = 88
-SIZE_VBONE = 120
-SIZE_FNAMEDBONEBINARY = 120
-SIZE_VRAWBONEINFLUENCE = 12
-SIZE_VQUATANIMKEY = 32
-SIZE_VVERTEX = 16
-SIZE_VPOINT = 12
-SIZE_VTRIANGLE = 12
-
-MaterialName = []
-
-
-# Python 3 doesn't have cmp anymore
-def cmp(a, b):
-    return (a > b) - (a < b)
-
-
-# ===========================================================================
-# Custom exception class
-# ===========================================================================
-class Error(Exception):
-
-    def __init__(self, message):
-        self.message = message
-
-
-# ===========================================================================
-# Verbose logging with loop truncation
-# ===========================================================================
-def verbose(msg, iteration=-1, max_iterations=4, msg_truncated="..."):
-
-    if bpy.context.scene.udk_option_verbose is True:
-        # limit the number of times a loop can output messages
-        if iteration > max_iterations:
-            return
-        elif iteration == max_iterations:
-            print(msg_truncated)
-            return
-
-        print(msg)
-
-
-# ===========================================================================
-# Log header/separator
-# ===========================================================================
-def header(msg, justify='LEFT', spacer='_', cols=78):
-
-    if justify == 'LEFT':
-        s = '{:{spacer}<{cols}}'.format(msg + " ", spacer=spacer, cols=cols)
-
-    elif justify == 'RIGHT':
-        s = '{:{spacer}>{cols}}'.format(" " + msg, spacer=spacer, cols=cols)
-
-    else:
-        s = '{:{spacer}^{cols}}'.format(" " + msg + " ", spacer=spacer, cols=cols)
-
-    return "\n" + s + "\n"
-
-
-# ===========================================================================
-# Generic Object->Integer mapping
-# the object must be usable as a dictionary key
-# ===========================================================================
-class ObjMap:
-
-    def __init__(self):
-        self.dict = {}
-        self.next = 0
-
-    def get(self, obj):
-        if obj in self.dict:
-            return self.dict[obj]
-        else:
-            id = self.next
-            self.next = self.next + 1
-            self.dict[obj] = id
-            return id
-
-    def items(self):
-        getval = operator.itemgetter(0)
-        getkey = operator.itemgetter(1)
-        return map(getval, sorted(self.dict.items(), key=getkey))
-
-
-# ===========================================================================
-# RG - UNREAL DATA STRUCTS - CONVERTED FROM C STRUCTS GIVEN ON UDN SITE
-# provided here: http://udn.epicgames.com/Two/BinaryFormatSpecifications.html
-# updated UDK (Unreal Engine 3): http://udn.epicgames.com/Three/BinaryFormatSpecifications.html
-# ===========================================================================
-class FQuat:
-
-    def __init__(self):
-        self.X = 0.0
-        self.Y = 0.0
-        self.Z = 0.0
-        self.W = 1.0
-
-    def dump(self):
-        return pack('ffff', self.X, self.Y, self.Z, self.W)
-
-    def __cmp__(self, other):
-        return cmp(self.X, other.X) or \
-               cmp(self.Y, other.Y) or \
-               cmp(self.Z, other.Z) or \
-               cmp(self.W, other.W)
-
-    def __hash__(self):
-        return hash(self.X) ^ hash(self.Y) ^ hash(self.Z) ^ hash(self.W)
-
-    def __str__(self):
-        return "[%f,%f,%f,%f](FQuat)" % (self.X, self.Y, self.Z, self.W)
-
-
-class FVector(object):
-
-    def __init__(self, X=0.0, Y=0.0, Z=0.0):
-        self.X = X
-        self.Y = Y
-        self.Z = Z
-
-    def dump(self):
-        return pack('fff', self.X, self.Y, self.Z)
-
-    def __cmp__(self, other):
-        return cmp(self.X, other.X) or \
-               cmp(self.Y, other.Y) or \
-               cmp(self.Z, other.Z)
-
-    def _key(self):
-        return (type(self).__name__, self.X, self.Y, self.Z)
-
-    def __hash__(self):
-        return hash(self._key())
-
-    def __eq__(self, other):
-        if not hasattr(other, '_key'):
-            return False
-        return self._key() == other._key()
-
-    def dot(self, other):
-        return self.X * other.X + self.Y * other.Y + self.Z * other.Z
-
-    def cross(self, other):
-        return FVector(self.Y * other.Z - self.Z * other.Y,
-                self.Z * other.X - self.X * other.Z,
-                self.X * other.Y - self.Y * other.X)
-
-    def sub(self, other):
-        return FVector(self.X - other.X,
-            self.Y - other.Y,
-            self.Z - other.Z)
-
-
-class VJointPos:
-
-    def __init__(self):
-        self.Orientation = FQuat()
-        self.Position = FVector()
-        self.Length = 0.0
-        self.XSize = 0.0
-        self.YSize = 0.0
-        self.ZSize = 0.0
-
-    def dump(self):
-        return self.Orientation.dump() + self.Position.dump() + \
-               pack('4f', self.Length, self.XSize, self.YSize, self.ZSize)
-
-
-class AnimInfoBinary:
-
-    def __init__(self):
-        self.Name = ""      # length=64
-        self.Group = ""     # length=64
-        self.TotalBones = 0
-        self.RootInclude = 0
-        self.KeyCompressionStyle = 0
-        self.KeyQuotum = 0
-        self.KeyPrediction = 0.0
-        self.TrackTime = 0.0
-        self.AnimRate = 0.0
-        self.StartBone = 0
-        self.FirstRawFrame = 0
-        self.NumRawFrames = 0
-
-    def dump(self):
-        return pack('64s64siiiifffiii', str.encode(self.Name), str.encode(self.Group),
-                    self.TotalBones, self.RootInclude, self.KeyCompressionStyle, self.KeyQuotum,
-                    self.KeyPrediction, self.TrackTime, self.AnimRate, self.StartBone,
-                    self.FirstRawFrame, self.NumRawFrames)
-
-
-class VChunkHeader:
-
-    def __init__(self, name, type_size):
-        self.ChunkID = str.encode(name)  # length=20
-        self.TypeFlag = 1999801           # special value
-        self.DataSize = type_size
-        self.DataCount = 0
-
-    def dump(self):
-        return pack('20siii', self.ChunkID, self.TypeFlag, self.DataSize, self.DataCount)
-
-
-class VMaterial:
-
-    def __init__(self):
-        self.MaterialName = ""    # length=64
-        self.TextureIndex = 0
-        self.PolyFlags = 0        # DWORD
-        self.AuxMaterial = 0
-        self.AuxFlags = 0         # DWORD
-        self.LodBias = 0
-        self.LodStyle = 0
-
-    def dump(self):
-        # print("DATA MATERIAL:",self.MaterialName)
-        return pack('64siLiLii', str.encode(self.MaterialName), self.TextureIndex,
-                    self.PolyFlags, self.AuxMaterial, self.AuxFlags, self.LodBias, self.LodStyle)
-
-
-class VBone:
-
-    def __init__(self):
-        self.Name = ""    # length = 64
-        self.Flags = 0     # DWORD
-        self.NumChildren = 0
-        self.ParentIndex = 0
-        self.BonePos = VJointPos()
-
-    def dump(self):
-        return pack('64sLii', str.encode(self.Name), self.Flags,
-                    self.NumChildren, self.ParentIndex) + self.BonePos.dump()
-
-
-# same as above - whatever - this is how Epic does it...
-class FNamedBoneBinary:
-
-    def __init__(self):
-        self.Name = ""    # length = 64
-        self.Flags = 0    # DWORD
-        self.NumChildren = 0
-        self.ParentIndex = 0
-        self.BonePos = VJointPos()
-        self.IsRealBone = 0  # this is set to 1 when the bone is actually a bone in the mesh and not a dummy
-
-    def dump(self):
-        return pack('64sLii', str.encode(self.Name), self.Flags,
-                    self.NumChildren, self.ParentIndex) + self.BonePos.dump()
-
-
-class VRawBoneInfluence:
-
-    def __init__(self):
-        self.Weight = 0.0
-        self.PointIndex = 0
-        self.BoneIndex = 0
-
-    def dump(self):
-        return pack('fii', self.Weight, self.PointIndex, self.BoneIndex)
-
-
-class VQuatAnimKey:
-
-    def __init__(self):
-        self.Position = FVector()
-        self.Orientation = FQuat()
-        self.Time = 0.0
-
-    def dump(self):
-        return self.Position.dump() + self.Orientation.dump() + pack('f', self.Time)
-
-
-class VVertex(object):
-
-    def __init__(self):
-        self.PointIndex = 0     # WORD
-        self.U = 0.0
-        self.V = 0.0
-        self.MatIndex = 0       # BYTE
-        self.Reserved = 0       # BYTE
-        self.SmoothGroup = 0
-
-    def dump(self):
-        return pack('HHffBBH', self.PointIndex, 0, self.U, self.V, self.MatIndex, self.Reserved, 0)
-
-    def __cmp__(self, other):
-        return cmp(self.PointIndex, other.PointIndex) or\
-               cmp(self.U, other.U) or \
-               cmp(self.V, other.V) or \
-               cmp(self.MatIndex, other.MatIndex) or \
-               cmp(self.Reserved, other.Reserved) or \
-               cmp(self.SmoothGroup, other.SmoothGroup)
-
-    def _key(self):
-        return (type(self).__name__, self.PointIndex, self.U, self.V, self.MatIndex, self.Reserved)
-
-    def __hash__(self):
-        return hash(self._key())
-
-    def __eq__(self, other):
-        if not hasattr(other, '_key'):
-            return False
-        return self._key() == other._key()
-
-
-class VPointSimple:
-
-    def __init__(self):
-        self.Point = FVector()
-
-    def __cmp__(self, other):
-        return cmp(self.Point, other.Point)
-
-    def __hash__(self):
-        return hash(self._key())
-
-    def _key(self):
-        return (type(self).__name__, self.Point)
-
-    def __eq__(self, other):
-        if not hasattr(other, '_key'):
-            return False
-        return self._key() == other._key()
-
-
-class VPoint(object):
-
-    def __init__(self):
-        self.Point = FVector()
-        self.SmoothGroup = 0
-
-    def dump(self):
-        return self.Point.dump()
-
-    def __cmp__(self, other):
-        return cmp(self.Point, other.Point) \
-            or cmp(self.SmoothGroup, other.SmoothGroup)
-
-    def _key(self):
-        return (type(self).__name__, self.Point, self.SmoothGroup)
-
-    def __hash__(self):
-        return hash(self._key()) \
-            ^ hash(self.SmoothGroup)
-
-    def __eq__(self, other):
-        if not hasattr(other, '_key'):
-            return False
-        return self._key() == other._key()
-
-
-class VTriangle:
-
-    def __init__(self):
-        self.WedgeIndex0 = 0        # WORD
-        self.WedgeIndex1 = 0        # WORD
-        self.WedgeIndex2 = 0        # WORD
-        self.MatIndex = 0           # BYTE
-        self.AuxMatIndex = 0        # BYTE
-        self.SmoothingGroups = 0    # DWORD
-
-    def dump(self):
-        return pack('HHHBBL', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2,
-                    self.MatIndex, self.AuxMatIndex, self.SmoothingGroups)
-        """
-        print("smooth",self.SmoothingGroups)
-        return pack('HHHBBI', self.WedgeIndex0, self.WedgeIndex1, self.WedgeIndex2,
-                     self.MatIndex, self.AuxMatIndex, self.SmoothingGroups)
-        """
-# END UNREAL DATA STRUCTS
-# ===========================================================================
-
-
-# ===========================================================================
-# RG - helper class to handle the normal way the UT files are stored
-# as sections consisting of a header and then a list of data structures
-# ===========================================================================
-class FileSection:
-
-    def __init__(self, name, type_size):
-        self.Header = VChunkHeader(name, type_size)
-        self.Data = []  # list of datatypes
-
-    def dump(self):
-        data = self.Header.dump()
-        for i in range(len(self.Data)):
-            data = data + self.Data[i].dump()
-        return data
-
-    def UpdateHeader(self):
-        self.Header.DataCount = len(self.Data)
-
-
-# ===========================================================================
-# PSK
-# ===========================================================================
-class PSKFile:
-
-    def __init__(self):
-        self.GeneralHeader = VChunkHeader("ACTRHEAD", 0)
-        self.Points = FileSection("PNTS0000", SIZE_VPOINT)              # VPoint
-        self.Wedges = FileSection("VTXW0000", SIZE_VVERTEX)             # VVertex
-        self.Faces = FileSection("FACE0000", SIZE_VTRIANGLE)            # VTriangle
-        self.Materials = FileSection("MATT0000", SIZE_VMATERIAL)        # VMaterial
-        self.Bones = FileSection("REFSKELT", SIZE_VBONE)                # VBone
-        self.Influences = FileSection("RAWWEIGHTS", SIZE_VRAWBONEINFLUENCE)  # VRawBoneInfluence
-
-        # RG - this mapping is not dumped, but is used internally to store the new point indices
-        # for vertex groups calculated during the mesh dump, so they can be used again
-        # to dump bone influences during the armature dump
-        #
-        # the key in this dictionary is the VertexGroup/Bone Name, and the value
-        # is a list of tuples containing the new point index and the weight, in that order
-        #
-        # Layout:
-        # { groupname : [ (index, weight), ... ], ... }
-        #
-        # example:
-        # {'MyVertexGroup' : [ (0, 1.0), (5, 1.0), (3, 0.5) ] , 'OtherGroup' : [(2, 1.0)]}
-
-        self.VertexGroups = {}
-
-    def AddPoint(self, p):
-        self.Points.Data.append(p)
-
-    def AddWedge(self, w):
-        self.Wedges.Data.append(w)
-
-    def AddFace(self, f):
-        self.Faces.Data.append(f)
-
-    def AddMaterial(self, m):
-        self.Materials.Data.append(m)
-
-    def AddBone(self, b):
-        self.Bones.Data.append(b)
-
-    def AddInfluence(self, i):
-        self.Influences.Data.append(i)
-
-    def UpdateHeaders(self):
-        self.Points.UpdateHeader()
-        self.Wedges.UpdateHeader()
-        self.Faces.UpdateHeader()
-        self.Materials.UpdateHeader()
-        self.Bones.UpdateHeader()
-        self.Influences.UpdateHeader()
-
-    def dump(self):
-        self.UpdateHeaders()
-        data = self.GeneralHeader.dump() + self.Points.dump() + self.Wedges.dump() + \
-               self.Faces.dump() + self.Materials.dump() + self.Bones.dump() + self.Influences.dump()
-        return data
-
-    def GetMatByIndex(self, mat_index):
-        if mat_index >= 0 and len(self.Materials.Data) > mat_index:
-            return self.Materials.Data[mat_index]
-        else:
-            m = VMaterial()
-            # modified by VendorX
-            m.MaterialName = MaterialName[mat_index]
-            self.AddMaterial(m)
-            return m
-
-    def PrintOut(self):
-        print("{:>16} {:}".format("Points", len(self.Points.Data)))
-        print("{:>16} {:}".format("Wedges", len(self.Wedges.Data)))
-        print("{:>16} {:}".format("Faces", len(self.Faces.Data)))
-        print("{:>16} {:}".format("Materials", len(self.Materials.Data)))
-        print("{:>16} {:}".format("Bones", len(self.Bones.Data)))
-        print("{:>16} {:}".format("Influences", len(self.Influences.Data)))
-
-
-# ===========================================================================
-# PSA
-#
-# Notes from UDN:
-#   The raw key array holds all the keys for all the bones in all the specified sequences,
-#   organized as follows:
-#   For each AnimInfoBinary's sequence there are [Number of bones] times [Number of frames keys]
-#   in the VQuatAnimKeys, laid out as tracks of [numframes] keys for each bone in the order of
-#   the bones as defined in the array of FnamedBoneBinary in the PSA.
-#
-#   Once the data from the PSK (now digested into native skeletal mesh) and PSA (digested into
-#   a native animation object containing one or more sequences) are associated together at runtime,
-#   bones are linked up by name. Any bone in a skeleton (from the PSK) that finds no partner in
-#   the animation sequence (from the PSA) will assume its reference pose stance ( as defined in
-#   the offsets & rotations that are in the VBones making up the reference skeleton from the PSK)
-# ===========================================================================
-class PSAFile:
-
-    def __init__(self):
-        self.GeneralHeader = VChunkHeader("ANIMHEAD", 0)
-        self.Bones = FileSection("BONENAMES", SIZE_FNAMEDBONEBINARY)        # FNamedBoneBinary
-        self.Animations = FileSection("ANIMINFO", SIZE_ANIMINFOBINARY)      # AnimInfoBinary
-        self.RawKeys = FileSection("ANIMKEYS", SIZE_VQUATANIMKEY)           # VQuatAnimKey
-        # this will take the format of key=Bone Name, value = (BoneIndex, Bone Object)
-        # THIS IS NOT DUMPED
-        self.BoneLookup = {}
-
-    def AddBone(self, b):
-        self.Bones.Data.append(b)
-
-    def AddAnimation(self, a):
-        self.Animations.Data.append(a)
-
-    def AddRawKey(self, k):
-        self.RawKeys.Data.append(k)
-
-    def UpdateHeaders(self):
-        self.Bones.UpdateHeader()
-        self.Animations.UpdateHeader()
-        self.RawKeys.UpdateHeader()
-
-    def GetBoneByIndex(self, bone_index):
-        if bone_index >= 0 and len(self.Bones.Data) > bone_index:
-            return self.Bones.Data[bone_index]
-
-    def IsEmpty(self):
-        return (len(self.Bones.Data) == 0 or len(self.Animations.Data) == 0)
-
-    def StoreBone(self, b):
-        self.BoneLookup[b.Name] = [-1, b]
-
-    def UseBone(self, bone_name):
-        if bone_name in self.BoneLookup:
-            bone_data = self.BoneLookup[bone_name]
-
-            if bone_data[0] == -1:
-                bone_data[0] = len(self.Bones.Data)
-                self.AddBone(bone_data[1])
-                # self.Bones.Data.append(bone_data[1])
-
-            return bone_data[0]
-
-    def GetBoneByName(self, bone_name):
-        if bone_name in self.BoneLookup:
-            bone_data = self.BoneLookup[bone_name]
-            return bone_data[1]
-
-    def GetBoneIndex(self, bone_name):
-        if bone_name in self.BoneLookup:
-            bone_data = self.BoneLookup[bone_name]
-            return bone_data[0]
-
-    def dump(self):
-        self.UpdateHeaders()
-        return self.GeneralHeader.dump() + self.Bones.dump() + self.Animations.dump() + self.RawKeys.dump()
-
-    def PrintOut(self):
-        print("{:>16} {:}".format("Bones", len(self.Bones.Data)))
-        print("{:>16} {:}".format("Animations", len(self.Animations.Data)))
-        print("{:>16} {:}".format("Raw keys", len(self.RawKeys.Data)))
-
-
-# ===========================================================================
-#  Helpers to create bone structs
-# ===========================================================================
-def make_vbone(name, parent_index, child_count, orientation_quat, position_vect):
-    bone = VBone()
-    bone.Name = name
-    bone.ParentIndex = parent_index
-    bone.NumChildren = child_count
-    bone.BonePos.Orientation = orientation_quat
-    bone.BonePos.Position.X = position_vect.x
-    bone.BonePos.Position.Y = position_vect.y
-    bone.BonePos.Position.Z = position_vect.z
-    # these values seem to be ignored?
-    # bone.BonePos.Length = tail.length
-    # bone.BonePos.XSize = tail.x
-    # bone.BonePos.YSize = tail.y
-    # bone.BonePos.ZSize = tail.z
-    return bone
-
-
-def make_namedbonebinary(name, parent_index, child_count, orientation_quat, position_vect, is_real):
-    bone = FNamedBoneBinary()
-    bone.Name = name
-    bone.ParentIndex = parent_index
-    bone.NumChildren = child_count
-    bone.BonePos.Orientation = orientation_quat
-    bone.BonePos.Position.X = position_vect.x
-    bone.BonePos.Position.Y = position_vect.y
-    bone.BonePos.Position.Z = position_vect.z
-    bone.IsRealBone = is_real
-    return bone
-
-
-def make_fquat(bquat):
-    quat = FQuat()
-    # flip handedness for UT = set x,y,z to negative (rotate in other direction)
-    quat.X = -bquat.x
-    quat.Y = -bquat.y
-    quat.Z = -bquat.z
-    quat.W = bquat.w
-
-    return quat
-
-
-def make_fquat_default(bquat):
-    quat = FQuat()
-    # print(dir(bquat))
-    quat.X = bquat.x
-    quat.Y = bquat.y
-    quat.Z = bquat.z
-    quat.W = bquat.w
-
-    return quat
-
-
-# ===========================================================================
-# RG - check to make sure face isnt a line
-# ===========================================================================
-def is_1d_face(face, mesh):
-    # ID Vertex of id point
-    v0 = face.vertices[0]
-    v1 = face.vertices[1]
-    v2 = face.vertices[2]
-
-    return (mesh.vertices[v0].co == mesh.vertices[v1].co or
-            mesh.vertices[v1].co == mesh.vertices[v2].co or
-            mesh.vertices[v2].co == mesh.vertices[v0].co)
-    return False
-
-
-# ===========================================================================
-# Smoothing group
-# (renamed to separate it from VVertex.SmoothGroup)
-# ===========================================================================
-class SmoothingGroup:
-
-    static_id = 1
-
-    def __init__(self):
-        self.faces = []
-        self.neighboring_faces = []
-        self.neighboring_groups = []
-        self.id = -1
-        self.local_id = SmoothingGroup.static_id
-        SmoothingGroup.static_id += 1
-
-    def __cmp__(self, other):
-        if isinstance(other, SmoothingGroup):
-            return cmp(self.local_id, other.local_id)
-        return -1
-
-    def __hash__(self):
-        return hash(self.local_id)
-
-    # searches neighboring faces to determine which smoothing group ID can be used
-    def get_valid_smoothgroup_id(self):
-        temp_id = 1
-        for group in self.neighboring_groups:
-            if group is not None and group.id == temp_id:
-                if temp_id < 0x80000000:
-                    temp_id = temp_id << 1
-                else:
-                    raise Error("Smoothing Group ID Overflowed, "
-                                "Smoothing Group evidently has more than 31 neighboring groups")
-
-        self.id = temp_id
-        return self.id
-
-    def make_neighbor(self, new_neighbor):
-        if new_neighbor not in self.neighboring_groups:
-            self.neighboring_groups.append(new_neighbor)
-
-    def contains_face(self, face):
-        return (face in self.faces)
-
-    def add_neighbor_face(self, face):
-        if face not in self.neighboring_faces:
-            self.neighboring_faces.append(face)
-
-    def add_face(self, face):
-        if face not in self.faces:
-            self.faces.append(face)
-
-
-def determine_edge_sharing(mesh):
-
-    edge_sharing_list = dict()
-
-    for edge in mesh.edges:
-        edge_sharing_list[edge.key] = []
-
-    for face in mesh.tessfaces:
-        for key in face.edge_keys:
-            if face not in edge_sharing_list[key]:
-                edge_sharing_list[key].append(face)  # mark this face as sharing this edge
-
-    return edge_sharing_list
-
-
-def find_edges(mesh, key):
-    """ Temp replacement for mesh.findEdges().
-        This is painfully slow.
-    """
-    for edge in mesh.edges:
-        v = edge.vertices
-        if key[0] == v[0] and key[1] == v[1]:
-            return edge.index
-
-
-def add_face_to_smoothgroup(mesh, face, edge_sharing_list, smoothgroup):
-
-    if face in smoothgroup.faces:
-        return
-
-    smoothgroup.add_face(face)
-
-    for key in face.edge_keys:
-
-        edge_id = find_edges(mesh, key)
-
-        if edge_id is not None:
-
-            # not sharp
-            if not (mesh.edges[edge_id].use_edge_sharp):
-
-                for shared_face in edge_sharing_list[key]:
-                    if shared_face != face:
-                        # recursive
-                        add_face_to_smoothgroup(mesh, shared_face, edge_sharing_list, smoothgroup)
-            # sharp
-            else:
-                for shared_face in edge_sharing_list[key]:
-                    if shared_face != face:
-                        smoothgroup.add_neighbor_face(shared_face)
-
-
-def determine_smoothgroup_for_face(mesh, face, edge_sharing_list, smoothgroup_list):
-
-    for group in smoothgroup_list:
-        if (face in group.faces):
-            return
-
-    smoothgroup = SmoothingGroup()
-    add_face_to_smoothgroup(mesh, face, edge_sharing_list, smoothgroup)
-
-    if smoothgroup not in smoothgroup_list:
-        smoothgroup_list.append(smoothgroup)
-
-
-def build_neighbors_tree(smoothgroup_list):
-
-    for group in smoothgroup_list:
-        for face in group.neighboring_faces:
-            for neighbor_group in smoothgroup_list:
-                if neighbor_group.contains_face(face) and neighbor_group not in group.neighboring_groups:
-                    group.make_neighbor(neighbor_group)
-                    neighbor_group.make_neighbor(group)
-
-
-# ===========================================================================
-# parse_smooth_groups
-# ===========================================================================
-def parse_smooth_groups(mesh):
-
-    print("Parsing smooth groups...")
-
-    t = time.clock()
-    smoothgroup_list = []
-    edge_sharing_list = determine_edge_sharing(mesh)
-
-    # print("faces:",len(mesh.tessfaces))
-    interval = math.floor(len(mesh.tessfaces) / 100)
-
-    if interval == 0:  # if the faces are few do this
-        interval = math.floor(len(mesh.tessfaces) / 10)
-    # print("FACES:",len(mesh.tessfaces),"//100 =" "interval:",interval)
-
-    for face in mesh.tessfaces:
-        # print(dir(face))
-        determine_smoothgroup_for_face(mesh, face, edge_sharing_list, smoothgroup_list)
-        # progress indicator, writes to console without scrolling
-        if face.index > 0 and (face.index % interval) == 0:
-            print("Processing... {}%\r".format(int(face.index / len(mesh.tessfaces) * 100)), end='')
-            sys.stdout.flush()
-    print("Completed", ' ' * 20)
-
-    verbose("len(smoothgroup_list)={}".format(len(smoothgroup_list)))
-
-    build_neighbors_tree(smoothgroup_list)
-
-    for group in smoothgroup_list:
-        group.get_valid_smoothgroup_id()
-
-    print("Smooth group parsing completed in {:.2f}s".format(time.clock() - t))
-    return smoothgroup_list
-
-
-# ===========================================================================
-# http://en.wikibooks.org/wiki/Blender_3D:_Blending_Into_Python/Cookbook#Triangulate_NMesh
-# blender 2.50 format using the Operators/command convert the mesh to tri mesh
-# ===========================================================================
-def triangulate_mesh(object):
-
-    verbose(header("triangulateNMesh"))
-    # print(type(object))
-    scene = bpy.context.scene
-    view_layer = bpy.context.view_layer
-
-    me_ob = object.copy()
-    depsgraph = bpy.context.evaluated_depsgraph_get()
-    me_ob.data = bpy.data.meshes.new_from_object(object.evaluated_get(depsgraph))  # write data object
-    bpy.context.collection.objects.link(me_ob)
-    view_layer.update()
-    bpy.ops.object.mode_set(mode='OBJECT')
-
-    for i in scene.objects:
-        i.select_set(False)  # deselect all objects
-
-    me_ob.select_set(True)
-    view_layer.objects.active = me_ob
-
-    print("Copy and Convert mesh just incase any way...")
-
-    bpy.ops.object.mode_set(mode='EDIT')
-    bpy.ops.mesh.select_all(action='SELECT')  # select all the face/vertex/edge
-    bpy.ops.object.mode_set(mode='EDIT')
-    bpy.ops.mesh.quads_convert_to_tris()
-    view_layer.update()
-
-    bpy.ops.object.mode_set(mode='OBJECT')
-
-    bpy.context.scene.udk_option_triangulate = True
-
-    verbose("Triangulated mesh")
-
-    me_ob.data = bpy.data.meshes.new_from_object(me_ob.evaluated_get(depsgraph))  # write data object
-    view_layer.update()
-    return me_ob
-
-
-# copy mesh data and then merge them into one object
-def meshmerge(selectedobjects):
-    bpy.ops.object.mode_set(mode='OBJECT')  # object mode and not edit mode
-    cloneobjects = []  # object holder for copying object data
-
-    if len(selectedobjects) > 1:
-        print("selectedobjects:", len(selectedobjects))  # print select object
-        count = 0  # reset count
-
-        for count in range(len(selectedobjects)):
-            # print("Index:",count)
-            if selectedobjects[count] is not None:
-                me_da = selectedobjects[count].data.copy()  # copy data
-                me_ob = selectedobjects[count].copy()  # copy object
-                # note two copy two types else it will use the current data or mesh
-                me_ob.data = me_da  # assign the data
-                bpy.context.collection.objects.link(me_ob)  # link the object to the collection (current obj location)
-                print("Index:", count, "clone object", me_ob.name)  # print clone object
-                cloneobjects.append(me_ob)  # add object to the array
-
-        for i in bpy.data.objects:
-            i.select_set(False)  # deselect all objects
-        count = 0  # reset count
-        # begin merging the mesh together as one
-        for count in range(len(cloneobjects)):
-            if count == 0:
-                bpy.context.view_layer.objects.active = cloneobjects[count]
-                print("Set Active Object:", cloneobjects[count].name)
-            cloneobjects[count].select_set(True)
-        bpy.ops.object.join()  # join object together
-        if len(cloneobjects) > 1:
-            bpy.types.Scene.udk_copy_merge = True
-    return cloneobjects[0]
-
-
-# sort the mesh center top list and not center at the last array.
-# Base on order while select to merge mesh to make them center.
-def sortmesh(selectmesh):
-    print("MESH SORTING...")
-    centermesh = []
-    notcentermesh = []
-    for countm in range(len(selectmesh)):
-        # if object are center add here
-        if selectmesh[countm].location.x == 0 and \
-                    selectmesh[countm].location.y == 0 and \
-                    selectmesh[countm].location.z == 0:
-            centermesh.append(selectmesh[countm])
-        else:  # if not add here for not center
-            notcentermesh.append(selectmesh[countm])
-    selectmesh = []
-    # add mesh object in order for merge object
-    for countm in range(len(centermesh)):
-        selectmesh.append(centermesh[countm])
-    for countm in range(len(notcentermesh)):
-        selectmesh.append(notcentermesh[countm])
-    if len(selectmesh) == 1:  # if there one mesh just do some here
-        return selectmesh[0]  # return object mesh
-    else:
-        return meshmerge(selectmesh)  # return merge object mesh
-
-
-import binascii
-
-
-# ===========================================================================
-# parse_mesh
-# ===========================================================================
-def parse_mesh(mesh, psk):
-    # bpy.ops.object.mode_set(mode='OBJECT')
-    # error ? on commands for select object?
-    print(header("MESH", 'RIGHT'))
-    print("Mesh object:", mesh.name)
-    scene = bpy.context.scene
-    view_layer = bpy.context.view_layer
-
-    for i in scene.objects:
-        i.select_set(False)  # deselect all objects
-
-    view_layer.objects.active = mesh
-    setmesh = mesh
-    mesh = triangulate_mesh(mesh)
-
-    if bpy.types.Scene.udk_copy_merge is True:
-        bpy.context.collection.objects.unlink(setmesh)
-
-    # print("FACES----:",len(mesh.data.tessfaces))
-    verbose("Working mesh object: {}".format(mesh.name))
-
-    # collect a list of the material names
-    print("Materials...")
-
-    mat_slot_index = 0
-
-    for slot in mesh.material_slots:
-
-        print("  Material {} '{}'".format(mat_slot_index, slot.name))
-        MaterialName.append(slot.name)
-
-        """
-        if slot.material.texture_slots[0] is not None:
-            if slot.material.texture_slots[0].texture.image.filepath is not None:
-                print("    Texture path {}".format(slot.material.texture_slots[0].texture.image.filepath))
-        """
-
-        # create the current material
-        v_material = psk.GetMatByIndex(mat_slot_index)
-        v_material.MaterialName = slot.name
-        v_material.TextureIndex = mat_slot_index
-        v_material.AuxMaterial = mat_slot_index
-        mat_slot_index += 1
-        verbose("    PSK index {}".format(v_material.TextureIndex))
-
-    # END slot in mesh.material_slots
-
-    # object_mat = mesh.materials[0]
-    # object_material_index = mesh.active_material_index
-    # FIXME ^ this is redundant due to "= face.material_index" in face loop
-
-    wedges = ObjMap()
-    points = ObjMap()  # vertex
-    points_linked = {}
-
-    discarded_face_count = 0
-    sys.setrecursionlimit(1000000)
-    smoothgroup_list = parse_smooth_groups(mesh.data)
-
-    print("{} faces".format(len(mesh.data.tessfaces)))
-
-    print("Smooth groups active:", bpy.context.scene.udk_option_smoothing_groups)
-
-    for face in mesh.data.tessfaces:
-
-        smoothgroup_id = 0x80000000
-
-        for smooth_group in smoothgroup_list:
-            if smooth_group.contains_face(face):
-                smoothgroup_id = smooth_group.id
-                break
-
-        # modified by VendorX
-        object_material_index = face.material_index
-
-        if len(face.vertices) != 3:
-            raise Error("Non-triangular face (%i)" % len(face.vertices))
-
-        # RG - apparently blender sometimes has problems when you do quad to triangle
-        #   conversion, and ends up creating faces that have only TWO points -
-        #   one of the points is simply in the vertex list for the face twice.
-        #   This is bad, since we can't get a real face normal for a LINE, we need
-        #   a plane for this. So, before we add the face to the list of real faces,
-        #   ensure that the face is actually a plane, and not a line. If it is not
-        #   planar, just discard it and notify the user in the console after we're
-        #   done dumping the rest of the faces
-
-        if not is_1d_face(face, mesh.data):
-
-            wedge_list = []
-            vect_list = []
-
-            # get or create the current material
-            psk.GetMatByIndex(object_material_index)
-
-            face_index = face.index
-            has_uv = False
-            face_uv = None
-
-            if len(mesh.data.uv_textures) > 0:
-                has_uv = True
-                uv_layer = mesh.data.tessface_uv_textures.active
-                face_uv = uv_layer.data[face_index]
-                # size(data) is number of texture faces. Each face has UVs
-                # print("DATA face uv: ",len(faceUV.uv), " >> ",(faceUV.uv[0][0]))
-
-            for i in range(3):
-                vert_index = face.vertices[i]
-                vert = mesh.data.vertices[vert_index]
-                uv = []
-                # assumes 3 UVs Per face (for now)
-                if (has_uv):
-                    if len(face_uv.uv) != 3:
-                        print("WARNING: face has more or less than 3 UV coordinates - writing 0,0...")
-                        uv = [0.0, 0.0]
-                    else:
-                        uv = [face_uv.uv[i][0], face_uv.uv[i][1]]  # OR bottom works better # 24 for cube
-                else:
-                    # print ("No UVs?")
-                    uv = [0.0, 0.0]
-
-                # flip V coordinate because UEd requires it and DOESN'T flip it on its own like it
-                # does with the mesh Y coordinates. this is otherwise known as MAGIC-2
-                uv[1] = 1.0 - uv[1]
-
-                # clamp UV coords if udk_option_clight_uv is True
-                if bpy.context.scene.udk_option_clight_uv:
-                    if (uv[0] > 1):
-                        uv[0] = 1
-                    if (uv[0] < 0):
-                        uv[0] = 0
-                    if (uv[1] > 1):
-                        uv[1] = 1
-                    if (uv[1] < 0):
-                        uv[1] = 0
-
-                # RE - Append untransformed vector (for normal calc below)
-                # TODO: convert to Blender.Mathutils
-                vect_list.append(FVector(vert.co.x, vert.co.y, vert.co.z))
-
-                # Transform position for export
-                # vpos = vert.co * object_material_index
-
-                # should fixed this!!
-                vpos = mesh.matrix_local * vert.co
-                if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
-                    # print("OK!")
-                    vpos.x = vpos.x * bpy.context.scene.udk_option_scale
-                    vpos.y = vpos.y * bpy.context.scene.udk_option_scale
-                    vpos.z = vpos.z * bpy.context.scene.udk_option_scale
-
-                # print("scale pos:", vpos)
-                # Create the point
-                p = VPoint()
-                p.Point.X = vpos.x
-                p.Point.Y = vpos.y
-                p.Point.Z = vpos.z
-                if bpy.context.scene.udk_option_smoothing_groups:  # is this necessary?
-                    p.SmoothGroup = smoothgroup_id
-
-                lPoint = VPointSimple()
-                lPoint.Point.X = vpos.x
-                lPoint.Point.Y = vpos.y
-                lPoint.Point.Z = vpos.z
-
-                if lPoint in points_linked:
-                    if not(p in points_linked[lPoint]):
-                        points_linked[lPoint].append(p)
-                else:
-                    points_linked[lPoint] = [p]
-
-                # Create the wedge
-                w = VVertex()
-                w.MatIndex = object_material_index
-                w.PointIndex = points.get(p)  # store keys
-                w.U = uv[0]
-                w.V = uv[1]
-                if bpy.context.scene.udk_option_smoothing_groups:  # is this necessary?
-                    w.SmoothGroup = smoothgroup_id
-                index_wedge = wedges.get(w)
-                wedge_list.append(index_wedge)
-
-                # print results
-                # print("result PointIndex={}, U={:.6f}, V={:.6f}, wedge_index={}".format(
-                #   w.PointIndex,
-                #   w.U,
-                #   w.V,
-                #   index_wedge))
-
-            # END for i in range(3)
-
-            # Determine face vertex order
-
-            # TODO: convert to Blender.Mathutils
-            # get normal from blender
-            no = face.normal
-            # convert to FVector
-            norm = FVector(no[0], no[1], no[2])
-            # Calculate the normal of the face in blender order
-            tnorm = vect_list[1].sub(vect_list[0]).cross(vect_list[2].sub(vect_list[1]))
-            # RE - dot the normal from blender order against the blender normal
-            # this gives the product of the two vectors' lengths along the blender normal axis
-            # all that matters is the sign
-            dot = norm.dot(tnorm)
-
-            tri = VTriangle()
-            # RE - magic: if the dot product above > 0, order the vertices 2, 1, 0
-            #      if the dot product above < 0, order the vertices 0, 1, 2
-            #      if the dot product is 0, then blender's normal is coplanar with the face
-            #      and we cannot deduce which side of the face is the outside of the mesh
-            if dot > 0:
-                (tri.WedgeIndex2, tri.WedgeIndex1, tri.WedgeIndex0) = wedge_list
-            elif dot < 0:
-                (tri.WedgeIndex0, tri.WedgeIndex1, tri.WedgeIndex2) = wedge_list
-            else:
-                dindex0 = face.vertices[0]
-                dindex1 = face.vertices[1]
-                dindex2 = face.vertices[2]
-
-                mesh.data.vertices[dindex0].select = True
-                mesh.data.vertices[dindex1].select = True
-                mesh.data.vertices[dindex2].select = True
-
-                raise Error("Normal coplanar with face! points: %s, %s, %s" % (str(mesh.data.vertices[dindex0].co),
-                                                                               str(mesh.data.vertices[dindex1].co),
-                                                                               str(mesh.data.vertices[dindex2].co)))
-
-            face.select = True
-            if face.use_smooth is True:
-                tri.SmoothingGroups = 1
-            else:
-                tri.SmoothingGroups = 0
-            tri.MatIndex = object_material_index
-
-            if bpy.context.scene.udk_option_smoothing_groups:
-                tri.SmoothingGroups = smoothgroup_id
-                print("Bool Smooth")
-
-            psk.AddFace(tri)
-
-        # END if not is_1d_face(current_face, mesh.data)
-
-        else:
-            discarded_face_count += 1
-
-    # END face in mesh.data.faces
-
-    print("{} points".format(len(points.dict)))
-
-    for point in points.items():
-        psk.AddPoint(point)
-
-    if len(points.dict) > 32767:
-        raise Error("Mesh vertex limit exceeded! {} > 32767".format(len(points.dict)))
-
-    print("{} wedges".format(len(wedges.dict)))
-
-    for wedge in wedges.items():
-        psk.AddWedge(wedge)
-
-    # alert the user to degenerate face issues
-    if discarded_face_count > 0:
-        print("WARNING: Mesh contained degenerate faces (non-planar)")
-        print("      Discarded {} faces".format(discarded_face_count))
-
-    # RG - walk through the vertex groups and find the indexes into the PSK points array
-    # for them, then store that index and the weight as a tuple in a new list of
-    # verts for the group that we can look up later by bone name, since Blender matches
-    # verts to bones for influences by having the VertexGroup named the same thing as
-    # the bone
-
-    # [print(x, len(points_linked[x])) for x in points_linked]
-    # print("pointsindex length ",len(points_linked))
-    # vertex group
-
-    # all vertex groups of the mesh (obj)...
-    for obj_vertex_group in mesh.vertex_groups:
-
-        # print("  bone group build:",obj_vertex_group.name)#print bone name
-        # print(dir(obj_vertex_group))
-        verbose("obj_vertex_group.name={}".format(obj_vertex_group.name))
-
-        vertex_list = []
-
-        # all vertices in the mesh...
-        for vertex in mesh.data.vertices:
-            # print(dir(vertex))
-            # all groups this vertex is a member of...
-            for vgroup in vertex.groups:
-                if vgroup.group == obj_vertex_group.index:
-                    vertex_weight = vgroup.weight
-                    p = VPointSimple()
-                    vpos = mesh.matrix_local * vertex.co
-
-                    if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
-                        vpos.x = vpos.x * bpy.context.scene.udk_option_scale
-                        vpos.y = vpos.y * bpy.context.scene.udk_option_scale
-                        vpos.z = vpos.z * bpy.context.scene.udk_option_scale
-                    p.Point.X = vpos.x
-                    p.Point.Y = vpos.y
-                    p.Point.Z = vpos.z
-                    # print(p)
-                    # print(len(points_linked[p]))
-                    try:  # check if point doesn't give error
-                        for point in points_linked[p]:
-                            point_index = points.get(point)  # point index
-                            v_item = (point_index, vertex_weight)
-                            vertex_list.append(v_item)
-                    except Exception:  # if get error ignore them # not safe I think
-                        print("Error link points!")
-                        pass
-
-        # bone name, [point id and wieght]
-        # print("Add Vertex Group:",obj_vertex_group.name, " No. Points:",len(vertex_list))
-        psk.VertexGroups[obj_vertex_group.name] = vertex_list
-
-    # remove the temporary triangulated mesh
-    if bpy.context.scene.udk_option_triangulate is True:
-        verbose("Removing temporary triangle mesh: {}".format(mesh.name))
-        bpy.ops.object.mode_set(mode='OBJECT')    # OBJECT mode
-        mesh.parent = None                        # unparent to avoid phantom links
-        bpy.context.collection.objects.unlink(mesh)    # unlink
-
-
-# ===========================================================================
-# Collate bones that belong to the UDK skeletal mesh
-# ===========================================================================
-def parse_armature(armature, psk, psa):
-
-    print(header("ARMATURE", 'RIGHT'))
-    verbose("Armature object: {} Armature data: {}".format(armature.name, armature.data.name))
-
-    # generate a list of root bone candidates
-    root_candidates = [b for b in armature.data.bones if b.parent is None and b.use_deform is True]
-
-    # should be a single, unambiguous result
-    if len(root_candidates) == 0:
-        raise Error("Cannot find root for UDK bones. The root bone must use deform.")
-
-    if len(root_candidates) > 1:
-        raise Error("Ambiguous root for UDK. More than one root bone is using deform.")
-
-    # prep for bone collection
-    udk_root_bone = root_candidates[0]
-    udk_bones = []
-    BoneUtil.static_bone_id = 0  # replaces global
-
-    # traverse bone chain
-    print("{: <3} {: <48} {: <20}".format("ID", "Bone", "Status"))
-    print()
-    recurse_bone(udk_root_bone, udk_bones, psk, psa, 0, armature.matrix_local)
-
-    # final validation
-    if len(udk_bones) < 3:
-        raise Error("Less than three bones may crash UDK (legacy issue?)")
-
-    # return a list of bones making up the entire udk skel
-    # this is passed to parse_animation instead of working from keyed bones in the action
-    return udk_bones
-
-
-# ===========================================================================
-# bone              current bone
-# bones             bone list
-# psk               the PSK file object
-# psa               the PSA file object
-# parent_id
-# parent_matrix
-# indent            text indent for recursive log
-# ===========================================================================
-def recurse_bone(bone, bones, psk, psa, parent_id, parent_matrix, indent=""):
-
-    status = "Ok"
-    bones.append(bone)
-
-    if not bone.use_deform:
-        status = "No effect"
-
-    # calc parented bone transform
-    if bone.parent is not None:
-        quat = make_fquat(bone.matrix.to_quaternion())
-        quat_parent = bone.parent.matrix.to_quaternion().inverted()
-        parent_head = quat_parent * bone.parent.head
-        parent_tail = quat_parent * bone.parent.tail
-        translation = (parent_tail - parent_head) + bone.head
-
-    # calc root bone transform
-    else:
-        translation = parent_matrix * bone.head             # ARMATURE OBJECT Location
-        rot_matrix = bone.matrix * parent_matrix.to_3x3()   # ARMATURE OBJECT Rotation
-        quat = make_fquat_default(rot_matrix.to_quaternion())
-
-    # udk_option_scale bones here?
-    if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
-        translation.x = translation.x * bpy.context.scene.udk_option_scale
-        translation.y = translation.y * bpy.context.scene.udk_option_scale
-        translation.z = translation.z * bpy.context.scene.udk_option_scale
-    bone_id = BoneUtil.static_bone_id       # ALT VERS
-    BoneUtil.static_bone_id += 1            # ALT VERS
-
-    child_count = len(bone.children)
-
-    psk.AddBone(make_vbone(bone.name, parent_id, child_count, quat, translation))
-    psa.StoreBone(make_namedbonebinary(bone.name, parent_id, child_count, quat, translation, 1))
-
-    # RG - dump influences for this bone - use the data we collected
-    # in the mesh dump phase to map our bones to vertex groups
-    if bone.name in psk.VertexGroups:
-        vertex_list = psk.VertexGroups[bone.name]
-        # print("vertex list:", len(vertex_list), " of >" ,bone.name)
-
-        for vertex_data in vertex_list:
-            point_index = vertex_data[0]
-            vertex_weight = vertex_data[1]
-            influence = VRawBoneInfluence()
-            influence.Weight = vertex_weight
-            influence.BoneIndex = bone_id
-            influence.PointIndex = point_index
-            # print ("   AddInfluence to vertex {}, weight={},".format(point_index, vertex_weight))
-            psk.AddInfluence(influence)
-    else:
-        status = "No vertex group"
-        # FIXME overwriting previous status error?
-
-    print("{:<3} {:<48} {:<20}".format(bone_id, indent + bone.name, status))
-
-    # bone.matrix_local
-    # recursively dump child bones
-
-    for child_bone in bone.children:
-        recurse_bone(child_bone, bones, psk, psa, bone_id, parent_matrix, " " + indent)
-
-
-# FIXME rename? remove?
-class BoneUtil:
-    static_bone_id = 0  # static property to replace global
-
-
-# ===========================================================================
-# armature          the armature
-# udk_bones         list of bones to be exported
-# actions_to_export list of actions to process for export
-# psa               the PSA file object
-# ===========================================================================
-def parse_animation(armature, udk_bones, actions_to_export, psa):
-
-    print(header("ANIMATION", 'RIGHT'))
-
-    context = bpy.context
-    anim_rate = context.scene.render.fps
-
-    verbose("Armature object: {}".format(armature.name))
-    print("Scene: {} FPS: {} Frames: {} to {}".format(context.scene.name, anim_rate,
-                                                      context.scene.frame_start, context.scene.frame_end)
-        )
-    print("Processing {} action(s)\n".format(len(actions_to_export)))
-
-    # if animation data was not create for the armature it will skip the exporting action set(s)
-    if armature.animation_data is None:
-        print("None Actions Set! skipping...")
-        return
-    restoreAction = armature.animation_data.action    # Q: is animation_data always valid?
-    # we already do this in export_proxy, but we'll do it here too for now
-    restoreFrame = context.scene.frame_current
-    raw_frame_index = 0  # used to set FirstRawFrame, separating actions in the raw keyframe array
-
-    # action loop...
-    for action in actions_to_export:
-
-        # removed: check for armature with no animation; all it did was force you to add one
-
-        if not len(action.fcurves):
-            print("{} has no keys, skipping".format(action.name))
-            continue
-
-        # apply action to armature and update scene
-        # note if loop all actions that is not armature it will override and will break armature animation
-        armature.animation_data.action = action
-        context.view_layer.update()
-
-        # min/max frames define range
-        framemin, framemax = action.frame_range
-        start_frame = int(framemin)
-        end_frame = int(framemax)
-        scene_range = range(start_frame, end_frame + 1)
-        frame_count = len(scene_range)
-
-        # create the AnimInfoBinary
-        anim = AnimInfoBinary()
-        anim.Name = action.name
-        anim.Group = ""  # unused?
-        anim.NumRawFrames = frame_count
-        anim.AnimRate = anim_rate
-        anim.FirstRawFrame = raw_frame_index
-
-        print("{}, frames {} to {} ({} frames)".format(action.name, start_frame, end_frame, frame_count))
-
-        # removed: bone lookup table
-
-        # build a list of pose bones relevant to the collated udk_bones
-        # fixme: could be done once, prior to loop?
-        udk_pose_bones = []
-        for b in udk_bones:
-            for pb in armature.pose.bones:
-                if b.name == pb.name:
-                    udk_pose_bones.append(pb)
-                    break
-
-        # sort in the order the bones appear in the PSA file
-        ordered_bones = {}
-        ordered_bones = sorted([(psa.UseBone(b.name), b) for b in udk_pose_bones], key=operator.itemgetter(0))
-
-        # NOTE: posebone.bone references the obj/edit bone
-        # REMOVED: unique_bone_indexes is redundant?
-
-        # frame loop...
-        for i in range(frame_count):
-
-            frame = scene_range[i]
-
-            # verbose("FRAME {}".format(i), i) # test loop sampling
-
-            # advance to frame (automatically updates the pose)
-            context.scene.frame_set(frame)
-
-            # compute the key for each bone
-            for bone_data in ordered_bones:
-
-                bone_index = bone_data[0]
-                pose_bone = bone_data[1]
-                pose_bone_matrix = mathutils.Matrix(pose_bone.matrix)
-
-                if pose_bone.parent is not None:
-                    pose_bone_parent_matrix = mathutils.Matrix(pose_bone.parent.matrix)
-                    pose_bone_matrix = pose_bone_parent_matrix.inverted() * pose_bone_matrix
-
-                head = pose_bone_matrix.to_translation()
-                quat = pose_bone_matrix.to_quaternion().normalized()
-
-                if pose_bone.parent is not None:
-                    quat = make_fquat(quat)
-                else:
-                    quat = make_fquat_default(quat)
-
-                # scale animation position here?
-                if bpy.context.scene.udk_option_scale < 0 or bpy.context.scene.udk_option_scale > 1:
-                    head.x = head.x * bpy.context.scene.udk_option_scale
-                    head.y = head.y * bpy.context.scene.udk_option_scale
-                    head.z = head.z * bpy.context.scene.udk_option_scale
-
-                vkey = VQuatAnimKey()
-                vkey.Position.X = head.x
-                vkey.Position.Y = head.y
-                vkey.Position.Z = head.z
-                vkey.Orientation = quat
-
-                # frame delta = 1.0 / fps
-                vkey.Time = 1.0 / anim_rate  # according to C++ header this is "disregarded"
-
-                psa.AddRawKey(vkey)
-
-            # END for bone_data in ordered_bones
-
-            raw_frame_index += 1
-
-        # END for i in range(frame_count)
-
-        # REMOVED len(unique_bone_indexes)
-        anim.TotalBones = len(ordered_bones)
-        # frame_count/anim.AnimRate makes more sense, but this is what actually works in UDK
-        anim.TrackTime = float(frame_count)
-
-        verbose("anim.TotalBones={}, anim.TrackTime={}".format(anim.TotalBones, anim.TrackTime))
-
-        psa.AddAnimation(anim)
-
-    # END for action in actions
-
-    # restore
-    armature.animation_data.action = restoreAction
-    context.scene.frame_set(restoreFrame)
-
-
-# ===========================================================================
-# Collate actions to be exported
-# Modify this to filter for one, some or all actions. For now use all.
-# RETURNS list of actions
-# ===========================================================================
-def collate_actions():
-    verbose(header("collate_actions"))
-    actions_to_export = []
-
-    for action in bpy.data.actions:
-        if bpy.context.scene.udk_option_selectanimations:  # check if needed to select actions set for exporting it
-            print("Action Set is selected!")
-            bready = False
-            for actionlist in bpy.context.scene.udkas_list:  # list the action set from the list
-                if actionlist.name == action.name and actionlist.bmatch is True and actionlist.bexport is True:
-                    bready = True
-                    print("Added Action Set:", action.name)
-                    break
-            if bready is False:  # don't export it
-                print("Skipping Action Set:", action.name)
-                continue
-        verbose(" + {}".format(action.name))  # action set name
-        actions_to_export.append(action)  # add to the action array
-
-    return actions_to_export
-
-
-# ===========================================================================
-# Locate the target armature and mesh for export
-# RETURNS armature, mesh
-# ===========================================================================
-def find_armature_and_mesh():
-    verbose(header("find_armature_and_mesh", 'LEFT', '<', 60))
-
-    context = bpy.context
-    active_object = context.active_object
-    armature = None
-    mesh = None
-
-    # TODO:
-    # this could be more intuitive
-    # bpy.ops.object.mode_set(mode='OBJECT')
-
-    if bpy.context.scene.udk_option_selectobjects:  # if checked select object true do list object on export
-        print("select mode:")
-        if len(bpy.context.scene.udkArm_list) > 0:
-            print("Armature Name:", bpy.context.scene.udkArm_list[bpy.context.scene.udkArm_list_idx].name)
-            for obj in bpy.context.scene.objects:
-                if obj.name == bpy.context.scene.udkArm_list[bpy.context.scene.udkArm_list_idx].name:
-                    armature = obj
-                    break
-        else:
-            raise Error("There is no Armature in the list!")
-        meshselected = []
-        # parented_meshes = [obj for obj in armature.children if obj.type == 'MESH']
-        meshes = [obj for obj in bpy.context.scene.objects if obj.type == 'MESH']
-        for obj in meshes:
-            # print(dir(obj))
-            if obj.type == 'MESH':
-                bexportmesh = False
-                # print("PARENT MESH:",obj.name)
-                for udkmeshlist in bpy.context.scene.udkmesh_list:
-                    if obj.name == udkmeshlist.name and udkmeshlist.bexport is True:
-                        bexportmesh = True
-                        break
-                if bexportmesh is True:
-                    print("Mesh Name:", obj.name, " < SELECT TO EXPORT!")
-                    meshselected.append(obj)
-
-        print("MESH COUNT:", len(meshselected))
-        # try the active object
-        if active_object and active_object.type == 'MESH' and len(meshselected) == 0:
-            if active_object.parent == armature:
-                mesh = active_object
-            else:
-                raise Error("The selected mesh is not parented to the armature")
-
-        # otherwise, expect a single mesh parented to the armature (other object types are ignored)
-        else:
-            print("Number of meshes:", len(meshes))
-            print("Number of meshes (selected):", len(meshes))
-            if len(meshes) == 1:
-                mesh = meshes[0]
-
-            elif len(meshes) > 1:
-                if len(meshselected) >= 1:
-                    mesh = sortmesh(meshselected)
-                else:
-                    raise Error("More than one mesh(s) parented to armature. Select object(s)!")
-            else:
-                raise Error("No mesh parented to armature")
-    else:  # if not check for select function from the list work the code here
-        print("normal mode:")
-        # try the active object
-        if active_object and active_object.type == 'ARMATURE':
-            armature = active_object
-            bpy.ops.object.mode_set(mode='OBJECT')
-        # otherwise, try for a single armature in the scene
-        else:
-            # bpy.ops.object.mode_set(mode='OBJECT')
-            all_armatures = [obj for obj in bpy.context.scene.objects if obj.type == 'ARMATURE']
-
-            if len(all_armatures) == 1:  # if armature has one scene just assign it
-                armature = all_armatures[0]
-            elif len(all_armatures) > 1:  # if there more armature then find the select armature
-                barmselect = False
-                for _armobj in all_armatures:
-                    if _armobj.select_get():
-                        armature = _armobj
-                        barmselect = True
-                        break
-                if barmselect is False:
-                    raise Error("Please select an armatures in the scene")
-            else:
-                raise Error("No armatures in scene")
-
-        verbose("Found armature: {}".format(armature.name))
-
-        meshselected = []
-        parented_meshes = [obj for obj in armature.children if obj.type == 'MESH']
-
-        if len(armature.children) == 0:
-            raise Error("The selected Armature has no mesh parented to the Armature Object!")
-
-        for obj in armature.children:
-            # print(dir(obj))
-            if obj.type == 'MESH' and obj.select_get() is True:
-                meshselected.append(obj)
-        # try the active object
-        if active_object and active_object.type == 'MESH' and len(meshselected) == 0:
-            if active_object.parent == armature:
-                mesh = active_object
-            else:
-                raise Error("The selected mesh is not parented to the armature")
-
-        # otherwise, expect a single mesh parented to the armature (other object types are ignored)
-        else:
-            print("Number of meshes:", len(parented_meshes))
-            print("Number of meshes (selected):", len(meshselected))
-            if len(parented_meshes) == 1:
-                mesh = parented_meshes[0]
-
-            elif len(parented_meshes) > 1:
-                if len(meshselected) >= 1:
-                    mesh = sortmesh(meshselected)
-                else:
-                    raise Error("More than one mesh(s) parented to armature. Select object(s)!")
-            else:
-                raise Error("No mesh parented to armature")
-
-        verbose("Found mesh: {}".format(mesh.name))
-    if mesh is None or armature is None:
-        raise Error("Check Mesh and Armature are list!")
-
-    """
-    if len(armature.pose.bones) == len(mesh.vertex_groups):
-        print("Armature and Mesh Vertex Groups matches Ok!")
-    else:
-        raise Error("Armature bones:" + str(len(armature.pose.bones)) +
-                     " Mesh Vertex Groups:" + str(len(mesh.vertex_groups)) +" doesn't match!")
-    """
-    # this will check if object need to be rebuild
-    if bpy.context.scene.udk_option_rebuildobjects:
-        # print("INIT... REBUILDING...")
-        print("REBUILDING ARMATURE...")
-        # if deform mesh
-        # rebuild the armature to raw. If there IK constraint it will ignore it
-        armature = rebuildarmature(armature)
-        print("REBUILDING MESH...")
-        mesh = rebuildmesh(mesh)  # rebuild the mesh to raw data format.
-
-    return armature, mesh
-
-
-# ===========================================================================
-# Returns a list of vertex groups in the mesh. Can be modified to filter
-# groups as necessary.
-# UNUSED
-# ===========================================================================
-def collate_vertex_groups(mesh):
-    verbose("collate_vertex_groups")
-    groups = []
-
-    for group in mesh.vertex_groups:
-
-        groups.append(group)
-        verbose("  " + group.name)
-
-    return groups
-
-
-# ===========================================================================
-# Main
-# ===========================================================================
-def export(filepath):
-    print(header("Export", 'RIGHT'))
-    bpy.types.Scene.udk_copy_merge = False  # in case fail to export set this to default
-    t = time.clock()
-    context = bpy.context
-
-    print("Blender Version {}.{}.{}".format(bpy.app.version[0], bpy.app.version[1], bpy.app.version[2]))
-    print("Filepath: {}".format(filepath))
-
-    verbose("PSK={}, PSA={}".format(context.scene.udk_option_export_psk, context.scene.udk_option_export_psa))
-
-    # find armature and mesh
-    # [change this to implement alternative methods; raise Error() if not found]
-    udk_armature, udk_mesh = find_armature_and_mesh()
-
-    # check misc conditions
-    if not (udk_armature.scale.x == udk_armature.scale.y == udk_armature.scale.z == 1):
-        raise Error("bad armature scale: armature object should have uniform scale of 1 (ALT-S)")
-
-    if not (udk_mesh.scale.x == udk_mesh.scale.y == udk_mesh.scale.z == 1):
-        raise Error("bad mesh scale: mesh object should have uniform scale of 1 (ALT-S)")
-
-    if not (udk_armature.location.x == udk_armature.location.y == udk_armature.location.z == 0):
-        raise Error("bad armature location: armature should be located at origin (ALT-G)")
-
-    if not (udk_mesh.location.x == udk_mesh.location.y == udk_mesh.location.z == 0):
-        raise Error("bad mesh location: mesh should be located at origin (ALT-G)")
-
-    # prep
-    psk = PSKFile()
-    psa = PSAFile()
-
-    # step 1
-    parse_mesh(udk_mesh, psk)
-
-    # step 2
-    udk_bones = parse_armature(udk_armature, psk, psa)
-
-    # step 3
-    if context.scene.udk_option_export_psa is True:
-        actions = collate_actions()
-        parse_animation(udk_armature, udk_bones, actions, psa)
-
-    # write files
-    print(header("Exporting", 'CENTER'))
-
-    psk_filename = filepath + '.psk'
-    psa_filename = filepath + '.psa'
-
-    if context.scene.udk_option_export_psk is True:
-        print("Skeletal mesh data...")
-        psk.PrintOut()
-        file = open(psk_filename, "wb")
-        file.write(psk.dump())
-        file.close()
-        print("Exported: " + psk_filename)
-        print()
-
-    if context.scene.udk_option_export_psa is True:
-        print("Animation data...")
-        if not psa.IsEmpty():
-            psa.PrintOut()
-            file = open(psa_filename, "wb")
-            file.write(psa.dump())
-            file.close()
-            print("Exported: " + psa_filename)
-        else:
-            print("No Animation (.psa file) to export")
-
-        print()
-
-    # if objects are rebuild do the unlink
-    if bpy.context.scene.udk_option_rebuildobjects:
-        print("Unlinking Objects")
-        print("Armature Object Name:", udk_armature.name)  # display object name
-        bpy.context.collection.objects.unlink(udk_armature)     # remove armature from the collection
-        print("Mesh Object Name:", udk_mesh.name)          # display object name
-        bpy.context.collection.objects.unlink(udk_mesh)         # remove mesh from the collection
-
-    print("Export completed in {:.2f} seconds".format((time.clock() - t)))
-
-
-# ===========================================================================
-# Operator
-# ===========================================================================
-class Operator_UDKExport(Operator):
-    """Export to UDK"""
-    bl_idname = "object.udk_export"
-    bl_label = "Export now"
-
-    def execute(self, context):
-        print("\n" * 8)
-        scene = bpy.context.scene
-
-        scene.udk_option_export_psk = (scene.udk_option_export == '0' or scene.udk_option_export == '2')
-        scene.udk_option_export_psa = (scene.udk_option_export == '1' or scene.udk_option_export == '2')
-
-        filepath = get_dst_path()
-
-        # cache settings
-        restore_frame = scene.frame_current
-        message = "Object(s) exported to: {}".format(filepath)
-        try:
-            export(filepath)
-
-        except Error as err:
-            print(err.message)
-            message = err.message
-
-        # restore settings
-        scene.frame_set(restore_frame)
-
-        def draw(self, context):
-            self.layout.label(text="Export Finished")
-        try:
-            context.window_manager.popup_menu(draw, title=message, icon="INFO")
-        except:
-            pass
-
-        self.report({'INFO'}, message)
-
-        # restore settings
-        scene.frame_set(restore_frame)
-
-        return {'FINISHED'}
-
-
-# ===========================================================================
-# Operator
-# ===========================================================================
-class Operator_ToggleConsole(Operator):
-    """Show or hide the console"""
-    bl_idname = "object.toggle_console"
-    bl_label = "Toggle console"
-
-    def execute(self, context):
-        bpy.ops.wm.console_toggle()
-        return {'FINISHED'}
-
-
-# ===========================================================================
-# Get filepath for export
-# ===========================================================================
-def get_dst_path():
-    if bpy.context.scene.udk_option_filename_src == '0':
-        if bpy.context.active_object:
-            path = os.path.split(bpy.data.filepath)[0] + "\\" + bpy.context.active_object.name  # + ".psk"
-        else:
-            # path = os.path.split(bpy.data.filepath)[0] + "\\" + "Unknown";
-            path = os.path.splitext(bpy.data.filepath)[0]  # + ".psk"
-    else:
-        path = os.path.splitext(bpy.data.filepath)[0]  # + ".psk"
-    return path
-
-
-# ===========================================================================
-# User interface
-# ===========================================================================
-class OBJECT_OT_UTSelectedFaceSmooth(Operator):
-    """It will only select smooth faces that is select mesh"""
-    bl_idname = "object.utselectfacesmooth"  # XXX, name???
-    bl_label = "Select Smooth Faces"         # "Select Smooth faces"
-
-    def invoke(self, context, event):
-        print("----------------------------------------")
-        print("Init Select Face(s):")
-        bselected = False
-        for obj in bpy.data.objects:
-            if obj.type == 'MESH' and obj.select_get() is True:
-                smoothcount = 0
-                flatcount = 0
-                bpy.ops.object.mode_set(mode='OBJECT')  # it need to go into object mode to able to select the faces
-
-                for i in bpy.context.scene.objects:
-                    i.select_set(False)  # deselect all objects
-
-                obj.select_set(True)  # set current object select
-                bpy.context.view_layer.objects.active = obj  # set active object
-                mesh = bmesh.new()
-                mesh.from_mesh(obj.data)
-
-                for face in mesh.faces:
-                    face.select = False
-
-                for face in mesh.faces:
-                    if face.smooth is True:
-                        face.select = True
-                        smoothcount += 1
-                    else:
-                        flatcount += 1
-                        face.select = False
-                mesh.to_mesh(obj.data)
-                bpy.context.view_layer.update()
-                bpy.ops.object.mode_set(mode='EDIT')
-                print("Select Smooth Count(s):", smoothcount, " Flat Count(s):", flatcount)
-                bselected = True
-                break
-        if bselected:
-            self.report({'INFO'}, "Selected Face(s) Executed")
-        else:
-            self.report({'INFO'}, "Mesh Object is not selected")
-        print("----------------------------------------")
-
-        return{'FINISHED'}
-
-
-class OBJECT_OT_MeshClearWeights(Operator):
-    """Remove all mesh vertex groups weights for the bones"""
-    bl_idname = "object.meshclearweights"  # XXX, name???
-    bl_label = "Remove Vertex Weights"     # "Remove Mesh vertex weights"
-
-    def invoke(self, context, event):
-        for obj in bpy.data.objects:
-            if obj.type == 'MESH' and obj.select_get() is True:
-                for vg in obj.vertex_groups:
-                    obj.vertex_groups.remove(vg)
-                self.report({'INFO'}, "Mesh Vertex Groups Removed")
-                break
-        return{'FINISHED'}
-
-
-def unpack_list(list_of_tuples):
-    l = []
-    for t in list_of_tuples:
-        l.extend(t)
-    return l
-
-
-def rebuildmesh(obj):
-    # make sure it in object mode
-    print("Mesh Object Name:", obj.name)
-    bpy.ops.object.mode_set(mode='OBJECT')
-
-    for i in bpy.context.scene.objects:
-        i.select_set(False)  # deselect all objects
-    obj.select_set(True)
-    bpy.context.view_layer.objects.active = obj
-
-    me_ob = bpy.data.meshes.new(("Re_" + obj.name))
-    mesh = obj.data
-    faces = []
-    verts = []
-    smoothings = []
-    uvfaces = []
-    # print("creating array build mesh...")
-    depsgraph = bpy.context.evaluated_depsgraph_get()
-    obj_eval = obj.evaluated_get(depsgraph)
-    mmesh = obj_eval.to_mesh()
-    uv_layer = mmesh.tessface_uv_textures.active
-
-    for face in mmesh.tessfaces:
-        smoothings.append(face.use_smooth)  # smooth or flat in boolean
-        if uv_layer is not None:            # check if there texture data exist
-            faceUV = uv_layer.data[face.index]
-            uvs = []
-            for uv in faceUV.uv:
-                uvs.append((uv[0], uv[1]))
-            uvfaces.append(uvs)
-        # print((face.vertices[:]))
-        if len(face.vertices) == 3:
-            faces.extend([(face.vertices[0], face.vertices[1], face.vertices[2], 0)])
-        else:
-            faces.extend([(face.vertices[0], face.vertices[1], face.vertices[2], face.vertices[3])])
-
-    obj_eval.to_mesh_clear()
-
-    # vertex positions
-    for vertex in mesh.vertices:
-        verts.append(vertex.co.to_tuple())
-    # vertices weight groups into array
-    vertGroups = {}  # array in strings
-
-    for vgroup in obj.vertex_groups:
-        vlist = []
-        for v in mesh.vertices:
-            for vg in v.groups:
-                if vg.group == vgroup.index:
-                    vlist.append((v.index, vg.weight))
-                    # print((v.index,vg.weight))
-        vertGroups[vgroup.name] = vlist
-
-    # print("creating mesh object...")
-    # me_ob.from_pydata(verts, [], faces)
-    me_ob.vertices.add(len(verts))
-    me_ob.tessfaces.add(len(faces))
-    me_ob.vertices.foreach_set("co", unpack_list(verts))
-    me_ob.tessfaces.foreach_set("vertices_raw", unpack_list(faces))
-    me_ob.tessfaces.foreach_set("use_smooth", smoothings)  # smooth array from face
-
-    # check if there is uv faces
-    if len(uvfaces) > 0:
-        uvtex = me_ob.tessface_uv_textures.new(name="retex")
-        for i, face in enumerate(me_ob.tessfaces):
-            blender_tface = uvtex.data[i]  # face
-            mfaceuv = uvfaces[i]
-            if len(mfaceuv) == 3:
-                blender_tface.uv1 = mfaceuv[0]
-                blender_tface.uv2 = mfaceuv[1]
-                blender_tface.uv3 = mfaceuv[2]
-            if len(mfaceuv) == 4:
-                blender_tface.uv1 = mfaceuv[0]
-                blender_tface.uv2 = mfaceuv[1]
-                blender_tface.uv3 = mfaceuv[2]
-                blender_tface.uv4 = mfaceuv[3]
-
-    me_ob.update()  # need to update the information to able to see into the secne
-    obmesh = bpy.data.objects.new(("Re_" + obj.name), me_ob)
-    bpy.context.view_layer.update()
-
-    # Build tmp materials
-    materialname = "ReMaterial"
-    for matcount in mesh.materials:
-        matdata = bpy.data.materials.new(materialname)
-        me_ob.materials.append(matdata)
-
-    # assign face to material id
-    for face in mesh.tessfaces:
-        me_ob.faces[face.index].material_index = face.material_index
-
-    # vertices weight groups
-    for vgroup in vertGroups:
-        group = obmesh.vertex_groups.new(name=vgroup)
-        for v in vertGroups[vgroup]:
-            group.add([v[0]], v[1], 'ADD')  # group.add(array[vertex id],weight,add)
-    bpy.context.collection.objects.link(obmesh)
-    # print("Mesh Material Count:",len(me_ob.materials))
-    matcount = 0
-    # print("MATERIAL ID OREDER:")
-    for mat in me_ob.materials:
-        # print("-Material:",mat.name,"INDEX:",matcount)
-        matcount += 1
-
-    print("Mesh Object Name:", obmesh.name)
-    bpy.context.view_layer.update()
-
-    return obmesh
-
-
-class OBJECT_OT_UTRebuildMesh(Operator):
-    """It rebuild the mesh from scrape from the selected mesh object. """ \
-    """Note the scale will be 1:1 for object mode. To keep from deforming"""
-    bl_idname = "object.utrebuildmesh"  # XXX, name???
-    bl_label = "Rebuild Mesh"           # "Rebuild Mesh"
-
-    def invoke(self, context, event):
-        print("----------------------------------------")
-        print("Init Mesh Bebuild...")
-        bselected = False
-        bpy.ops.object.mode_set(mode='OBJECT')
-
-        for obj in bpy.data.objects:
-            if obj.type == 'MESH' and obj.select_get() is True:
-                rebuildmesh(obj)
-
-        self.report({'INFO'}, "Rebuild Mesh Finished!")
-        print("Finish Mesh Build...")
-        print("----------------------------------------")
-        return{'FINISHED'}
-
-
-def rebuildarmature(obj):
-    currentbone = []  # select armature for roll copy
-    print("Armature Name:", obj.name)
-    objectname = "ArmatureDataPSK"
-    meshname = "ArmatureObjectPSK"
-    armdata = bpy.data.armatures.new(objectname)
-    ob_new = bpy.data.objects.new(meshname, armdata)
-    bpy.context.collection.objects.link(ob_new)
-    # bpy.ops.object.mode_set(mode='OBJECT')
-
-    for i in bpy.context.scene.objects:
-        i.select_set(False)  # deselect all objects
-
-    ob_new.select_set(True)
-    bpy.context.view_layer.objects.active = obj
-
-    bpy.ops.object.mode_set(mode='EDIT')
-    for bone in obj.data.edit_bones:
-        if bone.parent is not None:
-            currentbone.append([bone.name, bone.roll])
-        else:
-            currentbone.append([bone.name, bone.roll])
-    bpy.ops.object.mode_set(mode='OBJECT')
-
-    for i in bpy.context.scene.objects:
-        i.select_set(False)  # deselect all objects
-
-    bpy.context.view_layer.objects.active = ob_new
-    bpy.ops.object.mode_set(mode='EDIT')
-
-    for bone in obj.data.bones:
-        bpy.ops.object.mode_set(mode='EDIT')
-        newbone = ob_new.data.edit_bones.new(bone.name)
-        newbone.head = bone.head_local
-        newbone.tail = bone.tail_local
-        for bonelist in currentbone:
-            if bone.name == bonelist[0]:
-                newbone.roll = bonelist[1]
-                break
-        if bone.parent is not None:
-            parentbone = ob_new.data.edit_bones[bone.parent.name]
-            newbone.parent = parentbone
-
-    ob_new.animation_data_create()      # create animation data
-    if obj.animation_data is not None:  # check for animation
-        # just make sure it here to do the animations if exist
-        ob_new.animation_data.action = obj.animation_data.action
-
-    print("Armature Object Name:", ob_new.name)
-    return ob_new
-
-
-class OBJECT_OT_UTRebuildArmature(Operator):
-    """If mesh is deform when importing to unreal engine try this. """ \
-    """It rebuild the bones one at the time by select one armature object scrape to raw setup build. """ \
-    """Note the scale will be 1:1 for object mode. To keep from deforming"""
-    bl_idname = "object.utrebuildarmature"  # XXX, name???
-    bl_label = "Rebuild Armature"           # Rebuild Armature
-
-    def invoke(self, context, event):
-        print("----------------------------------------")
-        print("Init Rebuild Armature...")
-        bselected = False
-        for obj in bpy.data.objects:
-            if obj.type == 'ARMATURE' and obj.select_get() is True:
-                rebuildarmature(obj)
-        self.report({'INFO'}, "Rebuild Armature Finish!")
-        print("End of Rebuild Armature.")
-        print("----------------------------------------")
-        return{'FINISHED'}
-
-
-class UDKActionSetListPG(PropertyGroup):
-    bool: BoolProperty(default=False)
-    string: StringProperty()
-    actionname: StringProperty()
-    bmatch: BoolProperty(
-            default=False,
-            name="Match",
-            options={"HIDDEN"},
-            description="This check against bone names and action group "
-                        "names matches and override boolean if true"
-            )
-    bexport: BoolProperty(
-            default=False,
-            name="Export",
-            description="Check this to export the animation"
-            )
-
-
-class UL_UDKActionSetList(UIList):
-    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
-        layout.label(item.name)
-        layout.prop(item, "bmatch", text="Match")
-        layout.prop(item, "bexport", text="Export")
-
-
-class UDKObjListPG(PropertyGroup):
-    bool: BoolProperty(default=False)
-    string: StringProperty()
-    bexport: BoolProperty(
-            default=False,
-            name="Export",
-            options={"HIDDEN"},
-            description="This will be ignore when exported"
-            )
-    bselect: BoolProperty(
-            default=False,
-            name="Select",
-            options={"HIDDEN"},
-            description="This will be ignore when exported"
-            )
-    otype: StringProperty(
-            name="Type",
-            description="This will be ignore when exported"
-            )
-
-
-class UL_UDKObjList(UIList):
-    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
-        layout.label(item.name)
-        layout.prop(item, "otype", text="")
-        layout.prop(item, "bselect", text="")
-
-
-class UDKMeshListPG(PropertyGroup):
-    bool: BoolProperty(
-            default=False
-            )
-    string: StringProperty()
-    bexport: BoolProperty(
-            default=False,
-            name="Export",
-            options={"HIDDEN"},
-            description="This object will be export when true"
-            )
-    bselect: BoolProperty(
-            default=False,
-            name="Select",
-            options={"HIDDEN"},
-            description="Make sure you have Mesh is parent to Armature"
-            )
-    otype: StringProperty(
-            name="Type",
-            description="This will be ignore when exported"
-            )
-
-
-class UL_UDKMeshList(UIList):
-    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
-        layout.label(item.name)
-        # layout.prop(item, "bselect", text="Select")
-        layout.prop(item, "bexport", text="Export")
-
-
-class UDKArmListPG(PropertyGroup):
-    bool: BoolProperty(default=False)
-    string: StringProperty()
-    bexport: BoolProperty(
-            default=False,
-            name="Export",
-            options={"HIDDEN"},
-            description="This will be ignore when exported"
-            )
-    bselect: BoolProperty(
-            default=False,
-            name="Select",
-            options={"HIDDEN"},
-            description="This will be ignore when exported"
-            )
-    otype: StringProperty(
-            name="Type",
-            description="This will be ignore when exported"
-            )
-
-
-class UL_UDKArmList(UIList):
-    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
-        layout.label(item.name)
-
-
-class Panel_UDKExport(Panel):
-    bl_label = "UDK Export"
-    bl_idname = "OBJECT_PT_udk_tools"
-    bl_category = "File I/O"
-    bl_space_type = "VIEW_3D"
-    bl_region_type = "TOOLS"
-    bl_context = "objectmode"
-
-    """
-    def draw_header(self, context):
-        layout = self.layout
-        obj = context.object
-        layout.prop(obj, "select", text="")
-
-    @classmethod
-    def poll(cls, context):
-        return context.active_object
-    """
-
-    def draw(self, context):
-        layout = self.layout
-        path = get_dst_path()
-
-        object_name = ""
-        """
-        if context.object:
-            object_name = context.object.name
-        """
-        if context.active_object:
-            object_name = context.active_object.name
-        row10 = layout.row()
-        row10.prop(context.scene, "udk_option_smoothing_groups")
-        row10.prop(context.scene, "udk_option_clight_uv")
-        row10.prop(context.scene, "udk_option_verbose")
-
-        row = layout.row()
-        row.label(text="Active object: " + object_name)
-        layout.prop(context.scene, "udk_option_filename_src")
-        row = layout.row()
-        row.label(text=path)
-
-        layout.prop(context.scene, "udk_option_export")
-        layout.prop(context.scene, "udk_option_selectobjects")
-
-        if context.scene.udk_option_selectobjects:
-            layout.operator("object.selobjectpdate")
-            layout.label(text="ARMATURE - Index")
-            layout.template_list("UL_UDKArmList", "udk_armatures", context.scene, "udkArm_list",
-                                 context.scene, "udkArm_list_idx", rows=3)
-            layout.label(text="MESH - Export")
-            layout.template_list("UL_UDKMeshList", "", context.scene, "udkmesh_list",
-                                 context.scene, "udkmesh_list_idx", rows=5)
-        layout.prop(context.scene, "udk_option_selectanimations")
-
-        if context.scene.udk_option_selectanimations:
-            layout.operator("action.setanimupdate")
-            layout.label(text="Action Set(s) - Match / Export")
-            layout.template_list("UL_UDKActionSetList", "", context.scene, "udkas_list",
-                                 context.scene, "udkas_list_idx", rows=5)
-        layout.separator()
-        layout.prop(context.scene, "udk_option_scale")
-        layout.prop(context.scene, "udk_option_rebuildobjects")
-        # layout.prop(context.scene, "udk_option_ignoreactiongroupnames")
-
-        row11 = layout.row()
-        row11.operator("object.udk_export")
-        row11.operator("object.toggle_console")
-        layout.operator(OBJECT_OT_UTRebuildArmature.bl_idname)
-        layout.label(text="Mesh")
-        layout.operator(OBJECT_OT_MeshClearWeights.bl_idname)
-        layout.operator(OBJECT_OT_UTSelectedFaceSmooth.bl_idname)
-        layout.operator(OBJECT_OT_UTRebuildMesh.bl_idname)
-        layout.operator(OBJECT_OT_UDKCheckMeshLines.bl_idname)
-
-
-def udkupdateobjects():
-    my_objlist = bpy.context.scene.udkArm_list
-    objectl = []
-    for objarm in bpy.context.scene.objects:  # list and filter only mesh and armature
-        if objarm.type == 'ARMATURE':
-            objectl.append(objarm)
-
-    for _objd in objectl:  # check if list has in udk list
-        bfound_obj = False
-        for _obj in my_objlist:
-            if _obj.name == _objd.name and _obj.otype == _objd.type:
-                _obj.bselect = _objd.select
-                bfound_obj = True
-                break
-
-        if bfound_obj is False:
-            # print("ADD ARMATURE...")
-            my_item = my_objlist.add()
-            my_item.name = _objd.name
-            my_item.bselect = _objd.select
-            my_item.otype = _objd.type
-    removeobject = []
-    for _udkobj in my_objlist:
-        bfound_objv = False
-
-        for _objd in bpy.context.scene.objects:  # check if there no existing object from sense to remove it
-            if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
-                bfound_objv = True
-                break
-
-        if bfound_objv is False:
-            removeobject.append(_udkobj)
-    # print("remove check...")
-    for _item in removeobject:  # loop remove object from udk list object
-        count = 0
-        for _obj in my_objlist:
-            if _obj.name == _item.name and _obj.otype == _item.otype:
-                my_objlist.remove(count)
-                break
-            count += 1
-
-    my_objlist = bpy.context.scene.udkmesh_list
-    objectl = []
-    for objarm in bpy.context.scene.objects:  # list and filter only mesh and armature
-        if objarm.type == 'MESH':
-            objectl.append(objarm)
-    for _objd in objectl:  # check if list has in udk list
-        bfound_obj = False
-        for _obj in my_objlist:
-            if _obj.name == _objd.name and _obj.otype == _objd.type:
-                _obj.bselect = _objd.select
-                bfound_obj = True
-                break
-        if bfound_obj is False:
-            my_item = my_objlist.add()
-            my_item.name = _objd.name
-            my_item.bselect = _objd.select
-            my_item.otype = _objd.type
-    removeobject = []
-    for _udkobj in my_objlist:
-        bfound_objv = False
-        for _objd in bpy.context.scene.objects:  # check if there no existing object from sense to remove it
-            if _udkobj.name == _objd.name and _udkobj.otype == _objd.type:
-                bfound_objv = True
-                break
-        if bfound_objv is False:
-            removeobject.append(_udkobj)
-    # print("remove check...")
-    for _item in removeobject:  # loop remove object from udk list object
-        count = 0
-        for _obj in my_objlist:
-            if _obj.name == _item.name and _obj.otype == _item.otype:
-                my_objlist.remove(count)
-                break
-            count += 1
-
-
-class OBJECT_OT_UDKObjUpdate(Operator):
-    """This will update the filter of the mesh and armature"""
-    bl_idname = "object.selobjectpdate"
-    bl_label = "Update Object(s)"
-
-    actionname: bpy.props.StringProperty()
-
-    def execute(self, context):
-        udkupdateobjects()
-        return{'FINISHED'}
-
-
-def udkcheckmeshline():
-    objmesh = None