replace import *'s with named imports (using * is convenient for some scripts but...
[blender.git] / release / scripts / keyingsets / keyingsets_builtins.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
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.
7 #
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.
12 #
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.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19 # <pep8 compliant>
20
21 """
22 Built-In Keying Sets
23 None of these Keying Sets should be removed, as these
24 are needed by various parts of Blender in order for them
25 to work correctly.
26 """
27
28 import bpy
29 import keyingsets_utils
30
31 ###############################
32 # Built-In KeyingSets
33
34
35 # Location
36 class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo):
37     bl_label = "Location"
38
39     # poll - use predefined callback for selected bones/objects
40     poll = keyingsets_utils.RKS_POLL_selected_items
41
42     # iterator - use callback for selected bones/objects
43     iterator = keyingsets_utils.RKS_ITER_selected_item
44
45     # generator - use callback for location
46     generate = keyingsets_utils.RKS_GEN_location
47
48
49 # Rotation
50 class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo):
51     bl_label = "Rotation"
52
53     # poll - use predefined callback for selected bones/objects
54     poll = keyingsets_utils.RKS_POLL_selected_items
55
56     # iterator - use callback for selected bones/objects
57     iterator = keyingsets_utils.RKS_ITER_selected_item
58
59     # generator - use callback for location
60     generate = keyingsets_utils.RKS_GEN_rotation
61
62
63 # Scale
64 class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo):
65     bl_label = "Scaling"
66
67     # poll - use predefined callback for selected bones/objects
68     poll = keyingsets_utils.RKS_POLL_selected_items
69
70     # iterator - use callback for selected bones/objects
71     iterator = keyingsets_utils.RKS_ITER_selected_item
72
73     # generator - use callback for location
74     generate = keyingsets_utils.RKS_GEN_scaling
75
76 # ------------
77
78
79 # LocRot
80 class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo):
81     bl_label = "LocRot"
82
83     # poll - use predefined callback for selected bones/objects
84     poll = keyingsets_utils.RKS_POLL_selected_items
85
86     # iterator - use callback for selected bones/objects
87     iterator = keyingsets_utils.RKS_ITER_selected_item
88
89     # generator
90     def generate(self, context, ks, data):
91         # location
92         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
93         # rotation
94         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
95
96
97 # LocScale
98 class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo):
99     bl_label = "LocScale"
100
101     # poll - use predefined callback for selected bones/objects
102     poll = keyingsets_utils.RKS_POLL_selected_items
103
104     # iterator - use callback for selected bones/objects
105     iterator = keyingsets_utils.RKS_ITER_selected_item
106
107     # generator
108     def generate(self, context, ks, data):
109         # location
110         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
111         # scale
112         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
113
114
115 # LocRotScale
116 class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo):
117     bl_label = "LocRotScale"
118
119     # poll - use predefined callback for selected bones/objects
120     poll = keyingsets_utils.RKS_POLL_selected_items
121
122     # iterator - use callback for selected bones/objects
123     iterator = keyingsets_utils.RKS_ITER_selected_item
124
125     # generator
126     def generate(self, context, ks, data):
127         # location
128         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
129         # rotation
130         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
131         # scale
132         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
133
134
135 # RotScale
136 class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
137     bl_label = "RotScale"
138
139     # poll - use predefined callback for selected bones/objects
140     poll = keyingsets_utils.RKS_POLL_selected_items
141
142     # iterator - use callback for selected bones/objects
143     iterator = keyingsets_utils.RKS_ITER_selected_item
144
145     # generator
146     def generate(self, context, ks, data):
147         # rotation
148         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
149         # scaling
150         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
151
152 # ------------
153
154
155 # Location
156 class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo):
157     bl_label = "Visual Location"
158
159     bl_options = {'INSERTKEY_VISUAL'}
160
161     # poll - use predefined callback for selected bones/objects
162     poll = keyingsets_utils.RKS_POLL_selected_items
163
164     # iterator - use callback for selected bones/objects
165     iterator = keyingsets_utils.RKS_ITER_selected_item
166
167     # generator - use callback for location
168     generate = keyingsets_utils.RKS_GEN_location
169
170
171 # Rotation
172 class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo):
173     bl_label = "Visual Rotation"
174
175     bl_options = {'INSERTKEY_VISUAL'}
176
177     # poll - use predefined callback for selected bones/objects
178     poll = keyingsets_utils.RKS_POLL_selected_items
179
180     # iterator - use callback for selected bones/objects
181     iterator = keyingsets_utils.RKS_ITER_selected_item
182
183     # generator - use callback for rotation
184     generate = keyingsets_utils.RKS_GEN_rotation
185
186
187 # VisualLocRot
188 class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
189     bl_label = "Visual LocRot"
190
191     bl_options = {'INSERTKEY_VISUAL'}
192
193     # poll - use predefined callback for selected bones/objects
194     poll = keyingsets_utils.RKS_POLL_selected_items
195
196     # iterator - use callback for selected bones/objects
197     iterator = keyingsets_utils.RKS_ITER_selected_item
198
199     # generator
200     def generate(self, context, ks, data):
201         # location
202         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
203         # rotation
204         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
205
206 # ------------
207
208
209 # Available
210 class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo):
211     bl_label = "Available"
212
213     # poll - use predefined callback for selected objects
214     # TODO: this should really check whether the selected object (or datablock)
215     #         has any animation data defined yet
216     poll = keyingsets_utils.RKS_POLL_selected_objects
217
218     # iterator - use callback for selected bones/objects
219     iterator = keyingsets_utils.RKS_ITER_selected_item
220
221     # generator - use callback for doing this
222     generate = keyingsets_utils.RKS_GEN_available
223
224 ###############################
225
226
227 # All properties that are likely to get animated in a character rig
228 class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
229     bl_label = "Whole Character"
230
231     # these prefixes should be avoided, as they are not really bones
232     # that animators should be touching (or need to touch)
233     badBonePrefixes = (
234         'DEF',
235         'GEO',
236         'MCH',
237         'ORG',
238         'COR',
239         'VIS',
240         # ... more can be added here as you need in your own rigs ...
241     )
242
243     # poll - pose-mode on active object only
244     def poll(ksi, context):
245         return ((context.active_object) and (context.active_object.pose) and
246                 (context.active_object.mode == 'POSE'))
247
248     # iterator - all bones regardless of selection
249     def iterator(ksi, context, ks):
250         for bone in context.active_object.pose.bones:
251             if not bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
252                 ksi.generate(context, ks, bone)
253
254     # generator - all unlocked bone transforms + custom properties
255     def generate(ksi, context, ks, bone):
256         # loc, rot, scale - only include unlocked ones
257         ksi.doLoc(ks, bone)
258
259         if bone.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
260             ksi.doRot4d(ks, bone)
261         else:
262             ksi.doRot3d(ks, bone)
263         ksi.doScale(ks, bone)
264
265         # custom props?
266         ksi.doCustomProps(ks, bone)
267
268     # ----------------
269
270     # helper to add some bone's property to the Keying Set
271     def addProp(ksi, ks, bone, prop, index=-1, use_groups=True):
272         # add the property name to the base path
273         id_path = bone.path_from_id()
274         id_block = bone.id_data
275
276         if prop.startswith('['):
277             # custom properties
278             path = id_path + prop
279         else:
280             # standard transforms/properties
281             path = keyingsets_utils.path_add_property(id_path, prop)
282
283         # add Keying Set entry for this...
284         if use_groups:
285             ks.paths.add(id_block, path, index, group_method='NAMED', group_name=bone.name)
286         else:
287             ks.paths.add(id_block, path, index)
288
289     # ----------------
290
291     # location properties
292     def doLoc(ksi, ks, bone):
293         if bone.lock_location == (False, False, False):
294             ksi.addProp(ks, bone, "location")
295         else:
296             for i in range(3):
297                 if not bone.lock_location[i]:
298                     ksi.addProp(ks, bone, "location", i)
299
300     # rotation properties
301     def doRot4d(ksi, ks, bone):
302         # rotation mode affects the property used
303         if bone.rotation_mode == 'QUATERNION':
304             prop = "rotation_quaternion"
305         elif bone.rotation_mode == 'AXIS_ANGLE':
306             prop = "rotation_axis_angle"
307
308         # add rotation properties if they will
309         if bone.lock_rotations_4d:
310             # can check individually
311             if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w == False):
312                 ksi.addProp(ks, bone, prop)
313             else:
314                 if bone.lock_rotation_w == False:
315                     ksi.addProp(ks, bone, prop, 0)  # w = 0
316
317                 for i in range(3):
318                     if not bone.lock_rotation[i]:
319                         ksi.addProp(ks, bone, prop, i + 1)  # i + 1, since here x,y,z = 1,2,3, and w=0
320         elif True not in bone.lock_rotation:
321             # if axis-angle rotations get locked as eulers, then it's too messy to allow anything
322             # other than all open unless we keyframe the whole lot
323             ksi.addProp(ks, bone, prop)
324
325     def doRot3d(ksi, ks, bone):
326         if bone.lock_rotation == (False, False, False):
327             ksi.addProp(ks, bone, "rotation_euler")
328         else:
329             for i in range(3):
330                 if not bone.lock_rotation[i]:
331                     ksi.addProp(ks, bone, "rotation_euler", i)
332
333     # scale properties
334     def doScale(ksi, ks, bone):
335         if bone.lock_scale == (0, 0, 0):
336             ksi.addProp(ks, bone, "scale")
337         else:
338             for i in range(3):
339                 if not bone.lock_scale[i]:
340                     ksi.addProp(ks, bone, "scale", i)
341
342     # ----------------
343
344     # custom properties
345     def doCustomProps(ksi, ks, bone):
346         # go over all custom properties for bone
347         for prop, val in bone.items():
348             # ignore special "_RNA_UI" used for UI editing
349             if prop == "_RNA_UI":
350                 continue
351
352             # for now, just add all of 'em
353             ksi.addProp(ks, bone, '["%s"]' % (prop))
354
355
356 def register():
357     bpy.utils.register_module(__name__)
358
359
360 def unregister():
361     bpy.utils.unregister_module(__name__)
362
363
364 if __name__ == "__main__":
365     register()