1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2013 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup depsgraph
22  *
23  * Methods for constructing depsgraph
24  */
25 
26 #include "intern/builder/deg_builder_relations.h"
27 
28 #include <cstring> /* required for STREQ later on. */
29 #include <stdio.h>
30 #include <stdlib.h>
31 
32 #include "MEM_guardedalloc.h"
33 
34 #include "BLI_blenlib.h"
35 #include "BLI_utildefines.h"
36 
37 #include "DNA_action_types.h"
38 #include "DNA_anim_types.h"
39 #include "DNA_armature_types.h"
40 #include "DNA_constraint_types.h"
41 #include "DNA_customdata_types.h"
42 #include "DNA_object_types.h"
43 
44 #include "BKE_action.h"
45 #include "BKE_armature.h"
46 #include "BKE_constraint.h"
47 
48 #include "DEG_depsgraph.h"
49 #include "DEG_depsgraph_build.h"
50 
51 #include "intern/builder/deg_builder.h"
52 #include "intern/builder/deg_builder_pchanmap.h"
53 #include "intern/debug/deg_debug.h"
54 #include "intern/node/deg_node.h"
55 #include "intern/node/deg_node_component.h"
56 #include "intern/node/deg_node_operation.h"
57 
58 #include "intern/depsgraph_relation.h"
59 #include "intern/depsgraph_type.h"
60 
61 namespace blender {
62 namespace deg {
63 
64 /* IK Solver Eval Steps */
build_ik_pose(Object * object,bPoseChannel * pchan,bConstraint * con,RootPChanMap * root_map)65 void DepsgraphRelationBuilder::build_ik_pose(Object *object,
66                                              bPoseChannel *pchan,
67                                              bConstraint *con,
68                                              RootPChanMap *root_map)
69 {
70   if ((con->flag & CONSTRAINT_DISABLE) != 0) {
71     /* Do not add disabled IK constraints to the relations. If these needs to be temporarily
72      * enabled, they will be added as temporary constraints during transform. */
73     return;
74   }
75 
76   bKinematicConstraint *data = (bKinematicConstraint *)con->data;
77   /* Attach owner to IK Solver to. */
78   bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
79   if (rootchan == nullptr) {
80     return;
81   }
82   OperationKey pchan_local_key(
83       &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
84   OperationKey init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK);
85   OperationKey solver_key(
86       &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_IK_SOLVER);
87   OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
88   add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree");
89   add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
90   /* Never cleanup before solver is run. */
91   add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup", RELATION_FLAG_GODMODE);
92   /* The ITASC solver currently accesses the target transforms in init tree :(
93    * TODO: Fix ITASC and remove this.
94    */
95   bool is_itasc = (object->pose->iksolver == IKSOLVER_ITASC);
96   OperationKey target_dependent_key = is_itasc ? init_ik_key : solver_key;
97   /* IK target */
98   /* TODO(sergey): This should get handled as part of the constraint code. */
99   if (data->tar != nullptr) {
100     /* Different object - requires its transform. */
101     if (data->tar != object) {
102       ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM);
103       add_relation(target_key, target_dependent_key, con->name);
104     }
105     /* Subtarget references: */
106     if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
107       /* Bone - use the final transformation. */
108       OperationKey target_key(
109           &data->tar->id, NodeType::BONE, data->subtarget, OperationCode::BONE_DONE);
110       add_relation(target_key, target_dependent_key, con->name);
111     }
112     else if (data->subtarget[0] && ELEM(data->tar->type, OB_MESH, OB_LATTICE)) {
113       /* Vertex group target. */
114       /* NOTE: for now, we don't need to represent vertex groups
115        * separately. */
116       ComponentKey target_key(&data->tar->id, NodeType::GEOMETRY);
117       add_relation(target_key, target_dependent_key, con->name);
118       add_customdata_mask(data->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT));
119     }
120     if (data->tar == object && data->subtarget[0]) {
121       /* Prevent target's constraints from linking to anything from same
122        * chain that it controls. */
123       root_map->add_bone(data->subtarget, rootchan->name);
124     }
125   }
126   /* Pole Target. */
127   /* TODO(sergey): This should get handled as part of the constraint code. */
128   if (data->poletar != nullptr) {
129     /* Different object - requires its transform. */
130     if (data->poletar != object) {
131       ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM);
132       add_relation(target_key, target_dependent_key, con->name);
133     }
134     /* Subtarget references: */
135     if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
136       /* Bone - use the final transformation. */
137       OperationKey target_key(
138           &data->poletar->id, NodeType::BONE, data->polesubtarget, OperationCode::BONE_DONE);
139       add_relation(target_key, target_dependent_key, con->name);
140     }
141     else if (data->polesubtarget[0] && ELEM(data->poletar->type, OB_MESH, OB_LATTICE)) {
142       /* Vertex group target. */
143       /* NOTE: for now, we don't need to represent vertex groups
144        * separately. */
145       ComponentKey target_key(&data->poletar->id, NodeType::GEOMETRY);
146       add_relation(target_key, target_dependent_key, con->name);
147       add_customdata_mask(data->poletar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT));
148     }
149   }
150   DEG_DEBUG_PRINTF((::Depsgraph *)graph_,
151                    BUILD,
152                    "\nStarting IK Build: pchan = %s, target = (%s, %s), "
153                    "segcount = %d\n",
154                    pchan->name,
155                    data->tar ? data->tar->id.name : "nullptr",
156                    data->subtarget,
157                    data->rootbone);
158   bPoseChannel *parchan = pchan;
159   /* Exclude tip from chain if needed. */
160   if (!(data->flag & CONSTRAINT_IK_TIP)) {
161     parchan = pchan->parent;
162   }
163   root_map->add_bone(parchan->name, rootchan->name);
164   OperationKey parchan_transforms_key(
165       &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY);
166   add_relation(parchan_transforms_key, solver_key, "IK Solver Owner");
167   /* Walk to the chain's root. */
168   int segcount = 0;
169   while (parchan != nullptr) {
170     /* Make IK-solver dependent on this bone's result, since it can only run
171      * after the standard results of the bone are know. Validate links step
172      * on the bone will ensure that users of this bone only grab the result
173      * with IK solver results. */
174     if (parchan != pchan) {
175       OperationKey parent_key(
176           &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY);
177       add_relation(parent_key, solver_key, "IK Chain Parent");
178       OperationKey bone_done_key(
179           &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE);
180       add_relation(solver_key, bone_done_key, "IK Chain Result");
181     }
182     else {
183       OperationKey final_transforms_key(
184           &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE);
185       add_relation(solver_key, final_transforms_key, "IK Solver Result");
186     }
187     parchan->flag |= POSE_DONE;
188     root_map->add_bone(parchan->name, rootchan->name);
189     /* continue up chain, until we reach target number of items. */
190     DEG_DEBUG_PRINTF((::Depsgraph *)graph_, BUILD, "  %d = %s\n", segcount, parchan->name);
191     /* TODO(sergey): This is an arbitrary value, which was just following
192      * old code convention. */
193     segcount++;
194     if ((segcount == data->rootbone) || (segcount > 255)) {
195       break;
196     }
197     parchan = parchan->parent;
198   }
199   OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
200   add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
201 
202   /* Add relation when the root of this IK chain is influenced by another IK chain. */
203   build_inter_ik_chains(object, solver_key, rootchan, root_map);
204 }
205 
206 /* Spline IK Eval Steps */
build_splineik_pose(Object * object,bPoseChannel * pchan,bConstraint * con,RootPChanMap * root_map)207 void DepsgraphRelationBuilder::build_splineik_pose(Object *object,
208                                                    bPoseChannel *pchan,
209                                                    bConstraint *con,
210                                                    RootPChanMap *root_map)
211 {
212   bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
213   bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
214   OperationKey transforms_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY);
215   OperationKey init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK);
216   OperationKey solver_key(
217       &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_SPLINE_IK_SOLVER);
218   OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
219   /* Solver depends on initialization. */
220   add_relation(init_ik_key, solver_key, "Init IK -> IK Solver");
221   /* Never cleanup before solver is run. */
222   add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup");
223   /* Attach owner to IK Solver. */
224   add_relation(transforms_key, solver_key, "Spline IK Solver Owner", RELATION_FLAG_GODMODE);
225   /* Attach path dependency to solver. */
226   if (data->tar != nullptr) {
227     ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY);
228     add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK");
229     ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM);
230     add_relation(target_transform_key, solver_key, "Curve.Transform -> Spline IK");
231     add_special_eval_flag(&data->tar->id, DAG_EVAL_NEED_CURVE_PATH);
232   }
233   pchan->flag |= POSE_DONE;
234   OperationKey final_transforms_key(
235       &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE);
236   add_relation(solver_key, final_transforms_key, "Spline IK Result");
237   root_map->add_bone(pchan->name, rootchan->name);
238   /* Walk to the chain's root/ */
239   int segcount = 1;
240   for (bPoseChannel *parchan = pchan->parent; parchan != nullptr && segcount < data->chainlen;
241        parchan = parchan->parent, segcount++) {
242     /* Make Spline IK solver dependent on this bone's result, since it can
243      * only run after the standard results of the bone are know. Validate
244      * links step on the bone will ensure that users of this bone only grab
245      * the result with IK solver results. */
246     OperationKey parent_key(&object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY);
247     add_relation(parent_key, solver_key, "Spline IK Solver Update");
248     OperationKey bone_done_key(
249         &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE);
250     add_relation(solver_key, bone_done_key, "Spline IK Solver Result");
251     parchan->flag |= POSE_DONE;
252     root_map->add_bone(parchan->name, rootchan->name);
253   }
254   OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
255   add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link");
256 
257   /* Add relation when the root of this IK chain is influenced by another IK chain. */
258   build_inter_ik_chains(object, solver_key, rootchan, root_map);
259 }
260 
build_inter_ik_chains(Object * object,const OperationKey & solver_key,const bPoseChannel * rootchan,const RootPChanMap * root_map)261 void DepsgraphRelationBuilder::build_inter_ik_chains(Object *object,
262                                                      const OperationKey &solver_key,
263                                                      const bPoseChannel *rootchan,
264                                                      const RootPChanMap *root_map)
265 {
266   bPoseChannel *deepest_root = nullptr;
267   const char *root_name = rootchan->name;
268 
269   /* Find shared IK chain root. */
270   for (bPoseChannel *parchan = rootchan->parent; parchan; parchan = parchan->parent) {
271     if (!root_map->has_common_root(root_name, parchan->name)) {
272       break;
273     }
274     deepest_root = parchan;
275   }
276   if (deepest_root == nullptr) {
277     return;
278   }
279 
280   OperationKey other_bone_key(
281       &object->id, NodeType::BONE, deepest_root->name, OperationCode::BONE_DONE);
282   add_relation(other_bone_key, solver_key, "IK Chain Overlap");
283 }
284 
285 /* Pose/Armature Bones Graph */
build_rig(Object * object)286 void DepsgraphRelationBuilder::build_rig(Object *object)
287 {
288   /* Armature-Data */
289   bArmature *armature = (bArmature *)object->data;
290   // TODO: selection status?
291   /* Attach links between pose operations. */
292   ComponentKey local_transform(&object->id, NodeType::TRANSFORM);
293   OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT);
294   OperationKey pose_init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK);
295   OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
296   OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
297   add_relation(local_transform, pose_init_key, "Local Transform -> Pose Init");
298   add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK");
299   add_relation(pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup");
300   /* Make sure pose is up-to-date with armature updates. */
301   build_armature(armature);
302   OperationKey armature_key(&armature->id, NodeType::ARMATURE, OperationCode::ARMATURE_EVAL);
303   add_relation(armature_key, pose_init_key, "Data dependency");
304   /* Run cleanup even when there are no bones. */
305   add_relation(pose_init_key, pose_cleanup_key, "Init -> Cleanup");
306   /* IK Solvers.
307    *
308    * - These require separate processing steps are pose-level to be executed
309    *   between chains of bones (i.e. once the base transforms of a bunch of
310    *   bones is done).
311    *
312    * - We build relations for these before the dependencies between operations
313    *   in the same component as it is necessary to check whether such bones
314    *   are in the same IK chain (or else we get weird issues with either
315    *   in-chain references, or with bones being parented to IK'd bones).
316    *
317    * Unsolved Issues:
318    * - Care is needed to ensure that multi-headed trees work out the same as
319    *   in ik-tree building
320    * - Animated chain-lengths are a problem. */
321   RootPChanMap root_map;
322   bool pose_depends_on_local_transform = false;
323   LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
324     LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
325       switch (con->type) {
326         case CONSTRAINT_TYPE_KINEMATIC:
327           build_ik_pose(object, pchan, con, &root_map);
328           pose_depends_on_local_transform = true;
329           break;
330         case CONSTRAINT_TYPE_SPLINEIK:
331           build_splineik_pose(object, pchan, con, &root_map);
332           pose_depends_on_local_transform = true;
333           break;
334         /* Constraints which needs world's matrix for transform.
335          * TODO(sergey): More constraints here? */
336         case CONSTRAINT_TYPE_ROTLIKE:
337         case CONSTRAINT_TYPE_SIZELIKE:
338         case CONSTRAINT_TYPE_LOCLIKE:
339         case CONSTRAINT_TYPE_TRANSLIKE:
340           /* TODO(sergey): Add used space check. */
341           pose_depends_on_local_transform = true;
342           break;
343         default:
344           break;
345       }
346     }
347   }
348   // root_map.print_debug();
349   if (pose_depends_on_local_transform) {
350     /* TODO(sergey): Once partial updates are possible use relation between
351      * object transform and solver itself in its build function. */
352     ComponentKey pose_key(&object->id, NodeType::EVAL_POSE);
353     ComponentKey local_transform_key(&object->id, NodeType::TRANSFORM);
354     add_relation(local_transform_key, pose_key, "Local Transforms");
355   }
356   /* Links between operations for each bone. */
357   LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
358     build_idproperties(pchan->prop);
359     OperationKey bone_local_key(
360         &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
361     OperationKey bone_pose_key(
362         &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_POSE_PARENT);
363     OperationKey bone_ready_key(
364         &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY);
365     OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE);
366     pchan->flag &= ~POSE_DONE;
367     /* Pose init to bone local. */
368     add_relation(pose_init_key, bone_local_key, "Pose Init - Bone Local", RELATION_FLAG_GODMODE);
369     /* Local to pose parenting operation. */
370     add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose");
371     /* Parent relation. */
372     if (pchan->parent != nullptr) {
373       OperationCode parent_key_opcode;
374       /* NOTE: this difference in handling allows us to prevent lockups
375        * while ensuring correct poses for separate chains. */
376       if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
377         parent_key_opcode = OperationCode::BONE_READY;
378       }
379       else {
380         parent_key_opcode = OperationCode::BONE_DONE;
381       }
382 
383       OperationKey parent_key(&object->id, NodeType::BONE, pchan->parent->name, parent_key_opcode);
384       add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone");
385     }
386     /* Build constraints. */
387     if (pchan->constraints.first != nullptr) {
388       /* Build relations for indirectly linked objects. */
389       BuilderWalkUserData data;
390       data.builder = this;
391       BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data);
392       /* Constraints stack and constraint dependencies. */
393       build_constraints(&object->id, NodeType::BONE, pchan->name, &pchan->constraints, &root_map);
394       /* Pose -> constraints. */
395       OperationKey constraints_key(
396           &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_CONSTRAINTS);
397       add_relation(bone_pose_key, constraints_key, "Pose -> Constraints Stack");
398       add_relation(bone_local_key, constraints_key, "Local -> Constraints Stack");
399       /* Constraints -> ready/ */
400       /* TODO(sergey): When constraint stack is exploded, this step should
401        * occur before the first IK solver.  */
402       add_relation(constraints_key, bone_ready_key, "Constraints -> Ready");
403     }
404     else {
405       /* Pose -> Ready */
406       add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready");
407     }
408     /* Bone ready -> Bone done.
409      * NOTE: For bones without IK, this is all that's needed.
410      *       For IK chains however, an additional rel is created from IK
411      *       to done, with transitive reduction removing this one. */
412     add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
413     /* B-Bone shape is the real final step after Done if present. */
414     if (check_pchan_has_bbone(object, pchan)) {
415       OperationKey bone_segments_key(
416           &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS);
417       /* B-Bone shape depends on the final position of the bone. */
418       add_relation(bone_done_key, bone_segments_key, "Done -> B-Bone Segments");
419       /* B-Bone shape depends on final position of handle bones. */
420       bPoseChannel *prev, *next;
421       BKE_pchan_bbone_handles_get(pchan, &prev, &next);
422       if (prev) {
423         OperationCode opcode = OperationCode::BONE_DONE;
424         /* Inheriting parent roll requires access to prev handle's B-Bone properties. */
425         if ((pchan->bone->flag & BONE_ADD_PARENT_END_ROLL) != 0 &&
426             check_pchan_has_bbone_segments(object, prev)) {
427           opcode = OperationCode::BONE_SEGMENTS;
428         }
429         OperationKey prev_key(&object->id, NodeType::BONE, prev->name, opcode);
430         add_relation(prev_key, bone_segments_key, "Prev Handle -> B-Bone Segments");
431       }
432       if (next) {
433         OperationKey next_key(&object->id, NodeType::BONE, next->name, OperationCode::BONE_DONE);
434         add_relation(next_key, bone_segments_key, "Next Handle -> B-Bone Segments");
435       }
436       /* Pose requires the B-Bone shape. */
437       add_relation(
438           bone_segments_key, pose_done_key, "PoseEval Result-Bone Link", RELATION_FLAG_GODMODE);
439       add_relation(bone_segments_key, pose_cleanup_key, "Cleanup dependency");
440     }
441     else {
442       /* Assume that all bones must be done for the pose to be ready
443        * (for deformers). */
444       add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link");
445 
446       /* Bones must be traversed before cleanup. */
447       add_relation(bone_done_key, pose_cleanup_key, "Done -> Cleanup");
448 
449       add_relation(bone_ready_key, pose_cleanup_key, "Ready -> Cleanup");
450     }
451     /* Custom shape. */
452     if (pchan->custom != nullptr) {
453       build_object(pchan->custom);
454     }
455   }
456 }
457 
build_proxy_rig(Object * object)458 void DepsgraphRelationBuilder::build_proxy_rig(Object *object)
459 {
460   bArmature *armature = (bArmature *)object->data;
461   Object *proxy_from = object->proxy_from;
462   build_armature(armature);
463   OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT);
464   OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE);
465   OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP);
466   LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) {
467     build_idproperties(pchan->prop);
468     OperationKey bone_local_key(
469         &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL);
470     OperationKey bone_ready_key(
471         &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY);
472     OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE);
473     OperationKey from_bone_done_key(
474         &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE);
475     add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local");
476     add_relation(bone_local_key, bone_ready_key, "Local -> Ready");
477     add_relation(bone_ready_key, bone_done_key, "Ready -> Done");
478     add_relation(bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup");
479     add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done", RELATION_FLAG_GODMODE);
480     /* Make sure bone in the proxy is not done before its FROM is done. */
481     if (check_pchan_has_bbone(object, pchan)) {
482       OperationKey from_bone_segments_key(
483           &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS);
484       add_relation(from_bone_segments_key,
485                    bone_done_key,
486                    "Bone Segments -> Bone Done",
487                    RELATION_FLAG_GODMODE);
488     }
489     else {
490       add_relation(from_bone_done_key, bone_done_key, "Bone Done -> Bone Done");
491     }
492 
493     /* Parent relation: even though the proxy bone itself doesn't need
494      * the parent bone, some users expect the parent to be ready if the
495      * bone itself is (e.g. for computing the local space matrix).
496      */
497     if (pchan->parent != nullptr) {
498       OperationKey parent_key(
499           &object->id, NodeType::BONE, pchan->parent->name, OperationCode::BONE_DONE);
500       add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone");
501     }
502 
503     if (pchan->prop != nullptr) {
504       OperationKey bone_parameters(
505           &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
506       OperationKey from_bone_parameters(
507           &proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name);
508       add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters");
509     }
510   }
511 }
512 
513 }  // namespace deg
514 }  // namespace blender
515