glTF exporter: fix wrong detection of basis SK
[blender-addons.git] / io_export_pc2.py
blob4dbe6b310bfc1ed70c958b518492f3c088bf4691
1 # SPDX-FileCopyrightText: 2010-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "Export Pointcache Format(.pc2)",
7 "author": "Florian Meyer (tstscr)",
8 "version": (1, 1, 2),
9 "blender": (2, 80, 0),
10 "location": "File > Export > Pointcache (.pc2)",
11 "description": "Export mesh Pointcache data (.pc2)",
12 "warning": "",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/pc2.html",
14 "category": "Import-Export",
17 """
18 Related links:
19 https://developer.blender.org/T34456
20 https://developer.blender.org/T25408
22 Usage Notes:
24 in Maya Mel:
25 cacheFile -pc2 1 -pcf "<insert filepath of source>" -f "<insert target filename w/o extension>" -dir "<insert directory path for target>" -format "OneFile";
27 """
29 import bpy
30 from bpy.props import BoolProperty, IntProperty, EnumProperty
31 import mathutils
32 from bpy_extras.io_utils import ExportHelper
34 from os import remove
35 import time
36 import math
37 import struct
40 def get_sampled_frames(start, end, sampling):
41 return [math.modf(start + x * sampling) for x in range(int((end - start) / sampling) + 1)]
44 def do_export(context, props, filepath):
45 mat_x90 = mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
46 ob = context.active_object
47 sc = context.scene
48 start = props.range_start
49 end = props.range_end
50 sampling = float(props.sampling)
51 apply_modifiers = props.apply_modifiers
52 depsgraph = None
53 if apply_modifiers:
54 depsgraph = context.evaluated_depsgraph_get()
55 me = ob.evaluated_get(depsgraph).to_mesh()
56 else:
57 me = ob.to_mesh()
58 vertCount = len(me.vertices)
59 sampletimes = get_sampled_frames(start, end, sampling)
60 sampleCount = len(sampletimes)
62 # Create the header
63 headerFormat = '<12siiffi'
64 headerStr = struct.pack(headerFormat, b'POINTCACHE2\0',
65 1, vertCount, start, sampling, sampleCount)
67 file = open(filepath, "wb")
68 file.write(headerStr)
70 for frame in sampletimes:
71 # stupid modf() gives decimal part first!
72 sc.frame_set(int(frame[1]), subframe=frame[0])
73 if apply_modifiers:
74 me = ob.evaluated_get(depsgraph).to_mesh()
75 else:
76 me = ob.to_mesh()
78 if len(me.vertices) != vertCount:
79 bpy.data.meshes.remove(me, do_unlink=True)
80 file.close()
81 try:
82 remove(filepath)
83 except:
84 empty = open(filepath, 'w')
85 empty.write('DUMMIFILE - export failed\n')
86 empty.close()
87 print('Export failed. Vertexcount of Object is not constant')
88 return False
90 if props.world_space:
91 me.transform(ob.matrix_world)
92 if props.rot_x90:
93 me.transform(mat_x90)
95 for v in me.vertices:
96 thisVertex = struct.pack('<fff', float(v.co[0]),
97 float(v.co[1]),
98 float(v.co[2]))
99 file.write(thisVertex)
101 if apply_modifiers:
102 ob.evaluated_get(depsgraph).to_mesh_clear()
103 else:
104 me = ob.to_mesh_clear()
106 file.flush()
107 file.close()
108 return True
111 # EXPORT OPERATOR
112 class Export_pc2(bpy.types.Operator, ExportHelper):
113 """Export the active Object as a .pc2 Pointcache file"""
114 bl_idname = "export_shape.pc2"
115 bl_label = "Export Pointcache (.pc2)"
117 filename_ext = ".pc2"
119 rot_x90: BoolProperty(
120 name="Convert to Y-up",
121 description="Rotate 90 degrees around X to convert to y-up",
122 default=True,)
123 world_space: BoolProperty(
124 name="Export into Worldspace",
125 description="Transform the Vertexcoordinates into Worldspace",
126 default=False,)
127 apply_modifiers: BoolProperty(
128 name="Apply Modifiers",
129 description="Applies the Modifiers",
130 default=True,)
131 range_start: IntProperty(
132 name='Start Frame',
133 description='First frame to use for Export',
134 default=1,)
135 range_end: IntProperty(
136 name='End Frame',
137 description='Last frame to use for Export',
138 default=250,)
139 sampling: EnumProperty(
140 name='Sampling',
141 description='Sampling --> frames per sample (0.1 yields 10 samples per frame)',
142 items=(('0.01', '0.01', ''),
143 ('0.05', '0.05', ''),
144 ('0.1', '0.1', ''),
145 ('0.2', '0.2', ''),
146 ('0.25', '0.25', ''),
147 ('0.5', '0.5', ''),
148 ('1', '1', ''),
149 ('2', '2', ''),
150 ('3', '3', ''),
151 ('4', '4', ''),
152 ('5', '5', ''),
153 ('10', '10', ''),
155 default='1',
158 @classmethod
159 def poll(cls, context):
160 obj = context.active_object
161 return (
162 obj is not None
163 and obj.type in {'MESH', 'CURVE', 'SURFACE', 'FONT'}
166 def execute(self, context):
167 start_time = time.time()
168 print('\n_____START_____')
169 props = self.properties
170 filepath = self.filepath
171 filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
173 exported = do_export(context, props, filepath)
175 if exported:
176 print('finished export in %s seconds' %
177 ((time.time() - start_time)))
178 print(filepath)
180 return {'FINISHED'}
182 def invoke(self, context, event):
183 wm = context.window_manager
185 if True:
186 # File selector
187 wm.fileselect_add(self) # will run self.execute()
188 return {'RUNNING_MODAL'}
189 elif True:
190 # search the enum
191 wm.invoke_search_popup(self)
192 return {'RUNNING_MODAL'}
193 elif False:
194 # Redo popup
195 return wm.invoke_props_popup(self, event)
196 elif False:
197 return self.execute(context)
200 def menu_func_export_button(self, context):
201 self.layout.operator(Export_pc2.bl_idname, text="Pointcache (.pc2)")
204 classes = [
205 Export_pc2,
209 def register():
210 for cls in classes:
211 bpy.utils.register_class(cls)
213 bpy.types.TOPBAR_MT_file_export.append(menu_func_export_button)
214 #bpy.types.VIEW3D_PT_tools_objectmode.prepend(menu_func_export_button)
217 def unregister():
218 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export_button)
219 #bpy.types.VIEW3D_PT_tools_objectmode.remove(menu_func_export_button)
220 for cls in classes:
221 bpy.utils.unregister_class(cls)
224 if __name__ == "__main__":
225 register()