/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2017 Blender Foundation. * All rights reserved. * * Original Author: Dalai Felinto * Contributor(s): Sergey Sharybin * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/depsgraph/intern/depsgraph_query_iter.cc * \ingroup depsgraph * * Implementation of Querying and Filtering API's */ #include "MEM_guardedalloc.h" extern "C" { #include "BLI_utildefines.h" #include "BLI_math.h" #include "BKE_anim.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_object.h" } /* extern "C" */ #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" #include "intern/depsgraph_intern.h" #include "util/deg_util_foreach.h" #include "intern/nodes/deg_node_id.h" #ifndef NDEBUG # include "intern/eval/deg_eval_copy_on_write.h" #endif /* ************************ DEG ITERATORS ********************* */ static void verify_id_proeprties_freed(DEGObjectIterData *data) { if (data->dupli_object_current == NULL) { // We didn't enter duplication yet, so we can't have any dangling // pointers. return; } const Object *dupli_object = data->dupli_object_current->ob; Object *temp_dupli_object = &data->temp_dupli_object; if (temp_dupli_object->id.properties == NULL) { // No ID proeprties in temp datablock -- no leak is possible. return; } if (temp_dupli_object->id.properties == dupli_object->id.properties) { // Temp copy of object did not modify ID properties. return; } // Free memory which is owned by temporary storage which is about to // get overwritten. IDP_FreeProperty(temp_dupli_object->id.properties); MEM_freeN(temp_dupli_object->id.properties); temp_dupli_object->id.properties = NULL; } static bool deg_objects_dupli_iterator_next(BLI_Iterator *iter) { DEGObjectIterData *data = (DEGObjectIterData *)iter->data; while (data->dupli_object_next != NULL) { DupliObject *dob = data->dupli_object_next; Object *obd = dob->ob; data->dupli_object_next = data->dupli_object_next->next; /* Group duplis need to set ob matrices correct, for deform. so no_draw * is part handled. */ if ((obd->transflag & OB_RENDER_DUPLI) == 0 && dob->no_draw) { continue; } if (obd->type == OB_MBALL) { continue; } verify_id_proeprties_freed(data); data->dupli_object_current = dob; /* Temporary object to evaluate. */ Object *dupli_parent = data->dupli_parent; Object *temp_dupli_object = &data->temp_dupli_object; *temp_dupli_object = *dob->ob; temp_dupli_object->transflag &= ~OB_DUPLI; temp_dupli_object->select_color = dupli_parent->select_color; temp_dupli_object->base_flag = dupli_parent->base_flag | BASE_FROMDUPLI; if (dob->collection_properties != NULL) { temp_dupli_object->base_collection_properties = dob->collection_properties; IDP_MergeGroup(temp_dupli_object->base_collection_properties, dupli_parent->base_collection_properties, false); } else { temp_dupli_object->base_collection_properties = dupli_parent->base_collection_properties; } copy_m4_m4(data->temp_dupli_object.obmat, dob->mat); iter->current = &data->temp_dupli_object; BLI_assert( DEG::deg_validate_copy_on_write_datablock( &data->temp_dupli_object.id)); return true; } return false; } static void DEG_iterator_objects_step(BLI_Iterator *iter, DEG::IDDepsNode *id_node) { /* Set it early in case we need to exit and we are running from within a loop. */ iter->skip = true; DEGObjectIterData *data = (DEGObjectIterData *)iter->data; const ID_Type id_type = GS(id_node->id_orig->name); if (id_type != ID_OB) { return; } switch (id_node->linked_state) { case DEG::DEG_ID_LINKED_DIRECTLY: if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY) == 0) { return; } break; case DEG::DEG_ID_LINKED_VIA_SET: if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET) == 0) { return; } break; case DEG::DEG_ID_LINKED_INDIRECTLY: if ((data->flag & DEG_ITER_OBJECT_FLAG_LINKED_INDIRECTLY) == 0) { return; } break; } Object *object = (Object *)id_node->id_cow; BLI_assert(DEG::deg_validate_copy_on_write_datablock(&object->id)); if ((BKE_object_is_visible(object, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE) == false) && ((data->flag & DEG_ITER_OBJECT_FLAG_VISIBLE) != 0)) { return; } if ((data->flag & DEG_ITER_OBJECT_FLAG_DUPLI) && (object->transflag & OB_DUPLI)) { data->dupli_parent = object; data->dupli_list = object_duplilist(&data->eval_ctx, data->scene, object); data->dupli_object_next = (DupliObject *)data->dupli_list->first; const eObjectVisibilityCheck mode = (data->mode == DEG_ITER_OBJECT_MODE_RENDER) ? OB_VISIBILITY_CHECK_FOR_RENDER : OB_VISIBILITY_CHECK_FOR_VIEWPORT; if (BKE_object_is_visible(object, mode) == false) { return; } } iter->current = object; iter->skip = false; } void DEG_iterator_objects_begin(BLI_Iterator *iter, DEGObjectIterData *data) { Depsgraph *depsgraph = data->graph; DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); const size_t num_id_nodes = deg_graph->id_nodes.size(); if (num_id_nodes == 0) { iter->valid = false; return; } /* TODO(sergey): What evaluation type we want here? */ /* TODO(dfelinto): Get rid of evaluation context here, it's only used to do * direct dupli-objects update in group.c. Which is terribly bad, and all * objects are expected to be evaluated already. */ DEG_evaluation_context_init(&data->eval_ctx, DAG_EVAL_VIEWPORT); data->eval_ctx.view_layer = DEG_get_evaluated_view_layer(depsgraph); iter->data = data; data->dupli_parent = NULL; data->dupli_list = NULL; data->dupli_object_next = NULL; data->dupli_object_current = NULL; data->scene = DEG_get_evaluated_scene(depsgraph); data->id_node_index = 0; data->num_id_nodes = num_id_nodes; DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index]; DEG_iterator_objects_step(iter, id_node); if (iter->skip) { DEG_iterator_objects_next(iter); } } void DEG_iterator_objects_next(BLI_Iterator *iter) { DEGObjectIterData *data = (DEGObjectIterData *)iter->data; Depsgraph *depsgraph = data->graph; DEG::Depsgraph *deg_graph = reinterpret_cast(depsgraph); do { iter->skip = false; if (data->dupli_list) { if (deg_objects_dupli_iterator_next(iter)) { return; } else { verify_id_proeprties_freed(data); free_object_duplilist(data->dupli_list); data->dupli_parent = NULL; data->dupli_list = NULL; data->dupli_object_next = NULL; data->dupli_object_current = NULL; } } ++data->id_node_index; if (data->id_node_index == data->num_id_nodes) { iter->valid = false; return; } DEG::IDDepsNode *id_node = deg_graph->id_nodes[data->id_node_index]; DEG_iterator_objects_step(iter, id_node); } while (iter->skip); } void DEG_iterator_objects_end(BLI_Iterator *iter) { #ifndef NDEBUG DEGObjectIterData *data = (DEGObjectIterData *)iter->data; /* Force crash in case the iterator data is referenced and accessed down * the line. (T51718) */ memset(&data->temp_dupli_object, 0xff, sizeof(data->temp_dupli_object)); #else (void) iter; #endif }