This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/depsgraph/intern/depsgraph_query_foreach.cc
Campbell Barton de13d0a80c doxygen: add newline after \file
While \file doesn't need an argument, it can't have another doxy
command after it.
2019-02-18 08:22:12 +11:00

234 lines
7.0 KiB
C++

/*
* 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.
*/
/** \file
* \ingroup depsgraph
*
* Implementation of Querying and Filtering API's
*/
// TODO(sergey): Use some sort of wrapper.
#include <deque>
#include "MEM_guardedalloc.h"
extern "C" {
#include "BLI_utildefines.h"
#include "BLI_ghash.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.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_operation.h"
/* ************************ DEG TRAVERSAL ********************* */
namespace DEG {
typedef std::deque<OperationNode *> TraversalQueue;
enum {
DEG_NODE_VISITED = (1 << 0),
};
static void deg_foreach_clear_flags(const Depsgraph *graph)
{
for (OperationNode *op_node : graph->operations) {
op_node->scheduled = false;
}
for (IDNode *id_node : graph->id_nodes) {
id_node->custom_flags = 0;
}
}
static void deg_foreach_dependent_ID(const Depsgraph *graph,
const ID *id,
DEGForeachIDCallback callback,
void *user_data)
{
/* Start with getting ID node from the graph. */
IDNode *target_id_node = graph->find_id_node(id);
if (target_id_node == NULL) {
/* TODO(sergey): Shall we inform or assert here about attempt to start
* iterating over non-existing ID? */
return;
}
/* Make sure all runtime flags are ready and clear. */
deg_foreach_clear_flags(graph);
/* Start with scheduling all operations from ID node. */
TraversalQueue queue;
GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, target_id_node->components)
{
for (OperationNode *op_node : comp_node->operations) {
queue.push_back(op_node);
op_node->scheduled = true;
}
}
GHASH_FOREACH_END();
target_id_node->custom_flags |= DEG_NODE_VISITED;
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
OperationNode *op_node = queue.front();
queue.pop_front();
for (;;) {
/* Check whether we need to inform callee about corresponding ID node. */
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
/* TODO(sergey): Is it orig or CoW? */
callback(id_node->id_orig, user_data);
id_node->custom_flags |= DEG_NODE_VISITED;
}
/* Schedule outgoing operation nodes. */
if (op_node->outlinks.size() == 1) {
OperationNode *to_node = (OperationNode *)op_node->outlinks[0]->to;
if (to_node->scheduled == false) {
to_node->scheduled = true;
op_node = to_node;
}
else {
break;
}
}
else {
for (Relation *rel : op_node->outlinks) {
OperationNode *to_node = (OperationNode *)rel->to;
if (to_node->scheduled == false) {
queue.push_front(to_node);
to_node->scheduled = true;
}
}
break;
}
}
}
}
static void deg_foreach_ancestor_ID(const Depsgraph *graph,
const ID *id,
DEGForeachIDCallback callback,
void *user_data)
{
/* Start with getting ID node from the graph. */
IDNode *target_id_node = graph->find_id_node(id);
if (target_id_node == NULL) {
/* TODO(sergey): Shall we inform or assert here about attempt to start
* iterating over non-existing ID? */
return;
}
/* Make sure all runtime flags are ready and clear. */
deg_foreach_clear_flags(graph);
/* Start with scheduling all operations from ID node. */
TraversalQueue queue;
GHASH_FOREACH_BEGIN(ComponentNode *, comp_node, target_id_node->components)
{
for (OperationNode *op_node : comp_node->operations) {
queue.push_back(op_node);
op_node->scheduled = true;
}
}
GHASH_FOREACH_END();
target_id_node->custom_flags |= DEG_NODE_VISITED;
/* Process the queue. */
while (!queue.empty()) {
/* get next operation node to process. */
OperationNode *op_node = queue.front();
queue.pop_front();
for (;;) {
/* Check whether we need to inform callee about corresponding ID node. */
ComponentNode *comp_node = op_node->owner;
IDNode *id_node = comp_node->owner;
if ((id_node->custom_flags & DEG_NODE_VISITED) == 0) {
/* TODO(sergey): Is it orig or CoW? */
callback(id_node->id_orig, user_data);
id_node->custom_flags |= DEG_NODE_VISITED;
}
/* Schedule incoming operation nodes. */
if (op_node->inlinks.size() == 1) {
Node *from = op_node->inlinks[0]->from;
if (from->get_class() == NodeClass::OPERATION) {
OperationNode *from_node = (OperationNode *)from;
if (from_node->scheduled == false) {
from_node->scheduled = true;
op_node = from_node;
}
else {
break;
}
}
}
else {
for (Relation *rel : op_node->inlinks) {
Node *from = rel->from;
if (from->get_class() == NodeClass::OPERATION) {
OperationNode *from_node = (OperationNode *)from;
if (from_node->scheduled == false) {
queue.push_front(from_node);
from_node->scheduled = true;
}
}
}
break;
}
}
}
}
static void deg_foreach_id(const Depsgraph *depsgraph,
DEGForeachIDCallback callback, void *user_data)
{
for (const IDNode *id_node : depsgraph->id_nodes) {
callback(id_node->id_orig, user_data);
}
}
} // namespace DEG
void DEG_foreach_dependent_ID(const Depsgraph *depsgraph,
const ID *id,
DEGForeachIDCallback callback, void *user_data)
{
DEG::deg_foreach_dependent_ID((const DEG::Depsgraph *)depsgraph,
id,
callback, user_data);
}
void DEG_foreach_ancestor_ID(const Depsgraph *depsgraph,
const ID *id,
DEGForeachIDCallback callback, void *user_data)
{
DEG::deg_foreach_ancestor_ID((const DEG::Depsgraph *)depsgraph,
id,
callback, user_data);
}
void DEG_foreach_ID(const Depsgraph *depsgraph,
DEGForeachIDCallback callback, void *user_data)
{
DEG::deg_foreach_id((const DEG::Depsgraph *)depsgraph, callback, user_data);
}