Blender  V3.3
deg_builder_rna.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2019 Blender Foundation. All rights reserved. */
3 
9 
10 #include <cstring>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_listbase.h"
15 #include "BLI_utildefines.h"
16 
17 #include "DNA_action_types.h"
18 #include "DNA_armature_types.h"
19 #include "DNA_constraint_types.h"
20 #include "DNA_key_types.h"
21 #include "DNA_object_types.h"
22 #include "DNA_sequence_types.h"
23 
24 #include "BKE_constraint.h"
25 
26 #include "RNA_access.h"
27 #include "RNA_prototypes.h"
28 
30 #include "intern/depsgraph.h"
31 #include "intern/node/deg_node.h"
35 
36 namespace blender::deg {
37 
38 /* ********************************* ID Data ******************************** */
39 
41  public:
42  explicit RNANodeQueryIDData(const ID *id) : id_(id)
43  {
44  }
45 
47  {
49  }
50 
52  {
54  return constraint_to_pchan_map_->lookup_default(constraint, nullptr);
55  }
56 
58  {
59  if (constraint_to_pchan_map_ != nullptr) {
60  return;
61  }
62  BLI_assert(GS(id_->name) == ID_OB);
63  const Object *object = reinterpret_cast<const Object *>(id_);
65  if (object->pose != nullptr) {
66  LISTBASE_FOREACH (const bPoseChannel *, pchan, &object->pose->chanbase) {
67  LISTBASE_FOREACH (const bConstraint *, constraint, &pchan->constraints) {
68  constraint_to_pchan_map_->add_new(constraint, pchan);
69  }
70  }
71  }
72  }
73 
74  protected:
75  /* ID this data corresponds to. */
76  const ID *id_;
77 
78  /* indexed by bConstraint*, returns pose channel which contains that
79  * constraint. */
81 };
82 
83 /* ***************************** Node Identifier **************************** */
84 
86  : id(nullptr),
88  component_name(""),
89  operation_code(OperationCode::OPERATION),
90  operation_name(),
91  operation_name_tag(-1)
92 {
93 }
94 
96 {
97  return id != nullptr && type != NodeType::UNDEFINED;
98 }
99 
100 /* ********************************** Query ********************************* */
101 
103  : depsgraph_(depsgraph), builder_(builder)
104 {
105 }
106 
107 RNANodeQuery::~RNANodeQuery() = default;
108 
110  const PropertyRNA *prop,
111  RNAPointerSource source)
112 {
113  const RNANodeIdentifier node_identifier = construct_node_identifier(ptr, prop, source);
114  if (!node_identifier.is_valid()) {
115  return nullptr;
116  }
117  IDNode *id_node = depsgraph_->find_id_node(node_identifier.id);
118  if (id_node == nullptr) {
119  return nullptr;
120  }
121  ComponentNode *comp_node = id_node->find_component(node_identifier.type,
122  node_identifier.component_name);
123  if (comp_node == nullptr) {
124  return nullptr;
125  }
126  if (node_identifier.operation_code == OperationCode::OPERATION) {
127  return comp_node;
128  }
129  return comp_node->find_operation(node_identifier.operation_code,
130  node_identifier.operation_name,
131  node_identifier.operation_name_tag);
132 }
133 
134 bool RNANodeQuery::contains(const char *prop_identifier, const char *rna_path_component)
135 {
136  const char *substr = strstr(prop_identifier, rna_path_component);
137  if (substr == nullptr) {
138  return false;
139  }
140 
141  /* If substr != prop_identifier, it means that the substring is found further in prop_identifier,
142  * and that thus index -1 is a valid memory location. */
143  const bool start_ok = substr == prop_identifier || substr[-1] == '.';
144  if (!start_ok) {
145  return false;
146  }
147 
148  const size_t component_len = strlen(rna_path_component);
149  const bool end_ok = ELEM(substr[component_len], '\0', '.', '[');
150  return end_ok;
151 }
152 
154  const PropertyRNA *prop,
155  RNAPointerSource source)
156 {
157  RNANodeIdentifier node_identifier;
158  if (ptr->type == nullptr) {
159  return node_identifier;
160  }
161  /* Set default values for returns. */
162  node_identifier.id = ptr->owner_id;
163  node_identifier.component_name = "";
164  node_identifier.operation_code = OperationCode::OPERATION;
165  node_identifier.operation_name = "";
166  node_identifier.operation_name_tag = -1;
167  /* Handling of commonly known scenarios. */
169  /* Custom properties of bones are placed in their components to improve granularity. */
170  if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
171  const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr->data);
172  node_identifier.type = NodeType::BONE;
173  node_identifier.component_name = pchan->name;
174  }
175  else {
176  node_identifier.type = NodeType::PARAMETERS;
177  }
178  node_identifier.operation_code = OperationCode::ID_PROPERTY;
179  node_identifier.operation_name = RNA_property_identifier(
180  reinterpret_cast<const PropertyRNA *>(prop));
181  return node_identifier;
182  }
183  if (ptr->type == &RNA_PoseBone) {
184  const bPoseChannel *pchan = static_cast<const bPoseChannel *>(ptr->data);
185  /* Bone - generally, we just want the bone component. */
186  node_identifier.type = NodeType::BONE;
187  node_identifier.component_name = pchan->name;
188  /* However check property name for special handling. */
189  if (prop != nullptr) {
190  Object *object = reinterpret_cast<Object *>(node_identifier.id);
191  const char *prop_name = RNA_property_identifier(prop);
192  /* B-Bone properties should connect to the final operation. */
193  if (STRPREFIX(prop_name, "bbone_")) {
194  if (builder_->check_pchan_has_bbone_segments(object, pchan)) {
196  }
197  else {
198  node_identifier.operation_code = OperationCode::BONE_DONE;
199  }
200  }
201  /* Final transform properties go to the Done node for the exit. */
202  else if (STR_ELEM(prop_name, "head", "tail", "length") || STRPREFIX(prop_name, "matrix")) {
203  if (source == RNAPointerSource::EXIT) {
204  node_identifier.operation_code = OperationCode::BONE_DONE;
205  }
206  }
207  /* And other properties can always go to the entry operation. */
208  else {
209  node_identifier.operation_code = OperationCode::BONE_LOCAL;
210  }
211  }
212  return node_identifier;
213  }
214  if (ptr->type == &RNA_Bone) {
215  /* Armature-level bone mapped to Armature Eval, and thus Pose Init.
216  * Drivers have special code elsewhere that links them to the pose
217  * bone components, instead of using this generic code. */
218  node_identifier.type = NodeType::ARMATURE;
220  /* If trying to look up via an Object, e.g. due to lookup via
221  * obj.pose.bones[].bone in a driver attached to the Object,
222  * redirect to its data. */
223  if (GS(node_identifier.id->name) == ID_OB) {
224  node_identifier.id = (ID *)((Object *)node_identifier.id)->data;
225  }
226  return node_identifier;
227  }
228  if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
229  const Object *object = reinterpret_cast<const Object *>(ptr->owner_id);
230  const bConstraint *constraint = static_cast<const bConstraint *>(ptr->data);
231  RNANodeQueryIDData *id_data = ensure_id_data(&object->id);
232  /* Check whether is object or bone constraint. */
233  /* NOTE: Currently none of the area can address transform of an object
234  * at a given constraint, but for rigging one might use constraint
235  * influence to be used to drive some corrective shape keys or so. */
236  const bPoseChannel *pchan = id_data->get_pchan_for_constraint(constraint);
237  if (pchan == nullptr) {
238  node_identifier.type = NodeType::TRANSFORM;
240  }
241  else {
242  node_identifier.type = NodeType::BONE;
243  node_identifier.operation_code = OperationCode::BONE_LOCAL;
244  node_identifier.component_name = pchan->name;
245  }
246  return node_identifier;
247  }
248  if (ELEM(ptr->type, &RNA_ConstraintTarget, &RNA_ConstraintTargetBone)) {
249  Object *object = reinterpret_cast<Object *>(ptr->owner_id);
251  /* Check whether is object or bone constraint. */
252  bPoseChannel *pchan = nullptr;
253  bConstraint *con = BKE_constraint_find_from_target(object, tgt, &pchan);
254  if (con != nullptr) {
255  if (pchan != nullptr) {
256  node_identifier.type = NodeType::BONE;
257  node_identifier.operation_code = OperationCode::BONE_LOCAL;
258  node_identifier.component_name = pchan->name;
259  }
260  else {
261  node_identifier.type = NodeType::TRANSFORM;
263  }
264  return node_identifier;
265  }
266  }
267  else if (RNA_struct_is_a(ptr->type, &RNA_Mesh) || RNA_struct_is_a(ptr->type, &RNA_Modifier) ||
268  RNA_struct_is_a(ptr->type, &RNA_GpencilModifier) ||
269  RNA_struct_is_a(ptr->type, &RNA_Spline) || RNA_struct_is_a(ptr->type, &RNA_TextBox) ||
270  RNA_struct_is_a(ptr->type, &RNA_GPencilLayer) ||
271  RNA_struct_is_a(ptr->type, &RNA_LatticePoint) ||
272  RNA_struct_is_a(ptr->type, &RNA_MeshUVLoop) ||
273  RNA_struct_is_a(ptr->type, &RNA_MeshLoopColor) ||
274  RNA_struct_is_a(ptr->type, &RNA_VertexGroupElement) ||
275  RNA_struct_is_a(ptr->type, &RNA_ShaderFx)) {
276  /* When modifier is used as FROM operation this is likely referencing to
277  * the property (for example, modifier's influence).
278  * But when it's used as TO operation, this is geometry component. */
279  switch (source) {
281  node_identifier.type = NodeType::GEOMETRY;
282  break;
284  node_identifier.type = NodeType::PARAMETERS;
286  break;
287  }
288  return node_identifier;
289  }
290  else if (ptr->type == &RNA_Object) {
291  /* Transforms props? */
292  if (prop != nullptr) {
293  const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
294  /* TODO(sergey): How to optimize this? */
295  if (contains(prop_identifier, "location") || contains(prop_identifier, "matrix_basis") ||
296  contains(prop_identifier, "matrix_channel") ||
297  contains(prop_identifier, "matrix_inverse") ||
298  contains(prop_identifier, "matrix_local") ||
299  contains(prop_identifier, "matrix_parent_inverse") ||
300  contains(prop_identifier, "matrix_world") ||
301  contains(prop_identifier, "rotation_axis_angle") ||
302  contains(prop_identifier, "rotation_euler") ||
303  contains(prop_identifier, "rotation_mode") ||
304  contains(prop_identifier, "rotation_quaternion") || contains(prop_identifier, "scale") ||
305  contains(prop_identifier, "delta_location") ||
306  contains(prop_identifier, "delta_rotation_euler") ||
307  contains(prop_identifier, "delta_rotation_quaternion") ||
308  contains(prop_identifier, "delta_scale")) {
309  node_identifier.type = NodeType::TRANSFORM;
310  return node_identifier;
311  }
312  if (contains(prop_identifier, "data")) {
313  /* We access object.data, most likely a geometry.
314  * Might be a bone tho. */
315  node_identifier.type = NodeType::GEOMETRY;
316  return node_identifier;
317  }
318  if (STR_ELEM(prop_identifier, "hide_viewport", "hide_render")) {
319  node_identifier.type = NodeType::OBJECT_FROM_LAYER;
320  return node_identifier;
321  }
322  if (STREQ(prop_identifier, "dimensions")) {
323  node_identifier.type = NodeType::PARAMETERS;
324  node_identifier.operation_code = OperationCode::DIMENSIONS;
325  return node_identifier;
326  }
327  }
328  }
329  else if (ptr->type == &RNA_ShapeKey) {
330  KeyBlock *key_block = static_cast<KeyBlock *>(ptr->data);
331  node_identifier.id = ptr->owner_id;
332  node_identifier.type = NodeType::PARAMETERS;
334  node_identifier.operation_name = key_block->name;
335  return node_identifier;
336  }
337  else if (ptr->type == &RNA_Key) {
338  node_identifier.id = ptr->owner_id;
339  node_identifier.type = NodeType::GEOMETRY;
340  return node_identifier;
341  }
342  else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
343  /* Sequencer strip */
344  node_identifier.type = NodeType::SEQUENCER;
345  return node_identifier;
346  }
347  else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {
348  node_identifier.type = NodeType::NTREE_OUTPUT;
349  return node_identifier;
350  }
351  else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) {
352  node_identifier.type = NodeType::SHADING;
353  return node_identifier;
354  }
355  else if (ELEM(ptr->type, &RNA_Curve, &RNA_TextCurve)) {
356  node_identifier.id = ptr->owner_id;
357  node_identifier.type = NodeType::GEOMETRY;
358  return node_identifier;
359  }
360  else if (ELEM(ptr->type, &RNA_BezierSplinePoint, &RNA_SplinePoint)) {
361  node_identifier.id = ptr->owner_id;
362  node_identifier.type = NodeType::GEOMETRY;
363  return node_identifier;
364  }
365  else if (RNA_struct_is_a(ptr->type, &RNA_ImageUser)) {
366  if (GS(node_identifier.id->name) == ID_NT) {
367  node_identifier.type = NodeType::IMAGE_ANIMATION;
369  return node_identifier;
370  }
371  }
372  else if (ELEM(ptr->type, &RNA_MeshVertex, &RNA_MeshEdge, &RNA_MeshLoop, &RNA_MeshPolygon)) {
373  node_identifier.type = NodeType::GEOMETRY;
374  return node_identifier;
375  }
376  if (prop != nullptr) {
377  /* All unknown data effectively falls under "parameter evaluation". */
378  node_identifier.type = NodeType::PARAMETERS;
380  node_identifier.operation_name = "";
381  node_identifier.operation_name_tag = -1;
382  return node_identifier;
383  }
384  return node_identifier;
385 }
386 
388 {
389  unique_ptr<RNANodeQueryIDData> &id_data = id_data_map_.lookup_or_add_cb(
390  id, [&]() { return std::make_unique<RNANodeQueryIDData>(id); });
391  return id_data.get();
392 }
393 
395 {
396  return prop != nullptr && RNA_property_is_idprop(prop) &&
397  /* ID properties in the geometry nodes modifier don't affect that parameters node.
398  * Instead they affect the modifier and therefore the geometry node directly. */
399  !RNA_struct_is_a(ptr->type, &RNA_NodesModifier);
400 }
401 
402 } // namespace blender::deg
struct bConstraint * BKE_constraint_find_from_target(struct Object *ob, struct bConstraintTarget *tgt, struct bPoseChannel **r_pchan)
Definition: constraint.c:6052
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define STR_ELEM(...)
Definition: BLI_string.h:539
#define STRPREFIX(a, b)
#define ELEM(...)
#define STREQ(a, b)
@ ID_NT
Definition: DNA_ID_enums.h:68
@ ID_OB
Definition: DNA_ID_enums.h:47
Object is a sort of wrapper for general info.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
Value lookup_default(const Key &key, const Value &default_value) const
Definition: BLI_map.hh:510
void add_new(const Key &key, const Value &value)
Definition: BLI_map.hh:220
virtual bool check_pchan_has_bbone_segments(const Object *object, const bPoseChannel *pchan)
Definition: deg_builder.cc:118
const bPoseChannel * get_pchan_for_constraint(const bConstraint *constraint)
Map< const bConstraint *, const bPoseChannel * > * constraint_to_pchan_map_
Node * find_node(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source)
RNANodeIdentifier construct_node_identifier(const PointerRNA *ptr, const PropertyRNA *prop, RNAPointerSource source)
static bool contains(const char *prop_identifier, const char *rna_path_component)
DepsgraphBuilder * builder_
RNANodeQuery(Depsgraph *depsgraph, DepsgraphBuilder *builder)
RNANodeQueryIDData * ensure_id_data(const ID *id)
Map< const ID *, unique_ptr< RNANodeQueryIDData > > id_data_map_
const IDNode * id_node
const Depsgraph * depsgraph
#define GS(x)
Definition: iris.c:225
bool rna_prop_affects_parameters_node(const PointerRNA *ptr, const PropertyRNA *prop)
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
Definition: rna_access.c:695
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
bool RNA_property_is_idprop(const PropertyRNA *prop)
Definition: rna_access.c:5322
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
char name[64]
Definition: DNA_key_types.h:52
struct bPose * pose
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
struct ID * owner_id
Definition: RNA_types.h:36
ListBase chanbase
OperationNode * find_operation(OperationIDKey key) const
IDNode * find_id_node(const ID *id) const
Definition: depsgraph.cc:101
PointerRNA * ptr
Definition: wm_files.c:3480