ant landscape: other required updates for 2.8
[blender-addons.git] / io_export_pc2.py
blob7384e21efdfb0d1fcc5d5d467fd02be9bea3ff49
1 # ##### BEGIN GPL LICENSE BLOCK #####
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.
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.
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.
17 # ##### END GPL LICENSE BLOCK #####
19 bl_info = {
20 "name": "Export Pointcache Format(.pc2)",
21 "author": "Florian Meyer (tstscr)",
22 "version": (1, 1, 2),
23 "blender": (2, 80, 0),
24 "location": "File > Export > Pointcache (.pc2)",
25 "description": "Export mesh Pointcache data (.pc2)",
26 "warning": "",
27 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
28 "Scripts/Import-Export/PC2_Pointcache_export",
29 "category": "Import-Export"}
31 """
32 Related links:
33 https://developer.blender.org/T34456
34 https://developer.blender.org/T25408
36 Usage Notes:
38 in Maya Mel:
39 cacheFile -pc2 1 -pcf "<insert filepath of source>" -f "<insert target filename w/o extension>" -dir "<insert directory path for target>" -format "OneFile";
41 """
43 import bpy
44 from bpy.props import BoolProperty, IntProperty, EnumProperty
45 import mathutils
46 from bpy_extras.io_utils import ExportHelper
48 from os import remove
49 import time
50 import math
51 import struct
54 def get_sampled_frames(start, end, sampling):
55 return [math.modf(start + x * sampling) for x in range(int((end - start) / sampling) + 1)]
58 def do_export(context, props, filepath):
59 mat_x90 = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
60 ob = context.active_object
61 sc = context.scene
62 start = props.range_start
63 end = props.range_end
64 sampling = float(props.sampling)
65 apply_modifiers = props.apply_modifiers
66 me = ob.to_mesh(context.depsgraph, apply_modifiers)
67 vertCount = len(me.vertices)
68 sampletimes = get_sampled_frames(start, end, sampling)
69 sampleCount = len(sampletimes)
71 # Create the header
72 headerFormat = '<12siiffi'
73 headerStr = struct.pack(headerFormat, b'POINTCACHE2\0',
74 1, vertCount, start, sampling, sampleCount)
76 file = open(filepath, "wb")
77 file.write(headerStr)
79 for frame in sampletimes:
80 # stupid modf() gives decimal part first!
81 sc.frame_set(int(frame[1]), subframe=frame[0])
82 me = ob.to_mesh(context.depsgraph, apply_modifiers)
84 if len(me.vertices) != vertCount:
85 bpy.data.meshes.remove(me, do_unlink=True)
86 file.close()
87 try:
88 remove(filepath)
89 except:
90 empty = open(filepath, 'w')
91 empty.write('DUMMIFILE - export failed\n')
92 empty.close()
93 print('Export failed. Vertexcount of Object is not constant')
94 return False
96 if props.world_space:
97 me.transform(ob.matrix_world)
98 if props.rot_x90:
99 me.transform(mat_x90)
101 for v in me.vertices:
102 thisVertex = struct.pack('<fff', float(v.co[0]),
103 float(v.co[1]),
104 float(v.co[2]))
105 file.write(thisVertex)
107 bpy.data.meshes.remove(me, do_unlink=True)
109 file.flush()
110 file.close()
111 return True
114 # EXPORT OPERATOR
115 class Export_pc2(bpy.types.Operator, ExportHelper):
116 """Export the active Object as a .pc2 Pointcache file"""
117 bl_idname = "export_shape.pc2"
118 bl_label = "Export Pointcache (.pc2)"
120 filename_ext = ".pc2"
122 rot_x90: BoolProperty(
123 name="Convert to Y-up",
124 description="Rotate 90 degrees around X to convert to y-up",
125 default=True,)
126 world_space: BoolProperty(
127 name="Export into Worldspace",
128 description="Transform the Vertexcoordinates into Worldspace",
129 default=False,)
130 apply_modifiers: BoolProperty(
131 name="Apply Modifiers",
132 description="Applies the Modifiers",
133 default=True,)
134 range_start: IntProperty(
135 name='Start Frame',
136 description='First frame to use for Export',
137 default=1,)
138 range_end: IntProperty(
139 name='End Frame',
140 description='Last frame to use for Export',
141 default=250,)
142 sampling: EnumProperty(
143 name='Sampling',
144 description='Sampling --> frames per sample (0.1 yields 10 samples per frame)',
145 items=(('0.01', '0.01', ''),
146 ('0.05', '0.05', ''),
147 ('0.1', '0.1', ''),
148 ('0.2', '0.2', ''),
149 ('0.25', '0.25', ''),
150 ('0.5', '0.5', ''),
151 ('1', '1', ''),
152 ('2', '2', ''),
153 ('3', '3', ''),
154 ('4', '4', ''),
155 ('5', '5', ''),
156 ('10', '10', ''),
158 default='1',
161 @classmethod
162 def poll(cls, context):
163 obj = context.active_object
164 return (
165 obj is not None
166 and obj.type in {'MESH', 'CURVE', 'SURFACE', 'FONT'}
169 def execute(self, context):
170 start_time = time.time()
171 print('\n_____START_____')
172 props = self.properties
173 filepath = self.filepath
174 filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
176 exported = do_export(context, props, filepath)
178 if exported:
179 print('finished export in %s seconds' %
180 ((time.time() - start_time)))
181 print(filepath)
183 return {'FINISHED'}
185 def invoke(self, context, event):
186 wm = context.window_manager
188 if True:
189 # File selector
190 wm.fileselect_add(self) # will run self.execute()
191 return {'RUNNING_MODAL'}
192 elif True:
193 # search the enum
194 wm.invoke_search_popup(self)
195 return {'RUNNING_MODAL'}
196 elif False:
197 # Redo popup
198 return wm.invoke_props_popup(self, event)
199 elif False:
200 return self.execute(context)
203 def menu_func_export_button(self, context):
204 self.layout.operator(Export_pc2.bl_idname, text="Pointcache (.pc2)")
207 classes = [
208 Export_pc2,
212 def register():
213 for cls in classes:
214 bpy.utils.register_class(cls)
216 bpy.types.TOPBAR_MT_file_export.append(menu_func_export_button)
217 #bpy.types.VIEW3D_PT_tools_objectmode.prepend(menu_func_export_button)
220 def unregister():
221 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export_button)
222 #bpy.types.VIEW3D_PT_tools_objectmode.remove(menu_func_export_button)
223 for cls in classes:
224 bpy.utils.unregister_class(cls)
227 if __name__ == "__main__":
228 register()