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