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