finished moving importers and exporters into python packages (as proposed on the...
authorCampbell Barton <ideasman42@gmail.com>
Wed, 1 Sep 2010 12:11:34 +0000 (12:11 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 1 Sep 2010 12:11:34 +0000 (12:11 +0000)
- made operator dir's into python packages
- lazy loading of module which do the actual import and export (faster blender load times)
- general maintanance and small fixes.
- bugfix for exporting x3d materials
- leak fix for exporting 3ds

19 files changed:
release/scripts/io/netrender/__init__.py
release/scripts/modules/io_utils.py
release/scripts/op/io_anim_bvh/__init__.py [new file with mode: 0644]
release/scripts/op/io_anim_bvh/import_bvh.py
release/scripts/op/io_mesh_ply/__init__.py [new file with mode: 0644]
release/scripts/op/io_mesh_ply/export_ply.py
release/scripts/op/io_scene_3ds/__init__.py [new file with mode: 0644]
release/scripts/op/io_scene_3ds/export_3ds.py
release/scripts/op/io_scene_3ds/import_3ds.py
release/scripts/op/io_scene_fbx/__init__.py [new file with mode: 0644]
release/scripts/op/io_scene_fbx/export_fbx.py
release/scripts/op/io_scene_obj/__init__.py [new file with mode: 0644]
release/scripts/op/io_scene_obj/export_obj.py
release/scripts/op/io_scene_obj/import_obj.py
release/scripts/op/io_scene_x3d/__init__.py [new file with mode: 0644]
release/scripts/op/io_scene_x3d/export_x3d.py
release/scripts/op/io_shape_mdd/__init__.py [new file with mode: 0644]
release/scripts/op/io_shape_mdd/export_mdd.py
release/scripts/op/io_shape_mdd/import_mdd.py

index 5a705e95aa82393030a3c00a3b6af3a1339f01d2..e4f6bf65fe24033815cadacec34a5adaa6809369 100644 (file)
@@ -19,9 +19,7 @@
 # This directory is a Python package.
 
 # To support reload properly, try to access a package var, if it's there, reload everything
-try:
-    init_data
-
+if "bpy" in locals():
     reload(model)
     reload(operators)
     reload(client)
@@ -32,7 +30,7 @@ try:
     reload(balancing)
     reload(ui)
     reload(repath)
-except:
+else:
     from netrender import model
     from netrender import operators
     from netrender import client
@@ -49,7 +47,6 @@ slaves = []
 blacklist = []
 
 init_file = ""
-init_data = True
 init_address = True
 
 def register():
index b65ada8d804e017b30180928479f83e8c8ddb699..db783dd10548e51c41e78bb4ba11cb4d1e6e86ed 100644 (file)
@@ -42,6 +42,23 @@ class ImportHelper:
                return {'RUNNING_MODAL'}
 
 
+# limited replacement for BPyImage.comprehensiveImageLoad
+def load_image(imagepath, dirname):
+
+    if os.path.exists(imagepath):
+        return bpy.data.images.load(imagepath)
+
+    variants = [imagepath, os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
+
+    for filepath in variants:
+        for nfilepath in (filepath, bpy.path.resolve_ncase(filepath)):
+            if os.path.exists(nfilepath):
+                return bpy.data.images.load(nfilepath)
+
+    # TODO comprehensiveImageLoad also searched in bpy.config.textureDir
+    return None
+
+
 # return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects()
 def create_derived_objects(scene, ob):
     if ob.parent and ob.parent.dupli_type != 'NONE':
@@ -54,42 +71,16 @@ def create_derived_objects(scene, ob):
         return False, [(ob, ob.matrix_world)]
 
 
-
 def free_derived_objects(ob):
     ob.free_dupli_list()
 
 
-# So 3ds max can open files, limit names to 12 in length
-# this is verry annoying for filenames!
-name_unique = []
-name_mapping = {}
-def sane_name(name):
-    name_fixed = name_mapping.get(name)
-    if name_fixed != None:
-        return name_fixed
-
-    if len(name) > 12:
-        new_name = name[:12]
-    else:
-        new_name = name
-
-    i = 0
-
-    while new_name in name_unique:
-        new_name = new_name[:-4] + '.%.3d' % i
-        i+=1
-
-    name_unique.append(new_name)
-    name_mapping[name] = new_name
-    return new_name
-
-
 def unpack_list(list_of_tuples):
     flat_list = []
     flat_list_extend = flat_list.extend # a tich faster
     for t in list_of_tuples:
         flat_list_extend(t)
-    return l
+    return flat_list
 
 # same as above except that it adds 0 for triangle faces
 def unpack_face_list(list_of_tuples):
diff --git a/release/scripts/op/io_anim_bvh/__init__.py b/release/scripts/op/io_anim_bvh/__init__.py
new file mode 100644 (file)
index 0000000..6b529f8
--- /dev/null
@@ -0,0 +1,74 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    # only reload if we alredy loaded, highly annoying
+    import sys
+    reload(sys.modules.get("io_mesh_ply.export_ply", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ImportHelper
+
+
+class BvhImporter(bpy.types.Operator, ImportHelper):
+    '''Load a OBJ Motion Capture File'''
+    bl_idname = "import_anim.bvh"
+    bl_label = "Import BVH"
+    
+    filename_ext = ".bvh"
+
+    scale = FloatProperty(name="Scale", description="Scale the BVH by this value", min=0.0001, max=1000000.0, soft_min=0.001, soft_max=100.0, default=0.1)
+    frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
+    loop = BoolProperty(name="Loop", description="Loop the animation playback", default=False)
+    rotate_mode = EnumProperty(items=(
+            ('QUATERNION', "Quaternion", "Convert rotations to quaternions"),
+            ('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
+            ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
+            ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
+            ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
+            ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
+            ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
+            ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
+            ),
+                name="Rotation",
+                description="Rotation conversion.",
+                default='NATIVE')
+
+    def execute(self, context):
+        import io_anim_bvh.import_bvh
+        return io_anim_bvh.import_bvh.load(self, context, **self.properties)
+
+
+def menu_func(self, context):
+    self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)")
+
+
+def register():
+    bpy.types.INFO_MT_file_import.append(menu_func)
+
+
+def unregister():
+    bpy.types.INFO_MT_file_import.remove(menu_func)
+
+if __name__ == "__main__":
+    register()
index 21b3e5e9aa121f48e05b82327a58ed21329a02a9..befd6cdbe89de318c8e858e87475be61db6878b6 100644 (file)
@@ -555,67 +555,24 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
     return arm_ob
 
 
-from bpy.props import *
-from io_utils import ImportHelper
+def load(operator, context, filepath="", rotate_mode='NATIVE', scale=1.0, use_cyclic=False, frame_start=1):
+    import time
+    t1 = time.time()
+    print('\tparsing bvh %r...' % filepath, end="")
 
+    bvh_nodes = read_bvh(context, filepath,
+            ROT_MODE=rotate_mode,
+            GLOBAL_SCALE=scale)
 
-class BvhImporter(bpy.types.Operator, ImportHelper):
-    '''Load a OBJ Motion Capture File'''
-    bl_idname = "import_anim.bvh"
-    bl_label = "Import BVH"
-    
-    filename_ext = ".bvh"
-
-    scale = FloatProperty(name="Scale", description="Scale the BVH by this value", min=0.0001, max=1000000.0, soft_min=0.001, soft_max=100.0, default=0.1)
-    frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
-    loop = BoolProperty(name="Loop", description="Loop the animation playback", default=False)
-    rotate_mode = EnumProperty(items=(
-            ('QUATERNION', "Quaternion", "Convert rotations to quaternions"),
-            ('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
-            ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
-            ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
-            ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
-            ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
-            ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
-            ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
-            ),
-                name="Rotation",
-                description="Rotation conversion.",
-                default='NATIVE')
-
-    def execute(self, context):
-        # print("Selected: " + context.active_object.name)
-        import time
-        t1 = time.time()
-        print('\tparsing bvh...', end="")
-
-        bvh_nodes = read_bvh(context, self.properties.filepath,
-                ROT_MODE=self.properties.rotate_mode,
-                GLOBAL_SCALE=self.properties.scale)
-
-        print('%.4f' % (time.time() - t1))
-        t1 = time.time()
-        print('\timporting to blender...', end="")
-
-        bvh_node_dict2armature(context, bvh_nodes,
-                ROT_MODE=self.properties.rotate_mode,
-                IMPORT_START_FRAME=self.properties.frame_start,
-                IMPORT_LOOP=self.properties.loop)
-
-        print('Done in %.4f\n' % (time.time() - t1))
-        return {'FINISHED'}
+    print('%.4f' % (time.time() - t1))
+    t1 = time.time()
+    print('\timporting to blender...', end="")
 
+    bvh_node_dict2armature(context, bvh_nodes,
+            ROT_MODE=rotate_mode,
+            IMPORT_START_FRAME=frame_start,
+            IMPORT_LOOP=use_cyclic)
 
-def menu_func(self, context):
-    self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)")
-
-
-def register():
-    bpy.types.INFO_MT_file_import.append(menu_func)
-
-
-def unregister():
-    bpy.types.INFO_MT_file_import.remove(menu_func)
-
-if __name__ == "__main__":
-    register()
+    print('Done in %.4f\n' % (time.time() - t1))
+    
+    return {'FINISHED'}
diff --git a/release/scripts/op/io_mesh_ply/__init__.py b/release/scripts/op/io_mesh_ply/__init__.py
new file mode 100644 (file)
index 0000000..c174b16
--- /dev/null
@@ -0,0 +1,76 @@
+# ##### 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 #####
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    import sys
+    reload(sys.modules.get("io_mesh_ply.export_ply", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ExportHelper
+
+
+class ExportPLY(bpy.types.Operator, ExportHelper):
+    '''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
+    bl_idname = "export.ply"
+    bl_label = "Export PLY"
+    
+    filename_ext = ".ply"
+
+    use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
+    use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
+    use_uv_coords = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
+    use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
+
+    @classmethod
+    def poll(cls, context):
+        return context.active_object != None
+
+    def execute(self, context):
+        filepath = self.properties.filepath
+        filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
+        import io_mesh_ply.export_ply
+        return io_mesh_ply.export_ply.save(self, context, **self.properties)
+
+    def draw(self, context):
+        layout = self.layout
+        props = self.properties
+
+        row = layout.row()
+        row.prop(props, "use_modifiers")
+        row.prop(props, "use_normals")
+        row = layout.row()
+        row.prop(props, "use_uv_coords")
+        row.prop(props, "use_colors")
+
+
+def menu_func(self, context):
+    self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)")
+
+
+def register():
+    bpy.types.INFO_MT_file_export.append(menu_func)
+
+
+def unregister():
+    bpy.types.INFO_MT_file_export.remove(menu_func)
+
+if __name__ == "__main__":
+    register()
index f6b33239fe75756ee6d3849dfd2e72ba938e3ce1..aef4df43841f0763ebe10ec68e995d2dbb822b8f 100644 (file)
 # Copyright (C) 2004, 2005: Bruce Merry, bmerry@cs.uct.ac.za
 # Contributors: Bruce Merry, Campbell Barton
 
-import bpy
-
 """
 This script exports Stanford PLY files from Blender. It supports normals,
 colours, and texture coordinates per face or per vertex.
 Only one mesh can be exported at a time.
 """
 
-def rvec3d(v):
-    return round(v[0], 6), round(v[1], 6), round(v[2], 6)
-
+import bpy
+import os
 
-def rvec2d(v):
-    return round(v[0], 6), round(v[1], 6)
 
+def save(operator, context, filepath="", use_modifiers=True, use_normals=True, use_uv_coords=True, use_colors=True):
+    
+    def rvec3d(v):
+        return round(v[0], 6), round(v[1], 6), round(v[2], 6)
 
-def write(filename, scene, ob, \
-        EXPORT_APPLY_MODIFIERS=True,\
-        EXPORT_NORMALS=True,\
-        EXPORT_UV=True,\
-        EXPORT_COLORS=True):
 
-    if not filename.lower().endswith('.ply'):
-        filename += '.ply'
+    def rvec2d(v):
+        return round(v[0], 6), round(v[1], 6)
+    
+    scene = context.scene
+    obj = context.object
 
-    if not ob:
+    if not obj:
         raise Exception("Error, Select 1 active object")
-        return
 
-    file = open(filename, 'w')
+    file = open(filepath, 'w')
 
-
-    #EXPORT_EDGES = Draw.Create(0)
-    """
-    is_editmode = Blender.Window.EditMode()
-    if is_editmode:
-        Blender.Window.EditMode(0, '', 0)
-
-    Window.WaitCursor(1)
-    """
     if scene.objects.active:
         bpy.ops.object.mode_set(mode='OBJECT')
 
-    #mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn) # XXX
-    if EXPORT_APPLY_MODIFIERS:
-        mesh = ob.create_mesh(scene, True, 'PREVIEW')
+    if use_modifiers:
+        mesh = obj.create_mesh(scene, True, 'PREVIEW')
     else:
-        mesh = ob.data
+        mesh = obj.data
 
     if not mesh:
-        raise ("Error, could not get mesh data from active object")
-        return
+        raise Exception("Error, could not get mesh data from active object")
 
-    # mesh.transform(ob.matrix_world) # XXX
+    # mesh.transform(obj.matrix_world) # XXX
 
     faceUV = (len(mesh.uv_textures) > 0)
     vertexUV = (len(mesh.sticky) > 0)
     vertexColors = len(mesh.vertex_colors) > 0
 
     if (not faceUV) and (not vertexUV):
-        EXPORT_UV = False
+        use_uv_coords = False
     if not vertexColors:
-        EXPORT_COLORS = False
+        use_colors = False
 
-    if not EXPORT_UV:
+    if not use_uv_coords:
         faceUV = vertexUV = False
-    if not EXPORT_COLORS:
+    if not use_colors:
         vertexColors = False
 
     if faceUV:
         active_uv_layer = mesh.uv_textures.active
         if not active_uv_layer:
-            EXPORT_UV = False
+            use_uv_coords = False
             faceUV = None
         else:
             active_uv_layer = active_uv_layer.data
@@ -101,7 +86,7 @@ def write(filename, scene, ob, \
     if vertexColors:
         active_col_layer = mesh.vertex_colors.active
         if not active_col_layer:
-            EXPORT_COLORS = False
+            use_colors = False
             vertexColors = None
         else:
             active_col_layer = active_col_layer.data
@@ -166,7 +151,7 @@ def write(filename, scene, ob, \
 
     file.write('ply\n')
     file.write('format ascii 1.0\n')
-    file.write('comment Created by Blender %s - www.blender.org, source file: %s\n' % (bpy.app.version_string, bpy.data.filepath.split('/')[-1].split('\\')[-1]))
+    file.write('comment Created by Blender %s - www.blender.org, source file: %r\n' % (bpy.app.version_string, os.path.basename(bpy.data.filepath)))
 
     file.write('element vertex %d\n' % len(ply_verts))
 
@@ -174,14 +159,14 @@ def write(filename, scene, ob, \
     file.write('property float y\n')
     file.write('property float z\n')
 
-    if EXPORT_NORMALS:
+    if use_normals:
         file.write('property float nx\n')
         file.write('property float ny\n')
         file.write('property float nz\n')
-    if EXPORT_UV:
+    if use_uv_coords:
         file.write('property float s\n')
         file.write('property float t\n')
-    if EXPORT_COLORS:
+    if use_colors:
         file.write('property uchar red\n')
         file.write('property uchar green\n')
         file.write('property uchar blue\n')
@@ -192,11 +177,11 @@ def write(filename, scene, ob, \
 
     for i, v in enumerate(ply_verts):
         file.write('%.6f %.6f %.6f ' % tuple(mesh_verts[v[0]].co)) # co
-        if EXPORT_NORMALS:
+        if use_normals:
             file.write('%.6f %.6f %.6f ' % v[1]) # no
-        if EXPORT_UV:
+        if use_uv_coords:
             file.write('%.6f %.6f ' % v[2]) # uv
-        if EXPORT_COLORS:
+        if use_colors:
             file.write('%u %u %u' % v[3]) # col
         file.write('\n')
 
@@ -207,9 +192,9 @@ def write(filename, scene, ob, \
             file.write('4 %d %d %d %d\n' % tuple(pf))
 
     file.close()
-    print("writing", filename, "done")
+    print("writing %r done" % filepath)
 
-    if EXPORT_APPLY_MODIFIERS:
+    if use_modifiers:
         bpy.data.meshes.remove(mesh)
 
     # XXX
@@ -217,65 +202,5 @@ def write(filename, scene, ob, \
     if is_editmode:
         Blender.Window.EditMode(1, '', 0)
     """
-
-from bpy.props import *
-from io_utils import ExportHelper
-
-
-class ExportPLY(bpy.types.Operator, ExportHelper):
-    '''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
-    bl_idname = "export.ply"
-    bl_label = "Export PLY"
     
-    filename_ext = ".ply"
-
-    # List of operator properties, the attributes will be assigned
-    # to the class instance from the operator settings before calling.
-
-    use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
-    use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
-    use_uvs = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
-    use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
-
-    @classmethod
-    def poll(cls, context):
-        return context.active_object != None
-
-    def execute(self, context):
-        filepath = self.properties.filepath
-        filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
-
-        write(filepath, context.scene, context.active_object,\
-            EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
-            EXPORT_NORMALS=self.properties.use_normals,
-            EXPORT_UV=self.properties.use_uvs,
-            EXPORT_COLORS=self.properties.use_colors,
-        )
-
-        return {'FINISHED'}
-
-    def draw(self, context):
-        layout = self.layout
-        props = self.properties
-
-        row = layout.row()
-        row.prop(props, "use_modifiers")
-        row.prop(props, "use_normals")
-        row = layout.row()
-        row.prop(props, "use_uvs")
-        row.prop(props, "use_colors")
-
-
-def menu_func(self, context):
-    self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)")
-
-
-def register():
-    bpy.types.INFO_MT_file_export.append(menu_func)
-
-
-def unregister():
-    bpy.types.INFO_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
-    register()
+    return {'FINISHED'}
diff --git a/release/scripts/op/io_scene_3ds/__init__.py b/release/scripts/op/io_scene_3ds/__init__.py
new file mode 100644 (file)
index 0000000..cff8feb
--- /dev/null
@@ -0,0 +1,86 @@
+# ##### 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>
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    import sys
+    reload(sys.modules.get("io_scene_3ds.import_3ds", sys))
+    reload(sys.modules.get("io_scene_3ds.export_3ds", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ImportHelper, ExportHelper
+
+
+class Import3DS(bpy.types.Operator, ImportHelper):
+    '''Import from 3DS file format (.3ds)'''
+    bl_idname = "import_scene.autodesk_3ds"
+    bl_label = 'Import 3DS'
+
+    filename_ext = ".3ds"
+
+    constrain_size = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0)
+    use_image_search = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True)
+    use_apply_transform = BoolProperty(name="Apply Transform", description="Workaround for object transformations importing incorrectly", default=False)
+
+    def execute(self, context):
+        import io_scene_3ds.import_3ds
+        return io_scene_3ds.import_3ds.load(self, context, **self.properties)
+
+
+class Export3DS(bpy.types.Operator, ExportHelper):
+    '''Export to 3DS file format (.3ds)'''
+    bl_idname = "export_scene.autodesk_3ds"
+    bl_label = 'Export 3DS'
+
+    filename_ext = ".3ds"
+
+    def execute(self, context):
+        import io_scene_3ds.export_3ds
+        return io_scene_3ds.export_3ds.save(self, context, **self.properties)
+
+
+# Add to a menu
+def menu_func_export(self, context):
+    self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)")
+
+def menu_func_import(self, context):
+    self.layout.operator(Import3DS.bl_idname, text="3D Studio (.3ds)")
+
+def register():
+    bpy.types.INFO_MT_file_import.append(menu_func_import)
+    bpy.types.INFO_MT_file_export.append(menu_func_export)
+
+
+def unregister():
+    bpy.types.INFO_MT_file_import.remove(menu_func_import)
+    bpy.types.INFO_MT_file_export.remove(menu_func_export)
+
+if __name__ == "__main__":
+    register()
+
+# NOTES:
+# why add 1 extra vertex? and remove it when done? - "Answer - eekadoodle - would need to re-order UV's without this since face order isnt always what we give blender, BMesh will solve :D"
+# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)
+
+if __name__ == "__main__":
+    register()
+
index c972ba221787c22c5f55acc82ea4496fb301ac0a..3d1cc02a8d812c3bf4306576cee6a87ee040749a 100644 (file)
@@ -32,58 +32,81 @@ from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode.
 
 #Some of the chunks that we will export
 #----- Primary Chunk, at the beginning of each file
-PRIMARY= int("0x4D4D",16)
+PRIMARY= 0x4D4D
 
 #------ Main Chunks
-OBJECTINFO   =      int("0x3D3D",16);      #This gives the version of the mesh and is found right before the material and object information
-VERSION      =      int("0x0002",16);      #This gives the version of the .3ds file
-KFDATA       =      int("0xB000",16);      #This is the header for all of the key frame info
+OBJECTINFO   =      0x3D3D      #This gives the version of the mesh and is found right before the material and object information
+VERSION      =      0x0002      #This gives the version of the .3ds file
+KFDATA       =      0xB000      #This is the header for all of the key frame info
 
 #------ sub defines of OBJECTINFO
 MATERIAL=45055         #0xAFFF                         // This stored the texture info
 OBJECT=16384           #0x4000                         // This stores the faces, vertices, etc...
 
 #>------ sub defines of MATERIAL
-MATNAME    =      int("0xA000",16);      # This holds the material name
-MATAMBIENT   =      int("0xA010",16);      # Ambient color of the object/material
-MATDIFFUSE   =      int("0xA020",16);      # This holds the color of the object/material
-MATSPECULAR   =      int("0xA030",16);      # SPecular color of the object/material
-MATSHINESS   =      int("0xA040",16);      # ??
-MATMAP       =      int("0xA200",16);      # This is a header for a new material
-MATMAPFILE    =      int("0xA300",16);      # This holds the file name of the texture
+MATNAME    =      0xA000      # This holds the material name
+MATAMBIENT   =      0xA010      # Ambient color of the object/material
+MATDIFFUSE   =      0xA020      # This holds the color of the object/material
+MATSPECULAR   =      0xA030      # SPecular color of the object/material
+MATSHINESS   =      0xA040      # ??
+MATMAP       =      0xA200      # This is a header for a new material
+MATMAPFILE    =      0xA300      # This holds the file name of the texture
 
-RGB1=  int("0x0011",16)
-RGB2=  int("0x0012",16)
+RGB1=  0x0011
+RGB2=  0x0012
 
 #>------ sub defines of OBJECT
-OBJECT_MESH  =      int("0x4100",16);      # This lets us know that we are reading a new object
-OBJECT_LIGHT =      int("0x4600",16);      # This lets un know we are reading a light object
-OBJECT_CAMERA=      int("0x4700",16);      # This lets un know we are reading a camera object
+OBJECT_MESH  =      0x4100      # This lets us know that we are reading a new object
+OBJECT_LIGHT =      0x4600      # This lets un know we are reading a light object
+OBJECT_CAMERA=      0x4700      # This lets un know we are reading a camera object
 
 #>------ sub defines of CAMERA
-OBJECT_CAM_RANGES=   int("0x4720",16);      # The camera range values
+OBJECT_CAM_RANGES=   0x4720      # The camera range values
 
 #>------ sub defines of OBJECT_MESH
-OBJECT_VERTICES =   int("0x4110",16);      # The objects vertices
-OBJECT_FACES    =   int("0x4120",16);      # The objects faces
-OBJECT_MATERIAL =   int("0x4130",16);      # This is found if the object has a material, either texture map or color
-OBJECT_UV       =   int("0x4140",16);      # The UV texture coordinates
-OBJECT_TRANS_MATRIX  =   int("0x4160",16); # The Object Matrix
+OBJECT_VERTICES =   0x4110      # The objects vertices
+OBJECT_FACES    =   0x4120      # The objects faces
+OBJECT_MATERIAL =   0x4130      # This is found if the object has a material, either texture map or color
+OBJECT_UV       =   0x4140      # The UV texture coordinates
+OBJECT_TRANS_MATRIX  =   0x4160 # The Object Matrix
 
 #>------ sub defines of KFDATA
-KFDATA_KFHDR            = int("0xB00A",16);
-KFDATA_KFSEG            = int("0xB008",16);
-KFDATA_KFCURTIME        = int("0xB009",16);
-KFDATA_OBJECT_NODE_TAG  = int("0xB002",16);
+KFDATA_KFHDR            = 0xB00A
+KFDATA_KFSEG            = 0xB008
+KFDATA_KFCURTIME        = 0xB009
+KFDATA_OBJECT_NODE_TAG  = 0xB002
 
 #>------ sub defines of OBJECT_NODE_TAG
-OBJECT_NODE_ID          = int("0xB030",16);
-OBJECT_NODE_HDR         = int("0xB010",16);
-OBJECT_PIVOT            = int("0xB013",16);
-OBJECT_INSTANCE_NAME    = int("0xB011",16);
-POS_TRACK_TAG                  = int("0xB020",16);
-ROT_TRACK_TAG                  = int("0xB021",16);
-SCL_TRACK_TAG                  = int("0xB022",16);
+OBJECT_NODE_ID          = 0xB030
+OBJECT_NODE_HDR         = 0xB010
+OBJECT_PIVOT            = 0xB013
+OBJECT_INSTANCE_NAME    = 0xB011
+POS_TRACK_TAG                  = 0xB020
+ROT_TRACK_TAG                  = 0xB021
+SCL_TRACK_TAG                  = 0xB022
+
+import struct
+
+# So 3ds max can open files, limit names to 12 in length
+# this is verry annoying for filenames!
+name_unique = []
+name_mapping = {}
+def sane_name(name):
+    name_fixed = name_mapping.get(name)
+    if name_fixed is not None:
+        return name_fixed
+
+    new_name = name[:12]
+
+    i = 0
+
+    while new_name in name_unique:
+        new_name = new_name[:-4] + '.%.3d' % i
+        i+=1
+
+    name_unique.append(new_name)
+    name_mapping[name] = new_name
+    return new_name
 
 def uv_key(uv):
     return round(uv[0], 6), round(uv[1], 6)
@@ -293,7 +316,7 @@ class _3ds_named_variable(object):
         if (self.value!=None):
             spaces=""
             for i in range(indent):
-                spaces+="  ";
+                spaces += "  "
             if (self.name!=""):
                 print(spaces, self.name, " = ", self.value)
             else:
@@ -358,7 +381,7 @@ class _3ds_chunk(object):
         Uses the dump function of the named variables and the subchunks to do the actual work.'''
         spaces=""
         for i in range(indent):
-            spaces+="  ";
+            spaces += "  "
         print(spaces, "ID=", hex(self.ID.value), "size=", self.get_size())
         for variable in self.variables:
             variable.dump(indent+1)
@@ -393,11 +416,11 @@ def make_material_subchunk(id, color):
     Used for color subchunks, such as diffuse color or ambient color subchunks.'''
     mat_sub = _3ds_chunk(id)
     col1 = _3ds_chunk(RGB1)
-    col1.add_variable("color1", _3ds_rgb_color(color));
+    col1.add_variable("color1", _3ds_rgb_color(color))
     mat_sub.add_subchunk(col1)
 # optional:
 #      col2 = _3ds_chunk(RGB1)
-#      col2.add_variable("color2", _3ds_rgb_color(color));
+#      col2.add_variable("color2", _3ds_rgb_color(color))
 #      mat_sub.add_subchunk(col2)
     return mat_sub
 
@@ -835,21 +858,21 @@ def make_kf_obj_node(obj, name_to_id):
     return kf_obj_node
 """
 
-# import BPyMessages
-def write(filename, context):
+
+def save(operator, context, filepath=""):
+    import bpy
+    import time
+    from io_utils import create_derived_objects, free_derived_objects
+    
     '''Save the Blender scene to a 3ds file.'''
+    
     # Time the export
-
-    # XXX
-#      if not BPyMessages.Warning_SaveOver(filename):
-#              return
-
     time1 = time.clock()
 #      Blender.Window.WaitCursor(1)
 
     sce = context.scene
 
-    if context.object:
+    if bpy.ops.object.mode_set.poll():
         bpy.ops.object.mode_set(mode='OBJECT')
 
     # Initialize the main chunk (primary):
@@ -998,7 +1021,7 @@ def write(filename, context):
     # Check the size:
     primary.get_size()
     # Open the file for writing:
-    file = open( filename, 'wb' )
+    file = open(filepath, 'wb')
 
     # Recursively write the chunks to file:
     primary.write(file)
@@ -1006,50 +1029,15 @@ def write(filename, context):
     # Close the file:
     file.close()
 
+    # Clear name mapping vars, could make locals too
+    name_unique[:] = []
+    name_mapping.clear()
+
     # Debugging only: report the exporting time:
 #      Blender.Window.WaitCursor(0)
     print("3ds export time: %.2f" % (time.clock() - time1))
-#      print("3ds export time: %.2f" % (Blender.sys.time() - time1))
 
     # Debugging only: dump the chunk hierarchy:
     #primary.dump()
-
-import bpy
-from bpy.props import *
-from io_utils import ExportHelper
-from io_utils import create_derived_objects, free_derived_objects
-
-
-class Export3DS(bpy.types.Operator, ExportHelper):
-    '''Export to 3DS file format (.3ds)'''
-    bl_idname = "export.autodesk_3ds"
-    bl_label = 'Export 3DS'
     
-    filename_ext = ".3ds"
-
-    @classmethod
-    def poll(cls, context): # Poll isnt working yet
-        return context.active_object != None
-
-    def execute(self, context):
-        filepath = self.properties.filepath
-        filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
-
-        write(filepath, context)
-        return {'FINISHED'}
-
-
-# Add to a menu
-def menu_func(self, context):
-    self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)")
-
-
-def register():
-    bpy.types.INFO_MT_file_export.append(menu_func)
-
-
-def unregister():
-    bpy.types.INFO_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
-    register()
+    return {'FINISHED'}
index 37f707af3e3a304643e904f9b62004666f701eb0..5ea705f15f7a3af7f03819e4b2f7496e5851b7b7 100644 (file)
@@ -25,7 +25,7 @@ import os
 import time
 import struct
 
-from import_scene_obj import load_image
+from io_utils import load_image
 
 import bpy
 import mathutils
@@ -42,9 +42,9 @@ BOUNDS_3DS = []
 PRIMARY = int('0x4D4D',16)
 
 #------ Main Chunks
-OBJECTINFO   =      int('0x3D3D',16);      #This gives the version of the mesh and is found right before the material and object information
-VERSION      =      int('0x0002',16);      #This gives the version of the .3ds file
-EDITKEYFRAME=      int('0xB000',16);      #This is the header for all of the key frame info
+OBJECTINFO   =     0x3D3D      #This gives the version of the mesh and is found right before the material and object information
+VERSION      =     0x0002      #This gives the version of the .3ds file
+EDITKEYFRAME=      0xB000      #This is the header for all of the key frame info
 
 #------ sub defines of OBJECTINFO
 MATERIAL = 45055               #0xAFFF                         // This stored the texture info
@@ -52,62 +52,62 @@ OBJECT = 16384              #0x4000                         // This stores the faces, vertices, etc...
 
 #>------ sub defines of MATERIAL
 #------ sub defines of MATERIAL_BLOCK
-MAT_NAME               =       int('0xA000',16)        # This holds the material name
-MAT_AMBIENT            =       int('0xA010',16)        # Ambient color of the object/material
-MAT_DIFFUSE            =       int('0xA020',16)        # This holds the color of the object/material
-MAT_SPECULAR   =       int('0xA030',16)        # SPecular color of the object/material
-MAT_SHINESS            =       int('0xA040',16)        # ??
-MAT_TRANSPARENCY=      int('0xA050',16)        # Transparency value of material
-MAT_SELF_ILLUM =       int('0xA080',16)        # Self Illumination value of material
-MAT_WIRE               =       int('0xA085',16)        # Only render's wireframe
-
-MAT_TEXTURE_MAP        =       int('0xA200',16)        # This is a header for a new texture map
-MAT_SPECULAR_MAP=      int('0xA204',16)        # This is a header for a new specular map
-MAT_OPACITY_MAP        =       int('0xA210',16)        # This is a header for a new opacity map
-MAT_REFLECTION_MAP=    int('0xA220',16)        # This is a header for a new reflection map
-MAT_BUMP_MAP   =       int('0xA230',16)        # This is a header for a new bump map
-MAT_MAP_FILENAME =      int('0xA300',16)      # This holds the file name of the texture
-
-MAT_FLOAT_COLOR = int ('0x0010', 16) #color defined as 3 floats
-MAT_24BIT_COLOR        = int ('0x0011', 16) #color defined as 3 bytes
+MAT_NAME               =       0xA000  # This holds the material name
+MAT_AMBIENT            =       0xA010  # Ambient color of the object/material
+MAT_DIFFUSE            =       0xA020  # This holds the color of the object/material
+MAT_SPECULAR   =       0xA030  # SPecular color of the object/material
+MAT_SHINESS            =       0xA040  # ??
+MAT_TRANSPARENCY=      0xA050  # Transparency value of material
+MAT_SELF_ILLUM =       0xA080  # Self Illumination value of material
+MAT_WIRE               =       0xA085  # Only render's wireframe
+
+MAT_TEXTURE_MAP        =       0xA200  # This is a header for a new texture map
+MAT_SPECULAR_MAP=      0xA204  # This is a header for a new specular map
+MAT_OPACITY_MAP        =       0xA210  # This is a header for a new opacity map
+MAT_REFLECTION_MAP=    0xA220  # This is a header for a new reflection map
+MAT_BUMP_MAP   =       0xA230  # This is a header for a new bump map
+MAT_MAP_FILEPATH =  0xA300  # This holds the file name of the texture
+
+MAT_FLOAT_COLOR = 0x0010  #color defined as 3 floats
+MAT_24BIT_COLOR        = 0x0011  #color defined as 3 bytes
 
 #>------ sub defines of OBJECT
-OBJECT_MESH  =      int('0x4100',16);      # This lets us know that we are reading a new object
-OBJECT_LAMP =      int('0x4600',16);      # This lets un know we are reading a light object
-OBJECT_LAMP_SPOT = int('0x4610',16);           # The light is a spotloght.
-OBJECT_LAMP_OFF = int('0x4620',16);            # The light off.
-OBJECT_LAMP_ATTENUATE = int('0x4625',16);
-OBJECT_LAMP_RAYSHADE = int('0x4627',16);
-OBJECT_LAMP_SHADOWED = int('0x4630',16);
-OBJECT_LAMP_LOCAL_SHADOW = int('0x4640',16);
-OBJECT_LAMP_LOCAL_SHADOW2 = int('0x4641',16);
-OBJECT_LAMP_SEE_CONE = int('0x4650',16);
-OBJECT_LAMP_SPOT_RECTANGULAR = int('0x4651',16);
-OBJECT_LAMP_SPOT_OVERSHOOT = int('0x4652',16);
-OBJECT_LAMP_SPOT_PROJECTOR = int('0x4653',16);
-OBJECT_LAMP_EXCLUDE = int('0x4654',16);
-OBJECT_LAMP_RANGE = int('0x4655',16);
-OBJECT_LAMP_ROLL = int('0x4656',16);
-OBJECT_LAMP_SPOT_ASPECT = int('0x4657',16);
-OBJECT_LAMP_RAY_BIAS = int('0x4658',16);
-OBJECT_LAMP_INNER_RANGE = int('0x4659',16);
-OBJECT_LAMP_OUTER_RANGE = int('0x465A',16);
-OBJECT_LAMP_MULTIPLIER = int('0x465B',16);
-OBJECT_LAMP_AMBIENT_LIGHT = int('0x4680',16);
-
-
-
-OBJECT_CAMERA=      int('0x4700',16);      # This lets un know we are reading a camera object
+OBJECT_MESH  =      0x4100      # This lets us know that we are reading a new object
+OBJECT_LAMP =      0x4600      # This lets un know we are reading a light object
+OBJECT_LAMP_SPOT = 0x4610              # The light is a spotloght.
+OBJECT_LAMP_OFF = 0x4620               # The light off.
+OBJECT_LAMP_ATTENUATE = 0x4625
+OBJECT_LAMP_RAYSHADE = 0x4627
+OBJECT_LAMP_SHADOWED = 0x4630
+OBJECT_LAMP_LOCAL_SHADOW = 0x4640
+OBJECT_LAMP_LOCAL_SHADOW2 = 0x4641
+OBJECT_LAMP_SEE_CONE = 0x4650
+OBJECT_LAMP_SPOT_RECTANGULAR = 0x4651
+OBJECT_LAMP_SPOT_OVERSHOOT = 0x4652
+OBJECT_LAMP_SPOT_PROJECTOR = 0x4653
+OBJECT_LAMP_EXCLUDE = 0x4654
+OBJECT_LAMP_RANGE = 0x4655
+OBJECT_LAMP_ROLL = 0x4656
+OBJECT_LAMP_SPOT_ASPECT = 0x4657
+OBJECT_LAMP_RAY_BIAS = 0x4658
+OBJECT_LAMP_INNER_RANGE = 0x4659
+OBJECT_LAMP_OUTER_RANGE = 0x465A
+OBJECT_LAMP_MULTIPLIER = 0x465B
+OBJECT_LAMP_AMBIENT_LIGHT = 0x4680
+
+
+
+OBJECT_CAMERA=      0x4700      # This lets un know we are reading a camera object
 
 #>------ sub defines of CAMERA
-OBJECT_CAM_RANGES=   int('0x4720',16);      # The camera range values
+OBJECT_CAM_RANGES=   0x4720      # The camera range values
 
 #>------ sub defines of OBJECT_MESH
-OBJECT_VERTICES =   int('0x4110',16);      # The objects vertices
-OBJECT_FACES    =   int('0x4120',16);      # The objects faces
-OBJECT_MATERIAL =   int('0x4130',16);      # This is found if the object has a material, either texture map or color
-OBJECT_UV       =   int('0x4140',16);      # The UV texture coordinates
-OBJECT_TRANS_MATRIX  =   int('0x4160',16); # The Object Matrix
+OBJECT_VERTICES =   0x4110      # The objects vertices
+OBJECT_FACES    =   0x4120      # The objects faces
+OBJECT_MATERIAL =   0x4130      # This is found if the object has a material, either texture map or color
+OBJECT_UV       =   0x4140      # The UV texture coordinates
+OBJECT_TRANS_MATRIX  =   0x4160 # The Object Matrix
 
 global scn
 scn = None
@@ -304,7 +304,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
             #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
             read_chunk(file, temp_chunk)
 
-            if (temp_chunk.ID == MAT_MAP_FILENAME):
+            if (temp_chunk.ID == MAT_MAP_FILEPATH):
                 texture_name = read_string(file)
                 img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
                 new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
@@ -318,7 +318,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
         if img:
             add_texture_to_material(img, new_texture, contextMaterial, mapto)
 
-    dirname = os.path.dirname(FILENAME)
+    dirname = os.path.dirname(file.name)
 
     #loop through all the data for this chunk (previous chunk) and see what it is
     while (previous_chunk.bytes_read < previous_chunk.length):
@@ -604,14 +604,14 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
             #contextMatrix = contextMatrix * tx
             #contextMatrix = contextMatrix  *tx
 
-        elif  (new_chunk.ID == MAT_MAP_FILENAME):
+        elif  (new_chunk.ID == MAT_MAP_FILEPATH):
             texture_name = read_string(file)
             try:
                 TEXTURE_DICT[contextMaterial.name]
             except:
-                #img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME)
+                #img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILEPATH)
                 img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
-#                              img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILENAME, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
+#                              img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILEPATH, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
 
             new_chunk.bytes_read += len(texture_name)+1 #plus one for the null character that gets removed
 
@@ -634,30 +634,27 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
     if CreateBlenderObject:
         putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
 
-def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
-    global FILENAME, SCN
-#      global FILENAME, SCN_OBJECTS
+def load_3ds(filepath, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
+    global SCN
 
     # XXX
-#      if BPyMessages.Error_NoFile(filename):
+#      if BPyMessages.Error_NoFile(filepath):
 #              return
 
-    print('\n\nImporting 3DS: "%s"' % (filename))
-#      print('\n\nImporting 3DS: "%s"' % (Blender.sys.expandpath(filename)))
+    print('\n\nImporting 3DS: %r' % (filepath))
 
     time1 = time.clock()
 #      time1 = Blender.sys.time()
 
-    FILENAME = filename
     current_chunk = chunk()
 
-    file = open(filename,'rb')
+    file = open(filepath, 'rb')
 
     #here we go!
     # print 'reading the first chunk'
     read_chunk(file, current_chunk)
     if (current_chunk.ID!=PRIMARY):
-        print('\tFatal Error:  Not a valid 3ds file: ', filename)
+        print('\tFatal Error:  Not a valid 3ds file: %r' % filepath)
         file.close()
         return
 
@@ -718,7 +715,7 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
     # Done DUMMYVERT
     """
     if IMPORT_AS_INSTANCE:
-        name = filename.split('\\')[-1].split('/')[-1]
+        name = filepath.split('\\')[-1].split('/')[-1]
         # Create a group for this import.
         group_scn = Scene.New(name)
         for ob in importedObjects:
@@ -776,90 +773,10 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
         # Done constraining to bounds.
 
     # Select all new objects.
-    print('finished importing: "%s" in %.4f sec.' % (filename, (time.clock()-time1)))
-#      print('finished importing: "%s" in %.4f sec.' % (filename, (Blender.sys.time()-time1)))
+    print('finished importing: %r in %.4f sec.' % (filepath, (time.clock()-time1)))
     file.close()
 
 
-DEBUG = False
-# For testing compatibility
-#load_3ds('/metavr/convert/vehicle/truck_002/TruckTanker1.3DS', False)
-#load_3ds('/metavr/archive/convert/old/arranged_3ds_to_hpx-2/only-need-engine-trains/Engine2.3DS', False)
-'''
-
-else:
-    import os
-    # DEBUG ONLY
-    TIME = Blender.sys.time()
-    import os
-    print 'Searching for files'
-    os.system('find /metavr/ -iname "*.3ds" > /tmp/temp3ds_list')
-    # os.system('find /storage/ -iname "*.3ds" > /tmp/temp3ds_list')
-    print '...Done'
-    file = open('/tmp/temp3ds_list', 'r')
-    lines = file.readlines()
-    file.close()
-    # sort by filesize for faster testing
-    lines_size = [(os.path.getsize(f[:-1]), f[:-1]) for f in lines]
-    lines_size.sort()
-    lines = [f[1] for f in lines_size]
-
-
-    def between(v,a,b):
-        if v <= max(a,b) and v >= min(a,b):
-            return True
-        return False
-
-    for i, _3ds in enumerate(lines):
-        if between(i, 650,800):
-            #_3ds= _3ds[:-1]
-            print 'Importing', _3ds, '\nNUMBER', i, 'of', len(lines)
-            _3ds_file= _3ds.split('/')[-1].split('\\')[-1]
-            newScn = Blender.Scene.New(_3ds_file)
-            newScn.makeCurrent()
-            load_3ds(_3ds, False)
-
-    print 'TOTAL TIME: %.6f' % (Blender.sys.time() - TIME)
-
-'''
-from bpy.props import *
-from io_utils import ImportHelper
-
-
-class IMPORT_OT_autodesk_3ds(bpy.types.Operator, ImportHelper):
-    '''Import from 3DS file format (.3ds)'''
-    bl_idname = "import_scene.autodesk_3ds"
-    bl_label = 'Import 3DS'
-    
-    filename_ext = ".3ds"
-
-    constrain_size = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0)
-    search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True)
-    apply_transform = BoolProperty(name="Apply Transform", description="Workaround for object transformations importing incorrectly", default=False)
-
-    def execute(self, context):
-        load_3ds(self.properties.filepath,
-                 context,
-                 IMPORT_CONSTRAIN_BOUNDS=self.properties.constrain_size,
-                 IMAGE_SEARCH=self.properties.search_images,
-                 APPLY_MATRIX=self.properties.apply_transform)
-
-        return {'FINISHED'}
-
-
-def menu_func(self, context):
-    self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)")
-
-def register():
-    bpy.types.INFO_MT_file_import.append(menu_func)
-
-def unregister():
-    bpy.types.INFO_MT_file_import.remove(menu_func)
-
-# NOTES:
-# why add 1 extra vertex? and remove it when done? - "Answer - eekadoodle - would need to re-order UV's without this since face order isnt always what we give blender, BMesh will solve :D"
-# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)
-
-if __name__ == "__main__":
-    register()
-
+def load(operator, context, filepath="", constrain_size=0.0, use_image_search=True, use_apply_transform=True):
+    load_3ds(filepath, context, IMPORT_CONSTRAIN_BOUNDS=constrain_size, IMAGE_SEARCH=use_image_search, APPLY_MATRIX=use_apply_transform)
+    return {'FINISHED'}
diff --git a/release/scripts/op/io_scene_fbx/__init__.py b/release/scripts/op/io_scene_fbx/__init__.py
new file mode 100644 (file)
index 0000000..f719560
--- /dev/null
@@ -0,0 +1,102 @@
+# ##### 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>
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    # only reload if we alredy loaded, highly annoying
+    import sys
+    reload(sys.modules.get("io_scene_fbx.export_fbx", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ExportHelper
+
+
+class ExportFBX(bpy.types.Operator, ExportHelper):
+    '''Selection to an ASCII Autodesk FBX'''
+    bl_idname = "export_scene.fbx"
+    bl_label = "Export FBX"
+    
+    filename_ext = ".fbx"
+
+    # List of operator properties, the attributes will be assigned
+    # to the class instance from the operator settings before calling.
+
+    EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
+#      EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True)
+    TX_SCALE = FloatProperty(name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0)
+    TX_XROT90 = BoolProperty(name="Rot X90", description="Rotate all objects 90 degrees about the X axis", default=True)
+    TX_YROT90 = BoolProperty(name="Rot Y90", description="Rotate all objects 90 degrees about the Y axis", default=False)
+    TX_ZROT90 = BoolProperty(name="Rot Z90", description="Rotate all objects 90 degrees about the Z axis", default=False)
+    EXP_EMPTY = BoolProperty(name="Empties", description="Export empty objects", default=True)
+    EXP_CAMERA = BoolProperty(name="Cameras", description="Export camera objects", default=True)
+    EXP_LAMP = BoolProperty(name="Lamps", description="Export lamp objects", default=True)
+    EXP_ARMATURE = BoolProperty(name="Armatures", description="Export armature objects", default=True)
+    EXP_MESH = BoolProperty(name="Meshes", description="Export mesh objects", default=True)
+    EXP_MESH_APPLY_MOD = BoolProperty(name="Modifiers", description="Apply modifiers to mesh objects", default=True)
+    EXP_MESH_HQ_NORMALS = BoolProperty(name="HQ Normals", description="Generate high quality normals", default=True)
+    EXP_IMAGE_COPY = BoolProperty(name="Copy Image Files", description="Copy image files to the destination path", default=False)
+    # armature animation
+    ANIM_ENABLE = BoolProperty(name="Enable Animation", description="Export keyframe animation", default=True)
+    ANIM_OPTIMIZE = BoolProperty(name="Optimize Keyframes", description="Remove double keyframes", default=True)
+    ANIM_OPTIMIZE_PRECISSION = FloatProperty(name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0)
+#      ANIM_ACTION_ALL = BoolProperty(name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True)
+    ANIM_ACTION_ALL = BoolProperty(name="All Actions", description="Use all actions for armatures, if false, use current action", default=False)
+    # batch
+    BATCH_ENABLE = BoolProperty(name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False)
+    BATCH_GROUP = BoolProperty(name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False)
+    BATCH_OWN_DIR = BoolProperty(name="Own Dir", description="Create a dir for each exported file", default=True)
+    BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen=1024, default="")
+
+
+    def execute(self, context):
+        import math
+        from mathutils import Matrix
+        if not self.properties.filepath:
+            raise Exception("filepath not set")
+
+        mtx4_x90n      = Matrix.Rotation(-math.pi/2.0, 4, 'X')
+        mtx4_y90n      = Matrix.Rotation(-math.pi/2.0, 4, 'Y')
+        mtx4_z90n      = Matrix.Rotation(-math.pi/2.0, 4, 'Z')
+
+        GLOBAL_MATRIX = Matrix()
+        GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self.properties.TX_SCALE
+        if self.properties.TX_XROT90: GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
+        if self.properties.TX_YROT90: GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
+        if self.properties.TX_ZROT90: GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
+
+        import io_scene_fbx.export_fbx
+        return io_scene_fbx.export_fbx.save(self, context, GLOBAL_MATRIX=GLOBAL_MATRIX, **self.properties)
+
+
+def menu_func(self, context):
+    self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)")
+
+
+def register():
+    bpy.types.INFO_MT_file_export.append(menu_func)
+
+
+def unregister():
+    bpy.types.INFO_MT_file_export.remove(menu_func)
+
+if __name__ == "__main__":
+    register()
index c48e86c25191298267f56ca04ff1a5efae024323..ec13decc02688a57ebb79bd3d795cf32c5e6522e 100644 (file)
@@ -34,19 +34,10 @@ import shutil # for file copying
 import bpy
 from mathutils import Vector, Euler, Matrix
 
-def copy_file(source, dest):
-    # XXX - remove, can use shutil
-    file = open(source, 'rb')
-    data = file.read()
-    file.close()
-
-    file = open(dest, 'wb')
-    file.write(data)
-    file.close()
-
-
 # XXX not used anymore, images are copied one at a time
 def copy_images(dest_dir, textures):
+    import shutil
+    
     if not dest_dir.endswith(os.sep):
         dest_dir += os.sep
 
@@ -61,12 +52,12 @@ def copy_images(dest_dir, textures):
             # Make a name for the target path.
             dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
             if not Blender.sys.exists(dest_image_path): # Image isnt already there
-                print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
+                print("\tCopying %r > %r" % (image_path, dest_image_path))
                 try:
-                    copy_file(image_path, dest_image_path)
+                    shutil.copy(image_path, dest_image_path)
                     copyCount+=1
                 except:
-                    print('\t\tWarning, file failed to copy, skipping.')
+                    print("\t\tWarning, file failed to copy, skipping.")
 
     print('\tCopied %d images' % copyCount)
 
@@ -81,27 +72,11 @@ def eulerRadToDeg(eul):
 
     return ret
 
-mtx4_identity = Matrix()
-
-# testing
-mtx_x90                = Matrix.Rotation( math.pi/2, 3, 'X') # used
-#mtx_x90n      = Matrix.Rotation(-90, 3, 'x')
-#mtx_y90       = Matrix.Rotation( 90, 3, 'y')
-#mtx_y90n      = Matrix.Rotation(-90, 3, 'y')
-#mtx_z90       = Matrix.Rotation( 90, 3, 'z')
-#mtx_z90n      = Matrix.Rotation(-90, 3, 'z')
-
-#mtx4_x90      = Matrix.Rotation( 90, 4, 'x')
-mtx4_x90n      = Matrix.Rotation(-math.pi/2, 4, 'X') # used
-#mtx4_y90      = Matrix.Rotation( 90, 4, 'y')
-mtx4_y90n      = Matrix.Rotation(-math.pi/2, 4, 'Y') # used
-mtx4_z90       = Matrix.Rotation( math.pi/2, 4, 'Z') # used
-mtx4_z90n      = Matrix.Rotation(-math.pi/2, 4, 'Z') # used
 
 # def strip_path(p):
 #      return p.split('\\')[-1].split('/')[-1]
 
-# Used to add the scene name into the filename without using odd chars
+# Used to add the scene name into the filepath without using odd chars
 sane_name_mapping_ob = {}
 sane_name_mapping_mat = {}
 sane_name_mapping_tex = {}
@@ -174,7 +149,7 @@ def sane_groupname(data):   return sane_name(data, sane_name_mapping_group)
 #      '''
 #      fname_orig - blender path, can be relative
 #      basepath - fname_rel will be relative to this
-#      FORCE_CWD - dont use the basepath, just add a ./ to the filename.
+#      FORCE_CWD - dont use the basepath, just add a ./ to the filepath.
 #              use when we know the file will be in the basepath.
 #      '''
 #      fname = bpy.path.abspath(fname_orig)
@@ -259,19 +234,17 @@ header_comment = \
 
 '''
 
-# This func can be called with just the filename
-def write(filename, batch_objects = None, \
-        context = None,
+# This func can be called with just the filepath
+def save(operator, context, filepath="", \
         EXP_OBS_SELECTED =                     True,
         EXP_MESH =                                     True,
         EXP_MESH_APPLY_MOD =           True,
-#              EXP_MESH_HQ_NORMALS =           False,
         EXP_ARMATURE =                         True,
         EXP_LAMP =                                     True,
         EXP_CAMERA =                           True,
         EXP_EMPTY =                                    True,
         EXP_IMAGE_COPY =                       False,
-        GLOBAL_MATRIX =                                Matrix(),
+        GLOBAL_MATRIX =                                None,
         ANIM_ENABLE =                          True,
         ANIM_OPTIMIZE =                                True,
         ANIM_OPTIMIZE_PRECISSION =     6,
@@ -282,16 +255,26 @@ def write(filename, batch_objects = None, \
         BATCH_OWN_DIR =                                False
     ):
 
-    if bpy.context.object:
+    #XXX, missing arg 
+    batch_objects = None
+
+    # testing
+    mtx_x90            = Matrix.Rotation( math.pi/2.0, 3, 'X') # used
+    mtx4_z90   = Matrix.Rotation( math.pi/2.0, 4, 'Z')
+
+    if GLOBAL_MATRIX is None:
+        GLOBAL_MATRIX = Matrix()
+
+    if bpy.ops.object.mode_set.poll():
         bpy.ops.object.mode_set(mode='OBJECT')
 
     # ----------------- Batch support!
     if BATCH_ENABLE:
         if os == None: BATCH_OWN_DIR = False
 
-        fbxpath = filename
+        fbxpath = filepath
 
-        # get the path component of filename
+        # get the path component of filepath
         tmp_exists = bpy.utils.exists(fbxpath)
 #              tmp_exists = Blender.sys.exists(fbxpath)
 
@@ -300,7 +283,7 @@ def write(filename, batch_objects = None, \
 #                      while fbxpath and fbxpath[-1] not in ('/', '\\'):
 #                              fbxpath = fbxpath[:-1]
             if not fbxpath:
-#                      if not filename:
+#                      if not filepath:
                 # XXX
                 print('Error%t|Directory does not exist!')
 #                              Draw.PupMenu('Error%t|Directory does not exist!')
@@ -345,9 +328,9 @@ def write(filename, batch_objects = None, \
                     os.mkdir(new_fbxpath)
 
 
-            filename = new_fbxpath + newname + '.fbx'
+            filepath = new_fbxpath + newname + '.fbx'
 
-            print('\nBatch exporting %s as...\n\t"%s"' % (data, filename))
+            print('\nBatch exporting %s as...\n\t%r' % (data, filepath))
 
             # XXX don't know what to do with this, probably do the same? (Arystan)
             if BATCH_GROUP: #group
@@ -370,12 +353,11 @@ def write(filename, batch_objects = None, \
 
             # Call self with modified args
             # Dont pass batch options since we already usedt them
-            write(filename, data.objects,
+            write(filepath, data.objects,
                 context,
                 False,
                 EXP_MESH,
                 EXP_MESH_APPLY_MOD,
-#                              EXP_MESH_HQ_NORMALS,
                 EXP_ARMATURE,
                 EXP_LAMP,
                 EXP_CAMERA,
@@ -400,9 +382,9 @@ def write(filename, batch_objects = None, \
     # end batch support
 
     # Use this for working out paths relative to the export location
-    basepath = os.path.dirname(filename) or '.'
+    basepath = os.path.dirname(filepath) or '.'
     basepath += os.sep
-#      basepath = Blender.sys.dirname(filename)
+#      basepath = Blender.sys.dirname(filepath)
 
     # ----------------------------------------------
     # storage classes
@@ -549,11 +531,11 @@ def write(filename, batch_objects = None, \
 
 
 
-    print('\nFBX export starting...', filename)
+    print('\nFBX export starting... %r' % filepath)
     start_time = time.clock()
 #      start_time = Blender.sys.time()
     try:
-        file = open(filename, 'w')
+        file = open(filepath, 'w')
     except:
         return False
 
@@ -2449,7 +2431,7 @@ Objects:  {''')
         file.write('\n\t\tPoseNode:  {')
         file.write('\n\t\t\tNode: "Model::%s"' % fbxName )
         if matrix:             file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix))
