Blender V5.0
depsgraph_query_iter.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11/* Silence warnings from copying deprecated fields. */
12#define DNA_DEPRECATED_ALLOW
13
14#include "BKE_duplilist.hh"
15#include "BKE_idprop.hh"
16#include "BKE_layer.hh"
17#include "BKE_modifier.hh"
18#include "BKE_node.hh"
19#include "BKE_object.hh"
20#include "BKE_object_types.hh"
21
22#include "BLI_listbase.h"
23#include "BLI_math_matrix.h"
24#include "BLI_math_vector.h"
25#include "BLI_utildefines.h"
26
27#include "DNA_object_types.h"
28#include "DNA_scene_types.h"
29
30#include "DEG_depsgraph.hh"
32
33#include "intern/depsgraph.hh"
35
36#ifndef NDEBUG
38#endif
39
40/* If defined, all working data will be set to an invalid state, helping
41 * to catch issues when areas accessing data which is considered to be no
42 * longer available. */
43#undef INVALIDATE_WORK_DATA
44
45#ifndef NDEBUG
46# define INVALIDATE_WORK_DATA
47#endif
48
49namespace deg = blender::deg;
50
53
54/* ************************ DEG ITERATORS ********************* */
55
56namespace {
57
58void deg_invalidate_iterator_work_data(DEGObjectIterData *data)
59{
60#ifdef INVALIDATE_WORK_DATA
61 BLI_assert(data != nullptr);
62 memset((void *)&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
63#else
64 (void)data;
65#endif
66}
67
68bool deg_object_hide_original(eEvaluationMode eval_mode, const Object *ob, const DupliObject *dob)
69{
70 /* Automatic hiding if this object is being instanced on verts/faces/frames
71 * by its parent. Ideally this should not be needed, but due to the wrong
72 * dependency direction in the data design there is no way to keep the object
73 * visible otherwise. The better solution eventually would be for objects
74 * to specify which object they instance, instead of through parenting.
75 *
76 * This function should not be used for meta-balls. They have custom visibility rules, as hiding
77 * the base meta-ball will also hide all the other balls in the group. */
78 if (eval_mode == DAG_EVAL_RENDER || dob) {
79 const int hide_original_types = OB_DUPLIVERTS | OB_DUPLIFACES;
80
81 if (!dob || !(dob->type & hide_original_types)) {
82 if (ob->parent && (ob->parent->transflag & hide_original_types)) {
83 return true;
84 }
85 }
86 }
87
88 return false;
89}
90
91void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object)
92{
93 /* This should have been set to default values at `DEG_iterator_objects_begin`, or at the end of
94 * the previous `deg_iterator_duplis_step` cycle. */
95 BLI_assert(data->dupli_parent == nullptr);
96 BLI_assert(data->dupli_object_next == nullptr);
97 BLI_assert(data->dupli_object_next_index == -1);
98 if (data->dupli_list.is_empty()) {
99 return;
100 }
101 data->dupli_parent = object;
102 data->dupli_object_next = &data->dupli_list.first();
103 data->dupli_object_next_index = 0;
104}
105
106/* Returns false when iterator is exhausted. */
107bool deg_iterator_duplis_step(DEGObjectIterData *data)
108{
109 if (data->dupli_list.is_empty()) {
110 return false;
111 }
112
113 while (data->dupli_object_next != nullptr) {
114 DupliObject *dob = data->dupli_object_next;
115 Object *obd = dob->ob;
116
117 if (++data->dupli_object_next_index < data->dupli_list.size()) {
118 data->dupli_object_next = &data->dupli_list[data->dupli_object_next_index];
119 }
120 else {
121 data->dupli_object_next = nullptr;
122 data->dupli_object_next_index = -1;
123 }
124
125 if (!DEG_iterator_dupli_is_visible(dob, data->eval_mode)) {
126 continue;
127 }
128
129 /* TODO: Can this be removed? included_objects is already passed to object_duplilist(). */
130 DEGObjectIterSettings *settings = data->settings;
131 if (settings->included_objects) {
132 Object *object_orig = DEG_get_original(obd);
133 if (!settings->included_objects->contains(object_orig)) {
134 continue;
135 }
136 }
137
138 if (data->dupli_object_current) {
140 &data->temp_dupli_object);
141 }
142
143 data->dupli_object_current = dob;
144
146 data->dupli_object_current,
147 data->eval_mode,
148 true,
149 &data->temp_dupli_object,
150 &data->temp_dupli_object_runtime))
151 {
152 data->next_object = &data->temp_dupli_object;
153 return true;
154 }
155 }
156
157 /* Even if the `dupli_list` is not empty, it may happen that none of its entry is displayed (e.g.
158 * #DEG_iterator_dupli_is_visible return `false` for all of the duplis). In such cases,
159 * `dupli_object_current` will also be `nullptr`, and nothing needs to be freed here.
160 * See also #149673 for a reproducible case. */
161 if (data->dupli_object_current) {
162 DEG_iterator_temp_object_free_properties(data->dupli_object_current, &data->temp_dupli_object);
163 }
164 data->dupli_list.clear();
165 data->dupli_parent = nullptr;
166 data->dupli_object_next = nullptr;
167 data->dupli_object_next_index = -1;
168 data->dupli_object_current = nullptr;
169 deg_invalidate_iterator_work_data(data);
170 return false;
171}
172
173/* Returns false when iterator is exhausted. */
174bool deg_iterator_objects_step(DEGObjectIterData *data)
175{
176 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(data->graph);
177
178 for (; data->id_node_index < data->num_id_nodes; data->id_node_index++) {
179 deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index];
180
181 /* Use the build time visibility so that the ID is not appearing/disappearing throughout
182 * animation export. */
183 if (!id_node->is_visible_on_build) {
184 continue;
185 }
186
187 const ID_Type id_type = GS(id_node->id_orig->name);
188
189 if (id_type != ID_OB) {
190 continue;
191 }
192
193 switch (id_node->linked_state) {
195 if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) {
196 continue;
197 }
198 break;
200 if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) {
201 continue;
202 }
203 break;
205 if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) {
206 continue;
207 }
208 break;
209 }
210
211 Object *object = (Object *)id_node->id_cow;
212 Object *object_orig = DEG_get_original(object);
213
214 DEGObjectIterSettings *settings = data->settings;
215 if (settings->included_objects) {
216 if (!settings->included_objects->contains(object_orig)) {
217 continue;
218 }
219 }
220
221 /* NOTE: The object might be invisible after the latest depsgraph evaluation, in which case
222 * going into its evaluated state might not be safe. For example, its evaluated mesh state
223 * might point to a freed data-block if the mesh is animated.
224 * So it is required to perform the visibility checks prior to looking into any deeper into the
225 * object. */
226
228
229 object->runtime->select_id = object_orig->runtime->select_id;
230
231 const bool use_preview = object_orig == data->object_orig_with_preview;
232 if (use_preview) {
234 data->graph, data->scene, object, data->settings->viewer_path, data->dupli_list);
235 deg_iterator_duplis_init(data, object);
236 data->id_node_index++;
237 return true;
238 }
239
240 int ob_visibility = OB_VISIBLE_ALL;
242 ob_visibility = BKE_object_visibility(object, data->eval_mode);
243
244 if (!DEG_iterator_object_is_visible(data->eval_mode, object)) {
245 continue;
246 }
247 }
248
249 if (ob_visibility & OB_VISIBLE_INSTANCES) {
250 if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
251 ((object->transflag & OB_DUPLI) || object->runtime->geometry_set_eval != nullptr))
252 {
255 data->graph, data->scene, object, data->settings->included_objects, data->dupli_list);
256 deg_iterator_duplis_init(data, object);
257 }
258 }
259
260 if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) {
262 data->next_object = object;
263 }
264 data->id_node_index++;
265 return true;
266 }
267 return false;
268}
269
270} // namespace
271
273{
274 BLI_assert(this != &other);
275
276 this->settings = other.settings;
277 this->graph = other.graph;
278 this->flag = other.flag;
279 this->scene = other.scene;
280 this->eval_mode = other.eval_mode;
282 this->next_object = other.next_object;
283 this->dupli_parent = other.dupli_parent;
284 this->dupli_list = std::move(other.dupli_list);
288 this->temp_dupli_object = blender::dna::shallow_copy(other.temp_dupli_object);
291 this->id_node_index = other.id_node_index;
292 this->num_id_nodes = other.num_id_nodes;
293}
294
296{
297 if (BLI_listbase_is_empty(&viewer_path.path)) {
298 return nullptr;
299 }
300 const ViewerPathElem *elem = static_cast<const ViewerPathElem *>(viewer_path.path.first);
301 if (elem->type != VIEWER_PATH_ELEM_TYPE_ID) {
302 return nullptr;
303 }
304 const IDViewerPathElem *id_elem = reinterpret_cast<const IDViewerPathElem *>(elem);
305 if (id_elem->id == nullptr) {
306 return nullptr;
307 }
308 if (GS(id_elem->id->name) != ID_OB) {
309 return nullptr;
310 }
311 Object *object = reinterpret_cast<Object *>(id_elem->id);
313 return nullptr;
314 }
315 const ModifierViewerPathElem *modifier_elem = reinterpret_cast<const ModifierViewerPathElem *>(
316 elem->next);
318 if (md == nullptr) {
319 return nullptr;
320 }
321 if (!(md->mode & eModifierMode_Realtime)) {
322 return nullptr;
323 }
324 return reinterpret_cast<Object *>(id_elem->id);
325}
326
328{
329 Depsgraph *depsgraph = data->graph;
330 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
331 const size_t num_id_nodes = deg_graph->id_nodes.size();
332
333 iter->data = data;
334
335 if (num_id_nodes == 0) {
336 iter->valid = false;
337 return;
338 }
339
340 data->next_object = nullptr;
341 data->dupli_parent = nullptr;
342 data->dupli_list.clear();
343 data->dupli_object_next = nullptr;
344 data->dupli_object_next_index = -1;
345 data->dupli_object_current = nullptr;
347 data->id_node_index = 0;
348 data->num_id_nodes = num_id_nodes;
349 data->eval_mode = DEG_get_mode(depsgraph);
350 deg_invalidate_iterator_work_data(data);
351
352 /* Determine if the preview of any object should be in the iterator. */
353 const ViewerPath *viewer_path = data->settings->viewer_path;
354 if (viewer_path != nullptr) {
355 data->object_orig_with_preview = find_object_with_preview_geometry(*viewer_path);
356 }
357
359}
360
362{
364 while (true) {
365 if (data->next_object != nullptr) {
366 iter->current = data->next_object;
367 data->next_object = nullptr;
368 return;
369 }
370 if (deg_iterator_duplis_step(data)) {
371 continue;
372 }
373 if (deg_iterator_objects_step(data)) {
374 continue;
375 }
376 iter->valid = false;
377 break;
378 }
379}
380
382{
384 if (data != nullptr) {
385 /* Force crash in case the iterator data is referenced and accessed down
386 * the line. (#51718) */
387 deg_invalidate_iterator_work_data(data);
388 }
389}
390
391/* ************************ DEG ID ITERATOR ********************* */
392
393static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool only_updated)
394{
395 ID *id_cow = id_node->id_cow;
396
397 /* Use the build time visibility so that the ID is not appearing/disappearing throughout
398 * animation export.
399 * When the dependency graph is asked for updates report all IDs, as the user of those updates
400 * might need to react to updates coming from IDs which do change visibility throughout the
401 * life-time of the graph. */
402 if (!only_updated && !id_node->is_visible_on_build) {
403 iter->skip = true;
404 return;
405 }
406
407 if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) {
408 /* Node-tree is considered part of the data-block. */
410 if (ntree == nullptr) {
411 iter->skip = true;
412 return;
413 }
414 if ((ntree->id.recalc & ID_RECALC_NTREE_OUTPUT) == 0) {
415 iter->skip = true;
416 return;
417 }
418 }
419
420 iter->current = id_cow;
421 iter->skip = false;
422}
423
425{
426 Depsgraph *depsgraph = data->graph;
427 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
428 const size_t num_id_nodes = deg_graph->id_nodes.size();
429
430 iter->data = data;
431
432 if ((num_id_nodes == 0) || (data->only_updated && !DEG_id_type_any_updated(depsgraph))) {
433 iter->valid = false;
434 return;
435 }
436
437 data->id_node_index = 0;
438 data->num_id_nodes = num_id_nodes;
439
440 deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index];
441 DEG_iterator_ids_step(iter, id_node, data->only_updated);
442
443 if (iter->skip) {
445 }
446}
447
449{
451 Depsgraph *depsgraph = data->graph;
452 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
453
454 do {
455 iter->skip = false;
456
457 ++data->id_node_index;
458 if (data->id_node_index == data->num_id_nodes) {
459 iter->valid = false;
460 return;
461 }
462
463 deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index];
464 DEG_iterator_ids_step(iter, id_node, data->only_updated);
465 } while (iter->skip);
466}
467
469
471{
472 if (ob->type == OB_MBALL) {
473 return true;
474 }
475 return !deg_object_hide_original(eval_mode, ob, nullptr);
476}
477
479{
480 if (dupli->no_draw) {
481 return false;
482 }
483 if (dupli->ob_data && GS(dupli->ob_data->name) == ID_MB) {
484 return false;
485 }
486 if (dupli->ob->type != OB_MBALL && deg_object_hide_original(eval_mode, dupli->ob, dupli)) {
487 return false;
488 }
489
490 return true;
491}
492
494 const DupliObject *dupli,
495 eEvaluationMode eval_mode,
496 bool do_matrix_setup,
497 Object *r_temp_object,
498 ObjectRuntimeHandle *r_temp_runtime)
499{
500 *r_temp_object = blender::dna::shallow_copy(*dupli->ob);
501 r_temp_object->runtime = r_temp_runtime;
502 *r_temp_object->runtime = *dupli->ob->runtime;
503
504 r_temp_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI;
505 r_temp_object->base_local_view_bits = dupli_parent->base_local_view_bits;
506 r_temp_object->runtime->local_collections_bits = dupli_parent->runtime->local_collections_bits;
507 r_temp_object->dt = std::min(r_temp_object->dt, dupli_parent->dt);
508 copy_v4_v4(r_temp_object->color, dupli_parent->color);
509 r_temp_object->runtime->select_id = dupli_parent->runtime->select_id;
510 if (dupli->ob->data != dupli->ob_data) {
512 }
513
514 /* Duplicated elements shouldn't care whether their original collection is visible or not. */
516
517 /* TODO: Could this be computed in DEG_iterator_dupli_is_visible,
518 * before setting up the shallow copy? */
519 int ob_visibility = BKE_object_visibility(r_temp_object, eval_mode);
520 if ((ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) == 0) {
521 return false;
522 }
523
524 if (do_matrix_setup) {
525 /* This could be avoided by refactoring make_dupli() in order to track all negative scaling
526 * recursively. */
527 bool is_neg_scale = is_negative_m4(dupli->mat);
528 SET_FLAG_FROM_TEST(r_temp_object->transflag, is_neg_scale, OB_NEG_SCALE);
529
530 copy_m4_m4(r_temp_object->runtime->object_to_world.ptr(), dupli->mat);
531 invert_m4_m4(r_temp_object->runtime->world_to_object.ptr(),
532 r_temp_object->object_to_world().ptr());
533 }
534
536
537 return true;
538}
539
540static void ensure_id_properties_freed(const IDProperty *dupli_idprops,
541 IDProperty **temp_dupli_idprops)
542{
543 if (*temp_dupli_idprops == nullptr) {
544 /* No ID properties in temp data-block -- no leak is possible. */
545 return;
546 }
547 if (*temp_dupli_idprops == dupli_idprops) {
548 /* Temp copy of object did not modify ID properties. */
549 return;
550 }
551 /* Free memory which is owned by temporary storage which is about to get overwritten. */
552 IDP_FreeProperty(*temp_dupli_idprops);
553 *temp_dupli_idprops = nullptr;
554}
555
void object_duplilist_preview(Depsgraph *depsgraph, Scene *scene, Object *ob, const ViewerPath *viewer_path, DupliList &r_duplilist)
void object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob, blender::Set< const Object * > *include_objects, DupliList &r_duplilist)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1251
ModifierData * BKE_modifiers_findby_persistent_uid(const Object *ob, int persistent_uid)
General operations, lookup, etc. for blender objects.
void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data)
@ OB_VISIBLE_INSTANCES
@ OB_VISIBLE_SELF
@ OB_VISIBLE_PARTICLES
@ OB_VISIBLE_ALL
int BKE_object_visibility(const Object *ob, int dag_eval_mode)
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void copy_m4_m4(float m1[4][4], const float m2[4][4])
bool is_negative_m4(const float mat[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
#define SET_FLAG_FROM_TEST(value, test, flag)
eEvaluationMode
@ DAG_EVAL_RENDER
bool DEG_iterator_dupli_is_visible(const DupliObject *dupli, eEvaluationMode eval_mode)
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
bool DEG_iterator_object_is_visible(eEvaluationMode eval_mode, const Object *ob)
bool DEG_id_type_any_updated(const Depsgraph *depsgraph)
T * DEG_get_original(T *id)
@ DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY
@ DEG_ITER_OBJECT_FLAG_VISIBLE
@ DEG_ITER_OBJECT_FLAG_DUPLI
@ DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY
@ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET
@ ID_RECALC_NTREE_OUTPUT
Definition DNA_ID.h:1155
@ ID_RECALC_ALL
Definition DNA_ID.h:1188
ID_Type
@ ID_MB
@ ID_OB
@ BASE_FROM_DUPLI
@ BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT
@ eModifierMode_Realtime
Object is a sort of wrapper for general info.
@ OB_MBALL
struct ObjectRuntimeHandle ObjectRuntimeHandle
@ OB_DUPLIFACES
@ OB_DUPLI
@ OB_NEG_SCALE
@ OB_DUPLIVERTS
@ VIEWER_PATH_ELEM_TYPE_MODIFIER
@ VIEWER_PATH_ELEM_TYPE_ID
BMesh const char void * data
BPy_StructRNA * depsgraph
bool contains(const Key &key) const
Definition BLI_set.hh:310
int64_t size() const
bool DEG_iterator_dupli_is_visible(const DupliObject *dupli, eEvaluationMode eval_mode)
void DEG_iterator_ids_begin(BLI_Iterator *iter, DEGIDIterData *data)
void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data)
void DEG_iterator_objects_end(BLI_Iterator *iter)
static void ensure_id_properties_freed(const IDProperty *dupli_idprops, IDProperty **temp_dupli_idprops)
void DEG_iterator_ids_end(BLI_Iterator *)
void DEG_iterator_temp_object_free_properties(const DupliObject *dupli, Object *temp_object)
bool DEG_iterator_object_is_visible(eEvaluationMode eval_mode, const Object *ob)
void DEG_iterator_objects_next(BLI_Iterator *iter)
static Object * find_object_with_preview_geometry(const ViewerPath &viewer_path)
void DEG_iterator_ids_next(BLI_Iterator *iter)
bool DEG_iterator_temp_object_from_dupli(const Object *dupli_parent, const DupliObject *dupli, eEvaluationMode eval_mode, bool do_matrix_setup, Object *r_temp_object, ObjectRuntimeHandle *r_temp_runtime)
static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool only_updated)
#define GS(x)
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4568
bool deg_eval_copy_is_expanded(const ID *id_cow)
bool deg_validate_eval_copy_datablock(ID *id_cow)
@ DEG_ID_LINKED_INDIRECTLY
void DEG_iterator_temp_object_free_properties(const DupliObject *dupli, Object *temp_object)
bool DEG_iterator_temp_object_from_dupli(const Object *dupli_parent, const DupliObject *dupli, eEvaluationMode eval_mode, bool do_matrix_setup, Object *r_temp_object, ObjectRuntimeHandle *r_temp_runtime)
DEGObjectIterSettings * settings
eEvaluationMode eval_mode
void transfer_from(DEGObjectIterData &other)
DupliObject * dupli_object_next
DupliObject * dupli_object_current
blender::bke::ObjectRuntime temp_dupli_object_runtime
blender::Set< const Object * > * included_objects
float mat[4][4]
Definition DNA_ID.h:414
unsigned int recalc
Definition DNA_ID.h:445
char name[258]
Definition DNA_ID.h:432
IDProperty * system_properties
Definition DNA_ID.h:489
IDProperty * properties
Definition DNA_ID.h:480
void * first
short transflag
short base_flag
ObjectRuntimeHandle * runtime
float color[4]
struct Object * parent
unsigned short base_local_view_bits
struct ViewerPathElem * next
eDepsNode_LinkedState_Type linked_state