addons contrib: bulk remove unmaintained i/o part 2
authormeta-androcto <meta.androcto1@gmail.com>
Sat, 14 Sep 2019 02:46:15 +0000 (12:46 +1000)
committermeta-androcto <meta.androcto1@gmail.com>
Sat, 14 Sep 2019 02:46:15 +0000 (12:46 +1000)
21 files changed:
io_export_marmalade.py [deleted file]
io_export_md3.py [deleted file]
io_import_lipSync_Importer.py [deleted file]
io_mesh_raw/__init__.py [deleted file]
io_mesh_raw/export_raw.py [deleted file]
io_mesh_raw/import_raw.py [deleted file]
io_points_pcd/__init__.py [deleted file]
io_points_pcd/pcd_utils.py [deleted file]
io_points_pcd/pcdparser.py [deleted file]
io_points_pcd/test.pcd [deleted file]
io_scene_map/__init__.py [deleted file]
io_scene_map/export_map.py [deleted file]
io_scene_ms3d/__init__.py [deleted file]
io_scene_ms3d/ms3d_export.py [deleted file]
io_scene_ms3d/ms3d_import.py [deleted file]
io_scene_ms3d/ms3d_spec.py [deleted file]
io_scene_ms3d/ms3d_strings.py [deleted file]
io_scene_ms3d/ms3d_ui.py [deleted file]
io_scene_ms3d/ms3d_utils.py [deleted file]
io_scene_vrml2/__init__.py [deleted file]
io_scene_vrml2/export_vrml2.py [deleted file]

