Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/depsgraph/CMakeLists.txt1
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc9
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc424
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.h124
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h155
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc5
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc155
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h14
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_access.c5
10 files changed, 494 insertions, 399 deletions
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
index 89ba6e27aed..9495321a0ff 100644
--- a/source/blender/depsgraph/CMakeLists.txt
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -80,6 +80,7 @@ set(SRC
intern/builder/deg_builder_nodes.h
intern/builder/deg_builder_pchanmap.h
intern/builder/deg_builder_relations.h
+ intern/builder/deg_builder_relations_impl.h
intern/builder/deg_builder_transitive.h
intern/eval/deg_eval.h
intern/eval/deg_eval_copy_on_write.h
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
index dfe97d02ec6..f6f2dcce467 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc
@@ -359,6 +359,15 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object)
NULL,
DEG_OPCODE_BONE_DONE);
op_node->set_as_exit();
+
+ /* Custom properties. */
+ if (pchan->prop != NULL) {
+ add_operation_node(&object->id,
+ DEG_NODE_TYPE_PARAMETERS,
+ NULL,
+ DEG_OPCODE_PARAMETERS_EVAL,
+ pchan->name);
+ }
}
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index aeb9f9ab937..5c984535cb8 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -120,10 +120,10 @@ struct BuilderWalkUserData {
DepsgraphRelationBuilder *builder;
};
-static void modifier_walk(void *user_data,
- struct Object * /*object*/,
- struct Object **obpoin,
- int /*cb_flag*/)
+void modifier_walk(void *user_data,
+ struct Object * /*object*/,
+ struct Object **obpoin,
+ int /*cb_flag*/)
{
BuilderWalkUserData *data = (BuilderWalkUserData *)user_data;
if (*obpoin) {
@@ -275,10 +275,11 @@ bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const
void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
DepsNode *node_to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
if (timesrc && node_to) {
- graph_->add_new_relation(timesrc, node_to, description);
+ graph_->add_new_relation(timesrc, node_to, description, check_unique);
}
else {
DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
@@ -291,10 +292,11 @@ void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
void DepsgraphRelationBuilder::add_operation_relation(
OperationDepsNode *node_from,
OperationDepsNode *node_to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
if (node_from && node_to) {
- graph_->add_new_relation(node_from, node_to, description);
+ graph_->add_new_relation(node_from, node_to, description, check_unique);
}
else {
DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %s) Failed\n",
@@ -304,13 +306,22 @@ void DepsgraphRelationBuilder::add_operation_relation(
}
}
-void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key, Scene *scene, Object *object, Group *group, bool dupli, const char *name)
+void DepsgraphRelationBuilder::add_collision_relations(
+ const OperationKey &key,
+ Scene *scene,
+ Object *object,
+ Group *group,
+ bool dupli,
+ const char *name)
{
unsigned int numcollobj;
- Object **collobjs = get_collisionobjects_ext(scene, object, group, &numcollobj, eModifierType_Collision, dupli);
-
- for (unsigned int i = 0; i < numcollobj; i++)
- {
+ Object **collobjs = get_collisionobjects_ext(scene,
+ object,
+ group,
+ &numcollobj,
+ eModifierType_Collision,
+ dupli);
+ for (unsigned int i = 0; i < numcollobj; i++) {
Object *ob1 = collobjs[i];
ComponentKey trf_key(&ob1->id, DEG_NODE_TYPE_TRANSFORM);
@@ -319,47 +330,62 @@ void DepsgraphRelationBuilder::add_collision_relations(const OperationKey &key,
ComponentKey coll_key(&ob1->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(coll_key, key, name);
}
-
- if (collobjs)
+ if (collobjs != NULL) {
MEM_freeN(collobjs);
+ }
}
-void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, Scene *scene, Object *object, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name)
+void DepsgraphRelationBuilder::add_forcefield_relations(
+ const OperationKey &key,
+ Scene *scene,
+ Object *object,
+ ParticleSystem *psys,
+ EffectorWeights *eff,
+ bool add_absorption,
+ const char *name)
{
ListBase *effectors = pdInitEffectors(NULL, scene, object, psys, eff, false);
-
- if (effectors) {
- for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
+ if (effectors != NULL) {
+ LINKLIST_FOREACH(EffectorCache *, eff, effectors) {
if (eff->ob != object) {
ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_TRANSFORM);
add_relation(eff_key, key, name);
}
-
- if (eff->psys) {
+ if (eff->psys != NULL) {
if (eff->ob != object) {
ComponentKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
add_relation(eff_key, key, name);
- /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */
+ /* TODO: remove this when/if EVAL_PARTICLES is sufficient
+ * for up to date particles.
+ */
ComponentKey mod_key(&eff->ob->id, DEG_NODE_TYPE_GEOMETRY);
add_relation(mod_key, key, name);
}
else if (eff->psys != psys) {
- OperationKey eff_key(&eff->ob->id, DEG_NODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PARTICLE_SYSTEM_EVAL, eff->psys->name);
+ OperationKey eff_key(&eff->ob->id,
+ DEG_NODE_TYPE_EVAL_PARTICLES,
+ DEG_OPCODE_PARTICLE_SYSTEM_EVAL,
+ eff->psys->name);
add_relation(eff_key, key, name);
}
}
-
if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) {
- ComponentKey trf_key(&eff->pd->f_source->id, DEG_NODE_TYPE_TRANSFORM);
+ ComponentKey trf_key(&eff->pd->f_source->id,
+ DEG_NODE_TYPE_TRANSFORM);
add_relation(trf_key, key, "Smoke Force Domain");
- ComponentKey eff_key(&eff->pd->f_source->id, DEG_NODE_TYPE_GEOMETRY);
+ ComponentKey eff_key(&eff->pd->f_source->id,
+ DEG_NODE_TYPE_GEOMETRY);
add_relation(eff_key, key, "Smoke Force Domain");
}
-
if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) {
- add_collision_relations(key, scene, object, NULL, true, "Force Absorption");
+ add_collision_relations(key,
+ scene,
+ object,
+ NULL,
+ true,
+ "Force Absorption");
}
}
}
@@ -496,11 +522,6 @@ void DepsgraphRelationBuilder::build_object(Base *base, Object *object)
}
/* Animation data */
build_animdata(&object->id);
- // XXX: This should be hooked up by the build_animdata code
- if (needs_animdata_node(&object->id)) {
- ComponentKey adt_key(&object->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(adt_key, local_transform_key, "Object Animation");
- }
/* Object data. */
build_object_data(object);
/* Particle systems. */
@@ -900,25 +921,85 @@ void DepsgraphRelationBuilder::build_constraints(ID *id,
void DepsgraphRelationBuilder::build_animdata(ID *id)
{
- AnimData *adt = BKE_animdata_from_id(id);
+ /* Animation curves and NLA. */
+ build_animdata_curves(id);
+ /* Drivers. */
+ build_animdata_drievrs(id);
+}
- if (adt == NULL)
+void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
return;
-
+ }
+ if (adt->action == NULL && adt->nla_tracks.first == NULL) {
+ return;
+ }
+ /* Wire up dependency to time source. */
ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, adt_key, "TimeSrc -> Animation");
+ /* Build relations from animation operation to properties it changes. */
+ build_animdata_curves_targets(id);
+}
- /* animation */
- if (adt->action || adt->nla_tracks.first) {
- /* wire up dependency to time source */
- TimeSourceKey time_src_key;
- add_relation(time_src_key, adt_key, "TimeSrc -> Animation");
-
- // XXX: Hook up specific update callbacks for special properties which may need it...
-
- // XXX: animdata "hierarchy" - top-level overrides need to go after lower-down
+void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL || adt->action == NULL) {
+ return;
+ }
+ /* Get source operation. */
+ ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
+ DepsNode *node_from = get_node(adt_key);
+ BLI_assert(node_from != NULL);
+ if (node_from == NULL) {
+ return;
+ }
+ OperationDepsNode *operation_from = node_from->get_exit_operation();
+ BLI_assert(operation_from != NULL);
+ /* Iterate over all curves and build relations. */
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ LINKLIST_FOREACH(FCurve *, fcu, &adt->action->curves) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+ if (!RNA_path_resolve_full(&id_ptr, fcu->rna_path,
+ &ptr, &prop, &index))
+ {
+ continue;
+ }
+ DepsNode *node_to = graph_->find_node_from_pointer(&ptr, prop);
+ if (node_to == NULL) {
+ continue;
+ }
+ OperationDepsNode *operation_to = node_to->get_entry_operation();
+ /* NOTE: Special case for bones, avoid relation from animation to
+ * each of the bones. Bone evaluation could only start from pose
+ * init anyway.
+ */
+ if (operation_to->opcode == DEG_OPCODE_BONE_LOCAL) {
+ OperationKey pose_init_key(id,
+ DEG_NODE_TYPE_EVAL_POSE,
+ DEG_OPCODE_POSE_INIT);
+ add_relation(adt_key, pose_init_key, "Animation -> Prop", true);
+ continue;
+ }
+ graph_->add_new_relation(operation_from, operation_to,
+ "Animation -> Prop",
+ true);
}
+}
- /* drivers */
+void DepsgraphRelationBuilder::build_animdata_drievrs(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt == NULL) {
+ return;
+ }
+ ComponentKey adt_key(id, DEG_NODE_TYPE_ANIMATION);
LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) {
OperationKey driver_key(id,
DEG_NODE_TYPE_PARAMETERS,
@@ -990,45 +1071,34 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
DEG_OPCODE_DRIVER,
fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
- bPoseChannel *pchan = NULL;
- const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
- const ID_Type id_type = GS(id->name);
-
- /* Create dependency between driver and data affected by it. */
- /* - direct property relationship... */
- //RNAPathKey affected_key(id, fcu->rna_path);
- //add_relation(driver_key, affected_key, "Driver -> Data");
-
/* Driver -> data components (for interleaved evaluation
* bones/constraints/modifiers).
*/
- // XXX: this probably should probably be moved out into a separate function.
- if (strstr(rna_path, "pose.bones[") != NULL) {
- /* interleaved drivers during bone eval */
- /* TODO: ideally, if this is for a constraint, it goes to said
- * constraint.
- */
- Object *object = (Object *)id;
- char *bone_name = BLI_str_quoted_substrN(rna_path, "pose.bones[");
- pchan = BKE_pose_channel_find_name(object->pose, bone_name);
- if (bone_name != NULL) {
- MEM_freeN(bone_name);
- bone_name = NULL;
- }
- if (pchan != NULL) {
- OperationKey bone_key(id,
- DEG_NODE_TYPE_BONE,
- pchan->name,
- DEG_OPCODE_BONE_LOCAL);
- add_relation(driver_key, bone_key, "Driver -> Bone");
- }
- else {
- fprintf(stderr,
- "Couldn't find bone name for driver path - '%s'\n",
- rna_path);
- }
+ build_driver_data(id, fcu);
+ /* Loop over variables to get the target relationships. */
+ build_driver_variables(id, fcu);
+ /* It's quite tricky to detect if the driver actually depends on time or
+ * not, so for now we'll be quite conservative here about optimization and
+ * consider all python drivers to be depending on time.
+ */
+ if ((driver->type == DRIVER_TYPE_PYTHON) &&
+ python_driver_depends_on_time(driver))
+ {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, driver_key, "TimeSrc -> Driver");
}
- else if (id_type == ID_AR && strstr(rna_path, "bones[")) {
+}
+
+void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu)
+{
+ OperationKey driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+ const RNAPathKey self_key(id, rna_path);
+ if (GS(id->name) == ID_AR && strstr(rna_path, "bones[")) {
/* Drivers on armature-level bone settings (i.e. bbone stuff),
* which will affect the evaluation of corresponding pose bones.
*/
@@ -1067,55 +1137,23 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
rna_path);
}
}
- else if (id_type == ID_OB && strstr(rna_path, "modifiers[")) {
- OperationKey modifier_key(id,
- DEG_NODE_TYPE_GEOMETRY,
- DEG_OPCODE_GEOMETRY_UBEREVAL);
- if (has_node(modifier_key)) {
- add_relation(driver_key, modifier_key, "Driver -> Modifier");
- }
- else {
- printf("Unexisting driver RNA path: %s\n", rna_path);
- }
- }
- else if (id_type == ID_KE && strstr(rna_path, "key_blocks[")) {
- /* Shape key driver - hook into the base geometry operation. */
- // XXX: double check where this points
- Key *shape_key = (Key *)id;
- ComponentKey geometry_key(shape_key->from, DEG_NODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, "Driver -> ShapeKey Geom");
- }
- else if (strstr(rna_path, "key_blocks[")) {
- ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(driver_key, geometry_key, "Driver -> ShapeKey Geom");
- }
else {
- if (GS(id->name) == ID_OB) {
- /* assume that driver affects a transform... */
- OperationKey local_transform_key(id,
- DEG_NODE_TYPE_TRANSFORM,
- DEG_OPCODE_TRANSFORM_LOCAL);
- add_relation(driver_key,
- local_transform_key,
- "Driver -> Transform");
- }
- else if (GS(id->name) == ID_KE) {
- ComponentKey geometry_key(id, DEG_NODE_TYPE_GEOMETRY);
- add_relation(driver_key,
- geometry_key,
- "Driver -> Shapekey Geometry");
- }
+ RNAPathKey target_key(id, rna_path);
+ add_relation(driver_key, target_key, "Driver -> Target");
}
- /* Ensure that affected prop's update callbacks will be triggered once
- * done.
- */
- /* TODO: Implement this once the functionality to add these links exists
- * RNA.
- */
- /* XXX: the data itself could also set this, if it were to be truly
- * initialised later?
- */
- /* Loop over variables to get the target relationships. */
+}
+
+void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+ OperationKey driver_key(id,
+ DEG_NODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ fcu->rna_path ? fcu->rna_path : "",
+ fcu->array_index);
+ const char *rna_path = fcu->rna_path ? fcu->rna_path : "";
+ const RNAPathKey self_key(id, rna_path);
+
LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) {
/* Only used targets. */
DRIVER_TARGETS_USED_LOOPER(dvar)
@@ -1124,31 +1162,25 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
continue;
}
/* Special handling for directly-named bones. */
- if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) {
+ if ((dtar->flag & DTAR_FLAG_STRUCT_REF) &&
+ (((Object *)dtar->id)->type == OB_ARMATURE) &&
+ (dtar->pchan_name[0]))
+ {
Object *object = (Object *)dtar->id;
bPoseChannel *target_pchan =
- BKE_pose_channel_find_name(object->pose, dtar->pchan_name);
- if (target_pchan != NULL) {
- /* Get node associated with bone. */
- // XXX: watch the space!
- /* Some cases can't use final bone transform, for example:
- * - Driving the bone with itself (addressed here)
- * - Relations inside an IK chain (TODO?)
- */
- if (dtar->id == id &&
- pchan != NULL &&
- STREQ(pchan->name, target_pchan->name))
- {
- continue;
- }
- OperationKey target_key(dtar->id,
- DEG_NODE_TYPE_BONE,
- target_pchan->name,
- DEG_OPCODE_BONE_DONE);
- add_relation(target_key,
- driver_key,
- "Bone Target -> Driver");
+ BKE_pose_channel_find_name(object->pose,
+ dtar->pchan_name);
+ if (target_pchan == NULL) {
+ continue;
}
+ OperationKey variable_key(dtar->id,
+ DEG_NODE_TYPE_BONE,
+ target_pchan->name,
+ DEG_OPCODE_BONE_DONE);
+ if (is_same_bone_dependency(variable_key, self_key)) {
+ continue;
+ }
+ add_relation(variable_key, driver_key, "Bone Target -> Driver");
}
else if (dtar->flag & DTAR_FLAG_STRUCT_REF) {
/* Get node associated with the object's transforms. */
@@ -1164,32 +1196,15 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
DEG_OPCODE_TRANSFORM_FINAL);
add_relation(target_key, driver_key, "Target -> Driver");
}
- else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) {
- /* Workaround for ensuring that local bone transforms don't end
- * up having to wait for pose eval to finish (to prevent cycles).
- */
- Object *object = (Object *)dtar->id;
- char *bone_name = BLI_str_quoted_substrN(dtar->rna_path,
- "pose.bones[");
- bPoseChannel *target_pchan =
- BKE_pose_channel_find_name(object->pose, bone_name);
- if (bone_name != NULL) {
- MEM_freeN(bone_name);
- bone_name = NULL;
+ else if (dtar->rna_path) {
+ RNAPathKey variable_key(dtar->id, dtar->rna_path);
+ if (RNA_pointer_is_null(&variable_key.ptr)) {
+ continue;
}
- if (target_pchan != NULL) {
- if (dtar->id == id &&
- pchan != NULL &&
- STREQ(pchan->name, target_pchan->name))
- {
- continue;
- }
- OperationKey bone_key(dtar->id,
- DEG_NODE_TYPE_BONE,
- target_pchan->name,
- DEG_OPCODE_BONE_LOCAL);
- add_relation(bone_key, driver_key, "RNA Bone -> Driver");
+ if (is_same_bone_dependency(variable_key, self_key)) {
+ continue;
}
+ add_relation(variable_key, driver_key, "RNA Bone -> Driver");
}
else {
if (dtar->id == id) {
@@ -1207,16 +1222,6 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
}
DRIVER_TARGETS_LOOPER_END
}
- /* It's quite tricky to detect if the driver actually depends on time or
- * not, so for now we'll be quite conservative here about optimization and
- * consider all python drivers to be depending on time.
- */
- if ((driver->type == DRIVER_TYPE_PYTHON) &&
- python_driver_depends_on_time(driver))
- {
- TimeSourceKey time_src_key;
- add_relation(time_src_key, driver_key, "TimeSrc -> Driver");
- }
}
void DepsgraphRelationBuilder::build_world(World *world)
@@ -1574,7 +1579,6 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
if (object->modifiers.first != NULL) {
LINKLIST_FOREACH (ModifierData *, md, &object->modifiers) {
const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
-
if (mti->updateDepsgraph) {
DepsNodeHandle handle = create_node_handle(obdata_ubereval_key);
mti->updateDepsgraph(
@@ -1584,23 +1588,10 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
object,
reinterpret_cast< ::DepsNodeHandle* >(&handle));
}
-
if (BKE_object_modifier_use_time(object, md)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, obdata_ubereval_key, "Time Source");
-
- /* Hacky fix for T45633 (Animated modifiers aren't updated)
- *
- * This check works because BKE_object_modifier_use_time() tests
- * for either the modifier needing time, or that it is animated.
- */
- /* XXX: Remove this hack when these links are added as part of build_animdata() instead */
- if (modifier_dependsOnTime(md) == false && needs_animdata_node(&object->id)) {
- ComponentKey animation_key(&object->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, obdata_ubereval_key, "Modifier Animation");
- }
}
-
if (md->type == eModifierType_Cloth) {
build_cloth(object, md);
}
@@ -1733,16 +1724,6 @@ void DepsgraphRelationBuilder::build_obdata_geom(Object *object)
if (key) {
build_shapekeys(obdata, key);
}
-
- if (needs_animdata_node(obdata)) {
- ComponentKey animation_key(obdata, DEG_NODE_TYPE_ANIMATION);
- ComponentKey parameters_key(obdata, DEG_NODE_TYPE_PARAMETERS);
- add_relation(animation_key, parameters_key, "Geom Parameters");
- /* Evaluation usually depends on animation.
- * TODO(sergey): Need to re-hook it after granular update is implemented..
- */
- add_relation(animation_key, obdata_geom_eval_key, "Animation");
- }
}
/* Cameras */
@@ -1762,11 +1743,6 @@ void DepsgraphRelationBuilder::build_camera(Object *object)
add_relation(camera_parameters_key, object_parameters_key,
"Camera -> Object");
- if (needs_animdata_node(camera_id)) {
- ComponentKey animation_key(camera_id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, camera_parameters_key, "Camera Parameters");
- }
-
/* DOF */
if (cam->dof_ob != NULL) {
ComponentKey dof_ob_key(&cam->dof_ob->id, DEG_NODE_TYPE_TRANSFORM);
@@ -1790,18 +1766,12 @@ void DepsgraphRelationBuilder::build_lamp(Object *object)
add_relation(lamp_parameters_key, object_parameters_key,
"Lamp -> Object");
- if (needs_animdata_node(lamp_id)) {
- ComponentKey animation_key(lamp_id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, lamp_parameters_key, "Lamp Parameters");
- }
-
/* lamp's nodetree */
- if (la->nodetree) {
+ if (la->nodetree != NULL) {
build_nodetree(la->nodetree);
ComponentKey nodetree_key(&la->nodetree->id, DEG_NODE_TYPE_SHADING);
add_relation(nodetree_key, lamp_parameters_key, "NTree->Lamp Parameters");
}
-
/* textures */
build_texture_stack(la->mtex);
@@ -1866,11 +1836,6 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree)
}
}
- if (needs_animdata_node(ntree_id)) {
- ComponentKey animation_key(ntree_id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, shading_key, "NTree Parameters");
- }
-
OperationKey shading_update_key(ntree_id,
DEG_NODE_TYPE_SHADING,
DEG_OPCODE_MATERIAL_UPDATE);
@@ -1951,15 +1916,6 @@ void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd)
// TODO: parent object (when that feature is implemented)
}
-bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
-{
- AnimData *adt = BKE_animdata_from_id(id);
- if (adt != NULL) {
- return (adt->action != NULL) || (adt->nla_tracks.first != NULL);
- }
- return false;
-}
-
void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) {
/* Animation. */
build_animdata(&cache_file->id);
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
index 569383fe479..9f661b8e825 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h
@@ -31,6 +31,7 @@
#pragma once
#include <cstdio>
+#include <cstring>
#include "intern/depsgraph_types.h"
@@ -43,6 +44,7 @@
#include "BLI_string.h"
#include "intern/nodes/deg_node.h"
+#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
struct Base;
@@ -175,17 +177,20 @@ struct DepsgraphRelationBuilder
template <typename KeyFrom, typename KeyTo>
void add_relation(const KeyFrom& key_from,
const KeyTo& key_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
template <typename KeyTo>
void add_relation(const TimeSourceKey& key_from,
const KeyTo& key_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
template <typename KeyType>
void add_node_handle_relation(const KeyType& key_from,
const DepsNodeHandle *handle,
- const char *description);
+ const char *description,
+ bool check_unique = false);
void build_view_layer(Scene *scene, ViewLayer *view_layer);
void build_group(Object *object, Group *group);
@@ -199,7 +204,12 @@ struct DepsgraphRelationBuilder
ListBase *constraints,
RootPChanMap *root_map);
void build_animdata(ID *id);
+ void build_animdata_curves(ID *id);
+ void build_animdata_curves_targets(ID *id);
+ void build_animdata_drievrs(ID *id);
void build_driver(ID *id, FCurve *fcurve);
+ void build_driver_data(ID *id, FCurve *fcurve);
+ void build_driver_variables(ID *id, FCurve *fcurve);
void build_world(World *world);
void build_rigidbody(Scene *scene);
void build_particles(Object *object);
@@ -276,16 +286,19 @@ protected:
void add_time_relation(TimeSourceDepsNode *timesrc,
DepsNode *node_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
void add_operation_relation(OperationDepsNode *node_from,
OperationDepsNode *node_to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
template <typename KeyType>
DepsNodeHandle create_node_handle(const KeyType& key,
const char *default_name = "");
- bool needs_animdata_node(ID *id);
+ template <typename KeyFrom, typename KeyTo>
+ bool is_same_bone_dependency(const KeyFrom& key_from, const KeyTo& key_to);
private:
/* State which never changes, same for the whole builder time. */
@@ -298,10 +311,12 @@ private:
struct DepsNodeHandle
{
- DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const char *default_name = "") :
- builder(builder),
- node(node),
- default_name(default_name)
+ DepsNodeHandle(DepsgraphRelationBuilder *builder,
+ OperationDepsNode *node,
+ const char *default_name = "")
+ : builder(builder),
+ node(node),
+ default_name(default_name)
{
BLI_assert(node != NULL);
}
@@ -311,92 +326,7 @@ struct DepsNodeHandle
const char *default_name;
};
-/* Utilities for Builders ----------------------------------------------------- */
-
-template <typename KeyType>
-OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key)
-{
- DepsNode *node = get_node(key);
- return node != NULL ? node->get_exit_operation() : NULL;
-}
-
-template <typename KeyFrom, typename KeyTo>
-void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
- const KeyTo &key_to,
- const char *description)
-{
- DepsNode *node_from = get_node(key_from);
- DepsNode *node_to = get_node(key_to);
- OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
- OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
- if (op_from && op_to) {
- add_operation_relation(op_from, op_to, description);
- }
- else {
- if (!op_from) {
- /* XXX TODO handle as error or report if needed */
- fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n",
- description, key_from.identifier().c_str());
- }
- else {
- fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n",
- description, key_from.identifier().c_str());
- }
- if (!op_to) {
- /* XXX TODO handle as error or report if needed */
- fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n",
- description, key_to.identifier().c_str());
- }
- else {
- fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n",
- description, key_to.identifier().c_str());
- }
- }
-}
-
-template <typename KeyTo>
-void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
- const KeyTo &key_to,
- const char *description)
-{
- TimeSourceDepsNode *time_from = get_node(key_from);
- DepsNode *node_to = get_node(key_to);
- OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
- if (time_from != NULL && op_to != NULL) {
- add_time_relation(time_from, op_to, description);
- }
-}
-
-template <typename KeyType>
-void DepsgraphRelationBuilder::add_node_handle_relation(
- const KeyType &key_from,
- const DepsNodeHandle *handle,
- const char *description)
-{
- DepsNode *node_from = get_node(key_from);
- OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
- OperationDepsNode *op_to = handle->node->get_entry_operation();
- if (op_from != NULL && op_to != NULL) {
- add_operation_relation(op_from, op_to, description);
- }
- else {
- if (!op_from) {
- fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n",
- description, key_from.identifier().c_str());
- }
- if (!op_to) {
- fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n",
- description, key_from.identifier().c_str());
- }
- }
-}
+} // namespace DEG
-template <typename KeyType>
-DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
- const KeyType &key,
- const char *default_name)
-{
- return DepsNodeHandle(this, get_node(key), default_name);
-}
-} // namespace DEG
+#include "intern/builder/deg_builder_relations_impl.h"
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
new file mode 100644
index 00000000000..ba55a83b767
--- /dev/null
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h
@@ -0,0 +1,155 @@
+/*
+ * ***** 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: Lukas Toenne
+ * Contributor(s): Sergey SHarybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/depsgraph/intern/builder/deg_builder_relations_impl.h
+ * \ingroup depsgraph
+ */
+
+#pragma once
+
+namespace DEG {
+
+template <typename KeyType>
+OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key)
+{
+ DepsNode *node = get_node(key);
+ return node != NULL ? node->get_exit_operation() : NULL;
+}
+
+template <typename KeyFrom, typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
+ const KeyTo &key_to,
+ const char *description,
+ bool check_unique)
+{
+ DepsNode *node_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (op_from && op_to) {
+ add_operation_relation(op_from, op_to, description, check_unique);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%s) - Failed, but op_from (%s) was ok\n",
+ description, key_from.identifier().c_str());
+ }
+ if (!op_to) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%s) - Could not find op_to (%s)\n",
+ description, key_to.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%s) - Failed, but op_to (%s) was ok\n",
+ description, key_to.identifier().c_str());
+ }
+ }
+}
+
+template <typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
+ const KeyTo &key_to,
+ const char *description,
+ bool check_unique)
+{
+ TimeSourceDepsNode *time_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (time_from != NULL && op_to != NULL) {
+ add_time_relation(time_from, op_to, description, check_unique);
+ }
+}
+
+template <typename KeyType>
+void DepsgraphRelationBuilder::add_node_handle_relation(
+ const KeyType &key_from,
+ const DepsNodeHandle *handle,
+ const char *description,
+ bool check_unique)
+{
+ DepsNode *node_from = get_node(key_from);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = handle->node->get_entry_operation();
+ if (op_from != NULL && op_to != NULL) {
+ add_operation_relation(op_from, op_to, description, check_unique);
+ }
+ else {
+ if (!op_from) {
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_from (%s)\n",
+ description, key_from.identifier().c_str());
+ }
+ if (!op_to) {
+ fprintf(stderr, "add_node_handle_relation(%s) - Could not find op_to (%s)\n",
+ description, key_from.identifier().c_str());
+ }
+ }
+}
+
+template <typename KeyType>
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(
+ const KeyType &key,
+ const char *default_name)
+{
+ return DepsNodeHandle(this, get_node(key), default_name);
+}
+
+/* Rig compatibility: we check if bone is using local transform as a variable
+ * for driver on itself and ignore those relations to avoid "false-positive"
+ * dependency cycles.
+ */
+template <typename KeyFrom, typename KeyTo>
+bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom& key_from,
+ const KeyTo& key_to)
+{
+ /* Get operations for requested keys. */
+ DepsNode *node_from = get_node(key_from);
+ DepsNode *node_to = get_node(key_to);
+ if (node_from == NULL || node_to == NULL) {
+ return false;
+ }
+ OperationDepsNode *op_from = node_from->get_exit_operation();
+ OperationDepsNode *op_to = node_to->get_entry_operation();
+ if (op_from == NULL || op_to == NULL) {
+ return false;
+ }
+ /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */
+ if (!(op_from->opcode == DEG_OPCODE_BONE_DONE &&
+ op_to->opcode == DEG_OPCODE_BONE_LOCAL)) {
+ return false;
+ }
+ /* ... BUT, we also need to check if it's same bone. */
+ if (!STREQ(op_from->owner->name, op_to->owner->name)) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace DEG
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index 2a2108e8480..2aff1ca33c7 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -324,11 +324,6 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
"Armature Eval");
add_relation(armature_key, init_key, "Data dependency");
- if (needs_animdata_node(&object->id)) {
- ComponentKey animation_key(&object->id, DEG_NODE_TYPE_ANIMATION);
- add_relation(animation_key, init_key, "Rig Animation");
- }
-
/* IK Solvers...
* - These require separate processing steps are pose-level
* to be executed between chains of bones (i.e. once the
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
index e30e00e61b5..4fea8b49706 100644
--- a/source/blender/depsgraph/intern/depsgraph.cc
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -103,41 +103,39 @@ Depsgraph::~Depsgraph()
/* Query Conditions from RNA ----------------------- */
-static bool pointer_to_id_node_criteria(const PointerRNA *ptr,
- const PropertyRNA *prop,
- ID **id)
-{
- if (ptr->type == NULL) {
- return false;
- }
- if (prop != NULL) {
- if (RNA_struct_is_ID(ptr->type)) {
- *id = (ID *)ptr->data;
- return true;
- }
- }
- return false;
-}
-
-static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
- const PropertyRNA *prop,
- ID **id,
- eDepsNode_Type *type,
- const char **subdata)
+static bool pointer_to_component_node_criteria(
+ const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id,
+ eDepsNode_Type *type,
+ const char **subdata,
+ eDepsOperation_Code *operation_code,
+ const char **operation_name,
+ int *operation_name_tag)
{
if (ptr->type == NULL) {
return false;
}
/* Set default values for returns. */
- *id = (ID *)ptr->id.data; /* For obvious reasons... */
- *subdata = ""; /* Default to no subdata (e.g. bone) name
- * lookup in most cases. */
+ *id = (ID *)ptr->id.data;
+ *subdata = "";
+ *operation_code = DEG_OPCODE_OPERATION;
+ *operation_name = "";
+ *operation_name_tag = -1;
/* Handling of commonly known scenarios. */
if (ptr->type == &RNA_PoseBone) {
bPoseChannel *pchan = (bPoseChannel *)ptr->data;
- /* Bone - generally, we just want the bone component. */
- *type = DEG_NODE_TYPE_BONE;
- *subdata = pchan->name;
+ if (prop != NULL && RNA_property_is_idprop(prop)) {
+ *type = DEG_NODE_TYPE_PARAMETERS;
+ *subdata = "";
+ *operation_code = DEG_OPCODE_PARAMETERS_EVAL;
+ *operation_name = pchan->name;;
+ }
+ else {
+ /* Bone - generally, we just want the bone component. */
+ *type = DEG_NODE_TYPE_BONE;
+ *subdata = pchan->name;
+ }
return true;
}
else if (ptr->type == &RNA_Bone) {
@@ -200,7 +198,12 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
* owns it.
*/
*id = key->from;
- *type = DEG_NODE_TYPE_PARAMETERS;
+ *type = DEG_NODE_TYPE_GEOMETRY;
+ return true;
+ }
+ else if (ptr->type == &RNA_Key) {
+ *id = (ID *)ptr->id.data;
+ *type = DEG_NODE_TYPE_GEOMETRY;
return true;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
@@ -213,6 +216,9 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
if (prop != NULL) {
/* All unknown data effectively falls under "parameter evaluation". */
*type = DEG_NODE_TYPE_PARAMETERS;
+ *operation_code = DEG_OPCODE_PARAMETERS_EVAL;
+ *operation_name = "";
+ *operation_name_tag = -1;
return true;
}
return false;
@@ -223,20 +229,32 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
const PropertyRNA *prop) const
{
ID *id;
- eDepsNode_Type type;
- const char *name;
-
- /* Get querying conditions. */
- if (pointer_to_id_node_criteria(ptr, prop, &id)) {
- return find_id_node(id);
- }
- else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
+ eDepsNode_Type node_type;
+ const char *component_name, *operation_name;
+ eDepsOperation_Code operation_code;
+ int operation_name_tag;
+
+ if (pointer_to_component_node_criteria(
+ ptr, prop,
+ &id, &node_type, &component_name,
+ &operation_code, &operation_name, &operation_name_tag))
+ {
IDDepsNode *id_node = find_id_node(id);
- if (id_node != NULL) {
- return id_node->find_component(type, name);
+ if (id_node == NULL) {
+ return NULL;
+ }
+ ComponentDepsNode *comp_node =
+ id_node->find_component(node_type, component_name);
+ if (comp_node == NULL) {
+ return NULL;
+ }
+ if (operation_code == DEG_OPCODE_OPERATION) {
+ return comp_node;
}
+ return comp_node->find_operation(operation_code,
+ operation_name,
+ operation_name_tag);
}
-
return NULL;
}
@@ -318,10 +336,18 @@ void Depsgraph::clear_id_nodes()
/* Add new relationship between two nodes. */
DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
+ DepsRelation *rel = NULL;
+ if (check_unique) {
+ rel = check_nodes_connected(from, to, description);
+ }
+ if (rel != NULL) {
+ return rel;
+ }
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
+ rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
/* TODO(sergey): Find a better place for this. */
#ifdef WITH_OPENSUBDIV
ComponentDepsNode *comp_node = from->owner;
@@ -341,13 +367,38 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
/* Add new relation between two nodes */
DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
- const char *description)
+ const char *description,
+ bool check_unique)
{
+ DepsRelation *rel = NULL;
+ if (check_unique) {
+ rel = check_nodes_connected(from, to, description);
+ }
+ if (rel != NULL) {
+ return rel;
+ }
/* Create new relation, and add it to the graph. */
- DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
+ rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, description);
return rel;
}
+DepsRelation *Depsgraph::check_nodes_connected(const DepsNode *from,
+ const DepsNode *to,
+ const char *description)
+{
+ foreach (DepsRelation *rel, from->outlinks) {
+ BLI_assert(rel->from == from);
+ if (rel->to != to) {
+ continue;
+ }
+ if (description != NULL && !STREQ(rel->name, description)) {
+ continue;
+ }
+ return rel;
+ }
+ return NULL;
+}
+
/* ************************ */
/* Relationships Management */
@@ -359,24 +410,6 @@ DepsRelation::DepsRelation(DepsNode *from,
name(description),
flag(0)
{
-#ifndef NDEBUG
-/*
- for (OperationDepsNode::Relations::const_iterator it = from->outlinks.begin();
- it != from->outlinks.end();
- ++it)
- {
- DepsRelation *rel = *it;
- if (rel->from == from &&
- rel->to == to &&
- rel->type == type &&
- rel->name == description)
- {
- BLI_assert(!"Duplicated relation, should not happen!");
- }
- }
-*/
-#endif
-
/* Hook it up to the nodes which use it.
*
* NOTE: We register relation in the nodes which this link connects to here
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
index d841ae045f2..8a34be0c7a2 100644
--- a/source/blender/depsgraph/intern/depsgraph.h
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -123,11 +123,21 @@ struct Depsgraph {
/* Add new relationship between two nodes. */
DepsRelation *add_new_relation(OperationDepsNode *from,
OperationDepsNode *to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
DepsRelation *add_new_relation(DepsNode *from,
DepsNode *to,
- const char *description);
+ const char *description,
+ bool check_unique = false);
+
+ /* Check whether two nodes are connected by relation with given
+ * description. Description might be NULL to check ANY relation between
+ * given nodes.
+ */
+ DepsRelation *check_nodes_connected(const DepsNode *from,
+ const DepsNode *to,
+ const char *description);
/* Tag a specific node as needing updates. */
void add_entry_tag(OperationDepsNode *node);
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index b7f038dd3f6..a99541385d0 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -741,6 +741,7 @@ extern StructRNA RNA_XorController;
void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr);
void RNA_id_pointer_create(struct ID *id, PointerRNA *r_ptr);
void RNA_pointer_create(struct ID *id, StructRNA *type, void *data, PointerRNA *r_ptr);
+bool RNA_pointer_is_null(const PointerRNA *ptr);
bool RNA_path_resolved_create(
PointerRNA *ptr, struct PropertyRNA *prop,
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 6e90cd5a013..345c3d23dbe 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -175,6 +175,11 @@ void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
}
}
+bool RNA_pointer_is_null(const PointerRNA *ptr)
+{
+ return !((ptr->data != NULL) && (ptr->id.data != NULL) && (ptr->type != NULL));
+}
+
static void rna_pointer_inherit_id(StructRNA *type, PointerRNA *parent, PointerRNA *ptr)
{
if (type && type->flag & STRUCT_ID) {