forked from bartvdbraak/blender
more files
This commit is contained in:
parent
cc2c57b793
commit
a91fdd61dc
201
release/scripts/modules/animsys_refactor.py
Executable file
201
release/scripts/modules/animsys_refactor.py
Executable file
@ -0,0 +1,201 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""
|
||||
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, rna_update_from_map=None):
|
||||
""" Return (attribute, value) pairs.
|
||||
"""
|
||||
pairs = []
|
||||
base = real_base
|
||||
for item in self.data_path:
|
||||
if base is not Ellipsis:
|
||||
try:
|
||||
# this only works when running with an old blender
|
||||
# where the old path will resolve
|
||||
base = eval("base" + item)
|
||||
except:
|
||||
base_new = Ellipsis
|
||||
# guess the new name
|
||||
if item.startswith("."):
|
||||
for item_new in rna_update_from_map.get(item[1:], ()):
|
||||
try:
|
||||
print("base." + item_new)
|
||||
base_new = eval("base." + item_new)
|
||||
break # found, dont keep looking
|
||||
except:
|
||||
pass
|
||||
|
||||
if base_new is Ellipsis:
|
||||
print("Failed to resolve data path:", self.data_path)
|
||||
base = base_new
|
||||
|
||||
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, rna_update_from_map):
|
||||
# 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, rna_update_from_map)
|
||||
|
||||
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
|
||||
|
||||
rna_update_from_map = {}
|
||||
for ren_class, ren_from, ren_to in rna_update:
|
||||
rna_update_from_map.setdefault(ren_from, []).append(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, rna_update_from_map)
|
||||
# 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, rna_update_from_map)
|
||||
# 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', 'frame_after', 'frame_after'),
|
||||
('AnimVizMotionPaths', 'frame_before', 'frame_before'),
|
||||
('AnimVizOnionSkinning', 'frame_after', 'frame_after'),
|
||||
]
|
||||
|
||||
update_data_paths(replace_ls)
|
204
release/scripts/modules/bpyml.py
Executable file
204
release/scripts/modules/bpyml.py
Executable file
@ -0,0 +1,204 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
"""
|
||||
This module translates a python like XML representation into XML
|
||||
or simple python blender/ui function calls.
|
||||
|
||||
sometag(arg=10) [
|
||||
another()
|
||||
another(key="value")
|
||||
]
|
||||
|
||||
# converts into ...
|
||||
|
||||
<sometag arg="10">
|
||||
<another/>
|
||||
<another key="value" />
|
||||
</sometag>
|
||||
|
||||
"""
|
||||
|
||||
TAG, ARGS, CHILDREN = range(3)
|
||||
class ReturnStore(tuple):
|
||||
def __getitem__(self, key):
|
||||
|
||||
# single item get's
|
||||
if type(key) is ReturnStore:
|
||||
key = (key, )
|
||||
|
||||
if type(key) is tuple:
|
||||
children = self[CHILDREN]
|
||||
if children:
|
||||
raise Exception("Only a single __getitem__ is allowed on the ReturnStore")
|
||||
else:
|
||||
children[:] = key
|
||||
return self
|
||||
else:
|
||||
return tuple.__getitem__(self, key)
|
||||
|
||||
|
||||
class FunctionStore(object):
|
||||
def __call__(self, **kwargs):
|
||||
return ReturnStore((self.__class__.__name__, kwargs, []))
|
||||
|
||||
|
||||
def tag_vars(tags, module=__name__):
|
||||
return {tag: type(tag, (FunctionStore, ), {"__module__": module})() for tag in tags}
|
||||
|
||||
|
||||
def tag_module(mod_name, tags):
|
||||
import sys
|
||||
from types import ModuleType
|
||||
mod = ModuleType(mod_name)
|
||||
sys.modules[mod_name] = mod
|
||||
dict_values = tag_vars(tags, mod_name)
|
||||
mod.__dict__.update(dict_values)
|
||||
return mod
|
||||
|
||||
|
||||
def toxml(py_data, indent=" "):
|
||||
|
||||
if len(py_data) != 1 or type(py_data) != list:
|
||||
raise Exception("Expected a list with one member")
|
||||
|
||||
def _to_xml(py_item, xml_node=None):
|
||||
if xml_node is None:
|
||||
xml_node = newdoc.createElement(py_item[TAG])
|
||||
|
||||
for key, value in py_item[ARGS].items():
|
||||
xml_node.setAttribute(key, str(value))
|
||||
|
||||
for py_item_child in py_item[CHILDREN]:
|
||||
xml_node.appendChild(_to_xml(py_item_child))
|
||||
|
||||
return xml_node
|
||||
|
||||
def _to_xml_iter(xml_parent, data_ls):
|
||||
for py_item in data_ls:
|
||||
xml_node = newdoc.createElement(py_item[TAG])
|
||||
|
||||
|
||||
# ok if its empty
|
||||
_to_xml_iter(xml_node, py_item[CHILDREN])
|
||||
|
||||
import xml.dom.minidom
|
||||
impl = xml.dom.minidom.getDOMImplementation()
|
||||
newdoc = impl.createDocument(None, py_data[0][TAG], None)
|
||||
|
||||
_to_xml(py_data[0], newdoc.documentElement)
|
||||
|
||||
return newdoc.documentElement.toprettyxml(indent=" ")
|
||||
|
||||
|
||||
def fromxml(data):
|
||||
def _fromxml_kwargs(xml_node):
|
||||
kwargs = {}
|
||||
for key, value in xml_node.attributes.items():
|
||||
kwargs[key] = value
|
||||
return kwargs
|
||||
|
||||
|
||||
def _fromxml(xml_node):
|
||||
py_item = (xml_node.tagName, _fromxml_kwargs(xml_node), [])
|
||||
#_fromxml_iter(py_item, xml_node.childNodes)
|
||||
for xml_node_child in xml_node.childNodes:
|
||||
if xml_node_child.nodeType not in (xml_node_child.TEXT_NODE, xml_node_child.COMMENT_NODE):
|
||||
py_item[CHILDREN].append(_fromxml(xml_node_child))
|
||||
return py_item
|
||||
|
||||
import xml.dom.minidom
|
||||
xml_doc = xml.dom.minidom.parseString(data)
|
||||
return [_fromxml(xml_doc.documentElement)]
|
||||
|
||||
|
||||
def topretty_py(py_data, indent=" "):
|
||||
|
||||
if len(py_data) != 1:
|
||||
raise Exception("Expected a list with one member")
|
||||
|
||||
lines = []
|
||||
|
||||
def _to_kwargs(kwargs):
|
||||
return ", ".join([("%s=%s" % (key, repr(value))) for key, value in sorted(kwargs.items())])
|
||||
|
||||
def _topretty(py_item, indent_ctx, last):
|
||||
if py_item[CHILDREN]:
|
||||
lines.append("%s%s(%s) [" % (indent_ctx, py_item[TAG], _to_kwargs(py_item[ARGS])))
|
||||
py_item_last = py_item[CHILDREN][-1]
|
||||
for py_item_child in py_item[CHILDREN]:
|
||||
_topretty(py_item_child, indent_ctx + indent, (py_item_child is py_item_last))
|
||||
lines.append("%s]%s" % (indent_ctx, ("" if last else ",")))
|
||||
else:
|
||||
lines.append("%s%s(%s)%s" % (indent_ctx, py_item[TAG], _to_kwargs(py_item[ARGS]), ("" if last else ",")))
|
||||
|
||||
_topretty(py_data[0], "", True)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
if __name__ == "__main__":
|
||||
# testing code.
|
||||
|
||||
tag_module("bpyml_test", ("ui", "prop", "row", "column", "active", "separator", "split"))
|
||||
from bpyml_test import *
|
||||
|
||||
draw = [
|
||||
ui() [
|
||||
split() [
|
||||
column() [
|
||||
prop(data='context.scene.render', property='use_stamp_time', text='Time'),
|
||||
prop(data='context.scene.render', property='use_stamp_date', text='Date'),
|
||||
prop(data='context.scene.render', property='use_stamp_render_time', text='RenderTime'),
|
||||
prop(data='context.scene.render', property='use_stamp_frame', text='Frame'),
|
||||
prop(data='context.scene.render', property='use_stamp_scene', text='Scene'),
|
||||
prop(data='context.scene.render', property='use_stamp_camera', text='Camera'),
|
||||
prop(data='context.scene.render', property='use_stamp_filename', text='Filename'),
|
||||
prop(data='context.scene.render', property='use_stamp_marker', text='Marker'),
|
||||
prop(data='context.scene.render', property='use_stamp_sequencer_strip', text='Seq. Strip')
|
||||
],
|
||||
column() [
|
||||
active(expr='context.scene.render.use_stamp'),
|
||||
prop(data='context.scene.render', property='stamp_foreground', slider=True),
|
||||
prop(data='context.scene.render', property='stamp_background', slider=True),
|
||||
separator(),
|
||||
prop(data='context.scene.render', property='stamp_font_size', text='Font Size')
|
||||
]
|
||||
],
|
||||
split(percentage=0.2) [
|
||||
prop(data='context.scene.render', property='use_stamp_note', text='Note'),
|
||||
row() [
|
||||
active(expr='context.scene.render.use_stamp_note'),
|
||||
prop(data='context.scene.render', property='stamp_note_text', text='')
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
xml_data = toxml(draw)
|
||||
print(xml_data) # xml version
|
||||
|
||||
py_data = fromxml(xml_data)
|
||||
print(py_data) # converted back to py
|
||||
|
||||
xml_data = toxml(py_data)
|
||||
print(xml_data) # again back to xml
|
||||
|
||||
py_data = fromxml(xml_data) # pretty python version
|
||||
print(topretty_py(py_data))
|
100
release/scripts/modules/bpyml_ui.py
Executable file
100
release/scripts/modules/bpyml_ui.py
Executable file
@ -0,0 +1,100 @@
|
||||
# ##### 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 #####
|
||||
|
||||
# <pep8 compliant>
|
||||
|
||||
|
||||
import bpy as _bpy
|
||||
import bpyml
|
||||
from bpyml import TAG, ARGS, CHILDREN
|
||||
from types import ModuleType
|
||||
|
||||
_uilayout_rna = _bpy.types.UILayout.bl_rna
|
||||
|
||||
_uilayout_tags = ["ui"] + \
|
||||
_uilayout_rna.properties.keys() + \
|
||||
_uilayout_rna.functions.keys()
|
||||
|
||||
# these need to be imported directly
|
||||
# >>> from bpyml_ui.locals import *
|
||||
locals = bpyml.tag_module("%s.locals" % __name__ , _uilayout_tags)
|
||||
|
||||
|
||||
def _parse_rna(prop, value):
|
||||
if prop.type == 'FLOAT':
|
||||
value = float(value)
|
||||
elif prop.type == 'INT':
|
||||
value = int(value)
|
||||
elif prop.type == 'BOOLEAN':
|
||||
if value in (True, False):
|
||||
pass
|
||||
else:
|
||||
if value not in ("True", "False"):
|
||||
raise Exception("invalid bool value: %s" % value)
|
||||
value = bool(value == "True")
|
||||
elif prop.type in ('STRING', 'ENUM'):
|
||||
pass
|
||||
elif prop.type == 'POINTER':
|
||||
value = eval("_bpy." + value)
|
||||
else:
|
||||
raise Exception("type not supported %s.%s" % (prop.identifier, prop.type))
|
||||
return value
|
||||
|
||||
|
||||
def _parse_rna_args(base, py_node):
|
||||
rna_params = base.bl_rna.functions[py_node[TAG]].parameters
|
||||
args = {}
|
||||
for key, value in py_node[ARGS].items():
|
||||
args[key] = _parse_rna(rna_params[key], value)
|
||||
return args
|
||||
|
||||
|
||||
def _call_recursive(context, base, py_node):
|
||||
prop = base.bl_rna.properties.get(py_node[TAG])
|
||||
if py_node[TAG] in base.bl_rna.properties:
|
||||
value = py_node[ARGS].get("expr")
|
||||
if value:
|
||||
value = eval(value, {"context": _bpy.context})
|
||||
setattr(base, py_node[TAG], value)
|
||||
else:
|
||||
value = py_node[ARGS]['value'] # have to have this
|
||||
setattr(base, name, value)
|
||||
else:
|
||||
args = _parse_rna_args(base, py_node)
|
||||
func_new = getattr(base, py_node[TAG])
|
||||
base_new = func_new(**args) # call blender func
|
||||
if base_new is not None:
|
||||
for py_node_child in py_node[CHILDREN]:
|
||||
_call_recursive(context, base_new, py_node_child)
|
||||
|
||||
|
||||
class BPyML_BaseUI():
|
||||
'''
|
||||
This is a mix-in class that defines a draw function
|
||||
which checks for draw_data
|
||||
'''
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
for py_node in self.draw_data[CHILDREN]:
|
||||
_call_recursive(context, layout, py_node)
|
||||
|
||||
def draw_header(self, context):
|
||||
layout = self.layout
|
||||
for py_node in self.draw_header_data[CHILDREN]:
|
||||
_call_recursive(context, layout, py_node)
|
Loading…
Reference in New Issue
Block a user