diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/depsgraph/intern/builder | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/depsgraph/intern/builder')
21 files changed, 5423 insertions, 6209 deletions
diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index b6e516ee9b4..ef36dec6f34 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -58,65 +58,63 @@ namespace DEG { namespace { struct VisibilityCheckData { - eEvaluationMode eval_mode; - bool is_visibility_animated; + eEvaluationMode eval_mode; + bool is_visibility_animated; }; void visibility_animated_check_cb(ID * /*id*/, FCurve *fcu, void *user_data) { - VisibilityCheckData *data = - reinterpret_cast<VisibilityCheckData *>(user_data); - if (data->is_visibility_animated) { - return; - } - if (data->eval_mode == DAG_EVAL_VIEWPORT) { - if (STREQ(fcu->rna_path, "hide_viewport")) { - data->is_visibility_animated = true; - } - } - else if (data->eval_mode == DAG_EVAL_RENDER) { - if (STREQ(fcu->rna_path, "hide_render")) { - data->is_visibility_animated = true; - } - } + VisibilityCheckData *data = reinterpret_cast<VisibilityCheckData *>(user_data); + if (data->is_visibility_animated) { + return; + } + if (data->eval_mode == DAG_EVAL_VIEWPORT) { + if (STREQ(fcu->rna_path, "hide_viewport")) { + data->is_visibility_animated = true; + } + } + else if (data->eval_mode == DAG_EVAL_RENDER) { + if (STREQ(fcu->rna_path, "hide_render")) { + data->is_visibility_animated = true; + } + } } bool is_object_visibility_animated(const Depsgraph *graph, Object *object) { - AnimData *anim_data = BKE_animdata_from_id(&object->id); - if (anim_data == NULL) { - return false; - } - VisibilityCheckData data; - data.eval_mode = graph->mode; - data.is_visibility_animated = false; - BKE_fcurves_id_cb(&object->id, visibility_animated_check_cb, &data); - return data.is_visibility_animated; + AnimData *anim_data = BKE_animdata_from_id(&object->id); + if (anim_data == NULL) { + return false; + } + VisibilityCheckData data; + data.eval_mode = graph->mode; + data.is_visibility_animated = false; + BKE_fcurves_id_cb(&object->id, visibility_animated_check_cb, &data); + return data.is_visibility_animated; } } // namespace bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base) { - const int base_flag = (graph->mode == DAG_EVAL_VIEWPORT) ? - BASE_ENABLED_VIEWPORT : BASE_ENABLED_RENDER; - if (base->flag & base_flag) { - return true; - } - if (is_object_visibility_animated(graph, base->object)) { - return true; - } - return false; + const int base_flag = (graph->mode == DAG_EVAL_VIEWPORT) ? BASE_ENABLED_VIEWPORT : + BASE_ENABLED_RENDER; + if (base->flag & base_flag) { + return true; + } + if (is_object_visibility_animated(graph, base->object)) { + return true; + } + return false; } -DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph) - : bmain_(bmain), - graph_(graph) { +DepsgraphBuilder::DepsgraphBuilder(Main *bmain, Depsgraph *graph) : bmain_(bmain), graph_(graph) +{ } bool DepsgraphBuilder::need_pull_base_into_graph(Base *base) { - return deg_check_base_available_for_build(graph_, base); + return deg_check_base_available_for_build(graph_, base); } /******************************************************************************* @@ -127,101 +125,90 @@ namespace { void deg_graph_build_flush_visibility(Depsgraph *graph) { - enum { - DEG_NODE_VISITED = (1 << 0), - }; - - BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), - "DEG flush layers stack"); - for (IDNode *id_node : graph->id_nodes) { - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - comp_node->affects_directly_visible |= id_node->is_directly_visible; - } - GHASH_FOREACH_END(); - } - for (OperationNode *op_node : graph->operations) { - op_node->custom_flags = 0; - op_node->num_links_pending = 0; - for (Relation *rel : op_node->outlinks) { - if ((rel->from->type == NodeType::OPERATION) && - (rel->flag & RELATION_FLAG_CYCLIC) == 0) - { - ++op_node->num_links_pending; - } - } - if (op_node->num_links_pending == 0) { - BLI_stack_push(stack, &op_node); - op_node->custom_flags |= DEG_NODE_VISITED; - } - } - while (!BLI_stack_is_empty(stack)) { - OperationNode *op_node; - BLI_stack_pop(stack, &op_node); - /* Flush layers to parents. */ - for (Relation *rel : op_node->inlinks) { - if (rel->from->type == NodeType::OPERATION) { - OperationNode *op_from = (OperationNode *)rel->from; - op_from->owner->affects_directly_visible |= - op_node->owner->affects_directly_visible; - } - } - /* Schedule parent nodes. */ - for (Relation *rel : op_node->inlinks) { - if (rel->from->type == NodeType::OPERATION) { - OperationNode *op_from = (OperationNode *)rel->from; - if ((rel->flag & RELATION_FLAG_CYCLIC) == 0) { - BLI_assert(op_from->num_links_pending > 0); - --op_from->num_links_pending; - } - if ((op_from->num_links_pending == 0) && - (op_from->custom_flags & DEG_NODE_VISITED) == 0) - { - BLI_stack_push(stack, &op_from); - op_from->custom_flags |= DEG_NODE_VISITED; - } - } - } - } - BLI_stack_free(stack); + enum { + DEG_NODE_VISITED = (1 << 0), + }; + + BLI_Stack *stack = BLI_stack_new(sizeof(OperationNode *), "DEG flush layers stack"); + for (IDNode *id_node : graph->id_nodes) { + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + comp_node->affects_directly_visible |= id_node->is_directly_visible; + } + GHASH_FOREACH_END(); + } + for (OperationNode *op_node : graph->operations) { + op_node->custom_flags = 0; + op_node->num_links_pending = 0; + for (Relation *rel : op_node->outlinks) { + if ((rel->from->type == NodeType::OPERATION) && (rel->flag & RELATION_FLAG_CYCLIC) == 0) { + ++op_node->num_links_pending; + } + } + if (op_node->num_links_pending == 0) { + BLI_stack_push(stack, &op_node); + op_node->custom_flags |= DEG_NODE_VISITED; + } + } + while (!BLI_stack_is_empty(stack)) { + OperationNode *op_node; + BLI_stack_pop(stack, &op_node); + /* Flush layers to parents. */ + for (Relation *rel : op_node->inlinks) { + if (rel->from->type == NodeType::OPERATION) { + OperationNode *op_from = (OperationNode *)rel->from; + op_from->owner->affects_directly_visible |= op_node->owner->affects_directly_visible; + } + } + /* Schedule parent nodes. */ + for (Relation *rel : op_node->inlinks) { + if (rel->from->type == NodeType::OPERATION) { + OperationNode *op_from = (OperationNode *)rel->from; + if ((rel->flag & RELATION_FLAG_CYCLIC) == 0) { + BLI_assert(op_from->num_links_pending > 0); + --op_from->num_links_pending; + } + if ((op_from->num_links_pending == 0) && (op_from->custom_flags & DEG_NODE_VISITED) == 0) { + BLI_stack_push(stack, &op_from); + op_from->custom_flags |= DEG_NODE_VISITED; + } + } + } + } + BLI_stack_free(stack); } } // namespace void deg_graph_build_finalize(Main *bmain, Depsgraph *graph) { - /* Make sure dependencies of visible ID datablocks are visible. */ - deg_graph_build_flush_visibility(graph); - /* Re-tag IDs for update if it was tagged before the relations - * update tag. */ - for (IDNode *id_node : graph->id_nodes) { - ID *id = id_node->id_orig; - id_node->finalize_build(graph); - int flag = 0; - /* Tag rebuild if special evaluation flags changed. */ - if (id_node->eval_flags != id_node->previous_eval_flags) { - flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; - } - /* Tag rebuild if the custom data mask changed. */ - if (id_node->customdata_masks != id_node->previous_customdata_masks) { - flag |= ID_RECALC_GEOMETRY; - } - if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { - flag |= ID_RECALC_COPY_ON_WRITE; - /* This means ID is being added to the dependency graph first - * time, which is similar to "ob-visible-change" */ - if (GS(id->name) == ID_OB) { - flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; - } - } - if (flag != 0) { - graph_id_tag_update(bmain, - graph, - id_node->id_orig, - flag, - DEG_UPDATE_SOURCE_RELATIONS); - } - } + /* Make sure dependencies of visible ID datablocks are visible. */ + deg_graph_build_flush_visibility(graph); + /* Re-tag IDs for update if it was tagged before the relations + * update tag. */ + for (IDNode *id_node : graph->id_nodes) { + ID *id = id_node->id_orig; + id_node->finalize_build(graph); + int flag = 0; + /* Tag rebuild if special evaluation flags changed. */ + if (id_node->eval_flags != id_node->previous_eval_flags) { + flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; + } + /* Tag rebuild if the custom data mask changed. */ + if (id_node->customdata_masks != id_node->previous_customdata_masks) { + flag |= ID_RECALC_GEOMETRY; + } + if (!deg_copy_on_write_is_expanded(id_node->id_cow)) { + flag |= ID_RECALC_COPY_ON_WRITE; + /* This means ID is being added to the dependency graph first + * time, which is similar to "ob-visible-change" */ + if (GS(id->name) == ID_OB) { + flag |= ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY; + } + } + if (flag != 0) { + graph_id_tag_update(bmain, graph, id_node->id_orig, flag, DEG_UPDATE_SOURCE_RELATIONS); + } + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 2461ca2211f..310944f2f28 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -31,19 +31,18 @@ namespace DEG { struct Depsgraph; class DepsgraphBuilder { -public: - bool need_pull_base_into_graph(struct Base *base); + public: + bool need_pull_base_into_graph(struct Base *base); -protected: - DepsgraphBuilder(Main *bmain, Depsgraph *graph); + protected: + DepsgraphBuilder(Main *bmain, Depsgraph *graph); - /* State which never changes, same for the whole builder time. */ - Main *bmain_; - Depsgraph *graph_; + /* State which never changes, same for the whole builder time. */ + Main *bmain_; + Depsgraph *graph_; }; -bool deg_check_base_available_for_build(const Depsgraph *graph, - Base *base); +bool deg_check_base_available_for_build(const Depsgraph *graph, Base *base); void deg_graph_build_finalize(struct Main *bmain, struct Depsgraph *graph); } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index a6d86f5178f..af5c4e7130b 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -41,89 +41,88 @@ namespace DEG { namespace { enum eCyclicCheckVisitedState { - /* Not is not visited at all during traversal. */ - NODE_NOT_VISITED = 0, - /* Node has been visited during traversal and not in current stack. */ - NODE_VISITED = 1, - /* Node has been visited during traversal and is in current stack. */ - NODE_IN_STACK = 2, + /* Not is not visited at all during traversal. */ + NODE_NOT_VISITED = 0, + /* Node has been visited during traversal and not in current stack. */ + NODE_VISITED = 1, + /* Node has been visited during traversal and is in current stack. */ + NODE_IN_STACK = 2, }; struct StackEntry { - OperationNode *node; - StackEntry *from; - Relation *via_relation; + OperationNode *node; + StackEntry *from; + Relation *via_relation; }; struct CyclesSolverState { - CyclesSolverState(Depsgraph *graph) - : graph(graph), - traversal_stack(BLI_stack_new(sizeof(StackEntry), - "DEG detect cycles stack")), - num_cycles(0) - { - /* pass */ - } - ~CyclesSolverState() { - BLI_stack_free(traversal_stack); - if (num_cycles != 0) { - printf("Detected %d dependency cycles\n", num_cycles); - } - } - Depsgraph *graph; - BLI_Stack *traversal_stack; - int num_cycles; + CyclesSolverState(Depsgraph *graph) + : graph(graph), + traversal_stack(BLI_stack_new(sizeof(StackEntry), "DEG detect cycles stack")), + num_cycles(0) + { + /* pass */ + } + ~CyclesSolverState() + { + BLI_stack_free(traversal_stack); + if (num_cycles != 0) { + printf("Detected %d dependency cycles\n", num_cycles); + } + } + Depsgraph *graph; + BLI_Stack *traversal_stack; + int num_cycles; }; -BLI_INLINE void set_node_visited_state(Node *node, - eCyclicCheckVisitedState state) +BLI_INLINE void set_node_visited_state(Node *node, eCyclicCheckVisitedState state) { - node->custom_flags = (node->custom_flags & ~0x3) | (int)state; + node->custom_flags = (node->custom_flags & ~0x3) | (int)state; } BLI_INLINE eCyclicCheckVisitedState get_node_visited_state(Node *node) { - return (eCyclicCheckVisitedState)(node->custom_flags & 0x3); + return (eCyclicCheckVisitedState)(node->custom_flags & 0x3); } BLI_INLINE void set_node_num_visited_children(Node *node, int num_children) { - node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2); + node->custom_flags = (node->custom_flags & 0x3) | (num_children << 2); } BLI_INLINE int get_node_num_visited_children(Node *node) { - return node->custom_flags >> 2; + return node->custom_flags >> 2; } void schedule_node_to_stack(CyclesSolverState *state, OperationNode *node) { - StackEntry entry; - entry.node = node; - entry.from = NULL; - entry.via_relation = NULL; - BLI_stack_push(state->traversal_stack, &entry); - set_node_visited_state(node, NODE_IN_STACK); + StackEntry entry; + entry.node = node; + entry.from = NULL; + entry.via_relation = NULL; + BLI_stack_push(state->traversal_stack, &entry); + set_node_visited_state(node, NODE_IN_STACK); } /* Schedule leaf nodes (node without input links) for traversal. */ void schedule_leaf_nodes(CyclesSolverState *state) { - for (OperationNode *node : state->graph->operations) { - bool has_inlinks = false; - for (Relation *rel : node->inlinks) { - if (rel->from->type == NodeType::OPERATION) { - has_inlinks = true; - } - } - node->custom_flags = 0; - if (has_inlinks == false) { - schedule_node_to_stack(state, node); - } - else { - set_node_visited_state(node, NODE_NOT_VISITED); - } - } + for (OperationNode *node : state->graph->operations) { + bool has_inlinks = false; + for (Relation *rel : node->inlinks) { + if (rel->from->type == NodeType::OPERATION) { + has_inlinks = true; + } + } + node->custom_flags = 0; + if (has_inlinks == false) { + schedule_node_to_stack(state, node); + } + else { + set_node_visited_state(node, NODE_NOT_VISITED); + } + } } /* Schedule node which was not checked yet for being belong to @@ -131,113 +130,111 @@ void schedule_leaf_nodes(CyclesSolverState *state) */ bool schedule_non_checked_node(CyclesSolverState *state) { - for (OperationNode *node : state->graph->operations) { - if (get_node_visited_state(node) == NODE_NOT_VISITED) { - schedule_node_to_stack(state, node); - return true; - } - } - return false; + for (OperationNode *node : state->graph->operations) { + if (get_node_visited_state(node) == NODE_NOT_VISITED) { + schedule_node_to_stack(state, node); + return true; + } + } + return false; } bool check_relation_can_murder(Relation *relation) { - if (relation->flag & RELATION_FLAG_GODMODE) { - return false; - } - return true; + if (relation->flag & RELATION_FLAG_GODMODE) { + return false; + } + return true; } -Relation *select_relation_to_murder(Relation *relation, - StackEntry *cycle_start_entry) +Relation *select_relation_to_murder(Relation *relation, StackEntry *cycle_start_entry) { - /* More or less russian roulette solver, which will make sure only - * specially marked relations are kept alive. - * - * TODO(sergey): There might be better strategies here. */ - if (check_relation_can_murder(relation)) { - return relation; - } - StackEntry *current = cycle_start_entry; - OperationNode *to_node = (OperationNode *)relation->to; - while (current->node != to_node) { - if (check_relation_can_murder(current->via_relation)) { - return current->via_relation; - } - current = current->from; - } - return relation; + /* More or less russian roulette solver, which will make sure only + * specially marked relations are kept alive. + * + * TODO(sergey): There might be better strategies here. */ + if (check_relation_can_murder(relation)) { + return relation; + } + StackEntry *current = cycle_start_entry; + OperationNode *to_node = (OperationNode *)relation->to; + while (current->node != to_node) { + if (check_relation_can_murder(current->via_relation)) { + return current->via_relation; + } + current = current->from; + } + return relation; } /* Solve cycles with all nodes which are scheduled for traversal. */ void solve_cycles(CyclesSolverState *state) { - BLI_Stack *traversal_stack = state->traversal_stack; - while (!BLI_stack_is_empty(traversal_stack)) { - StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack); - OperationNode *node = entry->node; - bool all_child_traversed = true; - const int num_visited = get_node_num_visited_children(node); - for (int i = num_visited; i < node->outlinks.size(); ++i) { - Relation *rel = node->outlinks[i]; - if (rel->to->type == NodeType::OPERATION) { - OperationNode *to = (OperationNode *)rel->to; - eCyclicCheckVisitedState to_state = get_node_visited_state(to); - if (to_state == NODE_IN_STACK) { - printf("Dependency cycle detected:\n"); - printf(" '%s' depends on '%s' through '%s'\n", - to->full_identifier().c_str(), - node->full_identifier().c_str(), - rel->name); - StackEntry *current = entry; - while (current->node != to) { - BLI_assert(current != NULL); - printf(" '%s' depends on '%s' through '%s'\n", - current->node->full_identifier().c_str(), - current->from->node->full_identifier().c_str(), - current->via_relation->name); - current = current->from; - } - Relation *sacrificial_relation = - select_relation_to_murder(rel, entry); - sacrificial_relation->flag |= RELATION_FLAG_CYCLIC; - ++state->num_cycles; - } - else if (to_state == NODE_NOT_VISITED) { - StackEntry new_entry; - new_entry.node = to; - new_entry.from = entry; - new_entry.via_relation = rel; - BLI_stack_push(traversal_stack, &new_entry); - set_node_visited_state(node, NODE_IN_STACK); - all_child_traversed = false; - set_node_num_visited_children(node, i); - break; - } - } - } - if (all_child_traversed) { - set_node_visited_state(node, NODE_VISITED); - BLI_stack_discard(traversal_stack); - } - } + BLI_Stack *traversal_stack = state->traversal_stack; + while (!BLI_stack_is_empty(traversal_stack)) { + StackEntry *entry = (StackEntry *)BLI_stack_peek(traversal_stack); + OperationNode *node = entry->node; + bool all_child_traversed = true; + const int num_visited = get_node_num_visited_children(node); + for (int i = num_visited; i < node->outlinks.size(); ++i) { + Relation *rel = node->outlinks[i]; + if (rel->to->type == NodeType::OPERATION) { + OperationNode *to = (OperationNode *)rel->to; + eCyclicCheckVisitedState to_state = get_node_visited_state(to); + if (to_state == NODE_IN_STACK) { + printf("Dependency cycle detected:\n"); + printf(" '%s' depends on '%s' through '%s'\n", + to->full_identifier().c_str(), + node->full_identifier().c_str(), + rel->name); + StackEntry *current = entry; + while (current->node != to) { + BLI_assert(current != NULL); + printf(" '%s' depends on '%s' through '%s'\n", + current->node->full_identifier().c_str(), + current->from->node->full_identifier().c_str(), + current->via_relation->name); + current = current->from; + } + Relation *sacrificial_relation = select_relation_to_murder(rel, entry); + sacrificial_relation->flag |= RELATION_FLAG_CYCLIC; + ++state->num_cycles; + } + else if (to_state == NODE_NOT_VISITED) { + StackEntry new_entry; + new_entry.node = to; + new_entry.from = entry; + new_entry.via_relation = rel; + BLI_stack_push(traversal_stack, &new_entry); + set_node_visited_state(node, NODE_IN_STACK); + all_child_traversed = false; + set_node_num_visited_children(node, i); + break; + } + } + } + if (all_child_traversed) { + set_node_visited_state(node, NODE_VISITED); + BLI_stack_discard(traversal_stack); + } + } } } // namespace void deg_graph_detect_cycles(Depsgraph *graph) { - CyclesSolverState state(graph); - /* First we solve cycles which are reachable from leaf nodes. */ - schedule_leaf_nodes(&state); - solve_cycles(&state); - /* We are not done yet. It is possible to have closed loop cycle, - * for example A -> B -> C -> A. These nodes were not scheduled - * yet (since they all have inlinks), and were not traversed since - * nobody else points to them. */ - while (schedule_non_checked_node(&state)) { - solve_cycles(&state); - } + CyclesSolverState state(graph); + /* First we solve cycles which are reachable from leaf nodes. */ + schedule_leaf_nodes(&state); + solve_cycles(&state); + /* We are not done yet. It is possible to have closed loop cycle, + * for example A -> B -> C -> A. These nodes were not scheduled + * yet (since they all have inlinks), and were not traversed since + * nobody else points to them. */ + while (schedule_non_checked_node(&state)) { + solve_cycles(&state); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h index 2fe24d1795a..aafdcdbea04 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.h @@ -21,7 +21,6 @@ * \ingroup depsgraph */ - #pragma once namespace DEG { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.cc b/source/blender/depsgraph/intern/builder/deg_builder_map.cc index cc5ea98ca93..a519f3e60b5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_map.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_map.cc @@ -32,32 +32,32 @@ namespace DEG { BuilderMap::BuilderMap() { - set = BLI_gset_ptr_new("deg builder gset"); + set = BLI_gset_ptr_new("deg builder gset"); } BuilderMap::~BuilderMap() { - BLI_gset_free(set, NULL); + BLI_gset_free(set, NULL); } bool BuilderMap::checkIsBuilt(ID *id) { - return BLI_gset_haskey(set, id); + return BLI_gset_haskey(set, id); } void BuilderMap::tagBuild(ID *id) { - BLI_gset_insert(set, id); + BLI_gset_insert(set, id); } bool BuilderMap::checkIsBuiltAndTag(ID *id) { - void **key_p; - if (!BLI_gset_ensure_p_ex(set, id, &key_p)) { - *key_p = id; - return false; - } - return true; + void **key_p; + if (!BLI_gset_ensure_p_ex(set, id, &key_p)) { + *key_p = id; + return false; + } + return true; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_map.h b/source/blender/depsgraph/intern/builder/deg_builder_map.h index 193a7837aa6..c1db1d9d2bb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_map.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_map.h @@ -29,32 +29,35 @@ struct ID; namespace DEG { class BuilderMap { -public: - BuilderMap(); - ~BuilderMap(); - - /* Check whether given ID is already handled by builder (or if it's being - * handled). */ - bool checkIsBuilt(ID *id); - - /* Tag given ID as handled/built. */ - void tagBuild(ID *id); - - /* Combination of previous two functions, returns truth if ID was already - * handled, or tags is handled otherwise and return false. */ - bool checkIsBuiltAndTag(ID *id); - - template<typename T> bool checkIsBuilt(T *datablock) { - return checkIsBuilt(&datablock->id); - } - template<typename T> void tagBuild(T *datablock) { - tagBuild(&datablock->id); - } - template<typename T> bool checkIsBuiltAndTag(T *datablock) { - return checkIsBuiltAndTag(&datablock->id); - } - - GSet *set; + public: + BuilderMap(); + ~BuilderMap(); + + /* Check whether given ID is already handled by builder (or if it's being + * handled). */ + bool checkIsBuilt(ID *id); + + /* Tag given ID as handled/built. */ + void tagBuild(ID *id); + + /* Combination of previous two functions, returns truth if ID was already + * handled, or tags is handled otherwise and return false. */ + bool checkIsBuiltAndTag(ID *id); + + template<typename T> bool checkIsBuilt(T *datablock) + { + return checkIsBuilt(&datablock->id); + } + template<typename T> void tagBuild(T *datablock) + { + tagBuild(&datablock->id); + } + template<typename T> bool checkIsBuiltAndTag(T *datablock) + { + return checkIsBuiltAndTag(&datablock->id); + } + + GSet *set; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 0cc1c2aa211..b37ecb45ac8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -114,16 +114,15 @@ namespace { void free_copy_on_write_datablock(void *id_info_v) { - DepsgraphNodeBuilder::IDInfo *id_info = - (DepsgraphNodeBuilder::IDInfo *)id_info_v; - if (id_info->id_cow != NULL) { - deg_free_copy_on_write_datablock(id_info->id_cow); - MEM_freeN(id_info->id_cow); - } - MEM_freeN(id_info); + DepsgraphNodeBuilder::IDInfo *id_info = (DepsgraphNodeBuilder::IDInfo *)id_info_v; + if (id_info->id_cow != NULL) { + deg_free_copy_on_write_datablock(id_info->id_cow); + MEM_freeN(id_info->id_cow); + } + MEM_freeN(id_info); } -} /* namespace */ +} /* namespace */ /* ************ */ /* Node Builder */ @@ -143,131 +142,122 @@ DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph) DepsgraphNodeBuilder::~DepsgraphNodeBuilder() { - if (id_info_hash_ != NULL) { - BLI_ghash_free(id_info_hash_, NULL, free_copy_on_write_datablock); - } + if (id_info_hash_ != NULL) { + BLI_ghash_free(id_info_hash_, NULL, free_copy_on_write_datablock); + } } IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) { - IDNode *id_node = NULL; - ID *id_cow = NULL; - IDComponentsMask previously_visible_components_mask = 0; - uint32_t previous_eval_flags = 0; - DEGCustomDataMeshMasks previous_customdata_masks; - IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id); - if (id_info != NULL) { - id_cow = id_info->id_cow; - previously_visible_components_mask = - id_info->previously_visible_components_mask; - previous_eval_flags = id_info->previous_eval_flags; - previous_customdata_masks = id_info->previous_customdata_masks; - /* Tag ID info to not free the CoW ID pointer. */ - id_info->id_cow = NULL; - } - id_node = graph_->add_id_node(id, id_cow); - id_node->previously_visible_components_mask = - previously_visible_components_mask; - id_node->previous_eval_flags = previous_eval_flags; - id_node->previous_customdata_masks = previous_customdata_masks; - /* Currently all ID nodes are supposed to have copy-on-write logic. - * - * NOTE: Zero number of components indicates that ID node was just created. */ - if (BLI_ghash_len(id_node->components) == 0) { - ComponentNode *comp_cow = - id_node->add_component(NodeType::COPY_ON_WRITE); - OperationNode *op_cow = comp_cow->add_operation( - function_bind(deg_evaluate_copy_on_write, _1, id_node), - OperationCode::COPY_ON_WRITE, - "", -1); - graph_->operations.push_back(op_cow); - } - return id_node; + IDNode *id_node = NULL; + ID *id_cow = NULL; + IDComponentsMask previously_visible_components_mask = 0; + uint32_t previous_eval_flags = 0; + DEGCustomDataMeshMasks previous_customdata_masks; + IDInfo *id_info = (IDInfo *)BLI_ghash_lookup(id_info_hash_, id); + if (id_info != NULL) { + id_cow = id_info->id_cow; + previously_visible_components_mask = id_info->previously_visible_components_mask; + previous_eval_flags = id_info->previous_eval_flags; + previous_customdata_masks = id_info->previous_customdata_masks; + /* Tag ID info to not free the CoW ID pointer. */ + id_info->id_cow = NULL; + } + id_node = graph_->add_id_node(id, id_cow); + id_node->previously_visible_components_mask = previously_visible_components_mask; + id_node->previous_eval_flags = previous_eval_flags; + id_node->previous_customdata_masks = previous_customdata_masks; + /* Currently all ID nodes are supposed to have copy-on-write logic. + * + * NOTE: Zero number of components indicates that ID node was just created. */ + if (BLI_ghash_len(id_node->components) == 0) { + ComponentNode *comp_cow = id_node->add_component(NodeType::COPY_ON_WRITE); + OperationNode *op_cow = comp_cow->add_operation( + function_bind(deg_evaluate_copy_on_write, _1, id_node), + OperationCode::COPY_ON_WRITE, + "", + -1); + graph_->operations.push_back(op_cow); + } + return id_node; } IDNode *DepsgraphNodeBuilder::find_id_node(ID *id) { - return graph_->find_id_node(id); + return graph_->find_id_node(id); } TimeSourceNode *DepsgraphNodeBuilder::add_time_source() { - return graph_->add_time_source(); + return graph_->add_time_source(); } -ComponentNode *DepsgraphNodeBuilder::add_component_node( - ID *id, - NodeType comp_type, - const char *comp_name) +ComponentNode *DepsgraphNodeBuilder::add_component_node(ID *id, + NodeType comp_type, + const char *comp_name) { - IDNode *id_node = add_id_node(id); - ComponentNode *comp_node = id_node->add_component(comp_type, comp_name); - comp_node->owner = id_node; - return comp_node; + IDNode *id_node = add_id_node(id); + ComponentNode *comp_node = id_node->add_component(comp_type, comp_name); + comp_node->owner = id_node; + return comp_node; } -OperationNode *DepsgraphNodeBuilder::add_operation_node( - ComponentNode *comp_node, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::add_operation_node(ComponentNode *comp_node, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - OperationNode *op_node = comp_node->find_operation(opcode, name, name_tag); - if (op_node == NULL) { - op_node = comp_node->add_operation(op, opcode, name, name_tag); - graph_->operations.push_back(op_node); - } - else { - fprintf(stderr, - "add_operation: Operation already exists - %s has %s at %p\n", - comp_node->identifier().c_str(), - op_node->identifier().c_str(), - op_node); - BLI_assert(!"Should not happen!"); - } - return op_node; + OperationNode *op_node = comp_node->find_operation(opcode, name, name_tag); + if (op_node == NULL) { + op_node = comp_node->add_operation(op, opcode, name, name_tag); + graph_->operations.push_back(op_node); + } + else { + fprintf(stderr, + "add_operation: Operation already exists - %s has %s at %p\n", + comp_node->identifier().c_str(), + op_node->identifier().c_str(), + op_node); + BLI_assert(!"Should not happen!"); + } + return op_node; } -OperationNode *DepsgraphNodeBuilder::add_operation_node( - ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::add_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); - return add_operation_node(comp_node, opcode, op, name, name_tag); + ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); + return add_operation_node(comp_node, opcode, op, name, name_tag); } -OperationNode *DepsgraphNodeBuilder::add_operation_node( - ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::add_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - return add_operation_node( - id, comp_type, "", opcode, op, name, name_tag); + return add_operation_node(id, comp_type, "", opcode, op, name, name_tag); } -OperationNode *DepsgraphNodeBuilder::ensure_operation_node( - ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::ensure_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op, + const char *name, + int name_tag) { - OperationNode *operation = - find_operation_node(id, comp_type, opcode, name, name_tag); - if (operation != NULL) { - return operation; - } - return add_operation_node(id, comp_type, opcode, op, name, name_tag); + OperationNode *operation = find_operation_node(id, comp_type, opcode, name, name_tag); + if (operation != NULL) { + return operation; + } + return add_operation_node(id, comp_type, opcode, op, name, name_tag); } bool DepsgraphNodeBuilder::has_operation_node(ID *id, @@ -277,266 +267,245 @@ bool DepsgraphNodeBuilder::has_operation_node(ID *id, const char *name, int name_tag) { - return find_operation_node( - id, comp_type, comp_name, opcode, name, name_tag) != NULL; + return find_operation_node(id, comp_type, comp_name, opcode, name, name_tag) != NULL; } -OperationNode *DepsgraphNodeBuilder::find_operation_node( - ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const char *name, - int name_tag) +OperationNode *DepsgraphNodeBuilder::find_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const char *name, + int name_tag) { - ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); - return comp_node->find_operation(opcode, name, name_tag); + ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); + return comp_node->find_operation(opcode, name, name_tag); } OperationNode *DepsgraphNodeBuilder::find_operation_node( - ID *id, - NodeType comp_type, - OperationCode opcode, - const char *name, - int name_tag) + ID *id, NodeType comp_type, OperationCode opcode, const char *name, int name_tag) { - return find_operation_node(id, comp_type, "", opcode, name, name_tag); + return find_operation_node(id, comp_type, "", opcode, name, name_tag); } ID *DepsgraphNodeBuilder::get_cow_id(const ID *id_orig) const { - return graph_->get_cow_id(id_orig); + return graph_->get_cow_id(id_orig); } ID *DepsgraphNodeBuilder::ensure_cow_id(ID *id_orig) { - if (id_orig->tag & LIB_TAG_COPIED_ON_WRITE) { - /* ID is already remapped to copy-on-write. */ - return id_orig; - } - IDNode *id_node = add_id_node(id_orig); - return id_node->id_cow; + if (id_orig->tag & LIB_TAG_COPIED_ON_WRITE) { + /* ID is already remapped to copy-on-write. */ + return id_orig; + } + IDNode *id_node = add_id_node(id_orig); + return id_node->id_cow; } /* **** Build functions for entity nodes **** */ void DepsgraphNodeBuilder::begin_build() { - /* Store existing copy-on-write versions of datablock, so we can re-use - * them for new ID nodes. */ - id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash"); - for (IDNode *id_node : graph_->id_nodes) { - IDInfo *id_info = (IDInfo *)MEM_mallocN( - sizeof(IDInfo), "depsgraph id info"); - if (deg_copy_on_write_is_expanded(id_node->id_cow) && - id_node->id_orig != id_node->id_cow) - { - id_info->id_cow = id_node->id_cow; - } - else { - id_info->id_cow = NULL; - } - id_info->previously_visible_components_mask = - id_node->visible_components_mask; - id_info->previous_eval_flags = id_node->eval_flags; - id_info->previous_customdata_masks = id_node->customdata_masks; - BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info); - id_node->id_cow = NULL; - } - - GSET_FOREACH_BEGIN(OperationNode *, op_node, graph_->entry_tags) - { - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - - SavedEntryTag entry_tag; - entry_tag.id_orig = id_node->id_orig; - entry_tag.component_type = comp_node->type; - entry_tag.opcode = op_node->opcode; - entry_tag.name = op_node->name; - entry_tag.name_tag = op_node->name_tag; - saved_entry_tags_.push_back(entry_tag); - }; - GSET_FOREACH_END(); - - /* Make sure graph has no nodes left from previous state. */ - graph_->clear_all_nodes(); - graph_->operations.clear(); - BLI_gset_clear(graph_->entry_tags, NULL); + /* Store existing copy-on-write versions of datablock, so we can re-use + * them for new ID nodes. */ + id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash"); + for (IDNode *id_node : graph_->id_nodes) { + IDInfo *id_info = (IDInfo *)MEM_mallocN(sizeof(IDInfo), "depsgraph id info"); + if (deg_copy_on_write_is_expanded(id_node->id_cow) && id_node->id_orig != id_node->id_cow) { + id_info->id_cow = id_node->id_cow; + } + else { + id_info->id_cow = NULL; + } + id_info->previously_visible_components_mask = id_node->visible_components_mask; + id_info->previous_eval_flags = id_node->eval_flags; + id_info->previous_customdata_masks = id_node->customdata_masks; + BLI_ghash_insert(id_info_hash_, id_node->id_orig, id_info); + id_node->id_cow = NULL; + } + + GSET_FOREACH_BEGIN (OperationNode *, op_node, graph_->entry_tags) { + ComponentNode *comp_node = op_node->owner; + IDNode *id_node = comp_node->owner; + + SavedEntryTag entry_tag; + entry_tag.id_orig = id_node->id_orig; + entry_tag.component_type = comp_node->type; + entry_tag.opcode = op_node->opcode; + entry_tag.name = op_node->name; + entry_tag.name_tag = op_node->name_tag; + saved_entry_tags_.push_back(entry_tag); + }; + GSET_FOREACH_END(); + + /* Make sure graph has no nodes left from previous state. */ + graph_->clear_all_nodes(); + graph_->operations.clear(); + BLI_gset_clear(graph_->entry_tags, NULL); } void DepsgraphNodeBuilder::end_build() { - for (const SavedEntryTag& entry_tag : saved_entry_tags_) { - IDNode *id_node = find_id_node(entry_tag.id_orig); - if (id_node == NULL) { - continue; - } - ComponentNode *comp_node = - id_node->find_component(entry_tag.component_type); - if (comp_node == NULL) { - continue; - } - OperationNode *op_node = comp_node->find_operation( - entry_tag.opcode, entry_tag.name.c_str(), entry_tag.name_tag); - if (op_node == NULL) { - continue; - } - /* Since the tag is coming from a saved copy of entry tags, this means - * that originally node was explicitly tagged for user update. */ - op_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT); - } + for (const SavedEntryTag &entry_tag : saved_entry_tags_) { + IDNode *id_node = find_id_node(entry_tag.id_orig); + if (id_node == NULL) { + continue; + } + ComponentNode *comp_node = id_node->find_component(entry_tag.component_type); + if (comp_node == NULL) { + continue; + } + OperationNode *op_node = comp_node->find_operation( + entry_tag.opcode, entry_tag.name.c_str(), entry_tag.name_tag); + if (op_node == NULL) { + continue; + } + /* Since the tag is coming from a saved copy of entry tags, this means + * that originally node was explicitly tagged for user update. */ + op_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT); + } } void DepsgraphNodeBuilder::build_id(ID *id) { - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_AC: - build_action((bAction *)id); - break; - case ID_AR: - build_armature((bArmature *)id); - break; - case ID_CA: - build_camera((Camera *)id); - break; - case ID_GR: - build_collection(NULL, (Collection *)id); - break; - case ID_OB: - /* TODO(sergey): Get visibility from a "parent" somehow. - * - * NOTE: Using `false` visibility here should be fine, since if this - * driver affects on something invisible we don't really care if the - * driver gets evaluated (and even don't want this to force object - * to become visible). - * - * If this happened to be affecting visible object, then it is up to - * deg_graph_build_flush_visibility() to ensure visibility of the - * object is true. */ - build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false); - break; - case ID_KE: - build_shapekeys((Key *)id); - break; - case ID_LA: - build_light((Light *)id); - break; - case ID_LP: - build_lightprobe((LightProbe *)id); - break; - case ID_NT: - build_nodetree((bNodeTree *)id); - break; - case ID_MA: - build_material((Material *)id); - break; - case ID_TE: - build_texture((Tex *)id); - break; - case ID_IM: - build_image((Image *)id); - break; - case ID_WO: - build_world((World *)id); - break; - case ID_MSK: - build_mask((Mask *)id); - break; - case ID_MC: - build_movieclip((MovieClip *)id); - break; - case ID_ME: - case ID_CU: - case ID_MB: - case ID_LT: - /* TODO(sergey): Get visibility from a "parent" somehow. - * - * NOTE: Similarly to above, we don't want false-positives on - * visibility. */ - build_object_data_geometry_datablock(id, false); - break; - case ID_SPK: - build_speaker((Speaker *)id); - break; - case ID_TXT: - /* Not a part of dependency graph. */ - break; - case ID_CF: - build_cachefile((CacheFile *)id); - break; - default: - fprintf(stderr, "Unhandled ID %s\n", id->name); - BLI_assert(!"Should never happen"); - break; - } + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_AC: + build_action((bAction *)id); + break; + case ID_AR: + build_armature((bArmature *)id); + break; + case ID_CA: + build_camera((Camera *)id); + break; + case ID_GR: + build_collection(NULL, (Collection *)id); + break; + case ID_OB: + /* TODO(sergey): Get visibility from a "parent" somehow. + * + * NOTE: Using `false` visibility here should be fine, since if this + * driver affects on something invisible we don't really care if the + * driver gets evaluated (and even don't want this to force object + * to become visible). + * + * If this happened to be affecting visible object, then it is up to + * deg_graph_build_flush_visibility() to ensure visibility of the + * object is true. */ + build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false); + break; + case ID_KE: + build_shapekeys((Key *)id); + break; + case ID_LA: + build_light((Light *)id); + break; + case ID_LP: + build_lightprobe((LightProbe *)id); + break; + case ID_NT: + build_nodetree((bNodeTree *)id); + break; + case ID_MA: + build_material((Material *)id); + break; + case ID_TE: + build_texture((Tex *)id); + break; + case ID_IM: + build_image((Image *)id); + break; + case ID_WO: + build_world((World *)id); + break; + case ID_MSK: + build_mask((Mask *)id); + break; + case ID_MC: + build_movieclip((MovieClip *)id); + break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + /* TODO(sergey): Get visibility from a "parent" somehow. + * + * NOTE: Similarly to above, we don't want false-positives on + * visibility. */ + build_object_data_geometry_datablock(id, false); + break; + case ID_SPK: + build_speaker((Speaker *)id); + break; + case ID_TXT: + /* Not a part of dependency graph. */ + break; + case ID_CF: + build_cachefile((CacheFile *)id); + break; + default: + fprintf(stderr, "Unhandled ID %s\n", id->name); + BLI_assert(!"Should never happen"); + break; + } } -void DepsgraphNodeBuilder::build_collection( - LayerCollection *from_layer_collection, - Collection *collection) +void DepsgraphNodeBuilder::build_collection(LayerCollection *from_layer_collection, + Collection *collection) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) - ? COLLECTION_RESTRICT_VIEW - : COLLECTION_RESTRICT_RENDER; - const bool is_collection_restricted = (collection->flag & restrict_flag); - const bool is_collection_visible = - !is_collection_restricted && is_parent_collection_visible_; - IDNode *id_node; - if (built_map_.checkIsBuiltAndTag(collection)) { - id_node = find_id_node(&collection->id); - if (is_collection_visible && - id_node->is_directly_visible == false && - id_node->is_collection_fully_expanded == true) - { - /* Collection became visible, make sure nested collections and - * objects are poked with the new visibility flag, since they - * might become visible too. */ - } - else if (from_layer_collection == NULL && - !id_node->is_collection_fully_expanded) - { - /* Initially collection was built from layer now, and was requested - * to not recurs into object. But nw it's asked to recurs into all - * objects. */ - } - else { - return; - } - } - else { - /* Collection itself. */ - id_node = add_id_node(&collection->id); - id_node->is_directly_visible = is_collection_visible; - } - if (from_layer_collection != NULL) { - /* If we came from layer collection we don't go deeper, view layer - * builder takes care of going deeper. */ - return; - } - /* Backup state. */ - Collection *current_state_collection = collection_; - const bool is_current_parent_collection_visible = - is_parent_collection_visible_; - /* Modify state as we've entered new collection/ */ - collection_ = collection; - is_parent_collection_visible_ = is_collection_visible; - /* Build collection objects. */ - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - build_object( - -1, cob->ob, DEG_ID_LINKED_INDIRECTLY, is_collection_visible); - } - /* Build child collections. */ - LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(NULL, child->collection); - } - /* Restore state. */ - collection_ = current_state_collection; - is_parent_collection_visible_ = is_current_parent_collection_visible; - id_node->is_collection_fully_expanded = true; + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + COLLECTION_RESTRICT_RENDER; + const bool is_collection_restricted = (collection->flag & restrict_flag); + const bool is_collection_visible = !is_collection_restricted && is_parent_collection_visible_; + IDNode *id_node; + if (built_map_.checkIsBuiltAndTag(collection)) { + id_node = find_id_node(&collection->id); + if (is_collection_visible && id_node->is_directly_visible == false && + id_node->is_collection_fully_expanded == true) { + /* Collection became visible, make sure nested collections and + * objects are poked with the new visibility flag, since they + * might become visible too. */ + } + else if (from_layer_collection == NULL && !id_node->is_collection_fully_expanded) { + /* Initially collection was built from layer now, and was requested + * to not recurs into object. But nw it's asked to recurs into all + * objects. */ + } + else { + return; + } + } + else { + /* Collection itself. */ + id_node = add_id_node(&collection->id); + id_node->is_directly_visible = is_collection_visible; + } + if (from_layer_collection != NULL) { + /* If we came from layer collection we don't go deeper, view layer + * builder takes care of going deeper. */ + return; + } + /* Backup state. */ + Collection *current_state_collection = collection_; + const bool is_current_parent_collection_visible = is_parent_collection_visible_; + /* Modify state as we've entered new collection/ */ + collection_ = collection; + is_parent_collection_visible_ = is_collection_visible; + /* Build collection objects. */ + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + build_object(-1, cob->ob, DEG_ID_LINKED_INDIRECTLY, is_collection_visible); + } + /* Build child collections. */ + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + build_collection(NULL, child->collection); + } + /* Restore state. */ + collection_ = current_state_collection; + is_parent_collection_visible_ = is_current_parent_collection_visible; + id_node->is_collection_fully_expanded = true; } void DepsgraphNodeBuilder::build_object(int base_index, @@ -544,252 +513,236 @@ void DepsgraphNodeBuilder::build_object(int base_index, eDepsNode_LinkedState_Type linked_state, bool is_visible) { - const bool has_object = built_map_.checkIsBuiltAndTag(object); - /* Skip rest of components if the ID node was already there. */ - if (has_object) { - IDNode *id_node = find_id_node(&object->id); - /* We need to build some extra stuff if object becomes linked - * directly. */ - if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) { - build_object_flags(base_index, object, linked_state); - } - id_node->linked_state = max(id_node->linked_state, linked_state); - if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { - id_node->is_directly_visible |= is_visible; - } - return; - } - /* Create ID node for object and begin init. */ - IDNode *id_node = add_id_node(&object->id); - Object *object_cow = get_cow_datablock(object); - id_node->linked_state = linked_state; - if (object == scene_->camera) { - id_node->is_directly_visible = true; - } - else { - id_node->is_directly_visible = is_visible; - } - /* Various flags, flushing from bases/collections. */ - build_object_flags(base_index, object, linked_state); - /* Transform. */ - build_object_transform(object); - /* Parent. */ - if (object->parent != NULL) { - build_object( - -1, object->parent, DEG_ID_LINKED_INDIRECTLY, is_visible); - } - /* Modifiers. */ - if (object->modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Shader FX. */ - if (object->shader_fx.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); - } - /* Constraints. */ - if (object->constraints.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_visible; - BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); - } - /* Object data. */ - build_object_data(object, is_visible); - /* Paramaters, used by both drivers/animation and also to inform dependency - * from object's data. */ - build_parameters(&object->id); - /* Build animation data, - * - * Do it now because it's possible object data will affect - * on object's level animation, for example in case of rebuilding - * pose for proxy. */ - build_animdata(&object->id); - /* Particle systems. */ - if (object->particlesystem.first != NULL) { - build_particle_systems(object, is_visible); - } - /* Proxy object to copy from. */ - if (object->proxy_from != NULL) { - build_object( - -1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible); - } - if (object->proxy_group != NULL) { - build_object( - -1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible); - } - /* Object dupligroup. */ - if (object->instance_collection != NULL) { - const bool is_current_parent_collection_visible = - is_parent_collection_visible_; - is_parent_collection_visible_ = is_visible; - build_collection(NULL, object->instance_collection); - is_parent_collection_visible_ = is_current_parent_collection_visible; - add_operation_node( - &object->id, NodeType::DUPLI, OperationCode::DUPLI); - } - /* Syncronization back to original object. */ - add_operation_node(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL, - function_bind(BKE_object_synchronize_to_original, - _1, - object_cow)); + const bool has_object = built_map_.checkIsBuiltAndTag(object); + /* Skip rest of components if the ID node was already there. */ + if (has_object) { + IDNode *id_node = find_id_node(&object->id); + /* We need to build some extra stuff if object becomes linked + * directly. */ + if (id_node->linked_state == DEG_ID_LINKED_INDIRECTLY) { + build_object_flags(base_index, object, linked_state); + } + id_node->linked_state = max(id_node->linked_state, linked_state); + if (id_node->linked_state == DEG_ID_LINKED_DIRECTLY) { + id_node->is_directly_visible |= is_visible; + } + return; + } + /* Create ID node for object and begin init. */ + IDNode *id_node = add_id_node(&object->id); + Object *object_cow = get_cow_datablock(object); + id_node->linked_state = linked_state; + if (object == scene_->camera) { + id_node->is_directly_visible = true; + } + else { + id_node->is_directly_visible = is_visible; + } + /* Various flags, flushing from bases/collections. */ + build_object_flags(base_index, object, linked_state); + /* Transform. */ + build_object_transform(object); + /* Parent. */ + if (object->parent != NULL) { + build_object(-1, object->parent, DEG_ID_LINKED_INDIRECTLY, is_visible); + } + /* Modifiers. */ + if (object->modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Shader FX. */ + if (object->shader_fx.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); + } + /* Constraints. */ + if (object->constraints.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_visible; + BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); + } + /* Object data. */ + build_object_data(object, is_visible); + /* Paramaters, used by both drivers/animation and also to inform dependency + * from object's data. */ + build_parameters(&object->id); + /* Build animation data, + * + * Do it now because it's possible object data will affect + * on object's level animation, for example in case of rebuilding + * pose for proxy. */ + build_animdata(&object->id); + /* Particle systems. */ + if (object->particlesystem.first != NULL) { + build_particle_systems(object, is_visible); + } + /* Proxy object to copy from. */ + if (object->proxy_from != NULL) { + build_object(-1, object->proxy_from, DEG_ID_LINKED_INDIRECTLY, is_visible); + } + if (object->proxy_group != NULL) { + build_object(-1, object->proxy_group, DEG_ID_LINKED_INDIRECTLY, is_visible); + } + /* Object dupligroup. */ + if (object->instance_collection != NULL) { + const bool is_current_parent_collection_visible = is_parent_collection_visible_; + is_parent_collection_visible_ = is_visible; + build_collection(NULL, object->instance_collection); + is_parent_collection_visible_ = is_current_parent_collection_visible; + add_operation_node(&object->id, NodeType::DUPLI, OperationCode::DUPLI); + } + /* Syncronization back to original object. */ + add_operation_node(&object->id, + NodeType::SYNCHRONIZATION, + OperationCode::SYNCHRONIZE_TO_ORIGINAL, + function_bind(BKE_object_synchronize_to_original, _1, object_cow)); } -void DepsgraphNodeBuilder::build_object_flags( - int base_index, - Object *object, - eDepsNode_LinkedState_Type linked_state) +void DepsgraphNodeBuilder::build_object_flags(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state) { - if (base_index == -1) { - return; - } - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - const bool is_from_set = (linked_state == DEG_ID_LINKED_VIA_SET); - /* TODO(sergey): Is this really best component to be used? */ - add_operation_node(&object->id, - NodeType::OBJECT_FROM_LAYER, - OperationCode::OBJECT_BASE_FLAGS, - function_bind(BKE_object_eval_eval_base_flags, - _1, - scene_cow, - view_layer_index_, - object_cow, base_index, - is_from_set)); + if (base_index == -1) { + return; + } + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + const bool is_from_set = (linked_state == DEG_ID_LINKED_VIA_SET); + /* TODO(sergey): Is this really best component to be used? */ + add_operation_node(&object->id, + NodeType::OBJECT_FROM_LAYER, + OperationCode::OBJECT_BASE_FLAGS, + function_bind(BKE_object_eval_eval_base_flags, + _1, + scene_cow, + view_layer_index_, + object_cow, + base_index, + is_from_set)); } -void DepsgraphNodeBuilder::build_object_data( - Object *object, bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible) { - if (object->data == NULL) { - return; - } - /* type-specific data. */ - switch (object->type) { - case OB_MESH: - case OB_CURVE: - case OB_FONT: - case OB_SURF: - case OB_MBALL: - case OB_LATTICE: - case OB_GPENCIL: - build_object_data_geometry(object, is_object_visible); - break; - case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { - build_proxy_rig(object); - } - else { - build_rig(object, is_object_visible); - } - break; - case OB_LAMP: - build_object_data_light(object); - break; - case OB_CAMERA: - build_object_data_camera(object); - break; - case OB_LIGHTPROBE: - build_object_data_lightprobe(object); - break; - case OB_SPEAKER: - build_object_data_speaker(object); - break; - default: - { - ID *obdata = (ID *)object->data; - if (built_map_.checkIsBuilt(obdata) == 0) { - build_animdata(obdata); - } - break; - } - } + if (object->data == NULL) { + return; + } + /* type-specific data. */ + switch (object->type) { + case OB_MESH: + case OB_CURVE: + case OB_FONT: + case OB_SURF: + case OB_MBALL: + case OB_LATTICE: + case OB_GPENCIL: + build_object_data_geometry(object, is_object_visible); + break; + case OB_ARMATURE: + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + build_proxy_rig(object); + } + else { + build_rig(object, is_object_visible); + } + break; + case OB_LAMP: + build_object_data_light(object); + break; + case OB_CAMERA: + build_object_data_camera(object); + break; + case OB_LIGHTPROBE: + build_object_data_lightprobe(object); + break; + case OB_SPEAKER: + build_object_data_speaker(object); + break; + default: { + ID *obdata = (ID *)object->data; + if (built_map_.checkIsBuilt(obdata) == 0) { + build_animdata(obdata); + } + break; + } + } } void DepsgraphNodeBuilder::build_object_data_camera(Object *object) { - Camera *camera = (Camera *)object->data; - build_camera(camera); + Camera *camera = (Camera *)object->data; + build_camera(camera); } void DepsgraphNodeBuilder::build_object_data_light(Object *object) { - Light *lamp = (Light *)object->data; - build_light(lamp); + Light *lamp = (Light *)object->data; + build_light(lamp); } void DepsgraphNodeBuilder::build_object_data_lightprobe(Object *object) { - LightProbe *probe = (LightProbe *)object->data; - build_lightprobe(probe); - add_operation_node( - &object->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + LightProbe *probe = (LightProbe *)object->data; + build_lightprobe(probe); + add_operation_node(&object->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); } void DepsgraphNodeBuilder::build_object_data_speaker(Object *object) { - Speaker *speaker = (Speaker *)object->data; - build_speaker(speaker); - add_operation_node( - &object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + Speaker *speaker = (Speaker *)object->data; + build_speaker(speaker); + add_operation_node(&object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); } void DepsgraphNodeBuilder::build_object_transform(Object *object) { - OperationNode *op_node; - Object *ob_cow = get_cow_datablock(object); - /* Transform entry operation. */ - op_node = add_operation_node( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); - op_node->set_as_entry(); - /* Local transforms (from transform channels - loc/rot/scale + deltas). */ - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_LOCAL, - function_bind(BKE_object_eval_local_transform, - _1, - ob_cow)); - /* Object parent. */ - if (object->parent != NULL) { - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_PARENT, - function_bind(BKE_object_eval_parent, _1, ob_cow)); - } - /* Object constraints. */ - if (object->constraints.first != NULL) { - build_object_constraints(object); - } - /* Rest of transformation update. */ - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL, - function_bind(BKE_object_eval_uber_transform, - _1, - ob_cow)); - /* Operation to take of rigid body simulation. soft bodies and other firends - * in the context of point cache invalidation. */ - add_operation_node(&object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - /* Object transform is done. */ - op_node = add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL, - function_bind(BKE_object_eval_transform_final, - _1, - ob_cow)); - op_node->set_as_exit(); + OperationNode *op_node; + Object *ob_cow = get_cow_datablock(object); + /* Transform entry operation. */ + op_node = add_operation_node(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); + op_node->set_as_entry(); + /* Local transforms (from transform channels - loc/rot/scale + deltas). */ + add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_LOCAL, + function_bind(BKE_object_eval_local_transform, _1, ob_cow)); + /* Object parent. */ + if (object->parent != NULL) { + add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_PARENT, + function_bind(BKE_object_eval_parent, _1, ob_cow)); + } + /* Object constraints. */ + if (object->constraints.first != NULL) { + build_object_constraints(object); + } + /* Rest of transformation update. */ + add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_EVAL, + function_bind(BKE_object_eval_uber_transform, _1, ob_cow)); + /* Operation to take of rigid body simulation. soft bodies and other firends + * in the context of point cache invalidation. */ + add_operation_node(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + /* Object transform is done. */ + op_node = add_operation_node(&object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_FINAL, + function_bind(BKE_object_eval_transform_final, _1, ob_cow)); + op_node->set_as_exit(); } /** @@ -811,29 +764,26 @@ void DepsgraphNodeBuilder::build_object_transform(Object *object) */ void DepsgraphNodeBuilder::build_object_constraints(Object *object) { - /* create node for constraint stack */ - add_operation_node(&object->id, NodeType::TRANSFORM, - OperationCode::TRANSFORM_CONSTRAINTS, - function_bind(BKE_object_eval_constraints, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object))); + /* create node for constraint stack */ + add_operation_node( + &object->id, + NodeType::TRANSFORM, + OperationCode::TRANSFORM_CONSTRAINTS, + function_bind( + BKE_object_eval_constraints, _1, get_cow_datablock(scene_), get_cow_datablock(object))); } void DepsgraphNodeBuilder::build_object_pointcache(Object *object) { - if (!BKE_ptcache_object_has(scene_, object, 0)) { - return; - } - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - add_operation_node(&object->id, - NodeType::POINT_CACHE, - OperationCode::POINT_CACHE_RESET, - function_bind(BKE_object_eval_ptcache_reset, - _1, - scene_cow, - object_cow)); + if (!BKE_ptcache_object_has(scene_, object, 0)) { + return; + } + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + add_operation_node(&object->id, + NodeType::POINT_CACHE, + OperationCode::POINT_CACHE_RESET, + function_bind(BKE_object_eval_ptcache_reset, _1, scene_cow, object_cow)); } /** @@ -842,58 +792,55 @@ void DepsgraphNodeBuilder::build_object_pointcache(Object *object) */ void DepsgraphNodeBuilder::build_animdata(ID *id) { - /* Special handling for animated images/sequences. */ - build_animation_images(id); - /* Regular animation. */ - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return; - } - if (adt->action != NULL) { - build_action(adt->action); - } - /* Make sure ID node exists. */ - (void) add_id_node(id); - ID *id_cow = get_cow_id(id); - if (adt->action != NULL || !BLI_listbase_is_empty(&adt->nla_tracks)) { - OperationNode *operation_node; - /* Explicit entry operation. */ - operation_node = add_operation_node( - id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); - operation_node->set_as_entry(); - /* All the evaluation nodes. */ - add_operation_node( - id, - NodeType::ANIMATION, - OperationCode::ANIMATION_EVAL, - function_bind(BKE_animsys_eval_animdata, _1, id_cow)); - /* Explicit exit operation. */ - operation_node = add_operation_node( - id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); - operation_node->set_as_exit(); - } - /* NLA strips contain actions. */ - LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) { - build_animdata_nlastrip_targets(&nlt->strips); - } - /* Drivers. */ - int driver_index = 0; - LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - /* create driver */ - build_driver(id, fcu, driver_index++); - } + /* Special handling for animated images/sequences. */ + build_animation_images(id); + /* Regular animation. */ + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return; + } + if (adt->action != NULL) { + build_action(adt->action); + } + /* Make sure ID node exists. */ + (void)add_id_node(id); + ID *id_cow = get_cow_id(id); + if (adt->action != NULL || !BLI_listbase_is_empty(&adt->nla_tracks)) { + OperationNode *operation_node; + /* Explicit entry operation. */ + operation_node = add_operation_node(id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); + operation_node->set_as_entry(); + /* All the evaluation nodes. */ + add_operation_node(id, + NodeType::ANIMATION, + OperationCode::ANIMATION_EVAL, + function_bind(BKE_animsys_eval_animdata, _1, id_cow)); + /* Explicit exit operation. */ + operation_node = add_operation_node(id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); + operation_node->set_as_exit(); + } + /* NLA strips contain actions. */ + LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) { + build_animdata_nlastrip_targets(&nlt->strips); + } + /* Drivers. */ + int driver_index = 0; + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + /* create driver */ + build_driver(id, fcu, driver_index++); + } } void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips) { - LISTBASE_FOREACH (NlaStrip *, strip, strips) { - if (strip->act != NULL) { - build_action(strip->act); - } - else if (strip->strips.first != NULL) { - build_animdata_nlastrip_targets(&strip->strips); - } - } + LISTBASE_FOREACH (NlaStrip *, strip, strips) { + if (strip->act != NULL) { + build_action(strip->act); + } + else if (strip->strips.first != NULL) { + build_animdata_nlastrip_targets(&strip->strips); + } + } } /** @@ -901,22 +848,21 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips) */ void DepsgraphNodeBuilder::build_animation_images(ID *id) { - if (BKE_image_user_id_has_animation(id)) { - ID *id_cow = get_cow_id(id); - add_operation_node(id, - NodeType::ANIMATION, - OperationCode::IMAGE_ANIMATION, - function_bind(BKE_image_user_id_eval_animation, _1, id_cow)); - } + if (BKE_image_user_id_has_animation(id)) { + ID *id_cow = get_cow_id(id); + add_operation_node(id, + NodeType::ANIMATION, + OperationCode::IMAGE_ANIMATION, + function_bind(BKE_image_user_id_eval_animation, _1, id_cow)); + } } void DepsgraphNodeBuilder::build_action(bAction *action) { - if (built_map_.checkIsBuiltAndTag(action)) { - return; - } - add_operation_node( - &action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); + if (built_map_.checkIsBuiltAndTag(action)) { + return; + } + add_operation_node(&action->id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); } /** @@ -927,754 +873,675 @@ void DepsgraphNodeBuilder::build_action(bAction *action) */ void DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcurve, int driver_index) { - /* Create data node for this driver */ - ID *id_cow = get_cow_id(id); - ChannelDriver *driver_orig = fcurve->driver; - - /* TODO(sergey): ideally we could pass the COW of fcu, but since it - * has not yet been allocated at this point we can't. As a workaround - * the animation systems allocates an array so we can do a fast lookup - * with the driver index. */ - ensure_operation_node(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig), - fcurve->rna_path ? fcurve->rna_path : "", - fcurve->array_index); - build_driver_variables(id, fcurve); + /* Create data node for this driver */ + ID *id_cow = get_cow_id(id); + ChannelDriver *driver_orig = fcurve->driver; + + /* TODO(sergey): ideally we could pass the COW of fcu, but since it + * has not yet been allocated at this point we can't. As a workaround + * the animation systems allocates an array so we can do a fast lookup + * with the driver index. */ + ensure_operation_node( + id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + function_bind(BKE_animsys_eval_driver, _1, id_cow, driver_index, driver_orig), + fcurve->rna_path ? fcurve->rna_path : "", + fcurve->array_index); + build_driver_variables(id, fcurve); } -void DepsgraphNodeBuilder::build_driver_variables(ID * id, FCurve *fcurve) +void DepsgraphNodeBuilder::build_driver_variables(ID *id, FCurve *fcurve) { - build_driver_id_property(id, fcurve->rna_path); - LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) { - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - if (dtar->id == NULL) { - continue; - } - build_id(dtar->id); - build_driver_id_property(dtar->id, dtar->rna_path); - /* Corresponds to dtar_id_ensure_proxy_from(). */ - if ((GS(dtar->id->name) == ID_OB) && - (((Object *)dtar->id)->proxy_from != NULL)) - { - Object *proxy_from = ((Object *)dtar->id)->proxy_from; - build_id(&proxy_from->id); - build_driver_id_property(&proxy_from->id, dtar->rna_path); - } - } - DRIVER_TARGETS_LOOPER_END; - } + build_driver_id_property(id, fcurve->rna_path); + LISTBASE_FOREACH (DriverVar *, dvar, &fcurve->driver->variables) { + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (dtar->id == NULL) { + continue; + } + build_id(dtar->id); + build_driver_id_property(dtar->id, dtar->rna_path); + /* Corresponds to dtar_id_ensure_proxy_from(). */ + if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != NULL)) { + Object *proxy_from = ((Object *)dtar->id)->proxy_from; + build_id(&proxy_from->id); + build_driver_id_property(&proxy_from->id, dtar->rna_path); + } + } + DRIVER_TARGETS_LOOPER_END; + } } -void DepsgraphNodeBuilder::build_driver_id_property(ID *id, - const char *rna_path) +void DepsgraphNodeBuilder::build_driver_id_property(ID *id, const char *rna_path) { - if (id == NULL || rna_path == NULL) { - return; - } - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - RNA_id_pointer_create(id, &id_ptr); - if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { - return; - } - if (prop == NULL) { - return; - } - if (!RNA_property_is_idprop(prop)) { - return; - } - const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); - ensure_operation_node(id, - NodeType::PARAMETERS, - OperationCode::ID_PROPERTY, - NULL, - prop_identifier); + if (id == NULL || rna_path == NULL) { + return; + } + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + RNA_id_pointer_create(id, &id_ptr); + if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { + return; + } + if (prop == NULL) { + return; + } + if (!RNA_property_is_idprop(prop)) { + return; + } + const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); + ensure_operation_node( + id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, NULL, prop_identifier); } void DepsgraphNodeBuilder::build_parameters(ID *id) { - (void) add_id_node(id); - OperationNode *op_node; - /* Explicit entry. */ - op_node = add_operation_node( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); - op_node->set_as_entry(); - /* Generic evaluation node. */ - add_operation_node( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); - /* Explicit exit operation. */ - op_node = add_operation_node( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); - op_node->set_as_exit(); + (void)add_id_node(id); + OperationNode *op_node; + /* Explicit entry. */ + op_node = add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); + op_node->set_as_entry(); + /* Generic evaluation node. */ + add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + /* Explicit exit operation. */ + op_node = add_operation_node(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); + op_node->set_as_exit(); } /* Recursively build graph for world */ void DepsgraphNodeBuilder::build_world(World *world) { - if (built_map_.checkIsBuiltAndTag(world)) { - return; - } - /* World itself. */ - add_id_node(&world->id); - World *world_cow = get_cow_datablock(world); - /* Shading update. */ - add_operation_node(&world->id, - NodeType::SHADING, - OperationCode::WORLD_UPDATE, - function_bind(BKE_world_eval, _1, world_cow)); - /* Animation. */ - build_animdata(&world->id); - build_parameters(&world->id); - /* World's nodetree. */ - build_nodetree(world->nodetree); + if (built_map_.checkIsBuiltAndTag(world)) { + return; + } + /* World itself. */ + add_id_node(&world->id); + World *world_cow = get_cow_datablock(world); + /* Shading update. */ + add_operation_node(&world->id, + NodeType::SHADING, + OperationCode::WORLD_UPDATE, + function_bind(BKE_world_eval, _1, world_cow)); + /* Animation. */ + build_animdata(&world->id); + build_parameters(&world->id); + /* World's nodetree. */ + build_nodetree(world->nodetree); } /* Rigidbody Simulation - Scene Level */ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) { - RigidBodyWorld *rbw = scene->rigidbody_world; - Scene *scene_cow = get_cow_datablock(scene); - - /** - * Rigidbody Simulation Nodes - * ========================== - * - * There are 3 nodes related to Rigidbody Simulation: - * 1) "Initialize/Rebuild World" - this is called sparingly, only when the - * simulation needs to be rebuilt (mainly after file reload, or moving - * back to start frame) - * 2) "Do Simulation" - perform a simulation step - interleaved between the - * evaluation steps for clusters of objects (i.e. between those affected - * and/or not affected by the sim for instance). - * - * 3) "Pull Results" - grab the specific transforms applied for a specific - * object - performed as part of object's transform-stack building. */ - - /* Create nodes --------------------------------------------------------- */ - - /* XXX: is this the right component, or do we want to use another one - * instead? */ - - /* Init/rebuild operation. */ - add_operation_node(&scene->id, NodeType::TRANSFORM, - OperationCode::RIGIDBODY_REBUILD, - function_bind(BKE_rigidbody_rebuild_sim, _1, scene_cow)); - /* Do-sim operation. */ - OperationNode *sim_node = add_operation_node( - &scene->id, NodeType::TRANSFORM, - OperationCode::RIGIDBODY_SIM, - function_bind(BKE_rigidbody_eval_simulation, _1, scene_cow)); - sim_node->set_as_entry(); - sim_node->set_as_exit(); - sim_node->owner->entry_operation = sim_node; - /* Objects - simulation participants. */ - if (rbw->group != NULL) { - build_collection(NULL, rbw->group); - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - if (object->type != OB_MESH) { - continue; - } - /* Create operation for flushing results. */ - /* Object's transform component - where the rigidbody operation - * lives. */ - add_operation_node(&object->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY, - function_bind( - BKE_rigidbody_object_sync_transforms, - _1, - scene_cow, - get_cow_datablock(object))); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - /* Constraints. */ - if (rbw->constraints != NULL) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) - { - RigidBodyCon *rbc = object->rigidbody_constraint; - if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { - /* When either ob1 or ob2 is NULL, the constraint doesn't work. */ - continue; - } - /* Make sure indirectly linked objects are fully built. */ - build_object(-1, object, DEG_ID_LINKED_INDIRECTLY, false); - build_object(-1, rbc->ob1, DEG_ID_LINKED_INDIRECTLY, false); - build_object(-1, rbc->ob2, DEG_ID_LINKED_INDIRECTLY, false); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } + RigidBodyWorld *rbw = scene->rigidbody_world; + Scene *scene_cow = get_cow_datablock(scene); + + /** + * Rigidbody Simulation Nodes + * ========================== + * + * There are 3 nodes related to Rigidbody Simulation: + * 1) "Initialize/Rebuild World" - this is called sparingly, only when the + * simulation needs to be rebuilt (mainly after file reload, or moving + * back to start frame) + * 2) "Do Simulation" - perform a simulation step - interleaved between the + * evaluation steps for clusters of objects (i.e. between those affected + * and/or not affected by the sim for instance). + * + * 3) "Pull Results" - grab the specific transforms applied for a specific + * object - performed as part of object's transform-stack building. */ + + /* Create nodes --------------------------------------------------------- */ + + /* XXX: is this the right component, or do we want to use another one + * instead? */ + + /* Init/rebuild operation. */ + add_operation_node(&scene->id, + NodeType::TRANSFORM, + OperationCode::RIGIDBODY_REBUILD, + function_bind(BKE_rigidbody_rebuild_sim, _1, scene_cow)); + /* Do-sim operation. */ + OperationNode *sim_node = add_operation_node( + &scene->id, + NodeType::TRANSFORM, + OperationCode::RIGIDBODY_SIM, + function_bind(BKE_rigidbody_eval_simulation, _1, scene_cow)); + sim_node->set_as_entry(); + sim_node->set_as_exit(); + sim_node->owner->entry_operation = sim_node; + /* Objects - simulation participants. */ + if (rbw->group != NULL) { + build_collection(NULL, rbw->group); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + if (object->type != OB_MESH) { + continue; + } + /* Create operation for flushing results. */ + /* Object's transform component - where the rigidbody operation + * lives. */ + add_operation_node( + &object->id, + NodeType::TRANSFORM, + OperationCode::RIGIDBODY_TRANSFORM_COPY, + function_bind( + BKE_rigidbody_object_sync_transforms, _1, scene_cow, get_cow_datablock(object))); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + /* Constraints. */ + if (rbw->constraints != NULL) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { + RigidBodyCon *rbc = object->rigidbody_constraint; + if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { + /* When either ob1 or ob2 is NULL, the constraint doesn't work. */ + continue; + } + /* Make sure indirectly linked objects are fully built. */ + build_object(-1, object, DEG_ID_LINKED_INDIRECTLY, false); + build_object(-1, rbc->ob1, DEG_ID_LINKED_INDIRECTLY, false); + build_object(-1, rbc->ob2, DEG_ID_LINKED_INDIRECTLY, false); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } } -void DepsgraphNodeBuilder::build_particle_systems(Object *object, - bool is_object_visible) +void DepsgraphNodeBuilder::build_particle_systems(Object *object, bool is_object_visible) { - /** - * Particle Systems Nodes - * ====================== - * - * There are two types of nodes associated with representing - * particle systems: - * 1) Component (EVAL_PARTICLES) - This is the particle-system - * evaluation context for an object. It acts as the container - * for all the nodes associated with a particular set of particle - * systems. - * 2) Particle System Eval Operation - This operation node acts as a - * blackbox evaluation step for one particle system referenced by - * the particle systems stack. All dependencies link to this operation. */ - /* Component for all particle systems. */ - ComponentNode *psys_comp = - add_component_node(&object->id, NodeType::PARTICLE_SYSTEM); - - Object *ob_cow = get_cow_datablock(object); - OperationNode *op_node; - op_node = add_operation_node(psys_comp, - OperationCode::PARTICLE_SYSTEM_INIT, - function_bind(BKE_particle_system_eval_init, - _1, - ob_cow)); - op_node->set_as_entry(); - /* Build all particle systems. */ - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - ParticleSettings *part = psys->part; - /* Build particle settings operations. - * - * NOTE: The call itself ensures settings are only build once. */ - build_particle_settings(part); - /* Particle system evaluation. */ - add_operation_node(psys_comp, - OperationCode::PARTICLE_SYSTEM_EVAL, - NULL, - psys->name); - /* Keyed particle targets. */ - if (part->phystype == PART_PHYS_KEYED) { - LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { - if (particle_target->ob == NULL || - particle_target->ob == object) - { - continue; - } - build_object(-1, - particle_target->ob, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - } - /* Visualization of particle system. */ - switch (part->ren_as) { - case PART_DRAW_OB: - if (part->instance_object != NULL) { - build_object(-1, - part->instance_object, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - break; - case PART_DRAW_GR: - if (part->instance_collection != NULL) { - build_collection(NULL, part->instance_collection); - } - break; - } - } - op_node = add_operation_node( - psys_comp, OperationCode::PARTICLE_SYSTEM_DONE); - op_node->set_as_exit(); + /** + * Particle Systems Nodes + * ====================== + * + * There are two types of nodes associated with representing + * particle systems: + * 1) Component (EVAL_PARTICLES) - This is the particle-system + * evaluation context for an object. It acts as the container + * for all the nodes associated with a particular set of particle + * systems. + * 2) Particle System Eval Operation - This operation node acts as a + * blackbox evaluation step for one particle system referenced by + * the particle systems stack. All dependencies link to this operation. */ + /* Component for all particle systems. */ + ComponentNode *psys_comp = add_component_node(&object->id, NodeType::PARTICLE_SYSTEM); + + Object *ob_cow = get_cow_datablock(object); + OperationNode *op_node; + op_node = add_operation_node(psys_comp, + OperationCode::PARTICLE_SYSTEM_INIT, + function_bind(BKE_particle_system_eval_init, _1, ob_cow)); + op_node->set_as_entry(); + /* Build all particle systems. */ + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + ParticleSettings *part = psys->part; + /* Build particle settings operations. + * + * NOTE: The call itself ensures settings are only build once. */ + build_particle_settings(part); + /* Particle system evaluation. */ + add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_EVAL, NULL, psys->name); + /* Keyed particle targets. */ + if (part->phystype == PART_PHYS_KEYED) { + LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { + if (particle_target->ob == NULL || particle_target->ob == object) { + continue; + } + build_object(-1, particle_target->ob, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + } + /* Visualization of particle system. */ + switch (part->ren_as) { + case PART_DRAW_OB: + if (part->instance_object != NULL) { + build_object(-1, part->instance_object, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + break; + case PART_DRAW_GR: + if (part->instance_collection != NULL) { + build_collection(NULL, part->instance_collection); + } + break; + } + } + op_node = add_operation_node(psys_comp, OperationCode::PARTICLE_SYSTEM_DONE); + op_node->set_as_exit(); } -void DepsgraphNodeBuilder::build_particle_settings( - ParticleSettings *particle_settings) { - if (built_map_.checkIsBuiltAndTag(particle_settings)) { - return; - } - /* Make sure we've got proper copied ID pointer. */ - add_id_node(&particle_settings->id); - ParticleSettings *particle_settings_cow = - get_cow_datablock(particle_settings); - /* Animation data. */ - build_animdata(&particle_settings->id); - build_parameters(&particle_settings->id); - /* Parameters change. */ - OperationNode *op_node; - op_node = add_operation_node(&particle_settings->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_INIT); - op_node->set_as_entry(); - add_operation_node(&particle_settings->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_RESET, - function_bind(BKE_particle_settings_eval_reset, - _1, - particle_settings_cow)); - op_node = add_operation_node(&particle_settings->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_EVAL); - op_node->set_as_exit(); - /* Texture slots. */ - for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { - MTex *mtex = particle_settings->mtex[mtex_index]; - if (mtex == NULL || mtex->tex == NULL) { - continue; - } - build_texture(mtex->tex); - } +void DepsgraphNodeBuilder::build_particle_settings(ParticleSettings *particle_settings) +{ + if (built_map_.checkIsBuiltAndTag(particle_settings)) { + return; + } + /* Make sure we've got proper copied ID pointer. */ + add_id_node(&particle_settings->id); + ParticleSettings *particle_settings_cow = get_cow_datablock(particle_settings); + /* Animation data. */ + build_animdata(&particle_settings->id); + build_parameters(&particle_settings->id); + /* Parameters change. */ + OperationNode *op_node; + op_node = add_operation_node( + &particle_settings->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_INIT); + op_node->set_as_entry(); + add_operation_node(&particle_settings->id, + NodeType::PARTICLE_SETTINGS, + OperationCode::PARTICLE_SETTINGS_RESET, + function_bind(BKE_particle_settings_eval_reset, _1, particle_settings_cow)); + op_node = add_operation_node( + &particle_settings->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL); + op_node->set_as_exit(); + /* Texture slots. */ + for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { + MTex *mtex = particle_settings->mtex[mtex_index]; + if (mtex == NULL || mtex->tex == NULL) { + continue; + } + build_texture(mtex->tex); + } } /* Shapekeys */ void DepsgraphNodeBuilder::build_shapekeys(Key *key) { - if (built_map_.checkIsBuiltAndTag(key)) { - return; - } - build_animdata(&key->id); - build_parameters(&key->id); - /* This is an exit operation for the entire key datablock, is what is used - * as dependency for modifiers evaluation. */ - add_operation_node( - &key->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_SHAPEKEY); - /* Create per-key block properties, allowing tricky inter-dependnecies for - * drivers evaluation. */ - LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { - add_operation_node(&key->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - NULL, - key_block->name); - } + if (built_map_.checkIsBuiltAndTag(key)) { + return; + } + build_animdata(&key->id); + build_parameters(&key->id); + /* This is an exit operation for the entire key datablock, is what is used + * as dependency for modifiers evaluation. */ + add_operation_node(&key->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_SHAPEKEY); + /* Create per-key block properties, allowing tricky inter-dependnecies for + * drivers evaluation. */ + LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { + add_operation_node( + &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, key_block->name); + } } /* ObData Geometry Evaluation */ // XXX: what happens if the datablock is shared! -void DepsgraphNodeBuilder::build_object_data_geometry( - Object *object, - bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_object_visible) { - OperationNode *op_node; - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - /* Entry operation, takes care of initialization, and some other - * relations which needs to be run prior actual geometry evaluation. */ - op_node = add_operation_node( - &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); - op_node->set_as_entry(); - /* Geometry evaluation. */ - op_node = add_operation_node(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_object_eval_uber_data, - _1, - scene_cow, - object_cow)); - op_node->set_as_exit(); - /* Materials. */ - if (object->totcol != 0) { - if (object->type == OB_MESH) { - add_operation_node(&object->id, - NodeType::SHADING, - OperationCode::SHADING, - function_bind(BKE_object_eval_update_shading, - _1, - object_cow)); - } - for (int a = 1; a <= object->totcol; a++) { - Material *ma = give_current_material(object, a); - if (ma != NULL) { - build_material(ma); - } - } - } - /* Point caches. */ - build_object_pointcache(object); - /* Geometry. */ - build_object_data_geometry_datablock((ID *)object->data, is_object_visible); + OperationNode *op_node; + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + /* Entry operation, takes care of initialization, and some other + * relations which needs to be run prior actual geometry evaluation. */ + op_node = add_operation_node(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + op_node->set_as_entry(); + /* Geometry evaluation. */ + op_node = add_operation_node( + &object->id, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_object_eval_uber_data, _1, scene_cow, object_cow)); + op_node->set_as_exit(); + /* Materials. */ + if (object->totcol != 0) { + if (object->type == OB_MESH) { + add_operation_node(&object->id, + NodeType::SHADING, + OperationCode::SHADING, + function_bind(BKE_object_eval_update_shading, _1, object_cow)); + } + for (int a = 1; a <= object->totcol; a++) { + Material *ma = give_current_material(object, a); + if (ma != NULL) { + build_material(ma); + } + } + } + /* Point caches. */ + build_object_pointcache(object); + /* Geometry. */ + build_object_data_geometry_datablock((ID *)object->data, is_object_visible); } -void DepsgraphNodeBuilder::build_object_data_geometry_datablock( - ID *obdata, - bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool is_object_visible) { - if (built_map_.checkIsBuiltAndTag(obdata)) { - return; - } - OperationNode *op_node; - /* Make sure we've got an ID node before requesting CoW pointer. */ - (void) add_id_node((ID *)obdata); - ID *obdata_cow = get_cow_id(obdata); - /* Animation. */ - build_animdata(obdata); - /* ShapeKeys */ - Key *key = BKE_key_from_id(obdata); - if (key) { - build_shapekeys(key); - } - /* Nodes for result of obdata's evaluation, and geometry - * evaluation on object. */ - const ID_Type id_type = GS(obdata->name); - switch (id_type) { - case ID_ME: - { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_mesh_eval_geometry, - _1, - (Mesh *)obdata_cow)); - op_node->set_as_entry(); - break; - } - case ID_MB: - { - op_node = add_operation_node( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - op_node->set_as_entry(); - break; - } - case ID_CU: - { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_curve_eval_geometry, - _1, - (Curve *)obdata_cow)); - op_node->set_as_entry(); - /* Make sure objects used for bevel.taper are in the graph. - * NOTE: This objects might be not linked to the scene. */ - Curve *cu = (Curve *)obdata; - if (cu->bevobj != NULL) { - build_object(-1, - cu->bevobj, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - if (cu->taperobj != NULL) { - build_object(-1, - cu->taperobj, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - if (cu->textoncurve != NULL) { - build_object(-1, - cu->textoncurve, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - break; - } - case ID_LT: - { - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_lattice_eval_geometry, - _1, - (Lattice *)obdata_cow)); - op_node->set_as_entry(); - break; - } - - case ID_GD: - { - /* GPencil evaluation operations. */ - op_node = add_operation_node(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL, - function_bind(BKE_gpencil_eval_geometry, - _1, - (bGPdata *)obdata_cow)); - op_node->set_as_entry(); - break; - } - default: - BLI_assert(!"Should not happen"); - break; - } - op_node = add_operation_node( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); - op_node->set_as_exit(); - /* Parameters for driver sources. */ - build_parameters(obdata); - /* Batch cache. */ - add_operation_node(obdata, - NodeType::BATCH_CACHE, - OperationCode::GEOMETRY_SELECT_UPDATE, - function_bind(BKE_object_data_select_update, - _1, - obdata_cow)); + if (built_map_.checkIsBuiltAndTag(obdata)) { + return; + } + OperationNode *op_node; + /* Make sure we've got an ID node before requesting CoW pointer. */ + (void)add_id_node((ID *)obdata); + ID *obdata_cow = get_cow_id(obdata); + /* Animation. */ + build_animdata(obdata); + /* ShapeKeys */ + Key *key = BKE_key_from_id(obdata); + if (key) { + build_shapekeys(key); + } + /* Nodes for result of obdata's evaluation, and geometry + * evaluation on object. */ + const ID_Type id_type = GS(obdata->name); + switch (id_type) { + case ID_ME: { + op_node = add_operation_node(obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata_cow)); + op_node->set_as_entry(); + break; + } + case ID_MB: { + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + op_node->set_as_entry(); + break; + } + case ID_CU: { + op_node = add_operation_node( + obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata_cow)); + op_node->set_as_entry(); + /* Make sure objects used for bevel.taper are in the graph. + * NOTE: This objects might be not linked to the scene. */ + Curve *cu = (Curve *)obdata; + if (cu->bevobj != NULL) { + build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + if (cu->taperobj != NULL) { + build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + if (cu->textoncurve != NULL) { + build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + break; + } + case ID_LT: { + op_node = add_operation_node( + obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata_cow)); + op_node->set_as_entry(); + break; + } + + case ID_GD: { + /* GPencil evaluation operations. */ + op_node = add_operation_node( + obdata, + NodeType::GEOMETRY, + OperationCode::GEOMETRY_EVAL, + function_bind(BKE_gpencil_eval_geometry, _1, (bGPdata *)obdata_cow)); + op_node->set_as_entry(); + break; + } + default: + BLI_assert(!"Should not happen"); + break; + } + op_node = add_operation_node(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); + op_node->set_as_exit(); + /* Parameters for driver sources. */ + build_parameters(obdata); + /* Batch cache. */ + add_operation_node(obdata, + NodeType::BATCH_CACHE, + OperationCode::GEOMETRY_SELECT_UPDATE, + function_bind(BKE_object_data_select_update, _1, obdata_cow)); } void DepsgraphNodeBuilder::build_armature(bArmature *armature) { - if (built_map_.checkIsBuiltAndTag(armature)) { - return; - } - build_animdata(&armature->id); - build_parameters(&armature->id); - /* Make sure pose is up-to-date with armature updates. */ - add_operation_node( - &armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL); + if (built_map_.checkIsBuiltAndTag(armature)) { + return; + } + build_animdata(&armature->id); + build_parameters(&armature->id); + /* Make sure pose is up-to-date with armature updates. */ + add_operation_node(&armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL); } void DepsgraphNodeBuilder::build_camera(Camera *camera) { - if (built_map_.checkIsBuiltAndTag(camera)) { - return; - } - build_animdata(&camera->id); - build_parameters(&camera->id); + if (built_map_.checkIsBuiltAndTag(camera)) { + return; + } + build_animdata(&camera->id); + build_parameters(&camera->id); } void DepsgraphNodeBuilder::build_light(Light *lamp) { - if (built_map_.checkIsBuiltAndTag(lamp)) { - return; - } - build_animdata(&lamp->id); - build_parameters(&lamp->id); - /* light's nodetree */ - build_nodetree(lamp->nodetree); + if (built_map_.checkIsBuiltAndTag(lamp)) { + return; + } + build_animdata(&lamp->id); + build_parameters(&lamp->id); + /* light's nodetree */ + build_nodetree(lamp->nodetree); } void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) { - if (ntree == NULL) { - return; - } - if (built_map_.checkIsBuiltAndTag(ntree)) { - return; - } - /* nodetree itself */ - add_id_node(&ntree->id); - bNodeTree *ntree_cow = get_cow_datablock(ntree); - /* General parameters. */ - build_parameters(&ntree->id); - /* Animation, */ - build_animdata(&ntree->id); - /* Shading update. */ - add_operation_node( - &ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); - /* NOTE: We really pass original and CoW node trees here, this is how the - * callback works. Ideally we need to find a better way for that. */ - add_operation_node(&ntree->id, - NodeType::SHADING_PARAMETERS, - OperationCode::MATERIAL_UPDATE, - function_bind(BKE_nodetree_shading_params_eval, - _1, - ntree_cow, - ntree)); - /* nodetree's nodes... */ - LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { - ID *id = bnode->id; - if (id == NULL) { - continue; - } - ID_Type id_type = GS(id->name); - if (id_type == ID_MA) { - build_material((Material *)id); - } - else if (id_type == ID_TE) { - build_texture((Tex *)id); - } - else if (id_type == ID_IM) { - build_image((Image *)id); - } - else if (id_type == ID_OB) { - /* TODO(sergey): Use visibility of owner of the node tree. */ - build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, true); - } - else if (id_type == ID_SCE) { - /* Scenes are used by compositor trees, and handled by render - * pipeline. No need to build dependencies for them here. */ - } - else if (id_type == ID_TXT) { - /* Ignore script nodes. */ - } - else if (id_type == ID_MSK) { - build_mask((Mask *)id); - } - else if (id_type == ID_MC) { - build_movieclip((MovieClip *)id); - } - else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - bNodeTree *group_ntree = (bNodeTree *)id; - build_nodetree(group_ntree); - } - else { - BLI_assert(!"Unknown ID type used for node"); - } - } - - // TODO: link from nodetree to owner_component? + if (ntree == NULL) { + return; + } + if (built_map_.checkIsBuiltAndTag(ntree)) { + return; + } + /* nodetree itself */ + add_id_node(&ntree->id); + bNodeTree *ntree_cow = get_cow_datablock(ntree); + /* General parameters. */ + build_parameters(&ntree->id); + /* Animation, */ + build_animdata(&ntree->id); + /* Shading update. */ + add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + /* NOTE: We really pass original and CoW node trees here, this is how the + * callback works. Ideally we need to find a better way for that. */ + add_operation_node(&ntree->id, + NodeType::SHADING_PARAMETERS, + OperationCode::MATERIAL_UPDATE, + function_bind(BKE_nodetree_shading_params_eval, _1, ntree_cow, ntree)); + /* nodetree's nodes... */ + LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { + ID *id = bnode->id; + if (id == NULL) { + continue; + } + ID_Type id_type = GS(id->name); + if (id_type == ID_MA) { + build_material((Material *)id); + } + else if (id_type == ID_TE) { + build_texture((Tex *)id); + } + else if (id_type == ID_IM) { + build_image((Image *)id); + } + else if (id_type == ID_OB) { + /* TODO(sergey): Use visibility of owner of the node tree. */ + build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, true); + } + else if (id_type == ID_SCE) { + /* Scenes are used by compositor trees, and handled by render + * pipeline. No need to build dependencies for them here. */ + } + else if (id_type == ID_TXT) { + /* Ignore script nodes. */ + } + else if (id_type == ID_MSK) { + build_mask((Mask *)id); + } + else if (id_type == ID_MC) { + build_movieclip((MovieClip *)id); + } + else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { + bNodeTree *group_ntree = (bNodeTree *)id; + build_nodetree(group_ntree); + } + else { + BLI_assert(!"Unknown ID type used for node"); + } + } + + // TODO: link from nodetree to owner_component? } /* Recursively build graph for material */ void DepsgraphNodeBuilder::build_material(Material *material) { - if (built_map_.checkIsBuiltAndTag(material)) { - return; - } - /* Material itself. */ - add_id_node(&material->id); - Material *material_cow = get_cow_datablock(material); - /* Shading update. */ - add_operation_node(&material->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE, - function_bind(BKE_material_eval, - _1, - material_cow)); - /* Material animation. */ - build_animdata(&material->id); - build_parameters(&material->id); - /* Material's nodetree. */ - build_nodetree(material->nodetree); + if (built_map_.checkIsBuiltAndTag(material)) { + return; + } + /* Material itself. */ + add_id_node(&material->id); + Material *material_cow = get_cow_datablock(material); + /* Shading update. */ + add_operation_node(&material->id, + NodeType::SHADING, + OperationCode::MATERIAL_UPDATE, + function_bind(BKE_material_eval, _1, material_cow)); + /* Material animation. */ + build_animdata(&material->id); + build_parameters(&material->id); + /* Material's nodetree. */ + build_nodetree(material->nodetree); } /* Recursively build graph for texture */ void DepsgraphNodeBuilder::build_texture(Tex *texture) { - if (built_map_.checkIsBuiltAndTag(texture)) { - return; - } - /* Texture itself. */ - build_animdata(&texture->id); - build_parameters(&texture->id); - /* Texture's nodetree. */ - build_nodetree(texture->nodetree); - /* Special cases for different IDs which texture uses. */ - if (texture->type == TEX_IMAGE) { - if (texture->ima != NULL) { - build_image(texture->ima); - } - } - add_operation_node(&texture->id, - NodeType::GENERIC_DATABLOCK, - OperationCode::GENERIC_DATABLOCK_UPDATE); + if (built_map_.checkIsBuiltAndTag(texture)) { + return; + } + /* Texture itself. */ + build_animdata(&texture->id); + build_parameters(&texture->id); + /* Texture's nodetree. */ + build_nodetree(texture->nodetree); + /* Special cases for different IDs which texture uses. */ + if (texture->type == TEX_IMAGE) { + if (texture->ima != NULL) { + build_image(texture->ima); + } + } + add_operation_node( + &texture->id, NodeType::GENERIC_DATABLOCK, OperationCode::GENERIC_DATABLOCK_UPDATE); } -void DepsgraphNodeBuilder::build_image(Image *image) { - if (built_map_.checkIsBuiltAndTag(image)) { - return; - } - build_parameters(&image->id); - add_operation_node(&image->id, - NodeType::GENERIC_DATABLOCK, - OperationCode::GENERIC_DATABLOCK_UPDATE); +void DepsgraphNodeBuilder::build_image(Image *image) +{ + if (built_map_.checkIsBuiltAndTag(image)) { + return; + } + build_parameters(&image->id); + add_operation_node( + &image->id, NodeType::GENERIC_DATABLOCK, OperationCode::GENERIC_DATABLOCK_UPDATE); } void DepsgraphNodeBuilder::build_compositor(Scene *scene) { - /* For now, just a plain wrapper? */ - // TODO: create compositing component? - // XXX: component type undefined! - //graph->get_node(&scene->id, NULL, NodeType::COMPOSITING, NULL); - - /* for now, nodetrees are just parameters; compositing occurs in internals - * of renderer... */ - add_component_node(&scene->id, NodeType::PARAMETERS); - build_nodetree(scene->nodetree); + /* For now, just a plain wrapper? */ + // TODO: create compositing component? + // XXX: component type undefined! + //graph->get_node(&scene->id, NULL, NodeType::COMPOSITING, NULL); + + /* for now, nodetrees are just parameters; compositing occurs in internals + * of renderer... */ + add_component_node(&scene->id, NodeType::PARAMETERS); + build_nodetree(scene->nodetree); } void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd) { - if (built_map_.checkIsBuiltAndTag(gpd)) { - return; - } - ID *gpd_id = &gpd->id; - - /* TODO(sergey): what about multiple users of same datablock? This should - * only get added once. */ - - /* The main reason Grease Pencil is included here is because the animation - * (and drivers) need to be hosted somewhere. */ - build_animdata(gpd_id); - build_parameters(gpd_id); + if (built_map_.checkIsBuiltAndTag(gpd)) { + return; + } + ID *gpd_id = &gpd->id; + + /* TODO(sergey): what about multiple users of same datablock? This should + * only get added once. */ + + /* The main reason Grease Pencil is included here is because the animation + * (and drivers) need to be hosted somewhere. */ + build_animdata(gpd_id); + build_parameters(gpd_id); } void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) { - if (built_map_.checkIsBuiltAndTag(cache_file)) { - return; - } - ID *cache_file_id = &cache_file->id; - /* Animation, */ - build_animdata(cache_file_id); - build_parameters(cache_file_id); - /* Cache evaluation itself. */ - add_operation_node( - cache_file_id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE); + if (built_map_.checkIsBuiltAndTag(cache_file)) { + return; + } + ID *cache_file_id = &cache_file->id; + /* Animation, */ + build_animdata(cache_file_id); + build_parameters(cache_file_id); + /* Cache evaluation itself. */ + add_operation_node(cache_file_id, NodeType::CACHE, OperationCode::FILE_CACHE_UPDATE); } void DepsgraphNodeBuilder::build_mask(Mask *mask) { - if (built_map_.checkIsBuiltAndTag(mask)) { - return; - } - ID *mask_id = &mask->id; - Mask *mask_cow = get_cow_datablock(mask); - /* F-Curve based animation. */ - build_animdata(mask_id); - build_parameters(mask_id); - /* Animation based on mask's shapes. */ - add_operation_node(mask_id, - NodeType::ANIMATION, - OperationCode::MASK_ANIMATION, - function_bind(BKE_mask_eval_animation, _1, mask_cow)); - /* Final mask evaluation. */ - add_operation_node(mask_id, - NodeType::PARAMETERS, - OperationCode::MASK_EVAL, - function_bind(BKE_mask_eval_update, _1, mask_cow)); + if (built_map_.checkIsBuiltAndTag(mask)) { + return; + } + ID *mask_id = &mask->id; + Mask *mask_cow = get_cow_datablock(mask); + /* F-Curve based animation. */ + build_animdata(mask_id); + build_parameters(mask_id); + /* Animation based on mask's shapes. */ + add_operation_node(mask_id, + NodeType::ANIMATION, + OperationCode::MASK_ANIMATION, + function_bind(BKE_mask_eval_animation, _1, mask_cow)); + /* Final mask evaluation. */ + add_operation_node(mask_id, + NodeType::PARAMETERS, + OperationCode::MASK_EVAL, + function_bind(BKE_mask_eval_update, _1, mask_cow)); } void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) { - if (built_map_.checkIsBuiltAndTag(clip)) { - return; - } - ID *clip_id = &clip->id; - MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id); - /* Animation. */ - build_animdata(clip_id); - build_parameters(clip_id); - /* Movie clip evaluation. */ - add_operation_node(clip_id, - NodeType::PARAMETERS, - OperationCode::MOVIECLIP_EVAL, - function_bind(BKE_movieclip_eval_update, _1, clip_cow)); - - add_operation_node(clip_id, - NodeType::BATCH_CACHE, - OperationCode::MOVIECLIP_SELECT_UPDATE, - function_bind(BKE_movieclip_eval_selection_update, _1, clip_cow)); + if (built_map_.checkIsBuiltAndTag(clip)) { + return; + } + ID *clip_id = &clip->id; + MovieClip *clip_cow = (MovieClip *)ensure_cow_id(clip_id); + /* Animation. */ + build_animdata(clip_id); + build_parameters(clip_id); + /* Movie clip evaluation. */ + add_operation_node(clip_id, + NodeType::PARAMETERS, + OperationCode::MOVIECLIP_EVAL, + function_bind(BKE_movieclip_eval_update, _1, clip_cow)); + + add_operation_node(clip_id, + NodeType::BATCH_CACHE, + OperationCode::MOVIECLIP_SELECT_UPDATE, + function_bind(BKE_movieclip_eval_selection_update, _1, clip_cow)); } void DepsgraphNodeBuilder::build_lightprobe(LightProbe *probe) { - if (built_map_.checkIsBuiltAndTag(probe)) { - return; - } - /* Placeholder so we can add relations and tag ID node for update. */ - add_operation_node( - &probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); - build_animdata(&probe->id); - build_parameters(&probe->id); + if (built_map_.checkIsBuiltAndTag(probe)) { + return; + } + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(&probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + build_animdata(&probe->id); + build_parameters(&probe->id); } void DepsgraphNodeBuilder::build_speaker(Speaker *speaker) { - if (built_map_.checkIsBuiltAndTag(speaker)) { - return; - } - /* Placeholder so we can add relations and tag ID node for update. */ - add_operation_node( - &speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); - build_animdata(&speaker->id); - build_parameters(&speaker->id); + if (built_map_.checkIsBuiltAndTag(speaker)) { + return; + } + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(&speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + build_animdata(&speaker->id); + build_parameters(&speaker->id); } /* **** ID traversal callbacks functions **** */ @@ -1684,24 +1551,22 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data, struct ID **idpoin, int /*cb_flag*/) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_OB: - /* Special case for object, so we take owner visibility into - * account. */ - data->builder->build_object(-1, - (Object *)id, - DEG_ID_LINKED_INDIRECTLY, - data->is_parent_visible); - break; - default: - data->builder->build_id(id); - break; - } + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_OB: + /* Special case for object, so we take owner visibility into + * account. */ + data->builder->build_object( + -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible); + break; + default: + data->builder->build_id(id); + break; + } } void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, @@ -1709,24 +1574,22 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, bool /*is_reference*/, void *user_data) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_OB: - /* Special case for object, so we take owner visibility into - * account. */ - data->builder->build_object(-1, - (Object *)id, - DEG_ID_LINKED_INDIRECTLY, - data->is_parent_visible); - break; - default: - data->builder->build_id(id); - break; - } + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_OB: + /* Special case for object, so we take owner visibility into + * account. */ + data->builder->build_object( + -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible); + break; + default: + data->builder->build_id(id); + break; + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index d5d1ac2d33a..d88f5a792e0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -75,209 +75,196 @@ struct OperationNode; struct TimeSourceNode; class DepsgraphNodeBuilder : public DepsgraphBuilder { -public: - DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph); - ~DepsgraphNodeBuilder(); + public: + DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph); + ~DepsgraphNodeBuilder(); - /* For given original ID get ID which is created by CoW system. */ - ID *get_cow_id(const ID *id_orig) const; - /* Similar to above, but for the cases when there is no ID node we create - * one. */ - ID *ensure_cow_id(ID *id_orig); + /* For given original ID get ID which is created by CoW system. */ + ID *get_cow_id(const ID *id_orig) const; + /* Similar to above, but for the cases when there is no ID node we create + * one. */ + ID *ensure_cow_id(ID *id_orig); - /* Helper wrapper function which wraps get_cow_id with a needed type cast. */ - template<typename T> - T *get_cow_datablock(const T *orig) const { - return (T *)get_cow_id(&orig->id); - } + /* Helper wrapper function which wraps get_cow_id with a needed type cast. */ + template<typename T> T *get_cow_datablock(const T *orig) const + { + return (T *)get_cow_id(&orig->id); + } - /* For a given COW datablock get corresponding original one. */ - template<typename T> - T *get_orig_datablock(const T *cow) const { - return (T *)cow->id.orig_id; - } + /* For a given COW datablock get corresponding original one. */ + template<typename T> T *get_orig_datablock(const T *cow) const + { + return (T *)cow->id.orig_id; + } - void begin_build(); - void end_build(); + void begin_build(); + void end_build(); - IDNode *add_id_node(ID *id); - IDNode *find_id_node(ID *id); - TimeSourceNode *add_time_source(); + IDNode *add_id_node(ID *id); + IDNode *find_id_node(ID *id); + TimeSourceNode *add_time_source(); - ComponentNode *add_component_node(ID *id, - NodeType comp_type, - const char *comp_name = ""); + ComponentNode *add_component_node(ID *id, NodeType comp_type, const char *comp_name = ""); - OperationNode *add_operation_node(ComponentNode *comp_node, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); - OperationNode *add_operation_node(ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); - OperationNode *add_operation_node(ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); + OperationNode *add_operation_node(ComponentNode *comp_node, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); + OperationNode *add_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); + OperationNode *add_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); - OperationNode *ensure_operation_node(ID *id, - NodeType comp_type, - OperationCode opcode, - const DepsEvalOperationCb& op = NULL, - const char *name = "", - int name_tag = -1); + OperationNode *ensure_operation_node(ID *id, + NodeType comp_type, + OperationCode opcode, + const DepsEvalOperationCb &op = NULL, + const char *name = "", + int name_tag = -1); - bool has_operation_node(ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const char *name = "", - int name_tag = -1); + bool has_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const char *name = "", + int name_tag = -1); - OperationNode *find_operation_node(ID *id, - NodeType comp_type, - const char *comp_name, - OperationCode opcode, - const char *name = "", - int name_tag = -1); + OperationNode *find_operation_node(ID *id, + NodeType comp_type, + const char *comp_name, + OperationCode opcode, + const char *name = "", + int name_tag = -1); - OperationNode *find_operation_node(ID *id, - NodeType comp_type, - OperationCode opcode, - const char *name = "", - int name_tag = -1); + OperationNode *find_operation_node( + ID *id, NodeType comp_type, OperationCode opcode, const char *name = "", int name_tag = -1); - void build_id(ID *id); - void build_layer_collections(ListBase *lb); - void build_view_layer(Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state); - void build_collection(LayerCollection *from_layer_collection, - Collection *collection); - void build_object(int base_index, - Object *object, - eDepsNode_LinkedState_Type linked_state, - bool is_visible); - void build_object_flags(int base_index, - Object *object, - eDepsNode_LinkedState_Type linked_state); - void build_object_data(Object *object, bool is_object_visible); - void build_object_data_camera(Object *object); - void build_object_data_geometry(Object *object, bool is_object_visible); - void build_object_data_geometry_datablock(ID *obdata, - bool is_object_visible); - void build_object_data_light(Object *object); - void build_object_data_lightprobe(Object *object); - void build_object_data_speaker(Object *object); - void build_object_transform(Object *object); - void build_object_constraints(Object *object); - void build_object_pointcache(Object *object); - void build_pose_constraints(Object *object, - bPoseChannel *pchan, - int pchan_index, - bool is_object_visible); - void build_rigidbody(Scene *scene); - void build_particle_systems(Object *object, bool is_object_visible); - void build_particle_settings(ParticleSettings *part); - void build_animdata(ID *id); - void build_animdata_nlastrip_targets(ListBase *strips); - void build_animation_images(ID *id); - void build_action(bAction *action); - void build_driver(ID *id, FCurve *fcurve, int driver_index); - void build_driver_variables(ID *id, FCurve *fcurve); - void build_driver_id_property(ID *id, const char *rna_path); - void build_parameters(ID *id); - void build_ik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con); - void build_splineik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con); - void build_rig(Object *object, bool is_object_visible); - void build_proxy_rig(Object *object); - void build_armature(bArmature *armature); - void build_shapekeys(Key *key); - void build_camera(Camera *camera); - void build_light(Light *lamp); - void build_nodetree(bNodeTree *ntree); - void build_material(Material *ma); - void build_texture(Tex *tex); - void build_image(Image *image); - void build_world(World *world); - void build_compositor(Scene *scene); - void build_gpencil(bGPdata *gpd); - void build_cachefile(CacheFile *cache_file); - void build_mask(Mask *mask); - void build_movieclip(MovieClip *clip); - void build_lightprobe(LightProbe *probe); - void build_speaker(Speaker *speaker); + void build_id(ID *id); + void build_layer_collections(ListBase *lb); + void build_view_layer(Scene *scene, + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state); + void build_collection(LayerCollection *from_layer_collection, Collection *collection); + void build_object(int base_index, + Object *object, + eDepsNode_LinkedState_Type linked_state, + bool is_visible); + void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state); + void build_object_data(Object *object, bool is_object_visible); + void build_object_data_camera(Object *object); + void build_object_data_geometry(Object *object, bool is_object_visible); + void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible); + void build_object_data_light(Object *object); + void build_object_data_lightprobe(Object *object); + void build_object_data_speaker(Object *object); + void build_object_transform(Object *object); + void build_object_constraints(Object *object); + void build_object_pointcache(Object *object); + void build_pose_constraints(Object *object, + bPoseChannel *pchan, + int pchan_index, + bool is_object_visible); + void build_rigidbody(Scene *scene); + void build_particle_systems(Object *object, bool is_object_visible); + void build_particle_settings(ParticleSettings *part); + void build_animdata(ID *id); + void build_animdata_nlastrip_targets(ListBase *strips); + void build_animation_images(ID *id); + void build_action(bAction *action); + void build_driver(ID *id, FCurve *fcurve, int driver_index); + void build_driver_variables(ID *id, FCurve *fcurve); + void build_driver_id_property(ID *id, const char *rna_path); + void build_parameters(ID *id); + void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); + void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); + void build_rig(Object *object, bool is_object_visible); + void build_proxy_rig(Object *object); + void build_armature(bArmature *armature); + void build_shapekeys(Key *key); + void build_camera(Camera *camera); + void build_light(Light *lamp); + void build_nodetree(bNodeTree *ntree); + void build_material(Material *ma); + void build_texture(Tex *tex); + void build_image(Image *image); + void build_world(World *world); + void build_compositor(Scene *scene); + void build_gpencil(bGPdata *gpd); + void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); + void build_lightprobe(LightProbe *probe); + void build_speaker(Speaker *speaker); - /* Per-ID information about what was already in the dependency graph. - * Allows to re-use certain values, to speed up following evaluation. */ - struct IDInfo { - /* Copy-on-written pointer of the corresponding ID. */ - ID *id_cow; - /* Mask of visible components from previous state of the - * dependency graph. */ - IDComponentsMask previously_visible_components_mask; - /* Special evaluation flag mask from the previous depsgraph. */ - uint32_t previous_eval_flags; - /* Mesh CustomData mask from the previous depsgraph. */ - DEGCustomDataMeshMasks previous_customdata_masks; - }; + /* Per-ID information about what was already in the dependency graph. + * Allows to re-use certain values, to speed up following evaluation. */ + struct IDInfo { + /* Copy-on-written pointer of the corresponding ID. */ + ID *id_cow; + /* Mask of visible components from previous state of the + * dependency graph. */ + IDComponentsMask previously_visible_components_mask; + /* Special evaluation flag mask from the previous depsgraph. */ + uint32_t previous_eval_flags; + /* Mesh CustomData mask from the previous depsgraph. */ + DEGCustomDataMeshMasks previous_customdata_masks; + }; -protected: - /* Allows to identify an operation which was tagged for update at the time - * relations are being updated. We can not reuse operation node pointer - * since it will change during dependency graph construction. */ - struct SavedEntryTag { - ID *id_orig; - NodeType component_type; - OperationCode opcode; - string name; - int name_tag; - }; - vector<SavedEntryTag> saved_entry_tags_; + protected: + /* Allows to identify an operation which was tagged for update at the time + * relations are being updated. We can not reuse operation node pointer + * since it will change during dependency graph construction. */ + struct SavedEntryTag { + ID *id_orig; + NodeType component_type; + OperationCode opcode; + string name; + int name_tag; + }; + vector<SavedEntryTag> saved_entry_tags_; - struct BuilderWalkUserData { - DepsgraphNodeBuilder *builder; - /* Denotes whether object the walk is invoked from is visible. */ - bool is_parent_visible; - }; - static void modifier_walk(void *user_data, - struct Object *object, - struct ID **idpoin, - int cb_flag); - static void constraint_walk(bConstraint *constraint, - ID **idpoin, - bool is_reference, - void *user_data); + struct BuilderWalkUserData { + DepsgraphNodeBuilder *builder; + /* Denotes whether object the walk is invoked from is visible. */ + bool is_parent_visible; + }; + static void modifier_walk(void *user_data, + struct Object *object, + struct ID **idpoin, + int cb_flag); + static void constraint_walk(bConstraint *constraint, + ID **idpoin, + bool is_reference, + void *user_data); - /* State which demotes currently built entities. */ - Scene *scene_; - ViewLayer *view_layer_; - int view_layer_index_; - /* NOTE: Collection are possibly built recursively, so be careful when - * setting the current state. */ - Collection *collection_; - /* Accumulated flag over the hierarchy opf currently building collections. - * Denotes whether all the hierarchy from parent of collection_ to the - * very root is visible (aka not restricted.). */ - bool is_parent_collection_visible_; + /* State which demotes currently built entities. */ + Scene *scene_; + ViewLayer *view_layer_; + int view_layer_index_; + /* NOTE: Collection are possibly built recursively, so be careful when + * setting the current state. */ + Collection *collection_; + /* Accumulated flag over the hierarchy opf currently building collections. + * Denotes whether all the hierarchy from parent of collection_ to the + * very root is visible (aka not restricted.). */ + bool is_parent_collection_visible_; - /* Indexed by original ID, values are IDInfo. */ - GHash *id_info_hash_; + /* Indexed by original ID, values are IDInfo. */ + GHash *id_info_hash_; - /* Set of IDs which were already build. Makes it easier to keep track of - * what was already built and what was not. */ - BuilderMap built_map_; + /* Set of IDs which were already build. Makes it easier to keep track of + * what was already built and what was not. */ + BuilderMap built_map_; }; } // namespace DEG 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 132600f2fdd..6f141bd7222 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -58,60 +58,56 @@ extern "C" { namespace DEG { -void DepsgraphNodeBuilder::build_pose_constraints( - Object *object, - bPoseChannel *pchan, - int pchan_index, - bool is_object_visible) +void DepsgraphNodeBuilder::build_pose_constraints(Object *object, + bPoseChannel *pchan, + int pchan_index, + bool is_object_visible) { - /* Pull indirect dependencies via constraints. */ - BuilderWalkUserData data; - data.builder = this; - data.is_parent_visible = is_object_visible; - BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); - /* Create node for constraint stack. */ - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_CONSTRAINTS, - function_bind(BKE_pose_constraints_evaluate, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object), - pchan_index)); + /* Pull indirect dependencies via constraints. */ + BuilderWalkUserData data; + data.builder = this; + data.is_parent_visible = is_object_visible; + BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); + /* Create node for constraint stack. */ + add_operation_node(&object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_CONSTRAINTS, + function_bind(BKE_pose_constraints_evaluate, + _1, + get_cow_datablock(scene_), + get_cow_datablock(object), + pchan_index)); } /* IK Solver Eval Steps */ -void DepsgraphNodeBuilder::build_ik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con) +void DepsgraphNodeBuilder::build_ik_pose(Object *object, 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 (rootchan == NULL) { - return; - } - - if (has_operation_node(&object->id, NodeType::EVAL_POSE, rootchan->name, - OperationCode::POSE_IK_SOLVER)) - { - return; - } - - int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); - BLI_assert(rootchan_index != -1); - /* Operation node for evaluating/running IK Solver. */ - add_operation_node(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_IK_SOLVER, - function_bind(BKE_pose_iktree_evaluate, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object), - rootchan_index)); + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + if (rootchan == NULL) { + return; + } + + if (has_operation_node( + &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_IK_SOLVER)) { + return; + } + + int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); + BLI_assert(rootchan_index != -1); + /* Operation node for evaluating/running IK Solver. */ + add_operation_node(&object->id, + NodeType::EVAL_POSE, + rootchan->name, + OperationCode::POSE_IK_SOLVER, + function_bind(BKE_pose_iktree_evaluate, + _1, + get_cow_datablock(scene_), + get_cow_datablock(object), + rootchan_index)); } /* Spline IK Eval Steps */ @@ -119,277 +115,229 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object, 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. */ - int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); - BLI_assert(rootchan_index != -1); - add_operation_node(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_SPLINE_IK_SOLVER, - function_bind(BKE_pose_splineik_evaluate, - _1, - get_cow_datablock(scene_), - get_cow_datablock(object), - rootchan_index)); + 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. */ + int rootchan_index = BLI_findindex(&object->pose->chanbase, rootchan); + BLI_assert(rootchan_index != -1); + add_operation_node(&object->id, + NodeType::EVAL_POSE, + rootchan->name, + OperationCode::POSE_SPLINE_IK_SOLVER, + function_bind(BKE_pose_splineik_evaluate, + _1, + get_cow_datablock(scene_), + get_cow_datablock(object), + rootchan_index)); } /* Pose/Armature Bones Graph */ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) { - bArmature *armature = (bArmature *)object->data; - Scene *scene_cow = get_cow_datablock(scene_); - Object *object_cow = get_cow_datablock(object); - OperationNode *op_node; - /* 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. */ - /* Armature. */ - build_armature(armature); - /* Rebuild pose if not up to date. */ - if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { - /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */ - BKE_pose_rebuild(NULL, object, armature, true); - } - /* Speed optimization for animation lookups. */ - if (object->pose != NULL) { - BKE_pose_channels_hash_make(object->pose); - if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(object->pose); - } - } - /** - * 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 - * post-IK/post-constraint/post-matrix steps, as needed. */ - /* Pose eval context. */ - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT, - function_bind(BKE_pose_eval_init, - _1, - scene_cow, - object_cow)); - op_node->set_as_entry(); - - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT_IK, - function_bind(BKE_pose_eval_init_ik, - _1, - scene_cow, - object_cow)); - - add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_CLEANUP, - function_bind(BKE_pose_eval_cleanup, - _1, - scene_cow, - object_cow)); - - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_DONE, - function_bind(BKE_pose_eval_done, - _1, - object_cow)); - op_node->set_as_exit(); - /* Bones. */ - int pchan_index = 0; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - /* Node for bone evaluation. */ - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - op_node->set_as_entry(); - - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_POSE_PARENT, - function_bind(BKE_pose_eval_bone, _1, - scene_cow, - object_cow, - pchan_index)); - - /* NOTE: Dedicated noop for easier relationship construction. */ - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE, - function_bind(BKE_pose_bone_done, - _1, - object_cow, - pchan_index)); - - /* B-Bone shape computation - the real last step if present. */ - if (pchan->bone != NULL && pchan->bone->segments > 1) { - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_SEGMENTS, - function_bind(BKE_pose_eval_bbone_segments, _1, - object_cow, - pchan_index)); - } - - op_node->set_as_exit(); - - /* Custom properties. */ - if (pchan->prop != NULL) { - add_operation_node(&object->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - NULL, - pchan->name); - } - /* Build constraints. */ - if (pchan->constraints.first != NULL) { - build_pose_constraints( - object, pchan, pchan_index, is_object_visible); - } - /** - * 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. */ - LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(object, pchan, con); - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(object, pchan, con); - break; - - default: - break; - } - } - /* Custom shape. */ - if (pchan->custom != NULL) { - /* TODO(sergey): Use own visibility. */ - build_object( - -1, - pchan->custom, - DEG_ID_LINKED_INDIRECTLY, - is_object_visible); - } - pchan_index++; - } + bArmature *armature = (bArmature *)object->data; + Scene *scene_cow = get_cow_datablock(scene_); + Object *object_cow = get_cow_datablock(object); + OperationNode *op_node; + /* 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. */ + /* Armature. */ + build_armature(armature); + /* Rebuild pose if not up to date. */ + if (object->pose == NULL || (object->pose->flag & POSE_RECALC)) { + /* By definition, no need to tag depsgraph as dirty from here, so we can pass NULL bmain. */ + BKE_pose_rebuild(NULL, object, armature, true); + } + /* Speed optimization for animation lookups. */ + if (object->pose != NULL) { + BKE_pose_channels_hash_make(object->pose); + if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(object->pose); + } + } + /** + * 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 + * post-IK/post-constraint/post-matrix steps, as needed. */ + /* Pose eval context. */ + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_INIT, + function_bind(BKE_pose_eval_init, _1, scene_cow, object_cow)); + op_node->set_as_entry(); + + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_INIT_IK, + function_bind(BKE_pose_eval_init_ik, _1, scene_cow, object_cow)); + + add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_CLEANUP, + function_bind(BKE_pose_eval_cleanup, _1, scene_cow, object_cow)); + + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_DONE, + function_bind(BKE_pose_eval_done, _1, object_cow)); + op_node->set_as_exit(); + /* Bones. */ + int pchan_index = 0; + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + /* Node for bone evaluation. */ + op_node = add_operation_node( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + op_node->set_as_entry(); + + add_operation_node(&object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_POSE_PARENT, + function_bind(BKE_pose_eval_bone, _1, scene_cow, object_cow, pchan_index)); + + /* NOTE: Dedicated noop for easier relationship construction. */ + add_operation_node(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + + op_node = add_operation_node(&object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_DONE, + function_bind(BKE_pose_bone_done, _1, object_cow, pchan_index)); + + /* B-Bone shape computation - the real last step if present. */ + if (pchan->bone != NULL && pchan->bone->segments > 1) { + op_node = add_operation_node( + &object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_SEGMENTS, + function_bind(BKE_pose_eval_bbone_segments, _1, object_cow, pchan_index)); + } + + op_node->set_as_exit(); + + /* Custom properties. */ + if (pchan->prop != NULL) { + add_operation_node( + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name); + } + /* Build constraints. */ + if (pchan->constraints.first != NULL) { + build_pose_constraints(object, pchan, pchan_index, is_object_visible); + } + /** + * 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. */ + LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(object, pchan, con); + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(object, pchan, con); + break; + + default: + break; + } + } + /* Custom shape. */ + if (pchan->custom != NULL) { + /* TODO(sergey): Use own visibility. */ + build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + } + pchan_index++; + } } void DepsgraphNodeBuilder::build_proxy_rig(Object *object) { - bArmature *armature = (bArmature *)object->data; - OperationNode *op_node; - Object *object_cow = get_cow_datablock(object); - /* Sanity check. */ - BLI_assert(object->pose != NULL); - /* Armature. */ - build_armature(armature); - /* speed optimization for animation lookups */ - BKE_pose_channels_hash_make(object->pose); - if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(object->pose); - } - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT, - function_bind(BKE_pose_eval_proxy_init, - _1, - object_cow)); - op_node->set_as_entry(); - - int pchan_index = 0; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - op_node = add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - op_node->set_as_entry(); - /* Bone is ready for solvers. */ - add_operation_node(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - /* Bone is fully evaluated. */ - op_node = add_operation_node( - &object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE, - function_bind(BKE_pose_eval_proxy_copy_bone, - _1, - object_cow, - pchan_index)); - op_node->set_as_exit(); - - /* Custom properties. */ - if (pchan->prop != NULL) { - add_operation_node(&object->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - NULL, - pchan->name); - } - - pchan_index++; - } - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_CLEANUP, - function_bind(BKE_pose_eval_proxy_cleanup, - _1, - object_cow)); - op_node = add_operation_node(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_DONE, - function_bind(BKE_pose_eval_proxy_done, - _1, - object_cow)); - op_node->set_as_exit(); + bArmature *armature = (bArmature *)object->data; + OperationNode *op_node; + Object *object_cow = get_cow_datablock(object); + /* Sanity check. */ + BLI_assert(object->pose != NULL); + /* Armature. */ + build_armature(armature); + /* speed optimization for animation lookups */ + BKE_pose_channels_hash_make(object->pose); + if (object->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(object->pose); + } + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_INIT, + function_bind(BKE_pose_eval_proxy_init, _1, object_cow)); + op_node->set_as_entry(); + + int pchan_index = 0; + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + op_node = add_operation_node( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + op_node->set_as_entry(); + /* Bone is ready for solvers. */ + add_operation_node(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + /* Bone is fully evaluated. */ + op_node = add_operation_node( + &object->id, + NodeType::BONE, + pchan->name, + OperationCode::BONE_DONE, + function_bind(BKE_pose_eval_proxy_copy_bone, _1, object_cow, pchan_index)); + op_node->set_as_exit(); + + /* Custom properties. */ + if (pchan->prop != NULL) { + add_operation_node( + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, NULL, pchan->name); + } + + pchan_index++; + } + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_CLEANUP, + function_bind(BKE_pose_eval_proxy_cleanup, _1, object_cow)); + op_node = add_operation_node(&object->id, + NodeType::EVAL_POSE, + OperationCode::POSE_DONE, + function_bind(BKE_pose_eval_proxy_done, _1, object_cow)); + op_node->set_as_exit(); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc index 36a9d53d670..60b711d76d3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_view_layer.cc @@ -60,115 +60,111 @@ namespace DEG { void DepsgraphNodeBuilder::build_layer_collections(ListBase *lb) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? - COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + COLLECTION_RESTRICT_RENDER; - for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if (lc->collection->flag & restrict_flag) { - continue; - } - if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { - build_collection(lc, lc->collection); - } - build_layer_collections(&lc->layer_collections); - } + for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { + if (lc->collection->flag & restrict_flag) { + continue; + } + if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + build_collection(lc, lc->collection); + } + build_layer_collections(&lc->layer_collections); + } } -void DepsgraphNodeBuilder::build_view_layer( - Scene *scene, - ViewLayer *view_layer, - eDepsNode_LinkedState_Type linked_state) +void DepsgraphNodeBuilder::build_view_layer(Scene *scene, + ViewLayer *view_layer, + eDepsNode_LinkedState_Type linked_state) { - /* NOTE: Pass view layer index of 0 since after scene CoW there is - * only one view layer in there. */ - view_layer_index_ = 0; - /* Scene ID block. */ - IDNode *id_node = add_id_node(&scene->id); - id_node->linked_state = linked_state; - /* Time source. */ - add_time_source(); - /* Setup currently building context. */ - scene_ = scene; - view_layer_ = view_layer; - /* Get pointer to a CoW version of scene ID. */ - Scene *scene_cow = get_cow_datablock(scene); - /* Scene objects. */ - int select_id = 1; - /* NOTE: Base is used for function bindings as-is, so need to pass CoW base, - * but object is expected to be an original one. Hence we go into some - * tricks here iterating over the view layer. */ - int base_index = 0; - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - /* object itself */ - if (need_pull_base_into_graph(base)) { - /* NOTE: We consider object visible even if it's currently - * restricted by the base/restriction flags. Otherwise its drivers - * will never be evaluated. - * - * TODO(sergey): Need to go more granular on visibility checks. */ - build_object(base_index, base->object, linked_state, true); - ++base_index; - } - base->object->select_id = select_id++; - } - build_layer_collections(&view_layer->layer_collections); - if (scene->camera != NULL) { - build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true); - } - /* Rigidbody. */ - if (scene->rigidbody_world != NULL) { - build_rigidbody(scene); - } - /* Scene's animation and drivers. */ - if (scene->adt != NULL) { - build_animdata(&scene->id); - } - /* World. */ - if (scene->world != NULL) { - build_world(scene->world); - } - /* Compositor nodes */ - if (scene->nodetree != NULL) { - build_compositor(scene); - } - /* Cache file. */ - LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { - build_cachefile(cachefile); - } - /* Masks. */ - LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { - build_mask(mask); - } - /* Movie clips. */ - LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { - build_movieclip(clip); - } - /* Material override. */ - if (view_layer->mat_override != NULL) { - build_material(view_layer->mat_override); - } - /* Freestyle collections. */ - LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { - if (fls->group != NULL) { - build_collection(NULL, fls->group); - } - } - /* Collections. */ - add_operation_node(&scene->id, - NodeType::LAYER_COLLECTIONS, - OperationCode::VIEW_LAYER_EVAL, - function_bind(BKE_layer_eval_view_layer_indexed, - _1, - scene_cow, - view_layer_index_)); - /* Parameters evaluation for scene relations mainly. */ - add_operation_node( - &scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); - /* Build all set scenes. */ - if (scene->set != NULL) { - ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); - build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET); - } + /* NOTE: Pass view layer index of 0 since after scene CoW there is + * only one view layer in there. */ + view_layer_index_ = 0; + /* Scene ID block. */ + IDNode *id_node = add_id_node(&scene->id); + id_node->linked_state = linked_state; + /* Time source. */ + add_time_source(); + /* Setup currently building context. */ + scene_ = scene; + view_layer_ = view_layer; + /* Get pointer to a CoW version of scene ID. */ + Scene *scene_cow = get_cow_datablock(scene); + /* Scene objects. */ + int select_id = 1; + /* NOTE: Base is used for function bindings as-is, so need to pass CoW base, + * but object is expected to be an original one. Hence we go into some + * tricks here iterating over the view layer. */ + int base_index = 0; + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + /* object itself */ + if (need_pull_base_into_graph(base)) { + /* NOTE: We consider object visible even if it's currently + * restricted by the base/restriction flags. Otherwise its drivers + * will never be evaluated. + * + * TODO(sergey): Need to go more granular on visibility checks. */ + build_object(base_index, base->object, linked_state, true); + ++base_index; + } + base->object->select_id = select_id++; + } + build_layer_collections(&view_layer->layer_collections); + if (scene->camera != NULL) { + build_object(-1, scene->camera, DEG_ID_LINKED_INDIRECTLY, true); + } + /* Rigidbody. */ + if (scene->rigidbody_world != NULL) { + build_rigidbody(scene); + } + /* Scene's animation and drivers. */ + if (scene->adt != NULL) { + build_animdata(&scene->id); + } + /* World. */ + if (scene->world != NULL) { + build_world(scene->world); + } + /* Compositor nodes */ + if (scene->nodetree != NULL) { + build_compositor(scene); + } + /* Cache file. */ + LISTBASE_FOREACH (CacheFile *, cachefile, &bmain_->cachefiles) { + build_cachefile(cachefile); + } + /* Masks. */ + LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { + build_mask(mask); + } + /* Movie clips. */ + LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { + build_movieclip(clip); + } + /* Material override. */ + if (view_layer->mat_override != NULL) { + build_material(view_layer->mat_override); + } + /* Freestyle collections. */ + LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { + if (fls->group != NULL) { + build_collection(NULL, fls->group); + } + } + /* Collections. */ + add_operation_node( + &scene->id, + NodeType::LAYER_COLLECTIONS, + OperationCode::VIEW_LAYER_EVAL, + function_bind(BKE_layer_eval_view_layer_indexed, _1, scene_cow, view_layer_index_)); + /* Parameters evaluation for scene relations mainly. */ + add_operation_node(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL); + /* Build all set scenes. */ + if (scene->set != NULL) { + ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); + build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 9316a15c278..6d979724e7e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -33,98 +33,97 @@ namespace DEG { static void free_rootpchanmap_valueset(void *val) { - /* Just need to free the set itself - the names stored are all references. */ - GSet *values = (GSet *)val; - BLI_gset_free(values, NULL); + /* Just need to free the set itself - the names stored are all references. */ + GSet *values = (GSet *)val; + BLI_gset_free(values, NULL); } RootPChanMap::RootPChanMap() { - /* Just create empty map. */ - map_ = BLI_ghash_str_new("RootPChanMap"); + /* Just create empty map. */ + map_ = BLI_ghash_str_new("RootPChanMap"); } RootPChanMap::~RootPChanMap() { - /* Free the map, and all the value sets. */ - BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset); + /* Free the map, and all the value sets. */ + BLI_ghash_free(map_, NULL, free_rootpchanmap_valueset); } /* Debug contents of map */ void RootPChanMap::print_debug() { - GHashIterator it1; - GSetIterator it2; - - printf("Root PChan Map:\n"); - GHASH_ITER(it1, map_) { - const char *item = (const char *)BLI_ghashIterator_getKey(&it1); - GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1); - - printf(" %s : { ", item); - GSET_ITER(it2, values) { - const char *val = (const char *)BLI_gsetIterator_getKey(&it2); - printf("%s, ", val); - } - printf("}\n"); - } + GHashIterator it1; + GSetIterator it2; + + printf("Root PChan Map:\n"); + GHASH_ITER (it1, map_) { + const char *item = (const char *)BLI_ghashIterator_getKey(&it1); + GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1); + + printf(" %s : { ", item); + GSET_ITER (it2, values) { + const char *val = (const char *)BLI_gsetIterator_getKey(&it2); + printf("%s, ", val); + } + printf("}\n"); + } } /* Add a mapping. */ void RootPChanMap::add_bone(const char *bone, const char *root) { - if (BLI_ghash_haskey(map_, bone)) { - /* Add new entry, but only add the root if it doesn't already - * exist in there. */ - GSet *values = (GSet *)BLI_ghash_lookup(map_, bone); - BLI_gset_add(values, (void *)root); - } - else { - /* Create new set and mapping. */ - GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p, - BLI_ghashutil_strcmp, - "RootPChanMap Value Set"); - BLI_ghash_insert(map_, (void *)bone, (void *)values); - - /* Add new entry now. */ - BLI_gset_insert(values, (void *)root); - } + if (BLI_ghash_haskey(map_, bone)) { + /* Add new entry, but only add the root if it doesn't already + * exist in there. */ + GSet *values = (GSet *)BLI_ghash_lookup(map_, bone); + BLI_gset_add(values, (void *)root); + } + else { + /* Create new set and mapping. */ + GSet *values = BLI_gset_new( + BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "RootPChanMap Value Set"); + BLI_ghash_insert(map_, (void *)bone, (void *)values); + + /* Add new entry now. */ + BLI_gset_insert(values, (void *)root); + } } /* Check if there's a common root bone between two bones. */ bool RootPChanMap::has_common_root(const char *bone1, const char *bone2) { - /* Ensure that both are in the map... */ - if (BLI_ghash_haskey(map_, bone1) == false) { - //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); - //print_debug(); - return false; - } - - if (BLI_ghash_haskey(map_, bone2) == false) { - //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); - //print_debug(); - return false; - } - - GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1); - GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2); - - GSetIterator it1, it2; - GSET_ITER(it1, bone1_roots) { - GSET_ITER(it2, bone2_roots) { - const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1); - const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2); - - if (strcmp(v1, v2) == 0) { - //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2); - return true; - } - } - } - - //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); - return false; + /* Ensure that both are in the map... */ + if (BLI_ghash_haskey(map_, bone1) == false) { + //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2); + //print_debug(); + return false; + } + + if (BLI_ghash_haskey(map_, bone2) == false) { + //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2); + //print_debug(); + return false; + } + + GSet *bone1_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone1); + GSet *bone2_roots = (GSet *)BLI_ghash_lookup(map_, (void *)bone2); + + GSetIterator it1, it2; + GSET_ITER (it1, bone1_roots) { + GSET_ITER (it2, bone2_roots) { + const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1); + const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2); + + if (strcmp(v1, v2) == 0) { + //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2); + return true; + } + } + } + + //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2); + return false; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h index 1fb634a8707..0c1d22f9345 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.h @@ -28,27 +28,27 @@ struct GHash; namespace DEG { struct RootPChanMap { - /* ctor and dtor - Create and free the internal map respectively. */ - RootPChanMap(); - ~RootPChanMap(); - - /* Debug contents of map. */ - void print_debug(); - - /* Add a mapping. */ - void add_bone(const char *bone, const char *root); - - /* Check if there's a common root bone between two bones. */ - bool has_common_root(const char *bone1, const char *bone2); - -protected: - /* The actual map: - * - Keys are "strings" (const char *) - not dynamically allocated. - * - Values are "sets" (const char *) - not dynamically allocated. - * - * We don't use the C++ maps here, as it's more convenient to use - * Blender's GHash and be able to compare by-value instead of by-ref. */ - struct GHash *map_; + /* ctor and dtor - Create and free the internal map respectively. */ + RootPChanMap(); + ~RootPChanMap(); + + /* Debug contents of map. */ + void print_debug(); + + /* Add a mapping. */ + void add_bone(const char *bone, const char *root); + + /* Check if there's a common root bone between two bones. */ + bool has_common_root(const char *bone1, const char *bone2); + + protected: + /* The actual map: + * - Keys are "strings" (const char *) - not dynamically allocated. + * - Values are "sets" (const char *) - not dynamically allocated. + * + * We don't use the C++ maps here, as it's more convenient to use + * Blender's GHash and be able to compare by-value instead of by-ref. */ + struct GHash *map_; }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 489b688eaaa..87a8875f819 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -27,7 +27,7 @@ #include <stdio.h> #include <stdlib.h> -#include <cstring> /* required for STREQ later on. */ +#include <cstring> /* required for STREQ later on. */ #include "MEM_guardedalloc.h" @@ -121,61 +121,60 @@ namespace DEG { */ static bool python_driver_depends_on_time(ChannelDriver *driver) { - if (driver->expression[0] == '\0') { - /* Empty expression depends on nothing. */ - return false; - } - if (strchr(driver->expression, '(') != NULL) { - /* Function calls are considered dependent on a time. */ - return true; - } - if (strstr(driver->expression, "frame") != NULL) { - /* Variable `frame` depends on time. */ - /* TODO(sergey): This is a bit weak, but not sure about better way of - * handling this. */ - return true; - } - /* Possible indirect time relation s should be handled via variable - * targets. */ - return false; + if (driver->expression[0] == '\0') { + /* Empty expression depends on nothing. */ + return false; + } + if (strchr(driver->expression, '(') != NULL) { + /* Function calls are considered dependent on a time. */ + return true; + } + if (strstr(driver->expression, "frame") != NULL) { + /* Variable `frame` depends on time. */ + /* TODO(sergey): This is a bit weak, but not sure about better way of + * handling this. */ + return true; + } + /* Possible indirect time relation s should be handled via variable + * targets. */ + return false; } static bool particle_system_depends_on_time(ParticleSystem *psys) { - ParticleSettings *part = psys->part; - /* Non-hair particles we always consider dependent on time. */ - if (part->type != PART_HAIR) { - return true; - } - /* Dynamics always depends on time. */ - if (psys->flag & PSYS_HAIR_DYNAMICS) { - return true; - } - /* TODO(sergey): Check what else makes hair dependent on time. */ - return false; + ParticleSettings *part = psys->part; + /* Non-hair particles we always consider dependent on time. */ + if (part->type != PART_HAIR) { + return true; + } + /* Dynamics always depends on time. */ + if (psys->flag & PSYS_HAIR_DYNAMICS) { + return true; + } + /* TODO(sergey): Check what else makes hair dependent on time. */ + return false; } static bool object_particles_depends_on_time(Object *object) { - if (object->type != OB_MESH) { - return false; - } - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - if (particle_system_depends_on_time(psys)) { - return true; - } - } - return false; + if (object->type != OB_MESH) { + return false; + } + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + if (particle_system_depends_on_time(psys)) { + return true; + } + } + return false; } static bool check_id_has_anim_component(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return false; - } - return (adt->action != NULL) || - (!BLI_listbase_is_empty(&adt->nla_tracks)); + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return false; + } + return (adt->action != NULL) || (!BLI_listbase_is_empty(&adt->nla_tracks)); } static OperationCode bone_target_opcode(ID *target, @@ -184,267 +183,251 @@ static OperationCode bone_target_opcode(ID *target, const char *component_subdata, RootPChanMap *root_map) { - /* Same armature. */ - if (target == id) { - /* Using "done" here breaks in-chain deps, while using - * "ready" here breaks most production rigs instead. - * So, we do a compromise here, and only do this when an - * IK chain conflict may occur. */ - if (root_map->has_common_root(component_subdata, subtarget)) { - return OperationCode::BONE_READY; - } - } - return OperationCode::BONE_DONE; + /* Same armature. */ + if (target == id) { + /* Using "done" here breaks in-chain deps, while using + * "ready" here breaks most production rigs instead. + * So, we do a compromise here, and only do this when an + * IK chain conflict may occur. */ + if (root_map->has_common_root(component_subdata, subtarget)) { + return OperationCode::BONE_READY; + } + } + return OperationCode::BONE_DONE; } static bool bone_has_segments(Object *object, const char *bone_name) { - /* Proxies don't have BONE_SEGMENTS */ - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { - return false; - } - /* Only B-Bones have segments. */ - bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); - return pchan && pchan->bone && pchan->bone->segments > 1; + /* Proxies don't have BONE_SEGMENTS */ + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + return false; + } + /* Only B-Bones have segments. */ + bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + return pchan && pchan->bone && pchan->bone->segments > 1; } /* **** General purpose functions **** */ -DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, - Depsgraph *graph) - : DepsgraphBuilder(bmain, graph), - scene_(NULL), - rna_node_query_(graph) +DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph) + : DepsgraphBuilder(bmain, graph), scene_(NULL), rna_node_query_(graph) { } -TimeSourceNode *DepsgraphRelationBuilder::get_node( - const TimeSourceKey &key) const +TimeSourceNode *DepsgraphRelationBuilder::get_node(const TimeSourceKey &key) const { - if (key.id) { - /* XXX TODO */ - return NULL; - } - else { - return graph_->time_source; - } + if (key.id) { + /* XXX TODO */ + return NULL; + } + else { + return graph_->time_source; + } } -ComponentNode *DepsgraphRelationBuilder::get_node( - const ComponentKey &key) const +ComponentNode *DepsgraphRelationBuilder::get_node(const ComponentKey &key) const { - IDNode *id_node = graph_->find_id_node(key.id); - if (!id_node) { - fprintf(stderr, "find_node component: Could not find ID %s\n", - (key.id != NULL) ? key.id->name : "<null>"); - return NULL; - } + IDNode *id_node = graph_->find_id_node(key.id); + if (!id_node) { + fprintf(stderr, + "find_node component: Could not find ID %s\n", + (key.id != NULL) ? key.id->name : "<null>"); + return NULL; + } - ComponentNode *node = id_node->find_component(key.type, key.name); - return node; + ComponentNode *node = id_node->find_component(key.type, key.name); + return node; } -OperationNode *DepsgraphRelationBuilder::get_node( - const OperationKey &key) const +OperationNode *DepsgraphRelationBuilder::get_node(const OperationKey &key) const { - OperationNode *op_node = find_node(key); - if (op_node == NULL) { - fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n", - operationCodeAsString(key.opcode), key.name); - } - return op_node; + OperationNode *op_node = find_node(key); + if (op_node == NULL) { + fprintf(stderr, + "find_node_operation: Failed for (%s, '%s')\n", + operationCodeAsString(key.opcode), + key.name); + } + return op_node; } Node *DepsgraphRelationBuilder::get_node(const RNAPathKey &key) { - return rna_node_query_.find_node(&key.ptr, key.prop, key.source); + return rna_node_query_.find_node(&key.ptr, key.prop, key.source); } -OperationNode *DepsgraphRelationBuilder::find_node( - const OperationKey &key) const +OperationNode *DepsgraphRelationBuilder::find_node(const OperationKey &key) const { - IDNode *id_node = graph_->find_id_node(key.id); - if (!id_node) { - return NULL; - } - ComponentNode *comp_node = id_node->find_component(key.component_type, - key.component_name); - if (!comp_node) { - return NULL; - } - return comp_node->find_operation(key.opcode, key.name, key.name_tag); + IDNode *id_node = graph_->find_id_node(key.id); + if (!id_node) { + return NULL; + } + ComponentNode *comp_node = id_node->find_component(key.component_type, key.component_name); + if (!comp_node) { + return NULL; + } + return comp_node->find_operation(key.opcode, key.name, key.name_tag); } bool DepsgraphRelationBuilder::has_node(const OperationKey &key) const { - return find_node(key) != NULL; + return find_node(key) != NULL; } -void DepsgraphRelationBuilder::add_modifier_to_transform_relation( - const DepsNodeHandle *handle, - const char *description) +void DepsgraphRelationBuilder::add_modifier_to_transform_relation(const DepsNodeHandle *handle, + const char *description) { - IDNode *id_node = handle->node->owner->owner; - ID *id = id_node->id_orig; - ComponentKey geometry_key(id, NodeType::GEOMETRY); - /* Wire up the actual relation. */ - add_depends_on_transform_relation(id, geometry_key, description); + IDNode *id_node = handle->node->owner->owner; + ID *id = id_node->id_orig; + ComponentKey geometry_key(id, NodeType::GEOMETRY); + /* Wire up the actual relation. */ + add_depends_on_transform_relation(id, geometry_key, description); } -void DepsgraphRelationBuilder::add_customdata_mask( - Object *object, - const DEGCustomDataMeshMasks &customdata_masks) +void DepsgraphRelationBuilder::add_customdata_mask(Object *object, + const DEGCustomDataMeshMasks &customdata_masks) { - if (customdata_masks != DEGCustomDataMeshMasks() && object != NULL && object->type == OB_MESH) { - DEG::IDNode *id_node = graph_->find_id_node(&object->id); + if (customdata_masks != DEGCustomDataMeshMasks() && object != NULL && object->type == OB_MESH) { + DEG::IDNode *id_node = graph_->find_id_node(&object->id); - if (id_node == NULL) { - BLI_assert(!"ID should always be valid"); - } - else { - id_node->customdata_masks |= customdata_masks; - } - } + if (id_node == NULL) { + BLI_assert(!"ID should always be valid"); + } + else { + id_node->customdata_masks |= customdata_masks; + } + } } void DepsgraphRelationBuilder::add_special_eval_flag(ID *id, uint32_t flag) { - DEG::IDNode *id_node = graph_->find_id_node(id); - if (id_node == NULL) { - BLI_assert(!"ID should always be valid"); - } - else { - id_node->eval_flags |= flag; - } -} - -Relation *DepsgraphRelationBuilder::add_time_relation( - TimeSourceNode *timesrc, - Node *node_to, - const char *description, - int flags) -{ - if (timesrc && node_to) { - return graph_->add_new_relation( - timesrc, node_to, description, flags); - } - else { - DEG_DEBUG_PRINTF((::Depsgraph *)graph_, - BUILD, "add_time_relation(%p = %s, %p = %s, %s) Failed\n", - timesrc, (timesrc) ? timesrc->identifier().c_str() : "<None>", - node_to, (node_to) ? node_to->identifier().c_str() : "<None>", - description); - } - return NULL; -} - -Relation *DepsgraphRelationBuilder::add_operation_relation( - OperationNode *node_from, - OperationNode *node_to, - const char *description, - int flags) -{ - if (node_from && node_to) { - return graph_->add_new_relation(node_from, - node_to, - description, - flags); - } - else { - DEG_DEBUG_PRINTF((::Depsgraph *)graph_, - BUILD, "add_operation_relation(%p = %s, %p = %s, %s) Failed\n", - node_from, (node_from) ? node_from->identifier().c_str() : "<None>", - node_to, (node_to) ? node_to->identifier().c_str() : "<None>", - description); - } - return NULL; -} - -void DepsgraphRelationBuilder::add_particle_collision_relations( - const OperationKey &key, - Object *object, - Collection *collection, - const char *name) -{ - ListBase *relations = build_collision_relations(graph_, collection, eModifierType_Collision); - - LISTBASE_FOREACH (CollisionRelation *, relation, relations) { - if (relation->ob != object) { - ComponentKey trf_key(&relation->ob->id, NodeType::TRANSFORM); - add_relation(trf_key, key, name); - - ComponentKey coll_key(&relation->ob->id, NodeType::GEOMETRY); - add_relation(coll_key, key, name); - } - } -} - -void DepsgraphRelationBuilder::add_particle_forcefield_relations( - const OperationKey &key, - Object *object, - ParticleSystem *psys, - EffectorWeights *eff, - bool add_absorption, - const char *name) -{ - ListBase *relations = build_effector_relations(graph_, eff->group); - - LISTBASE_FOREACH (EffectorRelation *, relation, relations) { - if (relation->ob != object) { - /* Relation to forcefield object, optionally including geometry. */ - ComponentKey eff_key(&relation->ob->id, NodeType::TRANSFORM); - add_relation(eff_key, key, name); - - if (ELEM(relation->pd->shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS) || - relation->pd->forcefield == PFIELD_GUIDE) - { - ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); - add_relation(mod_key, key, name); - } - - /* Smoke flow relations. */ - if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) { - ComponentKey trf_key(&relation->pd->f_source->id, - NodeType::TRANSFORM); - add_relation(trf_key, key, "Smoke Force Domain"); - ComponentKey eff_key(&relation->pd->f_source->id, - NodeType::GEOMETRY); - add_relation(eff_key, key, "Smoke Force Domain"); - } - - /* Absorption forces need collision relation. */ - if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { - add_particle_collision_relations(key, - object, - NULL, - "Force Absorption"); - } - } - - if (relation->psys) { - if (relation->ob != object) { - ComponentKey eff_key(&relation->ob->id, - NodeType::PARTICLE_SYSTEM); - add_relation(eff_key, key, name); - /* TODO: remove this when/if EVAL_PARTICLES is sufficient - * for up to date particles. */ - ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); - add_relation(mod_key, key, name); - } - else if (relation->psys != psys) { - OperationKey eff_key(&relation->ob->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_EVAL, - relation->psys->name); - add_relation(eff_key, key, name); - } - } - } + DEG::IDNode *id_node = graph_->find_id_node(id); + if (id_node == NULL) { + BLI_assert(!"ID should always be valid"); + } + else { + id_node->eval_flags |= flag; + } +} + +Relation *DepsgraphRelationBuilder::add_time_relation(TimeSourceNode *timesrc, + Node *node_to, + const char *description, + int flags) +{ + if (timesrc && node_to) { + return graph_->add_new_relation(timesrc, node_to, description, flags); + } + else { + DEG_DEBUG_PRINTF((::Depsgraph *)graph_, + BUILD, + "add_time_relation(%p = %s, %p = %s, %s) Failed\n", + timesrc, + (timesrc) ? timesrc->identifier().c_str() : "<None>", + node_to, + (node_to) ? node_to->identifier().c_str() : "<None>", + description); + } + return NULL; +} + +Relation *DepsgraphRelationBuilder::add_operation_relation(OperationNode *node_from, + OperationNode *node_to, + const char *description, + int flags) +{ + if (node_from && node_to) { + return graph_->add_new_relation(node_from, node_to, description, flags); + } + else { + DEG_DEBUG_PRINTF((::Depsgraph *)graph_, + BUILD, + "add_operation_relation(%p = %s, %p = %s, %s) Failed\n", + node_from, + (node_from) ? node_from->identifier().c_str() : "<None>", + node_to, + (node_to) ? node_to->identifier().c_str() : "<None>", + description); + } + return NULL; +} + +void DepsgraphRelationBuilder::add_particle_collision_relations(const OperationKey &key, + Object *object, + Collection *collection, + const char *name) +{ + ListBase *relations = build_collision_relations(graph_, collection, eModifierType_Collision); + + LISTBASE_FOREACH (CollisionRelation *, relation, relations) { + if (relation->ob != object) { + ComponentKey trf_key(&relation->ob->id, NodeType::TRANSFORM); + add_relation(trf_key, key, name); + + ComponentKey coll_key(&relation->ob->id, NodeType::GEOMETRY); + add_relation(coll_key, key, name); + } + } +} + +void DepsgraphRelationBuilder::add_particle_forcefield_relations(const OperationKey &key, + Object *object, + ParticleSystem *psys, + EffectorWeights *eff, + bool add_absorption, + const char *name) +{ + ListBase *relations = build_effector_relations(graph_, eff->group); + + LISTBASE_FOREACH (EffectorRelation *, relation, relations) { + if (relation->ob != object) { + /* Relation to forcefield object, optionally including geometry. */ + ComponentKey eff_key(&relation->ob->id, NodeType::TRANSFORM); + add_relation(eff_key, key, name); + + if (ELEM(relation->pd->shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS) || + relation->pd->forcefield == PFIELD_GUIDE) { + ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); + add_relation(mod_key, key, name); + } + + /* Smoke flow relations. */ + if (relation->pd->forcefield == PFIELD_SMOKEFLOW && relation->pd->f_source) { + ComponentKey trf_key(&relation->pd->f_source->id, NodeType::TRANSFORM); + add_relation(trf_key, key, "Smoke Force Domain"); + ComponentKey eff_key(&relation->pd->f_source->id, NodeType::GEOMETRY); + add_relation(eff_key, key, "Smoke Force Domain"); + } + + /* Absorption forces need collision relation. */ + if (add_absorption && (relation->pd->flag & PFIELD_VISIBILITY)) { + add_particle_collision_relations(key, object, NULL, "Force Absorption"); + } + } + + if (relation->psys) { + if (relation->ob != object) { + ComponentKey eff_key(&relation->ob->id, NodeType::PARTICLE_SYSTEM); + add_relation(eff_key, key, name); + /* TODO: remove this when/if EVAL_PARTICLES is sufficient + * for up to date particles. */ + ComponentKey mod_key(&relation->ob->id, NodeType::GEOMETRY); + add_relation(mod_key, key, name); + } + else if (relation->psys != psys) { + OperationKey eff_key(&relation->ob->id, + NodeType::PARTICLE_SYSTEM, + OperationCode::PARTICLE_SYSTEM_EVAL, + relation->psys->name); + add_relation(eff_key, key, name); + } + } + } } Depsgraph *DepsgraphRelationBuilder::getGraph() { - return graph_; + return graph_; } /* **** Functions to build relations between entities **** */ @@ -455,549 +438,491 @@ void DepsgraphRelationBuilder::begin_build() void DepsgraphRelationBuilder::build_id(ID *id) { - if (id == NULL) { - return; - } - switch (GS(id->name)) { - case ID_AC: - build_action((bAction *)id); - break; - case ID_AR: - build_armature((bArmature *)id); - break; - case ID_CA: - build_camera((Camera *)id); - break; - case ID_GR: - build_collection(NULL, NULL, (Collection *)id); - break; - case ID_OB: - build_object(NULL, (Object *)id); - break; - case ID_KE: - build_shapekeys((Key *)id); - break; - case ID_LA: - build_light((Light *)id); - break; - case ID_LP: - build_lightprobe((LightProbe *)id); - break; - case ID_NT: - build_nodetree((bNodeTree *)id); - break; - case ID_MA: - build_material((Material *)id); - break; - case ID_TE: - build_texture((Tex *)id); - break; - case ID_IM: - build_image((Image *)id); - break; - case ID_WO: - build_world((World *)id); - break; - case ID_MSK: - build_mask((Mask *)id); - break; - case ID_MC: - build_movieclip((MovieClip *)id); - break; - case ID_ME: - case ID_CU: - case ID_MB: - case ID_LT: - build_object_data_geometry_datablock(id); - break; - case ID_SPK: - build_speaker((Speaker *)id); - break; - case ID_TXT: - /* Not a part of dependency graph. */ - break; - case ID_CF: - build_cachefile((CacheFile *)id); - break; - default: - fprintf(stderr, "Unhandled ID %s\n", id->name); - BLI_assert(!"Should never happen"); - break; - } -} - -void DepsgraphRelationBuilder::build_collection( - LayerCollection *from_layer_collection, - Object *object, - Collection *collection) -{ - if (from_layer_collection != NULL) { - /* If we came from layer collection we don't go deeper, view layer - * builder takes care of going deeper. - * - * NOTE: Do early output before tagging build as done, so possbile - * subsequent builds from outside of the layer collection properly - * recurses into all the nested objects and collections. */ - return; - } - const bool group_done = built_map_.checkIsBuiltAndTag(collection); - OperationKey object_transform_final_key(object != NULL ? &object->id : NULL, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - ComponentKey duplicator_key(object != NULL ? &object->id : NULL, - NodeType::DUPLI); - if (!group_done) { - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - build_object(NULL, cob->ob); - } - LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - build_collection(NULL, NULL, child->collection); - } - } - if (object != NULL) { - FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN(collection, ob, graph_->mode) - { - ComponentKey dupli_transform_key(&ob->id, NodeType::TRANSFORM); - add_relation(dupli_transform_key, - object_transform_final_key, - "Dupligroup"); - /* Hook to special component, to ensure proper visibility/evaluation - * optimizations. */ - add_relation(dupli_transform_key, duplicator_key, "Dupligroup"); - const NodeType dupli_geometry_component_type = - geometry_tag_to_component(&ob->id); - if (dupli_geometry_component_type != NodeType::UNDEFINED) { - ComponentKey dupli_geometry_component_key( - &ob->id, dupli_geometry_component_type); - add_relation(dupli_geometry_component_key, - duplicator_key, - "Dupligroup"); - } - } - FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; - } + if (id == NULL) { + return; + } + switch (GS(id->name)) { + case ID_AC: + build_action((bAction *)id); + break; + case ID_AR: + build_armature((bArmature *)id); + break; + case ID_CA: + build_camera((Camera *)id); + break; + case ID_GR: + build_collection(NULL, NULL, (Collection *)id); + break; + case ID_OB: + build_object(NULL, (Object *)id); + break; + case ID_KE: + build_shapekeys((Key *)id); + break; + case ID_LA: + build_light((Light *)id); + break; + case ID_LP: + build_lightprobe((LightProbe *)id); + break; + case ID_NT: + build_nodetree((bNodeTree *)id); + break; + case ID_MA: + build_material((Material *)id); + break; + case ID_TE: + build_texture((Tex *)id); + break; + case ID_IM: + build_image((Image *)id); + break; + case ID_WO: + build_world((World *)id); + break; + case ID_MSK: + build_mask((Mask *)id); + break; + case ID_MC: + build_movieclip((MovieClip *)id); + break; + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + build_object_data_geometry_datablock(id); + break; + case ID_SPK: + build_speaker((Speaker *)id); + break; + case ID_TXT: + /* Not a part of dependency graph. */ + break; + case ID_CF: + build_cachefile((CacheFile *)id); + break; + default: + fprintf(stderr, "Unhandled ID %s\n", id->name); + BLI_assert(!"Should never happen"); + break; + } +} + +void DepsgraphRelationBuilder::build_collection(LayerCollection *from_layer_collection, + Object *object, + Collection *collection) +{ + if (from_layer_collection != NULL) { + /* If we came from layer collection we don't go deeper, view layer + * builder takes care of going deeper. + * + * NOTE: Do early output before tagging build as done, so possbile + * subsequent builds from outside of the layer collection properly + * recurses into all the nested objects and collections. */ + return; + } + const bool group_done = built_map_.checkIsBuiltAndTag(collection); + OperationKey object_transform_final_key( + object != NULL ? &object->id : NULL, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + ComponentKey duplicator_key(object != NULL ? &object->id : NULL, NodeType::DUPLI); + if (!group_done) { + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + build_object(NULL, cob->ob); + } + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { + build_collection(NULL, NULL, child->collection); + } + } + if (object != NULL) { + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_BEGIN (collection, ob, graph_->mode) { + ComponentKey dupli_transform_key(&ob->id, NodeType::TRANSFORM); + add_relation(dupli_transform_key, object_transform_final_key, "Dupligroup"); + /* Hook to special component, to ensure proper visibility/evaluation + * optimizations. */ + add_relation(dupli_transform_key, duplicator_key, "Dupligroup"); + const NodeType dupli_geometry_component_type = geometry_tag_to_component(&ob->id); + if (dupli_geometry_component_type != NodeType::UNDEFINED) { + ComponentKey dupli_geometry_component_key(&ob->id, dupli_geometry_component_type); + add_relation(dupli_geometry_component_key, duplicator_key, "Dupligroup"); + } + } + FOREACH_COLLECTION_VISIBLE_OBJECT_RECURSIVE_END; + } } void DepsgraphRelationBuilder::build_object(Base *base, Object *object) { - if (built_map_.checkIsBuiltAndTag(object)) { - if (base != NULL) { - build_object_flags(base, object); - } - return; - } - /* Object Transforms */ - OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT - : OperationCode::TRANSFORM_LOCAL; - OperationKey base_op_key(&object->id, NodeType::TRANSFORM, base_op); - OperationKey init_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); - OperationKey local_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_LOCAL); - OperationKey parent_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_PARENT); - OperationKey final_transform_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); - OperationKey ob_eval_key( - &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); - add_relation(init_transform_key, local_transform_key, "Transform Init"); - /* Various flags, flushing from bases/collections. */ - build_object_flags(base, object); - /* Parenting. */ - if (object->parent != NULL) { - /* Make sure parent object's relations are built. */ - build_object(NULL, object->parent); - /* Parent relationship. */ - build_object_parent(object); - /* Local -> parent. */ - add_relation(local_transform_key, - parent_transform_key, - "ObLocal -> ObParent"); - } - /* Modifiers. */ - if (object->modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); - } - /* Shader FX. */ - if (object->shader_fx.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); - } - /* Constraints. */ - if (object->constraints.first != NULL) { - BuilderWalkUserData data; - data.builder = this; - BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); - } - /* Object constraints. */ - OperationKey object_transform_simulation_init_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - if (object->constraints.first != NULL) { - OperationKey constraint_key(&object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_CONSTRAINTS); - /* Constraint relations. */ - build_constraints(&object->id, - NodeType::TRANSFORM, - "", - &object->constraints, - NULL); - /* operation order */ - add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack"); - add_relation(constraint_key, final_transform_key, "ObConstraints -> Done"); - add_relation(constraint_key, ob_eval_key, "Constraint -> Transform Eval"); - add_relation(ob_eval_key, - object_transform_simulation_init_key, - "Transform Eval -> Simulation Init"); - add_relation(object_transform_simulation_init_key, - final_transform_key, - "Simulation -> Final Transform"); - } - else { - add_relation(base_op_key, ob_eval_key, "Eval"); - add_relation(ob_eval_key, - object_transform_simulation_init_key, - "Transform Eval -> Simulation Init"); - add_relation(object_transform_simulation_init_key, - final_transform_key, - "Simulation -> Final Transform"); - } - /* Animation data */ - build_animdata(&object->id); - /* Object data. */ - build_object_data(object); - /* Particle systems. */ - if (object->particlesystem.first != NULL) { - build_particle_systems(object); - } - /* Proxy object to copy from. */ - if (object->proxy_from != NULL) { - build_object(NULL, object->proxy_from); - ComponentKey ob_transform_key( - &object->proxy_from->id, NodeType::TRANSFORM); - ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); - add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); - } - if (object->proxy_group != NULL) { - build_object(NULL, object->proxy_group); - OperationKey proxy_group_eval_key(&object->proxy_group->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - add_relation(proxy_group_eval_key, - final_transform_key, - "Proxy Group Transform"); - } - /* Object dupligroup. */ - if (object->instance_collection != NULL) { - build_collection(NULL, object, object->instance_collection); - } - /* Point caches. */ - build_object_pointcache(object); - /* Syncronization back to original object. */ - OperationKey synchronize_key(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation( - final_transform_key, synchronize_key, "Synchronize to Original"); - /* Parameters. */ - build_parameters(&object->id); + if (built_map_.checkIsBuiltAndTag(object)) { + if (base != NULL) { + build_object_flags(base, object); + } + return; + } + /* Object Transforms */ + OperationCode base_op = (object->parent) ? OperationCode::TRANSFORM_PARENT : + OperationCode::TRANSFORM_LOCAL; + OperationKey base_op_key(&object->id, NodeType::TRANSFORM, base_op); + OperationKey init_transform_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_INIT); + OperationKey local_transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_LOCAL); + OperationKey parent_transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_PARENT); + OperationKey final_transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + OperationKey ob_eval_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + add_relation(init_transform_key, local_transform_key, "Transform Init"); + /* Various flags, flushing from bases/collections. */ + build_object_flags(base, object); + /* Parenting. */ + if (object->parent != NULL) { + /* Make sure parent object's relations are built. */ + build_object(NULL, object->parent); + /* Parent relationship. */ + build_object_parent(object); + /* Local -> parent. */ + add_relation(local_transform_key, parent_transform_key, "ObLocal -> ObParent"); + } + /* Modifiers. */ + if (object->modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_gpencil_modifiers_foreachIDLink(object, modifier_walk, &data); + } + /* Shader FX. */ + if (object->shader_fx.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_shaderfx_foreachIDLink(object, modifier_walk, &data); + } + /* Constraints. */ + if (object->constraints.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); + } + /* Object constraints. */ + OperationKey object_transform_simulation_init_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + if (object->constraints.first != NULL) { + OperationKey constraint_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_CONSTRAINTS); + /* Constraint relations. */ + build_constraints(&object->id, NodeType::TRANSFORM, "", &object->constraints, NULL); + /* operation order */ + add_relation(base_op_key, constraint_key, "ObBase-> Constraint Stack"); + add_relation(constraint_key, final_transform_key, "ObConstraints -> Done"); + add_relation(constraint_key, ob_eval_key, "Constraint -> Transform Eval"); + add_relation( + ob_eval_key, object_transform_simulation_init_key, "Transform Eval -> Simulation Init"); + add_relation(object_transform_simulation_init_key, + final_transform_key, + "Simulation -> Final Transform"); + } + else { + add_relation(base_op_key, ob_eval_key, "Eval"); + add_relation( + ob_eval_key, object_transform_simulation_init_key, "Transform Eval -> Simulation Init"); + add_relation(object_transform_simulation_init_key, + final_transform_key, + "Simulation -> Final Transform"); + } + /* Animation data */ + build_animdata(&object->id); + /* Object data. */ + build_object_data(object); + /* Particle systems. */ + if (object->particlesystem.first != NULL) { + build_particle_systems(object); + } + /* Proxy object to copy from. */ + if (object->proxy_from != NULL) { + build_object(NULL, object->proxy_from); + ComponentKey ob_transform_key(&object->proxy_from->id, NodeType::TRANSFORM); + ComponentKey proxy_transform_key(&object->id, NodeType::TRANSFORM); + add_relation(ob_transform_key, proxy_transform_key, "Proxy Transform"); + } + if (object->proxy_group != NULL) { + build_object(NULL, object->proxy_group); + OperationKey proxy_group_eval_key( + &object->proxy_group->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + add_relation(proxy_group_eval_key, final_transform_key, "Proxy Group Transform"); + } + /* Object dupligroup. */ + if (object->instance_collection != NULL) { + build_collection(NULL, object, object->instance_collection); + } + /* Point caches. */ + build_object_pointcache(object); + /* Syncronization back to original object. */ + OperationKey synchronize_key( + &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); + add_relation(final_transform_key, synchronize_key, "Synchronize to Original"); + /* Parameters. */ + build_parameters(&object->id); } void DepsgraphRelationBuilder::build_object_flags(Base *base, Object *object) { - if (base == NULL) { - return; - } - OperationKey view_layer_done_key(&scene_->id, - NodeType::LAYER_COLLECTIONS, - OperationCode::VIEW_LAYER_EVAL); - OperationKey object_flags_key(&object->id, - NodeType::OBJECT_FROM_LAYER, - OperationCode::OBJECT_BASE_FLAGS); - add_relation(view_layer_done_key, object_flags_key, "Base flags flush"); - /* Syncronization back to original object. */ - OperationKey synchronize_key(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation( - object_flags_key, synchronize_key, "Synchronize to Original"); + if (base == NULL) { + return; + } + OperationKey view_layer_done_key( + &scene_->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL); + OperationKey object_flags_key( + &object->id, NodeType::OBJECT_FROM_LAYER, OperationCode::OBJECT_BASE_FLAGS); + add_relation(view_layer_done_key, object_flags_key, "Base flags flush"); + /* Syncronization back to original object. */ + OperationKey synchronize_key( + &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); + add_relation(object_flags_key, synchronize_key, "Synchronize to Original"); } void DepsgraphRelationBuilder::build_object_data(Object *object) { - if (object->data == NULL) { - return; - } - ID *obdata_id = (ID *)object->data; - /* Object data animation. */ - if (!built_map_.checkIsBuilt(obdata_id)) { - build_animdata(obdata_id); - } - /* type-specific data. */ - switch (object->type) { - case OB_MESH: - case OB_CURVE: - case OB_FONT: - case OB_SURF: - case OB_MBALL: - case OB_LATTICE: - case OB_GPENCIL: - { - build_object_data_geometry(object); - /* TODO(sergey): Only for until we support granular - * update of curves. */ - if (object->type == OB_FONT) { - Curve *curve = (Curve *)object->data; - if (curve->textoncurve) { - add_special_eval_flag(&curve->textoncurve->id, DAG_EVAL_NEED_CURVE_PATH); - } - } - break; - } - case OB_ARMATURE: - if (ID_IS_LINKED(object) && object->proxy_from != NULL) { - build_proxy_rig(object); - } - else { - build_rig(object); - } - break; - case OB_LAMP: - build_object_data_light(object); - break; - case OB_CAMERA: - build_object_data_camera(object); - break; - case OB_LIGHTPROBE: - build_object_data_lightprobe(object); - break; - case OB_SPEAKER: - build_object_data_speaker(object); - break; - } - Key *key = BKE_key_from_object(object); - if (key != NULL) { - ComponentKey geometry_key((ID *)object->data, NodeType::GEOMETRY); - ComponentKey key_key(&key->id, NodeType::GEOMETRY); - add_relation(key_key, geometry_key, "Shapekeys"); - build_nested_shapekey(&object->id, key); - } + if (object->data == NULL) { + return; + } + ID *obdata_id = (ID *)object->data; + /* Object data animation. */ + if (!built_map_.checkIsBuilt(obdata_id)) { + build_animdata(obdata_id); + } + /* type-specific data. */ + switch (object->type) { + case OB_MESH: + case OB_CURVE: + case OB_FONT: + case OB_SURF: + case OB_MBALL: + case OB_LATTICE: + case OB_GPENCIL: { + build_object_data_geometry(object); + /* TODO(sergey): Only for until we support granular + * update of curves. */ + if (object->type == OB_FONT) { + Curve *curve = (Curve *)object->data; + if (curve->textoncurve) { + add_special_eval_flag(&curve->textoncurve->id, DAG_EVAL_NEED_CURVE_PATH); + } + } + break; + } + case OB_ARMATURE: + if (ID_IS_LINKED(object) && object->proxy_from != NULL) { + build_proxy_rig(object); + } + else { + build_rig(object); + } + break; + case OB_LAMP: + build_object_data_light(object); + break; + case OB_CAMERA: + build_object_data_camera(object); + break; + case OB_LIGHTPROBE: + build_object_data_lightprobe(object); + break; + case OB_SPEAKER: + build_object_data_speaker(object); + break; + } + Key *key = BKE_key_from_object(object); + if (key != NULL) { + ComponentKey geometry_key((ID *)object->data, NodeType::GEOMETRY); + ComponentKey key_key(&key->id, NodeType::GEOMETRY); + add_relation(key_key, geometry_key, "Shapekeys"); + build_nested_shapekey(&object->id, key); + } } void DepsgraphRelationBuilder::build_object_data_camera(Object *object) { - Camera *camera = (Camera *)object->data; - build_camera(camera); - ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); - ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); - add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object"); + Camera *camera = (Camera *)object->data; + build_camera(camera); + ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); + ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); + add_relation(camera_parameters_key, object_parameters_key, "Camera -> Object"); } void DepsgraphRelationBuilder::build_object_data_light(Object *object) { - Light *lamp = (Light *)object->data; - build_light(lamp); - ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); - ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); - add_relation(lamp_parameters_key, object_parameters_key, "Light -> Object"); + Light *lamp = (Light *)object->data; + build_light(lamp); + ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); + ComponentKey object_parameters_key(&object->id, NodeType::PARAMETERS); + add_relation(lamp_parameters_key, object_parameters_key, "Light -> Object"); } void DepsgraphRelationBuilder::build_object_data_lightprobe(Object *object) { - LightProbe *probe = (LightProbe *)object->data; - build_lightprobe(probe); - OperationKey probe_key(&probe->id, - NodeType::PARAMETERS, - OperationCode::LIGHT_PROBE_EVAL); - OperationKey object_key(&object->id, - NodeType::PARAMETERS, - OperationCode::LIGHT_PROBE_EVAL); - add_relation(probe_key, object_key, "LightProbe Update"); + LightProbe *probe = (LightProbe *)object->data; + build_lightprobe(probe); + OperationKey probe_key(&probe->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + OperationKey object_key(&object->id, NodeType::PARAMETERS, OperationCode::LIGHT_PROBE_EVAL); + add_relation(probe_key, object_key, "LightProbe Update"); } void DepsgraphRelationBuilder::build_object_data_speaker(Object *object) { - Speaker *speaker = (Speaker *)object->data; - build_speaker(speaker); - OperationKey probe_key(&speaker->id, - NodeType::PARAMETERS, - OperationCode::SPEAKER_EVAL); - OperationKey object_key(&object->id, - NodeType::PARAMETERS, - OperationCode::SPEAKER_EVAL); - add_relation(probe_key, object_key, "Speaker Update"); + Speaker *speaker = (Speaker *)object->data; + build_speaker(speaker); + OperationKey probe_key(&speaker->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + OperationKey object_key(&object->id, NodeType::PARAMETERS, OperationCode::SPEAKER_EVAL); + add_relation(probe_key, object_key, "Speaker Update"); } void DepsgraphRelationBuilder::build_object_parent(Object *object) { - Object *parent = object->parent; - ID *parent_id = &object->parent->id; - ComponentKey ob_key(&object->id, NodeType::TRANSFORM); - /* Type-specific links/ */ - switch (object->partype) { - /* Armature Deform (Virtual Modifier) */ - case PARSKEL: - { - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Armature Deform Parent"); - break; - } - - /* Vertex Parent */ - case PARVERT1: - case PARVERT3: - { - ComponentKey parent_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Vertex Parent"); - /* Original index is used for optimizations of lookups for subdiv - * only meshes. - * TODO(sergey): This optimization got lost at 2.8, so either verify - * we can get rid of this mask here, or bring the optimization - * back. */ - add_customdata_mask(object->parent, - DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX) | - DEGCustomDataMeshMasks::MaskEdge(CD_MASK_ORIGINDEX) | - DEGCustomDataMeshMasks::MaskFace(CD_MASK_ORIGINDEX) | - DEGCustomDataMeshMasks::MaskPoly(CD_MASK_ORIGINDEX)); - ComponentKey transform_key(parent_id, NodeType::TRANSFORM); - add_relation(transform_key, ob_key, "Vertex Parent TFM"); - break; - } - - /* Bone Parent */ - case PARBONE: - { - ComponentKey parent_bone_key( - parent_id, NodeType::BONE, object->parsubstr); - OperationKey parent_transform_key(parent_id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(parent_bone_key, ob_key, "Bone Parent"); - add_relation(parent_transform_key, ob_key, "Armature Parent"); - break; - } - - default: - { - if (object->parent->type == OB_LATTICE) { - /* Lattice Deform Parent - Virtual Modifier. */ - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - ComponentKey geom_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Lattice Deform Parent"); - add_relation(geom_key, ob_key, "Lattice Deform Parent Geom"); - } - else if (object->parent->type == OB_CURVE) { - Curve *cu = (Curve *)object->parent->data; - - if (cu->flag & CU_PATH) { - /* Follow Path. */ - ComponentKey parent_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Curve Follow Parent"); - ComponentKey transform_key(parent_id, NodeType::TRANSFORM); - add_relation(transform_key, ob_key, "Curve Follow TFM"); - } - else { - /* Standard Parent. */ - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Curve Parent"); - } - } - else { - /* Standard Parent. */ - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Parent"); - } - break; - } - } - /* Metaballs are the odd balls here (no pun intended): they will request - * instance-list (formerly known as dupli-list) during evaluation. This is - * their way of interacting with all instanced surfaces, making a nice - * effect when is used form particle system. */ - if (object->type == OB_MBALL && parent->transflag & OB_DUPLI) { - ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY); - /* NOTE: Metaballs are evaluating geometry only after their transform, - * so we onl;y hook up to transform channel here. */ - add_relation(parent_geometry_key, ob_key, "Parent"); - } - - /* Dupliverts uses original vertex index. */ - if (parent->transflag & OB_DUPLIVERTS) { - add_customdata_mask(parent, DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX)); - } + Object *parent = object->parent; + ID *parent_id = &object->parent->id; + ComponentKey ob_key(&object->id, NodeType::TRANSFORM); + /* Type-specific links/ */ + switch (object->partype) { + /* Armature Deform (Virtual Modifier) */ + case PARSKEL: { + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + add_relation(parent_key, ob_key, "Armature Deform Parent"); + break; + } + + /* Vertex Parent */ + case PARVERT1: + case PARVERT3: { + ComponentKey parent_key(parent_id, NodeType::GEOMETRY); + add_relation(parent_key, ob_key, "Vertex Parent"); + /* Original index is used for optimizations of lookups for subdiv + * only meshes. + * TODO(sergey): This optimization got lost at 2.8, so either verify + * we can get rid of this mask here, or bring the optimization + * back. */ + add_customdata_mask(object->parent, + DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX) | + DEGCustomDataMeshMasks::MaskEdge(CD_MASK_ORIGINDEX) | + DEGCustomDataMeshMasks::MaskFace(CD_MASK_ORIGINDEX) | + DEGCustomDataMeshMasks::MaskPoly(CD_MASK_ORIGINDEX)); + ComponentKey transform_key(parent_id, NodeType::TRANSFORM); + add_relation(transform_key, ob_key, "Vertex Parent TFM"); + break; + } + + /* Bone Parent */ + case PARBONE: { + ComponentKey parent_bone_key(parent_id, NodeType::BONE, object->parsubstr); + OperationKey parent_transform_key( + parent_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(parent_bone_key, ob_key, "Bone Parent"); + add_relation(parent_transform_key, ob_key, "Armature Parent"); + break; + } + + default: { + if (object->parent->type == OB_LATTICE) { + /* Lattice Deform Parent - Virtual Modifier. */ + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + ComponentKey geom_key(parent_id, NodeType::GEOMETRY); + add_relation(parent_key, ob_key, "Lattice Deform Parent"); + add_relation(geom_key, ob_key, "Lattice Deform Parent Geom"); + } + else if (object->parent->type == OB_CURVE) { + Curve *cu = (Curve *)object->parent->data; + + if (cu->flag & CU_PATH) { + /* Follow Path. */ + ComponentKey parent_key(parent_id, NodeType::GEOMETRY); + add_relation(parent_key, ob_key, "Curve Follow Parent"); + ComponentKey transform_key(parent_id, NodeType::TRANSFORM); + add_relation(transform_key, ob_key, "Curve Follow TFM"); + } + else { + /* Standard Parent. */ + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + add_relation(parent_key, ob_key, "Curve Parent"); + } + } + else { + /* Standard Parent. */ + ComponentKey parent_key(parent_id, NodeType::TRANSFORM); + add_relation(parent_key, ob_key, "Parent"); + } + break; + } + } + /* Metaballs are the odd balls here (no pun intended): they will request + * instance-list (formerly known as dupli-list) during evaluation. This is + * their way of interacting with all instanced surfaces, making a nice + * effect when is used form particle system. */ + if (object->type == OB_MBALL && parent->transflag & OB_DUPLI) { + ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY); + /* NOTE: Metaballs are evaluating geometry only after their transform, + * so we onl;y hook up to transform channel here. */ + add_relation(parent_geometry_key, ob_key, "Parent"); + } + + /* Dupliverts uses original vertex index. */ + if (parent->transflag & OB_DUPLIVERTS) { + add_customdata_mask(parent, DEGCustomDataMeshMasks::MaskVert(CD_MASK_ORIGINDEX)); + } } void DepsgraphRelationBuilder::build_object_pointcache(Object *object) { - ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); - /* Different point caches are affecting different aspects of life of the - * object. We keep track of those aspects and avoid duplicate relations. */ - enum { - FLAG_TRANSFORM = (1 << 0), - FLAG_GEOMETRY = (1 << 1), - FLAG_ALL = (FLAG_TRANSFORM | FLAG_GEOMETRY), - }; - ListBase ptcache_id_list; - BKE_ptcache_ids_from_object(&ptcache_id_list, object, scene_, 0); - int handled_components = 0; - LISTBASE_FOREACH (PTCacheID *, ptcache_id, &ptcache_id_list) { - /* Check which components needs the point cache. */ - int flag = -1; - if (ptcache_id->type == PTCACHE_TYPE_RIGIDBODY) { - flag = FLAG_TRANSFORM; - OperationKey transform_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - add_relation(point_cache_key, - transform_key, - "Point Cache -> Rigid Body"); - } - else { - flag = FLAG_GEOMETRY; - OperationKey geometry_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - add_relation( - point_cache_key, geometry_key, "Point Cache -> Geometry"); - } - BLI_assert(flag != -1); - /* Tag that we did handle that component. */ - handled_components |= flag; - if (handled_components == FLAG_ALL) { - break; - } - } - /* Manual edits to any dependency (or self) should reset the point cache. */ - if (!BLI_listbase_is_empty(&ptcache_id_list)) { - OperationKey transform_eval_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - OperationKey geometry_init_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL_INIT); - add_relation(transform_eval_key, - point_cache_key, - "Transform Simulation -> Point Cache", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - add_relation(geometry_init_key, - point_cache_key, - "Geometry Init -> Point Cache", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - } - BLI_freelistN(&ptcache_id_list); + ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); + /* Different point caches are affecting different aspects of life of the + * object. We keep track of those aspects and avoid duplicate relations. */ + enum { + FLAG_TRANSFORM = (1 << 0), + FLAG_GEOMETRY = (1 << 1), + FLAG_ALL = (FLAG_TRANSFORM | FLAG_GEOMETRY), + }; + ListBase ptcache_id_list; + BKE_ptcache_ids_from_object(&ptcache_id_list, object, scene_, 0); + int handled_components = 0; + LISTBASE_FOREACH (PTCacheID *, ptcache_id, &ptcache_id_list) { + /* Check which components needs the point cache. */ + int flag = -1; + if (ptcache_id->type == PTCACHE_TYPE_RIGIDBODY) { + flag = FLAG_TRANSFORM; + OperationKey transform_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + add_relation(point_cache_key, transform_key, "Point Cache -> Rigid Body"); + } + else { + flag = FLAG_GEOMETRY; + OperationKey geometry_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + add_relation(point_cache_key, geometry_key, "Point Cache -> Geometry"); + } + BLI_assert(flag != -1); + /* Tag that we did handle that component. */ + handled_components |= flag; + if (handled_components == FLAG_ALL) { + break; + } + } + /* Manual edits to any dependency (or self) should reset the point cache. */ + if (!BLI_listbase_is_empty(&ptcache_id_list)) { + OperationKey transform_eval_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + OperationKey geometry_init_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + add_relation(transform_eval_key, + point_cache_key, + "Transform Simulation -> Point Cache", + RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + add_relation(geometry_init_key, + point_cache_key, + "Geometry Init -> Point Cache", + RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + } + BLI_freelistN(&ptcache_id_list); } void DepsgraphRelationBuilder::build_constraints(ID *id, @@ -1006,1069 +931,879 @@ void DepsgraphRelationBuilder::build_constraints(ID *id, ListBase *constraints, RootPChanMap *root_map) { - OperationKey constraint_op_key( - id, - component_type, - component_subdata, - (component_type == NodeType::BONE) - ? OperationCode::BONE_CONSTRAINTS - : OperationCode::TRANSFORM_CONSTRAINTS); - /* Add dependencies for each constraint in turn. */ - for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - /* Invalid constraint type. */ - if (cti == NULL) { - continue; - } - /* Special case for camera tracking -- it doesn't use targets to - * define relations. */ - /* TODO: we can now represent dependencies in a much richer manner, - * so review how this is done. */ - if (ELEM(cti->type, - CONSTRAINT_TYPE_FOLLOWTRACK, - CONSTRAINT_TYPE_CAMERASOLVER, - CONSTRAINT_TYPE_OBJECTSOLVER)) - { - bool depends_on_camera = false; - if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; - if (((data->clip) || - (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) - { - depends_on_camera = true; - } - if (data->depth_ob) { - ComponentKey depth_transform_key(&data->depth_ob->id, - NodeType::TRANSFORM); - ComponentKey depth_geometry_key(&data->depth_ob->id, - NodeType::GEOMETRY); - add_relation(depth_transform_key, constraint_op_key, cti->name); - add_relation(depth_geometry_key, constraint_op_key, cti->name); - } - } - else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - depends_on_camera = true; - } - if (depends_on_camera && scene_->camera != NULL) { - ComponentKey camera_key(&scene_->camera->id, NodeType::TRANSFORM); - add_relation(camera_key, constraint_op_key, cti->name); - } - /* TODO(sergey): This is more a TimeSource -> MovieClip -> - * Constraint dependency chain. */ - TimeSourceKey time_src_key; - add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); - } - else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { - /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint - * dependency chain. */ - TimeSourceKey time_src_key; - add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); - bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; - if (data->cache_file) { - ComponentKey cache_key(&data->cache_file->id, NodeType::CACHE); - add_relation(cache_key, constraint_op_key, cti->name); - } - } - else if (cti->get_constraint_targets) { - ListBase targets = {NULL, NULL}; - cti->get_constraint_targets(con, &targets); - LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { - if (ct->tar == NULL) { - continue; - } - if (ELEM(con->type, - CONSTRAINT_TYPE_KINEMATIC, - CONSTRAINT_TYPE_SPLINEIK)) - { - /* Ignore IK constraints - these are handled separately - * (on pose level). */ - } - else if (ELEM(con->type, - CONSTRAINT_TYPE_FOLLOWPATH, - CONSTRAINT_TYPE_CLAMPTO)) - { - /* These constraints require path geometry data. */ - ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); - add_relation(target_key, constraint_op_key, cti->name); - ComponentKey target_transform_key(&ct->tar->id, - NodeType::TRANSFORM); - add_relation(target_transform_key, constraint_op_key, cti->name); - } - else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { - OperationCode opcode; - /* relation to bone */ - opcode = bone_target_opcode(&ct->tar->id, ct->subtarget, - id, component_subdata, root_map); - /* Armature constraint always wants the final position and chan_mat. */ - if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { - opcode = OperationCode::BONE_DONE; - } - /* if needs bbone shape, reference the segment computation */ - if (BKE_constraint_target_uses_bbone(con, ct) && - bone_has_segments(ct->tar, ct->subtarget)) - { - opcode = OperationCode::BONE_SEGMENTS; - } - OperationKey target_key(&ct->tar->id, - NodeType::BONE, - ct->subtarget, - opcode); - add_relation(target_key, constraint_op_key, cti->name); - } - else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && - (ct->subtarget[0])) - { - /* Vertex group. */ - /* NOTE: Vertex group is likely to be used to get vertices - * in a world space. This requires to know both geometry - * and transformation of the target object. */ - ComponentKey target_transform_key( - &ct->tar->id, NodeType::TRANSFORM); - ComponentKey target_geometry_key( - &ct->tar->id, NodeType::GEOMETRY); - add_relation( - target_transform_key, constraint_op_key, cti->name); - add_relation( - target_geometry_key, constraint_op_key, cti->name); - add_customdata_mask(ct->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); - } - else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { - bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *) con->data; - - /* Constraints which requires the target object surface. */ - ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); - add_relation(target_key, constraint_op_key, cti->name); - - /* Add dependency on normal layers if necessary. */ - if (ct->tar->type == OB_MESH && scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) { - bool track = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; - if (track || BKE_shrinkwrap_needs_normals(scon->shrinkType, scon->shrinkMode)) { - add_customdata_mask(ct->tar, - DEGCustomDataMeshMasks::MaskVert(CD_MASK_NORMAL) | - DEGCustomDataMeshMasks::MaskLoop(CD_MASK_CUSTOMLOOPNORMAL)); - } - if (scon->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { - add_special_eval_flag(&ct->tar->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); - } - } - - /* NOTE: obdata eval now doesn't necessarily depend on the - * object's transform. */ - ComponentKey target_transform_key(&ct->tar->id, - NodeType::TRANSFORM); - add_relation(target_transform_key, constraint_op_key, cti->name); - } - else { - /* Standard object relation. */ - // TODO: loc vs rot vs scale? - if (&ct->tar->id == id) { - /* Constraint targeting own object: - * - This case is fine IFF we're dealing with a bone - * constraint pointing to its own armature. In that - * case, it's just transform -> bone. - * - If however it is a real self targeting case, just - * make it depend on the previous constraint (or the - * pre-constraint state). */ - if ((ct->tar->type == OB_ARMATURE) && - (component_type == NodeType::BONE)) - { - OperationKey target_key(&ct->tar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(target_key, constraint_op_key, cti->name); - } - else { - OperationKey target_key(&ct->tar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_LOCAL); - add_relation(target_key, constraint_op_key, cti->name); - } - } - else { - /* Normal object dependency. */ - OperationKey target_key(&ct->tar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(target_key, constraint_op_key, cti->name); - } - } - /* Constraints which needs world's matrix for transform. - * TODO(sergey): More constraints here? */ - if (ELEM(con->type, - CONSTRAINT_TYPE_ROTLIKE, - CONSTRAINT_TYPE_SIZELIKE, - CONSTRAINT_TYPE_LOCLIKE, - CONSTRAINT_TYPE_TRANSLIKE)) - { - /* TODO(sergey): Add used space check. */ - ComponentKey target_transform_key(&ct->tar->id, - NodeType::TRANSFORM); - add_relation(target_transform_key, constraint_op_key, cti->name); - } - } - if (cti->flush_constraint_targets) { - cti->flush_constraint_targets(con, &targets, 1); - } - } - } + OperationKey constraint_op_key(id, + component_type, + component_subdata, + (component_type == NodeType::BONE) ? + OperationCode::BONE_CONSTRAINTS : + OperationCode::TRANSFORM_CONSTRAINTS); + /* Add dependencies for each constraint in turn. */ + for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + /* Invalid constraint type. */ + if (cti == NULL) { + continue; + } + /* Special case for camera tracking -- it doesn't use targets to + * define relations. */ + /* TODO: we can now represent dependencies in a much richer manner, + * so review how this is done. */ + if (ELEM(cti->type, + CONSTRAINT_TYPE_FOLLOWTRACK, + CONSTRAINT_TYPE_CAMERASOLVER, + CONSTRAINT_TYPE_OBJECTSOLVER)) { + bool depends_on_camera = false; + if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) { + bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data; + if (((data->clip) || (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0]) { + depends_on_camera = true; + } + if (data->depth_ob) { + ComponentKey depth_transform_key(&data->depth_ob->id, NodeType::TRANSFORM); + ComponentKey depth_geometry_key(&data->depth_ob->id, NodeType::GEOMETRY); + add_relation(depth_transform_key, constraint_op_key, cti->name); + add_relation(depth_geometry_key, constraint_op_key, cti->name); + } + } + else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) { + depends_on_camera = true; + } + if (depends_on_camera && scene_->camera != NULL) { + ComponentKey camera_key(&scene_->camera->id, NodeType::TRANSFORM); + add_relation(camera_key, constraint_op_key, cti->name); + } + /* TODO(sergey): This is more a TimeSource -> MovieClip -> + * Constraint dependency chain. */ + TimeSourceKey time_src_key; + add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); + } + else if (cti->type == CONSTRAINT_TYPE_TRANSFORM_CACHE) { + /* TODO(kevin): This is more a TimeSource -> CacheFile -> Constraint + * dependency chain. */ + TimeSourceKey time_src_key; + add_relation(time_src_key, constraint_op_key, "TimeSrc -> Animation"); + bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; + if (data->cache_file) { + ComponentKey cache_key(&data->cache_file->id, NodeType::CACHE); + add_relation(cache_key, constraint_op_key, cti->name); + } + } + else if (cti->get_constraint_targets) { + ListBase targets = {NULL, NULL}; + cti->get_constraint_targets(con, &targets); + LISTBASE_FOREACH (bConstraintTarget *, ct, &targets) { + if (ct->tar == NULL) { + continue; + } + if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { + /* Ignore IK constraints - these are handled separately + * (on pose level). */ + } + else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) { + /* These constraints require path geometry data. */ + ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); + add_relation(target_key, constraint_op_key, cti->name); + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); + } + else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) { + OperationCode opcode; + /* relation to bone */ + opcode = bone_target_opcode( + &ct->tar->id, ct->subtarget, id, component_subdata, root_map); + /* Armature constraint always wants the final position and chan_mat. */ + if (ELEM(con->type, CONSTRAINT_TYPE_ARMATURE)) { + opcode = OperationCode::BONE_DONE; + } + /* if needs bbone shape, reference the segment computation */ + if (BKE_constraint_target_uses_bbone(con, ct) && + bone_has_segments(ct->tar, ct->subtarget)) { + opcode = OperationCode::BONE_SEGMENTS; + } + OperationKey target_key(&ct->tar->id, NodeType::BONE, ct->subtarget, opcode); + add_relation(target_key, constraint_op_key, cti->name); + } + else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) { + /* Vertex group. */ + /* NOTE: Vertex group is likely to be used to get vertices + * in a world space. This requires to know both geometry + * and transformation of the target object. */ + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + ComponentKey target_geometry_key(&ct->tar->id, NodeType::GEOMETRY); + add_relation(target_transform_key, constraint_op_key, cti->name); + add_relation(target_geometry_key, constraint_op_key, cti->name); + add_customdata_mask(ct->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); + } + else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) { + bShrinkwrapConstraint *scon = (bShrinkwrapConstraint *)con->data; + + /* Constraints which requires the target object surface. */ + ComponentKey target_key(&ct->tar->id, NodeType::GEOMETRY); + add_relation(target_key, constraint_op_key, cti->name); + + /* Add dependency on normal layers if necessary. */ + if (ct->tar->type == OB_MESH && scon->shrinkType != MOD_SHRINKWRAP_NEAREST_VERTEX) { + bool track = (scon->flag & CON_SHRINKWRAP_TRACK_NORMAL) != 0; + if (track || BKE_shrinkwrap_needs_normals(scon->shrinkType, scon->shrinkMode)) { + add_customdata_mask(ct->tar, + DEGCustomDataMeshMasks::MaskVert(CD_MASK_NORMAL) | + DEGCustomDataMeshMasks::MaskLoop(CD_MASK_CUSTOMLOOPNORMAL)); + } + if (scon->shrinkType == MOD_SHRINKWRAP_TARGET_PROJECT) { + add_special_eval_flag(&ct->tar->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY); + } + } + + /* NOTE: obdata eval now doesn't necessarily depend on the + * object's transform. */ + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); + } + else { + /* Standard object relation. */ + // TODO: loc vs rot vs scale? + if (&ct->tar->id == id) { + /* Constraint targeting own object: + * - This case is fine IFF we're dealing with a bone + * constraint pointing to its own armature. In that + * case, it's just transform -> bone. + * - If however it is a real self targeting case, just + * make it depend on the previous constraint (or the + * pre-constraint state). */ + if ((ct->tar->type == OB_ARMATURE) && (component_type == NodeType::BONE)) { + OperationKey target_key( + &ct->tar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(target_key, constraint_op_key, cti->name); + } + else { + OperationKey target_key( + &ct->tar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_LOCAL); + add_relation(target_key, constraint_op_key, cti->name); + } + } + else { + /* Normal object dependency. */ + OperationKey target_key( + &ct->tar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(target_key, constraint_op_key, cti->name); + } + } + /* Constraints which needs world's matrix for transform. + * TODO(sergey): More constraints here? */ + if (ELEM(con->type, + CONSTRAINT_TYPE_ROTLIKE, + CONSTRAINT_TYPE_SIZELIKE, + CONSTRAINT_TYPE_LOCLIKE, + CONSTRAINT_TYPE_TRANSLIKE)) { + /* TODO(sergey): Add used space check. */ + ComponentKey target_transform_key(&ct->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, constraint_op_key, cti->name); + } + } + if (cti->flush_constraint_targets) { + cti->flush_constraint_targets(con, &targets, 1); + } + } + } } void DepsgraphRelationBuilder::build_animdata(ID *id) { - /* Images. */ - build_animation_images(id); - /* Animation curves and NLA. */ - build_animdata_curves(id); - /* Drivers. */ - build_animdata_drivers(id); + /* Images. */ + build_animation_images(id); + /* Animation curves and NLA. */ + build_animdata_curves(id); + /* Drivers. */ + build_animdata_drivers(id); } void DepsgraphRelationBuilder::build_animdata_curves(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return; - } - if (adt->action != NULL) { - build_action(adt->action); - } - if (adt->action == NULL && BLI_listbase_is_empty(&adt->nla_tracks)) { - return; - } - /* Ensure evaluation order from entry to exit. */ - OperationKey animation_entry_key( - id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); - OperationKey animation_eval_key( - id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); - OperationKey animation_exit_key( - id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); - add_relation(animation_entry_key, animation_eval_key, "Init -> Eval"); - add_relation(animation_eval_key, animation_exit_key, "Eval -> Exit"); - /* Wire up dependency from action. */ - ComponentKey adt_key(id, NodeType::ANIMATION); - /* Relation from action itself. */ - if (adt->action != NULL) { - ComponentKey action_key(&adt->action->id, NodeType::ANIMATION); - add_relation(action_key, adt_key, "Action -> Animation"); - } - /* Get source operations. */ - Node *node_from = get_node(adt_key); - BLI_assert(node_from != NULL); - if (node_from == NULL) { - return; - } - OperationNode *operation_from = node_from->get_exit_operation(); - BLI_assert(operation_from != NULL); - /* Build relations from animation operation to properties it changes. */ - if (adt->action != NULL) { - build_animdata_curves_targets( - id, adt_key, operation_from, &adt->action->curves); - } - LISTBASE_FOREACH(NlaTrack *, nlt, &adt->nla_tracks) { - build_animdata_nlastrip_targets( - id, adt_key, operation_from, &nlt->strips); - } -} - -void DepsgraphRelationBuilder::build_animdata_curves_targets( - ID *id, ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *curves) -{ - /* Iterate over all curves and build relations. */ - PointerRNA id_ptr; - RNA_id_pointer_create(id, &id_ptr); - LISTBASE_FOREACH (FCurve *, fcu, curves) { - PointerRNA ptr; - PropertyRNA *prop; - int index; - if (!RNA_path_resolve_full( - &id_ptr, fcu->rna_path, &ptr, &prop, &index)) - { - continue; - } - Node *node_to = rna_node_query_.find_node( - &ptr, prop, RNAPointerSource::ENTRY); - if (node_to == NULL) { - continue; - } - OperationNode *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 == OperationCode::BONE_LOCAL) { - OperationKey pose_init_key( - id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); - add_relation(adt_key, - pose_init_key, - "Animation -> Prop", - RELATION_CHECK_BEFORE_ADD); - continue; - } - graph_->add_new_relation(operation_from, operation_to, - "Animation -> Prop", - RELATION_CHECK_BEFORE_ADD); - /* It is possible that animation is writing to a nested ID datablock, - * need to make sure animation is evaluated after target ID is copied. */ - const IDNode *id_node_from = operation_from->owner->owner; - const IDNode *id_node_to = operation_to->owner->owner; - if (id_node_from != id_node_to) { - ComponentKey cow_key(id_node_to->id_orig, NodeType::COPY_ON_WRITE); - add_relation(cow_key, - adt_key, - "Animated CoW -> Animation", - RELATION_CHECK_BEFORE_ADD); - } - } -} - -void DepsgraphRelationBuilder::build_animdata_nlastrip_targets( - ID *id, ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *strips) -{ - LISTBASE_FOREACH (NlaStrip *, strip, strips) { - if (strip->act != NULL) { - build_action(strip->act); - - ComponentKey action_key(&strip->act->id, NodeType::ANIMATION); - add_relation(action_key, adt_key, "Action -> Animation"); - - build_animdata_curves_targets( - id, adt_key, operation_from, &strip->act->curves); - } - else if (strip->strips.first != NULL) { - build_animdata_nlastrip_targets( - id, adt_key, operation_from, &strip->strips); - } - } + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return; + } + if (adt->action != NULL) { + build_action(adt->action); + } + if (adt->action == NULL && BLI_listbase_is_empty(&adt->nla_tracks)) { + return; + } + /* Ensure evaluation order from entry to exit. */ + OperationKey animation_entry_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_ENTRY); + OperationKey animation_eval_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_EVAL); + OperationKey animation_exit_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); + add_relation(animation_entry_key, animation_eval_key, "Init -> Eval"); + add_relation(animation_eval_key, animation_exit_key, "Eval -> Exit"); + /* Wire up dependency from action. */ + ComponentKey adt_key(id, NodeType::ANIMATION); + /* Relation from action itself. */ + if (adt->action != NULL) { + ComponentKey action_key(&adt->action->id, NodeType::ANIMATION); + add_relation(action_key, adt_key, "Action -> Animation"); + } + /* Get source operations. */ + Node *node_from = get_node(adt_key); + BLI_assert(node_from != NULL); + if (node_from == NULL) { + return; + } + OperationNode *operation_from = node_from->get_exit_operation(); + BLI_assert(operation_from != NULL); + /* Build relations from animation operation to properties it changes. */ + if (adt->action != NULL) { + build_animdata_curves_targets(id, adt_key, operation_from, &adt->action->curves); + } + LISTBASE_FOREACH (NlaTrack *, nlt, &adt->nla_tracks) { + build_animdata_nlastrip_targets(id, adt_key, operation_from, &nlt->strips); + } +} + +void DepsgraphRelationBuilder::build_animdata_curves_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *curves) +{ + /* Iterate over all curves and build relations. */ + PointerRNA id_ptr; + RNA_id_pointer_create(id, &id_ptr); + LISTBASE_FOREACH (FCurve *, fcu, curves) { + PointerRNA ptr; + PropertyRNA *prop; + int index; + if (!RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, &prop, &index)) { + continue; + } + Node *node_to = rna_node_query_.find_node(&ptr, prop, RNAPointerSource::ENTRY); + if (node_to == NULL) { + continue; + } + OperationNode *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 == OperationCode::BONE_LOCAL) { + OperationKey pose_init_key(id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); + add_relation(adt_key, pose_init_key, "Animation -> Prop", RELATION_CHECK_BEFORE_ADD); + continue; + } + graph_->add_new_relation( + operation_from, operation_to, "Animation -> Prop", RELATION_CHECK_BEFORE_ADD); + /* It is possible that animation is writing to a nested ID datablock, + * need to make sure animation is evaluated after target ID is copied. */ + const IDNode *id_node_from = operation_from->owner->owner; + const IDNode *id_node_to = operation_to->owner->owner; + if (id_node_from != id_node_to) { + ComponentKey cow_key(id_node_to->id_orig, NodeType::COPY_ON_WRITE); + add_relation(cow_key, adt_key, "Animated CoW -> Animation", RELATION_CHECK_BEFORE_ADD); + } + } +} + +void DepsgraphRelationBuilder::build_animdata_nlastrip_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *strips) +{ + LISTBASE_FOREACH (NlaStrip *, strip, strips) { + if (strip->act != NULL) { + build_action(strip->act); + + ComponentKey action_key(&strip->act->id, NodeType::ANIMATION); + add_relation(action_key, adt_key, "Action -> Animation"); + + build_animdata_curves_targets(id, adt_key, operation_from, &strip->act->curves); + } + else if (strip->strips.first != NULL) { + build_animdata_nlastrip_targets(id, adt_key, operation_from, &strip->strips); + } + } } void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) { - AnimData *adt = BKE_animdata_from_id(id); - if (adt == NULL) { - return; - } - ComponentKey adt_key(id, NodeType::ANIMATION); - LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - - /* create the driver's relations to targets */ - build_driver(id, fcu); - /* Special case for array drivers: we can not multithread them because - * of the way how they work internally: animation system will write the - * whole array back to RNA even when changing individual array value. - * - * Some tricky things here: - * - array_index is -1 for single channel drivers, meaning we only have - * to do some magic when array_index is not -1. - * - We do relation from next array index to a previous one, so we don't - * have to deal with array index 0. - * - * TODO(sergey): Avoid liner lookup somehow. */ - if (fcu->array_index > 0) { - FCurve *fcu_prev = NULL; - LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { - /* Writing to different RNA paths is */ - const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; - if (!STREQ(fcu_candidate->rna_path, rna_path)) { - continue; - } - /* We only do relation from previous fcurve to previous one. */ - if (fcu_candidate->array_index >= fcu->array_index) { - continue; - } - /* Choose fcurve with highest possible array index. */ - if (fcu_prev == NULL || - fcu_candidate->array_index > fcu_prev->array_index) - { - fcu_prev = fcu_candidate; - } - } - if (fcu_prev != NULL) { - OperationKey prev_driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu_prev->rna_path ? fcu_prev->rna_path : "", - fcu_prev->array_index); - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - add_relation(prev_driver_key, driver_key, "Driver Order"); - } - } - - /* prevent driver from occurring before own animation... */ - if (adt->action || adt->nla_tracks.first) { - add_relation(adt_key, driver_key, "AnimData Before Drivers"); - } - } + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + return; + } + ComponentKey adt_key(id, NodeType::ANIMATION); + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + + /* create the driver's relations to targets */ + build_driver(id, fcu); + /* Special case for array drivers: we can not multithread them because + * of the way how they work internally: animation system will write the + * whole array back to RNA even when changing individual array value. + * + * Some tricky things here: + * - array_index is -1 for single channel drivers, meaning we only have + * to do some magic when array_index is not -1. + * - We do relation from next array index to a previous one, so we don't + * have to deal with array index 0. + * + * TODO(sergey): Avoid liner lookup somehow. */ + if (fcu->array_index > 0) { + FCurve *fcu_prev = NULL; + LISTBASE_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { + /* Writing to different RNA paths is */ + const char *rna_path = fcu->rna_path ? fcu->rna_path : ""; + if (!STREQ(fcu_candidate->rna_path, rna_path)) { + continue; + } + /* We only do relation from previous fcurve to previous one. */ + if (fcu_candidate->array_index >= fcu->array_index) { + continue; + } + /* Choose fcurve with highest possible array index. */ + if (fcu_prev == NULL || fcu_candidate->array_index > fcu_prev->array_index) { + fcu_prev = fcu_candidate; + } + } + if (fcu_prev != NULL) { + OperationKey prev_driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu_prev->rna_path ? fcu_prev->rna_path : "", + fcu_prev->array_index); + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + add_relation(prev_driver_key, driver_key, "Driver Order"); + } + } + + /* prevent driver from occurring before own animation... */ + if (adt->action || adt->nla_tracks.first) { + add_relation(adt_key, driver_key, "AnimData Before Drivers"); + } + } } void DepsgraphRelationBuilder::build_animation_images(ID *id) { - /* TODO: can we check for existance of node for performance? */ - if (BKE_image_user_id_has_animation(id)) { - OperationKey image_animation_key(id, - NodeType::ANIMATION, - OperationCode::IMAGE_ANIMATION); - TimeSourceKey time_src_key; - add_relation(time_src_key, image_animation_key, "TimeSrc -> Image Animation"); - } + /* TODO: can we check for existance of node for performance? */ + if (BKE_image_user_id_has_animation(id)) { + OperationKey image_animation_key(id, NodeType::ANIMATION, OperationCode::IMAGE_ANIMATION); + TimeSourceKey time_src_key; + add_relation(time_src_key, image_animation_key, "TimeSrc -> Image Animation"); + } } void DepsgraphRelationBuilder::build_action(bAction *action) { - if (built_map_.checkIsBuiltAndTag(action)) { - return; - } - TimeSourceKey time_src_key; - ComponentKey animation_key(&action->id, NodeType::ANIMATION); - add_relation(time_src_key, animation_key, "TimeSrc -> Animation"); + if (built_map_.checkIsBuiltAndTag(action)) { + return; + } + TimeSourceKey time_src_key; + ComponentKey animation_key(&action->id, NodeType::ANIMATION); + add_relation(time_src_key, animation_key, "TimeSrc -> Animation"); } void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) { - ChannelDriver *driver = fcu->driver; - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - /* Driver -> data components (for interleaved evaluation - * bones/constraints/modifiers). */ - 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"); - } + ChannelDriver *driver = fcu->driver; + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + /* Driver -> data components (for interleaved evaluation + * bones/constraints/modifiers). */ + 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"); + } } void DepsgraphRelationBuilder::build_driver_data(ID *id, FCurve *fcu) { - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::DRIVER, - fcu->rna_path ? fcu->rna_path : "", - fcu->array_index); - const char *rna_path = fcu->rna_path ? fcu->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. */ - IDNode *arm_node = graph_->find_id_node(id); - char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); - if (arm_node != NULL && bone_name != NULL) { - /* Find objects which use this, and make their eval callbacks - * depend on this. */ - for (Relation *rel : arm_node->outlinks) { - IDNode *to_node = (IDNode *)rel->to; - /* We only care about objects with pose data which use this. */ - if (GS(to_node->id_orig->name) == ID_OB) { - Object *object = (Object *)to_node->id_orig; - // NOTE: object->pose may be NULL - bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, - bone_name); - if (pchan != NULL) { - OperationKey bone_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - add_relation(driver_key, - bone_key, - "Arm Bone -> Driver -> Bone"); - } - } - } - /* Free temp data. */ - MEM_freeN(bone_name); - bone_name = NULL; - } - else { - fprintf(stderr, - "Couldn't find armature bone name for driver path - '%s'\n", - rna_path); - } - } - else if (rna_path != NULL && rna_path[0] != '\0') { - RNAPathKey property_entry_key(id, rna_path, RNAPointerSource::ENTRY); - if (RNA_pointer_is_null(&property_entry_key.ptr)) { - /* TODO(sergey): This would only mean that driver is broken. - * so we can't create relation anyway. However, we need to avoid - * adding drivers which are known to be buggy to a dependency - * graph, in order to save computational power. */ - return; - } - add_relation( - driver_key, property_entry_key, "Driver -> Driven Property"); - /* Similar to the case with f-curves, driver might drive a nested - * datablock, which means driver execution should wait for that - * datablock to be copied. */ - { - PointerRNA id_ptr; - PointerRNA ptr; - RNA_id_pointer_create(id, &id_ptr); - if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) { - if (id_ptr.id.data != ptr.id.data) { - ComponentKey cow_key((ID *)ptr.id.data, - NodeType::COPY_ON_WRITE); - add_relation(cow_key, - driver_key, - "Driven CoW -> Driver", - RELATION_CHECK_BEFORE_ADD); - } - } - } - if (property_entry_key.prop != NULL && - RNA_property_is_idprop(property_entry_key.prop)) - { - RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT); - OperationKey parameters_key(id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL); - add_relation(property_exit_key, - parameters_key, - "Driven Property -> Properties"); - } - } + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::DRIVER, + fcu->rna_path ? fcu->rna_path : "", + fcu->array_index); + const char *rna_path = fcu->rna_path ? fcu->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. */ + IDNode *arm_node = graph_->find_id_node(id); + char *bone_name = BLI_str_quoted_substrN(rna_path, "bones["); + if (arm_node != NULL && bone_name != NULL) { + /* Find objects which use this, and make their eval callbacks + * depend on this. */ + for (Relation *rel : arm_node->outlinks) { + IDNode *to_node = (IDNode *)rel->to; + /* We only care about objects with pose data which use this. */ + if (GS(to_node->id_orig->name) == ID_OB) { + Object *object = (Object *)to_node->id_orig; + // NOTE: object->pose may be NULL + bPoseChannel *pchan = BKE_pose_channel_find_name(object->pose, bone_name); + if (pchan != NULL) { + OperationKey bone_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + add_relation(driver_key, bone_key, "Arm Bone -> Driver -> Bone"); + } + } + } + /* Free temp data. */ + MEM_freeN(bone_name); + bone_name = NULL; + } + else { + fprintf(stderr, "Couldn't find armature bone name for driver path - '%s'\n", rna_path); + } + } + else if (rna_path != NULL && rna_path[0] != '\0') { + RNAPathKey property_entry_key(id, rna_path, RNAPointerSource::ENTRY); + if (RNA_pointer_is_null(&property_entry_key.ptr)) { + /* TODO(sergey): This would only mean that driver is broken. + * so we can't create relation anyway. However, we need to avoid + * adding drivers which are known to be buggy to a dependency + * graph, in order to save computational power. */ + return; + } + add_relation(driver_key, property_entry_key, "Driver -> Driven Property"); + /* Similar to the case with f-curves, driver might drive a nested + * datablock, which means driver execution should wait for that + * datablock to be copied. */ + { + PointerRNA id_ptr; + PointerRNA ptr; + RNA_id_pointer_create(id, &id_ptr); + if (RNA_path_resolve_full(&id_ptr, fcu->rna_path, &ptr, NULL, NULL)) { + if (id_ptr.id.data != ptr.id.data) { + ComponentKey cow_key((ID *)ptr.id.data, NodeType::COPY_ON_WRITE); + add_relation(cow_key, driver_key, "Driven CoW -> Driver", RELATION_CHECK_BEFORE_ADD); + } + } + } + if (property_entry_key.prop != NULL && RNA_property_is_idprop(property_entry_key.prop)) { + RNAPathKey property_exit_key(id, rna_path, RNAPointerSource::EXIT); + OperationKey parameters_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + add_relation(property_exit_key, parameters_key, "Driven Property -> Properties"); + } + } } void DepsgraphRelationBuilder::build_driver_variables(ID *id, FCurve *fcu) { - ChannelDriver *driver = fcu->driver; - OperationKey driver_key(id, - NodeType::PARAMETERS, - OperationCode::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, RNAPointerSource::ENTRY); - LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { - /* Only used targets. */ - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - if (dtar->id == NULL) { - continue; - } - build_id(dtar->id); - build_driver_id_property(dtar->id, dtar->rna_path); - /* Initialize relations coming to proxy_from. */ - Object *proxy_from = NULL; - if ((GS(dtar->id->name) == ID_OB) && - (((Object *)dtar->id)->proxy_from != NULL)) - { - proxy_from = ((Object *)dtar->id)->proxy_from; - build_id(&proxy_from->id); - } - /* Special handling for directly-named bones. */ - 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) { - continue; - } - OperationKey variable_key(dtar->id, - NodeType::BONE, - target_pchan->name, - OperationCode::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. */ - if (dtar->id == id) { - /* Ignore input dependency if we're driving properties of - * the same ID, otherwise we'll be ending up in a cyclic - * dependency here. */ - continue; - } - OperationKey target_key(dtar->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(target_key, driver_key, "Target -> Driver"); - } - else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') { - RNAPathKey variable_exit_key( - dtar->id, dtar->rna_path, RNAPointerSource::EXIT); - if (RNA_pointer_is_null(&variable_exit_key.ptr)) { - continue; - } - if (is_same_bone_dependency(variable_exit_key, self_key) || - is_same_nodetree_node_dependency(variable_exit_key, self_key)) - { - continue; - } - add_relation(variable_exit_key, - driver_key, - "RNA Target -> Driver"); - if (proxy_from != NULL) { - RNAPathKey proxy_from_variable_key(&proxy_from->id, - dtar->rna_path, - RNAPointerSource::EXIT); - RNAPathKey variable_entry_key( - dtar->id, dtar->rna_path, RNAPointerSource::ENTRY); - add_relation(proxy_from_variable_key, - variable_entry_key, - "Proxy From -> Variable"); - } - } - else { - /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this - * is an incomplete target reference, so nothing to do here. */ - } - } - DRIVER_TARGETS_LOOPER_END; - } -} - -void DepsgraphRelationBuilder::build_driver_id_property(ID *id, - const char *rna_path) -{ - if (id == NULL || rna_path == NULL) { - return; - } - PointerRNA id_ptr, ptr; - PropertyRNA *prop; - RNA_id_pointer_create(id, &id_ptr); - if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { - return; - } - if (prop == NULL) { - return; - } - if (!RNA_property_is_idprop(prop)) { - return; - } - const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); - OperationKey id_property_key(id, - NodeType::PARAMETERS, - OperationCode::ID_PROPERTY, - prop_identifier); - OperationKey parameters_exit_key(id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EXIT); - add_relation(id_property_key, - parameters_exit_key, - "ID Property -> Done", - RELATION_CHECK_BEFORE_ADD); + ChannelDriver *driver = fcu->driver; + OperationKey driver_key(id, + NodeType::PARAMETERS, + OperationCode::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, RNAPointerSource::ENTRY); + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + /* Only used targets. */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (dtar->id == NULL) { + continue; + } + build_id(dtar->id); + build_driver_id_property(dtar->id, dtar->rna_path); + /* Initialize relations coming to proxy_from. */ + Object *proxy_from = NULL; + if ((GS(dtar->id->name) == ID_OB) && (((Object *)dtar->id)->proxy_from != NULL)) { + proxy_from = ((Object *)dtar->id)->proxy_from; + build_id(&proxy_from->id); + } + /* Special handling for directly-named bones. */ + 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) { + continue; + } + OperationKey variable_key( + dtar->id, NodeType::BONE, target_pchan->name, OperationCode::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. */ + if (dtar->id == id) { + /* Ignore input dependency if we're driving properties of + * the same ID, otherwise we'll be ending up in a cyclic + * dependency here. */ + continue; + } + OperationKey target_key(dtar->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation(target_key, driver_key, "Target -> Driver"); + } + else if (dtar->rna_path != NULL && dtar->rna_path[0] != '\0') { + RNAPathKey variable_exit_key(dtar->id, dtar->rna_path, RNAPointerSource::EXIT); + if (RNA_pointer_is_null(&variable_exit_key.ptr)) { + continue; + } + if (is_same_bone_dependency(variable_exit_key, self_key) || + is_same_nodetree_node_dependency(variable_exit_key, self_key)) { + continue; + } + add_relation(variable_exit_key, driver_key, "RNA Target -> Driver"); + if (proxy_from != NULL) { + RNAPathKey proxy_from_variable_key( + &proxy_from->id, dtar->rna_path, RNAPointerSource::EXIT); + RNAPathKey variable_entry_key(dtar->id, dtar->rna_path, RNAPointerSource::ENTRY); + add_relation(proxy_from_variable_key, variable_entry_key, "Proxy From -> Variable"); + } + } + else { + /* If rna_path is NULL, and DTAR_FLAG_STRUCT_REF isn't set, this + * is an incomplete target reference, so nothing to do here. */ + } + } + DRIVER_TARGETS_LOOPER_END; + } +} + +void DepsgraphRelationBuilder::build_driver_id_property(ID *id, const char *rna_path) +{ + if (id == NULL || rna_path == NULL) { + return; + } + PointerRNA id_ptr, ptr; + PropertyRNA *prop; + RNA_id_pointer_create(id, &id_ptr); + if (!RNA_path_resolve_full(&id_ptr, rna_path, &ptr, &prop, NULL)) { + return; + } + if (prop == NULL) { + return; + } + if (!RNA_property_is_idprop(prop)) { + return; + } + const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); + OperationKey id_property_key( + id, NodeType::PARAMETERS, OperationCode::ID_PROPERTY, prop_identifier); + OperationKey parameters_exit_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); + add_relation( + id_property_key, parameters_exit_key, "ID Property -> Done", RELATION_CHECK_BEFORE_ADD); } void DepsgraphRelationBuilder::build_parameters(ID *id) { - OperationKey parameters_entry_key( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); - OperationKey parameters_eval_key( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); - OperationKey parameters_exit_key( - id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); - add_relation( - parameters_entry_key, parameters_eval_key, "Entry -> Eval"); - add_relation( - parameters_eval_key, parameters_exit_key, "Entry -> Exit"); + OperationKey parameters_entry_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_ENTRY); + OperationKey parameters_eval_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + OperationKey parameters_exit_key(id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EXIT); + add_relation(parameters_entry_key, parameters_eval_key, "Entry -> Eval"); + add_relation(parameters_eval_key, parameters_exit_key, "Entry -> Exit"); } void DepsgraphRelationBuilder::build_world(World *world) { - if (built_map_.checkIsBuiltAndTag(world)) { - return; - } - /* animation */ - build_animdata(&world->id); - build_parameters(&world->id); - /* world's nodetree */ - if (world->nodetree != NULL) { - build_nodetree(world->nodetree); - OperationKey ntree_key(&world->nodetree->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey world_key(&world->id, - NodeType::SHADING, - OperationCode::WORLD_UPDATE); - add_relation(ntree_key, world_key, "World's NTree"); - build_nested_nodetree(&world->id, world->nodetree); - } + if (built_map_.checkIsBuiltAndTag(world)) { + return; + } + /* animation */ + build_animdata(&world->id); + build_parameters(&world->id); + /* world's nodetree */ + if (world->nodetree != NULL) { + build_nodetree(world->nodetree); + OperationKey ntree_key( + &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey world_key(&world->id, NodeType::SHADING, OperationCode::WORLD_UPDATE); + add_relation(ntree_key, world_key, "World's NTree"); + build_nested_nodetree(&world->id, world->nodetree); + } } void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) { - RigidBodyWorld *rbw = scene->rigidbody_world; - OperationKey rb_init_key(&scene->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_REBUILD); - OperationKey rb_simulate_key(&scene->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_SIM); - /* Simulation depends on time. */ - TimeSourceKey time_src_key; - add_relation(time_src_key, rb_init_key, "TimeSrc -> Rigidbody Init"); - /* Simulation should always be run after initialization. */ - /* NOTE: It is possible in theory to have dependency cycle which involves - * this relation. We never want it to be killed. */ - add_relation(rb_init_key, - rb_simulate_key, - "Rigidbody [Init -> SimStep]", - RELATION_FLAG_GODMODE); - /* Effectors should be evaluated at the time simulation is being - * initialized. - * TODO(sergey): Verify that it indeed goes to initialization and not to a - * simulation. */ - ListBase *effector_relations = - build_effector_relations(graph_, rbw->effector_weights->group); - LISTBASE_FOREACH (EffectorRelation *, effector_relation, effector_relations) { - ComponentKey effector_transform_key( - &effector_relation->ob->id, NodeType::TRANSFORM); - add_relation(effector_transform_key, rb_init_key, "RigidBody Field"); - if (effector_relation->pd != NULL) { - const short shape = effector_relation->pd->shape; - if (ELEM(shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS)) { - ComponentKey effector_geometry_key( - &effector_relation->ob->id, NodeType::GEOMETRY); - add_relation( - effector_geometry_key, rb_init_key, "RigidBody Field"); - } - } - } - /* Objects. */ - if (rbw->group != NULL) { - build_collection(NULL, NULL, rbw->group); - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - if (object->type != OB_MESH) { - continue; - } - OperationKey rb_transform_copy_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY); - /* Rigid body synchronization depends on the actual simulation. */ - add_relation(rb_simulate_key, - rb_transform_copy_key, - "Rigidbody Sim Eval -> RBO Sync"); - /* Simulation uses object transformation after parenting and solving - * contraints. */ - OperationKey object_transform_simulation_init_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_SIMULATION_INIT); - OperationKey object_transform_eval_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - add_relation(object_transform_simulation_init_key, - rb_simulate_key, - "Object Transform -> Rigidbody Sim Eval"); - /* Geometry must be known to create the rigid body. RBO_MESH_BASE - * uses the non-evaluated mesh, so then the evaluation is - * unnecessary. */ - if (object->rigidbody_object != NULL && - object->rigidbody_object->mesh_source != RBO_MESH_BASE) - { - /* NOTE: We prefer this relation to be never killed, to avoid - * access partially evaluated mesh from solver. */ - ComponentKey object_geometry_key( - &object->id, NodeType::GEOMETRY); - add_relation(object_geometry_key, - rb_simulate_key, - "Object Geom Eval -> Rigidbody Rebuild", - RELATION_FLAG_GODMODE); - } - /* Final transform is whetever solver gave to us. */ - OperationKey object_transform_final_key( - &object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_FINAL); - add_relation(rb_transform_copy_key, - object_transform_final_key, - "Rigidbody Sync -> Transform Final"); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - /* Constraints. */ - if (rbw->constraints != NULL) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) - { - RigidBodyCon *rbc = object->rigidbody_constraint; - if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { - /* When either ob1 or ob2 is NULL, the constraint doesn't - * work. */ - continue; - } - /* Make sure indirectly linked objects are fully built. */ - build_object(NULL, object); - build_object(NULL, rbc->ob1); - build_object(NULL, rbc->ob2); - /* final result of the constraint object's transform controls how - * the constraint affects the physics sim for these objects. */ - ComponentKey trans_key(&object->id, NodeType::TRANSFORM); - OperationKey ob1_key(&rbc->ob1->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY); - OperationKey ob2_key(&rbc->ob2->id, - NodeType::TRANSFORM, - OperationCode::RIGIDBODY_TRANSFORM_COPY); - /* Constrained-objects sync depends on the constraint-holder. */ - add_relation( - trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1"); - add_relation( - trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2"); - /* Ensure that sim depends on this constraint's transform. */ - add_relation(trans_key, - rb_simulate_key, - "RigidBodyConstraint Transform -> RB Simulation"); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } + RigidBodyWorld *rbw = scene->rigidbody_world; + OperationKey rb_init_key(&scene->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_REBUILD); + OperationKey rb_simulate_key(&scene->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_SIM); + /* Simulation depends on time. */ + TimeSourceKey time_src_key; + add_relation(time_src_key, rb_init_key, "TimeSrc -> Rigidbody Init"); + /* Simulation should always be run after initialization. */ + /* NOTE: It is possible in theory to have dependency cycle which involves + * this relation. We never want it to be killed. */ + add_relation(rb_init_key, rb_simulate_key, "Rigidbody [Init -> SimStep]", RELATION_FLAG_GODMODE); + /* Effectors should be evaluated at the time simulation is being + * initialized. + * TODO(sergey): Verify that it indeed goes to initialization and not to a + * simulation. */ + ListBase *effector_relations = build_effector_relations(graph_, rbw->effector_weights->group); + LISTBASE_FOREACH (EffectorRelation *, effector_relation, effector_relations) { + ComponentKey effector_transform_key(&effector_relation->ob->id, NodeType::TRANSFORM); + add_relation(effector_transform_key, rb_init_key, "RigidBody Field"); + if (effector_relation->pd != NULL) { + const short shape = effector_relation->pd->shape; + if (ELEM(shape, PFIELD_SHAPE_SURFACE, PFIELD_SHAPE_POINTS)) { + ComponentKey effector_geometry_key(&effector_relation->ob->id, NodeType::GEOMETRY); + add_relation(effector_geometry_key, rb_init_key, "RigidBody Field"); + } + } + } + /* Objects. */ + if (rbw->group != NULL) { + build_collection(NULL, NULL, rbw->group); + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + if (object->type != OB_MESH) { + continue; + } + OperationKey rb_transform_copy_key( + &object->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY); + /* Rigid body synchronization depends on the actual simulation. */ + add_relation(rb_simulate_key, rb_transform_copy_key, "Rigidbody Sim Eval -> RBO Sync"); + /* Simulation uses object transformation after parenting and solving + * contraints. */ + OperationKey object_transform_simulation_init_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT); + OperationKey object_transform_eval_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + add_relation(object_transform_simulation_init_key, + rb_simulate_key, + "Object Transform -> Rigidbody Sim Eval"); + /* Geometry must be known to create the rigid body. RBO_MESH_BASE + * uses the non-evaluated mesh, so then the evaluation is + * unnecessary. */ + if (object->rigidbody_object != NULL && + object->rigidbody_object->mesh_source != RBO_MESH_BASE) { + /* NOTE: We prefer this relation to be never killed, to avoid + * access partially evaluated mesh from solver. */ + ComponentKey object_geometry_key(&object->id, NodeType::GEOMETRY); + add_relation(object_geometry_key, + rb_simulate_key, + "Object Geom Eval -> Rigidbody Rebuild", + RELATION_FLAG_GODMODE); + } + /* Final transform is whetever solver gave to us. */ + OperationKey object_transform_final_key( + &object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); + add_relation( + rb_transform_copy_key, object_transform_final_key, "Rigidbody Sync -> Transform Final"); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + /* Constraints. */ + if (rbw->constraints != NULL) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { + RigidBodyCon *rbc = object->rigidbody_constraint; + if (rbc == NULL || rbc->ob1 == NULL || rbc->ob2 == NULL) { + /* When either ob1 or ob2 is NULL, the constraint doesn't + * work. */ + continue; + } + /* Make sure indirectly linked objects are fully built. */ + build_object(NULL, object); + build_object(NULL, rbc->ob1); + build_object(NULL, rbc->ob2); + /* final result of the constraint object's transform controls how + * the constraint affects the physics sim for these objects. */ + ComponentKey trans_key(&object->id, NodeType::TRANSFORM); + OperationKey ob1_key( + &rbc->ob1->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY); + OperationKey ob2_key( + &rbc->ob2->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY); + /* Constrained-objects sync depends on the constraint-holder. */ + add_relation(trans_key, ob1_key, "RigidBodyConstraint -> RBC.Object_1"); + add_relation(trans_key, ob2_key, "RigidBodyConstraint -> RBC.Object_2"); + /* Ensure that sim depends on this constraint's transform. */ + add_relation(trans_key, rb_simulate_key, "RigidBodyConstraint Transform -> RB Simulation"); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } } void DepsgraphRelationBuilder::build_particle_systems(Object *object) { - TimeSourceKey time_src_key; - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - OperationKey eval_init_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_INIT); - OperationKey eval_done_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_DONE); - ComponentKey eval_key(&object->id, NodeType::PARTICLE_SYSTEM); - if (BKE_ptcache_object_has(scene_, object, 0)) { - ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); - add_relation(eval_key, - point_cache_key, - "Particle Point Cache", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - } - /* Particle systems. */ - LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - ParticleSettings *part = psys->part; - /* Build particle settings relations. - * NOTE: The call itself ensures settings are only build once. */ - build_particle_settings(part); - /* This particle system. */ - OperationKey psys_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_EVAL, - psys->name); - /* Update particle system when settings changes. */ - OperationKey particle_settings_key(&part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_EVAL); - add_relation(particle_settings_key, - eval_init_key, - "Particle Settings Change"); - add_relation(eval_init_key, psys_key, "Init -> PSys"); - add_relation(psys_key, eval_done_key, "PSys -> Done"); - /* TODO(sergey): Currently particle update is just a placeholder, - * hook it to the ubereval node so particle system is getting updated - * on playback. */ - add_relation(psys_key, obdata_ubereval_key, "PSys -> UberEval"); - /* Collisions. */ - if (part->type != PART_HAIR) { - add_particle_collision_relations(psys_key, - object, - part->collision_group, - "Particle Collision"); - } - else if ((psys->flag & PSYS_HAIR_DYNAMICS) && - psys->clmd != NULL && - psys->clmd->coll_parms != NULL) - { - add_particle_collision_relations(psys_key, - object, - psys->clmd->coll_parms->group, - "Hair Collision"); - } - /* Effectors. */ - add_particle_forcefield_relations(psys_key, - object, - psys, - part->effector_weights, - part->type == PART_HAIR, - "Particle Field"); - /* Boids .*/ - if (part->boids != NULL) { - LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { - LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { - Object *ruleob = NULL; - if (rule->type == eBoidRuleType_Avoid) { - ruleob = ((BoidRuleGoalAvoid *)rule)->ob; - } - else if (rule->type == eBoidRuleType_FollowLeader) { - ruleob = ((BoidRuleFollowLeader *)rule)->ob; - } - if (ruleob != NULL) { - ComponentKey ruleob_key(&ruleob->id, - NodeType::TRANSFORM); - add_relation(ruleob_key, psys_key, "Boid Rule"); - } - } - } - } - /* Keyed particle targets. */ - if (part->phystype == PART_PHYS_KEYED) { - LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { - if (particle_target->ob == NULL || - particle_target->ob == object) - { - continue; - } - /* Make sure target object is pulled into the graph. */ - build_object(NULL, particle_target->ob); - /* Use geometry component, since that's where particles are - * actually evaluated. */ - ComponentKey target_key(&particle_target->ob->id, - NodeType::GEOMETRY); - add_relation(target_key, psys_key, "Keyed Target"); - } - } - /* Visualization. */ - switch (part->ren_as) { - case PART_DRAW_OB: - if (part->instance_object != NULL) { - /* Make sure object's relations are all built. */ - build_object(NULL, part->instance_object); - /* Build relation for the particle visualization. */ - build_particle_system_visualization_object( - object, psys, part->instance_object); - } - break; - case PART_DRAW_GR: - if (part->instance_collection != NULL) { - build_collection(NULL, NULL, part->instance_collection); - LISTBASE_FOREACH (CollectionObject *, go, &part->instance_collection->gobject) { - build_particle_system_visualization_object( - object, psys, go->ob); - } - } - break; - } - } - /* Particle depends on the object transform, so that channel is to be ready - * first. */ - add_depends_on_transform_relation( - &object->id, obdata_ubereval_key, "Particle Eval"); + TimeSourceKey time_src_key; + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + OperationKey eval_init_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_INIT); + OperationKey eval_done_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_DONE); + ComponentKey eval_key(&object->id, NodeType::PARTICLE_SYSTEM); + if (BKE_ptcache_object_has(scene_, object, 0)) { + ComponentKey point_cache_key(&object->id, NodeType::POINT_CACHE); + add_relation( + eval_key, point_cache_key, "Particle Point Cache", RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + } + /* Particle systems. */ + LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { + ParticleSettings *part = psys->part; + /* Build particle settings relations. + * NOTE: The call itself ensures settings are only build once. */ + build_particle_settings(part); + /* This particle system. */ + OperationKey psys_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name); + /* Update particle system when settings changes. */ + OperationKey particle_settings_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL); + add_relation(particle_settings_key, eval_init_key, "Particle Settings Change"); + add_relation(eval_init_key, psys_key, "Init -> PSys"); + add_relation(psys_key, eval_done_key, "PSys -> Done"); + /* TODO(sergey): Currently particle update is just a placeholder, + * hook it to the ubereval node so particle system is getting updated + * on playback. */ + add_relation(psys_key, obdata_ubereval_key, "PSys -> UberEval"); + /* Collisions. */ + if (part->type != PART_HAIR) { + add_particle_collision_relations( + psys_key, object, part->collision_group, "Particle Collision"); + } + else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd != NULL && + psys->clmd->coll_parms != NULL) { + add_particle_collision_relations( + psys_key, object, psys->clmd->coll_parms->group, "Hair Collision"); + } + /* Effectors. */ + add_particle_forcefield_relations( + psys_key, object, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field"); + /* Boids .*/ + if (part->boids != NULL) { + LISTBASE_FOREACH (BoidState *, state, &part->boids->states) { + LISTBASE_FOREACH (BoidRule *, rule, &state->rules) { + Object *ruleob = NULL; + if (rule->type == eBoidRuleType_Avoid) { + ruleob = ((BoidRuleGoalAvoid *)rule)->ob; + } + else if (rule->type == eBoidRuleType_FollowLeader) { + ruleob = ((BoidRuleFollowLeader *)rule)->ob; + } + if (ruleob != NULL) { + ComponentKey ruleob_key(&ruleob->id, NodeType::TRANSFORM); + add_relation(ruleob_key, psys_key, "Boid Rule"); + } + } + } + } + /* Keyed particle targets. */ + if (part->phystype == PART_PHYS_KEYED) { + LISTBASE_FOREACH (ParticleTarget *, particle_target, &psys->targets) { + if (particle_target->ob == NULL || particle_target->ob == object) { + continue; + } + /* Make sure target object is pulled into the graph. */ + build_object(NULL, particle_target->ob); + /* Use geometry component, since that's where particles are + * actually evaluated. */ + ComponentKey target_key(&particle_target->ob->id, NodeType::GEOMETRY); + add_relation(target_key, psys_key, "Keyed Target"); + } + } + /* Visualization. */ + switch (part->ren_as) { + case PART_DRAW_OB: + if (part->instance_object != NULL) { + /* Make sure object's relations are all built. */ + build_object(NULL, part->instance_object); + /* Build relation for the particle visualization. */ + build_particle_system_visualization_object(object, psys, part->instance_object); + } + break; + case PART_DRAW_GR: + if (part->instance_collection != NULL) { + build_collection(NULL, NULL, part->instance_collection); + LISTBASE_FOREACH (CollectionObject *, go, &part->instance_collection->gobject) { + build_particle_system_visualization_object(object, psys, go->ob); + } + } + break; + } + } + /* Particle depends on the object transform, so that channel is to be ready + * first. */ + add_depends_on_transform_relation(&object->id, obdata_ubereval_key, "Particle Eval"); } void DepsgraphRelationBuilder::build_particle_settings(ParticleSettings *part) { - if (built_map_.checkIsBuiltAndTag(part)) { - return; - } - /* Animation data relations. */ - build_animdata(&part->id); - build_parameters(&part->id); - OperationKey particle_settings_init_key(&part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_INIT); - OperationKey particle_settings_eval_key(&part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_EVAL); - OperationKey particle_settings_reset_key( - &part->id, - NodeType::PARTICLE_SETTINGS, - OperationCode::PARTICLE_SETTINGS_RESET); - add_relation(particle_settings_init_key, - particle_settings_eval_key, - "Particle Settings Init Order"); - add_relation(particle_settings_reset_key, - particle_settings_eval_key, - "Particle Settings Reset"); - /* Texture slots. */ - for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { - MTex *mtex = part->mtex[mtex_index]; - if (mtex == NULL || mtex->tex == NULL) { - continue; - } - build_texture(mtex->tex); - ComponentKey texture_key(&mtex->tex->id, - NodeType::GENERIC_DATABLOCK); - add_relation(texture_key, - particle_settings_reset_key, - "Particle Texture", - RELATION_FLAG_FLUSH_USER_EDIT_ONLY); - /* TODO(sergey): Consider moving texture space handling to an own - * function. */ - if (mtex->texco == TEXCO_OBJECT && mtex->object != NULL) { - ComponentKey object_key(&mtex->object->id, NodeType::TRANSFORM); - add_relation(object_key, - particle_settings_eval_key, - "Particle Texture Space"); - } - } - if (check_id_has_anim_component(&part->id)) { - ComponentKey animation_key(&part->id, NodeType::ANIMATION); - add_relation(animation_key, - particle_settings_eval_key, - "Particle Settings Animation"); - } -} - -void DepsgraphRelationBuilder::build_particle_system_visualization_object( - Object *object, - ParticleSystem *psys, - Object *draw_object) -{ - OperationKey psys_key(&object->id, - NodeType::PARTICLE_SYSTEM, - OperationCode::PARTICLE_SYSTEM_EVAL, - psys->name); - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM); - add_relation(dup_ob_key, psys_key, "Particle Object Visualization"); - if (draw_object->type == OB_MBALL) { - ComponentKey dup_geometry_key(&draw_object->id, NodeType::GEOMETRY); - add_relation(obdata_ubereval_key, - dup_geometry_key, - "Particle MBall Visualization"); - } + if (built_map_.checkIsBuiltAndTag(part)) { + return; + } + /* Animation data relations. */ + build_animdata(&part->id); + build_parameters(&part->id); + OperationKey particle_settings_init_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_INIT); + OperationKey particle_settings_eval_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_EVAL); + OperationKey particle_settings_reset_key( + &part->id, NodeType::PARTICLE_SETTINGS, OperationCode::PARTICLE_SETTINGS_RESET); + add_relation( + particle_settings_init_key, particle_settings_eval_key, "Particle Settings Init Order"); + add_relation(particle_settings_reset_key, particle_settings_eval_key, "Particle Settings Reset"); + /* Texture slots. */ + for (int mtex_index = 0; mtex_index < MAX_MTEX; ++mtex_index) { + MTex *mtex = part->mtex[mtex_index]; + if (mtex == NULL || mtex->tex == NULL) { + continue; + } + build_texture(mtex->tex); + ComponentKey texture_key(&mtex->tex->id, NodeType::GENERIC_DATABLOCK); + add_relation(texture_key, + particle_settings_reset_key, + "Particle Texture", + RELATION_FLAG_FLUSH_USER_EDIT_ONLY); + /* TODO(sergey): Consider moving texture space handling to an own + * function. */ + if (mtex->texco == TEXCO_OBJECT && mtex->object != NULL) { + ComponentKey object_key(&mtex->object->id, NodeType::TRANSFORM); + add_relation(object_key, particle_settings_eval_key, "Particle Texture Space"); + } + } + if (check_id_has_anim_component(&part->id)) { + ComponentKey animation_key(&part->id, NodeType::ANIMATION); + add_relation(animation_key, particle_settings_eval_key, "Particle Settings Animation"); + } +} + +void DepsgraphRelationBuilder::build_particle_system_visualization_object(Object *object, + ParticleSystem *psys, + Object *draw_object) +{ + OperationKey psys_key( + &object->id, NodeType::PARTICLE_SYSTEM, OperationCode::PARTICLE_SYSTEM_EVAL, psys->name); + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + ComponentKey dup_ob_key(&draw_object->id, NodeType::TRANSFORM); + add_relation(dup_ob_key, psys_key, "Particle Object Visualization"); + if (draw_object->type == OB_MBALL) { + ComponentKey dup_geometry_key(&draw_object->id, NodeType::GEOMETRY); + add_relation(obdata_ubereval_key, dup_geometry_key, "Particle MBall Visualization"); + } } /* Shapekeys */ void DepsgraphRelationBuilder::build_shapekeys(Key *key) { - if (built_map_.checkIsBuiltAndTag(key)) { - return; - } - /* Attach animdata to geometry. */ - build_animdata(&key->id); - build_parameters(&key->id); - /* Connect all blocks properties to the final result evaluation. */ - ComponentKey geometry_key(&key->id, NodeType::GEOMETRY); - OperationKey parameters_eval_key(&key->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL); - LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { - OperationKey key_block_key(&key->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - key_block->name); - add_relation(key_block_key, geometry_key, "Key Block Properties"); - add_relation(key_block_key, parameters_eval_key, "Key Block Properties"); - } + if (built_map_.checkIsBuiltAndTag(key)) { + return; + } + /* Attach animdata to geometry. */ + build_animdata(&key->id); + build_parameters(&key->id); + /* Connect all blocks properties to the final result evaluation. */ + ComponentKey geometry_key(&key->id, NodeType::GEOMETRY); + OperationKey parameters_eval_key(&key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL); + LISTBASE_FOREACH (KeyBlock *, key_block, &key->block) { + OperationKey key_block_key( + &key->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, key_block->name); + add_relation(key_block_key, geometry_key, "Key Block Properties"); + add_relation(key_block_key, parameters_eval_key, "Key Block Properties"); + } } /** @@ -2092,535 +1827,475 @@ void DepsgraphRelationBuilder::build_shapekeys(Key *key) * downstream re-evaluation of the individual instances of this geometry. */ void DepsgraphRelationBuilder::build_object_data_geometry(Object *object) { - ID *obdata = (ID *)object->data; - /* Init operation of object-level geometry evaluation. */ - OperationKey geom_init_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL_INIT); - /* Get nodes for result of obdata's evaluation, and geometry evaluation - * on object. */ - ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY); - ComponentKey geom_key(&object->id, NodeType::GEOMETRY); - /* Link components to each other. */ - add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data"); - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - /* Special case: modifiers evaluation queries scene for various things like - * data mask to be used. We add relation here to ensure object is never - * evaluated prior to Scene's CoW is ready. */ - OperationKey scene_key(&scene_->id, - NodeType::LAYER_COLLECTIONS, - OperationCode::VIEW_LAYER_EVAL); - Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); - rel->flag |= RELATION_FLAG_NO_FLUSH; - /* Modifiers */ - if (object->modifiers.first != NULL) { - ModifierUpdateDepsgraphContext ctx = {}; - ctx.scene = scene_; - ctx.object = object; - LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { - const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); - if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); - ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); - mti->updateDepsgraph(md, &ctx); - } - if (BKE_object_modifier_use_time(object, md)) { - TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); - } - } - } - /* Grease Pencil Modifiers. */ - if (object->greasepencil_modifiers.first != NULL) { - ModifierUpdateDepsgraphContext ctx = {}; - ctx.scene = scene_; - ctx.object = object; - LISTBASE_FOREACH (GpencilModifierData *, md, &object->greasepencil_modifiers) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo((GpencilModifierType)md->type); - if (mti->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); - ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); - mti->updateDepsgraph(md, &ctx); - } - if (BKE_object_modifier_gpencil_use_time(object, md)) { - TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); - } - } - } - /* Shader FX. */ - if (object->shader_fx.first != NULL) { - ModifierUpdateDepsgraphContext ctx = {}; - ctx.scene = scene_; - ctx.object = object; - LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) { - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type); - if (fxi->updateDepsgraph) { - DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); - ctx.node = reinterpret_cast< ::DepsNodeHandle* >(&handle); - fxi->updateDepsgraph(fx, &ctx); - } - if (BKE_object_shaderfx_use_time(object, fx)) { - TimeSourceKey time_src_key; - add_relation(time_src_key, obdata_ubereval_key, "Time Source"); - } - } - } - /* Materials. */ - if (object->totcol) { - for (int a = 1; a <= object->totcol; a++) { - Material *ma = give_current_material(object, a); - if (ma != NULL) { - build_material(ma); - - if (object->type == OB_MESH) { - OperationKey material_key(&ma->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey shading_key(&object->id, - NodeType::SHADING, - OperationCode::SHADING); - add_relation(material_key, shading_key, "Material Update"); - } - } - } - } - /* Geometry collision. */ - if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { - // add geometry collider relations - } - /* Make sure uber update is the last in the dependencies. */ - if (object->type != OB_ARMATURE) { - /* Armatures does no longer require uber node. */ - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - add_relation(geom_init_key, - obdata_ubereval_key, - "Object Geometry UberEval"); - if (object->totcol != 0 && object->type == OB_MESH) { - ComponentKey object_shading_key(&object->id, NodeType::SHADING); - Relation *rel = add_relation(obdata_ubereval_key, - object_shading_key, - "Object Geometry batch Update"); - rel->flag |= RELATION_FLAG_NO_FLUSH; - } - } - if (object->type == OB_MBALL) { - Object *mom = BKE_mball_basis_find(scene_, object); - ComponentKey mom_geom_key(&mom->id, NodeType::GEOMETRY); - /* motherball - mom depends on children! */ - if (mom == object) { - ComponentKey mom_transform_key(&mom->id, - NodeType::TRANSFORM); - add_relation(mom_transform_key, - mom_geom_key, - "Metaball Motherball Transform -> Geometry"); - } - else { - ComponentKey transform_key(&object->id, NodeType::TRANSFORM); - add_relation(geom_key, mom_geom_key, "Metaball Motherball"); - add_relation(transform_key, mom_geom_key, "Metaball Motherball"); - } - } - /* NOTE: This is compatibility code to support particle systems - * - * for viewport being properly rendered in final render mode. - * This relation is similar to what dag_object_time_update_flags() - * was doing for mesh objects with particle system. - * - * Ideally we need to get rid of this relation. */ - if (object_particles_depends_on_time(object)) { - TimeSourceKey time_key; - OperationKey obdata_ubereval_key(&object->id, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL); - add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); - } - /* Object data datablock. */ - build_object_data_geometry_datablock((ID *)object->data); - Key *key = BKE_key_from_object(object); - if (key != NULL) { - if (key->adt != NULL) { - if (key->adt->action || key->adt->nla_tracks.first) { - ComponentKey obdata_key((ID *)object->data, - NodeType::GEOMETRY); - ComponentKey adt_key(&key->id, NodeType::ANIMATION); - add_relation(adt_key, obdata_key, "Animation"); - } - } - } - /* Syncronization back to original object. */ - ComponentKey final_geometry_jey(&object->id, NodeType::GEOMETRY); - OperationKey synchronize_key(&object->id, - NodeType::SYNCHRONIZATION, - OperationCode::SYNCHRONIZE_TO_ORIGINAL); - add_relation( - final_geometry_jey, synchronize_key, "Synchronize to Original"); + ID *obdata = (ID *)object->data; + /* Init operation of object-level geometry evaluation. */ + OperationKey geom_init_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_INIT); + /* Get nodes for result of obdata's evaluation, and geometry evaluation + * on object. */ + ComponentKey obdata_geom_key(obdata, NodeType::GEOMETRY); + ComponentKey geom_key(&object->id, NodeType::GEOMETRY); + /* Link components to each other. */ + add_relation(obdata_geom_key, geom_key, "Object Geometry Base Data"); + OperationKey obdata_ubereval_key(&object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + /* Special case: modifiers evaluation queries scene for various things like + * data mask to be used. We add relation here to ensure object is never + * evaluated prior to Scene's CoW is ready. */ + OperationKey scene_key(&scene_->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL); + Relation *rel = add_relation(scene_key, obdata_ubereval_key, "CoW Relation"); + rel->flag |= RELATION_FLAG_NO_FLUSH; + /* Modifiers */ + if (object->modifiers.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); + if (mti->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); + mti->updateDepsgraph(md, &ctx); + } + if (BKE_object_modifier_use_time(object, md)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } + /* Grease Pencil Modifiers. */ + if (object->greasepencil_modifiers.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH (GpencilModifierData *, md, &object->greasepencil_modifiers) { + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo( + (GpencilModifierType)md->type); + if (mti->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); + mti->updateDepsgraph(md, &ctx); + } + if (BKE_object_modifier_gpencil_use_time(object, md)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } + /* Shader FX. */ + if (object->shader_fx.first != NULL) { + ModifierUpdateDepsgraphContext ctx = {}; + ctx.scene = scene_; + ctx.object = object; + LISTBASE_FOREACH (ShaderFxData *, fx, &object->shader_fx) { + const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo((ShaderFxType)fx->type); + if (fxi->updateDepsgraph) { + DepsNodeHandle handle = create_node_handle(obdata_ubereval_key); + ctx.node = reinterpret_cast<::DepsNodeHandle *>(&handle); + fxi->updateDepsgraph(fx, &ctx); + } + if (BKE_object_shaderfx_use_time(object, fx)) { + TimeSourceKey time_src_key; + add_relation(time_src_key, obdata_ubereval_key, "Time Source"); + } + } + } + /* Materials. */ + if (object->totcol) { + for (int a = 1; a <= object->totcol; a++) { + Material *ma = give_current_material(object, a); + if (ma != NULL) { + build_material(ma); + + if (object->type == OB_MESH) { + OperationKey material_key(&ma->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey shading_key(&object->id, NodeType::SHADING, OperationCode::SHADING); + add_relation(material_key, shading_key, "Material Update"); + } + } + } + } + /* Geometry collision. */ + if (ELEM(object->type, OB_MESH, OB_CURVE, OB_LATTICE)) { + // add geometry collider relations + } + /* Make sure uber update is the last in the dependencies. */ + if (object->type != OB_ARMATURE) { + /* Armatures does no longer require uber node. */ + OperationKey obdata_ubereval_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + add_relation(geom_init_key, obdata_ubereval_key, "Object Geometry UberEval"); + if (object->totcol != 0 && object->type == OB_MESH) { + ComponentKey object_shading_key(&object->id, NodeType::SHADING); + Relation *rel = add_relation( + obdata_ubereval_key, object_shading_key, "Object Geometry batch Update"); + rel->flag |= RELATION_FLAG_NO_FLUSH; + } + } + if (object->type == OB_MBALL) { + Object *mom = BKE_mball_basis_find(scene_, object); + ComponentKey mom_geom_key(&mom->id, NodeType::GEOMETRY); + /* motherball - mom depends on children! */ + if (mom == object) { + ComponentKey mom_transform_key(&mom->id, NodeType::TRANSFORM); + add_relation(mom_transform_key, mom_geom_key, "Metaball Motherball Transform -> Geometry"); + } + else { + ComponentKey transform_key(&object->id, NodeType::TRANSFORM); + add_relation(geom_key, mom_geom_key, "Metaball Motherball"); + add_relation(transform_key, mom_geom_key, "Metaball Motherball"); + } + } + /* NOTE: This is compatibility code to support particle systems + * + * for viewport being properly rendered in final render mode. + * This relation is similar to what dag_object_time_update_flags() + * was doing for mesh objects with particle system. + * + * Ideally we need to get rid of this relation. */ + if (object_particles_depends_on_time(object)) { + TimeSourceKey time_key; + OperationKey obdata_ubereval_key( + &object->id, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + add_relation(time_key, obdata_ubereval_key, "Legacy particle time"); + } + /* Object data datablock. */ + build_object_data_geometry_datablock((ID *)object->data); + Key *key = BKE_key_from_object(object); + if (key != NULL) { + if (key->adt != NULL) { + if (key->adt->action || key->adt->nla_tracks.first) { + ComponentKey obdata_key((ID *)object->data, NodeType::GEOMETRY); + ComponentKey adt_key(&key->id, NodeType::ANIMATION); + add_relation(adt_key, obdata_key, "Animation"); + } + } + } + /* Syncronization back to original object. */ + ComponentKey final_geometry_jey(&object->id, NodeType::GEOMETRY); + OperationKey synchronize_key( + &object->id, NodeType::SYNCHRONIZATION, OperationCode::SYNCHRONIZE_TO_ORIGINAL); + add_relation(final_geometry_jey, synchronize_key, "Synchronize to Original"); } void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) { - if (built_map_.checkIsBuiltAndTag(obdata)) { - return; - } - /* Animation. */ - build_animdata(obdata); - build_parameters(obdata); - /* ShapeKeys. */ - Key *key = BKE_key_from_id(obdata); - if (key != NULL) { - build_shapekeys(key); - } - /* Link object data evaluation node to exit operation. */ - OperationKey obdata_geom_eval_key( - obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); - OperationKey obdata_geom_done_key(obdata, - NodeType::GEOMETRY, - OperationCode::GEOMETRY_EVAL_DONE); - add_relation(obdata_geom_eval_key, - obdata_geom_done_key, - "ObData Geom Eval Done"); - /* Type-specific links. */ - const ID_Type id_type = GS(obdata->name); - switch (id_type) { - case ID_ME: - break; - case ID_MB: - break; - case ID_CU: - { - Curve *cu = (Curve *)obdata; - if (cu->bevobj != NULL) { - ComponentKey bevob_geom_key( - &cu->bevobj->id, - NodeType::GEOMETRY); - add_relation( - bevob_geom_key, - obdata_geom_eval_key, - "Curve Bevel Geometry"); - ComponentKey bevob_key( - &cu->bevobj->id, - NodeType::TRANSFORM); - add_relation( - bevob_key, - obdata_geom_eval_key, - "Curve Bevel Transform"); - build_object(NULL, cu->bevobj); - } - if (cu->taperobj != NULL) { - ComponentKey taperob_key( - &cu->taperobj->id, - NodeType::GEOMETRY); - add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); - build_object(NULL, cu->taperobj); - } - if (cu->textoncurve != NULL) { - ComponentKey textoncurve_key( - &cu->textoncurve->id, - NodeType::GEOMETRY); - add_relation( - textoncurve_key, - obdata_geom_eval_key, - "Text on Curve"); - build_object(NULL, cu->textoncurve); - } - break; - } - case ID_LT: - break; - case ID_GD: /* Grease Pencil */ - { - bGPdata *gpd = (bGPdata *)obdata; - - /* Geometry cache needs to be recalculated on frame change - * (e.g. to fix crashes after scrubbing the timeline when - * onion skinning is enabled, since the ghosts need to be - * re-added to the cache once scrubbing ends). */ - TimeSourceKey time_key; - ComponentKey geometry_key(obdata, NodeType::GEOMETRY); - add_relation(time_key, - geometry_key, - "GP Frame Change"); - - /* Geometry cache also needs to be recalculated when Material - * settings change (e.g. when fill.opacity changes on/off, - * we need to rebuild the bGPDstroke->triangles caches). */ - for (int i = 0; i < gpd->totcol; i++) { - Material *ma = gpd->mat[i]; - if ((ma != NULL) && (ma->gp_style != NULL)) { - OperationKey material_key(&ma->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - add_relation(material_key, - geometry_key, - "Material -> GP Data"); - } - } - break; - } - default: - BLI_assert(!"Should not happen"); - break; - } + if (built_map_.checkIsBuiltAndTag(obdata)) { + return; + } + /* Animation. */ + build_animdata(obdata); + build_parameters(obdata); + /* ShapeKeys. */ + Key *key = BKE_key_from_id(obdata); + if (key != NULL) { + build_shapekeys(key); + } + /* Link object data evaluation node to exit operation. */ + OperationKey obdata_geom_eval_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL); + OperationKey obdata_geom_done_key(obdata, NodeType::GEOMETRY, OperationCode::GEOMETRY_EVAL_DONE); + add_relation(obdata_geom_eval_key, obdata_geom_done_key, "ObData Geom Eval Done"); + /* Type-specific links. */ + const ID_Type id_type = GS(obdata->name); + switch (id_type) { + case ID_ME: + break; + case ID_MB: + break; + case ID_CU: { + Curve *cu = (Curve *)obdata; + if (cu->bevobj != NULL) { + ComponentKey bevob_geom_key(&cu->bevobj->id, NodeType::GEOMETRY); + add_relation(bevob_geom_key, obdata_geom_eval_key, "Curve Bevel Geometry"); + ComponentKey bevob_key(&cu->bevobj->id, NodeType::TRANSFORM); + add_relation(bevob_key, obdata_geom_eval_key, "Curve Bevel Transform"); + build_object(NULL, cu->bevobj); + } + if (cu->taperobj != NULL) { + ComponentKey taperob_key(&cu->taperobj->id, NodeType::GEOMETRY); + add_relation(taperob_key, obdata_geom_eval_key, "Curve Taper"); + build_object(NULL, cu->taperobj); + } + if (cu->textoncurve != NULL) { + ComponentKey textoncurve_key(&cu->textoncurve->id, NodeType::GEOMETRY); + add_relation(textoncurve_key, obdata_geom_eval_key, "Text on Curve"); + build_object(NULL, cu->textoncurve); + } + break; + } + case ID_LT: + break; + case ID_GD: /* Grease Pencil */ + { + bGPdata *gpd = (bGPdata *)obdata; + + /* Geometry cache needs to be recalculated on frame change + * (e.g. to fix crashes after scrubbing the timeline when + * onion skinning is enabled, since the ghosts need to be + * re-added to the cache once scrubbing ends). */ + TimeSourceKey time_key; + ComponentKey geometry_key(obdata, NodeType::GEOMETRY); + add_relation(time_key, geometry_key, "GP Frame Change"); + + /* Geometry cache also needs to be recalculated when Material + * settings change (e.g. when fill.opacity changes on/off, + * we need to rebuild the bGPDstroke->triangles caches). */ + for (int i = 0; i < gpd->totcol; i++) { + Material *ma = gpd->mat[i]; + if ((ma != NULL) && (ma->gp_style != NULL)) { + OperationKey material_key(&ma->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + add_relation(material_key, geometry_key, "Material -> GP Data"); + } + } + break; + } + default: + BLI_assert(!"Should not happen"); + break; + } } void DepsgraphRelationBuilder::build_armature(bArmature *armature) { - if (built_map_.checkIsBuiltAndTag(armature)) { - return; - } - build_animdata(&armature->id); - build_parameters(&armature->id); + if (built_map_.checkIsBuiltAndTag(armature)) { + return; + } + build_animdata(&armature->id); + build_parameters(&armature->id); } void DepsgraphRelationBuilder::build_camera(Camera *camera) { - if (built_map_.checkIsBuiltAndTag(camera)) { - return; - } - build_parameters(&camera->id); - if (camera->dof_ob != NULL) { - ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); - ComponentKey dof_ob_key(&camera->dof_ob->id, NodeType::TRANSFORM); - add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); - } + if (built_map_.checkIsBuiltAndTag(camera)) { + return; + } + build_parameters(&camera->id); + if (camera->dof_ob != NULL) { + ComponentKey camera_parameters_key(&camera->id, NodeType::PARAMETERS); + ComponentKey dof_ob_key(&camera->dof_ob->id, NodeType::TRANSFORM); + add_relation(dof_ob_key, camera_parameters_key, "Camera DOF"); + } } /* Lights */ void DepsgraphRelationBuilder::build_light(Light *lamp) { - if (built_map_.checkIsBuiltAndTag(lamp)) { - return; - } - build_parameters(&lamp->id); - /* light's nodetree */ - if (lamp->nodetree != NULL) { - build_nodetree(lamp->nodetree); - ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); - ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); - add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters"); - build_nested_nodetree(&lamp->id, lamp->nodetree); - } + if (built_map_.checkIsBuiltAndTag(lamp)) { + return; + } + build_parameters(&lamp->id); + /* light's nodetree */ + if (lamp->nodetree != NULL) { + build_nodetree(lamp->nodetree); + ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); + ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); + add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters"); + build_nested_nodetree(&lamp->id, lamp->nodetree); + } } void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) { - if (ntree == NULL) { - return; - } - if (built_map_.checkIsBuiltAndTag(ntree)) { - return; - } - build_animdata(&ntree->id); - build_parameters(&ntree->id); - ComponentKey shading_key(&ntree->id, NodeType::SHADING); - /* nodetree's nodes... */ - LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { - ID *id = bnode->id; - if (id == NULL) { - continue; - } - ID_Type id_type = GS(id->name); - if (id_type == ID_MA) { - build_material((Material *)bnode->id); - } - else if (id_type == ID_TE) { - build_texture((Tex *)bnode->id); - } - else if (id_type == ID_IM) { - build_image((Image *)bnode->id); - } - else if (id_type == ID_OB) { - build_object(NULL, (Object *)id); - } - else if (id_type == ID_SCE) { - /* Scenes are used by compositor trees, and handled by render - * pipeline. No need to build dependencies for them here. */ - } - else if (id_type == ID_TXT) { - /* Ignore script nodes. */ - } - else if (id_type == ID_MSK) { - build_mask((Mask *)id); - } - else if (id_type == ID_MC) { - build_movieclip((MovieClip *)id); - } - else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - bNodeTree *group_ntree = (bNodeTree *)id; - build_nodetree(group_ntree); - ComponentKey group_shading_key(&group_ntree->id, - NodeType::SHADING); - add_relation(group_shading_key, shading_key, "Group Node"); - } - else { - BLI_assert(!"Unknown ID type used for node"); - } - } - - OperationKey shading_update_key(&ntree->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey shading_parameters_key(&ntree->id, - NodeType::SHADING_PARAMETERS, - OperationCode::MATERIAL_UPDATE); - add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters"); - - if (check_id_has_anim_component(&ntree->id)) { - ComponentKey animation_key(&ntree->id, NodeType::ANIMATION); - add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters"); - } - ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS); - add_relation(parameters_key, shading_parameters_key, "NTree Shading Parameters"); + if (ntree == NULL) { + return; + } + if (built_map_.checkIsBuiltAndTag(ntree)) { + return; + } + build_animdata(&ntree->id); + build_parameters(&ntree->id); + ComponentKey shading_key(&ntree->id, NodeType::SHADING); + /* nodetree's nodes... */ + LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { + ID *id = bnode->id; + if (id == NULL) { + continue; + } + ID_Type id_type = GS(id->name); + if (id_type == ID_MA) { + build_material((Material *)bnode->id); + } + else if (id_type == ID_TE) { + build_texture((Tex *)bnode->id); + } + else if (id_type == ID_IM) { + build_image((Image *)bnode->id); + } + else if (id_type == ID_OB) { + build_object(NULL, (Object *)id); + } + else if (id_type == ID_SCE) { + /* Scenes are used by compositor trees, and handled by render + * pipeline. No need to build dependencies for them here. */ + } + else if (id_type == ID_TXT) { + /* Ignore script nodes. */ + } + else if (id_type == ID_MSK) { + build_mask((Mask *)id); + } + else if (id_type == ID_MC) { + build_movieclip((MovieClip *)id); + } + else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { + bNodeTree *group_ntree = (bNodeTree *)id; + build_nodetree(group_ntree); + ComponentKey group_shading_key(&group_ntree->id, NodeType::SHADING); + add_relation(group_shading_key, shading_key, "Group Node"); + } + else { + BLI_assert(!"Unknown ID type used for node"); + } + } + + OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey shading_parameters_key( + &ntree->id, NodeType::SHADING_PARAMETERS, OperationCode::MATERIAL_UPDATE); + add_relation(shading_parameters_key, shading_update_key, "NTree Shading Parameters"); + + if (check_id_has_anim_component(&ntree->id)) { + ComponentKey animation_key(&ntree->id, NodeType::ANIMATION); + add_relation(animation_key, shading_parameters_key, "NTree Shading Parameters"); + } + ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS); + add_relation(parameters_key, shading_parameters_key, "NTree Shading Parameters"); } /* Recursively build graph for material */ void DepsgraphRelationBuilder::build_material(Material *material) { - if (built_map_.checkIsBuiltAndTag(material)) { - return; - } - /* animation */ - build_animdata(&material->id); - build_parameters(&material->id); - /* material's nodetree */ - if (material->nodetree != NULL) { - build_nodetree(material->nodetree); - OperationKey ntree_key(&material->nodetree->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - OperationKey material_key(&material->id, - NodeType::SHADING, - OperationCode::MATERIAL_UPDATE); - add_relation(ntree_key, material_key, "Material's NTree"); - build_nested_nodetree(&material->id, material->nodetree); - } + if (built_map_.checkIsBuiltAndTag(material)) { + return; + } + /* animation */ + build_animdata(&material->id); + build_parameters(&material->id); + /* material's nodetree */ + if (material->nodetree != NULL) { + build_nodetree(material->nodetree); + OperationKey ntree_key( + &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + OperationKey material_key(&material->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + add_relation(ntree_key, material_key, "Material's NTree"); + build_nested_nodetree(&material->id, material->nodetree); + } } /* Recursively build graph for texture */ void DepsgraphRelationBuilder::build_texture(Tex *texture) { - if (built_map_.checkIsBuiltAndTag(texture)) { - return; - } - /* texture itself */ - build_animdata(&texture->id); - build_parameters(&texture->id); - /* texture's nodetree */ - build_nodetree(texture->nodetree); - /* Special cases for different IDs which texture uses. */ - if (texture->type == TEX_IMAGE) { - if (texture->ima != NULL) { - build_image(texture->ima); - } - } - build_nested_nodetree(&texture->id, texture->nodetree); - if (check_id_has_anim_component(&texture->id)) { - ComponentKey animation_key(&texture->id, NodeType::ANIMATION); - ComponentKey datablock_key(&texture->id, - NodeType::GENERIC_DATABLOCK); - add_relation(animation_key, datablock_key, "Datablock Animation"); - } + if (built_map_.checkIsBuiltAndTag(texture)) { + return; + } + /* texture itself */ + build_animdata(&texture->id); + build_parameters(&texture->id); + /* texture's nodetree */ + build_nodetree(texture->nodetree); + /* Special cases for different IDs which texture uses. */ + if (texture->type == TEX_IMAGE) { + if (texture->ima != NULL) { + build_image(texture->ima); + } + } + build_nested_nodetree(&texture->id, texture->nodetree); + if (check_id_has_anim_component(&texture->id)) { + ComponentKey animation_key(&texture->id, NodeType::ANIMATION); + ComponentKey datablock_key(&texture->id, NodeType::GENERIC_DATABLOCK); + add_relation(animation_key, datablock_key, "Datablock Animation"); + } } void DepsgraphRelationBuilder::build_image(Image *image) { - if (built_map_.checkIsBuiltAndTag(image)) { - return; - } - build_parameters(&image->id); + if (built_map_.checkIsBuiltAndTag(image)) { + return; + } + build_parameters(&image->id); } void DepsgraphRelationBuilder::build_compositor(Scene *scene) { - /* For now, just a plain wrapper? */ - build_nodetree(scene->nodetree); + /* For now, just a plain wrapper? */ + build_nodetree(scene->nodetree); } void DepsgraphRelationBuilder::build_gpencil(bGPdata *gpd) { - if (built_map_.checkIsBuiltAndTag(gpd)) { - return; - } - /* animation */ - build_animdata(&gpd->id); - build_parameters(&gpd->id); + if (built_map_.checkIsBuiltAndTag(gpd)) { + return; + } + /* animation */ + build_animdata(&gpd->id); + build_parameters(&gpd->id); - // TODO: parent object (when that feature is implemented) + // TODO: parent object (when that feature is implemented) } void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { - if (built_map_.checkIsBuiltAndTag(cache_file)) { - return; - } - /* Animation. */ - build_animdata(&cache_file->id); - build_parameters(&cache_file->id); - if (check_id_has_anim_component(&cache_file->id)) { - ComponentKey animation_key(&cache_file->id, NodeType::ANIMATION); - ComponentKey datablock_key(&cache_file->id, - NodeType::CACHE); - add_relation(animation_key, datablock_key, "Datablock Animation"); - } + if (built_map_.checkIsBuiltAndTag(cache_file)) { + return; + } + /* Animation. */ + build_animdata(&cache_file->id); + build_parameters(&cache_file->id); + if (check_id_has_anim_component(&cache_file->id)) { + ComponentKey animation_key(&cache_file->id, NodeType::ANIMATION); + ComponentKey datablock_key(&cache_file->id, NodeType::CACHE); + add_relation(animation_key, datablock_key, "Datablock Animation"); + } } void DepsgraphRelationBuilder::build_mask(Mask *mask) { - if (built_map_.checkIsBuiltAndTag(mask)) { - return; - } - ID *mask_id = &mask->id; - /* F-Curve animation. */ - build_animdata(mask_id); - build_parameters(mask_id); - /* Own mask animation. */ - OperationKey mask_animation_key(mask_id, - NodeType::ANIMATION, - OperationCode::MASK_ANIMATION); - TimeSourceKey time_src_key; - add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation"); - /* Final mask evaluation. */ - ComponentKey parameters_key(mask_id, NodeType::PARAMETERS); - add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval"); + if (built_map_.checkIsBuiltAndTag(mask)) { + return; + } + ID *mask_id = &mask->id; + /* F-Curve animation. */ + build_animdata(mask_id); + build_parameters(mask_id); + /* Own mask animation. */ + OperationKey mask_animation_key(mask_id, NodeType::ANIMATION, OperationCode::MASK_ANIMATION); + TimeSourceKey time_src_key; + add_relation(time_src_key, mask_animation_key, "TimeSrc -> Mask Animation"); + /* Final mask evaluation. */ + ComponentKey parameters_key(mask_id, NodeType::PARAMETERS); + add_relation(mask_animation_key, parameters_key, "Mask Animation -> Mask Eval"); } void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) { - if (built_map_.checkIsBuiltAndTag(clip)) { - return; - } - /* Animation. */ - build_animdata(&clip->id); - build_parameters(&clip->id); + if (built_map_.checkIsBuiltAndTag(clip)) { + return; + } + /* Animation. */ + build_animdata(&clip->id); + build_parameters(&clip->id); } void DepsgraphRelationBuilder::build_lightprobe(LightProbe *probe) { - if (built_map_.checkIsBuiltAndTag(probe)) { - return; - } - build_animdata(&probe->id); - build_parameters(&probe->id); + if (built_map_.checkIsBuiltAndTag(probe)) { + return; + } + build_animdata(&probe->id); + build_parameters(&probe->id); } void DepsgraphRelationBuilder::build_speaker(Speaker *speaker) { - if (built_map_.checkIsBuiltAndTag(speaker)) { - return; - } - build_animdata(&speaker->id); - build_parameters(&speaker->id); + if (built_map_.checkIsBuiltAndTag(speaker)) { + return; + } + build_animdata(&speaker->id); + build_parameters(&speaker->id); } void DepsgraphRelationBuilder::build_copy_on_write_relations() { - for (IDNode *id_node : graph_->id_nodes) { - build_copy_on_write_relations(id_node); - } + for (IDNode *id_node : graph_->id_nodes) { + build_copy_on_write_relations(id_node); + } } /* Nested datablocks (node trees, shape keys) requires special relation to @@ -2630,150 +2305,132 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations() */ void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id) { - OperationKey owner_copy_on_write_key(owner, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - OperationKey id_copy_on_write_key(id, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - add_relation(id_copy_on_write_key, - owner_copy_on_write_key, - "Eval Order"); + OperationKey owner_copy_on_write_key( + owner, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + OperationKey id_copy_on_write_key(id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order"); } -void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, - bNodeTree *ntree) +void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree) { - if (ntree == NULL) { - return; - } - build_nested_datablock(owner, &ntree->id); + if (ntree == NULL) { + return; + } + build_nested_datablock(owner, &ntree->id); } void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key) { - if (key == NULL) { - return; - } - build_nested_datablock(owner, &key->id); + if (key == NULL) { + return; + } + build_nested_datablock(owner, &key->id); } void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) { - ID *id_orig = id_node->id_orig; - const ID_Type id_type = GS(id_orig->name); - TimeSourceKey time_source_key; - OperationKey copy_on_write_key(id_orig, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - /* XXX: This is a quick hack to make Alt-A to work. */ - // add_relation(time_source_key, copy_on_write_key, "Fluxgate capacitor hack"); - /* Resat of code is using rather low level trickery, so need to get some - * explicit pointers. */ - Node *node_cow = find_node(copy_on_write_key); - OperationNode *op_cow = node_cow->get_exit_operation(); - /* Plug any other components to this one. */ - GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, id_node->components) - { - if (comp_node->type == NodeType::COPY_ON_WRITE) { - /* Copy-on-write component never depends on itself. */ - continue; - } - if (!comp_node->depends_on_cow()) { - /* Component explicitly requests to not add relation. */ - continue; - } - int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE); - if (id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) { - rel_flag &= ~RELATION_FLAG_NO_FLUSH; - } - /* Notes on exceptions: - * - Parameters component is where drivers are living. Changing any - * of the (custom) properties in the original datablock (even the - * ones which do not imply other component update) need to make - * sure drivers are properly updated. - * This way, for example, changing ID property will properly poke - * all drivers to be updated. - * - * - View layers have cached array of bases in them, which is not - * copied by copy-on-write, and not preserved. PROBABLY it is better - * to preserve that cache in copy-on-write, but for the time being - * we allow flush to layer collections component which will ensure - * that cached array fo bases exists and is up-to-date. */ - if (comp_node->type == NodeType::PARAMETERS || - comp_node->type == NodeType::LAYER_COLLECTIONS) - { - rel_flag &= ~RELATION_FLAG_NO_FLUSH; - } - /* All entry operations of each component should wait for a proper - * copy of ID. */ - OperationNode *op_entry = comp_node->get_entry_operation(); - if (op_entry != NULL) { - Relation *rel = graph_->add_new_relation( - op_cow, op_entry, "CoW Dependency"); - rel->flag |= rel_flag; - } - /* All dangling operations should also be executed after copy-on-write. */ - GHASH_FOREACH_BEGIN(OperationNode *, op_node, comp_node->operations_map) - { - if (op_node == op_entry) { - continue; - } - if (op_node->inlinks.size() == 0) { - Relation *rel = graph_->add_new_relation( - op_cow, op_node, "CoW Dependency"); - rel->flag |= rel_flag; - } - else { - bool has_same_comp_dependency = false; - for (Relation *rel_current : op_node->inlinks) { - if (rel_current->from->type != NodeType::OPERATION) { - continue; - } - OperationNode *op_node_from = - (OperationNode *)rel_current->from; - if (op_node_from->owner == op_node->owner) { - has_same_comp_dependency = true; - break; - } - } - if (!has_same_comp_dependency) { - Relation *rel = graph_->add_new_relation( - op_cow, op_node, "CoW Dependency"); - rel->flag |= rel_flag; - } - } - } - GHASH_FOREACH_END(); - /* NOTE: We currently ignore implicit relations to an external - * datablocks for copy-on-write operations. This means, for example, - * copy-on-write component of Object will not wait for copy-on-write - * component of it's Mesh. This is because pointers are all known - * already so remapping will happen all correct. And then If some object - * evaluation step needs geometry, it will have transitive dependency - * to Mesh copy-on-write already. */ - } - GHASH_FOREACH_END(); - /* TODO(sergey): This solves crash for now, but causes too many - * updates potentially. */ - if (GS(id_orig->name) == ID_OB) { - Object *object = (Object *)id_orig; - ID *object_data_id = (ID *)object->data; - if (object_data_id != NULL) { - if (deg_copy_on_write_is_needed(object_data_id)) { - OperationKey data_copy_on_write_key(object_data_id, - NodeType::COPY_ON_WRITE, - OperationCode::COPY_ON_WRITE); - add_relation(data_copy_on_write_key, - copy_on_write_key, - "Eval Order", - RELATION_FLAG_GODMODE); - } - } - else { - BLI_assert(object->type == OB_EMPTY); - } - } + ID *id_orig = id_node->id_orig; + const ID_Type id_type = GS(id_orig->name); + TimeSourceKey time_source_key; + OperationKey copy_on_write_key(id_orig, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + /* XXX: This is a quick hack to make Alt-A to work. */ + // add_relation(time_source_key, copy_on_write_key, "Fluxgate capacitor hack"); + /* Resat of code is using rather low level trickery, so need to get some + * explicit pointers. */ + Node *node_cow = find_node(copy_on_write_key); + OperationNode *op_cow = node_cow->get_exit_operation(); + /* Plug any other components to this one. */ + GHASH_FOREACH_BEGIN (ComponentNode *, comp_node, id_node->components) { + if (comp_node->type == NodeType::COPY_ON_WRITE) { + /* Copy-on-write component never depends on itself. */ + continue; + } + if (!comp_node->depends_on_cow()) { + /* Component explicitly requests to not add relation. */ + continue; + } + int rel_flag = (RELATION_FLAG_NO_FLUSH | RELATION_FLAG_GODMODE); + if (id_type == ID_ME && comp_node->type == NodeType::GEOMETRY) { + rel_flag &= ~RELATION_FLAG_NO_FLUSH; + } + /* Notes on exceptions: + * - Parameters component is where drivers are living. Changing any + * of the (custom) properties in the original datablock (even the + * ones which do not imply other component update) need to make + * sure drivers are properly updated. + * This way, for example, changing ID property will properly poke + * all drivers to be updated. + * + * - View layers have cached array of bases in them, which is not + * copied by copy-on-write, and not preserved. PROBABLY it is better + * to preserve that cache in copy-on-write, but for the time being + * we allow flush to layer collections component which will ensure + * that cached array fo bases exists and is up-to-date. */ + if (comp_node->type == NodeType::PARAMETERS || + comp_node->type == NodeType::LAYER_COLLECTIONS) { + rel_flag &= ~RELATION_FLAG_NO_FLUSH; + } + /* All entry operations of each component should wait for a proper + * copy of ID. */ + OperationNode *op_entry = comp_node->get_entry_operation(); + if (op_entry != NULL) { + Relation *rel = graph_->add_new_relation(op_cow, op_entry, "CoW Dependency"); + rel->flag |= rel_flag; + } + /* All dangling operations should also be executed after copy-on-write. */ + GHASH_FOREACH_BEGIN (OperationNode *, op_node, comp_node->operations_map) { + if (op_node == op_entry) { + continue; + } + if (op_node->inlinks.size() == 0) { + Relation *rel = graph_->add_new_relation(op_cow, op_node, "CoW Dependency"); + rel->flag |= rel_flag; + } + else { + bool has_same_comp_dependency = false; + for (Relation *rel_current : op_node->inlinks) { + if (rel_current->from->type != NodeType::OPERATION) { + continue; + } + OperationNode *op_node_from = (OperationNode *)rel_current->from; + if (op_node_from->owner == op_node->owner) { + has_same_comp_dependency = true; + break; + } + } + if (!has_same_comp_dependency) { + Relation *rel = graph_->add_new_relation(op_cow, op_node, "CoW Dependency"); + rel->flag |= rel_flag; + } + } + } + GHASH_FOREACH_END(); + /* NOTE: We currently ignore implicit relations to an external + * datablocks for copy-on-write operations. This means, for example, + * copy-on-write component of Object will not wait for copy-on-write + * component of it's Mesh. This is because pointers are all known + * already so remapping will happen all correct. And then If some object + * evaluation step needs geometry, it will have transitive dependency + * to Mesh copy-on-write already. */ + } + GHASH_FOREACH_END(); + /* TODO(sergey): This solves crash for now, but causes too many + * updates potentially. */ + if (GS(id_orig->name) == ID_OB) { + Object *object = (Object *)id_orig; + ID *object_data_id = (ID *)object->data; + if (object_data_id != NULL) { + if (deg_copy_on_write_is_needed(object_data_id)) { + OperationKey data_copy_on_write_key( + object_data_id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); + add_relation( + data_copy_on_write_key, copy_on_write_key, "Eval Order", RELATION_FLAG_GODMODE); + } + } + else { + BLI_assert(object->type == OB_EMPTY); + } + } } /* **** ID traversal callbacks functions **** */ @@ -2783,12 +2440,12 @@ void DepsgraphRelationBuilder::modifier_walk(void *user_data, struct ID **idpoin, int /*cb_flag*/) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - data->builder->build_id(id); + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + data->builder->build_id(id); } void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/, @@ -2796,12 +2453,12 @@ void DepsgraphRelationBuilder::constraint_walk(bConstraint * /*con*/, bool /*is_reference*/, void *user_data) { - BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; - ID *id = *idpoin; - if (id == NULL) { - return; - } - data->builder->build_id(id); + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + ID *id = *idpoin; + if (id == NULL) { + return; + } + data->builder->build_id(id); } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 0a0f0e99865..5b2d34a270c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -93,301 +93,268 @@ struct Relation; struct RootPChanMap; struct TimeSourceNode; -struct TimeSourceKey -{ - TimeSourceKey(); - TimeSourceKey(ID *id); +struct TimeSourceKey { + TimeSourceKey(); + TimeSourceKey(ID *id); - string identifier() const; + string identifier() const; - ID *id; + ID *id; }; -struct ComponentKey -{ - ComponentKey(); - ComponentKey(ID *id, NodeType type, const char *name = ""); +struct ComponentKey { + ComponentKey(); + ComponentKey(ID *id, NodeType type, const char *name = ""); - string identifier() const; + string identifier() const; - ID *id; - NodeType type; - const char *name; + ID *id; + NodeType type; + const char *name; }; -struct OperationKey -{ - OperationKey(); - OperationKey(ID *id, - NodeType component_type, - const char *name, - int name_tag = -1); - OperationKey(ID *id, - NodeType component_type, - const char *component_name, - const char *name, - int name_tag); - - OperationKey(ID *id, - NodeType component_type, - OperationCode opcode); - OperationKey(ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode); - - OperationKey(ID *id, - NodeType component_type, - OperationCode opcode, - const char *name, - int name_tag = -1); - OperationKey(ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode, - const char *name, - int name_tag = -1); - - string identifier() const; - - ID *id; - NodeType component_type; - const char *component_name; - OperationCode opcode; - const char *name; - int name_tag; +struct OperationKey { + OperationKey(); + OperationKey(ID *id, NodeType component_type, const char *name, int name_tag = -1); + OperationKey( + ID *id, NodeType component_type, const char *component_name, const char *name, int name_tag); + + OperationKey(ID *id, NodeType component_type, OperationCode opcode); + OperationKey(ID *id, NodeType component_type, const char *component_name, OperationCode opcode); + + OperationKey( + ID *id, NodeType component_type, OperationCode opcode, const char *name, int name_tag = -1); + OperationKey(ID *id, + NodeType component_type, + const char *component_name, + OperationCode opcode, + const char *name, + int name_tag = -1); + + string identifier() const; + + ID *id; + NodeType component_type; + const char *component_name; + OperationCode opcode; + const char *name; + int name_tag; }; -struct RNAPathKey -{ - RNAPathKey(ID *id, const char *path, RNAPointerSource source); - RNAPathKey(ID *id, - const PointerRNA &ptr, - PropertyRNA *prop, - RNAPointerSource source); +struct RNAPathKey { + RNAPathKey(ID *id, const char *path, RNAPointerSource source); + RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source); - string identifier() const; + string identifier() const; - ID *id; - PointerRNA ptr; - PropertyRNA *prop; - RNAPointerSource source; + ID *id; + PointerRNA ptr; + PropertyRNA *prop; + RNAPointerSource source; }; -class DepsgraphRelationBuilder : public DepsgraphBuilder -{ -public: - DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph); - - void begin_build(); - - template <typename KeyFrom, typename KeyTo> - Relation *add_relation(const KeyFrom& key_from, - const KeyTo& key_to, - const char *description, - int flags = 0); - - template <typename KeyTo> - Relation *add_relation(const TimeSourceKey& key_from, - const KeyTo& key_to, - const char *description, - int flags = 0); - - template <typename KeyType> - Relation *add_node_handle_relation(const KeyType& key_from, - const DepsNodeHandle *handle, - const char *description, - int flags = 0); - - template <typename KeyTo> - Relation *add_depends_on_transform_relation(ID *id, - const KeyTo& key_to, - const char *description, - int flags = 0); - - /* Adds relation from proper transformation opertation to the modifier. - * Takes care of checking for possible physics solvers modifying position - * of this object. */ - void add_modifier_to_transform_relation(const DepsNodeHandle *handle, - const char *description); - - void add_customdata_mask(Object *object, - const DEGCustomDataMeshMasks &customdata_masks); - void add_special_eval_flag(ID *object, uint32_t flag); - - void build_id(ID *id); - void build_layer_collections(ListBase *lb); - void build_view_layer(Scene *scene, ViewLayer *view_layer); - void build_collection(LayerCollection *from_layer_collection, - Object *object, - Collection *collection); - void build_object(Base *base, Object *object); - void build_object_flags(Base *base, Object *object); - void build_object_data(Object *object); - void build_object_data_camera(Object *object); - void build_object_data_geometry(Object *object); - void build_object_data_geometry_datablock(ID *obdata); - void build_object_data_light(Object *object); - void build_object_data_lightprobe(Object *object); - void build_object_data_speaker(Object *object); - void build_object_parent(Object *object); - void build_object_pointcache(Object *object); - void build_constraints(ID *id, - NodeType component_type, - const char *component_subdata, - ListBase *constraints, - RootPChanMap *root_map); - void build_animdata(ID *id); - void build_animdata_curves(ID *id); - void build_animdata_curves_targets(ID *id, - ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *curves); - void build_animdata_nlastrip_targets(ID *id, - ComponentKey &adt_key, - OperationNode *operation_from, - ListBase *strips); - void build_animdata_drivers(ID *id); - void build_animation_images(ID *id); - void build_action(bAction *action); - 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_driver_id_property(ID *id, const char *rna_path); - void build_parameters(ID *id); - void build_world(World *world); - void build_rigidbody(Scene *scene); - void build_particle_systems(Object *object); - void build_particle_settings(ParticleSettings *part); - void build_particle_system_visualization_object(Object *object, - ParticleSystem *psys, - Object *draw_object); - void build_ik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map); - void build_splineik_pose(Object *object, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map); - void build_rig(Object *object); - void build_proxy_rig(Object *object); - void build_shapekeys(Key *key); - void build_armature(bArmature *armature); - void build_camera(Camera *camera); - void build_light(Light *lamp); - void build_nodetree(bNodeTree *ntree); - void build_material(Material *ma); - void build_texture(Tex *tex); - void build_image(Image *image); - void build_compositor(Scene *scene); - void build_gpencil(bGPdata *gpd); - void build_cachefile(CacheFile *cache_file); - void build_mask(Mask *mask); - void build_movieclip(MovieClip *clip); - void build_lightprobe(LightProbe *probe); - void build_speaker(Speaker *speaker); - - void build_nested_datablock(ID *owner, ID *id); - void build_nested_nodetree(ID *owner, bNodeTree *ntree); - void build_nested_shapekey(ID *owner, Key *key); - - void add_particle_collision_relations(const OperationKey &key, - Object *object, - Collection *collection, - const char *name); - void add_particle_forcefield_relations(const OperationKey &key, - Object *object, - ParticleSystem *psys, - EffectorWeights *eff, - bool add_absorption, const char *name); - - void build_copy_on_write_relations(); - void build_copy_on_write_relations(IDNode *id_node); - - template <typename KeyType> - OperationNode *find_operation_node(const KeyType &key); - - Depsgraph *getGraph(); - -protected: - TimeSourceNode *get_node(const TimeSourceKey &key) const; - ComponentNode *get_node(const ComponentKey &key) const; - OperationNode *get_node(const OperationKey &key) const; - Node *get_node(const RNAPathKey &key); - - OperationNode *find_node(const OperationKey &key) const; - bool has_node(const OperationKey &key) const; - - Relation *add_time_relation(TimeSourceNode *timesrc, - Node *node_to, - const char *description, - int flags = 0); - Relation *add_operation_relation(OperationNode *node_from, - OperationNode *node_to, - const char *description, - int flags = 0); - - template <typename KeyType> - DepsNodeHandle create_node_handle(const KeyType& key, - const char *default_name = ""); - - /* TODO(sergey): All those is_same* functions are to be generalized. */ - - /* Check whether two keys corresponds to the same bone from same armature. - * - * This is used by drivers relations builder to avoid possible fake - * dependency cycle when one bone property drives another property of the - * same bone. */ - template <typename KeyFrom, typename KeyTo> - bool is_same_bone_dependency(const KeyFrom& key_from, const KeyTo& key_to); - - /* Similar to above, but used to check whether driver is using node from - * the same node tree as a driver variable. */ - template <typename KeyFrom, typename KeyTo> - bool is_same_nodetree_node_dependency(const KeyFrom& key_from, - const KeyTo& key_to); - -private: - struct BuilderWalkUserData { - DepsgraphRelationBuilder *builder; - }; - - static void modifier_walk(void *user_data, - struct Object *object, - struct ID **idpoin, - int cb_flag); - - static void constraint_walk(bConstraint *con, - ID **idpoin, - bool is_reference, - void *user_data); - - /* State which demotes currently built entities. */ - Scene *scene_; - - BuilderMap built_map_; - RNANodeQuery rna_node_query_; +class DepsgraphRelationBuilder : public DepsgraphBuilder { + public: + DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph); + + void begin_build(); + + template<typename KeyFrom, typename KeyTo> + Relation *add_relation(const KeyFrom &key_from, + const KeyTo &key_to, + const char *description, + int flags = 0); + + template<typename KeyTo> + Relation *add_relation(const TimeSourceKey &key_from, + const KeyTo &key_to, + const char *description, + int flags = 0); + + template<typename KeyType> + Relation *add_node_handle_relation(const KeyType &key_from, + const DepsNodeHandle *handle, + const char *description, + int flags = 0); + + template<typename KeyTo> + Relation *add_depends_on_transform_relation(ID *id, + const KeyTo &key_to, + const char *description, + int flags = 0); + + /* Adds relation from proper transformation opertation to the modifier. + * Takes care of checking for possible physics solvers modifying position + * of this object. */ + void add_modifier_to_transform_relation(const DepsNodeHandle *handle, const char *description); + + void add_customdata_mask(Object *object, const DEGCustomDataMeshMasks &customdata_masks); + void add_special_eval_flag(ID *object, uint32_t flag); + + void build_id(ID *id); + void build_layer_collections(ListBase *lb); + void build_view_layer(Scene *scene, ViewLayer *view_layer); + void build_collection(LayerCollection *from_layer_collection, + Object *object, + Collection *collection); + void build_object(Base *base, Object *object); + void build_object_flags(Base *base, Object *object); + void build_object_data(Object *object); + void build_object_data_camera(Object *object); + void build_object_data_geometry(Object *object); + void build_object_data_geometry_datablock(ID *obdata); + void build_object_data_light(Object *object); + void build_object_data_lightprobe(Object *object); + void build_object_data_speaker(Object *object); + void build_object_parent(Object *object); + void build_object_pointcache(Object *object); + void build_constraints(ID *id, + NodeType component_type, + const char *component_subdata, + ListBase *constraints, + RootPChanMap *root_map); + void build_animdata(ID *id); + void build_animdata_curves(ID *id); + void build_animdata_curves_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *curves); + void build_animdata_nlastrip_targets(ID *id, + ComponentKey &adt_key, + OperationNode *operation_from, + ListBase *strips); + void build_animdata_drivers(ID *id); + void build_animation_images(ID *id); + void build_action(bAction *action); + 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_driver_id_property(ID *id, const char *rna_path); + void build_parameters(ID *id); + void build_world(World *world); + void build_rigidbody(Scene *scene); + void build_particle_systems(Object *object); + void build_particle_settings(ParticleSettings *part); + void build_particle_system_visualization_object(Object *object, + ParticleSystem *psys, + Object *draw_object); + void build_ik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); + void build_splineik_pose(Object *object, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map); + void build_rig(Object *object); + void build_proxy_rig(Object *object); + void build_shapekeys(Key *key); + void build_armature(bArmature *armature); + void build_camera(Camera *camera); + void build_light(Light *lamp); + void build_nodetree(bNodeTree *ntree); + void build_material(Material *ma); + void build_texture(Tex *tex); + void build_image(Image *image); + void build_compositor(Scene *scene); + void build_gpencil(bGPdata *gpd); + void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); + void build_lightprobe(LightProbe *probe); + void build_speaker(Speaker *speaker); + + void build_nested_datablock(ID *owner, ID *id); + void build_nested_nodetree(ID *owner, bNodeTree *ntree); + void build_nested_shapekey(ID *owner, Key *key); + + void add_particle_collision_relations(const OperationKey &key, + Object *object, + Collection *collection, + const char *name); + void add_particle_forcefield_relations(const OperationKey &key, + Object *object, + ParticleSystem *psys, + EffectorWeights *eff, + bool add_absorption, + const char *name); + + void build_copy_on_write_relations(); + void build_copy_on_write_relations(IDNode *id_node); + + template<typename KeyType> OperationNode *find_operation_node(const KeyType &key); + + Depsgraph *getGraph(); + + protected: + TimeSourceNode *get_node(const TimeSourceKey &key) const; + ComponentNode *get_node(const ComponentKey &key) const; + OperationNode *get_node(const OperationKey &key) const; + Node *get_node(const RNAPathKey &key); + + OperationNode *find_node(const OperationKey &key) const; + bool has_node(const OperationKey &key) const; + + Relation *add_time_relation(TimeSourceNode *timesrc, + Node *node_to, + const char *description, + int flags = 0); + Relation *add_operation_relation(OperationNode *node_from, + OperationNode *node_to, + const char *description, + int flags = 0); + + template<typename KeyType> + DepsNodeHandle create_node_handle(const KeyType &key, const char *default_name = ""); + + /* TODO(sergey): All those is_same* functions are to be generalized. */ + + /* Check whether two keys corresponds to the same bone from same armature. + * + * This is used by drivers relations builder to avoid possible fake + * dependency cycle when one bone property drives another property of the + * same bone. */ + template<typename KeyFrom, typename KeyTo> + bool is_same_bone_dependency(const KeyFrom &key_from, const KeyTo &key_to); + + /* Similar to above, but used to check whether driver is using node from + * the same node tree as a driver variable. */ + template<typename KeyFrom, typename KeyTo> + bool is_same_nodetree_node_dependency(const KeyFrom &key_from, const KeyTo &key_to); + + private: + struct BuilderWalkUserData { + DepsgraphRelationBuilder *builder; + }; + + static void modifier_walk(void *user_data, + struct Object *object, + struct ID **idpoin, + int cb_flag); + + static void constraint_walk(bConstraint *con, ID **idpoin, bool is_reference, void *user_data); + + /* State which demotes currently built entities. */ + Scene *scene_; + + BuilderMap built_map_; + RNANodeQuery rna_node_query_; }; -struct DepsNodeHandle -{ - DepsNodeHandle(DepsgraphRelationBuilder *builder, - OperationNode *node, - const char *default_name = "") - : builder(builder), - node(node), - default_name(default_name) - { - BLI_assert(node != NULL); - } - - DepsgraphRelationBuilder *builder; - OperationNode *node; - const char *default_name; +struct DepsNodeHandle { + DepsNodeHandle(DepsgraphRelationBuilder *builder, + OperationNode *node, + const char *default_name = "") + : builder(builder), node(node), default_name(default_name) + { + BLI_assert(node != NULL); + } + + DepsgraphRelationBuilder *builder; + OperationNode *node; + const char *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 index 86a17ae4a47..4412fa3fca3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_impl.h @@ -32,187 +32,189 @@ extern "C" { namespace DEG { -template <typename KeyType> -OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) +template<typename KeyType> +OperationNode *DepsgraphRelationBuilder::find_operation_node(const KeyType &key) { - Node *node = get_node(key); - return node != NULL ? node->get_exit_operation() : NULL; + Node *node = get_node(key); + return node != NULL ? node->get_exit_operation() : NULL; } -template <typename KeyFrom, typename KeyTo> +template<typename KeyFrom, typename KeyTo> Relation *DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, const KeyTo &key_to, const char *description, int flags) { - Node *node_from = get_node(key_from); - Node *node_to = get_node(key_to); - OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; - OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; - if (op_from && op_to) { - return add_operation_relation(op_from, op_to, description, flags); - } - 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()); - } - } - return NULL; + Node *node_from = get_node(key_from); + Node *node_to = get_node(key_to); + OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; + OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; + if (op_from && op_to) { + return add_operation_relation(op_from, op_to, description, flags); + } + 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()); + } + } + return NULL; } -template <typename KeyTo> -Relation *DepsgraphRelationBuilder::add_relation( - const TimeSourceKey &key_from, - const KeyTo &key_to, - const char *description, - int flags) +template<typename KeyTo> +Relation *DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from, + const KeyTo &key_to, + const char *description, + int flags) { - TimeSourceNode *time_from = get_node(key_from); - Node *node_to = get_node(key_to); - OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; - if (time_from != NULL && op_to != NULL) { - return add_time_relation( - time_from, op_to, description, flags); - } - return NULL; + TimeSourceNode *time_from = get_node(key_from); + Node *node_to = get_node(key_to); + OperationNode *op_to = node_to ? node_to->get_entry_operation() : NULL; + if (time_from != NULL && op_to != NULL) { + return add_time_relation(time_from, op_to, description, flags); + } + return NULL; } -template <typename KeyType> -Relation *DepsgraphRelationBuilder::add_node_handle_relation( - const KeyType &key_from, - const DepsNodeHandle *handle, - const char *description, - int flags) +template<typename KeyType> +Relation *DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from, + const DepsNodeHandle *handle, + const char *description, + int flags) { - Node *node_from = get_node(key_from); - OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; - OperationNode *op_to = handle->node->get_entry_operation(); - if (op_from != NULL && op_to != NULL) { - return add_operation_relation(op_from, op_to, description, flags); - } - 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()); - } - } - return NULL; + Node *node_from = get_node(key_from); + OperationNode *op_from = node_from ? node_from->get_exit_operation() : NULL; + OperationNode *op_to = handle->node->get_entry_operation(); + if (op_from != NULL && op_to != NULL) { + return add_operation_relation(op_from, op_to, description, flags); + } + 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()); + } + } + return NULL; } -template <typename KeyTo> -Relation *DepsgraphRelationBuilder::add_depends_on_transform_relation( - ID *id, - const KeyTo& key_to, - const char *description, - int flags) +template<typename KeyTo> +Relation *DepsgraphRelationBuilder::add_depends_on_transform_relation(ID *id, + const KeyTo &key_to, + const char *description, + int flags) { - if (GS(id->name) == ID_OB) { - Object *object = reinterpret_cast<Object *>(id); - if (object->rigidbody_object != NULL) { - OperationKey transform_key(&object->id, - NodeType::TRANSFORM, - OperationCode::TRANSFORM_EVAL); - return add_relation(transform_key, key_to, description, flags); - } - } - ComponentKey transform_key(id, NodeType::TRANSFORM); - return add_relation(transform_key, key_to, description, flags); + if (GS(id->name) == ID_OB) { + Object *object = reinterpret_cast<Object *>(id); + if (object->rigidbody_object != NULL) { + OperationKey transform_key(&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_EVAL); + return add_relation(transform_key, key_to, description, flags); + } + } + ComponentKey transform_key(id, NodeType::TRANSFORM); + return add_relation(transform_key, key_to, description, flags); } -template <typename KeyType> -DepsNodeHandle DepsgraphRelationBuilder::create_node_handle( - const KeyType &key, - const char *default_name) +template<typename KeyType> +DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key, + const char *default_name) { - return DepsNodeHandle(this, get_node(key), 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) +template<typename KeyFrom, typename KeyTo> +bool DepsgraphRelationBuilder::is_same_bone_dependency(const KeyFrom &key_from, + const KeyTo &key_to) { - /* Get operations for requested keys. */ - Node *node_from = get_node(key_from); - Node *node_to = get_node(key_to); - if (node_from == NULL || node_to == NULL) { - return false; - } - OperationNode *op_from = node_from->get_exit_operation(); - OperationNode *op_to = node_to->get_entry_operation(); - if (op_from == NULL || op_to == NULL) { - return false; - } - /* Different armatures, bone can't be the same. */ - if (op_from->owner->owner != op_to->owner->owner) { - return false; - } - /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ - if (!(op_from->opcode == OperationCode::BONE_DONE && - op_to->opcode == OperationCode::BONE_LOCAL)) - { - return false; - } - /* ... BUT, we also need to check if it's same bone. */ - if (op_from->owner->name != op_to->owner->name) { - return false; - } - return true; + /* Get operations for requested keys. */ + Node *node_from = get_node(key_from); + Node *node_to = get_node(key_to); + if (node_from == NULL || node_to == NULL) { + return false; + } + OperationNode *op_from = node_from->get_exit_operation(); + OperationNode *op_to = node_to->get_entry_operation(); + if (op_from == NULL || op_to == NULL) { + return false; + } + /* Different armatures, bone can't be the same. */ + if (op_from->owner->owner != op_to->owner->owner) { + return false; + } + /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ + if (!(op_from->opcode == OperationCode::BONE_DONE && + op_to->opcode == OperationCode::BONE_LOCAL)) { + return false; + } + /* ... BUT, we also need to check if it's same bone. */ + if (op_from->owner->name != op_to->owner->name) { + return false; + } + return true; } -template <typename KeyFrom, typename KeyTo> -bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency( - const KeyFrom& key_from, - const KeyTo& key_to) +template<typename KeyFrom, typename KeyTo> +bool DepsgraphRelationBuilder::is_same_nodetree_node_dependency(const KeyFrom &key_from, + const KeyTo &key_to) { - /* Get operations for requested keys. */ - Node *node_from = get_node(key_from); - Node *node_to = get_node(key_to); - if (node_from == NULL || node_to == NULL) { - return false; - } - OperationNode *op_from = node_from->get_exit_operation(); - OperationNode *op_to = node_to->get_entry_operation(); - if (op_from == NULL || op_to == NULL) { - return false; - } - /* Check if this is actually a node tree. */ - if (GS(op_from->owner->owner->id_orig->name) != ID_NT) { - return false; - } - /* Different node trees. */ - if (op_from->owner->owner != op_to->owner->owner) { - return false; - } - /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ - if (!(op_from->opcode == OperationCode::PARAMETERS_EVAL && - op_to->opcode == OperationCode::PARAMETERS_EVAL)) - { - return false; - } - return true; + /* Get operations for requested keys. */ + Node *node_from = get_node(key_from); + Node *node_to = get_node(key_to); + if (node_from == NULL || node_to == NULL) { + return false; + } + OperationNode *op_from = node_from->get_exit_operation(); + OperationNode *op_to = node_to->get_entry_operation(); + if (op_from == NULL || op_to == NULL) { + return false; + } + /* Check if this is actually a node tree. */ + if (GS(op_from->owner->owner->id_orig->name) != ID_NT) { + return false; + } + /* Different node trees. */ + if (op_from->owner->owner != op_to->owner->owner) { + return false; + } + /* We are only interested in relations like BONE_DONE -> BONE_LOCAL... */ + if (!(op_from->opcode == OperationCode::PARAMETERS_EVAL && + op_to->opcode == OperationCode::PARAMETERS_EVAL)) { + return false; + } + return true; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index 22ff10d3b70..35af968d46e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -30,100 +30,85 @@ namespace DEG { //////////////////////////////////////////////////////////////////////////////// // Time source. -TimeSourceKey::TimeSourceKey() - : id(NULL) +TimeSourceKey::TimeSourceKey() : id(NULL) { } -TimeSourceKey::TimeSourceKey(ID *id) - : id(id) +TimeSourceKey::TimeSourceKey(ID *id) : id(id) { } string TimeSourceKey::identifier() const { - return string("TimeSourceKey"); + return string("TimeSourceKey"); } //////////////////////////////////////////////////////////////////////////////// // Component. -ComponentKey::ComponentKey() - : id(NULL), - type(NodeType::UNDEFINED), - name("") +ComponentKey::ComponentKey() : id(NULL), type(NodeType::UNDEFINED), name("") { } ComponentKey::ComponentKey(ID *id, NodeType type, const char *name) - : id(id), - type(type), - name(name) + : id(id), type(type), name(name) { } string ComponentKey::identifier() const { - const char *idname = (id) ? id->name : "<None>"; - string result = string("ComponentKey("); - result += idname; - result += ", " + string(nodeTypeAsString(type)); - if (name[0] != '\0') { - result += ", '" + string(name) + "'"; - } - result += ')'; - return result; + const char *idname = (id) ? id->name : "<None>"; + string result = string("ComponentKey("); + result += idname; + result += ", " + string(nodeTypeAsString(type)); + if (name[0] != '\0') { + result += ", '" + string(name) + "'"; + } + result += ')'; + return result; } //////////////////////////////////////////////////////////////////////////////// // Operation. OperationKey::OperationKey() - : id(NULL), - component_type(NodeType::UNDEFINED), - component_name(""), - opcode(OperationCode::OPERATION), - name(""), - name_tag(-1) + : id(NULL), + component_type(NodeType::UNDEFINED), + component_name(""), + opcode(OperationCode::OPERATION), + name(""), + name_tag(-1) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(""), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) +OperationKey::OperationKey(ID *id, NodeType component_type, const char *name, int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - const char *component_name, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) +OperationKey::OperationKey( + ID *id, NodeType component_type, const char *component_name, const char *name, int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - OperationCode opcode) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(""), - name_tag(-1) +OperationKey::OperationKey(ID *id, NodeType component_type, OperationCode opcode) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(""), + name_tag(-1) { } @@ -131,26 +116,23 @@ OperationKey::OperationKey(ID *id, NodeType component_type, const char *component_name, OperationCode opcode) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(""), - name_tag(-1) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(""), + name_tag(-1) { } -OperationKey::OperationKey(ID *id, - NodeType component_type, - OperationCode opcode, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(name), - name_tag(name_tag) +OperationKey::OperationKey( + ID *id, NodeType component_type, OperationCode opcode, const char *name, int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(name), + name_tag(name_tag) { } @@ -160,63 +142,54 @@ OperationKey::OperationKey(ID *id, OperationCode opcode, const char *name, int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(name), - name_tag(name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(name), + name_tag(name_tag) { } string OperationKey::identifier() const { - string result = string("OperationKey("); - result += "type: " + string(nodeTypeAsString(component_type)); - result += ", component name: '" + string(component_name) + "'"; - result += ", operation code: " + string(operationCodeAsString(opcode)); - if (name[0] != '\0') { - result += ", '" + string(name) + "'"; - } - result += ")"; - return result; + string result = string("OperationKey("); + result += "type: " + string(nodeTypeAsString(component_type)); + result += ", component name: '" + string(component_name) + "'"; + result += ", operation code: " + string(operationCodeAsString(opcode)); + if (name[0] != '\0') { + result += ", '" + string(name) + "'"; + } + result += ")"; + return result; } //////////////////////////////////////////////////////////////////////////////// // RNA path. -RNAPathKey::RNAPathKey(ID *id, const char *path, RNAPointerSource source) - : id(id), - source(source) +RNAPathKey::RNAPathKey(ID *id, const char *path, RNAPointerSource source) : id(id), source(source) { - /* Create ID pointer for root of path lookup. */ - PointerRNA id_ptr; - RNA_id_pointer_create(id, &id_ptr); - /* Try to resolve path. */ - int index; - if (!RNA_path_resolve_full(&id_ptr, path, &ptr, &prop, &index)) { - ptr = PointerRNA_NULL; - prop = NULL; - } + /* Create ID pointer for root of path lookup. */ + PointerRNA id_ptr; + RNA_id_pointer_create(id, &id_ptr); + /* Try to resolve path. */ + int index; + if (!RNA_path_resolve_full(&id_ptr, path, &ptr, &prop, &index)) { + ptr = PointerRNA_NULL; + prop = NULL; + } } -RNAPathKey::RNAPathKey(ID *id, - const PointerRNA &ptr, - PropertyRNA *prop, - RNAPointerSource source) - : id(id), - ptr(ptr), - prop(prop), - source(source) +RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source) + : id(id), ptr(ptr), prop(prop), source(source) { } string RNAPathKey::identifier() const { - const char *id_name = (id) ? id->name : "<No ID>"; - const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>"; - return string("RnaPathKey(") + "id: " + id_name + - ", prop: '" + prop_name + "')"; + const char *id_name = (id) ? id->name : "<No ID>"; + const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>"; + return string("RnaPathKey(") + "id: " + id_name + ", prop: '" + prop_name + "')"; } } // 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 9d36e9495e3..1d222258449 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -27,7 +27,7 @@ #include <stdio.h> #include <stdlib.h> -#include <cstring> /* required for STREQ later on. */ +#include <cstring> /* required for STREQ later on. */ #include "MEM_guardedalloc.h" @@ -67,166 +67,139 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *object, bConstraint *con, RootPChanMap *root_map) { - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - /* Attach owner to IK Solver to. */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - if (rootchan == NULL) { - return; - } - OperationKey pchan_local_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - OperationKey init_ik_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); - OperationKey solver_key(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_IK_SOLVER); - OperationKey pose_cleanup_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); - add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree"); - add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); - /* Never cleanup before solver is run. */ - add_relation(solver_key, - pose_cleanup_key, - "IK Solver -> Cleanup", - RELATION_FLAG_GODMODE); - /* IK target */ - /* TODO(sergey): This should get handled as part of the constraint code. */ - if (data->tar != NULL) { - /* TODO(sergey): For until we'll store partial matrices 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 matrices. This is an overkill, but good - * enough for testing IK solver. */ - ComponentKey pose_key(&object->id, NodeType::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 != object) { - /* Different armature - can just read the results. */ - ComponentKey target_key( - &data->tar->id, NodeType::BONE, data->subtarget); - add_relation(target_key, pose_key, 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, - NodeType::BONE, - data->subtarget, - OperationCode::BONE_DONE); - add_relation(target_key, solver_key, con->name); - } - } - else if (data->subtarget[0] && - ELEM(data->tar->type, OB_MESH, OB_LATTICE)) - { - /* Vertex group target. */ - /* NOTE: for now, we don't need to represent vertex groups - * separately. */ - ComponentKey target_key(&data->tar->id, NodeType::GEOMETRY); - add_relation(target_key, solver_key, con->name); - add_customdata_mask(data->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); - } - else { - /* Standard Object Target. */ - ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM); - add_relation(target_key, pose_key, con->name); - } - if (data->tar == object && 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. */ - /* TODO(sergey): This should get handled as part of the constraint code. */ - if (data->poletar != NULL) { - if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { - ComponentKey target_key(&data->poletar->id, - NodeType::BONE, - data->polesubtarget); - add_relation(target_key, solver_key, con->name); - } - else if (data->polesubtarget[0] && - ELEM(data->poletar->type, OB_MESH, OB_LATTICE)) - { - /* Vertex group target. */ - /* NOTE: for now, we don't need to represent vertex groups - * separately. */ - ComponentKey target_key(&data->poletar->id, NodeType::GEOMETRY); - add_relation(target_key, solver_key, con->name); - add_customdata_mask(data->poletar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); - } - else { - ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM); - add_relation(target_key, solver_key, con->name); - } - } - DEG_DEBUG_PRINTF( - (::Depsgraph *)graph_, - BUILD, - "\nStarting IK Build: pchan = %s, target = (%s, %s), " - "segcount = %d\n", - pchan->name, data->tar ? data->tar->id.name : "NULL", - data->subtarget, data->rootbone); - bPoseChannel *parchan = pchan; - /* Exclude tip from chain if needed. */ - if (!(data->flag & CONSTRAINT_IK_TIP)) { - parchan = pchan->parent; - } - root_map->add_bone(parchan->name, rootchan->name); - OperationKey parchan_transforms_key(&object->id, NodeType::BONE, - parchan->name, OperationCode::BONE_READY); - add_relation(parchan_transforms_key, solver_key, "IK Solver Owner"); - /* Walk to the chain's root. */ - int segcount = 0; - while (parchan != NULL) { - /* 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(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_READY); - add_relation(parent_key, solver_key, "IK Chain Parent"); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_DONE); - add_relation(solver_key, bone_done_key, "IK Chain Result"); - } - else { - OperationKey final_transforms_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_DONE); - add_relation(solver_key, final_transforms_key, "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((::Depsgraph *)graph_, - BUILD, - " %d = %s\n", - segcount, parchan->name); - /* TODO(sergey): This is an arbitrary value, which was just following - * old code convention. */ - segcount++; - if ((segcount == data->rootbone) || (segcount > 255)) { - break; - } - parchan = parchan->parent; - } - OperationKey pose_done_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); - add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + /* Attach owner to IK Solver to. */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + if (rootchan == NULL) { + return; + } + OperationKey pchan_local_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + OperationKey init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); + OperationKey solver_key( + &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_IK_SOLVER); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + add_relation(pchan_local_key, init_ik_key, "IK Constraint -> Init IK Tree"); + add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); + /* Never cleanup before solver is run. */ + add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup", RELATION_FLAG_GODMODE); + /* IK target */ + /* TODO(sergey): This should get handled as part of the constraint code. */ + if (data->tar != NULL) { + /* TODO(sergey): For until we'll store partial matrices 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 matrices. This is an overkill, but good + * enough for testing IK solver. */ + ComponentKey pose_key(&object->id, NodeType::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 != object) { + /* Different armature - can just read the results. */ + ComponentKey target_key(&data->tar->id, NodeType::BONE, data->subtarget); + add_relation(target_key, pose_key, 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, NodeType::BONE, data->subtarget, OperationCode::BONE_DONE); + add_relation(target_key, solver_key, con->name); + } + } + else if (data->subtarget[0] && ELEM(data->tar->type, OB_MESH, OB_LATTICE)) { + /* Vertex group target. */ + /* NOTE: for now, we don't need to represent vertex groups + * separately. */ + ComponentKey target_key(&data->tar->id, NodeType::GEOMETRY); + add_relation(target_key, solver_key, con->name); + add_customdata_mask(data->tar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); + } + else { + /* Standard Object Target. */ + ComponentKey target_key(&data->tar->id, NodeType::TRANSFORM); + add_relation(target_key, pose_key, con->name); + } + if (data->tar == object && 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. */ + /* TODO(sergey): This should get handled as part of the constraint code. */ + if (data->poletar != NULL) { + if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { + ComponentKey target_key(&data->poletar->id, NodeType::BONE, data->polesubtarget); + add_relation(target_key, solver_key, con->name); + } + else if (data->polesubtarget[0] && ELEM(data->poletar->type, OB_MESH, OB_LATTICE)) { + /* Vertex group target. */ + /* NOTE: for now, we don't need to represent vertex groups + * separately. */ + ComponentKey target_key(&data->poletar->id, NodeType::GEOMETRY); + add_relation(target_key, solver_key, con->name); + add_customdata_mask(data->poletar, DEGCustomDataMeshMasks::MaskVert(CD_MASK_MDEFORMVERT)); + } + else { + ComponentKey target_key(&data->poletar->id, NodeType::TRANSFORM); + add_relation(target_key, solver_key, con->name); + } + } + DEG_DEBUG_PRINTF((::Depsgraph *)graph_, + BUILD, + "\nStarting IK Build: pchan = %s, target = (%s, %s), " + "segcount = %d\n", + pchan->name, + data->tar ? data->tar->id.name : "NULL", + data->subtarget, + data->rootbone); + bPoseChannel *parchan = pchan; + /* Exclude tip from chain if needed. */ + if (!(data->flag & CONSTRAINT_IK_TIP)) { + parchan = pchan->parent; + } + root_map->add_bone(parchan->name, rootchan->name); + OperationKey parchan_transforms_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY); + add_relation(parchan_transforms_key, solver_key, "IK Solver Owner"); + /* Walk to the chain's root. */ + int segcount = 0; + while (parchan != NULL) { + /* 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( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY); + add_relation(parent_key, solver_key, "IK Chain Parent"); + OperationKey bone_done_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, bone_done_key, "IK Chain Result"); + } + else { + OperationKey final_transforms_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, final_transforms_key, "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((::Depsgraph *)graph_, BUILD, " %d = %s\n", segcount, parchan->name); + /* TODO(sergey): This is an arbitrary value, which was just following + * old code convention. */ + segcount++; + if ((segcount == data->rootbone) || (segcount > 255)) { + break; + } + parchan = parchan->parent; + } + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); } /* Spline IK Eval Steps */ @@ -235,375 +208,270 @@ void DepsgraphRelationBuilder::build_splineik_pose(Object *object, bConstraint *con, RootPChanMap *root_map) { - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - OperationKey transforms_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - OperationKey init_ik_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT_IK); - OperationKey solver_key(&object->id, - NodeType::EVAL_POSE, - rootchan->name, - OperationCode::POSE_SPLINE_IK_SOLVER); - OperationKey pose_cleanup_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); - /* Solver depends on initialization. */ - add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); - /* Never cleanup before solver is run. */ - add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup"); - /* Attach owner to IK Solver. */ - add_relation(transforms_key, - solver_key, - "Spline IK Solver Owner", - RELATION_FLAG_GODMODE); - /* Attach path dependency to solver. */ - if (data->tar != NULL) { - ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY); - add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK"); - ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM); - add_relation(target_transform_key, solver_key, "Curve.Transform -> Spline IK"); - add_special_eval_flag(&data->tar->id, DAG_EVAL_NEED_CURVE_PATH); - } - pchan->flag |= POSE_DONE; - OperationKey final_transforms_key( - &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); - add_relation(solver_key, final_transforms_key, "Spline IK Result"); - root_map->add_bone(pchan->name, rootchan->name); - /* Walk to the chain's root/ */ - int segcount = 1; - for (bPoseChannel *parchan = pchan->parent; - parchan != NULL && segcount < data->chainlen; - parchan = parchan->parent, segcount++) - { - /* 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. */ - OperationKey parent_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_READY); - add_relation(parent_key, solver_key, "Spline IK Solver Update"); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - parchan->name, - OperationCode::BONE_DONE); - add_relation(solver_key, bone_done_key, "Spline IK Solver Result"); - parchan->flag |= POSE_DONE; - root_map->add_bone(parchan->name, rootchan->name); - } - OperationKey pose_done_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); - add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + OperationKey transforms_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + OperationKey init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); + OperationKey solver_key( + &object->id, NodeType::EVAL_POSE, rootchan->name, OperationCode::POSE_SPLINE_IK_SOLVER); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + /* Solver depends on initialization. */ + add_relation(init_ik_key, solver_key, "Init IK -> IK Solver"); + /* Never cleanup before solver is run. */ + add_relation(solver_key, pose_cleanup_key, "IK Solver -> Cleanup"); + /* Attach owner to IK Solver. */ + add_relation(transforms_key, solver_key, "Spline IK Solver Owner", RELATION_FLAG_GODMODE); + /* Attach path dependency to solver. */ + if (data->tar != NULL) { + ComponentKey target_geometry_key(&data->tar->id, NodeType::GEOMETRY); + add_relation(target_geometry_key, solver_key, "Curve.Path -> Spline IK"); + ComponentKey target_transform_key(&data->tar->id, NodeType::TRANSFORM); + add_relation(target_transform_key, solver_key, "Curve.Transform -> Spline IK"); + add_special_eval_flag(&data->tar->id, DAG_EVAL_NEED_CURVE_PATH); + } + pchan->flag |= POSE_DONE; + OperationKey final_transforms_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, final_transforms_key, "Spline IK Result"); + root_map->add_bone(pchan->name, rootchan->name); + /* Walk to the chain's root/ */ + int segcount = 1; + for (bPoseChannel *parchan = pchan->parent; parchan != NULL && segcount < data->chainlen; + parchan = parchan->parent, segcount++) { + /* 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. */ + OperationKey parent_key(&object->id, NodeType::BONE, parchan->name, OperationCode::BONE_READY); + add_relation(parent_key, solver_key, "Spline IK Solver Update"); + OperationKey bone_done_key( + &object->id, NodeType::BONE, parchan->name, OperationCode::BONE_DONE); + add_relation(solver_key, bone_done_key, "Spline IK Solver Result"); + parchan->flag |= POSE_DONE; + root_map->add_bone(parchan->name, rootchan->name); + } + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + add_relation(solver_key, pose_done_key, "PoseEval Result-Bone Link"); } /* Pose/Armature Bones Graph */ void DepsgraphRelationBuilder::build_rig(Object *object) { - /* Armature-Data */ - bArmature *armature = (bArmature *)object->data; - // TODO: selection status? - /* Attach links between pose operations. */ - ComponentKey local_transform(&object->id, NodeType::TRANSFORM); - OperationKey pose_init_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); - OperationKey pose_init_ik_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); - OperationKey pose_cleanup_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); - OperationKey pose_done_key( - &object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); - add_relation( - local_transform, pose_init_key, "Local Transform -> Pose Init"); - add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK"); - add_relation( - pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup"); - /* Make sure pose is up-to-date with armature updates. */ - build_armature(armature); - OperationKey armature_key(&armature->id, - NodeType::PARAMETERS, - OperationCode::ARMATURE_EVAL); - add_relation(armature_key, pose_init_key, "Data dependency"); - /* Run cleanup even when there are no bones. */ - add_relation(pose_init_key, pose_cleanup_key, "Init -> Cleanup"); - /* 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 operations - * 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; - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(object, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(object, 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(&object->id, NodeType::EVAL_POSE); - ComponentKey local_transform_key(&object->id, NodeType::TRANSFORM); - add_relation(local_transform_key, pose_key, "Local Transforms"); - } - /* Links between operations for each bone. */ - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - OperationKey bone_local_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_LOCAL); - OperationKey bone_pose_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_POSE_PARENT); - OperationKey bone_ready_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE); - pchan->flag &= ~POSE_DONE; - /* Pose init to bone local. */ - add_relation(pose_init_key, - bone_local_key, - "Pose Init - Bone Local", - RELATION_FLAG_GODMODE); - /* Local to pose parenting operation. */ - add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose"); - /* Parent relation. */ - if (pchan->parent != NULL) { - OperationCode 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 = OperationCode::BONE_READY; - } - else { - parent_key_opcode = OperationCode::BONE_DONE; - } + /* Armature-Data */ + bArmature *armature = (bArmature *)object->data; + // TODO: selection status? + /* Attach links between pose operations. */ + ComponentKey local_transform(&object->id, NodeType::TRANSFORM); + OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); + OperationKey pose_init_ik_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT_IK); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + add_relation(local_transform, pose_init_key, "Local Transform -> Pose Init"); + add_relation(pose_init_key, pose_init_ik_key, "Pose Init -> Pose Init IK"); + add_relation(pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup"); + /* Make sure pose is up-to-date with armature updates. */ + build_armature(armature); + OperationKey armature_key(&armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL); + add_relation(armature_key, pose_init_key, "Data dependency"); + /* Run cleanup even when there are no bones. */ + add_relation(pose_init_key, pose_cleanup_key, "Init -> Cleanup"); + /* 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 operations + * 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; + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(object, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(object, 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(&object->id, NodeType::EVAL_POSE); + ComponentKey local_transform_key(&object->id, NodeType::TRANSFORM); + add_relation(local_transform_key, pose_key, "Local Transforms"); + } + /* Links between operations for each bone. */ + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + OperationKey bone_local_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + OperationKey bone_pose_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_POSE_PARENT); + OperationKey bone_ready_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + pchan->flag &= ~POSE_DONE; + /* Pose init to bone local. */ + add_relation(pose_init_key, bone_local_key, "Pose Init - Bone Local", RELATION_FLAG_GODMODE); + /* Local to pose parenting operation. */ + add_relation(bone_local_key, bone_pose_key, "Bone Local - Bone Pose"); + /* Parent relation. */ + if (pchan->parent != NULL) { + OperationCode 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 = OperationCode::BONE_READY; + } + else { + parent_key_opcode = OperationCode::BONE_DONE; + } - OperationKey parent_key(&object->id, - NodeType::BONE, - pchan->parent->name, - parent_key_opcode); - add_relation( - parent_key, bone_pose_key, "Parent Bone -> Child Bone"); - } - /* Build constraints. */ - if (pchan->constraints.first != NULL) { - /* Build relations for indirectly linked objects. */ - BuilderWalkUserData data; - data.builder = this; - BKE_constraints_id_loop( - &pchan->constraints, constraint_walk, &data); - /* Constraints stack and constraint dependencies. */ - build_constraints(&object->id, - NodeType::BONE, - pchan->name, - &pchan->constraints, - &root_map); - /* Pose -> constraints. */ - OperationKey constraints_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_CONSTRAINTS); - add_relation(bone_pose_key, constraints_key, "Pose -> Constraints Stack"); - add_relation(bone_local_key, constraints_key, "Local -> Constraints Stack"); - /* Constraints -> ready/ */ - /* TODO(sergey): When constraint stack is exploded, this step should - * occur before the first IK solver. */ - add_relation( - constraints_key, bone_ready_key, "Constraints -> Ready"); - } - else { - /* Pose -> Ready */ - add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready"); - } - /* Bone ready -> Bone 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, "Ready -> Done"); - /* B-Bone shape is the real final step after Done if present. */ - if (pchan->bone != NULL && pchan->bone->segments > 1) { - OperationKey bone_segments_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_SEGMENTS); - /* B-Bone shape depends on the final position of the bone. */ - add_relation(bone_done_key, - bone_segments_key, - "Done -> B-Bone Segments"); - /* B-Bone shape depends on final position of handle bones. */ - bPoseChannel *prev, *next; - BKE_pchan_bbone_handles_get(pchan, &prev, &next); - if (prev) { - OperationKey prev_key(&object->id, - NodeType::BONE, - prev->name, - OperationCode::BONE_DONE); - add_relation(prev_key, - bone_segments_key, - "Prev Handle -> B-Bone Segments"); - } - if (next) { - OperationKey next_key(&object->id, - NodeType::BONE, - next->name, - OperationCode::BONE_DONE); - add_relation(next_key, - bone_segments_key, - "Next Handle -> B-Bone Segments"); - } - /* Pose requires the B-Bone shape. */ - add_relation(bone_segments_key, - pose_done_key, - "PoseEval Result-Bone Link", - RELATION_FLAG_GODMODE); - add_relation(bone_segments_key, - pose_cleanup_key, - "Cleanup dependency"); - } - else { - /* Assume that all bones must be done for the pose to be ready - * (for deformers). */ - add_relation(bone_done_key, - pose_done_key, - "PoseEval Result-Bone Link"); + OperationKey parent_key(&object->id, NodeType::BONE, pchan->parent->name, parent_key_opcode); + add_relation(parent_key, bone_pose_key, "Parent Bone -> Child Bone"); + } + /* Build constraints. */ + if (pchan->constraints.first != NULL) { + /* Build relations for indirectly linked objects. */ + BuilderWalkUserData data; + data.builder = this; + BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); + /* Constraints stack and constraint dependencies. */ + build_constraints(&object->id, NodeType::BONE, pchan->name, &pchan->constraints, &root_map); + /* Pose -> constraints. */ + OperationKey constraints_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_CONSTRAINTS); + add_relation(bone_pose_key, constraints_key, "Pose -> Constraints Stack"); + add_relation(bone_local_key, constraints_key, "Local -> Constraints Stack"); + /* Constraints -> ready/ */ + /* TODO(sergey): When constraint stack is exploded, this step should + * occur before the first IK solver. */ + add_relation(constraints_key, bone_ready_key, "Constraints -> Ready"); + } + else { + /* Pose -> Ready */ + add_relation(bone_pose_key, bone_ready_key, "Pose -> Ready"); + } + /* Bone ready -> Bone 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, "Ready -> Done"); + /* B-Bone shape is the real final step after Done if present. */ + if (pchan->bone != NULL && pchan->bone->segments > 1) { + OperationKey bone_segments_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS); + /* B-Bone shape depends on the final position of the bone. */ + add_relation(bone_done_key, bone_segments_key, "Done -> B-Bone Segments"); + /* B-Bone shape depends on final position of handle bones. */ + bPoseChannel *prev, *next; + BKE_pchan_bbone_handles_get(pchan, &prev, &next); + if (prev) { + OperationKey prev_key(&object->id, NodeType::BONE, prev->name, OperationCode::BONE_DONE); + add_relation(prev_key, bone_segments_key, "Prev Handle -> B-Bone Segments"); + } + if (next) { + OperationKey next_key(&object->id, NodeType::BONE, next->name, OperationCode::BONE_DONE); + add_relation(next_key, bone_segments_key, "Next Handle -> B-Bone Segments"); + } + /* Pose requires the B-Bone shape. */ + add_relation( + bone_segments_key, pose_done_key, "PoseEval Result-Bone Link", RELATION_FLAG_GODMODE); + add_relation(bone_segments_key, pose_cleanup_key, "Cleanup dependency"); + } + else { + /* Assume that all bones must be done for the pose to be ready + * (for deformers). */ + add_relation(bone_done_key, pose_done_key, "PoseEval Result-Bone Link"); - /* Bones must be traversed before cleanup. */ - add_relation(bone_done_key, - pose_cleanup_key, - "Done -> Cleanup"); + /* Bones must be traversed before cleanup. */ + add_relation(bone_done_key, pose_cleanup_key, "Done -> Cleanup"); - add_relation(bone_ready_key, - pose_cleanup_key, - "Ready -> Cleanup"); - } - /* Custom shape. */ - if (pchan->custom != NULL) { - build_object(NULL, pchan->custom); - } - } + add_relation(bone_ready_key, pose_cleanup_key, "Ready -> Cleanup"); + } + /* Custom shape. */ + if (pchan->custom != NULL) { + build_object(NULL, pchan->custom); + } + } } void DepsgraphRelationBuilder::build_proxy_rig(Object *object) { - bArmature *armature = (bArmature *)object->data; - Object *proxy_from = object->proxy_from; - build_armature(armature); - OperationKey pose_init_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_INIT); - OperationKey pose_done_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_DONE); - OperationKey pose_cleanup_key(&object->id, - NodeType::EVAL_POSE, - OperationCode::POSE_CLEANUP); - LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - OperationKey bone_local_key(&object->id, - NodeType::BONE, pchan->name, - OperationCode::BONE_LOCAL); - OperationKey bone_ready_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_READY); - OperationKey bone_done_key(&object->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE); - OperationKey from_bone_done_key(&proxy_from->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_DONE); - add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local"); - add_relation(bone_local_key, bone_ready_key, "Local -> Ready"); - add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); - add_relation( - bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup"); - add_relation(bone_done_key, - pose_done_key, - "Bone Done -> Pose Done", - RELATION_FLAG_GODMODE); - /* Make sure bone in the proxy is not done before it's FROM is done. */ - if (pchan->bone && pchan->bone->segments > 1) { - OperationKey from_bone_segments_key(&proxy_from->id, - NodeType::BONE, - pchan->name, - OperationCode::BONE_SEGMENTS); - add_relation(from_bone_segments_key, - bone_done_key, - "Bone Segments -> Bone Done", - RELATION_FLAG_GODMODE); - } - else { - add_relation(from_bone_done_key, - bone_done_key, - "Bone Done -> Bone Done"); - } + bArmature *armature = (bArmature *)object->data; + Object *proxy_from = object->proxy_from; + build_armature(armature); + OperationKey pose_init_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_INIT); + OperationKey pose_done_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_DONE); + OperationKey pose_cleanup_key(&object->id, NodeType::EVAL_POSE, OperationCode::POSE_CLEANUP); + LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { + OperationKey bone_local_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_LOCAL); + OperationKey bone_ready_key( + &object->id, NodeType::BONE, pchan->name, OperationCode::BONE_READY); + OperationKey bone_done_key(&object->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + OperationKey from_bone_done_key( + &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_DONE); + add_relation(pose_init_key, bone_local_key, "Pose Init -> Bone Local"); + add_relation(bone_local_key, bone_ready_key, "Local -> Ready"); + add_relation(bone_ready_key, bone_done_key, "Ready -> Done"); + add_relation(bone_done_key, pose_cleanup_key, "Bone Done -> Pose Cleanup"); + add_relation(bone_done_key, pose_done_key, "Bone Done -> Pose Done", RELATION_FLAG_GODMODE); + /* Make sure bone in the proxy is not done before it's FROM is done. */ + if (pchan->bone && pchan->bone->segments > 1) { + OperationKey from_bone_segments_key( + &proxy_from->id, NodeType::BONE, pchan->name, OperationCode::BONE_SEGMENTS); + add_relation(from_bone_segments_key, + bone_done_key, + "Bone Segments -> Bone Done", + RELATION_FLAG_GODMODE); + } + else { + add_relation(from_bone_done_key, bone_done_key, "Bone Done -> Bone Done"); + } - /* Parent relation: even though the proxy bone itself doesn't need - * the parent bone, some users expect the parent to be ready if the - * bone itself is (e.g. for computing the local space matrix). - */ - if (pchan->parent != NULL) { - OperationKey parent_key(&object->id, - NodeType::BONE, - pchan->parent->name, - OperationCode::BONE_DONE); - add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone"); - } + /* Parent relation: even though the proxy bone itself doesn't need + * the parent bone, some users expect the parent to be ready if the + * bone itself is (e.g. for computing the local space matrix). + */ + if (pchan->parent != NULL) { + OperationKey parent_key( + &object->id, NodeType::BONE, pchan->parent->name, OperationCode::BONE_DONE); + add_relation(parent_key, bone_done_key, "Parent Bone -> Child Bone"); + } - if (pchan->prop != NULL) { - OperationKey bone_parameters(&object->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - pchan->name); - OperationKey from_bone_parameters(&proxy_from->id, - NodeType::PARAMETERS, - OperationCode::PARAMETERS_EVAL, - pchan->name); - add_relation(from_bone_parameters, - bone_parameters, - "Proxy Bone Parameters"); - } - } + if (pchan->prop != NULL) { + OperationKey bone_parameters( + &object->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name); + OperationKey from_bone_parameters( + &proxy_from->id, NodeType::PARAMETERS, OperationCode::PARAMETERS_EVAL, pchan->name); + add_relation(from_bone_parameters, bone_parameters, "Proxy Bone Parameters"); + } + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc index 622bb4a8a02..a325544e046 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_view_layer.cc @@ -27,7 +27,7 @@ #include <stdio.h> #include <stdlib.h> -#include <cstring> /* required for STREQ later on. */ +#include <cstring> /* required for STREQ later on. */ #include "MEM_guardedalloc.h" @@ -61,78 +61,78 @@ namespace DEG { void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb) { - const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? - COLLECTION_RESTRICT_VIEW : COLLECTION_RESTRICT_RENDER; - - for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { - if ((lc->collection->flag & restrict_flag)) { - continue; - } - if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { - build_collection(lc, NULL, lc->collection); - } - build_layer_collections(&lc->layer_collections); - } + const int restrict_flag = (graph_->mode == DAG_EVAL_VIEWPORT) ? COLLECTION_RESTRICT_VIEW : + COLLECTION_RESTRICT_RENDER; + + for (LayerCollection *lc = (LayerCollection *)lb->first; lc; lc = lc->next) { + if ((lc->collection->flag & restrict_flag)) { + continue; + } + if ((lc->flag & LAYER_COLLECTION_EXCLUDE) == 0) { + build_collection(lc, NULL, lc->collection); + } + build_layer_collections(&lc->layer_collections); + } } void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_layer) { - /* Setup currently building context. */ - scene_ = scene; - /* Scene objects. */ - /* NOTE: Nodes builder requires us to pass CoW base because it's being - * passed to the evaluation functions. During relations builder we only - * do NULL-pointer check of the base, so it's fine to pass original one. */ - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { - if (need_pull_base_into_graph(base)) { - build_object(base, base->object); - } - } - - build_layer_collections(&view_layer->layer_collections); - - if (scene->camera != NULL) { - build_object(NULL, scene->camera); - } - /* Rigidbody. */ - if (scene->rigidbody_world != NULL) { - build_rigidbody(scene); - } - /* Scene's animation and drivers. */ - if (scene->adt != NULL) { - build_animdata(&scene->id); - } - /* World. */ - if (scene->world != NULL) { - build_world(scene->world); - } - /* Compositor nodes. */ - if (scene->nodetree != NULL) { - build_compositor(scene); - } - /* Masks. */ - LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { - build_mask(mask); - } - /* Movie clips. */ - LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { - build_movieclip(clip); - } - /* Material override. */ - if (view_layer->mat_override != NULL) { - build_material(view_layer->mat_override); - } - /* Freestyle collections. */ - LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { - if (fls->group != NULL) { - build_collection(NULL, NULL, fls->group); - } - } - /* Build all set scenes. */ - if (scene->set != NULL) { - ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); - build_view_layer(scene->set, set_view_layer); - } + /* Setup currently building context. */ + scene_ = scene; + /* Scene objects. */ + /* NOTE: Nodes builder requires us to pass CoW base because it's being + * passed to the evaluation functions. During relations builder we only + * do NULL-pointer check of the base, so it's fine to pass original one. */ + LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + if (need_pull_base_into_graph(base)) { + build_object(base, base->object); + } + } + + build_layer_collections(&view_layer->layer_collections); + + if (scene->camera != NULL) { + build_object(NULL, scene->camera); + } + /* Rigidbody. */ + if (scene->rigidbody_world != NULL) { + build_rigidbody(scene); + } + /* Scene's animation and drivers. */ + if (scene->adt != NULL) { + build_animdata(&scene->id); + } + /* World. */ + if (scene->world != NULL) { + build_world(scene->world); + } + /* Compositor nodes. */ + if (scene->nodetree != NULL) { + build_compositor(scene); + } + /* Masks. */ + LISTBASE_FOREACH (Mask *, mask, &bmain_->masks) { + build_mask(mask); + } + /* Movie clips. */ + LISTBASE_FOREACH (MovieClip *, clip, &bmain_->movieclips) { + build_movieclip(clip); + } + /* Material override. */ + if (view_layer->mat_override != NULL) { + build_material(view_layer->mat_override); + } + /* Freestyle collections. */ + LISTBASE_FOREACH (FreestyleLineSet *, fls, &view_layer->freestyle_config.linesets) { + if (fls->group != NULL) { + build_collection(NULL, NULL, fls->group); + } + } + /* Build all set scenes. */ + if (scene->set != NULL) { + ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set); + build_view_layer(scene->set, set_view_layer); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index c8c6cc75418..810d3ee3f66 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -55,74 +55,67 @@ namespace DEG { /* ********************************* ID Data ******************************** */ class RNANodeQueryIDData { -public: - explicit RNANodeQueryIDData(const ID *id) - : id_(id), - contraint_to_pchan_map_(NULL) { - } + public: + explicit RNANodeQueryIDData(const ID *id) : id_(id), contraint_to_pchan_map_(NULL) + { + } - ~RNANodeQueryIDData() { - if (contraint_to_pchan_map_ != NULL) { - BLI_ghash_free(contraint_to_pchan_map_, NULL, NULL); - } - } + ~RNANodeQueryIDData() + { + if (contraint_to_pchan_map_ != NULL) { + BLI_ghash_free(contraint_to_pchan_map_, NULL, NULL); + } + } - const bPoseChannel *get_pchan_for_constraint(const bConstraint *constraint) - { - ensure_constraint_to_pchan_map(); - return static_cast<bPoseChannel *>( - BLI_ghash_lookup(contraint_to_pchan_map_, constraint)); - } + const bPoseChannel *get_pchan_for_constraint(const bConstraint *constraint) + { + ensure_constraint_to_pchan_map(); + return static_cast<bPoseChannel *>(BLI_ghash_lookup(contraint_to_pchan_map_, constraint)); + } - void ensure_constraint_to_pchan_map() - { - if (contraint_to_pchan_map_ != NULL) { - return; - } - BLI_assert(GS(id_->name) == ID_OB); - const Object *object = reinterpret_cast<const Object *>(id_); - contraint_to_pchan_map_ = - BLI_ghash_ptr_new("id data pchan constraint map"); - if (object->pose != NULL) { - LISTBASE_FOREACH ( - const bPoseChannel *, pchan, &object->pose->chanbase) - { - LISTBASE_FOREACH ( - const bConstraint *, constraint, &pchan->constraints) - { - BLI_ghash_insert(contraint_to_pchan_map_, - const_cast<bConstraint *>(constraint), - const_cast<bPoseChannel *>(pchan)); - } - } - } - } + void ensure_constraint_to_pchan_map() + { + if (contraint_to_pchan_map_ != NULL) { + return; + } + BLI_assert(GS(id_->name) == ID_OB); + const Object *object = reinterpret_cast<const Object *>(id_); + contraint_to_pchan_map_ = BLI_ghash_ptr_new("id data pchan constraint map"); + if (object->pose != NULL) { + LISTBASE_FOREACH (const bPoseChannel *, pchan, &object->pose->chanbase) { + LISTBASE_FOREACH (const bConstraint *, constraint, &pchan->constraints) { + BLI_ghash_insert(contraint_to_pchan_map_, + const_cast<bConstraint *>(constraint), + const_cast<bPoseChannel *>(pchan)); + } + } + } + } -protected: - /* ID this data corresponds to. */ - const ID *id_; + protected: + /* ID this data corresponds to. */ + const ID *id_; - /* indexed by bConstraint*, returns pose channel which contains that - * constraint. */ - GHash *contraint_to_pchan_map_; + /* indexed by bConstraint*, returns pose channel which contains that + * constraint. */ + GHash *contraint_to_pchan_map_; }; /* ***************************** Node Identifier **************************** */ RNANodeIdentifier::RNANodeIdentifier() - : id(NULL), - type(NodeType::UNDEFINED), - component_name(""), - operation_code(OperationCode::OPERATION), - operation_name(), - operation_name_tag(-1) + : id(NULL), + type(NodeType::UNDEFINED), + component_name(""), + operation_code(OperationCode::OPERATION), + operation_name(), + operation_name_tag(-1) { } bool RNANodeIdentifier::is_valid() const { - return id != NULL && - type != NodeType::UNDEFINED; + return id != NULL && type != NodeType::UNDEFINED; } /* ********************************** Query ********************************* */ @@ -131,264 +124,244 @@ namespace { void ghash_id_data_free_func(void *value) { - RNANodeQueryIDData *id_data = static_cast<RNANodeQueryIDData *>(value); - OBJECT_GUARDED_DELETE(id_data, RNANodeQueryIDData); + RNANodeQueryIDData *id_data = static_cast<RNANodeQueryIDData *>(value); + OBJECT_GUARDED_DELETE(id_data, RNANodeQueryIDData); } } // namespace RNANodeQuery::RNANodeQuery(Depsgraph *depsgraph) - : depsgraph_(depsgraph), - id_data_map_(BLI_ghash_ptr_new("rna node query id data hash")) + : depsgraph_(depsgraph), id_data_map_(BLI_ghash_ptr_new("rna node query id data hash")) { } RNANodeQuery::~RNANodeQuery() { - BLI_ghash_free(id_data_map_, NULL, ghash_id_data_free_func); + BLI_ghash_free(id_data_map_, NULL, ghash_id_data_free_func); } Node *RNANodeQuery::find_node(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source) { - const RNANodeIdentifier node_identifier = construct_node_identifier( - ptr, prop, source); - if (!node_identifier.is_valid()) { - return NULL; - } - IDNode *id_node = depsgraph_->find_id_node(node_identifier.id); - if (id_node == NULL) { - return NULL; - } - ComponentNode *comp_node = id_node->find_component( - node_identifier.type, node_identifier.component_name); - if (comp_node == NULL) { - return NULL; - } - if (node_identifier.operation_code == OperationCode::OPERATION) { - return comp_node; - } - return comp_node->find_operation(node_identifier.operation_code, - node_identifier.operation_name, - node_identifier.operation_name_tag); + const RNANodeIdentifier node_identifier = construct_node_identifier(ptr, prop, source); + if (!node_identifier.is_valid()) { + return NULL; + } + IDNode *id_node = depsgraph_->find_id_node(node_identifier.id); + if (id_node == NULL) { + return NULL; + } + ComponentNode *comp_node = id_node->find_component(node_identifier.type, + node_identifier.component_name); + if (comp_node == NULL) { + return NULL; + } + if (node_identifier.operation_code == OperationCode::OPERATION) { + return comp_node; + } + return comp_node->find_operation(node_identifier.operation_code, + node_identifier.operation_name, + node_identifier.operation_name_tag); } -RNANodeIdentifier RNANodeQuery::construct_node_identifier( - const PointerRNA *ptr, - const PropertyRNA *prop, - RNAPointerSource source) +RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, + const PropertyRNA *prop, + RNAPointerSource source) { - RNANodeIdentifier node_identifier; - if (ptr->type == NULL) { - return node_identifier; - } - /* Set default values for returns. */ - node_identifier.id = static_cast<ID *>(ptr->id.data); - node_identifier.component_name = ""; - node_identifier.operation_code = OperationCode::OPERATION; - node_identifier.operation_name = ""; - node_identifier.operation_name_tag = -1; - /* Handling of commonly known scenarios. */ - if (ptr->type == &RNA_PoseBone) { - const bPoseChannel *pchan = - static_cast<const bPoseChannel *>(ptr->data); - if (prop != NULL && RNA_property_is_idprop(prop)) { - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::ID_PROPERTY; - node_identifier.operation_name = - RNA_property_identifier( - reinterpret_cast<const PropertyRNA *>(prop)); - node_identifier.operation_name_tag = -1; - } - else { - /* Bone - generally, we just want the bone component. */ - node_identifier.type = NodeType::BONE; - node_identifier.component_name = pchan->name; - /* But B-Bone properties should connect to the actual operation. */ - if (!ELEM(NULL, pchan->bone, prop) && pchan->bone->segments > 1 && - STRPREFIX(RNA_property_identifier(prop), "bbone_")) - { - node_identifier.operation_code = OperationCode::BONE_SEGMENTS; - } - } - return node_identifier; - } - else if (ptr->type == &RNA_Bone) { - const Bone *bone = static_cast<const Bone *>(ptr->data); - /* Armature-level bone, but it ends up going to bone component - * anyway. */ - // NOTE: the ID in this case will end up being bArmature. - node_identifier.type = NodeType::BONE; - node_identifier.component_name = bone->name; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { - const Object *object = static_cast<const Object *>(ptr->id.data); - const bConstraint *constraint = - static_cast<const bConstraint *>(ptr->data); - RNANodeQueryIDData *id_data = ensure_id_data(&object->id); - /* Check whether is object or bone constraint. */ - /* NOTE: Currently none of the area can address transform of an object - * at a given constraint, but for rigging one might use constraint - * influence to be used to drive some corrective shape keys or so. */ - const bPoseChannel *pchan = - id_data->get_pchan_for_constraint(constraint); - if (pchan == NULL) { - node_identifier.type = NodeType::TRANSFORM; - node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; - } - else { - node_identifier.type = NodeType::BONE; - node_identifier.operation_code = OperationCode::BONE_LOCAL; - node_identifier.component_name = pchan->name; - } - return node_identifier; - } - else if (ELEM(ptr->type, &RNA_ConstraintTarget, &RNA_ConstraintTargetBone)) { - Object *object = (Object *)ptr->id.data; - bConstraintTarget *tgt = (bConstraintTarget *)ptr->data; - /* Check whether is object or bone constraint. */ - bPoseChannel *pchan = NULL; - bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan); - if (con != NULL) { - if (pchan != NULL) { - node_identifier.type = NodeType::BONE; - node_identifier.operation_code = OperationCode::BONE_LOCAL; - node_identifier.component_name = pchan->name; - } - else { - node_identifier.type = NodeType::TRANSFORM; - node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; - } - return node_identifier; - } - } - else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) { - /* When modifier is used as FROM operation this is likely referencing to - * the property (for example, modifier's influence). - * But when it's used as TO operation, this is geometry component. */ - switch (source) { - case RNAPointerSource::ENTRY: - node_identifier.type = NodeType::GEOMETRY; - break; - case RNAPointerSource::EXIT: - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; - break; - } - return node_identifier; - } - else if (ptr->type == &RNA_Object) { - /* Transforms props? */ - if (prop != NULL) { - const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); - /* TODO(sergey): How to optimize this? */ - if (strstr(prop_identifier, "location") || - strstr(prop_identifier, "rotation") || - strstr(prop_identifier, "scale") || - strstr(prop_identifier, "matrix_")) - { - node_identifier.type = NodeType::TRANSFORM; - return node_identifier; - } - else if (strstr(prop_identifier, "data")) { - /* We access object.data, most likely a geometry. - * Might be a bone tho. */ - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (STREQ(prop_identifier, "hide_viewport") || - STREQ(prop_identifier, "hide_render")) - { - node_identifier.type = NodeType::OBJECT_FROM_LAYER; - return node_identifier; - } - } - } - else if (ptr->type == &RNA_ShapeKey) { - KeyBlock *key_block = static_cast<KeyBlock *>(ptr->data); - node_identifier.id = static_cast<ID *>(ptr->id.data); - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; - node_identifier.operation_name = key_block->name; - return node_identifier; - } - else if (ptr->type == &RNA_Key) { - node_identifier.id = static_cast<ID *>(ptr->id.data); - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { - const Sequence *seq = static_cast<Sequence *>(ptr->data); - /* Sequencer strip */ - node_identifier.type = NodeType::SEQUENCER; - node_identifier.component_name = seq->name; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { - node_identifier.type = NodeType::SHADING; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { - node_identifier.type = NodeType::SHADING; - return node_identifier; - } - else if (ELEM(ptr->type, &RNA_Curve, &RNA_TextCurve)) { - node_identifier.id = (ID *)ptr->id.data; - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (ELEM(ptr->type, &RNA_BezierSplinePoint, &RNA_SplinePoint)) { - node_identifier.id = (ID *)ptr->id.data; - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - else if (RNA_struct_is_a(ptr->type, &RNA_ImageUser)) { - if (GS(node_identifier.id->name) == ID_NT) { - node_identifier.type = NodeType::ANIMATION; - node_identifier.operation_code = OperationCode::IMAGE_ANIMATION; - return node_identifier; - } - } - else if (ELEM(ptr->type, &RNA_MeshVertex, - &RNA_MeshEdge, - &RNA_MeshLoop, - &RNA_MeshPolygon)) - { - node_identifier.type = NodeType::GEOMETRY; - return node_identifier; - } - if (prop != NULL) { - /* All unknown data effectively falls under "parameter evaluation". */ - if (RNA_property_is_idprop(prop)) { - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::ID_PROPERTY; - node_identifier.operation_name = - RNA_property_identifier((PropertyRNA *)prop); - node_identifier.operation_name_tag = -1; - } - else { - node_identifier.type = NodeType::PARAMETERS; - node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; - node_identifier.operation_name = ""; - node_identifier.operation_name_tag = -1; - } - return node_identifier; - } - return node_identifier; + RNANodeIdentifier node_identifier; + if (ptr->type == NULL) { + return node_identifier; + } + /* Set default values for returns. */ + node_identifier.id = static_cast<ID *>(ptr->id.data); + node_identifier.component_name = ""; + node_identifier.operation_code = OperationCode::OPERATION; + node_identifier.operation_name = ""; + node_identifier.operation_name_tag = -1; + /* Handling of commonly known scenarios. */ + if (ptr->type == &RNA_PoseBone) { + const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr->data); + if (prop != NULL && RNA_property_is_idprop(prop)) { + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::ID_PROPERTY; + node_identifier.operation_name = RNA_property_identifier( + reinterpret_cast<const PropertyRNA *>(prop)); + node_identifier.operation_name_tag = -1; + } + else { + /* Bone - generally, we just want the bone component. */ + node_identifier.type = NodeType::BONE; + node_identifier.component_name = pchan->name; + /* But B-Bone properties should connect to the actual operation. */ + if (!ELEM(NULL, pchan->bone, prop) && pchan->bone->segments > 1 && + STRPREFIX(RNA_property_identifier(prop), "bbone_")) { + node_identifier.operation_code = OperationCode::BONE_SEGMENTS; + } + } + return node_identifier; + } + else if (ptr->type == &RNA_Bone) { + const Bone *bone = static_cast<const Bone *>(ptr->data); + /* Armature-level bone, but it ends up going to bone component + * anyway. */ + // NOTE: the ID in this case will end up being bArmature. + node_identifier.type = NodeType::BONE; + node_identifier.component_name = bone->name; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) { + const Object *object = static_cast<const Object *>(ptr->id.data); + const bConstraint *constraint = static_cast<const bConstraint *>(ptr->data); + RNANodeQueryIDData *id_data = ensure_id_data(&object->id); + /* Check whether is object or bone constraint. */ + /* NOTE: Currently none of the area can address transform of an object + * at a given constraint, but for rigging one might use constraint + * influence to be used to drive some corrective shape keys or so. */ + const bPoseChannel *pchan = id_data->get_pchan_for_constraint(constraint); + if (pchan == NULL) { + node_identifier.type = NodeType::TRANSFORM; + node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; + } + else { + node_identifier.type = NodeType::BONE; + node_identifier.operation_code = OperationCode::BONE_LOCAL; + node_identifier.component_name = pchan->name; + } + return node_identifier; + } + else if (ELEM(ptr->type, &RNA_ConstraintTarget, &RNA_ConstraintTargetBone)) { + Object *object = (Object *)ptr->id.data; + bConstraintTarget *tgt = (bConstraintTarget *)ptr->data; + /* Check whether is object or bone constraint. */ + bPoseChannel *pchan = NULL; + bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan); + if (con != NULL) { + if (pchan != NULL) { + node_identifier.type = NodeType::BONE; + node_identifier.operation_code = OperationCode::BONE_LOCAL; + node_identifier.component_name = pchan->name; + } + else { + node_identifier.type = NodeType::TRANSFORM; + node_identifier.operation_code = OperationCode::TRANSFORM_LOCAL; + } + return node_identifier; + } + } + else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) { + /* When modifier is used as FROM operation this is likely referencing to + * the property (for example, modifier's influence). + * But when it's used as TO operation, this is geometry component. */ + switch (source) { + case RNAPointerSource::ENTRY: + node_identifier.type = NodeType::GEOMETRY; + break; + case RNAPointerSource::EXIT: + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; + break; + } + return node_identifier; + } + else if (ptr->type == &RNA_Object) { + /* Transforms props? */ + if (prop != NULL) { + const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); + /* TODO(sergey): How to optimize this? */ + if (strstr(prop_identifier, "location") || strstr(prop_identifier, "rotation") || + strstr(prop_identifier, "scale") || strstr(prop_identifier, "matrix_")) { + node_identifier.type = NodeType::TRANSFORM; + return node_identifier; + } + else if (strstr(prop_identifier, "data")) { + /* We access object.data, most likely a geometry. + * Might be a bone tho. */ + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (STREQ(prop_identifier, "hide_viewport") || STREQ(prop_identifier, "hide_render")) { + node_identifier.type = NodeType::OBJECT_FROM_LAYER; + return node_identifier; + } + } + } + else if (ptr->type == &RNA_ShapeKey) { + KeyBlock *key_block = static_cast<KeyBlock *>(ptr->data); + node_identifier.id = static_cast<ID *>(ptr->id.data); + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; + node_identifier.operation_name = key_block->name; + return node_identifier; + } + else if (ptr->type == &RNA_Key) { + node_identifier.id = static_cast<ID *>(ptr->id.data); + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { + const Sequence *seq = static_cast<Sequence *>(ptr->data); + /* Sequencer strip */ + node_identifier.type = NodeType::SEQUENCER; + node_identifier.component_name = seq->name; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { + node_identifier.type = NodeType::SHADING; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { + node_identifier.type = NodeType::SHADING; + return node_identifier; + } + else if (ELEM(ptr->type, &RNA_Curve, &RNA_TextCurve)) { + node_identifier.id = (ID *)ptr->id.data; + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (ELEM(ptr->type, &RNA_BezierSplinePoint, &RNA_SplinePoint)) { + node_identifier.id = (ID *)ptr->id.data; + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + else if (RNA_struct_is_a(ptr->type, &RNA_ImageUser)) { + if (GS(node_identifier.id->name) == ID_NT) { + node_identifier.type = NodeType::ANIMATION; + node_identifier.operation_code = OperationCode::IMAGE_ANIMATION; + return node_identifier; + } + } + else if (ELEM(ptr->type, &RNA_MeshVertex, &RNA_MeshEdge, &RNA_MeshLoop, &RNA_MeshPolygon)) { + node_identifier.type = NodeType::GEOMETRY; + return node_identifier; + } + if (prop != NULL) { + /* All unknown data effectively falls under "parameter evaluation". */ + if (RNA_property_is_idprop(prop)) { + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::ID_PROPERTY; + node_identifier.operation_name = RNA_property_identifier((PropertyRNA *)prop); + node_identifier.operation_name_tag = -1; + } + else { + node_identifier.type = NodeType::PARAMETERS; + node_identifier.operation_code = OperationCode::PARAMETERS_EVAL; + node_identifier.operation_name = ""; + node_identifier.operation_name_tag = -1; + } + return node_identifier; + } + return node_identifier; } RNANodeQueryIDData *RNANodeQuery::ensure_id_data(const ID *id) { - RNANodeQueryIDData **id_data_ptr; - if (!BLI_ghash_ensure_p(id_data_map_, - const_cast<ID *>(id), - reinterpret_cast<void***>(&id_data_ptr))) - { - *id_data_ptr = OBJECT_GUARDED_NEW(RNANodeQueryIDData, id); - } - return *id_data_ptr; + RNANodeQueryIDData **id_data_ptr; + if (!BLI_ghash_ensure_p( + id_data_map_, const_cast<ID *>(id), reinterpret_cast<void ***>(&id_data_ptr))) { + *id_data_ptr = OBJECT_GUARDED_NEW(RNANodeQueryIDData, id); + } + return *id_data_ptr; } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.h b/source/blender/depsgraph/intern/builder/deg_builder_rna.h index 5e121476087..e8dbd7fb523 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.h @@ -41,58 +41,56 @@ class RNANodeQueryIDData; * interested in a result of the given property or whether we are linking some * dependency to that property. */ enum class RNAPointerSource { - /* Query will return pointer to an entry operation of component which is - * responsible for evaluation of the given property. */ - ENTRY, - /* Query will return pointer to an exit operation of component which is - * responsible for evaluation of the given property. - * More precisely, it will return operation at which the property is known - * to be evaluated. */ - EXIT, + /* Query will return pointer to an entry operation of component which is + * responsible for evaluation of the given property. */ + ENTRY, + /* Query will return pointer to an exit operation of component which is + * responsible for evaluation of the given property. + * More precisely, it will return operation at which the property is known + * to be evaluated. */ + EXIT, }; /* A helper structure which wraps all fields needed to find a node inside of * the dependency graph. */ class RNANodeIdentifier { -public: - RNANodeIdentifier(); - - /* Check whether this identifier is valid and usable. */ - bool is_valid() const; - - ID *id; - NodeType type; - const char *component_name; - OperationCode operation_code; - const char *operation_name; - int operation_name_tag; + public: + RNANodeIdentifier(); + + /* Check whether this identifier is valid and usable. */ + bool is_valid() const; + + ID *id; + NodeType type; + const char *component_name; + OperationCode operation_code; + const char *operation_name; + int operation_name_tag; }; /* Helper class which performs optimized lookups of a node within a given * dependency graph which satisfies given RNA pointer or RAN path. */ class RNANodeQuery { -public: - RNANodeQuery(Depsgraph *depsgraph); - ~RNANodeQuery(); + public: + RNANodeQuery(Depsgraph *depsgraph); + ~RNANodeQuery(); - Node *find_node(const PointerRNA *ptr, - const PropertyRNA *prop, - RNAPointerSource source); + Node *find_node(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source); -protected: - Depsgraph *depsgraph_; + protected: + Depsgraph *depsgraph_; - /* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */ - GHash *id_data_map_; + /* Indexed by an ID, returns RNANodeQueryIDData associated with that ID. */ + GHash *id_data_map_; - /* Construct identifier of the node which correspods given configuration - * of RNA property. */ - RNANodeIdentifier construct_node_identifier(const PointerRNA *ptr, - const PropertyRNA *prop, - RNAPointerSource source); + /* Construct identifier of the node which correspods given configuration + * of RNA property. */ + RNANodeIdentifier construct_node_identifier(const PointerRNA *ptr, + const PropertyRNA *prop, + RNAPointerSource source); - /* Make sure ID data exists for the given ID, and returns it. */ - RNANodeQueryIDData *ensure_id_data(const ID *id); + /* Make sure ID data exists for the given ID, and returns it. */ + RNANodeQueryIDData *ensure_id_data(const ID *id); }; } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 2aa716fc87c..3e5e96d30ff 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -50,63 +50,61 @@ namespace DEG { */ enum { - OP_VISITED = 1, - OP_REACHABLE = 2, + OP_VISITED = 1, + OP_REACHABLE = 2, }; static void deg_graph_tag_paths_recursive(Node *node) { - if (node->custom_flags & OP_VISITED) { - return; - } - node->custom_flags |= OP_VISITED; - for (Relation *rel : node->inlinks) { - deg_graph_tag_paths_recursive(rel->from); - /* Do this only in inlinks loop, so the target node does not get - * flagged. */ - rel->from->custom_flags |= OP_REACHABLE; - } + if (node->custom_flags & OP_VISITED) { + return; + } + node->custom_flags |= OP_VISITED; + for (Relation *rel : node->inlinks) { + deg_graph_tag_paths_recursive(rel->from); + /* Do this only in inlinks loop, so the target node does not get + * flagged. */ + rel->from->custom_flags |= OP_REACHABLE; + } } void deg_graph_transitive_reduction(Depsgraph *graph) { - int num_removed_relations = 0; - for (OperationNode *target : graph->operations) { - /* Clear tags. */ - for (OperationNode *node : graph->operations) { - node->custom_flags = 0; - } - /* Mark nodes from which we can reach the target - * start with children, so the target node and direct children are not - * flagged. */ - target->custom_flags |= OP_VISITED; - for (Relation *rel : target->inlinks) { - deg_graph_tag_paths_recursive(rel->from); - } - /* Remove redundant paths to the target. */ - for (Node::Relations::const_iterator it_rel = target->inlinks.begin(); - it_rel != target->inlinks.end(); - ) - { - Relation *rel = *it_rel; - if (rel->from->type == NodeType::TIMESOURCE) { - /* HACK: time source nodes don't get "custom_flags" flag - * set/cleared. */ - /* TODO: there will be other types in future, so iterators above - * need modifying. */ - ++it_rel; - } - else if (rel->from->custom_flags & OP_REACHABLE) { - rel->unlink(); - OBJECT_GUARDED_DELETE(rel, Relation); - ++num_removed_relations; - } - else { - ++it_rel; - } - } - } - DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations); + int num_removed_relations = 0; + for (OperationNode *target : graph->operations) { + /* Clear tags. */ + for (OperationNode *node : graph->operations) { + node->custom_flags = 0; + } + /* Mark nodes from which we can reach the target + * start with children, so the target node and direct children are not + * flagged. */ + target->custom_flags |= OP_VISITED; + for (Relation *rel : target->inlinks) { + deg_graph_tag_paths_recursive(rel->from); + } + /* Remove redundant paths to the target. */ + for (Node::Relations::const_iterator it_rel = target->inlinks.begin(); + it_rel != target->inlinks.end();) { + Relation *rel = *it_rel; + if (rel->from->type == NodeType::TIMESOURCE) { + /* HACK: time source nodes don't get "custom_flags" flag + * set/cleared. */ + /* TODO: there will be other types in future, so iterators above + * need modifying. */ + ++it_rel; + } + else if (rel->from->custom_flags & OP_REACHABLE) { + rel->unlink(); + OBJECT_GUARDED_DELETE(rel, Relation); + ++num_removed_relations; + } + else { + ++it_rel; + } + } + } + DEG_DEBUG_PRINTF((::Depsgraph *)graph, BUILD, "Removed %d relations\n", num_removed_relations); } } // namespace DEG |