animation_animall: return to release: T68332 T63750 e6a1dfbe53be
[blender-addons.git] / animation_animall.py
blobb2f655ce3515d611e90f4679fb4bb633ccad6297
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 bl_info = {
20 "name": "AnimAll",
21 "author": "Daniel Salazar <zanqdo@gmail.com>",
22 "version": (0, 8, 2),
23 "blender": (2, 80, 0),
24 "location": "3D View > Toolbox > Animation tab > AnimAll",
25 "description": "Allows animation of mesh, lattice, curve and surface data",
26 "warning": "",
27 "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
28 "Scripts/Animation/AnimAll",
29 "category": "Animation",
32 """
33 Thanks to Campbell Barton and Joshua Leung for hes API additions and fixes
34 Daniel 'ZanQdo' Salazar
35 """
37 import bpy
38 from bpy.types import (
39 Operator,
40 Panel,
41 AddonPreferences,
43 from bpy.props import (
44 BoolProperty,
45 StringProperty,
49 # Property Definitions
50 class AnimallProperties(bpy.types.PropertyGroup):
51 key_selected: BoolProperty(
52 name="Selected Only",
53 description="Insert keyframes only on selected elements",
54 default=True
56 key_shape: BoolProperty(
57 name="Shape",
58 description="Insert keyframes on active Shape Key layer",
59 default=False
61 key_uvs: BoolProperty(
62 name="UVs",
63 description="Insert keyframes on active UV coordinates",
64 default=False
66 key_ebevel: BoolProperty(
67 name="E-Bevel",
68 description="Insert keyframes on edge bevel weight",
69 default=False
71 key_vbevel: BoolProperty(
72 name="V-Bevel",
73 description="Insert keyframes on vertex bevel weight",
74 default=False
76 key_crease: BoolProperty(
77 name="Crease",
78 description="Insert keyframes on edge creases",
79 default=False
81 key_vcols: BoolProperty(
82 name="V-Cols",
83 description="Insert keyframes on active Vertex Color values",
84 default=False
86 key_vgroups: BoolProperty(
87 name="V-groups",
88 description="Insert keyframes on active Vertex group values",
89 default=False
91 key_points: BoolProperty(
92 name="Points",
93 description="Insert keyframes on point locations",
94 default=False
96 key_radius: BoolProperty(
97 name="Radius",
98 description="Insert keyframes on point radius (Shrink/Fatten)",
99 default=False
101 key_tilt: BoolProperty(
102 name="Tilt",
103 description="Insert keyframes on point tilt",
104 default=False
108 # Utility functions
110 def refresh_ui_keyframes():
111 try:
112 for area in bpy.context.screen.areas:
113 if area.type in ('TIMELINE', 'GRAPH_EDITOR', 'DOPESHEET_EDITOR'):
114 area.tag_redraw()
115 except:
116 pass
119 def insert_key(data, key, group=''):
120 try:
121 data.keyframe_insert(key, group=group)
122 except:
123 pass
126 def delete_key(data, key):
127 try:
128 data.keyframe_delete(key)
129 except:
130 pass
133 # GUI (Panel)
135 class VIEW3D_PT_animall(Panel):
136 bl_space_type = 'VIEW_3D'
137 bl_region_type = 'UI'
138 bl_category = "Animation"
139 bl_label = 'AnimAll'
141 @classmethod
142 def poll(self, context):
143 return context.active_object and context.active_object.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}
145 def draw(self, context):
146 obj = context.active_object
147 animall_properties = context.window_manager.animall_properties
149 layout = self.layout
150 col = layout.column(align=True)
151 row = col.row()
152 row.prop(animall_properties, "key_selected")
153 col.separator()
155 row = col.row()
157 if obj.type == 'LATTICE':
158 row.prop(animall_properties, "key_points")
159 row.prop(animall_properties, "key_shape")
161 elif obj.type == 'MESH':
162 row.prop(animall_properties, "key_points")
163 row.prop(animall_properties, "key_shape")
164 row = col.row()
165 row.prop(animall_properties, "key_ebevel")
166 row.prop(animall_properties, "key_vbevel")
167 row = col.row()
168 row.prop(animall_properties, "key_crease")
169 row.prop(animall_properties, "key_uvs")
170 row = col.row()
171 row.prop(animall_properties, "key_vcols")
172 row.prop(animall_properties, "key_vgroups")
174 elif obj.type == 'CURVE':
175 row.prop(animall_properties, "key_points")
176 row.prop(animall_properties, "key_shape")
177 row = col.row()
178 row.prop(animall_properties, "key_radius")
179 row.prop(animall_properties, "key_tilt")
181 elif obj.type == 'SURFACE':
182 row.prop(animall_properties, "key_points")
183 row.prop(animall_properties, "key_shape")
184 row = col.row()
185 row.prop(animall_properties, "key_radius")
186 row.prop(animall_properties, "key_tilt")
188 layout.separator()
189 row = layout.row(align=True)
190 row.operator("anim.insert_keyframe_animall", icon="KEY_HLT")
191 row.operator("anim.delete_keyframe_animall", icon="KEY_DEHLT")
192 row = layout.row()
193 row.operator("anim.clear_animation_animall", icon="X")
195 if animall_properties.key_shape:
196 shape_key = obj.active_shape_key
197 shape_key_index = obj.active_shape_key_index
199 split = layout.split()
200 row = split.row()
202 if shape_key_index > 0:
203 row.label(text=shape_key.name, icon="SHAPEKEY_DATA")
204 row.prop(shape_key, "value", text="")
205 row.prop(obj, "show_only_shape_key", text="")
206 if shape_key.value < 1:
207 row = layout.row()
208 row.label(text='Maybe set "%s" to 1.0?' % shape_key.name, icon="INFO")
209 elif shape_key:
210 row.label(text="Cannot key on Basis Shape", icon="ERROR")
211 else:
212 row.label(text="No active Shape Key", icon="ERROR")
214 if animall_properties.key_points and animall_properties.key_shape:
215 row = layout.row()
216 row.label(text='"Points" and "Shape" are redundant?', icon="INFO")
219 class ANIM_OT_insert_keyframe_animall(Operator):
220 bl_label = "Insert"
221 bl_idname = "anim.insert_keyframe_animall"
222 bl_description = "Insert a Keyframe"
223 bl_options = {'REGISTER', 'UNDO'}
225 def invoke(self, context, event):
226 self.execute(context)
228 return {'FINISHED'}
230 def execute(op, context):
231 obj = context.active_object
232 animall_properties = context.window_manager.animall_properties
234 # Maybe this should be done for all object types,
235 # but keys can only be inserted in Edit Mode for CURVEs and SURFACEs,
236 # and Object Mode for MESHes and LATTICEs.
237 # Putting it inside if blocks for now
238 # # Set object mode
239 # if obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}:
240 # mode = obj.mode
241 # bpy.ops.object.mode_set(mode='OBJECT')
242 # data = obj.data
244 if obj.type == 'MESH':
245 mode = obj.mode
246 bpy.ops.object.mode_set(mode='OBJECT')
247 data = obj.data
249 if animall_properties.key_points:
250 for v_i, vert in enumerate(data.vertices):
251 if not animall_properties.key_selected or vert.select:
252 insert_key(vert, 'co', group="vertex %s" % v_i)
254 if animall_properties.key_vbevel:
255 for v_i, vert in enumerate(data.vertices):
256 if not animall_properties.key_selected or vert.select:
257 insert_key(vert, 'bevel_weight', group="vertex %s" % v_i)
259 if animall_properties.key_vgroups:
260 for v_i, vert in enumerate(data.vertices):
261 if not animall_properties.key_selected or vert.select:
262 for group in vert.groups:
263 insert_key(group, 'weight', group="vertex %s" % v_i)
265 if animall_properties.key_ebevel:
266 for e_i, edge in enumerate(data.edges):
267 if not animall_properties.key_selected or edge.select:
268 insert_key(edge, 'bevel_weight', group="edge %s" % e_i)
270 if animall_properties.key_crease:
271 for e_i, edge in enumerate(data.edges):
272 if not animall_properties.key_selected or edge.select:
273 insert_key(edge, 'crease', group="edge %s" % e_i)
275 if animall_properties.key_shape:
276 if obj.active_shape_key_index > 0:
277 for v_i, vert in enumerate(obj.active_shape_key.data):
278 insert_key(vert, 'co', group="vertex %s" % v_i)
280 if animall_properties.key_uvs:
281 if data.uv_layers.active is not None:
282 for uv_i, uv in enumerate(data.uv_layers.active.data):
283 insert_key(uv, 'uv', group="UV layer %s" % uv_i)
285 if animall_properties.key_vcols:
286 for v_col_layer in data.vertex_colors:
287 if v_col_layer.active: # only insert in active VCol layer
288 for v_i, data in enumerate(v_col_layer.data):
289 insert_key(data, 'color', group="Loop %s" % v_i)
291 bpy.ops.object.mode_set(mode=mode)
293 elif obj.type == 'LATTICE':
294 mode = obj.mode
295 bpy.ops.object.mode_set(mode='OBJECT')
296 data = obj.data
298 if animall_properties.key_shape:
299 if obj.active_shape_key_index > 0:
300 for p_i, point in enumerate(obj.active_shape_key.data):
301 insert_key(point, 'co', group="Point %s" % p_i)
303 if animall_properties.key_points:
304 for p_i, point in enumerate(data.points):
305 if not animall_properties.key_selected or point.select:
306 insert_key(point, 'co_deform', group="Point %s" % p_i)
308 bpy.ops.object.mode_set(mode=mode)
310 elif obj.type in {'CURVE', 'SURFACE'}:
311 data = obj.data
313 # run this outside the splines loop (only once)
314 if animall_properties.key_shape:
315 if obj.active_shape_key_index > 0:
316 for CV in obj.active_shape_key.data:
317 insert_key(CV, 'co')
318 insert_key(CV, 'handle_left')
319 insert_key(CV, 'handle_right')
321 for s_i, spline in enumerate(data.splines):
322 if spline.type == 'BEZIER':
323 for v_i, CV in enumerate(spline.bezier_points):
324 if (not animall_properties.key_selected
325 or CV.select_control_point
326 or CV.select_left_handle
327 or CV.select_right_handle):
328 if animall_properties.key_points:
329 insert_key(CV, 'co', group="spline %s CV %s" % (s_i, v_i))
330 insert_key(CV, 'handle_left', group="spline %s CV %s" % (s_i, v_i))
331 insert_key(CV, 'handle_right', group="spline %s CV %s" % (s_i, v_i))
333 if animall_properties.key_radius:
334 insert_key(CV, 'radius', group="spline %s CV %s" % (s_i, v_i))
336 if animall_properties.key_tilt:
337 insert_key(CV, 'tilt', group="spline %s CV %s" % (s_i, v_i))
339 elif spline.type in ('POLY', 'NURBS'):
340 for v_i, CV in enumerate(spline.points):
341 if not animall_properties.key_selected or CV.select:
342 if animall_properties.key_points:
343 insert_key(CV, 'co', group="spline %s CV %s" % (s_i, v_i))
345 if animall_properties.key_radius:
346 insert_key(CV, 'radius', group="spline %s CV %s" % (s_i, v_i))
348 if animall_properties.key_tilt:
349 insert_key(CV, 'tilt', group="spline %s CV %s" % (s_i, v_i))
351 # See previous remark
352 # # Set previous mode
353 # if obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}:
354 # bpy.ops.object.mode_set(mode=mode)
356 refresh_ui_keyframes()
358 return {'FINISHED'}
361 class ANIM_OT_delete_keyframe_animall(Operator):
362 bl_label = "Delete"
363 bl_idname = "anim.delete_keyframe_animall"
364 bl_description = "Delete a Keyframe"
365 bl_options = {'REGISTER', 'UNDO'}
367 def invoke(self, context, event):
368 self.execute(context)
370 return {'FINISHED'}
372 def execute(op, context):
373 obj = context.active_object
374 animall_properties = context.window_manager.animall_properties
376 # Set object mode
377 if obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}:
378 mode = obj.mode
379 bpy.ops.object.mode_set(mode='OBJECT')
381 data = obj.data
383 if obj.type == 'MESH':
384 if animall_properties.key_shape:
385 if obj.active_shape_key:
386 for vert in obj.active_shape_key.data:
387 delete_key(vert, 'co')
389 if animall_properties.key_points:
390 for vert in data.vertices:
391 delete_key(vert, 'co')
393 if animall_properties.key_ebevel:
394 for edge in data.edges:
395 delete_key(edge, 'bevel_weight')
397 if animall_properties.key_vbevel:
398 for vert in data.vertices:
399 delete_key(vert, 'bevel_weight')
401 if animall_properties.key_crease:
402 for edge in data.edges:
403 delete_key(edge, 'crease')
405 if animall_properties.key_vgroups:
406 for vert in data.vertices:
407 for group in vert.groups:
408 delete_key(group, 'weight')
410 if animall_properties.key_uvs:
411 for UV in data.uv_layers.active.data:
412 delete_key(UV, 'uv')
414 if animall_properties.key_vcols:
415 for v_col_layer in data.vertex_colors:
416 if v_col_layer.active: # only delete in active VCol layer
417 for data in v_col_layer.data:
418 delete_key(data, 'color')
420 if obj.type == 'LATTICE':
421 if animall_properties.key_shape:
422 if obj.active_shape_key:
423 for point in obj.active_shape_key.data:
424 delete_key(point, 'co')
426 if animall_properties.key_points:
427 for point in data.points:
428 delete_key(Point, 'co_deform')
430 if obj.type in {'CURVE', 'SURFACE'}:
431 # run this outside the splines loop (only once)
432 if animall_properties.key_shape:
433 if obj.active_shape_key_index > 0:
434 for CV in obj.active_shape_key.data:
435 delete_key(CV, 'co')
436 delete_key(CV, 'handle_left')
437 delete_key(CV, 'handle_right')
439 for spline in data.splines:
440 if spline.type == 'BEZIER':
441 for CV in spline.bezier_points:
442 if animall_properties.key_points:
443 delete_key(CV, 'co')
444 delete_key(CV, 'handle_left')
445 delete_key(CV, 'handle_right')
446 if animall_properties.key_radius:
447 delete_key(CV, 'radius')
448 if animall_properties.key_tilt:
449 delete_key(CV, 'tilt')
451 elif spline.type == 'NURBS':
452 for CV in spline.points:
453 if animall_properties.key_points:
454 delete_key(CV, 'co')
455 if animall_properties.key_radius:
456 delete_key(CV, 'radius')
457 if animall_properties.key_tilt:
458 delete_key(CV, 'tilt')
460 # Set previous mode
461 if obj.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}:
462 bpy.ops.object.mode_set(mode=mode)
464 refresh_ui_keyframes()
466 return {'FINISHED'}
469 class ANIM_OT_clear_animation_animall(Operator):
470 bl_label = "Clear Animation"
471 bl_idname = "anim.clear_animation_animall"
472 bl_description = ("Delete all keyframes for this object\n"
473 "If in a specific case it doesn't work\n"
474 "try to delete the keys manually")
475 bl_options = {'REGISTER', 'UNDO'}
477 def invoke(self, context, event):
478 wm = context.window_manager
479 return wm.invoke_confirm(self, event)
481 def execute(self, context):
482 try:
483 data = context.active_object.data
484 data.animation_data_clear()
485 except:
486 self.report({'WARNING'}, "Clear Animation could not be performed")
487 return {'CANCELLED'}
489 refresh_ui_keyframes()
491 return {'FINISHED'}
494 # Add-ons Preferences Update Panel
496 # Define Panel classes for updating
497 panels = [
498 VIEW3D_PT_animall
502 def update_panel(self, context):
503 message = "AnimAll: Updating Panel locations has failed"
504 try:
505 for panel in panels:
506 if "bl_rna" in panel.__dict__:
507 bpy.utils.unregister_class(panel)
509 for panel in panels:
510 panel.bl_category = context.preferences.addons[__name__].preferences.category
511 bpy.utils.register_class(panel)
513 except Exception as e:
514 print("\n[{}]\n{}\n\nError:\n{}".format(__name__, message, e))
515 pass
518 class AnimallAddonPreferences(AddonPreferences):
519 # this must match the addon name, use '__package__'
520 # when defining this in a submodule of a python package.
521 bl_idname = __name__
523 category: StringProperty(
524 name="Tab Category",
525 description="Choose a name for the category of the panel",
526 default="Animation",
527 update=update_panel
530 def draw(self, context):
531 layout = self.layout
532 row = layout.row()
533 col = row.column()
535 col.label(text="Tab Category:")
536 col.prop(self, "category", text="")
539 def register():
540 bpy.utils.register_class(AnimallProperties)
541 bpy.types.WindowManager.animall_properties = bpy.props.PointerProperty(type=AnimallProperties)
542 bpy.utils.register_class(VIEW3D_PT_animall)
543 bpy.utils.register_class(ANIM_OT_insert_keyframe_animall)
544 bpy.utils.register_class(ANIM_OT_delete_keyframe_animall)
545 bpy.utils.register_class(ANIM_OT_clear_animation_animall)
546 bpy.utils.register_class(AnimallAddonPreferences)
547 update_panel(None, bpy.context)
550 def unregister():
551 del bpy.types.WindowManager.animall_properties
552 bpy.utils.unregister_class(AnimallProperties)
553 bpy.utils.unregister_class(VIEW3D_PT_animall)
554 bpy.utils.unregister_class(ANIM_OT_insert_keyframe_animall)
555 bpy.utils.unregister_class(ANIM_OT_delete_keyframe_animall)
556 bpy.utils.unregister_class(ANIM_OT_clear_animation_animall)
557 bpy.utils.unregister_class(AnimallAddonPreferences)
559 if __name__ == "__main__":
560 register()