Cleanup: remove redundant doxygen \file argument
[blender.git] / source / blender / depsgraph / intern / depsgraph_query_foreach.cc
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2017 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file \ingroup depsgraph
21  *
22  * Implementation of Querying and Filtering API's
23  */
24
25 // TODO(sergey): Use some sort of wrapper.
26 #include <deque>
27
28 #include "MEM_guardedalloc.h"
29
30 extern "C" {
31 #include "BLI_utildefines.h"
32 #include "BLI_ghash.h"
33 } /* extern "C" */
34
35 #include "DNA_object_types.h"
36 #include "DNA_scene_types.h"
37
38 #include "DEG_depsgraph.h"
39 #include "DEG_depsgraph_query.h"
40
41 #include "intern/depsgraph.h"
42 #include "intern/node/deg_node.h"
43 #include "intern/node/deg_node_component.h"
44 #include "intern/node/deg_node_id.h"
45 #include "intern/node/deg_node_operation.h"
46
47 /* ************************ DEG TRAVERSAL ********************* */
48
49 namespace DEG {
50
51 typedef std::deque<OperationNode *> TraversalQueue;
52 enum {
53         DEG_NODE_VISITED = (1 << 0),
54 };
55
56 static void deg_foreach_clear_flags(const Depsgraph *graph)
57 {
58         for (OperationNode *op_node : graph->operations) {
59                 op_node->scheduled = false;
60         }
61         for (IDNode *id_node : graph->id_nodes) {
62                 id_node->custom_flags = 0;
63         }
64 }
65
66 static void deg_foreach_dependent_ID(const Depsgraph *graph,
67                                      const ID *id,
68                                      DEGForeachIDCallback callback,
69                                      void *user_data)
70 {
71         /* Start with getting ID node from the graph. */
72         IDNode *target_id_node = graph->find_id_node(id);
73         if (target_id_node == NULL) {
74                 /* TODO(sergey): Shall we inform or assert here about attempt to start
75                  * iterating over non-existing ID? */
76                 return;
77         }
78         /* Make sure all runtime flags are ready and clear. */
79         deg_foreach_clear_flags(graph);
80         /* Start with scheduling all operations from ID node. */
81         TraversalQueue queue;
82         GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, target_id_node->components)
83         {
84                 for (OperationNode *op_node : comp_node->operations) {
85                         queue.push_back(op_node);
86                         op_node->scheduled = true;
87                 }
88         }
89         GHASH_FOREACH_END();
90         target_id_node->custom_flags |= DEG_NODE_VISITED;
91         /* Process the queue. */
92         while (!queue.empty()) {
93                 /* get next operation node to process. */
94                 OperationNode *op_node = queue.front();
95                 queue.pop_front();
96                 for (;;) {
97                         /* Check whether we need to inform callee about corresponding ID node. */
98                         ComponentNode *comp_node = op_node->owner;
99                         IDNode *id_node = comp_node->owner;
100                         if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
101                                 /* TODO(sergey): Is it orig or CoW? */
102                                 callback(id_node->id_orig, user_data);
103                                 id_node->custom_flags |= DEG_NODE_VISITED;
104                         }
105                         /* Schedule outgoing operation nodes. */
106                         if (op_node->outlinks.size() == 1) {
107                                 OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
108                                 if (to_node->scheduled == false) {
109                                         to_node->scheduled = true;
110                                         op_node = to_node;
111                                 }
112                                 else {
113                                         break;
114                                 }
115                         }
116                         else {
117                                 for (Relation *rel : op_node->outlinks) {
118                                         OperationNode *to_node = (OperationNode *)rel->to;
119                                         if (to_node->scheduled == false) {
120                                                 queue.push_front(to_node);
121                                                 to_node->scheduled = true;
122                                         }
123                                 }
124                                 break;
125                         }
126                 }
127         }
128 }
129
130 static void deg_foreach_ancestor_ID(const Depsgraph *graph,
131                                      const ID *id,
132                                      DEGForeachIDCallback callback,
133                                      void *user_data)
134 {
135         /* Start with getting ID node from the graph. */
136         IDNode *target_id_node = graph->find_id_node(id);
137         if (target_id_node == NULL) {
138                 /* TODO(sergey): Shall we inform or assert here about attempt to start
139                  * iterating over non-existing ID? */
140                 return;
141         }
142         /* Make sure all runtime flags are ready and clear. */
143         deg_foreach_clear_flags(graph);
144         /* Start with scheduling all operations from ID node. */
145         TraversalQueue queue;
146         GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, target_id_node->components)
147         {
148                 for (OperationNode *op_node : comp_node->operations) {
149                         queue.push_back(op_node);
150                         op_node->scheduled = true;
151                 }
152         }
153         GHASH_FOREACH_END();
154         target_id_node->custom_flags |= DEG_NODE_VISITED;
155         /* Process the queue. */
156         while (!queue.empty()) {
157                 /* get next operation node to process. */
158                 OperationNode *op_node = queue.front();
159                 queue.pop_front();
160                 for (;;) {
161                         /* Check whether we need to inform callee about corresponding ID node. */
162                         ComponentNode *comp_node = op_node->owner;
163                         IDNode *id_node = comp_node->owner;
164                         if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
165                                 /* TODO(sergey): Is it orig or CoW? */
166                                 callback(id_node->id_orig, user_data);
167                                 id_node->custom_flags |= DEG_NODE_VISITED;
168                         }
169                         /* Schedule incoming operation nodes. */
170                         if (op_node->inlinks.size() == 1) {
171                                 Node *from = op_node->inlinks[0]->from;
172                                 if (from->get_class() == NodeClass::OPERATION) {
173                                         OperationNode *from_node = (OperationNode *)from;
174                                         if (from_node->scheduled == false) {
175                                                 from_node->scheduled = true;
176                                                 op_node = from_node;
177                                         }
178                                         else {
179                                                 break;
180                                         }
181                                 }
182                         }
183                         else {
184                                 for (Relation *rel : op_node->inlinks) {
185                                         Node *from = rel->from;
186                                         if (from->get_class() == NodeClass::OPERATION) {
187                                                 OperationNode *from_node = (OperationNode *)from;
188                                                 if (from_node->scheduled == false) {
189                                                         queue.push_front(from_node);
190                                                         from_node->scheduled = true;
191                                                 }
192                                         }
193                                 }
194                                 break;
195                         }
196                 }
197         }
198 }
199
200 static void deg_foreach_id(const Depsgraph *depsgraph,
201                            DEGForeachIDCallback callback, void *user_data)
202 {
203         for (const IDNode *id_node : depsgraph->id_nodes) {
204                 callback(id_node->id_orig, user_data);
205         }
206 }
207
208 }  // namespace DEG
209
210 void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
211                               const ID *id,
212                               DEGForeachIDCallback callback, void *user_data)
213 {
214         DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph,
215                                       id,
216                                       callback, user_data);
217 }
218
219 void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
220                              const ID *id,
221                              DEGForeachIDCallback callback, void *user_data)
222 {
223         DEG::deg_foreach_ancestor_ID((const DEG::Depsgraph *)depsgraph,
224                                      id,
225                                      callback, user_data);
226 }
227
228 void DEG_foreach_ID(const Depsgraph *depsgraph,
229                     DEGForeachIDCallback callback, void *user_data)
230 {
231         DEG::deg_foreach_id((const DEG::Depsgraph *)depsgraph, callback, user_data);
232 }