File headers: use SPDX license identifiers
[blender-addons.git] / rigify / utils / layers.py
blob1b807cc7d2f31badef28a1999aca4569bbacab07
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # <pep8 compliant>
5 import bpy
8 ORG_LAYER = [n == 31 for n in range(0, 32)] # Armature layer that original bones should be moved to.
9 MCH_LAYER = [n == 30 for n in range(0, 32)] # Armature layer that mechanism bones should be moved to.
10 DEF_LAYER = [n == 29 for n in range(0, 32)] # Armature layer that deformation bones should be moved to.
11 ROOT_LAYER = [n == 28 for n in range(0, 32)] # Armature layer that root bone should be moved to.
14 def get_layers(layers):
15 """ Does its best to extract a set of layers from any data thrown at it.
16 """
17 if type(layers) == int:
18 return [x == layers for x in range(0, 32)]
19 elif type(layers) == str:
20 s = layers.split(",")
21 l = []
22 for i in s:
23 try:
24 l += [int(float(i))]
25 except ValueError:
26 pass
27 return [x in l for x in range(0, 32)]
28 elif type(layers) == tuple or type(layers) == list:
29 return [x in layers for x in range(0, 32)]
30 else:
31 try:
32 list(layers)
33 except TypeError:
34 pass
35 else:
36 return [x in layers for x in range(0, 32)]
39 def set_bone_layers(bone, layers, combine=False):
40 if combine:
41 bone.layers = [ a or b for a, b in zip(bone.layers, layers) ]
42 else:
43 bone.layers = layers
46 #=============================================
47 # UI utilities
48 #=============================================
51 def layout_layer_buttons(layout, params, option, active_layers):
52 "Draw a layer selection button UI with certain layers marked with dots."
53 outer = layout.row()
55 for x in [0, 8]:
56 col = outer.column(align=True)
58 for y in [0, 16]:
59 row = col.row(align=True)
61 for i in range(x+y, x+y+8):
62 row.prop(
63 params, option, index=i, toggle=True, text="",
64 icon="LAYER_ACTIVE" if active_layers[i] else "NONE"
68 class ControlLayersOption:
69 def __init__(self, name, toggle_name=None, toggle_default=True, description="Set of control layers"):
70 self.name = name
71 self.toggle_default = toggle_default
72 self.description = description
74 self.toggle_option = self.name+'_layers_extra'
75 self.layers_option = self.name+'_layers'
76 self.toggle_name = toggle_name if toggle_name else "Assign " + self.name.title() + " Layers"
78 def get(self, params):
79 if getattr(params, self.toggle_option):
80 return list(getattr(params, self.layers_option))
81 else:
82 return None
84 def assign(self, params, bone_set, bone_list, combine=False):
85 layers = self.get(params)
87 if isinstance(bone_set, bpy.types.Object):
88 bone_set = bone_set.data.bones
90 if layers:
91 for name in bone_list:
92 bone = bone_set[name]
93 if isinstance(bone, bpy.types.PoseBone):
94 bone = bone.bone
96 set_bone_layers(bone, layers, combine)
98 def assign_rig(self, rig, bone_list, combine=False, priority=None):
99 layers = self.get(rig.params)
100 bone_set = rig.obj.data.bones
102 if layers:
103 for name in bone_list:
104 set_bone_layers(bone_set[name], layers, combine)
106 if priority is not None:
107 rig.generator.set_layer_group_priority(name, layers, priority)
109 def add_parameters(self, params):
110 prop_toggle = bpy.props.BoolProperty(
111 name=self.toggle_name,
112 default=self.toggle_default,
113 description=""
116 setattr(params, self.toggle_option, prop_toggle)
118 prop_layers = bpy.props.BoolVectorProperty(
119 size=32,
120 description=self.description,
121 subtype='LAYER',
122 default=tuple([i == 1 for i in range(0, 32)])
125 setattr(params, self.layers_option, prop_layers)
127 def parameters_ui(self, layout, params):
128 box = layout.box()
129 box.prop(params, self.toggle_option)
131 active = getattr(params, self.toggle_option)
133 if not active:
134 return
136 active_layers = bpy.context.active_pose_bone.bone.layers[:]
138 layout_layer_buttons(box, params, self.layers_option, active_layers)
141 ControlLayersOption.FK = ControlLayersOption('fk', description="Layers for the FK controls to be on")
142 ControlLayersOption.TWEAK = ControlLayersOption('tweak', description="Layers for the tweak controls to be on")
144 ControlLayersOption.EXTRA_IK = ControlLayersOption(
145 'extra_ik', toggle_default=False,
146 toggle_name="Extra IK Layers",
147 description="Layers for the optional IK controls to be on",
150 # Layer parameters used by the super_face rig.
151 ControlLayersOption.FACE_PRIMARY = ControlLayersOption('primary', description="Layers for the primary controls to be on")
152 ControlLayersOption.FACE_SECONDARY = ControlLayersOption('secondary', description="Layers for the secondary controls to be on")
154 # Layer parameters used by the skin rigs
155 ControlLayersOption.SKIN_PRIMARY = ControlLayersOption(
156 'skin_primary', toggle_default=False,
157 toggle_name="Primary Control Layers",
158 description="Layers for the primary controls to be on",
161 ControlLayersOption.SKIN_SECONDARY = ControlLayersOption(
162 'skin_secondary', toggle_default=False,
163 toggle_name="Secondary Control Layers",
164 description="Layers for the secondary controls to be on",