Blender  V2.93
deg_node_component.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2013 Blender Foundation.
17  * All rights reserved.
18  */
19 
25 
26 #include <cstdio>
27 #include <cstring> /* required for STREQ later on. */
28 
29 #include "BLI_ghash.h"
30 #include "BLI_hash.hh"
31 #include "BLI_utildefines.h"
32 
33 #include "DNA_object_types.h"
34 
35 #include "BKE_action.h"
36 
40 
41 namespace blender::deg {
42 
43 /* *********** */
44 /* Outer Nodes */
45 
46 /* Standard Component Methods ============================= */
47 
49  : opcode(OperationCode::OPERATION), name(""), name_tag(-1)
50 {
51 }
52 
54  : opcode(opcode), name(""), name_tag(-1)
55 {
56 }
57 
59  : opcode(opcode), name(name), name_tag(name_tag)
60 {
61 }
62 
64 {
65  const string codebuf = to_string(static_cast<int>(opcode));
66  return "OperationIDKey(" + codebuf + ", " + name + ")";
67 }
68 
70 {
71  return (opcode == other.opcode) && (STREQ(name, other.name)) && (name_tag == other.name_tag);
72 }
73 
75 {
76  const int opcode_as_int = static_cast<int>(opcode);
78  name_tag,
81 }
82 
84  : entry_operation(nullptr), exit_operation(nullptr), affects_directly_visible(false)
85 {
87 }
88 
89 /* Initialize 'component' node - from pointer data given */
90 void ComponentNode::init(const ID * /*id*/, const char * /*subdata*/)
91 {
92  /* hook up eval context? */
93  // XXX: maybe this needs a special API?
94 }
95 
96 /* Free 'component' node */
98 {
100  delete operations_map;
101 }
102 
104 {
105  const string idname = this->owner->name;
106  const string typebuf = "" + to_string(static_cast<int>(type)) + ")";
107  return typebuf + name + " : " + idname +
108  "( affects_directly_visible: " + (affects_directly_visible ? "true" : "false") + ")";
109 }
110 
112 {
113  OperationNode *node = nullptr;
114  if (operations_map != nullptr) {
115  node = operations_map->lookup_default(key, nullptr);
116  }
117  else {
118  for (OperationNode *op_node : operations) {
119  if (op_node->opcode == key.opcode && op_node->name_tag == key.name_tag &&
120  STREQ(op_node->name.c_str(), key.name)) {
121  node = op_node;
122  break;
123  }
124  }
125  }
126  return node;
127 }
128 
130  const char *name,
131  int name_tag) const
132 {
133  OperationIDKey key(opcode, name, name_tag);
134  return find_operation(key);
135 }
136 
138 {
140  if (node == nullptr) {
141  fprintf(stderr,
142  "%s: find_operation(%s) failed\n",
143  this->identifier().c_str(),
144  key.identifier().c_str());
145  BLI_assert(!"Request for non-existing operation, should not happen");
146  return nullptr;
147  }
148  return node;
149 }
150 
152  const char *name,
153  int name_tag) const
154 {
155  OperationIDKey key(opcode, name, name_tag);
156  return get_operation(key);
157 }
158 
160 {
161  return find_operation(key) != nullptr;
162 }
163 
164 bool ComponentNode::has_operation(OperationCode opcode, const char *name, int name_tag) const
165 {
166  OperationIDKey key(opcode, name, name_tag);
167  return has_operation(key);
168 }
169 
171  OperationCode opcode,
172  const char *name,
173  int name_tag)
174 {
175  OperationNode *op_node = find_operation(opcode, name, name_tag);
176  if (!op_node) {
178  op_node = (OperationNode *)factory->create_node(this->owner->id_orig, "", name);
179 
180  /* register opnode in this component's operation set */
181  OperationIDKey key(opcode, name, name_tag);
182  operations_map->add(key, op_node);
183 
184  /* set backlink */
185  op_node->owner = this;
186  }
187  else {
188  fprintf(stderr,
189  "add_operation: Operation already exists - %s has %s at %p\n",
190  this->identifier().c_str(),
191  op_node->identifier().c_str(),
192  op_node);
193  BLI_assert(!"Should not happen!");
194  }
195 
196  /* attach extra data */
197  op_node->evaluate = op;
198  op_node->opcode = opcode;
199  op_node->name = name;
200  op_node->name_tag = name_tag;
201 
202  return op_node;
203 }
204 
206 {
207  BLI_assert(entry_operation == nullptr);
208  entry_operation = op_node;
209 }
210 
212 {
213  BLI_assert(exit_operation == nullptr);
214  exit_operation = op_node;
215 }
216 
218 {
219  if (operations_map != nullptr) {
220  for (OperationNode *op_node : operations_map->values()) {
221  delete op_node;
222  }
223  operations_map->clear();
224  }
225  for (OperationNode *op_node : operations) {
226  delete op_node;
227  }
228  operations.clear();
229 }
230 
232 {
233  OperationNode *entry_op = get_entry_operation();
234  if (entry_op != nullptr && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
235  return;
236  }
237  for (OperationNode *op_node : operations) {
238  op_node->tag_update(graph, source);
239  }
240  // It is possible that tag happens before finalization.
241  if (operations_map != nullptr) {
242  for (OperationNode *op_node : operations_map->values()) {
243  op_node->tag_update(graph, source);
244  }
245  }
246 }
247 
249 {
250  if (entry_operation) {
251  return entry_operation;
252  }
253  if (operations_map != nullptr && operations_map->size() == 1) {
254  OperationNode *op_node = nullptr;
255  /* TODO(sergey): This is somewhat slow. */
256  for (OperationNode *tmp : operations_map->values()) {
257  op_node = tmp;
258  }
259  /* Cache for the subsequent usage. */
260  entry_operation = op_node;
261  return op_node;
262  }
263  if (operations.size() == 1) {
264  return operations[0];
265  }
266  return nullptr;
267 }
268 
270 {
271  if (exit_operation) {
272  return exit_operation;
273  }
274  if (operations_map != nullptr && operations_map->size() == 1) {
275  OperationNode *op_node = nullptr;
276  /* TODO(sergey): This is somewhat slow. */
277  for (OperationNode *tmp : operations_map->values()) {
278  op_node = tmp;
279  }
280  /* Cache for the subsequent usage. */
281  exit_operation = op_node;
282  return op_node;
283  }
284  if (operations.size() == 1) {
285  return operations[0];
286  }
287  return nullptr;
288 }
289 
291 {
293  for (OperationNode *op_node : operations_map->values()) {
294  operations.append(op_node);
295  }
296  delete operations_map;
297  operations_map = nullptr;
298 }
299 
300 /* Bone Component ========================================= */
301 
302 /* Initialize 'bone component' node - from pointer data given */
303 void BoneComponentNode::init(const ID *id, const char *subdata)
304 {
305  /* generic component-node... */
306  ComponentNode::init(id, subdata);
307 
308  /* name of component comes is bone name */
309  /* TODO(sergey): This sets name to an empty string because subdata is
310  * empty. Is it a bug? */
311  // this->name = subdata;
312 
313  /* bone-specific node data */
314  Object *object = (Object *)id;
315  this->pchan = BKE_pose_channel_find_name(object->pose, subdata);
316 }
317 
318 /* Register all components. =============================== */
319 
321 /* TODO(sergey): Is this a correct tag? */
324 DEG_COMPONENT_NODE_DEFINE(Cache, CACHE, 0);
326 DEG_COMPONENT_NODE_DEFINE(ImageAnimation, IMAGE_ANIMATION, 0);
328 DEG_COMPONENT_NODE_DEFINE(LayerCollections, LAYER_COLLECTIONS, 0);
329 DEG_COMPONENT_NODE_DEFINE(Parameters, PARAMETERS, 0);
330 DEG_COMPONENT_NODE_DEFINE(Particles, PARTICLE_SYSTEM, ID_RECALC_GEOMETRY);
335 DEG_COMPONENT_NODE_DEFINE(Sequencer, SEQUENCER, 0);
337 DEG_COMPONENT_NODE_DEFINE(ShadingParameters, SHADING_PARAMETERS, ID_RECALC_SHADING);
339 DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0);
340 DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0);
341 DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0);
342 DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0);
343 DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
344 DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
346 
347 /* Node Types Register =================================== */
348 
350 {
351  register_node_typeinfo(&DNTI_ANIMATION);
352  register_node_typeinfo(&DNTI_BONE);
353  register_node_typeinfo(&DNTI_CACHE);
354  register_node_typeinfo(&DNTI_BATCH_CACHE);
355  register_node_typeinfo(&DNTI_COPY_ON_WRITE);
356  register_node_typeinfo(&DNTI_GEOMETRY);
357  register_node_typeinfo(&DNTI_LAYER_COLLECTIONS);
358  register_node_typeinfo(&DNTI_PARAMETERS);
359  register_node_typeinfo(&DNTI_PARTICLE_SYSTEM);
360  register_node_typeinfo(&DNTI_PARTICLE_SETTINGS);
361  register_node_typeinfo(&DNTI_POINT_CACHE);
362  register_node_typeinfo(&DNTI_IMAGE_ANIMATION);
363  register_node_typeinfo(&DNTI_PROXY);
364  register_node_typeinfo(&DNTI_EVAL_POSE);
365  register_node_typeinfo(&DNTI_SEQUENCER);
366  register_node_typeinfo(&DNTI_SHADING);
367  register_node_typeinfo(&DNTI_SHADING_PARAMETERS);
368  register_node_typeinfo(&DNTI_TRANSFORM);
369  register_node_typeinfo(&DNTI_OBJECT_FROM_LAYER);
370  register_node_typeinfo(&DNTI_DUPLI);
371  register_node_typeinfo(&DNTI_SYNCHRONIZATION);
372  register_node_typeinfo(&DNTI_AUDIO);
373  register_node_typeinfo(&DNTI_ARMATURE);
374  register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
375  register_node_typeinfo(&DNTI_SIMULATION);
376 }
377 
378 } // namespace blender::deg
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
#define BLI_assert(a)
Definition: BLI_assert.h:58
size_t BLI_ghashutil_combine_hash(size_t hash_a, size_t hash_b)
unsigned int BLI_ghashutil_uinthash(unsigned int key)
unsigned int BLI_ghashutil_strhash_p(const void *ptr)
#define STREQ(a, b)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:599
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_SHADING
Definition: DNA_ID.h:631
@ ID_RECALC_ANIMATION
Definition: DNA_ID.h:614
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
Object is a sort of wrapper for general info.
int64_t size() const
Definition: BLI_vector.hh:662
void append(const T &value)
Definition: BLI_vector.hh:438
void reserve(const int64_t min_capacity)
Definition: BLI_vector.hh:355
OperationNode * node
Depsgraph * graph
DEG_COMPONENT_NODE_DEFINE(Animation, ANIMATION, ID_RECALC_ANIMATION)
void register_node_typeinfo(DepsNodeFactory *factory)
void deg_register_component_depsnodes()
DepsNodeFactory * type_get_factory(const NodeType type)
function< void(struct ::Depsgraph *)> DepsEvalOperationCb
std::string to_string(const T &n)
unsigned __int64 uint64_t
Definition: stdint.h:93
Definition: DNA_ID.h:273
struct bPose * pose
void init(const ID *id, const char *subdata)
bool operator==(const OperationIDKey &other) const
virtual OperationNode * get_entry_operation() override
OperationNode * get_operation(OperationIDKey key) const
void init(const ID *id, const char *subdata) override
virtual void tag_update(Depsgraph *graph, eUpdateSource source) override
Vector< OperationNode * > operations
OperationNode * find_operation(OperationIDKey key) const
OperationNode * add_operation(const DepsEvalOperationCb &op, OperationCode opcode, const char *name, int name_tag)
virtual OperationNode * get_exit_operation() override
bool has_operation(OperationIDKey key) const
void set_exit_operation(OperationNode *op_node)
void finalize_build(Depsgraph *graph)
virtual string identifier() const override
Map< ComponentNode::OperationIDKey, OperationNode * > * operations_map
void set_entry_operation(OperationNode *op_node)
virtual Node * create_node(const ID *id, const char *subdata, const char *name) const =0
virtual string identifier() const override