Newer
Older
#====================== 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 ========================
from bpy.props import (
BoolProperty,
IntProperty,
EnumProperty,
StringProperty
)
from mathutils import Color
Alexander Gavrilov
committed
from .utils.errors import MetarigError
from .utils.rig import write_metarig
from .utils.widgets import write_widget
from .utils.naming import unique_name
from .utils.rig import upgradeMetarigTypes, outdated_types
from .rigs.utils import get_limb_generated_names
from .utils.animation import get_keyed_frames_in_range, bones_in_frame, overwrite_prop_animation
from .utils.animation import RIGIFY_OT_get_frame_range
from .utils.animation import register as animation_register
from .utils.animation import unregister as animation_unregister
from . import base_rig
from . import rig_lists
from . import generate
from . import rot_mode
from . import feature_set_list
Alexander Gavrilov
committed
def build_type_list(context, rigify_types):
rigify_types.clear()
for r in sorted(rig_lists.rigs):
if (context.object.data.active_feature_set in ('all', rig_lists.rigs[r]['feature_set'])
or len(feature_set_list.get_installed_list()) == 0
Alexander Gavrilov
committed
):
a = rigify_types.add()
a.name = r
class DATA_PT_rigify_generate_base(bpy.types.Panel):
@classmethod
def poll(cls, context):
obj = context.object
if not context.object:
return False
return obj.type == 'ARMATURE' \
and obj.data.get("rig_id") is None \
and obj.mode in {'POSE', 'OBJECT'}
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
class DATA_PT_rigify_generate(DATA_PT_rigify_generate_base):
bl_label = "Rigify Generation"
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
id_store = context.window_manager
armature_id_store = context.object.data
show_warning = False
show_update_metarig = False
show_not_updatable = False
show_upgrade_face = False
check_props = ['IK_follow', 'root/parent', 'FK_limb_follow', 'IK_Stretch']
for bone in obj.pose.bones:
if bone.bone.layers[30] and (list(set(bone.keys()) & set(check_props))):
show_warning = True
break
for b in obj.pose.bones:
if b.rigify_type in outdated_types.keys():
old_bone = b.name
old_rig = b.rigify_type
if outdated_types[b.rigify_type]:
show_update_metarig = True
else:
show_update_metarig = False
show_not_updatable = True
Alexander Gavrilov
committed
break
elif b.rigify_type == 'faces.super_face':
show_upgrade_face = True
if show_warning:
layout.label(text="Warning: Some features may change after generation", icon='ERROR')
if show_not_updatable:
layout.label(text="WARNING: This metarig contains deprecated rigify rig-types and cannot be upgraded automatically.", icon='ERROR')
layout.label(text="("+old_rig+" on bone "+old_bone+")")
layout.label(text="If you want to use it anyway try enabling the legacy mode before generating again.")
Alexander Gavrilov
committed
layout.operator("pose.rigify_switch_to_legacy", text="Switch to Legacy")
elif show_update_metarig:
layout.label(text="This metarig contains old rig-types that can be automatically upgraded to benefit of rigify's new features.", icon='ERROR')
layout.label(text="("+old_rig+" on bone "+old_bone+")")
layout.label(text="To use it as-is you need to enable legacy mode.",)
layout.operator("pose.rigify_upgrade_types", text="Upgrade Metarig")
elif show_upgrade_face:
layout.label(text="This metarig uses the old face rig.", icon='INFO')
layout.operator("pose.rigify_upgrade_face")
Alexander Gavrilov
committed
enable_generation = not (show_not_updatable or show_update_metarig)
Alexander Gavrilov
committed
col = layout.column()
col.enabled = enable_generation
# Make it clear whether we are generating a new object or overwriting existing one.
text = "Generate New Rig"
if armature_id_store.rigify_target_rig:
text = f'Re-Generate Target Rig'
col.row().operator("pose.rigify_generate", text=text, icon='POSE_HLT')
class DATA_PT_rigify_generate_advanced(DATA_PT_rigify_generate_base):
bl_label = "Advanced"
bl_parent_id = 'DATA_PT_rigify_generate'
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
armature_id_store = context.object.data
col = layout.column()
col.row().prop(armature_id_store, 'rigify_target_rig', text="Target Rig")
col.row().prop(armature_id_store, 'rigify_rig_ui', text="Rig UI Script")
col.row().prop(armature_id_store, 'rigify_force_widget_update')
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
class DATA_PT_rigify_samples(bpy.types.Panel):
bl_label = "Rigify Samples"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
@classmethod
def poll(cls, context):
obj = context.object
if not obj:
return False
return obj.type == 'ARMATURE' \
and obj.data.get("rig_id") is None \
and obj.mode == 'EDIT'
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
obj = context.object
id_store = context.window_manager
# Build types list
build_type_list(context, id_store.rigify_types)
if id_store.rigify_active_type > len(id_store.rigify_types):
id_store.rigify_active_type = 0
# Rig type list
if len(feature_set_list.get_installed_list()) > 0:
layout.row().prop(obj.data, "active_feature_set")
row = layout.row()
row.template_list("UI_UL_list", "rigify_types", id_store, "rigify_types", id_store, 'rigify_active_type')
props = layout.operator("armature.metarig_sample_add", text="Add sample")
props.metarig_type = id_store.rigify_types[id_store.rigify_active_type].name
Nathan Vegdahl
committed
class DATA_PT_rigify_layer_names(bpy.types.Panel):
bl_label = "Rigify Layer Names"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
if not context.object:
return False
return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is None
Nathan Vegdahl
committed
def draw(self, context):
layout = self.layout
obj = context.object
Nathan Vegdahl
committed
# Ensure that the layers exist
Campbell Barton
committed
if 0:
for i in range(1 + len(arm.rigify_layers), 29):
arm.rigify_layers.add()
Campbell Barton
committed
else:
# Can't add while drawing, just use button
if len(arm.rigify_layers) < 29:
Campbell Barton
committed
layout.operator("pose.rigify_layer_init")
return
Nathan Vegdahl
committed
# UI
main_row = layout.row(align=True).split(factor=0.05)
col1 = main_row.column()
col2 = main_row.column()
col1.label()
for i in range(32):
if i == 16 or i == 29:
col1.label()
for i, rigify_layer in enumerate(arm.rigify_layers):
# note: rigify_layer == arm.rigify_layers[i]
Nathan Vegdahl
committed
if (i % 16) == 0:
col = col2.column()
Nathan Vegdahl
committed
if i == 0:
col.label(text="Top Row:")
else:
col.label(text="Bottom Row:")
if (i % 8) == 0:
col = col2.column()
if i != 28:
row = col.row(align=True)
icon = 'RESTRICT_VIEW_OFF' if arm.layers[i] else 'RESTRICT_VIEW_ON'
row.prop(arm, "layers", index=i, text="", toggle=True, icon=icon)
#row.prop(arm, "layers", index=i, text="Layer %d" % (i + 1), toggle=True, icon=icon)
row.prop(rigify_layer, "name", text="")
row.prop(rigify_layer, "row", text="UI Row")
icon = 'RADIOBUT_ON' if rigify_layer.selset else 'RADIOBUT_OFF'
row.prop(rigify_layer, "selset", text="", toggle=True, icon=icon)
row.prop(rigify_layer, "group", text="Bone Group")
else:
row = col.row(align=True)
icon = 'RESTRICT_VIEW_OFF' if arm.layers[i] else 'RESTRICT_VIEW_ON'
row.prop(arm, "layers", index=i, text="", toggle=True, icon=icon)
# row.prop(arm, "layers", index=i, text="Layer %d" % (i + 1), toggle=True, icon=icon)
row1 = row.split(align=True).row(align=True)
row1.prop(rigify_layer, "name", text="")
row1.prop(rigify_layer, "row", text="UI Row")
row1.enabled = False
icon = 'RADIOBUT_ON' if rigify_layer.selset else 'RADIOBUT_OFF'
row.prop(rigify_layer, "selset", text="", toggle=True, icon=icon)
row.prop(rigify_layer, "group", text="Bone Group")
if rigify_layer.group == 0:
row.label(text='None')
else:
row.label(text=arm.rigify_colors[rigify_layer.group-1].name)
col = col2.column()
col.label(text="Reserved:")
# reserved_names = {28: 'Root', 29: 'DEF', 30: 'MCH', 31: 'ORG'}
reserved_names = {29: 'DEF', 30: 'MCH', 31: 'ORG'}
# for i in range(28, 32):
for i in range(29, 32):
row = col.row(align=True)
icon = 'RESTRICT_VIEW_OFF' if arm.layers[i] else 'RESTRICT_VIEW_ON'
row.prop(arm, "layers", index=i, text="", toggle=True, icon=icon)
row.label(text=reserved_names[i])
class DATA_OT_rigify_add_bone_groups(bpy.types.Operator):
bl_idname = "armature.rigify_add_bone_groups"
bl_label = "Rigify Add Standard Bone Groups"
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
obj = context.object
armature = obj.data
if not hasattr(armature, 'rigify_colors'):
return {'FINISHED'}
groups = ['Root', 'IK', 'Special', 'Tweak', 'FK', 'Extra']
for g in groups:
if g in armature.rigify_colors.keys():
continue
armature.rigify_colors.add()
armature.rigify_colors[-1].name = g
armature.rigify_colors[g].select = Color((0.3140000104904175, 0.7839999794960022, 1.0))
armature.rigify_colors[g].active = Color((0.5490000247955322, 1.0, 1.0))
armature.rigify_colors[g].standard_colors_lock = True
if g == "Root":
armature.rigify_colors[g].normal = Color((0.43529415130615234, 0.18431372940540314, 0.41568630933761597))
if g == "IK":
armature.rigify_colors[g].normal = Color((0.6039215922355652, 0.0, 0.0))
if g== "Special":
armature.rigify_colors[g].normal = Color((0.9568628072738647, 0.7882353663444519, 0.0470588281750679))
if g== "Tweak":
armature.rigify_colors[g].normal = Color((0.03921568766236305, 0.21176472306251526, 0.5803921818733215))
if g== "FK":
armature.rigify_colors[g].normal = Color((0.11764706671237946, 0.5686274766921997, 0.03529411926865578))
if g== "Extra":
armature.rigify_colors[g].normal = Color((0.9686275124549866, 0.250980406999588, 0.0941176563501358))
return {'FINISHED'}
class DATA_OT_rigify_use_standard_colors(bpy.types.Operator):
bl_idname = "armature.rigify_use_standard_colors"
bl_label = "Rigify Get active/select colors from current theme"
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
obj = context.object
armature = obj.data
if not hasattr(armature, 'rigify_colors'):
return {'FINISHED'}
current_theme = bpy.context.preferences.themes.items()[0][0]
theme = bpy.context.preferences.themes[current_theme]
armature.rigify_selection_colors.select = theme.view_3d.bone_pose
armature.rigify_selection_colors.active = theme.view_3d.bone_pose_active
# for col in armature.rigify_colors:
# col.select = theme.view_3d.bone_pose
# col.active = theme.view_3d.bone_pose_active
return {'FINISHED'}
class DATA_OT_rigify_apply_selection_colors(bpy.types.Operator):
bl_idname = "armature.rigify_apply_selection_colors"
bl_label = "Rigify Apply user defined active/select colors"
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
obj = context.object
armature = obj.data
if not hasattr(armature, 'rigify_colors'):
return {'FINISHED'}
#current_theme = bpy.context.preferences.themes.items()[0][0]
#theme = bpy.context.preferences.themes[current_theme]
for col in armature.rigify_colors:
col.select = armature.rigify_selection_colors.select
col.active = armature.rigify_selection_colors.active
return {'FINISHED'}
class DATA_OT_rigify_bone_group_add(bpy.types.Operator):
bl_idname = "armature.rigify_bone_group_add"
bl_label = "Rigify Add Bone Group color set"
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
obj = context.object
armature = obj.data
if hasattr(armature, 'rigify_colors'):
armature.rigify_colors.add()
armature.rigify_colors[-1].name = unique_name(armature.rigify_colors, 'Group')
current_theme = bpy.context.preferences.themes.items()[0][0]
theme = bpy.context.preferences.themes[current_theme]
armature.rigify_colors[-1].normal = theme.view_3d.wire
armature.rigify_colors[-1].normal.hsv = theme.view_3d.wire.hsv
armature.rigify_colors[-1].select = theme.view_3d.bone_pose
armature.rigify_colors[-1].select.hsv = theme.view_3d.bone_pose.hsv
armature.rigify_colors[-1].active = theme.view_3d.bone_pose_active
armature.rigify_colors[-1].active.hsv = theme.view_3d.bone_pose_active.hsv
return {'FINISHED'}
class DATA_OT_rigify_bone_group_add_theme(bpy.types.Operator):
bl_idname = "armature.rigify_bone_group_add_theme"
bl_label = "Rigify Add Bone Group color set from Theme"
bl_options = {"REGISTER", "UNDO"}
theme: EnumProperty(items=(
('THEME01', 'THEME01', ''),
('THEME02', 'THEME02', ''),
('THEME03', 'THEME03', ''),
('THEME04', 'THEME04', ''),
('THEME05', 'THEME05', ''),
('THEME06', 'THEME06', ''),
('THEME07', 'THEME07', ''),
('THEME08', 'THEME08', ''),
('THEME09', 'THEME09', ''),
('THEME10', 'THEME10', ''),
('THEME11', 'THEME11', ''),
('THEME12', 'THEME12', ''),
('THEME13', 'THEME13', ''),
('THEME14', 'THEME14', ''),
('THEME15', 'THEME15', ''),
('THEME16', 'THEME16', ''),
('THEME17', 'THEME17', ''),
('THEME18', 'THEME18', ''),
('THEME19', 'THEME19', ''),
('THEME20', 'THEME20', '')
),
name='Theme')
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
obj = context.object
armature = obj.data
if hasattr(armature, 'rigify_colors'):
if self.theme in armature.rigify_colors.keys():
return {'FINISHED'}
armature.rigify_colors.add()
armature.rigify_colors[-1].name = self.theme
id = int(self.theme[-2:]) - 1
theme_color_set = bpy.context.preferences.themes[0].bone_color_sets[id]
armature.rigify_colors[-1].normal = theme_color_set.normal
armature.rigify_colors[-1].select = theme_color_set.select
armature.rigify_colors[-1].active = theme_color_set.active
return {'FINISHED'}
class DATA_OT_rigify_bone_group_remove(bpy.types.Operator):
bl_idname = "armature.rigify_bone_group_remove"
bl_label = "Rigify Remove Bone Group color set"
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
obj = context.object
obj.data.rigify_colors.remove(self.idx)
# set layers references to 0
for l in obj.data.rigify_layers:
if l.group == self.idx + 1:
l.group = 0
elif l.group > self.idx + 1:
l.group -= 1
return {'FINISHED'}
class DATA_OT_rigify_bone_group_remove_all(bpy.types.Operator):
bl_idname = "armature.rigify_bone_group_remove_all"
bl_label = "Rigify Remove All Bone Groups"
@classmethod
def poll(cls, context):
return context.object and context.object.type == 'ARMATURE'
def execute(self, context):
obj = context.object
for i, col in enumerate(obj.data.rigify_colors):
obj.data.rigify_colors.remove(0)
# set layers references to 0
for l in obj.data.rigify_layers:
if l.group == i + 1:
l.group = 0
return {'FINISHED'}
class DATA_UL_rigify_bone_groups(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
row = layout.row(align=True)
row.label(text=str(index+1))
row.prop(item, "name", text='', emboss=False)
row = row.row(align=True)
icon = 'LOCKED' if item.standard_colors_lock else 'UNLOCKED'
#row.prop(item, "standard_colors_lock", text='', icon=icon)
row.prop(item, "normal", text='')
row2 = row.row(align=True)
row2.prop(item, "select", text='')
row2.prop(item, "active", text='')
#row2.enabled = not item.standard_colors_lock
row2.enabled = not bpy.context.object.data.rigify_colors_lock
class DATA_MT_rigify_bone_groups_context_menu(bpy.types.Menu):
bl_label = 'Rigify Bone Groups Specials'
def draw(self, context):
layout = self.layout
layout.operator('armature.rigify_bone_group_remove_all')
class DATA_PT_rigify_bone_groups(bpy.types.Panel):
bl_label = "Rigify Bone Groups"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
if not context.object:
return False
return context.object.type == 'ARMATURE' and context.active_object.data.get("rig_id") is None
def draw(self, context):
obj = context.object
armature = obj.data
color_sets = obj.data.rigify_colors
idx = obj.data.rigify_colors_index
layout = self.layout
row = layout.row()
row.operator("armature.rigify_use_standard_colors", icon='FILE_REFRESH', text='')
row = row.row(align=True)
row.prop(armature.rigify_selection_colors, 'select', text='')
row.prop(armature.rigify_selection_colors, 'active', text='')
row = layout.row(align=True)
icon = 'LOCKED' if armature.rigify_colors_lock else 'UNLOCKED'
row.prop(armature, 'rigify_colors_lock', text = 'Unified select/active colors', icon=icon)
row.operator("armature.rigify_apply_selection_colors", icon='FILE_REFRESH', text='Apply')
row = layout.row()
row.template_list("DATA_UL_rigify_bone_groups", "", obj.data, "rigify_colors", obj.data, "rigify_colors_index")
col = row.column(align=True)
col.operator("armature.rigify_bone_group_add", icon='ZOOM_IN', text="")
col.operator("armature.rigify_bone_group_remove", icon='ZOOM_OUT', text="").idx = obj.data.rigify_colors_index
col.menu("DATA_MT_rigify_bone_groups_context_menu", icon='DOWNARROW_HLT', text="")
row = layout.row()
row.prop(armature, 'rigify_theme_to_add', text = 'Theme')
op = row.operator("armature.rigify_bone_group_add_theme", text="Add From Theme")
op.theme = armature.rigify_theme_to_add
row = layout.row()
row.operator("armature.rigify_add_bone_groups", text="Add Standard")
Nathan Vegdahl
committed
class BONE_PT_rigify_buttons(bpy.types.Panel):
bl_label = "Rigify Type"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "bone"
#bl_options = {'DEFAULT_OPEN'}
@classmethod
def poll(cls, context):
if not context.object:
return False
return context.object.type == 'ARMATURE' and context.active_pose_bone\
and context.active_object.data.get("rig_id") is None
def draw(self, context):
C = context
Campbell Barton
committed
id_store = C.window_manager
bone = context.active_pose_bone
rig_name = str(context.active_pose_bone.rigify_type).replace(" ", "")
layout = self.layout
# Build types list
Alexander Gavrilov
committed
build_type_list(context, id_store.rigify_types)
if len(feature_set_list.get_installed_list()) > 0:
Alexander Gavrilov
committed
row = layout.row()
row.prop(context.object.data, "active_feature_set")
Alexander Gavrilov
committed
row.prop_search(bone, "rigify_type", id_store, "rigify_types", text="Rig type")
# Rig type parameters / Rig type non-exist alert
if rig_name != "":
try:
Alexander Gavrilov
committed
rig = rig_lists.rigs[rig_name]['module']
except (ImportError, AttributeError, KeyError):
box.label(text="ERROR: type \"%s\" does not exist!" % rig_name, icon='ERROR')
if hasattr(rig.Rig, 'parameters_ui'):
rig = rig.Rig
param_cb = rig.parameters_ui
# Ignore the known empty base method
if getattr(param_cb, '__func__', None) == base_rig.BaseRig.parameters_ui.__func__:
param_cb = None
param_cb = None
if param_cb is None:
col = layout.column()
col.label(text="No options")
else:
col = layout.column()
col.label(text="Options:")
box = layout.box()
param_cb(box, bone.rigify_parameters)
class VIEW3D_PT_tools_rigify_dev(bpy.types.Panel):
bl_label = "Rigify Dev Tools"
bl_space_type = 'VIEW_3D'
Alexander Gavrilov
committed
@classmethod
def poll(cls, context):
return context.mode in ['EDIT_ARMATURE', 'EDIT_MESH']
@classmethod
def poll(cls, context):
return context.mode in ['EDIT_ARMATURE', 'EDIT_MESH']
obj = context.active_object
if context.mode == 'EDIT_ARMATURE':
r = self.layout.row()
r.operator("armature.rigify_encode_metarig", text="Encode Metarig to Python")
r = self.layout.row()
r.operator("armature.rigify_encode_metarig_sample", text="Encode Sample to Python")
if context.mode == 'EDIT_MESH':
r = self.layout.row()
r.operator("mesh.rigify_encode_mesh_widget", text="Encode Mesh Widget to Python")
class VIEW3D_PT_rigify_animation_tools(bpy.types.Panel):
bl_label = "Rigify Animation Tools"
bl_context = "posemode"
bl_space_type = 'VIEW_3D'
@classmethod
def poll(cls, context):
obj = context.active_object
if obj and obj.type == 'ARMATURE':
rig_id = obj.data.get("rig_id")
if rig_id is not None:
has_arm = hasattr(bpy.types, 'POSE_OT_rigify_arm_ik2fk_' + rig_id)
has_leg = hasattr(bpy.types, 'POSE_OT_rigify_leg_ik2fk_' + rig_id)
return has_arm or has_leg
return False
def draw(self, context):
obj = context.active_object
id_store = context.window_manager
if obj is not None:
row = self.layout.row()
if id_store.rigify_transfer_only_selected:
icon = 'OUTLINER_DATA_ARMATURE'
else:
icon = 'ARMATURE_DATA'
row.prop(id_store, 'rigify_transfer_only_selected', toggle=True, icon=icon)
row = self.layout.row(align=True)
row.operator("rigify.ik2fk", text='IK2FK Pose', icon='SNAP_ON')
row.operator("rigify.fk2ik", text='FK2IK Pose', icon='SNAP_ON')
row = self.layout.row(align=True)
row.operator("rigify.transfer_fk_to_ik", text='IK2FK Action', icon='ACTION_TWEAK')
row.operator("rigify.transfer_ik_to_fk", text='FK2IK Action', icon='ACTION_TWEAK')
row = self.layout.row(align=True)
row.operator("rigify.clear_animation", text="Clear IK Action", icon='CANCEL').anim_type = "IK"
row.operator("rigify.clear_animation", text="Clear FK Action", icon='CANCEL').anim_type = "FK"
row = self.layout.row(align=True)
op = row.operator("rigify.rotation_pole", icon='FORCE_HARMONIC', text='Switch to pole')
op.value = True
op.toggle = False
op.bake = True
op = row.operator("rigify.rotation_pole", icon='FORCE_MAGNETIC', text='Switch to rotation')
op.value = False
op.toggle = False
op.bake = True
RIGIFY_OT_get_frame_range.draw_range_ui(context, self.layout)
def rigify_report_exception(operator, exception):
import traceback
import sys
import os
# find the non-utils module name where the error happened
# hint, this is the metarig type!
exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
fns = [ item.filename for item in traceback.extract_tb(exceptionTraceback) ]
fns_rig = [ fn for fn in fns if os.path.basename(os.path.dirname(fn)) != 'utils' ]
fn = fns_rig[-1]
fn = os.path.basename(fn)
fn = os.path.splitext(fn)[0]
message = []
if fn.startswith("__"):
message.append("Incorrect armature...")
else:
message.append("Incorrect armature for type '%s'" % fn)
message.append(exception.message)
message.reverse() # XXX - stupid! menu's are upside down!
operator.report({'ERROR'}, '\n'.join(message))
Campbell Barton
committed
class LayerInit(bpy.types.Operator):
"""Initialize armature rigify layers"""
bl_idname = "pose.rigify_layer_init"
bl_label = "Add Rigify Layers"
bl_options = {'UNDO', 'INTERNAL'}
Campbell Barton
committed
def execute(self, context):
obj = context.object
for i in range(1 + len(arm.rigify_layers), 30):
arm.rigify_layers[28].name = 'Root'
arm.rigify_layers[28].row = 14
Campbell Barton
committed
return {'FINISHED'}
def is_metarig(obj):
if not (obj and obj.data and obj.type == 'ARMATURE'):
return False
if 'rig_id' in obj.data:
return False
for b in obj.pose.bones:
if b.rigify_type != "":
return True
return False
"""Generates a rig from the active metarig armature"""
bl_idname = "pose.rigify_generate"
bl_label = "Rigify Generate Rig"
bl_options = {'UNDO'}
bl_description = 'Generates a rig from the active metarig armature'
@classmethod
def poll(cls, context):
return is_metarig(context.object)
generate.generate_rig(context, metarig)
except MetarigError as rig_exception:
import traceback
traceback.print_exc()
rigify_report_exception(self, rig_exception)
except Exception as rig_exception:
import traceback
traceback.print_exc()
self.report({'ERROR'}, 'Generation has thrown an exception: ' + str(rig_exception))
else:
self.report({'INFO'}, 'Successfully generated: "' + metarig.data.rigify_target_rig.name + '"')
finally:
bpy.ops.object.mode_set(mode='OBJECT')
class UpgradeMetarigTypes(bpy.types.Operator):
"""Upgrades metarig bones rigify_types"""
bl_idname = "pose.rigify_upgrade_types"
bl_label = "Rigify Upgrade Metarig Types"
bl_description = 'Upgrades the rigify types on the active metarig armature'
bl_options = {'UNDO'}
def execute(self, context):
for obj in bpy.data.objects:
if type(obj.data) == bpy.types.Armature:
upgradeMetarigTypes(obj)
return {'FINISHED'}
"""Create a sample metarig to be modified before generating the final rig"""
bl_idname = "armature.metarig_sample_add"
bl_label = "Add Metarig Sample"
bl_options = {'UNDO'}
metarig_type: StringProperty(
name="Type",
description="Name of the rig type to generate a sample of",
maxlen=128,
options={'SKIP_SAVE'}
@classmethod
def poll(cls, context):
return context.mode == 'EDIT_ARMATURE'
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False
col = layout.column()
build_type_list(context, context.window_manager.rigify_types)
col.prop(context.object.data, "active_feature_set")
col.prop_search(self, "metarig_type", context.window_manager, "rigify_types")
def invoke(self, context, event):
if self.metarig_type == "":
return context.window_manager.invoke_props_dialog(self)
return self.execute(context)
if self.metarig_type == "":
self.report({'ERROR'}, "You must select a rig type to create a sample of.")
return {'CANCELLED'}
try:
rig = rig_lists.rigs[self.metarig_type]["module"]
create_sample = rig.create_sample
except (ImportError, AttributeError, KeyError):
raise Exception("rig type '" + self.metarig_type + "' has no sample.")
else:
create_sample(context.active_object)
finally:
bpy.ops.object.mode_set(mode='EDIT')
class EncodeMetarig(bpy.types.Operator):
"""Creates Python code that will generate the selected metarig"""
bl_idname = "armature.rigify_encode_metarig"
bl_label = "Rigify Encode Metarig"
bl_options = {'UNDO'}
@classmethod
def poll(self, context):
return context.mode == 'EDIT_ARMATURE' and is_metarig(context.object)
def execute(self, context):
name = "metarig.py"
if name in bpy.data.texts:
text_block = bpy.data.texts[name]
text_block.clear()
else:
text_block = bpy.data.texts.new(name)
text = write_metarig(context.active_object, layers=True, func_name="create", groups=True, widgets=True)
text_block.write(text)
bpy.ops.object.mode_set(mode='EDIT')
self.report({'INFO'}, f"Metarig written to text datablock: {text_block.name}")
return {'FINISHED'}
class EncodeMetarigSample(bpy.types.Operator):
"""Creates Python code that will generate the selected metarig as a sample"""
bl_idname = "armature.rigify_encode_metarig_sample"
bl_label = "Rigify Encode Metarig Sample"
bl_options = {'UNDO'}
@classmethod
def poll(self, context):
return context.mode == 'EDIT_ARMATURE' and is_metarig(context.object)
def execute(self, context):
name = "metarig_sample.py"
if name in bpy.data.texts:
text_block = bpy.data.texts[name]
text_block.clear()
else:
text_block = bpy.data.texts.new(name)
text = write_metarig(context.active_object, layers=False, func_name="create_sample")
text_block.write(text)
bpy.ops.object.mode_set(mode='EDIT')
self.report({'INFO'}, f"Metarig Sample written to text datablock: {text_block.name}")
class VIEW3D_MT_rigify(bpy.types.Menu):
bl_label = "Rigify"
bl_idname = "VIEW3D_MT_rigify"
def draw(self, context):
layout = self.layout
layout.operator(Generate.bl_idname, text="Generate")
if context.mode == 'EDIT_ARMATURE':
layout.separator()
layout.operator(Sample.bl_idname)
layout.separator()
layout.operator(EncodeMetarig.bl_idname, text="Encode Metarig")
layout.operator(EncodeMetarigSample.bl_idname, text="Encode Metarig Sample")
def draw_rigify_menu(self, context):
if is_metarig(context.object):
self.layout.menu(VIEW3D_MT_rigify.bl_idname)
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
class EncodeWidget(bpy.types.Operator):
""" Creates Python code that will generate the selected metarig.
"""
bl_idname = "mesh.rigify_encode_mesh_widget"
bl_label = "Rigify Encode Widget"
bl_options = {'UNDO'}
@classmethod
def poll(self, context):
return context.mode == 'EDIT_MESH'
def execute(self, context):
name = "widget.py"
if name in bpy.data.texts:
text_block = bpy.data.texts[name]
text_block.clear()
else:
text_block = bpy.data.texts.new(name)
text = write_widget(context.active_object)
text_block.write(text)
bpy.ops.object.mode_set(mode='EDIT')
return {'FINISHED'}
def draw_mesh_edit_menu(self, context):
self.layout.operator(EncodeWidget.bl_idname)
self.layout.separator()
def FktoIk(rig, window='ALL'):
scn = bpy.context.scene
id_store = bpy.context.window_manager
rig_id = rig.data['rig_id']
leg_ik2fk = eval('bpy.ops.pose.rigify_leg_ik2fk_' + rig_id)
arm_ik2fk = eval('bpy.ops.pose.rigify_arm_ik2fk_' + rig_id)
limb_generated_names = get_limb_generated_names(rig)
if window == 'ALL':
frames = get_keyed_frames_in_range(bpy.context, rig)
elif window == 'CURRENT':
frames = [scn.frame_current]
else:
frames = [scn.frame_current]
if not id_store.rigify_transfer_only_selected:
pbones = rig.pose.bones
bpy.ops.pose.select_all(action='DESELECT')
else:
pbones = bpy.context.selected_pose_bones
bpy.ops.pose.select_all(action='DESELECT')