diff options
Diffstat (limited to 'release/scripts/modules')
38 files changed, 2702 insertions, 834 deletions
diff --git a/release/scripts/modules/add_object_utils.py b/release/scripts/modules/add_object_utils.py new file mode 100644 index 00000000000..eaa97512f89 --- /dev/null +++ b/release/scripts/modules/add_object_utils.py @@ -0,0 +1,83 @@ +# ##### 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 +import mathutils + + +def add_object_align_init(context, operator): + + if operator and operator.properties.is_property_set("location") and operator.properties.is_property_set("rotation"): + location = mathutils.Matrix.Translation(mathutils.Vector(operator.properties.location)) + rotation = mathutils.Euler(operator.properties.rotation).to_matrix().resize4x4() + else: + # TODO, local view cursor! + location = mathutils.Matrix.Translation(context.scene.cursor_location) + + if context.user_preferences.edit.object_align == 'VIEW' and context.space_data.type == 'VIEW_3D': + rotation = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4() + else: + rotation = mathutils.Matrix() + + # set the operator properties + if operator: + operator.properties.location = location.translation_part() + operator.properties.rotation = rotation.to_euler() + + return location * rotation + + +def add_object_data(context, obdata, operator=None): + + scene = context.scene + + # ugh, could be made nicer + for ob in scene.objects: + ob.select = False + + obj_new = bpy.data.objects.new(obdata.name, obdata) + + base = scene.objects.link(obj_new) + base.select = True + + if context.space_data and context.space_data.type == 'VIEW_3D': + base.layers_from_view(context.space_data) + + + obj_new.matrix_world = add_object_align_init(context, operator) + + obj_act = scene.objects.active + + if obj_act and obj_act.mode == 'EDIT' and obj_act.type == obj_new.type: + bpy.ops.object.mode_set(mode='OBJECT') + + obj_act.select = True + scene.update() # apply location + #scene.objects.active = obj_new + + bpy.ops.object.join() # join into the active. + + bpy.ops.object.mode_set(mode='EDIT') + else: + scene.objects.active = obj_new + if context.user_preferences.edit.use_enter_edit_mode: + bpy.ops.object.mode_set(mode='EDIT') + + return base diff --git a/release/scripts/modules/animsys_refactor.py b/release/scripts/modules/animsys_refactor.py new file mode 100644 index 00000000000..8cc91873b0e --- /dev/null +++ b/release/scripts/modules/animsys_refactor.py @@ -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) diff --git a/release/scripts/modules/blend_render_info.py b/release/scripts/modules/blend_render_info.py new file mode 100755 index 00000000000..dcd1f9cbee3 --- /dev/null +++ b/release/scripts/modules/blend_render_info.py @@ -0,0 +1,100 @@ +#!/usr/bin/python + +# ##### 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 can get render info without running from inside blender. +# +# This struct wont change according to Ton. +# Note that the size differs on 32/64bit +# +# typedef struct BHead { +# int code, len; +# void *old; +# int SDNAnr, nr; +# } BHead; + + +def read_blend_rend_chunk(path): + + import struct + + blendfile = open(path, 'rb') + + head = blendfile.read(7) + + if head[0:2] == b'\x1f\x8b': # gzip magic + import gzip + blendfile.close() + blendfile = gzip.open(path, 'rb') + head = blendfile.read(7) + + if head != b'BLENDER': + print("not a blend file:", path) + blendfile.close() + return [] + + is_64_bit = (blendfile.read(1) == b'-') + + # true for PPC, false for X86 + is_big_endian = (blendfile.read(1) == b'V') + + # Now read the bhead chunk!!! + blendfile.read(3) # skip the version + + scenes = [] + + sizeof_bhead = 24 if is_64_bit else 20 + + while blendfile.read(4) == b'REND': + sizeof_bhead_left = sizeof_bhead - 4 + + struct.unpack('>i' if is_big_endian else '<i', blendfile.read(4))[0] + sizeof_bhead_left -= 4 + + # We dont care about the rest of the bhead struct + blendfile.read(sizeof_bhead_left) + + # Now we want the scene name, start and end frame. this is 32bites long + start_frame, end_frame = struct.unpack('>2i' if is_big_endian else '<2i', blendfile.read(8)) + + scene_name = blendfile.read(24) + + scene_name = scene_name[:scene_name.index(b'\0')] + + try: + scene_name = str(scene_name, 'utf8') + except TypeError: + pass + + scenes.append((start_frame, end_frame, scene_name)) + + return scenes + + +def main(): + import sys + for arg in sys.argv[1:]: + if arg.lower().endswith('.blend'): + for value in read_blend_rend_chunk(arg): + print("%d %d %s" % value) + +if __name__ == '__main__': + main() diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py index f0025290f09..5b7d5a76336 100644 --- a/release/scripts/modules/bpy/__init__.py +++ b/release/scripts/modules/bpy/__init__.py @@ -26,7 +26,7 @@ data = _bpy.data context = _bpy.context # python modules -from bpy import utils +from bpy import utils, path from bpy import ops as _ops_module @@ -43,18 +43,12 @@ def _main(): ## people need to explain how this is even a fix. # _sys.path[:] = filter(None, _sys.path) - # a bit nasty but this prevents help() and input() from locking blender - # Ideally we could have some way for the console to replace sys.stdin but - # python would lock blender while waiting for a return value, not easy :| - - if not app.debug: - _sys.stdin = None - # because of how the console works. we need our own help() pager func. # replace the bold function because it adds crazy chars import pydoc pydoc.getpager = lambda: pydoc.plainpager - pydoc.TextDoc.bold = lambda self, text: text + pydoc.Helper.getline = lambda self, prompt: None + pydoc.TextDoc.use_bold = lambda self, text: text # if "-d" in sys.argv: # Enable this to measure startup speed diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py new file mode 100644 index 00000000000..63149f2fce8 --- /dev/null +++ b/release/scripts/modules/bpy/path.py @@ -0,0 +1,174 @@ +# ##### 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 a similar scope to os.path, containing utility +functions for dealing with paths in Blender. +""" + +import bpy as _bpy +import os as _os + +def abspath(path): + """ + Returns the absolute path relative to the current blend file using the "//" prefix. + """ + if path.startswith("//"): + return _os.path.join(_os.path.dirname(_bpy.data.filepath), path[2:]) + + return path + + +def relpath(path, start=None): + """ + Returns the path relative to the current blend file using the "//" prefix. + + :arg start: Relative to this path, when not set the current filename is used. + :type start: string + """ + if not path.startswith("//"): + if start is None: + start = _os.path.dirname(_bpy.data.filepath) + return "//" + _os.path.relpath(path, start) + + return path + + +def clean_name(name, replace="_"): + """ + Returns a name with characters replaced that may cause problems under various circumstances, such as writing to a file. + All characters besides A-Z/a-z, 0-9 are replaced with "_" + or the replace argument if defined. + """ + + unclean_chars = \ + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\ + \x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\ + \x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\ + \x2e\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x40\x5b\x5c\x5d\x5e\x60\x7b\ + \x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\ + \x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\ + \x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\ + \xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\ + \xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\ + \xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\ + \xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\ + \xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\ + \xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe" + + for ch in unclean_chars: + name = name.replace(ch, replace) + return name + + +def display_name(name): + """ + Creates a display string from name to be used menus and the user interface. + Capitalize the first letter in all lowercase names, mixed case names are kept as is. + Intended for use with filenames and module names. + """ + + name_base = _os.path.splitext(name)[0] + + # string replacements + name_base = name_base.replace("_colon_", ":") + + name_base = name_base.replace("_", " ") + + if name_base.islower(): + return name_base.capitalize() + else: + return name_base + + +def resolve_ncase(path): + """ + Resolve a case insensitive path on a case sensitive system, + returning a string with the path if found else return the original path. + """ + + import os + + def _ncase_path_found(path): + if path=='' or os.path.exists(path): + return path, True + + filename = os.path.basename(path) # filename may be a directory or a file + dirpath = os.path.dirname(path) + + suffix = "" + if not filename: # dir ends with a slash? + if len(dirpath) < len(path): + suffix = path[:len(path)-len(dirpath)] + + filename = os.path.basename(dirpath) + dirpath = os.path.dirname(dirpath) + + if not os.path.exists(dirpath): + dirpath, found = _ncase_path_found(dirpath) + + if not found: + return path, False + + # at this point, the directory exists but not the file + + # we are expecting 'dirpath' to be a directory, but it could be a file + if os.path.isdir(dirpath): + files = os.listdir(dirpath) + else: + return path, False + + filename_low = filename.lower() + f_iter_nocase = None + + for f_iter in files: + if f_iter.lower() == filename_low: + f_iter_nocase = f_iter + break + + if f_iter_nocase: + return os.path.join(dirpath, f_iter_nocase) + suffix, True + else: + # cant find the right one, just return the path as is. + return path, False + + ncase_path, found = _ncase_path_found(path) + return ncase_path if found else path + + +def ensure_ext(filepath, ext, case_sensitive=False): + """ + Return the path with the extension added its its not alredy set. + + :arg ext: The extension to check for. + :type ext: string + :arg case_sensitive: Check for matching case when comparing extensions. + :type case_sensitive: bool + """ + import os + fn_base, fn_ext = os.path.splitext(filepath) + if fn_base and fn_ext: + if (case_sensitive and ext == fn_ext) or (ext.lower() == fn_ext.lower()): + return filepath + else: + return fn_base + ext + + else: + return filepath + ext diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py index 5b0599fe25f..7cfe476c2e7 100644 --- a/release/scripts/modules/bpy/utils.py +++ b/release/scripts/modules/bpy/utils.py @@ -19,7 +19,7 @@ # <pep8 compliant> """ -This module contains utility functions spesific to blender but +This module contains utility functions specific to blender but not assosiated with blenders internal data. """ @@ -27,8 +27,8 @@ import bpy as _bpy import os as _os import sys as _sys -from _bpy import home_paths - +from _bpy import blend_paths +from _bpy import script_paths as _bpy_script_paths def _test_import(module_name, loaded_modules): import traceback @@ -59,7 +59,7 @@ def modules_from_path(path, loaded_modules): :arg path: this path is scanned for scripts and packages. :type path: string - :arg loaded_modules: alredy loaded module names, files matching these names will be ignored. + :arg loaded_modules: already loaded module names, files matching these names will be ignored. :type loaded_modules: set :return: all loaded modules. :rtype: list @@ -83,9 +83,9 @@ def modules_from_path(path, loaded_modules): modules.append(mod) return modules - -_loaded = [] # store loaded modules for reloading. -_bpy_types = __import__("bpy_types") # keep for comparisons, never ever reload this. + +_global_loaded_modules = [] # store loaded module names for reloading. +import bpy_types as _bpy_types # keep for comparisons, never ever reload this. def load_scripts(reload_scripts=False, refresh_scripts=False): @@ -100,12 +100,39 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): import traceback import time + # must be set back to True on exits + _bpy_types._register_immediate = False + t_main = time.time() loaded_modules = set() if refresh_scripts: original_modules = _sys.modules.values() + + if reload_scripts: + _bpy_types.TypeMap.clear() + _bpy_types.PropertiesMap.clear() + + def register_module_call(mod): + _bpy_types._register_module(mod.__name__) + register = getattr(mod, "register", None) + if register: + try: + register() + except: + traceback.print_exc() + else: + print("\nWarning! '%s' has no register function, this is now a requirement for registerable scripts." % mod.__file__) + + def unregister_module_call(mod): + _bpy_types._unregister_module(mod.__name__) + unregister = getattr(mod, "unregister", None) + if unregister: + try: + unregister() + except: + traceback.print_exc() def sys_path_ensure(path): if path not in _sys.path: # reloading would add twice @@ -133,63 +160,45 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): mod = test_reload(mod) if mod: - register = getattr(mod, "register", None) - if register: - try: - register() - except: - traceback.print_exc() - else: - print("\nWarning! '%s' has no register function, this is now a requirement for registerable scripts." % mod.__file__) - _loaded.append(mod) + register_module_call(mod) + _global_loaded_modules.append(mod.__name__) if reload_scripts: - # reload modules that may not be directly included - for type_class_name in dir(_bpy.types): - type_class = getattr(_bpy.types, type_class_name) - module_name = getattr(type_class, "__module__", "") - - if module_name and module_name != "bpy.types": # hard coded for C types - loaded_modules.add(module_name) - # sorting isnt needed but rather it be pradictable - for module_name in sorted(loaded_modules): - print("Reloading:", module_name) - test_reload(_sys.modules[module_name]) + # module names -> modules + _global_loaded_modules[:] = [_sys.modules[mod_name] for mod_name in _global_loaded_modules] # loop over and unload all scripts - _loaded.reverse() - for mod in _loaded: - unregister = getattr(mod, "unregister", None) - if unregister: - try: - unregister() - except: - traceback.print_exc() - _loaded[:] = [] - - for base_path in script_paths(user=False): - for path_subdir in ("ui", "op", "io", "cfg", "keyingsets"): - path = _os.path.join(base_path, path_subdir) - if _os.path.isdir(path): - sys_path_ensure(path) + _global_loaded_modules.reverse() + for mod in _global_loaded_modules: + unregister_module_call(mod) - for mod in modules_from_path(path, loaded_modules): - test_register(mod) + for mod in _global_loaded_modules: + test_reload(mod) + + _global_loaded_modules[:] = [] user_path = user_script_path() - if user_path: - for path_subdir in ("", "ui", "op", "io", "cfg", "keyingsets"): - path = _os.path.join(user_path, path_subdir) + + for base_path in script_paths(): + for path_subdir in ("", "ui", "op", "io", "cfg", "keyingsets", "modules"): + path = _os.path.join(base_path, path_subdir) if _os.path.isdir(path): sys_path_ensure(path) + # only add this to sys.modules, dont run + if path_subdir == "modules": + continue + + if user_path != base_path and path_subdir == "": + continue # avoid loading 2.4x scripts + for mod in modules_from_path(path, loaded_modules): test_register(mod) # load addons used_ext = {ext.module for ext in _bpy.context.user_preferences.addons} - paths = script_paths("addons") + paths = script_paths("addons") + script_paths("addons_contrib") for path in paths: sys_path_ensure(path) @@ -202,61 +211,11 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): print("gc.collect() -> %d" % gc.collect()) if _bpy.app.debug: - print("Time %.4f" % (time.time() - t_main)) - - -def expandpath(path): - if path.startswith("//"): - return _os.path.join(_os.path.dirname(_bpy.data.filename), path[2:]) - - return path - + print("Python Script Load Time %.4f" % (time.time() - t_main)) + + _bpy_types._register_immediate = True -_unclean_chars = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, \ - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, \ - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 46, 47, 58, 59, 60, 61, 62, 63, \ - 64, 91, 92, 93, 94, 96, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, \ - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, \ - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, \ - 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, \ - 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, \ - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, \ - 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, \ - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, \ - 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, \ - 245, 246, 247, 248, 249, 250, 251, 252, 253, 254] -_unclean_chars = ''.join([chr(i) for i in _unclean_chars]) - - -def clean_name(name, replace="_"): - """ - Returns a name with characters replaced that may cause problems under various circumstances, such as writing to a file. - All characters besides A-Z/a-z, 0-9 are replaced with "_" - or the replace argument if defined. - """ - for ch in _unclean_chars: - name = name.replace(ch, replace) - return name - - -def display_name(name): - """ - Creates a display string from name to be used menus and the user interface. - Capitalize the first letter in all lowercase names, mixed case names are kept as is. - Intended for use with filenames and module names. - """ - name_base = _os.path.splitext(name)[0] - - # string replacements - name_base = name_base.replace("_colon_", ":") - - name_base = name_base.replace("_", " ") - - if name_base.islower(): - return name_base.capitalize() - else: - return name_base # base scripts @@ -265,7 +224,7 @@ _scripts = (_os.path.normpath(_scripts), ) def user_script_path(): - path = _bpy.context.user_preferences.filepaths.python_scripts_directory + path = _bpy.context.user_preferences.filepaths.script_directory if path: path = _os.path.normpath(path) @@ -284,11 +243,11 @@ def script_paths(subdir=None, user=True): # add user scripts dir if user: - user_script_path = _bpy.context.user_preferences.filepaths.python_scripts_directory + user_script_path = _bpy.context.user_preferences.filepaths.script_directory else: user_script_path = None - for path in home_paths("scripts") + (user_script_path, ): + for path in _bpy_script_paths() + (user_script_path, ): if path: path = _os.path.normpath(path) if path not in scripts and _os.path.isdir(path): @@ -311,7 +270,55 @@ _presets = _os.path.join(_scripts[0], "presets") # FIXME - multiple paths def preset_paths(subdir): ''' - Returns a list of paths for a spesific preset. + Returns a list of paths for a specific preset. ''' return (_os.path.join(_presets, subdir), ) + + +def smpte_from_seconds(time, fps=None): + ''' + Returns an SMPTE formatted string from the time in seconds: "HH:MM:SS:FF". + + If the fps is not given the current scene is used. + ''' + import math + + if fps is None: + fps = _bpy.context.scene.render.fps + + hours = minutes = seconds = frames = 0 + + if time < 0: + time = - time + neg = "-" + else: + neg = "" + + if time >= 3600.0: # hours + hours = int(time / 3600.0) + time = time % 3600.0 + if time >= 60.0: # mins + minutes = int(time / 60.0) + time = time % 60.0 + + seconds = int(time) + frames = int(round(math.floor(((time - seconds) * fps)))) + + return "%s%02d:%02d:%02d:%02d" % (neg, hours, minutes, seconds, frames) + + +def smpte_from_frame(frame, fps=None, fps_base=None): + ''' + Returns an SMPTE formatted string from the frame: "HH:MM:SS:FF". + + If the fps and fps_base are not given the current scene is used. + ''' + + if fps is None: + fps = _bpy.context.scene.render.fps + + if fps_base is None: + fps_base = _bpy.context.scene.render.fps_base + + return smpte_from_seconds((frame * fps_base) / fps, fps) diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 16fac74b9d0..84d05a7a48d 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -19,7 +19,8 @@ # <pep8 compliant> from _bpy import types as bpy_types -from Mathutils import Vector +import _bpy +from mathutils import Vector StructRNA = bpy_types.Struct.__bases__[0] # StructRNA = bpy_types.Struct @@ -29,15 +30,62 @@ class Context(StructRNA): __slots__ = () def copy(self): + from types import BuiltinMethodType new_context = {} - generic_keys = StructRNA.__dict__.keys() - for item in dir(self): - if item not in generic_keys: - new_context[item] = getattr(self, item) + generic_attrs = list(StructRNA.__dict__.keys()) + ["bl_rna", "rna_type", "copy"] + for attr in dir(self): + if not (attr.startswith("_") or attr in generic_attrs): + value = getattr(self, attr) + if type(value) != BuiltinMethodType: + new_context[attr] = value return new_context +class Library(bpy_types.ID): + __slots__ = () + + @property + def users_id(self): + """ID datablocks which use this library""" + import bpy + + # See: readblenentry.c, IDTYPE_FLAGS_ISLINKABLE, we could make this an attribute in rna. + attr_links = "actions", "armatures", "brushes", "cameras", \ + "curves", "grease_pencil", "groups", "images", \ + "lamps", "lattices", "materials", "metaballs", \ + "meshes", "node_groups", "objects", "scenes", \ + "sounds", "textures", "texts", "fonts", "worlds" + + return tuple(id_block for attr in attr_links for id_block in getattr(bpy.data, attr) if id_block.library == self) + + +class Texture(bpy_types.ID): + __slots__ = () + + @property + def users_material(self): + """Materials that use this texture""" + import bpy + return tuple(mat for mat in bpy.data.materials if self in [slot.texture for slot in mat.texture_slots if slot]) + + @property + def users_object_modifier(self): + """Object modifiers that use this texture""" + import bpy + return tuple(obj for obj in bpy.data.objects if self in [mod.texture for mod in obj.modifiers if mod.type == 'DISPLACE']) + + +class Group(bpy_types.ID): + __slots__ = () + + @property + def users_dupli_group(self): + """The dupli group this group is used in""" + import bpy + return tuple(obj for obj in bpy.data.objects if self == obj.dupli_group) + + class Object(bpy_types.ID): __slots__ = () @@ -45,21 +93,19 @@ class Object(bpy_types.ID): def children(self): """All the children of this object""" import bpy - return [child for child in bpy.data.objects if child.parent == self] + return tuple(child for child in bpy.data.objects if child.parent == self) @property - def group_users(self): + def users_group(self): """The groups this object is in""" import bpy - name = self.name - return [group for group in bpy.data.groups if name in group.objects] + return tuple(group for group in bpy.data.groups if self in group.objects[:]) @property - def scene_users(self): + def users_scene(self): """The scenes this object is in""" import bpy - name = self.name - return [scene for scene in bpy.data.scenes if name in scene.objects] + return tuple(scene for scene in bpy.data.scenes if self in scene.objects[:]) class _GenericBone: @@ -95,19 +141,19 @@ class _GenericBone: def x_axis(self): """ Vector pointing down the x-axis of the bone. """ - return self.matrix.rotation_part() * Vector(1.0, 0.0, 0.0) + return self.matrix.rotation_part() * Vector((1.0, 0.0, 0.0)) @property def y_axis(self): """ Vector pointing down the x-axis of the bone. """ - return self.matrix.rotation_part() * Vector(0.0, 1.0, 0.0) + return self.matrix.rotation_part() * Vector((0.0, 1.0, 0.0)) @property def z_axis(self): """ Vector pointing down the x-axis of the bone. """ - return self.matrix.rotation_part() * Vector(0.0, 0.0, 1.0) + return self.matrix.rotation_part() * Vector((0.0, 0.0, 1.0)) @property def basename(self): @@ -236,8 +282,8 @@ class EditBone(StructRNA, _GenericBone): Transform the the bones head, tail, roll and envalope (when the matrix has a scale component). Expects a 4x4 or 3x3 matrix. """ - from Mathutils import Vector - z_vec = self.matrix.rotation_part() * Vector(0.0, 0.0, 1.0) + from mathutils import Vector + z_vec = self.matrix.rotation_part() * Vector((0.0, 0.0, 1.0)) self.tail = matrix * self.tail self.head = matrix * self.head scalar = matrix.median_scale @@ -260,25 +306,30 @@ class Mesh(bpy_types.ID): Make a mesh from a list of verts/edges/faces Until we have a nicer way to make geometry, use this. """ - self.add_geometry(len(verts), len(edges), len(faces)) + self.vertices.add(len(verts)) + self.edges.add(len(edges)) + self.faces.add(len(faces)) verts_flat = [f for v in verts for f in v] - self.verts.foreach_set("co", verts_flat) + self.vertices.foreach_set("co", verts_flat) del verts_flat edges_flat = [i for e in edges for i in e] - self.edges.foreach_set("verts", edges_flat) + self.edges.foreach_set("vertices", edges_flat) del edges_flat def treat_face(f): if len(f) == 3: - return f[0], f[1], f[2], 0 - elif f[3] == 0: + if f[2] == 0: + return f[2], f[0], f[1], 0 + else: + return f[0], f[1], f[2], 0 + elif f[2] == 0 or f[3] == 0: return f[3], f[0], f[1], f[2] return f faces_flat = [v for f in faces for v in treat_face(f)] - self.faces.foreach_set("verts_raw", faces_flat) + self.faces.foreach_set("vertices_raw", faces_flat) del faces_flat @property @@ -303,7 +354,7 @@ class Mesh(bpy_types.ID): edge_face_count_dict = self.edge_face_count_dict return [edge_face_count_dict.get(ed.key, 0) for ed in self.edges] - def edge_loops(self, faces=None, seams=()): + def edge_loops_from_faces(self, faces=None, seams=()): """ Edge loops defined by faces @@ -314,7 +365,7 @@ class Mesh(bpy_types.ID): return a list of edge key lists [ [(0,1), (4, 8), (3,8)], ...] - optionaly, seams are edge keys that will be removed + return a list of edge vertex index lists """ OTHER_INDEX = 2, 3, 0, 1 # opposite face index @@ -326,7 +377,7 @@ class Mesh(bpy_types.ID): for f in faces: # if len(f) == 4: - if f.verts_raw[3] != 0: + if f.vertices_raw[3] != 0: edge_keys = f.edge_keys for i, edkey in enumerate(f.edge_keys): edges.setdefault(edkey, []).append(edge_keys[OTHER_INDEX[i]]) @@ -379,13 +430,77 @@ class Mesh(bpy_types.ID): return edge_loops + def edge_loops_from_edges(self, edges=None): + """ + Edge loops defined by edges + + Takes me.edges or a list of edges and returns the edge loops + + return a list of vertex indices. + [ [1, 6, 7, 2], ...] + + closed loops have matching start and end values. + """ + line_polys = [] + + # Get edges not used by a face + if edges is None: + edges = self.edges + + if not hasattr(edges, "pop"): + edges = edges[:] + + edge_dict = {ed.key: ed for ed in self.edges if ed.select} + + while edges: + current_edge = edges.pop() + vert_end, vert_start = current_edge.vertices[:] + line_poly = [vert_start, vert_end] + + ok = True + while ok: + ok = False + #for i, ed in enumerate(edges): + i = len(edges) + while i: + i -= 1 + ed = edges[i] + v1, v2 = ed.vertices + if v1 == vert_end: + line_poly.append(v2) + vert_end = line_poly[-1] + ok = 1 + del edges[i] + # break + elif v2 == vert_end: + line_poly.append(v1) + vert_end = line_poly[-1] + ok = 1 + del edges[i] + #break + elif v1 == vert_start: + line_poly.insert(0, v2) + vert_start = line_poly[0] + ok = 1 + del edges[i] + # break + elif v2 == vert_start: + line_poly.insert(0, v1) + vert_start = line_poly[0] + ok = 1 + del edges[i] + #break + line_polys.append(line_poly) + + return line_polys + class MeshEdge(StructRNA): __slots__ = () @property def key(self): - return ord_ind(*tuple(self.verts)) + return ord_ind(*tuple(self.vertices)) class MeshFace(StructRNA): @@ -394,8 +509,8 @@ class MeshFace(StructRNA): @property def center(self): """The midpoint of the face.""" - face_verts = self.verts[:] - mesh_verts = self.id_data.verts + face_verts = self.vertices[:] + mesh_verts = self.id_data.vertices if len(face_verts) == 3: return (mesh_verts[face_verts[0]].co + mesh_verts[face_verts[1]].co + mesh_verts[face_verts[2]].co) / 3.0 else: @@ -403,17 +518,110 @@ class MeshFace(StructRNA): @property def edge_keys(self): - verts = self.verts[:] + verts = self.vertices[:] if len(verts) == 3: return ord_ind(verts[0], verts[1]), ord_ind(verts[1], verts[2]), ord_ind(verts[2], verts[0]) return ord_ind(verts[0], verts[1]), ord_ind(verts[1], verts[2]), ord_ind(verts[2], verts[3]), ord_ind(verts[3], verts[0]) +class Text(bpy_types.ID): + __slots__ = () + + def as_string(self): + """Return the text as a string.""" + return "\n".join(line.body for line in self.lines) + + def from_string(self, string): + """Replace text with this string.""" + self.clear() + self.write(string) + + @property + def users_logic(self): + """Logic bricks that use this text""" + import bpy + return tuple(obj for obj in bpy.data.objects if self in [cont.text for cont in obj.game.controllers if cont.type == 'PYTHON']) + import collections +TypeMap = {} +# Properties (IDPropertyGroup) are different from types because they need to be registered +# before adding sub properties to them, so they are registered on definition +# and unregistered on unload +PropertiesMap = {} + +# Using our own loading function we set this to false +# so when running a script directly in the text editor +# registers moduals instantly. +_register_immediate = True + +def _unregister_module(module, free=True): + for t in TypeMap.get(module, ()): + try: + bpy_types.unregister(t) + except: + import traceback + print("bpy.utils._unregister_module(): Module '%s' failed to unregister class '%s.%s'" % (module, t.__module__, t.__name__)) + traceback.print_exc() + + if free == True and module in TypeMap: + del TypeMap[module] + -class OrderedMeta(type): + for t in PropertiesMap.get(module, ()): + try: + bpy_types.unregister(t) + except: + import traceback + print("bpy.utils._unload_module(): Module '%s' failed to unregister class '%s.%s'" % (module, t.__module__, t.__name__)) + traceback.print_exc() + + if free == True and module in PropertiesMap: + del PropertiesMap[module] + + +def _register_module(module): + for t in TypeMap.get(module, ()): + try: + bpy_types.register(t) + except: + import traceback + print("bpy.utils._register_module(): Module '%s' failed to register class '%s.%s'" % (module, t.__module__, t.__name__)) + traceback.print_exc() + + +class RNAMeta(type): + @classmethod + def _register_immediate(cls): + return _register_immediate + + def __new__(cls, name, bases, classdict, **args): + result = type.__new__(cls, name, bases, classdict) + if bases and bases[0] != StructRNA: + module = result.__module__ + + ClassMap = TypeMap + + # Register right away if needed + if cls._register_immediate(): + bpy_types.register(result) + ClassMap = PropertiesMap + + # first part of packages only + if "." in module: + module = module[:module.index(".")] + + ClassMap.setdefault(module, []).append(result) + + return result + +class RNAMetaRegister(RNAMeta): + @classmethod + def _register_immediate(cls): + return True + +class OrderedMeta(RNAMeta): def __init__(cls, name, bases, attributes): super(OrderedMeta, cls).__init__(name, bases, attributes) @@ -422,7 +630,6 @@ class OrderedMeta(type): def __prepare__(name, bases, **kwargs): return collections.OrderedDict() - # Only defined so operators members can be used by accessing self.order class Operator(StructRNA, metaclass=OrderedMeta): __slots__ = () @@ -437,7 +644,12 @@ class Macro(StructRNA, metaclass=OrderedMeta): def define(self, opname): from _bpy import ops return ops.macro_define(self, opname) + +class IDPropertyGroup(StructRNA, metaclass=RNAMetaRegister): + __slots__ = () +class RenderEngine(StructRNA, metaclass=RNAMeta): + __slots__ = () class _GenericUI: __slots__ = () @@ -479,20 +691,20 @@ class _GenericUI: pass -class Panel(StructRNA, _GenericUI): +class Panel(StructRNA, _GenericUI, metaclass=RNAMeta): __slots__ = () -class Header(StructRNA, _GenericUI): +class Header(StructRNA, _GenericUI, metaclass=RNAMeta): __slots__ = () -class Menu(StructRNA, _GenericUI): +class Menu(StructRNA, _GenericUI, metaclass=RNAMeta): __slots__ = () def path_menu(self, searchpaths, operator, props_default={}): layout = self.layout - # hard coded to set the operators 'path' to the filename. + # hard coded to set the operators 'filepath' to the filename. import os import bpy.utils @@ -501,22 +713,26 @@ class Menu(StructRNA, _GenericUI): # collect paths files = [] - for path in searchpaths: - files.extend([(f, os.path.join(path, f)) for f in os.listdir(path)]) + for directory in searchpaths: + files.extend([(f, os.path.join(directory, f)) for f in os.listdir(directory)]) files.sort() - for f, path in files: + for f, filepath in files: if f.startswith("."): continue - props = layout.operator(operator, text=bpy.utils.display_name(f)) + preset_name = bpy.path.display_name(f) + props = layout.operator(operator, text=preset_name) for attr, value in props_default.items(): setattr(props, attr, value) - props.path = path + props.filepath = filepath + if operator == "script.execute_preset": + props.menu_idname = self.bl_idname + props.preset_name = preset_name def draw_preset(self, context): """Define these on the subclass diff --git a/release/scripts/modules/bpyml.py b/release/scripts/modules/bpyml.py new file mode 100644 index 00000000000..a2ba9ec8006 --- /dev/null +++ b/release/scripts/modules/bpyml.py @@ -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)) diff --git a/release/scripts/modules/bpyml_ui.py b/release/scripts/modules/bpyml_ui.py new file mode 100644 index 00000000000..ad68d1b0d7e --- /dev/null +++ b/release/scripts/modules/bpyml_ui.py @@ -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) diff --git a/release/scripts/modules/console/complete_calltip.py b/release/scripts/modules/console/complete_calltip.py index c4687b4f10b..87fac9f4c07 100644 --- a/release/scripts/modules/console/complete_calltip.py +++ b/release/scripts/modules/console/complete_calltip.py @@ -124,7 +124,7 @@ def get_argspec(func, strip_self=True, doc=None, source=None): if source is None: try: source = inspect.getsource(func) - except TypeError: + except (TypeError, IOError): source = '' if source: match = re.search(DEF_SOURCE % func_name, source, RE_FLAG) diff --git a/release/scripts/modules/console/complete_import.py b/release/scripts/modules/console/complete_import.py index 875c557f497..4b50cf6deb8 100644 --- a/release/scripts/modules/console/complete_import.py +++ b/release/scripts/modules/console/complete_import.py @@ -32,6 +32,7 @@ changes have been made: - limit list of modules to prefix in case of "from w" - sorted modules - added sphinx documentation +- complete() returns a blank list of the module isnt found """ @@ -183,3 +184,8 @@ def complete(line): if len(words) >= 3 and words[0] == 'from': mod = words[1] return filter_prefix(try_import(mod), words[-1]) + + # get here if the import is not found + # import invalidmodule + # ^, in this case return nothing + return [] diff --git a/release/scripts/modules/graphviz_export.py b/release/scripts/modules/graphviz_export.py index 1e7c7adfb7f..2389e1f9020 100644 --- a/release/scripts/modules/graphviz_export.py +++ b/release/scripts/modules/graphviz_export.py @@ -51,13 +51,13 @@ def compat_str(text, line_length=0): return text -def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, XTRA_INFO=True): +def graph_armature(obj, filepath, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, XTRA_INFO=True): CONSTRAINTS = DRIVERS = True - fileobject = open(path, "w") + fileobject = open(filepath, "w") fw = fileobject.write fw(header) - fw('label = "%s::%s" ;' % (bpy.data.filename.split("/")[-1].split("\\")[-1], obj.name)) + fw('label = "%s::%s" ;' % (bpy.data.filepath.split("/")[-1].split("\\")[-1], obj.name)) arm = obj.data @@ -66,7 +66,7 @@ def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, print("") for bone in bones: b = arm.bones[bone] - print(">>", bone, ["*>", "->"][b.connected], getattr(getattr(b, "parent", ""), "name", "")) + print(">>", bone, ["*>", "->"][b.use_connect], getattr(getattr(b, "parent", ""), "name", "")) label = [bone] bone = arm.bones[bone] @@ -103,7 +103,7 @@ def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, parent = bone.parent if parent: parent_name = parent.name - connected = bone.connected + connected = bone.use_connect elif FAKE_PARENT: parent_name = 'Object::%s' % obj.name connected = False @@ -157,17 +157,18 @@ def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, pbone = rna_path_as_pbone(rna_path) if pbone: - for target in fcurve_driver.driver.targets: - pbone_target = rna_path_as_pbone(target.data_path) - rna_path_target = target.data_path - if pbone_target: - opts = ['dir=forward', "weight=1", "arrowhead=normal", "arrowtail=none", "constraint=false", 'color="blue"', "labelfontsize=4"] # , - display_source = rna_path.replace("pose.bones", "") - display_target = rna_path_target.replace("pose.bones", "") - if XTRA_INFO: - label = "%s\\n%s" % (display_source, display_target) - opts.append('label="%s"' % compat_str(label)) - fw('"%s" -> "%s" [%s] ;\n' % (pbone_target.name, pbone.name, ','.join(opts))) + for var in fcurve_driver.driver.variables: + for target in var.targets: + pbone_target = rna_path_as_pbone(target.data_path) + rna_path_target = target.data_path + if pbone_target: + opts = ['dir=forward', "weight=1", "arrowhead=normal", "arrowtail=none", "constraint=false", 'color="blue"', "labelfontsize=4"] # , + display_source = rna_path.replace("pose.bones", "") + display_target = rna_path_target.replace("pose.bones", "") + if XTRA_INFO: + label = "%s\\n%s" % (display_source, display_target) + opts.append('label="%s"' % compat_str(label)) + fw('"%s" -> "%s" [%s] ;\n' % (pbone_target.name, pbone.name, ','.join(opts))) fw(footer) fileobject.close() @@ -177,7 +178,7 @@ def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, import sys sys.stdout.flush() ''' - print("\nSaved:", path) + print("\nSaved:", filepath) return True if __name__ == "__main__": diff --git a/release/scripts/modules/rigify/__init__.py b/release/scripts/modules/rigify/__init__.py index ee6cc934c1b..98d9bb235a2 100644 --- a/release/scripts/modules/rigify/__init__.py +++ b/release/scripts/modules/rigify/__init__.py @@ -19,7 +19,7 @@ # <pep8 compliant> import bpy -from Mathutils import Vector +from mathutils import Vector # TODO, have these in a more general module from rna_prop_ui import rna_idprop_ui_prop_get @@ -159,8 +159,8 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): # Not needed but catches any errors before duplicating validate_rig(context, obj_orig) - global_undo = context.user_preferences.edit.global_undo - context.user_preferences.edit.global_undo = False + use_global_undo = context.user_preferences.edit.use_global_undo + context.user_preferences.edit.use_global_undo = False mode_orig = context.mode rest_backup = obj_orig.data.pose_position obj_orig.data.pose_position = 'REST' @@ -191,8 +191,8 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): obj.animation_data_clear() # Select generated rig object - obj_orig.selected = False - obj.selected = True + obj_orig.select = False + obj.select = True scene.objects.active = obj # Remove all bones from the generated rig armature. @@ -212,9 +212,9 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): # Select the temp rigs for merging for objt in scene.objects: - objt.selected = False # deselect all objects - temp_rig_1.selected = True - temp_rig_2.selected = True + objt.select = False # deselect all objects + temp_rig_1.select = True + temp_rig_2.select = True scene.objects.active = temp_rig_2 # Merge the temporary rigs @@ -225,8 +225,8 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): # Select the generated rig for objt in scene.objects: - objt.selected = False # deselect all objects - obj.selected = True + objt.select = False # deselect all objects + obj.select = True scene.objects.active = obj # Copy over the pose_bone properties @@ -282,7 +282,7 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): edit_bone.head = (0.0, 0.0, 0.0) edit_bone.tail = (0.0, 1.0, 0.0) edit_bone.roll = 0.0 - edit_bone.layer = ROOT_LAYERS + edit_bone.layers = ROOT_LAYERS bpy.ops.object.mode_set(mode='OBJECT') # key: bone name @@ -412,7 +412,7 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): else: root_ebone_tmp = root_ebone - ebone.connected = False + ebone.use_connect = False ebone.parent = root_ebone_tmp ''' @@ -429,7 +429,7 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): con.target = obj con.subtarget = bone_name - if not pbone.bone.connected: + if not pbone.bone.use_connect: con = pbone.constraints.new('COPY_LOCATION') con.target = obj con.subtarget = bone_name @@ -445,33 +445,33 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True): layer_second_last[30] = True for bone_name, bone in arm.bones.items(): - bone.deform = False # Non DEF bones shouldn't deform + bone.use_deform = False # Non DEF bones shouldn't deform if bone_name.startswith(ORG_PREFIX): - bone.layer = ORG_LAYERS + bone.layers = ORG_LAYERS elif bone_name.startswith(MCH_PREFIX): # XXX fixme - bone.layer = MCH_LAYERS + bone.layers = MCH_LAYERS elif bone_name.startswith(DEF_PREFIX): # XXX fixme - bone.layer = DEF_LAYERS - bone.deform = True + bone.layers = DEF_LAYERS + bone.use_deform = True else: # Assign bone appearance if there is a widget for it obj.pose.bones[bone_name].custom_shape = context.scene.objects.get(WGT_PREFIX + bone_name) - layer_tot[:] = [max(lay) for lay in zip(layer_tot, bone.layer)] + layer_tot[:] = [max(lay) for lay in zip(layer_tot, bone.layers)] # Only for demo'ing layer_show = [a and not (b or c or d) for a, b, c, d in zip(layer_tot, ORG_LAYERS, MCH_LAYERS, DEF_LAYERS)] - arm.layer = layer_show + arm.layers = layer_show - # obj.restrict_view = True - obj.data.draw_axes = False + # obj.hide = True + obj.data.show_axes = False bpy.ops.object.mode_set(mode=mode_orig) obj_orig.data.pose_position = rest_backup obj.data.pose_position = 'POSE' obj_orig.data.pose_position = 'POSE' - context.user_preferences.edit.global_undo = global_undo + context.user_preferences.edit.use_global_undo = use_global_undo print("Done.\n") @@ -490,8 +490,8 @@ def generate_test(context, metarig_type="", GENERATE_FINAL=True): scene.objects.link(obj_new) scene.objects.active = obj_new for obj in scene.objects: - obj.selected = False - obj_new.selected = True + obj.select = False + obj_new.select = True for module_name in get_submodule_types(): if (metarig_type and module_name != metarig_type): @@ -534,10 +534,10 @@ def generate_test_all(context, GRAPH=False): new_objects = rigify.generate_test(context) if GRAPH: - base_name = os.path.splitext(bpy.data.filename)[0] + base_name = os.path.splitext(bpy.data.filepath)[0] for obj, obj_new in new_objects: for obj in (obj, obj_new): - fn = base_name + "-" + bpy.utils.clean_name(obj.name) + fn = base_name + "-" + bpy.path.clean_name(obj.name) path_dot = fn + ".dot" path_png = fn + ".png" @@ -548,11 +548,11 @@ def generate_test_all(context, GRAPH=False): i = 0 for obj, obj_new in new_objects: - obj.data.drawtype = 'STICK' + obj.data.draw_type = 'STICK' obj.location[1] += i obj_new.location[1] += i - obj_new.selected = False - obj.selected = True + obj_new.select = False + obj.select = True i += 4 diff --git a/release/scripts/modules/rigify/arm_biped.py b/release/scripts/modules/rigify/arm_biped.py index 7aa6a37304a..ac878c3c076 100644 --- a/release/scripts/modules/rigify/arm_biped.py +++ b/release/scripts/modules/rigify/arm_biped.py @@ -23,7 +23,7 @@ from math import radians, pi from rigify import RigifyError, ORG_PREFIX from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone, add_stretch_to, blend_bone_list, get_side_name, get_base_name from rna_prop_ui import rna_idprop_ui_prop_get -from Mathutils import Vector +from mathutils import Vector METARIG_NAMES = "shoulder", "arm", "forearm", "hand" @@ -37,24 +37,24 @@ def metarig_template(): bone.head[:] = 0.0000, -0.0425, 0.0000 bone.tail[:] = 0.0942, -0.0075, 0.0333 bone.roll = -0.2227 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('upper_arm') bone.head[:] = 0.1066, -0.0076, -0.0010 bone.tail[:] = 0.2855, 0.0206, -0.0104 bone.roll = 1.6152 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['shoulder'] bone = arm.edit_bones.new('forearm') bone.head[:] = 0.2855, 0.0206, -0.0104 bone.tail[:] = 0.4550, -0.0076, -0.0023 bone.roll = 1.5153 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['upper_arm'] bone = arm.edit_bones.new('hand') bone.head[:] = 0.4550, -0.0076, -0.0023 bone.tail[:] = 0.5423, -0.0146, -0.0131 bone.roll = -3.0083 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['forearm'] bpy.ops.object.mode_set(mode='OBJECT') @@ -78,7 +78,7 @@ def metarig_definition(obj, orig_bone_name): hands = [] for pbone in obj.pose.bones: index = pbone.parent_index(mt.arm_p) - if index == 2 and pbone.bone.connected and pbone.bone.parent.connected: + if index == 2 and pbone.bone.use_connect and pbone.bone.parent.use_connect: hands.append(pbone) if len(hands) != 1: @@ -106,12 +106,12 @@ def ik(obj, definitions, base_names, options): ik_chain = mt.copy(to_fmt="MCH-%s_ik", base_names=base_names, exclude_attrs=["shoulder"]) # IK needs no parent_index - ik_chain.hand_e.connected = False + ik_chain.hand_e.use_connect = False ik_chain.hand_e.parent = None - ik_chain.hand_e.local_location = False + ik_chain.hand_e.use_local_location = False ik_chain.rename("hand", get_base_name(base_names[mt.hand]) + "_ik" + get_side_name(mt.hand)) - ik_chain.arm_e.connected = False + ik_chain.arm_e.use_connect = False ik_chain.arm_e.parent = mt.shoulder_e # Add the bone used for the arms poll target @@ -119,7 +119,7 @@ def ik(obj, definitions, base_names, options): ik.pole = add_pole_target_bone(obj, mt.forearm, "elbow_target" + get_side_name(mt.forearm), mode='ZAVERAGE') ik.update() - ik.pole_e.local_location = False + ik.pole_e.use_local_location = False # option: elbow_parent elbow_parent_name = options.get("elbow_parent", "") @@ -137,8 +137,8 @@ def ik(obj, definitions, base_names, options): ik.pole_vis = add_stretch_to(obj, mt.forearm, ik.pole, "VIS-%s_ik" % base_names[mt.forearm]) ik.update() - ik.hand_vis_e.restrict_select = True - ik.pole_vis_e.restrict_select = True + ik.hand_vis_e.hide_select = True + ik.pole_vis_e.hide_select = True bpy.ops.object.mode_set(mode='OBJECT') @@ -147,9 +147,9 @@ def ik(obj, definitions, base_names, options): ik_chain.update() # Set IK dof - ik_chain.forearm_p.ik_dof_x = True - ik_chain.forearm_p.ik_dof_y = False - ik_chain.forearm_p.ik_dof_z = False + ik_chain.forearm_p.lock_ik_x = False + ik_chain.forearm_p.lock_ik_y = True + ik_chain.forearm_p.lock_ik_z = True con = ik_chain.forearm_p.constraints.new('IK') con.target = obj @@ -161,18 +161,18 @@ def ik(obj, definitions, base_names, options): con.use_stretch = True con.use_target = True con.use_rotation = False - con.chain_length = 2 + con.chain_count = 2 con.pole_angle = -pi/2 # last step setup layers if "ik_layer" in options: layer = [n==options["ik_layer"] for n in range(0,32)] else: - layer = list(mt.arm_b.layer) - ik_chain.hand_b.layer = layer - ik.hand_vis_b.layer = layer - ik.pole_b.layer = layer - ik.pole_vis_b.layer = layer + layer = list(mt.arm_b.layers) + ik_chain.hand_b.layers = layer + ik.hand_vis_b.layers = layer + ik.pole_b.layers = layer + ik.pole_vis_b.layers = layer bpy.ops.object.mode_set(mode='EDIT') # don't blend the shoulder @@ -192,12 +192,12 @@ def fk(obj, definitions, base_names, options): # shoulder is used as a hinge fk_chain.rename("shoulder", "MCH-%s_hinge" % base_names[mt.arm]) - fk_chain.shoulder_e.translate(Vector(0.0, fk_chain.shoulder_e.length / 2, 0.0)) + fk_chain.shoulder_e.translate(Vector((0.0, fk_chain.shoulder_e.length / 2, 0.0))) # upper arm constrains to this. ex.socket_e = copy_bone_simple(arm, mt.arm, "MCH-%s_socket" % base_names[mt.arm]) ex.socket = ex.socket_e.name - ex.socket_e.connected = False + ex.socket_e.use_connect = False ex.socket_e.parent = mt.shoulder_e ex.socket_e.length *= 0.5 @@ -206,11 +206,11 @@ def fk(obj, definitions, base_names, options): ex.hand_delta_e = copy_bone_simple(arm, fk_chain.hand, "MCH-delta_%s" % base_names[mt.hand], parent=True) ex.hand_delta = ex.hand_delta_e.name ex.hand_delta_e.length *= 0.5 - ex.hand_delta_e.connected = False + ex.hand_delta_e.use_connect = False if "hand_roll" in options: ex.hand_delta_e.roll += radians(options["hand_roll"]) - fk_chain.hand_e.connected = False + fk_chain.hand_e.use_connect = False fk_chain.hand_e.parent = ex.hand_delta_e bpy.ops.object.mode_set(mode='OBJECT') @@ -240,11 +240,11 @@ def fk(obj, definitions, base_names, options): con.name = "hinge" con.target = obj con.subtarget = mt.shoulder - driver_fcurve = con.driver_add("influence", 0) + driver_fcurve = con.driver_add("influence") driver = driver_fcurve.driver - controller_path = fk_chain.arm_p.path_to_id() + controller_path = fk_chain.arm_p.path_from_id() # add custom prop fk_chain.arm_p["hinge"] = 0.0 prop = rna_idprop_ui_prop_get(fk_chain.arm_p, "hinge", create=True) @@ -273,10 +273,10 @@ def fk(obj, definitions, base_names, options): if "fk_layer" in options: layer = [n==options["fk_layer"] for n in range(0,32)] else: - layer = list(mt.arm_b.layer) - fk_chain.arm_b.layer = layer - fk_chain.forearm_b.layer = layer - fk_chain.hand_b.layer = layer + layer = list(mt.arm_b.layers) + fk_chain.arm_b.layers = layer + fk_chain.forearm_b.layers = layer + fk_chain.hand_b.layers = layer # Forearm was getting wrong roll somehow. Hack to fix that. bpy.ops.object.mode_set(mode='EDIT') @@ -295,8 +295,8 @@ def deform(obj, definitions, base_names, options): # Create upper arm bones: two bones, each half of the upper arm. uarm1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True) uarm2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True) - uarm1.connected = False - uarm2.connected = False + uarm1.use_connect = False + uarm2.use_connect = False uarm2.parent = uarm1 center = uarm1.center uarm1.tail = center @@ -305,8 +305,8 @@ def deform(obj, definitions, base_names, options): # Create forearm bones: two bones, each half of the forearm. farm1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True) farm2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True) - farm1.connected = False - farm2.connected = False + farm1.use_connect = False + farm2.use_connect = False farm2.parent = farm1 center = farm1.center farm1.tail = center @@ -314,7 +314,7 @@ def deform(obj, definitions, base_names, options): # Create twist bone twist = copy_bone_simple(obj.data, definitions[2], "MCH-arm_twist") - twist.connected = False + twist.use_connect = False twist.parent = obj.data.edit_bones[definitions[3]] twist.length /= 2 diff --git a/release/scripts/modules/rigify/copy.py b/release/scripts/modules/rigify/copy.py index e0bff555a9b..c051e5bb7f6 100644 --- a/release/scripts/modules/rigify/copy.py +++ b/release/scripts/modules/rigify/copy.py @@ -33,7 +33,7 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0000, 0.0000, 1.0000 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones['Bone'] @@ -98,7 +98,7 @@ def control(obj, definitions, base_names, options): cp.cpy_p.lock_scale = tuple(mt.cpy_p.lock_scale) # Layers - cp.cpy_b.layer = list(mt.cpy_b.layer) + cp.cpy_b.layers = list(mt.cpy_b.layers) return (mt.cpy,) diff --git a/release/scripts/modules/rigify/delta.py b/release/scripts/modules/rigify/delta.py index dce03b5f412..d0b4fbccce9 100644 --- a/release/scripts/modules/rigify/delta.py +++ b/release/scripts/modules/rigify/delta.py @@ -34,18 +34,18 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = -0.0000, 0.7382, 0.1895 bone.roll = -0.0000 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('delta') bone.head[:] = -0.0497, 0.8414, 0.3530 bone.tail[:] = -0.2511, 1.1588, 0.9653 bone.roll = 2.6044 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['bonesker'] bone = arm.edit_bones.new('boney') bone.head[:] = 0.7940, 2.5592, 0.4134 bone.tail[:] = 0.7940, 3.3975, 0.4890 bone.roll = 3.1416 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['delta'] bpy.ops.object.mode_set(mode='OBJECT') @@ -67,7 +67,7 @@ def metarig_definition(obj, orig_bone_name): if len(children) != 1: raise RigifyError("only 1 child supported for delta on bone '%s'" % delta.name) - if delta.connected: + if delta.use_connect: raise RigifyError("bone cannot be connected to its parent '%s'" % delta.name) bone_definition = [delta.name, children[0].name] diff --git a/release/scripts/modules/rigify/eye_balls.py b/release/scripts/modules/rigify/eye_balls.py index 8c126151024..f65d56b9f2b 100644 --- a/release/scripts/modules/rigify/eye_balls.py +++ b/release/scripts/modules/rigify/eye_balls.py @@ -20,13 +20,92 @@ import bpy from rna_prop_ui import rna_idprop_ui_prop_get -from Mathutils import Vector +from mathutils import Vector from rigify import RigifyError from rigify_utils import copy_bone_simple #METARIG_NAMES = ("cpy",) RIG_TYPE = "eye_balls" +def addget_shape_key(obj, name="Key"): + """ Fetches a shape key, or creates it if it doesn't exist + """ + # Create a shapekey set if it doesn't already exist + if obj.data.shape_keys is None: + shape = obj.add_shape_key(name="Basis", from_mix=False) + obj.active_shape_key_index = 0 + + # Get the shapekey, or create it if it doesn't already exist + if name in obj.data.shape_keys.keys: + shape_key = obj.data.shape_keys.keys[name] + else: + shape_key = obj.add_shape_key(name=name, from_mix=False) + + return shape_key + + +def addget_shape_key_driver(obj, name="Key"): + """ Fetches the driver for the shape key, or creates it if it doesn't + already exist. + """ + driver_path = 'keys["' + name + '"].value' + fcurve = None + driver = None + new = False + if obj.data.shape_keys.animation_data is not None: + for driver_s in obj.data.shape_keys.animation_data.drivers: + if driver_s.data_path == driver_path: + fcurve = driver_s + if fcurve == None: + fcurve = obj.data.shape_keys.keys[name].driver_add("value") + fcurve.driver.type = 'AVERAGE' + new = True + + return fcurve, new + + +def create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression): + """ Creates/gets a shape key and sets up a driver for it. + + obj = armature object + bone = driving bone name + meshes = list of meshes to create the shapekey/driver on + shape_name = name of the shape key + var_name = name of the driving variable + var_path = path to the property on the bone to drive with + expression = python expression for the driver + """ + pb = obj.pose.bones + bpy.ops.object.mode_set(mode='OBJECT') + + for mesh_name in meshes: + mesh_obj = bpy.data.objects[mesh_name] + + # Add/get the shape key + shape = addget_shape_key(mesh_obj, name=shape_name) + + # Add/get the shape key driver + fcurve, a = addget_shape_key_driver(mesh_obj, name=shape_name) + + # Set up the driver + driver = fcurve.driver + driver.type = 'SCRIPTED' + driver.expression = expression + + # Get the variable, or create it if it doesn't already exist + if var_name in driver.variables: + var = driver.variables[var_name] + else: + var = driver.variables.new() + var.name = var_name + + # Set up the variable + var.type = "SINGLE_PROP" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = 'pose.bones["' + bone + '"]' + var_path + + def mark_actions(): for action in bpy.data.actions: action.tag = True @@ -55,7 +134,7 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0000, 0.0000, 1.0000 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones['Bone'] @@ -120,6 +199,12 @@ def control(obj, definitions, base_names, options): head = definitions[0] eye_target = definitions[1] + # Get list of pupil mesh objects + if "mesh" in options: + pupil_meshes = options["mesh"].replace(" ", "").split(",") + else: + pupil_meshes = [] + # Get list of eyes if "eyes" in options: eye_base_names = options["eyes"].replace(" ", "").split(",") @@ -132,7 +217,7 @@ def control(obj, definitions, base_names, options): eyes += ["ORG-"+name] # Get the average position of the eyes - center = Vector(0,0,0) + center = Vector((0, 0, 0)) for eye in eyes: center += eb[eye].head if len(eyes) != 0: @@ -197,7 +282,7 @@ def control(obj, definitions, base_names, options): prop["min"] = 0.0 prop["max"] = 1.0 - free_driver_path = pb[target_ctrl].path_to_id() + '["free"]' + free_driver_path = pb[target_ctrl].path_from_id() + '["free"]' # Constraints # Mind's eye tracks eye target control @@ -210,7 +295,7 @@ def control(obj, definitions, base_names, options): con.target = obj con.subtarget = head - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' mod = fcurve.modifiers[0] @@ -243,22 +328,66 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_X' con.frame_start = -20 con.frame_end = 20 - con.minimum = 0.0 - con.maximum = 2.0 + con.min = 0.0 + con.max = 2.0 con.target_space = 'LOCAL' + + + # Get/create the shape keys and drivers for pupil dilation + shape_names = ["PUPILS-dilate_wide", "PUPILS-dilate_narrow"] + slider_name = "pupil_dilate" + + # Set up the custom property on the bone + prop = rna_idprop_ui_prop_get(pb[target_ctrl], slider_name, create=True) + pb[target_ctrl][slider_name] = 0.0 + prop["min"] = 0.0 + prop["max"] = 1.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + if len(shape_names) > 1: + prop["min"] = -1.0 + prop["soft_min"] = -1.0 + + # Add the shape drivers + # Positive + if shape_names[0] != "": + # Set up the variables for creating the shape key driver + shape_name = shape_names[0] + var_name = slider_name.replace(".", "_").replace("-", "_") + var_path = '["' + slider_name + '"]' + if slider_name + "_fac" in options: + fac = options[slider_name + "_fac"] + else: + fac = 1.0 + expression = var_name + " * " + str(fac) + # Create the shape key driver + create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression) + # Negative + if shape_names[0] != "" and len(shape_names) > 1: + # Set up the variables for creating the shape key driver + shape_name = shape_names[1] + var_name = slider_name.replace(".", "_").replace("-", "_") + var_path = '["' + slider_name + '"]' + if slider_name + "_fac" in options: + fac = options[slider_name + "_fac"] + else: + fac = 1.0 + expression = var_name + " * " + str(fac) + " * -1" + # Create the shape key driver + create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression) # Set layers - #layer = list(bb[definitions[2]].layer) - #bb[lid1].layer = layer - #bb[lid2].layer = layer - #bb[lid3].layer = layer - #bb[lid4].layer = layer - #bb[lid5].layer = layer - #bb[lid6].layer = layer - #bb[lid7].layer = layer - #bb[lid8].layer = layer + #layer = list(bb[definitions[2]].layers) + #bb[lid1].layers = layer + #bb[lid2].layers = layer + #bb[lid3].layers = layer + #bb[lid4].layers = layer + #bb[lid5].layers = layer + #bb[lid6].layers = layer + #bb[lid7].layers = layer + #bb[lid8].layers = layer return (None,) diff --git a/release/scripts/modules/rigify/eye_lid.py b/release/scripts/modules/rigify/eye_lid.py index 6eb1ff87d82..3f336e268c6 100644 --- a/release/scripts/modules/rigify/eye_lid.py +++ b/release/scripts/modules/rigify/eye_lid.py @@ -21,7 +21,7 @@ import bpy from rna_prop_ui import rna_idprop_ui_prop_get from math import acos -from Mathutils import Vector +from mathutils import Vector from rigify import RigifyError from rigify_utils import copy_bone_simple @@ -56,7 +56,7 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0000, 0.0000, 1.0000 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones['Bone'] @@ -148,10 +148,10 @@ def deform(obj, definitions, base_names, options): eb[dlid3].parent = eb[dlid4] eb[dlid33].parent = eb[dlid3] - eb[dlid2].connected = True - eb[dlid22].connected = True - eb[dlid3].connected = True - eb[dlid33].connected = True + eb[dlid2].use_connect = True + eb[dlid22].use_connect = True + eb[dlid3].use_connect = True + eb[dlid33].use_connect = True eb[dlid1].bbone_segments = 8 eb[dlid2].bbone_segments = 8 @@ -170,10 +170,10 @@ def deform(obj, definitions, base_names, options): eb[dlid7].parent = eb[dlid8] eb[dlid77].parent = eb[dlid7] - eb[dlid6].connected = True - eb[dlid66].connected = True - eb[dlid7].connected = True - eb[dlid77].connected = True + eb[dlid6].use_connect = True + eb[dlid66].use_connect = True + eb[dlid7].use_connect = True + eb[dlid77].use_connect = True eb[dlid5].bbone_segments = 8 eb[dlid6].bbone_segments = 8 @@ -299,14 +299,15 @@ def control(obj, definitions, base_names, options): lid8 = copy_bone_simple(obj.data, definitions[9], base_names[definitions[9]]).name size = eb[lid1].length - eb[lid1].tail = eb[lid1].head + Vector(0,size,0) - eb[lid2].tail = eb[lid2].head + Vector(0,size,0) - eb[lid3].tail = eb[lid3].head + Vector(0,size,0) - eb[lid4].tail = eb[lid4].head + Vector(0,size,0) - eb[lid5].tail = eb[lid5].head + Vector(0,size,0) - eb[lid6].tail = eb[lid6].head + Vector(0,size,0) - eb[lid7].tail = eb[lid7].head + Vector(0,size,0) - eb[lid8].tail = eb[lid8].head + Vector(0,size,0) + size_y = Vector(0.0, size, 0.0) + eb[lid1].tail = eb[lid1].head + size_y + eb[lid2].tail = eb[lid2].head + size_y + eb[lid3].tail = eb[lid3].head + size_y + eb[lid4].tail = eb[lid4].head + size_y + eb[lid5].tail = eb[lid5].head + size_y + eb[lid6].tail = eb[lid6].head + size_y + eb[lid7].tail = eb[lid7].head + size_y + eb[lid8].tail = eb[lid8].head + size_y eb[lid1].roll = 0 eb[lid2].roll = 0 @@ -355,7 +356,7 @@ def control(obj, definitions, base_names, options): prop["min"] = 0.0 prop["max"] = 1.0 - close_driver_path = pb[upper_lid_ctrl].path_to_id() + '["close_action"]' + close_driver_path = pb[upper_lid_ctrl].path_from_id() + '["close_action"]' # Constraints @@ -435,10 +436,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance*2 - con.maximum = distance + con.min = -distance*2 + con.max = distance con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -454,10 +455,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance*2 - con.maximum = distance + con.min = -distance*2 + con.max = distance con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -472,10 +473,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance*2 - con.maximum = distance + con.min = -distance*2 + con.max = distance con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -490,10 +491,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance*2 - con.maximum = distance + con.min = -distance*2 + con.max = distance con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -508,10 +509,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance*2 - con.maximum = distance + con.min = -distance*2 + con.max = distance con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -527,10 +528,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance - con.maximum = distance*2 + con.min = -distance + con.max = distance*2 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -545,10 +546,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance - con.maximum = distance*2 + con.min = -distance + con.max = distance*2 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -563,10 +564,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance - con.maximum = distance*2 + con.min = -distance + con.max = distance*2 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -581,10 +582,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance - con.maximum = distance*2 + con.min = -distance + con.max = distance*2 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -599,10 +600,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'LOCATION_Y' con.frame_start = -30 con.frame_end = 30 - con.minimum = -distance - con.maximum = distance*2 + con.min = -distance + con.max = distance*2 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -614,15 +615,15 @@ def control(obj, definitions, base_names, options): # Set layers - layer = list(bb[definitions[2]].layer) - bb[lid1].layer = layer - bb[lid2].layer = layer - bb[lid3].layer = layer - bb[lid4].layer = layer - bb[lid5].layer = layer - bb[lid6].layer = layer - bb[lid7].layer = layer - bb[lid8].layer = layer + layer = list(bb[definitions[2]].layers) + bb[lid1].layers = layer + bb[lid2].layers = layer + bb[lid3].layers = layer + bb[lid4].layers = layer + bb[lid5].layers = layer + bb[lid6].layers = layer + bb[lid7].layers = layer + bb[lid8].layers = layer return (None,) @@ -647,7 +648,7 @@ def make_lid_stretch_bone(obj, name, bone1, bone2, roll_alpha): # Create the bone, pointing from bone1 to bone2 bone_e = copy_bone_simple(obj.data, bone1, name, parent=True) - bone_e.connected = False + bone_e.use_connect = False bone_e.tail = eb[bone2].head bone = bone_e.name diff --git a/release/scripts/modules/rigify/finger_curl.py b/release/scripts/modules/rigify/finger_curl.py index fcf57f81d3e..947ec75c9f8 100644 --- a/release/scripts/modules/rigify/finger_curl.py +++ b/release/scripts/modules/rigify/finger_curl.py @@ -35,18 +35,18 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0353, -0.0184, -0.0053 bone.roll = -2.8722 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('finger.02') bone.head[:] = 0.0353, -0.0184, -0.0053 bone.tail[:] = 0.0702, -0.0364, -0.0146 bone.roll = -2.7099 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['finger.01'] bone = arm.edit_bones.new('finger.03') bone.head[:] = 0.0702, -0.0364, -0.0146 bone.tail[:] = 0.0903, -0.0461, -0.0298 bone.roll = -2.1709 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['finger.02'] bpy.ops.object.mode_set(mode='OBJECT') @@ -57,31 +57,20 @@ def metarig_template(): def metarig_definition(obj, orig_bone_name): ''' The bone given is the first in a chain - Expects a chain of at least 2 children. + Expects a chain with at least 1 child of the same base name. eg. - finger -> finger_01 -> finger_02 + finger_01 -> finger_02 ''' - bone_definition = [] - orig_bone = obj.data.bones[orig_bone_name] - bone_definition.append(orig_bone.name) - - bone = orig_bone - chain = 0 - while chain < 2: # first 2 bones only have 1 child - children = bone.children - - if len(children) != 1: - raise RigifyError("expected the chain to have 2 children from bone '%s' without a fork" % orig_bone_name) - bone = children[0] - bone_definition.append(bone.name) # finger_02, finger_03 - chain += 1 - - if len(bone_definition) != len(METARIG_NAMES): - raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES)) - + bone_definition = [orig_bone.name] + + bone_definition.extend([child.name for child in orig_bone.children_recursive_basename]) + + if len(bone_definition) < 2: + raise RigifyError("expected the chain to have at least 1 child from bone '%s' without the same base name" % orig_bone_name) + return bone_definition @@ -90,11 +79,13 @@ def deform(obj, definitions, base_names, options): """ bpy.ops.object.mode_set(mode='EDIT') + three_digits = True if len(definitions) > 2 else False + # Create base digit bones: two bones, each half of the base digit. f1a = copy_bone_simple(obj.data, definitions[0], "DEF-%s.01" % base_names[definitions[0]], parent=True) f1b = copy_bone_simple(obj.data, definitions[0], "DEF-%s.02" % base_names[definitions[0]], parent=True) - f1a.connected = False - f1b.connected = False + f1a.use_connect = False + f1b.use_connect = False f1b.parent = f1a center = f1a.center f1a.tail = center @@ -102,13 +93,15 @@ def deform(obj, definitions, base_names, options): # Create the other deform bones. f2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s" % base_names[definitions[1]], parent=True) - f3 = copy_bone_simple(obj.data, definitions[2], "DEF-%s" % base_names[definitions[2]], parent=True) + if three_digits: + f3 = copy_bone_simple(obj.data, definitions[2], "DEF-%s" % base_names[definitions[2]], parent=True) # Store names before leaving edit mode f1a_name = f1a.name f1b_name = f1b.name f2_name = f2.name - f3_name = f3.name + if three_digits: + f3_name = f3.name # Leave edit mode bpy.ops.object.mode_set(mode='OBJECT') @@ -117,7 +110,8 @@ def deform(obj, definitions, base_names, options): f1a = obj.pose.bones[f1a_name] f1b = obj.pose.bones[f1b_name] f2 = obj.pose.bones[f2_name] - f3 = obj.pose.bones[f3_name] + if three_digits: + f3 = obj.pose.bones[f3_name] # Constrain the base digit's bones con = f1a.constraints.new('DAMPED_TRACK') @@ -141,15 +135,18 @@ def deform(obj, definitions, base_names, options): con.target = obj con.subtarget = definitions[1] - con = f3.constraints.new('COPY_TRANSFORMS') - con.name = "copy_transforms" - con.target = obj - con.subtarget = definitions[2] + if three_digits: + con = f3.constraints.new('COPY_TRANSFORMS') + con.name = "copy_transforms" + con.target = obj + con.subtarget = definitions[2] def main(obj, bone_definition, base_names, options): # *** EDITMODE bpy.ops.object.mode_set(mode='EDIT') + + three_digits = True if len(bone_definition) > 2 else False # get assosiated data arm = obj.data @@ -159,7 +156,8 @@ def main(obj, bone_definition, base_names, options): org_f1 = bone_definition[0] # Original finger bone 01 org_f2 = bone_definition[1] # Original finger bone 02 - org_f3 = bone_definition[2] # Original finger bone 03 + if three_digits: + org_f3 = bone_definition[2] # Original finger bone 03 # Check options if "bend_ratio" in options: @@ -179,35 +177,42 @@ def main(obj, bone_definition, base_names, options): # Create the control bone base_name = base_names[bone_definition[0]].split(".", 1)[0] - tot_len = eb[org_f1].length + eb[org_f2].length + eb[org_f3].length + if three_digits: + tot_len = eb[org_f1].length + eb[org_f2].length + eb[org_f3].length + else: + tot_len = eb[org_f1].length + eb[org_f2].length control = copy_bone_simple(arm, bone_definition[0], base_name + get_side_name(base_names[bone_definition[0]]), parent=True).name - eb[control].connected = eb[org_f1].connected + eb[control].use_connect = eb[org_f1].use_connect eb[control].parent = eb[org_f1].parent eb[control].length = tot_len # Create secondary control bones f1 = copy_bone_simple(arm, bone_definition[0], base_names[bone_definition[0]]).name f2 = copy_bone_simple(arm, bone_definition[1], base_names[bone_definition[1]]).name - f3 = copy_bone_simple(arm, bone_definition[2], base_names[bone_definition[2]]).name + if three_digits: + f3 = copy_bone_simple(arm, bone_definition[2], base_names[bone_definition[2]]).name # Create driver bones df1 = copy_bone_simple(arm, bone_definition[0], "MCH-" + base_names[bone_definition[0]]).name eb[df1].length /= 2 df2 = copy_bone_simple(arm, bone_definition[1], "MCH-" + base_names[bone_definition[1]]).name eb[df2].length /= 2 - df3 = copy_bone_simple(arm, bone_definition[2], "MCH-" + base_names[bone_definition[2]]).name - eb[df3].length /= 2 + if three_digits: + df3 = copy_bone_simple(arm, bone_definition[2], "MCH-" + base_names[bone_definition[2]]).name + eb[df3].length /= 2 # Set parents of the bones, interleaving the driver bones with the secondary control bones - eb[f3].connected = False - eb[df3].connected = False - eb[f2].connected = False - eb[df2].connected = False - eb[f1].connected = False - eb[df1].connected = eb[org_f1].connected - - eb[f3].parent = eb[df3] - eb[df3].parent = eb[f2] + if three_digits: + eb[f3].use_connect = False + eb[df3].use_connect = False + eb[f2].use_connect = False + eb[df2].use_connect = False + eb[f1].use_connect = False + eb[df1].use_connect = eb[org_f1].use_connect + + if three_digits: + eb[f3].parent = eb[df3] + eb[df3].parent = eb[f2] eb[f2].parent = eb[df2] eb[df2].parent = eb[f1] eb[f1].parent = eb[df1] @@ -215,10 +220,10 @@ def main(obj, bone_definition, base_names, options): # Set up bones for hinge if make_hinge: - socket = copy_bone_simple(arm, org_f1, "MCH-socket_" + control, parent=True).name - hinge = copy_bone_simple(arm, eb[org_f1].parent.name, "MCH-hinge_" + control).name + socket = copy_bone_simple(arm, org_f1, "MCH-socket_"+control, parent=True).name + hinge = copy_bone_simple(arm, eb[org_f1].parent.name, "MCH-hinge_"+control).name - eb[control].connected = False + eb[control].use_connect = False eb[control].parent = eb[hinge] # Create the deform rig while we're still in edit mode @@ -234,12 +239,15 @@ def main(obj, bone_definition, base_names, options): pb[control].lock_scale = True, False, True pb[f1].rotation_mode = 'YZX' pb[f2].rotation_mode = 'YZX' - pb[f3].rotation_mode = 'YZX' + if three_digits: + pb[f3].rotation_mode = 'YZX' pb[f1].lock_location = True, True, True pb[f2].lock_location = True, True, True - pb[f3].lock_location = True, True, True + if three_digits: + pb[f3].lock_location = True, True, True pb[df2].rotation_mode = 'YZX' - pb[df3].rotation_mode = 'YZX' + if three_digits: + pb[df3].rotation_mode = 'YZX' # Add the bend_ratio property to the control bone pb[control]["bend_ratio"] = bend_ratio @@ -271,18 +279,19 @@ def main(obj, bone_definition, base_names, options): con.target = obj con.subtarget = f2 - con = pb[org_f3].constraints.new('COPY_TRANSFORMS') - con.target = obj - con.subtarget = f3 + if three_digits: + con = pb[org_f3].constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = f3 if make_hinge: con = pb[hinge].constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = bb[org_f1].parent.name - hinge_driver_path = pb[control].path_to_id() + '["hinge"]' + hinge_driver_path = pb[control].path_from_id() + '["hinge"]' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -301,10 +310,15 @@ def main(obj, bone_definition, base_names, options): con.subtarget = socket # Create the drivers for the driver bones (control bone scale rotates driver bones) - controller_path = pb[control].path_to_id() # 'pose.bones["%s"]' % control_bone_name + controller_path = pb[control].path_from_id() # 'pose.bones["%s"]' % control_bone_name + + if three_digits: + finger_digits = [df2, df3] + else: + finger_digits = [df2] i = 0 - for bone in [df2, df3]: + for bone in finger_digits: # XXX - todo, any number if i == 2: @@ -334,23 +348,31 @@ def main(obj, bone_definition, base_names, options): var.targets[0].data_path = controller_path + '["bend_ratio"]' # XXX - todo, any number - if i == 0: - driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)' - elif i == 1: - driver.expression = '(-scale+1.0)*pi*2.0*br' + if three_digits: + if i == 0: + driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)' + elif i == 1: + driver.expression = '(-scale+1.0)*pi*2.0*br' + else: + driver.expression = driver.expression = '(-scale+1.0)*pi*2.0' i += 1 # Last step setup layers if "ex_layer" in options: - layer = [n == options["ex_layer"] for n in range(0, 32)] + layer = [n==options["ex_layer"] for n in range(0,32)] else: - layer = list(arm.bones[bone_definition[0]].layer) - for bone_name in [f1, f2, f3]: - arm.bones[bone_name].layer = layer + layer = list(arm.bones[bone_definition[0]].layers) + #for bone_name in [f1, f2, f3]: + # arm.bones[bone_name].layers = layer + arm.bones[f1].layers = layer + arm.bones[f2].layers = layer + if three_digits: + arm.bones[f3].layers = layer - layer = list(arm.bones[bone_definition[0]].layer) - bb[control].layer = layer + layer = list(arm.bones[bone_definition[0]].layers) + bb[control].layers = layer # no blending the result of this return None + diff --git a/release/scripts/modules/rigify/leg_biped.py b/release/scripts/modules/rigify/leg_biped.py index 0d3fbabba68..d2ddba9f549 100644 --- a/release/scripts/modules/rigify/leg_biped.py +++ b/release/scripts/modules/rigify/leg_biped.py @@ -36,36 +36,36 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0000, 0.0000, 0.2506 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('thigh') bone.head[:] = 0.1253, 0.0000, -0.0000 bone.tail[:] = 0.0752, -0.0251, -0.4260 bone.roll = 0.1171 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['hips'] bone = arm.edit_bones.new('shin') bone.head[:] = 0.0752, -0.0251, -0.4260 bone.tail[:] = 0.0752, 0.0000, -0.8771 bone.roll = 0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['thigh'] bone = arm.edit_bones.new('foot') bone.head[:] = 0.0752, 0.0000, -0.8771 bone.tail[:] = 0.1013, -0.1481, -0.9773 bone.roll = -0.4662 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['shin'] bone = arm.edit_bones.new('toe') bone.head[:] = 0.1013, -0.1481, -0.9773 bone.tail[:] = 0.1100, -0.2479, -0.9773 bone.roll = 3.1416 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['foot'] bone = arm.edit_bones.new('heel') bone.head[:] = 0.0652, 0.0501, -1.0024 bone.tail[:] = 0.0927, -0.1002, -1.0024 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['foot'] bpy.ops.object.mode_set(mode='OBJECT') @@ -109,11 +109,11 @@ def metarig_definition(obj, orig_bone_name): if len(children) != 2: raise RigifyError("expected the foot bone:'%s' to have 2 children" % bone.name) - if children[0].connected == children[1].connected: + if children[0].use_connect == children[1].use_connect: raise RigifyError("expected one bone to be connected") toe, heel = children - if heel.connected: + if heel.use_connect: toe, heel = heel, toe @@ -154,7 +154,7 @@ def ik(obj, bone_definition, base_names, options): ik.foot_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_ik" + get_side_name(base_names[mt_chain.foot])) ik.foot = ik.foot_e.name ik.foot_e.translate(mt_chain.foot_e.head - ik.foot_e.head) - ik.foot_e.local_location = False + ik.foot_e.use_local_location = False # foot roll: heel pointing backwards, half length ik.foot_roll_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_roll" + get_side_name(base_names[mt_chain.foot])) @@ -180,11 +180,11 @@ def ik(obj, bone_definition, base_names, options): # rename 'MCH-toe' --> to 'toe_ik' and make the child of ik.foot_roll_01 # ------------------ FK or IK? ik_chain.rename("toe", get_base_name(base_names[mt_chain.toe]) + "_ik" + get_side_name(base_names[mt_chain.toe])) - ik_chain.toe_e.connected = False + ik_chain.toe_e.use_connect = False ik_chain.toe_e.parent = ik.foot_roll_01_e # re-parent ik_chain.foot to the - ik_chain.foot_e.connected = False + ik_chain.foot_e.use_connect = False ik_chain.foot_e.parent = ik.foot_roll_02_e @@ -198,10 +198,10 @@ def ik(obj, bone_definition, base_names, options): ik.knee_target_e.translate(offset) ik.knee_target_e.length *= 0.5 ik.knee_target_e.parent = ik.foot_e - ik.knee_target_e.local_location = False + ik.knee_target_e.use_local_location = False # roll the bone to point up... could also point in the same direction as ik.foot_roll - # ik.foot_roll_02_e.matrix * Vector(0.0, 0.0, 1.0) # ACK!, no rest matrix in editmode + # ik.foot_roll_02_e.matrix * Vector((0.0, 0.0, 1.0)) # ACK!, no rest matrix in editmode ik.foot_roll_01_e.align_roll((0.0, 0.0, -1.0)) bpy.ops.object.mode_set(mode='OBJECT') @@ -211,9 +211,9 @@ def ik(obj, bone_definition, base_names, options): ik_chain.update() # Set IK dof - ik_chain.shin_p.ik_dof_x = True - ik_chain.shin_p.ik_dof_y = False - ik_chain.shin_p.ik_dof_z = False + ik_chain.shin_p.lock_ik_x = False + ik_chain.shin_p.lock_ik_y = True + ik_chain.shin_p.lock_ik_z = True # Set rotation modes and axis locks ik.foot_roll_p.rotation_mode = 'XYZ' @@ -225,7 +225,7 @@ def ik(obj, bone_definition, base_names, options): # IK con = ik_chain.shin_p.constraints.new('IK') - con.chain_length = 2 + con.chain_count = 2 con.iterations = 500 con.pole_angle = -pi / 2.0 con.use_tail = True @@ -256,22 +256,22 @@ def ik(obj, bone_definition, base_names, options): con.owner_space = 'LOCAL' if con_l is cons[-1][-1]: - con.minimum_x = 0.0 - con.maximum_x = 180.0 # XXX -deg + con.min_x = 0.0 + con.max_x = 180.0 # XXX -deg else: - con.minimum_x = -180.0 # XXX -deg - con.maximum_x = 0.0 + con.min_x = -180.0 # XXX -deg + con.max_x = 0.0 # last step setup layers if "ik_layer" in options: layer = [n == options["ik_layer"] for n in range(0, 32)] else: - layer = list(mt_chain.thigh_b.layer) + layer = list(mt_chain.thigh_b.layers) for attr in ik_chain.attr_names: - getattr(ik_chain, attr + "_b").layer = layer + getattr(ik_chain, attr + "_b").layers = layer for attr in ik.attr_names: - getattr(ik, attr + "_b").layer = layer + getattr(ik, attr + "_b").layers = layer bpy.ops.object.mode_set(mode='EDIT') @@ -279,7 +279,7 @@ def ik(obj, bone_definition, base_names, options): def fk(obj, bone_definition, base_names, options): - from Mathutils import Vector + from mathutils import Vector arm = obj.data # these account for all bones in METARIG_NAMES @@ -298,7 +298,7 @@ def fk(obj, bone_definition, base_names, options): ex.thigh_socket_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_socket" % base_names[mt_chain.thigh], parent=True) ex.thigh_socket = ex.thigh_socket_e.name - ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector(0.0, 0.0, ex.thigh_socket_e.length / 4.0) + ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector((0.0, 0.0, ex.thigh_socket_e.length / 4.0)) ex.thigh_hinge_e = copy_bone_simple(arm, mt.hips, "MCH-%s_hinge" % base_names[mt_chain.thigh], parent=False) ex.thigh_hinge = ex.thigh_hinge_e.name @@ -312,11 +312,11 @@ def fk(obj, bone_definition, base_names, options): foot = foot_e.name foot_e.translate(mt_chain.foot_e.head - foot_e.head) foot_e.parent = fk_chain.shin_e - foot_e.connected = fk_chain.foot_e.connected - fk_chain.foot_e.connected = False + foot_e.use_connect = fk_chain.foot_e.use_connect + fk_chain.foot_e.use_connect = False fk_chain.foot_e.parent = foot_e - fk_chain.thigh_e.connected = False + fk_chain.thigh_e.use_connect = False fk_chain.thigh_e.parent = ex.thigh_hinge_e bpy.ops.object.mode_set(mode='OBJECT') @@ -349,9 +349,9 @@ def fk(obj, bone_definition, base_names, options): con.subtarget = mt.hips # add driver - hinge_driver_path = fk_chain.thigh_p.path_to_id() + '["hinge"]' + hinge_driver_path = fk_chain.thigh_p.path_from_id() + '["hinge"]' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -370,12 +370,12 @@ def fk(obj, bone_definition, base_names, options): if "fk_layer" in options: layer = [n == options["fk_layer"] for n in range(0, 32)] else: - layer = list(mt_chain.thigh_b.layer) + layer = list(mt_chain.thigh_b.layers) for attr in fk_chain.attr_names: - getattr(fk_chain, attr + "_b").layer = layer + getattr(fk_chain, attr + "_b").layers = layer for attr in ex.attr_names: - getattr(ex, attr + "_b").layer = layer - arm.bones[foot].layer = layer + getattr(ex, attr + "_b").layers = layer + arm.bones[foot].layers = layer bpy.ops.object.mode_set(mode='EDIT') @@ -390,8 +390,8 @@ def deform(obj, definitions, base_names, options): # Create upper leg bones: two bones, each half of the upper leg. uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True) uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True) - uleg1.connected = False - uleg2.connected = False + uleg1.use_connect = False + uleg2.use_connect = False uleg2.parent = uleg1 center = uleg1.center uleg1.tail = center @@ -400,8 +400,8 @@ def deform(obj, definitions, base_names, options): # Create lower leg bones: two bones, each half of the lower leg. lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True) lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True) - lleg1.connected = False - lleg2.connected = False + lleg1.use_connect = False + lleg2.use_connect = False lleg2.parent = lleg1 center = lleg1.center lleg1.tail = center @@ -410,7 +410,7 @@ def deform(obj, definitions, base_names, options): # Create a bone for the second lower leg deform bone to twist with twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist") twist.length /= 4 - twist.connected = False + twist.use_connect = False twist.parent = obj.data.edit_bones[definitions[3]] # Create foot bone diff --git a/release/scripts/modules/rigify/leg_quadruped.py b/release/scripts/modules/rigify/leg_quadruped.py index c21680740bd..739a6402c4b 100644 --- a/release/scripts/modules/rigify/leg_quadruped.py +++ b/release/scripts/modules/rigify/leg_quadruped.py @@ -23,7 +23,7 @@ from rna_prop_ui import rna_idprop_ui_prop_get from math import pi from rigify import RigifyError from rigify_utils import bone_class_instance, copy_bone_simple, get_side_name, get_base_name -from Mathutils import Vector +from mathutils import Vector METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe" @@ -37,30 +37,30 @@ def metarig_template(): bone.head[:] = -0.0728, -0.2427, 0.0000 bone.tail[:] = -0.0728, -0.2427, 0.2427 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('thigh') bone.head[:] = 0.0000, 0.0000, -0.0000 bone.tail[:] = 0.0813, -0.2109, -0.3374 bone.roll = -0.4656 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['body'] bone = arm.edit_bones.new('shin') bone.head[:] = 0.0813, -0.2109, -0.3374 bone.tail[:] = 0.0714, -0.0043, -0.5830 bone.roll = -0.2024 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['thigh'] bone = arm.edit_bones.new('foot') bone.head[:] = 0.0714, -0.0043, -0.5830 bone.tail[:] = 0.0929, -0.0484, -0.7652 bone.roll = -0.3766 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['shin'] bone = arm.edit_bones.new('toe') bone.head[:] = 0.0929, -0.0484, -0.7652 bone.tail[:] = 0.1146, -0.1244, -0.7652 bone.roll = -0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['foot'] bpy.ops.object.mode_set(mode='OBJECT') @@ -120,7 +120,7 @@ def ik(obj, bone_definition, base_names, options): ik_chain = mt_chain.copy(to_fmt="MCH-%s.ik", base_names=base_names) - ik_chain.thigh_e.connected = False + ik_chain.thigh_e.use_connect = False ik_chain.thigh_e.parent = mt.hips_e ik_chain.foot_e.parent = None @@ -128,10 +128,10 @@ def ik(obj, bone_definition, base_names, options): ik_chain.rename("toe", get_base_name(base_names[bone_definition[4]]) + "_ik" + get_side_name(base_names[bone_definition[4]])) # keep the foot_ik as the parent - ik_chain.toe_e.connected = False + ik_chain.toe_e.use_connect = False # Foot uses pose space, not local space, for translation - ik_chain.foot_e.local_location = False + ik_chain.foot_e.use_local_location = False # must be after disconnecting the toe ik_chain.foot_e.align_orientation(mt_chain.toe_e) @@ -141,7 +141,7 @@ def ik(obj, bone_definition, base_names, options): # knee rotator knee_rotator = copy_bone_simple(arm, mt_chain.toe, "knee_rotator" + get_side_name(base_names[mt_chain.foot]), parent=True).name - eb[knee_rotator].connected = False + eb[knee_rotator].use_connect = False eb[knee_rotator].parent = eb[mt.hips] eb[knee_rotator].head = eb[ik_chain.thigh].head eb[knee_rotator].tail = eb[knee_rotator].head + eb[mt_chain.toe].vector @@ -156,11 +156,11 @@ def ik(obj, bone_definition, base_names, options): # then align it with the foot but reverse direction. ik.foot_roll_e = copy_bone_simple(arm, mt_chain.toe, get_base_name(base_names[mt_chain.foot]) + "_roll" + get_side_name(base_names[mt_chain.foot])) ik.foot_roll = ik.foot_roll_e.name - ik.foot_roll_e.connected = False + ik.foot_roll_e.use_connect = False ik.foot_roll_e.parent = ik_chain.foot_e ik.foot_roll_e.head -= mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length ik.foot_roll_e.tail = ik.foot_roll_e.head - (mt_chain.foot_e.vector.normalize() * mt_chain.toe_e.length) - ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotation_part() * Vector(0.0, 0.0, -1.0)) + ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotation_part() * Vector((0.0, 0.0, -1.0))) # MCH-foot ik.foot_roll_01_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot]) @@ -175,7 +175,7 @@ def ik(obj, bone_definition, base_names, options): ik.foot_target_e.parent = ik.foot_roll_01_e ik.foot_target_e.align_orientation(ik_chain.foot_e) ik.foot_target_e.length = ik_chain.foot_e.length / 2.0 - ik.foot_target_e.connected = True + ik.foot_target_e.use_connect = True # MCH-foot.02 child of MCH-foot ik.foot_roll_02_e = copy_bone_simple(arm, mt_chain.foot, "MCH-%s_02" % base_names[mt_chain.foot]) @@ -207,13 +207,13 @@ def ik(obj, bone_definition, base_names, options): prop["min"] = 0.0 prop["max"] = 1.0 - ik_driver_path = pb[ik_chain.foot].path_to_id() + '["ik"]' + ik_driver_path = pb[ik_chain.foot].path_from_id() + '["ik"]' # simple constraining of orig bones con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik_chain.thigh - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -225,7 +225,7 @@ def ik(obj, bone_definition, base_names, options): con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik_chain.shin - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -237,7 +237,7 @@ def ik(obj, bone_definition, base_names, options): con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik.foot_roll_02 - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -249,7 +249,7 @@ def ik(obj, bone_definition, base_names, options): con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS') con.target = obj con.subtarget = ik_chain.toe - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -268,7 +268,7 @@ def ik(obj, bone_definition, base_names, options): # IK con = ik_chain.shin_p.constraints.new('IK') - con.chain_length = 2 + con.chain_count = 2 con.iterations = 500 con.pole_angle = -90.0 # XXX - in deg! con.use_tail = True @@ -289,12 +289,12 @@ def ik(obj, bone_definition, base_names, options): if "ik_layer" in options: layer = [n==options["ik_layer"] for n in range(0,32)] else: - layer = list(mt_chain.thigh_b.layer) + layer = list(mt_chain.thigh_b.layers) for attr in ik_chain.attr_names: - obj.data.bones[getattr(ik_chain, attr)].layer = layer + obj.data.bones[getattr(ik_chain, attr)].layers = layer for attr in ik.attr_names: - obj.data.bones[getattr(ik, attr)].layer = layer - obj.data.bones[knee_rotator].layer = layer + obj.data.bones[getattr(ik, attr)].layers = layer + obj.data.bones[knee_rotator].layers = layer return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe @@ -325,7 +325,7 @@ def fk(obj, bone_definition, base_names, options): eb[hinge].length = eb[mt.hips].length / 2 # Make leg child of hinge - eb[fk_chain.thigh].connected = False + eb[fk_chain.thigh].use_connect = False eb[fk_chain.thigh].parent = eb[hinge] @@ -369,9 +369,9 @@ def fk(obj, bone_definition, base_names, options): prop["min"] = 0.0 prop["max"] = 1.0 - hinge_driver_path = pb[fk_chain.thigh].path_to_id() + '["hinge"]' + hinge_driver_path = pb[fk_chain.thigh].path_from_id() + '["hinge"]' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -396,8 +396,8 @@ def deform(obj, definitions, base_names, options): # Create upper leg bones: two bones, each half of the upper leg. uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True) uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True) - uleg1.connected = False - uleg2.connected = False + uleg1.use_connect = False + uleg2.use_connect = False uleg2.parent = uleg1 center = uleg1.center uleg1.tail = center @@ -406,8 +406,8 @@ def deform(obj, definitions, base_names, options): # Create lower leg bones: two bones, each half of the lower leg. lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True) lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True) - lleg1.connected = False - lleg2.connected = False + lleg1.use_connect = False + lleg2.use_connect = False lleg2.parent = lleg1 center = lleg1.center lleg1.tail = center @@ -416,7 +416,7 @@ def deform(obj, definitions, base_names, options): # Create a bone for the second lower leg deform bone to twist with twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist") twist.length /= 4 - twist.connected = False + twist.use_connect = False twist.parent = obj.data.edit_bones[definitions[3]] # Create foot bone diff --git a/release/scripts/modules/rigify/mouth.py b/release/scripts/modules/rigify/mouth.py index 4defd28f56a..ce232b91e7b 100644 --- a/release/scripts/modules/rigify/mouth.py +++ b/release/scripts/modules/rigify/mouth.py @@ -21,7 +21,7 @@ import bpy from rna_prop_ui import rna_idprop_ui_prop_get from math import acos, pi -from Mathutils import Vector +from mathutils import Vector from rigify import RigifyError from rigify_utils import copy_bone_simple @@ -77,7 +77,7 @@ def addget_shape_key_driver(obj, name="Key"): if driver_s.data_path == driver_path: fcurve = driver_s if fcurve == None: - fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0) + fcurve = obj.data.shape_keys.keys[name].driver_add("value") fcurve.driver.type = 'AVERAGE' new = True @@ -93,7 +93,7 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0000, 0.0000, 1.0000 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones['Bone'] @@ -151,8 +151,8 @@ def deform(obj, definitions, base_names, options): eb[spread_l_2].tail = eb[definitions[5]].head eb[spread_l_1].roll = 0 eb[spread_l_2].roll = 0 - eb[spread_l_1].connected = False - eb[spread_l_2].connected = False + eb[spread_l_1].use_connect = False + eb[spread_l_2].use_connect = False eb[spread_l_1].parent = eb[definitions[6]] eb[spread_l_2].parent = eb[definitions[6]] @@ -162,8 +162,8 @@ def deform(obj, definitions, base_names, options): eb[spread_r_2].tail = eb[definitions[3]].head eb[spread_r_1].roll = 0 eb[spread_r_2].roll = 0 - eb[spread_r_1].connected = False - eb[spread_r_2].connected = False + eb[spread_r_1].use_connect = False + eb[spread_r_2].use_connect = False eb[spread_r_1].parent = eb[definitions[2]] eb[spread_r_2].parent = eb[definitions[2]] @@ -171,9 +171,9 @@ def deform(obj, definitions, base_names, options): # Jaw open bones (for driving corrective shape keys) jopen1 = copy_bone_simple(obj.data, jaw, "MCH-"+base_names[jaw]+".track1", parent=True).name - eb[jopen1].connected = False + eb[jopen1].use_connect = False eb[jopen1].head = eb[jaw].tail - eb[jopen1].tail = eb[jopen1].head + Vector(0, 0, eb[jaw].length/4) + eb[jopen1].tail = eb[jopen1].head + Vector((0, 0, eb[jaw].length/4)) jopen2 = copy_bone_simple(obj.data, jopen1, "MCH-"+base_names[jaw]+".track2").name eb[jopen2].parent = eb[jaw] @@ -426,8 +426,8 @@ def control(obj, definitions, base_names, options): # Jaw open tracker jopent = copy_bone_simple(obj.data, jaw_e.name, "MCH-"+base_names[jaw_e.name]+".track", parent=True).name - eb[jopent].connected = False - eb[jopent].tail = jaw_e.tail + Vector(0,0,jaw_e.length) + eb[jopent].use_connect = False + eb[jopent].tail = jaw_e.tail + Vector((0.0, 0.0, jaw_e.length)) eb[jopent].head = jaw_e.tail bpy.ops.object.mode_set(mode='OBJECT') @@ -448,7 +448,7 @@ def control(obj, definitions, base_names, options): prop["min"] = 0.0 prop["max"] = 1.0 - open_driver_path = pb[lip1].path_to_id() + '["open_action"]' + open_driver_path = pb[lip1].path_from_id() + '["open_action"]' # Constraints @@ -458,7 +458,7 @@ def control(obj, definitions, base_names, options): con.target = obj con.subtarget = jaw con.head_tail = 1.0 - con.original_length = bb[jopent].length + con.rest_length = bb[jopent].length con.volume = 'NO_VOLUME' # Head lips to jaw lips @@ -545,10 +545,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -563,10 +563,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -581,10 +581,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -599,10 +599,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -617,10 +617,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -635,10 +635,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -653,10 +653,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -671,10 +671,10 @@ def control(obj, definitions, base_names, options): con.transform_channel = 'SCALE_Y' con.frame_start = 0 con.frame_end = 60 - con.minimum = 0.0 - con.maximum = 1.0 + con.min = 0.0 + con.max = 1.0 con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -684,15 +684,15 @@ def control(obj, definitions, base_names, options): # Set layers - layer = list(bb[definitions[2]].layer) - bb[lip1].layer = layer - bb[lip2].layer = layer - bb[lip3].layer = layer - bb[lip4].layer = layer - bb[lip5].layer = layer - bb[lip6].layer = layer - bb[lip7].layer = layer - bb[lip8].layer = layer + layer = list(bb[definitions[2]].layers) + bb[lip1].layers = layer + bb[lip2].layers = layer + bb[lip3].layers = layer + bb[lip4].layers = layer + bb[lip5].layers = layer + bb[lip6].layers = layer + bb[lip7].layers = layer + bb[lip8].layers = layer return (None,) @@ -717,7 +717,7 @@ def make_lip_stretch_bone(obj, name, bone1, bone2, roll_alpha): # Create the bone, pointing from bone1 to bone2 bone_e = copy_bone_simple(obj.data, bone1, name, parent=True) - bone_e.connected = False + bone_e.use_connect = False bone_e.tail = eb[bone2].head bone = bone_e.name diff --git a/release/scripts/modules/rigify/neck.py b/release/scripts/modules/rigify/neck.py new file mode 100644 index 00000000000..56717f0ebb0 --- /dev/null +++ b/release/scripts/modules/rigify/neck.py @@ -0,0 +1,344 @@ +# ##### 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 +from rigify import RigifyError +from rigify_utils import bone_class_instance, copy_bone_simple +from rna_prop_ui import rna_idprop_ui_prop_get + + + +def metarig_template(): + # TODO: + ## generated by rigify.write_meta_rig + #bpy.ops.object.mode_set(mode='EDIT') + #obj = bpy.context.active_object + #arm = obj.data + #bone = arm.edit_bones.new('body') + #bone.head[:] = 0.0000, -0.0276, -0.1328 + #bone.tail[:] = 0.0000, -0.0170, -0.0197 + #bone.roll = 0.0000 + #bone.use_connect = False + #bone = arm.edit_bones.new('head') + #bone.head[:] = 0.0000, -0.0170, -0.0197 + #bone.tail[:] = 0.0000, 0.0726, 0.1354 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['body'] + #bone = arm.edit_bones.new('neck.01') + #bone.head[:] = 0.0000, -0.0170, -0.0197 + #bone.tail[:] = 0.0000, -0.0099, 0.0146 + #bone.roll = 0.0000 + #bone.use_connect = False + #bone.parent = arm.edit_bones['head'] + #bone = arm.edit_bones.new('neck.02') + #bone.head[:] = 0.0000, -0.0099, 0.0146 + #bone.tail[:] = 0.0000, -0.0242, 0.0514 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.01'] + #bone = arm.edit_bones.new('neck.03') + #bone.head[:] = 0.0000, -0.0242, 0.0514 + #bone.tail[:] = 0.0000, -0.0417, 0.0868 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.02'] + #bone = arm.edit_bones.new('neck.04') + #bone.head[:] = 0.0000, -0.0417, 0.0868 + #bone.tail[:] = 0.0000, -0.0509, 0.1190 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.03'] + #bone = arm.edit_bones.new('neck.05') + #bone.head[:] = 0.0000, -0.0509, 0.1190 + #bone.tail[:] = 0.0000, -0.0537, 0.1600 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.04'] + # + #bpy.ops.object.mode_set(mode='OBJECT') + #pbone = obj.pose.bones['head'] + #pbone['type'] = 'neck_flex' + pass + + +def metarig_definition(obj, orig_bone_name): + ''' + The bone given is neck_01, its parent is the body + eg. + body -> neck_01 -> neck_02 -> neck_03.... etc + ''' + arm = obj.data + neck = arm.bones[orig_bone_name] + body = neck.parent + + bone_definition = [body.name, neck.name] + bone_definition.extend([child.name for child in neck.children_recursive_basename]) + return bone_definition + + +def deform(obj, definitions, base_names, options): + for org_bone_name in definitions[1:]: + bpy.ops.object.mode_set(mode='EDIT') + + # Create deform bone. + bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True) + + # Store name before leaving edit mode + bone_name = bone.name + + # Leave edit mode + bpy.ops.object.mode_set(mode='OBJECT') + + # Get the pose bone + bone = obj.pose.bones[bone_name] + + # Constrain to the original bone + # XXX. Todo, is this needed if the bone is connected to its parent? + con = bone.constraints.new('COPY_TRANSFORMS') + con.name = "copy_loc" + con.target = obj + con.subtarget = org_bone_name + + +def main(obj, bone_definition, base_names, options): + from mathutils import Vector + + arm = obj.data + eb = obj.data.edit_bones + bb = obj.data.bones + pb = obj.pose.bones + + body = bone_definition[0] + + # Create the neck and head control bones + if "head_name" in options: + head_name = options["head_name"] + else: + head_name = "head" + + neck_name = base_names[bone_definition[1]].split(".")[0] + + neck_ctrl = copy_bone_simple(arm, bone_definition[1], neck_name).name + head_ctrl = copy_bone_simple(arm, bone_definition[len(bone_definition)-1], head_name).name + eb[head_ctrl].tail += eb[neck_ctrl].head - eb[head_ctrl].head + eb[head_ctrl].head = eb[neck_ctrl].head + + # Create hinge and socket bones + neck_hinge = copy_bone_simple(arm, bone_definition[0], "MCH-" + neck_name + "_hinge").name + head_hinge = copy_bone_simple(arm, neck_ctrl, "MCH-" + head_name + "_hinge").name + eb[neck_hinge].tail += eb[neck_ctrl].head - eb[neck_hinge].head + eb[neck_hinge].head = eb[neck_ctrl].head + eb[head_hinge].tail += eb[neck_ctrl].head - eb[head_hinge].head + eb[head_hinge].head = eb[neck_ctrl].head + + neck_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + neck_name + "_socket").name + head_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + head_name + "_socket").name + + # Parent-child relationships between the body, hinges, controls, and sockets + eb[neck_ctrl].parent = eb[neck_hinge] + eb[head_ctrl].parent = eb[head_hinge] + + eb[neck_socket].parent = eb[body] + eb[head_socket].parent = eb[body] + + # Create neck bones + neck = [] # neck bones + neck_neck = [] # bones constrained to neck control + neck_head = [] # bones constrained to head control + for i in range(1, len(bone_definition)): + # Create bones + neck_bone = copy_bone_simple(arm, bone_definition[i], base_names[bone_definition[i]]).name + neck_neck_bone = copy_bone_simple(arm, neck_ctrl, "MCH-" + base_names[bone_definition[i]] + ".neck").name + neck_head_bone = copy_bone_simple(arm, head_ctrl, "MCH-" + base_names[bone_definition[i]] + ".head").name + + # Move them all to the same place + eb[neck_neck_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head + eb[neck_head_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head + eb[neck_neck_bone].head = eb[neck_bone].head + eb[neck_head_bone].head = eb[neck_bone].head + + # Parent/child relationships + eb[neck_bone].parent = eb[neck_head_bone] + eb[neck_head_bone].parent = eb[neck_neck_bone] + + if i > 1: + eb[neck_neck_bone].parent = eb[neck[i-2]] + else: + eb[neck_neck_bone].parent = eb[body] + + # Add them to the lists + neck += [neck_bone] + neck_neck += [neck_neck_bone] + neck_head += [neck_head_bone] + + # Create deformation rig + deform(obj, bone_definition, base_names, options) + + + bpy.ops.object.mode_set(mode='OBJECT') + + # Axis locks + pb[neck_ctrl].lock_location = True, True, True + pb[head_ctrl].lock_location = True, True, True + + for bone in neck: + pb[bone].lock_location = True, True, True + + # Neck hinge + prop = rna_idprop_ui_prop_get(pb[neck_ctrl], "hinge", create=True) + pb[neck_ctrl]["hinge"] = 0.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + prop["hard_min"] = 0.0 + prop["hard_max"] = 1.0 + + con = pb[neck_hinge].constraints.new('COPY_LOCATION') + con.name = "socket" + con.target = obj + con.subtarget = neck_socket + + con = pb[neck_hinge].constraints.new('COPY_ROTATION') + con.name = "hinge" + con.target = obj + con.subtarget = body + + hinge_driver_path = pb[neck_ctrl].path_from_id() + '["hinge"]' + + fcurve = con.driver_add("influence") + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'AVERAGE' + var.name = "var" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = hinge_driver_path + + mod = fcurve.modifiers[0] + mod.poly_order = 1 + mod.coefficients[0] = 1.0 + mod.coefficients[1] = -1.0 + + # Head hinge + prop = rna_idprop_ui_prop_get(pb[head_ctrl], "hinge", create=True) + pb[head_ctrl]["hinge"] = 0.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + prop["hard_min"] = 0.0 + prop["hard_max"] = 1.0 + + con = pb[head_hinge].constraints.new('COPY_LOCATION') + con.name = "socket" + con.target = obj + con.subtarget = head_socket + + con = pb[head_hinge].constraints.new('COPY_ROTATION') + con.name = "hinge" + con.target = obj + con.subtarget = neck_ctrl + + hinge_driver_path = pb[head_ctrl].path_from_id() + '["hinge"]' + + fcurve = con.driver_add("influence") + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'AVERAGE' + var.name = "var" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = hinge_driver_path + + mod = fcurve.modifiers[0] + mod.poly_order = 1 + mod.coefficients[0] = 1.0 + mod.coefficients[1] = -1.0 + + # Neck rotation constraints + for i in range(0, len(neck_neck)): + con = pb[neck_neck[i]].constraints.new('COPY_ROTATION') + con.name = "neck rotation" + con.target = obj + con.subtarget = neck_ctrl + con.influence = (i+1) / len(neck_neck) + + + # Head rotation constraints/drivers + prop = rna_idprop_ui_prop_get(pb[head_ctrl], "extent", create=True) + if "extent" in options: + pb[head_ctrl]["extent"] = options["extent"] + else: + pb[head_ctrl]["extent"] = 0.5 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + prop["hard_min"] = 0.0 + prop["hard_max"] = 1.0 + + extent_prop_path = pb[head_ctrl].path_from_id() + '["extent"]' + + for i in range(0, len(neck_head)): + con = pb[neck_head[i]].constraints.new('COPY_ROTATION') + con.name = "head rotation" + con.target = obj + con.subtarget = head_ctrl + + if i < (len(neck_head)-1): + inf = (i+1) / len(neck_head) + + fcurve = con.driver_add("influence") + driver = fcurve.driver + var = driver.variables.new() + var.name = "ext" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = extent_prop_path + + driver.expression = "0 if ext == 0 else (((%s-1)/ext)+1)" % inf + else: + con.influence = 1.0 + + # Constrain original bones to the neck bones + for i in range(0, len(neck)): + con = pb[bone_definition[i+1]].constraints.new('COPY_TRANSFORMS') + con.name = "copy_transform" + con.target = obj + con.subtarget = neck[i] + + + # Set the controls' custom shapes to use other bones for transforms + pb[neck_ctrl].custom_shape_transform = pb[bone_definition[len(bone_definition)//2]] + pb[head_ctrl].custom_shape_transform = pb[bone_definition[len(bone_definition)-1]] + + + # last step setup layers + if "ex_layer" in options: + layer = [n==options["ex_layer"] for n in range(0,32)] + else: + layer = list(arm.bones[bone_definition[1]].layers) + for bone in neck: + bb[bone].layers = layer + + layer = list(arm.bones[bone_definition[1]].layers) + bb[neck_ctrl].layers = layer + bb[head_ctrl].layers = layer + + + # no blending the result of this + return None + diff --git a/release/scripts/modules/rigify/neck_flex.py b/release/scripts/modules/rigify/neck_flex.py index e45d128433a..7daf3d3bb4b 100644 --- a/release/scripts/modules/rigify/neck_flex.py +++ b/release/scripts/modules/rigify/neck_flex.py @@ -36,42 +36,42 @@ def metarig_template(): bone.head[:] = 0.0000, -0.0276, -0.1328 bone.tail[:] = 0.0000, -0.0170, -0.0197 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('head') bone.head[:] = 0.0000, -0.0170, -0.0197 bone.tail[:] = 0.0000, 0.0726, 0.1354 bone.roll = 0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['body'] bone = arm.edit_bones.new('neck.01') bone.head[:] = 0.0000, -0.0170, -0.0197 bone.tail[:] = 0.0000, -0.0099, 0.0146 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['head'] bone = arm.edit_bones.new('neck.02') bone.head[:] = 0.0000, -0.0099, 0.0146 bone.tail[:] = 0.0000, -0.0242, 0.0514 bone.roll = 0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['neck.01'] bone = arm.edit_bones.new('neck.03') bone.head[:] = 0.0000, -0.0242, 0.0514 bone.tail[:] = 0.0000, -0.0417, 0.0868 bone.roll = 0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['neck.02'] bone = arm.edit_bones.new('neck.04') bone.head[:] = 0.0000, -0.0417, 0.0868 bone.tail[:] = 0.0000, -0.0509, 0.1190 bone.roll = 0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['neck.03'] bone = arm.edit_bones.new('neck.05') bone.head[:] = 0.0000, -0.0509, 0.1190 bone.tail[:] = 0.0000, -0.0537, 0.1600 bone.roll = 0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['neck.04'] bpy.ops.object.mode_set(mode='OBJECT') @@ -125,7 +125,7 @@ def deform(obj, definitions, base_names, options): def main(obj, bone_definition, base_names, options): - from Mathutils import Vector + from mathutils import Vector arm = obj.data @@ -156,7 +156,7 @@ def main(obj, bone_definition, base_names, options): # Copy the head bone and offset ex.head_e = copy_bone_simple(arm, mt.head, "MCH-%s" % base_names[mt.head], parent=True) - ex.head_e.connected = False + ex.head_e.use_connect = False ex.head = ex.head_e.name # offset head_length = ex.head_e.length @@ -165,7 +165,7 @@ def main(obj, bone_definition, base_names, options): # Yes, use the body bone but call it a head hinge ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH-%s_hinge" % base_names[mt.head], parent=False) - ex.head_hinge_e.connected = False + ex.head_hinge_e.use_connect = False ex.head_hinge = ex.head_hinge_e.name ex.head_hinge_e.head.y += head_length / 4.0 ex.head_hinge_e.tail.y += head_length / 4.0 @@ -173,10 +173,10 @@ def main(obj, bone_definition, base_names, options): # Insert the neck socket, the head copys this loation ex.neck_socket_e = arm.edit_bones.new("MCH-%s_socked" % neck_chain_basename) ex.neck_socket = ex.neck_socket_e.name - ex.neck_socket_e.connected = False + ex.neck_socket_e.use_connect = False ex.neck_socket_e.parent = mt.body_e ex.neck_socket_e.head = mt.head_e.head - ex.neck_socket_e.tail = mt.head_e.head - Vector(0.0, neck_chain_segment_length / 2.0, 0.0) + ex.neck_socket_e.tail = mt.head_e.head - Vector((0.0, neck_chain_segment_length / 2.0, 0.0)) ex.neck_socket_e.roll = 0.0 @@ -195,9 +195,9 @@ def main(obj, bone_definition, base_names, options): neck_e_parent.roll = mt.head_e.roll orig_parent = neck_e.parent - neck_e.connected = False + neck_e.use_connect = False neck_e.parent = neck_e_parent - neck_e_parent.connected = False + neck_e_parent.use_connect = False if i == 0: neck_e_parent.parent = mt.body_e @@ -237,9 +237,9 @@ def main(obj, bone_definition, base_names, options): con.subtarget = mt.body # add driver - hinge_driver_path = ex.head_ctrl_p.path_to_id() + '["hinge"]' + hinge_driver_path = ex.head_ctrl_p.path_from_id() + '["hinge"]' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -254,15 +254,15 @@ def main(obj, bone_definition, base_names, options): mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 - head_driver_path = ex.head_ctrl_p.path_to_id() + head_driver_path = ex.head_ctrl_p.path_from_id() target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))] ex.head_ctrl_p["bend_tot"] = 0.0 - fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]', 0) + fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]') driver = fcurve.driver driver.type = 'SUM' - fcurve.modifiers.remove(0) # grr dont need a modifier + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier for i in range(len(neck_chain)): var = driver.variables.new() @@ -296,12 +296,12 @@ def main(obj, bone_definition, base_names, options): con.owner_space = 'LOCAL' con.target_space = 'LOCAL' - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'SCRIPTED' driver.expression = "bend/bend_tot" - fcurve.modifiers.remove(0) # grr dont need a modifier + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier # add target @@ -334,14 +334,14 @@ def main(obj, bone_definition, base_names, options): if "ex_layer" in options: layer = [n == options["ex_layer"] for n in range(0, 32)] else: - layer = list(arm.bones[bone_definition[1]].layer) + layer = list(arm.bones[bone_definition[1]].layers) for attr in ex_chain.attr_names: - getattr(ex_chain, attr + "_b").layer = layer + getattr(ex_chain, attr + "_b").layers = layer for attr in ex.attr_names: - getattr(ex, attr + "_b").layer = layer + getattr(ex, attr + "_b").layers = layer - layer = list(arm.bones[bone_definition[1]].layer) - ex.head_ctrl_b.layer = layer + layer = list(arm.bones[bone_definition[1]].layers) + ex.head_ctrl_b.layers = layer # no blending the result of this diff --git a/release/scripts/modules/rigify/palm_curl.py b/release/scripts/modules/rigify/palm_curl.py index 6626438709d..c063e2b31c9 100644 --- a/release/scripts/modules/rigify/palm_curl.py +++ b/release/scripts/modules/rigify/palm_curl.py @@ -35,42 +35,42 @@ def metarig_template(): bone.head[:] = 0.0004, -0.0629, 0.0000 bone.tail[:] = 0.0021, -0.0209, 0.0000 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('palm.03') bone.head[:] = -0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0025, 0.0644, -0.0065 bone.roll = -3.1396 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['hand'] bone = arm.edit_bones.new('palm.02') bone.head[:] = 0.0252, -0.0000, 0.0000 bone.tail[:] = 0.0324, 0.0627, -0.0065 bone.roll = -3.1357 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['hand'] bone = arm.edit_bones.new('palm.01') bone.head[:] = 0.0504, 0.0000, 0.0000 bone.tail[:] = 0.0703, 0.0508, -0.0065 bone.roll = -3.1190 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['hand'] bone = arm.edit_bones.new('palm.04') bone.head[:] = -0.0252, 0.0000, 0.0000 bone.tail[:] = -0.0286, 0.0606, -0.0065 bone.roll = 3.1386 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['hand'] bone = arm.edit_bones.new('palm.05') bone.head[:] = -0.0504, 0.0000, 0.0000 bone.tail[:] = -0.0669, 0.0534, -0.0065 bone.roll = 3.1239 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['hand'] bone = arm.edit_bones.new('thumb') bone.head[:] = 0.0682, -0.0148, 0.0000 bone.tail[:] = 0.1063, 0.0242, -0.0065 bone.roll = -3.0929 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['hand'] bpy.ops.object.mode_set(mode='OBJECT') @@ -156,7 +156,7 @@ def main(obj, bone_definition, base_names, options): driver_fcurves = pinky_pbone.driver_add("rotation_euler") - controller_path = control_pbone.path_to_id() + controller_path = control_pbone.path_from_id() # add custom prop control_pbone["spread"] = 0.0 @@ -194,7 +194,7 @@ def main(obj, bone_definition, base_names, options): driver.expression = "(1.0-cos(x))-s" for fcurve in driver_fcurves: - fcurve.modifiers.remove(0) # grr dont need a modifier + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier var = driver.variables.new() var.name = "x" @@ -248,13 +248,13 @@ def main(obj, bone_definition, base_names, options): # NOTE: the direction of the Z rotation depends on which side the palm is on. # we could do a simple side-of-x test but better to work out the direction # the hand is facing. - from Mathutils import Vector + from mathutils import Vector from math import degrees child_pbone_01 = obj.pose.bones[children[0]].bone child_pbone_02 = obj.pose.bones[children[1]].bone rel_vec = child_pbone_01.head - child_pbone_02.head - x_vec = child_pbone_01.matrix.rotation_part() * Vector(1.0, 0.0, 0.0) + x_vec = child_pbone_01.matrix.rotation_part() * Vector((1.0, 0.0, 0.0)) return degrees(rel_vec.angle(x_vec)) > 90.0 @@ -263,7 +263,7 @@ def main(obj, bone_definition, base_names, options): # last step setup layers - arm.bones[control_name].layer = list(arm.bones[bone_definition[1]].layer) + arm.bones[control_name].layers = list(arm.bones[bone_definition[1]].layers) # no blending the result of this diff --git a/release/scripts/modules/rigify/shape_key_control.py b/release/scripts/modules/rigify/shape_key_control.py index fd0e900a7b5..1bfca60255d 100644 --- a/release/scripts/modules/rigify/shape_key_control.py +++ b/release/scripts/modules/rigify/shape_key_control.py @@ -57,7 +57,7 @@ def addget_shape_key_driver(obj, name="Key"): if driver_s.data_path == driver_path: fcurve = driver_s if fcurve == None: - fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0) + fcurve = obj.data.shape_keys.keys[name].driver_add("value") fcurve.driver.type = 'AVERAGE' new = True @@ -74,7 +74,7 @@ def metarig_template(): #bone.head[:] = 0.0000, 0.0000, 0.0000 #bone.tail[:] = 0.0000, 0.0000, 1.0000 #bone.roll = 0.0000 - #bone.connected = False + #bone.use_connect = False # #bpy.ops.object.mode_set(mode='OBJECT') #pbone = obj.pose.bones['Bone'] diff --git a/release/scripts/modules/rigify/shape_key_distance.py b/release/scripts/modules/rigify/shape_key_distance.py index 68501ac829b..7d69517216f 100644 --- a/release/scripts/modules/rigify/shape_key_distance.py +++ b/release/scripts/modules/rigify/shape_key_distance.py @@ -54,7 +54,7 @@ def addget_shape_key_driver(obj, name="Key"): if driver_s.data_path == driver_path: fcurve = driver_s if fcurve == None: - fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0) + fcurve = obj.data.shape_keys.keys[name].driver_add("value") fcurve.driver.type = 'AVERAGE' return fcurve @@ -71,7 +71,7 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0000, 0.0000, 1.0000 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones['Bone'] diff --git a/release/scripts/modules/rigify/shape_key_rotdiff.py b/release/scripts/modules/rigify/shape_key_rotdiff.py index 2c30d95e666..dfc3b914a6a 100644 --- a/release/scripts/modules/rigify/shape_key_rotdiff.py +++ b/release/scripts/modules/rigify/shape_key_rotdiff.py @@ -54,7 +54,7 @@ def addget_shape_key_driver(obj, name="Key"): if driver_s.data_path == driver_path: fcurve = driver_s if fcurve == None: - fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0) + fcurve = obj.data.shape_keys.keys[name].driver_add("value") fcurve.driver.type = 'AVERAGE' return fcurve @@ -71,7 +71,7 @@ def metarig_template(): bone.head[:] = 0.0000, 0.0000, 0.0000 bone.tail[:] = 0.0000, 0.0000, 1.0000 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones['Bone'] diff --git a/release/scripts/modules/rigify/spine_pivot_flex.py b/release/scripts/modules/rigify/spine_pivot_flex.py index 422c632e95a..7782380eedb 100644 --- a/release/scripts/modules/rigify/spine_pivot_flex.py +++ b/release/scripts/modules/rigify/spine_pivot_flex.py @@ -36,54 +36,54 @@ def metarig_template(): bone.head[:] = 0.0000, -0.0306, 0.1039 bone.tail[:] = 0.0000, -0.0306, -0.0159 bone.roll = 0.0000 - bone.connected = False + bone.use_connect = False bone = arm.edit_bones.new('rib_cage') bone.head[:] = 0.0000, -0.0306, 0.1039 bone.tail[:] = 0.0000, -0.0306, 0.2236 bone.roll = -0.0000 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['pelvis'] bone = arm.edit_bones.new('spine.01') bone.head[:] = 0.0000, 0.0000, -0.0000 bone.tail[:] = 0.0000, -0.0306, 0.1039 bone.roll = -0.0000 - bone.connected = False + bone.use_connect = False bone.parent = arm.edit_bones['rib_cage'] bone = arm.edit_bones.new('spine.02') bone.head[:] = 0.0000, -0.0306, 0.1039 bone.tail[:] = -0.0000, -0.0398, 0.2045 bone.roll = -0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['spine.01'] bone = arm.edit_bones.new('spine.03') bone.head[:] = -0.0000, -0.0398, 0.2045 bone.tail[:] = -0.0000, -0.0094, 0.2893 bone.roll = -0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['spine.02'] bone = arm.edit_bones.new('spine.04') bone.head[:] = -0.0000, -0.0094, 0.2893 bone.tail[:] = -0.0000, 0.0335, 0.3595 bone.roll = -0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['spine.03'] bone = arm.edit_bones.new('spine.05') bone.head[:] = -0.0000, 0.0335, 0.3595 bone.tail[:] = -0.0000, 0.0555, 0.4327 bone.roll = -0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['spine.04'] bone = arm.edit_bones.new('spine.06') bone.head[:] = -0.0000, 0.0555, 0.4327 bone.tail[:] = -0.0000, 0.0440, 0.5207 bone.roll = -0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['spine.05'] bone = arm.edit_bones.new('spine.07') bone.head[:] = -0.0000, 0.0440, 0.5207 bone.tail[:] = -0.0000, 0.0021, 0.5992 bone.roll = -0.0000 - bone.connected = True + bone.use_connect = True bone.parent = arm.edit_bones['spine.06'] bpy.ops.object.mode_set(mode='OBJECT') @@ -147,7 +147,7 @@ def deform(obj, definitions, base_names, options): def main(obj, bone_definition, base_names, options): - from Mathutils import Vector, RotationMatrix + from mathutils import Vector, Matrix from math import radians, pi arm = obj.data @@ -172,17 +172,17 @@ def main(obj, bone_definition, base_names, options): ex.pelvis_copy_e = copy_bone_simple(arm, mt.pelvis, base_names[mt.pelvis]) # no parent ex.pelvis_copy = ex.pelvis_copy_e.name - ex.pelvis_copy_e.local_location = False + ex.pelvis_copy_e.use_local_location = False # copy the pelvis, offset to make MCH-spine_rotate and MCH-ribcage_hinge ex.ribcage_hinge_e = copy_bone_simple(arm, mt.pelvis, "MCH-%s_hinge" % base_names[mt.ribcage]) ex.ribcage_hinge = ex.ribcage_hinge_e.name - ex.ribcage_hinge_e.translate(Vector(0.0, spine_chain_segment_length / 4.0, 0.0)) + ex.ribcage_hinge_e.translate(Vector((0.0, spine_chain_segment_length / 4.0, 0.0))) ex.spine_rotate_e = copy_bone_simple(arm, mt.ribcage, "MCH-%s_rotate" % spine_chain_basename) ex.spine_rotate = ex.spine_rotate_e.name - ex.spine_rotate_e.translate(Vector(0.0, spine_chain_segment_length / 2.0, 0.0)) - ex.spine_rotate_e.connected = False + ex.spine_rotate_e.translate(Vector((0.0, spine_chain_segment_length / 2.0, 0.0))) + ex.spine_rotate_e.use_connect = False ex.spine_rotate_e.parent = ex.pelvis_copy_e @@ -191,7 +191,7 @@ def main(obj, bone_definition, base_names, options): ex.ribcage_copy_e = copy_bone_simple(arm, mt.ribcage, base_names[mt.ribcage]) ex.ribcage_copy = ex.ribcage_copy_e.name - ex.ribcage_copy_e.connected = False + ex.ribcage_copy_e.use_connect = False ex.ribcage_copy_e.parent = ex.ribcage_hinge_e spine_chain = [child.name for child in spine_chain] @@ -219,7 +219,7 @@ def main(obj, bone_definition, base_names, options): ebone = copy_bone_simple(arm, child_name, "MCH-rev_%s" % child_name_orig) setattr(rv_chain, attr, ebone.name) - ebone.connected = False + ebone.use_connect = False mt_chain.update() ex_chain.update() @@ -230,13 +230,13 @@ def main(obj, bone_definition, base_names, options): attr = ex_chain.attr_names[i] + "_e" ebone = getattr(ex_chain, attr) if i == 0: - ebone.connected = False + ebone.use_connect = False ebone.parent = ex.pelvis_copy_e else: attr_parent = ex_chain.attr_names[i - 1] + "_e" ebone.parent = getattr(ex_chain, attr_parent) - # intentional! get the parent from the other paralelle chain member + # intentional! get the parent from the other parallel chain member getattr(rv_chain, attr).parent = ebone @@ -255,16 +255,16 @@ def main(obj, bone_definition, base_names, options): spine_e = getattr(ex_chain, ex_chain.attr_names[i] + "_e") orig_parent = spine_e.parent - spine_e.connected = False + spine_e.use_connect = False spine_e.parent = spine_e_parent - spine_e_parent.connected = False + spine_e_parent.use_connect = False spine_e_parent.parent = orig_parent # Rotate the rev chain 180 about the by the first bones center point pivot = (rv_chain.spine_01_e.head + rv_chain.spine_01_e.tail) * 0.5 - matrix = RotationMatrix(radians(180), 3, 'X') + matrix = Matrix.Rotation(radians(180), 3, 'X') for i, attr in enumerate(rv_chain.attr_names): # similar to neck spine_e = getattr(rv_chain, attr + "_e") # use the first bone as the pivot @@ -294,14 +294,14 @@ def main(obj, bone_definition, base_names, options): con.subtarget = ex.pelvis_copy # add driver - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' var.name = "var" var.targets[0].id_type = 'OBJECT' var.targets[0].id = obj - var.targets[0].data_path = ex.ribcage_copy_p.path_to_id() + '["hinge"]' + var.targets[0].data_path = ex.ribcage_copy_p.path_from_id() + '["hinge"]' mod = fcurve.modifiers[0] mod.poly_order = 1 @@ -347,13 +347,13 @@ def main(obj, bone_definition, base_names, options): # Constrain 'inbetween' bones target_names = [("b%.2d" % (i + 1)) for i in range(spine_chain_len - 1)] - rib_driver_path = ex.ribcage_copy_p.path_to_id() + rib_driver_path = ex.ribcage_copy_p.path_from_id() ex.ribcage_copy_p["bend_tot"] = 0.0 - fcurve = ex.ribcage_copy_p.driver_add('["bend_tot"]', 0) + fcurve = ex.ribcage_copy_p.driver_add('["bend_tot"]') driver = fcurve.driver driver.type = 'SUM' - fcurve.modifiers.remove(0) # grr dont need a modifier + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier for i in range(spine_chain_len - 1): var = driver.variables.new() @@ -385,12 +385,12 @@ def main(obj, bone_definition, base_names, options): del spine_p # add driver - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'SCRIPTED' driver.expression = "bend/bend_tot" - fcurve.modifiers.remove(0) # grr dont need a modifier + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier # add target @@ -440,7 +440,7 @@ def main(obj, bone_definition, base_names, options): if i == spine_chain_len: con.head_tail = 1.0 - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver var = driver.variables.new() driver.type = 'AVERAGE' @@ -465,17 +465,17 @@ def main(obj, bone_definition, base_names, options): if "ex_layer" in options: layer = [n == options["ex_layer"] for n in range(0, 32)] else: - layer = list(arm.bones[bone_definition[1]].layer) + layer = list(arm.bones[bone_definition[1]].layers) for attr in ex.attr_names: - getattr(ex, attr + "_b").layer = layer + getattr(ex, attr + "_b").layers = layer for attr in ex_chain.attr_names: - getattr(ex_chain, attr + "_b").layer = layer + getattr(ex_chain, attr + "_b").layers = layer for attr in rv_chain.attr_names: - getattr(rv_chain, attr + "_b").layer = layer + getattr(rv_chain, attr + "_b").layers = layer - layer = list(arm.bones[bone_definition[1]].layer) - arm.bones[ex.pelvis_copy].layer = layer - arm.bones[ex.ribcage_copy].layer = layer + layer = list(arm.bones[bone_definition[1]].layers) + arm.bones[ex.pelvis_copy].layers = layer + arm.bones[ex.ribcage_copy].layers = layer # no support for blending chains return None diff --git a/release/scripts/modules/rigify/stretch.py b/release/scripts/modules/rigify/stretch.py index 1c3d317b4b1..6a498e5aa29 100644 --- a/release/scripts/modules/rigify/stretch.py +++ b/release/scripts/modules/rigify/stretch.py @@ -35,7 +35,7 @@ RIG_TYPE = "stretch" # bone.head[:] = 0.0000, 0.0000, 0.0000 # bone.tail[:] = 0.0000, 0.0000, 1.0000 # bone.roll = 0.0000 -# bone.connected = False +# bone.use_connect = False # # bpy.ops.object.mode_set(mode='OBJECT') # pbone = obj.pose.bones['Bone'] @@ -84,7 +84,7 @@ def main(obj, bone_definition, base_names, options): mbone2 = "ORG-" + options["to"] bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s" % base_names[bone_definition[0]]) - bone_e.connected = False + bone_e.use_connect = False bone_e.parent = eb[mbone1] bone_e.tail = eb[mbone2].head bone = bone_e.name @@ -100,7 +100,7 @@ def main(obj, bone_definition, base_names, options): con = pb[bone].constraints.new('STRETCH_TO') con.target = obj con.subtarget = mbone2 - con.original_length = bb[bone].length + con.rest_length = bb[bone].length if preserve_volume: con.volume = 'VOLUME_XZX' else: diff --git a/release/scripts/modules/rigify/stretch_twist.py b/release/scripts/modules/rigify/stretch_twist.py index 66719d80d42..07ce031967f 100644 --- a/release/scripts/modules/rigify/stretch_twist.py +++ b/release/scripts/modules/rigify/stretch_twist.py @@ -35,7 +35,7 @@ RIG_TYPE = "stretch_twist" # bone.head[:] = 0.0000, 0.0000, 0.0000 # bone.tail[:] = 0.0000, 0.0000, 1.0000 # bone.roll = 0.0000 -# bone.connected = False +# bone.use_connect = False # # bpy.ops.object.mode_set(mode='OBJECT') # pbone = obj.pose.bones['Bone'] @@ -86,20 +86,20 @@ def main(obj, bone_definition, base_names, options): mbone2 = "ORG-" + options["to"] bone_e = copy_bone_simple(obj.data, mbone1, "MCH-%s" % base_names[bone_definition[0]]) - bone_e.connected = False + bone_e.use_connect = False bone_e.parent = None bone_e.head = (eb[mbone1].head + eb[mbone2].head) / 2 bone_e.tail = (bone_e.head[0], bone_e.head[1], bone_e.head[2]+0.1) mid_bone = bone_e.name bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s.01" % base_names[bone_definition[0]]) - bone_e.connected = False + bone_e.use_connect = False bone_e.parent = eb[mbone1] bone_e.tail = eb[mid_bone].head bone1 = bone_e.name bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]]) - bone_e.connected = False + bone_e.use_connect = False bone_e.parent = eb[mbone2] bone_e.tail = eb[mid_bone].head bone2 = bone_e.name @@ -128,7 +128,7 @@ def main(obj, bone_definition, base_names, options): con = pb[bone1].constraints.new('STRETCH_TO') con.target = obj con.subtarget = mid_bone - con.original_length = bb[bone1].length + con.rest_length = bb[bone1].length if preserve_volume: con.volume = 'VOLUME_XZX' else: @@ -142,7 +142,7 @@ def main(obj, bone_definition, base_names, options): con = pb[bone2].constraints.new('STRETCH_TO') con.target = obj con.subtarget = mid_bone - con.original_length = bb[bone2].length + con.rest_length = bb[bone2].length if preserve_volume: con.volume = 'VOLUME_XZX' else: diff --git a/release/scripts/modules/rigify/tail_control.py b/release/scripts/modules/rigify/tail_control.py index c0addf97a52..50a9bb236da 100644 --- a/release/scripts/modules/rigify/tail_control.py +++ b/release/scripts/modules/rigify/tail_control.py @@ -12,7 +12,7 @@ # # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ##### END GPL LICENSE BLOCK ##### @@ -22,7 +22,7 @@ import bpy from rigify import RigifyError from rigify_utils import bone_class_instance, copy_bone_simple from rna_prop_ui import rna_idprop_ui_prop_get -from Mathutils import Vector, RotationMatrix +from mathutils import Vector, Matrix from math import radians, pi # not used, defined for completeness @@ -40,7 +40,7 @@ def metarig_template(): #bone.head[:] = 0.0000, -0.0306, 0.1039 #bone.tail[:] = 0.0000, -0.0306, -0.0159 #bone.roll = 0.0000 - #bone.connected = False + #bone.use_connect = False #bpy.ops.object.mode_set(mode='OBJECT') #pbone = obj.pose.bones['tail.01'] @@ -85,9 +85,9 @@ def main(obj, bone_definitions, base_names, options): for bone_def in bone_definitions: bone = copy_bone_simple(arm, bone_def, base_names[bone_def], parent=True).name if i == 1: # Don't change parent of first tail bone - eb[bone].connected = False + eb[bone].use_connect = False eb[bone].parent = eb[hinge2] - eb[bone].local_location = False + eb[bone].use_local_location = False i = 1 bones += [bone] @@ -133,9 +133,9 @@ def main(obj, bone_definitions, base_names, options): con_h.subtarget = hinge1 # Add drivers - bone_path = pb[bones[0]].path_to_id() + bone_path = pb[bones[0]].path_from_id() - driver_fcurve = con_f.driver_add("influence", 0) + driver_fcurve = con_f.driver_add("influence") driver = driver_fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() @@ -148,7 +148,7 @@ def main(obj, bone_definitions, base_names, options): mod.coefficients[0] = 1.0 mod.coefficients[1] = -1.0 - driver_fcurve = con_h.driver_add("influence", 0) + driver_fcurve = con_h.driver_add("influence") driver = driver_fcurve.driver driver.type = 'AVERAGE' var = driver.variables.new() diff --git a/release/scripts/modules/rigify/tongue.py b/release/scripts/modules/rigify/tongue.py new file mode 100644 index 00000000000..36c4316adc5 --- /dev/null +++ b/release/scripts/modules/rigify/tongue.py @@ -0,0 +1,361 @@ +# ##### 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 +from rigify import RigifyError +from rigify_utils import bone_class_instance, copy_bone_simple +from rna_prop_ui import rna_idprop_ui_prop_get + +# not used, defined for completeness +METARIG_NAMES = ("body", "head") + + +def metarig_template(): + # TODO: + ## generated by rigify.write_meta_rig + #bpy.ops.object.mode_set(mode='EDIT') + #obj = bpy.context.active_object + #arm = obj.data + #bone = arm.edit_bones.new('body') + #bone.head[:] = 0.0000, -0.0276, -0.1328 + #bone.tail[:] = 0.0000, -0.0170, -0.0197 + #bone.roll = 0.0000 + #bone.use_connect = False + #bone = arm.edit_bones.new('head') + #bone.head[:] = 0.0000, -0.0170, -0.0197 + #bone.tail[:] = 0.0000, 0.0726, 0.1354 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['body'] + #bone = arm.edit_bones.new('neck.01') + #bone.head[:] = 0.0000, -0.0170, -0.0197 + #bone.tail[:] = 0.0000, -0.0099, 0.0146 + #bone.roll = 0.0000 + #bone.use_connect = False + #bone.parent = arm.edit_bones['head'] + #bone = arm.edit_bones.new('neck.02') + #bone.head[:] = 0.0000, -0.0099, 0.0146 + #bone.tail[:] = 0.0000, -0.0242, 0.0514 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.01'] + #bone = arm.edit_bones.new('neck.03') + #bone.head[:] = 0.0000, -0.0242, 0.0514 + #bone.tail[:] = 0.0000, -0.0417, 0.0868 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.02'] + #bone = arm.edit_bones.new('neck.04') + #bone.head[:] = 0.0000, -0.0417, 0.0868 + #bone.tail[:] = 0.0000, -0.0509, 0.1190 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.03'] + #bone = arm.edit_bones.new('neck.05') + #bone.head[:] = 0.0000, -0.0509, 0.1190 + #bone.tail[:] = 0.0000, -0.0537, 0.1600 + #bone.roll = 0.0000 + #bone.use_connect = True + #bone.parent = arm.edit_bones['neck.04'] + # + #bpy.ops.object.mode_set(mode='OBJECT') + #pbone = obj.pose.bones['head'] + #pbone['type'] = 'neck_flex' + pass + + +def metarig_definition(obj, orig_bone_name): + ''' + The bone given is the tongue control, its parent is the body, + # its only child the first of a chain with matching basenames. + eg. + body -> tongue_control -> tongue_01 -> tongue_02 -> tongue_03.... etc + ''' + arm = obj.data + tongue = arm.bones[orig_bone_name] + body = tongue.parent + + children = tongue.children + if len(children) != 1: + raise RigifyError("expected the tongue bone '%s' to have only 1 child." % orig_bone_name) + + child = children[0] + bone_definition = [body.name, tongue.name, child.name] + bone_definition.extend([child.name for child in child.children_recursive_basename]) + return bone_definition + + +def deform(obj, definitions, base_names, options): + for org_bone_name in definitions[2:]: + bpy.ops.object.mode_set(mode='EDIT') + + # Create deform bone. + bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True) + + # Store name before leaving edit mode + bone_name = bone.name + + # Leave edit mode + bpy.ops.object.mode_set(mode='OBJECT') + + # Get the pose bone + bone = obj.pose.bones[bone_name] + + # Constrain to the original bone + # XXX. Todo, is this needed if the bone is connected to its parent? + con = bone.constraints.new('COPY_TRANSFORMS') + con.name = "copy_loc" + con.target = obj + con.subtarget = org_bone_name + + +# TODO: rename all of the head/neck references to tongue +def main(obj, bone_definition, base_names, options): + from mathutils import Vector + + arm = obj.data + + # Initialize container classes for convenience + mt = bone_class_instance(obj, ["body", "head"]) # meta + mt.body = bone_definition[0] + mt.head = bone_definition[1] + mt.update() + + neck_chain = bone_definition[2:] + + mt_chain = bone_class_instance(obj, [("neck_%.2d" % (i + 1)) for i in range(len(neck_chain))]) # 99 bones enough eh? + for i, attr in enumerate(mt_chain.attr_names): + setattr(mt_chain, attr, neck_chain[i]) + mt_chain.update() + + neck_chain_basename = base_names[mt_chain.neck_01_e.name].split(".")[0] + neck_chain_segment_length = mt_chain.neck_01_e.length + + ex = bone_class_instance(obj, ["head", "head_hinge", "neck_socket", "head_ctrl"]) # hinge & extras + + # Add the head hinge at the bodys location, becomes the parent of the original head + + # apply everything to this copy of the chain + ex_chain = mt_chain.copy(base_names=base_names) + ex_chain.neck_01_e.parent = mt_chain.neck_01_e.parent + + + # Copy the head bone and offset + ex.head_e = copy_bone_simple(arm, mt.head, "MCH-%s" % base_names[mt.head], parent=True) + ex.head_e.use_connect = False + ex.head = ex.head_e.name + # offset + head_length = ex.head_e.length + ex.head_e.head.y += head_length / 2.0 + ex.head_e.tail.y += head_length / 2.0 + + # Yes, use the body bone but call it a head hinge + ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH-%s_hinge" % base_names[mt.head], parent=False) + ex.head_hinge_e.use_connect = False + ex.head_hinge = ex.head_hinge_e.name + ex.head_hinge_e.head.y += head_length / 4.0 + ex.head_hinge_e.tail.y += head_length / 4.0 + + # Insert the neck socket, the head copys this loation + ex.neck_socket_e = arm.edit_bones.new("MCH-%s_socked" % neck_chain_basename) + ex.neck_socket = ex.neck_socket_e.name + ex.neck_socket_e.use_connect = False + ex.neck_socket_e.parent = mt.body_e + ex.neck_socket_e.head = mt.head_e.head + ex.neck_socket_e.tail = mt.head_e.head - Vector((0.0, neck_chain_segment_length / 2.0, 0.0)) + ex.neck_socket_e.roll = 0.0 + + + # copy of the head for controling + ex.head_ctrl_e = copy_bone_simple(arm, mt.head, base_names[mt.head]) + ex.head_ctrl = ex.head_ctrl_e.name + ex.head_ctrl_e.parent = ex.head_hinge_e + + for i, attr in enumerate(ex_chain.attr_names): + neck_e = getattr(ex_chain, attr + "_e") + + # dont store parent names, re-reference as each chain bones parent. + neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % base_names[getattr(mt_chain, attr)]) + neck_e_parent.head = neck_e.head + neck_e_parent.tail = neck_e.head + (mt.head_e.vector.normalize() * neck_chain_segment_length / 2.0) + neck_e_parent.roll = mt.head_e.roll + + orig_parent = neck_e.parent + neck_e.use_connect = False + neck_e.parent = neck_e_parent + neck_e_parent.use_connect = False + + if i == 0: + neck_e_parent.parent = mt.body_e + else: + neck_e_parent.parent = orig_parent + + deform(obj, bone_definition, base_names, options) + + bpy.ops.object.mode_set(mode='OBJECT') + + mt.update() + mt_chain.update() + ex_chain.update() + ex.update() + + # Axis locks + ex.head_ctrl_p.lock_location = True, True, True + ex.head_ctrl_p.lock_scale = True, False, True + + # Simple one off constraints, no drivers + con = ex.head_ctrl_p.constraints.new('COPY_LOCATION') + con.target = obj + con.subtarget = ex.neck_socket + + con = ex.head_p.constraints.new('COPY_ROTATION') + con.target = obj + con.subtarget = ex.head_ctrl + + # driven hinge + prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, "hinge", create=True) + ex.head_ctrl_p["hinge"] = 0.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + + con = ex.head_hinge_p.constraints.new('COPY_ROTATION') + con.name = "hinge" + con.target = obj + con.subtarget = mt.body + + # add driver + hinge_driver_path = ex.head_ctrl_p.path_to_id() + '["hinge"]' + + fcurve = con.driver_add("influence") + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'AVERAGE' + var.name = "var" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = hinge_driver_path + + #mod = fcurve_driver.modifiers.new('GENERATOR') + mod = fcurve.modifiers[0] + mod.poly_order = 1 + mod.coefficients[0] = 1.0 + mod.coefficients[1] = -1.0 + + head_driver_path = ex.head_ctrl_p.path_to_id() + + target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))] + + ex.head_ctrl_p["bend_tot"] = 0.0 + fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]') + driver = fcurve.driver + driver.type = 'SUM' + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier + + for i in range(len(neck_chain)): + var = driver.variables.new() + var.name = target_names[i] + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = head_driver_path + ('["bend_%.2d"]' % (i + 1)) + + + for i, attr in enumerate(ex_chain.attr_names): + neck_p = getattr(ex_chain, attr + "_p") + neck_p.lock_location = True, True, True + neck_p.lock_location = True, True, True + neck_p.lock_rotations_4d = True + + # Add bend prop + prop_name = "bend_%.2d" % (i + 1) + prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, prop_name, create=True) + ex.head_ctrl_p[prop_name] = 1.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + + # add parent constraint + neck_p_parent = neck_p.parent + + # add constraints + if i == 0: + con = neck_p.constraints.new('COPY_SCALE') + con.name = "Copy Scale" + con.target = obj + con.subtarget = ex.head_ctrl + con.owner_space = 'LOCAL' + con.target_space = 'LOCAL' + + con = neck_p_parent.constraints.new('COPY_ROTATION') + con.name = "Copy Rotation" + con.target = obj + con.subtarget = ex.head + con.owner_space = 'LOCAL' + con.target_space = 'LOCAL' + + fcurve = con.driver_add("influence") + driver = fcurve.driver + driver.type = 'SCRIPTED' + driver.expression = "bend/bend_tot" + + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier + + + # add target + var = driver.variables.new() + var.name = "bend_tot" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = head_driver_path + ('["bend_tot"]') + + var = driver.variables.new() + var.name = "bend" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = obj + var.targets[0].data_path = head_driver_path + ('["%s"]' % prop_name) + + + # finally constrain the original bone to this one + orig_neck_p = getattr(mt_chain, attr + "_p") + con = orig_neck_p.constraints.new('COPY_TRANSFORMS') + con.target = obj + con.subtarget = neck_p.name + + + # Set the head control's custom shape to use the last + # org neck bone for its transform + ex.head_ctrl_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]] + + + # last step setup layers + if "ex_layer" in options: + layer = [n==options["ex_layer"] for n in range(0,32)] + else: + layer = list(arm.bones[bone_definition[1]].layers) + for attr in ex_chain.attr_names: + getattr(ex_chain, attr + "_b").layers = layer + for attr in ex.attr_names: + getattr(ex, attr + "_b").layers = layer + + layer = list(arm.bones[bone_definition[1]].layers) + ex.head_ctrl_b.layers = layer + + + # no blending the result of this + return None + diff --git a/release/scripts/modules/rigify/track_dual.py b/release/scripts/modules/rigify/track_dual.py index 38c2a86ab32..f9c48a3bfcb 100644 --- a/release/scripts/modules/rigify/track_dual.py +++ b/release/scripts/modules/rigify/track_dual.py @@ -35,7 +35,7 @@ RIG_TYPE = "track_dual" # bone.head[:] = 0.0000, 0.0000, 0.0000 # bone.tail[:] = 0.0000, 0.0000, 1.0000 # bone.roll = 0.0000 -# bone.connected = False +# bone.use_connect = False # # bpy.ops.object.mode_set(mode='OBJECT') # pbone = obj.pose.bones['Bone'] @@ -76,13 +76,13 @@ def main(obj, bone_definition, base_names, options): mbone2 = "ORG-" + options["to"] bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s.01" % base_names[bone_definition[0]]) - bone_e.connected = False + bone_e.use_connect = False bone_e.parent = eb[mbone1] bone_e.tail = (eb[mbone1].head + eb[mbone2].head) / 2 bone1 = bone_e.name bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]]) - bone_e.connected = False + bone_e.use_connect = False bone_e.parent = eb[mbone1] bone_e.tail = (eb[mbone1].head + eb[mbone2].head) / 2 bone2 = bone_e.name diff --git a/release/scripts/modules/rigify/track_reverse.py b/release/scripts/modules/rigify/track_reverse.py index 21d38c28920..a65ac0e9416 100644 --- a/release/scripts/modules/rigify/track_reverse.py +++ b/release/scripts/modules/rigify/track_reverse.py @@ -35,7 +35,7 @@ RIG_TYPE = "track_reverse" # bone.head[:] = 0.0000, 0.0000, 0.0000 # bone.tail[:] = 0.0000, 0.0000, 1.0000 # bone.roll = 0.0000 -# bone.connected = False +# bone.use_connect = False # # bpy.ops.object.mode_set(mode='OBJECT') # pbone = obj.pose.bones['Bone'] @@ -78,7 +78,7 @@ def main(obj, bone_definition, base_names, options): mbone2 = "ORG-" + options["to"] bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]]) - bone_e.connected = False + bone_e.use_connect = False bone_e.parent = eb[mbone1] bone_e.tail = eb[mbone1].head bone = bone_e.name diff --git a/release/scripts/modules/rigify_utils.py b/release/scripts/modules/rigify_utils.py index 812342b3ebc..1ffe366e0d5 100644 --- a/release/scripts/modules/rigify_utils.py +++ b/release/scripts/modules/rigify_utils.py @@ -26,7 +26,7 @@ # that a generic function would need to check for. import bpy -from Mathutils import Vector +from mathutils import Vector from rna_prop_ui import rna_idprop_ui_prop_get DELIMITER = '-._' @@ -67,7 +67,7 @@ def add_stretch_to(obj, from_name, to_name, name): con = stretch_pbone.constraints.new('STRETCH_TO') con.target = obj con.subtarget = to_name - con.original_length = (head - tail).length + con.rest_length = (head - tail).length con.keep_axis = 'PLANE_X' con.volume = 'NO_VOLUME' @@ -81,13 +81,13 @@ def copy_bone_simple(arm, from_bone, name, parent=False): ebone_new = arm.edit_bones.new(name) if parent: - ebone_new.connected = ebone.connected + ebone_new.use_connect = ebone.use_connect ebone_new.parent = ebone.parent ebone_new.head = ebone.head ebone_new.tail = ebone.tail ebone_new.roll = ebone.roll - ebone_new.layer = list(ebone.layer) + ebone_new.layers = list(ebone.layers) return ebone_new @@ -136,7 +136,7 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta prop["soft_min"] = 0.0 prop["soft_max"] = 1.0 - driver_path = prop_pbone.path_to_id() + ('["%s"]' % target_prop) + driver_path = prop_pbone.path_from_id() + ('["%s"]' % target_prop) def blend_target(driver): var = driver.variables.new() @@ -154,10 +154,10 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta con.target = obj con.subtarget = to_bone_name - fcurve = con.driver_add("influence", 0) + fcurve = con.driver_add("influence") driver = fcurve.driver driver.type = 'AVERAGE' - fcurve.modifiers.remove(0) # grr dont need a modifier + fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier blend_target(driver) @@ -204,12 +204,12 @@ def add_pole_target_bone(obj, base_bone_name, name, mode='CROSS'): offset.length = distance elif mode == 'ZAVERAGE': # between both bones Z axis - z_axis_a = base_ebone.matrix.copy().rotation_part() * Vector(0.0, 0.0, -1.0) - z_axis_b = parent_ebone.matrix.copy().rotation_part() * Vector(0.0, 0.0, -1.0) + z_axis_a = base_ebone.matrix.copy().rotation_part() * Vector((0.0, 0.0, -1.0)) + z_axis_b = parent_ebone.matrix.copy().rotation_part() * Vector((0.0, 0.0, -1.0)) offset = (z_axis_a + z_axis_b).normalize() * distance else: # preset axis - offset = Vector(0, 0, 0) + offset = Vector((0.0, 0.0, 0.0)) if mode[0] == "+": val = distance else: @@ -276,7 +276,7 @@ def write_meta_rig(obj, func_name="metarig_template"): code.append(" bone.head[:] = %.4f, %.4f, %.4f" % bone.head.to_tuple(4)) code.append(" bone.tail[:] = %.4f, %.4f, %.4f" % bone.tail.to_tuple(4)) code.append(" bone.roll = %.4f" % bone.roll) - code.append(" bone.connected = %s" % str(bone.connected)) + code.append(" bone.use_connect = %s" % str(bone.use_connect)) if bone.parent: code.append(" bone.parent = arm.edit_bones['%s']" % bone.parent.name) diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py index 8a93f98815c..0a93121c559 100644 --- a/release/scripts/modules/rna_info.py +++ b/release/scripts/modules/rna_info.py @@ -25,6 +25,44 @@ import bpy # use to strip python paths script_paths = bpy.utils.script_paths() +_FAKE_STRUCT_SUBCLASS = True + + +def _get_direct_attr(rna_type, attr): + props = getattr(rna_type, attr) + base = rna_type.base + + if not base: + return [prop for prop in props] + else: + props_base = getattr(base, attr).values() + return [prop for prop in props if prop not in props_base] + + +def get_direct_properties(rna_type): + return _get_direct_attr(rna_type, "properties") + + +def get_direct_functions(rna_type): + return _get_direct_attr(rna_type, "functions") + + +def rna_id_ignore(rna_id): + if rna_id == "rna_type": + return True + + if "_OT_" in rna_id: + return True + if "_MT_" in rna_id: + return True + if "_PT_" in rna_id: + return True + if "_HT_" in rna_id: + return True + if "_KSI_" in rna_id: + return True + return False + def range_str(val): if val < -10000000: @@ -67,8 +105,8 @@ class InfoStructRNA: def build(self): rna_type = self.bl_rna parent_id = self.identifier - self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_id, rna_prop in rna_type.properties.items() if rna_id != "rna_type"] - self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in rna_type.functions.values()] + self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_prop in get_direct_properties(rna_type) if rna_prop.identifier != "rna_type"] + self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in get_direct_functions(rna_type)] def get_bases(self): bases = [] @@ -116,17 +154,17 @@ class InfoStructRNA: def __repr__(self): - txt = '' + txt = "" txt += self.identifier if self.base: - txt += '(%s)' % self.base.identifier - txt += ': ' + self.description + '\n' + txt += "(%s)" % self.base.identifier + txt += ": " + self.description + "\n" for prop in self.properties: - txt += prop.__repr__() + '\n' + txt += prop.__repr__() + "\n" for func in self.functions: - txt += func.__repr__() + '\n' + txt += func.__repr__() + "\n" return txt @@ -163,40 +201,40 @@ class InfoPropertyRNA: if self.type == "enum": self.enum_items[:] = rna_prop.items.keys() + if self.array_length: self.default = tuple(getattr(rna_prop, "default_array", ())) + else: + self.default = getattr(rna_prop, "default", None) + self.default_str = "" # fallback + + + if self.type == "pointer": + # pointer has no default, just set as None + self.default = None + self.default_str = "None" + elif self.type == "string": + self.default_str = "\"%s\"" % self.default + elif self.type == "enum": + self.default_str = "'%s'" % self.default + elif self.array_length: self.default_str = '' # special case for floats if len(self.default) > 0: - if type(self.default[0]) is float: + if self.type == "float": self.default_str = "(%s)" % ", ".join([float_as_string(f) for f in self.default]) if not self.default_str: self.default_str = str(self.default) else: - self.default = getattr(rna_prop, "default", "") - if type(self.default) is float: + if self.type == "float": self.default_str = float_as_string(self.default) else: self.default_str = str(self.default) self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections - def get_default_string(self): - # pointer has no default, just set as None - if self.type == "pointer": - return "None" - elif self.type == "string": - return '"' + self.default_str + '"' - elif self.type == "enum": - if self.default_str: - return "'" + self.default_str + "'" - else: - return "" - - return self.default_str - def get_arg_default(self, force=True): - default = self.get_default_string() + default = self.default_str if default and (force or self.is_required == False): return "%s=%s" % (self.identifier, default) return self.identifier @@ -212,6 +250,13 @@ class InfoPropertyRNA: type_str += " in [%s, %s]" % (range_str(self.min), range_str(self.max)) elif self.type == "enum": type_str += " in [%s]" % ', '.join([("'%s'" % s) for s in self.enum_items]) + + if not (as_arg or as_ret): + # write default property, ignore function args for this + if self.type != "pointer": + if self.default_str: + type_str += ", default %s" % self.default_str + else: if self.type == "collection": if self.collection_type: @@ -223,17 +268,22 @@ class InfoPropertyRNA: type_str += collection_str + (class_fmt % self.fixed_type.identifier) + # setup qualifiers for this value. + type_info = [] if as_ret: pass elif as_arg: if not self.is_required: - type_str += ", (optional)" + type_info.append("optional") else: # readonly is only useful for selfs, not args if self.is_readonly: - type_str += ", (readonly)" + type_info.append("readonly") if self.is_never_none: - type_str += ", (never None)" + type_info.append("never None") + + if type_info: + type_str += (", (%s)" % ", ".join(type_info)) return type_str @@ -252,6 +302,7 @@ class InfoFunctionRNA: self.identifier = rna_func.identifier # self.name = rna_func.name # functions have no name! self.description = rna_func.description.strip() + self.is_classmethod = not rna_func.use_self self.args = [] self.return_values = () @@ -263,7 +314,7 @@ class InfoFunctionRNA: for rna_prop in rna_func.parameters.values(): prop = GetInfoPropertyRNA(rna_prop, parent_id) - if rna_prop.use_output: + if rna_prop.is_output: self.return_values.append(prop) else: self.args.append(prop) @@ -366,21 +417,7 @@ def BuildRNAInfo(): rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct) rna_children_dict = {} # store all rna_structs nested from here rna_references_dict = {} # store a list of rna path strings that reference this type - rna_functions_dict = {} # store all functions directly in this type (not inherited) - - def rna_id_ignore(rna_id): - if rna_id == "rna_type": - return True - - if "_OT_" in rna_id: - return True - if "_MT_" in rna_id: - return True - if "_PT_" in rna_id: - return True - if "_HT_" in rna_id: - return True - return False + # rna_functions_dict = {} # store all functions directly in this type (not inherited) def full_rna_struct_path(rna_struct): ''' @@ -426,7 +463,8 @@ def BuildRNAInfo(): rna_full_path_dict[identifier] = full_rna_struct_path(rna_struct) # Store a list of functions, remove inherited later - rna_functions_dict[identifier] = list(rna_struct.functions) + # NOT USED YET + ## rna_functions_dict[identifier] = get_direct_functions(rna_struct) # fill in these later @@ -438,12 +476,6 @@ def BuildRNAInfo(): print("Ignoring", rna_type_name) - # Sucks but we need to copy this so we can check original parent functions - rna_functions_dict__copy = {} - for key, val in rna_functions_dict.items(): - rna_functions_dict__copy[key] = val[:] - - structs.sort() # not needed but speeds up sort below, setting items without an inheritance first # Arrange so classes are always defined in the correct order @@ -478,41 +510,27 @@ def BuildRNAInfo(): # precalc vars to avoid a lot of looping for (rna_base, identifier, rna_struct) in structs: - if rna_base: - rna_base_prop_keys = rna_struct_dict[rna_base].properties.keys() # could cache - rna_base_func_keys = [f.identifier for f in rna_struct_dict[rna_base].functions] - else: - rna_base_prop_keys = [] - rna_base_func_keys = [] - # rna_struct_path = full_rna_struct_path(rna_struct) rna_struct_path = rna_full_path_dict[identifier] - for rna_prop_identifier, rna_prop in rna_struct.properties.items(): + for rna_prop in get_direct_properties(rna_struct): + rna_prop_identifier = rna_prop.identifier - if rna_prop_identifier == 'RNA' or \ - rna_id_ignore(rna_prop_identifier) or \ - rna_prop_identifier in rna_base_prop_keys: + if rna_prop_identifier == 'RNA' or rna_id_ignore(rna_prop_identifier): continue - for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)): # Does this property point to me? if rna_prop_ptr: rna_references_dict[rna_prop_ptr.identifier].append("%s.%s" % (rna_struct_path, rna_prop_identifier)) - for rna_func in rna_struct.functions: + for rna_func in get_direct_functions(rna_struct): for rna_prop_identifier, rna_prop in rna_func.parameters.items(): - if rna_prop_identifier == 'RNA' or \ - rna_id_ignore(rna_prop_identifier) or \ - rna_prop_identifier in rna_base_func_keys: + if rna_prop_identifier == 'RNA' or rna_id_ignore(rna_prop_identifier): continue - try: - rna_prop_ptr = rna_prop.fixed_type - except AttributeError: - rna_prop_ptr = None + rna_prop_ptr = getattr(rna_prop, "fixed_type", None) # Does this property point to me? if rna_prop_ptr: @@ -525,16 +543,6 @@ def BuildRNAInfo(): rna_children_dict[nested.identifier].append(rna_struct) - if rna_base: - rna_funcs = rna_functions_dict[identifier] - if rna_funcs: - # Remove inherited functions if we have any - rna_base_funcs = rna_functions_dict__copy[rna_base] - rna_funcs[:] = [f for f in rna_funcs if f not in rna_base_funcs] - - rna_functions_dict__copy.clear() - del rna_functions_dict__copy - # Sort the refs, just reads nicer for rna_refs in rna_references_dict.values(): rna_refs.sort() @@ -573,11 +581,21 @@ def BuildRNAInfo(): for prop in func.return_values: prop.build() + if 1: + for rna_info in InfoStructRNA.global_lookup.values(): + for prop in rna_info.properties: + # ERROR CHECK + default = prop.default + if type(default) in (float, int): + if default < prop.min or default > prop.max: + print("\t %s.%s, %s not in [%s - %s]" % (rna_info.identifier, prop.identifier, default, prop.min, prop.max)) + + # now for operators op_mods = dir(bpy.ops) for op_mod_name in sorted(op_mods): - if op_mod_name.startswith('__') or op_mod_name in ("add", "remove"): + if op_mod_name.startswith('__'): continue op_mod = getattr(bpy.ops, op_mod_name) @@ -603,3 +621,33 @@ def BuildRNAInfo(): # print(rna_info) return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup + + +if __name__ == "__main__": + import rna_info + struct = rna_info.BuildRNAInfo()[0] + data = [] + for struct_id, v in sorted(struct.items()): + struct_id_str = v.identifier # "".join(sid for sid in struct_id if struct_id) + + for base in v.get_bases(): + struct_id_str = base.identifier + "|" + struct_id_str + + props = [(prop.identifier, prop) for prop in v.properties] + for prop_id, prop in sorted(props): + # if prop.type == 'boolean': + # continue + prop_type = prop.type + if prop.array_length > 0: + prop_type += "[%d]" % prop.array_length + + data.append("%s.%s -> %s: %s%s %s" % (struct_id_str, prop.identifier, prop.identifier, prop_type, ", (read-only)" if prop.is_readonly else "", prop.description)) + data.sort() + + if bpy.app.background: + import sys + sys.stderr.write("\n".join(data)) + sys.stderr.write("\n\nEOF\n") + else: + text = bpy.data.texts.new(name="api.py") + text.from_string(data) diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py index 246fa4bdb7d..4ee0b40faa8 100644 --- a/release/scripts/modules/rna_prop_ui.py +++ b/release/scripts/modules/rna_prop_ui.py @@ -61,7 +61,7 @@ def rna_idprop_ui_prop_clear(item, prop): def draw(layout, context, context_member, use_edit=True): def assign_props(prop, val, key): - prop.path = context_member + prop.data_path = context_member prop.property = key try: @@ -81,7 +81,7 @@ def draw(layout, context, context_member, use_edit=True): if use_edit: row = layout.row() props = row.operator("wm.properties_add", text="Add") - props.path = context_member + props.data_path = context_member del row for key, val in items: @@ -124,141 +124,18 @@ def draw(layout, context, context_member, use_edit=True): assign_props(prop, val_draw, key) -class PropertyPanel(bpy.types.Panel): +class PropertyPanel(): """ The subclass should have its own poll function and the variable '_context_path' MUST be set. """ bl_label = "Custom Properties" - bl_default_closed = True + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + return bool(eval("context.%s" % cls._context_path)) def draw(self, context): draw(self.layout, context, self._context_path) - -from bpy.props import * - - -rna_path = StringProperty(name="Property Edit", - description="Property path edit", maxlen=1024, default="", options={'HIDDEN'}) - -rna_value = StringProperty(name="Property Value", - description="Property value edit", maxlen=1024, default="") - -rna_property = StringProperty(name="Property Name", - description="Property name edit", maxlen=1024, default="") - -rna_min = FloatProperty(name="Min", default=0.0, precision=3) -rna_max = FloatProperty(name="Max", default=1.0, precision=3) - - -class WM_OT_properties_edit(bpy.types.Operator): - '''Internal use (edit a property path)''' - bl_idname = "wm.properties_edit" - bl_label = "Edit Property" - - path = rna_path - property = rna_property - value = rna_value - min = rna_min - max = rna_max - description = StringProperty(name="Tip", default="") - - def execute(self, context): - path = self.properties.path - value = self.properties.value - prop = self.properties.property - prop_old = self._last_prop[0] - - try: - value_eval = eval(value) - except: - value_eval = value - - # First remove - item = eval("context.%s" % path) - - rna_idprop_ui_prop_clear(item, prop_old) - exec_str = "del item['%s']" % prop_old - # print(exec_str) - exec(exec_str) - - - # Reassign - exec_str = "item['%s'] = %s" % (prop, repr(value_eval)) - # print(exec_str) - exec(exec_str) - self._last_prop[:] = [prop] - - prop_type = type(item[prop]) - - prop_ui = rna_idprop_ui_prop_get(item, prop) - - if prop_type in (float, int): - - prop_ui['soft_min'] = prop_ui['min'] = prop_type(self.properties.min) - prop_ui['soft_max'] = prop_ui['max'] = prop_type(self.properties.max) - - prop_ui['description'] = self.properties.description - - return {'FINISHED'} - - def invoke(self, context, event): - - self._last_prop = [self.properties.property] - - item = eval("context.%s" % self.properties.path) - - # setup defaults - prop_ui = rna_idprop_ui_prop_get(item, self.properties.property, False) # dont create - if prop_ui: - self.properties.min = prop_ui.get("min", -1000000000) - self.properties.max = prop_ui.get("max", 1000000000) - self.properties.description = prop_ui.get("description", "") - - wm = context.manager - # This crashes, TODO - fix - #return wm.invoke_props_popup(self, event) - - wm.invoke_props_popup(self, event) - return {'RUNNING_MODAL'} - - -class WM_OT_properties_add(bpy.types.Operator): - '''Internal use (edit a property path)''' - bl_idname = "wm.properties_add" - bl_label = "Add Property" - - path = rna_path - - def execute(self, context): - item = eval("context.%s" % self.properties.path) - - def unique_name(names): - prop = 'prop' - prop_new = prop - i = 1 - while prop_new in names: - prop_new = prop + str(i) - i += 1 - - return prop_new - - property = unique_name(item.keys()) - - item[property] = 1.0 - return {'FINISHED'} - - -class WM_OT_properties_remove(bpy.types.Operator): - '''Internal use (edit a property path)''' - bl_idname = "wm.properties_remove" - bl_label = "Add Property" - - path = rna_path - property = rna_property - - def execute(self, context): - item = eval("context.%s" % self.properties.path) - del item[self.properties.property] - return {'FINISHED'} |