Cleanup: BVH import/export
[blender-addons.git] / io_anim_bvh / __init__.py
blob4a4983ffa0110f6ca954a693b1c6130406e9ed2b
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 # <pep8-80 compliant>
21 bl_info = {
22 "name": "BioVision Motion Capture (BVH) format",
23 "author": "Campbell Barton",
24 "version": (1, 0, 0),
25 "blender": (2, 74, 0),
26 "location": "File > Import-Export",
27 "description": "Import-Export BVH from armature objects",
28 "warning": "",
29 "wiki_url": (
30 "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
31 "Scripts/Import-Export/BVH_Importer_Exporter"
33 "support": 'OFFICIAL',
34 "category": "Import-Export",
37 if "bpy" in locals():
38 import importlib
39 if "import_bvh" in locals():
40 importlib.reload(import_bvh)
41 if "export_bvh" in locals():
42 importlib.reload(export_bvh)
44 import bpy
45 from bpy.props import (
46 StringProperty,
47 FloatProperty,
48 IntProperty,
49 BoolProperty,
50 EnumProperty,
52 from bpy_extras.io_utils import (
53 ImportHelper,
54 ExportHelper,
55 orientation_helper_factory,
56 axis_conversion,
60 ImportBVHOrientationHelper = orientation_helper_factory("ImportBVHOrientationHelper", axis_forward='-Z', axis_up='Y')
63 class ImportBVH(bpy.types.Operator, ImportHelper, ImportBVHOrientationHelper):
64 """Load a BVH motion capture file"""
65 bl_idname = "import_anim.bvh"
66 bl_label = "Import BVH"
67 bl_options = {'REGISTER', 'UNDO'}
69 filename_ext = ".bvh"
70 filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
72 target = EnumProperty(
73 items=(
74 ('ARMATURE', "Armature", ""),
75 ('OBJECT', "Object", ""),
77 name="Target",
78 description="Import target type",
79 default='ARMATURE',
82 global_scale = FloatProperty(
83 name="Scale",
84 description="Scale the BVH by this value",
85 min=0.0001, max=1000000.0,
86 soft_min=0.001, soft_max=100.0,
87 default=1.0,
89 frame_start = IntProperty(
90 name="Start Frame",
91 description="Starting frame for the animation",
92 default=1,
94 use_fps_scale = BoolProperty(
95 name="Scale FPS",
96 description=(
97 "Scale the framerate from the BVH to the current scenes, "
98 "otherwise each BVH frame maps directly to a Blender frame"
100 default=False,
102 update_scene_fps = BoolProperty(
103 name="Update Scene FPS",
104 description=(
105 "Set the scene framerate to that of the BVH file (note that this "
106 "nullifies the 'Scale FPS' option, as the scale will be 1:1)"
108 default=False
110 update_scene_duration = BoolProperty(
111 name="Update Scene Duration",
112 description="Extend the scene's duration to the BVH duration (never shortens the scene)",
113 default=False,
115 use_cyclic = BoolProperty(
116 name="Loop",
117 description="Loop the animation playback",
118 default=False,
120 rotate_mode = EnumProperty(
121 name="Rotation",
122 description="Rotation conversion",
123 items=(
124 ('QUATERNION', "Quaternion",
125 "Convert rotations to quaternions"),
126 ('NATIVE', "Euler (Native)",
127 "Use the rotation order defined in the BVH file"),
128 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
129 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
130 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
131 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
132 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
133 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
135 default='NATIVE',
138 def execute(self, context):
139 keywords = self.as_keywords(
140 ignore=(
141 "axis_forward",
142 "axis_up",
143 "filter_glob",
147 global_matrix = axis_conversion(
148 from_forward=self.axis_forward,
149 from_up=self.axis_up,
150 ).to_4x4()
152 keywords["global_matrix"] = global_matrix
154 from . import import_bvh
155 return import_bvh.load(context, report=self.report, **keywords)
158 class ExportBVH(bpy.types.Operator, ExportHelper):
159 """Save a BVH motion capture file from an armature"""
160 bl_idname = "export_anim.bvh"
161 bl_label = "Export BVH"
163 filename_ext = ".bvh"
164 filter_glob = StringProperty(
165 default="*.bvh",
166 options={'HIDDEN'},
169 global_scale = FloatProperty(
170 name="Scale",
171 description="Scale the BVH by this value",
172 min=0.0001, max=1000000.0,
173 soft_min=0.001, soft_max=100.0,
174 default=1.0,
176 frame_start = IntProperty(
177 name="Start Frame",
178 description="Starting frame to export",
179 default=0,
181 frame_end = IntProperty(
182 name="End Frame",
183 description="End frame to export",
184 default=0,
186 rotate_mode = EnumProperty(
187 name="Rotation",
188 description="Rotation conversion",
189 items=(
190 ('NATIVE', "Euler (Native)",
191 "Use the rotation order defined in the BVH file"),
192 ('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
193 ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
194 ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
195 ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
196 ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
197 ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
199 default='NATIVE',
201 root_transform_only = BoolProperty(
202 name="Root Translation Only",
203 description="Only write out translation channels for the root bone",
204 default=False,
207 @classmethod
208 def poll(cls, context):
209 obj = context.object
210 return obj and obj.type == 'ARMATURE'
212 def invoke(self, context, event):
213 self.frame_start = context.scene.frame_start
214 self.frame_end = context.scene.frame_end
216 return super().invoke(context, event)
218 def execute(self, context):
219 if self.frame_start == 0 and self.frame_end == 0:
220 self.frame_start = context.scene.frame_start
221 self.frame_end = context.scene.frame_end
223 keywords = self.as_keywords(ignore=("check_existing", "filter_glob"))
225 from . import export_bvh
226 return export_bvh.save(context, **keywords)
229 def menu_func_import(self, context):
230 self.layout.operator(ImportBVH.bl_idname, text="Motion Capture (.bvh)")
233 def menu_func_export(self, context):
234 self.layout.operator(ExportBVH.bl_idname, text="Motion Capture (.bvh)")
237 def register():
238 bpy.utils.register_module(__name__)
240 bpy.types.INFO_MT_file_import.append(menu_func_import)
241 bpy.types.INFO_MT_file_export.append(menu_func_export)
244 def unregister():
245 bpy.utils.unregister_module(__name__)
247 bpy.types.INFO_MT_file_import.remove(menu_func_import)
248 bpy.types.INFO_MT_file_export.remove(menu_func_export)
251 if __name__ == "__main__":
252 register()