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