From 5e530125582188ec658045da4acc74bdc6911992 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 18 Aug 2010 18:00:52 +0000 Subject: utility function for updating animation system values when RNA changes. - any numnber of attributes are supported for renaming, eg: modifiers["Foo.Bar"].prop.bar - the path is resolved in blender so each attribute is type checked against the naming list. - inherited properties are supported by recursively checking parent classes names aganst the name list. - fcurves and drivers are currently supported. --- release/scripts/modules/animsys_refactor.py | 183 ++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 release/scripts/modules/animsys_refactor.py (limited to 'release/scripts/modules/animsys_refactor.py') diff --git a/release/scripts/modules/animsys_refactor.py b/release/scripts/modules/animsys_refactor.py new file mode 100644 index 00000000000..3959904e0c5 --- /dev/null +++ b/release/scripts/modules/animsys_refactor.py @@ -0,0 +1,183 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# + +""" +This module has utility functions for renaming +rna values in fcurves and drivers. + +The main function to use is: update_data_paths(...) +""" + +IS_TESTING = False + +class DataPathBuilder(object): + __slots__ = ("data_path", ) + """ Dummy class used to parse fcurve and driver data paths. + """ + def __init__(self, attrs): + self.data_path = attrs + + def __getattr__(self, attr): + str_value = ".%s" % attr + return DataPathBuilder(self.data_path + (str_value, )) + + def __getitem__(self, key): + str_value = '["%s"]' % key + return DataPathBuilder(self.data_path + (str_value, )) + + def resolve(self, real_base): + """ Return (attribute, value) pairs. + """ + pairs = [] + base = real_base + for item in self.data_path: + if base is not Ellipsis: + try: + base = eval("base" + item) + except: + print("Failed to resolve data path:", self.data_path) + base = Ellipsis + + pairs.append((item, base)) + return pairs + +import bpy + + +def id_iter(): + type_iter = type(bpy.data.objects) + + for attr in dir(bpy.data): + data_iter = getattr(bpy.data, attr, None) + if type(data_iter) == type_iter: + for id_data in data_iter: + if id_data.library is None: + yield id_data + + +def anim_data_actions(anim_data): + actions = [] + actions.append(anim_data.action) + for track in anim_data.nla_tracks: + for strip in track.strips: + actions.append(strip.action) + + # filter out None + return [act for act in actions if act] + + +def classes_recursive(base_type, clss=None): + if clss is None: + clss = [base_type] + else: + clss.append(base_type) + + for base_type_iter in base_type.__bases__: + if base_type_iter is not object: + classes_recursive(base_type_iter, clss) + + return clss + + +def find_path_new(id_data, data_path, rna_update_dict): + # ignore ID props for now + if data_path.startswith("["): + return data_path + + # recursive path fixing, likely will be one in most cases. + data_path_builder = eval("DataPathBuilder(tuple())." + data_path) + data_resolve = data_path_builder.resolve(id_data) + + path_new = [pair[0] for pair in data_resolve] + + # print(data_resolve) + data_base = id_data + + for i, (attr, data) in enumerate(data_resolve): + if data is Ellipsis: + break + + if attr.startswith("."): + # try all classes + for data_base_type in classes_recursive(type(data_base)): + attr_new = rna_update_dict.get(data_base_type.__name__, {}).get(attr[1:]) + if attr_new: + path_new[i] = "." + attr_new + + # set this as the base for further properties + data_base = data + + data_path_new = "".join(path_new)[1:] # skip the first "." + return data_path_new + + +def update_data_paths(rna_update): + ''' rna_update triple [(class_name, from, to), ...] + ''' + + # make a faster lookup dict + rna_update_dict = {} + for ren_class, ren_from, ren_to in rna_update: + rna_update_dict.setdefault(ren_class, {})[ren_from] = ren_to + + for id_data in id_iter(): + anim_data = getattr(id_data, "animation_data", None) + if anim_data is None: + continue + + for fcurve in anim_data.drivers: + for var in fcurve.driver.variables: + if var.type == 'SINGLE_PROP': + for tar in var.targets: + id_data_other = tar.id + data_path = tar.data_path + + if id_data_other and data_path: + data_path_new = find_path_new(id_data_other, data_path, rna_update_dict) + # print(data_path_new) + if data_path_new != data_path: + if not IS_TESTING: + tar.data_path = data_path_new + print("driver (%s): %s -> %s" % (id_data_other.name, data_path, data_path_new)) + + + + for action in anim_data_actions(anim_data): + for fcu in action.fcurves: + data_path = fcu.data_path + data_path_new = find_path_new(id_data, data_path, rna_update_dict) + # print(data_path_new) + if data_path_new != data_path: + if not IS_TESTING: + fcu.data_path = data_path_new + print("fcurve (%s): %s -> %s" % (id_data.name, data_path, data_path_new)) + + +if __name__ == "__main__": + + # Example, should be called externally + # (class, from, to) + replace_ls = [ + ('AnimVizMotionPaths', 'after_current', 'frame_after'), + ('AnimVizMotionPaths', 'before_current', 'frame_before'), + ('AnimVizOnionSkinning', 'after_current', 'frame_after'), + ] + + update_data_paths(replace_ls) -- cgit v1.2.3