1 # SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
7 "author": "Daniel Salazar (ZanQdo), Damien Picard (pioverfour)",
10 "location": "3D View > Toolbox > Animation tab > AnimAll",
11 "description": "Allows animation of mesh, lattice, curve and surface data",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/animation/animall.html",
14 "category": "Animation",
18 from bpy
.types
import (Operator
, Panel
, AddonPreferences
)
19 from bpy
.props
import (BoolProperty
, StringProperty
)
20 from bpy
.app
.handlers
import persistent
21 from bpy
.app
.translations
import (pgettext_iface
as iface_
,
22 pgettext_data
as data_
)
23 from . import translations
27 # Property Definitions
28 class AnimallProperties(bpy
.types
.PropertyGroup
):
29 key_selected
: BoolProperty(
30 name
="Key Selected Only",
31 description
="Insert keyframes only on selected elements",
35 key_point_location
: BoolProperty(
37 description
="Insert keyframes on point locations",
39 key_shape_key
: BoolProperty(
41 description
="Insert keyframes on active Shape Key layer",
43 key_material_index
: BoolProperty(
44 name
="Material Index",
45 description
="Insert keyframes on face material indices",
49 key_vertex_bevel
: BoolProperty(
51 description
="Insert keyframes on vertex bevel weight",
54 key_vertex_crease
: BoolProperty(
56 description
="Insert keyframes on vertex crease weight",
59 key_vertex_group
: BoolProperty(
61 description
="Insert keyframes on active vertex group values",
64 key_edge_bevel
: BoolProperty(
66 description
="Insert keyframes on edge bevel weight",
68 key_edge_crease
: BoolProperty(
70 description
="Insert keyframes on edge creases",
73 key_active_attribute
: BoolProperty(
74 name
="Active Attribute",
75 description
="Insert keyframes on active attribute values",
77 key_uvs
: BoolProperty(
79 description
="Insert keyframes on active UV coordinates",
82 # Curve and surface attributes
83 key_radius
: BoolProperty(
85 description
="Insert keyframes on point radius (Shrink/Fatten)",
87 key_tilt
: BoolProperty(
89 description
="Insert keyframes on point tilt",
95 def refresh_ui_keyframes():
97 for area
in bpy
.context
.screen
.areas
:
98 if area
.type in ('TIMELINE', 'GRAPH_EDITOR', 'DOPESHEET_EDITOR'):
104 def insert_key(data
, key
, group
=None):
106 if group
is not None:
107 data
.keyframe_insert(key
, group
=group
)
109 data
.keyframe_insert(key
)
114 def delete_key(data
, key
):
116 data
.keyframe_delete(key
)
121 def get_attribute(data
, name
, type=None, domain
=None):
122 if name
in data
.attributes
:
123 return data
.attributes
[name
]
124 if type is not None and domain
is not None:
125 return data
.attributes
.new(name
, type, domain
)
128 def get_attribute_paths(data
, attribute
, key_selected
):
129 # Cannot animate string attributes?
130 if attribute
.data_type
== 'STRING':
133 if attribute
.data_type
in {'FLOAT', 'INT', 'BOOLEAN', 'INT8'}:
134 attribute_key
= "value"
135 elif attribute
.data_type
in {'FLOAT_COLOR', 'BYTE_COLOR'}:
136 attribute_key
= "color"
137 elif attribute
.data_type
in {'FLOAT_VECTOR', 'FLOAT2'}:
138 attribute_key
= "vector"
140 if attribute
.domain
== 'POINT':
141 group
= data_("Vertex %s")
142 elif attribute
.domain
== 'EDGE':
143 group
= data_("Edge %s")
144 elif attribute
.domain
== 'FACE':
145 group
= data_("Face %s")
146 elif attribute
.domain
== 'CORNER':
147 group
= data_("Loop %s")
149 for e_i
, _attribute_data
in enumerate(attribute
.data
):
151 or attribute
.domain
== 'POINT' and data
.vertices
[e_i
].select
152 or attribute
.domain
== 'EDGE' and data
.edges
[e_i
].select
153 or attribute
.domain
== 'FACE' and data
.polygons
[e_i
].select
154 or attribute
.domain
== 'CORNER' and is_selected_vert_loop(data
, e_i
)):
155 yield (f
'attributes["{attribute.name}"].data[{e_i}].{attribute_key}', group
% e_i
)
158 def insert_attribute_key(data
, attribute
, key_selected
):
159 for path
, group
in get_attribute_paths(data
, attribute
, key_selected
):
161 insert_key(data
, path
, group
=group
)
164 def delete_attribute_key(data
, attribute
, key_selected
):
165 for path
, group
in get_attribute_paths(data
, attribute
, key_selected
):
167 delete_key(data
, path
)
170 def is_selected_vert_loop(data
, loop_i
):
171 """Get selection status of vertex corresponding to a loop"""
172 vertex_index
= data
.loops
[loop_i
].vertex_index
173 return data
.vertices
[vertex_index
].select
178 class VIEW3D_PT_animall(Panel
):
179 bl_space_type
= 'VIEW_3D'
180 bl_region_type
= 'UI'
181 bl_category
= "Animation"
185 def poll(self
, context
):
186 return context
.active_object
and context
.active_object
.type in {'MESH', 'LATTICE', 'CURVE', 'SURFACE'}
188 def draw_header(self
, context
):
192 row
.label(text
='AnimAll', icon
='ARMATURE_DATA')
194 def draw(self
, context
):
195 obj
= context
.active_object
196 animall_properties
= context
.scene
.animall_properties
200 layout
.label(text
='Key:')
202 layout
.use_property_split
= True
203 layout
.use_property_decorate
= False
205 if obj
.type == 'LATTICE':
206 col
= layout
.column(heading
="Points", align
=True)
207 col
.prop(animall_properties
, "key_point_location")
209 col
= layout
.column(heading
="Others", align
=True)
210 col
.prop(animall_properties
, "key_shape_key")
212 elif obj
.type == 'MESH':
213 col
= layout
.column(heading
="Points", align
=True)
214 col
.prop(animall_properties
, "key_point_location")
215 col
.prop(animall_properties
, "key_vertex_bevel", text
="Bevel")
216 col
.prop(animall_properties
, "key_vertex_crease", text
="Crease")
217 col
.prop(animall_properties
, "key_vertex_group")
219 col
= layout
.column(heading
="Edges", align
=True)
220 col
.prop(animall_properties
, "key_edge_bevel", text
="Bevel")
221 col
.prop(animall_properties
, "key_edge_crease", text
="Crease")
223 col
= layout
.column(heading
="Faces", align
=True)
224 col
.prop(animall_properties
, "key_material_index")
226 col
= layout
.column(heading
="Others", align
=True)
227 col
.prop(animall_properties
, "key_active_attribute")
228 col
.prop(animall_properties
, "key_uvs")
229 col
.prop(animall_properties
, "key_shape_key")
231 elif obj
.type in {'CURVE', 'SURFACE'}:
232 col
= layout
.column(align
=True)
233 col
= layout
.column(heading
="Points", align
=True)
234 col
.prop(animall_properties
, "key_point_location")
235 col
.prop(animall_properties
, "key_radius")
236 col
.prop(animall_properties
, "key_tilt")
238 col
= layout
.column(heading
="Splines", align
=True)
239 col
.prop(animall_properties
, "key_material_index")
241 col
= layout
.column(heading
="Others", align
=True)
242 col
.prop(animall_properties
, "key_shape_key")
244 if animall_properties
.key_shape_key
:
245 shape_key
= obj
.active_shape_key
246 shape_key_index
= obj
.active_shape_key_index
248 if shape_key_index
> 0:
249 col
= layout
.column(align
=True)
250 row
= col
.row(align
=True)
251 row
.prop(shape_key
, "value", text
=shape_key
.name
, icon
="SHAPEKEY_DATA")
252 row
.prop(obj
, "show_only_shape_key", text
="")
253 if shape_key
.value
< 1:
254 col
.label(text
=iface_('Maybe set "%s" to 1.0?') % shape_key
.name
, icon
="INFO")
255 elif shape_key
is not None:
256 col
= layout
.column(align
=True)
257 col
.label(text
="Cannot key on Basis Shape", icon
="ERROR")
259 col
= layout
.column(align
=True)
260 col
.label(text
="No active Shape Key", icon
="ERROR")
262 if animall_properties
.key_point_location
:
263 col
.label(text
='"Location" and "Shape Key" are redundant?', icon
="INFO")
265 layout
.use_property_split
= False
268 row
.prop(animall_properties
, "key_selected")
270 row
= layout
.row(align
=True)
271 row
.operator("anim.insert_keyframe_animall", icon
="KEY_HLT")
272 row
.operator("anim.delete_keyframe_animall", icon
="KEY_DEHLT")
274 row
.operator("anim.clear_animation_animall", icon
="CANCEL")
277 class ANIM_OT_insert_keyframe_animall(Operator
):
278 bl_label
= "Insert Key"
279 bl_idname
= "anim.insert_keyframe_animall"
280 bl_description
= "Insert a Keyframe"
281 bl_options
= {'REGISTER', 'UNDO'}
283 def execute(self
, context
):
284 animall_properties
= context
.scene
.animall_properties
286 if context
.mode
== 'OBJECT':
287 objects
= context
.selected_objects
289 objects
= context
.objects_in_mode_unique_data
[:]
291 mode
= context
.object.mode
293 # Separate loop for lattices, curves and surfaces, since keyframe insertion
294 # has to happen in Edit Mode, otherwise points move back upon mode switch...
295 # (except for curve shape keys)
296 for obj
in [o
for o
in objects
if o
.type in {'CURVE', 'SURFACE', 'LATTICE'}]:
299 if obj
.type == 'LATTICE':
300 if animall_properties
.key_shape_key
:
301 if obj
.active_shape_key_index
> 0:
302 sk_name
= obj
.active_shape_key
.name
303 for p_i
, point
in enumerate(obj
.active_shape_key
.data
):
304 if not animall_properties
.key_selected
or data
.points
[p_i
].select
:
305 insert_key(point
, 'co', group
=data_("%s Point %s") % (sk_name
, p_i
))
307 if animall_properties
.key_point_location
:
308 for p_i
, point
in enumerate(data
.points
):
309 if not animall_properties
.key_selected
or point
.select
:
310 insert_key(point
, 'co_deform', group
=data_("Point %s") % p_i
)
313 if animall_properties
.key_material_index
:
314 for s_i
, spline
in enumerate(data
.splines
):
315 if (not animall_properties
.key_selected
316 or any(point
.select
for point
in spline
.points
)
317 or any(point
.select_control_point
for point
in spline
.bezier_points
)):
318 insert_key(spline
, 'material_index', group
=data_("Spline %s") % s_i
)
320 for s_i
, spline
in enumerate(data
.splines
):
321 if spline
.type == 'BEZIER':
322 for v_i
, CV
in enumerate(spline
.bezier_points
):
323 if (not animall_properties
.key_selected
324 or CV
.select_control_point
325 or CV
.select_left_handle
326 or CV
.select_right_handle
):
327 if animall_properties
.key_point_location
:
328 insert_key(CV
, 'co', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
329 insert_key(CV
, 'handle_left', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
330 insert_key(CV
, 'handle_right', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
332 if animall_properties
.key_radius
:
333 insert_key(CV
, 'radius', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
335 if animall_properties
.key_tilt
:
336 insert_key(CV
, 'tilt', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
338 elif spline
.type in ('POLY', 'NURBS'):
339 for v_i
, CV
in enumerate(spline
.points
):
340 if not animall_properties
.key_selected
or CV
.select
:
341 if animall_properties
.key_point_location
:
342 insert_key(CV
, 'co', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
344 if animall_properties
.key_radius
:
345 insert_key(CV
, 'radius', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
347 if animall_properties
.key_tilt
:
348 insert_key(CV
, 'tilt', group
=data_("Spline %s CV %s") % (s_i
, v_i
))
350 bpy
.ops
.object.mode_set(mode
='OBJECT')
352 for obj
in [o
for o
in objects
if o
.type in {'MESH', 'CURVE', 'SURFACE'}]:
354 if obj
.type == 'MESH':
355 if animall_properties
.key_point_location
:
356 for v_i
, vert
in enumerate(data
.vertices
):
357 if not animall_properties
.key_selected
or vert
.select
:
358 insert_key(vert
, 'co', group
=data_("Vertex %s") % v_i
)
360 if animall_properties
.key_vertex_bevel
:
361 attribute
= get_attribute(data
, "bevel_weight_vert", 'FLOAT', 'POINT')
362 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
364 if animall_properties
.key_vertex_crease
:
365 attribute
= get_attribute(data
, "crease_vert", 'FLOAT', 'POINT')
366 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
368 if animall_properties
.key_vertex_group
:
369 for v_i
, vert
in enumerate(data
.vertices
):
370 if not animall_properties
.key_selected
or vert
.select
:
371 for group
in vert
.groups
:
372 insert_key(group
, 'weight', group
=data_("Vertex %s") % v_i
)
374 if animall_properties
.key_edge_bevel
:
375 attribute
= get_attribute(data
, "bevel_weight_edge", 'FLOAT', 'EDGE')
376 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
378 if animall_properties
.key_edge_crease
:
379 attribute
= get_attribute(data
, "crease_edge", 'FLOAT', 'EDGE')
380 insert_attribute_key(data
, attribute
, animall_properties
.key_selected
)
382 if animall_properties
.key_material_index
:
383 for p_i
, polygon
in enumerate(data
.polygons
):
384 if not animall_properties
.key_selected
or polygon
.select
:
385 insert_key(polygon
, 'material_index', group
=data_("Face %s") % p_i
)
387 if animall_properties
.key_active_attribute
:
388 if data
.attributes
.active
is not None:
389 for path
, group
in get_attribute_paths(
390 data
, data
.attributes
.active
,
391 animall_properties
.key_selected
):
393 insert_key(data
, path
, group
=group
)
395 if animall_properties
.key_uvs
:
396 if data
.uv_layers
.active
is not None:
397 for uv_i
, uv
in enumerate(data
.uv_layers
.active
.data
):
398 if not animall_properties
.key_selected
or uv
.select
:
399 insert_key(uv
, 'uv', group
=data_("UV Layer %s") % uv_i
)
401 if animall_properties
.key_shape_key
:
402 if obj
.active_shape_key_index
> 0:
403 sk_name
= obj
.active_shape_key
.name
404 for v_i
, vert
in enumerate(obj
.active_shape_key
.data
):
405 if not animall_properties
.key_selected
or data
.vertices
[v_i
].select
:
406 insert_key(vert
, 'co', group
=data_("%s Vertex %s") % (sk_name
, v_i
))
408 elif obj
.type in {'CURVE', 'SURFACE'}:
409 # Shape key keys have to be inserted in object mode for curves...
410 if animall_properties
.key_shape_key
:
411 sk_name
= obj
.active_shape_key
.name
412 global_spline_index
= 0 # numbering for shape keys, which have flattened indices
413 for s_i
, spline
in enumerate(data
.splines
):
414 if spline
.type == 'BEZIER':
415 for v_i
, CV
in enumerate(spline
.bezier_points
):
416 if (not animall_properties
.key_selected
417 or CV
.select_control_point
418 or CV
.select_left_handle
419 or CV
.select_right_handle
):
420 if obj
.active_shape_key_index
> 0:
421 CV
= obj
.active_shape_key
.data
[global_spline_index
]
422 insert_key(CV
, 'co', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
424 CV
, 'handle_left', group
=data_("%s Spline %s CV %s") %
427 CV
, 'handle_right', group
=data_("%s Spline %s CV %s") %
430 CV
, 'radius', group
=data_("%s Spline %s CV %s") %
432 insert_key(CV
, 'tilt', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
433 global_spline_index
+= 1
435 elif spline
.type in ('POLY', 'NURBS'):
436 for v_i
, CV
in enumerate(spline
.points
):
437 if not animall_properties
.key_selected
or CV
.select
:
438 if obj
.active_shape_key_index
> 0:
439 CV
= obj
.active_shape_key
.data
[global_spline_index
]
440 insert_key(CV
, 'co', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
442 CV
, 'radius', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
443 insert_key(CV
, 'tilt', group
=data_("%s Spline %s CV %s") % (sk_name
, s_i
, v_i
))
444 global_spline_index
+= 1
446 bpy
.ops
.object.mode_set(mode
=mode
)
447 refresh_ui_keyframes()
452 class ANIM_OT_delete_keyframe_animall(Operator
):
453 bl_label
= "Delete Key"
454 bl_idname
= "anim.delete_keyframe_animall"
455 bl_description
= "Delete a Keyframe"
456 bl_options
= {'REGISTER', 'UNDO'}
458 def execute(self
, context
):
459 animall_properties
= context
.scene
.animall_properties
461 if context
.mode
== 'OBJECT':
462 objects
= context
.selected_objects
464 objects
= context
.objects_in_mode_unique_data
[:]
466 mode
= context
.object.mode
470 if obj
.type == 'MESH':
471 bpy
.ops
.object.mode_set(mode
='OBJECT')
473 if animall_properties
.key_point_location
:
474 for vert
in data
.vertices
:
475 if not animall_properties
.key_selected
or vert
.select
:
476 delete_key(vert
, 'co')
478 if animall_properties
.key_vertex_bevel
:
479 attribute
= get_attribute(data
, "bevel_weight_vert", 'FLOAT', 'POINT')
480 if attribute
is not None:
481 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
483 if animall_properties
.key_vertex_crease
:
484 attribute
= get_attribute(data
, "crease_vert", 'FLOAT', 'POINT')
485 if attribute
is not None:
486 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
488 if animall_properties
.key_vertex_group
:
489 for vert
in data
.vertices
:
490 if not animall_properties
.key_selected
or vert
.select
:
491 for group
in vert
.groups
:
492 delete_key(group
, 'weight')
494 if animall_properties
.key_edge_bevel
:
495 attribute
= get_attribute(data
, "bevel_weight_edge", 'FLOAT', 'EDGE')
496 if attribute
is not None:
497 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
499 if animall_properties
.key_edge_crease
:
500 attribute
= get_attribute(data
, "crease_edge", 'FLOAT', 'EDGE')
501 if attribute
is not None:
502 delete_attribute_key(data
, attribute
, animall_properties
.key_selected
)
504 if animall_properties
.key_material_index
:
505 for p_i
, polygon
in enumerate(data
.polygons
):
506 if not animall_properties
.key_selected
or polygon
.select
:
507 delete_key(polygon
, 'material_index')
509 if animall_properties
.key_shape_key
:
510 if obj
.active_shape_key
:
511 for v_i
, vert
in enumerate(obj
.active_shape_key
.data
):
512 if not animall_properties
.key_selected
or data
.vertices
[v_i
].select
:
513 delete_key(vert
, 'co')
515 if animall_properties
.key_uvs
:
516 if data
.uv_layers
.active
is not None:
517 for uv
in data
.uv_layers
.active
.data
:
518 if not animall_properties
.key_selected
or uv
.select
:
521 if animall_properties
.key_active_attribute
:
522 if data
.attributes
.active
is not None:
523 for path
, _group
in get_attribute_paths(
524 data
, data
.attributes
.active
,
525 animall_properties
.key_selected
):
527 delete_key(data
, path
)
529 bpy
.ops
.object.mode_set(mode
=mode
)
531 elif obj
.type == 'LATTICE':
532 if animall_properties
.key_shape_key
:
533 if obj
.active_shape_key
:
534 for point
in obj
.active_shape_key
.data
:
535 delete_key(point
, 'co')
537 if animall_properties
.key_point_location
:
538 for point
in data
.points
:
539 if not animall_properties
.key_selected
or point
.select
:
540 delete_key(point
, 'co_deform')
542 elif obj
.type in {'CURVE', 'SURFACE'}:
543 # Run this outside the splines loop (only once)
544 if animall_properties
.key_shape_key
:
545 if obj
.active_shape_key_index
> 0:
546 for CV
in obj
.active_shape_key
.data
:
548 delete_key(CV
, 'handle_left')
549 delete_key(CV
, 'handle_right')
551 for spline
in data
.splines
:
552 if spline
.type == 'BEZIER':
553 for CV
in spline
.bezier_points
:
554 if (not animall_properties
.key_selected
555 or CV
.select_control_point
556 or CV
.select_left_handle
557 or CV
.select_right_handle
):
558 if animall_properties
.key_point_location
:
560 delete_key(CV
, 'handle_left')
561 delete_key(CV
, 'handle_right')
562 if animall_properties
.key_radius
:
563 delete_key(CV
, 'radius')
564 if animall_properties
.key_tilt
:
565 delete_key(CV
, 'tilt')
567 elif spline
.type in ('POLY', 'NURBS'):
568 for CV
in spline
.points
:
569 if not animall_properties
.key_selected
or CV
.select
:
570 if animall_properties
.key_point_location
:
572 if animall_properties
.key_radius
:
573 delete_key(CV
, 'radius')
574 if animall_properties
.key_tilt
:
575 delete_key(CV
, 'tilt')
577 refresh_ui_keyframes()
582 class ANIM_OT_clear_animation_animall(Operator
):
583 bl_label
= "Clear Animation"
584 bl_idname
= "anim.clear_animation_animall"
585 bl_description
= ("Delete all keyframes for this object\n"
586 "If in a specific case it doesn't work\n"
587 "try to delete the keys manually")
588 bl_options
= {'REGISTER', 'UNDO'}
590 def invoke(self
, context
, event
):
591 wm
= context
.window_manager
592 return wm
.invoke_confirm(self
, event
)
594 def execute(self
, context
):
595 if context
.mode
== 'OBJECT':
596 objects
= context
.selected_objects
598 objects
= context
.objects_in_mode_unique_data
603 data
.animation_data_clear()
605 self
.report({'WARNING'}, "Clear Animation could not be performed")
608 refresh_ui_keyframes()
613 # Add-ons Preferences Update Panel
615 # Define Panel classes for updating
616 panels
= [VIEW3D_PT_animall
]
619 def update_panel(self
, context
):
620 message
= "AnimAll: Updating Panel locations has failed"
623 if "bl_rna" in panel
.__dict
__:
624 bpy
.utils
.unregister_class(panel
)
627 panel
.bl_category
= context
.preferences
.addons
[__name__
].preferences
.category
628 bpy
.utils
.register_class(panel
)
630 except Exception as e
:
631 print("\n[{}]\n{}\n\nError:\n{}".format(__name__
, message
, e
))
635 class AnimallAddonPreferences(AddonPreferences
):
636 # this must match the addon name, use '__package__'
637 # when defining this in a submodule of a python package.
640 category
: StringProperty(
642 description
="Choose a name for the category of the panel",
647 def draw(self
, context
):
652 col
.label(text
="Tab Category:")
653 col
.prop(self
, "category", text
="")
657 def update_attribute_animation(_
):
658 """Update attributes from the old format"""
659 path_re
= re
.compile(r
"^vertex_colors|(vertices|edges)\[([0-9]+)\]\.(bevel_weight|crease)")
661 ("vertices", "bevel_weight"): ("bevel_weight_vert", "FLOAT", "POINT"),
662 ("edges", "bevel_weight"): ("bevel_weight_edge", "FLOAT", "POINT"),
663 ("vertices", "crease"): ("crease_vert", "FLOAT", "EDGE"),
664 ("edges", "crease"): ("crease_edge", "FLOAT", "EDGE"),
666 for mesh
in bpy
.data
.meshes
:
667 if mesh
.animation_data
is None:
669 for fcurve
in mesh
.animation_data
.action
.fcurves
:
670 if fcurve
.data_path
.startswith("vertex_colors"):
671 # Update pre-3.3 vertex colors
672 fcurve
.data_path
= fcurve
.data_path
.replace("vertex_colors", "attributes")
674 # Update pre-4.0 attributes
675 match
= path_re
.match(fcurve
.data_path
)
678 domain
, index
, src_attribute
= match
.groups()
679 attribute
, type, domain
= attribute_map
[(domain
, src_attribute
)]
680 get_attribute(mesh
, attribute
, type, domain
)
681 fcurve
.data_path
= f
'attributes["{attribute}"].data[{index}].value'
684 register_classes
, unregister_classes
= bpy
.utils
.register_classes_factory(
685 (AnimallProperties
, VIEW3D_PT_animall
, ANIM_OT_insert_keyframe_animall
,
686 ANIM_OT_delete_keyframe_animall
, ANIM_OT_clear_animation_animall
,
687 AnimallAddonPreferences
))
691 bpy
.types
.Scene
.animall_properties
= bpy
.props
.PointerProperty(type=AnimallProperties
)
692 update_panel(None, bpy
.context
)
693 bpy
.app
.handlers
.load_post
.append(update_attribute_animation
)
694 bpy
.app
.translations
.register(__name__
, translations
.translations_dict
)
697 bpy
.app
.translations
.unregister(__name__
)
698 bpy
.app
.handlers
.load_post
.remove(update_attribute_animation
)
699 del bpy
.types
.Scene
.animall_properties
702 if __name__
== "__main__":