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