From fa68b830205780cb7fb6a4994195bce61323ae50 Mon Sep 17 00:00:00 2001 From: Campbell Barton <ideasman42@gmail.com> Date: Sat, 15 Jan 2011 19:34:59 +0000 Subject: [PATCH] move MDD io from svn into extensions. --- io_scene_obj/__init__.py | 2 +- io_shape_mdd/__init__.py | 132 +++++++++++++++++++++++++++++++++++++ io_shape_mdd/export_mdd.py | 130 ++++++++++++++++++++++++++++++++++++ io_shape_mdd/import_mdd.py | 102 ++++++++++++++++++++++++++++ 4 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 io_shape_mdd/__init__.py create mode 100644 io_shape_mdd/export_mdd.py create mode 100644 io_shape_mdd/import_mdd.py diff --git a/io_scene_obj/__init__.py b/io_scene_obj/__init__.py index dc7422d37..b4b928fe8 100644 --- a/io_scene_obj/__init__.py +++ b/io_scene_obj/__init__.py @@ -22,7 +22,7 @@ bl_info = { "name": "Wavefront OBJ format", "author": "Campbell Barton", "location": "File > Import-Export", - "description": "Import-Export X3D, Import OBJ mesh, UV's, materials and textures", + "description": "Import-Export OBJ, Import OBJ mesh, UV's, materials and textures", "warning": "", "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ "Scripts/Import-Export/Wavefront_OBJ", diff --git a/io_shape_mdd/__init__.py b/io_shape_mdd/__init__.py new file mode 100644 index 000000000..4dcb97e9c --- /dev/null +++ b/io_shape_mdd/__init__.py @@ -0,0 +1,132 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> + +bl_info = { + "name": "NewTek MDD format", + "author": "Bill L.Nieuwendorp", + "location": "File > Import-Export", + "description": "Import-Export MDD as mesh shape keys", + "warning": "", + "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\ + "Scripts/Import-Export/NewTek_OBJ", + "tracker_url": "", + "support": 'OFFICIAL', + "category": "Import-Export"} + +# To support reload properly, try to access a package var, if it's there, reload everything +if "bpy" in locals(): + import imp + if "import_mdd" in locals(): + imp.reload(import_mdd) + if "export_mdd" in locals(): + imp.reload(export_mdd) + + +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" + filter_glob = StringProperty(default="*.mdd", options={'HIDDEN'}) + + 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.frame_start: + self.frame_start = scene.frame_current + + from . import import_mdd + return import_mdd.load(self, context, **self.as_keywords(ignore=("filter_glob",))) + + +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" + filter_glob = StringProperty(default="*.mdd", options={'HIDDEN'}) + + # 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.frame_start: + self.frame_start = scene.frame_start + if not self.frame_end: + self.frame_end = scene.frame_end + if not self.fps: + self.fps = scene.render.fps + + from . import export_mdd + return export_mdd.save(self, context, **self.as_keywords(ignore=("check_existing", "filter_glob"))) + + +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() diff --git a/io_shape_mdd/export_mdd.py b/io_shape_mdd/export_mdd.py new file mode 100644 index 000000000..42795d450 --- /dev/null +++ b/io_shape_mdd/export_mdd.py @@ -0,0 +1,130 @@ +# ##### 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> + +# Contributors: Bill L.Nieuwendorp + +""" +This script Exports Lightwaves MotionDesigner format. + +The .mdd format has become quite a popular Pipeline format<br> +for moving animations from package to package. + +Be sure not to use modifiers that change the number or order of verts in the mesh +""" + +import bpy +import mathutils +from struct import pack + + +def zero_file(filepath): + ''' + If a file fails, this replaces it with 1 char, better not remove it? + ''' + file = open(filepath, 'w') + file.write('\n') # apparently macosx needs some data in a blank file? + file.close() + + +def check_vertcount(mesh, vertcount): + ''' + check and make sure the vertcount is consistent throughout the frame range + ''' + if len(mesh.vertices) != vertcount: + raise Exception('Error, number of verts has changed during animation, cannot export') + f.close() + zero_file(filepath) + return + + +def save(operator, context, filepath="", frame_start=1, frame_end=300, fps=25): + """ + Blender.Window.WaitCursor(1) + + mesh_orig = Mesh.New() + mesh_orig.getFromObject(obj.name) + """ + + scene = context.scene + obj = context.object + + if bpy.ops.object.mode_set.poll(): + bpy.ops.object.mode_set(mode='OBJECT') + + orig_frame = scene.frame_current + scene.frame_set(frame_start) + me = obj.create_mesh(scene, True, 'PREVIEW') + + #Flip y and z + mat_flip = mathutils.Matrix(((1.0, 0.0, 0.0, 0.0), \ + (0.0, 0.0, 1.0, 0.0), \ + (0.0, 1.0, 0.0, 0.0), \ + (0.0, 0.0, 0.0, 1.0), \ + )) + + numverts = len(me.vertices) + + 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 / fps for frame in range(numframes)])) # seconds + + #rest frame needed to keep frames in sync + """ + Blender.Set('curframe', frame_start) + me_tmp.getFromObject(obj.name) + """ + + check_vertcount(me, numverts) + 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(frame_start, frame_end + 1): # in order to start at desired frame + """ + Blender.Set('curframe', frame) + me_tmp.getFromObject(obj.name) + """ + + scene.frame_set(frame) + me = obj.create_mesh(scene, True, 'PREVIEW') + check_vertcount(me, numverts) + 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])) + + """ + me_tmp.vertices= None + """ + f.close() + + print('MDD Exported: %r frames:%d\n' % (filepath, numframes - 1)) + """ + Blender.Window.WaitCursor(0) + Blender.Set('curframe', orig_frame) + """ + scene.frame_set(orig_frame) + + return {'FINISHED'} diff --git a/io_shape_mdd/import_mdd.py b/io_shape_mdd/import_mdd.py new file mode 100644 index 000000000..02be14e97 --- /dev/null +++ b/io_shape_mdd/import_mdd.py @@ -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> + +# mdd importer by Bill L.Nieuwendorp +# conversion to blender 2.5: Ivo Grigull (loolarge) +# +# Warning if the vertex order or vertex count differs from the +# origonal model the mdd was Baked out from their will be Strange +# behavior +# +# vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0 +# A modifier to read mdd files would be Ideal but thats for another day :) +# +# Please send any fixes,updates,bugs to Slow67_at_Gmail.com +# Bill Niewuendorp + +import bpy +from struct import unpack + + +def load(operator, context, filepath, frame_start=0, frame_step=1): + + scene = context.scene + obj = context.object + + print('\n\nimporting mdd %r' % filepath) + + 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)) + time = unpack((">%df" % frames), file.read(frames * 4)) + + print('\tpoints:%d frames:%d' % (points, frames)) + + # If target object doesn't have Basis shape key, create it. + try: + num_keys = len(obj.data.shape_keys.keys) + except: + basis = obj.shape_key_add() + basis.name = "Basis" + obj.data.update() + + scene.frame_current = frame_start + + def UpdateMesh(ob, fr): + + # Insert new shape key + new_shapekey = obj.shape_key_add() + new_shapekey.name = ("frame_%.4d" % fr) + new_shapekey_name = new_shapekey.name + + obj.active_shape_key_index = len(obj.data.shape_keys.keys) - 1 + index = len(obj.data.shape_keys.keys) - 1 + obj.show_only_shape_key = True + + 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() + obj.show_only_shape_key = False + + # insert keyframes + shape_keys = obj.data.shape_keys + + scene.frame_current -= 1 + 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 + 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 + obj.data.shape_keys.keys[index].value = 0.0 + shape_keys.keys[len(obj.data.shape_keys.keys) - 1].keyframe_insert("value") + + obj.data.update() + + for i in range(frames): + UpdateMesh(obj, i) + + return {'FINISHED'} -- GitLab