Depsgraph: Move rig builder functions to own files
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 17 Nov 2016 13:34:46 +0000 (14:34 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 17 Nov 2016 13:41:16 +0000 (14:41 +0100)
Those routines are rather big and started to be annoying to have
one big file.

Should be no functional changes.

source/blender/depsgraph/CMakeLists.txt
source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc [new file with mode: 0644]
source/blender/depsgraph/intern/builder/deg_builder_relations.cc
source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc [new file with mode: 0644]

index ab12a8d5b3ef98c17e0c596664ac9ae4f469704b..ea839d11071a38314ad7b3a7f42922fb307dd229 100644 (file)
@@ -43,9 +43,11 @@ set(SRC
        intern/builder/deg_builder.cc
        intern/builder/deg_builder_cycle.cc
        intern/builder/deg_builder_nodes.cc
+       intern/builder/deg_builder_nodes_rig.cc
        intern/builder/deg_builder_pchanmap.cc
        intern/builder/deg_builder_relations.cc
        intern/builder/deg_builder_relations_keys.cc
+       intern/builder/deg_builder_relations_rig.cc
        intern/builder/deg_builder_transitive.cc
        intern/debug/deg_debug_graphviz.cc
        intern/eval/deg_eval.cc
index 12050e3e003c2166ceca37bc29fbf133be093a3f..1eaacea69ebea4dcd81e4d5caca5c02f00e1316d 100644 (file)
@@ -626,14 +626,6 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
                           DEG_OPCODE_TRANSFORM_CONSTRAINTS);
 }
 
