1 # SPDX-FileCopyrightText: 2019-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
7 from bpy
.types
import PoseBone
, UILayout
, Context
8 from typing
import TYPE_CHECKING
, Any
, Callable
, Optional
, TypeVar
, Generic
10 from .utils
.errors
import RaiseErrorMixin
11 from .utils
.bones
import BoneDict
, BoneUtilityMixin
, TypedBoneDict
, BaseBoneDict
12 from .utils
.mechanism
import MechanismUtilityMixin
13 from .utils
.metaclass
import BaseStagedClass
14 from .utils
.misc
import ArmatureObject
15 from .utils
.rig
import get_rigify_params
18 from .base_generate
import BaseGenerator
19 from .rig_ui_template
import ScriptGenerator
22 ##############################################
24 ##############################################
26 class GenerateCallbackHost(BaseStagedClass
, define_stages
=True):
28 Standard set of callback methods to redefine.
29 Shared between BaseRig and GeneratorPlugin.
31 These callbacks are called in this order; every one is
32 called for all rigs before proceeding to the next stage.
34 Switching modes is not allowed in rigs for performance
35 reasons. Place code in the appropriate callbacks to use
36 the mode set by the main engine.
38 After each callback, all other methods decorated with
39 @stage.<method_name> are called, for instance:
41 def generate_bones(self):
48 Will print 'first', then 'second'. Multiple methods in the
49 same stage are called in the order they are first defined;
50 in case of inheritance, the class bodies are scanned in
51 reverse MRO order. E.g.:
64 # Was first defined in Base so still first:
71 Multiple inheritance can make this ordering confusing, so it
74 When overriding such methods in a subclass the appropriate
75 decorator should be repeated for code clarity reasons;
76 a warning is printed if this is not done.
80 Initialize processing after all rig classes are constructed.
81 Called in Object mode. May not change the armature.
85 def prepare_bones(self
):
87 Prepare ORG bones for generation, e.g. align them.
88 Called in Edit mode. May not add bones.
92 def generate_bones(self
):
99 def parent_bones(self
):
101 Parent all bones and set other edit mode properties.
102 Called in Edit mode. May not add bones.
106 def configure_bones(self
):
108 Configure bone properties, e.g. transform locks, layers etc.
109 Called in Object mode. May not do Edit mode operations.
113 def preapply_bones(self
):
115 Read bone matrices for applying to edit mode.
116 Called in Object mode. May not do Edit mode operations.
120 def apply_bones(self
):
122 Can be used to apply some constraints to rest pose, and for final parenting.
123 Called in Edit mode. May not add bones.
129 Create and configure all constraints, drivers etc.
130 Called in Object mode. May not do Edit mode operations.
134 def generate_widgets(self
):
136 Create all widget objects.
137 Called in Object mode. May not do Edit mode operations.
143 Finishing touches to the construction of the rig.
144 Called in Object mode. May not do Edit mode operations.
149 _Org
= TypeVar('_Org', bound
=str |
list[str] | BaseBoneDict
)
150 _Ctrl
= TypeVar('_Ctrl', bound
=str |
list[str] | BaseBoneDict
)
151 _Mch
= TypeVar('_Mch', bound
=str |
list[str] | BaseBoneDict
)
152 _Deform
= TypeVar('_Deform', bound
=str |
list[str] | BaseBoneDict
)
155 class BaseRigMixin(RaiseErrorMixin
, BoneUtilityMixin
, MechanismUtilityMixin
):
156 generator
: 'BaseGenerator'
159 script
: 'ScriptGenerator'
163 rigify_parent
: Optional
['BaseRig']
164 rigify_children
: list['BaseRig']
165 rigify_org_bones
: set[str]
166 rigify_child_bones
: set[str]
167 rigify_new_bones
: dict[str, Optional
[str]]
168 rigify_derived_bones
: dict[str, set[str]]
170 ##############################################
171 # Annotated bone containers
173 class ToplevelBones(TypedBoneDict
, Generic
[_Org
, _Ctrl
, _Mch
, _Deform
]):
179 class CtrlBones(TypedBoneDict
):
182 class MchBones(TypedBoneDict
):
185 # Subclass and use the above CtrlBones and MchBones classes in overrides.
186 # It is necessary to reference them via absolute strings, e.g. 'Rig.CtrlBones',
187 # because when using just CtrlBones the annotation won't work fully in subclasses
188 # of the rig class in PyCharm (no warnings about unknown attribute access).
189 bones
: ToplevelBones
[str |
list[str] | BoneDict
,
190 str |
list[str] | BoneDict
,
191 str |
list[str] | BoneDict
,
192 str |
list[str] | BoneDict
]
195 class BaseRig(GenerateCallbackHost
, BaseRigMixin
):
197 Base class for all rigs.
199 The main weak areas in the legacy (pre-2.76b) Rigify rig class structure
200 was that there were no provisions for intelligent interactions
201 between rigs, and all processing was done via one generate
202 method, necessitating frequent expensive mode switches.
204 This structure fixes those problems by providing a mandatory
205 base class that hold documented connections between rigs, bones,
206 and the common generator object. The generation process is also
207 split into multiple stages.
209 def __init__(self
, generator
: 'BaseGenerator', pose_bone
: PoseBone
):
210 self
.generator
= generator
212 self
.obj
= generator
.obj
213 self
.script
= generator
.script
214 self
.base_bone
= pose_bone
.name
215 self
.params
= get_rigify_params(pose_bone
)
217 # Collection of bone names for use in implementing the rig
218 self
.bones
= self
.ToplevelBones(
220 org
=self
.find_org_bones(pose_bone
),
229 # Data useful for complex rig interaction:
230 # Parent-child links between rigs.
231 self
.rigify_parent
= None
232 self
.rigify_children
= []
233 # ORG bones directly owned by the rig.
234 self
.rigify_org_bones
= set(self
.bones
.flatten('org'))
235 # Children of bones owned by the rig.
236 self
.rigify_child_bones
= set()
237 # Bones created by the rig (mapped to original names)
238 self
.rigify_new_bones
= dict()
239 self
.rigify_derived_bones
= collections
.defaultdict(set)
241 def register_new_bone(self
, new_name
: str, old_name
: Optional
[str] = None):
242 """Registers this rig as the owner of this new bone."""
243 self
.rigify_new_bones
[new_name
] = old_name
244 self
.generator
.bone_owners
[new_name
] = self
246 self
.rigify_derived_bones
[old_name
].add(new_name
)
247 self
.generator
.derived_bones
[old_name
].add(new_name
)
249 ###########################################################
252 def find_org_bones(self
, pose_bone
: PoseBone
) -> str |
list[str] | BaseBoneDict
:
254 Select bones directly owned by the rig. Returning the
255 same bone from multiple rigs is an error.
257 May return a single name, a list, or a BoneDict.
259 Called in Object mode, may not change the armature.
261 return [pose_bone
.name
]
263 ###########################################################
267 def add_parameters(cls
, params
):
269 This method add more parameters to params
270 :param params: rigify_parameters of a pose_bone
276 def parameters_ui(cls
, layout
: UILayout
, params
):
278 This method draws the UI of the rigify_parameters defined on the pose_bone
286 def on_parameter_update(cls
, context
: Context
, pose_bone
: PoseBone
, params
, param_name
: str):
288 A callback invoked whenever a parameter value is changed by the user.
292 ##############################################
294 ##############################################
297 class RigUtility(BoneUtilityMixin
, MechanismUtilityMixin
):
298 """Base class for utility classes that generate part of a rig."""
299 def __init__(self
, owner
):
303 def register_new_bone(self
, new_name
: str, old_name
: Optional
[str] = None):
304 self
.owner
.register_new_bone(new_name
, old_name
)
307 class LazyRigComponent(GenerateCallbackHost
, RigUtility
):
308 """Base class for utility classes that generate part of a rig using callbacks. Starts as disabled."""
309 def __init__(self
, owner
):
310 super().__init
__(owner
)
312 self
.is_component_enabled
= False
314 def enable_component(self
):
315 if not self
.is_component_enabled
:
316 self
.is_component_enabled
= True
317 self
.owner
.rigify_sub_objects
= objects
= self
.owner
.rigify_sub_objects
or []
321 class RigComponent(LazyRigComponent
):
322 """Base class for utility classes that generate part of a rig using callbacks."""
323 def __init__(self
, owner
):
324 super().__init
__(owner
)
325 self
.enable_component()
328 ##############################################
329 # Rig Stage Decorators
330 ##############################################
332 # noinspection PyPep8Naming
333 @GenerateCallbackHost.stage_decorator_container
335 """Contains @stage.<...> decorators for all valid stages."""
336 # Declare stages for auto-completion - doesn't affect execution.
338 prepare_bones
: Callable
339 generate_bones
: Callable
340 parent_bones
: Callable
341 configure_bones
: Callable
342 preapply_bones
: Callable
343 apply_bones
: Callable
345 generate_widgets
: Callable