Blender V4.5
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
51/* ************************ DEG ITERATORS ********************* */
52
53namespace {
54
55void deg_invalidate_iterator_work_data(DEGObjectIterData *data)
56{
57#ifdef INVALIDATE_WORK_DATA
58 BLI_assert(data != nullptr);
59 memset((void *)&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object));
60#else
61 (void)data;
62#endif
63}
64
65void ensure_id_properties_freed(const Object *dupli_object, Object *temp_dupli_object)
66{
67 if (temp_dupli_object->id.properties == nullptr) {
68 /* No ID properties in temp data-block -- no leak is possible. */
69 return;
70 }
71 if (temp_dupli_object->id.properties == dupli_object->id.properties) {
72 /* Temp copy of object did not modify ID properties. */
73 return;
74 }
75 /* Free memory which is owned by temporary storage which is about to get overwritten. */
76 IDP_FreeProperty(temp_dupli_object->id.properties);
77 temp_dupli_object->id.properties = nullptr;
78}
79
80void free_owned_memory(DEGObjectIterData *data)
81{
82 if (data->dupli_object_current == nullptr) {
83 /* We didn't enter duplication yet, so we can't have any dangling pointers. */
84 return;
85 }
86
87 const Object *dupli_object = data->dupli_object_current->ob;
88 Object *temp_dupli_object = &data->temp_dupli_object;
89
90 ensure_id_properties_freed(dupli_object, temp_dupli_object);
91}
92
93bool deg_object_hide_original(eEvaluationMode eval_mode, Object *ob, DupliObject *dob)
94{
95 /* Automatic hiding if this object is being instanced on verts/faces/frames
96 * by its parent. Ideally this should not be needed, but due to the wrong
97 * dependency direction in the data design there is no way to keep the object
98 * visible otherwise. The better solution eventually would be for objects
99 * to specify which object they instance, instead of through parenting.
100 *
101 * This function should not be used for meta-balls. They have custom visibility rules, as hiding
102 * the base meta-ball will also hide all the other balls in the group. */
103 if (eval_mode == DAG_EVAL_RENDER || dob) {
104 const int hide_original_types = OB_DUPLIVERTS | OB_DUPLIFACES;
105
106 if (!dob || !(dob->type & hide_original_types)) {
107 if (ob->parent && (ob->parent->transflag & hide_original_types)) {
108 return true;
109 }
110 }
111 }
112
113 return false;
114}
115
116void deg_iterator_duplis_init(DEGObjectIterData *data, Object *object, ListBase *duplis)
117{
118 data->dupli_parent = object;
119 data->dupli_list = duplis;
120 data->dupli_object_next = static_cast<DupliObject *>(duplis->first);
121}
122
123/* Returns false when iterator is exhausted. */
124bool deg_iterator_duplis_step(DEGObjectIterData *data)
125{
126 if (data->dupli_list == nullptr) {
127 return false;
128 }
129
130 while (data->dupli_object_next != nullptr) {
131 DupliObject *dob = data->dupli_object_next;
132 Object *obd = dob->ob;
133
134 data->dupli_object_next = data->dupli_object_next->next;
135
136 if (dob->no_draw) {
137 continue;
138 }
139 if (dob->ob_data && GS(dob->ob_data->name) == ID_MB) {
140 continue;
141 }
142 if (obd->type != OB_MBALL && deg_object_hide_original(data->eval_mode, dob->ob, dob)) {
143 continue;
144 }
145
146 DEGObjectIterSettings *settings = data->settings;
147 if (settings->included_objects) {
148 Object *object_orig = DEG_get_original(obd);
149 if (!settings->included_objects->contains(object_orig)) {
150 continue;
151 }
152 }
153
154 free_owned_memory(data);
155
156 data->dupli_object_current = dob;
157
158 /* Temporary object to evaluate. */
159 Object *dupli_parent = data->dupli_parent;
160 Object *temp_dupli_object = &data->temp_dupli_object;
161
162 *temp_dupli_object = blender::dna::shallow_copy(*dob->ob);
163 temp_dupli_object->runtime = &data->temp_dupli_object_runtime;
164 *temp_dupli_object->runtime = *dob->ob->runtime;
165
166 temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROM_DUPLI;
167 temp_dupli_object->base_local_view_bits = dupli_parent->base_local_view_bits;
168 temp_dupli_object->runtime->local_collections_bits =
169 dupli_parent->runtime->local_collections_bits;
170 temp_dupli_object->dt = std::min(temp_dupli_object->dt, dupli_parent->dt);
171 copy_v4_v4(temp_dupli_object->color, dupli_parent->color);
172 temp_dupli_object->runtime->select_id = dupli_parent->runtime->select_id;
173 if (dob->ob->data != dob->ob_data) {
174 BKE_object_replace_data_on_shallow_copy(temp_dupli_object, dob->ob_data);
175 }
176
177 /* Duplicated elements shouldn't care whether their original collection is visible or not. */
179
180 int ob_visibility = BKE_object_visibility(temp_dupli_object, data->eval_mode);
181 if ((ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) == 0) {
182 continue;
183 }
184
185 /* This could be avoided by refactoring make_dupli() in order to track all negative scaling
186 * recursively. */
187 bool is_neg_scale = is_negative_m4(dob->mat);
188 SET_FLAG_FROM_TEST(data->temp_dupli_object.transflag, is_neg_scale, OB_NEG_SCALE);
189
190 copy_m4_m4(data->temp_dupli_object.runtime->object_to_world.ptr(), dob->mat);
191 invert_m4_m4(data->temp_dupli_object.runtime->world_to_object.ptr(),
192 data->temp_dupli_object.object_to_world().ptr());
193 data->next_object = &data->temp_dupli_object;
195 return true;
196 }
197
198 free_owned_memory(data);
199 free_object_duplilist(data->dupli_list);
200 data->dupli_parent = nullptr;
201 data->dupli_list = nullptr;
202 data->dupli_object_next = nullptr;
203 data->dupli_object_current = nullptr;
204 deg_invalidate_iterator_work_data(data);
205 return false;
206}
207
208/* Returns false when iterator is exhausted. */
209bool deg_iterator_objects_step(DEGObjectIterData *data)
210{
211 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(data->graph);
212
213 for (; data->id_node_index < data->num_id_nodes; data->id_node_index++) {
214 deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index];
215
216 /* Use the build time visibility so that the ID is not appearing/disappearing throughout
217 * animation export. */
218 if (!id_node->is_visible_on_build) {
219 continue;
220 }
221
222 const ID_Type id_type = GS(id_node->id_orig->name);
223
224 if (id_type != ID_OB) {
225 continue;
226 }
227
228 switch (id_node->linked_state) {
230 if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) {
231 continue;
232 }
233 break;
235 if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) {
236 continue;
237 }
238 break;
240 if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) {
241 continue;
242 }
243 break;
244 }
245
246 Object *object = (Object *)id_node->id_cow;
247 Object *object_orig = DEG_get_original(object);
248
249 DEGObjectIterSettings *settings = data->settings;
250 if (settings->included_objects) {
251 if (!settings->included_objects->contains(object_orig)) {
252 continue;
253 }
254 }
255
256 /* NOTE: The object might be invisible after the latest depsgraph evaluation, in which case
257 * going into its evaluated state might not be safe. For example, its evaluated mesh state
258 * might point to a freed data-block if the mesh is animated.
259 * So it is required to perform the visibility checks prior to looking into any deeper into the
260 * object. */
261
263
264 object->runtime->select_id = object_orig->runtime->select_id;
265
266 const bool use_preview = object_orig == data->object_orig_with_preview;
267 if (use_preview) {
268 ListBase *preview_duplis = object_duplilist_preview(
269 data->graph, data->scene, object, data->settings->viewer_path);
270 deg_iterator_duplis_init(data, object, preview_duplis);
271 data->id_node_index++;
272 return true;
273 }
274
275 int ob_visibility = OB_VISIBLE_ALL;
277 ob_visibility = BKE_object_visibility(object, data->eval_mode);
278
279 if (object->type != OB_MBALL && deg_object_hide_original(data->eval_mode, object, nullptr)) {
280 continue;
281 }
282 }
283
284 if (ob_visibility & OB_VISIBLE_INSTANCES) {
285 if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) &&
286 ((object->transflag & OB_DUPLI) || object->runtime->geometry_set_eval != nullptr))
287 {
289 ListBase *duplis = object_duplilist(
290 data->graph, data->scene, object, data->settings->included_objects);
291 deg_iterator_duplis_init(data, object, duplis);
292 }
293 }
294
295 if (ob_visibility & (OB_VISIBLE_SELF | OB_VISIBLE_PARTICLES)) {
297 data->next_object = object;
298 }
299 data->id_node_index++;
300 return true;
301 }
302 return false;
303}
304
305} // namespace
306
308{
309 if (this != &other) {
310 this->settings = other.settings;
311 this->graph = other.graph;
312 this->flag = other.flag;
313 this->scene = other.scene;
314 this->eval_mode = other.eval_mode;
316 this->next_object = other.next_object;
317 this->dupli_parent = other.dupli_parent;
318 this->dupli_list = other.dupli_list;
321 this->temp_dupli_object = blender::dna::shallow_copy(other.temp_dupli_object);
324 this->id_node_index = other.id_node_index;
325 this->num_id_nodes = other.num_id_nodes;
326 }
327 return *this;
328}
329
331{
332 if (BLI_listbase_is_empty(&viewer_path.path)) {
333 return nullptr;
334 }
335 const ViewerPathElem *elem = static_cast<const ViewerPathElem *>(viewer_path.path.first);
336 if (elem->type != VIEWER_PATH_ELEM_TYPE_ID) {
337 return nullptr;
338 }
339 const IDViewerPathElem *id_elem = reinterpret_cast<const IDViewerPathElem *>(elem);
340 if (id_elem->id == nullptr) {
341 return nullptr;
342 }
343 if (GS(id_elem->id->name) != ID_OB) {
344 return nullptr;
345 }
346 Object *object = reinterpret_cast<Object *>(id_elem->id);
348 return nullptr;
349 }
350 const ModifierViewerPathElem *modifier_elem = reinterpret_cast<const ModifierViewerPathElem *>(
351 elem->next);
353 if (md == nullptr) {
354 return nullptr;
355 }
356 if (!(md->mode & eModifierMode_Realtime)) {
357 return nullptr;
358 }
359 return reinterpret_cast<Object *>(id_elem->id);
360}
361
363{
364 Depsgraph *depsgraph = data->graph;
365 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
366 const size_t num_id_nodes = deg_graph->id_nodes.size();
367
368 iter->data = data;
369
370 if (num_id_nodes == 0) {
371 iter->valid = false;
372 return;
373 }
374
375 data->next_object = nullptr;
376 data->dupli_parent = nullptr;
377 data->dupli_list = nullptr;
378 data->dupli_object_next = nullptr;
379 data->dupli_object_current = nullptr;
381 data->id_node_index = 0;
382 data->num_id_nodes = num_id_nodes;
383 data->eval_mode = DEG_get_mode(depsgraph);
384 deg_invalidate_iterator_work_data(data);
385
386 /* Determine if the preview of any object should be in the iterator. */
387 const ViewerPath *viewer_path = data->settings->viewer_path;
388 if (viewer_path != nullptr) {
389 data->object_orig_with_preview = find_object_with_preview_geometry(*viewer_path);
390 }
391
393}
394
396{
398 while (true) {
399 if (data->next_object != nullptr) {
400 iter->current = data->next_object;
401 data->next_object = nullptr;
402 return;
403 }
404 if (deg_iterator_duplis_step(data)) {
405 continue;
406 }
407 if (deg_iterator_objects_step(data)) {
408 continue;
409 }
410 iter->valid = false;
411 break;
412 }
413}
414
416{
418 if (data != nullptr) {
419 /* Force crash in case the iterator data is referenced and accessed down
420 * the line. (#51718) */
421 deg_invalidate_iterator_work_data(data);
422 }
423}
424
425/* ************************ DEG ID ITERATOR ********************* */
426
427static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool only_updated)
428{
429 ID *id_cow = id_node->id_cow;
430
431 /* Use the build time visibility so that the ID is not appearing/disappearing throughout
432 * animation export.
433 * When the dependency graph is asked for updates report all IDs, as the user of those updates
434 * might need to react to updates coming from IDs which do change visibility throughout the
435 * life-time of the graph. */
436 if (!only_updated && !id_node->is_visible_on_build) {
437 iter->skip = true;
438 return;
439 }
440
441 if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) {
442 /* Node-tree is considered part of the data-block. */
444 if (ntree == nullptr) {
445 iter->skip = true;
446 return;
447 }
448 if ((ntree->id.recalc & ID_RECALC_NTREE_OUTPUT) == 0) {
449 iter->skip = true;
450 return;
451 }
452 }
453
454 iter->current = id_cow;
455 iter->skip = false;
456}
457
459{
460 Depsgraph *depsgraph = data->graph;
461 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
462 const size_t num_id_nodes = deg_graph->id_nodes.size();
463
464 iter->data = data;
465
466 if ((num_id_nodes == 0) || (data->only_updated && !DEG_id_type_any_updated(depsgraph))) {
467 iter->valid = false;
468 return;
469 }
470
471 data->id_node_index = 0;
472 data->num_id_nodes = num_id_nodes;
473
474 deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index];
475 DEG_iterator_ids_step(iter, id_node, data->only_updated);
476
477 if (iter->skip) {
479 }
480}
481
483{
485 Depsgraph *depsgraph = data->graph;
486 deg::Depsgraph *deg_graph = reinterpret_cast<deg::Depsgraph *>(depsgraph);
487
488 do {
489 iter->skip = false;
490
491 ++data->id_node_index;
492 if (data->id_node_index == data->num_id_nodes) {
493 iter->valid = false;
494 return;
495 }
496
497 deg::IDNode *id_node = deg_graph->id_nodes[data->id_node_index];
498 DEG_iterator_ids_step(iter, id_node, data->only_updated);
499 } while (iter->skip);
500}
501
void free_object_duplilist(ListBase *lb)
ListBase * object_duplilist_preview(Depsgraph *depsgraph, Scene *scene, Object *ob, const ViewerPath *viewer_path)
ListBase * object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob, blender::Set< const Object * > *include_objects=nullptr)
void IDP_FreeProperty(IDProperty *prop)
Definition idprop.cc:1243
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
Scene * DEG_get_evaluated_scene(const Depsgraph *graph)
eEvaluationMode DEG_get_mode(const Depsgraph *graph)
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:1063
@ ID_RECALC_ALL
Definition DNA_ID.h:1096
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_DUPLIFACES
@ OB_DUPLI
@ OB_NEG_SCALE
@ OB_DUPLIVERTS
@ OB_MBALL
@ 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
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)
void DEG_iterator_ids_end(BLI_Iterator *)
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)
static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool only_updated)
#define GS(a)
bNodeTree * node_tree_from_id(ID *id)
Definition node.cc:4840
bool deg_eval_copy_is_expanded(const ID *id_cow)
bool deg_validate_eval_copy_datablock(ID *id_cow)
@ DEG_ID_LINKED_INDIRECTLY
DEGObjectIterSettings * settings
eEvaluationMode eval_mode
DEGObjectIterData & operator=(const 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:404
unsigned int recalc
Definition DNA_ID.h:427
IDProperty * properties
Definition DNA_ID.h:446
char name[66]
Definition DNA_ID.h:415
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