-void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
-{
-       /* create node for constraint stack */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                          DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
-                          DEG_OPCODE_BONE_CONSTRAINTS);
-}
-
 /**
  * Build graph nodes for AnimData block
  * \param id: ID-Block which hosts the AnimData
@@ -829,207 +821,6 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
        // TODO...
 }
 
-/* IK Solver Eval Steps */
-void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
-{
-       bKinematicConstraint *data = (bKinematicConstraint *)con->data;
-
-       /* Find the chain's root. */
-       bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
-
-       if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
-                              DEG_OPCODE_POSE_IK_SOLVER))
-       {
-               return;
-       }
-
-       /* Operation node for evaluating/running IK Solver. */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
-                          DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
-                          DEG_OPCODE_POSE_IK_SOLVER);
-}
-
-/* Spline IK Eval Steps */
-void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
-{
-       bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
-
-       /* Find the chain's root. */
-       bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
-
-       /* Operation node for evaluating/running Spline IK Solver.
-        * Store the "root bone" of this chain in the solver, so it knows where to start.
-        */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
-                          DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
-                          DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
-}
-
-/* Pose/Armature Bones Graph */
-void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
-{
-       bArmature *arm = (bArmature *)ob->data;
-
-       /* animation and/or drivers linking posebones to base-armature used to define them
-        * NOTE: AnimData here is really used to control animated deform properties,
-        *       which ideally should be able to be unique across different instances.
-        *       Eventually, we need some type of proxy/isolation mechanism in-between here
-        *       to ensure that we can use same rig multiple times in same scene...
-        */
-       build_animdata(&arm->id);
-
-       /* Rebuild pose if not up to date. */
-       if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
-               BKE_pose_rebuild_ex(ob, arm, false);
-               /* XXX: Without this animation gets lost in certain circumstances
-                * after loading file. Need to investigate further since it does
-                * not happen with simple scenes..
-                */
-               if (ob->adt) {
-                       ob->adt->recalc |= ADT_RECALC_ANIM;
-               }
-       }
-
-       /* speed optimization for animation lookups */
-       if (ob->pose) {
-               BKE_pose_channels_hash_make(ob->pose);
-               if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
-                       BKE_pose_update_constraint_flags(ob->pose);
-               }
-       }
-
-       /* Make sure pose is up-to-date with armature updates. */
-       add_operation_node(&arm->id,
-                          DEPSNODE_TYPE_PARAMETERS,
-                          DEPSOP_TYPE_EXEC,
-                          NULL,
-                          DEG_OPCODE_PLACEHOLDER,
-                          "Armature Eval");
-
-       /**
-        * Pose Rig Graph
-        * ==============
-        *
-        * Pose Component:
-        * - Mainly used for referencing Bone components.
-        * - This is where the evaluation operations for init/exec/cleanup
-        *   (ik) solvers live, and are later hooked up (so that they can be
-        *   interleaved during runtime) with bone-operations they depend on/affect.
-        * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
-        *   steps of pose eval process. ALL bone operations must be performed
-        *   between these two...
-        *
-        * Bone Component:
-        * - Used for representing each bone within the rig
-        * - Acts to encapsulate the evaluation operations (base matrix + parenting,
-        *   and constraint stack) so that they can be easily found.
-        * - Everything else which depends on bone-results hook up to the component only
-        *   so that we can redirect those to point at either the the post-IK/
-        *   post-constraint/post-matrix steps, as needed.
-        */
-
-       /* pose eval context */
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
-
-       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
-
-       /* bones */
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               /* node for bone eval */
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
-                                  DEG_OPCODE_BONE_LOCAL);
-
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
-                                  DEG_OPCODE_BONE_POSE_PARENT);
-
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
-                                  DEG_OPCODE_BONE_READY);
-
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
-                                  DEG_OPCODE_BONE_DONE);
-
-               /* constraints */
-               if (pchan->constraints.first != NULL) {
-                       build_pose_constraints(ob, pchan);
-               }
-
-               /**
-                * IK Solvers...
-                *
-                * - These require separate processing steps are pose-level
-                *   to be executed between chains of bones (i.e. once the
-                *   base transforms of a bunch of bones is done)
-                *
-                * Unsolved Issues:
-                * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
-                * - Animated chain-lengths are a problem...
-                */
-               for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
-                       switch (con->type) {
-                               case CONSTRAINT_TYPE_KINEMATIC:
-                                       build_ik_pose(scene, ob, pchan, con);
-                                       break;
-
-                               case CONSTRAINT_TYPE_SPLINEIK:
-                                       build_splineik_pose(scene, ob, pchan, con);
-                                       break;
-
-                               default:
-                                       break;
-                       }
-               }
-       }
-}
-
-void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
-{
-       ID *obdata = (ID *)ob->data;
-       build_animdata(obdata);
-
-       BLI_assert(ob->pose != NULL);
-
-       /* speed optimization for animation lookups */
-       BKE_pose_channels_hash_make(ob->pose);
-       if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
-               BKE_pose_update_constraint_flags(ob->pose);
-       }
-
-       add_operation_node(&ob->id,
-                          DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_INIT,
-                          function_bind(BKE_pose_eval_proxy_copy, _1, ob),
-                          DEG_OPCODE_POSE_INIT);
-
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
-            pchan != NULL;
-            pchan = pchan->next)
-       {
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_INIT, NULL,
-                                  DEG_OPCODE_BONE_LOCAL);
-
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_EXEC, NULL,
-                                  DEG_OPCODE_BONE_READY);
-
-               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
-                                  DEPSOP_TYPE_POST, NULL,
-                                  DEG_OPCODE_BONE_DONE);
-       }
-
-       add_operation_node(&ob->id,
-                          DEPSNODE_TYPE_EVAL_POSE,
-                          DEPSOP_TYPE_POST,
-                          NULL,
-                          DEG_OPCODE_POSE_DONE);
-}
-
 /* Shapekeys */
 void DepsgraphNodeBuilder::build_shapekeys(Key *key)
 {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
new file mode 100644 (file)
index 0000000..b9c7c3c
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc
+ *  \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph's nodes
+ */
+
+#include "intern/builder/deg_builder_nodes.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+} /* extern "C" */
+
+#include "intern/builder/deg_builder.h"
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+#include "intern/depsgraph_types.h"
+#include "intern/depsgraph_intern.h"
+
+namespace DEG {
+
+void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
+{
+       /* create node for constraint stack */
+       add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                          DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
+                          DEG_OPCODE_BONE_CONSTRAINTS);
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+       bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+       /* Find the chain's root. */
+       bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+
+       if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+                              DEG_OPCODE_POSE_IK_SOLVER))
+       {
+               return;
+       }
+
+       /* Operation node for evaluating/running IK Solver. */
+       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+                          DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
+                          DEG_OPCODE_POSE_IK_SOLVER);
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+       bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+
+       /* Find the chain's root. */
+       bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+
+       /* Operation node for evaluating/running Spline IK Solver.
+        * Store the "root bone" of this chain in the solver, so it knows where to start.
+        */
+       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+                          DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
+                          DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
+{
+       bArmature *arm = (bArmature *)ob->data;
+
+       /* animation and/or drivers linking posebones to base-armature used to define them
+        * NOTE: AnimData here is really used to control animated deform properties,
+        *       which ideally should be able to be unique across different instances.
+        *       Eventually, we need some type of proxy/isolation mechanism in-between here
+        *       to ensure that we can use same rig multiple times in same scene...
+        */
+       build_animdata(&arm->id);
+
+       /* Rebuild pose if not up to date. */
+       if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+               BKE_pose_rebuild_ex(ob, arm, false);
+               /* XXX: Without this animation gets lost in certain circumstances
+                * after loading file. Need to investigate further since it does
+                * not happen with simple scenes..
+                */
+               if (ob->adt) {
+                       ob->adt->recalc |= ADT_RECALC_ANIM;
+               }
+       }
+
+       /* speed optimization for animation lookups */
+       if (ob->pose) {
+               BKE_pose_channels_hash_make(ob->pose);
+               if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+                       BKE_pose_update_constraint_flags(ob->pose);
+               }
+       }
+
+       /* Make sure pose is up-to-date with armature updates. */
+       add_operation_node(&arm->id,
+                          DEPSNODE_TYPE_PARAMETERS,
+                          DEPSOP_TYPE_EXEC,
+                          NULL,
+                          DEG_OPCODE_PLACEHOLDER,
+                          "Armature Eval");
+
+       /**
+        * Pose Rig Graph
+        * ==============
+        *
+        * Pose Component:
+        * - Mainly used for referencing Bone components.
+        * - This is where the evaluation operations for init/exec/cleanup
+        *   (ik) solvers live, and are later hooked up (so that they can be
+        *   interleaved during runtime) with bone-operations they depend on/affect.
+        * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
+        *   steps of pose eval process. ALL bone operations must be performed
+        *   between these two...
+        *
+        * Bone Component:
+        * - Used for representing each bone within the rig
+        * - Acts to encapsulate the evaluation operations (base matrix + parenting,
+        *   and constraint stack) so that they can be easily found.
+        * - Everything else which depends on bone-results hook up to the component only
+        *   so that we can redirect those to point at either the the post-IK/
+        *   post-constraint/post-matrix steps, as needed.
+        */
+
+       /* pose eval context */
+       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
+                          DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
+
+       add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
+                          DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
+
+       /* bones */
+       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+               /* node for bone eval */
+               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                                  DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
+                                  DEG_OPCODE_BONE_LOCAL);
+
+               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                                  DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
+                                  DEG_OPCODE_BONE_POSE_PARENT);
+
+               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                                  DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
+                                  DEG_OPCODE_BONE_READY);
+
+               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                                  DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
+                                  DEG_OPCODE_BONE_DONE);
+
+               /* constraints */
+               if (pchan->constraints.first != NULL) {
+                       build_pose_constraints(ob, pchan);
+               }
+
+               /**
+                * IK Solvers...
+                *
+                * - These require separate processing steps are pose-level
+                *   to be executed between chains of bones (i.e. once the
+                *   base transforms of a bunch of bones is done)
+                *
+                * Unsolved Issues:
+                * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+                * - Animated chain-lengths are a problem...
+                */
+               for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+                       switch (con->type) {
+                               case CONSTRAINT_TYPE_KINEMATIC:
+                                       build_ik_pose(scene, ob, pchan, con);
+                                       break;
+
+                               case CONSTRAINT_TYPE_SPLINEIK:
+                                       build_splineik_pose(scene, ob, pchan, con);
+                                       break;
+
+                               default:
+                                       break;
+                       }
+               }
+       }
+}
+
+void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
+{
+       ID *obdata = (ID *)ob->data;
+       build_animdata(obdata);
+
+       BLI_assert(ob->pose != NULL);
+
+       /* speed optimization for animation lookups */
+       BKE_pose_channels_hash_make(ob->pose);
+       if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
+               BKE_pose_update_constraint_flags(ob->pose);
+       }
+
+       add_operation_node(&ob->id,
+                          DEPSNODE_TYPE_EVAL_POSE,
+                          DEPSOP_TYPE_INIT,
+                          function_bind(BKE_pose_eval_proxy_copy, _1, ob),
+                          DEG_OPCODE_POSE_INIT);
+
+       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+            pchan != NULL;
+            pchan = pchan->next)
+       {
+               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                                  DEPSOP_TYPE_INIT, NULL,
+                                  DEG_OPCODE_BONE_LOCAL);
+
+               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                                  DEPSOP_TYPE_EXEC, NULL,
+                                  DEG_OPCODE_BONE_READY);
+
+               add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+                                  DEPSOP_TYPE_POST, NULL,
+                                  DEG_OPCODE_BONE_DONE);
+       }
+
+       add_operation_node(&ob->id,
+                          DEPSNODE_TYPE_EVAL_POSE,
+                          DEPSOP_TYPE_POST,
+                          NULL,
+                          DEG_OPCODE_POSE_DONE);
+}
+
+}  // namespace DEG
index fe75de5e3500c1b23cc7057dc86c4cb744150e5c..1497a16e47f7084d4a7ee6a967840b4795f4437a 100644 (file)
@@ -1345,391 +1345,6 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
        // TODO...
 }
 
