Cleanup: io_import_BrushSet, autopep8, formatting
[blender-addons.git] / io_anim_bvh / __init__.py
blob918d8d8ed1d3a7e7aa2bcab28bab051fc68e0d3a
1 # SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "BioVision Motion Capture (BVH) format",
7 "author": "Campbell Barton",
8 "version": (1, 0, 1),
9 "blender": (2, 81, 6),
10 "location": "File > Import-Export",
11 "description": "Import-Export BVH from armature objects",
12 "warning": "",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/anim_bvh.html",
14 "support": 'OFFICIAL',
15 "category": "Import-Export",
18 if "bpy" in locals():
19 import importlib
20 if "import_bvh" in locals():
21 importlib.reload(import_bvh)
22 if "export_bvh" in locals():
23 importlib.reload(export_bvh)
25 import bpy
26 from bpy.props import (
27 StringProperty,
28 FloatProperty,
29 IntProperty,
30 BoolProperty,
31 EnumProperty,
33 from bpy_extras.io_utils import (
34 ImportHelper,
35 ExportHelper,
36 orientation_helper,
37 axis_conversion,
41 @orientation_helper(axis_forward='-Z', axis_up='Y')
42 class ImportBVH(bpy.types.Operator, ImportHelper):
43 """Load a BVH motion capture file"""
44 bl_idname = "import_anim.bvh"
45 bl_label = "Import BVH"
46 bl_options = {'REGISTER', 'UNDO'}
48 filename_ext = ".bvh"
49 filter_glob: StringProperty(default="*.bvh", options={'HIDDEN'})
51 target: EnumProperty(
52 items=(
53 ('ARMATURE', "Armature", ""),
54 ('OBJECT', "Object", ""),
56 name="Target",
57 description="Import target type",
58 default='ARMATURE',
60 global_scale: FloatProperty(
61 name="Scale",
62 description="Scale the BVH by this value",
63 min=0.0001, max=1000000.0,
64 soft_min=0.001, soft_max=100.0,
65 default=1.0,
67 frame_start: IntProperty(
68 name="Start Frame",
69 description="Starting frame for the animation",
70 default=1,
72 use_fps_scale: BoolProperty(
73 name="Scale FPS",
74 description=(
75 "Scale the framerate from the BVH to the current scenes, "
76 "otherwise each BVH frame maps directly to a Blender frame"
78 default=False,
80 update_scene_fps: BoolProperty(
81 name="Update Scene FPS",
82 description=(
83 "Set the scene framerate to that of the BVH file (note that this "
84 "nullifies the 'Scale FPS' option, as the scale will be 1:1)"
86 default=False,
88 update_scene_duration: BoolProperty(
89 name="Update Scene Duration",
90 description="Extend the scene's duration to the BVH duration (never shortens the scene)",
91 default=False,
93 use_cyclic: BoolProperty(
94 name="Loop",
95 description="Loop the animation playback",
96 default=False,
98 rotate_mode: EnumProperty(
99 name="Rotation",
100 description="Rotation conversion",
101 items=(
102 ('QUATERNION', "Quaternion",
103 "Convert rotations to quaternions"),
104 ('NATIVE', "Euler (Native)",
105 "Use the rotation order defined in the BVH file"),
106 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
107 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
108 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
109 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
110 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
111 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
113 default='NATIVE',
116 def execute(self, context):
117 keywords = self.as_keywords(
118 ignore=(
119 "axis_forward",
120 "axis_up",
121 "filter_glob",
124 global_matrix = axis_conversion(
125 from_forward=self.axis_forward,
126 from_up=self.axis_up,
127 ).to_4x4()
129 keywords["global_matrix"] = global_matrix
131 from . import import_bvh
132 return import_bvh.load(context, report=self.report, **keywords)
134 def draw(self, context):
135 pass
138 class BVH_PT_import_main(bpy.types.Panel):
139 bl_space_type = 'FILE_BROWSER'
140 bl_region_type = 'TOOL_PROPS'
141 bl_label = ""
142 bl_parent_id = "FILE_PT_operator"
143 bl_options = {'HIDE_HEADER'}
145 @classmethod
146 def poll(cls, context):
147 sfile = context.space_data
148 operator = sfile.active_operator
150 return operator.bl_idname == "IMPORT_ANIM_OT_bvh"
152 def draw(self, context):
153 layout = self.layout
154 layout.use_property_split = True
155 layout.use_property_decorate = False # No animation.
157 sfile = context.space_data
158 operator = sfile.active_operator
160 layout.prop(operator, "target")
163 class BVH_PT_import_transform(bpy.types.Panel):
164 bl_space_type = 'FILE_BROWSER'
165 bl_region_type = 'TOOL_PROPS'
166 bl_label = "Transform"
167 bl_parent_id = "FILE_PT_operator"
169 @classmethod
170 def poll(cls, context):
171 sfile = context.space_data
172 operator = sfile.active_operator
174 return operator.bl_idname == "IMPORT_ANIM_OT_bvh"
176 def draw(self, context):
177 layout = self.layout
178 layout.use_property_split = True
179 layout.use_property_decorate = False # No animation.
181 sfile = context.space_data
182 operator = sfile.active_operator
184 layout.prop(operator, "global_scale")
185 layout.prop(operator, "rotate_mode")
186 layout.prop(operator, "axis_forward")
187 layout.prop(operator, "axis_up")
190 class BVH_PT_import_animation(bpy.types.Panel):
191 bl_space_type = 'FILE_BROWSER'
192 bl_region_type = 'TOOL_PROPS'
193 bl_label = "Animation"
194 bl_parent_id = "FILE_PT_operator"
196 @classmethod
197 def poll(cls, context):
198 sfile = context.space_data
199 operator = sfile.active_operator
201 return operator.bl_idname == "IMPORT_ANIM_OT_bvh"
203 def draw(self, context):
204 layout = self.layout
205 layout.use_property_split = True
206 layout.use_property_decorate = False # No animation.
208 sfile = context.space_data
209 operator = sfile.active_operator
211 layout.prop(operator, "frame_start")
212 layout.prop(operator, "use_fps_scale")
213 layout.prop(operator, "use_cyclic")
215 layout.prop(operator, "update_scene_fps")
216 layout.prop(operator, "update_scene_duration")
219 class ExportBVH(bpy.types.Operator, ExportHelper):
220 """Save a BVH motion capture file from an armature"""
221 bl_idname = "export_anim.bvh"
222 bl_label = "Export BVH"
224 filename_ext = ".bvh"
225 filter_glob: StringProperty(
226 default="*.bvh",
227 options={'HIDDEN'},
230 global_scale: FloatProperty(
231 name="Scale",
232 description="Scale the BVH by this value",
233 min=0.0001, max=1000000.0,
234 soft_min=0.001, soft_max=100.0,
235 default=1.0,
237 frame_start: IntProperty(
238 name="Start Frame",
239 description="Starting frame to export",
240 default=0,
242 frame_end: IntProperty(
243 name="End Frame",
244 description="End frame to export",
245 default=0,
247 rotate_mode: EnumProperty(
248 name="Rotation",
249 description="Rotation conversion",
250 items=(
251 ('NATIVE', "Euler (Native)",
252 "Use the rotation order defined in the BVH file"),
253 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
254 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
255 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
256 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
257 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
258 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
260 default='NATIVE',
262 root_transform_only: BoolProperty(
263 name="Root Translation Only",
264 description="Only write out translation channels for the root bone",
265 default=False,
268 @classmethod
269 def poll(cls, context):
270 obj = context.object
271 return obj and obj.type == 'ARMATURE'
273 def invoke(self, context, event):
274 self.frame_start = context.scene.frame_start
275 self.frame_end = context.scene.frame_end
277 return super().invoke(context, event)
279 def execute(self, context):
280 if self.frame_start == 0 and self.frame_end == 0:
281 self.frame_start = context.scene.frame_start
282 self.frame_end = context.scene.frame_end
284 keywords = self.as_keywords(
285 ignore=(
286 "axis_forward",
287 "axis_up",
288 "check_existing",
289 "filter_glob",
293 from . import export_bvh
294 return export_bvh.save(context, **keywords)
296 def draw(self, context):
297 pass
300 class BVH_PT_export_transform(bpy.types.Panel):
301 bl_space_type = 'FILE_BROWSER'
302 bl_region_type = 'TOOL_PROPS'
303 bl_label = "Transform"
304 bl_parent_id = "FILE_PT_operator"
306 @classmethod
307 def poll(cls, context):
308 sfile = context.space_data
309 operator = sfile.active_operator
311 return operator.bl_idname == "EXPORT_ANIM_OT_bvh"
313 def draw(self, context):
314 layout = self.layout
315 layout.use_property_split = True
316 layout.use_property_decorate = False # No animation.
318 sfile = context.space_data
319 operator = sfile.active_operator
321 layout.prop(operator, "global_scale")
322 layout.prop(operator, "rotate_mode")
323 layout.prop(operator, "root_transform_only")
326 class BVH_PT_export_animation(bpy.types.Panel):
327 bl_space_type = 'FILE_BROWSER'
328 bl_region_type = 'TOOL_PROPS'
329 bl_label = "Animation"
330 bl_parent_id = "FILE_PT_operator"
332 @classmethod
333 def poll(cls, context):
334 sfile = context.space_data
335 operator = sfile.active_operator
337 return operator.bl_idname == "EXPORT_ANIM_OT_bvh"
339 def draw(self, context):
340 layout = self.layout
341 layout.use_property_split = True
342 layout.use_property_decorate = False # No animation.
344 sfile = context.space_data
345 operator = sfile.active_operator
347 col = layout.column(align=True)
348 col.prop(operator, "frame_start", text="Frame Start")
349 col.prop(operator, "frame_end", text="End")
352 def menu_func_import(self, context):
353 self.layout.operator(ImportBVH.bl_idname, text="Motion Capture (.bvh)")
356 def menu_func_export(self, context):
357 self.layout.operator(ExportBVH.bl_idname, text="Motion Capture (.bvh)")
360 classes = (
361 ImportBVH,
362 BVH_PT_import_main,
363 BVH_PT_import_transform,
364 BVH_PT_import_animation,
365 ExportBVH,
366 BVH_PT_export_transform,
367 BVH_PT_export_animation,
371 def register():
372 for cls in classes:
373 bpy.utils.register_class(cls)
375 bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
376 bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
379 def unregister():
380 for cls in classes:
381 bpy.utils.unregister_class(cls)
383 bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
384 bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
387 if __name__ == "__main__":
388 register()