Export_3ds: Improved distance cue node search
[blender-addons.git] / animation_animall / __init__.py
blob21cdbc37f32404a3b63d5d656c13b612e8417665
1 # SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 bl_info = {
6 "name": "AnimAll",
7 "author": "Daniel Salazar (ZanQdo), Damien Picard (pioverfour)",
8 "version": (0, 10, 1),
9 "blender": (4, 0, 0),
10 "location": "3D View > Toolbox > Animation tab > AnimAll",
11 "description": "Allows animation of mesh, lattice, curve and surface data",
12 "warning": "",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/animation/animall.html",
14 "category": "Animation",
17 import bpy
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
25 import re
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",
32 default=False)
34 # Generic attributes
35 key_point_location: BoolProperty(
36 name="Location",
37 description="Insert keyframes on point locations",
38 default=False)
39 key_shape_key: BoolProperty(
40 name="Shape Key",
41 description="Insert keyframes on active Shape Key layer",
42 default=False)
43 key_material_index: BoolProperty(
44 name="Material Index",
45 description="Insert keyframes on face material indices",
46 default=False)
48 # Mesh attributes
49 key_vertex_bevel: BoolProperty(
50 name="Vertex Bevel",
51 description="Insert keyframes on vertex bevel weight",
52 default=False)
54 key_vertex_crease: BoolProperty(
55 name="Vertex Crease",
56 description="Insert keyframes on vertex crease weight",
57 default=False)
59 key_vertex_group: BoolProperty(
60 name="Vertex Group",
61 description="Insert keyframes on active vertex group values",
62 default=False)
64 key_edge_bevel: BoolProperty(
65 name="Edge Bevel",
66 description="Insert keyframes on edge bevel weight",
67 default=False)
68 key_edge_crease: BoolProperty(
69 name="Edge Crease",
70 description="Insert keyframes on edge creases",
71 default=False)
73 key_active_attribute: BoolProperty(
74 name="Active Attribute",
75 description="Insert keyframes on active attribute values",
76 default=False)
77 key_uvs: BoolProperty(
78 name="UV Map",
79 description="Insert keyframes on active UV coordinates",
80 default=False)
82 # Curve and surface attributes
83 key_radius: BoolProperty(
84 name="Radius",
85 description="Insert keyframes on point radius (Shrink/Fatten)",
86 default=False)
87 key_tilt: BoolProperty(
88 name="Tilt",
89 description="Insert keyframes on point tilt",
90 default=False)
93 # Utility functions
95 def refresh_ui_keyframes():
96 try:
97 for area in bpy.context.screen.areas:
98 if area.type in ('TIMELINE', 'GRAPH_EDITOR', 'DOPESHEET_EDITOR'):
99 area.tag_redraw()
100 except:
101 pass
104 def insert_key(data, key, group=None):
105 try:
106 if group is not None:
107 data.keyframe_insert(key, group=group)
108 else:
109 data.keyframe_insert(key)
110 except:
111 pass
114 def delete_key(data, key):
115 try:
116 data.keyframe_delete(key)
117 except:
118 pass
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':
131 return ()
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):
150 if (not key_selected
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):
160 if path:
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):
166 if path:
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
176 # GUI (Panel)
178 class VIEW3D_PT_animall(Panel):
179 bl_space_type = 'VIEW_3D'
180 bl_region_type = 'UI'
181 bl_category = "Animation"
182 bl_label = ''
184 @classmethod
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):
190 layout = self.layout
191 row = layout.row()
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
198 layout = self.layout
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")
258 else:
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
266 layout.separator()
267 row = layout.row()
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")
273 row = layout.row()
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
288 else:
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'}]:
297 data = obj.data
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)
312 else:
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'}]:
353 data = obj.data
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):
392 if path:
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))
423 insert_key(
424 CV, 'handle_left', group=data_("%s Spline %s CV %s") %
425 (sk_name, s_i, v_i))
426 insert_key(
427 CV, 'handle_right', group=data_("%s Spline %s CV %s") %
428 (sk_name, s_i, v_i))
429 insert_key(
430 CV, 'radius', group=data_("%s Spline %s CV %s") %
431 (sk_name, s_i, v_i))
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))
441 insert_key(
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()
449 return {'FINISHED'}
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
463 else:
464 objects = context.objects_in_mode_unique_data[:]
466 mode = context.object.mode
468 for obj in objects:
469 data = obj.data
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:
519 delete_key(uv, 'uv')
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):
526 if path:
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:
547 delete_key(CV, 'co')
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:
559 delete_key(CV, 'co')
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:
571 delete_key(CV, 'co')
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()
579 return {'FINISHED'}
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
597 else:
598 objects = context.objects_in_mode_unique_data
600 for obj in objects:
601 try:
602 data = obj.data
603 data.animation_data_clear()
604 except:
605 self.report({'WARNING'}, "Clear Animation could not be performed")
606 return {'CANCELLED'}
608 refresh_ui_keyframes()
610 return {'FINISHED'}
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"
621 try:
622 for panel in panels:
623 if "bl_rna" in panel.__dict__:
624 bpy.utils.unregister_class(panel)
626 for panel in panels:
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))
632 pass
635 class AnimallAddonPreferences(AddonPreferences):
636 # this must match the addon name, use '__package__'
637 # when defining this in a submodule of a python package.
638 bl_idname = __name__
640 category: StringProperty(
641 name="Tab Category",
642 description="Choose a name for the category of the panel",
643 default="Animation",
644 update=update_panel
647 def draw(self, context):
648 layout = self.layout
649 row = layout.row()
650 col = row.column()
652 col.label(text="Tab Category:")
653 col.prop(self, "category", text="")
656 @persistent
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)")
660 attribute_map = {
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:
668 continue
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")
673 else:
674 # Update pre-4.0 attributes
675 match = path_re.match(fcurve.data_path)
676 if match is None:
677 continue
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))
689 def register():
690 register_classes()
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)
696 def unregister():
697 bpy.app.translations.unregister(__name__)
698 bpy.app.handlers.load_post.remove(update_attribute_animation)
699 del bpy.types.Scene.animall_properties
700 unregister_classes()
702 if __name__ == "__main__":
703 register()