Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-02-16 13:57:57 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-03-14 14:39:16 +0300
commit36e8d00aec705b06008a0bc334fe266448b4f2c2 (patch)
tree02bf0290ec6423c611e3cd4ad49c69cb77acb67e /rigify/__init__.py
parenteabb5cddf79e5fae3ca429242cf2c6f5a272920e (diff)
Rigify: add support for user-defined rig packages and related utilities.
As suggested by @icappielo, and after discussion with @meta-androcto, I start a public request to commit third-party contributions already accepted to https://github.com/eigen-value/rigify/tree/rigify_0.6_beta Specifically, this includes: * User-defined rig package (feature set) support by @pioverfour. This allows users to install pre-packaged rig sets via zip files, which become accessible together with built-in rigs, as discussed in T52758. https://github.com/eigen-value/rigify/pull/1 * Modularization of python script generation, allowing rigs to add their own utility functions and operators to the generated script. This is critical to make custom rig support really useful. https://github.com/eigen-value/rigify/pull/5 * The utils.py file is split into multiple modules with a backward compatibility proxy for old functions. * Automatic verification that different rigs don't try to create different rig settings with the same name to alleviate increased risk of namespace conflicts with custom rigs. https://github.com/eigen-value/rigify/pull/7 * New utility class that implements bone layer selection UI. https://github.com/eigen-value/rigify/pull/6 * New utilities to replace copy & pasted boilerplate code for creating custom properties, constraints and drivers. https://github.com/eigen-value/rigify/pull/11 Some other random changes by MAD have likely slipped through. These changes have already been extensively discussed and accepted into the branch by @luciorossi, so I see no reason not to commit them to the official repository to be tested during 2.8 beta. Reviewers: icappiello Differential Revision: https://developer.blender.org/D4364
Diffstat (limited to 'rigify/__init__.py')
-rw-r--r--rigify/__init__.py151
1 files changed, 141 insertions, 10 deletions
diff --git a/rigify/__init__.py b/rigify/__init__.py
index 9fded5ef..2b0a553f 100644
--- a/rigify/__init__.py
+++ b/rigify/__init__.py
@@ -20,7 +20,7 @@
bl_info = {
"name": "Rigify",
- "version": (0, 5),
+ "version": (0, 5, 1),
"author": "Nathan Vegdahl, Lucio Rossi, Ivan Cappiello",
"blender": (2, 80, 0),
"description": "Automatic rigging from building-block components",
@@ -37,8 +37,9 @@ if "bpy" in locals():
importlib.reload(utils)
importlib.reload(metarig_menu)
importlib.reload(rig_lists)
+ importlib.reload(feature_sets)
else:
- from . import utils, rig_lists, generate, ui, metarig_menu
+ from . import (utils, rig_lists, generate, ui, metarig_menu, feature_sets)
import bpy
import sys
@@ -126,14 +127,35 @@ class RigifyPreferences(AddonPreferences):
register()
+ def update_external_rigs(self):
+ """Get external feature sets"""
+ if self.legacy_mode:
+ return
+
+ feature_sets_path = os.path.join(bpy.utils.script_path_user(), 'rigify')
+
+ if os.path.exists(feature_sets_path):
+ if feature_sets_path not in sys.path:
+ sys.path.append(feature_sets_path)
+ # Reload rigs
+ print('Reloading external rigs...')
+ rig_lists.get_external_rigs(feature_sets_path)
+
+ # Reload metarigs
+ print('Reloading external metarigs...')
+ metarig_menu.get_external_metarigs(feature_sets_path)
+
legacy_mode: BoolProperty(
name='Rigify Legacy Mode',
description='Select if you want to use Rigify in legacy mode',
default=False,
update=update_legacy
)
+
show_expanded: BoolProperty()
+ show_rigs_folder_expanded: BoolProperty()
+
def draw(self, context):
layout = self.layout
column = layout.column()
@@ -160,6 +182,33 @@ class RigifyPreferences(AddonPreferences):
split.label(text='Description:')
split.label(text='When enabled the add-on will run in legacy mode using the old 2.76b feature set.')
+ box = column.box()
+ rigs_expand = getattr(self, 'show_rigs_folder_expanded')
+ icon = 'TRIA_DOWN' if rigs_expand else 'TRIA_RIGHT'
+ col = box.column()
+ row = col.row()
+ sub = row.row()
+ sub.context_pointer_set('addon_prefs', self)
+ sub.alignment = 'LEFT'
+ op = sub.operator('wm.context_toggle', text='', icon=icon,
+ emboss=False)
+ op.data_path = 'addon_prefs.show_rigs_folder_expanded'
+ sub.label(text='{}: {}'.format('Rigify', 'External feature sets'))
+ if rigs_expand:
+ if os.path.exists(os.path.join(bpy.utils.script_path_user(), 'rigify')):
+ feature_sets_path = os.path.join(bpy.utils.script_path_user(), 'rigify')
+ for fs in os.listdir(feature_sets_path):
+ row = col.row()
+ row.label(text=fs)
+ op = row.operator("wm.rigify_remove_feature_set", text="Remove", icon='CANCEL')
+ op.featureset = fs
+ row = col.row(align=True)
+ row.operator("wm.rigify_add_feature_set", text="Install Feature Set from File...", icon='FILEBROWSER')
+
+ split = col.row().split(factor=0.15)
+ split.label(text='Description:')
+ split.label(text='External feature sets (rigs, metarigs, ui layouts)')
+
row = layout.row()
row.label(text="End of Rigify Preferences")
@@ -220,10 +269,65 @@ class RigifyParameters(bpy.types.PropertyGroup):
# Remember the initial property set
RIGIFY_PARAMETERS_BASE_DIR = set(dir(RigifyParameters))
+RIGIFY_PARAMETER_TABLE = {'name': ('DEFAULT', StringProperty())}
+
def clear_rigify_parameters():
for name in list(dir(RigifyParameters)):
if name not in RIGIFY_PARAMETERS_BASE_DIR:
delattr(RigifyParameters, name)
+ if name in RIGIFY_PARAMETER_TABLE:
+ del RIGIFY_PARAMETER_TABLE[name]
+
+
+def format_property_spec(spec):
+ """Turns the return value of bpy.props.SomeProperty(...) into a readable string."""
+ callback, params = spec
+ param_str = ["%s=%r" % (k, v) for k, v in params.items()]
+ return "%s(%s)" % (callback.__name__, ', '.join(param_str))
+
+
+class RigifyParameterValidator(object):
+ """
+ A wrapper around RigifyParameters that verifies properties
+ defined from rigs for incompatible redefinitions using a table.
+
+ Relies on the implementation details of bpy.props return values:
+ specifically, they just return a tuple containing the real define
+ function, and a dictionary with parameters. This allows comparing
+ parameters before the property is actually defined.
+ """
+ __params = None
+ __rig_name = ''
+ __prop_table = {}
+
+ def __init__(self, params, rig_name, prop_table):
+ self.__params = params
+ self.__rig_name = rig_name
+ self.__prop_table = prop_table
+
+ def __getattr__(self, name):
+ return getattr(self.__params, name)
+
+ def __setattr__(self, name, val):
+ # allow __init__ to work correctly
+ if hasattr(RigifyParameterValidator, name):
+ return object.__setattr__(self, name, val)
+
+ if not (isinstance(val, tuple) and callable(val[0]) and isinstance(val[1], dict)):
+ print("!!! RIGIFY RIG %s: INVALID DEFINITION FOR RIG PARAMETER %s: %r\n" % (self.__rig_name, name, val))
+ return
+
+ if name in self.__prop_table:
+ cur_rig, cur_info = self.__prop_table[name]
+ if val != cur_info:
+ print("!!! RIGIFY RIG %s: REDEFINING PARAMETER %s AS:\n\n %s\n" % (self.__rig_name, name, format_property_spec(val)))
+ print("!!! PREVIOUS DEFINITION BY %s:\n\n %s\n" % (cur_rig, format_property_spec(cur_info)))
+
+ # actually defining the property modifies the dictionary with new parameters, so copy it now
+ new_def = (val[0], val[1].copy())
+
+ setattr(self.__params, name, val)
+ self.__prop_table[name] = (self.__rig_name, new_def)
class RigifyArmatureLayer(bpy.types.PropertyGroup):
@@ -265,6 +369,7 @@ def register():
# Sub-modules.
ui.register()
+ feature_sets.register()
metarig_menu.register()
# Classes.
@@ -274,6 +379,12 @@ def register():
# Properties.
bpy.types.Armature.rigify_layers = CollectionProperty(type=RigifyArmatureLayer)
+ bpy.types.Armature.active_feature_set = EnumProperty(
+ items=feature_sets.feature_set_items,
+ name="Feature Set",
+ description="Restrict the rig list to a specific custom feature set"
+ )
+
bpy.types.PoseBone.rigify_type = StringProperty(name="Rigify Type", description="Rig type for this bone")
bpy.types.PoseBone.rigify_parameters = PointerProperty(type=RigifyParameters)
@@ -307,7 +418,7 @@ def register():
), name='Theme')
IDStore = bpy.types.WindowManager
- IDStore.rigify_collection = EnumProperty(items=rig_lists.col_enum_list, default="All",
+ IDStore.rigify_collection = EnumProperty(items=(("All", "All", "All"),), default="All",
name="Rigify Active Collection",
description="The selected rig collection")
@@ -360,22 +471,41 @@ def register():
if (ui and 'legacy' in str(ui)) or bpy.context.preferences.addons['rigify'].preferences.legacy_mode:
bpy.context.preferences.addons['rigify'].preferences.legacy_mode = True
+ bpy.context.preferences.addons['rigify'].preferences.update_external_rigs()
+
# Add rig parameters
- for rig in rig_lists.rig_list:
- r = utils.get_rig_type(rig)
- try:
- r.add_parameters(RigifyParameters)
- except AttributeError:
- pass
+ if bpy.context.preferences.addons['rigify'].preferences.legacy_mode:
+ for rig in rig_lists.rig_list:
+ r = utils.get_rig_type(rig)
+ try:
+ r.add_parameters(RigifyParameterValidator(RigifyParameters, rig, RIGIFY_PARAMETER_TABLE))
+ except AttributeError:
+ pass
+ else:
+ for rig in rig_lists.rigs:
+ r = rig_lists.rigs[rig]['module']
+ try:
+ r.add_parameters(RigifyParameterValidator(RigifyParameters, rig, RIGIFY_PARAMETER_TABLE))
+ except AttributeError:
+ pass
def unregister():
from bpy.utils import unregister_class
- # Properties.
+ # Properties on PoseBones and Armature.
del bpy.types.PoseBone.rigify_type
del bpy.types.PoseBone.rigify_parameters
+ ArmStore = bpy.types.Armature
+ del ArmStore.rigify_layers
+ del ArmStore.active_feature_set
+ del ArmStore.rigify_colors
+ del ArmStore.rigify_selection_colors
+ del ArmStore.rigify_colors_index
+ del ArmStore.rigify_colors_lock
+ del ArmStore.rigify_theme_to_add
+
IDStore = bpy.types.WindowManager
del IDStore.rigify_collection
del IDStore.rigify_types
@@ -401,3 +531,4 @@ def unregister():
# Sub-modules.
metarig_menu.unregister()
ui.unregister()
+ feature_sets.unregister()