Anim: find Action Slot users on embedded IDs

Find Action Slot users on embedded IDs, such as the Node Tree used by a
Material.

Pull Request: #125666
This commit is contained in:
Sybren A. Stüvel 2024-07-30 13:32:49 +02:00
parent 835e626a28
commit 402e87c6d2

View File

@ -10,6 +10,7 @@
#include "BKE_anim_data.hh"
#include "BKE_global.hh"
#include "BKE_lib_query.hh"
#include "BKE_main.hh"
#include "BLI_set.hh"
@ -42,6 +43,39 @@ void rebuild_slot_user_cache(Main &bmain)
* runtime directly, but this is IMO a bit cleaner. */
bmain.is_action_slot_to_id_map_dirty = false;
/* Visit any ID to see which Action+Slot it is using. Returns whether the ID
* was visited for the first time. */
Set<ID *> visited_ids;
auto visit_id = [&visited_ids](ID *id) -> bool {
BLI_assert(id);
if (!visited_ids.add(id)) {
return false;
}
std::optional<std::pair<Action *, Slot *>> action_slot = get_action_slot_pair(*id);
if (action_slot) {
Slot &slot = *action_slot->second;
slot.users_add(*id);
}
return true;
};
auto visit_linked_id = [&](LibraryIDLinkCallbackData *cb_data) -> int {
ID *id = *cb_data->id_pointer;
if (!id) {
/* Can happen when the 'foreach' code visits a nullptr. */
return IDWALK_RET_NOP;
}
if (!visit_id(id)) {
/* When we hit an ID that was already visited, the recursion can stop. */
return IDWALK_RET_STOP_RECURSION;
}
return IDWALK_RET_NOP;
};
/* Loop over all IDs to cache their slot usage. */
ListBase *ids_of_idtype;
ID *id;
@ -55,13 +89,22 @@ void rebuild_slot_user_cache(Main &bmain)
FOREACH_MAIN_LISTBASE_ID_BEGIN (ids_of_idtype, id) {
BLI_assert(id_can_have_animdata(id));
std::optional<std::pair<Action *, Slot *>> action_slot = get_action_slot_pair(*id);
if (!action_slot) {
/* Process the ID itself.*/
if (!visit_id(id)) {
continue;
}
Slot &slot = *action_slot->second;
slot.users_add(*id);
/* Process embedded IDs, as these are not listed in bmain, but still can
* have their own Action+Slot. */
BKE_library_foreach_ID_link(
&bmain,
id,
visit_linked_id,
nullptr,
IDWALK_READONLY | IDWALK_RECURSE |
/* This is more about "we don't care" than "must be ignored". We don't pass an owner
* ID, and it's not used in the callback either, so don't bother looking it up. */
IDWALK_IGNORE_MISSING_OWNER_ID);
}
FOREACH_MAIN_LISTBASE_ID_END;
}