Blender V4.3
rna_access_compare_override.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstring>
10#include <fmt/format.h>
11#include <optional>
12
13#include <CLG_log.h>
14
15#include "MEM_guardedalloc.h"
16
17#include "DNA_ID.h"
18#include "DNA_anim_types.h"
19#include "DNA_camera_types.h"
22#include "DNA_key_types.h"
23#include "DNA_modifier_types.h"
24#include "DNA_object_types.h"
25
26#include "BLI_listbase.h"
27#include "BLI_string.h"
28#include "BLI_utildefines.h"
29
30// #define DEBUG_OVERRIDE_TIMEIT
31
32#ifdef DEBUG_OVERRIDE_TIMEIT
33# include "BLI_time_utildefines.h"
34# include <stdio.h>
35#endif
36
37#include "BKE_armature.hh"
38#include "BKE_idprop.hh"
39#include "BKE_idtype.hh"
40#include "BKE_lib_override.hh"
41#include "BKE_main.hh"
42
43#include "RNA_access.hh"
44#include "RNA_define.hh"
45#include "RNA_enum_types.hh"
46#include "RNA_path.hh"
47#include "RNA_prototypes.hh"
48
50#include "rna_internal.hh"
51
52static CLG_LogRef LOG = {"rna.access_compare_override"};
53
64 PropertyRNA *prop,
65 std::optional<std::string> *r_rna_path)
66{
67 ID *id = ptr->owner_id;
68 ID *owner_id = id;
69 const char *rna_path_prefix = nullptr;
70
71 if (r_rna_path != nullptr) {
72 *r_rna_path = std::nullopt;
73 }
74
75 if (id == nullptr) {
76 return nullptr;
77 }
78
80 /* XXX this is very bad band-aid code, but for now it will do.
81 * We should at least use a #define for those prop names.
82 * Ideally RNA as a whole should be aware of those PITA of embedded IDs, and have a way to
83 * retrieve their owner IDs and generate paths from those.
84 */
85
86 switch (GS(id->name)) {
87 case ID_KE:
88 owner_id = ((Key *)id)->from;
89 rna_path_prefix = "shape_keys.";
90 break;
91 case ID_GR:
92 case ID_NT:
93 /* Master collections, Root node trees. */
94 owner_id = RNA_find_real_ID_and_path(id, &rna_path_prefix);
95 break;
96 default:
98 }
99 }
100
101 if (r_rna_path == nullptr) {
102 return owner_id;
103 }
104
105 if (std::optional<std::string> rna_path = RNA_path_from_ID_to_property(ptr, prop)) {
106 if (rna_path_prefix) {
107 r_rna_path->emplace(fmt::format("{}{}", rna_path_prefix, *rna_path));
108 }
109 else {
110 r_rna_path->emplace(std::move(*rna_path));
111 }
112
113 return owner_id;
114 }
115 return nullptr;
116}
117
122
124{
125 if (prop->magic == RNA_MAGIC) {
126 /* Special handling for insertions of constraints or modifiers... */
127 /* TODO: Note We may want to add a more generic system to RNA
128 * (like a special property in struct of items)
129 * if we get more overridable collections,
130 * for now we can live with those special-cases handling I think. */
131 if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
132 bConstraint *con = static_cast<bConstraint *>(ptr->data);
134 return true;
135 }
136 }
137 else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
138 ModifierData *mod = static_cast<ModifierData *>(ptr->data);
140 return true;
141 }
142 }
143 else if (RNA_struct_is_a(ptr->type, &RNA_NlaTrack)) {
144 NlaTrack *nla_track = static_cast<NlaTrack *>(ptr->data);
145 if (nla_track->flag & NLATRACK_OVERRIDELIBRARY_LOCAL) {
146 return true;
147 }
148 }
149 else if (RNA_struct_is_a(ptr->type, &RNA_CameraBackgroundImage)) {
150 CameraBGImage *bgpic = static_cast<CameraBGImage *>(ptr->data);
152 return true;
153 }
154 }
155 else if (RNA_struct_is_a(ptr->type, &RNA_BoneCollection)) {
156 BoneCollection *bcoll = static_cast<BoneCollection *>(ptr->data);
158 return true;
159 }
160 }
161 /* If this is a RNA-defined property (real or 'virtual' IDProp),
162 * we want to use RNA prop flag. */
163 return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
165 }
166 /* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
167 IDProperty *idprop = (IDProperty *)prop;
168 return (idprop->flag & IDP_FLAG_OVERRIDABLE_LIBRARY) != 0;
169}
170
172 PropertyRNA *prop,
173 const bool is_overridable)
174{
175 /* Only works for pure custom properties IDProps. */
176 if (prop->magic != RNA_MAGIC) {
177 IDProperty *idprop = (IDProperty *)prop;
178 constexpr short flags = (IDP_FLAG_OVERRIDABLE_LIBRARY | IDP_FLAG_STATIC_TYPE);
179 idprop->flag = is_overridable ? (idprop->flag | flags) : (idprop->flag & ~flags);
180 return true;
181 }
182
183 return false;
184}
185
187{
188 const std::optional<std::string> rna_path = RNA_path_from_ID_to_property(ptr, prop);
189 ID *id = ptr->owner_id;
190
191 if (!rna_path || id == nullptr || !ID_IS_OVERRIDE_LIBRARY(id)) {
192 return false;
193 }
194
195 return (BKE_lib_override_library_property_find(id->override_library, rna_path->c_str()) !=
196 nullptr);
197}
198
200{
201 prop = rna_ensure_property(prop);
202
204}
205
207 RNAPropertyOverrideApplyContext &rnaapply_ctx);
208
210 Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
211{
212 if (!RNA_property_editable(ptr, prop)) {
213 return false;
214 }
215
218 opop.subitem_reference_index = index;
219 opop.subitem_local_index = index;
220
222 rnaapply_ctx.ptr_dst = *ptr;
223 rnaapply_ctx.ptr_src = *fromptr;
224 rnaapply_ctx.prop_dst = prop;
225 rnaapply_ctx.prop_src = prop;
226 rnaapply_ctx.liboverride_operation = &opop;
227
228 return rna_property_override_operation_apply(bmain, rnaapply_ctx);
229}
230
231static int rna_property_override_diff(Main *bmain,
232 PropertyRNAOrID *prop_a,
233 PropertyRNAOrID *prop_b,
234 const char *rna_path,
235 const size_t rna_path_len,
236 eRNACompareMode mode,
237 IDOverrideLibrary *liboverride,
238 const eRNAOverrideMatch flags,
239 eRNAOverrideMatchResult *r_report_flags);
240
242 Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
243{
245
246 PropertyRNAOrID prop_a, prop_b;
247
248 rna_property_rna_or_id_get(prop, ptr_a, &prop_a);
249 rna_property_rna_or_id_get(prop, ptr_b, &prop_b);
250
252 bmain, &prop_a, &prop_b, nullptr, 0, mode, nullptr, eRNAOverrideMatch(0), nullptr) ==
253 0);
254}
255
257{
259 PropertyRNA *iterprop;
260 bool equals = true;
261
262 if (ptr_a == nullptr && ptr_b == nullptr) {
263 return true;
264 }
265 if (ptr_a == nullptr || ptr_b == nullptr) {
266 return false;
267 }
268 if (ptr_a->type != ptr_b->type) {
269 return false;
270 }
271
272 iterprop = RNA_struct_iterator_property(ptr_a->type);
273
274 RNA_property_collection_begin(ptr_a, iterprop, &iter);
275 for (; iter.valid; RNA_property_collection_next(&iter)) {
276 PropertyRNA *prop = static_cast<PropertyRNA *>(iter.ptr.data);
277
278 if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, mode)) {
279 equals = false;
280 break;
281 }
282 }
284
285 return equals;
286}
287
288/* Low-level functions, also used by non-override RNA API like copy or equality check. */
289
300 PropertyRNAOrID *prop_a,
301 PropertyRNAOrID *prop_b,
302 const char *rna_path,
303 const size_t rna_path_len,
304 eRNACompareMode mode,
305 IDOverrideLibrary *liboverride,
306 const eRNAOverrideMatch flags,
307 eRNAOverrideMatchResult *r_report_flags)
308{
309 BLI_assert(!ELEM(nullptr, prop_a, prop_b));
310
313 {
314 return 0;
315 }
316
317 if (mode == RNA_EQ_UNSET_MATCH_ANY) {
318 /* Unset properties are assumed to match anything. */
319 if (!prop_a->is_set || !prop_b->is_set) {
320 return 0;
321 }
322 }
323 else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
324 /* Unset properties never match set properties. */
325 if (prop_a->is_set != prop_b->is_set) {
326 return 1;
327 }
328 }
329
330 if (prop_a->is_idprop && ELEM(nullptr, prop_a->idprop, prop_b->idprop)) {
331 return (prop_a->idprop == prop_b->idprop) ? 0 : 1;
332 }
333
334 /* Check if we are working with arrays. */
335 const bool is_array_a = prop_a->is_array;
336 const bool is_array_b = prop_b->is_array;
337
338 if (is_array_a != is_array_b) {
339 /* Should probably never happen actually... */
341 return is_array_a ? 1 : -1;
342 }
343
344 /* Get the length of the array to work with. */
345 const uint len_a = prop_a->array_len;
346 const uint len_b = prop_b->array_len;
347
348 if (len_a != len_b) {
349 /* Do not handle override in that case,
350 * we do not support insertion/deletion from arrays for now. */
351 return len_a > len_b ? 1 : -1;
352 }
353
354 if (is_array_a && len_a == 0) {
355 /* Empty arrays, will happen in some case with dynamic ones. */
356 return 0;
357 }
358
359 RNAPropOverrideDiff override_diff = nullptr;
360 /* Special case for IDProps, we use default callback then. */
361 if (prop_a->is_idprop) {
363 if (!prop_b->is_idprop && prop_b->rnaprop->override_diff != override_diff) {
364 override_diff = nullptr;
365 }
366 }
367 else if (prop_b->is_idprop) {
369 if (prop_a->rnaprop->override_diff != override_diff) {
370 override_diff = nullptr;
371 }
372 }
373 else if (prop_a->rnaprop->override_diff == prop_b->rnaprop->override_diff) {
374 override_diff = prop_a->rnaprop->override_diff;
375 if (override_diff == nullptr) {
377 }
378 }
379
380 if (override_diff == nullptr) {
382 &LOG,
383 "'%s' gives unmatching or nullptr RNA diff callbacks, should not happen (%d vs. %d)",
384 rna_path ? rna_path : prop_a->identifier,
385 !prop_a->is_idprop,
386 !prop_b->is_idprop);
388 return 1;
389 }
390
391 eRNAOverrideMatch diff_flags = flags;
392 if (!RNA_property_overridable_get(&prop_a->ptr, prop_a->rawprop) ||
394 !RNA_property_editable_flag(&prop_a->ptr, prop_a->rawprop)))
395 {
396 diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
397 }
398
400 rnadiff_ctx.prop_a = prop_a;
401 rnadiff_ctx.prop_b = prop_b;
402 rnadiff_ctx.mode = mode;
403
404 rnadiff_ctx.liboverride = liboverride;
405 rnadiff_ctx.rna_path = rna_path;
406 rnadiff_ctx.rna_path_len = rna_path_len;
407 rnadiff_ctx.liboverride_flags = diff_flags;
408 override_diff(bmain, rnadiff_ctx);
409
410 if (r_report_flags) {
411 *r_report_flags = rnadiff_ctx.report_flag;
412 }
413 return rnadiff_ctx.comparison;
414}
415
416/* Modify local data-block to make it ready for override application
417 * (only needed for diff operations, where we use
418 * the local data-block's data as second operand). */
420 PointerRNA *ptr_local,
421 PointerRNA *ptr_reference,
422 PointerRNA *ptr_storage,
423 PropertyRNA *prop_local,
424 PropertyRNA *prop_reference,
425 PropertyRNA *prop_storage,
427{
428 int len_local, len_reference, len_storage = 0;
429 bool changed = false;
430
431 if (ptr_storage == nullptr) {
432 return changed;
433 }
434
435 /* get the length of the array to work with */
436 len_local = RNA_property_array_length(ptr_local, prop_local);
437 len_reference = RNA_property_array_length(ptr_reference, prop_reference);
438 if (prop_storage) {
439 len_storage = RNA_property_array_length(ptr_storage, prop_storage);
440 }
441
442 if (len_local != len_reference || len_local != len_storage) {
443 /* Do not handle override in that case,
444 * we do not support insertion/deletion from arrays for now. */
445 return changed;
446 }
447
448 RNAPropOverrideStore override_store = nullptr;
449 /* Special case for IDProps, we use default callback then. */
450 if (prop_local->magic != RNA_MAGIC) {
452 if (prop_reference->magic == RNA_MAGIC && prop_reference->override_store != override_store) {
453 override_store = nullptr;
454 }
455 }
456 else if (prop_reference->magic != RNA_MAGIC) {
458 if (prop_local->override_store != override_store) {
459 override_store = nullptr;
460 }
461 }
462 else if (prop_local->override_store == prop_reference->override_store) {
463 override_store = prop_local->override_store;
464 if (override_store == nullptr) {
466 }
467 }
468
469 if ((prop_storage->magic == RNA_MAGIC) &&
470 !ELEM(prop_storage->override_store, nullptr, override_store))
471 {
472 override_store = nullptr;
473 }
474
475 if (override_store == nullptr) {
477 &LOG,
478 "'%s' gives unmatching or nullptr RNA store callbacks, should not happen (%d vs. %d)",
479 op->rna_path,
480 prop_local->magic == RNA_MAGIC,
481 prop_reference->magic == RNA_MAGIC);
483 return changed;
484 }
485
487 /* Only needed for diff operations. */
488 if (!ELEM(
490 {
491 continue;
492 }
493
494 if (override_store(bmain,
495 ptr_local,
496 ptr_reference,
497 ptr_storage,
498 prop_local,
499 prop_reference,
500 prop_storage,
501 len_local,
502 len_reference,
503 len_storage,
504 opop))
505 {
506 changed = true;
507 }
508 }
509
510 return changed;
511}
512
515{
516 PointerRNA *ptr_dst = &rnaapply_ctx.ptr_dst;
517 PointerRNA *ptr_src = &rnaapply_ctx.ptr_src;
518 PointerRNA *ptr_storage = &rnaapply_ctx.ptr_storage;
519 PropertyRNA *prop_dst = rnaapply_ctx.prop_dst;
520 PropertyRNA *prop_src = rnaapply_ctx.prop_src;
521 PropertyRNA *prop_storage = rnaapply_ctx.prop_storage;
523
524 const short override_op = opop->operation;
525
527 opop, ptr_dst, ptr_src, ptr_storage, prop_dst, prop_src, prop_storage))
528 {
529 return false;
530 }
531
532 if (override_op == LIBOVERRIDE_OP_NOOP) {
533 return true;
534 }
535
536 RNAPropOverrideApply override_apply = nullptr;
537 /* Special case for IDProps, we use default callback then. */
538 if (prop_dst->magic != RNA_MAGIC) {
540 if (prop_src->magic == RNA_MAGIC && !ELEM(prop_src->override_apply, nullptr, override_apply)) {
541 override_apply = nullptr;
542 }
543 }
544 else if (prop_src->magic != RNA_MAGIC) {
546 if (!ELEM(prop_dst->override_apply, nullptr, override_apply)) {
547 override_apply = nullptr;
548 }
549 }
550 else if (prop_dst->override_apply == prop_src->override_apply) {
551 override_apply = prop_dst->override_apply;
552 if (override_apply == nullptr) {
554 }
555 }
556
557 if (prop_storage && prop_storage->magic == RNA_MAGIC &&
558 !ELEM(prop_storage->override_apply, nullptr, override_apply))
559 {
560 override_apply = nullptr;
561 }
562
563 if (override_apply == nullptr) {
565 &LOG,
566 "'%s' gives unmatching or nullptr RNA apply callbacks, should not happen (%d vs. %d)",
567 prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier,
568 prop_dst->magic == RNA_MAGIC,
569 prop_src->magic == RNA_MAGIC);
571 return false;
572 }
573
574 /* get the length of the array to work with */
575 rnaapply_ctx.len_dst = RNA_property_array_length(ptr_dst, prop_dst);
576 rnaapply_ctx.len_src = RNA_property_array_length(ptr_src, prop_src);
577 if (prop_storage) {
578 rnaapply_ctx.len_storage = RNA_property_array_length(ptr_storage, prop_storage);
579 }
580
581 if (rnaapply_ctx.len_dst != rnaapply_ctx.len_src ||
582 (prop_storage && rnaapply_ctx.len_dst != rnaapply_ctx.len_storage))
583 {
584 /* Do not handle override in that case,
585 * we do not support insertion/deletion from arrays for now. */
586 return false;
587 }
588
589 /* get and set the default values as appropriate for the various types */
590 const bool success = override_apply(bmain, rnaapply_ctx);
591 return success;
592}
593
595 PointerRNA *ptr_local,
596 PointerRNA *ptr_reference,
597 const char *root_path,
598 const size_t root_path_len,
599 IDOverrideLibrary *liboverride,
600 const eRNAOverrideMatch flags,
601 eRNAOverrideMatchResult *r_report_flags)
602{
604 PropertyRNA *iterprop;
605 bool matching = true;
606
607 BLI_assert(ptr_local->type == ptr_reference->type);
608 BLI_assert(ptr_local->owner_id && ptr_reference->owner_id);
609
610 const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0;
611 const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
612 const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
613 const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
614 const bool do_tag_for_restore = (flags & RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE) != 0;
615
616#ifdef DEBUG_OVERRIDE_TIMEIT
617 static float _sum_time_global = 0.0f;
618 static float _num_time_global = 0.0f;
619 double _timeit_time_global;
620 static float _sum_time_diffing = 0.0f;
621 static float _delta_time_diffing = 0.0f;
622 static int _num_delta_time_diffing = 0.0f;
623 static float _num_time_diffing = 0.0f;
624 double _timeit_time_diffing;
625
626 if (!root_path) {
627 _delta_time_diffing = 0.0f;
628 _num_delta_time_diffing = 0;
629 _timeit_time_global = BLI_time_now_seconds();
630 }
631#endif
632
633 if (ptr_local->owner_id == ptr_local->data && GS(ptr_local->owner_id->name) == ID_OB) {
634 /* Our beloved pose's bone cross-data pointers. Usually, depsgraph evaluation would
635 * ensure this is valid, but in some situations (like hidden collections etc.) this won't
636 * be the case, so we need to take care of this ourselves.
637 *
638 * NOTE: Typically callers of this function (from BKE_lib_override area) will already have
639 * ensured this. However, studio is still reporting sporadic, unreproducible crashes due to
640 * invalid pose data, so think there are still some cases where some armatures are somehow
641 * missing updates (possibly due to dependencies?). Since calling this function on same ID
642 * several time is almost free, and safe even in a threaded context as long as it has been done
643 * at least once first outside of threaded processing, we do it another time here. */
644 Object *ob_local = (Object *)ptr_local->owner_id;
645 if (ob_local->type == OB_ARMATURE) {
646 Object *ob_reference = (Object *)ptr_local->owner_id->override_library->reference;
647 BLI_assert(ob_local->data != nullptr);
648 BLI_assert(ob_reference->data != nullptr);
649 BKE_pose_ensure(bmain, ob_local, static_cast<bArmature *>(ob_local->data), true);
650 BKE_pose_ensure(bmain, ob_reference, static_cast<bArmature *>(ob_reference->data), true);
651 }
652 }
653
654 iterprop = RNA_struct_iterator_property(ptr_local->type);
655
656 for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid;
658 {
659 PropertyRNA *rawprop = static_cast<PropertyRNA *>(iter.ptr.data);
660
661 PropertyRNAOrID prop_local;
662 PropertyRNAOrID prop_reference;
663
664 rna_property_rna_or_id_get(rawprop, ptr_local, &prop_local);
665 rna_property_rna_or_id_get(rawprop, ptr_reference, &prop_reference);
666
667 BLI_assert(prop_local.rnaprop != nullptr);
668 BLI_assert(prop_local.rnaprop == prop_reference.rnaprop);
669 BLI_assert(prop_local.is_idprop == prop_reference.is_idprop);
670
671 if ((prop_local.is_idprop && prop_local.idprop == nullptr) ||
672 (prop_reference.is_idprop && prop_reference.idprop == nullptr))
673 {
674 continue;
675 }
676
677 if (ignore_non_overridable && !RNA_property_overridable_get(&prop_local.ptr, rawprop)) {
678 continue;
679 }
680
681 if (!prop_local.is_idprop &&
683 {
684 continue;
685 }
686
687#if 0
688 /* This actually makes things slower, since it has to check for animation paths etc! */
689 if (RNA_property_animated(ptr_local, prop_local)) {
690 /* We cannot do anything here really, animation is some kind of dynamic overrides that has
691 * precedence over static one... */
692 continue;
693 }
694#endif
695
696#define RNA_PATH_BUFFSIZE 8192
697
698 std::optional<std::string> rna_path;
699 size_t rna_path_len = 0;
700
701 /* XXX TODO: this will have to be refined to handle collections insertions, and array items. */
702 if (root_path) {
703 BLI_assert(strlen(root_path) == root_path_len);
704
705 const char *prop_name = prop_local.identifier;
706 const size_t prop_name_len = strlen(prop_name);
707
708 char rna_path_buffer[RNA_PATH_BUFFSIZE];
709 char *rna_path_c = rna_path_buffer;
710
711 /* Inlined building (significantly more efficient). */
712 if (!prop_local.is_idprop) {
713 rna_path_len = root_path_len + 1 + prop_name_len;
714 if (rna_path_len >= RNA_PATH_BUFFSIZE) {
715 rna_path = static_cast<char *>(MEM_mallocN(rna_path_len + 1, __func__));
716 }
717
718 memcpy(rna_path_c, root_path, root_path_len);
719 rna_path_c[root_path_len] = '.';
720 memcpy(rna_path_c + root_path_len + 1, prop_name, prop_name_len);
721 rna_path_c[rna_path_len] = '\0';
722 }
723 else {
724 rna_path_len = root_path_len + 2 + prop_name_len + 2;
725 if (rna_path_len >= RNA_PATH_BUFFSIZE) {
726 rna_path_c = static_cast<char *>(MEM_mallocN(rna_path_len + 1, __func__));
727 }
728
729 memcpy(rna_path_c, root_path, root_path_len);
730 rna_path_c[root_path_len] = '[';
731 rna_path_c[root_path_len + 1] = '"';
732 memcpy(rna_path_c + root_path_len + 2, prop_name, prop_name_len);
733 rna_path_c[root_path_len + 2 + prop_name_len] = '"';
734 rna_path_c[root_path_len + 2 + prop_name_len + 1] = ']';
735 rna_path_c[rna_path_len] = '\0';
736 }
737
738 rna_path.emplace(rna_path_c);
739 }
740 else {
741 /* This is rather slow, but is not much called, so not really worth optimizing. */
742 rna_path = RNA_path_from_ID_to_property(ptr_local, rawprop);
743 if (rna_path) {
744 rna_path_len = rna_path->size();
745 }
746 }
747 if (!rna_path) {
748 continue;
749 }
750
751 CLOG_INFO(&LOG, 5, "Override Checking %s", rna_path->c_str());
752
753 if (ignore_overridden) {
755 rna_path->c_str());
756 if (op != nullptr) {
758 continue;
759 }
760 }
761
762#ifdef DEBUG_OVERRIDE_TIMEIT
763 if (!root_path) {
764 _timeit_time_diffing = BLI_time_now_seconds();
765 }
766#endif
767
769 const int diff = rna_property_override_diff(bmain,
770 &prop_local,
771 &prop_reference,
772 rna_path->c_str(),
773 rna_path_len,
775 liboverride,
776 flags,
777 &report_flags);
778
779#ifdef DEBUG_OVERRIDE_TIMEIT
780 if (!root_path) {
781 const float _delta_time = float(BLI_time_now_seconds() - _timeit_time_diffing);
782 _delta_time_diffing += _delta_time;
783 _num_delta_time_diffing++;
784 }
785#endif
786
787 matching = matching && diff == 0;
788 if (r_report_flags) {
789 *r_report_flags = (*r_report_flags | report_flags);
790 }
791
792 if (diff != 0) {
793 /* XXX TODO: refine this for per-item overriding of arrays... */
795 rna_path->c_str());
797 op ? op->operations.first : nullptr);
798
799 if (op != nullptr) {
800 /* Only set all operations from this property as used (via
801 * #BKE_lib_override_library_operations_tag) if the property itself is still tagged as
802 * unused.
803 *
804 * In case the property itself is already tagged as used, in means lower-level diffing code
805 * took care of this property (as is needed for e.g. collections of items, since then some
806 * operations may be valid, while others may need to be purged). */
809 }
810 }
811
812 if ((do_restore || do_tag_for_restore) &&
813 (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0)
814 {
815 /* We are allowed to restore to reference's values. */
816 if (ELEM(nullptr, op, opop) || opop->operation == LIBOVERRIDE_OP_NOOP) {
817 if (RNA_property_editable(ptr_local, rawprop)) {
818 /* This property should be restored to its reference value. This should not be done
819 * here, since this code may be called from non-main thread (modifying data through RNA
820 * is not thread safe). */
821 if (do_restore) {
824 opop_tmp.subitem_reference_index = -1;
825 opop_tmp.subitem_local_index = -1;
826
828 rnaapply_ctx.ptr_dst = *ptr_local;
829 rnaapply_ctx.ptr_src = *ptr_reference;
830 rnaapply_ctx.prop_dst = rawprop;
831 rnaapply_ctx.prop_src = rawprop;
832 rnaapply_ctx.liboverride_operation = &opop_tmp;
833
834 const bool is_restored = rna_property_override_operation_apply(bmain, rnaapply_ctx);
835
836 if (is_restored) {
837 CLOG_INFO(&LOG,
838 5,
839 "Restoreed forbidden liboverride `%s` for override data '%s'",
840 rna_path->c_str(),
841 ptr_local->owner_id->name);
842 if (r_report_flags) {
843 *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
844 }
845 }
846 else {
847 CLOG_INFO(&LOG,
848 2,
849 "Failed to restore forbidden liboverride `%s` for override data '%s'",
850 rna_path->c_str(),
851 ptr_local->owner_id->name);
852 }
853 }
854 else {
855 if (op == nullptr) {
856 /* An override property is needed, create a temp one if necessary. */
858 liboverride, rna_path->c_str(), nullptr);
860 }
864 nullptr,
865 nullptr,
866 {},
867 {},
868 -1,
869 -1,
870 false,
871 nullptr,
872 nullptr);
873 /* Do not use `BKE_lib_override_library_operations_tag` here, as the property may be
874 * a valid one that has other operations that needs to remain (e.g. from a template,
875 * a NOOP operation to enforce no change on that property, etc.). */
877 opop_restore->tag |= LIBOVERRIDE_PROP_TAG_NEEDS_RETORE;
879
880 CLOG_INFO(
881 &LOG,
882 5,
883 "Tagging for restoration forbidden liboverride `%s` for override data '%s'",
884 rna_path->c_str(),
885 ptr_local->owner_id->name);
886 if (r_report_flags) {
888 }
889 }
890 }
891 else {
892 /* Too noisy for now, this triggers on runtime props like transform matrices etc. */
893#if 0
895 "We have differences between reference and "
896 "overriding data on non-editable property.");
897#endif
898 matching = false;
899 }
900 }
901 }
902 else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(nullptr, op, opop))
903 {
904 /* This property is not overridden, and differs from reference, so we have no match. */
905 matching = false;
906 if (!(do_create || do_restore || do_tag_for_restore)) {
907
908 break;
909 }
910 }
911 }
912#undef RNA_PATH_BUFFSIZE
913 }
915
916#ifdef DEBUG_OVERRIDE_TIMEIT
917 if (!root_path) {
918 const float _delta_time = float(BLI_time_now_seconds() - _timeit_time_global);
919 _sum_time_global += _delta_time;
920 _num_time_global++;
921 _sum_time_diffing += _delta_time_diffing;
922 _num_time_diffing++;
923 printf("ID: %s\n", ((ID *)ptr_local->owner_id)->name);
924 printf("time end (%s): %.6f\n", __func__, _delta_time);
925 printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
926 __func__,
927 (_sum_time_global / _num_time_global),
928 _sum_time_global,
929 int(_num_time_global));
930 printf("diffing time end (%s): %.6f (in %d runs)\n",
931 __func__,
932 _delta_time_diffing,
933 _num_delta_time_diffing);
934 printf("diffing time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
935 __func__,
936 (_sum_time_diffing / _num_time_diffing),
937 _sum_time_diffing,
938 int(_num_time_diffing));
939 }
940#endif
941
942 return matching;
943}
944
946 PointerRNA *ptr_local,
947 PointerRNA *ptr_reference,
948 PointerRNA *ptr_storage,
949 IDOverrideLibrary *liboverride)
950{
951 bool changed = false;
952
953#ifdef DEBUG_OVERRIDE_TIMEIT
955#endif
957 /* Simplified for now! */
958 PointerRNA data_reference, data_local;
959 PropertyRNA *prop_reference, *prop_local;
960
961 if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
962 RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference))
963 {
964 PointerRNA data_storage;
965 PropertyRNA *prop_storage = nullptr;
966
967 /* It is totally OK if this does not success,
968 * only a subset of override operations actually need storage. */
969 if (ptr_storage && (ptr_storage->owner_id != nullptr)) {
970 RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
971 }
972
974 &data_local,
975 &data_reference,
976 &data_storage,
977 prop_reference,
978 prop_local,
979 prop_storage,
980 op))
981 {
982 changed = true;
983 }
984 }
985 }
986#ifdef DEBUG_OVERRIDE_TIMEIT
988#endif
989
990 return changed;
991}
992
994 const char *item_name,
995 const int item_name_len,
996 const bool do_id_pointer,
997 const std::optional<ID *> &item_id,
998 PointerRNA *ptr_item_name)
999{
1000 BLI_assert(!do_id_pointer || RNA_struct_is_ID(ptr_item_name->type));
1001
1002 bool is_match = false;
1003
1004 if (do_id_pointer) {
1005 if (*item_id != static_cast<ID *>(ptr_item_name->data)) {
1006 /* If the ID pointer does not match, then there is no match, no need to check the
1007 * name itself. */
1008 return is_match;
1009 }
1010 }
1011
1012 PropertyRNA *nameprop = ptr_item_name->type->nameproperty;
1013 char name_buf[256];
1014 char *name;
1015 int namelen;
1016
1018 ptr_item_name, nameprop, name_buf, sizeof(name_buf), &namelen);
1019
1020 is_match = ((item_name_len == namelen) && STREQ(item_name, name));
1021
1022 if (UNLIKELY(name != name_buf)) {
1023 MEM_freeN(name);
1024 }
1025
1026 return is_match;
1027}
1028
1030 PointerRNA *ptr,
1031 PropertyRNA *prop,
1032 const char *item_name,
1033 const int item_name_len,
1034 const bool do_id_pointer,
1035 const std::optional<ID *> &item_id,
1036 PointerRNA *r_ptr_item_name)
1037{
1038 /* NOTE: This code is very similar to the one from #RNA_property_collection_lookup_string_index,
1039 * but it adds an extra early check on matching ID pointer.
1040 *
1041 * This custom code is needed because otherwise, it is only possible to check the first
1042 * name-matched item found by #RNA_property_collection_lookup_string, and not potential other
1043 * items having the same name. */
1044 if (do_id_pointer) {
1046
1047 /* We cannot use a potential `CollectionPropertyRNA->lookupstring` here. */
1049
1050 RNA_property_collection_begin(ptr, prop, &iter);
1051 for (; iter.valid; RNA_property_collection_next(&iter)) {
1052 if (iter.ptr.data && iter.ptr.type->nameproperty) {
1054 item_name, item_name_len, do_id_pointer, item_id, &iter.ptr))
1055 {
1056 *r_ptr_item_name = iter.ptr;
1057 break;
1058 }
1059 }
1060 }
1062
1063 if (!iter.valid) {
1064 *r_ptr_item_name = {};
1065 }
1066
1067 return iter.valid;
1068 }
1069 else {
1070 return RNA_property_collection_lookup_string(ptr, prop, item_name, r_ptr_item_name);
1071 }
1072}
1073
1075 PointerRNA *ptr,
1076 PropertyRNA *prop,
1077 const char *item_name,
1078 const std::optional<ID *> &item_id,
1079 const int item_index,
1080 PointerRNA *r_ptr_item_name,
1081 PointerRNA *r_ptr_item_index)
1082{
1083 RNA_POINTER_INVALIDATE(r_ptr_item_name);
1084 RNA_POINTER_INVALIDATE(r_ptr_item_index);
1085
1086 const bool do_id_pointer = item_id && RNA_struct_is_ID(RNA_property_pointer_type(ptr, prop));
1087
1088 const int item_name_len = item_name ? int(strlen(item_name)) : 0;
1089
1090 /* First, lookup by index, but only validate if name also matches (or if there is no given name).
1091 *
1092 * Note that this is also beneficial on performances (when looking up in big collections), since
1093 * typically index lookup will be faster than name lookup.
1094 */
1095 if (item_index != -1) {
1096 if (RNA_property_collection_lookup_int(ptr, prop, item_index, r_ptr_item_index)) {
1097 if (item_name && r_ptr_item_index->type) {
1099 item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_index))
1100 {
1101 *r_ptr_item_name = *r_ptr_item_index;
1102 return;
1103 }
1104 }
1105 }
1106 }
1107
1108 if (!item_name) {
1109 return;
1110 }
1111
1112 /* Then, lookup by name (+ id) only. */
1114 ptr, prop, item_name, item_name_len, do_id_pointer, item_id, r_ptr_item_name))
1115 {
1116 RNA_POINTER_INVALIDATE(r_ptr_item_index);
1117 return;
1118 }
1119
1120 /* If name (+ id) lookup failed, `r_ptr_item_name` is invalidated, so if index lookup was
1121 * successful it will be the only valid return value. */
1122}
1123
1125 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1126{
1127 PointerRNA *ptr_dst = &rnaapply_ctx.ptr_dst;
1128 PointerRNA *ptr_src = &rnaapply_ctx.ptr_src;
1129 PointerRNA *ptr_storage = &rnaapply_ctx.ptr_storage;
1130 PropertyRNA *prop_dst = rnaapply_ctx.prop_dst;
1131 PropertyRNA *prop_src = rnaapply_ctx.prop_src;
1132 PropertyRNA *prop_storage = rnaapply_ctx.prop_storage;
1133 PointerRNA *ptr_item_dst = &rnaapply_ctx.ptr_item_dst;
1134 PointerRNA *ptr_item_src = &rnaapply_ctx.ptr_item_src;
1135 PointerRNA *ptr_item_storage = &rnaapply_ctx.ptr_item_storage;
1138
1139 if ((RNA_property_type(prop_dst) != PROP_COLLECTION ||
1140 RNA_property_type(prop_src) != PROP_COLLECTION ||
1141 (prop_storage != nullptr && RNA_property_type(prop_storage) != PROP_COLLECTION)) ||
1142 (opop->subitem_local_name == nullptr && opop->subitem_reference_name == nullptr &&
1143 opop->subitem_local_index == -1 && opop->subitem_reference_index == -1))
1144 {
1145 return;
1146 }
1147
1148 const bool use_id_pointer = (opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID) != 0;
1149 std::optional<ID *> subitem_local_id = use_id_pointer ? std::optional(opop->subitem_local_id) :
1150 std::nullopt;
1151 std::optional<ID *> subitem_reference_id = use_id_pointer ?
1152 std::optional(opop->subitem_reference_id) :
1153 std::nullopt;
1154
1155 RNA_POINTER_INVALIDATE(ptr_item_dst);
1156 RNA_POINTER_INVALIDATE(ptr_item_src);
1157 if (prop_storage != nullptr) {
1158 RNA_POINTER_INVALIDATE(ptr_item_storage);
1159 }
1160
1161 PointerRNA ptr_item_dst_name, ptr_item_dst_index;
1162 PointerRNA ptr_item_src_name, ptr_item_src_index;
1163 PointerRNA ptr_item_storage_name, ptr_item_storage_index;
1165 prop_src,
1166 opop->subitem_local_name,
1167 subitem_local_id,
1168 opop->subitem_local_index,
1169 &ptr_item_src_name,
1170 &ptr_item_src_index);
1172 prop_dst,
1174 subitem_reference_id,
1176 &ptr_item_dst_name,
1177 &ptr_item_dst_index);
1178 /* This is rather fragile, but the fact that local override IDs may have a different name
1179 * than their linked reference makes it necessary.
1180 * Basically, here we are considering that if we cannot find the original linked ID in
1181 * the local override we are (re-)applying the operations, then it may be because some of
1182 * those operations have already been applied, and we may already have the local ID
1183 * pointer we want to set.
1184 * This happens e.g. during re-sync of an override, since we have already remapped all ID
1185 * pointers to their expected values.
1186 * In that case we simply try to get the property from the local expected name. */
1187 if (opop->subitem_reference_name != nullptr && opop->subitem_local_name != nullptr &&
1188 ptr_item_dst_name.type == nullptr)
1189 {
1191 ptr_dst,
1192 prop_dst,
1193 opop->subitem_local_name,
1194 {},
1196 opop->subitem_local_index,
1197 &ptr_item_dst_name,
1198 &ptr_item_dst_index);
1199 }
1200
1201 /* For historical compatibility reasons, we fallback to reference if no local item info is given,
1202 * and vice-versa. */
1203 if (opop->subitem_reference_name == nullptr && opop->subitem_local_name != nullptr) {
1205 ptr_dst,
1206 prop_dst,
1207 opop->subitem_local_name,
1208 {},
1210 opop->subitem_local_index,
1211 &ptr_item_dst_name,
1212 &ptr_item_dst_index);
1213 }
1214 else if (opop->subitem_reference_name != nullptr && opop->subitem_local_name == nullptr) {
1216 prop_src,
1218 {},
1219 opop->subitem_local_index != -1 ?
1220 opop->subitem_local_index :
1222 &ptr_item_src_name,
1223 &ptr_item_src_index);
1224 }
1225 if (opop->subitem_reference_index == -1 && opop->subitem_local_index != -1) {
1227 prop_dst,
1228 nullptr,
1229 {},
1230 opop->subitem_local_index,
1231 &ptr_item_dst_name,
1232 &ptr_item_dst_index);
1233 }
1234 else if (opop->subitem_reference_index != -1 && opop->subitem_local_index == -1) {
1236 prop_src,
1237 nullptr,
1238 {},
1240 &ptr_item_src_name,
1241 &ptr_item_src_index);
1242 }
1243
1244 /* For storage, simply lookup by name first, and fallback to indices. */
1245 if (prop_storage != nullptr) {
1247 prop_storage,
1248 opop->subitem_local_name,
1249 subitem_local_id,
1250 opop->subitem_local_index,
1251 &ptr_item_storage_name,
1252 &ptr_item_storage_index);
1253 if (ptr_item_storage_name.data == nullptr) {
1255 prop_storage,
1257 subitem_reference_id,
1259 &ptr_item_storage_name,
1260 &ptr_item_storage_index);
1261 }
1262 if (ptr_item_storage_name.data == nullptr && ptr_item_storage_index.data == nullptr) {
1264 prop_storage,
1265 nullptr,
1266 {},
1267 opop->subitem_local_index,
1268 &ptr_item_storage_name,
1269 &ptr_item_storage_index);
1270 }
1271 }
1272
1273 /* Final selection. both matches have to be based on names, or indices, but not a mix of both. */
1274 if (ptr_item_src_name.type != nullptr && ptr_item_dst_name.type != nullptr) {
1275 *ptr_item_src = ptr_item_src_name;
1276 *ptr_item_dst = ptr_item_dst_name;
1277 if (prop_storage != nullptr) {
1278 *ptr_item_storage = ptr_item_storage_name;
1279 }
1280 }
1281 else if (ptr_item_src_index.type != nullptr && ptr_item_dst_index.type != nullptr) {
1282 *ptr_item_src = ptr_item_src_index;
1283 *ptr_item_dst = ptr_item_dst_index;
1284 if (prop_storage != nullptr) {
1285 *ptr_item_storage = ptr_item_storage_index;
1286 }
1287 }
1288
1289 /* Note that there is no reason to report in case no item is expected, i.e. in case subitem name
1290 * and index are invalid. This can often happen when inserting new items (constraint,
1291 * modifier...) in a collection that supports it. */
1292 if (ptr_item_dst->type == nullptr &&
1293 ((opop->subitem_reference_name != nullptr && opop->subitem_reference_name[0] != '\0') ||
1294 opop->subitem_reference_index != -1))
1295 {
1296 CLOG_INFO(&LOG,
1297 2,
1298 "Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'",
1299 opop->subitem_reference_name != nullptr ? opop->subitem_reference_name : "",
1301 op->rna_path,
1302 ptr_dst->owner_id->name);
1303 }
1304 if (ptr_item_src->type == nullptr &&
1305 ((opop->subitem_local_name != nullptr && opop->subitem_local_name[0] != '\0') ||
1306 opop->subitem_local_index != -1))
1307 {
1308 CLOG_INFO(&LOG,
1309 2,
1310 "Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'",
1311 opop->subitem_local_name != nullptr ? opop->subitem_local_name : "",
1312 opop->subitem_local_index,
1313 op->rna_path,
1314 ptr_src->owner_id->name);
1315 }
1316}
1317
1319 PointerRNA *ptr_dst,
1320 PointerRNA *ptr_src,
1321 PointerRNA *ptr_item_dst,
1322 PointerRNA *ptr_item_src)
1323{
1325 bmain, ptr_src, nullptr, nullptr);
1327 bmain, ptr_dst, nullptr, nullptr);
1328 ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, nullptr, nullptr);
1329 ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, nullptr, nullptr);
1330
1332
1333 /* If the owner ID is not part of an override hierarchy, there is no possible resync. */
1335 return;
1336 }
1337
1338 /* If `id_src` is not a liboverride, we cannot perform any further 'need resync' checks from
1339 * here. */
1340 if (id_src != nullptr && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) {
1341 return;
1342 }
1343
1344 if (/* We might be in a case where id_dst has already been processed and its usages
1345 * remapped to its new local override. In that case overrides and linked data
1346 * are always properly matching. */
1347 id_src != id_dst &&
1348 /* If one of the pointers is nullptr and not the other, we are in a non-matching case. */
1349 (ELEM(nullptr, id_src, id_dst) ||
1350 /* If `id_dst` is not from same lib as id_src, and linked reference ID of `id_src` is not
1351 * `id_dst`, we are in a non-matching case. */
1352 (id_dst->lib != id_src->lib && id_src->override_library->reference != id_dst) ||
1353 /* If `id_dst` is from same lib as id_src, and is not same as `id_owner`, we are in a
1354 * non-matching case.
1355 *
1356 * NOTE: Here we are testing if `id_owner` is referencing itself, in that case the new
1357 * override copy generated by `BKE_lib_override_library_update` will already have its
1358 * self-references updated to itself, instead of still pointing to its linked source. */
1359 (id_dst->lib == id_src->lib && id_dst != id_owner_dst)))
1360 {
1361 id_owner_dst->tag |= ID_TAG_LIBOVERRIDE_NEED_RESYNC;
1362 if (ID_IS_LINKED(id_owner_src)) {
1363 id_owner_src->lib->runtime.tag |= LIBRARY_TAG_RESYNC_REQUIRED;
1364 }
1365 CLOG_INFO(&LOG,
1366 3,
1367 "Local override %s detected as needing resync due to mismatch in its used IDs",
1368 id_owner_dst->name);
1369 }
1370 if ((id_owner_src->override_library->reference->tag & ID_TAG_LIBOVERRIDE_NEED_RESYNC) != 0) {
1371 id_owner_dst->tag |= ID_TAG_LIBOVERRIDE_NEED_RESYNC;
1372 if (ID_IS_LINKED(id_owner_src)) {
1373 id_owner_src->lib->runtime.tag |= LIBRARY_TAG_RESYNC_REQUIRED;
1374 }
1375 CLOG_INFO(&LOG,
1376 3,
1377 "Local override %s detected as needing resync as its liboverride reference is "
1378 "already tagged for resync",
1379 id_owner_dst->name);
1380 }
1381}
1382
1384 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1385{
1387 const bool do_insert = rnaapply_ctx.do_insert;
1388
1390 if (opop->operation == LIBOVERRIDE_OP_NOOP) {
1391 continue;
1392 }
1393
1394 if (!do_insert !=
1396 {
1397 if (!do_insert) {
1398 CLOG_INFO(&LOG, 5, "Skipping insert override operations in first pass (%s)", op->rna_path);
1399 }
1400 continue;
1401 }
1402
1403 rnaapply_ctx.liboverride_operation = opop;
1404
1406
1407 if (!rna_property_override_operation_apply(bmain, rnaapply_ctx)) {
1408 CLOG_INFO(&LOG,
1409 4,
1410 "Failed to apply '%s' override operation on %s\n",
1411 op->rna_path,
1412 rnaapply_ctx.ptr_src.owner_id->name);
1413 }
1414 }
1415
1416 rnaapply_ctx.liboverride_operation = nullptr;
1417}
1418
1424 PointerRNA *id_ptr_dst,
1425 PointerRNA *id_ptr_src,
1426 RNAPropertyOverrideApplyContext &rnaapply_ctx)
1427{
1428 UNUSED_VARS_NDEBUG(bmain, id_ptr_src);
1429
1430 if ((rnaapply_ctx.flag & RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS) == 0) {
1431 return false;
1432 }
1433
1434 if (!RNA_struct_is_ID(RNA_property_pointer_type(&rnaapply_ctx.ptr_dst, rnaapply_ctx.prop_dst))) {
1436 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)));
1437 return false;
1438 }
1439
1441
1442 /* IDProperties case. */
1443 if (rnaapply_ctx.prop_dst->magic != RNA_MAGIC) {
1444 CLOG_INFO(&LOG,
1445 2,
1446 "%s: Ignoring local override on ID pointer custom property '%s', as requested by "
1447 "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1448 id_ptr_dst->owner_id->name,
1449 op->rna_path);
1450 return true;
1451 }
1452
1453 switch (op->rna_prop_type) {
1454 case PROP_POINTER: {
1455 if ((static_cast<IDOverrideLibraryPropertyOperation *>(op->operations.first)->flag &
1457 {
1459 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1461 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1462
1463 CLOG_INFO(&LOG,
1464 2,
1465 "%s: Ignoring local override on ID pointer property '%s', as requested by "
1466 "RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1467 id_ptr_dst->owner_id->name,
1468 op->rna_path);
1469 return true;
1470 }
1471 break;
1472 }
1473 case PROP_COLLECTION: {
1474 /* For collections of ID pointers just completely skip the override ops here... A tad brutal,
1475 * but this is a backup 'fix the mess' tool, and in practice this should never be an issue.
1476 * Can always be refined later if needed. */
1477 CLOG_INFO(&LOG,
1478 2,
1479 "%s: Ignoring all local override on ID pointer collection property '%s', as "
1480 "requested by RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS flag",
1481 id_ptr_dst->owner_id->name,
1482 op->rna_path);
1483 return true;
1484 }
1485 default:
1486 break;
1487 }
1488
1489 return false;
1490}
1491
1493 PointerRNA *id_ptr_dst,
1494 PointerRNA *id_ptr_src,
1495 PointerRNA *id_ptr_storage,
1496 IDOverrideLibrary *liboverride,
1498{
1499#ifdef DEBUG_OVERRIDE_TIMEIT
1501#endif
1502 const bool do_restore_only = (flag & RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY) != 0;
1503 /* NOTE: Applying insert operations in a separate pass is mandatory.
1504 * We could optimize this later, but for now, as inefficient as it is,
1505 * don't think this is a critical point.
1506 */
1507 bool do_insert = false;
1508 for (int i = 0; i < (do_restore_only ? 1 : 2); i++, do_insert = true) {
1510 if (do_restore_only && (op->tag % LIBOVERRIDE_PROP_TAG_NEEDS_RETORE) == 0) {
1511 continue;
1512 }
1513 /* That tag should only exist for short lifespan when restoring values from reference linked
1514 * data. */
1515 BLI_assert((op->tag & LIBOVERRIDE_PROP_TAG_NEEDS_RETORE) == 0 || do_restore_only);
1516
1518 rnaapply_ctx.flag = flag;
1519 rnaapply_ctx.do_insert = do_insert;
1520
1521 rnaapply_ctx.liboverride = liboverride;
1522 rnaapply_ctx.liboverride_property = op;
1523
1525 op->rna_path,
1526 &rnaapply_ctx.ptr_dst,
1527 &rnaapply_ctx.prop_dst,
1528 &rnaapply_ctx.ptr_item_dst) &&
1530 op->rna_path,
1531 &rnaapply_ctx.ptr_src,
1532 &rnaapply_ctx.prop_src,
1533 &rnaapply_ctx.ptr_item_src)))
1534 {
1535 CLOG_INFO(&LOG,
1536 4,
1537 "Failed to apply library override operation to '%s.%s' "
1538 "(could not resolve some properties, local: %d, override: %d)",
1539 static_cast<ID *>(id_ptr_src->owner_id)->name,
1540 op->rna_path,
1542 id_ptr_dst, op->rna_path, &rnaapply_ctx.ptr_dst, &rnaapply_ctx.prop_dst),
1544 id_ptr_src, op->rna_path, &rnaapply_ctx.ptr_src, &rnaapply_ctx.prop_src));
1545 continue;
1546 }
1547
1548 /* It is totally OK if this does not success,
1549 * only a subset of override operations actually need storage. */
1550 if (id_ptr_storage && (id_ptr_storage->owner_id != nullptr)) {
1552 op->rna_path,
1553 &rnaapply_ctx.ptr_storage,
1554 &rnaapply_ctx.prop_storage,
1555 &rnaapply_ctx.ptr_item_storage);
1556 }
1557
1558 /* Check if an overridden ID pointer supposed to be in sync with linked data gets out of
1559 * sync. */
1561 (id_ptr_dst->owner_id->tag & ID_TAG_LIBOVERRIDE_NEED_RESYNC) == 0)
1562 {
1563 if (op->rna_prop_type == PROP_POINTER && op->operations.first != nullptr &&
1564 (static_cast<IDOverrideLibraryPropertyOperation *>(op->operations.first)->flag &
1566 {
1568 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)));
1570 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1572 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1573
1574 PointerRNA prop_ptr_src = RNA_property_pointer_get(&rnaapply_ctx.ptr_src,
1575 rnaapply_ctx.prop_src);
1576 PointerRNA prop_ptr_dst = RNA_property_pointer_get(&rnaapply_ctx.ptr_dst,
1577 rnaapply_ctx.prop_dst);
1579 bmain, id_ptr_dst, id_ptr_src, &prop_ptr_dst, &prop_ptr_src);
1580 }
1581 else if (op->rna_prop_type == PROP_COLLECTION) {
1582 if (RNA_struct_is_ID(
1583 RNA_property_pointer_type(&rnaapply_ctx.ptr_src, rnaapply_ctx.prop_src)))
1584 {
1585 BLI_assert(id_ptr_src->owner_id ==
1587 bmain, &rnaapply_ctx.ptr_src, nullptr, nullptr));
1588 BLI_assert(id_ptr_dst->owner_id ==
1590 bmain, &rnaapply_ctx.ptr_dst, nullptr, nullptr));
1591
1592 LISTBASE_FOREACH (IDOverrideLibraryPropertyOperation *, opop, &op->operations) {
1593 if ((opop->flag & LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) {
1594 continue;
1595 }
1596 rnaapply_ctx.liboverride_operation = opop;
1597
1599
1601 id_ptr_dst,
1602 id_ptr_src,
1603 &rnaapply_ctx.ptr_item_dst,
1604 &rnaapply_ctx.ptr_item_src);
1605 }
1606 rnaapply_ctx.liboverride_operation = nullptr;
1607 }
1608 }
1609 }
1610
1611 if (override_apply_property_check_skip(bmain, id_ptr_dst, id_ptr_src, rnaapply_ctx)) {
1612 continue;
1613 }
1614
1615 rna_property_override_apply_ex(bmain, rnaapply_ctx);
1616 }
1617 }
1618
1619 /* Some cases (like point caches) may require additional post-processing. */
1620 if (RNA_struct_is_a(id_ptr_dst->type, &RNA_ID)) {
1621 ID *id_dst = static_cast<ID *>(id_ptr_dst->data);
1622 ID *id_src = static_cast<ID *>(id_ptr_src->data);
1623 const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id_dst);
1624 if (id_type->lib_override_apply_post != nullptr) {
1625 id_type->lib_override_apply_post(id_dst, id_src);
1626 }
1627 }
1628
1629#ifdef DEBUG_OVERRIDE_TIMEIT
1631#endif
1632}
1633
1635 PointerRNA *ptr,
1636 PropertyRNA *prop,
1637 ID **r_owner_id)
1638{
1639 std::optional<std::string> rna_path;
1640
1641 *r_owner_id = rna_property_override_property_real_id_owner(bmain, ptr, prop, &rna_path);
1642 if (rna_path) {
1644 (*r_owner_id)->override_library, rna_path->c_str());
1645 return op;
1646 }
1647 return nullptr;
1648}
1649
1651 PointerRNA *ptr,
1652 PropertyRNA *prop,
1653 bool *r_created)
1654{
1655 std::optional<std::string> rna_path;
1656
1657 if (r_created != nullptr) {
1658 *r_created = false;
1659 }
1660
1661 ID *id = rna_property_override_property_real_id_owner(bmain, ptr, prop, &rna_path);
1662 if (rna_path) {
1664 id->override_library, rna_path->c_str(), r_created);
1665 return op;
1666 }
1667 return nullptr;
1668}
1669
1671 Main *bmain,
1672 PointerRNA *ptr,
1673 PropertyRNA *prop,
1674 const int index,
1675 const bool strict,
1676 bool *r_strict)
1677{
1678 ID *owner_id;
1680
1681 if (!op) {
1682 return nullptr;
1683 }
1684
1686 op, nullptr, nullptr, {}, {}, index, index, strict, r_strict);
1687}
1688
1690 Main *bmain,
1691 PointerRNA *ptr,
1692 PropertyRNA *prop,
1693 const short operation,
1694 const int index,
1695 const bool strict,
1696 bool *r_strict,
1697 bool *r_created)
1698{
1699 if (r_created != nullptr) {
1700 *r_created = false;
1701 }
1702
1704
1705 if (!op) {
1706 return nullptr;
1707 }
1708
1710 op, operation, nullptr, nullptr, {}, {}, index, index, strict, r_strict, r_created);
1711}
1712
1714 PointerRNA *ptr,
1715 PropertyRNA *prop,
1716 const int index)
1717{
1718 eRNAOverrideStatus override_status = eRNAOverrideStatus(0);
1719
1720 if (!ptr || !prop || !ptr->owner_id || !ID_IS_OVERRIDE_LIBRARY(ptr->owner_id)) {
1721 return override_status;
1722 }
1723
1725 override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE;
1726 }
1727
1729 bmain, ptr, prop, index, false, nullptr);
1730 if (opop != nullptr) {
1731 override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN;
1732 if (opop->flag & LIBOVERRIDE_OP_FLAG_MANDATORY) {
1733 override_status |= RNA_OVERRIDE_STATUS_MANDATORY;
1734 }
1735 if (opop->flag & LIBOVERRIDE_OP_FLAG_LOCKED) {
1736 override_status |= RNA_OVERRIDE_STATUS_LOCKED;
1737 }
1738 }
1739
1740 return override_status;
1741}
void BKE_pose_ensure(Main *bmain, Object *ob, bArmature *arm, bool do_id_user)
Definition armature.cc:2822
const IDTypeInfo * BKE_idtype_get_info_from_id(const ID *id)
Definition idtype.cc:150
void BKE_lib_override_library_operations_tag(IDOverrideLibraryProperty *liboverride_property, short tag, bool do_set)
IDOverrideLibraryProperty * BKE_lib_override_library_property_find(IDOverrideLibrary *liboverride, const char *rna_path)
IDOverrideLibraryProperty * BKE_lib_override_library_property_get(IDOverrideLibrary *liboverride, const char *rna_path, bool *r_created)
IDOverrideLibraryPropertyOperation * BKE_lib_override_library_property_operation_get(IDOverrideLibraryProperty *liboverride_property, short operation, const char *subitem_refname, const char *subitem_locname, const std::optional< ID * > &subitem_refid, const std::optional< ID * > &subitem_locid, int subitem_refindex, int subitem_locindex, bool strict, bool *r_strict, bool *r_created)
IDOverrideLibraryPropertyOperation * BKE_lib_override_library_property_operation_find(IDOverrideLibraryProperty *liboverride_property, const char *subitem_refname, const char *subitem_locname, const std::optional< const ID * > &subitem_refid, const std::optional< const ID * > &subitem_locid, int subitem_refindex, int subitem_locindex, bool strict, bool *r_strict)
bool BKE_lib_override_library_property_operation_operands_validate(IDOverrideLibraryPropertyOperation *liboverride_property_operation, PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_storage, PropertyRNA *prop_dst, PropertyRNA *prop_src, PropertyRNA *prop_storage)
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#define LISTBASE_FOREACH(type, var, list)
unsigned int uint
double BLI_time_now_seconds(void)
Definition time.c:65
Utility defines for timing/benchmarks.
#define TIMEIT_START_AVERAGED(var)
#define TIMEIT_END_AVERAGED(var)
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
ID and Library types, which are fundamental for SDNA.
#define ID_IS_OVERRIDE_LIBRARY_REAL(_id)
Definition DNA_ID.h:676
@ LIBOVERRIDE_PROP_TAG_NEEDS_RETORE
Definition DNA_ID.h:296
@ LIBOVERRIDE_PROP_OP_TAG_UNUSED
Definition DNA_ID.h:293
@ LIBOVERRIDE_TAG_NEEDS_RESTORE
Definition DNA_ID.h:315
@ LIBOVERRIDE_OP_FLAG_MANDATORY
Definition DNA_ID.h:247
@ LIBOVERRIDE_OP_FLAG_LOCKED
Definition DNA_ID.h:249
@ LIBOVERRIDE_OP_FLAG_IDPOINTER_ITEM_USE_ID
Definition DNA_ID.h:261
@ LIBOVERRIDE_OP_FLAG_IDPOINTER_MATCH_REFERENCE
Definition DNA_ID.h:255
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
@ ID_FLAG_EMBEDDED_DATA_LIB_OVERRIDE
Definition DNA_ID.h:736
@ ID_FLAG_EMBEDDED_DATA
Definition DNA_ID.h:725
@ LIBOVERRIDE_OP_NOOP
Definition DNA_ID.h:227
@ LIBOVERRIDE_OP_ADD
Definition DNA_ID.h:232
@ LIBOVERRIDE_OP_SUBTRACT
Definition DNA_ID.h:234
@ LIBOVERRIDE_OP_REPLACE
Definition DNA_ID.h:229
@ LIBOVERRIDE_OP_MULTIPLY
Definition DNA_ID.h:236
@ LIBOVERRIDE_OP_INSERT_BEFORE
Definition DNA_ID.h:240
@ LIBOVERRIDE_OP_INSERT_AFTER
Definition DNA_ID.h:239
@ ID_TAG_LIBOVERRIDE_NEED_RESYNC
Definition DNA_ID.h:852
@ LIBOVERRIDE_FLAG_NO_HIERARCHY
Definition DNA_ID.h:362
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ LIBRARY_TAG_RESYNC_REQUIRED
Definition DNA_ID.h:541
@ ID_NT
@ ID_KE
@ ID_GR
@ ID_OB
@ IDP_FLAG_STATIC_TYPE
@ IDP_FLAG_OVERRIDABLE_LIBRARY
@ NLATRACK_OVERRIDELIBRARY_LOCAL
@ BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL
@ CAM_BGIMG_FLAG_OVERRIDE_LIBRARY_LOCAL
@ CONSTRAINT_OVERRIDE_LIBRARY_LOCAL
@ eModifierFlag_OverrideLibrary_Local
Object is a sort of wrapper for general info.
@ OB_ARMATURE
Read Guarded memory(de)allocation.
#define RNA_POINTER_INVALIDATE(ptr)
eRNAOverrideStatus
@ RNA_OVERRIDE_STATUS_OVERRIDABLE
@ RNA_OVERRIDE_STATUS_MANDATORY
@ RNA_OVERRIDE_STATUS_OVERRIDDEN
@ RNA_OVERRIDE_STATUS_LOCKED
eRNAOverrideApplyFlag
@ RNA_OVERRIDE_APPLY_FLAG_IGNORE_ID_POINTERS
@ RNA_OVERRIDE_APPLY_FLAG_SKIP_RESYNC_CHECK
@ RNA_OVERRIDE_APPLY_FLAG_RESTORE_ONLY
eRNAOverrideMatch
@ RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN
@ RNA_OVERRIDE_COMPARE_CREATE
@ RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE
@ RNA_OVERRIDE_COMPARE_RESTORE
@ RNA_OVERRIDE_COMPARE_TAG_FOR_RESTORE
eRNACompareMode
@ RNA_EQ_UNSET_MATCH_ANY
@ RNA_EQ_STRICT
@ RNA_EQ_UNSET_MATCH_NONE
eRNAOverrideMatchResult
@ RNA_OVERRIDE_MATCH_RESULT_RESTORED
@ RNA_OVERRIDE_MATCH_RESULT_RESTORE_TAGGED
@ RNA_OVERRIDE_MATCH_RESULT_CREATED
@ PROP_POINTER
Definition RNA_types.hh:70
@ PROP_COLLECTION
Definition RNA_types.hh:71
@ PROPOVERRIDE_OVERRIDABLE_LIBRARY
Definition RNA_types.hh:355
@ PROPOVERRIDE_NO_COMPARISON
Definition RNA_types.hh:363
@ PROPOVERRIDE_IGNORE
Definition RNA_types.hh:375
#define printf
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
void rna_property_rna_or_id_get(PropertyRNA *prop, PointerRNA *ptr, PropertyRNAOrID *r_prop_rna_or_id)
bool RNA_struct_is_ID(const StructRNA *type)
StructRNA * RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_collection_begin(PointerRNA *ptr, PropertyRNA *prop, CollectionPropertyIterator *iter)
PropertyType RNA_property_type(PropertyRNA *prop)
char * RNA_property_string_get_alloc(PointerRNA *ptr, PropertyRNA *prop, char *fixedbuf, int fixedlen, int *r_len)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_collection_next(CollectionPropertyIterator *iter)
bool RNA_property_collection_lookup_int(PointerRNA *ptr, PropertyRNA *prop, int key, PointerRNA *r_ptr)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_editable(const PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr)
void RNA_property_collection_end(CollectionPropertyIterator *iter)
PropertyRNA * RNA_struct_iterator_property(StructRNA *type)
bool RNA_property_editable_flag(const PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
PropertyRNA * rna_ensure_property(PropertyRNA *prop)
IDOverrideLibraryPropertyOperation * RNA_property_override_property_operation_get(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index, const bool strict, bool *r_strict, bool *r_created)
IDOverrideLibraryProperty * RNA_property_override_property_find(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, ID **r_owner_id)
IDOverrideLibraryProperty * RNA_property_override_property_get(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, bool *r_created)
bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
static void rna_property_override_collection_subitem_name_index_lookup(PointerRNA *ptr, PropertyRNA *prop, const char *item_name, const std::optional< ID * > &item_id, const int item_index, PointerRNA *r_ptr_item_name, PointerRNA *r_ptr_item_index)
static bool rna_property_override_collection_subitem_name_id_match(const char *item_name, const int item_name_len, const bool do_id_pointer, const std::optional< ID * > &item_id, PointerRNA *ptr_item_name)
static bool override_apply_property_check_skip(Main *bmain, PointerRNA *id_ptr_dst, PointerRNA *id_ptr_src, RNAPropertyOverrideApplyContext &rnaapply_ctx)
bool RNA_property_overridable_library_set(PointerRNA *, PropertyRNA *prop, const bool is_overridable)
IDOverrideLibraryPropertyOperation * RNA_property_override_property_operation_find(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
bool RNA_struct_override_store(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, IDOverrideLibrary *liboverride)
static void rna_property_override_apply_ex(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx)
static bool rna_property_override_operation_store(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, IDOverrideLibraryProperty *op)
static ID * rna_property_override_property_real_id_owner(Main *, PointerRNA *ptr, PropertyRNA *prop, std::optional< std::string > *r_rna_path)
int RNA_property_override_flag(PropertyRNA *prop)
static void rna_property_override_collection_subitem_lookup(RNAPropertyOverrideApplyContext &rnaapply_ctx)
bool RNA_property_comparable(PointerRNA *, PropertyRNA *prop)
static int rna_property_override_diff(Main *bmain, PropertyRNAOrID *prop_a, PropertyRNAOrID *prop_b, const char *rna_path, const size_t rna_path_len, eRNACompareMode mode, IDOverrideLibrary *liboverride, const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags)
#define RNA_PATH_BUFFSIZE
static bool rna_property_override_operation_apply(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx)
void RNA_struct_override_apply(Main *bmain, PointerRNA *id_ptr_dst, PointerRNA *id_ptr_src, PointerRNA *id_ptr_storage, IDOverrideLibrary *liboverride, const eRNAOverrideApplyFlag flag)
bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop)
bool RNA_property_overridable_get(const PointerRNA *ptr, PropertyRNA *prop)
static CLG_LogRef LOG
static bool rna_property_override_collection_subitem_name_id_lookup(PointerRNA *ptr, PropertyRNA *prop, const char *item_name, const int item_name_len, const bool do_id_pointer, const std::optional< ID * > &item_id, PointerRNA *r_ptr_item_name)
eRNAOverrideStatus RNA_property_override_library_status(Main *bmain, PointerRNA *ptr, PropertyRNA *prop, const int index)
bool RNA_property_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
static void rna_property_override_check_resync(Main *bmain, PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *ptr_item_dst, PointerRNA *ptr_item_src)
bool RNA_struct_override_matches(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, const char *root_path, const size_t root_path_len, IDOverrideLibrary *liboverride, const eRNAOverrideMatch flags, eRNAOverrideMatchResult *r_report_flags)
bool RNA_property_copy(Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
bool rna_property_override_apply_default(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx)
void rna_property_override_diff_default(Main *bmain, RNAPropertyOverrideDiffContext &rnadiff_ctx)
bool rna_property_override_store_default(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, int len_local, int len_reference, int len_storage, IDOverrideLibraryPropertyOperation *opop)
#define RNA_MAGIC
bool(*)(Main *bmain, RNAPropertyOverrideApplyContext &rnaapply_ctx) RNAPropOverrideApply
void(*)(Main *bmain, RNAPropertyOverrideDiffContext &rnadiff_ctx) RNAPropOverrideDiff
bool(*)(Main *bmain, PointerRNA *ptr_local, PointerRNA *ptr_reference, PointerRNA *ptr_storage, PropertyRNA *prop_local, PropertyRNA *prop_reference, PropertyRNA *prop_storage, int len_local, int len_reference, int len_storage, IDOverrideLibraryPropertyOperation *opop) RNAPropOverrideStore
ID * RNA_find_real_ID_and_path(ID *id, const char **r_path)
Definition rna_path.cc:947
bool RNA_path_resolve_property_and_item_pointer(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, PointerRNA *r_item_ptr)
Definition rna_path.cc:575
std::optional< std::string > RNA_path_from_ID_to_property(const PointerRNA *ptr, PropertyRNA *prop)
Definition rna_path.cc:1166
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
unsigned int rna_prop_type
Definition DNA_ID.h:287
ListBase properties
Definition DNA_ID.h:335
unsigned int flag
Definition DNA_ID.h:352
struct ID * reference
Definition DNA_ID.h:333
IDOverrideLibraryRuntime * runtime
Definition DNA_ID.h:350
short flag
Definition DNA_ID.h:161
IDTypeLibOverrideApplyPost lib_override_apply_post
Definition DNA_ID.h:413
int tag
Definition DNA_ID.h:434
struct Library * lib
Definition DNA_ID.h:419
IDOverrideLibrary * override_library
Definition DNA_ID.h:459
char name[66]
Definition DNA_ID.h:425
struct Library_Runtime runtime
Definition DNA_ID.h:535
void * first
ID * owner_id
Definition RNA_types.hh:40
StructRNA * type
Definition RNA_types.hh:41
void * data
Definition RNA_types.hh:42
RNAPropOverrideApply override_apply
RNAPropOverrideStore override_store
RNAPropOverrideDiff override_diff
IDOverrideLibraryProperty * liboverride_property
IDOverrideLibraryPropertyOperation * liboverride_operation
eRNAOverrideMatchResult report_flag
PropertyRNA * nameproperty
ccl_device_inline int mod(int x, int m)
Definition util/math.h:520
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138