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