-        else:                  file.write('\n\t\t\tMatrix: %s' % mat4x4str(mtx4_identity))
+        else:                  file.write('\n\t\t\tMatrix: %s' % mat4x4str(Matrix()))
         file.write('\n\t\t}')
 
     file.write('\n\t}')
@@ -2946,12 +2928,10 @@ Takes:  {''')
         mist_start = m.start
         mist_end = m.depth
         mist_height = m.height
-#              mist_intense, mist_start, mist_end, mist_height = world.mist
         world_hor = world.horizon_color
-#              world_hor = world.hor
     else:
         has_mist = mist_intense = mist_start = mist_end = mist_height = 0
-        world_hor = 0,0,0
+        world_hor = 0, 0, 0
 
     file.write('\n;Version 5 settings')
     file.write('\n;------------------------------------------------------------------')
@@ -3003,94 +2983,7 @@ Takes:  {''')
 #              bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath)
 
     print('export finished in %.4f sec.' % (time.clock() - start_time))
-    return True
-
-from bpy.props import *
-from io_utils import ExportHelper
-
-
-class ExportFBX(bpy.types.Operator, ExportHelper):
-    '''Selection to an ASCII Autodesk FBX'''
-    bl_idname = "export.fbx"
-    bl_label = "Export FBX"
-    
-    filename_ext = ".fbx"
-
-    # List of operator properties, the attributes will be assigned
-    # to the class instance from the operator settings before calling.
-
-    EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
-#      EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True)
-    TX_SCALE = FloatProperty(name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0)
-    TX_XROT90 = BoolProperty(name="Rot X90", description="Rotate all objects 90 degrees about the X axis", default=True)
-    TX_YROT90 = BoolProperty(name="Rot Y90", description="Rotate all objects 90 degrees about the Y axis", default=False)
-    TX_ZROT90 = BoolProperty(name="Rot Z90", description="Rotate all objects 90 degrees about the Z axis", default=False)
-    EXP_EMPTY = BoolProperty(name="Empties", description="Export empty objects", default=True)
-    EXP_CAMERA = BoolProperty(name="Cameras", description="Export camera objects", default=True)
-    EXP_LAMP = BoolProperty(name="Lamps", description="Export lamp objects", default=True)
-    EXP_ARMATURE = BoolProperty(name="Armatures", description="Export armature objects", default=True)
-    EXP_MESH = BoolProperty(name="Meshes", description="Export mesh objects", default=True)
-    EXP_MESH_APPLY_MOD = BoolProperty(name="Modifiers", description="Apply modifiers to mesh objects", default=True)
-    EXP_MESH_HQ_NORMALS = BoolProperty(name="HQ Normals", description="Generate high quality normals", default=True)
-    EXP_IMAGE_COPY = BoolProperty(name="Copy Image Files", description="Copy image files to the destination path", default=False)
-    # armature animation
-    ANIM_ENABLE = BoolProperty(name="Enable Animation", description="Export keyframe animation", default=True)
-    ANIM_OPTIMIZE = BoolProperty(name="Optimize Keyframes", description="Remove double keyframes", default=True)
-    ANIM_OPTIMIZE_PRECISSION = FloatProperty(name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0)
-#      ANIM_ACTION_ALL = BoolProperty(name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True)
-    ANIM_ACTION_ALL = BoolProperty(name="All Actions", description="Use all actions for armatures, if false, use current action", default=False)
-    # batch
-    BATCH_ENABLE = BoolProperty(name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False)
-    BATCH_GROUP = BoolProperty(name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False)
-    BATCH_OWN_DIR = BoolProperty(name="Own Dir", description="Create a dir for each exported file", default=True)
-    BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen=1024, default="")
-
-
-    @classmethod
-    def poll(cls, context):
-        return context.active_object
-
-    def execute(self, context):
-        if not self.properties.filepath:
-            raise Exception("filepath not set")
-
-        filepath = self.properties.filepath
-        filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
-
-        GLOBAL_MATRIX = mtx4_identity
-        GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self.properties.TX_SCALE
-        if self.properties.TX_XROT90: GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
-        if self.properties.TX_YROT90: GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
-        if self.properties.TX_ZROT90: GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
-
-        write(filepath,
-              None, # XXX
-              context,
-              self.properties.EXP_OBS_SELECTED,
-              self.properties.EXP_MESH,
-              self.properties.EXP_MESH_APPLY_MOD,
-#                        self.properties.EXP_MESH_HQ_NORMALS,
-              self.properties.EXP_ARMATURE,
-              self.properties.EXP_LAMP,
-              self.properties.EXP_CAMERA,
-              self.properties.EXP_EMPTY,
-              self.properties.EXP_IMAGE_COPY,
-              GLOBAL_MATRIX,
-              self.properties.ANIM_ENABLE,
-              self.properties.ANIM_OPTIMIZE,
-              self.properties.ANIM_OPTIMIZE_PRECISSION,
-              self.properties.ANIM_ACTION_ALL,
-              self.properties.BATCH_ENABLE,
-              self.properties.BATCH_GROUP,
-              self.properties.BATCH_FILE_PREFIX,
-              self.properties.BATCH_OWN_DIR,
-              )
-
-        return {'FINISHED'}
-
-
-# if __name__ == "__main__":
-#      bpy.ops.EXPORT_OT_ply(filepath="/tmp/test.ply")
+    return {'FINISHED'}
 
 
 # NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
