Pose Library: update for rename of asset_library to asset_library_ref
[blender-addons.git] / io_export_pc2.py
blob8dda3cd1390b1841f3b7da86a3f0995e32812643
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 "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/pc2.html",
28 "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 depsgraph = None
67 if apply_modifiers:
68 depsgraph = context.evaluated_depsgraph_get()
69 me = ob.evaluated_get(depsgraph).to_mesh()
70 else:
71 me = ob.to_mesh()
72 vertCount = len(me.vertices)
73 sampletimes = get_sampled_frames(start, end, sampling)
74 sampleCount = len(sampletimes)
76 # Create the header
77 headerFormat = '<12siiffi'
78 headerStr = struct.pack(headerFormat, b'POINTCACHE2\0',
79 1, vertCount, start, sampling, sampleCount)
81 file = open(filepath, "wb")
82 file.write(headerStr)
84 for frame in sampletimes:
85 # stupid modf() gives decimal part first!
86 sc.frame_set(int(frame[1]), subframe=frame[0])
87 if apply_modifiers:
88 me = ob.evaluated_get(depsgraph).to_mesh()
89 else:
90 me = ob.to_mesh()
92 if len(me.vertices) != vertCount:
93 bpy.data.meshes.remove(me, do_unlink=True)
94 file.close()
95 try:
96 remove(filepath)
97 except:
98 empty = open(filepath, 'w')
99 empty.write('DUMMIFILE - export failed\n')
100 empty.close()
101 print('Export failed. Vertexcount of Object is not constant')
102 return False
104 if props.world_space:
105 me.transform(ob.matrix_world)
106 if props.rot_x90:
107 me.transform(mat_x90)
109 for v in me.vertices:
110 thisVertex = struct.pack('<fff', float(v.co[0]),
111 float(v.co[1]),
112 float(v.co[2]))
113 file.write(thisVertex)
115 if apply_modifiers:
116 ob.evaluated_get(depsgraph).to_mesh_clear()
117 else:
118 me = ob.to_mesh_clear()
120 file.flush()
121 file.close()
122 return True
125 # EXPORT OPERATOR
126 class Export_pc2(bpy.types.Operator, ExportHelper):
127 """Export the active Object as a .pc2 Pointcache file"""
128 bl_idname = "export_shape.pc2"
129 bl_label = "Export Pointcache (.pc2)"
131 filename_ext = ".pc2"
133 rot_x90: BoolProperty(
134 name="Convert to Y-up",
135 description="Rotate 90 degrees around X to convert to y-up",
136 default=True,)
137 world_space: BoolProperty(
138 name="Export into Worldspace",
139 description="Transform the Vertexcoordinates into Worldspace",
140 default=False,)
141 apply_modifiers: BoolProperty(
142 name="Apply Modifiers",
143 description="Applies the Modifiers",
144 default=True,)
145 range_start: IntProperty(
146 name='Start Frame',
147 description='First frame to use for Export',
148 default=1,)
149 range_end: IntProperty(
150 name='End Frame',
151 description='Last frame to use for Export',
152 default=250,)
153 sampling: EnumProperty(
154 name='Sampling',
155 description='Sampling --> frames per sample (0.1 yields 10 samples per frame)',
156 items=(('0.01', '0.01', ''),
157 ('0.05', '0.05', ''),
158 ('0.1', '0.1', ''),
159 ('0.2', '0.2', ''),
160 ('0.25', '0.25', ''),
161 ('0.5', '0.5', ''),
162 ('1', '1', ''),
163 ('2', '2', ''),
164 ('3', '3', ''),
165 ('4', '4', ''),
166 ('5', '5', ''),
167 ('10', '10', ''),
169 default='1',
172 @classmethod
173 def poll(cls, context):
174 obj = context.active_object
175 return (
176 obj is not None
177 and obj.type in {'MESH', 'CURVE', 'SURFACE', 'FONT'}
180 def execute(self, context):
181 start_time = time.time()
182 print('\n_____START_____')
183 props = self.properties
184 filepath = self.filepath
185 filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
187 exported = do_export(context, props, filepath)
189 if exported:
190 print('finished export in %s seconds' %
191 ((time.time() - start_time)))
192 print(filepath)
194 return {'FINISHED'}
196 def invoke(self, context, event):
197 wm = context.window_manager
199 if True:
200 # File selector
201 wm.fileselect_add(self) # will run self.execute()
202 return {'RUNNING_MODAL'}
203 elif True:
204 # search the enum
205 wm.invoke_search_popup(self)
206 return {'RUNNING_MODAL'}
207 elif False:
208 # Redo popup
209 return wm.invoke_props_popup(self, event)
210 elif False:
211 return self.execute(context)
214 def menu_func_export_button(self, context):
215 self.layout.operator(Export_pc2.bl_idname, text="Pointcache (.pc2)")
218 classes = [
219 Export_pc2,
223 def register():
224 for cls in classes:
225 bpy.utils.register_class(cls)
227 bpy.types.TOPBAR_MT_file_export.append(menu_func_export_button)
228 #bpy.types.VIEW3D_PT_tools_objectmode.prepend(menu_func_export_button)
231 def unregister():
232 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export_button)
233 #bpy.types.VIEW3D_PT_tools_objectmode.remove(menu_func_export_button)
234 for cls in classes:
235 bpy.utils.unregister_class(cls)
238 if __name__ == "__main__":
239 register()