-/* IK Solver Eval Steps */
-void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
-                                             bPoseChannel *pchan,
-                                             bConstraint *con,
-                                             RootPChanMap *root_map)
-{
-       bKinematicConstraint *data = (bKinematicConstraint *)con->data;
-
-       /* attach owner to IK Solver too
-        * - assume that owner is always part of chain
-        * - see notes on direction of rel below...
-        */
-       bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
-       OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
-
-       /* IK target */
-       // XXX: this should get handled as part of the constraint code
-       if (data->tar != NULL) {
-               /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
-                * we create dependency between target object and pose eval component.
-                *
-                * This way we ensuring the whole subtree is updated from scratch without
-                * need of intermediate matricies. This is an overkill, but good enough for
-                * testing IK solver.
-                */
-               // FIXME: geometry targets...
-               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
-               if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
-                       /* TODO(sergey): This is only for until granular update stores intermediate result. */
-                       if (data->tar != ob) {
-                               /* different armature - can just read the results */
-                               ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
-                               add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
-                       }
-                       else {
-                               /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
-                               OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
-                               add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
-                       }
-               }
-               else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
-                       /* vertex group target */
-                       /* NOTE: for now, we don't need to represent vertex groups separately... */
-                       ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
-
-                       if (data->tar->type == OB_MESH) {
-                               OperationDepsNode *node2 = find_operation_node(target_key);
-                               if (node2 != NULL) {
-                                       node2->customdata_mask |= CD_MASK_MDEFORMVERT;
-                               }
-                       }
-               }
-               else {
-                       /* Standard Object Target */
-                       ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
-                       add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
-               }
-
-               if ((data->tar == ob) && (data->subtarget[0])) {
-                       /* Prevent target's constraints from linking to anything from same
-                        * chain that it controls.
-                        */
-                       root_map->add_bone(data->subtarget, rootchan->name);
-               }
-       }
-
-       /* Pole Target */
-       // XXX: this should get handled as part of the constraint code
-       if (data->poletar != NULL) {
-               if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
-                       // XXX: same armature issues - ready vs done?
-                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
-               }
-               else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
-                       /* vertex group target */
-                       /* NOTE: for now, we don't need to represent vertex groups separately... */
-                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
-
-                       if (data->poletar->type == OB_MESH) {
-                               OperationDepsNode *node2 = find_operation_node(target_key);
-                               if (node2 != NULL) {
-                                       node2->customdata_mask |= CD_MASK_MDEFORMVERT;
-                               }
-                       }
-               }
-               else {
-                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
-                       add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
-               }
-       }
-
-       DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
-                        pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
-
-       bPoseChannel *parchan = pchan;
-       /* exclude tip from chain? */
-       if (!(data->flag & CONSTRAINT_IK_TIP)) {
-               OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
-                                               parchan->name, DEG_OPCODE_BONE_LOCAL);
-               add_relation(solver_key, tip_transforms_key,
-                            DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
-               parchan = pchan->parent;
-       }
-
-       root_map->add_bone(parchan->name, rootchan->name);
-
-       OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
-                                           parchan->name, DEG_OPCODE_BONE_READY);
-       add_relation(parchan_transforms_key, solver_key,
-                    DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
-
-       /* Walk to the chain's root */
-       //size_t segcount = 0;
-       int segcount = 0;
-
-       while (parchan) {
-               /* Make IK-solver dependent on this bone's result,
-                * since it can only run after the standard results
-                * of the bone are know. Validate links step on the
-                * bone will ensure that users of this bone only
-                * grab the result with IK solver results...
-                */
-               if (parchan != pchan) {
-                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
-                       add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
-
-                       OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-                       add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
-               }
-               else {
-                       OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-                       add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
-               }
-               parchan->flag |= POSE_DONE;
-
-
-               root_map->add_bone(parchan->name, rootchan->name);
-
-               /* continue up chain, until we reach target number of items... */
-               DEG_DEBUG_PRINTF("  %d = %s\n", segcount, parchan->name);
-               segcount++;
-               if ((segcount == data->rootbone) || (segcount > 255)) break;  /* 255 is weak */
-
-               parchan  = parchan->parent;
-       }
-
-       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-       add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
-}
-
-/* Spline IK Eval Steps */
-void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
-                                                   bPoseChannel *pchan,
-                                                   bConstraint *con,
-                                                   RootPChanMap *root_map)
-{
-       bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
-       bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
-       OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
-       OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
-
-       /* attach owner to IK Solver too
-        * - assume that owner is always part of chain
-        * - see notes on direction of rel below...
-        */
-       add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
-
-       /* attach path dependency to solver */
-       if (data->tar) {
-               /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
-                * we create dependency between target object and pose eval component.
-                * See IK pose for a bit more information.
-                */
-               // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
-               ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
-               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
-               add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
-       }
-
-       pchan->flag |= POSE_DONE;
-       OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-       add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
-
-       root_map->add_bone(pchan->name, rootchan->name);
-
-       /* Walk to the chain's root */
-       //size_t segcount = 0;
-       int segcount = 0;
-
-       for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
-               /* Make Spline IK solver dependent on this bone's result,
-                * since it can only run after the standard results
-                * of the bone are know. Validate links step on the
-                * bone will ensure that users of this bone only
-                * grab the result with IK solver results...
-                */
-               if (parchan != pchan) {
-                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
-                       add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
-
-                       OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-                       add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
-               }
-               parchan->flag |= POSE_DONE;
-
-               OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
-               add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
-
-               root_map->add_bone(parchan->name, rootchan->name);
-
-               /* continue up chain, until we reach target number of items... */
-               segcount++;
-               if ((segcount == data->chainlen) || (segcount > 255)) break;  /* 255 is weak */
-       }
-
-       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-       add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
-}
-
-/* Pose/Armature Bones Graph */
-void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
-{
-       /* Armature-Data */
-       bArmature *arm = (bArmature *)ob->data;
-
-       // TODO: selection status?
-
-       /* attach links between pose operations */
-       OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
-       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-
-       add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
-
-       /* Make sure pose is up-to-date with armature updates. */
-       OperationKey armature_key(&arm->id,
-                                 DEPSNODE_TYPE_PARAMETERS,
-                                 DEG_OPCODE_PLACEHOLDER,
-                                 "Armature Eval");
-       add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
-
-       if (needs_animdata_node(&ob->id)) {
-               ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
-               add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
-       }
-
-       /* IK Solvers...
-        * - These require separate processing steps are pose-level
-        *   to be executed between chains of bones (i.e. once the
-        *   base transforms of a bunch of bones is done)
-        *
-        * - We build relations for these before the dependencies
-        *   between ops in the same component as it is necessary
-        *   to check whether such bones are in the same IK chain
-        *   (or else we get weird issues with either in-chain
-        *   references, or with bones being parented to IK'd bones)
-        *
-        * Unsolved Issues:
-        * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
-        * - Animated chain-lengths are a problem...
-        */
-       RootPChanMap root_map;
-       bool pose_depends_on_local_transform = false;
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
-                       switch (con->type) {
-                               case CONSTRAINT_TYPE_KINEMATIC:
-                                       build_ik_pose(ob, pchan, con, &root_map);
-                                       pose_depends_on_local_transform = true;
-                                       break;
-
-                               case CONSTRAINT_TYPE_SPLINEIK:
-                                       build_splineik_pose(ob, pchan, con, &root_map);
-                                       pose_depends_on_local_transform = true;
-                                       break;
-
-                               /* Constraints which needs world's matrix for transform.
-                                * TODO(sergey): More constraints here?
-                                */
-                               case CONSTRAINT_TYPE_ROTLIKE:
-                               case CONSTRAINT_TYPE_SIZELIKE:
-                               case CONSTRAINT_TYPE_LOCLIKE:
-                               case CONSTRAINT_TYPE_TRANSLIKE:
-                                       /* TODO(sergey): Add used space check. */
-                                       pose_depends_on_local_transform = true;
-                                       break;
-
-                               default:
-                                       break;
-                       }
-               }
-       }
-       //root_map.print_debug();
-
-       if (pose_depends_on_local_transform) {
-               /* TODO(sergey): Once partial updates are possible use relation between
-                * object transform and solver itself in it's build function.
-                */
-               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
-               ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
-               add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
-       }
-
-
-       /* links between operations for each bone */
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
-               OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
-               OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
-               OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
-               OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-
-               pchan->flag &= ~POSE_DONE;
-
-               /* pose init to bone local */
-               add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
-
-               /* local to pose parenting operation */
-               add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
-
-               /* parent relation */
-               if (pchan->parent != NULL) {
-                       eDepsOperation_Code parent_key_opcode;
-
-                       /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
-                       if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
-                               parent_key_opcode = DEG_OPCODE_BONE_READY;
-                       }
-                       else {
-                               parent_key_opcode = DEG_OPCODE_BONE_DONE;
-                       }
-
-                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
-                       add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
-               }
-
-               /* constraints */
-               if (pchan->constraints.first != NULL) {
-                       /* constraints stack and constraint dependencies */
-                       build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
-
-                       /* pose -> constraints */
-                       OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
-                       add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
-
-                       /* constraints -> ready */
-                       // TODO: when constraint stack is exploded, this step should occur before the first IK solver
-                       add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
-               }
-               else {
-                       /* pose -> ready */
-                       add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
-               }
-
-               /* bone ready -> done
-                * NOTE: For bones without IK, this is all that's needed.
-                *       For IK chains however, an additional rel is created from IK to done,
-                *       with transitive reduction removing this one...
-                */
-               add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
-
-               /* assume that all bones must be done for the pose to be ready (for deformers) */
-               add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
-       }
-}
-
-void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
-{
-       OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
-       OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
-       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
-            pchan != NULL;
-            pchan = pchan->next)
-       {
-               OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
-               OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
-               OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
-               add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
-               add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
-               add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
-               add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
-       }
-}
-
 /* Shapekeys */
 void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
 {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
new file mode 100644 (file)
index 0000000..3edb2b7
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc
+ *  \ingroup depsgraph
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include "intern/builder/deg_builder_relations.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cstring>  /* required for STREQ later on. */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_customdata_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+} /* extern "C" */
+
+#include "intern/builder/deg_builder.h"
+#include "intern/builder/deg_builder_pchanmap.h"
+
+#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
+#include "intern/nodes/deg_node_operation.h"
+
+#include "intern/depsgraph_intern.h"
+#include "intern/depsgraph_types.h"
+
+#include "util/deg_util_foreach.h"
+
+namespace DEG {
+
+/* IK Solver Eval Steps */
+void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
+                                             bPoseChannel *pchan,
+                                             bConstraint *con,
+                                             RootPChanMap *root_map)
+{
+       bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+       /* attach owner to IK Solver too
+        * - assume that owner is always part of chain
+        * - see notes on direction of rel below...
+        */
+       bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+       OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
+
+       /* IK target */
+       // XXX: this should get handled as part of the constraint code
+       if (data->tar != NULL) {
+               /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+                * we create dependency between target object and pose eval component.
+                *
+                * This way we ensuring the whole subtree is updated from scratch without
+                * need of intermediate matricies. This is an overkill, but good enough for
+                * testing IK solver.
+                */
+               // FIXME: geometry targets...
+               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+               if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
+                       /* TODO(sergey): This is only for until granular update stores intermediate result. */
+                       if (data->tar != ob) {
+                               /* different armature - can just read the results */
+                               ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+                               add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+                       }
+                       else {
+                               /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
+                               OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
+                               add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+                       }
+               }
+               else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
+                       /* vertex group target */
+                       /* NOTE: for now, we don't need to represent vertex groups separately... */
+                       ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
+                       add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+
+                       if (data->tar->type == OB_MESH) {
+                               OperationDepsNode *node2 = find_operation_node(target_key);
+                               if (node2 != NULL) {
+                                       node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+                               }
+                       }
+               }
+               else {
+                       /* Standard Object Target */
+                       ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
+                       add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+               }
+
+               if ((data->tar == ob) && (data->subtarget[0])) {
+                       /* Prevent target's constraints from linking to anything from same
+                        * chain that it controls.
+                        */
+                       root_map->add_bone(data->subtarget, rootchan->name);
+               }
+       }
+
+       /* Pole Target */
+       // XXX: this should get handled as part of the constraint code
+       if (data->poletar != NULL) {
+               if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) {
+                       // XXX: same armature issues - ready vs done?
+                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget);
+                       add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+               }
+               else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) {
+                       /* vertex group target */
+                       /* NOTE: for now, we don't need to represent vertex groups separately... */
+                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
+                       add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+
+                       if (data->poletar->type == OB_MESH) {
+                               OperationDepsNode *node2 = find_operation_node(target_key);
+                               if (node2 != NULL) {
+                                       node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+                               }
+                       }
+               }
+               else {
+                       ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
+                       add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+               }
+       }
+
+       DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
+                        pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
+
+       bPoseChannel *parchan = pchan;
+       /* exclude tip from chain? */
+       if (!(data->flag & CONSTRAINT_IK_TIP)) {
+               OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+                                               parchan->name, DEG_OPCODE_BONE_LOCAL);
+               add_relation(solver_key, tip_transforms_key,
+                            DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+               parchan = pchan->parent;
+       }
+
+       root_map->add_bone(parchan->name, rootchan->name);
+
+       OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+                                           parchan->name, DEG_OPCODE_BONE_READY);
+       add_relation(parchan_transforms_key, solver_key,
+                    DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
+
+       /* Walk to the chain's root */
+       //size_t segcount = 0;
+       int segcount = 0;
+
+       while (parchan) {
+               /* Make IK-solver dependent on this bone's result,
+                * since it can only run after the standard results
+                * of the bone are know. Validate links step on the
+                * bone will ensure that users of this bone only
+                * grab the result with IK solver results...
+                */
+               if (parchan != pchan) {
+                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+                       add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
+
+                       OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+                       add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
+               }
+               else {
+                       OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+                       add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+               }
+               parchan->flag |= POSE_DONE;
+
+
+               root_map->add_bone(parchan->name, rootchan->name);
+
+               /* continue up chain, until we reach target number of items... */
+               DEG_DEBUG_PRINTF("  %d = %s\n", segcount, parchan->name);
+               segcount++;
+               if ((segcount == data->rootbone) || (segcount > 255)) break;  /* 255 is weak */
+
+               parchan  = parchan->parent;
+       }
+
+       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+       add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
+                                                   bPoseChannel *pchan,
+                                                   bConstraint *con,
+                                                   RootPChanMap *root_map)
+{
+       bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+       bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+       OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+       OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+
+       /* attach owner to IK Solver too
+        * - assume that owner is always part of chain
+        * - see notes on direction of rel below...
+        */
+       add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
+
+       /* attach path dependency to solver */
+       if (data->tar) {
+               /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+                * we create dependency between target object and pose eval component.
+                * See IK pose for a bit more information.
+                */
+               // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
+               ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
+               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+               add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel");
+       }
+
+       pchan->flag |= POSE_DONE;
+       OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+       add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
+
+       root_map->add_bone(pchan->name, rootchan->name);
+
+       /* Walk to the chain's root */
+       //size_t segcount = 0;
+       int segcount = 0;
+
+       for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
+               /* Make Spline IK solver dependent on this bone's result,
+                * since it can only run after the standard results
+                * of the bone are know. Validate links step on the
+                * bone will ensure that users of this bone only
+                * grab the result with IK solver results...
+                */
+               if (parchan != pchan) {
+                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+                       add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
+
+                       OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+                       add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
+               }
+               parchan->flag |= POSE_DONE;
+
+               OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+               add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
+
+               root_map->add_bone(parchan->name, rootchan->name);
+
+               /* continue up chain, until we reach target number of items... */
+               segcount++;
+               if ((segcount == data->chainlen) || (segcount > 255)) break;  /* 255 is weak */
+       }
+
+       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+       add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
+{
+       /* Armature-Data */
+       bArmature *arm = (bArmature *)ob->data;
+
+       // TODO: selection status?
+
+       /* attach links between pose operations */
+       OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+       OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+
+       add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
+
+       /* Make sure pose is up-to-date with armature updates. */
+       OperationKey armature_key(&arm->id,
+                                 DEPSNODE_TYPE_PARAMETERS,
+                                 DEG_OPCODE_PLACEHOLDER,
+                                 "Armature Eval");
+       add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency");
+
+       if (needs_animdata_node(&ob->id)) {
+               ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
+               add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
+       }
+
+       /* IK Solvers...
+        * - These require separate processing steps are pose-level
+        *   to be executed between chains of bones (i.e. once the
+        *   base transforms of a bunch of bones is done)
+        *
+        * - We build relations for these before the dependencies
+        *   between ops in the same component as it is necessary
+        *   to check whether such bones are in the same IK chain
+        *   (or else we get weird issues with either in-chain
+        *   references, or with bones being parented to IK'd bones)
+        *
+        * Unsolved Issues:
+        * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+        * - Animated chain-lengths are a problem...
+        */
+       RootPChanMap root_map;
+       bool pose_depends_on_local_transform = false;
+       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+               for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+                       switch (con->type) {
+                               case CONSTRAINT_TYPE_KINEMATIC:
+                                       build_ik_pose(ob, pchan, con, &root_map);
+                                       pose_depends_on_local_transform = true;
+                                       break;
+
+                               case CONSTRAINT_TYPE_SPLINEIK:
+                                       build_splineik_pose(ob, pchan, con, &root_map);
+                                       pose_depends_on_local_transform = true;
+                                       break;
+
+                               /* Constraints which needs world's matrix for transform.
+                                * TODO(sergey): More constraints here?
+                                */
+                               case CONSTRAINT_TYPE_ROTLIKE:
+                               case CONSTRAINT_TYPE_SIZELIKE:
+                               case CONSTRAINT_TYPE_LOCLIKE:
+                               case CONSTRAINT_TYPE_TRANSLIKE:
+                                       /* TODO(sergey): Add used space check. */
+                                       pose_depends_on_local_transform = true;
+                                       break;
+
+                               default:
+                                       break;
+                       }
+               }
+       }
+       //root_map.print_debug();
+
+       if (pose_depends_on_local_transform) {
+               /* TODO(sergey): Once partial updates are possible use relation between
+                * object transform and solver itself in it's build function.
+                */
+               ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+               ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+               add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
+       }
+
+
+       /* links between operations for each bone */
+       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+               OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+               OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
+               OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+               OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+
+               pchan->flag &= ~POSE_DONE;
+
+               /* pose init to bone local */
+               add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
+
+               /* local to pose parenting operation */
+               add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
+
+               /* parent relation */
+               if (pchan->parent != NULL) {
+                       eDepsOperation_Code parent_key_opcode;
+
+                       /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
+                       if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
+                               parent_key_opcode = DEG_OPCODE_BONE_READY;
+                       }
+                       else {
+                               parent_key_opcode = DEG_OPCODE_BONE_DONE;
+                       }
+
+                       OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
+                       add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
+               }
+
+               /* constraints */
+               if (pchan->constraints.first != NULL) {
+                       /* constraints stack and constraint dependencies */
+                       build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
+
+                       /* pose -> constraints */
+                       OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
+                       add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
+
+                       /* constraints -> ready */
+                       // TODO: when constraint stack is exploded, this step should occur before the first IK solver
+                       add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
+               }
+               else {
+                       /* pose -> ready */
+                       add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
+               }
+
+               /* bone ready -> done
+                * NOTE: For bones without IK, this is all that's needed.
+                *       For IK chains however, an additional rel is created from IK to done,
+                *       with transitive reduction removing this one...
+                */
+               add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
+
+               /* assume that all bones must be done for the pose to be ready (for deformers) */
+               add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+       }
+}
+
+void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
+{
+       OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+       OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+       for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+            pchan != NULL;
+            pchan = pchan->next)
+       {
+               OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+               OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+               OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+               add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
+               add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
+               add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
+               add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
+       }
+}
+
+}  // namespace DEG