@@ -3111,21 +3004,3 @@ class ExportFBX(bpy.types.Operator, ExportHelper):
 # - bpy.sys.time move to bpy.sys.util?
 # - new scene creation, activation: lines 327-342, 368
 # - uses bpy.path.abspath, *.relpath - replace at least relpath
-
-# SMALL or COSMETICAL
-# - find a way to get blender version, and put it in bpy.util?, old was Blender.Get('version')
-
-
-def menu_func(self, context):
-    self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)")
-
-
-def register():
-    bpy.types.INFO_MT_file_export.append(menu_func)
-
-
-def unregister():
-    bpy.types.INFO_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
-    register()
diff --git a/release/scripts/op/io_scene_obj/__init__.py b/release/scripts/op/io_scene_obj/__init__.py
new file mode 100644 (file)
index 0000000..d3791d1
--- /dev/null
@@ -0,0 +1,144 @@
+# ##### 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>
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    # only reload if we alredy loaded, highly annoying
+    import sys
+    reload(sys.modules.get("io_scene_obj.import_obj", sys))
+    reload(sys.modules.get("io_scene_obj.export_obj", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ExportHelper, ImportHelper
+
+
+class ImportOBJ(bpy.types.Operator, ImportHelper):
+    '''Load a Wavefront OBJ File'''
+    bl_idname = "import_scene.obj"
+    bl_label = "Import OBJ"
+
+    filename_ext = ".obj"
+
+    CREATE_SMOOTH_GROUPS = BoolProperty(name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True)
+    CREATE_FGONS = BoolProperty(name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True)
+    CREATE_EDGES = BoolProperty(name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True)
+    SPLIT_OBJECTS = BoolProperty(name="Object", description="Import OBJ Objects into Blender Objects", default= True)
+    SPLIT_GROUPS = BoolProperty(name="Group", description="Import OBJ Groups into Blender Objects", default= True)
+    # old comment: only used for user feedback
+    # disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj
+    # KEEP_VERT_ORDER = BoolProperty(name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True)
+    ROTATE_X90 = BoolProperty(name="-X90", description="Rotate X 90.", default= True)
+    CLAMP_SIZE = FloatProperty(name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0)
+    POLYGROUPS = BoolProperty(name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True)
+    IMAGE_SEARCH = BoolProperty(name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True)
+
+
+    def execute(self, context):
+        # print("Selected: " + context.active_object.name)
+        import io_scene_obj.import_obj
+        return io_scene_obj.import_obj.load(self, context, **self.properties)
+        '''
+        load_obj(self.properties.filepath,
+                 context,
+                 self.properties.CLAMP_SIZE,
+                 self.properties.CREATE_FGONS,
+                 self.properties.CREATE_SMOOTH_GROUPS,
+                 self.properties.CREATE_EDGES,
+                 self.properties.SPLIT_OBJECTS,
+                 self.properties.SPLIT_GROUPS,
+                 self.properties.ROTATE_X90,
+                 self.properties.IMAGE_SEARCH,
+                 self.properties.POLYGROUPS)
+        '''
+
+        return {'FINISHED'}
+
+
+class ExportOBJ(bpy.types.Operator, ExportHelper):
+    '''Save a Wavefront OBJ File'''
+
+    bl_idname = "export_scene.obj"
+    bl_label = 'Export OBJ'
+    
+    filename_ext = ".obj"
+
+    # List of operator properties, the attributes will be assigned
+    # to the class instance from the operator settings before calling.
+
+    # context group
+    use_selection = BoolProperty(name="Selection Only", description="Export selected objects only", default= False)
+    use_all_scenes = BoolProperty(name="All Scenes", description="", default= False)
+    use_animation = BoolProperty(name="Animation", description="", default= False)
+
+    # object group
+    use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply modifiers (preview resolution)", default= True)
+    use_rotate_x90 = BoolProperty(name="Rotate X90", description="", default= True)
+
+    # extra data group
+    use_edges = BoolProperty(name="Edges", description="", default=True)
+    use_normals = BoolProperty(name="Normals", description="", default=False)
+    use_hq_normals = BoolProperty(name="High Quality Normals", description="", default=True)
+    use_uvs = BoolProperty(name="UVs", description="", default= True)
+    use_materials = BoolProperty(name="Materials", description="", default=True)
+    copy_images = BoolProperty(name="Copy Images", description="", default=False)
+    use_triangles = BoolProperty(name="Triangulate", description="", default=False)
+    use_vertex_groups = BoolProperty(name="Polygroups", description="", default=False)
+    use_nurbs = BoolProperty(name="Nurbs", description="", default=False)
+
+    # grouping group
+    use_blen_objects = BoolProperty(name="Objects as OBJ Objects", description="", default= True)
+    group_by_object = BoolProperty(name="Objects as OBJ Groups ", description="", default= False)
+    group_by_material = BoolProperty(name="Material Groups", description="", default= False)
+    keep_vertex_order = BoolProperty(name="Keep Vertex Order", description="", default= False)
+
+
+    def execute(self, context):
+        import io_scene_obj.export_obj
+        print(self.properties.keys())
+        return io_scene_obj.export_obj.save(self, context, **self.properties)
+
+
+def menu_func_import(self, context):
+    self.layout.operator(ImportOBJ.bl_idname, text="Wavefront (.obj)")
+
+
+def menu_func_export(self, context):
+    self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)")
+
+
+def register():
+    bpy.types.INFO_MT_file_import.append(menu_func_import)
+    bpy.types.INFO_MT_file_export.append(menu_func_export)
+
+def unregister():
+    bpy.types.INFO_MT_file_import.remove(menu_func_import)
+    bpy.types.INFO_MT_file_export.remove(menu_func_export)
+
+
+# CONVERSION ISSUES
+# - matrix problem
+# - duplis - only tested dupliverts
+# - all scenes export
+# + normals calculation
+
+if __name__ == "__main__":
+    register()
index 2265177c85a4af7cea7a6b7c1d6fb95dd5a0c468..01f5b221546c2bd1d3e84ee1ce1fdad992902333 100644 (file)
@@ -734,7 +734,8 @@ def write_file(filepath, objects, scene,
 
     print("OBJ Export time: %.2f" % (time.clock() - time1))
 
-def write(filepath, context,
+# 
+def _write(context, filepath,
               EXPORT_TRI, # ok
               EXPORT_EDGES,
               EXPORT_NORMALS, # not yet
@@ -760,7 +761,7 @@ def write(filepath, context,
     orig_scene = context.scene
 
     # Exit edit mode before exporting, so current object states are exported properly.
-    if context.object:
+    if bpy.ops.object.mode_set.poll():
         bpy.ops.object.mode_set(mode='OBJECT')
 
 #   if EXPORT_ALL_SCENES:
@@ -831,98 +832,51 @@ def write(filepath, context,
 
 '''
 Currently the exporter lacks these features:
-* nurbs
 * multiple scene export (only active scene is written)
 * particles
 '''
 
-from bpy.props import *
-from io_utils import ExportHelper
 
-
-class ExportOBJ(bpy.types.Operator, ExportHelper):
-    '''Save a Wavefront OBJ File'''
-
-    bl_idname = "export.obj"
-    bl_label = 'Export OBJ'
-    
-    filename_ext = ".obj"
-
-    # List of operator properties, the attributes will be assigned
-    # to the class instance from the operator settings before calling.
-
-    # context group
-    use_selection = BoolProperty(name="Selection Only", description="Export selected objects only", default= False)
-    use_all_scenes = BoolProperty(name="All Scenes", description="", default= False)
-    use_animation = BoolProperty(name="Animation", description="", default= False)
-
-    # object group
-    use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply modifiers (preview resolution)", default= True)
-    use_rotate90 = BoolProperty(name="Rotate X90", description="", default= True)
-
-    # extra data group
-    use_edges = BoolProperty(name="Edges", description="", default=True)
-    use_normals = BoolProperty(name="Normals", description="", default=False)
-    use_hq_normals = BoolProperty(name="High Quality Normals", description="", default=True)
-    use_uvs = BoolProperty(name="UVs", description="", default= True)
-    use_materials = BoolProperty(name="Materials", description="", default=True)
-    copy_images = BoolProperty(name="Copy Images", description="", default=False)
-    use_triangles = BoolProperty(name="Triangulate", description="", default=False)
-    use_vertex_groups = BoolProperty(name="Polygroups", description="", default=False)
-    use_nurbs = BoolProperty(name="Nurbs", description="", default=False)
-
-    # grouping group
-    use_blen_objects = BoolProperty(name="Objects as OBJ Objects", description="", default= True)
-    group_by_object = BoolProperty(name="Objects as OBJ Groups ", description="", default= False)
-    group_by_material = BoolProperty(name="Material Groups", description="", default= False)
-    keep_vertex_order = BoolProperty(name="Keep Vertex Order", description="", default= False)
-
-
-    def execute(self, context):
-
-        filepath = self.properties.filepath
-        filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
-
-        write(filepath, context,
-              EXPORT_TRI=self.properties.use_triangles,
-              EXPORT_EDGES=self.properties.use_edges,
-              EXPORT_NORMALS=self.properties.use_normals,
-              EXPORT_NORMALS_HQ=self.properties.use_hq_normals,
-              EXPORT_UV=self.properties.use_uvs,
-              EXPORT_MTL=self.properties.use_materials,
-              EXPORT_COPY_IMAGES=self.properties.copy_images,
-              EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
-              EXPORT_ROTX90=self.properties.use_rotate90,
-              EXPORT_BLEN_OBS=self.properties.use_blen_objects,
-              EXPORT_GROUP_BY_OB=self.properties.group_by_object,
-              EXPORT_GROUP_BY_MAT=self.properties.group_by_material,
-              EXPORT_KEEP_VERT_ORDER=self.properties.keep_vertex_order,
-              EXPORT_POLYGROUPS=self.properties.use_vertex_groups,
-              EXPORT_CURVE_AS_NURBS=self.properties.use_nurbs,
-              EXPORT_SEL_ONLY=self.properties.use_selection,
-              EXPORT_ALL_SCENES=self.properties.use_all_scenes,
-              EXPORT_ANIMATION=self.properties.use_animation)
-
-        return {'FINISHED'}
-
-
-def menu_func(self, context):
-    self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)")
-
-
-def register():
-    bpy.types.INFO_MT_file_export.append(menu_func)
-
-def unregister():
-    bpy.types.INFO_MT_file_export.remove(menu_func)
-
-
-# CONVERSION ISSUES
-# - matrix problem
-# - duplis - only tested dupliverts
-# - NURBS - needs API additions
-# - all scenes export
-# + normals calculation
-
-if __name__ == "__main__":
-    register()
+def save(operator, context, filepath="",
+         use_triangles=False,
+         use_edges=False,
+         use_normals=False,
+         use_hq_normals=False,
+         use_uvs=True,
+         use_materials=True,
+         copy_images=False,
+         use_modifiers=True,
+         use_rotate_x90=True,
+         use_blen_objects=True,
+         group_by_object=False,
+         group_by_material=False,
+         keep_vertex_order=False,
+         use_vertex_groups=False,
+         use_nurbs=True,
+         use_selection=True,
+         use_all_scenes=False,
+         use_animation=False,
+         ):
+
+    _write(context, filepath, 
+           EXPORT_TRI=use_triangles,
+           EXPORT_EDGES=use_edges,
+           EXPORT_NORMALS=use_normals,
+           EXPORT_NORMALS_HQ=use_hq_normals,
+           EXPORT_UV=use_uvs,
+           EXPORT_MTL=use_materials,
+           EXPORT_COPY_IMAGES=copy_images,
+           EXPORT_APPLY_MODIFIERS=use_modifiers,
+           EXPORT_ROTX90=use_rotate_x90,
+           EXPORT_BLEN_OBS=use_blen_objects,
+           EXPORT_GROUP_BY_OB=group_by_object,
+           EXPORT_GROUP_BY_MAT=group_by_material,
+           EXPORT_KEEP_VERT_ORDER=keep_vertex_order,
+           EXPORT_POLYGROUPS=use_vertex_groups,
+           EXPORT_CURVE_AS_NURBS=use_nurbs,
+           EXPORT_SEL_ONLY=use_selection,
+           EXPORT_ALL_SCENES=use_all_scenes,
+           EXPORT_ANIMATION=use_animation,
+           )
+
+    return {'FINISHED'}
index ab3c6ac19ca81c020aaebb5dfd9443cd1e593323..441a11a5f6eaf1033e08dcd1fd08361e6517a300 100644 (file)
@@ -36,30 +36,8 @@ import time
 import bpy
 import mathutils
 from geometry import PolyFill
+from io_utils import load_image, unpack_list, unpack_face_list
 
-def unpack_list(list_of_tuples):
-    l = []
-    for t in list_of_tuples:
-        l.extend(t)
-    return l
-
-# same as above except that it adds 0 for triangle faces
-def unpack_face_list(list_of_tuples):
-    # allocate the entire list
-    flat_ls = [0] * (len(list_of_tuples) * 4)
-    i = 0
-
-    for t in list_of_tuples:
-        if len(t) == 3:
-            if t[2] == 0:
-                t = t[1], t[2], t[0]
-        else: # assuem quad
-            if t[3] == 0 or t[2] == 0:
-                t = t[2], t[3], t[0], t[1]
-
-        flat_ls[i:i + len(t)] = t
-        i += 4
-    return flat_ls
 
 def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
     '''
@@ -260,21 +238,6 @@ def line_value(line_split):
     elif length > 2:
         return ' '.join( line_split[1:] )
 
-# limited replacement for BPyImage.comprehensiveImageLoad
-def load_image(imagepath, dirname):
-
-    if os.path.exists(imagepath):
-        return bpy.data.images.load(imagepath)
-
-    variants = [imagepath, os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
-
-    for filepath in variants:
-        for nfilepath in (filepath, bpy.path.resolve_ncase(filepath)):
-            if os.path.exists(nfilepath):
-                return bpy.data.images.load(nfilepath)
-
-    # TODO comprehensiveImageLoad also searched in bpy.config.textureDir
-    return None
 
 def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
     if '_' in imagepath:
@@ -874,17 +837,16 @@ def get_float_func(filepath):
     # incase all vert values were ints
     return float
 
-def load_obj(filepath,
-             context,
-             CLAMP_SIZE= 0.0,
-             CREATE_FGONS= True,
-             CREATE_SMOOTH_GROUPS= True,
-             CREATE_EDGES= True,
-             SPLIT_OBJECTS= True,
-             SPLIT_GROUPS= True,
-             ROTATE_X90= True,
-             IMAGE_SEARCH=True,
-             POLYGROUPS=False):
+def load(operator, context, filepath,
+         CLAMP_SIZE= 0.0,
+         CREATE_FGONS= True,
+         CREATE_SMOOTH_GROUPS= True,
+         CREATE_EDGES= True,
+         SPLIT_OBJECTS= True,
+         SPLIT_GROUPS= True,
+         ROTATE_X90= True,
+         IMAGE_SEARCH=True,
+         POLYGROUPS=False):
     '''
     Called by the user interface or another script.
     load_obj(path) - should give acceptable results.
@@ -1218,295 +1180,8 @@ def load_obj(filepath,
     time_new= time.time()
 #      time_new= sys.time()
 
-    print('%.4f sec' % (time_new-time_sub))
     print('finished importing: %r in %.4f sec.' % (filepath, (time_new-time_main)))
-
-
-DEBUG= True
-
-
-def load_obj_ui(filepath, BATCH_LOAD= False):
-    if BPyMessages.Error_NoFile(filepath):
-        return
-
-    global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
-
-    CREATE_SMOOTH_GROUPS= Draw.Create(0)
-    CREATE_FGONS= Draw.Create(1)
-    CREATE_EDGES= Draw.Create(1)
-    SPLIT_OBJECTS= Draw.Create(0)
-    SPLIT_GROUPS= Draw.Create(0)
-    CLAMP_SIZE= Draw.Create(10.0)
-    IMAGE_SEARCH= Draw.Create(1)
-    POLYGROUPS= Draw.Create(0)
-    KEEP_VERT_ORDER= Draw.Create(1)
-    ROTATE_X90= Draw.Create(1)
-
-
-    # Get USER Options
-    # Note, Works but not pretty, instead use a more complicated GUI
-    '''
-    pup_block= [\
-    'Import...',\
-    ('Smooth Groups', CREATE_SMOOTH_GROUPS, 'Surround smooth groups by sharp edges'),\
-    ('Create FGons', CREATE_FGONS, 'Import faces with more then 4 verts as fgons.'),\
-    ('Lines', CREATE_EDGES, 'Import lines and faces with 2 verts as edges'),\
-    'Separate objects from obj...',\
-    ('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\
-    ('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\
-    'Options...',\
-    ('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
-    ('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\
-    ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\
-    ]
-
-    if not Draw.PupBlock('Import OBJ...', pup_block):
-        return
-
-    if KEEP_VERT_ORDER.val:
-        SPLIT_OBJECTS.val = False
-        SPLIT_GROUPS.val = False
-    '''
-
-
-
-    # BEGIN ALTERNATIVE UI *******************
-    if True:
-
-        EVENT_NONE = 0
-        EVENT_EXIT = 1
-        EVENT_REDRAW = 2
-        EVENT_IMPORT = 3
-
-        GLOBALS = {}
-        GLOBALS['EVENT'] = EVENT_REDRAW
-        #GLOBALS['MOUSE'] = Window.GetMouseCoords()
-        GLOBALS['MOUSE'] = [i/2 for i in Window.GetScreenSize()]
-
-        def obj_ui_set_event(e,v):
-            GLOBALS['EVENT'] = e
-
-        def do_split(e,v):
-            global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER, POLYGROUPS
-            if SPLIT_OBJECTS.val or SPLIT_GROUPS.val:
-                KEEP_VERT_ORDER.val = 0
-                POLYGROUPS.val = 0
-            else:
-                KEEP_VERT_ORDER.val = 1
-
-        def do_vertorder(e,v):
-            global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER
-            if KEEP_VERT_ORDER.val:
-                SPLIT_OBJECTS.val = SPLIT_GROUPS.val = 0
-            else:
-                if not (SPLIT_OBJECTS.val or SPLIT_GROUPS.val):
-                    KEEP_VERT_ORDER.val = 1
-
-        def do_polygroups(e,v):
-            global SPLIT_OBJECTS, SPLIT_GROUPS, KEEP_VERT_ORDER, POLYGROUPS
-            if POLYGROUPS.val:
-                SPLIT_OBJECTS.val = SPLIT_GROUPS.val = 0
-
-        def do_help(e,v):
-            url = __url__[0]
-            print('Trying to open web browser with documentation at this address...')
-            print('\t' + url)
-
-            try:
-                import webbrowser
-                webbrowser.open(url)
-            except:
-                print('...could not open a browser window.')
-
-        def obj_ui():
-            ui_x, ui_y = GLOBALS['MOUSE']
-
-            # Center based on overall pup size
-            ui_x -= 165
-            ui_y -= 90
-
-            global CREATE_SMOOTH_GROUPS, CREATE_FGONS, CREATE_EDGES, SPLIT_OBJECTS, SPLIT_GROUPS, CLAMP_SIZE, IMAGE_SEARCH, POLYGROUPS, KEEP_VERT_ORDER, ROTATE_X90
-
-            Draw.Label('Import...', ui_x+9, ui_y+159, 220, 21)
-            Draw.BeginAlign()
-            CREATE_SMOOTH_GROUPS = Draw.Toggle('Smooth Groups', EVENT_NONE, ui_x+9, ui_y+139, 110, 20, CREATE_SMOOTH_GROUPS.val, 'Surround smooth groups by sharp edges')
-            CREATE_FGONS = Draw.Toggle('NGons as FGons', EVENT_NONE, ui_x+119, ui_y+139, 110, 20, CREATE_FGONS.val, 'Import faces with more then 4 verts as fgons')
-            CREATE_EDGES = Draw.Toggle('Lines as Edges', EVENT_NONE, ui_x+229, ui_y+139, 110, 20, CREATE_EDGES.val, 'Import lines and faces with 2 verts as edges')
-            Draw.EndAlign()
-
-            Draw.Label('Separate objects by OBJ...', ui_x+9, ui_y+110, 220, 20)
-            Draw.BeginAlign()
-            SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split)
-            SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split)
-            Draw.EndAlign()
-
-            # Only used for user feedback
-            KEEP_VERT_ORDER = Draw.Toggle('Keep Vert Order', EVENT_REDRAW, ui_x+184, ui_y+89, 113, 21, KEEP_VERT_ORDER.val, 'Keep vert and face order, disables split options, enable for morph targets', do_vertorder)
-
-            ROTATE_X90 = Draw.Toggle('-X90', EVENT_REDRAW, ui_x+302, ui_y+89, 38, 21, ROTATE_X90.val, 'Rotate X 90.')
-
-            Draw.Label('Options...', ui_x+9, ui_y+60, 211, 20)
-            CLAMP_SIZE = Draw.Number('Clamp Scale: ', EVENT_NONE, ui_x+9, ui_y+39, 130, 21, CLAMP_SIZE.val, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)')
-            POLYGROUPS = Draw.Toggle('Poly Groups', EVENT_REDRAW, ui_x+144, ui_y+39, 90, 21, POLYGROUPS.val, 'Import OBJ groups as vertex groups.', do_polygroups)
-            IMAGE_SEARCH = Draw.Toggle('Image Search', EVENT_NONE, ui_x+239, ui_y+39, 100, 21, IMAGE_SEARCH.val, 'Search subdirs for any assosiated images (Warning, may be slow)')
-            Draw.BeginAlign()
-            Draw.PushButton('Online Help', EVENT_REDRAW, ui_x+9, ui_y+9, 110, 21, 'Load the wiki page for this script', do_help)
-            Draw.PushButton('Cancel', EVENT_EXIT, ui_x+119, ui_y+9, 110, 21, '', obj_ui_set_event)
-            Draw.PushButton('Import', EVENT_IMPORT, ui_x+229, ui_y+9, 110, 21, 'Import with these settings', obj_ui_set_event)
-            Draw.EndAlign()
-
-
-        # hack so the toggle buttons redraw. this is not nice at all
-        while GLOBALS['EVENT'] not in (EVENT_EXIT, EVENT_IMPORT):
-            Draw.UIBlock(obj_ui, 0)
-
-        if GLOBALS['EVENT'] != EVENT_IMPORT:
-            return
-
-    # END ALTERNATIVE UI *********************
-
-
-
-
-
-
-
-    Window.WaitCursor(1)
-
-    if BATCH_LOAD: # load the dir
-        try:
-            files= [ f for f in os.listdir(filepath) if f.lower().endswith('.obj') ]
-        except:
-            Window.WaitCursor(0)
-            Draw.PupMenu('Error%t|Could not open path ' + filepath)
-            return
-
-        if not files:
-            Window.WaitCursor(0)
-            Draw.PupMenu('Error%t|No files at path ' + filepath)
-            return
-
-        for f in files:
-            scn= bpy.data.scenes.new(os.path.splitext(f)[0])
-            scn.makeCurrent()
-
-            load_obj(sys.join(filepath, f),\
-              CLAMP_SIZE.val,\
-              CREATE_FGONS.val,\
-              CREATE_SMOOTH_GROUPS.val,\
-              CREATE_EDGES.val,\
-              SPLIT_OBJECTS.val,\
-              SPLIT_GROUPS.val,\
-              ROTATE_X90.val,\
-              IMAGE_SEARCH.val,\
-              POLYGROUPS.val
-            )
-
-    else: # Normal load
-        load_obj(filepath,\
-          CLAMP_SIZE.val,\
-          CREATE_FGONS.val,\
-          CREATE_SMOOTH_GROUPS.val,\
-          CREATE_EDGES.val,\
-          SPLIT_OBJECTS.val,\
-          SPLIT_GROUPS.val,\
-          ROTATE_X90.val,\
-          IMAGE_SEARCH.val,\
-          POLYGROUPS.val
-        )
-
-    Window.WaitCursor(0)
-
-
-def load_obj_ui_batch(file):
-    load_obj_ui(file, True)
-
-DEBUG= False
-
-# if __name__=='__main__' and not DEBUG:
-#      if os and Window.GetKeyQualifiers() & Window.Qual.SHIFT:
-#              Window.FileSelector(load_obj_ui_batch, 'Import OBJ Dir', '')
-#      else:
-#              Window.FileSelector(load_obj_ui, 'Import a Wavefront OBJ', '*.obj')
-
-    # For testing compatibility
-'''
-else:
-    # DEBUG ONLY
-    TIME= sys.time()
-    DIR = '/fe/obj'
-    import os
-    print 'Searching for files'
-    def fileList(path):
-        for dirpath, dirnames, filenames in os.walk(path):
-            for filename in filenames:
-                yield os.path.join(dirpath, filename)
-
-    files = [f for f in fileList(DIR) if f.lower().endswith('.obj')]
-    files.sort()
-
-    for i, obj_file in enumerate(files):
-        if 0 < i < 20:
-            print 'Importing', obj_file, '\nNUMBER', i, 'of', len(files)
-            newScn= bpy.data.scenes.new(os.path.basename(obj_file))
-            newScn.makeCurrent()
-            load_obj(obj_file, False, IMAGE_SEARCH=0)
-
-    print 'TOTAL TIME: %.6f' % (sys.time() - TIME)
-'''
-
-from bpy.props import *
-from io_utils import ImportHelper
-
-
-class IMPORT_OT_obj(bpy.types.Operator, ImportHelper):
-    '''Load a Wavefront OBJ File'''
-    bl_idname = "import_scene.obj"
-    bl_label = "Import OBJ"
-
-    filename_ext = ".obj"
-
-    CREATE_SMOOTH_GROUPS = BoolProperty(name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True)
-    CREATE_FGONS = BoolProperty(name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True)
-    CREATE_EDGES = BoolProperty(name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True)
-    SPLIT_OBJECTS = BoolProperty(name="Object", description="Import OBJ Objects into Blender Objects", default= True)
-    SPLIT_GROUPS = BoolProperty(name="Group", description="Import OBJ Groups into Blender Objects", default= True)
-    # old comment: only used for user feedback
-    # disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj
-    # KEEP_VERT_ORDER = BoolProperty(name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True)
-    ROTATE_X90 = BoolProperty(name="-X90", description="Rotate X 90.", default= True)
-    CLAMP_SIZE = FloatProperty(name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0)
-    POLYGROUPS = BoolProperty(name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True)
-    IMAGE_SEARCH = BoolProperty(name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True)
-
-
-    def execute(self, context):
-        # print("Selected: " + context.active_object.name)
-
-        load_obj(self.properties.filepath,
-                 context,
-                 self.properties.CLAMP_SIZE,
-                 self.properties.CREATE_FGONS,
-                 self.properties.CREATE_SMOOTH_GROUPS,
-                 self.properties.CREATE_EDGES,
-                 self.properties.SPLIT_OBJECTS,
-                 self.properties.SPLIT_GROUPS,
-                 self.properties.ROTATE_X90,
-                 self.properties.IMAGE_SEARCH,
-                 self.properties.POLYGROUPS)
-
-        return {'FINISHED'}
-
-
-def menu_func(self, context):
-    self.layout.operator(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)")
-
-
-def register():
-    bpy.types.INFO_MT_file_import.append(menu_func)
-
-def unregister():
-    bpy.types.INFO_MT_file_import.remove(menu_func)
+    return {'FINISHED'}
 
 
 # NOTES (all line numbers refer to 2.4x import_obj.py, not this file)
diff --git a/release/scripts/op/io_scene_x3d/__init__.py b/release/scripts/op/io_scene_x3d/__init__.py
new file mode 100644 (file)
index 0000000..4ccd298
--- /dev/null
@@ -0,0 +1,61 @@
+# ##### 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 #####
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    # only reload if we alredy loaded, highly annoying
+    import sys
+    reload(sys.modules.get("io_scene_x3d.export_x3d", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ExportHelper
+
+
+class ExportX3D(bpy.types.Operator, ExportHelper):
+    '''Export selection to Extensible 3D file (.x3d)'''
+    bl_idname = "export_scene.x3d"
+    bl_label = 'Export X3D'
+
+    filename_ext = ".x3d"
+
+    use_apply_modifiers = BoolProperty(name="Apply Modifiers", description="Use transformed mesh data from each object", default=True)
+    use_triangulate = BoolProperty(name="Triangulate", description="Triangulate quads.", default=False)
+    use_compress = BoolProperty(name="Compress", description="GZip the resulting file, requires a full python install", default=False)
+
+    def execute(self, context):
+        import io_scene_x3d.export_x3d
+        return io_scene_x3d.export_x3d.save(self, context, **self.properties)
+
+
+def menu_func(self, context):
+    self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)")
+
+
+def register():
+    bpy.types.INFO_MT_file_export.append(menu_func)
+
+def unregister():
+    bpy.types.INFO_MT_file_export.remove(menu_func)
+
+# NOTES
+# - blender version is hardcoded
+
+if __name__ == "__main__":
+    register()
index 9dc9c6cb981ca0665f69908f740e4c9840372426..dd8b9b2c5f66a655415b22ccf009276d12fdbb21 100644 (file)
@@ -48,8 +48,7 @@ MATWORLD= mathutils.Matrix.Rotation(-90, 4, 'X')
 # Global Variables
 ####################################
 
-filename = ""
-# filename = Blender.Get('filename')
+filepath = ""
 _safeOverwrite = True
 
 extension = ''
@@ -60,7 +59,7 @@ extension = ''
 
 class x3d_class:
 
-    def __init__(self, filename):
+    def __init__(self, filepath):
         #--- public you can change these ---
         self.writingcolor = 0
         self.writingtexture = 0
@@ -83,18 +82,18 @@ class x3d_class:
         self.matNames={}   # dictionary of materiaNames
         self.meshNames={}   # dictionary of meshNames
         self.indentLevel=0 # keeps track of current indenting
-        self.filename=filename
+        self.filepath=filepath
         self.file = None
-        if filename.lower().endswith('.x3dz'):
+        if filepath.lower().endswith('.x3dz'):
             try:
                 import gzip
-                self.file = gzip.open(filename, "w")
+                self.file = gzip.open(filepath, "w")
             except:
                 print("failed to import compression modules, exporting uncompressed")
-                self.filename = filename[:-1] # remove trailing z
+                self.filepath = filepath[:-1] # remove trailing z
 
         if self.file == None:
-            self.file = open(self.filename, "w")
+            self.file = open(self.filepath, "w")
 
         self.bNav=0
         self.nodeID=0
@@ -136,8 +135,8 @@ class x3d_class:
 ##########################################################
 
     def writeHeader(self):
-        #bfile = sys.expandpath( Blender.Get('filename') ).replace('<', '&lt').replace('>', '&gt')
-        bfile = self.filename.replace('<', '&lt').replace('>', '&gt') # use outfile name
+        #bfile = sys.expandpath( Blender.Get('filepath') ).replace('<', '&lt').replace('>', '&gt')
+        bfile = self.filepath.replace('<', '&lt').replace('>', '&gt') # use outfile name
         self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
         self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n")
         self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n")
@@ -426,6 +425,7 @@ class x3d_class:
             self.writeIndented("<Appearance>\n", 1)
             # right now this script can only handle a single material per mesh.
             if len(maters) >= 1 and maters[0].use_face_texture == False:
+                mat = maters[0]
                 self.writeMaterial(mat, self.cleanStr(mat.name,''), world)
                 if len(maters) > 1:
                     print("Warning: mesh named %s has multiple materials" % meshName)
@@ -672,13 +672,13 @@ class x3d_class:
 
     def writeImageTexture(self, image):
         name = image.name
-        filename = os.path.basename(image.filepath)
+        filepath = os.path.basename(image.filepath)
         if name in self.texNames:
             self.writeIndented("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name))
             self.texNames[name] += 1
         else:
             self.writeIndented("<ImageTexture DEF=\"%s\" " % self.cleanStr(name), 1)
-            self.file.write("url=\"%s\" />" % filename)
+            self.file.write("url=\"%s\" />" % filepath)
             self.writeIndented("\n",-1)
             self.texNames[name] = 1
 
@@ -781,7 +781,7 @@ class x3d_class:
             EXPORT_TRI=                                False,\
         ):
 
-        print("Info: starting X3D export to " + self.filename + "...")
+        print("Info: starting X3D export to " + self.filepath + "...")
         self.writeHeader()
         # self.writeScript()
         self.writeNavigationInfo(scene)
@@ -879,7 +879,7 @@ class x3d_class:
         self.texNames={}
         self.matNames={}
         self.indentLevel=0
-        print("Info: finished X3D export to %s\n" % self.filename)
+        print("Info: finished X3D export to %s\n" % self.filepath)
 
     def cleanStr(self, name, prefix='rsvd_'):
         """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name"""
@@ -1089,82 +1089,35 @@ class x3d_class:
 # Callbacks, needed before Main
 ##########################################################
 
-def write(filename,
-               context,
-               EXPORT_APPLY_MODIFIERS=False,
-               EXPORT_TRI=False,
-               EXPORT_GZIP=False):
+def save(operator, context, filepath="",
+          use_apply_modifiers=False,
+          use_triangulate=False,
+          use_compress=False):
 
-    if EXPORT_GZIP:
-        if not filename.lower().endswith('.x3dz'):
-            filename = '.'.join(filename.split('.')[:-1]) + '.x3dz'
+    if use_compress:
+        if not filepath.lower().endswith('.x3dz'):
+            filepath = '.'.join(filepath.split('.')[:-1]) + '.x3dz'
     else:
-        if not filename.lower().endswith('.x3d'):
-            filename = '.'.join(filename.split('.')[:-1]) + '.x3d'
-
+        if not filepath.lower().endswith('.x3d'):
+            filepath = '.'.join(filepath.split('.')[:-1]) + '.x3d'
 
     scene = context.scene
     world = scene.world
 
-    if scene.objects.active:
+    if bpy.ops.object.mode_set.poll():
         bpy.ops.object.mode_set(mode='OBJECT')
 
     # XXX these are global textures while .Get() returned only scene's?
     alltextures = bpy.data.textures
     # alltextures = Blender.Texture.Get()
 
-    wrlexport=x3d_class(filename)
-    wrlexport.export(\
-        scene,\
-        world,\
-        alltextures,\
-        \
-        EXPORT_APPLY_MODIFIERS = EXPORT_APPLY_MODIFIERS,\
-        EXPORT_TRI = EXPORT_TRI,\
-        )
-
-
-from bpy.props import *
-from io_utils import ExportHelper
-
-
-class ExportX3D(bpy.types.Operator, ExportHelper):
-    '''Export selection to Extensible 3D file (.x3d)'''
-    bl_idname = "export.x3d"
-    bl_label = 'Export X3D'
-
-    filename_ext = ".x3d"
-
-    apply_modifiers = BoolProperty(name="Apply Modifiers", description="Use transformed mesh data from each object", default=True)
-    triangulate = BoolProperty(name="Triangulate", description="Triangulate quads.", default=False)
-    compress = BoolProperty(name="Compress", description="GZip the resulting file, requires a full python install", default=False)
-
-    def execute(self, context):
-        filepath = self.properties.filepath
-        filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
-
-        write(filepath,
-                   context,
-                   self.properties.apply_modifiers,
-                   self.properties.triangulate,
-                   self.properties.compress,
-                   )
-
-        return {'FINISHED'}
-
-
-def menu_func(self, context):
-    self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)")
-
-
-def register():
-    bpy.types.INFO_MT_file_export.append(menu_func)
-
-def unregister():
-    bpy.types.INFO_MT_file_export.remove(menu_func)
+    wrlexport = x3d_class(filepath)
+    wrlexport.export(scene,
+                     world,
+                     alltextures,
+                     EXPORT_APPLY_MODIFIERS=use_apply_modifiers,
+                     EXPORT_TRI=use_triangulate,
+                     )
 
-# NOTES
-# - blender version is hardcoded
+    return {'FINISHED'}
 
-if __name__ == "__main__":
-    register()
diff --git a/release/scripts/op/io_shape_mdd/__init__.py b/release/scripts/op/io_shape_mdd/__init__.py
new file mode 100644 (file)
index 0000000..0af4af9
--- /dev/null
@@ -0,0 +1,115 @@
+# ##### 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>
+
+# To support reload properly, try to access a package var, if it's there, reload everything
+if "bpy" in locals():
+    # only reload if we alredy loaded, highly annoying
+    import sys
+    reload(sys.modules.get("io_shape_mdd.import_mdd", sys))
+    reload(sys.modules.get("io_shape_mdd.export_mdd", sys))
+
+
+import bpy
+from bpy.props import *
+from io_utils import ExportHelper, ImportHelper
+
+
+class ImportMDD(bpy.types.Operator, ImportHelper):
+    '''Import MDD vertex keyframe file to shape keys'''
+    bl_idname = "import_shape.mdd"
+    bl_label = "Import MDD"
+
+    filename_ext = ".mdd"
+    frame_start = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=-300000, max=300000, default=0)
+    frame_step = IntProperty(name="Step", min=1, max=1000, default=1)
+
+    @classmethod
+    def poll(cls, context):
+        ob = context.active_object
+        return (ob and ob.type == 'MESH')
+
+    def execute(self, context):
+
+        # initialize from scene if unset
+        scene = context.scene
+        if not self.properties.is_property_set("frame_start"):
+            self.properties.frame_start = scene.frame_current
+        
+        import io_shape_mdd.import_mdd
+        return io_shape_mdd.import_mdd.load(self, context, **self.properties)
+
+class ExportMDD(bpy.types.Operator, ExportHelper):
+    '''Animated mesh to MDD vertex keyframe file'''
+    bl_idname = "export_shape.mdd"
+    bl_label = "Export MDD"
+    
+    filename_ext = ".mdd"
+
+    # get first scene to get min and max properties for frames, fps
+
+    minframe = 1
+    maxframe = 300000
+    minfps = 1
+    maxfps = 120
+
+    # List of operator properties, the attributes will be assigned
+    # to the class instance from the operator settings before calling.
+    fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
+    frame_start = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
+    frame_end = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
+
+    @classmethod
+    def poll(cls, context):
+        obj = context.active_object
+        return (obj and obj.type == 'MESH')
+
+    def execute(self, context):
+        # initialize from scene if unset
+        scene = context.scene
+        if not self.properties.is_property_set("frame_start"):
+            self.properties.frame_start = scene.frame_start
+        if not self.properties.is_property_set("frame_end"):
+            self.properties.frame_end = scene.frame_end
+        if not self.properties.is_property_set("fps"):
+            self.properties.fps = scene.render.fps
+
+        import io_shape_mdd.export_mdd
+        return io_shape_mdd.export_mdd.save(self, context, **self.properties)
+
+
+def menu_func_import(self, context):
+    self.layout.operator(ImportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
+
+
+def menu_func_export(self, context):
+    self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
+
+
+def register():
+    bpy.types.INFO_MT_file_import.append(menu_func_import)
+    bpy.types.INFO_MT_file_export.append(menu_func_export)
+
+
+def unregister():
+    bpy.types.INFO_MT_file_import.remove(menu_func_import)
+    bpy.types.INFO_MT_file_export.remove(menu_func_export)
+
+if __name__ == "__main__":
+    register()
index 91d75aaf445e669a53f06ee28c212b7a7c792b1f..1f0a5d9432079f53103df98886547e2ba4b9b117 100644 (file)
@@ -54,19 +54,23 @@ def check_vertcount(mesh, vertcount):
         return
 
 
-def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
+def save(operator, context, filepath="", frame_start=1, frame_end=300, fps=25):
     """
     Blender.Window.WaitCursor(1)
 
     mesh_orig = Mesh.New()
-    mesh_orig.getFromObject(ob.name)
+    mesh_orig.getFromObject(obj.name)
     """
 
-    bpy.ops.object.mode_set(mode='OBJECT')
+    scene = context.scene
+    obj = context.object
 
-    orig_frame = sce.frame_current
-    sce.set_frame(PREF_STARTFRAME)
-    me = ob.create_mesh(sce, True, 'PREVIEW')
+    if bpy.ops.object.mode_set.poll():
+        bpy.ops.object.mode_set(mode='OBJECT')
+
+    orig_frame = scene.frame_current
+    scene.set_frame(frame_start)
+    me = obj.create_mesh(scene, True, 'PREVIEW')
 
     #Flip y and z
     mat_flip = mathutils.Matrix(\
@@ -78,36 +82,36 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
 
     numverts = len(me.vertices)
 
-    numframes = PREF_ENDFRAME - PREF_STARTFRAME + 1
-    PREF_FPS = float(PREF_FPS)
-    f = open(filename, 'wb') #no Errors yet:Safe to create file
+    numframes = frame_end - frame_start + 1
+    fps = float(fps)
+    f = open(filepath, 'wb') #no Errors yet:Safe to create file
 
     # Write the header
     f.write(pack(">2i", numframes, numverts))
 
     # Write the frame times (should we use the time IPO??)
-    f.write(pack(">%df" % (numframes), *[frame / PREF_FPS for frame in range(numframes)])) # seconds
+    f.write(pack(">%df" % (numframes), *[frame / fps for frame in range(numframes)])) # seconds
 
     #rest frame needed to keep frames in sync
     """
-    Blender.Set('curframe', PREF_STARTFRAME)
-    me_tmp.getFromObject(ob.name)
+    Blender.Set('curframe', frame_start)
+    me_tmp.getFromObject(obj.name)
     """
 
     check_vertcount(me, numverts)
-    me.transform(mat_flip * ob.matrix_world)
+    me.transform(mat_flip * obj.matrix_world)
     f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
 
-    for frame in range(PREF_STARTFRAME, PREF_ENDFRAME + 1):#in order to start at desired frame
+    for frame in range(frame_start, frame_end + 1):#in order to start at desired frame
         """
         Blender.Set('curframe', frame)
-        me_tmp.getFromObject(ob.name)
+        me_tmp.getFromObject(obj.name)
         """
 
-        sce.set_frame(frame)
-        me = ob.create_mesh(sce, True, 'PREVIEW')
+        scene.set_frame(frame)
+        me = obj.create_mesh(scene, True, 'PREVIEW')
         check_vertcount(me, numverts)
-        me.transform(mat_flip * ob.matrix_world)
+        me.transform(mat_flip * obj.matrix_world)
 
         # Write the vertex data
         f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
@@ -117,67 +121,11 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
     """
     f.close()
 
-    print('MDD Exported: %s frames:%d\n' % (filename, numframes - 1))
+    print('MDD Exported: %r frames:%d\n' % (filepath, numframes - 1))
     """
     Blender.Window.WaitCursor(0)
     Blender.Set('curframe', orig_frame)
     """
-    sce.set_frame(orig_frame)
-
-from bpy.props import *
-from io_utils import ExportHelper
-
-
-class ExportMDD(bpy.types.Operator, ExportHelper):
-    '''Animated mesh to MDD vertex keyframe file'''
-    bl_idname = "export.mdd"
-    bl_label = "Export MDD"
+    scene.set_frame(orig_frame)
     
-    filename_ext = ".mdd"
-
-    # get first scene to get min and max properties for frames, fps
-
-    minframe = 1
-    maxframe = 300000
-    minfps = 1
-    maxfps = 120
-
-    # List of operator properties, the attributes will be assigned
-    # to the class instance from the operator settings before calling.
-    fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
-    frame_start = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
-    frame_end = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
-
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return (ob and ob.type == 'MESH')
-
-    def execute(self, context):
-        filepath = self.properties.filepath
-        filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
-        
-        write(filepath,
-              context.scene,
-              context.active_object,
-              self.properties.frame_start,
-              self.properties.frame_end,
-              self.properties.fps,
-              )
-
-        return {'FINISHED'}
-
-
-def menu_func(self, context):
-    self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
-
-
-def register():
-    bpy.types.INFO_MT_file_export.append(menu_func)
-
-
-def unregister():
-    bpy.types.INFO_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
-    register()
+    return {'FINISHED'}
index ff67d3bf7f3fd2737d65d685616510845cd7ed14..d008ff931ff21a62738e3ca98304bf7240b6ef06 100644 (file)
@@ -35,11 +35,15 @@ import bpy
 from struct import unpack
 
 
-def mdd_import(filepath, ob, scene, PREF_START_FRAME=0, PREF_JUMP=1):
+def load(operator, context, filepath, frame_start=0, frame_step=1):
+    
+    scene = context.scene
+    obj = context.object
+    
+    print('\n\nimporting mdd %r' % filepath)
 
-    print('\n\nimporting mdd "%s"' % filepath)
-
-    bpy.ops.object.mode_set(mode='OBJECT')
+    if bpy.ops.object.mode_set.poll():
+        bpy.ops.object.mode_set(mode='OBJECT')
 
     file = open(filepath, 'rb')
     frames, points = unpack(">2i", file.read(8))
@@ -49,92 +53,53 @@ def mdd_import(filepath, ob, scene, PREF_START_FRAME=0, PREF_JUMP=1):
 
     # If target object doesn't have Basis shape key, create it.
     try:
-        num_keys = len(ob.data.shape_keys.keys)
+        num_keys = len(obj.data.shape_keys.keys)
     except:
-        basis = ob.add_shape_key()
+        basis = obj.add_shape_key()
         basis.name = "Basis"
-        ob.data.update()
+        obj.data.update()
 
-    scene.frame_current = PREF_START_FRAME
+    scene.frame_current = frame_start
 
     def UpdateMesh(ob, fr):
 
         # Insert new shape key
-        new_shapekey = ob.add_shape_key()
+        new_shapekey = obj.add_shape_key()
         new_shapekey.name = ("frame_%.4d" % fr)
         new_shapekey_name = new_shapekey.name
 
-        ob.active_shape_key_index = len(ob.data.shape_keys.keys)-1
-        index = len(ob.data.shape_keys.keys)-1
-        ob.show_shape_key = True
+        obj.active_shape_key_index = len(obj.data.shape_keys.keys)-1
+        index = len(obj.data.shape_keys.keys)-1
+        obj.show_shape_key = True
 
-        verts = ob.data.shape_keys.keys[len(ob.data.shape_keys.keys)-1].data
+        verts = obj.data.shape_keys.keys[len(obj.data.shape_keys.keys)-1].data
 
 
         for v in verts: # 12 is the size of 3 floats
             v.co[:] = unpack('>3f', file.read(12))
         #me.update()
-        ob.show_shape_key = False
+        obj.show_shape_key = False
 
 
         # insert keyframes
-        shape_keys = ob.data.shape_keys
+        shape_keys = obj.data.shape_keys
 
         scene.frame_current -= 1
-        ob.data.shape_keys.keys[index].value = 0.0
-        shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
+        obj.data.shape_keys.keys[index].value = 0.0
+        shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
 
         scene.frame_current += 1
-        ob.data.shape_keys.keys[index].value = 1.0
-        shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
+        obj.data.shape_keys.keys[index].value = 1.0
+        shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
 
         scene.frame_current += 1
-        ob.data.shape_keys.keys[index].value = 0.0
-        shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
+        obj.data.shape_keys.keys[index].value = 0.0
+        shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
 
-        ob.data.update()
+        obj.data.update()
 
 
     for i in range(frames):
-        UpdateMesh(ob, i)
-
-
-from bpy.props import *
-from io_utils import ImportHelper
-
-
-class importMDD(bpy.types.Operator, ImportHelper):
-    '''Import MDD vertex keyframe file to shape keys'''
-    bl_idname = "import_shape.mdd"
-    bl_label = "Import MDD"
-
-    filename_ext = ".mdd"
-    frame_start = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=-300000, max=300000, default=0)
-
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return (ob and ob.type == 'MESH')
-
-    def execute(self, context):
-        if not self.properties.filepath:
-            raise Exception("filename not set")
-
-        mdd_import(self.properties.filepath, bpy.context.active_object, context.scene, self.properties.frame_start, 1)
-
-        return {'FINISHED'}
-
-
-def menu_func(self, context):
-    self.layout.operator(importMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
-
-
-def register():
-    bpy.types.INFO_MT_file_import.append(menu_func)
-
-
-def unregister():
-    bpy.types.INFO_MT_file_import.remove(menu_func)
+        UpdateMesh(obj, i)
 
-if __name__ == "__main__":
-    register()
+    return {'FINISHED'}