1 # SPDX-License-Identifier: GPL-2.0-or-later
4 "name": "NewTek MDD format",
5 "author": "Bill L.Nieuwendorp",
8 "location": "File > Import-Export",
9 "description": "Import-Export MDD as mesh shape keys",
11 "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/shape_mdd.html",
12 "support": 'OFFICIAL',
13 "category": "Import-Export",
18 if "import_mdd" in locals():
19 importlib
.reload(import_mdd
)
20 if "export_mdd" in locals():
21 importlib
.reload(export_mdd
)
25 from bpy
.props
import (
31 from bpy_extras
.io_utils
import ExportHelper
, ImportHelper
34 class ImportMDD(bpy
.types
.Operator
, ImportHelper
):
35 """Import MDD vertex keyframe file to shape keys"""
36 bl_idname
= "import_shape.mdd"
37 bl_label
= "Import MDD"
42 filter_glob
: StringProperty(
46 frame_start
: IntProperty(
48 description
="Start frame for inserting animation",
49 min=-300000, max=300000,
52 frame_step
: IntProperty(
59 def poll(cls
, context
):
60 obj
= context
.active_object
61 return (obj
and obj
.type == 'MESH')
63 def invoke(self
, context
, event
):
65 self
.frame_start
= scene
.frame_start
67 return super().invoke(context
, event
)
69 def execute(self
, context
):
70 keywords
= self
.as_keywords(ignore
=("filter_glob",))
72 from . import import_mdd
73 return import_mdd
.load(context
, **keywords
)
76 class ExportMDD(bpy
.types
.Operator
, ExportHelper
):
77 """Animated mesh to MDD vertex keyframe file"""
78 bl_idname
= "export_shape.mdd"
79 bl_label
= "Export MDD"
82 filter_glob
: StringProperty(default
="*.mdd", options
={'HIDDEN'})
84 # get first scene to get min and max properties for frames, fps
91 # List of operator properties, the attributes will be assigned
92 # to the class instance from the operator settings before calling.
94 name
="Frames Per Second",
95 description
="Number of frames/second",
96 min=minfps
, max=maxfps
,
99 frame_start
: IntProperty(
101 description
="Start frame for baking",
102 min=minframe
, max=maxframe
,
105 frame_end
: IntProperty(
107 description
="End frame for baking",
108 min=minframe
, max=maxframe
,
111 use_rest_frame
: BoolProperty(
113 description
="Write the rest state at the first frame",
118 def poll(cls
, context
):
119 obj
= context
.active_object
120 return (obj
and obj
.type == 'MESH')
122 def invoke(self
, context
, event
):
123 scene
= context
.scene
124 self
.frame_start
= scene
.frame_start
125 self
.frame_end
= scene
.frame_end
126 self
.fps
= scene
.render
.fps
/ scene
.render
.fps_base
128 return super().invoke(context
, event
)
130 def execute(self
, context
):
131 keywords
= self
.as_keywords(ignore
=("check_existing", "filter_glob"))
133 from . import export_mdd
134 return export_mdd
.save(context
, **keywords
)
137 def menu_func_import(self
, context
):
138 self
.layout
.operator(ImportMDD
.bl_idname
,
139 text
="Lightwave Point Cache (.mdd)",
143 def menu_func_export(self
, context
):
144 self
.layout
.operator(ExportMDD
.bl_idname
,
145 text
="Lightwave Point Cache (.mdd)",
156 bpy
.utils
.register_class(cls
)
158 bpy
.types
.TOPBAR_MT_file_import
.append(menu_func_import
)
159 bpy
.types
.TOPBAR_MT_file_export
.append(menu_func_export
)
164 bpy
.utils
.unregister_class(cls
)
166 bpy
.types
.TOPBAR_MT_file_import
.remove(menu_func_import
)
167 bpy
.types
.TOPBAR_MT_file_export
.remove(menu_func_export
)
169 if __name__
== "__main__":