change python scripts so modules which register with blender have a register() functi...
[blender.git] / release / scripts / io / export_mdd.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 __author__ = "Bill L.Nieuwendorp"
22 __bpydoc__ = """\
23 This script Exports Lightwaves MotionDesigner format.
24
25 The .mdd format has become quite a popular Pipeline format<br>
26 for moving animations from package to package.
27
28 Be sure not to use modifiers that change the number or order of verts in the mesh
29 """
30 #Please send any fixes,updates,bugs to Slow67_at_Gmail.com or cbarton_at_metavr.com
31 #Bill Niewuendorp
32 # ***** BEGIN GPL LICENSE BLOCK *****
33 #
34 # This program is free software; you can redistribute it and/or
35 # modify it under the terms of the GNU General Public License
36 # as published by the Free Software Foundation; either version 2
37 # of the License, or (at your option) any later version.
38 #
39 # This program is distributed in the hope that it will be useful,
40 # but WITHOUT ANY WARRANTY; without even the implied warranty of
41 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42 # GNU General Public License for more details.
43 #
44 # You should have received a copy of the GNU General Public License
45 # along with this program; if not, write to the Free Software Foundation,
46 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
47 #
48 # ***** END GPL LICENCE BLOCK *****
49
50 import bpy
51 import Mathutils
52 from struct import pack
53
54
55 def zero_file(filepath):
56     '''
57     If a file fails, this replaces it with 1 char, better not remove it?
58     '''
59     file = open(filepath, 'w')
60     file.write('\n') # apparently macosx needs some data in a blank file?
61     file.close()
62
63
64 def check_vertcount(mesh, vertcount):
65     '''
66     check and make sure the vertcount is consistent throughout the frame range
67     '''
68     if len(mesh.verts) != vertcount:
69         raise Exception('Error, number of verts has changed during animation, cannot export')
70         f.close()
71         zero_file(filepath)
72         return
73
74
75 def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
76     """
77     Blender.Window.WaitCursor(1)
78
79     mesh_orig = Mesh.New()
80     mesh_orig.getFromObject(ob.name)
81     """
82
83     bpy.ops.object.mode_set(mode='OBJECT')
84
85     orig_frame = sce.current_frame
86     sce.set_frame(PREF_STARTFRAME)
87     me = ob.create_mesh(True, 'PREVIEW')
88
89     #Flip y and z
90     mat_flip = Mathutils.Matrix(\
91     [1.0, 0.0, 0.0, 0.0],\
92     [0.0, 0.0, 1.0, 0.0],\
93     [0.0, 1.0, 0.0, 0.0],\
94     [0.0, 0.0, 0.0, 1.0],\
95     )
96
97     numverts = len(me.verts)
98
99     numframes = PREF_ENDFRAME - PREF_STARTFRAME + 1
100     PREF_FPS = float(PREF_FPS)
101     f = open(filename, 'wb') #no Errors yet:Safe to create file
102
103     # Write the header
104     f.write(pack(">2i", numframes, numverts))
105
106     # Write the frame times (should we use the time IPO??)
107     f.write(pack(">%df" % (numframes), *[frame / PREF_FPS for frame in range(numframes)])) # seconds
108
109     #rest frame needed to keep frames in sync
110     """
111     Blender.Set('curframe', PREF_STARTFRAME)
112     me_tmp.getFromObject(ob.name)
113     """
114
115     check_vertcount(me, numverts)
116     me.transform(mat_flip * ob.matrix)
117     f.write(pack(">%df" % (numverts * 3), *[axis for v in me.verts for axis in v.co]))
118
119     for frame in range(PREF_STARTFRAME, PREF_ENDFRAME + 1):#in order to start at desired frame
120         """
121         Blender.Set('curframe', frame)
122         me_tmp.getFromObject(ob.name)
123         """
124
125         sce.set_frame(frame)
126         me = ob.create_mesh(True, 'PREVIEW')
127         check_vertcount(me, numverts)
128         me.transform(mat_flip * ob.matrix)
129
130         # Write the vertex data
131         f.write(pack(">%df" % (numverts * 3), *[axis for v in me.verts for axis in v.co]))
132
133     """
134     me_tmp.verts= None
135     """
136     f.close()
137
138     print('MDD Exported: %s frames:%d\n' % (filename, numframes - 1))
139     """
140     Blender.Window.WaitCursor(0)
141     Blender.Set('curframe', orig_frame)
142     """
143     sce.set_frame(orig_frame)
144
145 from bpy.props import *
146
147
148 class ExportMDD(bpy.types.Operator):
149     '''Animated mesh to MDD vertex keyframe file.'''
150     bl_idname = "export.mdd"
151     bl_label = "Export MDD"
152
153     # get first scene to get min and max properties for frames, fps
154
155     minframe = 1
156     maxframe = 300000
157     minfps = 1
158     maxfps = 120
159
160     # List of operator properties, the attributes will be assigned
161     # to the class instance from the operator settings before calling.
162     path = StringProperty(name="File Path", description="File path used for exporting the MDD file", maxlen=1024)
163     check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
164     fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
165     start_frame = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
166     end_frame = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
167
168     def poll(self, context):
169         ob = context.active_object
170         return (ob and ob.type == 'MESH')
171
172     def execute(self, context):
173         if not self.properties.path:
174             raise Exception("filename not set")
175         write(self.properties.path, context.scene, context.active_object,
176             self.properties.start_frame, self.properties.end_frame, self.properties.fps)
177         return {'FINISHED'}
178
179     def invoke(self, context, event):
180         wm = context.manager
181         wm.add_fileselect(self)
182         return {'RUNNING_MODAL'}
183
184
185 def menu_func(self, context):
186     default_path = bpy.data.filename.replace(".blend", ".mdd")
187     self.layout.operator(ExportMDD.bl_idname, text="Vertex Keyframe Animation (.mdd)...").path = default_path
188
189
190 def register():
191     bpy.types.register(ExportMDD)
192     bpy.types.INFO_MT_file_export.append(menu_func)
193     
194 def unregister():
195     bpy.types.unregister(ExportMDD)
196     bpy.types.INFO_MT_file_export.remove(menu_func)