diff --git a/io_export_marmalade.py b/io_export_marmalade.py
deleted file mode 100644 (file)
index 311e200..0000000
+++ /dev/null
@@ -1,1473 +0,0 @@
-# ***** 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.
-# ***** GPL LICENSE BLOCK *****
-
-# Marmalade SDK is not responsible in any case of the following code.
-# This Blender add-on is freely shared for the Blender and Marmalade user communities.
-
-
-bl_info = {
-    "name": "Marmalade Cross-platform Apps (.group)",
-    "author": "Benoit Muller",
-    "version": (0, 6, 2),
-    "blender": (2, 63, 0),
-    "location": "File > Export > Marmalade cross-platform Apps (.group)",
-    "description": "Export Marmalade Format files (.group)",
-    "warning": "",
-    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
-        "Scripts/Import-Export/Marmalade_Exporter",
-    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
-    "category": "Import-Export"}
-
-import os
-import shutil
-from math import radians
-
-import bpy
-from mathutils import Matrix
-
-import mathutils
-import math
-
-import datetime
-
-import subprocess
-
-
-#Container for the exporter settings
-class MarmaladeExporterSettings:
-
-    def __init__(self,
-                 context,
-                 FilePath,
-                 CoordinateSystem=1,
-                 FlipNormals=False,
-                 ApplyModifiers=False,
-                 Scale=100,
-                 AnimFPS=30,
-                 ExportVertexColors=True,
-                 ExportMaterialColors=True,
-                 ExportTextures=True,
-                 CopyTextureFiles=True,
-                 ExportArmatures=False,
-                 ExportAnimationFrames=0,
-                 ExportAnimationActions=0,
-                 ExportMode=1,
-                 MergeModes=0,
-                 Verbose=False):
-        self.context = context
-        self.FilePath = FilePath
-        self.CoordinateSystem = int(CoordinateSystem)
-        self.FlipNormals = FlipNormals
-        self.ApplyModifiers = ApplyModifiers
-        self.Scale = Scale
-        self.AnimFPS = AnimFPS
-        self.ExportVertexColors = ExportVertexColors
-        self.ExportMaterialColors = ExportMaterialColors
-        self.ExportTextures = ExportTextures
-        self.CopyTextureFiles = CopyTextureFiles
-        self.ExportArmatures = ExportArmatures
-        self.ExportAnimationFrames = int(ExportAnimationFrames)
-        self.ExportAnimationActions = int(ExportAnimationActions)
-        self.ExportMode = int(ExportMode)
-        self.MergeModes = int(MergeModes)
-        self.Verbose = Verbose
-        self.WarningList = []
-
-
-def ExportMadeWithMarmaladeGroup(Config):
-    print("----------\nExporting to {}".format(Config.FilePath))
-    if Config.Verbose:
-        print("Opening File...")
-    Config.File = open(Config.FilePath, "w")
-
-    if Config.Verbose:
-        print("Done")
-
-    if Config.Verbose:
-        print("writing group header")
-
-    Config.File.write('// Marmalade group file exported from : %s\n' % bpy.data.filepath)
-    Config.File.write('// Exported %s\n' % str(datetime.datetime.now()))
-    Config.File.write("CIwResGroup\n{\n\tname \"%s\"\n" % bpy.path.display_name_from_filepath(Config.FilePath))
-
-    if Config.Verbose:
-        print("Generating Object list for export... (Root parents only)")
-    if Config.ExportMode == 1:
-        Config.ExportList = [Object for Object in Config.context.scene.objects
-                             if Object.type in {'ARMATURE', 'EMPTY', 'MESH'}
-                             and Object.parent is None]
-    else:
-        ExportList = [Object for Object in Config.context.selected_objects
-                      if Object.type in {'ARMATURE', 'EMPTY', 'MESH'}]
-        Config.ExportList = [Object for Object in ExportList
-                             if Object.parent not in ExportList]
-    if Config.Verbose:
-        print("  List: {}\nDone".format(Config.ExportList))
-
-    if Config.Verbose:
-        print("Setting up...")
-
-    if Config.ExportAnimationFrames:
-        if Config.Verbose:
-            print(bpy.context.scene)
-            print(bpy.context.scene.frame_current)
-        CurrentFrame = bpy.context.scene.frame_current
-    if Config.Verbose:
-        print("Done")
-
-    Config.ObjectList = []
-    if Config.Verbose:
-        print("Writing Objects...")
-    WriteObjects(Config, Config.ExportList)
-    if Config.Verbose:
-        print("Done")
-
-    if Config.Verbose:
-        print("Objects Exported: {}".format(Config.ExportList))
-
-    if Config.ExportAnimationFrames:
-        if Config.Verbose:
-            print("Writing Animation...")
-        WriteKeyedAnimationSet(Config, bpy.context.scene)
-        bpy.context.scene.frame_current = CurrentFrame
-        if Config.Verbose:
-            print("Done")
-    Config.File.write("}\n")
-    CloseFile(Config)
-    print("Finished")
-
-
-def GetObjectChildren(Parent):
-    return [Object for Object in Parent.children
-            if Object.type in {'ARMATURE', 'EMPTY', 'MESH'}]
-
-
-#Returns the file path of first image texture from Material.
-def GetMaterialTextureFullPath(Config, Material):
-    if Material:
-        #Create a list of Textures that have type "IMAGE"
-        ImageTextures = [Material.texture_slots[TextureSlot].texture for TextureSlot in Material.texture_slots.keys() if Material.texture_slots[TextureSlot].texture.type == "IMAGE"]
-        #Refine a new list with only image textures that have a file source
-        TexImages = [Texture.image for Texture in ImageTextures if getattr(Texture.image, "source", "") == "FILE"]
-        ImageFiles = [Texture.image.filepath for Texture in ImageTextures if getattr(Texture.image, "source", "") == "FILE"]
-        if TexImages:
-            filepath = TexImages[0].filepath
-            if TexImages[0].packed_file:
-                TexImages[0].unpack()
-            if not os.path.exists(filepath):
-                #try relative path to the blend file
-                filepath = os.path.dirname(bpy.data.filepath) + filepath
-            #Marmalade doesn't like jpeg/tif so try to convert in png on the fly
-            if (TexImages[0].file_format == 'JPEG' or TexImages[0].file_format == 'TIFF') and os.path.exists(filepath):
-                marmaladeConvert = os.path.expandvars("%S3E_DIR%\\..\\tools\\ImageMagick\\win32\\convert.exe")
-                if (os.path.exists(marmaladeConvert)):
-                    srcImagefilepath = filepath
-                    filepath = os.path.splitext(filepath)[0] + '.png'
-                    if Config.Verbose:
-                        print("  /!\\ Converting Texture %s in PNG: %s{}..." % (TexImages[0].file_format, filepath))
-                        print('"%s" "%s" "%s"' % (marmaladeConvert, srcImagefilepath, filepath))
-                    subprocess.call([marmaladeConvert, srcImagefilepath, filepath])
-            return filepath
-    return None
-
-
-def WriteObjects(Config, ObjectList, geoFile=None, mtlFile=None, GeoModel=None,  bChildObjects=False):
-    Config.ObjectList += ObjectList
-
-    if bChildObjects == False and Config.MergeModes > 0:
-        if geoFile == None:
-            #we merge objects, so use name of group file for the name of Geo
-            geoFile, mtlFile = CreateGeoMtlFiles(Config, bpy.path.display_name_from_filepath(Config.FilePath))
-            GeoModel = CGeoModel(bpy.path.display_name_from_filepath(Config.FilePath))
-
-    for Object in ObjectList:
-        if Config.Verbose:
-            print("  Writing Object: {}...".format(Object.name))
-
-        if Config.ExportArmatures and Object.type == "ARMATURE":
-            Armature = Object.data
-            ParentList = [Bone for Bone in Armature.bones if Bone.parent is None]
-            if Config.Verbose:
-                print("    Writing Armature Bones...")
-            #Create the skel file
-            skelfullname = os.path.dirname(Config.FilePath) + os.sep + "models" + os.sep + "%s.skel" % (StripName(Object.name))
-            ensure_dir(skelfullname)
-            if Config.Verbose:
-                print("      Creating skel file %s" % (skelfullname))
-
-            skelFile = open(skelfullname, "w")
-            skelFile.write('// skel file exported from : %r\n' % os.path.basename(bpy.data.filepath))
-            skelFile.write("CIwAnimSkel\n")
-            skelFile.write("{\n")
-            skelFile.write("\tnumBones %d\n" % (len(Armature.bones)))
-            Config.File.write("\t\".\models\%s.skel\"\n" % (StripName(Object.name)))
-
-            WriteArmatureParentRootBones(Config, Object, ParentList, skelFile)
-
-            skelFile.write("}\n")
-            skelFile.close()
-            if Config.Verbose:
-                print("    Done")
-
-        ChildList = GetObjectChildren(Object)
-        if Config.ExportMode == 2:  # Selected Objects Only
-            ChildList = [Child for Child in ChildList
-                         if Child in Config.context.selected_objects]
-        if Config.Verbose:
-            print("    Writing Children...")
-        WriteObjects(Config, ChildList, geoFile, mtlFile, GeoModel, True)
-        if Config.Verbose:
-            print("    Done Writing Children")
-
-        if Object.type == "MESH":
-            if Config.Verbose:
-                print("    Generating Mesh...")
-            if Config.ApplyModifiers:
-                if Config.ExportArmatures:
-                    #Create a copy of the object and remove all armature modifiers so an unshaped
-                    #mesh can be created from it.
-                    Object2 = Object.copy()
-                    for Modifier in [Modifier for Modifier in Object2.modifiers if Modifier.type == "ARMATURE"]:
-                        Object2.modifiers.remove(Modifier)
-                    Mesh = Object2.to_mesh(bpy.context.scene, True, "PREVIEW")
-                else:
-                    Mesh = Object.to_mesh(bpy.context.scene, True, "PREVIEW")
-            else:
-                Mesh = Object.to_mesh(bpy.context.scene, False, "PREVIEW")
-            if Config.Verbose:
-                print("    Done")
-                print("    Writing Mesh...")
-
-            # Flip ZY axis (Blender Z up: Marmalade: Y up) ans Scale appropriately
-            X_ROT = mathutils.Matrix.Rotation(-math.pi / 2, 4, 'X')
-
-            if Config.MergeModes == 0:
-                # No merge, so all objects are exported in MODEL SPACE and not in world space
-                # Calculate Scale of the Export
-                meshScale = Object.matrix_world.to_scale()  # Export is working, even if user doesn't have use apply scale in Edit mode.
-
-                scalematrix = Matrix()
-                scalematrix[0][0] = meshScale.x * Config.Scale
-                scalematrix[1][1] = meshScale.y * Config.Scale
-                scalematrix[2][2] = meshScale.z * Config.Scale
-
-                meshRot = Object.matrix_world.to_quaternion()  # Export is working, even if user doesn't have use apply Rotation in Edit mode.
-                Mesh.transform(X_ROT * meshRot.to_matrix().to_4x4() * scalematrix)
-            else:
-                # In Merge mode, we need to keep relative postion of each objects, so we export in WORLD SPACE
-                SCALE_MAT = mathutils.Matrix.Scale(Config.Scale, 4)
-                Mesh.transform(SCALE_MAT * X_ROT * Object.matrix_world)
-
-             # manage merge options
-
-            if Config.MergeModes == 0:
-                #one geo per Object, so use name of Object for the Geo file
-                geoFile, mtlFile = CreateGeoMtlFiles(Config, StripName(Object.name))
-                GeoModel = CGeoModel(StripName(Object.name))
-
-            # Write the Mesh in the Geo file
-            WriteMesh(Config, Object, Mesh, geoFile, mtlFile, GeoModel)
-
-            if Config.MergeModes == 0:
-                # no merge so finalize the file, and discard the file and geo class
-                FinalizeGeoMtlFiles(Config, geoFile, mtlFile)
-                geoFile = None
-                mtlFile = None
-                GeoModel = None
-            elif Config.MergeModes == 1:
-                # merge in one Mesh, so keep the Geo class and prepare to change object
-                GeoModel.NewObject()
-            elif Config.MergeModes == 2:
-                # merge several Meshes in one file: so clear the mesh data that we just written in the file,
-                # but keep Materials info that need to be merged across objects
-                GeoModel.ClearAllExceptMaterials()
-
-            if Config.Verbose:
-                print("    Done")
-
-            if Config.ApplyModifiers and Config.ExportArmatures:
-                bpy.data.objects.remove(Object2)
-            bpy.data.meshes.remove(Mesh)
-
-        if Config.Verbose:
-            print("  Done Writing Object: {}".format(Object.name))
-
-    if bChildObjects == False:
-        # we have finish to do all objects
-        if GeoModel:
-            if Config.MergeModes == 1:
-                # we have Merges all objects in one Mesh, so time to write this big mesh in the file
-                GeoModel.PrintGeoMesh(geoFile)
-                # time to write skinfile if any
-                if len(GeoModel.useBonesDict) > 0:
-                    # some mesh was not modified by the armature. so we must skinned the merged mesh.
-                    # So unskinned vertices from unarmatured meshes, are assigned to the root bone of the armature
-                    for i in range(0, len(GeoModel.vList)):
-                        if not i in GeoModel.skinnedVertices:
-                            GeoModel.skinnedVertices.append(i)
-                            useBonesKey = pow(2, GeoModel.armatureRootBoneIndex)
-                            vertexGroupIndices = list((GeoModel.armatureRootBoneIndex,))
-                            if useBonesKey not in GeoModel.useBonesDict:
-                                GeoModel.mapVertexGroupNames[GeoModel.armatureRootBoneIndex] = StripBoneName(GeoModel.armatureRootBone.name)
-                                VertexList = []
-                                VertexList.append("\t\tvertWeights { %d, 1.0}" % i)
-                                GeoModel.useBonesDict[useBonesKey] = (vertexGroupIndices, VertexList)
-                            else:
-                                pair_ListGroupIndices_ListAssignedVertices = GeoModel.useBonesDict[useBonesKey]
-                                pair_ListGroupIndices_ListAssignedVertices[1].append("\t\tvertWeights { %d, 1.0}" % i)
-                                GeoModel.useBonesDict[useBonesKey] = pair_ListGroupIndices_ListAssignedVertices
-                    # now generates the skin file
-                    PrintSkinWeights(Config, GeoModel.armatureObjectName, GeoModel.useBonesDict, GeoModel.mapVertexGroupNames, GeoModel.name)
-            if Config.MergeModes > 0:
-                WriteMeshMaterialsForGeoModel(Config, mtlFile, GeoModel)
-                FinalizeGeoMtlFiles(Config, geoFile, mtlFile)
-        geoFile = None
-        mtlFile = None
-        GeoModel = None
-
-
-def CreateGeoMtlFiles(Config, Name):
-    #Create the geo file
-    geofullname = os.path.dirname(Config.FilePath) + os.sep + "models" + os.sep + "%s.geo" % Name
-    ensure_dir(geofullname)
-    if Config.Verbose:
-        print("      Creating geo file %s" % (geofullname))
-    geoFile = open(geofullname, "w")
-    geoFile.write('// geo file exported from : %r\n' % os.path.basename(bpy.data.filepath))
-    geoFile.write("CIwModel\n")
-    geoFile.write("{\n")
-    geoFile.write("\tname \"%s\"\n" % Name)
-    # add it to the group
-    Config.File.write("\t\".\models\%s.geo\"\n" % Name)
-
-    # Create the mtl file
-    mtlfullname = os.path.dirname(Config.FilePath) + os.sep + "models" + os.sep + "%s.mtl" % Name
-    ensure_dir(mtlfullname)
-    if Config.Verbose:
-        print("      Creating mtl file %s" % (mtlfullname))
-    mtlFile = open(mtlfullname, "w")
-    mtlFile.write('// mtl file exported from : %r\n' % os.path.basename(bpy.data.filepath))
-    return geoFile, mtlFile
-
-
-def FinalizeGeoMtlFiles(Config, geoFile, mtlFile):
-    if Config.Verbose:
-        print("      Closing geo file")
-    geoFile.write("}\n")
-    geoFile.close()
-    if Config.Verbose:
-        print("      Closing mtl file")
-    mtlFile.close()
-
-
-def WriteMesh(Config, Object, Mesh,  geoFile=None, mtlFile=None, GeoModel=None):
-    if geoFile == None or mtlFile == None:
-        print (" ERROR not geo file arguments in WriteMesh method")
-        return
-
-    if GeoModel == None:
-        print (" ERROR not GeoModel arguments in WriteMesh method")
-        return
-
-    BuildOptimizedGeo(Config, Object, Mesh, GeoModel)
-    if Config.MergeModes == 0 or Config.MergeModes == 2:
-        #if we don't merge, or if we write several meshes into one file ... write the mesh everytime we do an object
-        GeoModel.PrintGeoMesh(geoFile)
-
-    if Config.Verbose:
-        print("      Done\n      Writing Mesh Materials...")
-
-    if Config.MergeModes == 0:
-        #No merge, so we can diretly write the Mtl file associated to this object
-        WriteMeshMaterialsForGeoModel(Config, mtlFile, GeoModel)
-
-    if Config.Verbose:
-        print("      Done")
-
-    if Config.ExportArmatures:
-        if Config.Verbose:
-            print("      Writing Mesh Weights...")
-        WriteMeshSkinWeightsForGeoModel(Config, Object, Mesh, GeoModel)
-        if Config.Verbose:
-            print("      Done")
-
-
-###### optimized version fo Export, can be used also to merge several object in one single geo File ######
-
-# CGeoModel
-#  -> List Vertices
-#  -> List Normales
-#  -> List uv 0
-#  -> List uv 1
-#  -> List Vertex Colors
-#  -> List Materials
-#       -> Material name
-#       -> Blender Material Object
-#       -> List Tris -> Stream Indices v,vn,uv0,uv1,vc
-#       -> List Quads -> Stream Indices v,vn,uv0,uv1,vc
-
-
-#############
-#Store one Point of a Quad or Tri in marmalade geo format: //index-list is: { <int> <int> <int> <int> <int> }   //v,vn,uv0,uv1,vc
-#############
-class CGeoIndexList:
-    __slots__ = "v", "vn", "uv0", "uv1", "vc"
-
-    def __init__(self, v, vn, uv0, uv1, vc):
-        self.v = v
-        self.vn = vn
-        self.uv0 = uv0
-        self.uv1 = uv1
-        self.vc = vc
-
-
-#############
-#Store a Quad or a Tri in marmalade geo format : 3 or 4 CIndexList depending it is a Tri or a Quad
-#############
-class CGeoPoly:
-    __slots__ = "pointsList",
-
-    def __init__(self):
-        self.pointsList = []
-
-    def AddPoint(self, v, vn, uv0, uv1, vc):
-        self.pointsList.append( CGeoIndexList(v, vn, uv0, uv1, vc))
-
-    def PointsCount(self):
-        return len(self.pointsList)
-
-    def PrintPoly(self, geoFile):
-        if len(self.pointsList) == 3:
-            geoFile.write("\t\t\t\tt ")
-        if len(self.pointsList) == 4:
-            geoFile.write("\t\t\t\tq ")
-        for point in self.pointsList:
-            geoFile.write(" {%d, %d, %d, %d, %d}" % (point.v, point.vn, point.uv0, point.uv1, point.vc))
-        geoFile.write("\n")
-
-
-#############
-#Store all the poly (tri or quad) assigned to a Material in marmalade geo format
-#############
-class CGeoMaterialPolys:
-    __slots__ = "name", "material", "quadList", "triList", "currentPoly"
-
-    def __init__(self, name, material=None):
-        self.name = name
-        self.material = material
-        self.quadList = []
-        self.triList = []
-        self.currentPoly = None
-
-    def BeginPoly(self):
-        self.currentPoly = CGeoPoly()
-
-    def AddPoint(self, v, vn, uv0, uv1, vc):
-        self.currentPoly.AddPoint(v, vn, uv0, uv1, vc)
-
-    def EndPoly(self):
-        if (self.currentPoly.PointsCount() == 3):
-            self.triList.append(self.currentPoly)
-        if (self.currentPoly.PointsCount() == 4):
-            self.quadList.append(self.currentPoly)
-        self.currentPoly = None
-
-    def ClearPolys(self):
-        self.quadList = []
-        self.triList = []
-        self.currentPoly = None
-
-    def PrintMaterialPolys(self, geoFile):
-        geoFile.write("\t\tCSurface\n")
-        geoFile.write("\t\t{\n")
-        geoFile.write("\t\t\tmaterial \"%s\"\n" % self.name)
-        if self.triList:
-            geoFile.write("\t\t\tCTris\n")
-            geoFile.write("\t\t\t{\n")
-            geoFile.write("\t\t\t\tnumTris %d\n" % (len(self.triList)))
-            for poly in self.triList:
-                poly.PrintPoly(geoFile)
-            geoFile.write("\t\t\t}\n")
-
-        if self.quadList:
-            geoFile.write("\t\t\tCQuads\n")
-            geoFile.write("\t\t\t{\n")
-            geoFile.write("\t\t\t\tnumQuads %d\n" % (len(self.quadList)))
-            for poly in self.quadList:
-                poly.PrintPoly(geoFile)
-            geoFile.write("\t\t\t}\n")
-        geoFile.write("\t\t}\n")
-
-
-#############
-#Store all the information on a Model/Mesh (vertices, normal, certcies color, uv0, uv1, TRI, QUAD) in marmalade geo format
-#############
-class CGeoModel:
-    __slots__ = ("name", "MaterialsDict", "vList", "vnList", "vcList", "uv0List", "uv1List",
-                "currentMaterialPolys", "vbaseIndex","vnbaseIndex", "uv0baseIndex", "uv1baseIndex",
-                "armatureObjectName", "useBonesDict", "mapVertexGroupNames", "armatureRootBone", "armatureRootBoneIndex", "skinnedVertices")
-
-    def __init__(self, name):
-        self.name = name
-        self.MaterialsDict = {}
-        self.vList = []
-        self.vnList = []
-        self.vcList = []
-        self.uv0List = []
-        self.uv1List = []
-        self.currentMaterialPolys = None
-        #used xx baseIndex are used when merging several blender objects into one Mesh in the geo file (internal offset)
-        self.vbaseIndex = 0
-        self.vnbaseIndex = 0
-        self.uv0baseIndex = 0
-        self.uv1baseIndex = 0
-
-        # Store some information for skin management , when we merge several object in one big mesh (MergeModes 1)
-        # can only work if in the object list only one is rigged with an armature... and if it is located in 0,0,0
-        self.armatureObjectName = ""
-        #useBonesKey : bit field, where each bit is a VertexGroup.Index): Sum(2^VertGroupIndex).
-        #useBonesDict[useBonesKey] = tuple(VertexGroups.group, list(Vertex))
-        self.useBonesDict = {}
-        self.mapVertexGroupNames = {}
-        self.armatureRootBone = None
-        self.armatureRootBoneIndex = 0
-        self.skinnedVertices = []
-
-
-
-    def AddVertex(self, vertex):
-        self.vList.append(vertex.copy())
-
-    def AddVertexNormal(self, vertexN):
-        self.vnList.append(vertexN.copy())
-
-    # add a uv coordiantes and return the current Index in the stream (index is local to the object, when we merge several object into a one Mesh)
-    def AddVertexUV0(self, u, v):
-        self.uv0List.append((u, v))
-        return len(self.uv0List) - 1 - self.uv0baseIndex
-
-    def AddVertexUV1(self, u, v):
-        self.uv1List.append((u, v))
-        return len(self.uv1List) - 1 - self.uv1baseIndex
-
-    # add a vertexcolor if it doesn't already exist and return the current Index in the stream (index is global to all objects, when we merge several object into a one Mesh)
-    def AddVertexColor(self, r, g, b, a):
-        for i in range(0, len(self.vcList)):
-            col = self.vcList[i]
-            if col[0] == r and col[1] == g and col[2] == b and col[3] == a:
-                return i
-
-        self.vcList.append((r, g, b, a))
-        return len(self.vcList)-1
-
-    def BeginPoly(self, MaterialName, material=None):
-        if MaterialName not in self.MaterialsDict:
-            self.currentMaterialPolys = CGeoMaterialPolys(MaterialName, material)
-        else:
-            self.currentMaterialPolys = self.MaterialsDict[MaterialName]
-        self.currentMaterialPolys.BeginPoly()
-
-    def AddPoint(self, v, vn, uv0, uv1, vc):
-        if v != -1:
-            v += self.vbaseIndex
-        if vn != -1:
-            vn += self.vnbaseIndex
-        if uv0 != -1:
-            uv0 += self.uv0baseIndex
-        if uv1 != -1:
-            uv1 += self.uv1baseIndex
-
-        self.currentMaterialPolys.AddPoint(v, vn, uv0, uv1, vc)
-
-    def EndPoly(self):
-        self.currentMaterialPolys.EndPoly()
-        self.MaterialsDict[self.currentMaterialPolys.name] = self.currentMaterialPolys
-        self.currentMaterialPolys = None
-
-    def NewObject(self):
-        #used in Merge mode 1: allows to merge several blender objects into one Mesh.
-        self.vbaseIndex = len(self.vList)
-        self.vnbaseIndex = len(self.vnList)
-        self.uv0baseIndex = len(self.uv0List)
-        self.uv1baseIndex = len(self.uv1List)
-
-    def ClearAllExceptMaterials(self):
-        #used in Merge mode 2: one geo with several mesh
-        self.vList = []
-        self.vnList = []
-        self.vcList = []
-        self.uv0List = []
-        self.uv1List = []
-        self.currentMaterialPolys = None
-        self.vbaseIndex = 0
-        self.vnbaseIndex = 0
-        self.uv0baseIndex = 0
-        self.uv1baseIndex = 0
-        for GeoMaterialPolys in self.MaterialsDict.values():
-            GeoMaterialPolys.ClearPolys()
-        self.useBonesDict = {}
-        self.mapVertexGroupNames = {}
-        self.armatureObjectName = ""
-        self.armatureRootBone = None
-        self.armatureRootBoneIndex = 0
-        self.skinnedVertices = []
-
-    def PrintGeoMesh(self, geoFile):
-        geoFile.write("\tCMesh\n")
-        geoFile.write("\t{\n")
-        geoFile.write("\t\tname \"%s\"\n" % (StripName(self.name)))
-
-        if self.vList:
-            geoFile.write("\t\tCVerts\n")
-            geoFile.write("\t\t{\n")
-            geoFile.write("\t\t\tnumVerts %d\n" % len(self.vList))
-            for vertex in self.vList:
-                geoFile.write("\t\t\tv { %.9f, %.9f, %.9f }\n" % (vertex[0], vertex[1], vertex[2]))
-            geoFile.write("\t\t}\n")
-
-        if self.vnList:
-            geoFile.write("\t\tCVertNorms\n")
-            geoFile.write("\t\t{\n")
-            geoFile.write("\t\t\tnumVertNorms  %d\n" % len(self.vnList))
-            for vertexn in self.vnList:
-                geoFile.write("\t\t\tvn { %.9f, %.9f, %.9f }\n" % (vertexn[0], vertexn[1], vertexn[2]))
-            geoFile.write("\t\t}\n")
-
-        if self.vcList:
-            geoFile.write("\t\tCVertCols\n")
-            geoFile.write("\t\t{\n")
-            geoFile.write("\t\t\tnumVertCols %d\n" % len(self.vcList))
-            for color in self.vcList:
-                geoFile.write("\t\t\tcol { %.6f, %.6f, %.6f, %.6f }\n" % (color[0], color[1], color[2], color[3])) #alpha is not supported on blender for vertex colors
-            geoFile.write("\t\t}\n")
-
-        if self.uv0List:
-            geoFile.write("\t\tCUVs\n")
-            geoFile.write("\t\t{\n")
-            geoFile.write("\t\t\tsetID 0\n")
-            geoFile.write("\t\t\tnumUVs %d\n" % len(self.uv0List))
-            for uv in self.uv0List:
-                 geoFile.write("\t\t\tuv { %.9f, %.9f }\n" % (uv[0], uv[1]))
-            geoFile.write("\t\t}\n")
-
-        if self.uv1List:
-            geoFile.write("\t\tCUVs\n")
-            geoFile.write("\t\t{\n")
-            geoFile.write("\t\t\tsetID 1\n")
-            geoFile.write("\t\t\tnumUVs %d\n" % len(self.uv1List))
-            for uv in self.uv1List:
-                 geoFile.write("\t\t\tuv { %.9f, %.9f }\n" % (uv[0], uv[1]))
-            geoFile.write("\t\t}\n")
-
-        for GeoMaterialPolys in self.MaterialsDict.values():
-            GeoMaterialPolys.PrintMaterialPolys(geoFile)
-        geoFile.write("\t}\n")
-
-    def GetMaterialList(self):
-        return list(self.MaterialsDict.keys())
-
-    def GetMaterialByName(self, name):
-        if name in self.MaterialsDict:
-            return self.MaterialsDict[name].material
-        else:
-            return None
-
-
-
-#############
-# iterates faces, vertices ... and store the information in the GeoModel container
-def BuildOptimizedGeo(Config, Object, Mesh, GeoModel):
-    if GeoModel == None:
-        GeoModel = CGeoModel(filename, Object.name)
-
-    #Ensure tessfaces data are here
-    Mesh.update (calc_tessface=True)
-
-    #Store Vertex stream, and Normal stream (use directly the order from blender collection
-    for Vertex in Mesh.vertices:
-        GeoModel.AddVertex(Vertex.co)
-        Normal = Vertex.normal
-        if Config.FlipNormals:
-            Normal = -Normal
-        GeoModel.AddVertexNormal(Normal)
-    #Check if some colors have been defined
-    vertexColors = None
-    if Config.ExportVertexColors and (len(Mesh.vertex_colors) > 0):
-        vertexColors = Mesh.tessface_vertex_colors[0].data
-
-    #Check if some uv coordinates have been defined
-    UVCoordinates = None
-    if Config.ExportTextures and (len(Mesh.uv_textures) > 0):
-        for UV in Mesh.tessface_uv_textures:
-            if UV.active_render:
-                UVCoordinates = UV.data
-                break
-
-    #Iterate on Faces and Store the poly (quad or tri) and the associate colors,UVs
-    for Face in Mesh.tessfaces:
-        # stream for vertex (we use the same for normal)
-        Vertices = list(Face.vertices)
-        if Config.CoordinateSystem == 1:
-            Vertices = Vertices[::-1]
-        # stream for vertex colors
-        if vertexColors:
-            MeshColor = vertexColors[Face.index]
-            if len(Vertices) == 3:
-                FaceColors = list((MeshColor.color1, MeshColor.color2, MeshColor.color3))
-            else:
-                FaceColors = list((MeshColor.color1, MeshColor.color2, MeshColor.color3, MeshColor.color4))
-            if Config.CoordinateSystem == 1:
-                FaceColors = FaceColors[::-1]
-            colorIndex = []
-            for color in FaceColors:
-                index = GeoModel.AddVertexColor(color[0], color[1], color[2], 1)  #rgba => no alpha on vertex color in Blender so use 1
-                colorIndex.append(index)
-        else:
-            colorIndex = list((-1,-1,-1,-1))
-
-        # stream for UV0 coordinates
-        if UVCoordinates:
-            uvFace = UVCoordinates[Face.index]
-            uvVertices = []
-            for uvVertex in uvFace.uv:
-                uvVertices.append(tuple(uvVertex))
-            if Config.CoordinateSystem == 1:
-                uvVertices = uvVertices[::-1]
-            uv0Index = []
-            for uvVertex in uvVertices:
-                index = GeoModel.AddVertexUV0(uvVertex[0], 1 - uvVertex[1])
-                uv0Index.append(index)
-        else:
-            uv0Index = list((-1, -1, -1, -1))
-
-        # stream for UV1 coordinates
-        uv1Index = list((-1, -1, -1, -1))
-
-        mat = None
-        # find the associated material
-        if Face.material_index < len(Mesh.materials):
-            mat = Mesh.materials[Face.material_index]
-        if mat:
-            matName =  mat.name
-        else:
-            matName = "NoMaterialAssigned"  # There is no material assigned in blender !!!, exporter have generated a default one
-
-        # now on the material, generates the tri/quad in v,vn,uv0,uv1,vc stream index
-        GeoModel.BeginPoly(matName, mat)
-
-        for i in range(0, len(Vertices)):
-            GeoModel.AddPoint(Vertices[i], Vertices[i], uv0Index[i], uv1Index[i], colorIndex[i])
-
-        GeoModel.EndPoly()
-
-
-
-#############
-# Get the list of Material in use by the CGeoModel
-def WriteMeshMaterialsForGeoModel(Config, mtlFile, GeoModel):
-    for matName in GeoModel.GetMaterialList():
-        Material = GeoModel.GetMaterialByName(matName)
-        WriteMaterial(Config, mtlFile, Material)
-
-
-def WriteMaterial(Config, mtlFile, Material=None):
-    mtlFile.write("CIwMaterial\n")
-    mtlFile.write("{\n")
-    if Material:
-        mtlFile.write("\tname \"%s\"\n" % Material.name)
-
-        if Config.ExportMaterialColors:
-            #if bpy.context.scene.world:
-            #    MatAmbientColor = Material.ambient * bpy.context.scene.world.ambient_color
-            MatAmbientColor = Material.ambient * Material.diffuse_color
-            mtlFile.write("\tcolAmbient {%.2f,%.2f,%.2f,%.2f} \n" % (min(255, MatAmbientColor[0] * 255), min(255, MatAmbientColor[1] * 255), min(255, MatAmbientColor[2] * 255), min(255, Material.alpha * 255)))
-            MatDiffuseColor = 255 * Material.diffuse_intensity * Material.diffuse_color
-            MatDiffuseColor = min((255, 255, 255)[:],MatDiffuseColor[:])
-            mtlFile.write("\tcolDiffuse  {%.2f,%.2f,%.2f} \n" % (MatDiffuseColor[:]))
-            MatSpecularColor = 255 * Material.specular_intensity * Material.specular_color
-            MatSpecularColor = min((255, 255, 255)[:],MatSpecularColor[:])
-            mtlFile.write("\tcolSpecular  {%.2f,%.2f,%.2f} \n" % (MatSpecularColor[:]))
-            # EmitColor = Material.emit * Material.diffuse_color
-            # mtlFile.write("\tcolEmissive {%.2f,%.2f,%.2f} \n" % (EmitColor* 255)[:])
-    else:
-        mtlFile.write("\tname \"NoMaterialAssigned\" // There is no material assigned in blender !!!, exporter have generated a default one\n")
-
-    #Copy texture
-    if Config.ExportTextures:
-        Texture = GetMaterialTextureFullPath(Config, Material)
-        if Texture:
-            mtlFile.write("\ttexture0 .\\textures\\%s\n" % (bpy.path.basename(Texture)))
-
-            if Config.CopyTextureFiles:
-                if not os.path.exists(Texture):
-                    #try relative path to the blend file
-                    Texture = os.path.dirname(bpy.data.filepath) + Texture
-                if os.path.exists(Texture):
-                    textureDest = os.path.dirname(Config.FilePath) + os.sep + "models" + os.sep + "textures" + os.sep + ("%s" % bpy.path.basename(Texture))
-                    ensure_dir(textureDest)
-                    if Config.Verbose:
-                        print("      Copying the texture file %s ---> %s" % (Texture, textureDest))
-                    shutil.copy(Texture, textureDest)
-                else:
-                    if Config.Verbose:
-                        print("      CANNOT Copy texture file (not found) %s" % (Texture))
-    mtlFile.write("}\n")
-
-def GetFirstRootBone(ArmatureObject):
-    ArmatureBones = ArmatureObject.data.bones
-    ParentBoneList = [Bone for Bone in ArmatureBones if Bone.parent is None]
-    if ParentBoneList:
-        return ParentBoneList[0]
-    return None
-
-
-def GetVertexGroupFromBone(Object, Bone):
-    if Bone:
-        vertexGroupList = [VertexGroup for VertexGroup in Object.vertex_groups  if VertexGroup.name == Bone.name]
-        if vertexGroupList:
-            return vertexGroupList[0]
-    return None
-
-
-def GetBoneListNames(Bones):
-    boneList = []
-    for Bone in Bones:
-        boneList.append(Bone.name)
-        boneList += GetBoneListNames(Bone.children)
-    return boneList
-
-
-def FindUniqueIndexForRootBone(Object, RootVertexGroup):
-    if RootVertexGroup:
-        return RootVertexGroup.index
-    else:
-        #If there is not VertexGroup associated to the root bone name, we don't have a vertex index.
-        #so use the next available free index
-        return len(Object.vertex_groups)
-
-
-def WriteMeshSkinWeightsForGeoModel(Config, Object, Mesh, GeoModel):
-    ArmatureList = [Modifier for Modifier in Object.modifiers if Modifier.type == "ARMATURE"]
-    if ArmatureList:
-        ArmatureObject = ArmatureList[0].object
-        if ArmatureObject is None:
-            return
-        RootBone = GetFirstRootBone(ArmatureObject)
-        RootVertexGroup = GetVertexGroupFromBone(Object, RootBone)
-        BoneNames = GetBoneListNames(ArmatureObject.data.bones)
-
-        GeoModel.armatureObjectName = StripName(ArmatureObject.name)
-        if RootBone:
-            GeoModel.armatureRootBone = RootBone
-            GeoModel.armatureRootBoneIndex = FindUniqueIndexForRootBone(Object, RootVertexGroup)
-
-        # Marmalade need to declare a vertex per list of affected bones
-        # so first we have to get all the combinations of affected bones that exist in the mesh
-        # to build thoses groups, we build a unique key (like a bit field, where each bit is a VertexGroup.Index): Sum(2^VertGroupIndex)... so we have a unique Number per combinations
-
-        for Vertex in Mesh.vertices:
-            VertexIndex = Vertex.index + GeoModel.vbaseIndex
-            AddVertexToDicionarySkinWeights(Config, Object, Mesh, Vertex, GeoModel.useBonesDict, GeoModel.mapVertexGroupNames, VertexIndex, RootBone, RootVertexGroup, BoneNames)
-            GeoModel.skinnedVertices.append(VertexIndex)
-
-        if Config.MergeModes != 1:
-            # write skin file directly
-            PrintSkinWeights(Config, GeoModel.armatureObjectName, GeoModel.useBonesDict, GeoModel.mapVertexGroupNames, StripName(Object.name))
-
-
-def PrintSkinWeights(Config, ArmatureObjectName, useBonesDict, mapVertexGroupNames, GeoName):
-        #Create the skin file
-        skinfullname = os.path.dirname(Config.FilePath) + os.sep + "models" + os.sep + "%s.skin" % GeoName
-        ensure_dir(skinfullname)
-        if Config.Verbose:
-            print("      Creating skin file %s" % (skinfullname))
-        skinFile = open(skinfullname, "w")
-        skinFile.write('// skin file exported from : %r\n' % os.path.basename(bpy.data.filepath))
-        skinFile.write("CIwAnimSkin\n")
-        skinFile.write("{\n")
-        skinFile.write("\tskeleton \"%s\"\n" % ArmatureObjectName)
-        skinFile.write("\tmodel \"%s\"\n" % GeoName)
-
-        # now we have Bones grouped in the dictionary , along with the associated influenced vertex weighting
-        # So simply iterate the dictionary
-        Config.File.write("\t\".\models\%s.skin\"\n" % GeoName)
-        for pair_ListGroupIndices_ListAssignedVertices in useBonesDict.values():
-            skinFile.write("\tCIwAnimSkinSet\n")
-            skinFile.write("\t{\n")
-            skinFile.write("\t\tuseBones {")
-            for vertexGroupIndex in pair_ListGroupIndices_ListAssignedVertices[0]:
-                skinFile.write(" %s" % mapVertexGroupNames[vertexGroupIndex])
-            skinFile.write(" }\n")
-            skinFile.write("\t\tnumVerts %d\n" % len(pair_ListGroupIndices_ListAssignedVertices[1]))
-            for VertexWeightString in pair_ListGroupIndices_ListAssignedVertices[1]:
-                skinFile.write(VertexWeightString)
-            skinFile.write("\t}\n")
-
-        skinFile.write("}\n")
-        skinFile.close()
-
-
-def AddVertexToDicionarySkinWeights(Config, Object, Mesh, Vertex, useBonesDict, mapVertexGroupNames, VertexIndex, RootBone, RootVertexGroup, BoneNames):
-    #build useBones
-    useBonesKey = 0
-    vertexGroupIndices = []
-    weightTotal = 0.0
-    if (len(Vertex.groups)) > 4:
-        print ("ERROR Vertex %d is influenced by more than 4 bones\n" % (VertexIndex))
-    for VertexGroup in Vertex.groups:
-        if (VertexGroup.weight > 0):
-            groupName = Object.vertex_groups[VertexGroup.group].name
-            if groupName in BoneNames:
-                mapVertexGroupNames[VertexGroup.group] = StripBoneName(groupName)
-                if (len(vertexGroupIndices))<4:  #ignore if more 4 bones are influencing the vertex
-                    useBonesKey = useBonesKey + pow(2, VertexGroup.group)
-                    vertexGroupIndices.append(VertexGroup.group)
-                    weightTotal = weightTotal + VertexGroup.weight
-    if (weightTotal == 0):
-        bWeightTotZero = True  #avoid divide by zero later on
-        if (RootBone):
-            if Config.Verbose:
-                print(" Warning Weight is ZERO for vertex %d => Add it to the root bone" % (VertexIndex))
-            RootBoneGroupIndex = FindUniqueIndexForRootBone(Object, RootVertexGroup)
-            mapVertexGroupNames[RootBoneGroupIndex] = StripBoneName(RootBone.name)
-            useBonesKey = pow(2, RootBoneGroupIndex)
-            vertexGroupIndices = list((RootBoneGroupIndex,))
-
-            weightTotal = 1
-    else:
-        bWeightTotZero = False
-
-    if len(vertexGroupIndices) > 0:
-        vertexGroupIndices.sort();
-
-        #build the vertex weight string: vertex indices, followed by influence weight for each bone
-        VertexWeightString = "\t\tvertWeights { %d" % (VertexIndex)
-        for vertexGroupIndex in vertexGroupIndices:
-            #get the weight of this specific VertexGroup (aka bone)
-            boneWeight = 1
-            for VertexGroup in Vertex.groups:
-                if VertexGroup.group == vertexGroupIndex:
-                    boneWeight = VertexGroup.weight
-            #calculate the influence of this bone compared to the total of weighting applied to this Vertex
-            if not bWeightTotZero:
-                VertexWeightString += ", %.7f" % (boneWeight / weightTotal)
-            else:
-                VertexWeightString += ", %.7f" % (1.0 / len(vertexGroupIndices))
-        VertexWeightString += "}"
-        if bWeightTotZero:
-            VertexWeightString += " // total weight was zero in blender , export assign it to the RootBone with weight 1."
-        if (len(Vertex.groups)) > 4:
-            VertexWeightString += " // vertex is associated to more than 4 bones in blender !! skip some bone association (was associated to %d bones)." % (len(Vertex.groups))
-        VertexWeightString += "\n"
-
-        #store in dictionnary information
-        if useBonesKey not in useBonesDict:
-            VertexList = []
-            VertexList.append(VertexWeightString)
-            useBonesDict[useBonesKey] = (vertexGroupIndices, VertexList)
-        else:
-            pair_ListGroupIndices_ListAssignedVertices = useBonesDict[useBonesKey]
-            pair_ListGroupIndices_ListAssignedVertices[1].append(VertexWeightString)
-            useBonesDict[useBonesKey] = pair_ListGroupIndices_ListAssignedVertices
-    else:
-        print ("ERROR Vertex %d is not skinned (it doesn't belong to any vertex group\n" % (VertexIndex))
-
-
-
-############# ARMATURE: Bone export, and Bone animation export
-
-
-def WriteArmatureParentRootBones(Config, Object, RootBonesList, skelFile):
-
-    if len(RootBonesList) > 1:
-        print(" /!\\  WARNING ,Marmelade need only one ROOT bone per armature, there is %d root bones " % len(RootBonesList))
-        print(RootBonesList)
-
-    PoseBones = Object.pose.bones
-    for Bone in RootBonesList:
-        if Config.Verbose:
-            print("      Writing Root Bone: {}...".format(Bone.name))
-
-        PoseBone = PoseBones[Bone.name]
-        WriteBonePosition(Config, Object, Bone, PoseBones, PoseBone, skelFile, True)
-        if Config.Verbose:
-            print("      Done")
-        WriteArmatureChildBones(Config, Object, Bone.children, skelFile)
-
-
-def WriteArmatureChildBones(Config, Object, BonesList, skelFile):
-    PoseBones = Object.pose.bones
-    for Bone in BonesList:
-        if Config.Verbose:
-            print("      Writing Child Bone: {}...".format(Bone.name))
-        PoseBone = PoseBones[Bone.name]
-        WriteBonePosition(Config, Object, Bone, PoseBones, PoseBone, skelFile, True)
-        if Config.Verbose:
-            print("      Done")
-
-        WriteArmatureChildBones(Config, Object, Bone.children, skelFile)
-
-
-def WriteBonePosition(Config, Object, Bone, PoseBones, PoseBone, File, isRestPoseNotAnimPose):
-    # Compute armature scale :
-    # Many others exporter require sthe user to do Apply Scale in Object Mode to have 1,1,1 scale and so that anim data are correctly scaled
-    # Here we retreive the Scale of the Armture Object.matrix_world.to_scale() and we use it to scale the bones :-)
-    # So new Blender user should not complain about bad animation export if they forgot to apply the Scale to 1,1,1
-
-    armScale = Object.matrix_world.to_scale()
-    armRot = Object.matrix_world.to_quaternion()
-    if isRestPoseNotAnimPose:
-        #skel file, bone header
-        File.write("\tCIwAnimBone\n")
-        File.write("\t{\n")
-        File.write("\t\tname \"%s\"\n" % StripBoneName(Bone.name))
-        #get bone local matrix for rest pose
-        if Bone.parent:
-            File.write("\t\tparent \"%s\"\n" % StripBoneName(Bone.parent.name))
-            localmat = Bone.parent.matrix_local.inverted() * Bone.matrix_local
-        else:
-            localmat = Bone.matrix_local
-    else:
-        #anim file, bone header
-        File.write("\t\t\n")
-        File.write("\t\tbone \"%s\" \n" % StripBoneName(Bone.name))
-        localmat = PoseBone.matrix
-        #get bone local matrix for current anim pose
-        if Bone.parent:
-            ParentPoseBone = PoseBones[Bone.parent.name]
-            localmat = ParentPoseBone.matrix.inverted() * PoseBone.matrix
-        else:
-            localmat = PoseBone.matrix
-
-    if not Bone.parent:
-        #Flip Y Z axes (only on root bone, other bones are local to root bones, so no need to rotate)
-        X_ROT = mathutils.Matrix.Rotation(-math.pi / 2, 4, 'X')
-        if Config.MergeModes > 0:
-            # Merge mode is in world coordinates and not in model coordinates: so apply the world coordinate on the rootbone
-            localmat = X_ROT * Object.matrix_world * localmat
-            armScale.x =  armScale.y = armScale.z = 1
-        else:
-            localmat= X_ROT * armRot.to_matrix().to_4x4() * localmat #apply the armature rotation on the root bone
-
-
-    loc = localmat.to_translation()
-    quat = localmat.to_quaternion()
-
-    #Scale the bone
-    loc.x *= (armScale.x * Config.Scale)
-    loc.y *= (armScale.y * Config.Scale)
-    loc.z *= (armScale.z * Config.Scale)
-
-    File.write("\t\tpos { %.9f, %.9f, %.9f }\n" % (loc[0], loc[1], loc[2]))
-    File.write("\t\trot { %.9f, %.9f, %.9f, %.9f }\n" % (quat.w, quat.x, quat.y, quat.z))
-
-    if isRestPoseNotAnimPose:
-        File.write("\t}\n")
-
-
-def WriteKeyedAnimationSet(Config, Scene):
-    for Object in [Object for Object in Config.ObjectList if Object.animation_data]:
-        if Config.Verbose:
-            print("  Writing Animation Data for Object: {}".format(Object.name))
-        actions = []
-        if Config.ExportAnimationActions == 0 and Object.animation_data.action:
-            actions.append(Object.animation_data.action)
-        else:
-            actions = bpy.data.actions[:]
-            DefaultAction = Object.animation_data.action
-
-        for Action in actions:
-            if Config.ExportAnimationActions == 0:
-                animFileName = StripName(Object.name)
-            else:
-                Object.animation_data.action = Action
-                animFileName = "%s_%s" % (StripName(Object.name),StripName(Action.name))
-
-            #Object animated (aka single bone object)
-            #build key frame time list
-
-            keyframeTimes = set()
-            if Config.ExportAnimationFrames == 1:
-                # Exports only key frames
-                for FCurve in Action.fcurves:
-                    for Keyframe in FCurve.keyframe_points:
-                        if Keyframe.co[0] < Scene.frame_start:
-                            keyframeTimes.add(Scene.frame_start)
-                        elif Keyframe.co[0] > Scene.frame_end:
-                            keyframeTimes.add(Scene.frame_end)
-                        else:
-                            keyframeTimes.add(int(Keyframe.co[0]))
-            else:
-                # Exports all frames
-                keyframeTimes.update(range(Scene.frame_start, Scene.frame_end + 1, 1))
-            keyframeTimes = list(keyframeTimes)
-            keyframeTimes.sort()
-            if len(keyframeTimes):
-                #Create the anim file for offset animation (or single bone animation
-                animfullname = os.path.dirname(Config.FilePath) + os.sep + "anims" + os.sep + "%s_offset.anim" % animFileName
-                #not yet supported
-                """
-                ##    ensure_dir(animfullname)
-                ##    if Config.Verbose:
-                ##        print("      Creating anim file (single bone animation) %s" % (animfullname))
-                ##    animFile = open(animfullname, "w")
-                ##    animFile.write('// anim file exported from : %r\n' % os.path.basename(bpy.data.filepath))
-                ##    animFile.write("CIwAnim\n")
-                ##    animFile.write("{\n")
-                ##    animFile.write("\tent \"%s\"\n" % (StripName(Object.name)))
-                ##    animFile.write("\tskeleton \"SingleBone\"\n")
-                ##    animFile.write("\t\t\n")
-                ##
-                ##    Config.File.write("\t\".\\anims\\%s_offset.anim\"\n" % animFileName))
-                ##
-                ##    for KeyframeTime in keyframeTimes:
-                ##        #Scene.frame_set(KeyframeTime)
-                ##        animFile.write("\tCIwAnimKeyFrame\n")
-                ##        animFile.write("\t{\n")
-                ##        animFile.write("\t\ttime %.2f // frame num %d \n" % (KeyframeTime/Config.AnimFPS, KeyframeTime))
-                ##        animFile.write("\t\t\n")
-                ##        animFile.write("\t\tbone \"SingleBone\" \n")
-                ##        #postion
-                ##        posx = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "location" and FCurve.array_index == 0: posx = FCurve.evaluate(KeyframeTime)
-                ##        posy = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "location" and FCurve.array_index == 1: posy = FCurve.evaluate(KeyframeTime)
-                ##        posz = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "location" and FCurve.array_index == 2: posz = FCurve.evaluate(KeyframeTime)
-                ##        animFile.write("\t\tpos {%.9f,%.9f,%.9f}\n" % (posx, posy, posz))
-                ##        #rotation
-                ##        rot = Euler()
-                ##        rot[0] = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "rotation_euler" and FCurve.array_index == 1: rot[0] = FCurve.evaluate(KeyframeTime)
-                ##        rot[1] = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "rotation_euler" and FCurve.array_index == 2: rot[1] = FCurve.evaluate(KeyframeTime)
-                ##        rot[2] = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "rotation_euler" and FCurve.array_index == 3: rot[2] = FCurve.evaluate(KeyframeTime)
-                ##        rot = rot.to_quaternion()
-                ##        animFile.write("\t\trot {%.9f,%.9f,%.9f,%.9f}\n" % (rot[0], rot[1], rot[2], rot[3]))
-                ##        #scale
-                ##        scalex = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "scale" and FCurve.array_index == 0: scalex = FCurve.evaluate(KeyframeTime)
-                ##        scaley = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "scale" and FCurve.array_index == 1: scaley = FCurve.evaluate(KeyframeTime)
-                ##        scalez = 0
-                ##        for FCurve in Action.fcurves:
-                ##            if FCurve.data_path == "scale" and FCurve.array_index == 2: scalez = FCurve.evaluate(KeyframeTime)
-                ##        animFile.write("\t\t//scale {%.9f,%.9f,%.9f}\n" % (scalex, scaley, scalez))
-                ##        #keyframe done
-                ##        animFile.write("\t}\n")
-                ##    animFile.write("}\n")
-                ##    animFile.close()
-                """
-            else:
-                if Config.Verbose:
-                    print("    Object %s has no useable animation data." % (StripName(Object.name)))
-
-            if Config.ExportArmatures and Object.type == "ARMATURE":
-                if Config.Verbose:
-                    print("    Writing Armature Bone Animation Data...\n")
-                PoseBones = Object.pose.bones
-                Bones = Object.data.bones
-                #riged bones animated
-                #build key frame time list
-                keyframeTimes = set()
-                if Config.ExportAnimationFrames == 1:
-                    # Exports only key frames
-                    for FCurve in Action.fcurves:
-                        for Keyframe in FCurve.keyframe_points:
-                            if Keyframe.co[0] < Scene.frame_start:
-                                keyframeTimes.add(Scene.frame_start)
-                            elif Keyframe.co[0] > Scene.frame_end:
-                                keyframeTimes.add(Scene.frame_end)
-                            else:
-                                keyframeTimes.add(int(Keyframe.co[0]))
-                else:
-                    # Exports all frame
-                    keyframeTimes.update(range(Scene.frame_start, Scene.frame_end + 1, 1))
-
-                keyframeTimes = list(keyframeTimes)
-                keyframeTimes.sort()
-                if Config.Verbose:
-                    print("Exporting frames: ")
-                    print(keyframeTimes)
-                    if (Scene.frame_preview_end > Scene.frame_end):
-                        print(" WARNING: END Frame of animation in UI preview is Higher than the Scene Frame end:\n Scene.frame_end %d versus Scene.frame_preview_end %d.\n"
-                              % (Scene.frame_end, Scene.frame_preview_end))
-                        print(" => You might need to change the Scene End Frame, to match the current UI preview frame end...\n=> if you don't want to miss end of animation.\n")
-
-                if len(keyframeTimes):
-                    #Create the anim file
-                    animfullname = os.path.dirname(Config.FilePath) + os.sep + "anims" + os.sep + "%s.anim" % animFileName
-                    ensure_dir(animfullname)
-                    if Config.Verbose:
-                        print("      Creating anim file (bones animation) %s\n" % (animfullname))
-                        print("      Frame count %d \n" % (len(keyframeTimes)))
-                    animFile = open(animfullname, "w")
-                    animFile.write('// anim file exported from : %r\n' % os.path.basename(bpy.data.filepath))
-                    animFile.write("CIwAnim\n")
-                    animFile.write("{\n")
-                    animFile.write("\tskeleton \"%s\"\n" % (StripName(Object.name)))
-                    animFile.write("\t\t\n")
-
-                    Config.File.write("\t\".\\anims\\%s.anim\"\n" % animFileName)
-
-                    for KeyframeTime in keyframeTimes:
-                        if Config.Verbose:
-                            print("     Writing Frame %d:" % KeyframeTime)
-                        animFile.write("\tCIwAnimKeyFrame\n")
-                        animFile.write("\t{\n")
-                        animFile.write("\t\ttime %.2f // frame num %d \n" % (KeyframeTime / Config.AnimFPS, KeyframeTime))
-                        #for every frame write bones positions
-                        Scene.frame_set(KeyframeTime)
-                        for PoseBone in PoseBones:
-                            if Config.Verbose:
-                                print("      Writing Bone: {}...".format(PoseBone.name))
-                            animFile.write("\t\t\n")
-
-                            Bone = Bones[PoseBone.name]
-                            WriteBonePosition(Config, Object, Bone, PoseBones, PoseBone, animFile, False)
-                        #keyframe done
-                        animFile.write("\t}\n")
-                    animFile.write("}\n")
-                    animFile.close()
-            else:
-                if Config.Verbose:
-                    print("    Object %s has no useable animation data." % (StripName(Object.name)))
-        if Config.ExportAnimationActions == 1:
-            #set back the original default animation
-            Object.animation_data.action = DefaultAction
-        if Config.Verbose:
-            print("  Done") #Done with Object
-
-
-
-
-################## Utilities
-
-def StripBoneName(name):
-    return name.replace(" ", "")
-
-
-def StripName(Name):
-
-    def ReplaceSet(String, OldSet, NewChar):
-        for OldChar in OldSet:
-            String = String.replace(OldChar, NewChar)
-        return String
-
-    import string
-
-    NewName = ReplaceSet(Name, string.punctuation + " ", "_")
-    return NewName
-
-
-def ensure_dir(f):
-    d = os.path.dirname(f)
-    if not os.path.exists(d):
-        os.makedirs(d)
-
-
-def CloseFile(Config):
-    if Config.Verbose:
-        print("Closing File...")
-    Config.File.close()
-    if Config.Verbose:
-        print("Done")
-
-
-CoordinateSystems = (
-    ("1", "Left-Handed", ""),
-    ("2", "Right-Handed", ""),
-    )
-
-
-AnimationFrameModes = (
-    ("0", "None", ""),
-    ("1", "Keyframes Only", ""),
-    ("2", "Full Animation", ""),
-    )
-
-AnimationActions = (
-    ("0", "Default Animation", ""),
-    ("1", "All Animations", ""),
-    )
-
-ExportModes = (
-    ("1", "All Objects", ""),
-    ("2", "Selected Objects", ""),
-    )
-
-MergeModes = (
-    ("0", "None", ""),
-    ("1", "Merge in one big Mesh", ""),
-    ("2", "Merge in unique Geo File containing several meshes", ""),
-    )
-
-
-from bpy.props import StringProperty, EnumProperty, BoolProperty, IntProperty
-
-
-class MarmaladeExporter(bpy.types.Operator):
-    """Export to the Marmalade model format (.group)"""
-
-    bl_idname = "export.marmalade"
-    bl_label = "Export Marmalade"
-
-    filepath: StringProperty(subtype='FILE_PATH')
-     #Export Mode
-    ExportMode: EnumProperty(
-        name="Export",
-        description="Select which objects to export. Only Mesh, Empty, " \
-                    "and Armature objects will be exported",
-        items=ExportModes,
-        default="1")
-
-    MergeModes: EnumProperty(
-        name="Merge",
-        description="Select if objects should be merged in one Geo File (it can be usefull if a scene is done by several cube/forms)." \
-                    "Do not merge rigged character that have an armature.",
-        items=MergeModes,
-        default="0")
-
-    #General Options
-    Scale: IntProperty(
-        name="Scale Percent",
-        description="Scale percentage applied for export",
-        default=100, min=1, max=1000)
-
-    FlipNormals: BoolProperty(
-        name="Flip Normals",
-        description="",
-        default=False)
-    ApplyModifiers: BoolProperty(
-        name="Apply Modifiers",
-        description="Apply object modifiers before export",
-        default=False)
-    ExportVertexColors: BoolProperty(
-        name="Export Vertices Colors",
-        description="Export colors set on vertices, if any",
-        default=True)
-    ExportMaterialColors: BoolProperty(
-        name="Export Material Colors",
-        description="Ambient color is exported on the Material",
-        default=True)
-    ExportTextures: BoolProperty(
-        name="Export Textures and UVs",
-        description="Exports UVs and Reference external image files to be used by the model",
-        default=True)
-    CopyTextureFiles: BoolProperty(
-        name="Copy Textures Files",
-        description="Copy referenced Textures files in the models\\textures directory",
-        default=True)
-    ExportArmatures: BoolProperty(
-        name="Export Armatures",
-        description="Export the bones of any armatures to deform meshes",
-        default=True)
-    ExportAnimationFrames: EnumProperty(
-        name="Animations Frames",
-        description="Select the type of animations to export. Only object " \
-                    "and armature bone animations can be exported. Keyframes exports only the keyed frames" \
-                    "Full Animation exports every frames, None disables animationq export. ",
-        items=AnimationFrameModes,
-        default="1")
-    ExportAnimationActions: EnumProperty(
-        name="Animations Actions",
-        description="By default only the Default Animation Action assoiated to an armature is exported." \
-                    "However if you have defined several animations on the same armature,"\
-                    "you can select to export all animations. You can see the list of animation actions in the DopeSheet window.",
-        items=AnimationActions,
-        default="0")
-    AnimFPS: IntProperty(
-        name="Animation FPS",
-        description="Frame rate used to export animation in seconds (can be used to artficially slow down the exported animation, or to speed up it",
-        default=30, min=1, max=300)
-
-    #Advance Options
-    CoordinateSystem: EnumProperty(
-        name="System",
-        description="Select a coordinate system to export to",
-        items=CoordinateSystems,
-        default="1")
-
-    Verbose: BoolProperty(
-        name="Verbose",
-        description="Run the exporter in debug mode. Check the console for output",
-        default=True)
-
-    def execute(self, context):
-        #Append .group
-        FilePath = bpy.path.ensure_ext(self.filepath, ".group")
-
-        Config = MarmaladeExporterSettings(context,
-                                         FilePath,
-                                         CoordinateSystem=self.CoordinateSystem,
-                                         FlipNormals=self.FlipNormals,
-                                         ApplyModifiers=self.ApplyModifiers,
-                                         Scale=self.Scale,
-                                         AnimFPS=self.AnimFPS,
-                                         ExportVertexColors=self.ExportVertexColors,
-                                         ExportMaterialColors=self.ExportMaterialColors,
-                                         ExportTextures=self.ExportTextures,
-                                         CopyTextureFiles=self.CopyTextureFiles,
-                                         ExportArmatures=self.ExportArmatures,
-                                         ExportAnimationFrames=self.ExportAnimationFrames,
-                                         ExportAnimationActions=self.ExportAnimationActions,
-                                         ExportMode=self.ExportMode,
-                                         MergeModes=self.MergeModes,
-                                         Verbose=self.Verbose)
-
-        # Exit edit mode before exporting, so current object states are exported properly.
-        if bpy.ops.object.mode_set.poll():
-            bpy.ops.object.mode_set(mode='OBJECT')
-
-        ExportMadeWithMarmaladeGroup(Config)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        if not self.filepath:
-            self.filepath = bpy.path.ensure_ext(bpy.data.filepath, ".group")
-        WindowManager = context.window_manager
-        WindowManager.fileselect_add(self)
-        return {'RUNNING_MODAL'}
-
-
-def menu_func(self, context):
-    self.layout.operator(MarmaladeExporter.bl_idname, text="Marmalade cross-platform Apps (.group)")
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_export.append(menu_func)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_export.remove(menu_func)
-
-
-if __name__ == "__main__":
-    register()
diff --git a/io_export_md3.py b/io_export_md3.py
deleted file mode 100644 (file)
index 402d514..0000000
+++ /dev/null
@@ -1,692 +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 #####
-
-bl_info = {
-    "name": "Quake Model 3 (.md3)",
-    "author": "Xembie",
-    "version": (0, 7),
-    "blender": (2, 53, 0),
-    "location": "File > Export",
-    "description": "Save a Quake Model 3 File)",
-    "warning": "", # used for warning icon and text in addons panel
-    "wiki_url": "",
-    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
-    "category": "Import-Export"}
-
-
-import bpy,struct,math,os
-
-MAX_QPATH = 64
-
-MD3_IDENT = "IDP3"
-MD3_VERSION = 15
-MD3_MAX_TAGS = 16
-MD3_MAX_SURFACES = 32
-MD3_MAX_FRAMES = 1024
-MD3_MAX_SHADERS = 256
-MD3_MAX_VERTICES = 4096
-MD3_MAX_TRIANGLES = 8192
-MD3_XYZ_SCALE = 64.0
-
-class md3Vert:
-    xyz = []
-    normal = 0
-    binaryFormat = "<3hH"
-
-    def __init__(self):
-        self.xyz = [0.0, 0.0, 0.0]
-        self.normal = 0
-
-    def GetSize(self):
-        return struct.calcsize(self.binaryFormat)
-
-    # copied from PhaethonH <phaethon@linux.ucla.edu> md3.py
-    def Decode(self, latlng):
-        lat = (latlng >> 8) & 0xFF;
-        lng = (latlng) & 0xFF;
-        lat *= math.pi / 128;
-        lng *= math.pi / 128;
-        x = math.cos(lat) * math.sin(lng)
-        y = math.sin(lat) * math.sin(lng)
-        z =                 math.cos(lng)
-        retval = [ x, y, z ]
-        return retval
-
-    # copied from PhaethonH <phaethon@linux.ucla.edu> md3.py
-    def Encode(self, normal):
-        x = normal[0]
-        y = normal[1]
-        z = normal[2]
-        # normalize
-        l = math.sqrt((x*x) + (y*y) + (z*z))
-        if l == 0:
-            return 0
-        x = x/l
-        y = y/l
-        z = z/l
-
-        if (x == 0.0) & (y == 0.0) :
-            if z > 0.0:
-                return 0
-            else:
-                return (128 << 8)
-
-        lng = math.acos(z) * 255 / (2 * math.pi)
-        lat = math.atan2(y, x) * 255 / (2 * math.pi)
-        retval = ((int(lat) & 0xFF) << 8) | (int(lng) & 0xFF)
-        return retval
-
-    def Save(self, file):
-        tmpData = [0] * 4
-        tmpData[0] = int(self.xyz[0] * MD3_XYZ_SCALE)
-        tmpData[1] = int(self.xyz[1] * MD3_XYZ_SCALE)
-        tmpData[2] = int(self.xyz[2] * MD3_XYZ_SCALE)
-        tmpData[3] = self.normal
-        data = struct.pack(self.binaryFormat, tmpData[0], tmpData[1], tmpData[2], tmpData[3])
-        file.write(data)
-
-class md3TexCoord:
-    u = 0.0
-    v = 0.0
-
-    binaryFormat = "<2f"
-
-    def __init__(self):
-        self.u = 0.0
-        self.v = 0.0
-
-    def GetSize(self):
-        return struct.calcsize(self.binaryFormat)
-
-    def Save(self, file):
-        tmpData = [0] * 2
-        tmpData[0] = self.u
-        tmpData[1] = 1.0 - self.v
-        data = struct.pack(self.binaryFormat, tmpData[0], tmpData[1])
-        file.write(data)
-
-class md3Triangle:
-    indexes = []
-
-    binaryFormat = "<3i"
-
-    def __init__(self):
-        self.indexes = [ 0, 0, 0 ]
-
-    def GetSize(self):
-        return struct.calcsize(self.binaryFormat)
-
-    def Save(self, file):
-        tmpData = [0] * 3
-        tmpData[0] = self.indexes[0]
-        tmpData[1] = self.indexes[2] # reverse
-        tmpData[2] = self.indexes[1] # reverse
-        data = struct.pack(self.binaryFormat,tmpData[0], tmpData[1], tmpData[2])
-        file.write(data)
-
-class md3Shader:
-    name = ""
-    index = 0
-
-    binaryFormat = "<%dsi" % MAX_QPATH
-
-    def __init__(self):
-        self.name = ""
-        self.index = 0
-
-    def GetSize(self):
-        return struct.calcsize(self.binaryFormat)
-
-    def Save(self, file):
-        tmpData = [0] * 2
-        tmpData[0] = self.name
-        tmpData[1] = self.index
-        data = struct.pack(self.binaryFormat, tmpData[0], tmpData[1])
-        file.write(data)
-
-class md3Surface:
-    ident = ""
-    name = ""
-    flags = 0
-    numFrames = 0
-    numShaders = 0
-    numVerts = 0
-    numTriangles = 0
-    ofsTriangles = 0
-    ofsShaders = 0
-    ofsUV = 0
-    ofsVerts = 0
-    ofsEnd = 0
-    shaders = []
-    triangles = []
-    uv = []
-    verts = []
-
-    binaryFormat = "<4s%ds10i" % MAX_QPATH  # 1 int, name, then 10 ints
-
-    def __init__(self):
-        self.ident = ""
-        self.name = ""
-        self.flags = 0
-        self.numFrames = 0
-        self.numShaders = 0
-        self.numVerts = 0
-        self.numTriangles = 0
-        self.ofsTriangles = 0
-        self.ofsShaders = 0
-        self.ofsUV = 0
-        self.ofsVerts = 0
-        self.ofsEnd
-        self.shaders = []
-        self.triangles = []
-        self.uv = []
-        self.verts = []
-
-    def GetSize(self):
-        sz = struct.calcsize(self.binaryFormat)
-        self.ofsTriangles = sz
-        for t in self.triangles:
-            sz += t.GetSize()
-        self.ofsShaders = sz
-        for s in self.shaders:
-            sz += s.GetSize()
-        self.ofsUV = sz
-        for u in self.uv:
-            sz += u.GetSize()
-        self.ofsVerts = sz
-        for v in self.verts:
-            sz += v.GetSize()
-        self.ofsEnd = sz
-        return self.ofsEnd
-
-    def Save(self, file):
-        self.GetSize()
-        tmpData = [0] * 12
-        tmpData[0] = self.ident
-        tmpData[1] = self.name
-        tmpData[2] = self.flags
-        tmpData[3] = self.numFrames
-        tmpData[4] = self.numShaders
-        tmpData[5] = self.numVerts
-        tmpData[6] = self.numTriangles
-        tmpData[7] = self.ofsTriangles
-        tmpData[8] = self.ofsShaders
-        tmpData[9] = self.ofsUV
-        tmpData[10] = self.ofsVerts
-        tmpData[11] = self.ofsEnd
-        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6],tmpData[7],tmpData[8],tmpData[9],tmpData[10],tmpData[11])
-        file.write(data)
-
-        # write the tri data
-        for t in self.triangles:
-            t.Save(file)
-
-        # save the shader coordinates
-        for s in self.shaders:
-            s.Save(file)
-
-        # save the uv info
-        for u in self.uv:
-            u.Save(file)
-
-        # save the verts
-        for v in self.verts:
-            v.Save(file)
-
-class md3Tag:
-    name = ""
-    origin = []
-    axis = []
-
-    binaryFormat="<%ds3f9f" % MAX_QPATH
-
-    def __init__(self):
-        self.name = ""
-        self.origin = [0, 0, 0]
-        self.axis = [0, 0, 0, 0, 0, 0, 0, 0, 0]
-
-    def GetSize(self):
-        return struct.calcsize(self.binaryFormat)
-
-    def Save(self, file):
-        tmpData = [0] * 13
-        tmpData[0] = self.name
-        tmpData[1] = float(self.origin[0])
-        tmpData[2] = float(self.origin[1])
-        tmpData[3] = float(self.origin[2])
-        tmpData[4] = float(self.axis[0])
-        tmpData[5] = float(self.axis[1])
-        tmpData[6] = float(self.axis[2])
-        tmpData[7] = float(self.axis[3])
-        tmpData[8] = float(self.axis[4])
-        tmpData[9] = float(self.axis[5])
-        tmpData[10] = float(self.axis[6])
-        tmpData[11] = float(self.axis[7])
-        tmpData[12] = float(self.axis[8])
-        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6], tmpData[7], tmpData[8], tmpData[9], tmpData[10], tmpData[11], tmpData[12])
-        file.write(data)
-
-class md3Frame:
-    mins = 0
-    maxs = 0
-    localOrigin = 0
-    radius = 0.0
-    name = ""
-
-    binaryFormat="<3f3f3ff16s"
-
-    def __init__(self):
-        self.mins = [0, 0, 0]
-        self.maxs = [0, 0, 0]
-        self.localOrigin = [0, 0, 0]
-        self.radius = 0.0
-        self.name = ""
-
-    def GetSize(self):
-        return struct.calcsize(self.binaryFormat)
-
-    def Save(self, file):
-        tmpData = [0] * 11
-        tmpData[0] = self.mins[0]
-        tmpData[1] = self.mins[1]
-        tmpData[2] = self.mins[2]
-        tmpData[3] = self.maxs[0]
-        tmpData[4] = self.maxs[1]
-        tmpData[5] = self.maxs[2]
-        tmpData[6] = self.localOrigin[0]
-        tmpData[7] = self.localOrigin[1]
-        tmpData[8] = self.localOrigin[2]
-        tmpData[9] = self.radius
-        tmpData[10] = self.name
-        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6],tmpData[7], tmpData[8], tmpData[9], tmpData[10])
-        file.write(data)
-
-class md3Object:
-    # header structure
-    ident = ""            # this is used to identify the file (must be IDP3)
-    version = 0            # the version number of the file (Must be 15)
-    name = ""
-    flags = 0
-    numFrames = 0
-    numTags = 0
-    numSurfaces = 0
-    numSkins = 0
-    ofsFrames = 0
-    ofsTags = 0
-    ofsSurfaces = 0
-    ofsEnd = 0
-    frames = []
-    tags = []
-    surfaces = []
-
-    binaryFormat="<4si%ds9i" % MAX_QPATH  # little-endian (<), 17 integers (17i)
-
-    def __init__(self):
-        self.ident = 0
-        self.version = 0
-        self.name = ""
-        self.flags = 0
-        self.numFrames = 0
-        self.numTags = 0
-        self.numSurfaces = 0
-        self.numSkins = 0
-        self.ofsFrames = 0
-        self.ofsTags = 0
-        self.ofsSurfaces = 0
-        self.ofsEnd = 0
-        self.frames = []
-        self.tags = []
-        self.surfaces = []
-
-    def GetSize(self):
-        self.ofsFrames = struct.calcsize(self.binaryFormat)
-        self.ofsTags = self.ofsFrames
-        for f in self.frames:
-            self.ofsTags += f.GetSize()
-        self.ofsSurfaces += self.ofsTags
-        for t in self.tags:
-            self.ofsSurfaces += t.GetSize()
-        self.ofsEnd = self.ofsSurfaces
-        for s in self.surfaces:
-            self.ofsEnd += s.GetSize()
-        return self.ofsEnd
-
-    def Save(self, file):
-        self.GetSize()
-        tmpData = [0] * 12
-        tmpData[0] = self.ident
-        tmpData[1] = self.version
-        tmpData[2] = self.name
-        tmpData[3] = self.flags
-        tmpData[4] = self.numFrames
-        tmpData[5] = self.numTags
-        tmpData[6] = self.numSurfaces
-        tmpData[7] = self.numSkins
-        tmpData[8] = self.ofsFrames
-        tmpData[9] = self.ofsTags
-        tmpData[10] = self.ofsSurfaces
-        tmpData[11] = self.ofsEnd
-
-        data = struct.pack(self.binaryFormat, tmpData[0],tmpData[1],tmpData[2],tmpData[3],tmpData[4],tmpData[5],tmpData[6],tmpData[7], tmpData[8], tmpData[9], tmpData[10], tmpData[11])
-        file.write(data)
-
-        for f in self.frames:
-            f.Save(file)
-
-        for t in self.tags:
-            t.Save(file)
-
-        for s in self.surfaces:
-            s.Save(file)
-
-
-def message(log,msg):
-  if log:
-    log.write(msg + "\n")
-  else:
-    print(msg)
-
-class md3Settings:
-  def __init__(self,
-               savepath,
-               name,
-               logpath,
-               overwrite=True,
-               dumpall=False,
-               ignoreuvs=False,
-               scale=1.0,
-               offsetx=0.0,
-               offsety=0.0,
-               offsetz=0.0):
-    self.savepath = savepath
-    self.name = name
-    self.logpath = logpath
-    self.overwrite = overwrite
-    self.dumpall = dumpall
-    self.ignoreuvs = ignoreuvs
-    self.scale = scale
-    self.offsetx = offsetx
-    self.offsety = offsety
-    self.offsetz = offsetz
-
-def print_md3(log,md3,dumpall):
-  message(log,"Header Information")
-  message(log,"Ident: " + str(md3.ident))
-  message(log,"Version: " + str(md3.version))
-  message(log,"Name: " + md3.name)
-  message(log,"Flags: " + str(md3.flags))
-  message(log,"Number of Frames: " + str(md3.numFrames))
-  message(log,"Number of Tags: " + str(md3.numTags))
-  message(log,"Number of Surfaces: " + str(md3.numSurfaces))
-  message(log,"Number of Skins: " + str(md3.numSkins))
-  message(log,"Offset Frames: " + str(md3.ofsFrames))
-  message(log,"Offset Tags: " + str(md3.ofsTags))
-  message(log,"Offset Surfaces: " + str(md3.ofsSurfaces))
-  message(log,"Offset end: " + str(md3.ofsEnd))
-  if dumpall:
-    message(log,"Frames:")
-    for f in md3.frames:
-      message(log," Mins: " + str(f.mins[0]) + " " + str(f.mins[1]) + " " + str(f.mins[2]))
-      message(log," Maxs: " + str(f.maxs[0]) + " " + str(f.maxs[1]) + " " + str(f.maxs[2]))
-      message(log," Origin(local): " + str(f.localOrigin[0]) + " " + str(f.localOrigin[1]) + " " + str(f.localOrigin[2]))
-      message(log," Radius: " + str(f.radius))
-      message(log," Name: " + f.name)
-
-    message(log,"Tags:")
-    for t in md3.tags:
-      message(log," Name: " + t.name)
-      message(log," Origin: " + str(t.origin[0]) + " " + str(t.origin[1]) + " " + str(t.origin[2]))
-      message(log," Axis[0]: " + str(t.axis[0]) + " " + str(t.axis[1]) + " " + str(t.axis[2]))
-      message(log," Axis[1]: " + str(t.axis[3]) + " " + str(t.axis[4]) + " " + str(t.axis[5]))
-      message(log," Axis[2]: " + str(t.axis[6]) + " " + str(t.axis[7]) + " " + str(t.axis[8]))
-
-    message(log,"Surfaces:")
-    for s in md3.surfaces:
-      message(log," Ident: " + s.ident)
-      message(log," Name: " + s.name)
-      message(log," Flags: " + str(s.flags))
-      message(log," # of Frames: " + str(s.numFrames))
-      message(log," # of Shaders: " + str(s.numShaders))
-      message(log," # of Verts: " + str(s.numVerts))
-      message(log," # of Triangles: " + str(s.numTriangles))
-      message(log," Offset Triangles: " + str(s.ofsTriangles))
-      message(log," Offset UVs: " + str(s.ofsUV))
-      message(log," Offset Verts: " + str(s.ofsVerts))
-      message(log," Offset End: " + str(s.ofsEnd))
-      message(log," Shaders:")
-      for shader in s.shaders:
-        message(log,"  Name: " + shader.name)
-        message(log,"  Index: " + str(shader.index))
-      message(log," Triangles:")
-      for tri in s.triangles:
-        message(log,"  Indexes: " + str(tri.indexes[0]) + " " + str(tri.indexes[1]) + " " + str(tri.indexes[2]))
-      message(log," UVs:")
-      for uv in s.uv:
-        message(log,"  U: " + str(uv.u))
-        message(log,"  V: " + str(uv.v))
-      message(log," Verts:")
-      for vert in s.verts:
-        message(log,"  XYZ: " + str(vert.xyz[0]) + " " + str(vert.xyz[1]) + " " + str(vert.xyz[2]))
-        message(log,"  Normal: " + str(vert.normal))
-
-  shader_count = 0
-  vert_count = 0
-  tri_count = 0
-  for surface in md3.surfaces:
-    shader_count += surface.numShaders
-    tri_count += surface.numTriangles
-    vert_count += surface.numVerts
-
-  if md3.numTags >= MD3_MAX_TAGS:
-    message(log,"!Warning: Tag limit reached! " + str(md3.numTags))
-  if md3.numSurfaces >= MD3_MAX_SURFACES:
-    message(log,"!Warning: Surface limit reached! " + str(md3.numSurfaces))
-  if md3.numFrames >= MD3_MAX_FRAMES:
-    message(log,"!Warning: Frame limit reached! " + str(md3.numFrames))
-  if shader_count >= MD3_MAX_SHADERS:
-    message(log,"!Warning: Shader limit reached! " + str(shader_count))
-  if vert_count >= MD3_MAX_VERTICES:
-    message(log,"!Warning: Vertex limit reached! " + str(vert_count))
-  if tri_count >= MD3_MAX_TRIANGLES:
-    message(log,"!Warning: Triangle limit reached! " + str(tri_count))
-
-def save_md3(settings):
-  if settings.logpath:
-    if settings.overwrite:
-      log = open(settings.logpath,"w")
-    else:
-      log = open(settings.logpath,"a")
-  else:
-    log = 0
-  message(log,"##########Exporting MD3##########")
-  bpy.ops.object.mode_set(mode='OBJECT')
-  md3 = md3Object()
-  md3.ident = MD3_IDENT
-  md3.version = MD3_VERSION
-  md3.name = settings.name
-  md3.numFrames = (bpy.context.scene.frame_end + 1) - bpy.context.scene.frame_start
-
-  for obj in bpy.context.selected_objects:
-    if obj.type == 'MESH':
-      nsurface = md3Surface()
-      nsurface.name = obj.name
-      nsurface.ident = MD3_IDENT
-
-      vertlist = []
-
-      for f,face in enumerate(obj.data.faces):
-        ntri = md3Triangle()
-        if len(face.verts) != 3:
-          message(log,"Found a nontriangle face in object " + obj.name)
-          continue
-
-        for v,vert_index in enumerate(face.verts):
-          uv_u = round(obj.data.active_uv_texture.data[f].uv[v][0],5)
-          uv_v = round(obj.data.active_uv_texture.data[f].uv[v][1],5)
-
-          match = 0
-          match_index = 0
-          for i,vi in enumerate(vertlist):
-            if vi == vert_index:
-              if settings.ignoreuvs:
-                match = 1#there is a uv match for all
-                match_index = i
-              else:
-                if nsurface.uv[i].u == uv_u and nsurface.uv[i].v == uv_v:
-                  match = 1
-                  match_index = i
-
-          if match == 0:
-            vertlist.append(vert_index)
-            ntri.indexes[v] = nsurface.numVerts
-            ntex = md3TexCoord()
-            ntex.u = uv_u
-            ntex.v = uv_v
-            nsurface.uv.append(ntex)
-            nsurface.numVerts += 1
-          else:
-            ntri.indexes[v] = match_index
-        nsurface.triangles.append(ntri)
-        nsurface.numTriangles += 1
-
-      if obj.data.active_uv_texture:
-        nshader = md3Shader()
-        nshader.name = obj.data.active_uv_texture.name
-        nshader.index = nsurface.numShaders
-        nsurface.shaders.append(nshader)
-        nsurface.numShaders += 1
-      if nsurface.numShaders < 1: #we should add a blank as a placeholder
-        nshader = md3Shader()
-        nshader.name = "NULL"
-        nsurface.shaders.append(nshader)
-        nsurface.numShaders += 1
-
-      for frame in range(bpy.context.scene.frame_start,bpy.context.scene.frame_end + 1):
-        bpy.context.scene.set_frame(frame)
-        fobj = obj.create_mesh(bpy.context.scene,True,'PREVIEW')
-        fobj.calc_normals()
-        nframe = md3Frame()
-        nframe.name = str(frame)
-        for vi in vertlist:
-            vert = fobj.verts[vi]
-            nvert = md3Vert()
-            nvert.xyz = vert.co * obj.matrix_world
-            nvert.xyz[0] = (round(nvert.xyz[0] + obj.matrix_world[3][0],5) * settings.scale) + settings.offsetx
-            nvert.xyz[1] = (round(nvert.xyz[1] + obj.matrix_world[3][1],5) * settings.scale) + settings.offsety
-            nvert.xyz[2] = (round(nvert.xyz[2] + obj.matrix_world[3][2],5) * settings.scale) + settings.offsetz
-            nvert.normal = nvert.Encode(vert.normal)
-            for i in range(0,3):
-              nframe.mins[i] = min(nframe.mins[i],nvert.xyz[i])
-              nframe.maxs[i] = max(nframe.maxs[i],nvert.xyz[i])
-            minlength = math.sqrt(math.pow(nframe.mins[0],2) + math.pow(nframe.mins[1],2) + math.pow(nframe.mins[2],2))
-            maxlength = math.sqrt(math.pow(nframe.maxs[0],2) + math.pow(nframe.maxs[1],2) + math.pow(nframe.maxs[2],2))
-            nframe.radius = round(max(minlength,maxlength),5)
-            nsurface.verts.append(nvert)
-        md3.frames.append(nframe)
-        nsurface.numFrames += 1
-        bpy.data.meshes.remove(fobj)
-      md3.surfaces.append(nsurface)
-      md3.numSurfaces += 1
-
-    elif obj.type == 'EMPTY':
-      md3.numTags += 1
-      for frame in range(bpy.context.scene.frame_start,bpy.context.scene.frame_end + 1):
-        bpy.context.scene.set_frame(frame)
-        ntag = md3Tag()
-        ntag.origin[0] = (round(obj.matrix_world[3][0] * settings.scale,5)) + settings.offsetx
-        ntag.origin[1] = (round(obj.matrix_world[3][1] * settings.scale,5)) + settings.offsety
-        ntag.origin[2] = (round(obj.matrix_world[3][2] * settings.scale,5)) + settings.offsetz
-        ntag.axis[0] = obj.matrix_world[0][0]
-        ntag.axis[1] = obj.matrix_world[0][1]
-        ntag.axis[2] = obj.matrix_world[0][2]
-        ntag.axis[3] = obj.matrix_world[1][0]
-        ntag.axis[4] = obj.matrix_world[1][1]
-        ntag.axis[5] = obj.matrix_world[1][2]
-        ntag.axis[6] = obj.matrix_world[2][0]
-        ntag.axis[7] = obj.matrix_world[2][1]
-        ntag.axis[8] = obj.matrix_world[2][2]
-        md3.tags.append(ntag)
-
-  if md3.numSurfaces < 1:
-    message(log,"Select a mesh to export!")
-    if log:
-      log.close()
-    return
-
-  file = open(settings.savepath, "wb")
-  md3.Save(file)
-  print_md3(log,md3,settings.dumpall)
-  file.close()
-
-  message(log,"MD3: " + settings.name + " saved to " + settings.savepath)
-  if log:
-    print("Logged to",settings.logpath)
-    log.close()
-
-from bpy.props import *
-class ExportMD3(bpy.types.Operator):
-  """Export to Quake Model 3 (.md3)"""
-  bl_idname = "export.md3"
-  bl_label = 'Export MD3'
-
-  filepath: StringProperty(subtype = 'FILE_PATH',name="File Path", description="Filepath for exporting", maxlen= 1024, default= "")
-  md3name: StringProperty(name="MD3 Name", description="MD3 header name / skin path (64 bytes)",maxlen=64,default="")
-  md3log: StringProperty(name="MD3 Log", description="MD3 log file path",maxlen=1024,default="export_md3.log")
-  md3overwritelog: BoolProperty(name="Overwrite log", description="Overwrite log (off == append)", default=True)
-  md3dumpall: BoolProperty(name="Dump all", description="Dump all data for md3 to log",default=False)
-  md3ignoreuvs: BoolProperty(name="Ignore UVs", description="Ignores uv influence on mesh generation. Use if uv map not made.",default=False)
-  md3scale: FloatProperty(name="Scale", description="Scale all objects from world origin (0,0,0)",default=1.0,precision=5)
-  md3offsetx: FloatProperty(name="Offset X", description="Transition scene along x axis",default=0.0,precision=5)
-  md3offsety: FloatProperty(name="Offset Y", description="Transition scene along y axis",default=0.0,precision=5)
-  md3offsetz: FloatProperty(name="Offset Z", description="Transition scene along z axis",default=0.0,precision=5)
-
-  def execute(self, context):
-   settings = md3Settings(savepath = self.properties.filepath,
-                          name = self.properties.md3name,
-                          logpath = self.properties.md3log,
-                          overwrite = self.properties.md3overwritelog,
-                          dumpall = self.properties.md3dumpall,
-                          ignoreuvs = self.properties.md3ignoreuvs,
-                          scale = self.properties.md3scale,
-                          offsetx = self.properties.md3offsetx,
-                          offsety = self.properties.md3offsety,
-                          offsetz = self.properties.md3offsetz)
-   save_md3(settings)
-   return {'FINISHED'}
-
-  def invoke(self, context, event):
-    wm = context.window_manager
-    wm.fileselect_add(self)
-    return {'RUNNING_MODAL'}
-
-  @classmethod
-  def poll(cls, context):
-    return context.active_object is not None
-
-def menu_func(self, context):
-  newpath = os.path.splitext(bpy.context.blend_data.filepath)[0] + ".md3"
-  self.layout.operator(ExportMD3.bl_idname, text="Quake Model 3 (.md3)").filepath = newpath
-
-def register():
-  bpy.types.TOPBAR_MT_file_export.append(menu_func)
-
-def unregister():
-  bpy.types.TOPBAR_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
-  register()
diff --git a/io_import_lipSync_Importer.py b/io_import_lipSync_Importer.py
deleted file mode 100644 (file)
index 08dd221..0000000
+++ /dev/null
@@ -1,540 +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 #####
-
-bl_info = {
-    "name": "LipSync Importer & Blinker",
-    "author": "Yousef Harfoush - bat3a)",
-    "version": (0, 5, 2),
-    "blender": (2, 70, 0),
-    "location": "3D window > Tool Shelf",
-    "description": "Plots Moho (Papagayo, Jlipsync, Yolo) file "
-                   "to frames and adds automatic blinking",
-    "warning": "",
-    "wiki_url": "https://wiki.blender.org/index.php?title=Extensions:2.6/Py/"
-                "Scripts/Import-Export/Lipsync Importer",
-    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
-    "category": "Import-Export"}
-
-
-import bpy
-import re
-from random import random
-from bpy.props import (
-        EnumProperty,
-        IntProperty,
-        FloatProperty,
-        StringProperty,
-        PointerProperty,
-        )
-
-global lastPhoneme
-lastPhoneme = "nothing"
-
-
-# add blinking
-def blinker():
-
-    scn = bpy.context.scene
-
-    if scn.regMenuTypes.enumBlinkTypes == '0':
-        modifier = 0
-    elif scn.regMenuTypes.enumBlinkTypes == '1':
-        modifier = scn.regMenuTypes.blinkMod
-
-    # creating keys with blinkNm count
-    for y in range(scn.regMenuTypes.blinkNm):
-        frame = y * scn.regMenuTypes.blinkSp + int(random() * modifier)
-        createShapekey('blink', frame)
-
-
-# -- code contributed by dalai felinto adds armature support modified by me --
-
-bone_keys = {
-    "AI": ('location', 0),
-    "E": ('location', 1),
-    "FV": ('location', 2),
-    "L": ('rotation_euler', 0),
-    "MBP": ('rotation_euler', 1),
-    "O": ('rotation_euler', 2),
-    "U": ('scale', 0),
-    "WQ": ('scale', 1),
-    "etc": ('scale', 2),
-    "rest": ('ik_stretch', -1)
-}
-
-
-def lipsyncerBone():
-    # reading imported file & creating keys
-    scene = bpy.context.scene
-    bone = bpy.context.active_pose_bone
-
-    resetBoneScale(bone)
-
-    f = open(scene.regMenuTypes.fpath)  # importing file
-    f.readline()           # reading the 1st line that we don"t need
-
-    for line in f:
-        # removing new lines
-        lsta = re.split("\n+", line)
-
-        # building a list of frames & shapes indexes
-        lst = re.split(":? ", lsta[0])  # making a list of a frame & number
-        frame = int(lst[0])
-
-        for key, attribute in bone_keys.items():
-            if lst[1] == key:
-                createBoneKeys(key, bone, attribute, frame)
-
-
-def resetBoneScale(bone):
-    # set the attributes used by papagayo to 0.0
-    for attribute, index in bone_keys.values():
-        if index != -1:
-            # bone.location[0] = 0.0
-            exec("bone.%s[%d] = %f" % (attribute, index, 0.0))
-        else:
-            exec("bone.%s = %f" % (attribute, 0.0))
-
-
-def addBoneKey(bone, data_path, index=-1, value=None, frame=0, group=""):
-    # set a value and keyframe for the bone
-    # it assumes the 'bone' variable was defined before
-    # and it's the current selected bone
-    frame = bpy.context.scene.frame_current
-    if value is not None:
-        if index != -1:
-            # bone.location[0] = 0.0
-            exec("bone.%s[%d] = %f" % (data_path, index, value))
-        else:
-            exec("bone.%s = %f" % (data_path, value))
-
-    # bone.keyframe_insert("location", 0, 10.0, "Lipsync")
-    exec('bone.keyframe_insert("%s", %d, %f, "%s")' % (data_path, index, frame, group))
-
-
-# creating keys with offset and eases for a phonem @ the Skframe
-def createBoneKeys(phoneme, bone, attribute, frame):
-    global lastPhoneme
-
-    scene = bpy.context.scene
-
-    offst = scene.regMenuTypes.offset     # offset value
-    skVlu = scene.regMenuTypes.skscale    # shape key value
-
-    # in case of Papagayo format
-    if scene.regMenuTypes.enumFileTypes == '0':
-        frmIn = scene.regMenuTypes.easeIn     # ease in value
-        frmOut = scene.regMenuTypes.easeOut   # ease out value
-        hldIn = scene.regMenuTypes.holdGap    # holding time value
-
-    # in case of Jlipsync format or Yolo
-    elif scene.regMenuTypes.enumFileTypes == '1':
-        frmIn = 1
-        frmOut = 1
-        hldIn = 0
-
-    # inserting the In key only when phonem change or when blinking
-    if lastPhoneme != phoneme or eval(scene.regMenuTypes.enumModeTypes) == 1:
-        addBoneKey(bone, attribute[0], attribute[1], 0.0, offst + frame - frmIn, "Lipsync")
-
-    addBoneKey(bone, attribute[0], attribute[1], skVlu, offst + frame, "Lipsync")
-    addBoneKey(bone, attribute[0], attribute[1], skVlu, offst + frame + hldIn, "Lipsync")
-    addBoneKey(bone, attribute[0], attribute[1], 0.0, offst + frame + hldIn + frmOut, "Lipsync")
-
-    lastPhoneme = phoneme
-
-
-# -------------------------------------------------------------------------------
-
-# reading imported file & creating keys
-def lipsyncer():
-
-    obj = bpy.context.object
-    scn = bpy.context.scene
-
-    f = open(bpy.path.abspath(scn.regMenuTypes.fpath))  # importing file
-    f.readline()         # reading the 1st line that we don"t need
-
-    for line in f:
-
-        # removing new lines
-        lsta = re.split("\n+", line)
-
-        # building a list of frames & shapes indexes
-        lst = re.split(":? ", lsta[0])  # making a list of a frame & number
-        frame = int(lst[0])
-
-        for key in obj.data.shape_keys.key_blocks:
-            if lst[1] == key.name:
-                createShapekey(key.name, frame)
-
-
-# creating keys with offset and eases for a phonem @ the frame
-def createShapekey(phoneme, frame):
-
-    global lastPhoneme
-
-    scn = bpy.context.scene
-    obj = bpy.context.object
-    objSK = obj.data.shape_keys
-
-    offst = scn.regMenuTypes.offset     # offset value
-    skVlu = scn.regMenuTypes.skscale    # shape key value
-
-    # in case of Papagayo format
-    if scn.regMenuTypes.enumFileTypes == '0':
-        frmIn = scn.regMenuTypes.easeIn     # ease in value
-        frmOut = scn.regMenuTypes.easeOut   # ease out value
-        hldIn = scn.regMenuTypes.holdGap    # holding time value
-
-    # in case of Jlipsync format or Yolo
-    elif scn.regMenuTypes.enumFileTypes == '1':
-        frmIn = 1
-        frmOut = 1
-        hldIn = 0
-
-    # inserting the In key only when phonem change or when blinking
-    if lastPhoneme != phoneme or eval(scn.regMenuTypes.enumModeTypes) == 1:
-        objSK.key_blocks[phoneme].value = 0.0
-        objSK.key_blocks[phoneme].keyframe_insert(
-            "value", -1, offst + frame - frmIn, "Lipsync"
-            )
-
-    objSK.key_blocks[phoneme].value = skVlu
-    objSK.key_blocks[phoneme].keyframe_insert(
-            "value", -1, offst + frame, "Lipsync"
-            )
-    objSK.key_blocks[phoneme].value = skVlu
-    objSK.key_blocks[phoneme].keyframe_insert(
-            "value", -1, offst + frame + hldIn, "Lipsync"
-            )
-    objSK.key_blocks[phoneme].value = 0.0
-    objSK.key_blocks[phoneme].keyframe_insert(
-            "value", -1, offst + frame + hldIn + frmOut, "Lipsync"
-            )
-    lastPhoneme = phoneme
-
-
-# lipsyncer operation start
-class btn_lipsyncer(bpy.types.Operator):
-    bl_idname = 'lipsync.go'
-    bl_label = 'Start Processing'
-    bl_description = 'Plots the voice file keys to timeline'
-
-    def execute(self, context):
-
-        scn = context.scene
-        obj = context.active_object
-
-        # testing if object is valid
-        if obj is not None:
-            if obj.type == "MESH":
-                if obj.data.shape_keys is not None:
-                    if scn.regMenuTypes.fpath != '':
-                        lipsyncer()
-                    else:
-                        print("select a Moho file")
-                else:
-                    print("No shape keys")
-
-            elif obj.type == "ARMATURE":
-                if 1:  # XXX add prop test
-                    if scn.regMenuTypes.fpath != '':
-                        lipsyncerBone()
-                    else:
-                        print("select a Moho file")
-                else:
-                    print("Create Pose properties")
-            else:
-                print("Object is not a mesh ot bone")
-        else:
-            print("Select object")
-
-        return {'FINISHED'}
-
-
-# blinker operation start
-class btn_blinker(bpy.types.Operator):
-    bl_idname = 'blink.go'
-    bl_label = 'Start Processing'
-    bl_description = 'Add blinks at random or specifice frames'
-
-    def execute(self, context):
-
-        obj = context.object
-
-        # testing if object is valid
-        if obj is not None:
-            if obj.type == "MESH":
-                if obj.data.shape_keys is not None:
-                    for key in obj.data.shape_keys.key_blocks:
-                        if key.name == 'blink':
-                            blinker()
-                            # return
-                else:
-                    print("No shape keys")
-            else:
-                print("Object is not a mesh ot bone")
-        else:
-            print("Select object")
-
-        return {'FINISHED'}
-
-
-# defining custom enumeratos
-class menuTypes(bpy.types.PropertyGroup):
-
-    enumFileTypes: EnumProperty(
-            items=(('0', 'Papagayo', ''),
-                    ('1', 'Jlipsync Or Yolo', '')
-                    # ('2', 'Retarget', '')
-                    ),
-            name='Choose FileType',
-            default='0'
-            )
-    enumBlinkTypes: EnumProperty(
-            items=(('0', 'Specific', ''),
-                    ('1', 'Random', '')),
-            name='Choose BlinkType',
-            default='0'
-            )
-    enumModeTypes: EnumProperty(
-            items=(('0', 'Lipsyncer', ''),
-                   ('1', 'Blinker', '')),
-            name='Choose Mode',
-            default='0'
-            )
-
-    fpath: StringProperty(
-            name="Import File ",
-            description="Select your voice file",
-            subtype="FILE_PATH"
-            )
-    skscale: FloatProperty(
-            description="Smoothing shape key values",
-            min=0.1, max=1.0,
-            default=0.8
-            )
-    offset: IntProperty(
-            description="Offset your frames",
-            default=0
-            )
-    easeIn: IntProperty(
-            description="Smoothing In curve",
-            min=1, default=3
-            )
-    easeOut: IntProperty(
-            description="Smoothing Out curve",
-            min=1,
-            default=3
-            )
-    holdGap: IntProperty(
-            description="Holding for slow keys",
-            min=0,
-            default=0
-            )
-    blinkSp: IntProperty(
-            description="Space between blinks",
-            min=1,
-            default=100
-            )
-    blinkNm: IntProperty(
-            description="Number of blinks",
-            min=1,
-            default=10
-            )
-    blinkMod: IntProperty(
-            description="Randomzing keyframe placment",
-            min=1,
-            default=10
-            )
-
-
-# drawing the user interface
-class LipSyncBoneUI(bpy.types.Panel):
-    bl_space_type = "VIEW_3D"
-    bl_region_type = "UI"
-    bl_label = "Phonemes"
-    bl_category = 'Animation'
-
-    def draw(self, context):
-        layout = self.layout
-        col = layout.column()
-
-        bone = bpy.context.active_pose_bone
-
-        # showing the current object type
-        if bone:  # and if scn.regMenuTypes.enumModeTypes == '0':
-            col.prop(bone, "location", index=0, text="AI")
-            col.prop(bone, "location", index=1, text="E")
-            col.prop(bone, "location", index=2, text="FV")
-
-            if bpy.context.scene.unit_settings.system_rotation == 'RADIANS':
-                col.prop(bone, "rotation_euler", index=0, text="L")
-                col.prop(bone, "rotation_euler", index=1, text="MBP")
-                col.prop(bone, "rotation_euler", index=2, text="O")
-            else:
-                row = col.row()
-                row.prop(bone, "rotation_euler", index=0, text="L")
-                row.label(text=str("%4.2f" % (bone.rotation_euler.x)))
-
-                row = col.row()
-                row.prop(bone, "rotation_euler", index=1, text="MBP")
-                row.label(text=str("%4.2f" % (bone.rotation_euler.y)))
-
-                row = col.row()
-                row.prop(bone, "rotation_euler", index=2, text="O")
-                row.label(text=str("%4.2f" % (bone.rotation_euler.z)))
-
-            col.prop(bone, "scale", index=0, text="U")
-            col.prop(bone, "scale", index=1, text="WQ")
-            col.prop(bone, "scale", index=2, text="etc")
-        else:
-            layout.label(text="No good bone is selected")
-
-
-# drawing the user interface
-class LipSyncUI(bpy.types.Panel):
-    bl_space_type = "VIEW_3D"
-    bl_region_type = "TOOL_PROPS"
-    bl_label = "LipSync Importer & Blinker"
-
-    def draw(self, context):
-        obj = bpy.context.active_object
-        scn = bpy.context.scene
-
-        layout = self.layout
-        col = layout.column()
-
-        # showing the current object type
-        if obj is not None:
-            if obj.type == "MESH":
-                split = col.split(align=True)
-                split.label(text="The active object is: ", icon="OBJECT_DATA")
-                split.label(text=obj.name, icon="EDITMODE_HLT")
-
-            elif obj.type == "ARMATURE":  # bone needs to be selected
-                if obj.mode == "POSE":    # mode needs to be pose
-                    split = col.split(align=True)
-                    split.label(text="The active object is: ", icon="ARMATURE_DATA")
-                    split.label(text=obj.name, icon="EDITMODE_HLT")
-                else:
-                    col.label(text="You need to select Pose mode!", icon="OBJECT_DATA")
-            else:
-                col.label(text="The active object is not a Mesh or Armature!", icon="OBJECT_DATA")
-        else:
-            layout.label(text="No object is selected", icon="OBJECT_DATA")
-
-        col.row().prop(scn.regMenuTypes, 'enumModeTypes')
-        col.separator()
-
-        # the lipsyncer panel
-        if scn.regMenuTypes.enumModeTypes == '0':
-            # choose the file format
-            col.row().prop(scn.regMenuTypes, 'enumFileTypes', text=' ', expand=True)
-
-            # Papagayo panel
-            if scn.regMenuTypes.enumFileTypes == '0':
-                col.prop(scn.regMenuTypes, "fpath")
-
-                split = col.split(align=True)
-                split.label(text="Key Value :")
-                split.prop(scn.regMenuTypes, "skscale")
-
-                split = col.split(align=True)
-                split.label(text="Frame Offset :")
-                split.prop(scn.regMenuTypes, "offset")
-
-                split = col.split(align=True)
-                split.prop(scn.regMenuTypes, "easeIn", "Ease In")
-                split.prop(scn.regMenuTypes, "holdGap", "Hold Gap")
-                split.prop(scn.regMenuTypes, "easeOut", "Ease Out")
-
-                col.operator('lipsync.go', text='Plot Keys to the Timeline')
-
-            # Jlipsync & Yolo panel
-            elif scn.regMenuTypes.enumFileTypes == '1':
-                col.prop(scn.regMenuTypes, "fpath")
-                split = col.split(align=True)
-                split.label(text="Key Value :")
-                split.prop(scn.regMenuTypes, "skscale")
-
-                split = col.split(align=True)
-                split.label(text="Frame Offset :")
-                split.prop(scn.regMenuTypes, "offset")
-
-                col.operator('lipsync.go', text='Plot Keys to the Timeline')
-
-        # the blinker panel
-        elif scn.regMenuTypes.enumModeTypes == '1':
-            # choose blink type
-            col.row().prop(scn.regMenuTypes, 'enumBlinkTypes', text=' ', expand=True)
-
-            # specific panel
-            if scn.regMenuTypes.enumBlinkTypes == '0':
-                split = col.split(align=True)
-                split.label(text="Key Value :")
-                split.prop(scn.regMenuTypes, "skscale")
-
-                split = col.split(align=True)
-                split.label(text="Frame Offset :")
-                split.prop(scn.regMenuTypes, "offset")
-
-                split = col.split(align=True)
-                split.prop(scn.regMenuTypes, "easeIn", "Ease In")
-                split.prop(scn.regMenuTypes, "holdGap", "Hold Gap")
-                split.prop(scn.regMenuTypes, "easeOut", "Ease Out")
-                col.prop(scn.regMenuTypes, "blinkSp", "Spacing")
-                col.prop(scn.regMenuTypes, "blinkNm", "Times")
-                col.operator('blink.go', text='Add Keys to the Timeline')
-
-            # Random panel
-            elif scn.regMenuTypes.enumBlinkTypes == '1':
-                split = col.split(align=True)
-                split.label(text="Key Value :")
-                split.prop(scn.regMenuTypes, "skscale")
-
-                split = col.split(align=True)
-                split.label(text="Frame Start :")
-                split.prop(scn.regMenuTypes, "offset")
-
-                split = col.split(align=True)
-                split.prop(scn.regMenuTypes, "easeIn", "Ease In")
-                split.prop(scn.regMenuTypes, "holdGap", "Hold Gap")
-                split.prop(scn.regMenuTypes, "easeOut", "Ease Out")
-
-                split = col.split(align=True)
-                split.prop(scn.regMenuTypes, "blinkSp", "Spacing")
-                split.prop(scn.regMenuTypes, "blinkMod", "Random Modifier")
-                col.prop(scn.regMenuTypes, "blinkNm", "Times")
-                col.operator('blink.go', text='Add Keys to the Timeline')
-
-
-# registering the script
-def register():
-    bpy.utils.register_module(__name__)
-    bpy.types.Scene.regMenuTypes = PointerProperty(type=menuTypes)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-    del bpy.types.Scene.regMenuTypes
-
-
-if __name__ == "__main__":
-    register()
diff --git a/io_mesh_raw/__init__.py b/io_mesh_raw/__init__.py
deleted file mode 100644 (file)
index 9219efa..0000000
+++ /dev/null
@@ -1,121 +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-80 compliant>
-
-
-bl_info = {
-    "name": "Raw mesh format (.raw)",
-    "author": "Anthony D,Agostino (Scorpius), Aurel Wildfellner",
-    "version": (0, 2),
-    "blender": (2, 57, 0),
-    "location": "File > Import-Export > Raw Faces (.raw) ",
-    "description": "Import-Export Raw Faces",
-    "warning": "",
-    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/Raw_Mesh_IO",
-    "category": "Import-Export",
-}
-
-if "bpy" in locals():
-    import importlib
-    if "import_raw" in locals():
-        importlib.reload(import_raw)
-    if "export_raw" in locals():
-        importlib.reload(export_raw)
-else:
-    import bpy
-
-from bpy.props import StringProperty, BoolProperty
-from bpy_extras.io_utils import ExportHelper
-
-
-class RawImporter(bpy.types.Operator):
-    """Load Raw triangle mesh data"""
-    bl_idname = "import_mesh.raw"
-    bl_label = "Import RAW"
-    bl_options = {'UNDO'}
-
-    filepath: StringProperty(
-            subtype='FILE_PATH',
-            )
-    filter_glob: StringProperty(default="*.raw", options={'HIDDEN'})
-
-    def execute(self, context):
-        from . import import_raw
-        import_raw.read(self.filepath)
-        return {'FINISHED'}
-
-    def invoke(self, context, event):
-        wm = context.window_manager
-        wm.fileselect_add(self)
-        return {'RUNNING_MODAL'}
-
-
-class RawExporter(bpy.types.Operator, ExportHelper):
-    """Save Raw triangle mesh data"""
-    bl_idname = "export_mesh.raw"
-    bl_label = "Export RAW"
-
-    filename_ext = ".raw"
-    filter_glob: StringProperty(default="*.raw", options={'HIDDEN'})
-
-    apply_modifiers: BoolProperty(
-            name="Apply Modifiers",
-            description="Use transformed mesh data from each object",
-            default=True,
-            )
-    triangulate: BoolProperty(
-            name="Triangulate",
-            description="Triangulate quads",
-            default=True,
-            )
-
-    def execute(self, context):
-        from . import export_raw
-        export_raw.write(self.filepath,
-                         self.apply_modifiers,
-                         self.triangulate,
-                         )
-
-        return {'FINISHED'}
-
-
-def menu_import(self, context):
-    self.layout.operator(RawImporter.bl_idname, text="Raw Faces (.raw)")
-
-
-def menu_export(self, context):
-    self.layout.operator(RawExporter.bl_idname, text="Raw Faces (.raw)")
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_import.append(menu_import)
-    bpy.types.TOPBAR_MT_file_export.append(menu_export)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_import.remove(menu_import)
-    bpy.types.TOPBAR_MT_file_export.remove(menu_export)
-
-if __name__ == "__main__":
-    register()
diff --git a/io_mesh_raw/export_raw.py b/io_mesh_raw/export_raw.py
deleted file mode 100644 (file)
index ed34e3a..0000000
+++ /dev/null
@@ -1,101 +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-80 compliant>
-
-"""
-This script exports a Mesh to a RAW triangle format file.
-
-The raw triangle format is very simple; it has no verts or faces lists.
-It's just a simple ascii text file with the vertices of each triangle
-listed on each line. In addition, also quads can be exported as a line
-of 12 values (this was the default before blender 2.5). Now default
-settings will triangulate the mesh.
-
-Usage:
-Execute this script from the "File->Export" menu. You can select
-whether modifiers should be applied and if the mesh is triangulated.
-
-"""
-
-import bpy
-
-
-def faceToTriangles(face):
-    triangles = []
-    if len(face) == 4:
-        triangles.append([face[0], face[1], face[2]])
-        triangles.append([face[2], face[3], face[0]])
-    else:
-        triangles.append(face)
-
-    return triangles
-
-
-def faceValues(face, mesh, matrix):
-    fv = []
-    for verti in face.vertices:
-        fv.append((matrix * mesh.vertices[verti].co)[:])
-    return fv
-
-
-def faceToLine(face):
-    return " ".join([("%.6f %.6f %.6f" % v) for v in face] + ["\n"])
-
-
-def write(filepath,
-          applyMods=True,
-          triangulate=True,
-          ):
-
-    scene = bpy.context.scene
-    depsgraph = bpy.context.evaluated_depsgraph_get()
-
-    faces = []
-    for obj in bpy.context.selected_objects:
-        obj_eval = None
-        if applyMods or obj.type != 'MESH':
-            try:
-                obj_eval = obj.evaluated_get(depsgraph)
-                me = obj_eval.to_mesh()
-            except:
-                me = None
-            is_tmp_mesh = True
-        else:
-            me = obj.data
-            if not me.tessfaces and me.polygons:
-                me.calc_tessface()
-            is_tmp_mesh = False
-
-        if me is not None:
-            matrix = obj.matrix_world.copy()
-            for face in me.tessfaces:
-                fv = faceValues(face, me, matrix)
-                if triangulate:
-                    faces.extend(faceToTriangles(fv))
-                else:
-                    faces.append(fv)
-
-            if is_tmp_mesh:
-                obj_eval.to_mesh_clear()
-
-    # write the faces to a file
-    file = open(filepath, "w")
-    for face in faces:
-        file.write(faceToLine(face))
-    file.close()
diff --git a/io_mesh_raw/import_raw.py b/io_mesh_raw/import_raw.py
deleted file mode 100644 (file)
index 093ee7a..0000000
+++ /dev/null
@@ -1,116 +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-80 compliant>
-
-"""
-This script imports Raw Triangle File format files to Blender.
-
-The raw triangle format is very simple; it has no verts or faces lists.
-It's just a simple ascii text file with the vertices of each triangle
-listed on each line. In addition, a line with 12 values will be
-imported as a quad. This may be in conflict with some other
-applications, which use a raw format, but this is how it was
-implemented back in blender 2.42.
-
-Usage:
-Execute this script from the "File->Import" menu and choose a Raw file to
-open.
-
-Notes:
-Generates the standard verts and faces lists, but without duplicate
-verts. Only *exact* duplicates are removed, there is no way to specify a
-tolerance.
-"""
-
-
-import bpy
-
-
-def readMesh(filename, objName):
-    filehandle = open(filename, "rb")
-
-    def line_to_face(line):
-        # Each triplet is an xyz float
-        line_split = line.split()
-        try:
-            line_split_float = map(float, line_split)
-        except:
-            return None
-
-        if len(line_split) in {9, 12}:
-            return zip(*[iter(line_split_float)] * 3)  # group in 3's
-        else:
-            return None
-
-    faces = []
-    for line in filehandle.readlines():
-        face = line_to_face(line)
-        if face:
-            faces.append(face)
-
-    filehandle.close()
-
-    # Generate verts and faces lists, without duplicates
-    verts = []
-    coords = {}
-    index_tot = 0
-    faces_indices = []
-
-    for f in faces:
-        fi = []
-        for i, v in enumerate(f):
-            index = coords.get(v)
-
-            if index is None:
-                index = coords[v] = index_tot
-                index_tot += 1
-                verts.append(v)
-
-            fi.append(index)
-
-        faces_indices.append(fi)
-
-    mesh = bpy.data.meshes.new(objName)
-    mesh.from_pydata(verts, [], faces_indices)
-
-    return mesh
-
-
-def addMeshObj(mesh, objName):
-    scn = bpy.context.scene
-
-    for o in scn.objects:
-        o.select_set(False)
-
-    mesh.update()
-    mesh.validate()
-
-    nobj = bpy.data.objects.new(objName, mesh)
-    scn.objects.link(nobj)
-    nobj.select_set(True)
-
-    if scn.objects.active is None or scn.objects.active.mode == 'OBJECT':
-        scn.objects.active = nobj
-
-
-def read(filepath):
-    #convert the filename to an object name
-    objName = bpy.path.display_name_from_filepath(filepath)
-    mesh = readMesh(filepath, objName)
-    addMeshObj(mesh, objName)
diff --git a/io_points_pcd/__init__.py b/io_points_pcd/__init__.py
deleted file mode 100644 (file)
index 0b72b44..0000000
+++ /dev/null
@@ -1,129 +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 #####
-
-bl_info = {
-    "name": "PCD",
-    "author": "Aurel Wildfellner",
-    "version": (0, 2),
-    "blender": (2, 57, 0),
-    "location": "File > Import-Export > Point Cloud Data",
-    "description": "Imports and Exports PCD (Point Cloud Data) files. PCD files are the default format used by  pcl (Point Cloud Library).",
-    "warning": "",
-    "wiki_url": "http://wiki.blender.org/index.php?title=Extensions:2.6/Py/Scripts/Import-Export/Point_Cloud_Data_IO",
-    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
-#    "support": 'OFFICAL',
-    "category": "Import-Export"}
-
-
-if "bpy" in locals():
-    import imp
-    imp.reload(pcd_utils)
-else:
-    from . import pcd_utils
-
-import itertools
-import os
-
-
-import bpy
-from bpy.props import *
-from bpy_extras.io_utils import ExportHelper, ImportHelper
-
-
-class ImportPCD(bpy.types.Operator, ImportHelper):
-    """Load PCD (Point Cloud Data) files"""
-    bl_idname = "import_points.stl"
-    bl_label = "Import PCD"
-
-    filename_ext = ".pcd"
-
-    filter_glob: StringProperty(default="*.pcd", options={'HIDDEN'})
-    object_name: StringProperty(default="", options={'HIDDEN'})
-
-    files: CollectionProperty(name="File Path",
-                          description="File path used for importing "
-                                      "the PCD file",
-                          type=bpy.types.OperatorFileListElement)
-
-    directory: StringProperty(subtype='DIR_PATH')
-
-    def execute(self, context):
-        paths = [os.path.join(self.directory, name.name) for name in self.files]
-        if not paths:
-            paths.append(self.filepath)
-
-        for path in paths:
-
-            objname = ""
-
-            if self.object_name == "":
-                # name the object with the filename exluding .pcd
-                objname = os.path.basename(path)[:-4]
-            else:
-                # use name set by calling the operator with the arg
-                objname = self.object_name
-
-            pcd_utils.import_pcd(path, objname)
-
-        return {'FINISHED'}
-
-
-
-
-class ExportPCD(bpy.types.Operator, ExportHelper):
-    """Save PCD (Point Cloud Data) files"""
-    bl_idname = "export_points.pcd"
-    bl_label = "Export PCD"
-
-    filename_ext = ".pcd"
-
-    filter_glob: StringProperty(default="*.pcd", options={'HIDDEN'})
-
-
-    def execute(self, context):
-        pcd_utils.export_pcd(self.filepath)
-
-        return {'FINISHED'}
-
-
-
-
-def menu_func_import(self, context):
-    self.layout.operator(ImportPCD.bl_idname, text="Point Cloud Data (.pcd)").filepath = "*.pcd"
-
-
-def menu_func_export(self, context):
-    self.layout.operator(ExportPCD.bl_idname, text="Point Cloud Data (.pcd)")
-
-
-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_points_pcd/pcd_utils.py b/io_points_pcd/pcd_utils.py
deleted file mode 100644 (file)
index 6b4315c..0000000
+++ /dev/null
@@ -1,93 +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 #####
-
-import bpy
-
-import os
-import subprocess
-import tempfile
-
-from . import pcdparser
-
-
-def create_and_link_mesh(name, points):
-    """
-    Create a blender mesh and object called name from a list of
-    *points* and link it in the current scene.
-    """
-
-    mesh = bpy.data.meshes.new(name)
-    mesh.from_pydata(points, [], [])
-
-    # update mesh to allow proper display
-    mesh.validate()
-    mesh.update()
-
-    obj = bpy.data.objects.new(name, mesh)
-    bpy.context.collection.objects.link(obj)
-    obj.select_set(True)
-
-
-def import_pcd(filepath, name="new_pointcloud"):
-    # check if the file is binary compressed
-    parser = pcdparser.PCDParser.factory(filepath, pcdparser.PointXYZ)
-    parser.onlyParseHeader()
-    is_binary_compressed = parser.datatype == 'BINARY_COMPRESSED'
-
-    # create a temp uncompressed pcd file
-    if (is_binary_compressed):
-        tmpdir = tempfile.TemporaryDirectory()
-        tmpfilepath = tmpdir.name + "blender_pcd_io_tmp.pcd"
-        try:
-            subprocess.call(["pcl_convert_pcd_ascii_binary", filepath, tmpfilepath, "1"])
-        except FileNotFoundError:
-            print("[ERROR] Can't read BINARY COMPRESSED PCD. No pcl_convert_pcd_ascii_binary found! Have you installed libPCL?")
-            return
-        filepath = tmpfilepath
-
-
-    # do actual parsing
-    parser = pcdparser.PCDParser.factory(filepath, pcdparser.PointXYZ)
-    parser.parseFile()
-    points = parser.getPoints()
-
-    blender_points = []
-    for point in points:
-        blender_points.append((point.x, point.y, point.z))
-
-    create_and_link_mesh(name, blender_points)
-
-
-def export_pcd(filepath):
-    obj = bpy.context.active_object
-
-    # apply object transformation and modifiers
-    mesh = obj.to_mesh(bpy.context.scene, True, "PREVIEW")
-    objmat = obj.matrix_world
-
-    points = []
-    for vert in mesh.vertices:
-        co = objmat * vert.co
-        point = pcdparser.PointXYZ()
-        point.x = co.x
-        point.y = co.y
-        point.z = co.z
-        points.append(point)
-
-    writer = pcdparser.PCDWriter(points)
-    writer.write(filepath)
diff --git a/io_points_pcd/pcdparser.py b/io_points_pcd/pcdparser.py
deleted file mode 100644 (file)
index 7827785..0000000
+++ /dev/null
@@ -1,418 +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 #####
-
-
-import struct
-import io
-
-try:
-    import lzf
-    GOT_LZF_MODULE=True
-except:
-    GOT_LZF_MODULE=False
-
-
-
-def dumpHexData(data):
-    for byte in data:
-        print(hex(byte) + " ", end="")
-    print()
-
-
-def encodeASCIILine(line):
-    return line.decode(encoding='ASCII')
-
-
-
-class Point:
-
-    def __init__(self):
-        pass
-
-
-    def setField(self, fieldname, values):
-        pass
-
-
-
-
-class PointXYZ(Point):
-
-    def __init__(self):
-        super().__init__()
-        self.x = 0
-        self.y = 0
-        self.z = 0
-
-
-    def setField(self, fieldname, values):
-        value = values[0]
-        if fieldname == 'x':
-            self.x = value
-        elif fieldname == 'y':
-            self.y = value
-        elif fieldname == 'z':
-            self.z = value
-
-
-
-
-class PCDParser:
-
-    filepath = ''
-    file = None
-
-    points = []
-    PointClass = None
-
-    headerEnd = False
-
-
-    @staticmethod
-    def factory(filepath, PointClass):
-        version = 'NO_VERSION_NUMBER'
-        with open(filepath, 'rb') as f:
-            for b in f:
-                line = encodeASCIILine(b)
-                line_split = line.split()
-                if line_split[0] == 'VERSION' and len(line_split) > 1:
-                    version = line_split[1]
-                    break
-
-        if version == ".7" or version == "0.7":
-            return PCDParser_v0_7(filepath, PointClass)
-        else:
-            return None
-
-
-    def __init__(self, filepath, PointClass):
-        self.filepath = filepath
-        self.PointClass = PointClass
-
-        self.file = None
-        self.headerEnd = False
-        self.points = []
-
-
-    def parserWarning(self, msg):
-        print("[WARNING] ", msg)
-
-
-    def rmComment(self, line):
-        return line[:line.find('#')]
-
-
-    def parseFile(self):
-        with open(self.filepath, 'rb') as self.file:
-            self.parseHeader()
-            self.parsePoints()
-
-    def onlyParseHeader(self):
-        with open(self.filepath, 'rb') as self.file:
-            self.parseHeader()
-
-
-    def parseHeader(self):
-        for b in self.file:
-            line = encodeASCIILine(b)
-            line = self.rmComment(line)
-
-            split = line.split()
-            if len(split) > 0:
-                self.parseHeaderLine(split)
-
-            if self.headerEnd:
-                self.finalizeHeader()
-                break
-
-
-    def parseHeaderLine(self, split):
-        keyword = split[0]
-        self.parserWarning("Uknown header Keyword '" + keyword + "' gets ignored")
-
-
-    def finalizeHeader(self):
-        pass
-
-
-    def parsePoints(self):
-        pass
-
-
-    def getPoints(self):
-        return self.points
-
-
-    def version(self):
-        return 'NO_VERSION_NUMBER'
-
-
-
-
-class PCDParser_v0_7(PCDParser):
-
-    fields = []
-
-    def __init__(self, filepath, PointClass):
-        super().__init__(filepath, PointClass)
-        self.fields = []
-
-
-    def version(self):
-        return '.7'
-
-
-    def parseHeaderLine(self, split):
-        keyword = split[0]
-        if keyword == 'VERSION':
-            self.parseVERSION(split[1:])
-        elif keyword == 'FIELDS':
-            self.parseFIELDS(split[1:])
-        elif keyword == 'SIZE':
-            self.parseSIZE(split[1:])
-        elif keyword == 'TYPE':
-            self.parseTYPE(split[1:])
-        elif keyword == 'COUNT':
-            self.parseCOUNT(split[1:])
-        elif keyword == 'WIDTH':
-            self.parseWIDTH(split[1:])
-        elif keyword == 'HEIGHT':
-            self.parseHEIGHT(split[1:])
-        elif keyword == 'POINTS':
-            self.parsePOINTS(split[1:])
-        elif keyword == 'DATA':
-            self.parseDATA(split[1:])
-        else:
-            super().parseHeaderLine(split)
-
-
-    def parseVERSION(self, split):
-        pass
-
-
-    def parseFIELDS(self, split):
-        print("SPLIT FIELDS:", split)
-        for field in split:
-            self.fields.append([field, None, None, None])
-        print("FIELDS, after parsing:", self.fields)
-
-
-    def parseSIZE(self, split):
-        for i, size in enumerate(split):
-            self.fields[i][1] = int(size)
-
-
-    def parseTYPE(self, split):
-        for i, type in enumerate(split):
-            self.fields[i][2] = type
-
-
-    def parseCOUNT(self, split):
-        for i, count in enumerate(split):
-            self.fields[i][3] = int(count)
-
-
-    def parseWIDTH(self, split):
-        self.width = int(split[0])
-
-
-    def parseHEIGHT(self, split):
-        self.height = int(split[0])
-
-
-    def parsePOINTS(self, split):
-        pass
-
-
-    def parseDATA(self, split):
-        if split[0] == "ascii":
-            self.datatype = 'ASCII'
-        elif split[0] == "binary":
-            self.datatype = 'BINARY'
-        elif split[0] == "binary_compressed":
-            self.datatype = 'BINARY_COMPRESSED'
-        self.headerEnd = True
-
-
-    def finalizeHeader(self):
-        self.numPoints = self.width * self.height
-        print("FIELDS - finalized", self.fields)
-
-
-    def parsePoints(self):
-        if self.datatype == 'ASCII':
-            self.parseASCII()
-        elif self.datatype == 'BINARY':
-            self.parseBINARY()
-        elif self.datatype == 'BINARY_COMPRESSED':
-            if not GOT_LZF_MODULE:
-                print("[ERROR] No support for BINARY COMPRESSED data format.")
-                return
-            else:
-                self.parseBINARY_COMPRESSED()
-
-
-    def parseASCII(self):
-        parsedPoints = 0
-        while parsedPoints < self.numPoints:
-
-            try:
-                b = self.file.readline()
-                line = encodeASCIILine(b)
-            except:
-                self.parserError("Unexpected end of data")
-                return
-            line = self.rmComment(line)
-            split = line.split()
-
-            if (len(split) == 0):
-                continue
-            else:
-                parsedPoints += 1
-
-            point = self.PointClass()
-
-            for field in self.fields:
-                fieldname = field[0]
-                fieldtype = field[2]
-                fieldcount = field[3]
-
-                values = []
-                for i in range(fieldcount):
-                    vs = split.pop(0)
-                    if fieldtype == 'F':
-                        values.append(float(vs))
-                    elif fieldtype in ['U', 'I']:
-                        values.append(int(vs))
-
-                point.setField(fieldname, values)
-
-            self.points.append(point)
-
-
-    def parseBINARY_COMPRESSED(self):
-        """ BROKEN!!! - There seem to be uncompatiblities
-            with pcl LZF and liblzf"""
-        max_size = 1024**3 # 1GB
-        fs = '<i'
-        compressed_len = struct.unpack('<i', self.file.read(4))[0]
-        decompressed_len = struct.unpack('<i', self.file.read(4))[0]
-
-        compressed_body = self.file.read(compressed_len)
-        decompressed_body = lzf.decompress(compressed_body, max_size)
-
-        fobj = io.BytesIO(decompressed_body)
-        self.parseBINARY(fobj)
-
-
-
-    def parseBINARY(self, infile=""):
-
-        if infile == "":
-            infile = self.file
-
-        for pointi in range(self.numPoints):
-            point = self.PointClass()
-
-            for field in self.fields:
-                fieldname = field[0]
-                fieldsize = field[1]
-                fieldtype = field[2]
-                fieldcount = field[3]
-
-                values = []
-                for i in range(fieldcount):
-
-                    fs = None
-                    if fieldtype == 'F':
-                        if fieldsize == 4: #float
-                            fs = '<f'
-                        elif fieldsize == 8: #double
-                            fs = '<d'
-                    elif fieldtype == 'U':
-                        if fieldsize == 1: #unsinged char
-                            fs = '<B'
-                        elif fieldsize == 2: #unsinged short
-                            fs = '<H'
-                        elif fieldsize == 4: #unsinged int
-                            fs =  '<I'
-                    elif fieldtype == 'I':
-                        if fieldsize == 1: #char
-                            fs = '<c'
-                        elif fieldsize == 2: #short
-                            fs = '<h'
-                        elif fieldsize == 4: #signed int
-                            fs =  '<i'
-
-                    raw = infile.read(fieldsize)
-                    if (fs):
-                        data = struct.unpack(fs, raw)
-                        values.append(data[0])
-
-                point.setField(fieldname, values)
-
-            self.points.append(point)
-
-
-
-
-class PCDWriter:
-
-    def __init__(self, points):
-        self.points = points
-
-
-    def _header(self):
-        header =  "# .PCD v0.7 - Point Cloud Data file format\n"
-        header += "VERSION 0.7\n"
-        header += "FIELDS x y z\n"
-        header += "SIZE 4 4 4\n"
-        header += "TYPE F F F\n"
-        header += "COUNT 1 1 1\n"
-        header += "WIDTH " + str(len(self.points)) + "\n"
-        header += "HEIGHT 1\n"
-        header += "VIEWPOINT 0 0 0 1 0 0 0\n"
-        header += "POINTS " + str(len(self.points)) + "\n"
-        header += "DATA ascii\n"
-
-        return header
-
-
-    def write(self, filepath):
-
-        with open(filepath, "w") as f:
-            f.write(self._header())
-            for point in self.points:
-                f.write(str(point.x))
-                f.write(" ")
-                f.write(str(point.y))
-                f.write(" ")
-                f.write(str(point.z))
-                f.write("\n")
-
-
-
-def test():
-    parser = PCDParser.factory('test.pcd', PointXYZ)
-    if parser:
-        parser.parseFile()
-        points = parser.getPoints()
-        for point in points:
-            print(point.x, point.y, point.z)
-    else:
-        print("Can't create parser for this file")
diff --git a/io_points_pcd/test.pcd b/io_points_pcd/test.pcd
deleted file mode 100644 (file)
index 79ec41d..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-# .PCD v.7 - Point Cloud Data file format
-VERSION .7
-FIELDS x y z rgb
-SIZE 4 4 4 4
-TYPE F F F F
-COUNT 1 1 1 1
-WIDTH 213
-HEIGHT 1
-VIEWPOINT 0 0 0 1 0 0 0
-POINTS 213
-DATA ascii
-0.93773 0.33763 0 4.2108e+06
-0.90805 0.35641 0 4.2108e+06
-0.81915 0.32 0 4.2108e+06
-0.97192 0.278 0 4.2108e+06
-0.944 0.29474 0 4.2108e+06
-0.98111 0.24247 0 4.2108e+06
-0.93655 0.26143 0 4.2108e+06
-0.91631 0.27442 0 4.2108e+06
-0.81921 0.29315 0 4.2108e+06
-0.90701 0.24109 0 4.2108e+06
-0.83239 0.23398 0 4.2108e+06
-0.99185 0.2116 0 4.2108e+06
-0.89264 0.21174 0 4.2108e+06
-0.85082 0.21212 0 4.2108e+06
-0.81044 0.32222 0 4.2108e+06
-0.74459 0.32192 0 4.2108e+06
-0.69927 0.32278 0 4.2108e+06
-0.8102 0.29315 0 4.2108e+06
-0.75504 0.29765 0 4.2108e+06
-0.8102 0.24399 0 4.2108e+06
-0.74995 0.24723 0 4.2108e+06
-0.68049 0.29768 0 4.2108e+06
-0.66509 0.29002 0 4.2108e+06
-0.69441 0.2526 0 4.2108e+06
-0.62807 0.22187 0 4.2108e+06
-0.58706 0.32199 0 4.2108e+06
-0.52125 0.31955 0 4.2108e+06
-0.49351 0.32282 0 4.2108e+06
-0.44313 0.32169 0 4.2108e+06
-0.58678 0.2929 0 4.2108e+06
-0.53436 0.29164 0 4.2108e+06
-0.59308 0.24134 0 4.2108e+06
-0.5357 0.2444 0 4.2108e+06
-0.50043 0.31235 0 4.2108e+06
-0.44107 0.29711 0 4.2108e+06
-0.50727 0.22193 0 4.2108e+06
-0.43957 0.23976 0 4.2108e+06
-0.8105 0.21112 0 4.2108e+06
-0.73555 0.2114 0 4.2108e+06
-0.69907 0.21082 0 4.2108e+06
-0.63327 0.21154 0 4.2108e+06
-0.59165 0.21201 0 4.2108e+06
-0.52477 0.21491 0 4.2108e+06
-0.49375 0.21006 0 4.2108e+06
-0.4384 0.19632 0 4.2108e+06
-0.43425 0.16052 0 4.2108e+06
-0.3787 0.32173 0 4.2108e+06
-0.33444 0.3216 0 4.2108e+06
-0.23815 0.32199 0 4.808e+06
-0.3788 0.29315 0 4.2108e+06
-0.33058 0.31073 0 4.2108e+06
-0.3788 0.24399 0 4.2108e+06
-0.30249 0.29189 0 4.2108e+06
-0.23492 0.29446 0 4.808e+06
-0.29465 0.24399 0 4.2108e+06
-0.23514 0.24172 0 4.808e+06
-0.18836 0.32277 0 4.808e+06
-0.15992 0.32176 0 4.808e+06
-0.08642 0.32181 0 4.808e+06
-0.039994 0.32283 0 4.808e+06
-0.20039 0.31211 0 4.808e+06
-0.1417 0.29506 0 4.808e+06
-0.20921 0.22332 0 4.808e+06
-0.13884 0.24227 0 4.808e+06
-0.085123 0.29441 0 4.808e+06
-0.048446 0.31279 0 4.808e+06
-0.086957 0.24399 0 4.808e+06
-0.3788 0.21189 0 4.2108e+06
-0.29465 0.19323 0 4.2108e+06
-0.23755 0.19348 0 4.808e+06
-0.29463 0.16054 0 4.2108e+06
-0.23776 0.16054 0 4.808e+06
-0.19016 0.21038 0 4.808e+06
-0.15704 0.21245 0 4.808e+06
-0.08678 0.21169 0 4.808e+06
-0.012746 0.32168 0 4.808e+06
--0.075715 0.32095 0 4.808e+06
--0.10622 0.32304 0 4.808e+06
--0.16391 0.32118 0 4.808e+06
-0.00088411 0.29487 0 4.808e+06
--0.057568 0.29457 0 4.808e+06
--0.0034333 0.24399 0 4.808e+06
--0.055185 0.24185 0 4.808e+06
--0.10983 0.31352 0 4.808e+06
--0.15082 0.29453 0 4.808e+06
--0.11534 0.22049 0 4.808e+06
--0.15155 0.24381 0 4.808e+06
--0.1912 0.32173 0 4.808e+06
--0.281 0.3185 0 4.808e+06
--0.30791 0.32307 0 4.808e+06
--0.33854 0.32148 0 4.808e+06
--0.21248 0.29805 0 4.808e+06
--0.26372 0.29905 0 4.808e+06
--0.22562 0.24399 0 4.808e+06
--0.25035 0.2371 0 4.808e+06
--0.29941 0.31191 0 4.808e+06
--0.35845 0.2954 0 4.808e+06
--0.29231 0.22236 0 4.808e+06
--0.36101 0.24172 0 4.808e+06
--0.0034393 0.21129 0 4.808e+06
--0.07306 0.21304 0 4.808e+06
--0.10579 0.2099 0 4.808e+06
--0.13642 0.21411 0 4.808e+06
--0.22562 0.19323 0 4.808e+06
--0.24439 0.19799 0 4.808e+06
--0.22591 0.16041 0 4.808e+06
--0.23466 0.16082 0 4.808e+06
--0.3077 0.20998 0 4.808e+06
--0.3413 0.21239 0 4.808e+06
--0.40551 0.32178 0 4.2108e+06
--0.50568 0.3218 0 4.2108e+06
--0.41732 0.30844 0 4.2108e+06
--0.44237 0.28859 0 4.2108e+06
--0.41591 0.22004 0 4.2108e+06
--0.44803 0.24236 0 4.2108e+06
--0.50623 0.29315 0 4.2108e+06
--0.50916 0.24296 0 4.2108e+06
--0.57019 0.22334 0 4.2108e+06
--0.59611 0.32199 0 4.2108e+06
--0.65104 0.32199 0 4.2108e+06
--0.72566 0.32129 0 4.2108e+06
--0.75538 0.32301 0 4.2108e+06
--0.59653 0.29315 0 4.2108e+06
--0.65063 0.29315 0 4.2108e+06
--0.59478 0.24245 0 4.2108e+06
--0.65063 0.24399 0 4.2108e+06
--0.70618 0.29525 0 4.2108e+06
--0.76203 0.31284 0 4.2108e+06
--0.70302 0.24183 0 4.2108e+06
--0.77062 0.22133 0 4.2108e+06
--0.41545 0.21099 0 4.2108e+06
--0.45004 0.19812 0 4.2108e+06
--0.4475 0.1673 0 4.2108e+06
--0.52031 0.21236 0 4.2108e+06
--0.55182 0.21045 0 4.2108e+06
--0.5965 0.21131 0 4.2108e+06
--0.65064 0.2113 0 4.2108e+06
--0.72216 0.21286 0 4.2108e+06
--0.7556 0.20987 0 4.2108e+06
--0.78343 0.31973 0 4.2108e+06
--0.87572 0.32111 0 4.2108e+06
--0.90519 0.32263 0 4.2108e+06
--0.95526 0.34127 0 4.2108e+06
--0.79774 0.29271 0 4.2108e+06
--0.85618 0.29497 0 4.2108e+06
--0.79975 0.24326 0 4.2108e+06
--0.8521 0.24246 0 4.2108e+06
--0.91157 0.31224 0 4.2108e+06
--0.95031 0.29572 0 4.2108e+06
--0.92223 0.2213 0 4.2108e+06
--0.94979 0.24354 0 4.2108e+06
--0.78641 0.21505 0 4.2108e+06
--0.87094 0.21237 0 4.2108e+06
--0.90637 0.20934 0 4.2108e+06
--0.93777 0.21481 0 4.2108e+06
-0.22244 -0.0296 0 4.808e+06
-0.2704 -0.078167 0 4.808e+06
-0.24416 -0.056883 0 4.808e+06
-0.27311 -0.10653 0 4.808e+06
-0.26172 -0.10653 0 4.808e+06
-0.2704 -0.1349 0 4.808e+06
-0.24428 -0.15599 0 4.808e+06
-0.19017 -0.025297 0 4.808e+06
-0.14248 -0.02428 0 4.808e+06
-0.19815 -0.037432 0 4.808e+06
-0.14248 -0.03515 0 4.808e+06
-0.093313 -0.02428 0 4.808e+06
-0.044144 -0.02428 0 4.808e+06
-0.093313 -0.03515 0 4.808e+06
-0.044144 -0.03515 0 4.808e+06
-0.21156 -0.17357 0 4.808e+06
-0.029114 -0.12594 0 4.2108e+06
-0.036583 -0.15619 0 4.2108e+06
-0.22446 -0.20514 0 4.808e+06
-0.2208 -0.2369 0 4.808e+06
-0.2129 -0.208 0 4.808e+06
-0.19316 -0.25672 0 4.808e+06
-0.14497 -0.27484 0 4.808e+06
-0.030167 -0.18748 0 4.2108e+06
-0.1021 -0.27453 0 4.808e+06
-0.1689 -0.2831 0 4.808e+06
-0.13875 -0.28647 0 4.808e+06
-0.086993 -0.29568 0 4.808e+06
-0.044924 -0.3154 0 4.808e+06
--0.0066125 -0.02428 0 4.808e+06
--0.057362 -0.02428 0 4.808e+06
--0.0066125 -0.03515 0 4.808e+06
--0.057362 -0.03515 0 4.808e+06
--0.10653 -0.02428 0 4.808e+06
--0.15266 -0.025282 0 4.808e+06
--0.10653 -0.03515 0 4.808e+06
--0.16036 -0.037257 0 4.808e+06
-0.0083286 -0.1259 0 4.2108e+06
-0.0007442 -0.15603 0 4.2108e+06
--0.1741 -0.17381 0 4.808e+06
--0.18502 -0.02954 0 4.808e+06
--0.20707 -0.056403 0 4.808e+06
--0.23348 -0.07764 0 4.808e+06
--0.2244 -0.10653 0 4.808e+06
--0.23604 -0.10652 0 4.808e+06
--0.20734 -0.15641 0 4.808e+06
--0.23348 -0.13542 0 4.808e+06
-0.0061083 -0.18729 0 4.2108e+06
--0.066235 -0.27472 0 4.808e+06
--0.17577 -0.20789 0 4.808e+06
--0.10861 -0.27494 0 4.808e+06
--0.15584 -0.25716 0 4.808e+06
--0.0075775 -0.31546 0 4.808e+06
--0.050817 -0.29595 0 4.808e+06
--0.10306 -0.28653 0 4.808e+06
--0.1319 -0.2831 0 4.808e+06
--0.18716 -0.20571 0 4.808e+06
--0.18369 -0.23729 0 4.808e+06
diff --git a/io_scene_map/__init__.py b/io_scene_map/__init__.py
deleted file mode 100644 (file)
index 77bc758..0000000
+++ /dev/null
@@ -1,128 +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": "Quake/Doom3 MAP format",
-    "author": "Campbell Barton, scorpion81, Bastien Montagne, motorstep",
-    "version": (2, 1, 0),
-    "blender": (2, 69, 0),
-    "location": "File > Export",
-    "description": "Export MAP brushes, nurbs surfaces, "
-                   "lamps and empties as map nodes",
-    "warning": "",
-    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/Quake_MAP",
-    "tracker_url": "https://developer.blender.org/maniphest/task/edit/form/2/",
-    "category": "Import-Export"}
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
-    import imp
-    if "export_map" in locals():
-        imp.reload(export_map)
-
-
-import bpy
-from bpy.props import StringProperty, FloatProperty, BoolProperty
-from bpy_extras.io_utils import ExportHelper
-
-
-class ExportMAP(bpy.types.Operator, ExportHelper):
-    """Export selection to a quake map"""
-    bl_idname = "export_scene.quake_map"
-    bl_label = "Export MAP"
-    bl_options = {'PRESET'}
-
-    filename_ext = ".map"
-    filter_glob: StringProperty(default="*.map", options={'HIDDEN'})
-
-    doom3_format: BoolProperty(
-            name="Doom 3 Format",
-            description="Export to Doom3 MAP Format",
-            default=True)
-
-    face_thickness: FloatProperty(
-            name="Face Thickness",
-            description=("Thickness given to geometry which can't be "
-                         "converted into a brush"),
-            min=0.0001, max=10.0,
-            default=0.1,
-            )
-    global_scale: FloatProperty(
-            name="Scale",
-            description="Scale everything by this value",
-            min=0.01, max=1000.0,
-            default=1.0,
-            )
-    grid_snap: BoolProperty(
-            name="Grid Snap",
-            description="Round to whole numbers",
-            default=False,
-            )
-
-    texture_null: StringProperty(
-            name="Tex Null",
-            description="Texture used when none is assigned",
-            default="NULL",
-            )
-    texture_opts: StringProperty(
-            name="Tex Opts",
-            description="Brush texture options",
-            default='0 0 0 1 1 0 0 0',
-            )
-
-    def execute(self, context):
-        # import math
-        # from mathutils import Matrix
-        if not self.filepath:
-            raise Exception("filepath not set")
-
-        '''
-        global_matrix = Matrix()
-        global_matrix[0][0] = global_matrix[1][1] = global_matrix[2][2] = self.global_scale
-        global_matrix = global_matrix * axis_conversion(to_forward=self.axis_forward, to_up=self.axis_up).to_4x4()
-
-        keywords = self.as_keywords(ignore=("axis_forward", "axis_up", "global_scale", "check_existing", "filter_glob"))
-        keywords["global_matrix"] = global_matrix
-        '''
-
-        keywords = self.as_keywords(ignore=("check_existing", "filter_glob"))
-
-        from . import export_map
-        return export_map.save(self, context, **keywords)
-
-
-def menu_func(self, context):
-    self.layout.operator(ExportMAP.bl_idname, text="Quake/Doom3 MAP (.map)")
-
-
-def register():
-    bpy.utils.register_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_export.append(menu_func)
-
-
-def unregister():
-    bpy.utils.unregister_module(__name__)
-
-    bpy.types.TOPBAR_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
-    register()
diff --git a/io_scene_map/export_map.py b/io_scene_map/export_map.py
deleted file mode 100644 (file)
index cce1f26..0000000
+++ /dev/null
@@ -1,700 +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 #####
-
-#http://www.pasteall.org/47943/python
-
-# <pep8-80 compliant>
-
-import bpy
-import os
-import mathutils
-from mathutils import Vector
-
-from contextlib import redirect_stdout
-import io
-stdout = io.StringIO()
-
-# TODO, make options
-PREF_SCALE = 1
-PREF_FACE_THICK = 0.1
-PREF_GRID_SNAP = False
-# Quake 1/2?
-# Quake 3+?
-PREF_DEF_TEX_OPTS = '0 0 0 1 1 0 0 0'  # not user settable yet
-
-PREF_NULL_TEX = 'NULL'  # not user settable yet
-PREF_INVIS_TEX = 'common/caulk'
-PREF_DOOM3_FORMAT = True
-
-
-def face_uv_image_get(me, face):
-    uv_faces = me.uv_textures.active
-    if uv_faces:
-        return uv_faces.data[face.index].image
-    else:
-        return None
-
-
-def face_uv_coords_get(me, face):
-    tf_uv_faces = me.tessface_uv_textures.active
-    if tf_uv_faces:
-        return tf_uv_faces.data[face.index].uv_raw[:]
-    else:
-        return None
-
-
-def face_material_get(me, face):
-    idx = face.material_index
-    return me.materials[idx] if idx < len(me.materials) else None
-
-
-def poly_to_doom(me, p, radius):
-    """
-    Convert a face into Doom3 representation (infinite plane defined by its normal
-    and distance from origin along that normal).
-    """
-    # Compute the distance to the mesh from the origin to the plane.
-    # Line from origin in the direction of the face normal.
-    origin = Vector((0, 0, 0))
-    target = Vector(p.normal) * radius
-    # Find the target point.
-    intersect = mathutils.geometry.intersect_line_plane(origin, target, Vector(p.center), Vector(p.normal))
-    # We have to handle cases where intersection with face happens on the "negative" part of the vector!
-    length = intersect.length
-    nor = p.normal.copy()
-    if (nor.dot(intersect.normalized()) > 0):
-        length *= -1
-    nor.resize_4d()
-    nor.w = length
-    return nor
-
-
-def doom_are_same_planes(p1, p2):
-    """
-    To avoid writing two planes that are nearly the same!
-    """
-    # XXX Is sign of the normal/length important in Doom for plane definition??? For now, assume that no!
-    if p1.w < 0:
-        p1 = p1 * -1.0
-    if p2.w < 0:
-        p2 = p2 * -1.0
-
-    threshold = 0.0001
-
-    if abs(p1.w - p2.w) > threshold:
-        return False
-
-    # Distances are the same, check orientations!
-    if p1.xyz.normalized().dot(p2.xyz.normalized()) < (1 - threshold):
-        return False
-
-    # Same plane!
-    return True
-
-
-def doom_check_plane(done_planes, plane):
-    """
-    Check if plane as already been handled, or is similar enough to an already handled one.
-    Return True if it has already been handled somehow.
-    done_planes is expected to be a dict {written_plane: {written_plane, similar_plane_1, similar_plane_2, ...}, ...}.
-    """
-    p_key = tuple(plane)
-    if p_key in done_planes:
-        return True
-    for p, dp in done_planes.items():
-        if p_key in dp:
-            return True
-        elif doom_are_same_planes(Vector(p), plane):
-            done_planes[p].add(p_key)
-            return True
-    done_planes[p_key] = {p_key}
-    return False
-
-
-def ob_to_radius(ob):
-    radius = max(Vector(pt).length for pt in ob.bound_box)
-
-    # Make the ray casts, go just outside the bounding sphere.
-    return radius * 1.1
-
-
-def is_cube_facegroup(faces):
-    """
-    Returns a bool, true if the faces make up a cube
-    """
-    # cube must have 6 faces
-    if len(faces) != 6:
-        # print('1')
-        return False
-
-    # Check for quads and that there are 6 unique verts
-    verts = {}
-    for f in faces:
-        f_v = f.vertices[:]
-        if len(f_v) != 4:
-            return False
-
-        for v in f_v:
-            verts[v] = 0
-
-    if len(verts) != 8:
-        return False
-
-    # Now check that each vert has 3 face users
-    for f in faces:
-        f_v = f.vertices[:]
-        for v in f_v:
-            verts[v] += 1
-
-    for v in verts.values():
-        if v != 3:  # vert has 3 users?
-            return False
-
-    # Could we check for 12 unique edges??, probably not needed.
-    return True
-
-
-def is_tricyl_facegroup(faces):
-    """
-    is the face group a tri cylinder
-    Returns a bool, true if the faces make an extruded tri solid
-    """
-
-    # tricyl must have 5 faces
-    if len(faces) != 5:
-        #  print('1')
-        return False
-
-    # Check for quads and that there are 6 unique verts
-    verts = {}
-    tottri = 0
-    for f in faces:
-        if len(f.vertices) == 3:
-            tottri += 1
-
-        for vi in f.vertices:
-            verts[vi] = 0
-
-    if len(verts) != 6 or tottri != 2:
-        return False
-
-    # Now check that each vert has 3 face users
-    for f in faces:
-        for vi in f.vertices:
-            verts[vi] += 1
-
-    for v in verts.values():
-        if v != 3:  # vert has 3 users?
-            return False
-
-    # Could we check for 9 unique edges??, probably not needed.
-    return True
-
-
-def split_mesh_in_convex_parts(me):
-    """
-    Not implemented yet. Should split given mesh into manifold convex meshes.
-    For now simply always returns the given mesh.
-    """
-    # TODO.
-    return (me,)
-
-
-def round_vec(v):
-    if PREF_GRID_SNAP:
-        return v.to_tuple(0)
-    else:
-        return v[:]
-
-
-def write_quake_brush_cube(fw, ob, faces):
-    """
-    Takes 6 faces and writes a brush,
-    these faces can be from 1 mesh, 1 cube within a mesh of larger cubes
-    Faces could even come from different meshes or be contrived.
-    """
-    format_vec = '( %d %d %d ) ' if PREF_GRID_SNAP else '( %.9g %.9g %.9g ) '
-
-    fw('// brush from cube\n{\n')
-
-    for f in faces:
-        # from 4 verts this gets them in reversed order and only 3 of them
-        # 0,1,2,3 -> 2,1,0
-        me = f.id_data  # XXX25
-
-        for v in f.vertices[:][2::-1]:
-            fw(format_vec % round_vec(me.vertices[v].co))
-
-        material = face_material_get(me, f)
-
-        if material and material.game_settings.invisible:
-            fw(PREF_INVIS_TEX)
-        else:
-            image = face_uv_image_get(me, f)
-            if image:
-                fw(os.path.splitext(bpy.path.basename(image.filepath))[0])
-            else:
-                fw(PREF_NULL_TEX)
-        fw(" %s\n" % PREF_DEF_TEX_OPTS)  # Texture stuff ignored for now
-
-    fw('}\n')
-
-
-def write_quake_brush_face(fw, ob, face):
-    """
-    takes a face and writes it as a brush
-    each face is a cube/brush.
-    """
-    format_vec = '( %d %d %d ) ' if PREF_GRID_SNAP else '( %.9g %.9g %.9g ) '
-
-    image_text = PREF_NULL_TEX
-
-    me = face.id_data
-    material = face_material_get(me, face)
-
-    if material and material.game_settings.invisible:
-        image_text = PREF_INVIS_TEX
-    else:
-        image = face_uv_image_get(me, face)
-        if image:
-            image_text = os.path.splitext(bpy.path.basename(image.filepath))[0]
-
-    # reuse face vertices
-    f_vertices = [me.vertices[vi] for vi in face.vertices]
-
-    # original verts as tuples for writing
-    orig_vco = tuple(round_vec(v.co) for v in f_vertices)
-
-    # new verts that give the face a thickness
-    dist = PREF_SCALE * PREF_FACE_THICK
-    new_vco = tuple(round_vec(v.co - (v.normal * dist)) for v in f_vertices)
-    #new_vco = [round_vec(v.co - (face.no * dist)) for v in face]
-
-    fw('// brush from face\n{\n')
-    # front
-    for co in orig_vco[2::-1]:
-        fw(format_vec % co)
-
-    fw(image_text)
-    fw(" %s\n" % PREF_DEF_TEX_OPTS)  # Texture stuff ignored for now
-
-    for co in new_vco[:3]:
-        fw(format_vec % co)
-    if image and not material.game_settings.use_backface_culling: #uf.use_twoside:
-        fw(image_text)
-    else:
-        fw(PREF_INVIS_TEX)
-    fw(" %s\n" % PREF_DEF_TEX_OPTS)  # Texture stuff ignored for now
-
-    # sides.
-    if len(orig_vco) == 3:  # Tri, it seemms tri brushes are supported.
-        index_pairs = ((0, 1), (1, 2), (2, 0))
-    else:
-        index_pairs = ((0, 1), (1, 2), (2, 3), (3, 0))
-
-    for i1, i2 in index_pairs:
-        for co in orig_vco[i1], orig_vco[i2], new_vco[i2]:
-            fw(format_vec % co)
-        fw(PREF_INVIS_TEX)
-        fw(" %s\n" % PREF_DEF_TEX_OPTS)  # Texture stuff ignored for now
-
-    fw('}\n')
-
-
-def write_doom_brush(fw, ob, me):
-    """
-    Takes a mesh object and writes its convex parts.
-    """
-    format_vec = '( {} {} {} {} ) '
-    format_vec_uv = '( ( {} {} {} ) ( {} {} {} ) ) '
-    # Get the bounding sphere for the object for ray-casting
-    radius = ob_to_radius(ob)
-
-    fw('// brush from faces\n{\n'
-       'brushDef3\n{\n'
-      )
-
-    done_planes = {}  # Store already written plane, to avoid writing the same one (or a similar-enough one) again.
-
-    for p in me.polygons:
-        image_text = PREF_NULL_TEX
-        material = face_material_get(me, p)
-
-        if material:
-            if material.game_settings.invisible:
-                image_text = PREF_INVIS_TEX
-            else:
-                image_text = material.name
-
-        # reuse face vertices
-        plane = poly_to_doom(me, p, radius)
-        if plane is None:
-            print("    ERROR: Could not create the plane from polygon!");
-        elif doom_check_plane(done_planes, plane):
-            #print("    WARNING: Polygon too similar to another one!");
-            pass
-        else:
-            fw(format_vec.format(*plane.to_tuple(6)))
-            fw(format_vec_uv.format(0.015625, 0, 1, 0, 0.015625, 1)) # TODO insert UV stuff here
-            fw('"%s" ' % image_text)
-            fw("%s\n" % PREF_DEF_TEX_OPTS)  # Texture stuff ignored for now
-
-    fw('}\n}\n')
-
-
-def write_node_map(fw, ob):
-    """
-    Writes the properties of an object (empty in this case)
-    as a MAP node as long as it has the property name - classname
-    returns True/False based on weather a node was written
-    """
-    props = [(p.name, p.value) for p in ob.game.properties]
-
-    IS_MAP_NODE = False
-    for name, value in props:
-        if name == "classname":
-            IS_MAP_NODE = True
-            break
-
-    if not IS_MAP_NODE:
-        return False
-
-    # Write a node
-    fw('{\n')
-    for name_value in props:
-        fw('"%s" "%s"\n' % name_value)
-    fw('"origin" "%.9g %.9g %.9g"\n' % round_vec(ob.matrix_world.to_translation()))
-
-    fw('}\n')
-    return True
-
-
-def split_objects(context, objects):
-    scene = context.scene
-    view_layer = context.view_layer
-    final_objects = []
-
-    bpy.ops.object.select_all(action='DESELECT')
-    for ob in objects:
-        ob.select_set(True)
-
-    bpy.ops.object.duplicate()
-    objects = bpy.context.selected_objects
-
-    bpy.ops.object.select_all(action='DESELECT')
-
-    tot_ob = len(objects)
-    for i, ob in enumerate(objects):
-        print("Splitting object: %d/%d" % (i, tot_ob))
-        ob.select_set(True)
-
-        if ob.type == "MESH":
-            view_layer.objects.active = ob
-            bpy.ops.object.mode_set(mode='EDIT')
-            bpy.ops.mesh.select_all(action='DESELECT')
-            bpy.ops.mesh.select_mode(type='EDGE')
-            bpy.ops.object.mode_set(mode='OBJECT')
-            for edge in ob.data.edges:
-                if edge.use_seam:
-                    edge.select = True
-            bpy.ops.object.mode_set(mode='EDIT')
-            bpy.ops.mesh.edge_split()
-            bpy.ops.mesh.separate(type='LOOSE')
-            bpy.ops.object.mode_set(mode='OBJECT')
-
-            split_objects = context.selected_objects
-            for split_ob in split_objects:
-                assert(split_ob.type == "MESH")
-
-                view_layer.objects.active = split_ob
-                bpy.ops.object.mode_set(mode='EDIT')
-                bpy.ops.mesh.select_mode(type='EDGE')
-                bpy.ops.mesh.select_all(action="SELECT")
-                bpy.ops.mesh.region_to_loop()
-                bpy.ops.mesh.fill_holes(sides=8)
-                slot_idx = 0
-                for slot_idx, m in enumerate(split_ob.material_slots):
-                   if m.name == "textures/common/caulk":
-                      break
-                   #if m.name != "textures/common/caulk":
-                   #   mat = bpy.data.materials.new("textures/common/caulk")
-                   #   bpy.context.object.data.materials.append(mat)
-                split_ob.active_material_index = slot_idx  # we need to use either actual material name or custom property instead of index
-                bpy.ops.object.material_slot_assign()
-                with redirect_stdout(stdout):
-                   bpy.ops.mesh.remove_doubles()
-                bpy.ops.mesh.quads_convert_to_tris()
-                bpy.ops.mesh.tris_convert_to_quads()
-                bpy.ops.object.mode_set(mode='OBJECT')
-            final_objects += split_objects
-
-        ob.select_set(False)
-
-    print(final_objects)
-    return final_objects
-
-
-def export_map(context, filepath):
-    """
-    pup_block = [\
-    ('Scale:', PREF_SCALE, 1, 1000,
-            'Scale the blender scene by this value.'),\
-    ('Face Width:', PREF_FACE_THICK, 0.01, 10,
-            'Thickness of faces exported as brushes.'),\
-    ('Grid Snap', PREF_GRID_SNAP,
-            'snaps floating point values to whole numbers.'),\
-    'Null Texture',\
-    ('', PREF_NULL_TEX, 1, 128,
-            'Export textureless faces with this texture'),\
-    'Unseen Texture',\
-    ('', PREF_INVIS_TEX, 1, 128,
-            'Export invisible faces with this texture'),\
-    ]
-
-    if not Draw.PupBlock('map export', pup_block):
-        return
-    """
-    import time
-    from mathutils import Matrix
-    from bpy_extras import mesh_utils
-
-    t = time.time()
-    print("Map Exporter 0.0")
-
-    scene = context.scene
-    collection = context.collection
-    objects = context.selected_objects
-
-    obs_mesh = []
-    obs_lamp = []
-    obs_surf = []
-    obs_empty = []
-
-    SCALE_MAT = Matrix()
-    SCALE_MAT[0][0] = SCALE_MAT[1][1] = SCALE_MAT[2][2] = PREF_SCALE
-
-    TOTBRUSH = TOTLAMP = TOTNODE = 0
-
-    for ob in objects:
-        type = ob.type
-        if type == 'MESH':
-            obs_mesh.append(ob)
-        elif type == 'SURFACE':
-            obs_surf.append(ob)
-        elif type == 'LAMP':
-            obs_lamp.append(ob)
-        elif type == 'EMPTY':
-            obs_empty.append(ob)
-
-    obs_mesh = split_objects(context, obs_mesh)
-
-    with open(filepath, 'w') as fl:
-        fw = fl.write
-
-        if obs_mesh or obs_surf:
-            if PREF_DOOM3_FORMAT:
-                fw('Version 2')
-
-            # brushes and surf's must be under worldspan
-            fw('\n// entity 0\n')
-            fw('{\n')
-            fw('"classname" "worldspawn"\n')
-
-        print("\twriting cubes from meshes")
-
-        tot_ob = len(obs_mesh)
-        for i, ob in enumerate(obs_mesh):
-            print("Exporting object: %d/%d" % (i, tot_ob))
-
-            dummy_mesh = ob.to_mesh(scene, True, 'PREVIEW')
-
-            #print len(mesh_split2connected(dummy_mesh))
-
-            # 1 to tx the normals also
-            dummy_mesh.transform(ob.matrix_world * SCALE_MAT)
-
-            # High quality normals
-            #XXX25: BPyMesh.meshCalcNormals(dummy_mesh)
-
-            if PREF_DOOM3_FORMAT:
-                for me in split_mesh_in_convex_parts(dummy_mesh):
-                    write_doom_brush(fw, ob, me)
-                    TOTBRUSH += 1
-                    if (me is not dummy_mesh):
-                        bpy.data.meshes.remove(me)
-            else:
-                # We need tessfaces
-                dummy_mesh.update(calc_tessface=True)
-                # Split mesh into connected regions
-                for face_group in mesh_utils.mesh_linked_tessfaces(dummy_mesh):
-                    if is_cube_facegroup(face_group):
-                        write_quake_brush_cube(fw, ob, face_group)
-                        TOTBRUSH += 1
-                    elif is_tricyl_facegroup(face_group):
-                        write_quake_brush_cube(fw, ob, face_group)
-                        TOTBRUSH += 1
-                    else:
-                        for f in face_group:
-                            write_quake_brush_face(fw, ob, f)
-                            TOTBRUSH += 1
-
-                #print 'warning, not exporting "%s" it is not a cube' % ob.name
-                bpy.data.meshes.remove(dummy_mesh)
-
-        valid_dims = 3, 5, 7, 9, 11, 13, 15
-        for ob in obs_surf:
-            '''
-            Surf, patches
-            '''
-            data = ob.data
-            surf_name = data.name
-            mat = ob.matrix_world * SCALE_MAT
-
-            # This is what a valid patch looks like
-            """
-            // brush 0
-            {
-            patchDef2
-            {
-            NULL
-            ( 3 3 0 0 0 )
-            (
-            ( ( -64 -64 0 0 0 ) ( -64 0 0 0 -2 ) ( -64 64 0 0 -4 ) )
-            ( ( 0 -64 0 2 0 ) ( 0 0 0 2 -2 ) ( 0 64 0 2 -4 ) )
-            ( ( 64 -64 0 4 0 ) ( 64 0 0 4 -2 ) ( 80 88 0 4 -4 ) )
-            )
-            }
-            }
-            """
-            for i, nurb in enumerate(data.splines):
-                u = nurb.point_count_u
-                v = nurb.point_count_v
-                if u in valid_dims and v in valid_dims:
-
-                    fw('// brush %d surf_name\n' % i)
-                    fw('{\n')
-                    fw('patchDef2\n')
-                    fw('{\n')
-                    fw('NULL\n')
-                    fw('( %d %d 0 0 0 )\n' % (u, v))
-                    fw('(\n')
-
-                    u_iter = 0
-                    for p in nurb.points:
-
-                        if u_iter == 0:
-                            fw('(')
-
-                        u_iter += 1
-
-                        # add nmapping 0 0 ?
-                        if PREF_GRID_SNAP:
-                            fw(" ( %d %d %d 0 0 )" %
-                                       round_vec(mat * p.co.xyz))
-                        else:
-                            fw(' ( %.6f %.6f %.6f 0 0 )' %
-                                       (mat * p.co.xyz)[:])
-
-                        # Move to next line
-                        if u_iter == u:
-                            fw(' )\n')
-                            u_iter = 0
-
-                    fw(')\n')
-                    fw('}\n')
-                    fw('}\n')
-                    # Debugging
-                    # for p in nurb: print 'patch', p
-
-                else:
-                    print("Warning: not exporting patch",
-                          surf_name, u, v, 'Unsupported')
-
-        if obs_mesh or obs_surf:
-            fw('}\n')  # end worldspan
-
-        print("\twriting lamps")
-        for ob in obs_lamp:
-            print("\t\t%s" % ob.name)
-            lamp = ob.data
-            fw('{\n')
-            fw('"classname" "light"\n')
-            fw('"light" "%.6f"\n' % (lamp.distance * PREF_SCALE))
-            if PREF_GRID_SNAP:
-                fw('"origin" "%d %d %d"\n' %
-                           tuple([round(axis * PREF_SCALE)
-                                  for axis in ob.matrix_world.to_translation()]))
-            else:
-                fw('"origin" "%.6f %.6f %.6f"\n' %
-                           tuple([axis * PREF_SCALE
-                                  for axis in ob.matrix_world.to_translation()]))
-
-            fw('"_color" "%.6f %.6f %.6f"\n' % tuple(lamp.color))
-            fw('"style" "0"\n')
-            fw('}\n')
-            TOTLAMP += 1
-
-        print("\twriting empty objects as nodes")
-        for ob in obs_empty:
-            if write_node_map(fw, ob):
-                print("\t\t%s" % ob.name)
-                TOTNODE += 1
-            else:
-                print("\t\tignoring %s" % ob.name)
-
-    for ob in obs_mesh:
-        collection.objects.unlink(ob)
-        bpy.data.objects.remove(ob)
-
-    print("Exported Map in %.4fsec" % (time.time() - t))
-    print("Brushes: %d  Nodes: %d  Lamps %d\n" % (TOTBRUSH, TOTNODE, TOTLAMP))
-
-
-def save(operator,
-         context,
-         filepath=None,
-         global_scale=1.0,
-         face_thickness=0.1,
-         texture_null="NULL",
-         texture_opts='0 0 0 1 1 0 0 0',
-         grid_snap=False,
-         doom3_format=True,
-         ):
-
-    global PREF_SCALE
-    global PREF_FACE_THICK
-    global PREF_NULL_TEX
-    global PREF_DEF_TEX_OPTS
-    global PREF_GRID_SNAP
-    global PREF_DOOM3_FORMAT
-
-    PREF_SCALE = global_scale
-    PREF_FACE_THICK = face_thickness
-    PREF_NULL_TEX = texture_null
-    PREF_DEF_TEX_OPTS = texture_opts
-    PREF_GRID_SNAP = grid_snap
-    PREF_DOOM3_FORMAT = doom3_format
-
-    if (PREF_DOOM3_FORMAT):
-        PREF_DEF_TEX_OPTS = '0 0 0'
-    else:
-        PREF_DEF_TEX_OPTS = '0 0 0 1 1 0 0 0'
-
-    export_map(context, filepath)
-
-    return {'FINISHED'}
diff --git a/io_scene_ms3d/__init__.py b/io_scene_ms3d/__init__.py
deleted file mode 100644 (file)
index 02b0e0a..0000000
+++ /dev/null
@@ -1,100 +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": "MilkShape3D MS3D format (.ms3d)",
-    "description": "Import / Export MilkShape3D MS3D files "
-                   "(conform with MilkShape3D v1.8.4)",
-    "author": "Alexander Nussbaumer",
-    "version": (2, 72, 2),
-    "blender": (2, 72, 2),
-    "location": "File > Import & File > Export",
-    "warning": "",
-    "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
-                "Scripts/Import-Export/MilkShape3D_MS3D",
-    "category": "Import-Export",
-}
-
-
-###############################################################################
-#234567890123456789012345678901234567890123456789012345678901234567890123456789
-#--------1---------2---------3---------4---------5---------6---------7---------
-
-
-# ##### BEGIN COPYRIGHT BLOCK #####
-#
-# initial script copyright (c)2011-2013 Alexander Nussbaumer
-#
-# ##### END COPYRIGHT BLOCK #####
-
-
-# To support reload properly, try to access a package var,
-# if it's there, reload everything
-if 'bpy' in locals():
-    import importlib
-    if 'io_scene_ms3d.ms3d_ui' in locals():
-        importlib.reload(io_scene_ms3d.ms3d_ui)
-else:
-    from io_scene_ms3d.ms3d_ui import (
-            Ms3dImportOperator,
-            Ms3dExportOperator,
-            )
-
-
-#import blender stuff
-from bpy.types import (
-        TOPBAR_MT_file_export,
-        TOPBAR_MT_file_import,
-        )
-
-
-###############################################################################
-# registration
-def register():
-    ####################
-    # F8 - key
-    import importlib
-    importlib.reload(ms3d_ui)
-    # F8 - key
-    ####################
-
-    ms3d_ui.register()
-
-    TOPBAR_MT_file_export.append(Ms3dExportOperator.menu_func)
-    TOPBAR_MT_file_import.append(Ms3dImportOperator.menu_func)
-
-
-def unregister():
-    ms3d_ui.unregister()
-
-    TOPBAR_MT_file_export.remove(Ms3dExportOperator.menu_func)
-    TOPBAR_MT_file_import.remove(Ms3dImportOperator.menu_func)
-
-
-###############################################################################
-# global entry point
-if (__name__ == "__main__"):
-    register()
-
-
-###############################################################################
-#234567890123456789012345678901234567890123456789012345678901234567890123456789
-#--------1---------2---------3---------4---------5---------6---------7---------
-# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_export.py b/io_scene_ms3d/ms3d_export.py
deleted file mode 100644 (file)
index bd5d2f2..0000000
+++ /dev/null
@@ -1,945 +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>
-
-###############################################################################
-#234567890123456789012345678901234567890123456789012345678901234567890123456789
-#--------1---------2---------3---------4---------5---------6---------7---------
-
-
-# ##### BEGIN COPYRIGHT BLOCK #####
-#
-# initial script copyright (c)2011-2013 Alexander Nussbaumer
-#
-# ##### END COPYRIGHT BLOCK #####
-
-
-#import python stuff
-import io
-from math import (
-        pi,
-        )
-from mathutils import (
-        Matrix,
-        )
-from os import (
-        path,
-        )
-from sys import (
-        exc_info,
-        )
-from time import (
-        time,
-        )
-
-
-# import io_scene_ms3d stuff
-from io_scene_ms3d.ms3d_strings import (
-        ms3d_str,
-        )
-from io_scene_ms3d.ms3d_spec import (
-        Ms3dSpec,
-        Ms3dModel,
-        Ms3dVertex,
-        Ms3dTriangle,
-        Ms3dGroup,
-        Ms3dMaterial,
-        Ms3dJoint,
-        Ms3dRotationKeyframe,
-        Ms3dTranslationKeyframe,
-        Ms3dCommentEx,
-        Ms3dComment,
-        )
-from io_scene_ms3d.ms3d_utils import (
-        select_all,
-        enable_edit_mode,
-        pre_setup_environment,
-        post_setup_environment,
-        matrix_difference,
-        )
-from io_scene_ms3d.ms3d_ui import (
-        Ms3dUi,
-        Ms3dMaterialProperties,
-        Ms3dMaterialHelper,
-        )
-
-
-#import blender stuff
-from bpy import (
-        ops,
-        )
-import bmesh
-
-
-###############################################################################
-class Ms3dExporter():
-    """
-    Load a MilkShape3D MS3D File
-    """
-    def __init__(self,
-            report,
-            verbose='NONE',
-            use_blender_names=True,
-            use_blender_materials=False,
-            apply_transform=True,
-            apply_modifiers=True,
-            apply_modifiers_mode='PREVIEW',
-            use_animation=True,
-            normalize_weights=True,
-            shrink_to_keys=False,
-            bake_each_frame=True,
-            ):
-        self.report = report
-        self.options_verbose = verbose
-        self.options_use_blender_names = use_blender_names
-        self.options_use_blender_materials = use_blender_materials
-        self.options_apply_transform = apply_transform
-        self.options_apply_modifiers = apply_modifiers
-        self.options_apply_modifiers_mode = apply_modifiers_mode
-        self.options_use_animation = use_animation
-        self.options_normalize_weights = normalize_weights
-        self.options_shrink_to_keys = shrink_to_keys
-        self.options_bake_each_frame = bake_each_frame
-        pass
-
-    # create a empty ms3d ms3d_model
-    # fill ms3d_model with blender content
-    # writer ms3d file
-    def write(self, blender_context, filepath):
-        """convert bender content to ms3d content and write it to file"""
-
-        t1 = time()
-        t2 = None
-
-        try:
-            # setup environment
-            pre_setup_environment(self, blender_context)
-
-            # create an empty ms3d template
-            ms3d_model = Ms3dModel()
-
-            # inject blender data to ms3d file
-            self.from_blender(blender_context, ms3d_model)
-
-            t2 = time()
-
-            try:
-                # write ms3d file to disk
-                with io.FileIO(filepath, "wb") as raw_io:
-                    debug_out = ms3d_model.write(raw_io)
-                    raw_io.flush()
-                    raw_io.close()
-
-                    if self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL:
-                        print(debug_out)
-            finally:
-                pass
-
-            # if option is set, this time will enlargs the io time
-            if self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL:
-                ms3d_model.print_internal()
-
-            post_setup_environment(self, blender_context)
-            # restore active object
-            blender_context.view_layer.objects.active = self.active_object
-
-            if ((not blender_context.view_layer.objects.active)
-                    and (blender_context.selected_objects)):
-                blender_context.view_layer.objects.active \
-                        = blender_context.selected_objects[0]
-
-            is_valid, statistics = ms3d_model.is_valid()
-            if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                print()
-                print("##########################################################")
-                print("Export from Blender to MS3D")
-                print(statistics)
-                print("##########################################################")
-
-        except Exception:
-            type, value, traceback = exc_info()
-            if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                print("write - exception in try block\n  type: '{0}'\n"
-                        "  value: '{1}'".format(type, value, traceback))
-                if self.report:
-                    self.report({'WARNING', 'ERROR', }, "write - exception.")
-
-            if t2 is None:
-                t2 = time()
-
-            return False
-
-        else:
-            pass
-
-        t3 = time()
-        if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-            print(ms3d_str['SUMMARY_EXPORT'].format(
-                    (t3 - t1), (t2 - t1), (t3 - t2)))
-
-        return True
-
-
-    ###########################################################################
-    def from_blender(self, blender_context, ms3d_model):
-        blender_mesh_objects = []
-
-        source = (blender_context.active_object, )
-
-        for blender_object in source:
-            if blender_object and blender_object.type == 'MESH' \
-                    and blender_object.is_visible(blender_context.scene):
-                blender_mesh_objects.append(blender_object)
-
-        blender_to_ms3d_bones = {}
-
-        self.create_animation(blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones)
-        self.create_geometry(blender_context, ms3d_model, blender_mesh_objects,
-                blender_to_ms3d_bones)
-
-
-    ###########################################################################
-    def create_geometry(self, blender_context, ms3d_model, blender_mesh_objects, blender_to_ms3d_bones):
-        blender_view_layer = blender_context.view_layer
-        blender_scene = blender_context.scene
-        blender_depsgraph = blender_context.evaluated_depsgraph_get()
-        blender_collection = blender_context.collection
-
-        blender_to_ms3d_vertices = {}
-        blender_to_ms3d_triangles = {}
-        blender_to_ms3d_groups = {}
-        blender_to_ms3d_materials = {}
-
-        for blender_mesh_object in blender_mesh_objects:
-            blender_mesh = blender_mesh_object.data
-
-            ms3d_model._model_ex_object.joint_size = \
-                    blender_mesh.ms3d.joint_size
-            ms3d_model._model_ex_object.alpha_ref = blender_mesh.ms3d.alpha_ref
-            ms3d_model._model_ex_object.transparency_mode = \
-                    Ms3dUi.transparency_mode_to_ms3d(
-                    blender_mesh.ms3d.transparency_mode)
-
-            if blender_mesh.ms3d.comment:
-                ms3d_model._comment_object = Ms3dComment(blender_mesh.ms3d.comment)
-
-            ##########################
-            # prepare ms3d groups if available
-            # works only for exporting active object
-            ##EXPORT_ACTIVE_ONLY:
-            for ms3d_local_group_index, blender_ms3d_group in enumerate(
-                    blender_mesh.ms3d.groups):
-                ms3d_group = Ms3dGroup()
-                ms3d_group.__index = len(ms3d_model._groups)
-                ms3d_group.name = blender_ms3d_group.name
-                ms3d_group.flags = Ms3dUi.flags_to_ms3d(blender_ms3d_group.flags)
-                if blender_ms3d_group.comment:
-                    ms3d_group._comment_object = Ms3dCommentEx()
-                    ms3d_group._comment_object.comment = \
-                            blender_ms3d_group.comment
-                    ms3d_group._comment_object.index = len(ms3d_model._groups)
-                ms3d_group.material_index = None # to mark as not set
-                ms3d_model._groups.append(ms3d_group)
-                blender_to_ms3d_groups[blender_ms3d_group.id] = ms3d_group
-
-            ##########################
-            # i have to use BMesh, because there are several custom data stored.
-            # BMesh doesn't support quads_convert_to_tris()
-            # so, i use that very ugly way:
-            # create a complete copy of mesh and bend object data
-            # to be able to apply operations to it.
-
-            # temporary, create a full heavy copy of the model
-            # (object, mesh, modifiers)
-            blender_mesh_temp = blender_mesh_object.data.copy()
-            blender_mesh_object_temp = blender_mesh_object.copy()
-            blender_mesh_object_temp.data = blender_mesh_temp
-            blender_collection.objects.link(blender_mesh_object_temp)
-            blender_view_layer.objects.active = blender_mesh_object_temp
-
-            # apply transform
-            if self.options_apply_transform:
-                matrix_transform = blender_mesh_object_temp.matrix_basis
-            else:
-                matrix_transform = 1
-
-            # apply modifiers
-            for modifier in blender_mesh_object_temp.modifiers:
-                if self.options_apply_modifiers:
-                    # disable only armature modifiers and only,
-                    # when use_animation is enabled
-                    if  self.options_use_animation \
-                            and modifier.type in {'ARMATURE', }:
-                        modifier.show_viewport = False
-                        modifier.show_render = False
-                else:
-                    # disable all modifiers,
-                    # to be able to add and apply triangulate modifier later
-                    modifier.show_viewport = False
-                    modifier.show_render = False
-
-            # convert to tris by using the triangulate modifier
-            blender_mesh_object_temp.modifiers.new("temp", 'TRIANGULATE')
-            blender_mesh_object_temp_eval = blender_mesh_object_temp.evaluated_get(blender_depsgraph)
-            blender_mesh_temp = blender_mesh_object_temp_eval.to_mesh()
-
-            enable_edit_mode(True, blender_context)
-            bm = bmesh.new()
-            bm.from_mesh(blender_mesh_temp)
-
-            blender_mesh_object_temp_eval.to_mesh_clear()
-
-            layer_texture = bm.faces.layers.tex.get(
-                    ms3d_str['OBJECT_LAYER_TEXTURE'])
-            if layer_texture is None:
-                layer_texture = bm.faces.layers.tex.new(
-                        ms3d_str['OBJECT_LAYER_TEXTURE'])
-
-            layer_smoothing_group = bm.faces.layers.int.get(
-                    ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
-            if layer_smoothing_group is None:
-                layer_smoothing_group = bm.faces.layers.int.new(
-                        ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
-
-            layer_group = bm.faces.layers.int.get(
-                    ms3d_str['OBJECT_LAYER_GROUP'])
-            if layer_group is None:
-                layer_group = bm.faces.layers.int.new(
-                        ms3d_str['OBJECT_LAYER_GROUP'])
-
-            layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV'])
-            if layer_uv is None:
-                if bm.loops.layers.uv:
-                    layer_uv = bm.loops.layers.uv[0]
-                else:
-                    layer_uv = bm.loops.layers.uv.new(
-                            ms3d_str['OBJECT_LAYER_UV'])
-
-            layer_deform = bm.verts.layers.deform.active
-
-            layer_extra = bm.verts.layers.int.get(ms3d_str['OBJECT_LAYER_EXTRA'])
-            if layer_extra is None:
-                layer_extra = bm.verts.layers.int.new(
-                        ms3d_str['OBJECT_LAYER_EXTRA'])
-
-
-            ##########################
-            # handle vertices
-            for bmv in bm.verts:
-                item = blender_to_ms3d_vertices.get(bmv)
-                if item is None:
-                    index = len(ms3d_model._vertices)
-                    ms3d_vertex = Ms3dVertex()
-                    ms3d_vertex.__index = index
-
-                    ms3d_vertex._vertex = self.geometry_correction(
-                            matrix_transform * bmv.co)
-
-                    if self.options_use_animation and layer_deform:
-                        blender_vertex_group_ids = bmv[layer_deform]
-                        if blender_vertex_group_ids:
-                            bone_weights = {}
-                            for blender_index, blender_weight \
-                                    in blender_vertex_group_ids.items():
-                                ms3d_joint = blender_to_ms3d_bones.get(
-                                        blender_mesh_object_temp.vertex_groups[\
-                                                blender_index].name)
-                                if ms3d_joint:
-                                    weight = bone_weights.get(ms3d_joint.__index)
-                                    if not weight:
-                                        weight = 0
-                                    bone_weights[ms3d_joint.__index] = weight + blender_weight
-
-                            # sort (bone_id: weight) according its weights
-                            # to skip only less important weights in the next pass
-                            bone_weights_sorted = sorted(bone_weights.items(), key=lambda item: item[1], reverse=True)
-
-                            count = 0
-                            bone_ids = []
-                            weights = []
-                            for ms3d_index, blender_weight \
-                                    in bone_weights_sorted:
-
-                                if count == 0:
-                                    ms3d_vertex.bone_id = ms3d_index
-                                    weights.append(blender_weight)
-                                elif count == 1:
-                                    bone_ids.append(ms3d_index)
-                                    weights.append(blender_weight)
-                                elif count == 2:
-                                    bone_ids.append(ms3d_index)
-                                    weights.append(blender_weight)
-                                elif count == 3:
-                                    bone_ids.append(ms3d_index)
-                                    if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                                        self.report(
-                                                {'WARNING', 'INFO'},
-                                                ms3d_str['WARNING_EXPORT_SKIP_WEIGHT'])
-                                else:
-                                    # only first three weights will be supported / four bones
-                                    if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                                        self.report(
-                                                {'WARNING', 'INFO'},
-                                                ms3d_str['WARNING_EXPORT_SKIP_WEIGHT_EX'])
-                                    break
-                                count += 1
-
-                            # normalize weights to 100%
-                            if self.options_normalize_weights:
-                                weight_sum = 0.0
-                                for weight in weights:
-                                    weight_sum += weight
-
-                                if weight_sum > 0.0:
-                                    weight_normalize = 1.0 / weight_sum
-                                else:
-                                    weight_normalize = 1.0
-
-                                weight_sum = 100
-                                for index, weight in enumerate(weights):
-                                    if index >= count-1 or index >= 2:
-                                        # take the full rest instead of calculate,
-                                        # that should fill up to exactly 100%
-                                        # (in some cases it is only 99% bacaus of roulding errors)
-                                        weights[index] = int(weight_sum)
-                                        break
-                                    normalized_weight = int(weight * weight_normalize * 100)
-                                    weights[index] = normalized_weight
-                                    weight_sum -= normalized_weight
-
-                            # fill up missing values
-                            while len(bone_ids) < 3:
-                                bone_ids.append(Ms3dSpec.DEFAULT_VERTEX_BONE_ID)
-                            while len(weights) < 3:
-                                weights.append(0)
-
-                            ms3d_vertex._vertex_ex_object._bone_ids = \
-                                    tuple(bone_ids)
-                            ms3d_vertex._vertex_ex_object._weights = \
-                                    tuple(weights)
-
-                    if layer_extra:
-                        #ms3d_vertex._vertex_ex_object.extra = bmv[layer_extra]
-                        # bm.verts.layers.int does only support signed int32
-                        # convert signed int32 to unsigned int32 (little-endian)
-                        signed_int32 = bmv[layer_extra]
-                        bytes_int32 = signed_int32.to_bytes(
-                                4, byteorder='little', signed=True)
-                        unsigned_int32 = int.from_bytes(
-                                bytes_int32, byteorder='little', signed=False)
-                        ms3d_vertex._vertex_ex_object.extra = unsigned_int32
-
-                    ms3d_model._vertices.append(ms3d_vertex)
-                    blender_to_ms3d_vertices[bmv] = ms3d_vertex
-
-            ##########################
-            # handle faces / tris
-            for bmf in bm.faces:
-                item = blender_to_ms3d_triangles.get(bmf)
-                if item is None:
-                    index = len(ms3d_model._triangles)
-                    ms3d_triangle = Ms3dTriangle()
-                    ms3d_triangle.__index = index
-                    bmv0 = bmf.verts[0]
-                    bmv1 = bmf.verts[1]
-                    bmv2 = bmf.verts[2]
-                    ms3d_vertex0 = blender_to_ms3d_vertices[bmv0]
-                    ms3d_vertex1 = blender_to_ms3d_vertices[bmv1]
-                    ms3d_vertex2 = blender_to_ms3d_vertices[bmv2]
-                    ms3d_vertex0.reference_count += 1
-                    ms3d_vertex1.reference_count += 1
-                    ms3d_vertex2.reference_count += 1
-                    ms3d_triangle._vertex_indices = (
-                            ms3d_vertex0.__index,
-                            ms3d_vertex1.__index,
-                            ms3d_vertex2.__index,
-                            )
-                    ms3d_triangle._vertex_normals = (
-                            self.geometry_correction(bmv0.normal),
-                            self.geometry_correction(bmv1.normal),
-                            self.geometry_correction(bmv2.normal),
-                            )
-                    ms3d_triangle._s = (
-                            bmf.loops[0][layer_uv].uv.x,
-                            bmf.loops[1][layer_uv].uv.x,
-                            bmf.loops[2][layer_uv].uv.x,
-                            )
-                    ms3d_triangle._t = (
-                            1.0 - bmf.loops[0][layer_uv].uv.y,
-                            1.0 - bmf.loops[1][layer_uv].uv.y,
-                            1.0 - bmf.loops[2][layer_uv].uv.y,
-                            )
-
-                    ms3d_triangle.smoothing_group = bmf[layer_smoothing_group]
-                    ms3d_model._triangles.append(ms3d_triangle)
-
-                    ms3d_material = self.get_ms3d_material_add_if(
-                            blender_mesh, ms3d_model,
-                            blender_to_ms3d_materials, bmf.material_index)
-                    ms3d_group = blender_to_ms3d_groups.get(bmf[layer_group])
-
-                    ##EXPORT_ACTIVE_ONLY:
-                    if ms3d_group is not None:
-                        if ms3d_material is None:
-                            ms3d_group.material_index = \
-                                    Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX
-                        else:
-                            if ms3d_group.material_index is None:
-                                ms3d_group.material_index = \
-                                        ms3d_material.__index
-                            else:
-                                if ms3d_group.material_index != \
-                                        ms3d_material.__index:
-                                    ms3d_group = \
-                                            self.get_ms3d_group_by_material_add_if(
-                                            ms3d_model, ms3d_material)
-                    else:
-                        if ms3d_material is not None:
-                            ms3d_group = self.get_ms3d_group_by_material_add_if(
-                                    ms3d_model, ms3d_material)
-                        else:
-                            ms3d_group = self.get_ms3d_group_default_material_add_if(
-                                    ms3d_model)
-
-                    if ms3d_group is not None:
-                        ms3d_group._triangle_indices.append(
-                                ms3d_triangle.__index)
-                        ms3d_triangle.group_index = ms3d_group.__index
-
-                    blender_to_ms3d_triangles[bmf] = ms3d_triangle
-
-            if bm is not None:
-                bm.free()
-
-            enable_edit_mode(False, blender_context)
-
-            ##########################
-            # remove the temporary data
-            blender_collection.objects.unlink(blender_mesh_object_temp)
-            if blender_mesh_temp is not None:
-                blender_mesh_temp.user_clear()
-                blender_context.blend_data.meshes.remove(blender_mesh_temp)
-            blender_mesh_temp = None
-            if blender_mesh_object_temp is not None:
-                blender_mesh_temp = blender_mesh_object_temp.data.user_clear()
-                blender_mesh_object_temp.user_clear()
-                blender_context.blend_data.objects.remove(
-                        blender_mesh_object_temp)
-            if blender_mesh_temp is not None:
-                blender_mesh_temp.user_clear()
-                blender_context.blend_data.meshes.remove(blender_mesh_temp)
-
-
-    ###########################################################################
-    def create_animation(self, blender_context, ms3d_model,
-            blender_mesh_objects, blender_to_ms3d_bones):
-        ##########################
-        # setup scene
-        blender_scene = blender_context.scene
-
-        if not self.options_use_animation:
-            ms3d_model.animation_fps = 24
-            ms3d_model.number_total_frames = 1
-            ms3d_model.current_time = 0
-            return
-
-        frame_start = blender_scene.frame_start
-        frame_end = blender_scene.frame_end
-        frame_total = (frame_end - frame_start) + 1
-        frame_step = blender_scene.frame_step
-        frame_offset = 0
-
-        fps = blender_scene.render.fps * blender_scene.render.fps_base
-        time_base = 1.0 / fps
-
-        base_bone_correction = Matrix.Rotation(pi / 2, 4, 'Z')
-
-        for blender_mesh_object in blender_mesh_objects:
-            blender_bones = None
-            blender_action = None
-            blender_nla_tracks = None
-
-            # note: only one armature modifier/parent will be handled.
-            #   if the parent is an armature, it will be handled irrespective
-            #   of existence of any armature modifier
-
-            # question: maybe it is better to handle
-            #   all existing armature sources (parent / modifier)
-            #   as a merged animation...
-            #   what is best practice in case of multiple animation sources?
-
-            # take parent to account if it is an armature
-            if blender_mesh_object.parent and \
-                    blender_mesh_object.parent_type == 'ARMATURE' and \
-                    blender_mesh_object.parent.pose:
-                blender_bones = blender_mesh_object.parent.data.bones
-                blender_pose_bones = blender_mesh_object.parent.pose.bones
-                if blender_mesh_object.parent.animation_data:
-                    blender_action = \
-                            blender_mesh_object.parent.animation_data.action
-                    blender_nla_tracks = \
-                            blender_mesh_object.parent.animation_data.nla_tracks
-
-                # apply transform
-                if self.options_apply_transform:
-                    matrix_transform = blender_mesh_object.parent.matrix_basis
-                else:
-                    matrix_transform = 1
-
-            # search for animation modifier
-            else:
-                for blender_modifier in blender_mesh_object.modifiers:
-                    if blender_modifier.type == 'ARMATURE' \
-                            and blender_modifier.object.pose:
-                        blender_bones = blender_modifier.object.data.bones
-                        blender_pose_bones = blender_modifier.object.pose.bones
-                        if blender_modifier.object.animation_data:
-                            blender_action = \
-                                    blender_modifier.object.animation_data.action
-                            blender_nla_tracks = \
-                                    blender_modifier.object.animation_data.nla_tracks
-
-                        # apply transform
-                        if self.options_apply_transform:
-                            matrix_transform = blender_modifier.object.matrix_basis
-                        else:
-                            matrix_transform = 1
-
-                        break
-
-            # skip animation/bone handling, if no animation data is available
-            if blender_bones is None \
-                    and (blender_action is None and blender_nla_tracks is None):
-                continue
-
-            ##########################
-            # bones
-            blender_bones_ordered = []
-            self.build_blender_bone_dependency_order(
-                    blender_bones, blender_bones_ordered)
-            for blender_bone_name in blender_bones_ordered:
-                blender_bone_oject = blender_bones[blender_bone_name]
-                ms3d_joint = Ms3dJoint()
-                ms3d_joint.__index = len(ms3d_model._joints)
-
-                blender_bone_ms3d = blender_bone_oject.ms3d
-                blender_bone = blender_bone_oject
-
-                ms3d_joint.flags = Ms3dUi.flags_to_ms3d(blender_bone_ms3d.flags)
-                if blender_bone_ms3d.comment:
-                    ms3d_joint._comment_object = Ms3dCommentEx()
-                    ms3d_joint._comment_object.comment = \
-                            blender_bone_ms3d.comment
-                    ms3d_joint._comment_object.index = ms3d_joint.__index
-
-                ms3d_joint.joint_ex_object._color = blender_bone_ms3d.color[:]
-
-                ms3d_joint.name = blender_bone.name
-
-                if blender_bone.parent:
-                    ms3d_joint.parent_name = blender_bone.parent.name
-                    ms3d_joint.__matrix = matrix_difference(
-                            matrix_transform * blender_bone.matrix_local,
-                            matrix_transform * blender_bone.parent.matrix_local)
-                else:
-                    ms3d_joint.__matrix = base_bone_correction \
-                            * matrix_transform * blender_bone.matrix_local
-
-                mat = ms3d_joint.__matrix
-                loc = mat.to_translation()
-                rot = mat.to_euler('XZY')
-                ms3d_joint._position = self.joint_correction(loc)
-                ms3d_joint._rotation = self.joint_correction(rot)
-
-                ms3d_model._joints.append(ms3d_joint)
-                blender_to_ms3d_bones[blender_bone.name] = ms3d_joint
-
-            ##########################
-            # animation
-            frames = None
-            frames_location = set()
-            frames_rotation = set()
-            frames_scale = set()
-
-            if blender_action:
-                self.fill_keyframe_sets(
-                        blender_action.fcurves,
-                        frames_location, frames_rotation, frames_scale,
-                        0)
-
-            if blender_nla_tracks:
-                for nla_track in blender_nla_tracks:
-                    if nla_track.mute:
-                        continue
-                    for strip in nla_track.strips:
-                        if strip.mute:
-                            continue
-                        frame_correction = strip.frame_start \
-                                - strip.action_frame_start
-                        self.fill_keyframe_sets(
-                                strip.action.fcurves,
-                                frames_location, frames_rotation, frames_scale,
-                                frame_correction)
-
-            frames = set(frames_location)
-            frames = frames.union(frames_rotation)
-            frames = frames.union(frames_scale)
-
-            if not self.options_shrink_to_keys:
-                frames = frames.intersection(range(
-                        blender_scene.frame_start, blender_scene.frame_end + 1))
-
-            frames_sorted = list(frames)
-            frames_sorted.sort()
-
-            if self.options_shrink_to_keys and len(frames_sorted) >= 2:
-                frame_start = frames_sorted[0]
-                frame_end = frames_sorted[len(frames_sorted)-1]
-                frame_total = (frame_end - frame_start) + 1
-                frame_offset = frame_start - 1
-
-            if self.options_bake_each_frame:
-                frames_sorted = range(int(frame_start), int(frame_end + 1),
-                        int(frame_step))
-
-            frame_temp = blender_scene.frame_current
-
-            for current_frame in frames_sorted:
-                blender_scene.frame_set(current_frame)
-
-                current_time = (current_frame - frame_offset) * time_base
-                for blender_bone_name in blender_bones_ordered:
-                    blender_bone = blender_bones[blender_bone_name]
-                    blender_pose_bone = blender_pose_bones[blender_bone_name]
-                    ms3d_joint = blender_to_ms3d_bones[blender_bone_name]
-
-                    m1 = blender_bone.matrix_local.inverted()
-                    if blender_pose_bone.parent:
-                        m2 = blender_pose_bone.parent.matrix_channel.inverted()
-                    else:
-                        m2 = 1
-                    m3 = blender_pose_bone.matrix.copy()
-                    m = ((m1 * m2) * m3)
-                    loc = m.to_translation()
-                    rot = m.to_euler('XZY')
-
-                    ms3d_joint.translation_key_frames.append(
-                            Ms3dTranslationKeyframe(
-                                    current_time, self.joint_correction(loc)
-                                    )
-                            )
-                    ms3d_joint.rotation_key_frames.append(
-                            Ms3dRotationKeyframe(
-                                    current_time, self.joint_correction(rot)
-                                    )
-                            )
-
-            blender_scene.frame_set(frame_temp)
-
-        ms3d_model.animation_fps = fps
-        if ms3d_model.number_joints > 0:
-            ms3d_model.number_total_frames = int(frame_total)
-            ms3d_model.current_time = ((blender_scene.frame_current \
-                    - blender_scene.frame_start) + 1) * time_base
-        else:
-            ms3d_model.number_total_frames = 1
-            ms3d_model.current_time = 0
-
-
-    ###########################################################################
-    def get_ms3d_group_default_material_add_if(self, ms3d_model):
-        markerName = "MaterialGroupDefault"
-        markerComment = "group without material"
-
-        for ms3d_group in ms3d_model._groups:
-            if ms3d_group.material_index == \
-                    Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX \
-                    and ms3d_group.name == markerName \
-                    and ms3d_group._comment_object \
-                    and ms3d_group._comment_object.comment == markerComment:
-                return ms3d_group
-
-        ms3d_group = Ms3dGroup()
-        ms3d_group.__index = len(ms3d_model._groups)
-        ms3d_group.name = markerName
-        ms3d_group._comment_object = Ms3dCommentEx()
-        ms3d_group._comment_object.comment = markerComment
-        ms3d_group._comment_object.index = len(ms3d_model._groups)
-        ms3d_group.material_index = Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX
-
-        ms3d_model._groups.append(ms3d_group)
-
-        return ms3d_group
-
-
-    ###########################################################################
-    def get_ms3d_group_by_material_add_if(self, ms3d_model, ms3d_material):
-        if ms3d_material.__index < 0 \
-                or ms3d_material.__index >= len(ms3d_model.materials):
-            return None
-
-        markerName = "MaterialGroup.{}".format(ms3d_material.__index)
-        markerComment = "MaterialGroup({})".format(ms3d_material.name)
-
-        for ms3d_group in ms3d_model._groups:
-            if ms3d_group.name == markerName \
-                    and ms3d_group._comment_object \
-                    and ms3d_group._comment_object.comment == markerComment:
-                return ms3d_group
-
-        ms3d_group = Ms3dGroup()
-        ms3d_group.__index = len(ms3d_model._groups)
-        ms3d_group.name = markerName
-        ms3d_group._comment_object = Ms3dCommentEx()
-        ms3d_group._comment_object.comment = markerComment
-        ms3d_group._comment_object.index = len(ms3d_model._groups)
-        ms3d_group.material_index = ms3d_material.__index
-
-        ms3d_model._groups.append(ms3d_group)
-
-        return ms3d_group
-
-
-    ###########################################################################
-    def get_ms3d_material_add_if(self, blender_mesh, ms3d_model,
-            blender_to_ms3d_materials, blender_index):
-        if blender_index < 0 or blender_index >= len(blender_mesh.materials):
-            return None
-
-        blender_material = blender_mesh.materials[blender_index]
-        ms3d_material = blender_to_ms3d_materials.get(blender_material)
-        if ms3d_material is None:
-            ms3d_material = Ms3dMaterial()
-            ms3d_material.__index = len(ms3d_model.materials)
-
-            blender_ms3d_material = blender_material.ms3d
-
-            if not self.options_use_blender_names \
-                    and not self.options_use_blender_materials \
-                    and blender_ms3d_material.name:
-                ms3d_material.name = blender_ms3d_material.name
-            else:
-                ms3d_material.name = blender_material.name
-
-            temp_material = None
-            if self.options_use_blender_materials:
-                temp_material = Ms3dMaterial()
-                Ms3dMaterialHelper.copy_from_blender(
-                        None, None, temp_material, blender_material)
-            else:
-                temp_material = blender_ms3d_material
-
-            ms3d_material._ambient = temp_material.ambient[:]
-            ms3d_material._diffuse = temp_material.diffuse[:]
-            ms3d_material._specular = temp_material.specular[:]
-            ms3d_material._emissive = temp_material.emissive[:]
-            ms3d_material.shininess = temp_material.shininess
-            ms3d_material.transparency = temp_material.transparency
-            ms3d_material.texture = temp_material.texture
-            ms3d_material.alphamap = temp_material.alphamap
-
-            ms3d_material.mode = Ms3dUi.texture_mode_to_ms3d(
-                    blender_ms3d_material.mode)
-            if blender_ms3d_material.comment:
-                ms3d_material._comment_object = Ms3dCommentEx()
-                ms3d_material._comment_object.comment = \
-                        blender_ms3d_material.comment
-                ms3d_material._comment_object.index = ms3d_material.__index
-
-            ms3d_model.materials.append(ms3d_material)
-
-            blender_to_ms3d_materials[blender_material] = ms3d_material
-
-        return ms3d_material
-
-
-    ###########################################################################
-    def geometry_correction(self, value):
-        return (value[1], value[2], value[0])
-
-
-    ###########################################################################
-    def joint_correction(self, value):
-        return (-value[0], value[2], value[1])
-
-
-    ###########################################################################
-    def build_blender_bone_dependency_order(self, blender_bones,
-            blender_bones_ordered):
-        if not blender_bones:
-            return blender_bones_ordered
-
-        blender_bones_children = {None: []}
-        for blender_bone in blender_bones:
-            if blender_bone.parent:
-                blender_bone_children = blender_bones_children.get(
-                        blender_bone.parent.name)
-                if blender_bone_children is None:
-                    blender_bone_children = blender_bones_children[
-                            blender_bone.parent.name] = []
-            else:
-                blender_bone_children = blender_bones_children[None]
-
-            blender_bone_children.append(blender_bone.name)
-
-        self.traverse_dependencies(
-                blender_bones_ordered,
-                blender_bones_children,
-                None)
-
-        return blender_bones_ordered
-
-
-    ###########################################################################
-    def traverse_dependencies(self, blender_bones_ordered,
-            blender_bones_children, key):
-        blender_bone_children = blender_bones_children.get(key)
-        if blender_bone_children:
-            for blender_bone_name in blender_bone_children:
-                blender_bones_ordered.append(blender_bone_name)
-                self.traverse_dependencies(
-                        blender_bones_ordered,
-                        blender_bones_children,
-                        blender_bone_name)
-
-    ###########################################################################
-    def fill_keyframe_sets(self,
-            fcurves,
-            frames_location, frames_rotation, frames_scale,
-            frame_correction):
-        for fcurve in fcurves:
-            if fcurve.data_path.endswith(".location"):
-                frames = frames_location
-            elif fcurve.data_path.endswith(".rotation_euler"):
-                frames = frames_rotation
-            elif fcurve.data_path.endswith(".rotation_quaternion"):
-                frames = frames_rotation
-            elif fcurve.data_path.endswith(".scale"):
-                frames = frames_scale
-            else:
-                pass
-
-            for keyframe_point in fcurve.keyframe_points:
-                frames.add(int(keyframe_point.co[0] + frame_correction))
-
-
-###############################################################################
-#234567890123456789012345678901234567890123456789012345678901234567890123456789
-#--------1---------2---------3---------4---------5---------6---------7---------
-# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_import.py b/io_scene_ms3d/ms3d_import.py
deleted file mode 100644 (file)
index ae6f164..0000000
+++ /dev/null
@@ -1,1036 +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>
-
-###############################################################################
-#234567890123456789012345678901234567890123456789012345678901234567890123456789
-#--------1---------2---------3---------4---------5---------6---------7---------
-
-
-# ##### BEGIN COPYRIGHT BLOCK #####
-#
-# initial script copyright (c)2011-2013 Alexander Nussbaumer
-#
-# ##### END COPYRIGHT BLOCK #####
-
-
-#import python stuff
-import io
-from mathutils import (
-        Vector,
-        Matrix,
-        )
-from os import (
-        path,
-        )
-from sys import (
-        exc_info,
-        )
-from time import (
-        time,
-        )
-
-
-# import io_scene_ms3d stuff
-from io_scene_ms3d.ms3d_strings import (
-        ms3d_str,
-        )
-from io_scene_ms3d.ms3d_spec import (
-        Ms3dSpec,
-        Ms3dModel,
-        Ms3dVertexEx2,
-        Ms3dVertexEx3,
-        Ms3dHeader,
-        )
-from io_scene_ms3d.ms3d_utils import (
-        select_all,
-        enable_pose_mode,
-        enable_edit_mode,
-        pre_setup_environment,
-        post_setup_environment,
-        get_edge_split_modifier_add_if,
-        )
-from io_scene_ms3d.ms3d_ui import (
-        Ms3dUi,
-        )
-
-
-#import blender stuff
-from bpy import (
-        ops,
-        )
-import bmesh
-from bpy_extras.image_utils import (
-        load_image,
-        )
-
-
-###############################################################################
-FORMAT_GROUP = "{}.g"
-FORMAT_IMAGE = "{}.i"
-FORMAT_TEXTURE = "{}.tex"
-# keep material name like it is (prevent name "snakes" on re-import)
-#FORMAT_MATERIAL = "{}.mat"
-FORMAT_MATERIAL = "{}"
-FORMAT_ACTION = "{}.act"
-FORMAT_MESH = "{}.m"
-FORMAT_MESH_OBJECT = "{}.mo"
-FORMAT_EMPTY_OBJECT = "{}.eo"
-FORMAT_ARMATURE = "{}.a"
-FORMAT_ARMATURE_OBJECT = "{}.ao"
-FORMAT_ARMATURE_NLA = "{}.an"
-
-###############################################################################
-class Ms3dImporter():
-    """
-    Load a MilkShape3D MS3D File
-    """
-    def __init__(self,
-            report,
-            verbose='NONE',
-            use_extended_normal_handling=False,
-            use_animation=True,
-            use_quaternion_rotation=False,
-            use_joint_size=False,
-            joint_size=1.0,
-            use_joint_to_bones=False,
-            ):
-        self.report = report
-        self.options_verbose = verbose
-        self.options_use_extended_normal_handling = use_extended_normal_handling
-        self.options_use_animation = use_animation
-        self.options_use_quaternion_rotation = use_quaternion_rotation
-        self.options_use_joint_size = use_joint_size
-        self.options_joint_size = joint_size
-        self.options_use_joint_to_bones = use_joint_to_bones
-        self.directory_name = ""
-        self.file_name = ""
-        pass
-
-    ###########################################################################
-    # create empty blender ms3d_model
-    # read ms3d file
-    # fill blender with ms3d_model content
-    def read(self, blender_context, filepath):
-        """ read ms3d file and convert ms3d content to bender content """
-        t1 = time()
-        t2 = None
-        self.has_textures = False
-
-        try:
-            # setup environment
-            pre_setup_environment(self, blender_context)
-
-            # inject splitted filepath
-            self.directory_name, self.file_name = path.split(filepath)
-
-            # create an empty ms3d template
-            ms3d_model = Ms3dModel(self.file_name)
-
-            try:
-                # open ms3d file
-                with io.FileIO(filepath, 'rb') as raw_io:
-                    # read and inject ms3d data from disk to internal structure
-                    debug_out = ms3d_model.read(raw_io)
-                    raw_io.close()
-
-                    if self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL:
-                        print(debug_out)
-            finally:
-                pass
-
-            # if option is set, this time will enlarges the io time
-            if self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL:
-                ms3d_model.print_internal()
-
-            t2 = time()
-
-            is_valid, statistics = ms3d_model.is_valid()
-
-            if is_valid:
-                # inject ms3d data to blender
-                self.to_blender(blender_context, ms3d_model)
-
-                post_setup_environment(self, blender_context)
-
-            if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                print()
-                print("##########################################################")
-                print("Import from MS3D to Blender")
-                print(statistics)
-                print("##########################################################")
-
-        except Ms3dHeader.HeaderError:
-            msg = "read - invalid file format."
-            if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                print(msg)
-                if self.report:
-                    self.report({'WARNING', 'ERROR', }, msg)
-
-            return False
-
-        except Exception:
-            type, value, traceback = exc_info()
-            if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                print("read - exception in try block\n  type: '{0}'\n"
-                        "  value: '{1}'".format(type, value, traceback))
-                if self.report:
-                    self.report({'WARNING', 'ERROR', }, "read - exception.")
-
-            if t2 is None:
-                t2 = time()
-
-            return False
-
-        else:
-            pass
-
-        t3 = time()
-
-        if self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-            print(ms3d_str['SUMMARY_IMPORT'].format(
-                    (t3 - t1), (t2 - t1), (t3 - t2)))
-
-        return True
-
-
-    ###########################################################################
-    def to_blender(self, blender_context, ms3d_model):
-        blender_mesh_object = self.create_geometry(blender_context, ms3d_model)
-        blender_armature_object = self.create_animation(
-                blender_context, ms3d_model, blender_mesh_object)
-
-        blender_empty_object = self.organize_objects(
-                blender_context, ms3d_model,
-                [blender_mesh_object, blender_armature_object])
-
-        return blender_empty_object, blender_mesh_object
-
-
-    ###########################################################################
-    def organize_objects(self, blender_context, ms3d_model, blender_objects):
-        ##########################
-        # blender_armature_object to blender_mesh_object
-        # that has bad side effects to the armature
-        # and causes cyclic dependencies
-        ###blender_armature_object.parent = blender_mesh_object
-        ###blender_mesh_object.parent = blender_armature_object
-
-        blender_scene = blender_context.scene
-        blender_collection = blender_context.collection
-
-        blender_group = blender_context.blend_data.collections.new(
-                FORMAT_GROUP.format(ms3d_model.name))
-        blender_empty_object = blender_context.blend_data.objects.new(
-                FORMAT_EMPTY_OBJECT.format(ms3d_model.name), None)
-        blender_empty_object.location = blender_scene.cursor.location
-        blender_collection.objects.link(blender_empty_object)
-        blender_group.objects.link(blender_empty_object)
-
-        for blender_object in blender_objects:
-            if blender_object is not None:
-                blender_group.objects.link(blender_object)
-                blender_object.parent = blender_empty_object
-
-        return blender_empty_object
-
-
-    ###########################################################################
-    def create_geometry(self, blender_context, ms3d_model):
-        ##########################
-        # blender stuff:
-        # create a blender Mesh
-        blender_mesh = blender_context.blend_data.meshes.new(
-                FORMAT_MESH.format(ms3d_model.name))
-        blender_mesh.ms3d.name = ms3d_model.name
-
-        ms3d_comment = ms3d_model.comment_object
-        if ms3d_comment is not None:
-            blender_mesh.ms3d.comment = ms3d_comment.comment
-        ms3d_model_ex = ms3d_model.model_ex_object
-        if ms3d_model_ex is not None:
-            blender_mesh.ms3d.joint_size = ms3d_model_ex.joint_size
-            blender_mesh.ms3d.alpha_ref = ms3d_model_ex.alpha_ref
-            blender_mesh.ms3d.transparency_mode \
-                    = Ms3dUi.transparency_mode_from_ms3d(
-                            ms3d_model_ex.transparency_mode)
-
-        ##########################
-        # blender stuff:
-        # link to blender object
-        blender_mesh_object = blender_context.blend_data.objects.new(
-                FORMAT_MESH_OBJECT.format(ms3d_model.name), blender_mesh)
-
-        ##########################
-        # blender stuff:
-        # create edge split modifier, to make sharp edges visible
-        blender_modifier = get_edge_split_modifier_add_if(blender_mesh_object)
-
-        ##########################
-        # blender stuff:
-        # link to blender scene
-        blender_collection = blender_context.collection
-        blender_view_layer = blender_context.view_layer
-        blender_collection.objects.link(blender_mesh_object)
-        #blender_mesh_object.location = blender_scene.cursor.location
-        enable_edit_mode(False, blender_context)
-        select_all(False)
-        blender_mesh_object.select_set(True)
-        blender_view_layer.objects.active = blender_mesh_object
-
-        ##########################
-        # take this as active object after import
-        self.active_object = blender_mesh_object
-
-        ##########################
-        # blender stuff:
-        # create all (ms3d) groups
-        ms3d_to_blender_group_index = {}
-        blender_group_manager = blender_mesh.ms3d
-        for ms3d_group_index, ms3d_group in enumerate(ms3d_model.groups):
-            blender_group = blender_group_manager.create_group()
-            blender_group.name = ms3d_group.name
-            blender_group.flags = Ms3dUi.flags_from_ms3d(ms3d_group.flags)
-            blender_group.material_index = ms3d_group.material_index
-
-            ms3d_comment = ms3d_group.comment_object
-            if ms3d_comment is not None:
-                blender_group.comment = ms3d_comment.comment
-
-            # translation dictionary
-            ms3d_to_blender_group_index[ms3d_group_index] = blender_group.id
-
-        ####################################################
-        # begin BMesh stuff
-        #
-
-        ##########################
-        # BMesh stuff:
-        # create an empty BMesh
-        bm = bmesh.new()
-
-        ##########################
-        # BMesh stuff:
-        # create new Layers for custom data per "mesh face"
-        layer_texture = bm.faces.layers.tex.get(
-                ms3d_str['OBJECT_LAYER_TEXTURE'])
-        if layer_texture is None:
-            layer_texture = bm.faces.layers.tex.new(
-                    ms3d_str['OBJECT_LAYER_TEXTURE'])
-
-        layer_smoothing_group = bm.faces.layers.int.get(
-                ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
-        if layer_smoothing_group is None:
-            layer_smoothing_group = bm.faces.layers.int.new(
-                    ms3d_str['OBJECT_LAYER_SMOOTHING_GROUP'])
-
-        layer_group = bm.faces.layers.int.get(
-                ms3d_str['OBJECT_LAYER_GROUP'])
-        if layer_group is None:
-            layer_group = bm.faces.layers.int.new(
-                    ms3d_str['OBJECT_LAYER_GROUP'])
-
-        ##########################
-        # BMesh stuff:
-        # create new Layers for custom data per "face vertex"
-        layer_uv = bm.loops.layers.uv.get(ms3d_str['OBJECT_LAYER_UV'])
-        if layer_uv is None:
-            layer_uv = bm.loops.layers.uv.new(ms3d_str['OBJECT_LAYER_UV'])
-
-        ##########################
-        # BMesh stuff:
-        # create new Layers for custom data per "vertex"
-        layer_extra = bm.verts.layers.int.get(ms3d_str['OBJECT_LAYER_EXTRA'])
-        if layer_extra is None:
-            layer_extra = bm.verts.layers.int.new(ms3d_str['OBJECT_LAYER_EXTRA'])
-
-        ##########################
-        # BMesh stuff:
-        # create all vertices
-        for ms3d_vertex_index, ms3d_vertex in enumerate(ms3d_model.vertices):
-            bmv = bm.verts.new(self.geometry_correction(ms3d_vertex.vertex))
-            bmv.index = ms3d_vertex_index
-
-            if layer_extra and ms3d_vertex.vertex_ex_object and \
-                    (isinstance(ms3d_vertex.vertex_ex_object, Ms3dVertexEx2) \
-                    or isinstance(ms3d_vertex.vertex_ex_object, Ms3dVertexEx3)):
-
-                #bmv[layer_extra] = ms3d_vertex.vertex_ex_object.extra
-                # bm.verts.layers.int does only support signed int32
-                # convert unsigned int32 to signed int32 (little-endian)
-                unsigned_int32 = ms3d_vertex.vertex_ex_object.extra
-                bytes_int32 = unsigned_int32.to_bytes(
-                        4, byteorder='little', signed=False)
-                signed_int32 = int.from_bytes(
-                        bytes_int32, byteorder='little', signed=True)
-                bmv[layer_extra] = signed_int32
-        bm.verts.ensure_lookup_table()
-
-        ##########################
-        # blender stuff (uses BMesh stuff):
-        # create all materials / image textures
-        ms3d_to_blender_material = {}
-        for ms3d_material_index, ms3d_material in enumerate(
-                ms3d_model.materials):
-            blender_material = blender_context.blend_data.materials.new(
-                    FORMAT_MATERIAL.format(ms3d_material.name))
-
-            # custom data
-            blender_material.ms3d.name = ms3d_material.name
-            blender_material.ms3d.ambient = ms3d_material.ambient
-            blender_material.ms3d.diffuse = ms3d_material.diffuse
-            blender_material.ms3d.specular = ms3d_material.specular
-            blender_material.ms3d.emissive = ms3d_material.emissive
-            blender_material.ms3d.shininess = ms3d_material.shininess
-            blender_material.ms3d.transparency = ms3d_material.transparency
-            blender_material.ms3d.mode = Ms3dUi.texture_mode_from_ms3d(
-                    ms3d_material.mode)
-
-            if ms3d_material.texture:
-                blender_material.ms3d.texture = ms3d_material.texture
-
-            if ms3d_material.alphamap:
-                blender_material.ms3d.alphamap = ms3d_material.alphamap
-
-            ms3d_comment = ms3d_material.comment_object
-            if ms3d_comment is not None:
-                blender_material.ms3d.comment = ms3d_comment.comment
-
-            # blender data
-            blender_material.ambient = (
-                    (ms3d_material.ambient[0]
-                    + ms3d_material.ambient[1]
-                    + ms3d_material.ambient[2]) / 3.0)
-
-            blender_material.diffuse_color[0] = ms3d_material.diffuse[0]
-            blender_material.diffuse_color[1] = ms3d_material.diffuse[1]
-            blender_material.diffuse_color[2] = ms3d_material.diffuse[2]
-
-            blender_material.specular_color[0] = ms3d_material.specular[0]
-            blender_material.specular_color[1] = ms3d_material.specular[1]
-            blender_material.specular_color[2] = ms3d_material.specular[2]
-
-            blender_material.emit = (
-                    (ms3d_material.emissive[0]
-                    + ms3d_material.emissive[1]
-                    + ms3d_material.emissive[2]) / 3.0)
-
-            blender_material.specular_hardness = ms3d_material.shininess * 4.0
-            blender_material.alpha = 1.0 - ms3d_material.transparency
-
-            # diffuse texture
-            if ms3d_material.texture:
-                dir_name_diffuse = self.directory_name
-                file_name_diffuse = path.split(ms3d_material.texture)[1]
-                blender_image_diffuse = load_image(
-                        file_name_diffuse, dir_name_diffuse)
-                name_diffuse = path.splitext(file_name_diffuse)[0]
-                if blender_image_diffuse:
-                    blender_image_diffuse.name = FORMAT_IMAGE.format(name_diffuse)
-                blender_texture_diffuse = \
-                        blender_context.blend_data.textures.new(
-                        name=FORMAT_TEXTURE.format(name_diffuse),
-                        type='IMAGE')
-                blender_texture_diffuse.image = blender_image_diffuse
-                blender_texture_slot_diffuse \
-                        = blender_material.texture_slots.add()
-                blender_texture_slot_diffuse.texture = blender_texture_diffuse
-                blender_texture_slot_diffuse.texture_coords = 'UV'
-                blender_texture_slot_diffuse.uv_layer = layer_uv.name
-                blender_texture_slot_diffuse.use_map_color_diffuse = True
-                blender_texture_slot_diffuse.use_map_alpha = False
-                if blender_image_diffuse is not None:
-                    self.has_textures = True
-            else:
-                blender_image_diffuse = None
-
-            # alpha texture
-            if ms3d_material.alphamap:
-                dir_name_alpha = self.directory_name
-                file_name_alpha = path.split(ms3d_material.alphamap)[1]
-                blender_image_alpha = load_image(
-                        file_name_alpha, dir_name_alpha)
-                name_alpha = path.splitext(file_name_alpha)[0]
-                if blender_image_alpha:
-                    blender_image_alpha.name = FORMAT_IMAGE.format(name_alpha)
-                blender_texture_alpha = blender_context.blend_data.textures.new(
-                        name=FORMAT_TEXTURE.format(file_name_alpha),
-                        type='IMAGE')
-                blender_texture_alpha.image = blender_image_alpha
-                blender_texture_slot_alpha \
-                        = blender_material.texture_slots.add()
-                blender_texture_slot_alpha.texture = blender_texture_alpha
-                blender_texture_slot_alpha.texture_coords = 'UV'
-                blender_texture_slot_alpha.uv_layer = layer_uv.name
-                blender_texture_slot_alpha.use_map_color_diffuse = False
-                blender_texture_slot_alpha.use_map_alpha = True
-                blender_texture_slot_alpha.use_rgb_to_intensity = True
-                blender_material.alpha = 0
-                blender_material.specular_alpha = 0
-
-            # append blender material to blender mesh, to be linked to
-            blender_mesh.materials.append(blender_material)
-
-            # translation dictionary
-            ms3d_to_blender_material[ms3d_material_index] \
-                    = blender_image_diffuse
-
-        ##########################
-        # BMesh stuff:
-        # create all triangles
-        length_verts = len(bm.verts)
-        vertex_extra_index = length_verts
-        blender_invalide_normal = Vector()
-        smoothing_group_blender_faces = {}
-        for ms3d_triangle_index, ms3d_triangle in enumerate(
-                ms3d_model.triangles):
-            bmv_list = []
-            bmf_normal = Vector()
-
-            for index, vert_index in enumerate(ms3d_triangle.vertex_indices):
-                if vert_index < 0 or vert_index >= length_verts:
-                    continue
-                bmv = bm.verts[vert_index]
-
-                blender_normal = self.geometry_correction(
-                        ms3d_triangle.vertex_normals[index])
-                if bmv.normal == blender_invalide_normal:
-                    bmv.normal = blender_normal
-                elif bmv.normal != blender_normal \
-                        and self.options_use_extended_normal_handling:
-                    ## search for an already created extra vertex
-                    bmv_new = None
-                    for vert_index_candidat in range(
-                            vertex_extra_index, length_verts):
-                        bmv_candidat = bm.verts[vert_index_candidat]
-                        if bmv_candidat.co == bmv.co \
-                                and bmv_candidat.normal == blender_normal:
-                            bmv_new = bmv_candidat
-                            vert_index = vert_index_candidat
-                            break
-
-                    ## if not exists, create one in blender and ms3d as well
-                    if bmv_new is None:
-                        ms3d_model.vertices.append(
-                                ms3d_model.vertices[vert_index])
-                        bmv_new = bm.verts.new(bmv.co)
-                        bm.verts.ensure_lookup_table()
-                        bmv_new.index = -vert_index
-                        bmv_new.normal = blender_normal
-                        bmv_new[layer_extra] = bmv[layer_extra]
-                        vert_index = length_verts
-                        length_verts += 1
-                        if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                            self.report({'WARNING', 'INFO'},
-                                    ms3d_str['WARNING_IMPORT_EXTRA_VERTEX_NORMAL'].format(
-                                    bmv.normal, blender_normal))
-                    bmv = bmv_new
-
-                if [[x] for x in bmv_list if x == bmv]:
-                    if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                        self.report(
-                                {'WARNING', 'INFO'},
-                                ms3d_str['WARNING_IMPORT_SKIP_VERTEX_DOUBLE'].format(
-                                        ms3d_triangle_index))
-                    continue
-                bmv_list.append(bmv)
-                bmf_normal += bmv.normal
-
-            if len(bmv_list) < 3:
-                if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                    self.report(
-                            {'WARNING', 'INFO'},
-                            ms3d_str['WARNING_IMPORT_SKIP_LESS_VERTICES'].format(
-                                    ms3d_triangle_index))
-                continue
-
-            # create edges for the face
-            # (not really needed, because bm.faces.new() will create its edges,
-            # if not exist, but good if we have already in case we need full control
-            # of bmesh stuff maybe in the future.
-            bme = bm.edges.get((bmv_list[0], bmv_list[1]))
-            if bme is None:
-                bme = bm.edges.new((bmv_list[0], bmv_list[1]))
-                ##bm.edges.ensure_lookup_table()
-                bme.index = len(bm.edges) - 1
-            bme = bm.edges.get((bmv_list[1], bmv_list[2]))
-            if bme is None:
-                bme = bm.edges.new((bmv_list[1], bmv_list[2]))
-                ##bm.edges.ensure_lookup_table()
-                bme.index = len(bm.edges) - 1
-            bme = bm.edges.get((bmv_list[2], bmv_list[0]))
-            if bme is None:
-                bme = bm.edges.new((bmv_list[2], bmv_list[0]))
-                ##bm.edges.ensure_lookup_table()
-                bme.index = len(bm.edges) - 1
-
-            bmf = bm.faces.get(bmv_list)
-            if bmf is not None:
-                if self.report and self.options_verbose in Ms3dUi.VERBOSE_NORMAL:
-                    self.report(
-                            {'WARNING', 'INFO'},
-                            ms3d_str['WARNING_IMPORT_SKIP_FACE_DOUBLE'].format(
-                                    ms3d_triangle_index))
-                continue
-
-            bmf = bm.faces.new(bmv_list)
-            bmf.index = ms3d_triangle_index
-            bmf_normal.normalize()
-            bmf.normal = bmf_normal
-
-            # blender uv custom data per "face vertex"
-            bmf.loops[0][layer_uv].uv = Vector(
-                    (ms3d_triangle.s[0], 1.0 - ms3d_triangle.t[0]))
-            bmf.loops[1][layer_uv].uv = Vector(
-                    (ms3d_triangle.s[1], 1.0 - ms3d_triangle.t[1]))
-            bmf.loops[2][layer_uv].uv = Vector(
-                    (ms3d_triangle.s[2], 1.0 - ms3d_triangle.t[2]))
-
-            # ms3d custom data per "mesh face"
-            bmf[layer_smoothing_group] = ms3d_triangle.smoothing_group
-
-            blender_group_id = ms3d_to_blender_group_index.get(
-                    ms3d_triangle.group_index)
-            if blender_group_id is not None:
-                bmf[layer_group] = blender_group_id
-
-            if ms3d_triangle.group_index >= 0 \
-                    and ms3d_triangle.group_index < len(ms3d_model.groups):
-                ms3d_material_index \
-                        = ms3d_model.groups[ms3d_triangle.group_index].material_index
-                if ms3d_material_index != Ms3dSpec.NONE_GROUP_MATERIAL_INDEX:
-                    bmf.material_index = ms3d_material_index
-                    # apply diffuse texture image to face, to be visible in 3d view
-                    bmf[layer_texture].image = ms3d_to_blender_material.get(
-                            ms3d_material_index)
-
-            # helper dictionary for post-processing smoothing_groups
-            smoothing_group_blender_face = smoothing_group_blender_faces.get(
-                    ms3d_triangle.smoothing_group)
-            if smoothing_group_blender_face is None:
-                smoothing_group_blender_face = []
-                smoothing_group_blender_faces[ms3d_triangle.smoothing_group] \
-                        = smoothing_group_blender_face
-            smoothing_group_blender_face.append(bmf)
-        ##bm.faces.ensure_lookup_table()
-
-        ##########################
-        # BMesh stuff:
-        # create all sharp edges for blender to make smoothing_groups visible
-        for ms3d_smoothing_group_index, blender_face_list \
-                in smoothing_group_blender_faces.items():
-            edge_dict = {}
-            for bmf in blender_face_list:
-                bmf.smooth = True
-                for bme in bmf.edges:
-                    if edge_dict.get(bme) is None:
-                        edge_dict[bme] = 0
-                    else:
-                        edge_dict[bme] += 1
-                    bme.seam = (edge_dict[bme] == 0)
-                    bme.smooth = (edge_dict[bme] != 0)
-
-        ##########################
-        # BMesh stuff:
-        # finally transfer BMesh to Mesh
-        bm.to_mesh(blender_mesh)
-        bm.free()
-
-
-        #
-        # end BMesh stuff
-        ####################################################
-
-        blender_mesh.validate(self.options_verbose in Ms3dUi.VERBOSE_MAXIMAL)
-
-        return blender_mesh_object
-
-
-    ###########################################################################
-    def create_animation(self, blender_context, ms3d_model, blender_mesh_object):
-        ##########################
-        # setup scene
-        blender_collection = blender_context.collection
-        blender_scene = blender_context.scene
-        blender_scene.render.fps = ms3d_model.animation_fps
-        if ms3d_model.animation_fps:
-            blender_scene.render.fps_base = (blender_scene.render.fps /
-                    ms3d_model.animation_fps)
-
-        blender_scene.frame_start = 1
-        blender_scene.frame_end = (ms3d_model.number_total_frames
-                + blender_scene.frame_start) - 1
-        blender_scene.frame_current = (ms3d_model.current_time
-                * ms3d_model.animation_fps)
-
-        ##########################
-        if not ms3d_model.joints:
-            return
-
-        ##########################
-        ms3d_armature_name = FORMAT_ARMATURE.format(ms3d_model.name)
-        ms3d_armature_object_name = FORMAT_ARMATURE_OBJECT.format(ms3d_model.name)
-        ms3d_action_name = FORMAT_ACTION.format(ms3d_model.name)
-
-        ##########################
-        # create new blender_armature_object
-        blender_armature = blender_context.blend_data.armatures.new(
-                ms3d_armature_name)
-        blender_armature.ms3d.name = ms3d_model.name
-        blender_armature.display_type = 'STICK'
-        blender_armature.show_axes = True
-        blender_armature.use_auto_ik = True
-        blender_armature_object = blender_context.blend_data.objects.new(
-                ms3d_armature_object_name, blender_armature)
-        blender_collection.objects.link(blender_armature_object)
-        #blender_armature_object.location = blender_scene.cursor.location
-        blender_armature_object.show_in_front = True
-
-        ##########################
-        # create new modifier
-        blender_modifier = blender_mesh_object.modifiers.new(
-                blender_armature.name, type='ARMATURE')
-        blender_modifier.show_expanded = False
-        blender_modifier.use_vertex_groups = True
-        blender_modifier.use_bone_envelopes = False
-        blender_modifier.object = blender_armature_object
-
-        ##########################
-        # prepare for vertex groups
-        ms3d_to_blender_vertex_groups = {}
-        for ms3d_vertex_index, ms3d_vertex in enumerate(ms3d_model.vertices):
-            # prepare for later use for blender vertex group
-            if ms3d_vertex.bone_id != Ms3dSpec.NONE_VERTEX_BONE_ID:
-                if ms3d_vertex.vertex_ex_object \
-                        and ( \
-                        ms3d_vertex.vertex_ex_object.bone_ids[0] != \
-                                Ms3dSpec.NONE_VERTEX_BONE_ID \
-                        or ms3d_vertex.vertex_ex_object.bone_ids[1] != \
-                                Ms3dSpec.NONE_VERTEX_BONE_ID \
-                        or ms3d_vertex.vertex_ex_object.bone_ids[2] != \
-                                Ms3dSpec.NONE_VERTEX_BONE_ID \
-                        ):
-                    ms3d_vertex_group_ids_weights = []
-                    ms3d_vertex_group_ids_weights.append(
-                            (ms3d_vertex.bone_id,
-                            float(ms3d_vertex.vertex_ex_object.weights[0] % 101) / 100.0,
-                            ))
-                    if ms3d_vertex.vertex_ex_object.bone_ids[0] != \
-                            Ms3dSpec.NONE_VERTEX_BONE_ID:
-                        ms3d_vertex_group_ids_weights.append(
-                                (ms3d_vertex.vertex_ex_object.bone_ids[0],
-                                float(ms3d_vertex.vertex_ex_object.weights[1] % 101) / 100.0
-                                ))
-                    if ms3d_vertex.vertex_ex_object.bone_ids[1] != \
-                            Ms3dSpec.NONE_VERTEX_BONE_ID:
-                        ms3d_vertex_group_ids_weights.append(
-                                (ms3d_vertex.vertex_ex_object.bone_ids[1],
-                                float(ms3d_vertex.vertex_ex_object.weights[2] % 101) / 100.0
-                                ))
-                    if ms3d_vertex.vertex_ex_object.bone_ids[2] != \
-                            Ms3dSpec.NONE_VERTEX_BONE_ID:
-                        ms3d_vertex_group_ids_weights.append(
-                                (ms3d_vertex.vertex_ex_object.bone_ids[2],
-                                1.0 -
-                                float((ms3d_vertex.vertex_ex_object.weights[0] % 101)
-                                + (ms3d_vertex.vertex_ex_object.weights[1] % 101)
-                                + (ms3d_vertex.vertex_ex_object.weights[2] % 101)) / 100.0
-                                ))
-
-                else:
-                    ms3d_vertex_group_ids_weights = [(ms3d_vertex.bone_id, 1.0), ]
-
-                for ms3d_vertex_group_id_weight in ms3d_vertex_group_ids_weights:
-                    ms3d_vertex_group_id = ms3d_vertex_group_id_weight[0]
-                    blender_vertex_weight = ms3d_vertex_group_id_weight[1]
-                    blender_vertex_group = ms3d_to_blender_vertex_groups.get(
-                            ms3d_vertex_group_id)
-                    if blender_vertex_group is None:
-                        ms3d_to_blender_vertex_groups[ms3d_vertex_group_id] \
-                                = blender_vertex_group = []
-                    blender_vertex_group.append((ms3d_vertex_index,
-                            blender_vertex_weight))
-
-        ##########################
-        # blender stuff:
-        # create all vertex groups to be used for bones
-        for ms3d_bone_id, blender_vertex_index_weight_list \
-                in ms3d_to_blender_vertex_groups.items():
-            ms3d_name = ms3d_model.joints[ms3d_bone_id].name
-            blender_vertex_group = blender_mesh_object.vertex_groups.new(
-                    name=ms3d_name)
-            for blender_vertex_id_weight in blender_vertex_index_weight_list:
-                blender_vertex_index = blender_vertex_id_weight[0]
-                blender_vertex_weight = blender_vertex_id_weight[1]
-                blender_vertex_group.add((blender_vertex_index, ),
-                        blender_vertex_weight, 'ADD')
-
-        ##########################
-        # bring joints in the correct order
-        ms3d_joints_ordered = []
-        self.build_ms3d_joint_dependency_order(ms3d_model.joints,
-                ms3d_joints_ordered)
-
-        ##########################
-        # prepare joint data for later use
-        ms3d_joint_by_name = {}
-        for ms3d_joint in ms3d_joints_ordered:
-            item = ms3d_joint_by_name.get(ms3d_joint.name)
-            if item is None:
-                ms3d_joint.__children = []
-                ms3d_joint_by_name[ms3d_joint.name] = ms3d_joint
-
-            matrix_local_rot = (Matrix.Rotation(ms3d_joint.rotation[2], 4, 'Z')
-                    * Matrix.Rotation(ms3d_joint.rotation[1], 4, 'Y')
-                    ) * Matrix.Rotation(ms3d_joint.rotation[0], 4, 'X')
-            matrix_local = Matrix.Translation(Vector(ms3d_joint.position)
-                    ) * matrix_local_rot
-
-            ms3d_joint.__matrix_local_rot = matrix_local_rot
-            ms3d_joint.__matrix_global_rot = matrix_local_rot
-            ms3d_joint.__matrix_local = matrix_local
-            ms3d_joint.__matrix_global = matrix_local
-
-            if ms3d_joint.parent_name:
-                ms3d_joint_parent = ms3d_joint_by_name.get(
-                        ms3d_joint.parent_name)
-                if ms3d_joint_parent is not None:
-                    ms3d_joint_parent.__children.append(ms3d_joint)
-
-                    matrix_global = ms3d_joint_parent.__matrix_global \
-                            * matrix_local
-                    ms3d_joint.__matrix_global = matrix_global
-
-                    matrix_global_rot = ms3d_joint_parent.__matrix_global_rot \
-                            * matrix_local_rot
-                    ms3d_joint.__matrix_global_rot = matrix_global_rot
-
-        ##########################
-        # ms3d_joint to blender_edit_bone
-        if ms3d_model.model_ex_object and not self.options_use_joint_size:
-            joint_length = ms3d_model.model_ex_object.joint_size
-        else:
-            joint_length = self.options_joint_size
-        if joint_length < 0.01:
-            joint_length = 0.01
-
-        blender_view_layer.objects.active = blender_armature_object
-        enable_edit_mode(True, blender_context)
-        for ms3d_joint in ms3d_joints_ordered:
-            blender_edit_bone = blender_armature.edit_bones.new(ms3d_joint.name)
-            blender_edit_bone.use_connect = False
-            blender_edit_bone.use_inherit_rotation = True
-            blender_edit_bone.use_inherit_scale = True
-            blender_edit_bone.use_local_location = True
-            blender_armature.edit_bones.active = blender_edit_bone
-
-            ms3d_joint = ms3d_joint_by_name[ms3d_joint.name]
-            ms3d_joint_vector = ms3d_joint.__matrix_global * Vector()
-
-            blender_edit_bone.head \
-                    = self.geometry_correction(ms3d_joint_vector)
-
-            vector_tail_end_up = ms3d_joint.__matrix_global_rot * Vector((0,1,0))
-            vector_tail_end_dir = ms3d_joint.__matrix_global_rot * Vector((0,0,1))
-            vector_tail_end_up.normalize()
-            vector_tail_end_dir.normalize()
-            blender_edit_bone.tail = blender_edit_bone.head \
-                    + self.geometry_correction(
-                    vector_tail_end_dir * joint_length)
-            blender_edit_bone.align_roll(self.geometry_correction(
-                    vector_tail_end_up))
-
-            if ms3d_joint.parent_name:
-                ms3d_joint_parent = ms3d_joint_by_name[ms3d_joint.parent_name]
-                blender_edit_bone_parent = ms3d_joint_parent.blender_edit_bone
-                blender_edit_bone.parent = blender_edit_bone_parent
-
-            ms3d_joint.blender_bone_name = blender_edit_bone.name
-            ms3d_joint.blender_edit_bone = blender_edit_bone
-        enable_edit_mode(False, blender_context)
-
-        if self.options_use_joint_to_bones:
-            enable_edit_mode(True, blender_context)
-            for ms3d_joint in ms3d_joints_ordered:
-                blender_edit_bone = blender_armature.edit_bones[ms3d_joint.name]
-                if blender_edit_bone.children:
-                    new_length = 0.0
-                    for child_bone in blender_edit_bone.children:
-                        length = (child_bone.head - blender_edit_bone.head).length
-                        if new_length <= 0 or length < new_length:
-                            new_length = length
-                    if new_length >= 0.01:
-                        direction = blender_edit_bone.tail - blender_edit_bone.head
-                        direction.normalize()
-                        blender_edit_bone.tail = blender_edit_bone.head + (direction * new_length)
-            enable_edit_mode(False, blender_context)
-
-        ##########################
-        # post process bones
-        enable_edit_mode(False, blender_context)
-        for ms3d_joint_name, ms3d_joint in ms3d_joint_by_name.items():
-            blender_bone = blender_armature.bones.get(
-                    ms3d_joint.blender_bone_name)
-            if blender_bone is None:
-                continue
-
-            blender_bone.ms3d.name = ms3d_joint.name
-            blender_bone.ms3d.flags = Ms3dUi.flags_from_ms3d(ms3d_joint.flags)
-
-            ms3d_joint_ex = ms3d_joint.joint_ex_object
-            if ms3d_joint_ex is not None:
-                blender_bone.ms3d.color = ms3d_joint_ex.color
-
-            ms3d_comment = ms3d_joint.comment_object
-            if ms3d_comment is not None:
-                blender_bone.ms3d.comment = ms3d_comment.comment
-
-        ##########################
-        if not self.options_use_animation:
-            return blender_armature_object
-
-
-        ##########################
-        # process pose bones
-        enable_pose_mode(True, blender_context)
-
-        blender_action = blender_context.blend_data.actions.new(ms3d_action_name)
-        if blender_armature_object.animation_data is None:
-            blender_armature_object.animation_data_create()
-        blender_armature_object.animation_data.action = blender_action
-
-        ##########################
-        # transition between keys may be incorrect
-        # because of the gimbal-lock problem!
-        # http://www.youtube.com/watch?v=zc8b2Jo7mno
-        # http://www.youtube.com/watch?v=rrUCBOlJdt4
-        # you can fix it manually by selecting the affected keyframes
-        # and apply the following option to it:
-        # "Graph Editor -> Key -> Discontinuity (Euler) Filter"
-        # ==> "bpy.ops.graph.euler_filter()"
-        # but this option is only available for Euler rotation f-curves!
-        #
-        for ms3d_joint_name, ms3d_joint in ms3d_joint_by_name.items():
-            blender_pose_bone = blender_armature_object.pose.bones.get(
-                    ms3d_joint.blender_bone_name)
-            if blender_pose_bone is None:
-                continue
-
-            data_path = blender_pose_bone.path_from_id('location')
-            fcurve_location_x = blender_action.fcurves.new(data_path, index=0)
-            fcurve_location_y = blender_action.fcurves.new(data_path, index=1)
-            fcurve_location_z = blender_action.fcurves.new(data_path, index=2)
-            for translation_key_frames in ms3d_joint.translation_key_frames:
-                frame = (translation_key_frames.time * ms3d_model.animation_fps)
-                matrix_local = Matrix.Translation(
-                        Vector(translation_key_frames.position))
-                v = (matrix_local) * Vector()
-                fcurve_location_x.keyframe_points.insert(frame, -v[0])
-                fcurve_location_y.keyframe_points.insert(frame, v[2])
-                fcurve_location_z.keyframe_points.insert(frame, v[1])
-
-            if self.options_use_quaternion_rotation:
-                blender_pose_bone.rotation_mode = 'QUATERNION'
-                data_path = blender_pose_bone.path_from_id("rotation_quaternion")
-                fcurve_rotation_w = blender_action.fcurves.new(data_path, index=0)
-                fcurve_rotation_x = blender_action.fcurves.new(data_path, index=1)
-                fcurve_rotation_y = blender_action.fcurves.new(data_path, index=2)
-                fcurve_rotation_z = blender_action.fcurves.new(data_path, index=3)
-                for rotation_key_frames in ms3d_joint.rotation_key_frames:
-                    frame = (rotation_key_frames.time * ms3d_model.animation_fps)
-                    matrix_local_rot = (
-                            Matrix.Rotation(
-                                    rotation_key_frames.rotation[2], 4, 'Y')
-                            * Matrix.Rotation(
-                                    rotation_key_frames.rotation[1], 4, 'Z')
-                            ) * Matrix.Rotation(
-                                    -rotation_key_frames.rotation[0], 4, 'X')
-                    q = (matrix_local_rot).to_quaternion()
-                    fcurve_rotation_w.keyframe_points.insert(frame, q.w)
-                    fcurve_rotation_x.keyframe_points.insert(frame, q.x)
-                    fcurve_rotation_y.keyframe_points.insert(frame, q.y)
-                    fcurve_rotation_z.keyframe_points.insert(frame, q.z)
-            else:
-                blender_pose_bone.rotation_mode = 'XZY'
-                data_path = blender_pose_bone.path_from_id("rotation_euler")
-                fcurve_rotation_x = blender_action.fcurves.new(data_path, index=0)
-                fcurve_rotation_y = blender_action.fcurves.new(data_path, index=1)
-                fcurve_rotation_z = blender_action.fcurves.new(data_path, index=2)
-                for rotation_key_frames in ms3d_joint.rotation_key_frames:
-                    frame = (rotation_key_frames.time * ms3d_model.animation_fps)
-                    fcurve_rotation_x.keyframe_points.insert(
-                            frame, -rotation_key_frames.rotation[0])
-                    fcurve_rotation_y.keyframe_points.insert(
-                            frame, rotation_key_frames.rotation[2])
-                    fcurve_rotation_z.keyframe_points.insert(
-                            frame, rotation_key_frames.rotation[1])
-
-        enable_pose_mode(False, blender_context)
-
-        return blender_armature_object
-
-
-    ###########################################################################
-    def geometry_correction(self, value):
-        return Vector((value[2], value[0], value[1]))
-
-
-    ###########################################################################
-    def build_ms3d_joint_dependency_order(self, ms3d_joints, ms3d_joints_ordered):
-        ms3d_joints_children = {"": {}}
-        for ms3d_joint in ms3d_joints:
-            if ms3d_joint.parent_name:
-                ms3d_joint_children = ms3d_joints_children.get(
-                        ms3d_joint.parent_name)
-                if ms3d_joint_children is None:
-                    ms3d_joint_children = ms3d_joints_children[
-                            ms3d_joint.parent_name] = {}
-            else:
-                ms3d_joint_children = ms3d_joints_children[""]
-
-            ms3d_joint_children[ms3d_joint.name] = ms3d_joint
-
-        self.traverse_dependencies(
-                ms3d_joints_ordered,
-                ms3d_joints_children,
-                "")
-
-
-        return ms3d_joints_ordered
-
-
-    ###########################################################################
-    def traverse_dependencies(self, ms3d_joints_ordered, ms3d_joints_children,
-            key):
-        ms3d_joint_children = ms3d_joints_children.get(key)
-        if ms3d_joint_children:
-            for item in ms3d_joint_children.items():
-                ms3d_joint_name = item[0]
-                ms3d_joint = item[1]
-                ms3d_joints_ordered.append(ms3d_joint)
-                self.traverse_dependencies(
-                        ms3d_joints_ordered,
-                        ms3d_joints_children,
-                        ms3d_joint_name)
-
-
-###############################################################################
-#234567890123456789012345678901234567890123456789012345678901234567890123456789
-#--------1---------2---------3---------4---------5---------6---------7---------
-# ##### END OF FILE #####
diff --git a/io_scene_ms3d/ms3d_spec.py b/io_scene_ms3d/ms3d_spec.py
deleted file mode 100644 (file)
index d5eadbe..0000000
+++ /dev/null
@@ -1,2086 +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>
-
-###############################################################################
-#234567890123456789012345678901234567890123456789012345678901234567890123456789
-#--------1---------2---------3---------4---------5---------6---------7---------
-
-
-# ##### BEGIN COPYRIGHT BLOCK #####
-#
-# initial script copyright (c)2011-2013 Alexander Nussbaumer
-#
-# ##### END COPYRIGHT BLOCK #####
-
-
-from struct import (
-        pack,
-        unpack,
-        )
-from sys import (
-        exc_info,
-        )
-from codecs import (
-        register_error,
-        )
-
-###############################################################################
-#
-# MilkShape 3D 1.8.5 File Format Specification
-#
-# all specifications were taken from SDK 1.8.5
-#
-# some additional specifications were taken from
-# MilkShape 3D Viewer v2.0 (Nov 06 2007) - msMesh.h
-#
-
-
-###############################################################################
-#
-# sizes
-#
-
-class Ms3dSpec:
-    ###########################################################################
-    #
-    # max values
-    #
-    MAX_VERTICES = 65534 # 0..65533; note: (65534???, 65535???)
-    MAX_TRIANGLES = 65534 # 0..65533; note: (65534???, 65535???)
-    MAX_GROUPS = 255 # 1..255; note: (0 default group)
-    MAX_MATERIALS = 128 # 0..127; note: (-1 no material)
-    MAX_JOINTS = 128 # 0..127; note: (-1 no joint)
-    MAX_SMOOTH_GROUP = 32 # 0..32; note: (0 no smoothing group)
-    MAX_TEXTURE_FILENAME_SIZE = 128
-
-    ###########################################################################
-    #
-    # flags
-    #
-    FLAG_NONE = 0
-    FLAG_SELECTED = 1
-    FLAG_HIDDEN = 2
-    FLAG_SELECTED2 = 4
-    FLAG_DIRTY = 8
-    FLAG_ISKEY = 16 # additional spec from [2]
-    FLAG_NEWLYCREATED = 32 # additional spec from [2]
-    FLAG_MARKED = 64 # additional spec from [2]
-
-    FLAG_TEXTURE_NONE = 0x00
-    FLAG_TEXTURE_COMBINE_ALPHA = 0x20
-    FLAG_TEXTURE_HAS_ALPHA = 0x40
-    FLAG_TEXTURE_SPHERE_MAP = 0x80
-
-    MODE_TRANSPARENCY_SIMPLE = 0
-    MODE_TRANSPARENCY_DEPTH_BUFFERED_WITH_ALPHA_REF = 1
-    MODE_TRANSPARENCY_DEPTH_SORTED_TRIANGLES = 2
-
-
-    ###########################################################################
-    #
-    # values
-    #
-    HEADER = "MS3D000000"
-
-
-    ## TEST_STR = 'START@€@µ@²@³@©@®@¶@ÿ@A@END.bmp'
-    ## TEST_RAW = b'START@\x80@\xb5@\xb2@\xb3@\xa9@\xae@\xb6@\xff@A@END.bmp\x00'
-    ##
-    STRING_MS3D_REPLACE = 'use_ms3d_replace'
-    STRING_ENCODING = "ascii" # wrong encoding (too limited), but there is an UnicodeEncodeError issue, that prevent using the correct one for the moment
-    ##STRING_ENCODING = "cp437" # US, wrong encoding and shows UnicodeEncodeError
-    ##STRING_ENCODING = "cp858" # Europe + €, wrong encoding and shows UnicodeEncodeError
-    ##STRING_ENCODING = "cp1252" # WIN EU, this would be the better codepage, but shows UnicodeEncodeError, on print on system console and writing to file
-    STRING_ERROR = STRING_MS3D_REPLACE
-    ##STRING_ERROR = 'replace'
-    ##STRING_ERROR = 'ignore'
-    ##STRING_ERROR = 'surrogateescape'
-    STRING_TERMINATION = b'\x00'
-    STRING_REPLACE = u'_'
-
-
-    ###########################################################################
-    #
-    # min, max, default values
-    #
-    NONE_VERTEX_BONE_ID = -1
-    NONE_GROUP_MATERIAL_INDEX = -1
-
-    DEFAULT_HEADER = HEADER
-    DEFAULT_HEADER_VERSION = 4
-    DEFAULT_VERTEX_BONE_ID = NONE_VERTEX_BONE_ID
-    DEFAULT_TRIANGLE_SMOOTHING_GROUP = 0
-    DEFAULT_TRIANGLE_GROUP = 0
-    DEFAULT_MATERIAL_MODE = FLAG_TEXTURE_NONE
-    DEFAULT_GROUP_MATERIAL_INDEX = NONE_GROUP_MATERIAL_INDEX
-    DEFAULT_MODEL_JOINT_SIZE = 1.0
-    DEFAULT_MODEL_TRANSPARENCY_MODE = MODE_TRANSPARENCY_SIMPLE
-    DEFAULT_MODEL_ANIMATION_FPS = 25.0
-    DEFAULT_MODEL_SUB_VERSION_COMMENTS = 1
-    DEFAULT_MODEL_SUB_VERSION_VERTEX_EXTRA = 2
-    DEFAULT_MODEL_SUB_VERSION_JOINT_EXTRA = 1
-    DEFAULT_MODEL_SUB_VERSION_MODEL_EXTRA = 1
-    DEFAULT_FLAGS = FLAG_NONE
-    MAX_MATERIAL_SHININESS = 128
-
-    # blender default / OpenGL default
-    DEFAULT_MATERIAL_AMBIENT = (0.2, 0.2, 0.2, 1.0)
-    DEFAULT_MATERIAL_DIFFUSE = (0.8, 0.8, 0.8, 1.0)
-    DEFAULT_MATERIAL_SPECULAR = (1.0, 1.0, 1.0, 1.0)
-    DEFAULT_MATERIAL_EMISSIVE = (0.0, 0.0, 0.0, 1.0)
-    DEFAULT_MATERIAL_SHININESS = 12.5
-
-    DEFAULT_JOINT_COLOR = (0.8, 0.8, 0.8)
-
-###############################################################################
-#
-# helper class for basic raw io
-#
-class Ms3dIo:
-    # sizes for IO
-    SIZE_BYTE = 1
-    SIZE_SBYTE = 1
-    SIZE_WORD = 2
-    SIZE_DWORD = 4
-    SIZE_FLOAT = 4
-    LENGTH_ID = 10
-    LENGTH_NAME = 32
-    LENGTH_FILENAME = 128
-
-    PRECISION = 4
-
-    @staticmethod
-    def read_byte(raw_io):
-        """ read a single byte from raw_io """
-        buffer = raw_io.read(Ms3dIo.SIZE_BYTE)
-        if not buffer:
-            raise EOFError()
-        value = unpack('<B', buffer)[0]
-        return value
-
-    @staticmethod
-    def write_byte(raw_io, value):
-        """ write a single byte to raw_io """
-        raw_io.write(pack('<B', value))
-
-    @staticmethod
-    def read_sbyte(raw_io):
-        """ read a single signed byte from raw_io """
-        buffer = raw_io.read(Ms3dIo.SIZE_BYTE)
-        if not buffer:
-            raise EOFError()
-        value = unpack('<b', buffer)[0]
-        return value
-
-    @staticmethod
-    def write_sbyte(raw_io, value):
-        """ write a single signed byte to raw_io """
-        raw_io.write(pack('<b', value))
-
-    @staticmethod
-    def read_word(raw_io):
-        """ read a word from raw_io """
-        buffer = raw_io.read(Ms3dIo.SIZE_WORD)
-        if not buffer:
-            raise EOFError()
-        value = unpack('<H', buffer)[0]
-        return value
-
-    @staticmethod
-    def write_word(raw_io, value):
-        """ write a word to raw_io """
-        raw_io.write(pack('<H', value))
-
-    @staticmethod
-    def read_dword(raw_io):
-        """ read a double word from raw_io """
-        buffer = raw_io.read(Ms3dIo.SIZE_DWORD)
-        if not buffer:
-            raise EOFError()
-        value = unpack('<I', buffer)[0]
-        return value
-
-    @staticmethod
-    def write_dword(raw_io, value):
-        """ write a double word to raw_io """
-        raw_io.write(pack('<I', value))
-
-    @staticmethod
-    def read_float(raw_io):
-        """ read a float from raw_io """
-        buffer = raw_io.read(Ms3dIo.SIZE_FLOAT)
-        if not buffer:
-            raise EOFError()
-        value = unpack('<f', buffer)[0]
-        return value
-
-    @staticmethod
-    def write_float(raw_io, value):
-        """ write a float to raw_io """
-        raw_io.write(pack('<f', value))
-
-    @staticmethod
-    def read_array(raw_io, itemReader, count):
-        """ read an array[count] of objects from raw_io, by using a itemReader """
-        value = []
-        for i in range(count):
-            itemValue = itemReader(raw_io)
-            value.append(itemValue)
-        return tuple(value)
-
-    @staticmethod
-    def write_array(raw_io, itemWriter, count, value):
-        """ write an array[count] of objects to raw_io, by using a itemWriter """
-        for i in range(count):
-            itemValue = value[i]
-            itemWriter(raw_io, itemValue)
-
-    @staticmethod
-    def read_array2(raw_io, itemReader, count, count2):
-        """ read an array[count][count2] of objects from raw_io,
-            by using a itemReader """
-        value = []
-        for i in range(count):
-            itemValue = Ms3dIo.read_array(raw_io, itemReader, count2)
-            value.append(tuple(itemValue))
-        return value
-
-    @staticmethod
-    def write_array2(raw_io, itemWriter, count, count2, value):
-        """ write an array[count][count2] of objects to raw_io,
-            by using a itemWriter """
-        for i in range(count):
-            itemValue = value[i]
-            Ms3dIo.write_array(raw_io, itemWriter, count2, itemValue)
-
-
-    @staticmethod
-    def ms3d_replace(exc):
-        """ http://www.python.org/dev/peps/pep-0293/ """
-        if isinstance(exc, UnicodeEncodeError):
-            return ((exc.end-exc.start)*Ms3dSpec.STRING_REPLACE, exc.end)
-        elif isinstance(exc, UnicodeDecodeError):
-            return (Ms3dSpec.STRING_REPLACE, exc.end)
-        elif isinstance(exc, UnicodeTranslateError):
-            return ((exc.end-exc.start)*Ms3dSpec.STRING_REPLACE, exc.end)
-        else:
-            raise TypeError("can't handle %s" % exc.__name__)
-
-    @staticmethod
-    def read_string(raw_io, length):
-        """ read a string of a specific length from raw_io """
-        buffer = raw_io.read(length)
-        if not buffer:
-            raise EOFError()
-        eol = buffer.find(Ms3dSpec.STRING_TERMINATION)
-        if eol < 0:
-            eol = len(buffer)
-        register_error(Ms3dSpec.STRING_MS3D_REPLACE, Ms3dIo.ms3d_replace)
-        s = buffer[:eol].decode(encoding=Ms3dSpec.STRING_ENCODING, errors=Ms3dSpec.STRING_ERROR)
-        return s
-
-    @staticmethod
-    def write_string(raw_io, length, value):
-        """ write a string of a specific length to raw_io """
-        register_error(Ms3dSpec.STRING_MS3D_REPLACE, Ms3dIo.ms3d_replace)
-        buffer = value.encode(encoding=Ms3dSpec.STRING_ENCODING, errors=Ms3dSpec.STRING_ERROR)
-        if not buffer:
-            buffer = bytes()
-        raw_io.write(pack('<{}s'.format(length), buffer))
-        return
-
-
-###############################################################################
-#
-# multi complex types
-#
-
-###############################################################################
-class Ms3dHeader:
-    """ Ms3dHeader """
-    __slots__ = (
-            'id',
-            'version',
-            )
-
-    def __init__(
-            self,
-            default_id=Ms3dSpec.DEFAULT_HEADER,
-            default_version=Ms3dSpec.DEFAULT_HEADER_VERSION
-            ):
-        self.id = default_id
-        self.version = default_version
-
-    def __repr__(self):
-        return "\n<id='{}', version={}>".format(
-            self.id,
-            self.version
-            )
-
-    def __hash__(self):
-        return hash(self.id) ^ hash(self.version)
-
-    def __eq__(self, other):
-        return ((self is not None) and (other is not None)
-                and (self.id == other.id)
-                and (self.version == other.version))
-
-    def read(self, raw_io):
-        self.id = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_ID)
-        self.version = Ms3dIo.read_dword(raw_io)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_ID, self.id)
-        Ms3dIo.write_dword(raw_io, self.version)
-
-    class HeaderError(Exception):
-        pass
-
-
-
-###############################################################################
-class Ms3dVertex:
-    """ Ms3dVertex """
-    """
-    __slots__ was taking out,
-    to be able to inject additional attributes during runtime
-    __slots__ = (
-            'flags',
-            'bone_id',
-            'reference_count',
-            '_vertex',
-            '_vertex_ex_object', # Ms3dVertexEx
-            )
-    """
-
-    def __init__(
-            self,
-            default_flags=Ms3dSpec.DEFAULT_FLAGS,
-            default_vertex=(0.0, 0.0, 0.0),
-            default_bone_id=Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
-            default_reference_count=0,
-            default_vertex_ex_object=None, # Ms3dVertexEx
-            ):
-        self.flags = default_flags
-        self._vertex = default_vertex
-        self.bone_id = default_bone_id
-        self.reference_count = default_reference_count
-
-        if default_vertex_ex_object is None:
-            default_vertex_ex_object = Ms3dVertexEx2()
-            # Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_VERTEX_EXTRA = 2
-        self._vertex_ex_object = default_vertex_ex_object
-        # Ms3dVertexEx
-
-    def __repr__(self):
-        return "\n<flags={}, vertex=({:.{p}f}, {:.{p}f}, {:.{p}f}), bone_id={},"\
-                " reference_count={}>".format(
-                self.flags,
-                self._vertex[0],
-                self._vertex[1],
-                self._vertex[2],
-                self.bone_id,
-                self.reference_count,
-                p=Ms3dIo.PRECISION
-                )
-
-    def __hash__(self):
-        return (hash(self.vertex)
-                #^ hash(self.flags)
-                #^ hash(self.bone_id)
-                #^ hash(self.reference_count)
-                )
-
-    def __eq__(self, other):
-        return ((self.vertex == other.vertex)
-                #and (self.flags == other.flags)
-                #and (self.bone_id == other.bone_id)
-                #and (self.reference_count == other.reference_count)
-                )
-
-
-    @property
-    def vertex(self):
-        return self._vertex
-
-    @property
-    def vertex_ex_object(self):
-        return self._vertex_ex_object
-
-
-    def read(self, raw_io):
-        self.flags = Ms3dIo.read_byte(raw_io)
-        self._vertex = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        self.bone_id = Ms3dIo.read_sbyte(raw_io)
-        self.reference_count = Ms3dIo.read_byte(raw_io)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_byte(raw_io, self.flags)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.vertex)
-        Ms3dIo.write_sbyte(raw_io, self.bone_id)
-        Ms3dIo.write_byte(raw_io, self.reference_count)
-
-
-###############################################################################
-class Ms3dTriangle:
-    """ Ms3dTriangle """
-    """
-    __slots__ was taking out,
-    to be able to inject additional attributes during runtime
-    __slots__ = (
-            'flags',
-            'smoothing_group',
-            'group_index',
-            '_vertex_indices',
-            '_vertex_normals',
-            '_s',
-            '_t',
-            )
-    """
-
-    def __init__(
-            self,
-            default_flags=Ms3dSpec.DEFAULT_FLAGS,
-            default_vertex_indices=(0, 0, 0),
-            default_vertex_normals=(
-                    (0.0, 0.0, 0.0),
-                    (0.0, 0.0, 0.0),
-                    (0.0, 0.0, 0.0)),
-            default_s=(0.0, 0.0, 0.0),
-            default_t=(0.0, 0.0, 0.0),
-            default_smoothing_group=Ms3dSpec.DEFAULT_TRIANGLE_SMOOTHING_GROUP,
-            default_group_index=Ms3dSpec.DEFAULT_TRIANGLE_GROUP
-            ):
-        self.flags = default_flags
-        self._vertex_indices = default_vertex_indices
-        self._vertex_normals = default_vertex_normals
-        self._s = default_s
-        self._t = default_t
-        self.smoothing_group = default_smoothing_group
-        self.group_index = default_group_index
-
-    def __repr__(self):
-        return "\n<flags={}, vertex_indices={}, vertex_normals=(({:.{p}f}, "\
-                "{:.{p}f}, {:.{p}f}), ({:.{p}f}, {:.{p}f}, {:.{p}f}), ({:.{p}f}, "\
-                "{:.{p}f}, {:.{p}f})), s=({:.{p}f}, {:.{p}f}, {:.{p}f}), "\
-                "t=({:.{p}f}, {:.{p}f}, {:.{p}f}), smoothing_group={}, "\
-                "group_index={}>".format(
-                self.flags,
-                self.vertex_indices,
-                self.vertex_normals[0][0],
-                self.vertex_normals[0][1],
-                self.vertex_normals[0][2],
-                self.vertex_normals[1][0],
-                self.vertex_normals[1][1],
-                self.vertex_normals[1][2],
-                self.vertex_normals[2][0],
-                self.vertex_normals[2][1],
-                self.vertex_normals[2][2],
-                self.s[0],
-                self.s[1],
-                self.s[2],
-                self.t[0],
-                self.t[1],
-                self.t[2],
-                self.smoothing_group,
-                self.group_index,
-                p=Ms3dIo.PRECISION
-                )
-
-
-    @property
-    def vertex_indices(self):
-        return self._vertex_indices
-
-    @property
-    def vertex_normals(self):
-        return self._vertex_normals
-
-    @property
-    def s(self):
-        return self._s
-
-    @property
-    def t(self):
-        return self._t
-
-
-    def read(self, raw_io):
-        self.flags = Ms3dIo.read_word(raw_io)
-        self._vertex_indices = Ms3dIo.read_array(raw_io, Ms3dIo.read_word, 3)
-        self._vertex_normals = Ms3dIo.read_array2(raw_io, Ms3dIo.read_float, 3, 3)
-        self._s = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        self._t = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        self.smoothing_group = Ms3dIo.read_byte(raw_io)
-        self.group_index = Ms3dIo.read_byte(raw_io)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_word(raw_io, self.flags)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_word, 3, self.vertex_indices)
-        Ms3dIo.write_array2(raw_io, Ms3dIo.write_float, 3, 3, self.vertex_normals)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.s)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.t)
-        Ms3dIo.write_byte(raw_io, self.smoothing_group)
-        Ms3dIo.write_byte(raw_io, self.group_index)
-
-
-###############################################################################
-class Ms3dGroup:
-    """ Ms3dGroup """
-    """
-    __slots__ was taking out,
-    to be able to inject additional attributes during runtime
-    __slots__ = (
-            'flags',
-            'name',
-            'material_index',
-            '_triangle_indices',
-            '_comment_object', # Ms3dComment
-            )
-    """
-
-    def __init__(
-            self,
-            default_flags=Ms3dSpec.DEFAULT_FLAGS,
-            default_name="",
-            default_triangle_indices=None,
-            default_material_index=Ms3dSpec.DEFAULT_GROUP_MATERIAL_INDEX,
-            default_comment_object=None, # Ms3dComment
-            ):
-        if (default_name is None):
-            default_name = ""
-
-        if (default_triangle_indices is None):
-            default_triangle_indices = []
-
-        self.flags = default_flags
-        self.name = default_name
-        self._triangle_indices = default_triangle_indices
-        self.material_index = default_material_index
-
-        if default_comment_object is None:
-            default_comment_object = Ms3dCommentEx()
-        self._comment_object = default_comment_object # Ms3dComment
-
-    def __repr__(self):
-        return "\n<flags={}, name='{}', number_triangles={},"\
-                " triangle_indices={}, material_index={}>".format(
-                self.flags,
-                self.name,
-                self.number_triangles,
-                self.triangle_indices,
-                self.material_index
-                )
-
-
-    @property
-    def number_triangles(self):
-        if self.triangle_indices is None:
-            return 0
-        return len(self.triangle_indices)
-
-    @property
-    def triangle_indices(self):
-        return self._triangle_indices
-
-    @property
-    def comment_object(self):
-        return self._comment_object
-
-
-    def read(self, raw_io):
-        self.flags = Ms3dIo.read_byte(raw_io)
-        self.name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
-        _number_triangles = Ms3dIo.read_word(raw_io)
-        self._triangle_indices = Ms3dIo.read_array(
-                raw_io, Ms3dIo.read_word, _number_triangles)
-        self.material_index = Ms3dIo.read_sbyte(raw_io)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_byte(raw_io, self.flags)
-        Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.name)
-        Ms3dIo.write_word(raw_io, self.number_triangles)
-        Ms3dIo.write_array(
-                raw_io, Ms3dIo.write_word, self.number_triangles,
-                self.triangle_indices)
-        Ms3dIo.write_sbyte(raw_io, self.material_index)
-
-
-###############################################################################
-class Ms3dMaterial:
-    """ Ms3dMaterial """
-    """
-    __slots__ was taking out,
-    to be able to inject additional attributes during runtime
-    __slots__ = (
-            'name',
-            'shininess',
-            'transparency',
-            'mode',
-            'texture',
-            'alphamap',
-            '_ambient',
-            '_diffuse',
-            '_specular',
-            '_emissive',
-            '_comment_object', # Ms3dComment
-            )
-    """
-
-    def __init__(
-            self,
-            default_name="",
-            default_ambient=list(Ms3dSpec.DEFAULT_MATERIAL_AMBIENT),
-            default_diffuse=list(Ms3dSpec.DEFAULT_MATERIAL_DIFFUSE),
-            default_specular=list(Ms3dSpec.DEFAULT_MATERIAL_SPECULAR),
-            default_emissive=list(Ms3dSpec.DEFAULT_MATERIAL_EMISSIVE),
-            default_shininess=Ms3dSpec.DEFAULT_MATERIAL_SHININESS,
-            default_transparency=0.0,
-            default_mode=Ms3dSpec.DEFAULT_MATERIAL_MODE,
-            default_texture="",
-            default_alphamap="",
-            default_comment_object=None, # Ms3dComment
-            ):
-        if (default_name is None):
-            default_name = ""
-
-        if (default_texture is None):
-            default_texture = ""
-
-        if (default_alphamap is None):
-            default_alphamap = ""
-
-        self.name = default_name
-        self._ambient = default_ambient
-        self._diffuse = default_diffuse
-        self._specular = default_specular
-        self._emissive = default_emissive
-        self.shininess = default_shininess
-        self.transparency = default_transparency
-        self.mode = default_mode
-        self.texture = default_texture
-        self.alphamap = default_alphamap
-
-        if default_comment_object is None:
-            default_comment_object = Ms3dCommentEx()
-        self._comment_object = default_comment_object # Ms3dComment
-
-    def __repr__(self):
-        return "\n<name='{}', ambient=({:.{p}f}, {:.{p}f}, {:.{p}f}, {:.{p}f}), "\
-                "diffuse=({:.{p}f}, {:.{p}f}, {:.{p}f}, {:.{p}f}), specular=("\
-                "{:.{p}f}, {:.{p}f}, {:.{p}f}, {:.{p}f}), emissive=({:.{p}f}, "\
-                "{:.{p}f}, {:.{p}f}, {:.{p}f}), shininess={:.{p}f}, transparency="\
-                "{:.{p}f}, mode={}, texture='{}', alphamap='{}'>".format(
-                self.name,
-                self.ambient[0],
-                self.ambient[1],
-                self.ambient[2],
-                self.ambient[3],
-                self.diffuse[0],
-                self.diffuse[1],
-                self.diffuse[2],
-                self.diffuse[3],
-                self.specular[0],
-                self.specular[1],
-                self.specular[2],
-                self.specular[3],
-                self.emissive[0],
-                self.emissive[1],
-                self.emissive[2],
-                self.emissive[3],
-                self.shininess,
-                self.transparency,
-                self.mode,
-                self.texture,
-                self.alphamap,
-                p=Ms3dIo.PRECISION
-                )
-
-    def __hash__(self):
-        return (hash(self.name)
-
-                ^ hash(self.ambient)
-                ^ hash(self.diffuse)
-                ^ hash(self.specular)
-                ^ hash(self.emissive)
-
-                ^ hash(self.shininess)
-                ^ hash(self.transparency)
-                ^ hash(self.mode)
-
-                ^ hash(self.texture)
-                ^ hash(self.alphamap)
-                )
-
-    def __eq__(self, other):
-        return ((self.name == other.name)
-
-                and (self.ambient == other.ambient)
-                and (self.diffuse == other.diffuse)
-                and (self.specular == other.specular)
-                and (self.emissive == other.emissive)
-
-                and (self.shininess == other.shininess)
-                and (self.transparency == other.transparency)
-                and (self.mode == other.mode)
-
-                #and (self.texture == other.texture)
-                #and (self.alphamap == other.alphamap)
-                )
-
-
-    @property
-    def ambient(self):
-        return self._ambient
-
-    @property
-    def diffuse(self):
-        return self._diffuse
-
-    @property
-    def specular(self):
-        return self._specular
-
-    @property
-    def emissive(self):
-        return self._emissive
-
-    @property
-    def comment_object(self):
-        return self._comment_object
-
-
-    def read(self, raw_io):
-        self.name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
-        self._ambient = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
-        self._diffuse = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
-        self._specular = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
-        self._emissive = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 4)
-        self.shininess = Ms3dIo.read_float(raw_io)
-        self.transparency = Ms3dIo.read_float(raw_io)
-        self.mode = Ms3dIo.read_byte(raw_io)
-        self.texture = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_FILENAME)
-        self.alphamap = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_FILENAME)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.name)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.ambient)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.diffuse)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.specular)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 4, self.emissive)
-        Ms3dIo.write_float(raw_io, self.shininess)
-        Ms3dIo.write_float(raw_io, self.transparency)
-        Ms3dIo.write_byte(raw_io, self.mode)
-        Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_FILENAME, self.texture)
-        Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_FILENAME, self.alphamap)
-
-
-###############################################################################
-class Ms3dRotationKeyframe:
-    """ Ms3dRotationKeyframe """
-    __slots__ = (
-            'time',
-            '_rotation',
-            )
-
-    def __init__(
-            self,
-            default_time=0.0,
-            default_rotation=(0.0, 0.0, 0.0)
-            ):
-        self.time = default_time
-        self._rotation = default_rotation
-
-    def __repr__(self):
-        return "\n<time={:.{p}f}, rotation=({:.{p}f}, {:.{p}f}, {:.{p}f})>".format(
-                self.time,
-                self.rotation[0],
-                self.rotation[1],
-                self.rotation[2],
-                p=Ms3dIo.PRECISION
-                )
-
-
-    @property
-    def rotation(self):
-        return self._rotation
-
-
-    def read(self, raw_io):
-        self.time = Ms3dIo.read_float(raw_io)
-        self._rotation = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_float(raw_io, self.time)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.rotation)
-
-
-###############################################################################
-class Ms3dTranslationKeyframe:
-    """ Ms3dTranslationKeyframe """
-    __slots__ = (
-            'time',
-            '_position',
-            )
-
-    def __init__(
-            self,
-            default_time=0.0,
-            default_position=(0.0, 0.0, 0.0)
-            ):
-        self.time = default_time
-        self._position = default_position
-
-    def __repr__(self):
-        return "\n<time={:.{p}f}, position=({:.{p}f}, {:.{p}f}, {:.{p}f})>".format(
-                self.time,
-                self.position[0],
-                self.position[1],
-                self.position[2],
-                p=Ms3dIo.PRECISION
-                )
-
-
-    @property
-    def position(self):
-        return self._position
-
-
-    def read(self, raw_io):
-        self.time = Ms3dIo.read_float(raw_io)
-        self._position = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_float(raw_io, self.time)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.position)
-
-
-###############################################################################
-class Ms3dJoint:
-    """ Ms3dJoint """
-    """
-    __slots__ was taking out,
-    to be able to inject additional attributes during runtime
-    __slots__ = (
-            'flags',
-            'name',
-            'parent_name',
-            '_rotation',
-            '_position',
-            '_rotation_keyframes',
-            '_translation_keyframes',
-            '_joint_ex_object', # Ms3dJointEx
-            '_comment_object', # Ms3dComment
-            )
-    """
-
-    def __init__(
-            self,
-            default_flags=Ms3dSpec.DEFAULT_FLAGS,
-            default_name="",
-            default_parent_name="",
-            default_rotation=(0.0, 0.0, 0.0),
-            default_position=(0.0, 0.0, 0.0),
-            default_rotation_keyframes=None,
-            default_translation_keyframes=None,
-            default_joint_ex_object=None, # Ms3dJointEx
-            default_comment_object=None, # Ms3dComment
-            ):
-        if (default_name is None):
-            default_name = ""
-
-        if (default_parent_name is None):
-            default_parent_name = ""
-
-        if (default_rotation_keyframes is None):
-            default_rotation_keyframes = [] #Ms3dRotationKeyframe()
-
-        if (default_translation_keyframes is None):
-            default_translation_keyframes = [] #Ms3dTranslationKeyframe()
-
-        self.flags = default_flags
-        self.name = default_name
-        self.parent_name = default_parent_name
-        self._rotation = default_rotation
-        self._position = default_position
-        self._rotation_keyframes = default_rotation_keyframes
-        self._translation_keyframes = default_translation_keyframes
-
-        if default_comment_object is None:
-            default_comment_object = Ms3dCommentEx()
-        self._comment_object = default_comment_object # Ms3dComment
-
-        if default_joint_ex_object is None:
-            default_joint_ex_object = Ms3dJointEx()
-        self._joint_ex_object = default_joint_ex_object # Ms3dJointEx
-
-    def __repr__(self):
-        return "\n<flags={}, name='{}', parent_name='{}', rotation=({:.{p}f}, "\
-                "{:.{p}f}, {:.{p}f}), position=({:.{p}f}, {:.{p}f}, {:.{p}f}), "\
-                "number_rotation_keyframes={}, number_translation_keyframes={},"\
-                " rotation_key_frames={}, translation_key_frames={}>".format(
-                self.flags,
-                self.name,
-                self.parent_name,
-                self.rotation[0],
-                self.rotation[1],
-                self.rotation[2],
-                self.position[0],
-                self.position[1],
-                self.position[2],
-                self.number_rotation_keyframes,
-                self.number_translation_keyframes,
-                self.rotation_key_frames,
-                self.translation_key_frames,
-                p=Ms3dIo.PRECISION
-                )
-
-
-    @property
-    def rotation(self):
-        return self._rotation
-
-    @property
-    def position(self):
-        return self._position
-
-    @property
-    def number_rotation_keyframes(self):
-        if self.rotation_key_frames is None:
-            return 0
-        return len(self.rotation_key_frames)
-
-    @property
-    def number_translation_keyframes(self):
-        if self.translation_key_frames is None:
-            return 0
-        return len(self.translation_key_frames)
-
-    @property
-    def rotation_key_frames(self):
-        return self._rotation_keyframes
-
-    @property
-    def translation_key_frames(self):
-        return self._translation_keyframes
-
-
-    @property
-    def joint_ex_object(self):
-        return self._joint_ex_object
-
-
-    @property
-    def comment_object(self):
-        return self._comment_object
-
-
-    def read(self, raw_io):
-        self.flags = Ms3dIo.read_byte(raw_io)
-        self.name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
-        self.parent_name = Ms3dIo.read_string(raw_io, Ms3dIo.LENGTH_NAME)
-        self._rotation = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        self._position = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        _number_rotation_keyframes = Ms3dIo.read_word(raw_io)
-        _number_translation_keyframes = Ms3dIo.read_word(raw_io)
-        self._rotation_keyframes = []
-        for i in range(_number_rotation_keyframes):
-            self.rotation_key_frames.append(Ms3dRotationKeyframe().read(raw_io))
-        self._translation_keyframes = []
-        for i in range(_number_translation_keyframes):
-            self.translation_key_frames.append(
-                    Ms3dTranslationKeyframe().read(raw_io))
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_byte(raw_io, self.flags)
-        Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.name)
-        Ms3dIo.write_string(raw_io, Ms3dIo.LENGTH_NAME, self.parent_name)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.rotation)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.position)
-        Ms3dIo.write_word(raw_io, self.number_rotation_keyframes)
-        Ms3dIo.write_word(raw_io, self.number_translation_keyframes)
-        for i in range(self.number_rotation_keyframes):
-            self.rotation_key_frames[i].write(raw_io)
-        for i in range(self.number_translation_keyframes):
-            self.translation_key_frames[i].write(raw_io)
-
-
-###############################################################################
-class Ms3dCommentEx:
-    """ Ms3dCommentEx """
-    __slots__ = (
-            'index',
-            'comment',
-            )
-
-    def __init__(
-            self,
-            default_index=0,
-            default_comment=""
-            ):
-        if (default_comment is None):
-            default_comment = ""
-
-        self.index = default_index
-        self.comment = default_comment
-
-    def __repr__(self):
-        return "\n<index={}, comment_length={}, comment='{}'>".format(
-                self.index,
-                self.comment_length,
-                self.comment
-                )
-
-
-    @property
-    def comment_length(self):
-        if self.comment is None:
-            return 0
-        return len(self.comment)
-
-
-    def read(self, raw_io):
-        self.index = Ms3dIo.read_dword(raw_io)
-        _comment_length = Ms3dIo.read_dword(raw_io)
-        self.comment = Ms3dIo.read_string(raw_io, _comment_length)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_dword(raw_io, self.index)
-        Ms3dIo.write_dword(raw_io, self.comment_length)
-        Ms3dIo.write_string(raw_io, self.comment_length, self.comment)
-
-
-###############################################################################
-class Ms3dComment:
-    """ Ms3dComment """
-    __slots__ = (
-            'comment',
-            )
-
-    def __init__(
-            self,
-            default_comment=""
-            ):
-        if (default_comment is None):
-            default_comment = ""
-
-        self.comment = default_comment
-
-    def __repr__(self):
-        return "\n<comment_length={}, comment='{}'>".format(
-                self.comment_length,
-                self.comment
-                )
-
-
-    @property
-    def comment_length(self):
-        if self.comment is None:
-            return 0
-        return len(self.comment)
-
-
-    def read(self, raw_io):
-        _comment_length = Ms3dIo.read_dword(raw_io)
-        self.comment = Ms3dIo.read_string(raw_io, _comment_length)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_dword(raw_io, self.comment_length)
-        Ms3dIo.write_string(raw_io, self.comment_length, self.comment)
-
-
-###############################################################################
-class Ms3dVertexEx1:
-    """ Ms3dVertexEx1 """
-    __slots__ = (
-            '_bone_ids',
-            '_weights',
-            )
-
-    def __init__(
-            self,
-            default_bone_ids=(
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID),
-            default_weights=(100, 0, 0)
-            ):
-        self._bone_ids = default_bone_ids
-        self._weights = default_weights
-
-    def __repr__(self):
-        return "\n<bone_ids={}, weights={}>".format(
-                self.bone_ids,
-                self.weights
-                )
-
-
-    @property
-    def bone_ids(self):
-        return self._bone_ids
-
-    @property
-    def weights(self):
-        return self._weights
-
-
-    @property
-    def weight_bone_id(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights
-        return 100
-
-    @property
-    def weight_bone_id0(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights[0]
-        return 0
-
-    @property
-    def weight_bone_id1(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights[1]
-        return 0
-
-    @property
-    def weight_bone_id2(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return 100 - (self._weights[0] + self._weights[1] \
-                    + self._weights[2])
-        return 0
-
-
-    def read(self, raw_io):
-        self._bone_ids = Ms3dIo.read_array(raw_io, Ms3dIo.read_sbyte, 3)
-        self._weights = Ms3dIo.read_array(raw_io, Ms3dIo.read_byte, 3)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_sbyte, 3, self.bone_ids)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_byte, 3, self.weights)
-
-
-###############################################################################
-class Ms3dVertexEx2:
-    """ Ms3dVertexEx2 """
-    __slots__ = (
-            'extra',
-            '_bone_ids',
-            '_weights',
-            )
-
-    def __init__(
-            self,
-            default_bone_ids=(
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID),
-            default_weights=(100, 0, 0),
-            default_extra=0
-            ):
-        self._bone_ids = default_bone_ids
-        self._weights = default_weights
-        self.extra = default_extra
-
-    def __repr__(self):
-        return "\n<bone_ids={}, weights={}, extra={}>".format(
-                self.bone_ids,
-                self.weights,
-                self.extra
-                )
-
-
-    @property
-    def bone_ids(self):
-        return self._bone_ids
-
-    @property
-    def weights(self):
-        return self._weights
-
-
-    @property
-    def weight_bone_id(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights
-        return 100
-
-    @property
-    def weight_bone_id0(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights[0]
-        return 0
-
-    @property
-    def weight_bone_id1(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights[1]
-        return 0
-
-    @property
-    def weight_bone_id2(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return 100 - (self._weights[0] + self._weights[1] \
-                    + self._weights[2])
-        return 0
-
-
-    def read(self, raw_io):
-        self._bone_ids = Ms3dIo.read_array(raw_io, Ms3dIo.read_sbyte, 3)
-        self._weights = Ms3dIo.read_array(raw_io, Ms3dIo.read_byte, 3)
-        self.extra = Ms3dIo.read_dword(raw_io)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_sbyte, 3, self.bone_ids)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_byte, 3, self.weights)
-        Ms3dIo.write_dword(raw_io, self.extra)
-
-
-###############################################################################
-class Ms3dVertexEx3:
-    """ Ms3dVertexEx3 """
-    #char bone_ids[3]; // index of joint or -1, if -1, then that weight is
-    #    ignored, since subVersion 1
-    #byte weights[3]; // vertex weight ranging from 0 - 100, last weight is
-    #    computed by 1.0 - sum(all weights), since subVersion 1
-    #// weight[0] is the weight for bone_id in Ms3dVertex
-    #// weight[1] is the weight for bone_ids[0]
-    #// weight[2] is the weight for bone_ids[1]
-    #// 1.0f - weight[0] - weight[1] - weight[2] is the weight for bone_ids[2]
-    #unsigned int extra; // vertex extra, which can be used as color or
-    #    anything else, since subVersion 2
-    __slots__ = (
-            'extra',
-            '_bone_ids',
-            '_weights',
-            )
-
-    def __init__(
-            self,
-            default_bone_ids=(
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID,
-                    Ms3dSpec.DEFAULT_VERTEX_BONE_ID),
-            default_weights=(100, 0, 0),
-            default_extra=0
-            ):
-        self._bone_ids = default_bone_ids
-        self._weights = default_weights
-        self.extra = default_extra
-
-    def __repr__(self):
-        return "\n<bone_ids={}, weights={}, extra={}>".format(
-                self.bone_ids,
-                self.weights,
-                self.extra
-                )
-
-
-    @property
-    def bone_ids(self):
-        return self._bone_ids
-
-    @property
-    def weights(self):
-        return self._weights
-
-
-    @property
-    def weight_bone_id(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights
-        return 100
-
-    @property
-    def weight_bone_id0(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights[0]
-        return 0
-
-    @property
-    def weight_bone_id1(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return self._weights[1]
-        return 0
-
-    @property
-    def weight_bone_id2(self):
-        if self._weights[0] or self._weights[1] or self._weights[2]:
-            return 100 - (self._weights[0] + self._weights[1] \
-                    + self._weights[2])
-        return 0
-
-
-    def read(self, raw_io):
-        self._bone_ids = Ms3dIo.read_array(raw_io, Ms3dIo.read_sbyte, 3)
-        self._weights = Ms3dIo.read_array(raw_io, Ms3dIo.read_byte, 3)
-        self.extra = Ms3dIo.read_dword(raw_io)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_sbyte, 3, self.bone_ids)
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_byte, 3, self.weights)
-        Ms3dIo.write_dword(raw_io, self.extra)
-
-
-###############################################################################
-class Ms3dJointEx:
-    """ Ms3dJointEx """
-    __slots__ = (
-            '_color',
-            )
-
-    def __init__(
-            self,
-            default_color=Ms3dSpec.DEFAULT_JOINT_COLOR
-            ):
-        self._color = default_color
-
-    def __repr__(self):
-        return "\n<color=({:.{p}f}, {:.{p}f}, {:.{p}f})>".format(
-                self.color[0],
-                self.color[1],
-                self.color[2],
-                p=Ms3dIo.PRECISION
-                )
-
-
-    @property
-    def color(self):
-        return self._color
-
-
-    def read(self, raw_io):
-        self._color = Ms3dIo.read_array(raw_io, Ms3dIo.read_float, 3)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_array(raw_io, Ms3dIo.write_float, 3, self.color)
-
-
-###############################################################################
-class Ms3dModelEx:
-    """ Ms3dModelEx """
-    __slots__ = (
-            'joint_size',
-            'transparency_mode',
-            'alpha_ref',
-            )
-
-    def __init__(
-            self,
-            default_joint_size=Ms3dSpec.DEFAULT_MODEL_JOINT_SIZE,
-            default_transparency_mode\
-                    =Ms3dSpec.DEFAULT_MODEL_TRANSPARENCY_MODE,
-            default_alpha_ref=0.0
-            ):
-        self.joint_size = default_joint_size
-        self.transparency_mode = default_transparency_mode
-        self.alpha_ref = default_alpha_ref
-
-    def __repr__(self):
-        return "\n<joint_size={:.{p}f}, transparency_mode={}, alpha_ref={:.{p}f}>".format(
-                self.joint_size,
-                self.transparency_mode,
-                self.alpha_ref,
-                p=Ms3dIo.PRECISION
-                )
-
-    def read(self, raw_io):
-        self.joint_size = Ms3dIo.read_float(raw_io)
-        self.transparency_mode = Ms3dIo.read_dword(raw_io)
-        self.alpha_ref = Ms3dIo.read_float(raw_io)
-        return self
-
-    def write(self, raw_io):
-        Ms3dIo.write_float(raw_io, self.joint_size)
-        Ms3dIo.write_dword(raw_io, self.transparency_mode)
-        Ms3dIo.write_float(raw_io, self.alpha_ref)
-
-
-###############################################################################
-#
-# file format
-#
-###############################################################################
-class Ms3dModel:
-    """ Ms3dModel """
-    __slot__ = (
-            'header',
-            'animation_fps',
-            'current_time',
-            'number_total_frames',
-            'sub_version_comments',
-            'sub_version_vertex_extra',
-            'sub_version_joint_extra',
-            'sub_version_model_extra',
-            'name',
-            '_vertices',
-            '_triangles',
-            '_groups',
-            '_materials',
-            '_joints',
-            '_has_model_comment',
-            '_comment_object', # Ms3dComment
-            '_model_ex_object', # Ms3dModelEx
-            )
-
-    def __init__(
-            self,
-            default_name=""
-            ):
-        if (default_name is None):
-            default_name = ""
-
-        self.name = default_name
-
-        self.animation_fps = Ms3dSpec.DEFAULT_MODEL_ANIMATION_FPS
-        self.current_time = 0.0
-        self.number_total_frames = 0
-        self.sub_version_comments \
-                = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_COMMENTS
-        self.sub_version_vertex_extra \
-                = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_VERTEX_EXTRA
-        self.sub_version_joint_extra \
-                = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_JOINT_EXTRA
-        self.sub_version_model_extra \
-                = Ms3dSpec.DEFAULT_MODEL_SUB_VERSION_MODEL_EXTRA
-
-        self._vertices = [] #Ms3dVertex()
-        self._triangles = [] #Ms3dTriangle()
-        self._groups = [] #Ms3dGroup()
-        self._materials = [] #Ms3dMaterial()
-        self._joints = [] #Ms3dJoint()
-
-        self.header = Ms3dHeader()
-        self._model_ex_object = Ms3dModelEx()
-        self._comment_object = None #Ms3dComment()
-
-
-    @property
-    def number_vertices(self):
-        if self.vertices is None:
-            return 0
-        return len(self.vertices)
-
-    @property
-    def vertices(self):
-        return self._vertices
-
-
-    @property
-    def number_triangles(self):
-        if self.triangles is None:
-            return 0
-        return len(self.triangles)
-
-    @property
-    def triangles(self):
-        return self._triangles
-
-
-    @property
-    def number_groups(self):
-        if self.groups is None:
-            return 0
-        return len(self.groups)
-
-    @property
-    def groups(self):
-        return self._groups
-
-
-    @property
-    def number_materials(self):
-        if self.materials is None:
-            return 0
-        return len(self.materials)
-
-    @property
-    def materials(self):
-        return self._materials
-
-
-    @property
-    def number_joints(self):
-        if self.joints is None:
-            return 0
-        return len(self.joints)
-
-    @property
-    def joints(self):
-        return self._joints
-
-
-    @property
-    def number_group_comments(self):
-        if self.groups is None:
-            return 0
-        number = 0
-        for item in self.groups:
-            if item.comment_object is not None and item.comment_object.comment:
-                number += 1
-        return number
-
-    @property
-    def group_comments(self):
-        if self.groups is None:
-            return None
-        items = []
-        for item in self.groups:
-            if item.comment_object is not None and item.comment_object.comment:
-                items.append(item)
-        return items
-
-
-    @property
-    def number_material_comments(self):
-        if self.materials is None:
-            return 0
-        number = 0
-        for item in self.materials:
-            if item.comment_object is not None and item.comment_object.comment:
-                number += 1
-        return number
-
-    @property
-    def material_comments(self):
-        if self.materials is None:
-            return None
-        items = []
-        for item in self.materials:
-            if item.comment_object is not None and item.comment_object.comment:
-                items.append(item)
-        return items
-
-
-    @property
-    def number_joint_comments(self):
-        if self.joints is None:
-            return 0
-        number = 0
-        for item in self.joints:
-            if item.comment_object is not None and item.comment_object.comment:
-                number += 1
-        return number
-
-    @property
-    def joint_comments(self):
-        if self.joints is None:
-            return None
-        items = []
-        for item in self.joints:
-            if item.comment_object is not None and item.comment_object.comment:
-                items.append(item)
-        return items
-
-
-    @property
-    def has_model_comment(self):
-        if self.comment_object is not None and self.comment_object.comment:
-            return 1
-        return 0
-
-    @property
-    def comment_object(self):
-        return self._comment_object
-
-
-    @property
-    def vertex_ex(self):
-        if not self.sub_version_vertex_extra:
-            return None
-        return [item.vertex_ex_object for item in self.vertices]
-
-    @property
-    def joint_ex(self):
-        if not self.sub_version_joint_extra:
-            return None
-        return [item.joint_ex_object for item in self.joints]
-
-    @property
-    def model_ex_object(self):
-        if not self.sub_version_model_extra:
-            return None
-        return self._model_ex_object
-
-
-    def print_internal(self):
-        print()
-        print("##############################################################")
-        print("## the internal data of Ms3dModel object...")
-        print("##")
-
-        print("header={}".format(self.header))
-
-        print("number_vertices={}".format(self.number_vertices))
-        print("vertices=[", end="")
-        if self.vertices:
-            for obj in self.vertices:
-                print("{}".format(obj), end="")
-        print("]")
-
-        print("number_triangles={}".format(self.number_triangles))
-        print("triangles=[", end="")
-        if self.triangles:
-            for obj in self.triangles:
-                print("{}".format(obj), end="")
-        print("]")
-
-        print("number_groups={}".format(self.number_groups))
-        print("groups=[", end="")
-        if self.groups:
-            for obj in self.groups:
-                print("{}".format(obj), end="")
-        print("]")
-
-        print("number_materials={}".format(self.number_materials))
-        print("materials=[", end="")
-        if self.materials:
-            for obj in self.materials:
-                print("{}".format(obj), end="")
-        print("]")
-
-        print("animation_fps={}".format(self.animation_fps))
-        print("current_time={}".format(self.current_time))
-        print("number_total_frames={}".format(self.number_total_frames))
-
-        print("number_joints={}".format(self.number_joints))
-        print("joints=[", end="")
-        if self.joints:
-            for obj in self.joints:
-                print("{}".format(obj), end="")
-        print("]")
-
-        print("sub_version_comments={}".format(self.sub_version_comments))
-
-        print("number_group_comments={}".format(self.number_group_comments))
-        print("group_comments=[", end="")
-        if self.group_comments:
-            for obj in self.group_comments:
-                print("{}".format(obj.comment_object), end="")
-        print("]")
-
-        print("number_material_comments={}".format(
-                self.number_material_comments))
-        print("material_comments=[", end="")
-        if self.material_comments:
-            for obj in self.material_comments:
-                print("{}".format(obj.comment_object), end="")
-        print("]")
-
-        print("number_joint_comments={}".format(self.number_joint_comments))
-        print("joint_comments=[", end="")
-        if self.joint_comments:
-            for obj in self.joint_comments:
-                print("{}".format(obj.comment_object), end="")
-        print("]")
-
-        print("has_model_comment={}".format(self.has_model_comment))
-        print("model_comment={}".format(self.comment_object))
-
-        print("sub_version_vertex_extra={}".format(
-                self.sub_version_vertex_extra))
-        print("vertex_ex=[", end="")
-        if self.vertex_ex:
-            for obj in self.vertex_ex:
-                print("{}".format(obj), end="")
-        print("]")
-
-        print("sub_version_joint_extra={}".format(
-                self.sub_version_joint_extra))
-        print("joint_ex=[", end="")
-        if self.joint_ex:
-            for obj in self.joint_ex:
-                print("{}".format(obj), end="")
-        print("]")
-
-        print("sub_version_model_extra={}".format(
-                self.sub_version_model_extra))
-        print("model_ex={}".format(self.model_ex_object))
-
-        print("##")
-        print("## ...end")
-        print("##############################################################")
-        print()
-
-
-    def read(self, raw_io):
-        """
-        opens, reads and pars MS3D file.
-        add content to blender scene
-        """
-
-        debug_out = []
-
-        self.header.read(raw_io)
-        if (self.header != Ms3dHeader()):
-            debug_out.append("\nwarning, invalid file header\n")
-            raise Ms3dHeader.HeaderError
-
-        _number_vertices = Ms3dIo.read_word(raw_io)
-        if (_number_vertices > Ms3dSpec.MAX_VERTICES):
-            debug_out.append("\nwarning, invalid count: number_vertices: {}\n".format(
-                    _number_vertices))
-        self._vertices = []
-        for i in range(_number_vertices):
-            self.vertices.append(Ms3dVertex().read(raw_io))
-
-        _number_triangles = Ms3dIo.read_word(raw_io)
-        if (_number_triangles > Ms3dSpec.MAX_TRIANGLES):
-            debug_out.append("\nwarning, invalid count: number_triangles: {}\n".format(
-                    _number_triangles))
-        self._triangles = []
-        for i in range(_number_triangles):
-            self.triangles.append(Ms3dTriangle().read(raw_io))
-
-  &nbs