Merging r39312 through r39329 from trunk into soc-2011-tomato
[blender.git] / release / scripts / startup / 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 Beware also about changing the order that these are defined
28 here, since this can result in old files referring to the
29 wrong Keying Set as the active one, potentially resulting
30 in lost (i.e. unkeyed) animation.
31 """
32
33 import bpy
34 import keyingsets_utils
35
36 ###############################
37 # Built-In KeyingSets
38
39
40 # Location
41 class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo):
42     bl_label = "Location"
43
44     # poll - use predefined callback for selected bones/objects
45     poll = keyingsets_utils.RKS_POLL_selected_items
46
47     # iterator - use callback for selected bones/objects
48     iterator = keyingsets_utils.RKS_ITER_selected_item
49
50     # generator - use callback for location
51     generate = keyingsets_utils.RKS_GEN_location
52
53
54 # Rotation
55 class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo):
56     bl_label = "Rotation"
57
58     # poll - use predefined callback for selected bones/objects
59     poll = keyingsets_utils.RKS_POLL_selected_items
60
61     # iterator - use callback for selected bones/objects
62     iterator = keyingsets_utils.RKS_ITER_selected_item
63
64     # generator - use callback for location
65     generate = keyingsets_utils.RKS_GEN_rotation
66
67
68 # Scale
69 class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo):
70     bl_label = "Scaling"
71
72     # poll - use predefined callback for selected bones/objects
73     poll = keyingsets_utils.RKS_POLL_selected_items
74
75     # iterator - use callback for selected bones/objects
76     iterator = keyingsets_utils.RKS_ITER_selected_item
77
78     # generator - use callback for location
79     generate = keyingsets_utils.RKS_GEN_scaling
80
81 # ------------
82
83
84 # LocRot
85 class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo):
86     bl_label = "LocRot"
87
88     # poll - use predefined callback for selected bones/objects
89     poll = keyingsets_utils.RKS_POLL_selected_items
90
91     # iterator - use callback for selected bones/objects
92     iterator = keyingsets_utils.RKS_ITER_selected_item
93
94     # generator
95     def generate(self, context, ks, data):
96         # location
97         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
98         # rotation
99         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
100
101
102 # LocScale
103 class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo):
104     bl_label = "LocScale"
105
106     # poll - use predefined callback for selected bones/objects
107     poll = keyingsets_utils.RKS_POLL_selected_items
108
109     # iterator - use callback for selected bones/objects
110     iterator = keyingsets_utils.RKS_ITER_selected_item
111
112     # generator
113     def generate(self, context, ks, data):
114         # location
115         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
116         # scale
117         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
118
119
120 # LocRotScale
121 class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo):
122     bl_label = "LocRotScale"
123
124     # poll - use predefined callback for selected bones/objects
125     poll = keyingsets_utils.RKS_POLL_selected_items
126
127     # iterator - use callback for selected bones/objects
128     iterator = keyingsets_utils.RKS_ITER_selected_item
129
130     # generator
131     def generate(self, context, ks, data):
132         # location
133         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
134         # rotation
135         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
136         # scale
137         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
138
139
140 # RotScale
141 class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
142     bl_label = "RotScale"
143
144     # poll - use predefined callback for selected bones/objects
145     poll = keyingsets_utils.RKS_POLL_selected_items
146
147     # iterator - use callback for selected bones/objects
148     iterator = keyingsets_utils.RKS_ITER_selected_item
149
150     # generator
151     def generate(self, context, ks, data):
152         # rotation
153         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
154         # scaling
155         keyingsets_utils.RKS_GEN_scaling(self, context, ks, data)
156
157 # ------------
158
159
160 # Location
161 class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo):
162     bl_label = "Visual Location"
163
164     bl_options = {'INSERTKEY_VISUAL'}
165
166     # poll - use predefined callback for selected bones/objects
167     poll = keyingsets_utils.RKS_POLL_selected_items
168
169     # iterator - use callback for selected bones/objects
170     iterator = keyingsets_utils.RKS_ITER_selected_item
171
172     # generator - use callback for location
173     generate = keyingsets_utils.RKS_GEN_location
174
175
176 # Rotation
177 class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo):
178     bl_label = "Visual Rotation"
179
180     bl_options = {'INSERTKEY_VISUAL'}
181
182     # poll - use predefined callback for selected bones/objects
183     poll = keyingsets_utils.RKS_POLL_selected_items
184
185     # iterator - use callback for selected bones/objects
186     iterator = keyingsets_utils.RKS_ITER_selected_item
187
188     # generator - use callback for rotation
189     generate = keyingsets_utils.RKS_GEN_rotation
190
191
192 # VisualLocRot
193 class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
194     bl_label = "Visual LocRot"
195
196     bl_options = {'INSERTKEY_VISUAL'}
197
198     # poll - use predefined callback for selected bones/objects
199     poll = keyingsets_utils.RKS_POLL_selected_items
200
201     # iterator - use callback for selected bones/objects
202     iterator = keyingsets_utils.RKS_ITER_selected_item
203
204     # generator
205     def generate(self, context, ks, data):
206         # location
207         keyingsets_utils.RKS_GEN_location(self, context, ks, data)
208         # rotation
209         keyingsets_utils.RKS_GEN_rotation(self, context, ks, data)
210
211 # ------------
212
213
214 # Available
215 class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo):
216     bl_label = "Available"
217
218     # poll - selected objects or selected object with animation data
219     def poll(ksi, context):
220         ob = context.active_object
221         if ob:
222             # TODO: this fails if one animation-less object is active, but many others are selected
223             return ob.animation_data and ob.animation_data.action
224         else:
225             return bool(context.selected_objects)
226
227     # iterator - use callback for selected bones/objects
228     iterator = keyingsets_utils.RKS_ITER_selected_item
229
230     # generator - use callback for doing this
231     generate = keyingsets_utils.RKS_GEN_available
232
233 ###############################
234
235
236 # All properties that are likely to get animated in a character rig
237 class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
238     bl_label = "Whole Character"
239
240     # these prefixes should be avoided, as they are not really bones
241     # that animators should be touching (or need to touch)
242     badBonePrefixes = (
243         'DEF',
244         'GEO',
245         'MCH',
246         'ORG',
247         'COR',
248         'VIS',
249         # ... more can be added here as you need in your own rigs ...
250     )
251
252     # poll - pose-mode on active object only
253     def poll(ksi, context):
254         return ((context.active_object) and (context.active_object.pose) and
255                 (context.active_object.mode == 'POSE'))
256
257     # iterator - all bones regardless of selection
258     def iterator(ksi, context, ks):
259         for bone in context.active_object.pose.bones:
260             if not bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
261                 ksi.generate(context, ks, bone)
262
263     # generator - all unlocked bone transforms + custom properties
264     def generate(ksi, context, ks, bone):
265         # loc, rot, scale - only include unlocked ones
266         ksi.doLoc(ks, bone)
267
268         if bone.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
269             ksi.doRot4d(ks, bone)
270         else:
271             ksi.doRot3d(ks, bone)
272         ksi.doScale(ks, bone)
273
274         # custom props?
275         ksi.doCustomProps(ks, bone)
276
277     # ----------------
278
279     # helper to add some bone's property to the Keying Set
280     def addProp(ksi, ks, bone, prop, index=-1, use_groups=True):
281         # add the property name to the base path
282         id_path = bone.path_from_id()
283         id_block = bone.id_data
284
285         if prop.startswith('['):
286             # custom properties
287             path = id_path + prop
288         else:
289             # standard transforms/properties
290             path = keyingsets_utils.path_add_property(id_path, prop)
291
292         # add Keying Set entry for this...
293         if use_groups:
294             ks.paths.add(id_block, path, index, group_method='NAMED', group_name=bone.name)
295         else:
296             ks.paths.add(id_block, path, index)
297
298     # ----------------
299
300     # location properties
301     def doLoc(ksi, ks, bone):
302         if bone.lock_location == (False, False, False):
303             ksi.addProp(ks, bone, "location")
304         else:
305             for i in range(3):
306                 if not bone.lock_location[i]:
307                     ksi.addProp(ks, bone, "location", i)
308
309     # rotation properties
310     def doRot4d(ksi, ks, bone):
311         # rotation mode affects the property used
312         if bone.rotation_mode == 'QUATERNION':
313             prop = "rotation_quaternion"
314         elif bone.rotation_mode == 'AXIS_ANGLE':
315             prop = "rotation_axis_angle"
316
317         # add rotation properties if they will
318         if bone.lock_rotations_4d:
319             # can check individually
320             if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w == False):
321                 ksi.addProp(ks, bone, prop)
322             else:
323                 if bone.lock_rotation_w == False:
324                     ksi.addProp(ks, bone, prop, 0)  # w = 0
325
326                 for i in range(3):
327                     if not bone.lock_rotation[i]:
328                         ksi.addProp(ks, bone, prop, i + 1)  # i + 1, since here x,y,z = 1,2,3, and w=0
329         elif True not in bone.lock_rotation:
330             # if axis-angle rotations get locked as eulers, then it's too messy to allow anything
331             # other than all open unless we keyframe the whole lot
332             ksi.addProp(ks, bone, prop)
333
334     def doRot3d(ksi, ks, bone):
335         if bone.lock_rotation == (False, False, False):
336             ksi.addProp(ks, bone, "rotation_euler")
337         else:
338             for i in range(3):
339                 if not bone.lock_rotation[i]:
340                     ksi.addProp(ks, bone, "rotation_euler", i)
341
342     # scale properties
343     def doScale(ksi, ks, bone):
344         if bone.lock_scale == (0, 0, 0):
345             ksi.addProp(ks, bone, "scale")
346         else:
347             for i in range(3):
348                 if not bone.lock_scale[i]:
349                     ksi.addProp(ks, bone, "scale", i)
350
351     # ----------------
352
353     # custom properties
354     def doCustomProps(ksi, ks, bone):
355         # go over all custom properties for bone
356         for prop, val in bone.items():
357             # ignore special "_RNA_UI" used for UI editing
358             if prop == "_RNA_UI":
359                 continue
360
361             # for now, just add all of 'em
362             ksi.addProp(ks, bone, '["%s"]' % (prop))
363
364 ###############################
365
366
367 # Delta Location
368 class BUILTIN_KSI_DeltaLocation(bpy.types.KeyingSetInfo):
369     bl_label = "Delta Location"
370
371     # poll - selected objects only (and only if active object in object mode)
372     poll = keyingsets_utils.RKS_POLL_selected_objects
373
374     # iterator - selected objects only
375     iterator = keyingsets_utils.RKS_ITER_selected_objects
376
377     # generator - delta location channels only
378     def generate(ksi, context, ks, data):
379         # get id-block and path info
380         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
381
382         # add the property name to the base path
383         path = keyingsets_utils.path_add_property(base_path, "delta_location")
384
385         # add Keying Set entry for this...
386         if grouping:
387             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
388         else:
389             ks.paths.add(id_block, path)
390
391
392 # Delta Rotation
393 class BUILTIN_KSI_DeltaRotation(bpy.types.KeyingSetInfo):
394     bl_label = "Delta Rotation"
395
396     # poll - selected objects only (and only if active object in object mode)
397     poll = keyingsets_utils.RKS_POLL_selected_objects
398
399     # iterator - selected objects only
400     iterator = keyingsets_utils.RKS_ITER_selected_objects
401
402     # generator - delta location channels only
403     def generate(ksi, context, ks, data):
404         # get id-block and path info
405         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
406
407         # add the property name to the base path
408         #   rotation mode affects the property used
409         if data.rotation_mode == 'QUATERNION':
410             path = keyingsets_utils.path_add_property(base_path, "delta_rotation_quaternion")
411         elif data.rotation_mode == 'AXIS_ANGLE':
412             # XXX: for now, this is not available yet
413             #path = path_add_property(base_path, "delta_rotation_axis_angle")
414             return
415         else:
416             path = keyingsets_utils.path_add_property(base_path, "delta_rotation_euler")
417
418         # add Keying Set entry for this...
419         if grouping:
420             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
421         else:
422             ks.paths.add(id_block, path)
423
424
425 # Delta Scale
426 class BUILTIN_KSI_DeltaScale(bpy.types.KeyingSetInfo):
427     bl_label = "Delta Scale"
428
429     # poll - selected objects only (and only if active object in object mode)
430     poll = keyingsets_utils.RKS_POLL_selected_objects
431
432     # iterator - selected objects only
433     iterator = keyingsets_utils.RKS_ITER_selected_objects
434
435     # generator - delta location channels only
436     def generate(ksi, context, ks, data):
437         # get id-block and path info
438         id_block, base_path, grouping = keyingsets_utils.get_transform_generators_base_info(data)
439
440         # add the property name to the base path
441         path = keyingsets_utils.path_add_property(base_path, "delta_scale")
442
443         # add Keying Set entry for this...
444         if grouping:
445             ks.paths.add(id_block, path, group_method='NAMED', group_name=grouping)
446         else:
447             ks.paths.add(id_block, path)
448
449 ###############################
450
451
452 def register():
453     bpy.utils.register_module(__name__)
454
455
456 def unregister():
457     bpy.utils.unregister_module(__name__)
458
459
460 if __name__ == "__main__":
461     register()